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/i386/isa/lpt.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 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 "lpt.h"
  105 #include "opt_devfs.h"
  106 #include "opt_inet.h"
  107 
  108 #include <sys/param.h>
  109 #include <sys/systm.h>
  110 #include <sys/conf.h>
  111 #include <sys/buf.h>
  112 #include <sys/kernel.h>
  113 #include <sys/uio.h>
  114 #include <sys/syslog.h>
  115 #ifdef DEVFS
  116 #include <sys/devfsext.h>
  117 #endif /*DEVFS*/
  118 
  119 #include <machine/clock.h>
  120 #include <machine/lpt.h>
  121 
  122 #include <vm/vm.h>
  123 #include <vm/vm_param.h>
  124 #include <vm/pmap.h>
  125 
  126 #include <i386/isa/isa.h>
  127 #include <i386/isa/isa_device.h>
  128 #include <i386/isa/lptreg.h>
  129 
  130 #ifdef INET
  131 #include <sys/malloc.h>
  132 #include <sys/mbuf.h>
  133 #include <sys/socket.h>
  134 #include <sys/sockio.h>
  135 
  136 #include <net/if.h>
  137 #include <net/if_types.h>
  138 #include <net/netisr.h>
  139 #include <netinet/in.h>
  140 #include <netinet/in_var.h>
  141 #include "bpfilter.h"
  142 #if NBPFILTER > 0
  143 #include <net/bpf.h>
  144 #endif
  145 #endif /* INET */
  146 
  147 
  148 #define LPINITRDY       4       /* wait up to 4 seconds for a ready */
  149 #define LPTOUTINITIAL   10      /* initial timeout to wait for ready 1/10 s */
  150 #define LPTOUTMAX       1       /* maximal timeout 1 s */
  151 #define LPPRI           (PZERO+8)
  152 #define BUFSIZE         1024
  153 
  154 #ifdef INET
  155 #ifndef LPMTU                   /* MTU for the lp# interfaces */
  156 #define LPMTU   1500
  157 #endif
  158 
  159 #ifndef LPMAXSPIN1              /* DELAY factor for the lp# interfaces */
  160 #define LPMAXSPIN1      8000   /* Spinning for remote intr to happen */
  161 #endif
  162 
  163 #ifndef LPMAXSPIN2              /* DELAY factor for the lp# interfaces */
  164 #define LPMAXSPIN2      500     /* Spinning for remote handshake to happen */
  165 #endif
  166 
  167 #ifndef LPMAXERRS               /* Max errors before !RUNNING */
  168 #define LPMAXERRS       100
  169 #endif
  170 
  171 #define CLPIPHDRLEN     14      /* We send dummy ethernet addresses (two) + packet type in front of packet */
  172 #define CLPIP_SHAKE     0x80    /* This bit toggles between nibble reception */
  173 #define MLPIPHDRLEN     CLPIPHDRLEN
  174 
  175 #define LPIPHDRLEN      2       /* We send 0x08, 0x00 in front of packet */
  176 #define LPIP_SHAKE      0x40    /* This bit toggles between nibble reception */
  177 #if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN
  178 #define MLPIPHDRLEN     LPIPHDRLEN
  179 #endif
  180 
  181 #define LPIPTBLSIZE     256     /* Size of octet translation table */
  182 
  183 #endif /* INET */
  184 
  185 /* BIOS printer list - used by BIOS probe*/
  186 #define BIOS_LPT_PORTS  0x408
  187 #define BIOS_PORTS      (short *)(KERNBASE+BIOS_LPT_PORTS)
  188 #define BIOS_MAX_LPT    4
  189 
  190 
  191 #ifndef DEBUG
  192 #define lprintf(args)
  193 #else
  194 #define lprintf(args)   do {                            \
  195                                 if (lptflag)            \
  196                                         printf args;    \
  197                         } while (0)
  198 static int volatile lptflag = 1;
  199 #endif
  200 
  201 #define LPTUNIT(s)      ((s)&0x03)
  202 #define LPTFLAGS(s)     ((s)&0xfc)
  203 
  204 static struct lpt_softc {
  205         int     sc_port;
  206         short   sc_state;
  207         /* default case: negative prime, negative ack, handshake strobe,
  208            prime once */
  209         u_char  sc_control;
  210         char    sc_flags;
  211 #define LP_POS_INIT     0x04    /* if we are a postive init signal */
  212 #define LP_POS_ACK      0x08    /* if we are a positive going ack */
  213 #define LP_NO_PRIME     0x10    /* don't prime the printer at all */
  214 #define LP_PRIMEOPEN    0x20    /* prime on every open */
  215 #define LP_AUTOLF       0x40    /* tell printer to do an automatic lf */
  216 #define LP_BYPASS       0x80    /* bypass  printer ready checks */
  217         struct  buf *sc_inbuf;
  218         short   sc_xfercnt ;
  219         char    sc_primed;
  220         char    *sc_cp ;
  221         u_char  sc_irq ;        /* IRQ status of port */
  222 #define LP_HAS_IRQ      0x01    /* we have an irq available */
  223 #define LP_USE_IRQ      0x02    /* we are using our irq */
  224 #define LP_ENABLE_IRQ   0x04    /* enable IRQ on open */
  225         u_char  sc_backoff ;    /* time to call lptout() again */
  226 
  227 #ifdef INET
  228         struct  ifnet   sc_if;
  229         u_char          *sc_ifbuf;
  230         int             sc_iferrs;
  231 #endif
  232 #ifdef DEVFS
  233         void    *devfs_token;
  234         void    *devfs_token_ctl;
  235 #endif
  236 } lpt_sc[NLPT] ;
  237 
  238 /* bits for state */
  239 #define OPEN            (1<<0)  /* device is open */
  240 #define ASLP            (1<<1)  /* awaiting draining of printer */
  241 #define ERROR           (1<<2)  /* error was received from printer */
  242 #define OBUSY           (1<<3)  /* printer is busy doing output */
  243 #define LPTOUT          (1<<4)  /* timeout while not selected */
  244 #define TOUT            (1<<5)  /* timeout while not selected */
  245 #define INIT            (1<<6)  /* waiting to initialize for open */
  246 #define INTERRUPTED     (1<<7)  /* write call was interrupted */
  247 
  248 
  249 /* status masks to interrogate printer status */
  250 #define RDY_MASK        (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)     /* ready ? */
  251 #define LP_READY        (LPS_SEL|LPS_NBSY|LPS_NERR)
  252 
  253 /* Printer Ready condition  - from lpa.c */
  254 /* Only used in polling code */
  255 #define LPS_INVERT      (LPS_NBSY | LPS_NACK |           LPS_SEL | LPS_NERR)
  256 #define LPS_MASK        (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)
  257 #define NOT_READY(x)    ((inb(x)^LPS_INVERT)&LPS_MASK)
  258 
  259 #define MAX_SLEEP       (hz*5)  /* Timeout while waiting for device ready */
  260 #define MAX_SPIN        20      /* Max delay for device ready in usecs */
  261 
  262 static timeout_t lptout;
  263 static int      lptprobe (struct isa_device *dvp);
  264 static int      lptattach (struct isa_device *isdp);
  265 static ointhand2_t      lptintr;
  266 
  267 #ifdef INET
  268 
  269 /* Tables for the lp# interface */
  270 static u_char *txmith;
  271 #define txmitl (txmith+(1*LPIPTBLSIZE))
  272 #define trecvh (txmith+(2*LPIPTBLSIZE))
  273 #define trecvl (txmith+(3*LPIPTBLSIZE))
  274 
  275 static u_char *ctxmith;
  276 #define ctxmitl (ctxmith+(1*LPIPTBLSIZE))
  277 #define ctrecvh (ctxmith+(2*LPIPTBLSIZE))
  278 #define ctrecvl (ctxmith+(3*LPIPTBLSIZE))
  279 
  280 /* Functions for the lp# interface */
  281 static void lpattach(struct lpt_softc *,int);
  282 static int lpinittables(void);
  283 static int lpioctl(struct ifnet *, u_long, caddr_t);
  284 static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
  285         struct rtentry *);
  286 static void lpintr(int);
  287 #endif /* INET */
  288 
  289 struct  isa_driver lptdriver = {
  290         lptprobe, lptattach, "lpt"
  291 };
  292 
  293 static  d_open_t        lptopen;
  294 static  d_close_t       lptclose;
  295 static  d_write_t       lptwrite;
  296 static  d_ioctl_t       lptioctl;
  297 
  298 #define CDEV_MAJOR 16
  299 static struct cdevsw lpt_cdevsw = 
  300         { lptopen,      lptclose,       noread,         lptwrite,       /*16*/
  301           lptioctl,     nullstop,       nullreset,      nodevtotty,/* lpt */
  302           seltrue,      nommap,         nostrat,        "lpt",  NULL,   -1 };
  303 
  304 
  305 /*
  306  * Internal routine to lptprobe to do port tests of one byte value
  307  */
  308 static int
  309 lpt_port_test (int port, u_char data, u_char mask)
  310 {
  311         int     temp, timeout;
  312 
  313         data = data & mask;
  314         outb(port, data);
  315         timeout = 10000;
  316         do {
  317                 DELAY(10);
  318                 temp = inb(port) & mask;
  319         }
  320         while (temp != data && --timeout);
  321         lprintf(("Port 0x%x\tout=%x\tin=%x\ttout=%d\n",
  322                 port, data, temp, timeout));
  323         return (temp == data);
  324 }
  325 
  326 /*
  327  * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94
  328  * Based partially on Rod Grimes' printer probe
  329  *
  330  * Logic:
  331  *      1) If no port address was given, use the bios detected ports
  332  *         and autodetect what ports the printers are on.
  333  *      2) Otherwise, probe the data port at the address given,
  334  *         using the method in Rod Grimes' port probe.
  335  *         (Much code ripped off directly from Rod's probe.)
  336  *
  337  * Comments from Rod's probe:
  338  * Logic:
  339  *      1) You should be able to write to and read back the same value
  340  *         to the data port.  Do an alternating zeros, alternating ones,
  341  *         walking zero, and walking one test to check for stuck bits.
  342  *
  343  *      2) You should be able to write to and read back the same value
  344  *         to the control port lower 5 bits, the upper 3 bits are reserved
  345  *         per the IBM PC technical reference manauls and different boards
  346  *         do different things with them.  Do an alternating zeros, alternating
  347  *         ones, walking zero, and walking one test to check for stuck bits.
  348  *
  349  *         Some printers drag the strobe line down when the are powered off
  350  *         so this bit has been masked out of the control port test.
  351  *
  352  *         XXX Some printers may not like a fast pulse on init or strobe, I
  353  *         don't know at this point, if that becomes a problem these bits
  354  *         should be turned off in the mask byte for the control port test.
  355  *
  356  *         We are finally left with a mask of 0x14, due to some printers
  357  *         being adamant about holding other bits high ........
  358  *
  359  *         Before probing the control port, we write a 0 to the data port -
  360  *         If not, some printers chuck out garbage when the strobe line
  361  *         gets toggled.
  362  *
  363  *      3) Set the data and control ports to a value of 0
  364  *
  365  *      This probe routine has been tested on Epson Lx-800, HP LJ3P,
  366  *      Epson FX-1170 and C.Itoh 8510RM
  367  *      printers.
  368  *      Quick exit on fail added.
  369  */
  370 int
  371 lptprobe(struct isa_device *dvp)
  372 {
  373         int             port;
  374         static short    next_bios_lpt = 0;
  375         int             status;
  376         static u_char   testbyte[18] = {
  377                 0x55,                   /* alternating zeros */
  378                 0xaa,                   /* alternating ones */
  379                 0xfe, 0xfd, 0xfb, 0xf7,
  380                 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */
  381                 0x01, 0x02, 0x04, 0x08,
  382                 0x10, 0x20, 0x40, 0x80  /* walking one */
  383         };
  384         int             i;
  385 
  386         /*
  387          * Make sure there is some way for lptopen to see that
  388          * the port is not configured
  389          * This 0 will remain if the port isn't attached
  390          */
  391         (lpt_sc + dvp->id_unit)->sc_port = 0;
  392 
  393         status = IO_LPTSIZE;
  394         /* If port not specified, use bios list */
  395         if(dvp->id_iobase < 0) {        /* port? */
  396                 if((next_bios_lpt < BIOS_MAX_LPT) &&
  397                                 (*(BIOS_PORTS+next_bios_lpt) != 0) ) {
  398                         dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++);
  399                         goto end_probe;
  400                 } else
  401                         return (0);
  402         }
  403 
  404         /* Port was explicitly specified */
  405         /* This allows probing of ports unknown to the BIOS */
  406         port = dvp->id_iobase + lpt_data;
  407         for (i = 0; i < 18; i++) {
  408                 if (!lpt_port_test(port, testbyte[i], 0xff)) {
  409                         status = 0;
  410                         goto end_probe;
  411                 }
  412         }
  413 
  414 end_probe:
  415         /* write 0's to control and data ports */
  416         outb(dvp->id_iobase+lpt_data, 0);
  417         outb(dvp->id_iobase+lpt_control, 0);
  418 
  419         return (status);
  420 }
  421 
  422 /* XXX Todo - try and detect if interrupt is working */
  423 int
  424 lptattach(struct isa_device *isdp)
  425 {
  426         struct  lpt_softc       *sc;
  427         int     unit;
  428 
  429         isdp->id_ointr = lptintr;
  430         unit = isdp->id_unit;
  431         sc = lpt_sc + unit;
  432         sc->sc_port = isdp->id_iobase;
  433         sc->sc_primed = 0;      /* not primed yet */
  434         outb(sc->sc_port+lpt_control, LPC_NINIT);
  435 
  436         /* check if we can use interrupt */
  437         lprintf(("oldirq %x\n", sc->sc_irq));
  438         if (isdp->id_irq) {
  439                 sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ;
  440                 printf("lpt%d: Interrupt-driven port\n", unit);
  441 #ifdef INET
  442                 lpattach(sc, unit);
  443 #endif
  444         } else {
  445                 sc->sc_irq = 0;
  446                 lprintf(("lpt%d: Polled port\n", unit));
  447         }
  448         lprintf(("irq %x\n", sc->sc_irq));
  449 
  450 #ifdef DEVFS
  451         /* XXX what to do about the flags in the minor number? */
  452         sc->devfs_token = devfs_add_devswf(&lpt_cdevsw,
  453                 unit, DV_CHR,
  454                 UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit);
  455         sc->devfs_token_ctl = devfs_add_devswf(&lpt_cdevsw,
  456                 unit | LP_BYPASS, DV_CHR,
  457                 UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);
  458 #endif
  459         printf("lpt%d: this driver is deprecated; use ppbus instead.\n");
  460         return (1);
  461 }
  462 
  463 /*
  464  * lptopen -- reset the printer, then wait until it's selected and not busy.
  465  *      If LP_BYPASS flag is selected, then we do not try to select the
  466  *      printer -- this is just used for passing ioctls.
  467  */
  468 
  469 static  int
  470 lptopen (dev_t dev, int flags, int fmt, struct proc *p)
  471 {
  472         struct lpt_softc *sc;
  473         int s;
  474         int trys, port;
  475         u_int unit = LPTUNIT(minor(dev));
  476 
  477         sc = lpt_sc + unit;
  478         if ((unit >= NLPT) || (sc->sc_port == 0))
  479                 return (ENXIO);
  480 
  481 #ifdef INET
  482         if (sc->sc_if.if_flags & IFF_UP)
  483                 return(EBUSY);
  484 #endif
  485 
  486         if (sc->sc_state) {
  487                 lprintf(("lp: still open %x\n", sc->sc_state));
  488                 return(EBUSY);
  489         } else
  490                 sc->sc_state |= INIT;
  491 
  492         sc->sc_flags = LPTFLAGS(minor(dev));
  493 
  494         /* Check for open with BYPASS flag set. */
  495         if (sc->sc_flags & LP_BYPASS) {
  496                 sc->sc_state = OPEN;
  497                 return(0);
  498         }
  499 
  500         s = spltty();
  501         lprintf(("lp flags 0x%x\n", sc->sc_flags));
  502         port = sc->sc_port;
  503 
  504         /* set IRQ status according to ENABLE_IRQ flag */
  505         if (sc->sc_irq & LP_ENABLE_IRQ)
  506                 sc->sc_irq |= LP_USE_IRQ;
  507         else
  508                 sc->sc_irq &= ~LP_USE_IRQ;
  509 
  510         /* init printer */
  511         if ((sc->sc_flags & LP_NO_PRIME) == 0) {
  512                 if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) {
  513                         outb(port+lpt_control, 0);
  514                         sc->sc_primed++;
  515                         DELAY(500);
  516                 }
  517         }
  518 
  519         outb (port+lpt_control, LPC_SEL|LPC_NINIT);
  520 
  521         /* wait till ready (printer running diagnostics) */
  522         trys = 0;
  523         do {
  524                 /* ran out of waiting for the printer */
  525                 if (trys++ >= LPINITRDY*4) {
  526                         splx(s);
  527                         sc->sc_state = 0;
  528                         lprintf(("status %x\n", inb(port+lpt_status)));
  529                         return (EBUSY);
  530                 }
  531 
  532                 /* wait 1/4 second, give up if we get a signal */
  533                 if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) !=
  534                     EWOULDBLOCK) {
  535                         sc->sc_state = 0;
  536                         splx(s);
  537                         return (EBUSY);
  538                 }
  539 
  540                 /* is printer online and ready for output */
  541         } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
  542                  (LPS_SEL|LPS_NBSY|LPS_NERR));
  543 
  544         sc->sc_control = LPC_SEL|LPC_NINIT;
  545         if (sc->sc_flags & LP_AUTOLF)
  546                 sc->sc_control |= LPC_AUTOL;
  547 
  548         /* enable interrupt if interrupt-driven */
  549         if (sc->sc_irq & LP_USE_IRQ)
  550                 sc->sc_control |= LPC_ENA;
  551 
  552         outb(port+lpt_control, sc->sc_control);
  553 
  554         sc->sc_state = OPEN;
  555         sc->sc_inbuf = geteblk(BUFSIZE);
  556         sc->sc_xfercnt = 0;
  557         splx(s);
  558 
  559         /* only use timeout if using interrupt */
  560         lprintf(("irq %x\n", sc->sc_irq));
  561         if (sc->sc_irq & LP_USE_IRQ) {
  562                 sc->sc_state |= TOUT;
  563                 timeout (lptout, (caddr_t)sc,
  564                          (sc->sc_backoff = hz/LPTOUTINITIAL));
  565         }
  566 
  567         lprintf(("opened.\n"));
  568         return(0);
  569 }
  570 
  571 static void
  572 lptout (void *arg)
  573 {
  574         struct lpt_softc *sc = arg;
  575         int pl;
  576 
  577         lprintf(("T %x ", inb(sc->sc_port+lpt_status)));
  578         if (sc->sc_state & OPEN) {
  579                 sc->sc_backoff++;
  580                 if (sc->sc_backoff > hz/LPTOUTMAX)
  581                         sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX;
  582                 timeout (lptout, (caddr_t)sc, sc->sc_backoff);
  583         } else
  584                 sc->sc_state &= ~TOUT;
  585 
  586         if (sc->sc_state & ERROR)
  587                 sc->sc_state &= ~ERROR;
  588 
  589         /*
  590          * Avoid possible hangs do to missed interrupts
  591          */
  592         if (sc->sc_xfercnt) {
  593                 pl = spltty();
  594                 lptintr(sc - lpt_sc);
  595                 splx(pl);
  596         } else {
  597                 sc->sc_state &= ~OBUSY;
  598                 wakeup((caddr_t)sc);
  599         }
  600 }
  601 
  602 /*
  603  * lptclose -- close the device, free the local line buffer.
  604  *
  605  * Check for interrupted write call added.
  606  */
  607 
  608 static  int
  609 lptclose(dev_t dev, int flags, int fmt, struct proc *p)
  610 {
  611         struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
  612         int port = sc->sc_port;
  613 
  614         if(sc->sc_flags & LP_BYPASS)
  615                 goto end_close;
  616 
  617         sc->sc_state &= ~OPEN;
  618 
  619         /* if the last write was interrupted, don't complete it */
  620         if((!(sc->sc_state  & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ))
  621                 while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) !=
  622                         (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt)
  623                         /* wait 1/4 second, give up if we get a signal */
  624                         if (tsleep ((caddr_t)sc, LPPRI|PCATCH,
  625                                 "lpclose", hz) != EWOULDBLOCK)
  626                                 break;
  627 
  628         outb(sc->sc_port+lpt_control, LPC_NINIT);
  629         brelse(sc->sc_inbuf);
  630 
  631 end_close:
  632         sc->sc_state = 0;
  633         sc->sc_xfercnt = 0;
  634         lprintf(("closed.\n"));
  635         return(0);
  636 }
  637 
  638 /*
  639  * pushbytes()
  640  *      Workhorse for actually spinning and writing bytes to printer
  641  *      Derived from lpa.c
  642  *      Originally by ?
  643  *
  644  *      This code is only used when we are polling the port
  645  */
  646 static int
  647 pushbytes(struct lpt_softc * sc)
  648 {
  649         int spin, err, tic;
  650         char ch;
  651         int port = sc->sc_port;
  652 
  653         lprintf(("p"));
  654         /* loop for every character .. */
  655         while (sc->sc_xfercnt > 0) {
  656                 /* printer data */
  657                 ch = *(sc->sc_cp);
  658                 sc->sc_cp++;
  659                 sc->sc_xfercnt--;
  660 
  661                 /*
  662                  * Wait for printer ready.
  663                  * Loop 20 usecs testing BUSY bit, then sleep
  664                  * for exponentially increasing timeout. (vak)
  665                  */
  666                 for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin)
  667                         DELAY(1);       /* XXX delay is NOT this accurate! */
  668                 if (spin >= MAX_SPIN) {
  669                         tic = 0;
  670                         while (NOT_READY(port+lpt_status)) {
  671                                 /*
  672                                  * Now sleep, every cycle a
  673                                  * little longer ..
  674                                  */
  675                                 tic = tic + tic + 1;
  676                                 /*
  677                                  * But no more than 10 seconds. (vak)
  678                                  */
  679                                 if (tic > MAX_SLEEP)
  680                                         tic = MAX_SLEEP;
  681                                 err = tsleep((caddr_t)sc, LPPRI,
  682                                         "lptpoll", tic);
  683                                 if (err != EWOULDBLOCK) {
  684                                         return (err);
  685                                 }
  686                         }
  687                 }
  688 
  689                 /* output data */
  690                 outb(port+lpt_data, ch);
  691                 /* strobe */
  692                 outb(port+lpt_control, sc->sc_control|LPC_STB);
  693                 outb(port+lpt_control, sc->sc_control);
  694 
  695         }
  696         return(0);
  697 }
  698 
  699 /*
  700  * lptwrite --copy a line from user space to a local buffer, then call
  701  * putc to get the chars moved to the output queue.
  702  *
  703  * Flagging of interrupted write added.
  704  */
  705 
  706 static  int
  707 lptwrite(dev_t dev, struct uio * uio, int ioflag)
  708 {
  709         register unsigned n;
  710         int pl, err;
  711         struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev));
  712 
  713         if(sc->sc_flags & LP_BYPASS) {
  714                 /* we can't do writes in bypass mode */
  715                 return(EPERM);
  716         }
  717 
  718         sc->sc_state &= ~INTERRUPTED;
  719         while ((n = min(BUFSIZE, uio->uio_resid)) != 0) {
  720                 sc->sc_cp = sc->sc_inbuf->b_data ;
  721                 uiomove(sc->sc_cp, n, uio);
  722                 sc->sc_xfercnt = n ;
  723                 while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) {
  724                         lprintf(("i"));
  725                         /* if the printer is ready for a char, */
  726                         /* give it one */
  727                         if ((sc->sc_state & OBUSY) == 0){
  728                                 lprintf(("\nC %d. ", sc->sc_xfercnt));
  729                                 pl = spltty();
  730                                 lptintr(sc - lpt_sc);
  731                                 (void) splx(pl);
  732                         }
  733                         lprintf(("W "));
  734                         if (sc->sc_state & OBUSY)
  735                                 if ((err = tsleep ((caddr_t)sc,
  736                                          LPPRI|PCATCH, "lpwrite", 0))) {
  737                                         sc->sc_state |= INTERRUPTED;
  738                                         return(err);
  739                                 }
  740                 }
  741                 /* check to see if we must do a polled write */
  742                 if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) {
  743                         lprintf(("p"));
  744                         if((err = pushbytes(sc)))
  745                                 return(err);
  746                 }
  747         }
  748         return(0);
  749 }
  750 
  751 /*
  752  * lptintr -- handle printer interrupts which occur when the printer is
  753  * ready to accept another char.
  754  *
  755  * do checking for interrupted write call.
  756  */
  757 
  758 static void
  759 lptintr(int unit)
  760 {
  761         struct lpt_softc *sc = lpt_sc + unit;
  762         int port = sc->sc_port, sts;
  763         int i;
  764 
  765 #ifdef INET
  766         if(sc->sc_if.if_flags & IFF_UP) {
  767             lpintr(unit);
  768             return;
  769         }
  770 #endif /* INET */
  771 
  772         /*
  773          * Is printer online and ready for output?
  774          *
  775          * Avoid falling back to lptout() too quickly.  First spin-loop
  776          * to see if the printer will become ready ``really soon now''.
  777          */
  778         for (i = 0;
  779              i < 100 &&
  780              ((sts=inb(port+lpt_status)) & RDY_MASK) != LP_READY;
  781              i++) ;
  782         if ((sts & RDY_MASK) == LP_READY) {
  783                 sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR;
  784                 sc->sc_backoff = hz/LPTOUTINITIAL;
  785 
  786                 if (sc->sc_xfercnt) {
  787                         /* send char */
  788                         /*lprintf(("%x ", *sc->sc_cp)); */
  789                         outb(port+lpt_data, *sc->sc_cp++) ;
  790                         outb(port+lpt_control, sc->sc_control|LPC_STB);
  791                         /* DELAY(X) */
  792                         outb(port+lpt_control, sc->sc_control);
  793 
  794                         /* any more data for printer */
  795                         if(--(sc->sc_xfercnt) > 0) return;
  796                 }
  797 
  798                 /*
  799                  * No more data waiting for printer.
  800                  * Wakeup is not done if write call was interrupted.
  801                  */
  802                 sc->sc_state &= ~OBUSY;
  803                 if(!(sc->sc_state & INTERRUPTED))
  804                         wakeup((caddr_t)sc);
  805                 lprintf(("w "));
  806                 return;
  807         } else  {       /* check for error */
  808                 if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) &&
  809                                 (sc->sc_state & OPEN))
  810                         sc->sc_state |= ERROR;
  811                 /* lptout() will jump in and try to restart. */
  812         }
  813         lprintf(("sts %x ", sts));
  814 }
  815 
  816 static  int
  817 lptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
  818 {
  819         int     error = 0;
  820         struct  lpt_softc *sc;
  821         u_int   unit = LPTUNIT(minor(dev));
  822         u_char  old_sc_irq;     /* old printer IRQ status */
  823 
  824         sc = lpt_sc + unit;
  825 
  826         switch (cmd) {
  827         case LPT_IRQ :
  828                 if(sc->sc_irq & LP_HAS_IRQ) {
  829                         /*
  830                          * NOTE:
  831                          * If the IRQ status is changed,
  832                          * this will only be visible on the
  833                          * next open.
  834                          *
  835                          * If interrupt status changes,
  836                          * this gets syslog'd.
  837                          */
  838                         old_sc_irq = sc->sc_irq;
  839                         if(*(int*)data == 0)
  840                                 sc->sc_irq &= (~LP_ENABLE_IRQ);
  841                         else
  842                                 sc->sc_irq |= LP_ENABLE_IRQ;
  843                         if (old_sc_irq != sc->sc_irq )
  844                                 log(LOG_NOTICE, "lpt%c switched to %s mode\n",
  845                                         (char)unit+'',
  846                                         (sc->sc_irq & LP_ENABLE_IRQ)?
  847                                         "interrupt-driven":"polled");
  848                 } else /* polled port */
  849                         error = EOPNOTSUPP;
  850                 break;
  851         default:
  852                 error = ENODEV;
  853         }
  854 
  855         return(error);
  856 }
  857 
  858 #ifdef INET
  859 
  860 static void
  861 lpattach (struct lpt_softc *sc, int unit)
  862 {
  863         struct ifnet *ifp = &sc->sc_if;
  864 
  865         ifp->if_softc = sc;
  866         ifp->if_name = "lp";
  867         ifp->if_unit = unit;
  868         ifp->if_mtu = LPMTU;
  869         ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
  870         ifp->if_ioctl = lpioctl;
  871         ifp->if_output = lpoutput;
  872         ifp->if_type = IFT_PARA;
  873         ifp->if_hdrlen = 0;
  874         ifp->if_addrlen = 0;
  875         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  876         if_attach(ifp);
  877         printf("lp%d: TCP/IP capable interface\n", unit);
  878 
  879 #if NBPFILTER > 0
  880         bpfattach(ifp, DLT_NULL, LPIPHDRLEN);
  881 #endif
  882 }
  883 /*
  884  * Build the translation tables for the LPIP (BSD unix) protocol.
  885  * We don't want to calculate these nasties in our tight loop, so we
  886  * precalculate them when we initialize.
  887  */
  888 static int
  889 lpinittables (void)
  890 {
  891     int i;
  892 
  893     if (!txmith)
  894         txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  895 
  896     if (!txmith)
  897         return 1;
  898 
  899     if (!ctxmith)
  900         ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT);
  901 
  902     if (!ctxmith)
  903         return 1;
  904 
  905     for (i=0; i < LPIPTBLSIZE; i++) {
  906         ctxmith[i] = (i & 0xF0) >> 4;
  907         ctxmitl[i] = 0x10 | (i & 0x0F);
  908         ctrecvh[i] = (i & 0x78) << 1;
  909         ctrecvl[i] = (i & 0x78) >> 3;
  910     }
  911 
  912     for (i=0; i < LPIPTBLSIZE; i++) {
  913         txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08;
  914         txmitl[i] = ((i & 0x08) << 1) | (i & 0x07);
  915         trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1);
  916         trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3);
  917     }
  918 
  919     return 0;
  920 }
  921 
  922 /*
  923  * Process an ioctl request.
  924  */
  925 
  926 static int
  927 lpioctl (struct ifnet *ifp, u_long cmd, caddr_t data)
  928 {
  929     struct lpt_softc *sc = lpt_sc + ifp->if_unit;
  930     struct ifaddr *ifa = (struct ifaddr *)data;
  931     struct ifreq *ifr = (struct ifreq *)data;
  932     u_char *ptr;
  933 
  934     switch (cmd) {
  935 
  936     case SIOCSIFDSTADDR:
  937     case SIOCAIFADDR:
  938     case SIOCSIFADDR:
  939         if (ifa->ifa_addr->sa_family != AF_INET)
  940             return EAFNOSUPPORT;
  941         ifp->if_flags |= IFF_UP;
  942         /* FALLTHROUGH */
  943     case SIOCSIFFLAGS:
  944         if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) {
  945             outb(sc->sc_port + lpt_control, 0x00);
  946             ifp->if_flags &= ~IFF_RUNNING;
  947             break;
  948         }
  949         if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) {
  950             if (lpinittables())
  951                 return ENOBUFS;
  952             sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN,
  953                                   M_DEVBUF, M_WAITOK);
  954             if (!sc->sc_ifbuf)
  955                 return ENOBUFS;
  956 
  957             outb(sc->sc_port + lpt_control, LPC_ENA);
  958             ifp->if_flags |= IFF_RUNNING;
  959         }
  960         break;
  961 
  962     case SIOCSIFMTU:
  963         ptr = sc->sc_ifbuf;
  964         sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT);
  965         if (!sc->sc_ifbuf) {
  966             sc->sc_ifbuf = ptr;
  967             return ENOBUFS;
  968         }
  969         if (ptr)
  970             free(ptr,M_DEVBUF);
  971         sc->sc_if.if_mtu = ifr->ifr_mtu;
  972         break;
  973 
  974     case SIOCGIFMTU:
  975         ifr->ifr_mtu = sc->sc_if.if_mtu;
  976         break;
  977 
  978     case SIOCADDMULTI:
  979     case SIOCDELMULTI:
  980         if (ifr == 0) {
  981             return EAFNOSUPPORT;                /* XXX */
  982         }
  983         switch (ifr->ifr_addr.sa_family) {
  984 
  985 #ifdef INET
  986         case AF_INET:
  987             break;
  988 #endif
  989 
  990         default:
  991             return EAFNOSUPPORT;
  992         }
  993         break;
  994 
  995     default:
  996         lprintf(("LP:ioctl(0x%lx)\n", cmd));
  997         return EINVAL;
  998     }
  999     return 0;
 1000 }
 1001 
 1002 static __inline int
 1003 clpoutbyte (u_char byte, int spin, int data_port, int status_port)
 1004 {
 1005         outb(data_port, ctxmitl[byte]);
 1006         while (inb(status_port) & CLPIP_SHAKE)
 1007                 if (--spin == 0) {
 1008                         return 1;
 1009                 }
 1010         outb(data_port, ctxmith[byte]);
 1011         while (!(inb(status_port) & CLPIP_SHAKE))
 1012                 if (--spin == 0) {
 1013                         return 1;
 1014                 }
 1015         return 0;
 1016 }
 1017 
 1018 static __inline int
 1019 clpinbyte (int spin, int data_port, int status_port)
 1020 {
 1021         int c, cl;
 1022 
 1023         while((inb(status_port) & CLPIP_SHAKE))
 1024             if(!--spin) {
 1025                 return -1;
 1026             }
 1027         cl = inb(status_port);
 1028         outb(data_port, 0x10);
 1029 
 1030         while(!(inb(status_port) & CLPIP_SHAKE))
 1031             if(!--spin) {
 1032                 return -1;
 1033             }
 1034         c = inb(status_port);
 1035         outb(data_port, 0x00);
 1036 
 1037         return (ctrecvl[cl] | ctrecvh[c]);
 1038 }
 1039 
 1040 static void
 1041 lpintr (int unit)
 1042 {
 1043         struct   lpt_softc *sc = lpt_sc + unit;
 1044         register int lpt_data_port = sc->sc_port + lpt_data;
 1045         register int lpt_stat_port = sc->sc_port + lpt_status;
 1046                  int lpt_ctrl_port = sc->sc_port + lpt_control;
 1047         int len, s, j;
 1048         u_char *bp;
 1049         u_char c, cl;
 1050         struct mbuf *top;
 1051 
 1052         s = splhigh();
 1053 
 1054         if (sc->sc_if.if_flags & IFF_LINK0) {
 1055 
 1056             /* Ack. the request */
 1057             outb(lpt_data_port, 0x01);
 1058 
 1059             /* Get the packet length */
 1060             j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
 1061             if (j == -1)
 1062                 goto err;
 1063             len = j;
 1064             j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
 1065             if (j == -1)
 1066                 goto err;
 1067             len = len + (j << 8);
 1068             if (len > sc->sc_if.if_mtu + MLPIPHDRLEN)
 1069                 goto err;
 1070 
 1071             bp  = sc->sc_ifbuf;
 1072         
 1073             while (len--) {
 1074                 j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
 1075                 if (j == -1) {
 1076                     goto err;
 1077                 }
 1078                 *bp++ = j;
 1079             }
 1080             /* Get and ignore checksum */
 1081             j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port);
 1082             if (j == -1) {
 1083                 goto err;
 1084             }
 1085 
 1086             len = bp - sc->sc_ifbuf;
 1087             if (len <= CLPIPHDRLEN)
 1088                 goto err;
 1089 
 1090             sc->sc_iferrs = 0;
 1091 
 1092             if (IF_QFULL(&ipintrq)) {
 1093                 lprintf(("DROP"));
 1094                 IF_DROP(&ipintrq);
 1095                 goto done;
 1096             }
 1097             len -= CLPIPHDRLEN;
 1098             sc->sc_if.if_ipackets++;
 1099             sc->sc_if.if_ibytes += len;
 1100             top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0);
 1101             if (top) {
 1102                 IF_ENQUEUE(&ipintrq, top);
 1103                 schednetisr(NETISR_IP);
 1104             }
 1105             goto done;
 1106         }
 1107         while ((inb(lpt_stat_port) & LPIP_SHAKE)) {
 1108             len = sc->sc_if.if_mtu + LPIPHDRLEN;
 1109             bp  = sc->sc_ifbuf;
 1110             while (len--) {
 1111 
 1112                 cl = inb(lpt_stat_port);
 1113                 outb(lpt_data_port, 8);
 1114 
 1115                 j = LPMAXSPIN2;
 1116                 while((inb(lpt_stat_port) & LPIP_SHAKE))
 1117                     if(!--j) goto err;
 1118 
 1119                 c = inb(lpt_stat_port);
 1120                 outb(lpt_data_port, 0);
 1121 
 1122                 *bp++= trecvh[cl] | trecvl[c];
 1123 
 1124                 j = LPMAXSPIN2;
 1125                 while (!((cl=inb(lpt_stat_port)) & LPIP_SHAKE)) {
 1126                     if (cl != c &&
 1127                         (((cl = inb(lpt_stat_port)) ^ 0xb8) & 0xf8) ==
 1128                           (c & 0xf8))
 1129                         goto end;
 1130                     if (!--j) goto err;
 1131                 }
 1132             }
 1133 
 1134         end:
 1135             len = bp - sc->sc_ifbuf;
 1136             if (len <= LPIPHDRLEN)
 1137                 goto err;
 1138 
 1139             sc->sc_iferrs = 0;
 1140 
 1141             if (IF_QFULL(&ipintrq)) {
 1142                 lprintf(("DROP"));
 1143                 IF_DROP(&ipintrq);
 1144                 goto done;
 1145             }
 1146 #if NBPFILTER > 0
 1147             if (sc->sc_if.if_bpf) {
 1148                 bpf_tap(&sc->sc_if, sc->sc_ifbuf, len);
 1149             }
 1150 #endif
 1151             len -= LPIPHDRLEN;
 1152             sc->sc_if.if_ipackets++;
 1153             sc->sc_if.if_ibytes += len;
 1154             top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0);
 1155             if (top) {
 1156                     IF_ENQUEUE(&ipintrq, top);
 1157                     schednetisr(NETISR_IP);
 1158             }
 1159         }
 1160         goto done;
 1161 
 1162     err:
 1163         outb(lpt_data_port, 0);
 1164         lprintf(("R"));
 1165         sc->sc_if.if_ierrors++;
 1166         sc->sc_iferrs++;
 1167 
 1168         /*
 1169          * We are not able to send receive anything for now,
 1170          * so stop wasting our time
 1171          */
 1172         if (sc->sc_iferrs > LPMAXERRS) {
 1173             printf("lp%d: Too many errors, Going off-line.\n", unit);
 1174             outb(lpt_ctrl_port, 0x00);
 1175             sc->sc_if.if_flags &= ~IFF_RUNNING;
 1176             sc->sc_iferrs=0;
 1177         }
 1178 
 1179     done:
 1180         splx(s);
 1181         return;
 1182 }
 1183 
 1184 static __inline int
 1185 lpoutbyte (u_char byte, int spin, int data_port, int status_port)
 1186 {
 1187     outb(data_port, txmith[byte]);
 1188     while (!(inb(status_port) & LPIP_SHAKE))
 1189         if (--spin == 0)
 1190                 return 1;
 1191     outb(data_port, txmitl[byte]);
 1192     while (inb(status_port) & LPIP_SHAKE)
 1193         if (--spin == 0)
 1194                 return 1;
 1195     return 0;
 1196 }
 1197 
 1198 static int
 1199 lpoutput (struct ifnet *ifp, struct mbuf *m,
 1200           struct sockaddr *dst, struct rtentry *rt)
 1201 {
 1202     register int lpt_data_port = lpt_sc[ifp->if_unit].sc_port + lpt_data;
 1203     register int lpt_stat_port = lpt_sc[ifp->if_unit].sc_port + lpt_status;
 1204              int lpt_ctrl_port = lpt_sc[ifp->if_unit].sc_port + lpt_control;
 1205 
 1206     int s, err;
 1207     struct mbuf *mm;
 1208     u_char *cp = "\0\0";
 1209     u_char chksum = 0;
 1210     int count = 0;
 1211     int i;
 1212     int spin;
 1213 
 1214     /* We need a sensible value if we abort */
 1215     cp++;
 1216     ifp->if_flags |= IFF_RUNNING;
 1217 
 1218     err = 1;                    /* assume we're aborting because of an error */
 1219 
 1220     s = splhigh();
 1221 
 1222     /* Suspend (on laptops) or receive-errors might have taken us offline */
 1223     outb(lpt_ctrl_port, LPC_ENA);
 1224 
 1225     if (ifp->if_flags & IFF_LINK0) {
 1226 
 1227         if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) {
 1228             lprintf(("&"));
 1229             lptintr(ifp->if_unit);
 1230         }
 1231 
 1232         /* Alert other end to pending packet */
 1233         spin = LPMAXSPIN1;
 1234         outb(lpt_data_port, 0x08);
 1235         while ((inb(lpt_stat_port) & 0x08) == 0)
 1236                 if (--spin == 0) {
 1237                         goto nend;
 1238                 }
 1239 
 1240         /* Calculate length of packet, then send that */
 1241 
 1242         count += 14;            /* Ethernet header len */
 1243 
 1244         mm = m;
 1245         for (mm = m; mm; mm = mm->m_next) {
 1246                 count += mm->m_len;
 1247         }
 1248         if (clpoutbyte(count & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
 1249                 goto nend;
 1250         if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
 1251                 goto nend;
 1252 
 1253         /* Send dummy ethernet header */
 1254         for (i = 0; i < 12; i++) {
 1255                 if (clpoutbyte(i, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
 1256                         goto nend;
 1257                 chksum += i;
 1258         }
 1259 
 1260         if (clpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
 1261                 goto nend;
 1262         if (clpoutbyte(0x00, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
 1263                 goto nend;
 1264         chksum += 0x08 + 0x00;          /* Add into checksum */
 1265 
 1266         mm = m;
 1267         do {
 1268                 cp = mtod(mm, u_char *);
 1269                 while (mm->m_len--) {
 1270                         chksum += *cp;
 1271                         if (clpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
 1272                                 goto nend;
 1273                 }
 1274         } while ((mm = mm->m_next));
 1275 
 1276         /* Send checksum */
 1277         if (clpoutbyte(chksum, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
 1278                 goto nend;
 1279 
 1280         /* Go quiescent */
 1281         outb(lpt_data_port, 0);
 1282 
 1283         err = 0;                        /* No errors */
 1284 
 1285         nend:
 1286         if (err)  {                             /* if we didn't timeout... */
 1287                 ifp->if_oerrors++;
 1288                 lprintf(("X"));
 1289         } else {
 1290                 ifp->if_opackets++;
 1291                 ifp->if_obytes += m->m_pkthdr.len;
 1292         }
 1293 
 1294         m_freem(m);
 1295 
 1296         if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) {
 1297                 lprintf(("^"));
 1298                 lptintr(ifp->if_unit);
 1299         }
 1300         (void) splx(s);
 1301         return 0;
 1302     }
 1303 
 1304     if (inb(lpt_stat_port) & LPIP_SHAKE) {
 1305         lprintf(("&"));
 1306         lptintr(ifp->if_unit);
 1307     }
 1308 
 1309     if (lpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port))
 1310         goto end;
 1311     if (lpoutbyte(0x00, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
 1312         goto end;
 1313 
 1314     mm = m;
 1315     do {
 1316         cp = mtod(mm,u_char *);
 1317         while (mm->m_len--)
 1318             if (lpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port))
 1319                 goto end;
 1320     } while ((mm = mm->m_next));
 1321 
 1322     err = 0;                            /* no errors were encountered */
 1323 
 1324     end:
 1325     --cp;
 1326     outb(lpt_data_port, txmitl[*cp] ^ 0x17);
 1327 
 1328     if (err)  {                         /* if we didn't timeout... */
 1329         ifp->if_oerrors++;
 1330         lprintf(("X"));
 1331     } else {
 1332         ifp->if_opackets++;
 1333         ifp->if_obytes += m->m_pkthdr.len;
 1334 #if NBPFILTER > 0
 1335         if (ifp->if_bpf) {
 1336             /*
 1337              * We need to prepend the packet type as
 1338              * a two byte field.  Cons up a dummy header
 1339              * to pacify bpf.  This is safe because bpf
 1340              * will only read from the mbuf (i.e., it won't
 1341              * try to free it or keep a pointer to it).
 1342              */
 1343             struct mbuf m0;
 1344             u_short hdr = 0x800;
 1345 
 1346             m0.m_next = m;
 1347             m0.m_len = 2;
 1348             m0.m_data = (char *)&hdr;
 1349 
 1350             bpf_mtap(ifp, &m0);
 1351         }
 1352 #endif
 1353     }
 1354 
 1355     m_freem(m);
 1356 
 1357     if (inb(lpt_stat_port) & LPIP_SHAKE) {
 1358         lprintf(("^"));
 1359         lptintr(ifp->if_unit);
 1360     }
 1361 
 1362     (void) splx(s);
 1363     return 0;
 1364 }
 1365 
 1366 #endif /* INET */
 1367 
 1368 static lpt_devsw_installed = 0;
 1369 
 1370 static void     lpt_drvinit(void *unused)
 1371 {
 1372         dev_t dev;
 1373 
 1374         if( ! lpt_devsw_installed ) {
 1375                 dev = makedev(CDEV_MAJOR, 0);
 1376                 cdevsw_add(&dev,&lpt_cdevsw, NULL);
 1377                 lpt_devsw_installed = 1;
 1378         }
 1379 }
 1380 
 1381 SYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL)
 1382 

Cache object: 8538693db1a2701401fa6f1144770b48


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