📄 basics of device drivers.htm
字号:
<tt>sys_select()</tt>, which originall called your
<tt>select()</tt> function, uses the information given to it by
the <tt>select_wait()</tt> function to put the process to
sleep. <tt>select_wait()</tt> adds the process to the wait
queue, but <tt>do_select()</tt> (called from
<tt>sys_select()</tt>) actually puts the process to sleep by
changing the process state to <tt>TASK_INTERRUPTIBLE</tt> and
calling <tt>schedule()</tt>.
</p><p>The first argument to <tt>select_wait()</tt> is the same
<tt>wait_queue</tt> that should be used for a
<tt>sleep_on()</tt>, and the second is the
<tt>select_table</tt> that was passed to your <tt>select()</tt>
function.
</p><p>After having explained all this in excruciating detail, here
are two rules to follow:
</p><ol>
<li>Call <tt>select_wait()</tt> if the device is not ready, and return 0.
</li><li>Return 1 if the device is ready.
</li></ol>
<p>If you provide a <tt>select()</tt> function, do not provide
timeouts by setting <tt>current->timeout</tt>, as the
<tt>select()</tt> mechanism uses <tt>current->timeout</tt>,
and the two methods cannot co-exist, as there is only one
<tt>timeout</tt> for each process. Instead, consider using a
timer to provide timeouts. See the description of the
<tt>add_timer()</tt> function in
<a href="http://tldp.org/LDP/khg/HyperNews/get/devices/reference.html">Supporting Functions</a>
for details.
</p><h4>The <tt>ioctl()</tt> function</h4>
<p>The <tt>ioctl()</tt> function processes ioctl calls. The
structure of your <tt>ioctl()</tt> function will be: first
error checking, then one giant (possibly nested) switch
statement to handle all possible ioctls. The ioctl number is
passed as <tt>cmd</tt>, and the argument to the ioctl is passed
as <tt>arg</tt>. It is good to have an understanding of how
<tt>ioctls</tt> ought to work before making them up. If you
are not sure about your ioctls, do not feel ashamed to ask
someone knowledgeable about it, for a few reasons: you may not
even need an ioctl for your purpose, and if you do need an
ioctl, there may be a better way to do it than what you have
thought of. Since ioctls are the least regular part of the
device interface, it takes perhaps the most work to get this
part right. Take the time and energy you need to get it right.
</p><p>The first thing you need to do is look in
Documentation/ioctl-number.txt, read it, and pick an unused number.
Then go from there.
</p><dl>
<dt><tt>struct inode * inode</tt>
</dt><dd>Pointer to the inode structure for this device.
</dd><dt><tt>struct file * file</tt>
</dt><dd>Pointer to the file structure for this device.
</dd><dt><tt>unsigned int cmd</tt>
</dt><dd>This is the ioctl command. It is
generally used as the switch variable for a case statement.
</dd><dt><tt>unsigned int arg</tt>
</dt><dd>This is the argument to the command.
This is user defined. Since this is the same size as a
<tt>(void *)</tt>, this can be used as a pointer to user space, accessed
through the fs register as usual.
</dd></dl>
<dl>
<dt><b>Returns:</b>
</dt><dd><tt>-errno</tt> on error<br>
Every other return is user-defined.
</dd></dl>
If the <tt>ioctl()</tt> slot in the <tt>file_operations</tt> structure is
not filled in, the VFS will return <tt>-EINVAL</tt>. However, in
all cases, if <tt>cmd</tt> is one of <tt>FIOCLEX</tt>, <tt>FIONCLEX</tt>,
<tt>FIONBIO</tt>, or <tt>FIOASYNC</tt>, default processing will be done:
<dl>
<dt><tt>FIOCLEX</tt> (0x5451)
</dt><dd>Sets the close-on-exec bit.
</dd><dt><tt>FIONCLEX</tt> (0x5450)
</dt><dd>Clears the close-on-exec bit.
</dd><dt><tt>FIONBIO</tt> (0x5421)
</dt><dd>If <tt>arg</tt> is non-zero, set <tt>O_NONBLOCK</tt>,
otherwise clear <tt>O_NONBLOCK</tt>.
</dd><dt><tt>FIOASYNC</tt> (0x5452)
</dt><dd>If <tt>arg</tt> is non-zero, set <tt>O_SYNC</tt>,
otherwise clear <tt>O_SYNC</tt>. <tt>O_SYNC</tt> is not yet implemented,
but it is documented here and parsed in the kernel for completeness.
</dd></dl>
Note that you have to avoid these four numbers when creating
your own ioctls, since if they conflict, the VFS ioctl code
will interpret them as being one of these four, and act
appropriately, causing a very hard-to-track-down bug.
<h4>The <tt>mmap()</tt> function</h4>
<dl>
<dt><tt>struct inode * inode</tt>
</dt><dd>Pointer to inode structure for device.
</dd><dt><tt>struct file * file</tt>
</dt><dd>Pointer to file structure for device.
</dd><dt><tt>unsigned long addr</tt>
</dt><dd>Beginning of address in main memory
to <tt>mmap()</tt> into.
</dd><dt><tt>size_t len</tt>
</dt><dd>Length of memory to <tt>mmap()</tt>.
</dd><dt><tt>int prot</tt>
</dt><dd>One of:
<table border="1">
<tbody><tr><td><tt>PROT_READ</tt></td><td>region can be read.</td></tr>
<tr><td><tt>PROT_WRITE</tt></td><td>region can be written.</td></tr>
<tr><td><tt>PROT_EXEC</tt></td><td>region can be executed.</td></tr>
<tr><td><tt>PROT_NONE</tt></td><td>region cannot be accessed.</td></tr>
</tbody></table>
</dd><dt><tt>unsigned long off</tt>
</dt><dd>Offset in the file to <tt>mmap()</tt> from.
This address in the file will be mapped to address <tt>addr</tt>.
</dd></dl>
<h4>The <tt>open()</tt> and <tt>release()</tt> functions</h4>
<dl>
<dt><tt>struct inode * inode</tt>
</dt><dd>Pointer to inode structure for device.
</dd><dt><tt>struct file * file</tt>
</dt><dd>Pointer to file structure for device.
</dd></dl>
<p><tt>open()</tt> is called when a device special files is
opened. It is the policy mechanism responsible for ensuring
consistency. If only one process is allowed to open the device
at once, <tt>open()</tt> should lock the device, using whatever
locking mechanism is appropriate, usually setting a bit in some
state variable to mark it as busy. If a process already is
using the device (if the busy bit is already set) then
<tt>open()</tt> should return <tt>-EBUSY</tt>. If more than
one process may open the device, this function is responsible
to set up any necessary queues that would not be set up in
<tt>write()</tt>. If no such device exists, <tt>open()</tt>
should return <tt>-ENODEV</tt> to indicate this. Return 0 on
success.
</p><p><tt>release()</tt> is called only when the process closes
its last open file descriptor on the files. <b>[I am not sure
this is true; it might be called on every close.]</b> If
devices have been marked as busy, <tt>release()</tt> should
unset the busy bits if appropriate. If you need to clean up
<tt>kmalloc()</tt>'ed queues or reset devices to preserve their
sanity, this is the place to do it. If no <tt>release()</tt>
function is defined, none is called.
</p><h4>The <tt>init()</tt> function</h4>
<p>This function is not actually included in the
<tt>file_operations</tt> structure, but you are required to
implement it, because it is this function that registers the
<tt>file_operations</tt> structure with the VFS in the first
place--without this function, the VFS could not route any
requests to the driver. This function is called when the
kernel first boots and is configuring itself. The init
function then detects all devices. You will have to call your
<tt>init()</tt> function from the correct place: for a
character device, this is <tt>chr_dev_init()</tt> in
drivers/char/mem.c.
</p><p>While the <tt>init()</tt> function runs, it registers your
driver by calling the proper registration function. For
character devices, this is <tt>register_chrdev()</tt>. (See
<a href="http://tldp.org/LDP/khg/HyperNews/get/devices/reference.html">Supporting Functions</a>
for more information on the registration functions.)
<tt>register_chrdev()</tt> takes three arguments: the major
device number (an int), the ``name'' of the device (a string),
and the address of the <tt><i>device</i>_fops</tt>
<tt>file_operations</tt> structure.
</p><p>When this is done, and a character or block special file is
accessed, the VFS filesystem switch automagically routes the
call, whatever it is, to the proper function, if a function
exists. If the function does not exist, the VFS routines take
some default action.
</p><p>The <tt>init()</tt> function usually displays some
information about the driver, and usually reports all hardware
found. All reporting is done via the <tt>printk()</tt>
function.
</p><p>Copyright (C) 1992, 1993, 1994, 1996 Michael K. Johnson,
johnsonm@redhat.com.<br>
</p><p>
</p><p></p><hr size="3">
<p><b><a name="Messages">Messages</a></b>
<nobr>
<font size="-1">
</font>
</nobr>
</p><p>
<nobr>
<dl compact="compact">
<dt> 1. <img src="basics%20of%20device%20drivers_files/question.gif" alt="Question:" align="middle" height="15" width="15">
<a href="http://tldp.org/LDP/khg/HyperNews/get/devices/basics/1.html">
using XX_select() for device without interrupts</a> <i> by <a href="http://iraf.noao.edu/%7Eecdowney">Elwood Downey</a></i> </dt>
<dt> 2. <img src="basics%20of%20device%20drivers_files/feedback.gif" alt="Feedback:" align="middle" height="15" width="15">
<a href="http://tldp.org/LDP/khg/HyperNews/get/devices/basics/2.html">
found reason for select() problem</a><i></i> </dt>
<dt> 3. <img src="basics%20of%20device%20drivers_files/question.gif" alt="Question:" align="middle" height="15" width="15">
<a href="http://tldp.org/LDP/khg/HyperNews/get/devices/basics/3.html">
Why do VFS functions get both structs inode and file?</a> <i> by Reinhold J. Gerharz</i> </dt>
</dl>
</nobr>
</p><p>
</p><p>
<br>
<br></p></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -