olpt.c revision 50436
1155192Srwatson/* 2155192Srwatson * Copyright (c) 1990 William F. Jolitz, TeleMuse 3155192Srwatson * All rights reserved. 4155192Srwatson * 5155192Srwatson * Redistribution and use in source and binary forms, with or without 6155192Srwatson * modification, are permitted provided that the following conditions 7155192Srwatson * are met: 8155192Srwatson * 1. Redistributions of source code must retain the above copyright 9155192Srwatson * notice, this list of conditions and the following disclaimer. 10155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11155192Srwatson * notice, this list of conditions and the following disclaimer in the 12155192Srwatson * documentation and/or other materials provided with the distribution. 13155192Srwatson * 3. All advertising materials mentioning features or use of this software 14155192Srwatson * must display the following acknowledgement: 15155192Srwatson * This software is a component of "386BSD" developed by 16155192Srwatson * William F. Jolitz, TeleMuse. 17155192Srwatson * 4. Neither the name of the developer nor the name "386BSD" 18155192Srwatson * may be used to endorse or promote products derived from this software 19155192Srwatson * without specific prior written permission. 20155192Srwatson * 21155192Srwatson * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 22155192Srwatson * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 23155192Srwatson * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 24155192Srwatson * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 25155192Srwatson * NOT MAKE USE OF THIS WORK. 26155192Srwatson * 27155192Srwatson * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 28155192Srwatson * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 29155192Srwatson * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 30155192Srwatson * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 31155192Srwatson * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 32155192Srwatson * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 33155192Srwatson * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 34155192Srwatson * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 35155192Srwatson * 36155192Srwatson * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 37155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 38155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 39160136Swsalamon * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 40155192Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 41155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 42155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 44155192Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 45155192Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 46155192Srwatson * SUCH DAMAGE. 47155192Srwatson * 48155192Srwatson * from: unknown origin, 386BSD 0.1 49155192Srwatson * $Id: olpt.c,v 1.2 1999/07/06 19:23:20 des Exp $ 50155192Srwatson */ 51155192Srwatson 52155192Srwatson/* 53155192Srwatson * Device Driver for AT parallel printer port 54155192Srwatson * Written by William Jolitz 12/18/90 55155192Srwatson */ 56155192Srwatson 57155192Srwatson/* 58155192Srwatson * Parallel port TCP/IP interfaces added. I looked at the driver from 59155192Srwatson * MACH but this is a complete rewrite, and btw. incompatible, and it 60155192Srwatson * should perform better too. I have never run the MACH driver though. 61155192Srwatson * 62155192Srwatson * This driver sends two bytes (0x08, 0x00) in front of each packet, 63155192Srwatson * to allow us to distinguish another format later. 64155192Srwatson * 65155192Srwatson * Now added an Linux/Crynwr compatibility mode which is enabled using 66155192Srwatson * IF_LINK0 - Tim Wilkinson. 67155192Srwatson * 68155192Srwatson * TODO: 69155192Srwatson * Make HDLC/PPP mode, use IF_LLC1 to enable. 70155192Srwatson * 71155192Srwatson * Connect the two computers using a Laplink parallel cable to use this 72156889Srwatson * feature: 73156889Srwatson * 74156889Srwatson * +----------------------------------------+ 75156889Srwatson * |A-name A-End B-End Descr. Port/Bit | 76156889Srwatson * +----------------------------------------+ 77156889Srwatson * |DATA0 2 15 Data 0/0x01 | 78155192Srwatson * |-ERROR 15 2 1/0x08 | 79156889Srwatson * +----------------------------------------+ 80155192Srwatson * |DATA1 3 13 Data 0/0x02 | 81156889Srwatson * |+SLCT 13 3 1/0x10 | 82155192Srwatson * +----------------------------------------+ 83162466Srwatson * |DATA2 4 12 Data 0/0x04 | 84155192Srwatson * |+PE 12 4 1/0x20 | 85155192Srwatson * +----------------------------------------+ 86155192Srwatson * |DATA3 5 10 Strobe 0/0x08 | 87155192Srwatson * |-ACK 10 5 1/0x40 | 88155192Srwatson * +----------------------------------------+ 89155192Srwatson * |DATA4 6 11 Data 0/0x10 | 90155192Srwatson * |BUSY 11 6 1/~0x80 | 91155192Srwatson * +----------------------------------------+ 92155192Srwatson * |GND 18-25 18-25 GND - | 93156889Srwatson * +----------------------------------------+ 94155192Srwatson * 95155192Srwatson * Expect transfer-rates up to 75 kbyte/sec. 96155192Srwatson * 97155192Srwatson * If GCC could correctly grok 98155192Srwatson * register int port asm("edx") 99155192Srwatson * the code would be cleaner 100155192Srwatson * 101155192Srwatson * Poul-Henning Kamp <phk@freebsd.org> 102155192Srwatson */ 103155192Srwatson 104155192Srwatson#include "olpt.h" 105155192Srwatson#include "opt_inet.h" 106155192Srwatson#ifdef PC98 107155192Srwatson#undef INET /* PLIP is not supported for old PC-98 */ 108155192Srwatson#endif 109155192Srwatson 110155192Srwatson#include <sys/param.h> 111155192Srwatson#include <sys/systm.h> 112155192Srwatson#include <sys/conf.h> 113155192Srwatson#include <sys/buf.h> 114155192Srwatson#include <sys/kernel.h> 115156889Srwatson#include <sys/uio.h> 116161635Srwatson#include <sys/syslog.h> 117162466Srwatson#include <machine/clock.h> 118170196Srwatson#include <machine/lpt.h> 119162466Srwatson 120162466Srwatson#include <vm/vm.h> 121162466Srwatson#include <vm/vm_param.h> 122162466Srwatson#include <vm/pmap.h> 123155192Srwatson 124162466Srwatson#ifdef PC98 125162466Srwatson#include <pc98/pc98/pc98.h> 126155192Srwatson#else 127162466Srwatson#include <i386/isa/isa.h> 128162466Srwatson#endif 129162466Srwatson#include <i386/isa/isa_device.h> 130162466Srwatson#include <i386/isa/lptreg.h> 131162466Srwatson 132155192Srwatson#ifdef INET 133155192Srwatson#include <sys/malloc.h> 134155192Srwatson#include <sys/mbuf.h> 135155192Srwatson#include <sys/socket.h> 136156889Srwatson#include <sys/sockio.h> 137156889Srwatson 138155192Srwatson#include <net/if.h> 139155192Srwatson#include <net/if_types.h> 140155192Srwatson#include <net/netisr.h> 141155192Srwatson#include <netinet/in.h> 142155192Srwatson#include <netinet/in_var.h> 143155192Srwatson#include "bpf.h" 144156889Srwatson#if NBPF > 0 145155192Srwatson#include <net/bpf.h> 146155192Srwatson#endif 147155192Srwatson#endif /* INET */ 148155192Srwatson 149156889Srwatson 150155192Srwatson#define LPINITRDY 4 /* wait up to 4 seconds for a ready */ 151155192Srwatson#define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */ 152156889Srwatson#define LPTOUTMAX 1 /* maximal timeout 1 s */ 153155192Srwatson#define LPPRI (PZERO+8) 154155192Srwatson#define BUFSIZE 1024 155155192Srwatson 156155192Srwatson#ifdef INET 157155192Srwatson#ifndef LPMTU /* MTU for the lp# interfaces */ 158170196Srwatson#define LPMTU 1500 159155192Srwatson#endif 160155192Srwatson 161155192Srwatson#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 162155192Srwatson#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 163155192Srwatson#endif 164155192Srwatson 165155192Srwatson#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 166155192Srwatson#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 167155192Srwatson#endif 168155192Srwatson 169155192Srwatson#ifndef LPMAXERRS /* Max errors before !RUNNING */ 170155192Srwatson#define LPMAXERRS 100 171155192Srwatson#endif 172155192Srwatson 173155192Srwatson#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 174155192Srwatson#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 175155192Srwatson#define MLPIPHDRLEN CLPIPHDRLEN 176155192Srwatson 177155192Srwatson#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 178155192Srwatson#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 179155192Srwatson#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 180155192Srwatson#define MLPIPHDRLEN LPIPHDRLEN 181155192Srwatson#endif 182155192Srwatson 183155192Srwatson#define LPIPTBLSIZE 256 /* Size of octet translation table */ 184155192Srwatson 185155192Srwatson#endif /* INET */ 186155192Srwatson 187155192Srwatson#ifndef PC98 188155192Srwatson/* BIOS printer list - used by BIOS probe*/ 189155192Srwatson#define BIOS_LPT_PORTS 0x408 190155192Srwatson#define BIOS_PORTS (short *)(KERNBASE+BIOS_LPT_PORTS) 191155192Srwatson#define BIOS_MAX_LPT 4 192155192Srwatson#endif 193155192Srwatson 194155192Srwatson 195155192Srwatson#ifndef DEBUG 196155192Srwatson#define lprintf(args) 197155192Srwatson#else 198155192Srwatson#define lprintf(args) do { \ 199155192Srwatson if (lptflag) \ 200155192Srwatson printf args; \ 201155192Srwatson } while (0) 202155192Srwatsonstatic int volatile lptflag = 1; 203155192Srwatson#endif 204155192Srwatson 205155192Srwatson#define LPTUNIT(s) ((s)&0x03) 206155192Srwatson#define LPTFLAGS(s) ((s)&0xfc) 207155192Srwatson 208155192Srwatsonstatic struct lpt_softc { 209155192Srwatson int sc_port; 210155192Srwatson short sc_state; 211155192Srwatson /* default case: negative prime, negative ack, handshake strobe, 212156889Srwatson prime once */ 213156889Srwatson u_char sc_control; 214155192Srwatson char sc_flags; 215155192Srwatson#define LP_POS_INIT 0x04 /* if we are a postive init signal */ 216155192Srwatson#define LP_POS_ACK 0x08 /* if we are a positive going ack */ 217155192Srwatson#define LP_NO_PRIME 0x10 /* don't prime the printer at all */ 218155192Srwatson#define LP_PRIMEOPEN 0x20 /* prime on every open */ 219155192Srwatson#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */ 220159277Srwatson#define LP_BYPASS 0x80 /* bypass printer ready checks */ 221159277Srwatson struct buf *sc_inbuf; 222172915Scsjp short sc_xfercnt ; 223159277Srwatson char sc_primed; 224159277Srwatson char *sc_cp ; 225159277Srwatson u_char sc_irq ; /* IRQ status of port */ 226172915Scsjp#define LP_HAS_IRQ 0x01 /* we have an irq available */ 227159277Srwatson#define LP_USE_IRQ 0x02 /* we are using our irq */ 228159277Srwatson#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ 229159277Srwatson u_char sc_backoff ; /* time to call lptout() again */ 230159277Srwatson 231155192Srwatson#ifdef INET 232155192Srwatson struct ifnet sc_if; 233155192Srwatson u_char *sc_ifbuf; 234160136Swsalamon int sc_iferrs; 235160136Swsalamon#endif 236160136Swsalamon} lpt_sc[NOLPT] ; 237160136Swsalamon 238160136Swsalamon/* bits for state */ 239160136Swsalamon#define OPEN (1<<0) /* device is open */ 240160136Swsalamon#define ASLP (1<<1) /* awaiting draining of printer */ 241160136Swsalamon#define ERROR (1<<2) /* error was received from printer */ 242160136Swsalamon#define OBUSY (1<<3) /* printer is busy doing output */ 243160136Swsalamon#define LPTOUT (1<<4) /* timeout while not selected */ 244160136Swsalamon#define TOUT (1<<5) /* timeout while not selected */ 245160136Swsalamon#define INIT (1<<6) /* waiting to initialize for open */ 246160136Swsalamon#define INTERRUPTED (1<<7) /* write call was interrupted */ 247160136Swsalamon 248160136Swsalamon 249160136Swsalamon/* status masks to interrogate printer status */ 250160136Swsalamon#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */ 251160136Swsalamon#define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR) 252160136Swsalamon 253160136Swsalamon/* Printer Ready condition - from lpa.c */ 254160136Swsalamon/* Only used in polling code */ 255160136Swsalamon#ifdef PC98 256160136Swsalamon#define NOT_READY(x) ((inb(x) & LPS_NBSY) != LPS_NBSY) 257155192Srwatson#else /* IBM-PC */ 258155192Srwatson#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) 259155192Srwatson#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) 260155192Srwatson#define NOT_READY(x) ((inb(x)^LPS_INVERT)&LPS_MASK) 261155192Srwatson#endif 262155192Srwatson 263155192Srwatson#define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */ 264155192Srwatson#define MAX_SPIN 20 /* Max delay for device ready in usecs */ 265155192Srwatson 266155192Srwatsonstatic timeout_t lptout; 267155192Srwatsonstatic int lptprobe (struct isa_device *dvp); 268156889Srwatsonstatic int lptattach (struct isa_device *isdp); 269155192Srwatsonstatic ointhand2_t lptintr; 270156889Srwatson 271156889Srwatson#ifdef INET 272155192Srwatson 273156889Srwatson/* Tables for the lp# interface */ 274156889Srwatsonstatic u_char *txmith; 275155192Srwatson#define txmitl (txmith+(1*LPIPTBLSIZE)) 276155192Srwatson#define trecvh (txmith+(2*LPIPTBLSIZE)) 277155192Srwatson#define trecvl (txmith+(3*LPIPTBLSIZE)) 278156889Srwatson 279156889Srwatsonstatic u_char *ctxmith; 280156889Srwatson#define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 281155192Srwatson#define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 282156889Srwatson#define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 283156889Srwatson 284155192Srwatson/* Functions for the lp# interface */ 285155192Srwatsonstatic void lpattach(struct lpt_softc *,int); 286155192Srwatson#ifndef PC98 287156889Srwatsonstatic int lpinittables(void); 288156889Srwatson#endif 289156889Srwatsonstatic int lpioctl(struct ifnet *, u_long, caddr_t); 290155192Srwatsonstatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 291156889Srwatson struct rtentry *); 292156889Srwatsonstatic void lpintr(int); 293155192Srwatson#endif /* INET */ 294156889Srwatson 295156889Srwatsonstruct isa_driver olptdriver = { 296155192Srwatson lptprobe, lptattach, "olpt" 297156889Srwatson}; 298156889Srwatson 299155192Srwatsonstatic d_open_t lptopen; 300156889Srwatsonstatic d_close_t lptclose; 301156889Srwatsonstatic d_write_t lptwrite; 302155192Srwatsonstatic d_ioctl_t lptioctl; 303155192Srwatson 304155192Srwatson#define CDEV_MAJOR 16 305156889Srwatsonstatic struct cdevsw lpt_cdevsw = { 306156889Srwatson /* open */ lptopen, 307156889Srwatson /* close */ lptclose, 308155192Srwatson /* read */ noread, 309156889Srwatson /* write */ lptwrite, 310156889Srwatson /* ioctl */ lptioctl, 311155192Srwatson /* stop */ nostop, 312155192Srwatson /* reset */ noreset, 313155192Srwatson /* devtotty */ nodevtotty, 314156889Srwatson /* poll */ nopoll, 315156889Srwatson /* mmap */ nommap, 316156889Srwatson /* strategy */ nostrategy, 317155192Srwatson /* name */ "lpt", 318156889Srwatson /* parms */ noparms, 319156889Srwatson /* maj */ CDEV_MAJOR, 320155192Srwatson /* dump */ nodump, 321155192Srwatson /* psize */ nopsize, 322155192Srwatson /* flags */ 0, 323156889Srwatson /* maxio */ 0, 324155192Srwatson /* bmaj */ -1 325156889Srwatson}; 326156889Srwatson 327155192Srwatson#ifndef PC98 328156889Srwatson/* 329156889Srwatson * Internal routine to lptprobe to do port tests of one byte value 330155192Srwatson */ 331155192Srwatsonstatic int 332155192Srwatsonlpt_port_test (int port, u_char data, u_char mask) 333156889Srwatson{ 334155192Srwatson int temp, timeout; 335156889Srwatson 336155192Srwatson data = data & mask; 337155192Srwatson outb(port, data); 338156889Srwatson timeout = 10000; 339155192Srwatson do { 340155192Srwatson DELAY(10); 341155192Srwatson temp = inb(port) & mask; 342156889Srwatson } 343156889Srwatson while (temp != data && --timeout); 344156889Srwatson lprintf(("Port 0x%x\tout=%x\tin=%x\ttout=%d\n", 345155192Srwatson port, data, temp, timeout)); 346156889Srwatson return (temp == data); 347156889Srwatson} 348155192Srwatson#endif /* PC98 */ 349155192Srwatson 350155192Srwatson/* 351156889Srwatson * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 352156889Srwatson * Based partially on Rod Grimes' printer probe 353156889Srwatson * 354155192Srwatson * Logic: 355155192Srwatson * 1) If no port address was given, use the bios detected ports 356155192Srwatson * and autodetect what ports the printers are on. 357155192Srwatson * 2) Otherwise, probe the data port at the address given, 358155192Srwatson * using the method in Rod Grimes' port probe. 359155192Srwatson * (Much code ripped off directly from Rod's probe.) 360155192Srwatson * 361155192Srwatson * Comments from Rod's probe: 362155192Srwatson * Logic: 363156889Srwatson * 1) You should be able to write to and read back the same value 364156889Srwatson * to the data port. Do an alternating zeros, alternating ones, 365156889Srwatson * walking zero, and walking one test to check for stuck bits. 366156889Srwatson * 367155192Srwatson * 2) You should be able to write to and read back the same value 368155192Srwatson * to the control port lower 5 bits, the upper 3 bits are reserved 369155192Srwatson * per the IBM PC technical reference manauls and different boards 370156889Srwatson * do different things with them. Do an alternating zeros, alternating 371155192Srwatson * ones, walking zero, and walking one test to check for stuck bits. 372155192Srwatson * 373155192Srwatson * Some printers drag the strobe line down when the are powered off 374155192Srwatson * so this bit has been masked out of the control port test. 375155192Srwatson * 376155192Srwatson * XXX Some printers may not like a fast pulse on init or strobe, I 377155192Srwatson * don't know at this point, if that becomes a problem these bits 378155192Srwatson * should be turned off in the mask byte for the control port test. 379155192Srwatson * 380155192Srwatson * We are finally left with a mask of 0x14, due to some printers 381155192Srwatson * being adamant about holding other bits high ........ 382155192Srwatson * 383155192Srwatson * Before probing the control port, we write a 0 to the data port - 384155192Srwatson * If not, some printers chuck out garbage when the strobe line 385155192Srwatson * gets toggled. 386155192Srwatson * 387155192Srwatson * 3) Set the data and control ports to a value of 0 388168688Scsjp * 389168688Scsjp * This probe routine has been tested on Epson Lx-800, HP LJ3P, 390168688Scsjp * Epson FX-1170 and C.Itoh 8510RM 391168688Scsjp * printers. 392168688Scsjp * Quick exit on fail added. 393168688Scsjp */ 394168688Scsjp 395168688Scsjpint 396168688Scsjplptprobe(struct isa_device *dvp) 397168688Scsjp{ 398168688Scsjp#ifdef PC98 399168688Scsjp#define PC98_OLD_LPT 0x40 400168688Scsjp#define PC98_IEEE_1284_FUNCTION 0x149 401168688Scsjp unsigned int pc98_ieee_mode, tmp; 402168688Scsjp 403168688Scsjp if (dvp->id_iobase == PC98_OLD_LPT) { 404168688Scsjp tmp = inb(PC98_IEEE_1284_FUNCTION); 405168688Scsjp pc98_ieee_mode = tmp; 406168688Scsjp if ((tmp & 0x10) == 0x10) { 407168688Scsjp outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10); 408168688Scsjp tmp = inb(PC98_IEEE_1284_FUNCTION); 409168688Scsjp if ((tmp & 0x10) != 0x10) { 410168688Scsjp outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode); 411168688Scsjp return 0; 412168688Scsjp } 413168688Scsjp } 414168688Scsjp } 415168688Scsjp return 8; 416168688Scsjp#else 417168688Scsjp int port; 418168688Scsjp static short next_bios_lpt = 0; 419168688Scsjp int status; 420168688Scsjp static u_char testbyte[18] = { 421168688Scsjp 0x55, /* alternating zeros */ 422155192Srwatson 0xaa, /* alternating ones */ 423156889Srwatson 0xfe, 0xfd, 0xfb, 0xf7, 424156889Srwatson 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ 425156889Srwatson 0x01, 0x02, 0x04, 0x08, 426155192Srwatson 0x10, 0x20, 0x40, 0x80 /* walking one */ 427155192Srwatson }; 428156889Srwatson int i; 429155192Srwatson 430155192Srwatson /* 431155192Srwatson * Make sure there is some way for lptopen to see that 432155192Srwatson * the port is not configured 433162990Srwatson * This 0 will remain if the port isn't attached 434155192Srwatson */ 435156889Srwatson (lpt_sc + dvp->id_unit)->sc_port = 0; 436162990Srwatson 437162990Srwatson status = IO_LPTSIZE; 438155192Srwatson /* If port not specified, use bios list */ 439155192Srwatson if(dvp->id_iobase < 0) { /* port? */ 440156889Srwatson if((next_bios_lpt < BIOS_MAX_LPT) && 441156889Srwatson (*(BIOS_PORTS+next_bios_lpt) != 0) ) { 442156889Srwatson dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++); 443155192Srwatson goto end_probe; 444155192Srwatson } else 445155192Srwatson return (0); 446155192Srwatson } 447155192Srwatson 448156889Srwatson /* Port was explicitly specified */ 449156889Srwatson /* This allows probing of ports unknown to the BIOS */ 450155192Srwatson port = dvp->id_iobase + lpt_data; 451155192Srwatson for (i = 0; i < 18; i++) { 452155192Srwatson if (!lpt_port_test(port, testbyte[i], 0xff)) { 453156889Srwatson status = 0; 454156889Srwatson goto end_probe; 455155192Srwatson } 456155192Srwatson } 457155192Srwatson 458155192Srwatsonend_probe: 459155192Srwatson /* write 0's to control and data ports */ 460155192Srwatson outb(dvp->id_iobase+lpt_data, 0); 461155192Srwatson outb(dvp->id_iobase+lpt_control, 0); 462155192Srwatson 463155192Srwatson return (status); 464155192Srwatson#endif 465155192Srwatson} 466155192Srwatson 467155192Srwatson/* XXX Todo - try and detect if interrupt is working */ 468155192Srwatsonint 469155192Srwatsonlptattach(struct isa_device *isdp) 470155192Srwatson{ 471155192Srwatson struct lpt_softc *sc; 472155192Srwatson int unit; 473155192Srwatson 474155192Srwatson isdp->id_ointr = lptintr; 475155192Srwatson unit = isdp->id_unit; 476155192Srwatson sc = lpt_sc + unit; 477155192Srwatson sc->sc_port = isdp->id_iobase; 478155192Srwatson sc->sc_primed = 0; /* not primed yet */ 479155192Srwatson#ifdef PC98 480155192Srwatson outb(sc->sc_port+lpt_pstb_ctrl, LPC_DIS_PSTB); /* PSTB disable */ 481155192Srwatson outb(sc->sc_port+lpt_control, LPC_MODE8255); /* 8255 mode set */ 482155192Srwatson outb(sc->sc_port+lpt_control, LPC_NIRQ8); /* IRQ8 inactive */ 483155192Srwatson outb(sc->sc_port+lpt_control, LPC_NPSTB); /* PSTB inactive */ 484155192Srwatson outb(sc->sc_port+lpt_pstb_ctrl, LPC_EN_PSTB); /* PSTB enable */ 485155192Srwatson#else 486155192Srwatson outb(sc->sc_port+lpt_control, LPC_NINIT); 487155192Srwatson#endif 488155192Srwatson 489155192Srwatson /* check if we can use interrupt */ 490155192Srwatson lprintf(("oldirq %x\n", sc->sc_irq)); 491155192Srwatson if (isdp->id_irq) { 492155192Srwatson sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; 493155192Srwatson printf("lpt%d: Interrupt-driven port\n", unit); 494155192Srwatson#ifdef INET 495155192Srwatson lpattach(sc, unit); 496155192Srwatson#endif 497155192Srwatson } else { 498155192Srwatson sc->sc_irq = 0; 499155192Srwatson lprintf(("lpt%d: Polled port\n", unit)); 500155192Srwatson } 501171066Scsjp lprintf(("irq %x\n", sc->sc_irq)); 502171066Scsjp 503171066Scsjp /* XXX what to do about the flags in the minor number? */ 504171066Scsjp make_dev(&lpt_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit); 505156889Srwatson make_dev(&lpt_cdevsw, unit | LP_BYPASS, 506156889Srwatson UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit); 507155192Srwatson return (1); 508156889Srwatson} 509156889Srwatson 510155192Srwatson/* 511156889Srwatson * lptopen -- reset the printer, then wait until it's selected and not busy. 512156889Srwatson * If LP_BYPASS flag is selected, then we do not try to select the 513155192Srwatson * printer -- this is just used for passing ioctls. 514156889Srwatson */ 515156889Srwatson 516155192Srwatsonstatic int 517156889Srwatsonlptopen (dev_t dev, int flags, int fmt, struct proc *p) 518156889Srwatson{ 519155192Srwatson struct lpt_softc *sc; 520156889Srwatson int s; 521156889Srwatson#ifdef PC98 522155192Srwatson int port; 523155192Srwatson#else 524155192Srwatson int trys, port; 525155192Srwatson#endif 526155192Srwatson u_int unit = LPTUNIT(minor(dev)); 527171066Scsjp 528171066Scsjp sc = lpt_sc + unit; 529171066Scsjp if ((unit >= NOLPT) || (sc->sc_port == 0)) 530171066Scsjp return (ENXIO); 531171066Scsjp 532171066Scsjp#ifdef INET 533171066Scsjp if (sc->sc_if.if_flags & IFF_UP) 534171066Scsjp return(EBUSY); 535171066Scsjp#endif 536171066Scsjp 537171066Scsjp if (sc->sc_state) { 538171066Scsjp lprintf(("lp: still open %x\n", sc->sc_state)); 539171066Scsjp return(EBUSY); 540171066Scsjp } else 541171066Scsjp sc->sc_state |= INIT; 542171066Scsjp 543171066Scsjp sc->sc_flags = LPTFLAGS(minor(dev)); 544171066Scsjp 545171066Scsjp /* Check for open with BYPASS flag set. */ 546171066Scsjp if (sc->sc_flags & LP_BYPASS) { 547171066Scsjp sc->sc_state = OPEN; 548171066Scsjp return(0); 549171066Scsjp } 550171066Scsjp 551171066Scsjp s = spltty(); 552171066Scsjp lprintf(("lp flags 0x%x\n", sc->sc_flags)); 553171066Scsjp port = sc->sc_port; 554171066Scsjp 555171066Scsjp /* set IRQ status according to ENABLE_IRQ flag */ 556171066Scsjp if (sc->sc_irq & LP_ENABLE_IRQ) 557171066Scsjp sc->sc_irq |= LP_USE_IRQ; 558155192Srwatson else 559155192Srwatson sc->sc_irq &= ~LP_USE_IRQ; 560156889Srwatson 561156889Srwatson /* init printer */ 562156889Srwatson#ifndef PC98 563155192Srwatson if ((sc->sc_flags & LP_NO_PRIME) == 0) { 564155192Srwatson if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { 565155192Srwatson outb(port+lpt_control, 0); 566155192Srwatson sc->sc_primed++; 567155192Srwatson DELAY(500); 568155192Srwatson } 569155192Srwatson } 570155192Srwatson 571155192Srwatson outb (port+lpt_control, LPC_SEL|LPC_NINIT); 572155192Srwatson 573155192Srwatson /* wait till ready (printer running diagnostics) */ 574155192Srwatson trys = 0; 575155192Srwatson do { 576155192Srwatson /* ran out of waiting for the printer */ 577155192Srwatson if (trys++ >= LPINITRDY*4) { 578155192Srwatson splx(s); 579155192Srwatson sc->sc_state = 0; 580155192Srwatson lprintf(("status %x\n", inb(port+lpt_status))); 581155192Srwatson return (EBUSY); 582155192Srwatson } 583155192Srwatson 584155192Srwatson /* wait 1/4 second, give up if we get a signal */ 585156889Srwatson if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) != 586155192Srwatson EWOULDBLOCK) { 587155192Srwatson sc->sc_state = 0; 588156889Srwatson splx(s); 589155192Srwatson return (EBUSY); 590155192Srwatson } 591155192Srwatson 592155192Srwatson /* is printer online and ready for output */ 593155192Srwatson } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != 594155192Srwatson (LPS_SEL|LPS_NBSY|LPS_NERR)); 595155192Srwatson 596155192Srwatson sc->sc_control = LPC_SEL|LPC_NINIT; 597155192Srwatson if (sc->sc_flags & LP_AUTOLF) 598155192Srwatson sc->sc_control |= LPC_AUTOL; 599155192Srwatson 600155192Srwatson /* enable interrupt if interrupt-driven */ 601155192Srwatson if (sc->sc_irq & LP_USE_IRQ) 602162990Srwatson sc->sc_control |= LPC_ENA; 603155192Srwatson 604162990Srwatson outb(port+lpt_control, sc->sc_control); 605155192Srwatson#endif 606155192Srwatson 607155192Srwatson sc->sc_state = OPEN; 608162990Srwatson sc->sc_inbuf = geteblk(BUFSIZE); 609155192Srwatson sc->sc_xfercnt = 0; 610162990Srwatson splx(s); 611162990Srwatson 612162990Srwatson /* only use timeout if using interrupt */ 613162990Srwatson lprintf(("irq %x\n", sc->sc_irq)); 614162990Srwatson if (sc->sc_irq & LP_USE_IRQ) { 615162990Srwatson sc->sc_state |= TOUT; 616162990Srwatson timeout (lptout, (caddr_t)sc, 617162990Srwatson (sc->sc_backoff = hz/LPTOUTINITIAL)); 618162990Srwatson } 619155192Srwatson 620162990Srwatson lprintf(("opened.\n")); 621162990Srwatson return(0); 622162990Srwatson} 623162990Srwatson 624155192Srwatsonstatic void 625155192Srwatsonlptout (void *arg) 626155192Srwatson{ 627155192Srwatson struct lpt_softc *sc = arg; 628162990Srwatson int pl; 629162990Srwatson 630156889Srwatson lprintf(("T %x ", inb(sc->sc_port+lpt_status))); 631156889Srwatson if (sc->sc_state & OPEN) { 632156889Srwatson sc->sc_backoff++; 633155192Srwatson if (sc->sc_backoff > hz/LPTOUTMAX) 634155192Srwatson sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX; 635159278Srwatson timeout (lptout, (caddr_t)sc, sc->sc_backoff); 636159278Srwatson } else 637159278Srwatson sc->sc_state &= ~TOUT; 638159278Srwatson 639159278Srwatson if (sc->sc_state & ERROR) 640159278Srwatson sc->sc_state &= ~ERROR; 641155192Srwatson 642155192Srwatson /* 643155192Srwatson * Avoid possible hangs do to missed interrupts 644155559Srwatson */ 645155192Srwatson if (sc->sc_xfercnt) { 646162990Srwatson pl = spltty(); 647162419Scsjp lptintr(sc - lpt_sc); 648155192Srwatson splx(pl); 649155192Srwatson } else { 650155192Srwatson sc->sc_state &= ~OBUSY; 651155192Srwatson wakeup((caddr_t)sc); 652155192Srwatson } 653155192Srwatson} 654155192Srwatson 655155192Srwatson/* 656155192Srwatson * lptclose -- close the device, free the local line buffer. 657155192Srwatson * 658162990Srwatson * Check for interrupted write call added. 659162990Srwatson */ 660155192Srwatson 661155192Srwatsonstatic int 662155192Srwatsonlptclose(dev_t dev, int flags, int fmt, struct proc *p) 663155192Srwatson{ 664155192Srwatson struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); 665155192Srwatson#ifndef PC98 666155192Srwatson int port = sc->sc_port; 667162990Srwatson#endif 668162990Srwatson 669162990Srwatson if(sc->sc_flags & LP_BYPASS) 670162990Srwatson goto end_close; 671162990Srwatson 672162990Srwatson sc->sc_state &= ~OPEN; 673155192Srwatson 674155192Srwatson#ifndef PC98 675155192Srwatson /* if the last write was interrupted, don't complete it */ 676155192Srwatson if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) 677155192Srwatson while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != 678155192Srwatson (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) 679155192Srwatson /* wait 1/4 second, give up if we get a signal */ 680155192Srwatson if (tsleep ((caddr_t)sc, LPPRI|PCATCH, 681156889Srwatson "lpclose", hz) != EWOULDBLOCK) 682155192Srwatson break; 683155192Srwatson 684155192Srwatson outb(sc->sc_port+lpt_control, LPC_NINIT); 685156889Srwatson#endif 686156889Srwatson brelse(sc->sc_inbuf); 687155192Srwatson 688155192Srwatsonend_close: 689155192Srwatson sc->sc_state = 0; 690155192Srwatson sc->sc_xfercnt = 0; 691156889Srwatson lprintf(("closed.\n")); 692155192Srwatson return(0); 693155192Srwatson} 694155192Srwatson 695155192Srwatson/* 696155192Srwatson * pushbytes() 697155192Srwatson * Workhorse for actually spinning and writing bytes to printer 698155192Srwatson * Derived from lpa.c 699155192Srwatson * Originally by ? 700155192Srwatson * 701155192Srwatson * This code is only used when we are polling the port 702155192Srwatson */ 703155192Srwatsonstatic int 704156889Srwatsonpushbytes(struct lpt_softc * sc) 705155192Srwatson{ 706155192Srwatson int spin, err, tic; 707155192Srwatson char ch; 708155192Srwatson int port = sc->sc_port; 709155192Srwatson 710155192Srwatson lprintf(("p")); 711155192Srwatson /* loop for every character .. */ 712155192Srwatson while (sc->sc_xfercnt > 0) { 713155192Srwatson /* printer data */ 714155192Srwatson ch = *(sc->sc_cp); 715155192Srwatson sc->sc_cp++; 716155192Srwatson sc->sc_xfercnt--; 717155192Srwatson 718160136Swsalamon /* 719160136Swsalamon * Wait for printer ready. 720160136Swsalamon * Loop 20 usecs testing BUSY bit, then sleep 721160136Swsalamon * for exponentially increasing timeout. (vak) 722160136Swsalamon */ 723160136Swsalamon for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin) 724160136Swsalamon DELAY(1); /* XXX delay is NOT this accurate! */ 725160136Swsalamon if (spin >= MAX_SPIN) { 726160136Swsalamon tic = 0; 727160136Swsalamon while (NOT_READY(port+lpt_status)) { 728160136Swsalamon /* 729160136Swsalamon * Now sleep, every cycle a 730160136Swsalamon * little longer .. 731160136Swsalamon */ 732160136Swsalamon tic = tic + tic + 1; 733160136Swsalamon /* 734160136Swsalamon * But no more than 10 seconds. (vak) 735160136Swsalamon */ 736160136Swsalamon if (tic > MAX_SLEEP) 737160136Swsalamon tic = MAX_SLEEP; 738160136Swsalamon err = tsleep((caddr_t)sc, LPPRI, 739160136Swsalamon "lptpoll", tic); 740160136Swsalamon if (err != EWOULDBLOCK) { 741160136Swsalamon return (err); 742160136Swsalamon } 743160136Swsalamon } 744160136Swsalamon } 745160136Swsalamon 746160136Swsalamon /* output data */ 747160136Swsalamon outb(port+lpt_data, ch); 748160136Swsalamon#ifdef PC98 749160136Swsalamon DELAY(1); 750160136Swsalamon outb(port+lpt_control, LPC_PSTB); 751160136Swsalamon DELAY(1); 752160136Swsalamon outb(port+lpt_control, LPC_NPSTB); 753161813Swsalamon#else 754161813Swsalamon /* strobe */ 755161813Swsalamon outb(port+lpt_control, sc->sc_control|LPC_STB); 756161813Swsalamon outb(port+lpt_control, sc->sc_control); 757161813Swsalamon#endif 758161813Swsalamon 759161813Swsalamon } 760161813Swsalamon return(0); 761161813Swsalamon} 762161813Swsalamon 763161813Swsalamon/* 764161813Swsalamon * lptwrite --copy a line from user space to a local buffer, then call 765161813Swsalamon * putc to get the chars moved to the output queue. 766161813Swsalamon * 767155192Srwatson * Flagging of interrupted write added. 768155192Srwatson */ 769156889Srwatson 770156889Srwatsonstatic int 771155192Srwatsonlptwrite(dev_t dev, struct uio * uio, int ioflag) 772155192Srwatson{ 773155192Srwatson register unsigned n; 774155192Srwatson int pl, err; 775156889Srwatson struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); 776162990Srwatson 777162990Srwatson if(sc->sc_flags & LP_BYPASS) { 778162990Srwatson /* we can't do writes in bypass mode */ 779155192Srwatson return(EPERM); 780155192Srwatson } 781162990Srwatson 782155192Srwatson sc->sc_state &= ~INTERRUPTED; 783155192Srwatson while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { 784155192Srwatson sc->sc_cp = sc->sc_inbuf->b_data ; 785155192Srwatson uiomove(sc->sc_cp, n, uio); 786155192Srwatson sc->sc_xfercnt = n ; 787155192Srwatson while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { 788162990Srwatson lprintf(("i")); 789162990Srwatson /* if the printer is ready for a char, */ 790162990Srwatson /* give it one */ 791162990Srwatson if ((sc->sc_state & OBUSY) == 0){ 792162990Srwatson lprintf(("\nC %d. ", sc->sc_xfercnt)); 793155192Srwatson pl = spltty(); 794155192Srwatson lptintr(sc - lpt_sc); 795156889Srwatson (void) splx(pl); 796155192Srwatson } 797155192Srwatson lprintf(("W ")); 798155192Srwatson if (sc->sc_state & OBUSY) 799155192Srwatson if ((err = tsleep ((caddr_t)sc, 800155192Srwatson LPPRI|PCATCH, "lpwrite", 0))) { 801155192Srwatson sc->sc_state |= INTERRUPTED; 802155192Srwatson return(err); 803155192Srwatson } 804155192Srwatson } 805155192Srwatson /* check to see if we must do a polled write */ 806155192Srwatson if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { 807156889Srwatson lprintf(("p")); 808155192Srwatson if((err = pushbytes(sc))) 809155192Srwatson return(err); 810155192Srwatson } 811155192Srwatson } 812155192Srwatson return(0); 813155192Srwatson} 814155192Srwatson 815155192Srwatson/* 816155192Srwatson * lptintr -- handle printer interrupts which occur when the printer is 817155192Srwatson * ready to accept another char. 818156889Srwatson * 819155192Srwatson * do checking for interrupted write call. 820155192Srwatson */ 821155192Srwatson 822155192Srwatsonstatic void 823155192Srwatsonlptintr(int unit) 824155192Srwatson{ 825155192Srwatson struct lpt_softc *sc = lpt_sc + unit; 826156889Srwatson#ifndef PC98 827155192Srwatson int port = sc->sc_port, sts; 828155192Srwatson int i; 829155192Srwatson#endif 830155192Srwatson 831155192Srwatson#ifdef INET 832155192Srwatson if(sc->sc_if.if_flags & IFF_UP) { 833155192Srwatson lpintr(unit); 834156889Srwatson return; 835155192Srwatson } 836155192Srwatson#endif /* INET */ 837155192Srwatson 838155192Srwatson#ifndef PC98 839155192Srwatson /* 840155192Srwatson * Is printer online and ready for output? 841155192Srwatson * 842155192Srwatson * Avoid falling back to lptout() too quickly. First spin-loop 843155192Srwatson * to see if the printer will become ready ``really soon now''. 844155192Srwatson */ 845155192Srwatson for (i = 0; 846155192Srwatson i < 100 && 847155192Srwatson ((sts=inb(port+lpt_status)) & RDY_MASK) != LP_READY; 848156889Srwatson i++) ; 849155192Srwatson if ((sts & RDY_MASK) == LP_READY) { 850155192Srwatson sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR; 851155192Srwatson sc->sc_backoff = hz/LPTOUTINITIAL; 852155192Srwatson 853155192Srwatson if (sc->sc_xfercnt) { 854155192Srwatson /* send char */ 855155271Srwatson /*lprintf(("%x ", *sc->sc_cp)); */ 856155271Srwatson outb(port+lpt_data, *sc->sc_cp++) ; 857155192Srwatson outb(port+lpt_control, sc->sc_control|LPC_STB); 858155192Srwatson /* DELAY(X) */ 859156889Srwatson outb(port+lpt_control, sc->sc_control); 860155192Srwatson 861156889Srwatson /* any more data for printer */ 862155192Srwatson if(--(sc->sc_xfercnt) > 0) return; 863156889Srwatson } 864155192Srwatson 865155192Srwatson /* 866155192Srwatson * No more data waiting for printer. 867155192Srwatson * Wakeup is not done if write call was interrupted. 868155192Srwatson */ 869155192Srwatson sc->sc_state &= ~OBUSY; 870155192Srwatson if(!(sc->sc_state & INTERRUPTED)) 871155192Srwatson wakeup((caddr_t)sc); 872155192Srwatson lprintf(("w ")); 873155192Srwatson return; 874155192Srwatson } else { /* check for error */ 875155192Srwatson if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) && 876162990Srwatson (sc->sc_state & OPEN)) 877155192Srwatson sc->sc_state |= ERROR; 878155192Srwatson /* lptout() will jump in and try to restart. */ 879155192Srwatson } 880155192Srwatson#endif 881155192Srwatson lprintf(("sts %x ", sts)); 882155192Srwatson} 883155192Srwatson 884155192Srwatsonstatic int 885155192Srwatsonlptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 886155192Srwatson{ 887155192Srwatson int error = 0; 888155192Srwatson struct lpt_softc *sc; 889155192Srwatson u_int unit = LPTUNIT(minor(dev)); 890155192Srwatson u_char old_sc_irq; /* old printer IRQ status */ 891155192Srwatson 892155192Srwatson sc = lpt_sc + unit; 893155192Srwatson 894155192Srwatson switch (cmd) { 895155192Srwatson case LPT_IRQ : 896155192Srwatson if(sc->sc_irq & LP_HAS_IRQ) { 897155192Srwatson /* 898155192Srwatson * NOTE: 899155192Srwatson * If the IRQ status is changed, 900155192Srwatson * this will only be visible on the 901155192Srwatson * next open. 902155192Srwatson * 903155192Srwatson * If interrupt status changes, 904155192Srwatson * this gets syslog'd. 905155192Srwatson */ 906155271Srwatson old_sc_irq = sc->sc_irq; 907155192Srwatson if(*(int*)data == 0) 908155192Srwatson sc->sc_irq &= (~LP_ENABLE_IRQ); 909155192Srwatson else 910155192Srwatson sc->sc_irq |= LP_ENABLE_IRQ; 911156889Srwatson if (old_sc_irq != sc->sc_irq ) 912155192Srwatson log(LOG_NOTICE, "lpt%c switched to %s mode\n", 913155192Srwatson (char)unit+'0', 914155192Srwatson (sc->sc_irq & LP_ENABLE_IRQ)? 915155192Srwatson "interrupt-driven":"polled"); 916155192Srwatson } else /* polled port */ 917155192Srwatson error = EOPNOTSUPP; 918155192Srwatson break; 919155192Srwatson default: 920155192Srwatson error = ENODEV; 921155192Srwatson } 922155192Srwatson 923155192Srwatson return(error); 924155192Srwatson} 925155192Srwatson 926155192Srwatson#ifdef INET 927155192Srwatson 928155192Srwatsonstatic void 929155192Srwatsonlpattach (struct lpt_softc *sc, int unit) 930155192Srwatson{ 931155192Srwatson struct ifnet *ifp = &sc->sc_if; 932155192Srwatson 933155192Srwatson ifp->if_softc = sc; 934155192Srwatson ifp->if_name = "lp"; 935155192Srwatson ifp->if_unit = unit; 936155192Srwatson ifp->if_mtu = LPMTU; 937155192Srwatson ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 938155192Srwatson ifp->if_ioctl = lpioctl; 939155192Srwatson ifp->if_output = lpoutput; 940155271Srwatson ifp->if_type = IFT_PARA; 941155192Srwatson ifp->if_hdrlen = 0; 942155192Srwatson ifp->if_addrlen = 0; 943155192Srwatson ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 944155192Srwatson if_attach(ifp); 945155192Srwatson printf("lp%d: TCP/IP capable interface\n", unit); 946155192Srwatson 947155192Srwatson#if NBPF > 0 948155192Srwatson bpfattach(ifp, DLT_NULL, LPIPHDRLEN); 949155192Srwatson#endif 950155192Srwatson} 951155192Srwatson 952155192Srwatson#ifndef PC98 953155192Srwatson/* 954155192Srwatson * Build the translation tables for the LPIP (BSD unix) protocol. 955155192Srwatson * We don't want to calculate these nasties in our tight loop, so we 956155192Srwatson * precalculate them when we initialize. 957155192Srwatson */ 958155192Srwatsonstatic int 959155192Srwatsonlpinittables (void) 960155192Srwatson{ 961155192Srwatson int i; 962155192Srwatson 963155192Srwatson if (!txmith) 964155192Srwatson txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 965155192Srwatson 966162990Srwatson if (!txmith) 967155192Srwatson return 1; 968155192Srwatson 969155192Srwatson if (!ctxmith) 970155192Srwatson ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 971155192Srwatson 972155192Srwatson if (!ctxmith) 973155192Srwatson return 1; 974155192Srwatson 975155192Srwatson for (i=0; i < LPIPTBLSIZE; i++) { 976155192Srwatson ctxmith[i] = (i & 0xF0) >> 4; 977156889Srwatson ctxmitl[i] = 0x10 | (i & 0x0F); 978155192Srwatson ctrecvh[i] = (i & 0x78) << 1; 979155192Srwatson ctrecvl[i] = (i & 0x78) >> 3; 980155192Srwatson } 981155192Srwatson 982155192Srwatson for (i=0; i < LPIPTBLSIZE; i++) { 983155192Srwatson txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 984155192Srwatson txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 985156889Srwatson trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 986155192Srwatson trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 987155192Srwatson } 988155192Srwatson 989155192Srwatson return 0; 990155192Srwatson} 991155192Srwatson#endif /* PC98 */ 992155192Srwatson 993155192Srwatson/* 994155192Srwatson * Process an ioctl request. 995155192Srwatson */ 996155192Srwatson 997155192Srwatsonstatic int 998155192Srwatsonlpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 999155192Srwatson{ 1000155192Srwatson struct lpt_softc *sc = lpt_sc + ifp->if_unit; 1001155192Srwatson struct ifaddr *ifa = (struct ifaddr *)data; 1002155192Srwatson struct ifreq *ifr = (struct ifreq *)data; 1003155192Srwatson u_char *ptr; 1004155192Srwatson 1005155192Srwatson switch (cmd) { 1006155192Srwatson 1007155192Srwatson case SIOCSIFDSTADDR: 1008155192Srwatson case SIOCAIFADDR: 1009155271Srwatson case SIOCSIFADDR: 1010155192Srwatson if (ifa->ifa_addr->sa_family != AF_INET) 1011155192Srwatson return EAFNOSUPPORT; 1012155192Srwatson ifp->if_flags |= IFF_UP; 1013156889Srwatson /* FALLTHROUGH */ 1014155192Srwatson case SIOCSIFFLAGS: 1015155192Srwatson if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 1016155192Srwatson outb(sc->sc_port + lpt_control, 0x00); 1017155192Srwatson ifp->if_flags &= ~IFF_RUNNING; 1018155192Srwatson break; 1019155192Srwatson } 1020162990Srwatson#ifdef PC98 1021155192Srwatson /* XXX */ 1022155192Srwatson return ENOBUFS; 1023155192Srwatson#else 1024155192Srwatson if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 1025155192Srwatson if (lpinittables()) 1026155192Srwatson return ENOBUFS; 1027155192Srwatson sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, 1028155192Srwatson M_DEVBUF, M_WAITOK); 1029155192Srwatson if (!sc->sc_ifbuf) 1030155192Srwatson return ENOBUFS; 1031155192Srwatson 1032155192Srwatson outb(sc->sc_port + lpt_control, LPC_ENA); 1033155192Srwatson ifp->if_flags |= IFF_RUNNING; 1034155192Srwatson } 1035155192Srwatson break; 1036155192Srwatson#endif 1037155192Srwatson case SIOCSIFMTU: 1038155192Srwatson ptr = sc->sc_ifbuf; 1039155192Srwatson sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 1040155192Srwatson if (!sc->sc_ifbuf) { 1041155192Srwatson sc->sc_ifbuf = ptr; 1042155192Srwatson return ENOBUFS; 1043155192Srwatson } 1044155192Srwatson if (ptr) 1045155192Srwatson free(ptr,M_DEVBUF); 1046155192Srwatson sc->sc_if.if_mtu = ifr->ifr_mtu; 1047155271Srwatson break; 1048155192Srwatson 1049155192Srwatson case SIOCGIFMTU: 1050155192Srwatson ifr->ifr_mtu = sc->sc_if.if_mtu; 1051155192Srwatson break; 1052155192Srwatson 1053155192Srwatson case SIOCADDMULTI: 1054155192Srwatson case SIOCDELMULTI: 1055155192Srwatson if (ifr == 0) { 1056155192Srwatson return EAFNOSUPPORT; /* XXX */ 1057155192Srwatson } 1058155192Srwatson switch (ifr->ifr_addr.sa_family) { 1059155192Srwatson 1060155192Srwatson#ifdef INET 1061155192Srwatson case AF_INET: 1062155192Srwatson break; 1063155192Srwatson#endif 1064155192Srwatson 1065155192Srwatson default: 1066155192Srwatson return EAFNOSUPPORT; 1067155192Srwatson } 1068155192Srwatson break; 1069155192Srwatson 1070155192Srwatson default: 1071155192Srwatson lprintf(("LP:ioctl(0x%lx)\n", cmd)); 1072155192Srwatson return EINVAL; 1073155192Srwatson } 1074155192Srwatson return 0; 1075155192Srwatson} 1076155192Srwatson 1077155192Srwatsonstatic __inline int 1078155192Srwatsonclpoutbyte (u_char byte, int spin, int data_port, int status_port) 1079156889Srwatson{ 1080155192Srwatson outb(data_port, ctxmitl[byte]); 1081155192Srwatson while (inb(status_port) & CLPIP_SHAKE) 1082155192Srwatson if (--spin == 0) { 1083155192Srwatson return 1; 1084155192Srwatson } 1085155192Srwatson outb(data_port, ctxmith[byte]); 1086155192Srwatson while (!(inb(status_port) & CLPIP_SHAKE)) 1087155192Srwatson if (--spin == 0) { 1088155192Srwatson return 1; 1089155192Srwatson } 1090155192Srwatson return 0; 1091156889Srwatson} 1092155192Srwatson 1093155192Srwatsonstatic __inline int 1094155192Srwatsonclpinbyte (int spin, int data_port, int status_port) 1095155192Srwatson{ 1096155192Srwatson int c, cl; 1097155192Srwatson 1098155192Srwatson while((inb(status_port) & CLPIP_SHAKE)) 1099155192Srwatson if(!--spin) { 1100155192Srwatson return -1; 1101156889Srwatson } 1102155192Srwatson cl = inb(status_port); 1103155192Srwatson outb(data_port, 0x10); 1104155192Srwatson 1105155192Srwatson while(!(inb(status_port) & CLPIP_SHAKE)) 1106155192Srwatson if(!--spin) { 1107155192Srwatson return -1; 1108156889Srwatson } 1109155192Srwatson c = inb(status_port); 1110155192Srwatson outb(data_port, 0x00); 1111155192Srwatson 1112155192Srwatson return (ctrecvl[cl] | ctrecvh[c]); 1113155192Srwatson} 1114155192Srwatson 1115156889Srwatsonstatic void 1116155192Srwatsonlpintr (int unit) 1117155192Srwatson{ 1118155192Srwatson struct lpt_softc *sc = lpt_sc + unit; 1119155192Srwatson register int lpt_data_port = sc->sc_port + lpt_data; 1120155192Srwatson register int lpt_stat_port = sc->sc_port + lpt_status; 1121155192Srwatson int lpt_ctrl_port = sc->sc_port + lpt_control; 1122155192Srwatson int len, s, j; 1123155192Srwatson u_char *bp; 1124155192Srwatson u_char c, cl; 1125155192Srwatson struct mbuf *top; 1126156889Srwatson 1127155192Srwatson s = splhigh(); 1128155192Srwatson 1129155192Srwatson if (sc->sc_if.if_flags & IFF_LINK0) { 1130155192Srwatson 1131155192Srwatson /* Ack. the request */ 1132155192Srwatson outb(lpt_data_port, 0x01); 1133155192Srwatson 1134155192Srwatson /* Get the packet length */ 1135155192Srwatson j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 1136155192Srwatson if (j == -1) 1137156889Srwatson goto err; 1138155192Srwatson len = j; 1139155192Srwatson j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 1140155192Srwatson if (j == -1) 1141155192Srwatson goto err; 1142155192Srwatson len = len + (j << 8); 1143155192Srwatson if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) 1144155192Srwatson goto err; 1145155192Srwatson 1146155192Srwatson bp = sc->sc_ifbuf; 1147155192Srwatson 1148155192Srwatson while (len--) { 1149155192Srwatson j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 1150155192Srwatson if (j == -1) { 1151155192Srwatson goto err; 1152156889Srwatson } 1153155192Srwatson *bp++ = j; 1154155192Srwatson } 1155155192Srwatson /* Get and ignore checksum */ 1156155192Srwatson j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 1157155192Srwatson if (j == -1) { 1158155192Srwatson goto err; 1159155192Srwatson } 1160155192Srwatson 1161155192Srwatson len = bp - sc->sc_ifbuf; 1162155192Srwatson if (len <= CLPIPHDRLEN) 1163155192Srwatson goto err; 1164155192Srwatson 1165155192Srwatson sc->sc_iferrs = 0; 1166155192Srwatson 1167156889Srwatson if (IF_QFULL(&ipintrq)) { 1168155192Srwatson lprintf(("DROP")); 1169155192Srwatson IF_DROP(&ipintrq); 1170155192Srwatson goto done; 1171155192Srwatson } 1172155192Srwatson len -= CLPIPHDRLEN; 1173155192Srwatson sc->sc_if.if_ipackets++; 1174156889Srwatson sc->sc_if.if_ibytes += len; 1175155192Srwatson top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); 1176155192Srwatson if (top) { 1177155192Srwatson IF_ENQUEUE(&ipintrq, top); 1178155192Srwatson schednetisr(NETISR_IP); 1179155192Srwatson } 1180155192Srwatson goto done; 1181156889Srwatson } 1182155192Srwatson while ((inb(lpt_stat_port) & LPIP_SHAKE)) { 1183155192Srwatson len = sc->sc_if.if_mtu + LPIPHDRLEN; 1184155192Srwatson bp = sc->sc_ifbuf; 1185155192Srwatson while (len--) { 1186155192Srwatson 1187155192Srwatson cl = inb(lpt_stat_port); 1188155192Srwatson outb(lpt_data_port, 8); 1189155192Srwatson 1190155192Srwatson j = LPMAXSPIN2; 1191155192Srwatson while((inb(lpt_stat_port) & LPIP_SHAKE)) 1192155192Srwatson if(!--j) goto err; 1193155192Srwatson 1194155192Srwatson c = inb(lpt_stat_port); 1195155192Srwatson outb(lpt_data_port, 0); 1196155192Srwatson 1197155192Srwatson *bp++= trecvh[cl] | trecvl[c]; 1198155192Srwatson 1199155192Srwatson j = LPMAXSPIN2; 1200155192Srwatson while (!((cl=inb(lpt_stat_port)) & LPIP_SHAKE)) { 1201155192Srwatson if (cl != c && 1202155192Srwatson (((cl = inb(lpt_stat_port)) ^ 0xb8) & 0xf8) == 1203155192Srwatson (c & 0xf8)) 1204155192Srwatson goto end; 1205155192Srwatson if (!--j) goto err; 1206155192Srwatson } 1207155192Srwatson } 1208155192Srwatson 1209155192Srwatson end: 1210155192Srwatson len = bp - sc->sc_ifbuf; 1211155192Srwatson if (len <= LPIPHDRLEN) 1212155192Srwatson goto err; 1213155192Srwatson 1214155192Srwatson sc->sc_iferrs = 0; 1215155192Srwatson 1216155192Srwatson if (IF_QFULL(&ipintrq)) { 1217155192Srwatson lprintf(("DROP")); 1218155192Srwatson IF_DROP(&ipintrq); 1219155192Srwatson goto done; 1220155192Srwatson } 1221155192Srwatson#if NBPF > 0 1222155192Srwatson if (sc->sc_if.if_bpf) { 1223155192Srwatson bpf_tap(&sc->sc_if, sc->sc_ifbuf, len); 1224155192Srwatson } 1225155192Srwatson#endif 1226155192Srwatson len -= LPIPHDRLEN; 1227155192Srwatson sc->sc_if.if_ipackets++; 1228155192Srwatson sc->sc_if.if_ibytes += len; 1229155192Srwatson top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); 1230155192Srwatson if (top) { 1231155192Srwatson IF_ENQUEUE(&ipintrq, top); 1232155271Srwatson schednetisr(NETISR_IP); 1233155192Srwatson } 1234155192Srwatson } 1235155192Srwatson goto done; 1236155192Srwatson 1237155192Srwatson err: 1238155192Srwatson outb(lpt_data_port, 0); 1239155192Srwatson lprintf(("R")); 1240155192Srwatson sc->sc_if.if_ierrors++; 1241155192Srwatson sc->sc_iferrs++; 1242155192Srwatson 1243155192Srwatson /* 1244155192Srwatson * We are not able to send receive anything for now, 1245155192Srwatson * so stop wasting our time 1246155192Srwatson */ 1247155192Srwatson if (sc->sc_iferrs > LPMAXERRS) { 1248155192Srwatson printf("lp%d: Too many errors, Going off-line.\n", unit); 1249155192Srwatson outb(lpt_ctrl_port, 0x00); 1250155192Srwatson sc->sc_if.if_flags &= ~IFF_RUNNING; 1251155192Srwatson sc->sc_iferrs=0; 1252155192Srwatson } 1253155192Srwatson 1254155192Srwatson done: 1255155192Srwatson splx(s); 1256155192Srwatson return; 1257155192Srwatson} 1258155192Srwatson 1259155192Srwatsonstatic __inline int 1260155192Srwatsonlpoutbyte (u_char byte, int spin, int data_port, int status_port) 1261155192Srwatson{ 1262155192Srwatson outb(data_port, txmith[byte]); 1263155192Srwatson while (!(inb(status_port) & LPIP_SHAKE)) 1264155192Srwatson if (--spin == 0) 1265155192Srwatson return 1; 1266155192Srwatson outb(data_port, txmitl[byte]); 1267155192Srwatson while (inb(status_port) & LPIP_SHAKE) 1268155192Srwatson if (--spin == 0) 1269155192Srwatson return 1; 1270155192Srwatson return 0; 1271155271Srwatson} 1272155192Srwatson 1273155192Srwatsonstatic int 1274155192Srwatsonlpoutput (struct ifnet *ifp, struct mbuf *m, 1275155192Srwatson struct sockaddr *dst, struct rtentry *rt) 1276155192Srwatson{ 1277155192Srwatson register int lpt_data_port = lpt_sc[ifp->if_unit].sc_port + lpt_data; 1278155192Srwatson register int lpt_stat_port = lpt_sc[ifp->if_unit].sc_port + lpt_status; 1279155192Srwatson#ifndef PC98 1280155192Srwatson int lpt_ctrl_port = lpt_sc[ifp->if_unit].sc_port + lpt_control; 1281155192Srwatson#endif 1282155192Srwatson 1283155192Srwatson int s, err; 1284155192Srwatson struct mbuf *mm; 1285155192Srwatson u_char *cp = "\0\0"; 1286155192Srwatson u_char chksum = 0; 1287155192Srwatson int count = 0; 1288155192Srwatson int i; 1289155192Srwatson int spin; 1290156889Srwatson 1291155192Srwatson /* We need a sensible value if we abort */ 1292155192Srwatson cp++; 1293155192Srwatson ifp->if_flags |= IFF_RUNNING; 1294155192Srwatson 1295155192Srwatson err = 1; /* assume we're aborting because of an error */ 1296155192Srwatson 1297155192Srwatson s = splhigh(); 1298155192Srwatson 1299155192Srwatson#ifndef PC98 1300155192Srwatson /* Suspend (on laptops) or receive-errors might have taken us offline */ 1301155192Srwatson outb(lpt_ctrl_port, LPC_ENA); 1302155192Srwatson#endif 1303155192Srwatson 1304155192Srwatson if (ifp->if_flags & IFF_LINK0) { 1305155192Srwatson 1306155192Srwatson if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) { 1307155192Srwatson lprintf(("&")); 1308155192Srwatson lptintr(ifp->if_unit); 1309155192Srwatson } 1310155192Srwatson 1311155192Srwatson /* Alert other end to pending packet */ 1312155192Srwatson spin = LPMAXSPIN1; 1313155192Srwatson outb(lpt_data_port, 0x08); 1314155192Srwatson while ((inb(lpt_stat_port) & 0x08) == 0) 1315155192Srwatson if (--spin == 0) { 1316155192Srwatson goto nend; 1317155192Srwatson } 1318155192Srwatson 1319155192Srwatson /* Calculate length of packet, then send that */ 1320155192Srwatson 1321155192Srwatson count += 14; /* Ethernet header len */ 1322155192Srwatson 1323155192Srwatson mm = m; 1324155192Srwatson for (mm = m; mm; mm = mm->m_next) { 1325155192Srwatson count += mm->m_len; 1326155192Srwatson } 1327155192Srwatson if (clpoutbyte(count & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 1328155192Srwatson goto nend; 1329155192Srwatson if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 1330155192Srwatson goto nend; 1331155192Srwatson 1332155192Srwatson /* Send dummy ethernet header */ 1333155192Srwatson for (i = 0; i < 12; i++) { 1334155192Srwatson if (clpoutbyte(i, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 1335156889Srwatson goto nend; 1336155192Srwatson chksum += i; 1337155192Srwatson } 1338155192Srwatson 1339155192Srwatson if (clpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 1340155192Srwatson goto nend; 1341155192Srwatson if (clpoutbyte(0x00, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 1342155192Srwatson goto nend; 1343155192Srwatson chksum += 0x08 + 0x00; /* Add into checksum */ 1344155192Srwatson 1345155192Srwatson mm = m; 1346155192Srwatson do { 1347155192Srwatson cp = mtod(mm, u_char *); 1348155192Srwatson while (mm->m_len--) { 1349155192Srwatson chksum += *cp; 1350155192Srwatson if (clpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 1351155192Srwatson goto nend; 1352155192Srwatson } 1353155192Srwatson } while ((mm = mm->m_next)); 1354155192Srwatson 1355155192Srwatson /* Send checksum */ 1356155192Srwatson if (clpoutbyte(chksum, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 1357155192Srwatson goto nend; 1358155192Srwatson 1359155192Srwatson /* Go quiescent */ 1360155192Srwatson outb(lpt_data_port, 0); 1361155192Srwatson 1362155192Srwatson err = 0; /* No errors */ 1363155192Srwatson 1364155192Srwatson nend: 1365155192Srwatson if (err) { /* if we didn't timeout... */ 1366155192Srwatson ifp->if_oerrors++; 1367155192Srwatson lprintf(("X")); 1368155192Srwatson } else { 1369155192Srwatson ifp->if_opackets++; 1370155192Srwatson ifp->if_obytes += m->m_pkthdr.len; 1371155192Srwatson } 1372155192Srwatson 1373155192Srwatson m_freem(m); 1374156889Srwatson 1375156889Srwatson if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) { 1376156889Srwatson lprintf(("^")); 1377155192Srwatson lptintr(ifp->if_unit); 1378155192Srwatson } 1379155192Srwatson (void) splx(s); 1380155192Srwatson return 0; 1381155192Srwatson } 1382155192Srwatson 1383155192Srwatson if (inb(lpt_stat_port) & LPIP_SHAKE) { 1384155192Srwatson lprintf(("&")); 1385155192Srwatson lptintr(ifp->if_unit); 1386155192Srwatson } 1387155192Srwatson 1388155192Srwatson if (lpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 1389155192Srwatson goto end; 1390155192Srwatson if (lpoutbyte(0x00, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 1391155192Srwatson goto end; 1392155192Srwatson 1393155192Srwatson mm = m; 1394155192Srwatson do { 1395155192Srwatson cp = mtod(mm,u_char *); 1396155192Srwatson while (mm->m_len--) 1397155192Srwatson if (lpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 1398155192Srwatson goto end; 1399155192Srwatson } while ((mm = mm->m_next)); 1400155192Srwatson 1401155192Srwatson err = 0; /* no errors were encountered */ 1402155192Srwatson 1403155192Srwatson end: 1404155192Srwatson --cp; 1405162990Srwatson outb(lpt_data_port, txmitl[*cp] ^ 0x17); 1406156889Srwatson 1407155192Srwatson if (err) { /* if we didn't timeout... */ 1408156889Srwatson ifp->if_oerrors++; 1409155192Srwatson lprintf(("X")); 1410155192Srwatson } else { 1411155192Srwatson ifp->if_opackets++; 1412155192Srwatson ifp->if_obytes += m->m_pkthdr.len; 1413155192Srwatson#if NBPF > 0 1414155192Srwatson if (ifp->if_bpf) { 1415156889Srwatson /* 1416155192Srwatson * We need to prepend the packet type as 1417155192Srwatson * a two byte field. Cons up a dummy header 1418155192Srwatson * to pacify bpf. This is safe because bpf 1419155192Srwatson * will only read from the mbuf (i.e., it won't 1420155192Srwatson * try to free it or keep a pointer to it). 1421155192Srwatson */ 1422155192Srwatson struct mbuf m0; 1423155192Srwatson u_short hdr = 0x800; 1424155192Srwatson 1425155192Srwatson m0.m_next = m; 1426156889Srwatson m0.m_len = 2; 1427156889Srwatson m0.m_data = (char *)&hdr; 1428156889Srwatson 1429155192Srwatson bpf_mtap(ifp, &m0); 1430155192Srwatson } 1431155192Srwatson#endif 1432155192Srwatson } 1433155192Srwatson 1434156889Srwatson m_freem(m); 1435156889Srwatson 1436155192Srwatson if (inb(lpt_stat_port) & LPIP_SHAKE) { 1437155192Srwatson lprintf(("^")); 1438156889Srwatson lptintr(ifp->if_unit); 1439156889Srwatson } 1440155192Srwatson 1441155192Srwatson (void) splx(s); 1442156889Srwatson return 0; 1443156889Srwatson} 1444155192Srwatson 1445155192Srwatson#endif /* INET */ 1446155192Srwatson 1447static int lpt_devsw_installed; 1448 1449static void lpt_drvinit(void *unused) 1450{ 1451 1452 if( ! lpt_devsw_installed ) { 1453 cdevsw_add(&lpt_cdevsw); 1454 lpt_devsw_installed = 1; 1455 } 1456} 1457 1458SYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL) 1459 1460