home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1742 / pp.c < prev    next >
C/C++ Source or Header  |  1990-12-28  |  7KB  |  319 lines

  1. /*
  2.     $Id: pp.c,v 2.6 90/08/24 11:48:24 sw Exp $
  3. */
  4.  
  5. static char Notice[] =
  6.     "Copyright 1990 Piercarlo Grandi. All rights reserved.";
  7.  
  8. /*
  9.     This driver is free software; you can redistribute it and/or
  10.     modify it under the terms of the GNU General Public License as
  11.     published by the Free Software Foundation; either version 1, or
  12.     (at your option) any later version.
  13.  
  14.     As a special case, this driver may be incorporated in any OS kernel,
  15.     whether the GNU General Public License applies to it or not.
  16.  
  17.     This driver is distributed in the hope that it will be useful,
  18.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.     GNU General Public License for more details.
  21.  
  22.     You may have received a copy of the GNU General Public License
  23.     along with this driver; if not, write to the Free Software
  24.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25. */
  26.  
  27. /*
  28.     Fast parallel port driver, polling, no interrupts (somewhat
  29.     inspired by a driver from Michael Grenier <mike@cimcor.mn.org>)
  30. */
  31.  
  32. #include "sys/param.h"
  33. #include "sys/types.h"
  34. #include "sys/dir.h"
  35. #include "sys/signal.h"
  36. #include "sys/user.h"
  37. #include "sys/buf.h"
  38. #include "sys/errno.h"
  39. #include "sys/immu.h"
  40. #include "sys/sysmacros.h"
  41. #include "sys/inline.h"
  42.  
  43. #ifdef ppDEBUG
  44.     unsigned            pp_debug = 1;
  45. #   define DEBUG(STMTS)        do { if (pp_debug) { STMTS; }; } while (0)
  46.  
  47.     unsigned            pp_nchar;
  48.     unsigned            pp_nlongpause;
  49.     unsigned            pp_nshortpause;
  50.     unsigned            pp_nspin;
  51. #else
  52. #   define DEBUG(list)        /* skip */
  53. #endif
  54.  
  55. #include "sys/pp.h"
  56.  
  57. #if (ppSTATICSZ == 0)
  58. #   define ppBUFSZ    SBUFSIZE
  59. #else
  60. #   define ppBUFSZ    ppSTATICSZ
  61. #endif
  62.  
  63. /*
  64.     A long pause for polling the printer until it is online again
  65.     the pause while the strobe is high, and a short pause to wait
  66.     for the interface to become ready for the next character.
  67.     The longer pause is done sleeping, the other two are done
  68.     spinning, so they had better be few.
  69. */
  70.  
  71. extern int        min();
  72. extern int        tenmicrosec();
  73. extern int        wakeup();
  74. extern int        timeout();
  75. extern int        sleep();
  76. #if (ppSTATICSZ == 0)
  77.     extern struct buf    *geteblk();
  78. #endif
  79.  
  80. #define ppSPIN()    (void) (tenmicrosec())
  81. #define ppPAUSE(U,N)    (void) (timeout(wakeup,(U),(N)),sleep((U),PSLEP))
  82.  
  83. extern int        copyin();
  84.  
  85. extern int        ppinit()
  86. {
  87.     register struct pp_config *pp;
  88.  
  89.     for (pp = pp_config; pp < (pp_config+pp_max); pp++)
  90.     {
  91. #    if (ppSTATICSZ != 0)
  92.         pp->buf = &pp_sbuf[pp-pp_config][0];
  93. #    endif
  94.     outb(pp->control,(ppSELECT|ppNOTRESET));
  95.     DEBUG(printf("Initial status of /dev/pp%d is %x\n",
  96.         pp-pp_config,inb(pp->status)));
  97.     }
  98. }
  99.  
  100. /* ARGSUSED */
  101. extern int              ppopen(dev,mode)
  102.     int                dev,mode;
  103. {
  104.     register int        unit = minor(dev);
  105.     register unsigned        status;
  106.     register struct pp_config *pp;
  107.  
  108.     if (unit >= pp_max)
  109.     {
  110.     u.u_error = EIO;
  111.     return;
  112.     }
  113.  
  114.     pp = &pp_config[unit];
  115.  
  116.     status = inb(pp->status);
  117.  
  118.     if ((status&0xff) == 0xff)
  119.     {
  120.     u.u_error = ENXIO;
  121.     DEBUG(printf("Printer /dev/pp%d does not exist\n",unit));
  122.     return;
  123.     }
  124.  
  125.     /*
  126.     We ignore error condition except when printer is online ready.
  127.     */
  128.  
  129.     if ((status&(ppONLINE|ppNOTBUSY|ppNOTERROR)) == (ppONLINE|ppNOTBUSY))
  130.     {
  131.     u.u_error = EIO;
  132.     DEBUG(printf("Error status %x detected on /dev/pp%d\n",status,unit));
  133.     return;
  134.     }
  135.  
  136.     DEBUG((pp_nchar = pp_nlongpause = pp_nshortpause = pp_nspin = 0));
  137.  
  138. #   if (ppSTATICSZ == 0)
  139.     {
  140.     int            s;
  141.  
  142.     s = spl3();
  143.     {
  144.         if (pp->hdr)
  145.         {
  146.         splx(s);
  147.         DEBUG(printf("Printer /dev/pp%d already open (%x)\n",
  148.             unit,pp->hdr));
  149.         return;
  150.         }
  151.         pp->hdr = (struct buf *) 1;
  152.     }
  153.     splx(s);
  154.  
  155.     pp->hdr = geteblk();
  156.     if (pp->hdr)
  157.     {
  158.         pp->hdr->b_flags |= B_PRIVLG;
  159.         pp->buf = pp->hdr->b_un.b_addr;
  160.     }
  161.     else
  162.     {
  163.         u.u_error = ENOMEM;
  164.         DEBUG(printf("Cannot allocate buffer for /dev/pp%d\n",unit));
  165.     }
  166.  
  167.     DEBUG(printf("Printer /dev/pp%d has bufhdr %x, buf %x\n",
  168.         unit,pp->hdr,pp->buf));
  169.     }
  170. #endif
  171. }
  172.  
  173. /* ARGSUSED */
  174. extern int              ppclose(dev)
  175.     int                dev;
  176. {
  177.     DEBUG(printf("Printed %d characters, paused %d and spun %d (%d) times\n",
  178.     pp_nchar,pp_longpause,pp_nspin,pp_nshortpause));
  179.  
  180. #   if (ppSTATICSZ == 0)
  181.     {
  182.     register struct pp_config *pp;
  183.  
  184.     pp = &pp_config[minor(dev)];
  185.  
  186.     if (pp->hdr)
  187.     {
  188.         pp->buf = (caddr_t) 0;
  189.         pp->hdr->b_flags &=~ B_PRIVLG;
  190.  
  191.         brelse(pp->hdr);
  192.         pp->hdr = (struct buf *) 0;
  193.     }
  194.     else
  195.         DEBUG(printf("Impossible close without buffer of /dev/pp%d\n",
  196.         pp-pp_config));
  197.     }
  198. #   endif
  199. }
  200.  
  201. static void        ppbufwrite(pp,buf,endbuf)
  202.     register struct pp_config *pp;
  203.     caddr_t            buf;
  204.     register caddr_t        endbuf;
  205. {
  206.     register unsigned        status;
  207.     register int        statusp;
  208.     register char        *ch;
  209.  
  210.     statusp = pp->status;
  211.  
  212.     for (ch = (char *) buf; ch < (char *) endbuf; ch++)
  213.     {
  214.     DEBUG(pp_nchar++);
  215.  
  216.     latch_character:
  217.  
  218.     outb(pp->data,*ch);
  219.  
  220.     /*
  221.         Here we wait for the printer to be ready, and this may
  222.         be a longish wait, because of paper end, offline, power off.
  223.         We sleep, polling a few times per second, as this is simpler
  224.         than taking an interrupt and the cost is very low.
  225.     */
  226.  
  227.     wait_printer_online:
  228.  
  229.     for
  230.     (
  231.         status = inb(statusp);
  232.         (status & pp_guard.pause.mask) != pp_guard.pause.done
  233.         || (status & pp_guard.spin.mask) != pp_guard.spin.done;
  234.         status = inb(statusp)
  235.     )
  236.     {
  237.         ppPAUSE((caddr_t) &pp->status,pp_longpause);
  238.         DEBUG(pp_nlongpause++);
  239.     }
  240.  
  241.     /*
  242.         Allelluiah! The printer is ready. Strobe the character
  243.         we had already latched in.
  244.     */
  245.  
  246.     strobe_awhile:
  247.  
  248.     outb(pp->control,(ppSELECT|ppNOTRESET|ppSTROBE));
  249.     ppSPIN(); /* This should last at least one microsecond */
  250.     outb(pp->control,(ppSELECT|ppNOTRESET));
  251.  
  252.     /*
  253.         Here we wait for the interface to be ready to accept another
  254.         character, and thus we spin, because we expect the wait to be
  255.         short (e.g. 3-6 turns). This is cheaper than the overheads
  256.         involved in sleeping or even in taking an interrupt.
  257.     */
  258.  
  259.     wait_interface_ready:
  260.  
  261.     {
  262.         register unsigned            spins;
  263.  
  264.         for
  265.         (
  266.         spins = 0, status = inb(statusp);
  267.         spins < pp_maxspins /* Don't waste too much time spinning */
  268.             && (status & pp_guard.spin.mask) != pp_guard.spin.done
  269.             && (status & pp_guard.pause.mask) == (pp_guard.pause.done);
  270.         spins++, status = inb(statusp)
  271.         )
  272.         {
  273.         ppSPIN();
  274.         DEBUG(pp_nspin++);
  275.         }
  276.  
  277.         /*
  278.         This is not really necessary; we could just have one pause
  279.         above, before latching the character. We do not do that
  280.         simply because we want to have a shorter pause for buffer
  281.         full here, to have snappier response. Well, in theory :->.
  282.         */
  283.  
  284.         if (spins == pp_maxspins)
  285.         {
  286.         ppPAUSE((caddr_t) &pp->status,pp_shortpause);
  287.         DEBUG(pp_nshortpause++);
  288.         }
  289.     }
  290.     }
  291. }
  292.  
  293. extern int              ppwrite(dev)
  294.     int                dev;
  295. {
  296.     register struct pp_config *pp;
  297.     register caddr_t        buf;
  298.     register unsigned        count;
  299.  
  300.     pp        = &pp_config[minor(dev)];
  301.     buf        = pp->buf;
  302.  
  303.     DEBUG(printf("Print total %d chars from %x on /dev/pp%d\n",
  304.     u.u_count,u.u_base,pp-pp_config));
  305.  
  306.     for
  307.     (
  308.     u.u_base, u.u_count;
  309.     (count = min(u.u_count,ppBUFSZ)) != 0
  310.         && copyin(u.u_base,buf,count) == 0;
  311.     u.u_base += count, u.u_count -= count
  312.     )
  313.     {
  314.     DEBUG(printf("Print %d chars from %x on /dev/pp%d\n",
  315.         count,u.u_base,pp-pp_config));
  316.     ppbufwrite(pp,buf,buf+count);
  317.     }
  318. }
  319.