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

📄 parportbook.tmpl

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 TMPL
📖 第 1 页 / 共 5 页
字号:
  </para>  <para>   For each port that the printer driver wants to use (see   <function>lp_register</function>), it calls   <function>parport_register_device</function> and stores the   resulting <structname>struct pardevice</structname> pointer in the   <varname>lp_table</varname>.  If the user told it to do so, it then   resets the printer.  </para>  <para>   The other interesting piece of the printer driver, from the point   of view of <literal>parport</literal>, is   <function>lp_write</function>.  In this function, the user space   process has data that it wants printed, and the printer driver   hands it off to the <literal>parport</literal> code to deal with.  </para>  <para>   The <literal>parport</literal> functions it uses that we have not   seen yet are <function>parport_negotiate</function>,   <function>parport_set_timeout</function>, and   <function>parport_write</function>.  These functions are part of   the IEEE 1284 implementation.  </para>  <para>   The way the IEEE 1284 protocol works is that the host tells the   peripheral what transfer mode it would like to use, and the   peripheral either accepts that mode or rejects it; if the mode is   rejected, the host can try again with a different mode.  This is   the negotation phase.  Once the peripheral has accepted a   particular transfer mode, data transfer can begin that mode.  </para>  <para>   The particular transfer mode that the printer driver wants to use   is named in IEEE 1284 as <quote>compatibility</quote> mode, and the   function to request a particular mode is called   <function>parport_negotiate</function>.  </para>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;   </funcsynopsisinfo>   <funcprototype>    <funcdef>int <function>parport_negotiate</function></funcdef>    <paramdef>struct parport *<parameter>port</parameter></paramdef>    <paramdef>int <parameter>mode</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <para>   The <parameter>modes</parameter> parameter is a symbolic constant   representing an IEEE 1284 mode; in this instance, it is   <constant>IEEE1284_MODE_COMPAT</constant>. (Compatibility mode is   slightly different to the other modes---rather than being   specifically requested, it is the default until another mode is   selected.)  </para>  <para>   Back to <function>lp_write</function> then.  First, access to the   parallel port is secured with   <function>parport_claim_or_block</function>.  At this point the   driver might sleep, waiting for another driver (perhaps a Zip drive   driver, for instance) to let the port go.  Next, it goes to   compatibility mode using <function>parport_negotiate</function>.  </para>  <para>   The main work is done in the write-loop.  In particular, the line   that hands the data over to <literal>parport</literal> reads:  </para><programlisting><![CDATA[        written = parport_write (port, kbuf, copy_size);]]></programlisting>  <para>   The <function>parport_write</function> function writes data to the   peripheral using the currently selected transfer mode   (compatibility mode, in this case).  It returns the number of bytes   successfully written:  </para>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;   </funcsynopsisinfo>   <funcprototype>    <funcdef>ssize_t <function>parport_write</function></funcdef>    <paramdef>struct parport *<parameter>port</parameter></paramdef>    <paramdef>const void *<parameter>buf</parameter></paramdef>    <paramdef>size_t <parameter>len</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <funcsynopsis>   <funcprototype>    <funcdef>ssize_t <function>parport_read</function></funcdef>    <paramdef>struct parport *<parameter>port</parameter></paramdef>    <paramdef>void *<parameter>buf</parameter></paramdef>    <paramdef>size_t <parameter>len</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <para>   (<function>parport_read</function> does what it sounds like, but   only works for modes in which reverse transfer is possible.  Of   course, <function>parport_write</function> only works in modes in   which forward transfer is possible, too.)  </para>  <para>   The <parameter>buf</parameter> pointer should be to kernel space   memory, and obviously the <parameter>len</parameter> parameter   specifies the amount of data to transfer.  </para>  <para>   In fact what <function>parport_write</function> does is call the   appropriate block transfer function from the <structname>struct   parport_operations</structname>:  </para>  <programlisting>   <![CDATA[struct parport_operations {        [...]        /* Block read/write */        size_t (*epp_write_data) (struct parport *port,                                  const void *buf,                                  size_t len, int flags);        size_t (*epp_read_data) (struct parport *port,                                 void *buf, size_t len,                                 int flags);        size_t (*epp_write_addr) (struct parport *port,                                  const void *buf,                                  size_t len, int flags);        size_t (*epp_read_addr) (struct parport *port,                                 void *buf, size_t len,                                 int flags);        size_t (*ecp_write_data) (struct parport *port,                                  const void *buf,                                  size_t len, int flags);        size_t (*ecp_read_data) (struct parport *port,                                 void *buf, size_t len,                                 int flags);        size_t (*ecp_write_addr) (struct parport *port,                                  const void *buf,                                  size_t len, int flags);        size_t (*compat_write_data) (struct parport *port,                                     const void *buf,                                     size_t len, int flags);        size_t (*nibble_read_data) (struct parport *port,                                    void *buf, size_t len,                                    int flags);        size_t (*byte_read_data) (struct parport *port,                                  void *buf, size_t len,                                  int flags);};   ]]></programlisting>  <para>   The transfer code in <literal>parport</literal> will tolerate a   data transfer stall only for so long, and this timeout can be   specified with <function>parport_set_timeout</function>, which   returns the previous timeout:  </para>  <funcsynopsis>   <funcsynopsisinfo>#include &lt;parport.h&gt;   </funcsynopsisinfo>   <funcprototype>    <funcdef>long <function>parport_set_timeout</function></funcdef>    <paramdef>struct pardevice *<parameter>dev</parameter></paramdef>    <paramdef>long <parameter>inactivity</parameter></paramdef>   </funcprototype>  </funcsynopsis>  <para>   This timeout is specific to the device, and is restored on   <function>parport_claim</function>.  </para>  <para>   The next function to look at is the one that allows processes to   read from <filename>/dev/lp0</filename>:   <function>lp_read</function>.  It's short, like   <function>lp_write</function>.  </para>  <para>   The semantics of reading from a line printer device are as follows:  </para>  <itemizedlist>   <listitem>    <para>     Switch to reverse nibble mode.    </para>   </listitem>   <listitem>    <para>     Try to read data from the peripheral using reverse nibble mode,     until either the user-provided buffer is full or the peripheral     indicates that there is no more data.    </para>   </listitem>   <listitem>    <para>     If there was data, stop, and return it.    </para>   </listitem>   <listitem>    <para>     Otherwise, we tried to read data and there was none.  If the user     opened the device node with the <constant>O_NONBLOCK</constant>     flag, return.  Otherwise wait until an interrupt occurs on the     port (or a timeout elapses).    </para>   </listitem>  </itemizedlist> </chapter> <chapter id="ppdev">  <title>User-level device drivers</title>  <!-- ppdev -->  <sect1>   <title>Introduction to ppdev</title>   <para>    The printer is accessible through <filename>/dev/lp0</filename>;    in the same way, the parallel port itself is accessible through    <filename>/dev/parport0</filename>.  The difference is in the    level of control that you have over the wires in the parallel port    cable.   </para>   <para>    With the printer driver, a user-space program (such as the printer    spooler) can send bytes in <quote>printer protocol</quote>.    Briefly, this means that for each byte, the eight data lines are    set up, then a <quote>strobe</quote> line tells the printer to    look at the data lines, and the printer sets an    <quote>acknowledgement</quote> line to say that it got the byte.    The printer driver also allows the user-space program to read    bytes in <quote>nibble mode</quote>, which is a way of    transferring data from the peripheral to the computer half a byte    at a time (and so it's quite slow).   </para>   <para>    In contrast, the <literal>ppdev</literal> driver (accessed via    <filename>/dev/parport0</filename>) allows you to:   </para>   <itemizedlist spacing=compact>    <listitem>     <para>      examine status lines,     </para>    </listitem>    <listitem>     <para>      set control lines,     </para>    </listitem>    <listitem>     <para>      set/examine data lines (and control the direction of the data      lines),     </para>    </listitem>    <listitem>     <para>      wait for an interrupt (triggered by one of the status lines),     </para>    </listitem>    <listitem>     <para>      find out how many new interrupts have occurred,     </para>    </listitem>    <listitem>     <para>      set up a response to an interrupt,     </para>    </listitem>    <listitem>     <para>      use IEEE 1284 negotiation (for telling peripheral which transfer      mode, to use)     </para>    </listitem>    <listitem>     <para>      transfer data using a specified IEEE 1284 mode.     </para>    </listitem>   </itemizedlist>  </sect1>  <sect1>   <title>User-level or kernel-level driver?</title>   <para>    The decision of whether to choose to write a kernel-level device    driver or a user-level device driver depends on several factors.    One of the main ones from a practical point of view is speed:    kernel-level device drivers get to run faster because they are not    preemptable, unlike user-level applications.   </para>   <para>    Another factor is ease of development.  It is in general easier to    write a user-level driver because (a) one wrong move does not    result in a crashed machine, (b) you have access to user libraries    (such as the C library), and (c) debugging is easier.   </para>  </sect1>  <sect1>   <title>Programming interface</title>   <para>    The <literal>ppdev</literal> interface is largely the same as that    of other character special devices, in that it supports    <function>open</function>, <function>close</function>,    <function>read</function>, <function>write</function>, and    <function>ioctl</function>.  The constants for the    <function>ioctl</function> commands are in    <filename>include/linux/ppdev.h</filename>.   </para>   <sect2>    <title>     Starting and stopping: <function>open</function> and     <function>close</function>    </title>    <para>     The device node <filename>/dev/parport0</filename> represents any     device that is connected to <filename>parport0</filename>, the     first parallel port in the system.  Each time the device node is     opened, it represents (to the process doing the opening) a     different device.  It can be opened more than once, but only one     instance can actually be in control of the parallel port at any     time.  A process that has opened

⌨️ 快捷键说明

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