📄 node14.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<!--Converted with LaTeX2HTML 98.1 release (February 19th, 1998)
originally by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds
* revised and updated by: Marcus Hennecke, Ross Moore, Herb Swan
* with significant contributions from:
Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
<HTML>
<HEAD>
<TITLE>Character Device Files</TITLE>
<META NAME="description" CONTENT="Character Device Files">
<META NAME="keywords" CONTENT="mpg">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<LINK REL="STYLESHEET" HREF="mpg.css">
<LINK REL="next" HREF="node16.html">
<LINK REL="previous" HREF="node11.html">
<LINK REL="up" HREF="mpg.html">
<LINK REL="next" HREF="node15.html">
</HEAD>
<BODY >
<!--Navigation Panel-->
<A NAME="tex2html552"
HREF="node15.html">
<IMG WIDTH="37" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="next"
SRC="next_motif.gif"></A>
<A NAME="tex2html548"
HREF="mpg.html">
<IMG WIDTH="26" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="up"
SRC="up_motif.gif"></A>
<A NAME="tex2html542"
HREF="node13.html">
<IMG WIDTH="63" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="previous"
SRC="previous_motif.gif"></A>
<A NAME="tex2html550"
HREF="node1.html">
<IMG WIDTH="65" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="contents"
SRC="contents_motif.gif"></A>
<A NAME="tex2html551"
HREF="node34.html">
<IMG WIDTH="43" HEIGHT="24" ALIGN="BOTTOM" BORDER="0" ALT="index"
SRC="index_motif.gif"></A>
<BR>
<B> Next:</B> <A NAME="tex2html553"
HREF="node15.html">Multiple Kernel Versions Source</A>
<B> Up:</B> <A NAME="tex2html549"
HREF="mpg.html">Linux Kernel Module Programming</A>
<B> Previous:</B> <A NAME="tex2html543"
HREF="node13.html">Multiple File Kernel Modules</A>
<BR>
<BR>
<!--End of Navigation Panel-->
<H1><A NAME="SECTION00400000000000000000"> </A><A NAME="char-dev-file"> </A><A NAME="227"> </A>
<A NAME="228"> </A>
<BR>
Character Device Files
</H1>
<P>
So, now we're bold kernel programmers and we know how to write kernel
modules to do nothing. We feel proud of ourselves and we hold our heads
up high. But somehow we get the feeling that something
is missing. Catatonic modules are not much fun.
<P>
There are two major ways for a kernel module to talk to processes. One
is through device files (like the files in the <TT>/dev</TT> directory), the other
is to use the proc file system. Since one of the major reasons to write
something in the kernel is to support some kind of hardware device, we'll
begin with device files.
<A NAME="230"> </A>
<P>
The original purpose of device files is to allow processes to communicate
with device drivers in the kernel, and through them with physical devices
(modems, terminals, etc.). The way this is implemented is the following.
<A NAME="231"> </A>
<A NAME="232"> </A>
<A NAME="233"> </A>
<A NAME="234"> </A>
<P>
Each device driver, which is responsible for some type of hardware, is
assigned its own major number. The list of drivers and their major numbers
is available in <TT>/proc/devices</TT>. Each physical device managed by a device
driver is assigned a minor number. The <TT>/dev</TT> directory is supposed to
include a special file, called a device file, for each of those devices,
whether or not it's really installed on the system.
<A NAME="237"> </A>
<A NAME="238"> </A>
<A NAME="239"> </A>
<A NAME="240"> </A>
<P>
For example, if you do <TT>ls -l /dev/hd[ab]*</TT>, you'll see all of the IDE hard
disk partitions which might be connected to a machine. Notice that all of
them use the same major number, 3, but the minor number changes from one to
the other <EM>Disclaimer: This assumes you're using a PC architecture. I
don't know about devices on Linux running on other architectures</EM>.
<A NAME="243"> </A>
<A NAME="244"> </A>
<A NAME="245"> </A>
<P>
When the system was installed, all of those device files were created by
the <TT>mknod</TT> command. There's no technical reason why they have to be in
the <TT>/dev</TT> directory, it's just a useful convention. When creating a
device file for testing purposes, as with the exercise here, it would
probably make more sense to place it in the directory where you compile
the kernel module.
<A NAME="248"> </A>
<A NAME="249"> </A>
<P>
Devices are divided into two types: character devices and block devices.
The difference is that block devices have a buffer for requests, so
they can choose by which order to respond to them. This is important in
the case of storage devices, where it's faster to read or write sectors
which are close to each other, rather than those which are further
apart. Another difference is that block devices can only accept input
and return output in blocks (whose size can vary according to the device),
whereas character devices are allowed to use as many or as few bytes as
they like.
Most devices in the world are character, because they don't need
this type of buffering, and they don't operate with a fixed block size.
You can tell whether a device file is for a block device
or a character device by looking at the first character in the output of
<TT>ls -l</TT>. If it's `b' then it's a block device, and if it's `c'
then it's a character device.
<A NAME="251"> </A>
<A NAME="252"> </A>
<A NAME="253"> </A>
<A NAME="254"> </A>
<P>
This module is divided into two separate parts: The module part which
registers the device and the device driver part. The <TT>init_module</TT>
function calls <TT>module_register_chrdev</TT> to add the device driver to
the kernel's character device driver table. It also returns the major
number to be used for the driver. The <TT>cleanup_module</TT> function
deregisters the device.
<A NAME="258"> </A>
<A NAME="259"> </A>
<A NAME="260"> </A>
<P>
This (registering something and unregistering it) is the general
functionality of those two functions. Things in the kernel don't run on
their own initiative, like processes, but are called, by processes via
system calls, or by hardware devices via interrupts, or by other parts of
the kernel (simply by calling specific functions). As a result, when you
add code to the kernel, you're supposed to register it as the
handler for a certain type of event and when you remove it, you're
supposed to unregister it.
<A NAME="261"> </A>
<A NAME="262"> </A>
<P>
The device driver proper is composed of the four device_<action>
functions, which are called when somebody tries to do something with a
device file which has our major number. The way the kernel knows to call
them is via the <TT>file_operations</TT> structure, <TT>Fops</TT>, which was
given when the device was registered, which includes pointers to those
four functions.
<A NAME="265"> </A>
<A NAME="266"> </A>
<P>
Another point we need to remember here is that we can't allow the kernel
module to be <TT>rmmod</TT>ed whenever root feels like it. The reason is that
if the device file is opened by a process and then we remove the kernel
module, using the file would cause a call to the memory location where the
appropriate function (read/write) used to be. If we're lucky, no other code
was loaded there, and we'll get an ugly error message. If we're unlucky,
another kernel module was loaded into the same location, which means a
jump into the middle of another function within the kernel. The results
of this would be impossible to predict, but they can't be positive.
<A NAME="268"> </A>
<P>
Normally, when you don't want to allow something, you return an error
code (a negative number) from the function which is supposed to do it.
With <TT>cleanup_module</TT> that is impossible because it's a void function.
Once <TT>cleanup_module</TT> is called, the module is dead.
However, there
is a use counter which counts how many other kernel modules are using this
kernel module, called the reference count (that's the last number of the line
in <TT>/proc/modules</TT>). If this number isn't zero, <TT>rmmod</TT> will fail.
The module's reference count is available in the variable
<TT>mod_use_count_</TT>. Since there are macros defined for handling this
variable (<TT>MOD_INC_USE_COUNT</TT> and <TT>MOD_DEC_USE_COUNT</TT>), we
prefer to use them, rather than <TT>mod_use_count_</TT> directly, so we'll
be safe if the implementation changes in the future.
<A NAME="277"> </A>
<A NAME="278"> </A>
<A NAME="279"> </A>
<A NAME="280"> </A>
<A NAME="281"> </A>
<A NAME="282"> </A>
<P>
ex
<FONT SIZE="+1"><B>chardev.c</B></FONT>
<A NAME="287"> </A><A NAME="288"> </A>
<P>
<PRE>
/* chardev.c
* Copyright (C) 1998-1999 by Ori Pomerantz
*
* Create a character device (read only)
*/
/* The necessary header files */
/* Standard in kernel modules */
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif
/* For character devices */
#include <linux/fs.h> /* The character device
* definitions are here */
#include <linux/wrapper.h> /* A wrapper which does
* next to nothing at
* at present, but may
* help for compatibility
* with future versions
* of Linux */
/* In 2.2.3 /usr/include/linux/version.h includes
* a macro for this, but 2.0.35 doesn't - so I add
* it here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif
/* Conditional compilation. LINUX_VERSION_CODE is
* the code (as per KERNEL_VERSION) of this version. */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)
#include <asm/uaccess.h> /* for put_user */
#endif
#define SUCCESS 0
/* Device Declarations **************************** */
/* The name for our device, as it will appear
* in /proc/devices */
#define DEVICE_NAME "char_dev"
/* The maximum length of the message from the device */
#define BUF_LEN 80
/* Is the device open right now? Used to prevent
* concurent access into the same device */
static int Device_Open = 0;
/* The message the device will give when asked */
static char Message[BUF_LEN];
/* How far did the process reading the message
* get? Useful if the message is larger than the size
* of the buffer we get to fill in device_read. */
static char *Message_Ptr;
/* This function is called whenever a process
* attempts to open the device file */
static int device_open(struct inode *inode,
struct file *file)
{
static int counter = 0;
#ifdef DEBUG
printk ("device_open(%p,%p)\n", inode, file);
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -