Sophie

Sophie

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

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

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML
><HEAD
><TITLE
>Examples</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="UP"
TITLE="User-level device drivers"
HREF="c587.html"><LINK
REL="PREVIOUS"
TITLE="Programming interface"
HREF="x623.html"><LINK
REL="NEXT"
TITLE="   Linux parallel port driver API reference
  "
HREF="a950.html"></HEAD
><BODY
CLASS="SECT1"
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="x623.html"
ACCESSKEY="P"
>&#60;&#60;&#60; Previous</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>User-level device drivers</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="a950.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="AEN916"
></A
>Examples</H1
><P
>    Presented here are two demonstrations of how to write a simple
    printer driver for <TT
CLASS="LITERAL"
>ppdev</TT
>.  Firstly we will
    use the <TT
CLASS="FUNCTION"
>write</TT
> function, and after that we
    will drive the control and data lines directly.
   </P
><P
>    The first thing to do is to actually open the device.
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>int drive_printer (const char *name)
{
    int fd;
    int mode; /* We'll need this later. */

    fd = open (name, O_RDWR);
    if (fd == -1) {
        perror ("open");
        return 1;
    }
    </PRE
></TD
></TR
></TABLE
><P
>    Here <TT
CLASS="VARNAME"
>name</TT
> should be something along the lines
    of <TT
CLASS="FILENAME"
>"/dev/parport0"</TT
>. (If you don't have any
    <TT
CLASS="FILENAME"
>/dev/parport</TT
> files, you can make them with
    <B
CLASS="COMMAND"
>mknod</B
>; they are character special device nodes
    with major 99.)
   </P
><P
>    In order to do anything with the port we need to claim access to
    it.
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>    if (ioctl (fd, PPCLAIM)) {
        perror ("PPCLAIM");
        close (fd);
        return 1;
    }
    </PRE
></TD
></TR
></TABLE
><P
>    Our printer driver will copy its input (from
    <TT
CLASS="VARNAME"
>stdin</TT
>) to the printer, and it can do that it
    one of two ways.  The first way is to hand it all off to the
    kernel driver, with the knowledge that the protocol that the
    printer speaks is IEEE 1284's <SPAN
CLASS="QUOTE"
>"compatibility"</SPAN
>
    mode.
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>    /* Switch to compatibility mode.  (In fact we don't need
     * to do this, since we start off in compatibility mode
     * anyway, but this demonstrates PPNEGOT.)
    mode = IEEE1284_MODE_COMPAT;
    if (ioctl (fd, PPNEGOT, &#38;mode)) {
        perror ("PPNEGOT");
        close (fd);
        return 1;
    }

    for (;;) {
        char buffer[1000];
        char *ptr = buffer;
        size_t got;

        got = read (0 /* stdin */, buffer, 1000);
        if (got &#60; 0) {
            perror ("read");
            close (fd);
            return 1;
        }

        if (got == 0)
            /* End of input */
            break;

        while (got &#62; 0) {
            int written = write_printer (fd, ptr, got);

            if (written &#60; 0) {
                perror ("write");
                close (fd);
                return 1;
            }

            ptr += written;
            got -= written;
        }
    }
    </PRE
></TD
></TR
></TABLE
><P
>    The <TT
CLASS="FUNCTION"
>write_printer</TT
> function is not pictured
    above.  This is because the main loop that is shown can be used
    for both methods of driving the printer.  Here is one
    implementation of <TT
CLASS="FUNCTION"
>write_printer</TT
>:
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>ssize_t write_printer (int fd, const void *ptr, size_t count)
{
    return write (fd, ptr, count);
}
    </PRE
></TD
></TR
></TABLE
><P
>    We hand the data to the kernel-level driver (using
    <TT
CLASS="FUNCTION"
>write</TT
>) and it handles the printer
    protocol.
   </P
><P
>    Now let's do it the hard way!  In this particular example there is
    no practical reason to do anything other than just call
    <TT
CLASS="FUNCTION"
>write</TT
>, because we know that the printer talks
    an IEEE 1284 protocol.  On the other hand, this particular example
    does not even need a user-land driver since there is already a
    kernel-level one; for the purpose of this discussion, try to
    imagine that the printer speaks a protocol that is not already
    implemented under Linux.
   </P
><P
>    So, here is the alternative implementation of
    <TT
CLASS="FUNCTION"
>write_printer</TT
> (for brevity, error checking
    has been omitted):
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>ssize_t write_printer (int fd, const void *ptr, size_t count)
{
    ssize_t wrote = 0;

    while (wrote &#60; count) {
        unsigned char status, control, data;
        unsigned char mask = (PARPORT_STATUS_ERROR
                              | PARPORT_STATUS_BUSY);
        unsigned char val = (PARPORT_STATUS_ERROR
                              | PARPORT_STATUS_BUSY);
        struct ppdev_frob_struct frob;
        struct timespec ts;

        /* Wait for printer to be ready */
        for (;;) {
            ioctl (fd, PPRSTATUS, &#38;status);

            if ((status &#38; mask) == val)
                break;

            ioctl (fd, PPRELEASE);
            sleep (1);
            ioctl (fd, PPCLAIM);
        }

        /* Set the data lines */
        data = * ((char *) ptr)++;
        ioctl (fd, PPWDATA, &#38;data);

        /* Delay for a bit */
        ts.tv_sec = 0;
        ts.tv_nsec = 1000;
        nanosleep (&#38;ts, NULL);

        /* Pulse strobe */
        frob.mask = PARPORT_CONTROL_STROBE;
        frob.val = PARPORT_CONTROL_STROBE;
        ioctl (fd, PPFCONTROL, &#38;frob);
        nanosleep (&#38;ts, NULL);

        /* End the pulse */
        frob.val = 0;
        ioctl (fd, PPFCONTROL, &#38;frob);
        nanosleep (&#38;ts, NULL);

        wrote++;
    }

    return wrote;
}
    </PRE
></TD
></TR
></TABLE
><P
>    To show a bit more of the <TT
CLASS="LITERAL"
>ppdev</TT
> interface,
    here is a small piece of code that is intended to mimic the
    printer's side of printer protocol.
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>  for (;;)
    {
      int irqc;
      int busy = nAck | nFault;
      int acking = nFault;
      int ready = Busy | nAck | nFault;
      char ch;

      /* Set up the control lines when an interrupt happens. */
      ioctl (fd, PPWCTLONIRQ, &#38;busy);

      /* Now we're ready. */
      ioctl (fd, PPWCONTROL, &#38;ready);

      /* Wait for an interrupt. */
      {
        fd_set rfds;
        FD_ZERO (&#38;rfds);
        FD_SET (fd, &#38;rfds);
        if (!select (fd + 1, &#38;rfds, NULL, NULL, NULL))
          /* Caught a signal? */
          continue;
      }

      /* We are now marked as busy. */

      /* Fetch the data. */
      ioctl (fd, PPRDATA, &#38;ch);

      /* Clear the interrupt. */
      ioctl (fd, PPCLRIRQ, &#38;irqc);
      if (irqc &#62; 1)
        fprintf (stderr, "Arghh! Missed %d interrupt%s!\n",
         irqc - 1, irqc == 2 ? "s" : "");

      /* Ack it. */
      ioctl (fd, PPWCONTROL, &#38;acking);
      usleep (2);
      ioctl (fd, PPWCONTROL, &#38;busy);

      putchar (ch);
    }
    </PRE
></TD
></TR
></TABLE
><P
>    And here is an example (with no error checking at all) to show how
    to read data from the port, using ECP mode, with optional
    negotiation to ECP mode first.
   </P
><TABLE
BORDER="0"
BGCOLOR="#E0E0E0"
WIDTH="100%"
><TR
><TD
><PRE
CLASS="PROGRAMLISTING"
>    {
      int fd, mode;
      fd = open ("/dev/parport0", O_RDONLY | O_NOCTTY);
      ioctl (fd, PPCLAIM);
      mode = IEEE1284_MODE_ECP;
      if (negotiate_first) {
        ioctl (fd, PPNEGOT, &#38;mode);
        /* no need for PPSETMODE */
      } else {
        ioctl (fd, PPSETMODE, &#38;mode);
      }

      /* Now do whatever we want with fd */
      close (0);
      dup2 (fd, 0);
      if (!fork()) {
        /* child */
        execlp ("cat", "cat", NULL);
        exit (1);
      } else {
        /* parent */
        wait (NULL);
      }

      /* Okay, finished */
      ioctl (fd, PPRELEASE);
      close (fd);
    }
    </PRE
></TD
></TR
></TABLE
></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="x623.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="a950.html"
ACCESSKEY="N"
>Next &#62;&#62;&#62;</A
></TD
></TR
><TR
><TD
WIDTH="33%"
ALIGN="left"
VALIGN="top"
>Programming interface</TD
><TD
WIDTH="34%"
ALIGN="center"
VALIGN="top"
><A
HREF="c587.html"
ACCESSKEY="U"
>Up</A
></TD
><TD
WIDTH="33%"
ALIGN="right"
VALIGN="top"
>Linux parallel port driver API reference</TD
></TR
></TABLE
></DIV
></BODY
></HTML
>