home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / unix / bsd / 5370 < prev    next >
Encoding:
Text File  |  1992-09-08  |  10.3 KB  |  400 lines

  1. Path: sparky!uunet!sun-barr!ames!data.nas.nasa.gov!taligent!apple!motcsd!xhost92.csd.mot.com!ajv
  2. From: ajv@xhost92.csd.mot.com
  3. Newsgroups: comp.unix.bsd
  4. Subject: Re: replacement for lpt.c without interrupts
  5. Message-ID: <7070@motcsd.csd.mot.com>
  6. Date: 9 Sep 92 06:00:18 GMT
  7. References: <1992Aug11.201127.1600@jbsys.com>,<PCG.92Aug6161828@aberdb.aber.ac.uk> <1992Sep6.143703.5848@dentaro.GUN.de>
  8. Sender: usenet@motcsd.csd.mot.com
  9. Lines: 389
  10.  
  11. wolf@dentaro.GUN.de (Wolfgang Stanglmeier) writes:
  12.  
  13. >I hacked the 386bsd LPT-driver to work without interrupts.
  14. >The busy loop timeout value adapts automatically to
  15. >the printer and system speed.
  16.  
  17. <excellent driver follows...>
  18.  
  19. I was working on something very much along the same lines.  However,
  20. Mr. Stanglmeier hit the nail right on the head first.  I have rolled
  21. in some of my other work on handling syscall restarts, and in the
  22. process applied my BSD-kernel style of indentation.  What follows is
  23. substantially the same driver, with my own minor improvements.
  24.  
  25. Kudos, Mr. Stanglmeier!  My printer thanks you. :-)
  26.  
  27.                     Andy Valencia
  28.                     ajv@csd.mot.com (for now)
  29.                     jtk@netcom.com (if it bounces)
  30.  
  31. /*
  32.  * Copyright (c) 1990 William F. Jolitz, TeleMuse
  33.  * All rights reserved.
  34.  *
  35.  * Redistribution and use in source and binary forms, with or without
  36.  * modification, are permitted provided that the following conditions
  37.  * are met:
  38.  * 1. Redistributions of source code must retain the above copyright
  39.  *    notice, this list of conditions and the following disclaimer.
  40.  * 2. Redistributions in binary form must reproduce the above copyright
  41.  *    notice, this list of conditions and the following disclaimer in the
  42.  *    documentation and/or other materials provided with the distribution.
  43.  * 3. All advertising materials mentioning features or use of this software
  44.  *    must display the following acknowledgement:
  45.  *   This software is a component of "386BSD" developed by 
  46.  *   William F. Jolitz, TeleMuse.
  47.  * 4. Neither the name of the developer nor the name "386BSD"
  48.  *    may be used to endorse or promote products derived from this software
  49.  *    without specific prior written permission.
  50.  *
  51.  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 
  52.  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 
  53.  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 
  54.  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 
  55.  * NOT MAKE USE OF THIS WORK.
  56.  *
  57.  * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
  58.  * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 
  59.  * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES 
  60.  * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 
  61.  * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 
  62.  * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 
  63.  * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 
  64.  * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
  65.  *
  66.  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
  67.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  68.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  69.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
  70.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  71.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  72.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  73.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  74.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  75.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  76.  * SUCH DAMAGE.
  77.  *
  78.  */
  79.  
  80. /*
  81.  * Device Driver for AT parallel printer port
  82.  * Written by William Jolitz 12/18/90
  83.  * Modified to run without interrupts
  84.  * 92-08-19  Wolfgang Stanglmeier  <wolf@dentaro.GUN.de>
  85.  * Slight cleanup and reorganization, try to handle restarted syscalls
  86.  * 92-09-08  Andy Valencia <jtk@netcom.com>
  87.  */
  88.  
  89. #include "lpt.h"
  90. #if NLPT > 0
  91.  
  92. #include "param.h"
  93. #include "buf.h"
  94. #include "systm.h"
  95. #include "ioctl.h"
  96. #include "tty.h"
  97. #include "proc.h"
  98. #include "user.h"
  99. #include "uio.h"
  100. #include "kernel.h"
  101. #include "malloc.h"
  102.  
  103. #include "i386/isa/isa_device.h"
  104. #include "i386/isa/lptreg.h"
  105.  
  106. /* internal used flags */
  107. #define   OPEN        (0x01)   /* device is open */
  108. #define   INIT        (0x02)   /* device in open procedure */
  109.  
  110. /* flags from minor device */
  111. #define   LPT_PRIME   (0x20)   /* prime printer on open   */
  112. #define   LPT_ERROR   (0x10)   /* log error conditions    */
  113.  
  114. #define   LPT_FLAG(x) ((x) & 0xfc)
  115. #define   LPT_UNIT(x) ((x) & 0x03)
  116.  
  117. /* Printer Ready condition */
  118. #define   LPS_INVERT  (LPS_NBSY | LPS_NACK |           LPS_SEL | LPS_NERR)
  119. #define   LPS_MASK    (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
  120. #define   NOT_READY()   ((inb(sc->sc_stat)^LPS_INVERT)&LPS_MASK)
  121.  
  122. /* tsleep priority */
  123. #define   LPPRI       ((PZERO+8) | PCATCH)
  124.  
  125. int lptprobe(), lptattach();
  126. struct   isa_driver lptdriver = {lptprobe, lptattach, "lpt"};
  127.  
  128. /*
  129.  *   copy usermode data into sysmode buffer
  130.  */
  131. #define   BUFSIZE      1024
  132.  
  133. /*
  134. **   Waittimes
  135. */
  136. #define   TIMEOUT   (hz*16)   /* Timeout while open device */
  137. #define   LONG      (hz* 1)   /* Timesteps while open      */
  138.  
  139. #define   MAX_SPIN  255       /* max loop counter for busy wait */
  140.  
  141. /*   Valid Controlbits for probe ...
  142. **
  143. **   The lower 5 bits of controlport should be
  144. **   readable and writable,
  145. ** 
  146. **   .... but if my deskjet is power down, it clobbers
  147. **   some lines, and the port will not be configured.
  148. **   So I mask them out
  149. */
  150. #define    LPC_MASK    (0xfa)
  151.  
  152. struct lpt_softc {
  153.     char    *sc_cp;        /* current data to print    */
  154.     int    sc_count;    /* bytes queued in sc_inbuf    */
  155.     short    sc_data;    /* printer data port        */
  156.     short    sc_stat;    /* printer control port        */
  157.     short    sc_ctrl;    /* printer status port        */
  158.     u_char    sc_flags;    /* flags (open and internal)    */
  159.     u_char    sc_unit;    /* unit-number            */
  160.     u_char    sc_smax;    /* current max busy loop cnt    */
  161.     char            /* buffer for data        */
  162.      *sc_inbuf;
  163. } lpt_sc[NLPT];
  164.  
  165. /* In fact, I need no interrupt, but how can I explain it to config ??? */
  166. lptintr(unit)
  167.     int unit;
  168. {
  169.     /* dummy */ ;
  170. }
  171.  
  172. /*
  173.  * lptprobe()
  174.  *    Probe for hardware
  175.  */
  176. lptprobe(idp)
  177.     struct isa_device *idp;
  178. {   
  179.     unsigned v, w, n = 0;
  180.  
  181.     /* status */
  182.     do {
  183.         if (++n >= 4)
  184.             return (0);
  185.  
  186.         /*
  187.          * Status port should be read only,
  188.          * so readback value may not change
  189.          */
  190.         outb(idp->id_iobase+lpt_status,0xf0);
  191.         v = inb(idp->id_iobase+lpt_status);
  192.         outb(idp->id_iobase+lpt_status,0);
  193.         w = inb(idp->id_iobase+lpt_status);
  194.     } while (v != w);
  195.  
  196.     /* control: the lower 5 bits of controlport should read back */
  197.     outb(idp->id_iobase+lpt_control,0xff);
  198.     DELAY(100);
  199.  
  200.     w = inb(idp->id_iobase+lpt_control);
  201.     if ((w ^ 0xff) & LPC_MASK) return(0);
  202.  
  203.     outb(idp->id_iobase+lpt_control,0);
  204.     DELAY(100);
  205.     w = inb(idp->id_iobase+lpt_control);
  206.     if ((w ^ 0xe0) & LPC_MASK)
  207.         return(0);
  208.     return(1);
  209. }
  210.  
  211. /*
  212.  * lptattach()
  213.  *    Install device
  214.  */
  215. lptattach(isdp)
  216.     struct isa_device *isdp;
  217. {
  218.     struct   lpt_softc   *sc;
  219.  
  220.     sc = lpt_sc + isdp->id_unit;
  221.     sc->sc_unit = isdp->id_unit;
  222.     sc->sc_data = isdp->id_iobase + lpt_data;
  223.     sc->sc_stat = isdp->id_iobase + lpt_status;
  224.     sc->sc_ctrl = isdp->id_iobase + lpt_control;
  225.     outb(sc->sc_ctrl, LPC_NINIT);
  226.     return (1);
  227. }
  228.  
  229. /*
  230.  * lptopen()
  231.  *    New open on device.
  232.  *
  233.  * We forbid all but first open
  234.  */
  235. lptopen(dev, flag)
  236.     dev_t dev;
  237.     int flag;
  238. {
  239.     struct lpt_softc *sc;
  240.     int delay;    /* slept time in 1/hz seconds of tsleep */
  241.     int err;
  242.     u_char sta, unit;
  243.  
  244.     unit= LPT_UNIT(minor(dev));
  245.     sta = LPT_FLAG(minor(dev));
  246.  
  247.     /* minor number out of limits ? */
  248.     if (unit >= NLPT)
  249.         return (ENXIO);
  250.     sc = lpt_sc + unit;
  251.  
  252.     /* Attached ? */
  253.     if (!sc->sc_ctrl) { /* not attached */
  254.         return(ENXIO);
  255.     }
  256.  
  257.     /* Printer busy ? */
  258.     if (sc->sc_flags) { /* too late .. */
  259.         return(EBUSY);
  260.     }
  261.  
  262.     /* Have memory for buffer? */
  263.     sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
  264.     if (sc->sc_inbuf == 0)
  265.         return(ENOMEM);
  266.  
  267.     /* Init printer */
  268.     sc->sc_flags = sta | INIT;
  269.     if (sc->sc_flags & LPT_PRIME) {
  270.         outb(sc->sc_ctrl, 0);
  271.     }
  272.  
  273.     /* Select printer */
  274.     outb(sc->sc_ctrl, LPC_SEL|LPC_NINIT);
  275.  
  276.     /* and wait for ready .. */
  277.     for (delay=0; NOT_READY(); delay+= LONG) {
  278.         if (delay >= TIMEOUT) { /* too long waited .. */
  279.             sc->sc_flags = 0;
  280.             return (EBUSY);
  281.         }
  282.  
  283.         /* sleep a moment */
  284.         if ((err = tsleep (sc, LPPRI, "lpt: open", LONG)) !=
  285.                 EWOULDBLOCK) {
  286.             sc->sc_flags = 0;
  287.             return (EBUSY);
  288.         }
  289.     }
  290.  
  291.     /* Printer ready .. set variables */
  292.     sc->sc_flags |= OPEN;
  293.     sc->sc_count = 0;
  294.  
  295.     return(0);
  296. }
  297.  
  298. /*
  299.  * pushbytes()
  300.  *    Workhorse for actually spinning and writing bytes to printer
  301.  */
  302. static
  303. pushbytes(sc)
  304.     struct lpt_softc *sc;
  305. {
  306.     int spin, err, tic;
  307.     char ch;
  308.  
  309.     /* loop for every character .. */
  310.     while (sc->sc_count > 0) {
  311.         /* printer data */
  312.         ch = *(sc->sc_cp);
  313.         sc->sc_cp += 1;
  314.         sc->sc_count -= 1;
  315.         outb(sc->sc_data, ch);
  316.  
  317.         /* Busy wait for printer ready .. */
  318.         spin = tic = 0;
  319.         while (NOT_READY()) {
  320.             if (++spin >= sc->sc_smax) {
  321.                 /*
  322.                  * Now sleep, every cycle a
  323.                  * little longer ..
  324.                  */
  325.                 tic = tic + tic + 1;
  326.                 err = tsleep(sc, LPPRI, "lpt: write", tic);
  327.                 if (err != EWOULDBLOCK) {
  328.                     return (err);
  329.                 }
  330.             }
  331.         }
  332.  
  333.         /* strobe */
  334.         outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL|LPC_STB);
  335.         outb(sc->sc_ctrl, LPC_NINIT|LPC_SEL);
  336.  
  337.         /* Adapt busy-wait length... */
  338.         if (spin >= sc->sc_smax) { /* was sleep wait */
  339.             if (sc->sc_smax<MAX_SPIN)
  340.                 sc->sc_smax++;
  341.         }
  342.         if (spin*2 < sc->sc_smax) {
  343.             sc->sc_smax--;
  344.         }
  345.     }
  346.     return(0);
  347. }
  348.  
  349. /*
  350.  * lptclose()
  351.  *    Close on lp.  Try to flush data in buffer out.
  352.  */
  353. lptclose(dev, flag)
  354.     dev_t dev;
  355.     int flag;
  356. {
  357.     struct lpt_softc *sc = lpt_sc + LPT_UNIT(minor(dev));
  358.  
  359.     /* If there's queued data, try to flush it */
  360.     (void)pushbytes(sc);
  361.  
  362.     /* really close .. quite simple :-)  */
  363.     outb(sc->sc_ctrl, LPC_NINIT);
  364.     sc->sc_flags = 0;
  365.     free(sc->sc_inbuf, M_DEVBUF);
  366.     sc->sc_inbuf = 0;    /* Sanity */
  367.     return(0);
  368. }
  369.  
  370. /*
  371.  * lptwrite()
  372.  *    Copy from user's buffer, then print
  373.  */
  374. lptwrite(dev, uio)
  375.     dev_t dev;
  376.     struct uio *uio;
  377. {
  378.     struct lpt_softc *sc = lpt_sc + LPT_UNIT(minor(dev));
  379.     int err;
  380.  
  381.     /* Write out old bytes from interrupted syscall */
  382.     if (sc->sc_count > 0) {
  383.         err = pushbytes(sc);
  384.         if (err)
  385.             return(err);
  386.     }
  387.  
  388.     /* main loop */
  389.     while ((sc->sc_count = MIN(BUFSIZE, uio->uio_resid)) > 0) {
  390.         /*  get from user-space  */
  391.         sc->sc_cp = sc->sc_inbuf;
  392.         uiomove(sc->sc_inbuf, sc->sc_count, uio);
  393.         err = pushbytes(sc);
  394.         if (err)
  395.             return(err);
  396.     }
  397.     return(0);
  398. }
  399. #endif /* NLP > 0 */
  400.