Sophie

Sophie

distrib > Mandriva > 9.0 > i586 > by-pkgid > 98e91bc877e03cf3582cd163550eb7e3 > files > 747

kernel-doc-html-2.4.19-16mdk.i586.rpm

<!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"
>&#60;&#60;&#60; 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 &#62;&#62;&#62;</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 &#60;parport.h&#62;

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 &#60;parport.h&#62;
   </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 &#60;parport.h&#62;
   </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 &#60;parport.h&#62;
   </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 &#60;parport.h&#62;
   </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 &#60;parport.h&#62;
   </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 &#60;parport.h&#62;
   </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-&#62;ops-&#62;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"
>&#60;&#60;&#60; 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 &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>The IEEE 1284.3 API</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
>&nbsp;</TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Port drivers</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>