<!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" ><<< 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 >>></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, &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 < 0) { perror ("read"); close (fd); return 1; } if (got == 0) /* End of input */ break; while (got > 0) { int written = write_printer (fd, ptr, got); if (written < 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 < 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, &status); if ((status & mask) == val) break; ioctl (fd, PPRELEASE); sleep (1); ioctl (fd, PPCLAIM); } /* Set the data lines */ data = * ((char *) ptr)++; ioctl (fd, PPWDATA, &data); /* Delay for a bit */ ts.tv_sec = 0; ts.tv_nsec = 1000; nanosleep (&ts, NULL); /* Pulse strobe */ frob.mask = PARPORT_CONTROL_STROBE; frob.val = PARPORT_CONTROL_STROBE; ioctl (fd, PPFCONTROL, &frob); nanosleep (&ts, NULL); /* End the pulse */ frob.val = 0; ioctl (fd, PPFCONTROL, &frob); nanosleep (&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, &busy); /* Now we're ready. */ ioctl (fd, PPWCONTROL, &ready); /* Wait for an interrupt. */ { fd_set rfds; FD_ZERO (&rfds); FD_SET (fd, &rfds); if (!select (fd + 1, &rfds, NULL, NULL, NULL)) /* Caught a signal? */ continue; } /* We are now marked as busy. */ /* Fetch the data. */ ioctl (fd, PPRDATA, &ch); /* Clear the interrupt. */ ioctl (fd, PPCLRIRQ, &irqc); if (irqc > 1) fprintf (stderr, "Arghh! Missed %d interrupt%s!\n", irqc - 1, irqc == 2 ? "s" : ""); /* Ack it. */ ioctl (fd, PPWCONTROL, &acking); usleep (2); ioctl (fd, PPWCONTROL, &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, &mode); /* no need for PPSETMODE */ } else { ioctl (fd, PPSETMODE, &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" ><<< 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 >>></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 >