olpt.c revision 48006
148006Skato/* 248006Skato * Copyright (c) 1990 William F. Jolitz, TeleMuse 348006Skato * All rights reserved. 448006Skato * 548006Skato * Redistribution and use in source and binary forms, with or without 648006Skato * modification, are permitted provided that the following conditions 748006Skato * are met: 848006Skato * 1. Redistributions of source code must retain the above copyright 948006Skato * notice, this list of conditions and the following disclaimer. 1048006Skato * 2. Redistributions in binary form must reproduce the above copyright 1148006Skato * notice, this list of conditions and the following disclaimer in the 1248006Skato * documentation and/or other materials provided with the distribution. 1348006Skato * 3. All advertising materials mentioning features or use of this software 1448006Skato * must display the following acknowledgement: 1548006Skato * This software is a component of "386BSD" developed by 1648006Skato * William F. Jolitz, TeleMuse. 1748006Skato * 4. Neither the name of the developer nor the name "386BSD" 1848006Skato * may be used to endorse or promote products derived from this software 1948006Skato * without specific prior written permission. 2048006Skato * 2148006Skato * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 2248006Skato * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 2348006Skato * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 2448006Skato * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 2548006Skato * NOT MAKE USE OF THIS WORK. 2648006Skato * 2748006Skato * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED 2848006Skato * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 2948006Skato * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES 3048006Skato * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 3148006Skato * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 3248006Skato * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 3348006Skato * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 3448006Skato * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. 3548006Skato * 3648006Skato * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND 3748006Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3848006Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3948006Skato * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE 4048006Skato * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4148006Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4248006Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4348006Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4448006Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 4548006Skato * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 4648006Skato * SUCH DAMAGE. 4748006Skato * 4848006Skato * from: unknown origin, 386BSD 0.1 4948006Skato * $Id$ 5048006Skato */ 5148006Skato 5248006Skato/* 5348006Skato * Device Driver for AT parallel printer port 5448006Skato * Written by William Jolitz 12/18/90 5548006Skato */ 5648006Skato 5748006Skato/* 5848006Skato * Parallel port TCP/IP interfaces added. I looked at the driver from 5948006Skato * MACH but this is a complete rewrite, and btw. incompatible, and it 6048006Skato * should perform better too. I have never run the MACH driver though. 6148006Skato * 6248006Skato * This driver sends two bytes (0x08, 0x00) in front of each packet, 6348006Skato * to allow us to distinguish another format later. 6448006Skato * 6548006Skato * Now added an Linux/Crynwr compatibility mode which is enabled using 6648006Skato * IF_LINK0 - Tim Wilkinson. 6748006Skato * 6848006Skato * TODO: 6948006Skato * Make HDLC/PPP mode, use IF_LLC1 to enable. 7048006Skato * 7148006Skato * Connect the two computers using a Laplink parallel cable to use this 7248006Skato * feature: 7348006Skato * 7448006Skato * +----------------------------------------+ 7548006Skato * |A-name A-End B-End Descr. Port/Bit | 7648006Skato * +----------------------------------------+ 7748006Skato * |DATA0 2 15 Data 0/0x01 | 7848006Skato * |-ERROR 15 2 1/0x08 | 7948006Skato * +----------------------------------------+ 8048006Skato * |DATA1 3 13 Data 0/0x02 | 8148006Skato * |+SLCT 13 3 1/0x10 | 8248006Skato * +----------------------------------------+ 8348006Skato * |DATA2 4 12 Data 0/0x04 | 8448006Skato * |+PE 12 4 1/0x20 | 8548006Skato * +----------------------------------------+ 8648006Skato * |DATA3 5 10 Strobe 0/0x08 | 8748006Skato * |-ACK 10 5 1/0x40 | 8848006Skato * +----------------------------------------+ 8948006Skato * |DATA4 6 11 Data 0/0x10 | 9048006Skato * |BUSY 11 6 1/~0x80 | 9148006Skato * +----------------------------------------+ 9248006Skato * |GND 18-25 18-25 GND - | 9348006Skato * +----------------------------------------+ 9448006Skato * 9548006Skato * Expect transfer-rates up to 75 kbyte/sec. 9648006Skato * 9748006Skato * If GCC could correctly grok 9848006Skato * register int port asm("edx") 9948006Skato * the code would be cleaner 10048006Skato * 10148006Skato * Poul-Henning Kamp <phk@freebsd.org> 10248006Skato */ 10348006Skato 10448006Skato#include "olpt.h" 10548006Skato#include "opt_devfs.h" 10648006Skato#include "opt_inet.h" 10748006Skato#ifdef PC98 10848006Skato#undef INET /* PLIP is not supported for old PC-98 */ 10948006Skato#endif 11048006Skato 11148006Skato#include <sys/param.h> 11248006Skato#include <sys/systm.h> 11348006Skato#include <sys/conf.h> 11448006Skato#include <sys/buf.h> 11548006Skato#include <sys/kernel.h> 11648006Skato#include <sys/uio.h> 11748006Skato#include <sys/syslog.h> 11848006Skato#ifdef DEVFS 11948006Skato#include <sys/devfsext.h> 12048006Skato#endif /*DEVFS*/ 12148006Skato 12248006Skato#include <machine/clock.h> 12348006Skato#include <machine/lpt.h> 12448006Skato 12548006Skato#include <vm/vm.h> 12648006Skato#include <vm/vm_param.h> 12748006Skato#include <vm/pmap.h> 12848006Skato 12948006Skato#ifdef PC98 13048006Skato#include <pc98/pc98/pc98.h> 13148006Skato#else 13248006Skato#include <i386/isa/isa.h> 13348006Skato#endif 13448006Skato#include <i386/isa/isa_device.h> 13548006Skato#include <i386/isa/lptreg.h> 13648006Skato 13748006Skato#ifdef INET 13848006Skato#include <sys/malloc.h> 13948006Skato#include <sys/mbuf.h> 14048006Skato#include <sys/socket.h> 14148006Skato#include <sys/sockio.h> 14248006Skato 14348006Skato#include <net/if.h> 14448006Skato#include <net/if_types.h> 14548006Skato#include <net/netisr.h> 14648006Skato#include <netinet/in.h> 14748006Skato#include <netinet/in_var.h> 14848006Skato#include "bpfilter.h" 14948006Skato#if NBPFILTER > 0 15048006Skato#include <net/bpf.h> 15148006Skato#endif 15248006Skato#endif /* INET */ 15348006Skato 15448006Skato 15548006Skato#define LPINITRDY 4 /* wait up to 4 seconds for a ready */ 15648006Skato#define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */ 15748006Skato#define LPTOUTMAX 1 /* maximal timeout 1 s */ 15848006Skato#define LPPRI (PZERO+8) 15948006Skato#define BUFSIZE 1024 16048006Skato 16148006Skato#ifdef INET 16248006Skato#ifndef LPMTU /* MTU for the lp# interfaces */ 16348006Skato#define LPMTU 1500 16448006Skato#endif 16548006Skato 16648006Skato#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */ 16748006Skato#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */ 16848006Skato#endif 16948006Skato 17048006Skato#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */ 17148006Skato#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */ 17248006Skato#endif 17348006Skato 17448006Skato#ifndef LPMAXERRS /* Max errors before !RUNNING */ 17548006Skato#define LPMAXERRS 100 17648006Skato#endif 17748006Skato 17848006Skato#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */ 17948006Skato#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */ 18048006Skato#define MLPIPHDRLEN CLPIPHDRLEN 18148006Skato 18248006Skato#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */ 18348006Skato#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */ 18448006Skato#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN 18548006Skato#define MLPIPHDRLEN LPIPHDRLEN 18648006Skato#endif 18748006Skato 18848006Skato#define LPIPTBLSIZE 256 /* Size of octet translation table */ 18948006Skato 19048006Skato#endif /* INET */ 19148006Skato 19248006Skato#ifndef PC98 19348006Skato/* BIOS printer list - used by BIOS probe*/ 19448006Skato#define BIOS_LPT_PORTS 0x408 19548006Skato#define BIOS_PORTS (short *)(KERNBASE+BIOS_LPT_PORTS) 19648006Skato#define BIOS_MAX_LPT 4 19748006Skato#endif 19848006Skato 19948006Skato 20048006Skato#ifndef DEBUG 20148006Skato#define lprintf(args) 20248006Skato#else 20348006Skato#define lprintf(args) do { \ 20448006Skato if (lptflag) \ 20548006Skato printf args; \ 20648006Skato } while (0) 20748006Skatostatic int volatile lptflag = 1; 20848006Skato#endif 20948006Skato 21048006Skato#define LPTUNIT(s) ((s)&0x03) 21148006Skato#define LPTFLAGS(s) ((s)&0xfc) 21248006Skato 21348006Skatostatic struct lpt_softc { 21448006Skato int sc_port; 21548006Skato short sc_state; 21648006Skato /* default case: negative prime, negative ack, handshake strobe, 21748006Skato prime once */ 21848006Skato u_char sc_control; 21948006Skato char sc_flags; 22048006Skato#define LP_POS_INIT 0x04 /* if we are a postive init signal */ 22148006Skato#define LP_POS_ACK 0x08 /* if we are a positive going ack */ 22248006Skato#define LP_NO_PRIME 0x10 /* don't prime the printer at all */ 22348006Skato#define LP_PRIMEOPEN 0x20 /* prime on every open */ 22448006Skato#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */ 22548006Skato#define LP_BYPASS 0x80 /* bypass printer ready checks */ 22648006Skato struct buf *sc_inbuf; 22748006Skato short sc_xfercnt ; 22848006Skato char sc_primed; 22948006Skato char *sc_cp ; 23048006Skato u_char sc_irq ; /* IRQ status of port */ 23148006Skato#define LP_HAS_IRQ 0x01 /* we have an irq available */ 23248006Skato#define LP_USE_IRQ 0x02 /* we are using our irq */ 23348006Skato#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ 23448006Skato u_char sc_backoff ; /* time to call lptout() again */ 23548006Skato 23648006Skato#ifdef INET 23748006Skato struct ifnet sc_if; 23848006Skato u_char *sc_ifbuf; 23948006Skato int sc_iferrs; 24048006Skato#endif 24148006Skato#ifdef DEVFS 24248006Skato void *devfs_token; 24348006Skato void *devfs_token_ctl; 24448006Skato#endif 24548006Skato} lpt_sc[NOLPT] ; 24648006Skato 24748006Skato/* bits for state */ 24848006Skato#define OPEN (1<<0) /* device is open */ 24948006Skato#define ASLP (1<<1) /* awaiting draining of printer */ 25048006Skato#define ERROR (1<<2) /* error was received from printer */ 25148006Skato#define OBUSY (1<<3) /* printer is busy doing output */ 25248006Skato#define LPTOUT (1<<4) /* timeout while not selected */ 25348006Skato#define TOUT (1<<5) /* timeout while not selected */ 25448006Skato#define INIT (1<<6) /* waiting to initialize for open */ 25548006Skato#define INTERRUPTED (1<<7) /* write call was interrupted */ 25648006Skato 25748006Skato 25848006Skato/* status masks to interrogate printer status */ 25948006Skato#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */ 26048006Skato#define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR) 26148006Skato 26248006Skato/* Printer Ready condition - from lpa.c */ 26348006Skato/* Only used in polling code */ 26448006Skato#ifdef PC98 26548006Skato#define NOT_READY(x) ((inb(x) & LPS_NBSY) != LPS_NBSY) 26648006Skato#else /* IBM-PC */ 26748006Skato#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR) 26848006Skato#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR) 26948006Skato#define NOT_READY(x) ((inb(x)^LPS_INVERT)&LPS_MASK) 27048006Skato#endif 27148006Skato 27248006Skato#define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */ 27348006Skato#define MAX_SPIN 20 /* Max delay for device ready in usecs */ 27448006Skato 27548006Skatostatic timeout_t lptout; 27648006Skatostatic int lptprobe (struct isa_device *dvp); 27748006Skatostatic int lptattach (struct isa_device *isdp); 27848006Skatostatic ointhand2_t lptintr; 27948006Skato 28048006Skato#ifdef INET 28148006Skato 28248006Skato/* Tables for the lp# interface */ 28348006Skatostatic u_char *txmith; 28448006Skato#define txmitl (txmith+(1*LPIPTBLSIZE)) 28548006Skato#define trecvh (txmith+(2*LPIPTBLSIZE)) 28648006Skato#define trecvl (txmith+(3*LPIPTBLSIZE)) 28748006Skato 28848006Skatostatic u_char *ctxmith; 28948006Skato#define ctxmitl (ctxmith+(1*LPIPTBLSIZE)) 29048006Skato#define ctrecvh (ctxmith+(2*LPIPTBLSIZE)) 29148006Skato#define ctrecvl (ctxmith+(3*LPIPTBLSIZE)) 29248006Skato 29348006Skato/* Functions for the lp# interface */ 29448006Skatostatic void lpattach(struct lpt_softc *,int); 29548006Skato#ifndef PC98 29648006Skatostatic int lpinittables(void); 29748006Skato#endif 29848006Skatostatic int lpioctl(struct ifnet *, u_long, caddr_t); 29948006Skatostatic int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 30048006Skato struct rtentry *); 30148006Skatostatic void lpintr(int); 30248006Skato#endif /* INET */ 30348006Skato 30448006Skatostruct isa_driver olptdriver = { 30548006Skato lptprobe, lptattach, "olpt" 30648006Skato}; 30748006Skato 30848006Skatostatic d_open_t lptopen; 30948006Skatostatic d_close_t lptclose; 31048006Skatostatic d_write_t lptwrite; 31148006Skatostatic d_ioctl_t lptioctl; 31248006Skato 31348006Skato#define CDEV_MAJOR 16 31448006Skatostatic struct cdevsw lpt_cdevsw = { 31548006Skato /* open */ lptopen, 31648006Skato /* close */ lptclose, 31748006Skato /* read */ noread, 31848006Skato /* write */ lptwrite, 31948006Skato /* ioctl */ lptioctl, 32048006Skato /* stop */ nostop, 32148006Skato /* reset */ noreset, 32248006Skato /* devtotty */ nodevtotty, 32348006Skato /* poll */ nopoll, 32448006Skato /* mmap */ nommap, 32548006Skato /* strategy */ nostrategy, 32648006Skato /* name */ "lpt", 32748006Skato /* parms */ noparms, 32848006Skato /* maj */ CDEV_MAJOR, 32948006Skato /* dump */ nodump, 33048006Skato /* psize */ nopsize, 33148006Skato /* flags */ 0, 33248006Skato /* maxio */ 0, 33348006Skato /* bmaj */ -1 33448006Skato}; 33548006Skato 33648006Skato#ifndef PC98 33748006Skato/* 33848006Skato * Internal routine to lptprobe to do port tests of one byte value 33948006Skato */ 34048006Skatostatic int 34148006Skatolpt_port_test (int port, u_char data, u_char mask) 34248006Skato{ 34348006Skato int temp, timeout; 34448006Skato 34548006Skato data = data & mask; 34648006Skato outb(port, data); 34748006Skato timeout = 10000; 34848006Skato do { 34948006Skato DELAY(10); 35048006Skato temp = inb(port) & mask; 35148006Skato } 35248006Skato while (temp != data && --timeout); 35348006Skato lprintf(("Port 0x%x\tout=%x\tin=%x\ttout=%d\n", 35448006Skato port, data, temp, timeout)); 35548006Skato return (temp == data); 35648006Skato} 35748006Skato#endif /* PC98 */ 35848006Skato 35948006Skato/* 36048006Skato * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 36148006Skato * Based partially on Rod Grimes' printer probe 36248006Skato * 36348006Skato * Logic: 36448006Skato * 1) If no port address was given, use the bios detected ports 36548006Skato * and autodetect what ports the printers are on. 36648006Skato * 2) Otherwise, probe the data port at the address given, 36748006Skato * using the method in Rod Grimes' port probe. 36848006Skato * (Much code ripped off directly from Rod's probe.) 36948006Skato * 37048006Skato * Comments from Rod's probe: 37148006Skato * Logic: 37248006Skato * 1) You should be able to write to and read back the same value 37348006Skato * to the data port. Do an alternating zeros, alternating ones, 37448006Skato * walking zero, and walking one test to check for stuck bits. 37548006Skato * 37648006Skato * 2) You should be able to write to and read back the same value 37748006Skato * to the control port lower 5 bits, the upper 3 bits are reserved 37848006Skato * per the IBM PC technical reference manauls and different boards 37948006Skato * do different things with them. Do an alternating zeros, alternating 38048006Skato * ones, walking zero, and walking one test to check for stuck bits. 38148006Skato * 38248006Skato * Some printers drag the strobe line down when the are powered off 38348006Skato * so this bit has been masked out of the control port test. 38448006Skato * 38548006Skato * XXX Some printers may not like a fast pulse on init or strobe, I 38648006Skato * don't know at this point, if that becomes a problem these bits 38748006Skato * should be turned off in the mask byte for the control port test. 38848006Skato * 38948006Skato * We are finally left with a mask of 0x14, due to some printers 39048006Skato * being adamant about holding other bits high ........ 39148006Skato * 39248006Skato * Before probing the control port, we write a 0 to the data port - 39348006Skato * If not, some printers chuck out garbage when the strobe line 39448006Skato * gets toggled. 39548006Skato * 39648006Skato * 3) Set the data and control ports to a value of 0 39748006Skato * 39848006Skato * This probe routine has been tested on Epson Lx-800, HP LJ3P, 39948006Skato * Epson FX-1170 and C.Itoh 8510RM 40048006Skato * printers. 40148006Skato * Quick exit on fail added. 40248006Skato */ 40348006Skato 40448006Skatoint 40548006Skatolptprobe(struct isa_device *dvp) 40648006Skato{ 40748006Skato#ifdef PC98 40848006Skato#define PC98_OLD_LPT 0x40 40948006Skato#define PC98_IEEE_1284_FUNCTION 0x149 41048006Skato unsigned int pc98_ieee_mode, tmp; 41148006Skato 41248006Skato if (dvp->id_iobase == PC98_OLD_LPT) { 41348006Skato tmp = inb(PC98_IEEE_1284_FUNCTION); 41448006Skato pc98_ieee_mode = tmp; 41548006Skato if ((tmp & 0x10) == 0x10) { 41648006Skato outb(PC98_IEEE_1284_FUNCTION, tmp & ~0x10); 41748006Skato tmp = inb(PC98_IEEE_1284_FUNCTION); 41848006Skato if ((tmp & 0x10) != 0x10) { 41948006Skato outb(PC98_IEEE_1284_FUNCTION, pc98_ieee_mode); 42048006Skato return 0; 42148006Skato } 42248006Skato } 42348006Skato } 42448006Skato return 8; 42548006Skato#else 42648006Skato int port; 42748006Skato static short next_bios_lpt = 0; 42848006Skato int status; 42948006Skato static u_char testbyte[18] = { 43048006Skato 0x55, /* alternating zeros */ 43148006Skato 0xaa, /* alternating ones */ 43248006Skato 0xfe, 0xfd, 0xfb, 0xf7, 43348006Skato 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ 43448006Skato 0x01, 0x02, 0x04, 0x08, 43548006Skato 0x10, 0x20, 0x40, 0x80 /* walking one */ 43648006Skato }; 43748006Skato int i; 43848006Skato 43948006Skato /* 44048006Skato * Make sure there is some way for lptopen to see that 44148006Skato * the port is not configured 44248006Skato * This 0 will remain if the port isn't attached 44348006Skato */ 44448006Skato (lpt_sc + dvp->id_unit)->sc_port = 0; 44548006Skato 44648006Skato status = IO_LPTSIZE; 44748006Skato /* If port not specified, use bios list */ 44848006Skato if(dvp->id_iobase < 0) { /* port? */ 44948006Skato if((next_bios_lpt < BIOS_MAX_LPT) && 45048006Skato (*(BIOS_PORTS+next_bios_lpt) != 0) ) { 45148006Skato dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++); 45248006Skato goto end_probe; 45348006Skato } else 45448006Skato return (0); 45548006Skato } 45648006Skato 45748006Skato /* Port was explicitly specified */ 45848006Skato /* This allows probing of ports unknown to the BIOS */ 45948006Skato port = dvp->id_iobase + lpt_data; 46048006Skato for (i = 0; i < 18; i++) { 46148006Skato if (!lpt_port_test(port, testbyte[i], 0xff)) { 46248006Skato status = 0; 46348006Skato goto end_probe; 46448006Skato } 46548006Skato } 46648006Skato 46748006Skatoend_probe: 46848006Skato /* write 0's to control and data ports */ 46948006Skato outb(dvp->id_iobase+lpt_data, 0); 47048006Skato outb(dvp->id_iobase+lpt_control, 0); 47148006Skato 47248006Skato return (status); 47348006Skato#endif 47448006Skato} 47548006Skato 47648006Skato/* XXX Todo - try and detect if interrupt is working */ 47748006Skatoint 47848006Skatolptattach(struct isa_device *isdp) 47948006Skato{ 48048006Skato struct lpt_softc *sc; 48148006Skato int unit; 48248006Skato 48348006Skato isdp->id_ointr = lptintr; 48448006Skato unit = isdp->id_unit; 48548006Skato sc = lpt_sc + unit; 48648006Skato sc->sc_port = isdp->id_iobase; 48748006Skato sc->sc_primed = 0; /* not primed yet */ 48848006Skato#ifdef PC98 48948006Skato outb(sc->sc_port+lpt_pstb_ctrl, LPC_DIS_PSTB); /* PSTB disable */ 49048006Skato outb(sc->sc_port+lpt_control, LPC_MODE8255); /* 8255 mode set */ 49148006Skato outb(sc->sc_port+lpt_control, LPC_NIRQ8); /* IRQ8 inactive */ 49248006Skato outb(sc->sc_port+lpt_control, LPC_NPSTB); /* PSTB inactive */ 49348006Skato outb(sc->sc_port+lpt_pstb_ctrl, LPC_EN_PSTB); /* PSTB enable */ 49448006Skato#else 49548006Skato outb(sc->sc_port+lpt_control, LPC_NINIT); 49648006Skato#endif 49748006Skato 49848006Skato /* check if we can use interrupt */ 49948006Skato lprintf(("oldirq %x\n", sc->sc_irq)); 50048006Skato if (isdp->id_irq) { 50148006Skato sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; 50248006Skato printf("lpt%d: Interrupt-driven port\n", unit); 50348006Skato#ifdef INET 50448006Skato lpattach(sc, unit); 50548006Skato#endif 50648006Skato } else { 50748006Skato sc->sc_irq = 0; 50848006Skato lprintf(("lpt%d: Polled port\n", unit)); 50948006Skato } 51048006Skato lprintf(("irq %x\n", sc->sc_irq)); 51148006Skato 51248006Skato#ifdef DEVFS 51348006Skato /* XXX what to do about the flags in the minor number? */ 51448006Skato sc->devfs_token = devfs_add_devswf(&lpt_cdevsw, 51548006Skato unit, DV_CHR, 51648006Skato UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit); 51748006Skato sc->devfs_token_ctl = devfs_add_devswf(&lpt_cdevsw, 51848006Skato unit | LP_BYPASS, DV_CHR, 51948006Skato UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit); 52048006Skato#endif 52148006Skato return (1); 52248006Skato} 52348006Skato 52448006Skato/* 52548006Skato * lptopen -- reset the printer, then wait until it's selected and not busy. 52648006Skato * If LP_BYPASS flag is selected, then we do not try to select the 52748006Skato * printer -- this is just used for passing ioctls. 52848006Skato */ 52948006Skato 53048006Skatostatic int 53148006Skatolptopen (dev_t dev, int flags, int fmt, struct proc *p) 53248006Skato{ 53348006Skato struct lpt_softc *sc; 53448006Skato int s; 53548006Skato#ifdef PC98 53648006Skato int port; 53748006Skato#else 53848006Skato int trys, port; 53948006Skato#endif 54048006Skato u_int unit = LPTUNIT(minor(dev)); 54148006Skato 54248006Skato sc = lpt_sc + unit; 54348006Skato if ((unit >= NOLPT) || (sc->sc_port == 0)) 54448006Skato return (ENXIO); 54548006Skato 54648006Skato#ifdef INET 54748006Skato if (sc->sc_if.if_flags & IFF_UP) 54848006Skato return(EBUSY); 54948006Skato#endif 55048006Skato 55148006Skato if (sc->sc_state) { 55248006Skato lprintf(("lp: still open %x\n", sc->sc_state)); 55348006Skato return(EBUSY); 55448006Skato } else 55548006Skato sc->sc_state |= INIT; 55648006Skato 55748006Skato sc->sc_flags = LPTFLAGS(minor(dev)); 55848006Skato 55948006Skato /* Check for open with BYPASS flag set. */ 56048006Skato if (sc->sc_flags & LP_BYPASS) { 56148006Skato sc->sc_state = OPEN; 56248006Skato return(0); 56348006Skato } 56448006Skato 56548006Skato s = spltty(); 56648006Skato lprintf(("lp flags 0x%x\n", sc->sc_flags)); 56748006Skato port = sc->sc_port; 56848006Skato 56948006Skato /* set IRQ status according to ENABLE_IRQ flag */ 57048006Skato if (sc->sc_irq & LP_ENABLE_IRQ) 57148006Skato sc->sc_irq |= LP_USE_IRQ; 57248006Skato else 57348006Skato sc->sc_irq &= ~LP_USE_IRQ; 57448006Skato 57548006Skato /* init printer */ 57648006Skato#ifndef PC98 57748006Skato if ((sc->sc_flags & LP_NO_PRIME) == 0) { 57848006Skato if((sc->sc_flags & LP_PRIMEOPEN) || sc->sc_primed == 0) { 57948006Skato outb(port+lpt_control, 0); 58048006Skato sc->sc_primed++; 58148006Skato DELAY(500); 58248006Skato } 58348006Skato } 58448006Skato 58548006Skato outb (port+lpt_control, LPC_SEL|LPC_NINIT); 58648006Skato 58748006Skato /* wait till ready (printer running diagnostics) */ 58848006Skato trys = 0; 58948006Skato do { 59048006Skato /* ran out of waiting for the printer */ 59148006Skato if (trys++ >= LPINITRDY*4) { 59248006Skato splx(s); 59348006Skato sc->sc_state = 0; 59448006Skato lprintf(("status %x\n", inb(port+lpt_status))); 59548006Skato return (EBUSY); 59648006Skato } 59748006Skato 59848006Skato /* wait 1/4 second, give up if we get a signal */ 59948006Skato if (tsleep ((caddr_t)sc, LPPRI|PCATCH, "lptinit", hz/4) != 60048006Skato EWOULDBLOCK) { 60148006Skato sc->sc_state = 0; 60248006Skato splx(s); 60348006Skato return (EBUSY); 60448006Skato } 60548006Skato 60648006Skato /* is printer online and ready for output */ 60748006Skato } while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != 60848006Skato (LPS_SEL|LPS_NBSY|LPS_NERR)); 60948006Skato 61048006Skato sc->sc_control = LPC_SEL|LPC_NINIT; 61148006Skato if (sc->sc_flags & LP_AUTOLF) 61248006Skato sc->sc_control |= LPC_AUTOL; 61348006Skato 61448006Skato /* enable interrupt if interrupt-driven */ 61548006Skato if (sc->sc_irq & LP_USE_IRQ) 61648006Skato sc->sc_control |= LPC_ENA; 61748006Skato 61848006Skato outb(port+lpt_control, sc->sc_control); 61948006Skato#endif 62048006Skato 62148006Skato sc->sc_state = OPEN; 62248006Skato sc->sc_inbuf = geteblk(BUFSIZE); 62348006Skato sc->sc_xfercnt = 0; 62448006Skato splx(s); 62548006Skato 62648006Skato /* only use timeout if using interrupt */ 62748006Skato lprintf(("irq %x\n", sc->sc_irq)); 62848006Skato if (sc->sc_irq & LP_USE_IRQ) { 62948006Skato sc->sc_state |= TOUT; 63048006Skato timeout (lptout, (caddr_t)sc, 63148006Skato (sc->sc_backoff = hz/LPTOUTINITIAL)); 63248006Skato } 63348006Skato 63448006Skato lprintf(("opened.\n")); 63548006Skato return(0); 63648006Skato} 63748006Skato 63848006Skatostatic void 63948006Skatolptout (void *arg) 64048006Skato{ 64148006Skato struct lpt_softc *sc = arg; 64248006Skato int pl; 64348006Skato 64448006Skato lprintf(("T %x ", inb(sc->sc_port+lpt_status))); 64548006Skato if (sc->sc_state & OPEN) { 64648006Skato sc->sc_backoff++; 64748006Skato if (sc->sc_backoff > hz/LPTOUTMAX) 64848006Skato sc->sc_backoff = sc->sc_backoff > hz/LPTOUTMAX; 64948006Skato timeout (lptout, (caddr_t)sc, sc->sc_backoff); 65048006Skato } else 65148006Skato sc->sc_state &= ~TOUT; 65248006Skato 65348006Skato if (sc->sc_state & ERROR) 65448006Skato sc->sc_state &= ~ERROR; 65548006Skato 65648006Skato /* 65748006Skato * Avoid possible hangs do to missed interrupts 65848006Skato */ 65948006Skato if (sc->sc_xfercnt) { 66048006Skato pl = spltty(); 66148006Skato lptintr(sc - lpt_sc); 66248006Skato splx(pl); 66348006Skato } else { 66448006Skato sc->sc_state &= ~OBUSY; 66548006Skato wakeup((caddr_t)sc); 66648006Skato } 66748006Skato} 66848006Skato 66948006Skato/* 67048006Skato * lptclose -- close the device, free the local line buffer. 67148006Skato * 67248006Skato * Check for interrupted write call added. 67348006Skato */ 67448006Skato 67548006Skatostatic int 67648006Skatolptclose(dev_t dev, int flags, int fmt, struct proc *p) 67748006Skato{ 67848006Skato struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); 67948006Skato#ifndef PC98 68048006Skato int port = sc->sc_port; 68148006Skato#endif 68248006Skato 68348006Skato if(sc->sc_flags & LP_BYPASS) 68448006Skato goto end_close; 68548006Skato 68648006Skato sc->sc_state &= ~OPEN; 68748006Skato 68848006Skato#ifndef PC98 68948006Skato /* if the last write was interrupted, don't complete it */ 69048006Skato if((!(sc->sc_state & INTERRUPTED)) && (sc->sc_irq & LP_USE_IRQ)) 69148006Skato while ((inb(port+lpt_status) & (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR)) != 69248006Skato (LPS_SEL|LPS_NBSY|LPS_NERR) || sc->sc_xfercnt) 69348006Skato /* wait 1/4 second, give up if we get a signal */ 69448006Skato if (tsleep ((caddr_t)sc, LPPRI|PCATCH, 69548006Skato "lpclose", hz) != EWOULDBLOCK) 69648006Skato break; 69748006Skato 69848006Skato outb(sc->sc_port+lpt_control, LPC_NINIT); 69948006Skato#endif 70048006Skato brelse(sc->sc_inbuf); 70148006Skato 70248006Skatoend_close: 70348006Skato sc->sc_state = 0; 70448006Skato sc->sc_xfercnt = 0; 70548006Skato lprintf(("closed.\n")); 70648006Skato return(0); 70748006Skato} 70848006Skato 70948006Skato/* 71048006Skato * pushbytes() 71148006Skato * Workhorse for actually spinning and writing bytes to printer 71248006Skato * Derived from lpa.c 71348006Skato * Originally by ? 71448006Skato * 71548006Skato * This code is only used when we are polling the port 71648006Skato */ 71748006Skatostatic int 71848006Skatopushbytes(struct lpt_softc * sc) 71948006Skato{ 72048006Skato int spin, err, tic; 72148006Skato char ch; 72248006Skato int port = sc->sc_port; 72348006Skato 72448006Skato lprintf(("p")); 72548006Skato /* loop for every character .. */ 72648006Skato while (sc->sc_xfercnt > 0) { 72748006Skato /* printer data */ 72848006Skato ch = *(sc->sc_cp); 72948006Skato sc->sc_cp++; 73048006Skato sc->sc_xfercnt--; 73148006Skato 73248006Skato /* 73348006Skato * Wait for printer ready. 73448006Skato * Loop 20 usecs testing BUSY bit, then sleep 73548006Skato * for exponentially increasing timeout. (vak) 73648006Skato */ 73748006Skato for (spin=0; NOT_READY(port+lpt_status) && spin<MAX_SPIN; ++spin) 73848006Skato DELAY(1); /* XXX delay is NOT this accurate! */ 73948006Skato if (spin >= MAX_SPIN) { 74048006Skato tic = 0; 74148006Skato while (NOT_READY(port+lpt_status)) { 74248006Skato /* 74348006Skato * Now sleep, every cycle a 74448006Skato * little longer .. 74548006Skato */ 74648006Skato tic = tic + tic + 1; 74748006Skato /* 74848006Skato * But no more than 10 seconds. (vak) 74948006Skato */ 75048006Skato if (tic > MAX_SLEEP) 75148006Skato tic = MAX_SLEEP; 75248006Skato err = tsleep((caddr_t)sc, LPPRI, 75348006Skato "lptpoll", tic); 75448006Skato if (err != EWOULDBLOCK) { 75548006Skato return (err); 75648006Skato } 75748006Skato } 75848006Skato } 75948006Skato 76048006Skato /* output data */ 76148006Skato outb(port+lpt_data, ch); 76248006Skato#ifdef PC98 76348006Skato DELAY(1); 76448006Skato outb(port+lpt_control, LPC_PSTB); 76548006Skato DELAY(1); 76648006Skato outb(port+lpt_control, LPC_NPSTB); 76748006Skato#else 76848006Skato /* strobe */ 76948006Skato outb(port+lpt_control, sc->sc_control|LPC_STB); 77048006Skato outb(port+lpt_control, sc->sc_control); 77148006Skato#endif 77248006Skato 77348006Skato } 77448006Skato return(0); 77548006Skato} 77648006Skato 77748006Skato/* 77848006Skato * lptwrite --copy a line from user space to a local buffer, then call 77948006Skato * putc to get the chars moved to the output queue. 78048006Skato * 78148006Skato * Flagging of interrupted write added. 78248006Skato */ 78348006Skato 78448006Skatostatic int 78548006Skatolptwrite(dev_t dev, struct uio * uio, int ioflag) 78648006Skato{ 78748006Skato register unsigned n; 78848006Skato int pl, err; 78948006Skato struct lpt_softc *sc = lpt_sc + LPTUNIT(minor(dev)); 79048006Skato 79148006Skato if(sc->sc_flags & LP_BYPASS) { 79248006Skato /* we can't do writes in bypass mode */ 79348006Skato return(EPERM); 79448006Skato } 79548006Skato 79648006Skato sc->sc_state &= ~INTERRUPTED; 79748006Skato while ((n = min(BUFSIZE, uio->uio_resid)) != 0) { 79848006Skato sc->sc_cp = sc->sc_inbuf->b_data ; 79948006Skato uiomove(sc->sc_cp, n, uio); 80048006Skato sc->sc_xfercnt = n ; 80148006Skato while ((sc->sc_xfercnt > 0)&&(sc->sc_irq & LP_USE_IRQ)) { 80248006Skato lprintf(("i")); 80348006Skato /* if the printer is ready for a char, */ 80448006Skato /* give it one */ 80548006Skato if ((sc->sc_state & OBUSY) == 0){ 80648006Skato lprintf(("\nC %d. ", sc->sc_xfercnt)); 80748006Skato pl = spltty(); 80848006Skato lptintr(sc - lpt_sc); 80948006Skato (void) splx(pl); 81048006Skato } 81148006Skato lprintf(("W ")); 81248006Skato if (sc->sc_state & OBUSY) 81348006Skato if ((err = tsleep ((caddr_t)sc, 81448006Skato LPPRI|PCATCH, "lpwrite", 0))) { 81548006Skato sc->sc_state |= INTERRUPTED; 81648006Skato return(err); 81748006Skato } 81848006Skato } 81948006Skato /* check to see if we must do a polled write */ 82048006Skato if(!(sc->sc_irq & LP_USE_IRQ) && (sc->sc_xfercnt)) { 82148006Skato lprintf(("p")); 82248006Skato if((err = pushbytes(sc))) 82348006Skato return(err); 82448006Skato } 82548006Skato } 82648006Skato return(0); 82748006Skato} 82848006Skato 82948006Skato/* 83048006Skato * lptintr -- handle printer interrupts which occur when the printer is 83148006Skato * ready to accept another char. 83248006Skato * 83348006Skato * do checking for interrupted write call. 83448006Skato */ 83548006Skato 83648006Skatostatic void 83748006Skatolptintr(int unit) 83848006Skato{ 83948006Skato struct lpt_softc *sc = lpt_sc + unit; 84048006Skato#ifndef PC98 84148006Skato int port = sc->sc_port, sts; 84248006Skato int i; 84348006Skato#endif 84448006Skato 84548006Skato#ifdef INET 84648006Skato if(sc->sc_if.if_flags & IFF_UP) { 84748006Skato lpintr(unit); 84848006Skato return; 84948006Skato } 85048006Skato#endif /* INET */ 85148006Skato 85248006Skato#ifndef PC98 85348006Skato /* 85448006Skato * Is printer online and ready for output? 85548006Skato * 85648006Skato * Avoid falling back to lptout() too quickly. First spin-loop 85748006Skato * to see if the printer will become ready ``really soon now''. 85848006Skato */ 85948006Skato for (i = 0; 86048006Skato i < 100 && 86148006Skato ((sts=inb(port+lpt_status)) & RDY_MASK) != LP_READY; 86248006Skato i++) ; 86348006Skato if ((sts & RDY_MASK) == LP_READY) { 86448006Skato sc->sc_state = (sc->sc_state | OBUSY) & ~ERROR; 86548006Skato sc->sc_backoff = hz/LPTOUTINITIAL; 86648006Skato 86748006Skato if (sc->sc_xfercnt) { 86848006Skato /* send char */ 86948006Skato /*lprintf(("%x ", *sc->sc_cp)); */ 87048006Skato outb(port+lpt_data, *sc->sc_cp++) ; 87148006Skato outb(port+lpt_control, sc->sc_control|LPC_STB); 87248006Skato /* DELAY(X) */ 87348006Skato outb(port+lpt_control, sc->sc_control); 87448006Skato 87548006Skato /* any more data for printer */ 87648006Skato if(--(sc->sc_xfercnt) > 0) return; 87748006Skato } 87848006Skato 87948006Skato /* 88048006Skato * No more data waiting for printer. 88148006Skato * Wakeup is not done if write call was interrupted. 88248006Skato */ 88348006Skato sc->sc_state &= ~OBUSY; 88448006Skato if(!(sc->sc_state & INTERRUPTED)) 88548006Skato wakeup((caddr_t)sc); 88648006Skato lprintf(("w ")); 88748006Skato return; 88848006Skato } else { /* check for error */ 88948006Skato if(((sts & (LPS_NERR | LPS_OUT) ) != LPS_NERR) && 89048006Skato (sc->sc_state & OPEN)) 89148006Skato sc->sc_state |= ERROR; 89248006Skato /* lptout() will jump in and try to restart. */ 89348006Skato } 89448006Skato#endif 89548006Skato lprintf(("sts %x ", sts)); 89648006Skato} 89748006Skato 89848006Skatostatic int 89948006Skatolptioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 90048006Skato{ 90148006Skato int error = 0; 90248006Skato struct lpt_softc *sc; 90348006Skato u_int unit = LPTUNIT(minor(dev)); 90448006Skato u_char old_sc_irq; /* old printer IRQ status */ 90548006Skato 90648006Skato sc = lpt_sc + unit; 90748006Skato 90848006Skato switch (cmd) { 90948006Skato case LPT_IRQ : 91048006Skato if(sc->sc_irq & LP_HAS_IRQ) { 91148006Skato /* 91248006Skato * NOTE: 91348006Skato * If the IRQ status is changed, 91448006Skato * this will only be visible on the 91548006Skato * next open. 91648006Skato * 91748006Skato * If interrupt status changes, 91848006Skato * this gets syslog'd. 91948006Skato */ 92048006Skato old_sc_irq = sc->sc_irq; 92148006Skato if(*(int*)data == 0) 92248006Skato sc->sc_irq &= (~LP_ENABLE_IRQ); 92348006Skato else 92448006Skato sc->sc_irq |= LP_ENABLE_IRQ; 92548006Skato if (old_sc_irq != sc->sc_irq ) 92648006Skato log(LOG_NOTICE, "lpt%c switched to %s mode\n", 92748006Skato (char)unit+'0', 92848006Skato (sc->sc_irq & LP_ENABLE_IRQ)? 92948006Skato "interrupt-driven":"polled"); 93048006Skato } else /* polled port */ 93148006Skato error = EOPNOTSUPP; 93248006Skato break; 93348006Skato default: 93448006Skato error = ENODEV; 93548006Skato } 93648006Skato 93748006Skato return(error); 93848006Skato} 93948006Skato 94048006Skato#ifdef INET 94148006Skato 94248006Skatostatic void 94348006Skatolpattach (struct lpt_softc *sc, int unit) 94448006Skato{ 94548006Skato struct ifnet *ifp = &sc->sc_if; 94648006Skato 94748006Skato ifp->if_softc = sc; 94848006Skato ifp->if_name = "lp"; 94948006Skato ifp->if_unit = unit; 95048006Skato ifp->if_mtu = LPMTU; 95148006Skato ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 95248006Skato ifp->if_ioctl = lpioctl; 95348006Skato ifp->if_output = lpoutput; 95448006Skato ifp->if_type = IFT_PARA; 95548006Skato ifp->if_hdrlen = 0; 95648006Skato ifp->if_addrlen = 0; 95748006Skato ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; 95848006Skato if_attach(ifp); 95948006Skato printf("lp%d: TCP/IP capable interface\n", unit); 96048006Skato 96148006Skato#if NBPFILTER > 0 96248006Skato bpfattach(ifp, DLT_NULL, LPIPHDRLEN); 96348006Skato#endif 96448006Skato} 96548006Skato 96648006Skato#ifndef PC98 96748006Skato/* 96848006Skato * Build the translation tables for the LPIP (BSD unix) protocol. 96948006Skato * We don't want to calculate these nasties in our tight loop, so we 97048006Skato * precalculate them when we initialize. 97148006Skato */ 97248006Skatostatic int 97348006Skatolpinittables (void) 97448006Skato{ 97548006Skato int i; 97648006Skato 97748006Skato if (!txmith) 97848006Skato txmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 97948006Skato 98048006Skato if (!txmith) 98148006Skato return 1; 98248006Skato 98348006Skato if (!ctxmith) 98448006Skato ctxmith = malloc(4*LPIPTBLSIZE, M_DEVBUF, M_NOWAIT); 98548006Skato 98648006Skato if (!ctxmith) 98748006Skato return 1; 98848006Skato 98948006Skato for (i=0; i < LPIPTBLSIZE; i++) { 99048006Skato ctxmith[i] = (i & 0xF0) >> 4; 99148006Skato ctxmitl[i] = 0x10 | (i & 0x0F); 99248006Skato ctrecvh[i] = (i & 0x78) << 1; 99348006Skato ctrecvl[i] = (i & 0x78) >> 3; 99448006Skato } 99548006Skato 99648006Skato for (i=0; i < LPIPTBLSIZE; i++) { 99748006Skato txmith[i] = ((i & 0x80) >> 3) | ((i & 0x70) >> 4) | 0x08; 99848006Skato txmitl[i] = ((i & 0x08) << 1) | (i & 0x07); 99948006Skato trecvh[i] = ((~i) & 0x80) | ((i & 0x38) << 1); 100048006Skato trecvl[i] = (((~i) & 0x80) >> 4) | ((i & 0x38) >> 3); 100148006Skato } 100248006Skato 100348006Skato return 0; 100448006Skato} 100548006Skato#endif /* PC98 */ 100648006Skato 100748006Skato/* 100848006Skato * Process an ioctl request. 100948006Skato */ 101048006Skato 101148006Skatostatic int 101248006Skatolpioctl (struct ifnet *ifp, u_long cmd, caddr_t data) 101348006Skato{ 101448006Skato struct lpt_softc *sc = lpt_sc + ifp->if_unit; 101548006Skato struct ifaddr *ifa = (struct ifaddr *)data; 101648006Skato struct ifreq *ifr = (struct ifreq *)data; 101748006Skato u_char *ptr; 101848006Skato 101948006Skato switch (cmd) { 102048006Skato 102148006Skato case SIOCSIFDSTADDR: 102248006Skato case SIOCAIFADDR: 102348006Skato case SIOCSIFADDR: 102448006Skato if (ifa->ifa_addr->sa_family != AF_INET) 102548006Skato return EAFNOSUPPORT; 102648006Skato ifp->if_flags |= IFF_UP; 102748006Skato /* FALLTHROUGH */ 102848006Skato case SIOCSIFFLAGS: 102948006Skato if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 103048006Skato outb(sc->sc_port + lpt_control, 0x00); 103148006Skato ifp->if_flags &= ~IFF_RUNNING; 103248006Skato break; 103348006Skato } 103448006Skato#ifdef PC98 103548006Skato /* XXX */ 103648006Skato return ENOBUFS; 103748006Skato#else 103848006Skato if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 103948006Skato if (lpinittables()) 104048006Skato return ENOBUFS; 104148006Skato sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, 104248006Skato M_DEVBUF, M_WAITOK); 104348006Skato if (!sc->sc_ifbuf) 104448006Skato return ENOBUFS; 104548006Skato 104648006Skato outb(sc->sc_port + lpt_control, LPC_ENA); 104748006Skato ifp->if_flags |= IFF_RUNNING; 104848006Skato } 104948006Skato break; 105048006Skato#endif 105148006Skato case SIOCSIFMTU: 105248006Skato ptr = sc->sc_ifbuf; 105348006Skato sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); 105448006Skato if (!sc->sc_ifbuf) { 105548006Skato sc->sc_ifbuf = ptr; 105648006Skato return ENOBUFS; 105748006Skato } 105848006Skato if (ptr) 105948006Skato free(ptr,M_DEVBUF); 106048006Skato sc->sc_if.if_mtu = ifr->ifr_mtu; 106148006Skato break; 106248006Skato 106348006Skato case SIOCGIFMTU: 106448006Skato ifr->ifr_mtu = sc->sc_if.if_mtu; 106548006Skato break; 106648006Skato 106748006Skato case SIOCADDMULTI: 106848006Skato case SIOCDELMULTI: 106948006Skato if (ifr == 0) { 107048006Skato return EAFNOSUPPORT; /* XXX */ 107148006Skato } 107248006Skato switch (ifr->ifr_addr.sa_family) { 107348006Skato 107448006Skato#ifdef INET 107548006Skato case AF_INET: 107648006Skato break; 107748006Skato#endif 107848006Skato 107948006Skato default: 108048006Skato return EAFNOSUPPORT; 108148006Skato } 108248006Skato break; 108348006Skato 108448006Skato default: 108548006Skato lprintf(("LP:ioctl(0x%lx)\n", cmd)); 108648006Skato return EINVAL; 108748006Skato } 108848006Skato return 0; 108948006Skato} 109048006Skato 109148006Skatostatic __inline int 109248006Skatoclpoutbyte (u_char byte, int spin, int data_port, int status_port) 109348006Skato{ 109448006Skato outb(data_port, ctxmitl[byte]); 109548006Skato while (inb(status_port) & CLPIP_SHAKE) 109648006Skato if (--spin == 0) { 109748006Skato return 1; 109848006Skato } 109948006Skato outb(data_port, ctxmith[byte]); 110048006Skato while (!(inb(status_port) & CLPIP_SHAKE)) 110148006Skato if (--spin == 0) { 110248006Skato return 1; 110348006Skato } 110448006Skato return 0; 110548006Skato} 110648006Skato 110748006Skatostatic __inline int 110848006Skatoclpinbyte (int spin, int data_port, int status_port) 110948006Skato{ 111048006Skato int c, cl; 111148006Skato 111248006Skato while((inb(status_port) & CLPIP_SHAKE)) 111348006Skato if(!--spin) { 111448006Skato return -1; 111548006Skato } 111648006Skato cl = inb(status_port); 111748006Skato outb(data_port, 0x10); 111848006Skato 111948006Skato while(!(inb(status_port) & CLPIP_SHAKE)) 112048006Skato if(!--spin) { 112148006Skato return -1; 112248006Skato } 112348006Skato c = inb(status_port); 112448006Skato outb(data_port, 0x00); 112548006Skato 112648006Skato return (ctrecvl[cl] | ctrecvh[c]); 112748006Skato} 112848006Skato 112948006Skatostatic void 113048006Skatolpintr (int unit) 113148006Skato{ 113248006Skato struct lpt_softc *sc = lpt_sc + unit; 113348006Skato register int lpt_data_port = sc->sc_port + lpt_data; 113448006Skato register int lpt_stat_port = sc->sc_port + lpt_status; 113548006Skato int lpt_ctrl_port = sc->sc_port + lpt_control; 113648006Skato int len, s, j; 113748006Skato u_char *bp; 113848006Skato u_char c, cl; 113948006Skato struct mbuf *top; 114048006Skato 114148006Skato s = splhigh(); 114248006Skato 114348006Skato if (sc->sc_if.if_flags & IFF_LINK0) { 114448006Skato 114548006Skato /* Ack. the request */ 114648006Skato outb(lpt_data_port, 0x01); 114748006Skato 114848006Skato /* Get the packet length */ 114948006Skato j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 115048006Skato if (j == -1) 115148006Skato goto err; 115248006Skato len = j; 115348006Skato j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 115448006Skato if (j == -1) 115548006Skato goto err; 115648006Skato len = len + (j << 8); 115748006Skato if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) 115848006Skato goto err; 115948006Skato 116048006Skato bp = sc->sc_ifbuf; 116148006Skato 116248006Skato while (len--) { 116348006Skato j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 116448006Skato if (j == -1) { 116548006Skato goto err; 116648006Skato } 116748006Skato *bp++ = j; 116848006Skato } 116948006Skato /* Get and ignore checksum */ 117048006Skato j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); 117148006Skato if (j == -1) { 117248006Skato goto err; 117348006Skato } 117448006Skato 117548006Skato len = bp - sc->sc_ifbuf; 117648006Skato if (len <= CLPIPHDRLEN) 117748006Skato goto err; 117848006Skato 117948006Skato sc->sc_iferrs = 0; 118048006Skato 118148006Skato if (IF_QFULL(&ipintrq)) { 118248006Skato lprintf(("DROP")); 118348006Skato IF_DROP(&ipintrq); 118448006Skato goto done; 118548006Skato } 118648006Skato len -= CLPIPHDRLEN; 118748006Skato sc->sc_if.if_ipackets++; 118848006Skato sc->sc_if.if_ibytes += len; 118948006Skato top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); 119048006Skato if (top) { 119148006Skato IF_ENQUEUE(&ipintrq, top); 119248006Skato schednetisr(NETISR_IP); 119348006Skato } 119448006Skato goto done; 119548006Skato } 119648006Skato while ((inb(lpt_stat_port) & LPIP_SHAKE)) { 119748006Skato len = sc->sc_if.if_mtu + LPIPHDRLEN; 119848006Skato bp = sc->sc_ifbuf; 119948006Skato while (len--) { 120048006Skato 120148006Skato cl = inb(lpt_stat_port); 120248006Skato outb(lpt_data_port, 8); 120348006Skato 120448006Skato j = LPMAXSPIN2; 120548006Skato while((inb(lpt_stat_port) & LPIP_SHAKE)) 120648006Skato if(!--j) goto err; 120748006Skato 120848006Skato c = inb(lpt_stat_port); 120948006Skato outb(lpt_data_port, 0); 121048006Skato 121148006Skato *bp++= trecvh[cl] | trecvl[c]; 121248006Skato 121348006Skato j = LPMAXSPIN2; 121448006Skato while (!((cl=inb(lpt_stat_port)) & LPIP_SHAKE)) { 121548006Skato if (cl != c && 121648006Skato (((cl = inb(lpt_stat_port)) ^ 0xb8) & 0xf8) == 121748006Skato (c & 0xf8)) 121848006Skato goto end; 121948006Skato if (!--j) goto err; 122048006Skato } 122148006Skato } 122248006Skato 122348006Skato end: 122448006Skato len = bp - sc->sc_ifbuf; 122548006Skato if (len <= LPIPHDRLEN) 122648006Skato goto err; 122748006Skato 122848006Skato sc->sc_iferrs = 0; 122948006Skato 123048006Skato if (IF_QFULL(&ipintrq)) { 123148006Skato lprintf(("DROP")); 123248006Skato IF_DROP(&ipintrq); 123348006Skato goto done; 123448006Skato } 123548006Skato#if NBPFILTER > 0 123648006Skato if (sc->sc_if.if_bpf) { 123748006Skato bpf_tap(&sc->sc_if, sc->sc_ifbuf, len); 123848006Skato } 123948006Skato#endif 124048006Skato len -= LPIPHDRLEN; 124148006Skato sc->sc_if.if_ipackets++; 124248006Skato sc->sc_if.if_ibytes += len; 124348006Skato top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); 124448006Skato if (top) { 124548006Skato IF_ENQUEUE(&ipintrq, top); 124648006Skato schednetisr(NETISR_IP); 124748006Skato } 124848006Skato } 124948006Skato goto done; 125048006Skato 125148006Skato err: 125248006Skato outb(lpt_data_port, 0); 125348006Skato lprintf(("R")); 125448006Skato sc->sc_if.if_ierrors++; 125548006Skato sc->sc_iferrs++; 125648006Skato 125748006Skato /* 125848006Skato * We are not able to send receive anything for now, 125948006Skato * so stop wasting our time 126048006Skato */ 126148006Skato if (sc->sc_iferrs > LPMAXERRS) { 126248006Skato printf("lp%d: Too many errors, Going off-line.\n", unit); 126348006Skato outb(lpt_ctrl_port, 0x00); 126448006Skato sc->sc_if.if_flags &= ~IFF_RUNNING; 126548006Skato sc->sc_iferrs=0; 126648006Skato } 126748006Skato 126848006Skato done: 126948006Skato splx(s); 127048006Skato return; 127148006Skato} 127248006Skato 127348006Skatostatic __inline int 127448006Skatolpoutbyte (u_char byte, int spin, int data_port, int status_port) 127548006Skato{ 127648006Skato outb(data_port, txmith[byte]); 127748006Skato while (!(inb(status_port) & LPIP_SHAKE)) 127848006Skato if (--spin == 0) 127948006Skato return 1; 128048006Skato outb(data_port, txmitl[byte]); 128148006Skato while (inb(status_port) & LPIP_SHAKE) 128248006Skato if (--spin == 0) 128348006Skato return 1; 128448006Skato return 0; 128548006Skato} 128648006Skato 128748006Skatostatic int 128848006Skatolpoutput (struct ifnet *ifp, struct mbuf *m, 128948006Skato struct sockaddr *dst, struct rtentry *rt) 129048006Skato{ 129148006Skato register int lpt_data_port = lpt_sc[ifp->if_unit].sc_port + lpt_data; 129248006Skato register int lpt_stat_port = lpt_sc[ifp->if_unit].sc_port + lpt_status; 129348006Skato#ifndef PC98 129448006Skato int lpt_ctrl_port = lpt_sc[ifp->if_unit].sc_port + lpt_control; 129548006Skato#endif 129648006Skato 129748006Skato int s, err; 129848006Skato struct mbuf *mm; 129948006Skato u_char *cp = "\0\0"; 130048006Skato u_char chksum = 0; 130148006Skato int count = 0; 130248006Skato int i; 130348006Skato int spin; 130448006Skato 130548006Skato /* We need a sensible value if we abort */ 130648006Skato cp++; 130748006Skato ifp->if_flags |= IFF_RUNNING; 130848006Skato 130948006Skato err = 1; /* assume we're aborting because of an error */ 131048006Skato 131148006Skato s = splhigh(); 131248006Skato 131348006Skato#ifndef PC98 131448006Skato /* Suspend (on laptops) or receive-errors might have taken us offline */ 131548006Skato outb(lpt_ctrl_port, LPC_ENA); 131648006Skato#endif 131748006Skato 131848006Skato if (ifp->if_flags & IFF_LINK0) { 131948006Skato 132048006Skato if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) { 132148006Skato lprintf(("&")); 132248006Skato lptintr(ifp->if_unit); 132348006Skato } 132448006Skato 132548006Skato /* Alert other end to pending packet */ 132648006Skato spin = LPMAXSPIN1; 132748006Skato outb(lpt_data_port, 0x08); 132848006Skato while ((inb(lpt_stat_port) & 0x08) == 0) 132948006Skato if (--spin == 0) { 133048006Skato goto nend; 133148006Skato } 133248006Skato 133348006Skato /* Calculate length of packet, then send that */ 133448006Skato 133548006Skato count += 14; /* Ethernet header len */ 133648006Skato 133748006Skato mm = m; 133848006Skato for (mm = m; mm; mm = mm->m_next) { 133948006Skato count += mm->m_len; 134048006Skato } 134148006Skato if (clpoutbyte(count & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 134248006Skato goto nend; 134348006Skato if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 134448006Skato goto nend; 134548006Skato 134648006Skato /* Send dummy ethernet header */ 134748006Skato for (i = 0; i < 12; i++) { 134848006Skato if (clpoutbyte(i, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 134948006Skato goto nend; 135048006Skato chksum += i; 135148006Skato } 135248006Skato 135348006Skato if (clpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 135448006Skato goto nend; 135548006Skato if (clpoutbyte(0x00, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 135648006Skato goto nend; 135748006Skato chksum += 0x08 + 0x00; /* Add into checksum */ 135848006Skato 135948006Skato mm = m; 136048006Skato do { 136148006Skato cp = mtod(mm, u_char *); 136248006Skato while (mm->m_len--) { 136348006Skato chksum += *cp; 136448006Skato if (clpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 136548006Skato goto nend; 136648006Skato } 136748006Skato } while ((mm = mm->m_next)); 136848006Skato 136948006Skato /* Send checksum */ 137048006Skato if (clpoutbyte(chksum, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 137148006Skato goto nend; 137248006Skato 137348006Skato /* Go quiescent */ 137448006Skato outb(lpt_data_port, 0); 137548006Skato 137648006Skato err = 0; /* No errors */ 137748006Skato 137848006Skato nend: 137948006Skato if (err) { /* if we didn't timeout... */ 138048006Skato ifp->if_oerrors++; 138148006Skato lprintf(("X")); 138248006Skato } else { 138348006Skato ifp->if_opackets++; 138448006Skato ifp->if_obytes += m->m_pkthdr.len; 138548006Skato } 138648006Skato 138748006Skato m_freem(m); 138848006Skato 138948006Skato if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) { 139048006Skato lprintf(("^")); 139148006Skato lptintr(ifp->if_unit); 139248006Skato } 139348006Skato (void) splx(s); 139448006Skato return 0; 139548006Skato } 139648006Skato 139748006Skato if (inb(lpt_stat_port) & LPIP_SHAKE) { 139848006Skato lprintf(("&")); 139948006Skato lptintr(ifp->if_unit); 140048006Skato } 140148006Skato 140248006Skato if (lpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) 140348006Skato goto end; 140448006Skato if (lpoutbyte(0x00, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 140548006Skato goto end; 140648006Skato 140748006Skato mm = m; 140848006Skato do { 140948006Skato cp = mtod(mm,u_char *); 141048006Skato while (mm->m_len--) 141148006Skato if (lpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) 141248006Skato goto end; 141348006Skato } while ((mm = mm->m_next)); 141448006Skato 141548006Skato err = 0; /* no errors were encountered */ 141648006Skato 141748006Skato end: 141848006Skato --cp; 141948006Skato outb(lpt_data_port, txmitl[*cp] ^ 0x17); 142048006Skato 142148006Skato if (err) { /* if we didn't timeout... */ 142248006Skato ifp->if_oerrors++; 142348006Skato lprintf(("X")); 142448006Skato } else { 142548006Skato ifp->if_opackets++; 142648006Skato ifp->if_obytes += m->m_pkthdr.len; 142748006Skato#if NBPFILTER > 0 142848006Skato if (ifp->if_bpf) { 142948006Skato /* 143048006Skato * We need to prepend the packet type as 143148006Skato * a two byte field. Cons up a dummy header 143248006Skato * to pacify bpf. This is safe because bpf 143348006Skato * will only read from the mbuf (i.e., it won't 143448006Skato * try to free it or keep a pointer to it). 143548006Skato */ 143648006Skato struct mbuf m0; 143748006Skato u_short hdr = 0x800; 143848006Skato 143948006Skato m0.m_next = m; 144048006Skato m0.m_len = 2; 144148006Skato m0.m_data = (char *)&hdr; 144248006Skato 144348006Skato bpf_mtap(ifp, &m0); 144448006Skato } 144548006Skato#endif 144648006Skato } 144748006Skato 144848006Skato m_freem(m); 144948006Skato 145048006Skato if (inb(lpt_stat_port) & LPIP_SHAKE) { 145148006Skato lprintf(("^")); 145248006Skato lptintr(ifp->if_unit); 145348006Skato } 145448006Skato 145548006Skato (void) splx(s); 145648006Skato return 0; 145748006Skato} 145848006Skato 145948006Skato#endif /* INET */ 146048006Skato 146148006Skatostatic int lpt_devsw_installed; 146248006Skato 146348006Skatostatic void lpt_drvinit(void *unused) 146448006Skato{ 146548006Skato 146648006Skato if( ! lpt_devsw_installed ) { 146748006Skato cdevsw_add(&lpt_cdevsw); 146848006Skato lpt_devsw_installed = 1; 146948006Skato } 147048006Skato} 147148006Skato 147248006SkatoSYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL) 147348006Skato 1474