<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <HTML ><HEAD ><TITLE >Device driver's view</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="The IEEE 1284.3 API" HREF="x123.html"><LINK REL="NEXT" TITLE="Port drivers" HREF="c419.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="x123.html" ACCESSKEY="P" ><<< Previous</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" ></TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="c419.html" ACCESSKEY="N" >Next >>></A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="CHAPTER" ><H1 ><A NAME="DRIVERS" ></A >Device driver's view</H1 ><P > 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 <TT CLASS="LITERAL" >parport</TT > interface to find parallel ports, use them, and share them with other device drivers. </P ><P > 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. </P ><P > The interactions between the device driver and the <TT CLASS="LITERAL" >parport</TT > layer are as follows. First, the device driver registers its existence with <TT CLASS="LITERAL" >parport</TT >, 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 <TT CLASS="LITERAL" >parport</TT > 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. </P ><P > So, the first thing for the device driver to do is tell <TT CLASS="LITERAL" >parport</TT > that it wants to know what parallel ports are on the system. To do this, it uses the <TT CLASS="FUNCTION" >parport_register_device</TT > function: </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN204" ></A ><P ></P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="FUNCSYNOPSISINFO" >#include <parport.h> struct parport_driver { const char *name; void (*attach) (struct parport *); void (*detach) (struct parport *); struct parport_driver *next; }; </PRE ></TD ></TR ></TABLE ><P ><CODE ><CODE CLASS="FUNCDEF" >int <TT CLASS="FUNCTION" >parport_register_driver</TT ></CODE >(struct parport_driver *<TT CLASS="PARAMETER" ><I >driver</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > In other words, the device driver passes pointers to a couple of functions to <TT CLASS="LITERAL" >parport</TT >, and <TT CLASS="LITERAL" >parport</TT > calls <TT CLASS="FUNCTION" >attach</TT > for each port that's detected (and <TT CLASS="FUNCTION" >detach</TT > for each port that disappears---yes, this can happen). </P ><P > The next thing that happens is that the device driver tells <TT CLASS="LITERAL" >parport</TT > that it thinks there's a device on the port that it can drive. This typically will happen in the driver's <TT CLASS="FUNCTION" >attach</TT > function, and is done with <TT CLASS="FUNCTION" >parport_register_device</TT >: </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN220" ></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" >struct pardevice *<TT CLASS="FUNCTION" >parport_register_device</TT ></CODE >(struct parport *<TT CLASS="PARAMETER" ><I >port</I ></TT >, const char *<TT CLASS="PARAMETER" ><I >name</I ></TT >, int <TT CLASS="PARAMETER" ><I >(*pf)</I ></TT > (void *), void <TT CLASS="PARAMETER" ><I >(*kf)</I ></TT > (void *), void <TT CLASS="PARAMETER" ><I >(*irq_func)</I ></TT > (int, void *, struct pt_regs *), int <TT CLASS="PARAMETER" ><I >flags</I ></TT >, void *<TT CLASS="PARAMETER" ><I >handle</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > The <TT CLASS="PARAMETER" ><I >port</I ></TT > comes from the parameter supplied to the <TT CLASS="FUNCTION" >attach</TT > function when it is called, or alternatively can be found from the list of detected parallel ports directly with the (now deprecated) <TT CLASS="FUNCTION" >parport_enumerate</TT > function. A better way of doing this is with <TT CLASS="FUNCTION" >parport_find_number</TT > or <TT CLASS="FUNCTION" >parport_find_base</TT > functions, which find ports by number and by base I/O address respectively. </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN248" ></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" >struct parport *<TT CLASS="FUNCTION" >parport_find_number</TT ></CODE >(int <TT CLASS="PARAMETER" ><I >number</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN255" ></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" >struct parport *<TT CLASS="FUNCTION" >parport_find_base</TT ></CODE >(unsigned long <TT CLASS="PARAMETER" ><I >base</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > The next three parameters, <TT CLASS="PARAMETER" ><I >pf</I ></TT >, <TT CLASS="PARAMETER" ><I >kf</I ></TT >, and <TT CLASS="PARAMETER" ><I >irq_func</I ></TT >, are more function pointers. These callback functions get called under various circumstances, and are always given the <TT CLASS="PARAMETER" ><I >handle</I ></TT > as one of their parameters. </P ><P > The preemption callback, <TT CLASS="PARAMETER" ><I >pf</I ></TT >, 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 <TT CLASS="FUNCTION" >parport_release</TT >. If <TT CLASS="PARAMETER" ><I >pf</I ></TT > 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. </P ><P > The <SPAN CLASS="QUOTE" >"kick"</SPAN > callback, <TT CLASS="PARAMETER" ><I >kf</I ></TT >, is called when the port can be claimed for exclusive access; that is, <TT CLASS="FUNCTION" >parport_claim</TT > is guaranteed to succeed inside the <SPAN CLASS="QUOTE" >"kick"</SPAN > callback. If the driver wants to claim the port it should do so; otherwise, it need not take any action. </P ><P > The <TT CLASS="PARAMETER" ><I >irq_func</I ></TT > 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 <TT CLASS="FUNCTION" >request_irq</TT >; 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 <TT CLASS="PARAMETER" ><I >irq_func</I ></TT > function is called. </P ><P > None of the callback functions are allowed to block. </P ><P > The <TT CLASS="PARAMETER" ><I >flags</I ></TT > are for telling <TT CLASS="LITERAL" >parport</TT > any requirements or hints that are useful. The only useful value here (other than <TT CLASS="CONSTANT" >0</TT >, which is the usual value) is <TT CLASS="CONSTANT" >PARPORT_DEV_EXCL</TT >. The point of that flag is to request exclusive access at all times---once a driver has successfully called <TT CLASS="FUNCTION" >parport_register_device</TT > 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). </P ><P > The <TT CLASS="CONSTANT" >PARPORT_DEV_EXCL</TT > flag is for preventing port sharing, and so should only be used when sharing the port with other device drivers is impossible and would lead to incorrect behaviour. Use it sparingly! </P ><P > Devices can also be registered by device drivers based on their device numbers (the same device numbers as in the previous section). </P ><P > The <TT CLASS="FUNCTION" >parport_open</TT > function is similar to <TT CLASS="FUNCTION" >parport_register_device</TT >, and <TT CLASS="FUNCTION" >parport_close</TT > is the equivalent of <TT CLASS="FUNCTION" >parport_unregister_device</TT >. The difference is that <TT CLASS="FUNCTION" >parport_open</TT > takes a device number rather than a pointer to a <SPAN CLASS="STRUCTNAME" >struct parport</SPAN >. </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN297" ></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" >struct pardevice *<TT CLASS="FUNCTION" >parport_open</TT ></CODE >(int <TT CLASS="PARAMETER" ><I >devnum</I ></TT >, const char *<TT CLASS="PARAMETER" ><I >name</I ></TT >, int <TT CLASS="PARAMETER" ><I >(*pf)</I ></TT > (void *), int <TT CLASS="PARAMETER" ><I >(*kf)</I ></TT > (void *), int <TT CLASS="PARAMETER" ><I >(*irqf)</I ></TT > (int, void *, struct pt_regs *), int <TT CLASS="PARAMETER" ><I >flags</I ></TT >, void *<TT CLASS="PARAMETER" ><I >handle</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN319" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >void <TT CLASS="FUNCTION" >parport_close</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN325" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >struct pardevice *<TT CLASS="FUNCTION" >parport_register_device</TT ></CODE >(struct parport *<TT CLASS="PARAMETER" ><I >port</I ></TT >, const char *<TT CLASS="PARAMETER" ><I >name</I ></TT >, int <TT CLASS="PARAMETER" ><I >(*pf)</I ></TT > (void *), int <TT CLASS="PARAMETER" ><I >(*kf)</I ></TT > (void *), int <TT CLASS="PARAMETER" ><I >(*irqf)</I ></TT > (int, void *, struct pt_regs *), int <TT CLASS="PARAMETER" ><I >flags</I ></TT >, void *<TT CLASS="PARAMETER" ><I >handle</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN346" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >void <TT CLASS="FUNCTION" >parport_unregister_device</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > The intended use of these functions is during driver initialisation while the driver looks for devices that it supports, as demonstrated by the following code fragment: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" > int devnum = -1; while ((devnum = parport_find_class (PARPORT_CLASS_DIGCAM, devnum)) != -1) { struct pardevice *dev = parport_open (devnum, ...); ... } </PRE ></TD ></TR ></TABLE ><P > Once your device driver has registered its device and been handed a pointer to a <SPAN CLASS="STRUCTNAME" >struct pardevice</SPAN >, the next thing you are likely to want to do is communicate with the device you think is there. To do that you'll need to claim access to the port. </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN356" ></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_claim</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN363" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >int <TT CLASS="FUNCTION" >parport_claim_or_block</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN369" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >void <TT CLASS="FUNCTION" >parport_release</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > To claim access to the port, use <TT CLASS="FUNCTION" >parport_claim</TT > or <TT CLASS="FUNCTION" >parport_claim_or_block</TT >. The first of these will not block, and so can be used from interrupt context. If <TT CLASS="FUNCTION" >parport_claim</TT > succeeds it will return zero and the port is available to use. It may fail (returning non-zero) if the port is in use by another driver and that driver is not willing to relinquish control of the port. </P ><P > The other function, <TT CLASS="FUNCTION" >parport_claim_or_block</TT >, will block if necessary to wait for the port to be free. If it slept, it returns <TT CLASS="CONSTANT" >1</TT >; if it succeeded without needing to sleep it returns <TT CLASS="CONSTANT" >0</TT >. If it fails it will return a negative error code. </P ><P > When you have finished communicating with the device, you can give up access to the port so that other drivers can communicate with their devices. The <TT CLASS="FUNCTION" >parport_release</TT > function cannot fail, but it should not be called without the port claimed. Similarly, you should not try to claim the port if you already have it claimed. </P ><P > You may find that although there are convenient points for your driver to relinquish the parallel port and allow other drivers to talk to their devices, it would be preferable to keep hold of the port. The printer driver only needs the port when there is data to print, for example, but a network driver (such as PLIP) could be sent a remote packet at any time. With PLIP, it is no huge catastrophe if a network packet is dropped, since it will likely be sent again, so it is possible for that kind of driver to share the port with other (pass-through) devices. </P ><P > The <TT CLASS="FUNCTION" >parport_yield</TT > and <TT CLASS="FUNCTION" >parport_yield_blocking</TT > functions are for marking points in the driver at which other drivers may claim the port and use their devices. Yielding the port is similar to releasing it and reclaiming it, but is more efficient because nothing is done if there are no other devices needing the port. In fact, nothing is done even if there are other devices waiting but the current device is still within its <SPAN CLASS="QUOTE" >"timeslice"</SPAN >. The default timeslice is half a second, but it can be adjusted via a <TT CLASS="FILENAME" >/proc</TT > entry. </P ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN391" ></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_yield</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><DIV CLASS="FUNCSYNOPSIS" ><A NAME="AEN398" ></A ><P ></P ><P ><CODE ><CODE CLASS="FUNCDEF" >int <TT CLASS="FUNCTION" >parport_yield_blocking</TT ></CODE >(struct pardevice *<TT CLASS="PARAMETER" ><I >dev</I ></TT >);</CODE ></P ><P ></P ></DIV ><P > The first of these, <TT CLASS="FUNCTION" >parport_yield</TT >, will not block but as a result may fail. The return value for <TT CLASS="FUNCTION" >parport_yield</TT > is the same as for <TT CLASS="FUNCTION" >parport_claim</TT >. The blocking version, <TT CLASS="FUNCTION" >parport_yield_blocking</TT >, has the same return code as <TT CLASS="FUNCTION" >parport_claim_or_block</TT >. </P ><P > Once the port has been claimed, the device driver can use the functions in the <SPAN CLASS="STRUCTNAME" >struct parport_operations</SPAN > pointer in the <SPAN CLASS="STRUCTNAME" >struct parport</SPAN > it has a pointer to. For example: </P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" > port->ops->write_data (port, d); </PRE ></TD ></TR ></TABLE ><P > Some of these operations have <SPAN CLASS="QUOTE" >"shortcuts"</SPAN >. For instance, <TT CLASS="FUNCTION" >parport_write_data</TT > is equivalent to the above, but may be a little bit faster (it's a macro that in some cases can avoid needing to indirect through <TT CLASS="VARNAME" >port</TT > and <TT CLASS="VARNAME" >ops</TT >). </P ></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="x123.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="c419.html" ACCESSKEY="N" >Next >>></A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >The IEEE 1284.3 API</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" > </TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >Port drivers</TD ></TR ></TABLE ></DIV ></BODY ></HTML >