<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <HTML ><HEAD ><TITLE >The printer driver</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.7"><LINK REL="HOME" TITLE="The Linux 2.4 Parallel Port Subsystem" HREF="book1.html"><LINK REL="PREVIOUS" TITLE="Port drivers" HREF="c419.html"><LINK REL="NEXT" TITLE="User-level device drivers" HREF="c587.html"></HEAD ><BODY CLASS="CHAPTER" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" >The Linux 2.4 Parallel Port Subsystem</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="c419.html" ACCESSKEY="P" ><<< Previous</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" ></TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="c587.html" ACCESSKEY="N" >Next >>></A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="CHAPTER" ><H1 ><A NAME="LP" ></A >The printer driver</H1 ><P > The printer driver, <TT CLASS="LITERAL" >lp</TT > is a character special device driver and a <TT CLASS="LITERAL" >parport</TT > client. As a character special device driver it registers a <SPAN CLASS="STRUCTNAME" >struct file_operations</SPAN > using <TT CLASS="FUNCTION" >register_chrdev</TT >, with pointers filled in for <TT CLASS="STRUCTFIELD" ><I >write</I ></TT >, <TT CLASS="STRUCTFIELD" ><I >ioctl</I ></TT >, <TT CLASS="STRUCTFIELD" ><I >open</I ></TT > and <TT CLASS="STRUCTFIELD" ><I >release</I ></TT >. As a client of <TT CLASS="LITERAL" >parport</TT >, it registers a <SPAN CLASS="STRUCTNAME" >struct parport_driver</SPAN > using <TT CLASS="FUNCTION" >parport_register_driver</TT >, so that <TT CLASS="LITERAL" >parport</TT > knows to call <TT CLASS="FUNCTION" >lp_attach</TT > when a new parallel port is discovered (and <TT CLASS="FUNCTION" >lp_detach</TT > when it goes away). </P ><P > The parallel port console functionality is also implemented in <TT CLASS="FILENAME" >drivers/char/lp.c</TT >, but that won't be covered here (it's quite simple though). </P ><P > The initialisation of the driver is quite easy to understand (see <TT CLASS="FUNCTION" >lp_init</TT >). The <TT CLASS="VARNAME" >lp_table</TT > is an array of structures that contain information about a specific device (the <SPAN CLASS="STRUCTNAME" >struct pardevice</SPAN > associated with it, for example). That array is initialised to sensible values first of all. </P ><P > Next, the printer driver calls <TT CLASS="FUNCTION" >register_chrdev</TT > passing it a pointer to <TT CLASS="VARNAME" >lp_fops</TT >, which contains function pointers for the printer driver's implementation of <TT CLASS="FUNCTION" >open</TT >, <TT CLASS="FUNCTION" >write</TT >, and so on. This part is the same as for any character special device driver. </P ><P > After successfully registering itself as a character special device driver, the printer driver registers itself as a <TT CLASS="LITERAL" >parport</TT > client using <TT CLASS="FUNCTION" >parport_register_driver</TT >. It passes a pointer to this structure: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" > static struct parport_driver lp_driver = { "lp", lp_attach, lp_detach, NULL }; </PRE ></TD ></TR ></TABLE ><P > The <TT CLASS="FUNCTION" >lp_detach</TT > function is not very interesting (it does nothing); the interesting bit is <TT CLASS="FUNCTION" >lp_attach</TT >. What goes on here depends on whether the user supplied any parameters. The possibilities are: no parameters supplied, in which case the printer driver uses every port that is detected; the user supplied the parameter <SPAN CLASS="QUOTE" >"auto"</SPAN >, in which case only ports on which the device ID string indicates a printer is present are used; or the user supplied a list of parallel port numbers to try, in which case only those are used. </P ><P > For each port that the printer driver wants to use (see <TT CLASS="FUNCTION" >lp_register</TT >), it calls <TT CLASS="FUNCTION" >parport_register_device</TT > and stores the resulting <SPAN CLASS="STRUCTNAME" >struct pardevice</SPAN > pointer in the <TT CLASS="VARNAME" >lp_table</TT >. If the user told it to do so, it then resets the printer. </P ><P > The other interesting piece of the printer driver, from the point of view of <TT CLASS="LITERAL" >parport</TT >, is <TT CLASS="FUNCTION" >lp_write</TT >. In this function, the user space process has data that it wants printed, and the printer driver hands it off to the <TT CLASS="LITERAL" >parport</TT > code to deal with. </P ><P > The <TT CLASS="LITERAL" >parport</TT > functions it uses that we have not seen yet are <TT CLASS="FUNCTION" >parport_negotiate</TT >, <TT CLASS="FUNCTION" >parport_set_timeout</TT >, and <TT CLASS="FUNCTION" >parport_write</TT >. These functions are part of the IEEE 1284 implementation. </P ><P > 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. </P ><P > The particular transfer mode that the printer driver wants to use is named in IEEE 1284 as <SPAN CLASS="QUOTE" >"compatibility"</SPAN > mode, and the function to request a particular mode is called <TT CLASS="FUNCTION" >parport_negotiate</TT >. </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN506" ></A ><P ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="FUNCSYNOPSISINFO" >#include <parport.h> </PRE ></TD ></TR ></TABLE ><P ><CODE ><CODE CLASS="FUNCDEF" >int <TT CLASS="FUNCTION" >parport_negotiate</TT ></CODE >(struct parport *<TT CLASS="PARAMETER" ><I >port</I ></TT >, int <TT CLASS="PARAMETER" ><I >mode</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > The <TT CLASS="PARAMETER" ><I >modes</I ></TT > parameter is a symbolic constant representing an IEEE 1284 mode; in this instance, it is <TT CLASS="CONSTANT" >IEEE1284_MODE_COMPAT</TT >. (Compatibility mode is slightly different to the other modes---rather than being specifically requested, it is the default until another mode is selected.) </P ><P > Back to <TT CLASS="FUNCTION" >lp_write</TT > then. First, access to the parallel port is secured with <TT CLASS="FUNCTION" >parport_claim_or_block</TT >. 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 <TT CLASS="FUNCTION" >parport_negotiate</TT >. </P ><P > The main work is done in the write-loop. In particular, the line that hands the data over to <TT CLASS="LITERAL" >parport</TT > reads: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" > written = parport_write (port, kbuf, copy_size);</PRE ></TD ></TR ></TABLE ><P > The <TT CLASS="FUNCTION" >parport_write</TT > 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: </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN527" ></A ><P ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="FUNCSYNOPSISINFO" >#include <parport.h> </PRE ></TD ></TR ></TABLE ><P ><CODE ><CODE CLASS="FUNCDEF" >ssize_t <TT CLASS="FUNCTION" >parport_write</TT ></CODE >(struct parport *<TT CLASS="PARAMETER" ><I >port</I ></TT >, const void *<TT CLASS="PARAMETER" ><I >buf</I ></TT >, size_t <TT CLASS="PARAMETER" ><I >len</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN538" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >ssize_t <TT CLASS="FUNCTION" >parport_read</TT ></CODE >(struct parport *<TT CLASS="PARAMETER" ><I >port</I ></TT >, void *<TT CLASS="PARAMETER" ><I >buf</I ></TT >, size_t <TT CLASS="PARAMETER" ><I >len</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > (<TT CLASS="FUNCTION" >parport_read</TT > does what it sounds like, but only works for modes in which reverse transfer is possible. Of course, <TT CLASS="FUNCTION" >parport_write</TT > only works in modes in which forward transfer is possible, too.) </P ><P > The <TT CLASS="PARAMETER" ><I >buf</I ></TT > pointer should be to kernel space memory, and obviously the <TT CLASS="PARAMETER" ><I >len</I ></TT > parameter specifies the amount of data to transfer. </P ><P > In fact what <TT CLASS="FUNCTION" >parport_write</TT > does is call the appropriate block transfer function from the <SPAN CLASS="STRUCTNAME" >struct parport_operations</SPAN >: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" > 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); }; </PRE ></TD ></TR ></TABLE ><P > The transfer code in <TT CLASS="LITERAL" >parport</TT > will tolerate a data transfer stall only for so long, and this timeout can be specified with <TT CLASS="FUNCTION" >parport_set_timeout</TT >, which returns the previous timeout: </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN561" ></A ><P ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="FUNCSYNOPSISINFO" >#include <parport.h> </PRE ></TD ></TR ></TABLE ><P ><CODE ><CODE CLASS="FUNCDEF" >long <TT CLASS="FUNCTION" >parport_set_timeout</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >, long <TT CLASS="PARAMETER" ><I >inactivity</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > This timeout is specific to the device, and is restored on <TT CLASS="FUNCTION" >parport_claim</TT >. </P ><P > The next function to look at is the one that allows processes to read from <TT CLASS="FILENAME" >/dev/lp0</TT >: <TT CLASS="FUNCTION" >lp_read</TT >. It's short, like <TT CLASS="FUNCTION" >lp_write</TT >. </P ><P > The semantics of reading from a line printer device are as follows: </P ><P ></P ><UL ><LI ><P > Switch to reverse nibble mode. </P ></LI ><LI ><P > 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. </P ></LI ><LI ><P > If there was data, stop, and return it. </P ></LI ><LI ><P > Otherwise, we tried to read data and there was none. If the user opened the device node with the <TT CLASS="CONSTANT" >O_NONBLOCK</TT > flag, return. Otherwise wait until an interrupt occurs on the port (or a timeout elapses). </P ></LI ></UL ></DIV ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="c419.html" ACCESSKEY="P" ><<< Previous</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="book1.html" ACCESSKEY="H" >Home</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="c587.html" ACCESSKEY="N" >Next >>></A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >Port drivers</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" > </TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >User-level device drivers</TD ></TR ></TABLE ></DIV ></BODY ></HTML >