The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/pc98/pc98/olpt.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 1990 William F. Jolitz, TeleMuse
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This software is a component of "386BSD" developed by
   16  *      William F. Jolitz, TeleMuse.
   17  * 4. Neither the name of the developer nor the name "386BSD"
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ
   22  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS
   23  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT.
   24  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT
   25  * NOT MAKE USE OF THIS WORK.
   26  *
   27  * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
   28  * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN
   29  * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES
   30  * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING
   31  * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND
   32  * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE
   33  * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS
   34  * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
   35  *
   36  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
   37  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
   40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   46  * SUCH DAMAGE.
   47  *
   48  *      from: unknown origin, 386BSD 0.1
   49  * $FreeBSD: releng/5.0/sys/pc98/pc98/olpt.c 83430 2001-09-14 04:50:27Z imp $
   50  */
   51 
   52 /*
   53  * Device Driver for AT parallel printer port
   54  * Written by William Jolitz 12/18/90
   55  */
   56 
   57 /*
   58  * Parallel port TCP/IP interfaces added.  I looked at the driver from
   59  * MACH but this is a complete rewrite, and btw. incompatible, and it
   60  * should perform better too.  I have never run the MACH driver though.
   61  *
   62  * This driver sends two bytes (0x08, 0x00) in front of each packet,
   63  * to allow us to distinguish another format later.
   64  *
   65  * Now added an Linux/Crynwr compatibility mode which is enabled using
   66  * IF_LINK0 - Tim Wilkinson.
   67  *
   68  * TODO:
   69  *    Make HDLC/PPP mode, use IF_LLC1 to enable.
   70  *
   71  * Connect the two computers using a Laplink parallel cable to use this
   72  * feature:
   73  *
   74  *      +----------------------------------------+
   75  *      |A-name A-End   B-End   Descr.  Port/Bit |
   76  *      +----------------------------------------+
   77  *      |DATA0  2       15      Data    0/0x01   |
   78  *      |-ERROR 15      2               1/0x08   |
   79  *      +----------------------------------------+
   80  *      |DATA1  3       13      Data    0/0x02   |
   81  *      |+SLCT  13      3               1/0x10   |
   82  *      +----------------------------------------+
   83  *      |DATA2  4       12      Data    0/0x04   |
   84  *      |+PE    12      4               1/0x20   |
   85  *      +----------------------------------------+
   86  *      |DATA3  5       10      Strobe  0/0x08   |
   87  *      |-ACK   10      5               1/0x40   |
   88  *      +----------------------------------------+
   89  *      |DATA4  6       11      Data    0/0x10   |
   90  *      |BUSY   11      6               1/~0x80  |
   91  *      +----------------------------------------+
   92  *      |GND    18-25   18-25   GND     -        |
   93  *      +----------------------------------------+
   94  *
   95  * Expect transfer-rates up to 75 kbyte/sec.
   96  *
   97  * If GCC could correctly grok
   98  *      register int port asm("edx")
   99  * the code would be cleaner
  100  *
  101  * Poul-Henning Kamp <phk@freebsd.org>
  102  */
  103 
  104 #include <sys/param.h>
  105 #include <sys/systm.h>
  106 #include <sys/conf.h>
  107 #include <sys/bio.h>
  108 #include <sys/buf.h>
  109 #include <sys/bus.h>
  110 #include <sys/kernel.h>
  111 #include <sys/uio.h>
  112 #include <sys/syslog.h>
  113 
  114 #include <machine/clock.h>
  115 #include <machine/bus.h>
  116 #include <machine/resource.h>
  117 #include <sys/rman.h>
  118 
  119 #include <isa/isavar.h>
  120 
  121 #include <i386/isa/lptreg.h>
  122 #include <dev/ppbus/lptio.h>
  123 
  124 #define LPINITRDY       4       /* wait up to 4 seconds for a ready */
  125 #define LPTOUTINITIAL   10      /* initial timeout to wait for ready 1/10 s */
  126 #define LPTOUTMAX       1       /* maximal timeout 1 s */
  127 #define LPPRI           (PZERO+8)
  128 #define BUFSIZE         1024
  129 
  130 #ifndef PC98
  131 /* BIOS printer list - used by BIOS probe*/
  132 #define BIOS_LPT_PORTS  0x408
  133 #define BIOS_PORTS      (short *)(KERNBASE+BIOS_LPT_PORTS)
  134 #define BIOS_MAX_LPT    4
  135 #endif
  136 
  137 
  138 #ifndef DEBUG
  139 #define lprintf(args)
  140 #else
  141 #define lprintf(args)   do {                            \
  142                                 if (lptflag)            \
  143                                         printf args;    \
  144                         } while (0)
  145 static int volatile lptflag = 1;
  146 #endif
  147 
  148 #define LPTUNIT(s)      ((s)&0x03)
  149 #define LPTFLAGS(s)     ((s)&0xfc)
  150 
  151 struct lpt_softc {
  152         struct resource *res_port;
  153         struct resource *res_irq;
  154         void *sc_ih;
  155 
  156         int     sc_port;
  157         short   sc_state;
  158         /* default case: negative prime, negative ack, handshake strobe,
  159            prime once */
  160         u_char  sc_control;
  161         char    sc_flags;
  162 #define LP_POS_INIT     0x04    /* if we are a postive init signal */
  163 #define LP_POS_ACK      0x08    /* if we are a positive going ack */
  164 #define LP_NO_PRIME     0x10    /* don't prime the printer at all */
  165 #define LP_PRIMEOPEN    0x20    /* prime on every open */
  166 #define LP_AUTOLF       0x40    /* tell printer to do an automatic lf */
  167 #define LP_BYPASS       0x80    /* bypass  printer ready checks */
  168         struct  buf *sc_inbuf;
  169         short   sc_xfercnt ;
  170         char    sc_primed;
  171         char    *sc_cp ;
  172         u_char  sc_irq ;        /* IRQ status of port */
  173 #define LP_HAS_IRQ      0x01    /* we have an irq available */
  174 #define LP_USE_IRQ      0x02    /* we are using our irq */
  175 #define LP_ENABLE_IRQ   0x04    /* enable IRQ on open */
  176         u_char  sc_backoff ;    /* time to call lptout() again */
  177 };
  178 
  179 /* bits for state */
  180 #define OPEN            (1<<0)  /* device is open */
  181 #define ASLP            (1<<1)  /* awaiting draining of printer */
  182 #define ERROR           (1<<2)  /* error was received from printer */
  183 #define OBUSY           (1<<3)  /* printer is busy doing output */
  184 #define LPTOUT          (1<<4)  /* timeout while not selected */
  185 #define TOUT            (1<<5)  /* timeout while not selected */
  186 #define INIT            (1<<6)  /* waiting to initialize for open */
  187 #define INTERRUPTED     (1<<7)  /* write call was interrupted */
  188 
  189 
  190 /* status masks to interrogate printer status */
  191 #define RDY_MASK        (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)     /* ready ? */
  192 #define LP_READY        (LPS_SEL|LPS_NBSY|LPS_NERR)
  193 
  194 /* Printer Ready condition  - from lpa.c */
  195 /* Only used in polling code */
  196 #ifdef PC98
  197 #define NOT_READY(x)    ((inb(x) & LPS_NBSY) != LPS_NBSY)
  198 #else   /* IBM-PC */
  199 #define LPS_INVERT      (LPS_NBSY | LPS_NACK |           LPS_SEL | LPS_NERR)
  200 #define LPS_MASK        (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
  201 #define NOT_READY(x)    ((inb(x)^LPS_INVERT)&LPS_MASK)
  202 #endif
  203 
  204 #define MAX_SLEEP       (hz*5)  /* Timeout while waiting for device ready */
  205 #define MAX_SPIN        20      /* Max delay for device ready in usecs */
  206 
  207 static timeout_t lptout;
  208 static int lpt_probe(device_t);
  209 static int lpt_attach(device_t);
  210 static void lpt_intr(void *);
  211 
  212 static devclass_t olpt_devclass;
  213 
  214 static device_method_t olpt_methods[] = {
  215         DEVMETHOD(device_probe,         lpt_probe),
  216         DEVMETHOD(device_attach,        lpt_attach),
  217         { 0, 0 }
  218 };
  219 
  220 static driver_t olpt_driver = {
  221         "olpt",
  222         olpt_methods,
  223         sizeof (struct lpt_softc),
  224 };
  225 
  226 DRIVER_MODULE(olpt, isa, olpt_driver, olpt_devclass, 0, 0);
  227 
  228 static  d_open_t        lptopen;
  229 static  d_close_t       lptclose;
  230 static  d_write_t       lptwrite;
  231 static  d_ioctl_t       lptioctl;
  232 
  233 #define CDEV_MAJOR 16
  234 static struct cdevsw lpt_cdevsw = {
  235         /* open */      lptopen,
  236         /* close */     lptclose,
  237         /* read */      noread,
  238         /* write */     lptwrite,
  239         /* ioctl */     lptioctl,
  240         /* poll */      nopoll,
  241         /* mmap */      nommap,
  242         /* strategy */  nostrategy,
  243         /* name */      "lpt",
  244         /* maj */       CDEV_MAJOR,
  245         /* dump */      nodump,
  246         /* psize */     nopsize,
  247         /* flags */     0,
  248 };
  249 
  250 static bus_addr_t lpt_iat[] = {0, 2, 4, 6};
  251 
  252 #ifndef PC98
  253 /*
  254  * Internal routine to lptprobe to do port tests of one byte value
  255  */
  256 static int
  257 lpt_port_test (int port, u_char data, u_char mask)
  258 {
  259         int     temp, timeout;
  260 
  261         data = data & mask;
  262         outb(port, data);
  263         timeout = 10000;
  264         do {
  265                 DELAY(10);
  266                 temp = inb(port) & mask;
  267         }
  268         while (temp != data && --timeout);
  269         lprintf(("Port 0x%x\tout=%x\tin=%x\ttout=%d\n",
  270                 port, data, temp, timeout));
  271         return (temp == data);
  272 }
  273 #endif /* PC98 */
  274 
  275 /*
  276  * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
  277  * Based partially on Rod Grimes' printer probe
  278  *
  279  * Logic:
  280  *      1) If no port address was given, use the bios detected ports
  281  *         and autodetect what ports the printers are on.
  282  *      2) Otherwise, probe the data port at the address given,
  283  *         using the method in Rod Grimes' port probe.
  284  *         (Much code ripped off directly from Rod's probe.)
  285  *
  286  * Comments from Rod's probe:
  287  * Logic:
  288  *      1) You should be able to write to and read back the same value
  289  *         to the data port.  Do an alternating zeros, alternating ones,
  290  *         walking zero, and walking one test to check for stuck bits.
  291  *
  292  *      2) You should be able to write to and read back the same value
  293  *         to the control port lower 5 bits, the upper 3 bits are reserved
  294  *         per the IBM PC technical reference manauls and different boards
  295  *         do different things with them.  Do an alternating zeros, alternating
  296  *         ones, walking zero, and walking one test to check for stuck bits.
  297  *
  298  *         Some printers drag the strobe line down when the are powered off
  299  *         so this bit has been masked out of the control port test.
  300  *
  301  *         XXX Some printers may not like a fast pulse on init or strobe, I
  302  *         don't know at this point, if that becomes a problem these bits
  303  *         should be turned off in the mask byte for the control port test.
  304  *
  305  *         We are finally left with a mask of 0x14, due to some printers
  306  *         being adamant about holding other bits high ........
  307  *
  308  *         Before probing the control port, we write a 0 to the data port -
  309  *         If not, some printers chuck out garbage when the strobe line
  310  *         gets toggled.
  311  *
  312  *      3) Set the data and control ports to a value of 0
  313  *
  314  *      This probe routine has been tested on Epson Lx-800, HP LJ3P,
  315  *      Epson FX-1170 and C.Itoh 8510RM
  316  *      printers.
  317  *      Quick exit on fail added.
  318  */
  319 
  320 int
  321 lpt_probe(device_t dev)
  322 {
  323 #ifdef PC98
  324 #define PC98_OLD_LPT 0x40
  325 #define PC98_IEEE_1284_FUNCTION 0x149
  326         int rid;
  327         struct resource *res;
  328 
  329         /* Check isapnp ids */
  330         if (isa_get_vendorid(dev))
  331                 return ENXIO;
  332 
  333         rid = 0;
  334         res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, lpt_iat, 4,
  335                                   RF_ACTIVE);
  336         if (res == NULL)
  337                 return ENXIO;
  338         isa_load_resourcev(res, lpt_iat, 4);
  339 
  340         if (isa_get_port(dev) == PC98_OLD_LPT) {
  341                 unsigned int pc98_ieee_mode, tmp;
  342 
  343                 tmp = inb(PC98_IEEE_1284_FUNCTION);
  344                 pc98_ieee_mode = tmp;
  345                 if ((tmp & 0x10) == 0x10) {
  346                         outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10);
  347                         tmp = inb(PC98_IEEE_1284_FUNCTION);
  348                         if ((tmp & 0x10) != 0x10) {
  349                                 outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode);
  350                                 bus_release_resource(dev, SYS_RES_IOPORT, rid,
  351                                                      res);
  352                                 return ENXIO;
  353                         }
  354                 }
  355         }
  356 
  357         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
  358         return 0;
  359 #else
  360         int             port;
  361         static short    next_bios_lpt = 0;
  362         int             status;
  363         static u_char   testbyte[18] = {
  364                 0x55,                   /* alternating zeros */
  365                 0xaa,                   /* alternating ones */
  366                 0xfe, 0xfd, 0xfb, 0xf7,
  367                 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */
  368                 0x01, 0x02, 0x04, 0x08,
  369                 0x10, 0x20, 0x40, 0x80  /* walking one */
  370         };
  371         int             i;
  372 
  373         /*
  374          * Make sure there is some way for lptopen to see that
  375          * the port is not configured
  376          * This 0 will remain if the port isn't attached
  377          */
  378         (lpt_sc + dvp->id_unit)->sc_port = 0;
  379 
  380         status = IO_LPTSIZE;
  381         /* If port not specified, use bios list */
  382         if(dvp->id_iobase < 0) {        /* port? */
  383                 if((next_bios_lpt < BIOS_MAX_LPT) &&
  384                                 (*(BIOS_PORTS+next_bios_lpt) != 0) ) {
  385                         dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++);
  386                         goto end_probe;
  387                 } else
  388                         return (0);
  389         }
  390 
  391         /* Port was explicitly specified */
  392         /* This allows probing of ports unknown to the BIOS */
  393         port = dvp->id_iobase + lpt_data;
  394         for (i = 0; i < 18; i++) {
  395                 if (!lpt_port_test(port, testbyte[i], 0xff)) {
  396                         status = 0;
  397                         goto end_probe;
  398                 }
  399         }
  400 
  401 end_probe:
  402         /* write 0's to control and data ports */
  403         outb(dvp->id_iobase+lpt_data, 0);
  404         outb(dvp->id_iobase+lpt_control, 0);
  405 
  406         return (status);
  407 #endif
  408 }
  409 
  410 /* XXX Todo - try and detect if interrupt is working */
  411 int
  412 lpt_attach(device_t dev)
  413 {
  414         int     rid, unit;
  415         struct  lpt_softc       *sc;
  416 
  417         unit = device_get_unit(dev);
  418         sc = device_get_softc(dev);
  419 
  420         rid = 0;
  421         sc->res_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
  422                                            lpt_iat, 4, RF_ACTIVE);
  423         if (sc->res_port == NULL)
  424                 return ENXIO;
  425         isa_load_resourcev(sc->res_port, lpt_iat, 4);
  426 
  427         sc->sc_port = rman_get_start(sc->res_port);
  428         sc->sc_primed = 0;      /* not primed yet */
  429 #ifdef PC98
  430         outb(sc->sc_port+lpt_pstb_ctrl, LPC_DIS_PSTB);  /* PSTB disable */
  431         outb(sc->sc_port+lpt_control,   LPC_MODE8255);  /* 8255 mode set */
  432         outb(sc->sc_port+lpt_control,   LPC_NIRQ8);     /* IRQ8 inactive */
  433         outb(sc->sc_port+lpt_control,   LPC_NPSTB);     /* PSTB inactive */
  434         outb(sc->sc_port+lpt_pstb_ctrl, LPC_EN_PSTB);   /* PSTB enable */
  435 #else
  436         outb(sc->sc_port+lpt_control, LPC_NINIT);
  437 #endif
  438 
  439         sc->sc_irq = 0;
  440         if (isa_get_irq(dev) != -1) {
  441                 rid = 0;
  442                 sc->res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
  443                                                  0, ~0, 1, RF_ACTIVE);
  444                 if (sc->res_irq == NULL) {
  445                         bus_release_resource(dev, SYS_RES_IOPORT, 0,
  446                                              sc->res_port);
  447                         return ENXIO;
  448                 }
  449                 if (bus_setup_intr(dev, sc->res_irq, INTR_TYPE_TTY, lpt_intr,
  450                                    sc, &sc->sc_ih)) {
  451                         bus_release_resource(dev, SYS_RES_IOPORT, 0,
  452                                              sc->res_port);
  453                         bus_release_resource(dev, SYS_RES_IRQ, 0,
  454                                              sc->res_irq);
  455                         return ENXIO;
  456                 }
  457                 sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
  458                 device_printf(dev, "Interrupt-driven port");
  459         }
  460 
  461         /* XXX what to do about the flags in the minor number? */
  462         make_dev(&lpt_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit);
  463         make_dev(&lpt_cdevsw, unit | LP_BYPASS,
  464                         UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
  465 
  466         return 0;
  467 }
  468 
  469 /*
  470  * lptopen -- reset the printer, then wait until it's selected and not busy.
  471  *      If LP_BYPASS flag is selected, then we do not try to select the
  472  *      printer -- this is just used for passing ioctls.
  473  */
  474 
  475 static  int
  476 lptopen (dev_t dev, int flags, int fmt, struct thread *td)
  477 {
  478         struct lpt_softc *sc;
  479         int s;
  480 #ifdef PC98
  481         int port;
  482 #else
  483         int trys, port;
  484 #endif
  485 
  486         sc = devclass_get_softc(olpt_devclass, LPTUNIT(minor(dev)));
  487         if (sc->sc_port == 0)
  488                 return (ENXIO);
  489 
  490         if (sc->sc_state) {
  491                 lprintf(("lp: still open %x\n", sc->sc_state));
  492                 return(EBUSY);
  493         } else
  494                 sc->sc_state |= INIT;
  495 
  496         sc->sc_flags = LPTFLAGS(minor(dev));
  497 
  498         /* Check for open with BYPASS flag set. */
  499         if (sc->sc_flags & LP_BYPASS) {
  500                 sc->sc_state = OPEN;
  501                 return(0);
  502         }
  503 
  504         s = spltty();
  505         lprintf(("lp flags 0x%x\n", sc->sc_flags));
  506         port = sc->sc_port;
  507 
  508         /* set IRQ status according to ENABLE_IRQ flag */
  509         if (sc->sc_irq & LP_ENABLE_IRQ)
  510                 sc->sc_irq |= LP_USE_IRQ;
  511         else
  512                 sc->sc_irq &= ~LP_USE_IRQ;
  513 
  514         /* init printer */
  515 #ifndef PC98
  516         if ((sc->sc_flags & LP_NO_PRIME) == 0) {
  517                 if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
  518                         outb(port+lpt_control, 0);
  519                         sc->sc_primed++;
  520                         DELAY(500);
  521                 }
  522         }
  523 
  524         outb (port+lpt_control, LPC_SEL|LPC_NINIT);
  525 
  526         /* wait till ready (printer running diagnostics) */
  527         trys = 0;
  528         do {
  529                 /* ran out of waiting for the printer */
  530                 if (trys++ >= LPINITRDY*4) {
  531                         splx(s);
  532                         sc->sc_state = 0;
  533                         lprintf(("status %x\n", inb(port+lpt_status)));
  534                         return (EBUSY);
  535                 }
  536 
  537                 /* wait 1/4 second, give up if we get a signal */
  538                 if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) !=
  539                     EWOULDBLOCK) {
  540                         sc->sc_state = 0;
  541                         splx(s);
  542                         return (EBUSY);
  543                 }
  544 
  545                 /* is printer online and ready for output */
  546         } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
  547                  (LPS_SEL|LPS_NBSY|LPS_NERR));
  548 
  549         sc->sc_control = LPC_SEL|LPC_NINIT;
  550         if (sc->sc_flags & LP_AUTOLF)
  551                 sc->sc_control |= LPC_AUTOL;
  552 
  553         /* enable interrupt if interrupt-driven */
  554         if (sc->sc_irq & LP_USE_IRQ)
  555                 sc->sc_control |= LPC_ENA;
  556 
  557         outb(port+lpt_control, sc->sc_control);
  558 #endif
  559 
  560         sc->sc_state = OPEN;
  561         sc->sc_inbuf = geteblk(BUFSIZE);
  562         sc->sc_xfercnt = 0;
  563         splx(s);
  564 
  565         /* only use timeout if using interrupt */
  566         lprintf(("irq %x\n", sc->sc_irq));
  567         if (sc->sc_irq & LP_USE_IRQ) {
  568                 sc->sc_state |= TOUT;
  569                 timeout (lptout, (caddr_t)sc,
  570                          (sc->sc_backoff = hz/LPTOUTINITIAL));
  571         }
  572 
  573         lprintf(("opened.\n"));
  574         return(0);
  575 }
  576 
  577 static void
  578 lptout (void *arg)
  579 {
  580         struct lpt_softc *sc = arg;
  581         int pl;
  582 
  583         lprintf(("T %x ", inb(sc->sc_port+lpt_status)));
  584         if (sc->sc_state & OPEN) {
  585                 sc->sc_backoff++;
  586                 if (sc->sc_backoff > hz/LPTOUTMAX)
  587                         sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
  588                 timeout (lptout, (caddr_t)sc, sc->sc_backoff);
  589         } else
  590                 sc->sc_state &= ~TOUT;
  591 
  592         if (sc->sc_state & ERROR)
  593                 sc->sc_state &= ~ERROR;
  594 
  595         /*
  596          * Avoid possible hangs do to missed interrupts
  597          */
  598         if (sc->sc_xfercnt) {
  599                 pl = spltty();
  600                 lpt_intr(sc);
  601                 splx(pl);
  602         } else {
  603                 sc->sc_state &= ~OBUSY;
  604                 wakeup((caddr_t)sc);
  605         }
  606 }
  607 
  608 /*
  609  * lptclose -- close the device, free the local line buffer.
  610  *
  611  * Check for interrupted write call added.
  612  */
  613 
  614 static  int
  615 lptclose(dev_t dev, int flags, int fmt, struct thread *td)
  616 {
  617         struct lpt_softc *sc;
  618 #ifndef PC98
  619         int port;
  620 #endif
  621 
  622         sc = devclass_get_softc(olpt_devclass, LPTUNIT(minor(dev)));
  623         if(sc->sc_flags & LP_BYPASS)
  624                 goto end_close;
  625 
  626 #ifndef PC98
  627         port = sc->sc_port;
  628 #endif
  629         sc->sc_state &= ~OPEN;
  630 
  631 #ifndef PC98
  632         /* if the last write was interrupted, don't complete it */
  633         if((!(sc->sc_state  & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ))
  634                 while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
  635                         (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
  636                         /* wait 1/4 second, give up if we get a signal */
  637                         if (tsleep ((caddr_t)sc, LPPRI|PCATCH,
  638                                 "lpclose", hz) != EWOULDBLOCK)
  639                                 break;
  640 
  641         outb(sc->sc_port+lpt_control, LPC_NINIT);
  642 #endif
  643         brelse(sc->sc_inbuf);
  644 
  645 end_close:
  646         sc->sc_state = 0;
  647         sc->sc_xfercnt = 0;
  648         lprintf(("closed.\n"));
  649         return(0);
  650 }
  651 
  652 /*
  653  * pushbytes()
  654  *      Workhorse for actually spinning and writing bytes to printer
  655  *      Derived from lpa.c
  656  *      Originally by ?
  657  *
  658  *      This code is only used when we are polling the port
  659  */
  660 static int
  661 pushbytes(struct lpt_softc * sc)
  662 {
  663         int spin, err, tic;
  664         char ch;
  665         int port = sc->sc_port;
  666 
  667         lprintf(("p"));
  668         /* loop for every character .. */
  669         while (sc->sc_xfercnt > 0) {
  670                 /* printer data */
  671                 ch = *(sc->sc_cp);
  672                 sc->sc_cp++;
  673                 sc->sc_xfercnt--;
  674 
  675                 /*
  676                  * Wait for printer ready.
  677                  * Loop 20 usecs testing BUSY bit, then sleep
  678                  * for exponentially increasing timeout. (vak)
  679                  */
  680                 for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
  681                         DELAY(1);       /* XXX delay is NOT this accurate! */
  682                 if (spin >= MAX_SPIN) {
  683                         tic = 0;
  684                         while (NOT_READY(port+lpt_status)) {
  685                                 /*
  686                                  * Now sleep, every cycle a
  687                                  * little longer ..
  688                                  */
  689                                 tic = tic + tic + 1;
  690                                 /*
  691                                  * But no more than 10 seconds. (vak)
  692                                  */
  693                                 if (tic > MAX_SLEEP)
  694                                         tic = MAX_SLEEP;
  695                                 err = tsleep((caddr_t)sc, LPPRI,
  696                                         "lptpoll", tic);
  697                                 if (err != EWOULDBLOCK) {
  698                                         return (err);
  699                                 }
  700                         }
  701                 }
  702 
  703                 /* output data */
  704                 outb(port+lpt_data, ch);
  705 #ifdef PC98
  706                 DELAY(1);
  707                 outb(port+lpt_control, LPC_PSTB);
  708                 DELAY(1);
  709                 outb(port+lpt_control, LPC_NPSTB);
  710 #else
  711                 /* strobe */
  712                 outb(port+lpt_control, sc->sc_control|LPC_STB);
  713                 outb(port+lpt_control, sc->sc_control);
  714 #endif
  715 
  716         }
  717         return(0);
  718 }
  719 
  720 /*
  721  * lptwrite --copy a line from user space to a local buffer, then call
  722  * putc to get the chars moved to the output queue.
  723  *
  724  * Flagging of interrupted write added.
  725  */
  726 
  727 static  int
  728 lptwrite(dev_t dev, struct uio * uio, int ioflag)
  729 {
  730         register unsigned n;
  731         int pl, err;
  732         struct lpt_softc *sc;
  733 
  734         sc = devclass_get_softc(olpt_devclass, LPTUNIT(minor(dev)));
  735         if(sc->sc_flags & LP_BYPASS) {
  736                 /* we can't do writes in bypass mode */
  737                 return(EPERM);
  738         }
  739 
  740         sc->sc_state &= ~INTERRUPTED;
  741         while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
  742                 sc->sc_cp = sc->sc_inbuf->b_data ;
  743                 uiomove(sc->sc_cp, n, uio);
  744                 sc->sc_xfercnt = n ;
  745                 while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
  746                         lprintf(("i"));
  747                         /* if the printer is ready for a char, */
  748                         /* give it one */
  749                         if ((sc->sc_state & OBUSY) == 0){
  750                                 lprintf(("\nC %d. ", sc->sc_xfercnt));
  751                                 pl = spltty();
  752                                 lpt_intr(sc);
  753                                 (void) splx(pl);
  754                         }
  755                         lprintf(("W "));
  756                         if (sc->sc_state & OBUSY)
  757                                 if ((err = tsleep ((caddr_t)sc,
  758                                          LPPRI|PCATCH, "lpwrite", 0))) {
  759                                         sc->sc_state |= INTERRUPTED;
  760                                         return(err);
  761                                 }
  762                 }
  763                 /* check to see if we must do a polled write */
  764                 if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
  765                         lprintf(("p"));
  766                         if((err = pushbytes(sc)))
  767                                 return(err);
  768                 }
  769         }
  770         return(0);
  771 }
  772 
  773 /*
  774  * lptintr -- handle printer interrupts which occur when the printer is
  775  * ready to accept another char.
  776  *
  777  * do checking for interrupted write call.
  778  */
  779 
  780 static void
  781 lpt_intr(void *arg)
  782 {
  783 }
  784 
  785 static  int
  786 lptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td)
  787 {
  788         int     error = 0;
  789         struct  lpt_softc *sc;
  790         u_int   unit = LPTUNIT(minor(dev));
  791         u_char  old_sc_irq;     /* old printer IRQ status */
  792 
  793         sc = devclass_get_softc(olpt_devclass, unit);
  794 
  795         switch (cmd) {
  796         case LPT_IRQ :
  797                 if(sc->sc_irq & LP_HAS_IRQ) {
  798                         /*
  799                          * NOTE:
  800                          * If the IRQ status is changed,
  801                          * this will only be visible on the
  802                          * next open.
  803                          *
  804                          * If interrupt status changes,
  805                          * this gets syslog'd.
  806                          */
  807                         old_sc_irq = sc->sc_irq;
  808                         if(*(int*)data == 0)
  809                                 sc->sc_irq &= (~LP_ENABLE_IRQ);
  810                         else
  811                                 sc->sc_irq |= LP_ENABLE_IRQ;
  812                         if (old_sc_irq != sc->sc_irq )
  813                                 log(LOG_NOTICE, "lpt%c switched to %s mode\n",
  814                                         (char)unit+'',
  815                                         (sc->sc_irq & LP_ENABLE_IRQ)?
  816                                         "interrupt-driven":"polled");
  817                 } else /* polled port */
  818                         error = EOPNOTSUPP;
  819                 break;
  820         default:
  821                 error = ENODEV;
  822         }
  823 
  824         return(error);
  825 }

Cache object: 20c7c17d4666006aad8c4b49a8b20078


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.