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

📄 parportbook.tmpl

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 TMPL
📖 第 1 页 / 共 5 页
字号:
    parport_operations</structname>, which is a list of function    pointers for the various operations that can be performed on a    port.  You can think of a <structname>struct parport</structname>    as a parallel port <quote>object</quote>, if    <quote>object-orientated</quote> programming is your thing.  The    <structname>parport</structname> structures are chained in a    linked list, whose head is <varname>portlist</varname> (in    <filename>drivers/parport/share.c</filename>).   </para>   <para>    Once the port has been registered, the low-level port driver    announces it.  The <function>parport_announce_port</function>    function walks down the list of parallel port device drivers    (<structname>struct parport_driver</structname>s) calling the    <function>attach</function> function of each (which may block).   </para>   <para>    Similarly, a low-level port driver can undo the effect of    registering a port with the    <function>parport_unregister_port</function> function, and device    drivers are notified using the <function>detach</function>    callback (which may not block).   </para>   <para>    Device drivers can undo the effect of registering themselves with    the <function>parport_unregister_driver</function>    function.   </para>  </sect1>  <!-- IEEE 1284.3 API -->  <sect1>   <title>The IEEE 1284.3 API</title>   <para>    The ability to daisy-chain devices is very useful, but if every    device does it in a different way it could lead to lots of    complications for device driver writers.  Fortunately, the IEEE    are standardising it in IEEE 1284.3, which covers daisy-chain    devices and port multiplexors.   </para>   <para>    At the time of writing, IEEE 1284.3 has not been published, but    the draft specifies the on-the-wire protocol for daisy-chaining    and multiplexing, and also suggests a programming interface for    using it.  That interface (or most of it) has been implemented in    the <literal>parport</literal> code in Linux.   </para>   <para>    At initialisation of the parallel port <quote>bus</quote>,    daisy-chained devices are assigned addresses starting from zero.    There can only be four devices with daisy-chain addresses, plus    one device on the end that doesn't know about daisy-chaining and    thinks it's connected directly to a computer.   </para>   <para>    Another way of connecting more parallel port devices is to use a    multiplexor.  The idea is to have a device that is connected    directly to a parallel port on a computer, but has a number of    parallel ports on the other side for other peripherals to connect    to (two or four ports are allowed).  The multiplexor switches    control to different ports under software control---it is, in    effect, a programmable printer switch.   </para>   <para>    Combining the ability of daisy-chaining five devices together with    the ability to multiplex one parallel port between four gives the    potential to have twenty peripherals connected to the same    parallel port!   </para>   <para>    In addition, of course, a single computer can have multiple    parallel ports.  So, each parallel port peripheral in the system    can be identified with three numbers, or co-ordinates: the    parallel port, the multiplexed port, and the daisy-chain    address.   </para>   <mediaobject>    <imageobject>     <imagedata fileref="parport-multi" format="eps">    </imageobject>    <imageobject>     <imagedata fileref="parport-multi.png" format="png">    </imageobject>   </mediaobject>   <para>    Each device in the system is numbered at initialisation (by    <function>parport_daisy_init</function>).  You can convert between    this device number and its co-ordinates with    <function>parport_device_num</function> and    <function>parport_device_coords</function>.   </para>   <funcsynopsis>    <funcsynopsisinfo>#include &lt;parport.h&gt;    </funcsynopsisinfo>    <funcprototype>     <funcdef>int <function>parport_device_num</function></funcdef>     <paramdef>int <parameter>parport</parameter></paramdef>     <paramdef>int <parameter>mux</parameter></paramdef>     <paramdef>int <parameter>daisy</parameter></paramdef>    </funcprototype>   </funcsynopsis>   <funcsynopsis>    <funcprototype>     <funcdef>int <function>parport_device_coords</function></funcdef>     <paramdef>int <parameter>devnum</parameter></paramdef>     <paramdef>int *<parameter>parport</parameter></paramdef>     <paramdef>int *<parameter>mux</parameter></paramdef>     <paramdef>int *<parameter>daisy</parameter></paramdef>    </funcprototype>   </funcsynopsis>   <para>    Any parallel port peripheral will be connected directly or    indirectly to a parallel port on the system, but it won't have a    daisy-chain address if it does not know about daisy-chaining, and    it won't be connected through a multiplexor port if there is no    multiplexor.  The special co-ordinate value    <constant>-1</constant> is used to indicate these cases.   </para>   <para>    Two functions are provided for finding devices based on their IEEE    1284 Device ID: <function>parport_find_device</function> and    <function>parport_find_class</function>.   </para>   <funcsynopsis>    <funcsynopsisinfo>#include &lt;parport.h&gt;    </funcsynopsisinfo>    <funcprototype>     <funcdef>int <function>parport_find_device</function></funcdef>     <paramdef>const char *<parameter>mfg</parameter></paramdef>     <paramdef>const char *<parameter>mdl</parameter></paramdef>     <paramdef>int <parameter>from</parameter></paramdef>    </funcprototype>   </funcsynopsis>   <funcsynopsis>    <funcprototype>     <funcdef>int <function>parport_find_class</function></funcdef>     <paramdef>parport_device_class <parameter>cls</parameter></paramdef>     <paramdef>int <parameter>from</parameter></paramdef>    </funcprototype>   </funcsynopsis>   <para>    These functions take a device number (in addition to some other    things), and return another device number.  They walk through the    list of detected devices until they find one that matches the    requirements, and then return that device number (or    <constant>-1</constant> if there are no more such devices).  They    start their search at the device after the one in the list with    the number given (at <parameter>from</parameter>+1, in other    words).   </para>  </sect1> </chapter> <chapter id="drivers">  <title>Device driver's view</title><!-- Cover:     - sharing interface, preemption, interrupts, wakeups...     - IEEE 1284.3 interface     - port operations       - why can read data but ctr is faked, etc.  --><!-- I should take a look at the kernel hackers' guide bit I wrote, --><!-- as that deals with a lot of this.  The main complaint with it  --><!-- was that there weren't enough examples, but 'The printer --><!-- driver' should deal with that later; might be worth mentioning --><!-- in the text. -->  <para>   This section is written from the point of view of the device driver   programmer, who might be writing a driver for a printer or a   scanner or else anything that plugs into the parallel port.  It   explains how to use the <literal>parport</literal> interface to   find parallel ports, use them, and share them with other device   drivers.  </para>  <para>   We'll start out with a description of the various functions that   can be called, and then look at a reasonably simple example of   their use: the printer driver.  </para>  <para>   The interactions between the device driver and the   <literal>parport</literal> layer are as follows.  First, the   device driver registers its existence with   <literal>parport</literal>, in order to get told about any   parallel ports that have been (or will be) detected.  When it gets   told about a parallel port, it then tells   <literal>parport</literal> that it wants to drive a device on   that port.  Thereafter it can claim exclusive access to the port in   order to talk to its device.  </para>  <para>   So, the first thing for the device driver to do is tell   <literal>parport</literal> that it wants to know what parallel   ports are on the system.  To do this, it uses the   <function>parport_register_device</function> function:  </para>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;struct parport_driver {        const char *name;        void (*attach) (struct parport *);        void (*detach) (struct parport *);        struct parport_driver *next;};   </funcsynopsisinfo>   <funcprototype>    <funcdef>int <function>parport_register_driver</function></funcdef>    <paramdef>struct parport_driver *<parameter>driver</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <para>   In other words, the device driver passes pointers to a couple of   functions to <literal>parport</literal>, and   <literal>parport</literal> calls <function>attach</function> for   each port that's detected (and <function>detach</function> for each   port that disappears---yes, this can happen).  </para>  <para>   The next thing that happens is that the device driver tells   <literal>parport</literal> that it thinks there's a device on the   port that it can drive.  This typically will happen in the driver's   <function>attach</function> function, and is done with   <function>parport_register_device</function>:  </para>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;   </funcsynopsisinfo>   <funcprototype>    <funcdef>struct pardevice *<function>parport_register_device</function></funcdef>    <paramdef>struct parport *<parameter>port</parameter></paramdef>    <paramdef>const char *<parameter>name</parameter></paramdef>    <paramdef>int <parameter>(*pf)</parameter>     <funcparams>void *</funcparams></paramdef>    <paramdef>void <parameter>(*kf)</parameter>     <funcparams>void *</funcparams></paramdef>    <paramdef>void <parameter>(*irq_func)</parameter>     <funcparams>int, void *, struct pt_regs *</funcparams></paramdef>    <paramdef>int <parameter>flags</parameter></paramdef>    <paramdef>void *<parameter>handle</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <para>   The <parameter>port</parameter> comes from the parameter supplied   to the <function>attach</function> function when it is called, or   alternatively can be found from the list of detected parallel ports   directly with the (now deprecated)   <function>parport_enumerate</function> function.  A better way of   doing this is with <function>parport_find_number</function> or   <function>parport_find_base</function> functions, which find ports   by number and by base I/O address respectively.  </para>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;   </funcsynopsisinfo>   <funcprototype>    <funcdef>struct parport *<function>parport_find_number</function></funcdef>    <paramdef>int <parameter>number</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;   </funcsynopsisinfo>   <funcprototype>    <funcdef>struct parport *<function>parport_find_base</function></funcdef>    <paramdef>unsigned long <parameter>base</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <para>   The next three parameters, <parameter>pf</parameter>,   <parameter>kf</parameter>, and <parameter>irq_func</parameter>, are   more function pointers.  These callback functions get called under   various circumstances, and are always given the   <parameter>handle</parameter> as one of their parameters.  </para>  <para>   The preemption callback, <parameter>pf</parameter>, is called when   the driver has claimed access to the port but another device driver   wants access.  If the driver is willing to let the port go, it   should return zero and the port will be released on its behalf.   There is no need to call <function>parport_release</function>.  If   <parameter>pf</parameter> gets called at a bad time for letting the   port go, it should return non-zero and no action will be taken.  It   is good manners for the driver to try to release the port at the   earliest opportunity after its preemption callback is   called.  </para>  <para>   The <quote>kick</quote> callback, <parameter>kf</parameter>, is   called when the port can be claimed for exclusive access; that is,   <function>parport_claim</function> is guaranteed to succeed inside   the <quote>kick</quote> callback.  If the driver wants to claim the   port it should do so; otherwise, it need not take any   action.  </para>  <para>   The <parameter>irq_func</parameter> callback is called,   predictably, when a parallel port interrupt is generated.  But it   is not the only code that hooks on the interrupt.  The sequence is   this: the lowlevel driver is the one that has done   <function>request_irq</function>; it then does whatever   hardware-specific things it needs to do to the parallel port   hardware (for PC-style ports, there is nothing special to do); it   then tells the IEEE 1284 code about the interrupt, which may   involve reacting to an IEEE 1284 event, depending on the current   IEEE 1284 phase; and finally the <parameter>irq_func</parameter>   function is called.  </para>  <para>   None of the callback functions are allowed to block.  </para>  <para>   The <parameter>flags</parameter> are for telling   <literal>parport</literal> any requirements or hints that are   useful.  The only useful value here (other than   <constant>0</constant>, which is the usual value) is   <constant>PARPORT_DEV_EXCL</constant>.  The point of that flag is   to request exclusive access at all times---once a driver has   successfully called <function>parport_register_device</function>   with that flag, no other device drivers will be able to register   devices on that port (until the successful driver deregisters its   device, of course).  </para>  <para>   The <constant>PARPORT_DEV_EXCL</constant> flag is for preventing

⌨️ 快捷键说明

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