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/cbus/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$
   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 a 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/bus.h>
  108 #include <sys/kernel.h>
  109 #include <sys/module.h>
  110 #include <sys/uio.h>
  111 #include <sys/syslog.h>
  112 #include <sys/malloc.h>
  113 
  114 #include <machine/bus.h>
  115 #include <machine/resource.h>
  116 #include <sys/rman.h>
  117 
  118 #include <isa/isavar.h>
  119 
  120 #include <pc98/cbus/olptreg.h>
  121 #include <dev/ppbus/lptio.h>
  122 
  123 #define LPINITRDY       4       /* wait up to 4 seconds for a ready */
  124 #define LPTOUTINITIAL   10      /* initial timeout to wait for ready 1/10 s */
  125 #define LPTOUTMAX       1       /* maximal timeout 1 s */
  126 #define LPPRI           (PZERO+8)
  127 #define BUFSIZE         1024
  128 
  129 #ifndef DEBUG
  130 #define lprintf(args)
  131 #else
  132 #define lprintf(args)   do {                            \
  133                                 if (lptflag)            \
  134                                         printf args;    \
  135                         } while (0)
  136 static int volatile lptflag = 1;
  137 #endif
  138 
  139 struct lpt_softc {
  140         struct resource *res_port;
  141         struct resource *res_irq;
  142         void *sc_ih;
  143         struct callout timer;
  144 
  145         int     sc_port;
  146         short   sc_state;
  147         /* default case: negative prime, negative ack, handshake strobe,
  148            prime once */
  149         u_char  sc_control;
  150         char    sc_flags;
  151 #define LP_POS_INIT     0x04    /* if we are a postive init signal */
  152 #define LP_POS_ACK      0x08    /* if we are a positive going ack */
  153 #define LP_NO_PRIME     0x10    /* don't prime the printer at all */
  154 #define LP_PRIMEOPEN    0x20    /* prime on every open */
  155 #define LP_AUTOLF       0x40    /* tell printer to do an automatic lf */
  156 #define LP_BYPASS       0x80    /* bypass  printer ready checks */
  157         void    *sc_inbuf;
  158         short   sc_xfercnt ;
  159         char    sc_primed;
  160         char    *sc_cp ;
  161         u_char  sc_irq ;        /* IRQ status of port */
  162 #define LP_HAS_IRQ      0x01    /* we have an irq available */
  163 #define LP_USE_IRQ      0x02    /* we are using our irq */
  164 #define LP_ENABLE_IRQ   0x04    /* enable IRQ on open */
  165         u_char  sc_backoff ;    /* time to call lptout() again */
  166 };
  167 
  168 /* bits for state */
  169 #define OPEN            (1<<0)  /* device is open */
  170 #define ASLP            (1<<1)  /* awaiting draining of printer */
  171 #define ERROR           (1<<2)  /* error was received from printer */
  172 #define OBUSY           (1<<3)  /* printer is busy doing output */
  173 #define LPTOUT          (1<<4)  /* timeout while not selected */
  174 #define TOUT            (1<<5)  /* timeout while not selected */
  175 #define INIT            (1<<6)  /* waiting to initialize for open */
  176 #define INTERRUPTED     (1<<7)  /* write call was interrupted */
  177 
  178 
  179 /* status masks to interrogate printer status */
  180 #define RDY_MASK        (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)     /* ready ? */
  181 #define LP_READY        (LPS_SEL|LPS_NBSY|LPS_NERR)
  182 
  183 /* Printer Ready condition  - from lpa.c */
  184 /* Only used in polling code */
  185 #define NOT_READY(x)    ((inb(x) & LPS_NBSY) != LPS_NBSY)
  186 
  187 #define MAX_SLEEP       (hz*5)  /* Timeout while waiting for device ready */
  188 #define MAX_SPIN        20      /* Max delay for device ready in usecs */
  189 
  190 static timeout_t lptout;
  191 static int lpt_probe(device_t);
  192 static int lpt_attach(device_t);
  193 static void lpt_intr(void *);
  194 
  195 static devclass_t olpt_devclass;
  196 
  197 static device_method_t olpt_methods[] = {
  198         DEVMETHOD(device_probe,         lpt_probe),
  199         DEVMETHOD(device_attach,        lpt_attach),
  200         { 0, 0 }
  201 };
  202 
  203 static driver_t olpt_driver = {
  204         "olpt",
  205         olpt_methods,
  206         sizeof (struct lpt_softc),
  207 };
  208 
  209 DRIVER_MODULE(olpt, isa, olpt_driver, olpt_devclass, 0, 0);
  210 
  211 static  d_open_t        lptopen;
  212 static  d_close_t       lptclose;
  213 static  d_write_t       lptwrite;
  214 static  d_ioctl_t       lptioctl;
  215 
  216 static struct cdevsw lpt_cdevsw = {
  217         .d_version =    D_VERSION,
  218         .d_flags =      D_NEEDGIANT,
  219         .d_open =       lptopen,
  220         .d_close =      lptclose,
  221         .d_write =      lptwrite,
  222         .d_ioctl =      lptioctl,
  223         .d_name =       "lpt",
  224 };
  225 
  226 static bus_addr_t lpt_iat[] = {0, 2, 4, 6};
  227 
  228 /*
  229  * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
  230  * Based partially on Rod Grimes' printer probe
  231  *
  232  * Logic:
  233  *      1) If no port address was given, use the bios detected ports
  234  *         and autodetect what ports the printers are on.
  235  *      2) Otherwise, probe the data port at the address given,
  236  *         using the method in Rod Grimes' port probe.
  237  *         (Much code ripped off directly from Rod's probe.)
  238  *
  239  * Comments from Rod's probe:
  240  * Logic:
  241  *      1) You should be able to write to and read back the same value
  242  *         to the data port.  Do an alternating zeros, alternating ones,
  243  *         walking zero, and walking one test to check for stuck bits.
  244  *
  245  *      2) You should be able to write to and read back the same value
  246  *         to the control port lower 5 bits, the upper 3 bits are reserved
  247  *         per the IBM PC technical reference manauls and different boards
  248  *         do different things with them.  Do an alternating zeros, alternating
  249  *         ones, walking zero, and walking one test to check for stuck bits.
  250  *
  251  *         Some printers drag the strobe line down when the are powered off
  252  *         so this bit has been masked out of the control port test.
  253  *
  254  *         XXX Some printers may not like a fast pulse on init or strobe, I
  255  *         don't know at this point, if that becomes a problem these bits
  256  *         should be turned off in the mask byte for the control port test.
  257  *
  258  *         We are finally left with a mask of 0x14, due to some printers
  259  *         being adamant about holding other bits high ........
  260  *
  261  *         Before probing the control port, we write a 0 to the data port -
  262  *         If not, some printers chuck out garbage when the strobe line
  263  *         gets toggled.
  264  *
  265  *      3) Set the data and control ports to a value of 0
  266  *
  267  *      This probe routine has been tested on Epson Lx-800, HP LJ3P,
  268  *      Epson FX-1170 and C.Itoh 8510RM
  269  *      printers.
  270  *      Quick exit on fail added.
  271  */
  272 
  273 int
  274 lpt_probe(device_t dev)
  275 {
  276 #define PC98_OLD_LPT 0x40
  277 #define PC98_IEEE_1284_FUNCTION 0x149
  278         int rid;
  279         struct resource *res;
  280 
  281         /* Check isapnp ids */
  282         if (isa_get_vendorid(dev))
  283                 return ENXIO;
  284 
  285         rid = 0;
  286         res = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, lpt_iat, 4,
  287                                   RF_ACTIVE);
  288         if (res == NULL)
  289                 return ENXIO;
  290         isa_load_resourcev(res, lpt_iat, 4);
  291 
  292         if (isa_get_port(dev) == PC98_OLD_LPT) {
  293                 unsigned int pc98_ieee_mode, tmp;
  294 
  295                 tmp = inb(PC98_IEEE_1284_FUNCTION);
  296                 pc98_ieee_mode = tmp;
  297                 if ((tmp & 0x10) == 0x10) {
  298                         outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10);
  299                         tmp = inb(PC98_IEEE_1284_FUNCTION);
  300                         if ((tmp & 0x10) != 0x10) {
  301                                 outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode);
  302                                 bus_release_resource(dev, SYS_RES_IOPORT, rid,
  303                                                      res);
  304                                 return ENXIO;
  305                         }
  306                 }
  307         }
  308 
  309         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
  310         return 0;
  311 }
  312 
  313 /* XXX Todo - try and detect if interrupt is working */
  314 int
  315 lpt_attach(device_t dev)
  316 {
  317         int     rid, unit;
  318         struct  lpt_softc       *sc;
  319         struct  cdev            *cdev;
  320 
  321         unit = device_get_unit(dev);
  322         sc = device_get_softc(dev);
  323         callout_init(&sc->timer, 0);
  324 
  325         rid = 0;
  326         sc->res_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid,
  327                                            lpt_iat, 4, RF_ACTIVE);
  328         if (sc->res_port == NULL)
  329                 return ENXIO;
  330         isa_load_resourcev(sc->res_port, lpt_iat, 4);
  331 
  332         sc->sc_port = rman_get_start(sc->res_port);
  333         sc->sc_primed = 0;      /* not primed yet */
  334 
  335         outb(sc->sc_port+lpt_pstb_ctrl, LPC_DIS_PSTB);  /* PSTB disable */
  336         outb(sc->sc_port+lpt_control,   LPC_MODE8255);  /* 8255 mode set */
  337         outb(sc->sc_port+lpt_control,   LPC_NIRQ8);     /* IRQ8 inactive */
  338         outb(sc->sc_port+lpt_control,   LPC_NPSTB);     /* PSTB inactive */
  339         outb(sc->sc_port+lpt_pstb_ctrl, LPC_EN_PSTB);   /* PSTB enable */
  340 
  341         sc->sc_irq = 0;
  342         if (isa_get_irq(dev) != -1) {
  343                 rid = 0;
  344                 sc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  345                                                      RF_ACTIVE);
  346                 if (sc->res_irq == NULL) {
  347                         bus_release_resource(dev, SYS_RES_IOPORT, 0,
  348                                              sc->res_port);
  349                         return ENXIO;
  350                 }
  351                 if (bus_setup_intr(dev, sc->res_irq, INTR_TYPE_TTY, NULL, lpt_intr,
  352                                    sc, &sc->sc_ih)) {
  353                         bus_release_resource(dev, SYS_RES_IOPORT, 0,
  354                                              sc->res_port);
  355                         bus_release_resource(dev, SYS_RES_IRQ, 0,
  356                                              sc->res_irq);
  357                         return ENXIO;
  358                 }
  359                 sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
  360                 device_printf(dev, "Interrupt-driven port");
  361         }
  362 
  363         cdev = make_dev(&lpt_cdevsw, 0,
  364                         UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit);
  365         cdev->si_drv1 = sc;
  366         cdev = make_dev(&lpt_cdevsw, LP_BYPASS,
  367                         UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
  368         cdev->si_drv1 = sc;
  369 
  370         return 0;
  371 }
  372 
  373 /*
  374  * lptopen -- reset the printer, then wait until it's selected and not busy.
  375  *      If LP_BYPASS flag is selected, then we do not try to select the
  376  *      printer -- this is just used for passing ioctls.
  377  */
  378 
  379 static  int
  380 lptopen (struct cdev *dev, int flags, int fmt, struct thread *td)
  381 {
  382         struct lpt_softc *sc = dev->si_drv1;
  383         int s;
  384         int port;
  385 
  386         if (sc->sc_port == 0)
  387                 return (ENXIO);
  388 
  389         if (sc->sc_state) {
  390                 lprintf(("lp: still open %x\n", sc->sc_state));
  391                 return(EBUSY);
  392         } else
  393                 sc->sc_state |= INIT;
  394 
  395         sc->sc_flags = dev2unit(dev);
  396 
  397         /* Check for open with BYPASS flag set. */
  398         if (sc->sc_flags & LP_BYPASS) {
  399                 sc->sc_state = OPEN;
  400                 return(0);
  401         }
  402 
  403         s = spltty();
  404         lprintf(("lp flags 0x%x\n", sc->sc_flags));
  405         port = sc->sc_port;
  406 
  407         /* set IRQ status according to ENABLE_IRQ flag */
  408         if (sc->sc_irq & LP_ENABLE_IRQ)
  409                 sc->sc_irq |= LP_USE_IRQ;
  410         else
  411                 sc->sc_irq &= ~LP_USE_IRQ;
  412 
  413         /* init printer */
  414         sc->sc_state = OPEN;
  415         sc->sc_inbuf = malloc(BUFSIZE, M_DEVBUF, M_WAITOK);
  416         sc->sc_xfercnt = 0;
  417         splx(s);
  418 
  419         /* only use timeout if using interrupt */
  420         lprintf(("irq %x\n", sc->sc_irq));
  421         if (sc->sc_irq & LP_USE_IRQ) {
  422                 sc->sc_state |= TOUT;
  423                 sc->sc_backoff = hz / LPTOUTINITIAL;
  424                 callout_reset(&sc->timer, sc->sc_backoff, lptout, sc);
  425         }
  426 
  427         lprintf(("opened.\n"));
  428         return(0);
  429 }
  430 
  431 static void
  432 lptout (void *arg)
  433 {
  434         struct lpt_softc *sc = arg;
  435         int pl;
  436 
  437         lprintf(("T %x ", inb(sc->sc_port+lpt_status)));
  438         if (sc->sc_state & OPEN) {
  439                 sc->sc_backoff++;
  440                 if (sc->sc_backoff > hz/LPTOUTMAX)
  441                         sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
  442                 callout_reset(&sc->timer, sc->sc_backoff, lptout, sc);
  443         } else
  444                 sc->sc_state &= ~TOUT;
  445 
  446         if (sc->sc_state & ERROR)
  447                 sc->sc_state &= ~ERROR;
  448 
  449         /*
  450          * Avoid possible hangs do to missed interrupts
  451          */
  452         if (sc->sc_xfercnt) {
  453                 pl = spltty();
  454                 lpt_intr(sc);
  455                 splx(pl);
  456         } else {
  457                 sc->sc_state &= ~OBUSY;
  458                 wakeup(sc);
  459         }
  460 }
  461 
  462 /*
  463  * lptclose -- close the device, free the local line buffer.
  464  *
  465  * Check for interrupted write call added.
  466  */
  467 
  468 static  int
  469 lptclose(struct cdev *dev, int flags, int fmt, struct thread *td)
  470 {
  471         struct lpt_softc *sc = dev->si_drv1;
  472 
  473         if(sc->sc_flags & LP_BYPASS)
  474                 goto end_close;
  475 
  476         sc->sc_state &= ~OPEN;
  477         free(sc->sc_inbuf, M_DEVBUF);
  478 
  479 end_close:
  480         sc->sc_state = 0;
  481         sc->sc_xfercnt = 0;
  482         lprintf(("closed.\n"));
  483         return(0);
  484 }
  485 
  486 /*
  487  * pushbytes()
  488  *      Workhorse for actually spinning and writing bytes to printer
  489  *      Derived from lpa.c
  490  *      Originally by ?
  491  *
  492  *      This code is only used when we are polling the port
  493  */
  494 static int
  495 pushbytes(struct lpt_softc * sc)
  496 {
  497         int spin, err, tic;
  498         char ch;
  499         int port = sc->sc_port;
  500 
  501         lprintf(("p"));
  502         /* loop for every character .. */
  503         while (sc->sc_xfercnt > 0) {
  504                 /* printer data */
  505                 ch = *(sc->sc_cp);
  506                 sc->sc_cp++;
  507                 sc->sc_xfercnt--;
  508 
  509                 /*
  510                  * Wait for printer ready.
  511                  * Loop 20 usecs testing BUSY bit, then sleep
  512                  * for exponentially increasing timeout. (vak)
  513                  */
  514                 for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
  515                         DELAY(1);       /* XXX delay is NOT this accurate! */
  516                 if (spin >= MAX_SPIN) {
  517                         tic = 0;
  518                         while (NOT_READY(port+lpt_status)) {
  519                                 /*
  520                                  * Now sleep, every cycle a
  521                                  * little longer ..
  522                                  */
  523                                 tic = tic + tic + 1;
  524                                 /*
  525                                  * But no more than 10 seconds. (vak)
  526                                  */
  527                                 if (tic > MAX_SLEEP)
  528                                         tic = MAX_SLEEP;
  529                                 err = tsleep(sc, LPPRI,
  530                                         "lptpoll", tic);
  531                                 if (err != EWOULDBLOCK) {
  532                                         return (err);
  533                                 }
  534                         }
  535                 }
  536 
  537                 /* output data */
  538                 outb(port+lpt_data, ch);
  539                 DELAY(1);
  540                 outb(port+lpt_control, LPC_PSTB);
  541                 DELAY(1);
  542                 outb(port+lpt_control, LPC_NPSTB);
  543         }
  544         return(0);
  545 }
  546 
  547 /*
  548  * lptwrite --copy a line from user space to a local buffer, then call
  549  * putc to get the chars moved to the output queue.
  550  *
  551  * Flagging of interrupted write added.
  552  */
  553 
  554 static  int
  555 lptwrite(struct cdev *dev, struct uio * uio, int ioflag)
  556 {
  557         register unsigned n;
  558         int pl, err;
  559         struct lpt_softc *sc = dev->si_drv1;
  560 
  561         if(sc->sc_flags & LP_BYPASS) {
  562                 /* we can't do writes in bypass mode */
  563                 return(EPERM);
  564         }
  565 
  566         sc->sc_state &= ~INTERRUPTED;
  567         while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
  568                 sc->sc_cp = sc->sc_inbuf;
  569                 uiomove(sc->sc_cp, n, uio);
  570                 sc->sc_xfercnt = n ;
  571                 while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
  572                         lprintf(("i"));
  573                         /* if the printer is ready for a char, */
  574                         /* give it one */
  575                         if ((sc->sc_state & OBUSY) == 0){
  576                                 lprintf(("\nC %d. ", sc->sc_xfercnt));
  577                                 pl = spltty();
  578                                 lpt_intr(sc);
  579                                 (void) splx(pl);
  580                         }
  581                         lprintf(("W "));
  582                         if (sc->sc_state & OBUSY)
  583                                 if ((err = tsleep (sc,
  584                                          LPPRI|PCATCH, "lpwrite", 0))) {
  585                                         sc->sc_state |= INTERRUPTED;
  586                                         return(err);
  587                                 }
  588                 }
  589                 /* check to see if we must do a polled write */
  590                 if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
  591                         lprintf(("p"));
  592                         if((err = pushbytes(sc)))
  593                                 return(err);
  594                 }
  595         }
  596         return(0);
  597 }
  598 
  599 /*
  600  * lptintr -- handle printer interrupts which occur when the printer is
  601  * ready to accept another char.
  602  *
  603  * do checking for interrupted write call.
  604  */
  605 
  606 static void
  607 lpt_intr(void *arg)
  608 {
  609 }
  610 
  611 static  int
  612 lptioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
  613 {
  614         int     error = 0;
  615         struct lpt_softc *sc = dev->si_drv1;
  616         u_char  old_sc_irq;     /* old printer IRQ status */
  617 
  618         switch (cmd) {
  619         case LPT_IRQ :
  620                 if(sc->sc_irq & LP_HAS_IRQ) {
  621                         /*
  622                          * NOTE:
  623                          * If the IRQ status is changed,
  624                          * this will only be visible on the
  625                          * next open.
  626                          *
  627                          * If interrupt status changes,
  628                          * this gets syslog'd.
  629                          */
  630                         old_sc_irq = sc->sc_irq;
  631                         if(*(int*)data == 0)
  632                                 sc->sc_irq &= (~LP_ENABLE_IRQ);
  633                         else
  634                                 sc->sc_irq |= LP_ENABLE_IRQ;
  635                         if (old_sc_irq != sc->sc_irq )
  636                                 log(LOG_NOTICE, "%s switched to %s mode\n",
  637                                         devtoname(dev),
  638                                         (sc->sc_irq & LP_ENABLE_IRQ)?
  639                                         "interrupt-driven":"polled");
  640                 } else /* polled port */
  641                         error = EOPNOTSUPP;
  642                 break;
  643         default:
  644                 error = ENODEV;
  645         }
  646 
  647         return(error);
  648 }

Cache object: bb7bd688b3ac699c914b56ef8c94cb94


[ 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.