⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 supporting functions.htm

📁 What is this ``device driver stuff anyway? Here s a very short introduction to the concept.
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html><head><title>Supporting Functions</title>

<link rel="owner" href="mailto:">
<script language="JavaScript">
<!-- hide this

function help(message) {
  self.status = message;
  return true;
}
// stop hiding -->
</script></head>

<body>
<strong>The
HyperNews <a href="http://tldp.org/LDP/khg/HyperNews/get/khg.html">Linux KHG</a>
Discussion Pages</strong>
<hr>
<h3>Supporting Functions</h3>

<p>Here is a list of many of the most common supporting
functions available to the device driver writer.  If you find
other supporting functions that are useful, please point them
out to me.  I know this is not a complete list, but I hope it
is a helpful one.

</p><h4><tt>add_request()</tt></h4>
<tt>static void add_request(struct blk_dev_struct *dev, struct request * req)</tt>

<p>This is a static function in ll_rw_block.c, and cannot be
called by other code.  However, an understanding of this
function, as well as an understanding of
<tt>ll_rw_block()</tt>, may help you understand the strategy
routine.

</p><p>If the device that the request is for has an empty request
queue, the request is put on the queue and the strategy routine
is called. Otherwise, the proper place in the queue is chosen
and the request is inserted in the queue, maintaining proper
order by insertion sort.

</p><p>Proper order (the elevator algorithm) is defined as:
</p><ol>
<li>Reads come before writes.
</li><li>Lower minor numbers come before higher minor numbers.
</li><li>Lower block numbers come before higher block numbers.
</li></ol>
The elevator algorithm is implemented by the macro
<tt>IN_ORDER()</tt>, which is defined in drivers/block/blk.h
<b>[This may have changed somewhat recently, but it shouldn't
matter to the driver writer anyway...]</b>

<p><b>Defined in:</b> drivers/block/ll_rw_block.c<br>
<b>See also:</b> <tt>make_request()</tt>, <tt>ll_rw_block()</tt>.


</p><h4><tt>add_timer()</tt></h4>
<tt>void add_timer(struct timer_list * timer)</tt><br>
<tt>#include &lt;linux/timer.h&gt;</tt>

<p>Installs the timer structures in the list <tt>timer</tt> in
the timer list.

</p><p>The <tt>timer_list</tt> structure is defined by:
</p><pre>struct timer_list {
        struct timer_list *next;
        struct timer_list *prev;
        unsigned long expires;
        unsigned long data;
        void (*function)(unsigned long);
};
</pre>

<p>In order to call <tt>add_timer()</tt>, you need to allocate
a <tt>timer_list</tt> structure, and then call
<tt>init_timer()</tt>, passing it a pointer to your
<tt>timer_list</tt>.  It will nullify the <tt>next</tt> and
<tt>prev</tt> elements, which is the correct initialization.
If necessary, you can allocate multiple <tt>timer_list</tt>
structures, and link them into a list.  Do make sure that you
properly initialize all the unused pointers to <tt>NULL</tt>,
or the timer code may get very confused.

</p><p>For each struct in your list, you set three variables:
</p><dl>
<dt><tt>expires</tt>
</dt><dd>The number of jiffies (100ths of a second in
Linux/86; thousandths or so in Linux/Alpha) after which to time out.
</dd><dt><tt>function</tt>
</dt><dd>Kernel-space function to run after timeout has occured.
</dd><dt><tt>data</tt>
</dt><dd>Passed as the argument to <tt>function</tt> when
<tt>function</tt> is called.
</dd></dl>

<p>Having created this list, you give a pointer to the first
(usually the only) element of the list as the argument to
<tt>add_timer()</tt>. Having passed that pointer, keep a copy
of the pointer handy, because you will need to use it to modify
the elements of the list (to set a new timeout when you need a
function called again, to change the function to be called, or
to change the data that is passed to the function) and to
delete the timer, if necessary.

</p><p><b>Note:</b> This is <i>not</i> process-specific.
Therefore, if you want to wake a certain process at a timeout,
you will have to use the sleep and wake primitives.  The
functions that you install through this mechanism will run in
the same context that interrupt handlers run in.

</p><p><b>Defined in:</b> kernel/sched.c<br>
<b>See also:</b> <tt>timer_table</tt> in include/linux/timer.h,
<tt>init_timer()</tt>, <tt>del_timer()</tt>.



</p><h4><tt>cli()</tt></h4>
<tt>#define cli() __asm__ __volatile__ ("cli"::)</tt><br>
<tt>#include &lt;asm/system.h&gt;</tt>

<p>Prevents interrupts from being acknowledged.  <tt>cli</tt>
stands for ``CLear Interrupt enable''.

</p><p><b>See also:</b> <tt>sti()</tt>



</p><h4><tt>del_timer</tt></h4>
<tt>void del_timer(struct timer_list * timer)</tt><br>
<tt>#include &lt;linux/timer.h&gt;</tt>

<p>Deletes the timer structures in the list <tt>timer</tt> in
the timer list.

</p><p>The timer list that you delete must be the address of a
timer list you have earlier installed with
<tt>add_timer()</tt>.  Once you have called
<tt>del_timer()</tt> to delete the timer from the kernel timer
list, you may deallocate the memory used in the
<tt>timer_list</tt> structures, as it is no longer referenced
by the kernel timer list.

</p><p><b>Defined in:</b> kernel/sched.c<br>
<b>See also:</b> <tt>timer_table</tt> in include/linux/timer.h,
<tt>init_timer()</tt>, <tt>add_timer()</tt>.



</p><h4><tt>end_request()</tt></h4>
<tt>static void end_request(int uptodate)</tt><br>
<tt>#include "blk.h"</tt>

<p>Called when a request has been satisfied or aborted.  Takes
one argument:
</p><dl>
<dt><tt>uptodate</tt>
</dt><dd>If not equal to 0, means that the request has been satisfied.<br>
If equal to 0, means that the request has not been satisfied.
</dd></dl>

<p>If the request was satisfied (<tt>uptodate != 0</tt>),
<tt>end_request()</tt> maintains the request list, unlocks the
buffer, and may arrange for the scheduler to be run at the next
convenient time (<tt>need_resched = 1</tt>; this is implicit in
<tt>wake_up()</tt>, and is not explicitly part of
<tt>end_request()</tt>), before waking up all processes
sleeping on the <tt>wait_for_request</tt> event, which is slept
on in <tt>make_request()</tt>, <tt>ll_rw_page()</tt>, and
<tt>ll_rw_swap_file()</tt>.

</p><p><b>Note:</b> This function is a static function, defined in
drivers/block/blk.h for every non-SCSI device that includes
blk.h. (SCSI devices do this differently; the high-level SCSI
code itself provides this functionality to the low-level
device-specific SCSI device drivers.) It includes several
defines dependent on static device information, such as the
device number.  This is marginally faster than a more generic
normal C function.

</p><p><b>Defined in:</b> kernel/blk_drv/blk.h<br>
<b>See also:</b> <tt>ll_rw_block()</tt>, <tt>add_request()</tt>,
<tt>make_request()</tt>.




</p><h4><tt>free_irq()</tt></h4>
<tt>void free_irq(unsigned int irq)</tt><br>
<tt>#include &lt;linux/sched.h&gt;</tt>

<p>Frees an irq previously aquired with <tt>request_irq()</tt>
or <tt>irqaction()</tt>.  Takes one argument:
</p><dl>
<dt><tt>irq</tt>
</dt><dd>interrupt level to free.
</dd></dl>

<p><b>Defined in:</b> kernel/irq.c<br>
<b>See also:</b> <tt>request_irq()</tt>, <tt>irqaction()</tt>.




</p><h4><tt>get_user()</tt></h4>
<tt>#define get_user(ptr) ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr))))</tt><br>
<tt>#include &lt;asm/segment.h&gt;</tt>

<p>Allows a driver to access data in user space, which is in a
different segment than the kernel.  Derives the type of the
argument and the return type automatically. <b>This means that
you have to use types correctly.  Shoddy typing will simply
fail to work.</b>

</p><p><img src="supporting%20functions_files/warning.gif" alt="[Caution!] "><b>Note:</b>
these functions may cause implicit I/O, if the memory being
accessed has been swapped out, and therefore pre-emption may
occur at this point.  Do not include these functions in
critical sections of your code even if the critical sections
are protected by <tt>cli()</tt>/<tt>sti()</tt> pairs, because
that implicit I/O will violate the integrity of your
<tt>cli()</tt>/<tt>sti()</tt> pair.  If you need to get at
user-space memory, copy it to kernel-space memory <i>before</i>
you enter your critical section.

</p><p>These functions take one argument:
</p><dl>
<dt><tt>addr</tt>
</dt><dd>Address to get data from.
</dd><dt><b>Returns:</b>
</dt><dd>Data at that offset in user space.
</dd></dl>

<p><b>Defined in:</b> include/asm/segment.h<br>
<b>See also:</b> <tt>memcpy_*fs()</tt>, <tt>put_user()</tt>, <tt>cli()</tt>,
<tt>sti()</tt>.



</p><h4><tt>inb(), inb_p()</tt></h4>
<tt>inline unsigned int inb(unsigned short port)</tt><br>
<tt>inline unsigned int inb_p(unsigned short port)</tt><br>
<tt>#include &lt;asm/io.h&gt;</tt>

<p>Reads a byte from a port.  <tt>inb()</tt> goes as fast as it
can, while <tt>inb_p()</tt> pauses before returning.  Some
devices are happier if you don't read from them as fast as
possible.  Both functions take one argument:
</p><dl>
<dt><tt>port</tt>
</dt><dd>Port to read byte from.
</dd><dt><b>Returns:</b>
</dt><dd>The byte is returned in the low byte of the
32-bit integer, and the 3 high bytes are unused, and may be garbage.
</dd></dl>

<p><b>Defined in:</b> include/asm/io.h<br>
<b>See also:</b> <tt>outb()</tt>, <tt>outb_p()</tt>.


</p><h4><tt>init_timer()</tt></h4>

<p>Inline function for initializing <tt>timer_list</tt>
structures for use with <tt>add_timer()</tt>.

</p><p><b>Defined in:</b> include/linux/timer.h<br>
<b>See also:</b> <tt>add_timer()</tt>.



</p><h4><tt>irqaction()</tt></h4>
<tt>int irqaction(unsigned int irq, struct sigaction *new)</tt><br>
<tt>#include &lt;linux/sched.h&gt;</tt>

<p>Hardware interrupts are really a lot like signals.
Therefore, it makes sense to be able to register an interrupt
like a signal.  The <tt>sa_restorer()</tt> field of the
<tt>struct sigaction</tt> is not used, but otherwise it is the
same.  The int argument to the <tt>sa.handler()</tt> function
may mean different things, depending on whether or not the IRQ
is installed with the <tt>SA_INTERRUPT</tt> flag.  If it is not
installed with the <tt>SA_INTERRUPT</tt> flag, then the
argument passed to the handler is a pointer to a register
structure, and if it is installed with the
<tt>SA_INTERRUPT</tt> flag, then the argument passed is the
number of the IRQ.  For an example of handler set to use the
<tt>SA_INTERRUPT</tt> flag, look at how <tt>rs_interrupt()</tt>
is installed in drivers/char/serial.c

</p><p>The <tt>SA_INTERRUPT</tt> flag is used to determine whether
or not the interrupt should be a ``fast'' interrupt.  Normally,
upon return from the interrupt, <tt>need_resched</tt>, a global
flag, is checked.  If it is set (!= 0), then
<tt>schedule()</tt> is run, which may schedule another process
to run.  They are also run with all other interrupts still
enabled.  However, by setting the <tt>sigaction</tt> structure
member <tt>sa_flags</tt> to <tt>SA_INTERRUPT</tt>, ``fast''
interrupts are chosen, which leave out some processing, and
very specifically do not call <tt>schedule()</tt>.

</p><p><tt>irqaction()</tt> takes two arguments:
</p><dl>
<dt><tt>irq</tt>
</dt><dd>The number of the IRQ the driver wishes to acquire.
</dd><dt><tt>new</tt>
</dt><dd>A pointer to a sigaction struct.
</dd><dt><b>Returns:</b>
</dt><dd><tt>-EBUSY</tt> if the interrupt has already been acquired,<br>
<tt>-EINVAL</tt> if <tt>sa.handler()</tt> is NULL,<br>
0 on success.
</dd></dl>

<p><b>Defined in:</b> kernel/irq.c<br>
<b>See also:</b> <tt>request_irq(), free_irq()</tt>



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -