lpt.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,398 行 · 第 1/3 页
C
1,398 行
/* * Copyright (c) 1990 William F. Jolitz, TeleMuse * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This software is a component of "386BSD" developed by * William F. Jolitz, TeleMuse. * 4. Neither the name of the developer nor the name "386BSD" * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT * NOT MAKE USE OF THIS WORK. * * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN * REFERENCES SUCH AS THE "PORTING UNIX TO THE 386" SERIES * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPER BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: unknown origin, 386BSD 0.1 * $\Id: lpt.c,v 1.30.4.9 1996/04/15 17:14:12 joerg Exp $ *//* * Device Driver for AT parallel printer port * Written by William Jolitz 12/18/90 *//* * Parallel port TCP/IP interfaces added. I looked at the driver from * MACH but this is a complete rewrite, and btw. incompatible, and it * should perform better too. I have never run the MACH driver though. * * This driver sends two bytes (0x08, 0x00) in front of each packet, * to allow us to distinguish another format later. * * Now added an Linux/Crynwr compatibility mode which is enabled using * IF_LINK0 - Tim Wilkinson. * * TODO: * Make HDLC/PPP mode, use IF_LLC1 to enable. * * Connect the two computers using a Laplink parallel cable to use this * feature: * * +----------------------------------------+ * |A-name A-End B-End Descr. Port/Bit | * +----------------------------------------+ * |DATA0 2 15 Data 0/0x01 | * |-ERROR 15 2 1/0x08 | * +----------------------------------------+ * |DATA1 3 13 Data 0/0x02 | * |+SLCT 13 3 1/0x10 | * +----------------------------------------+ * |DATA2 4 12 Data 0/0x04 | * |+PE 12 4 1/0x20 | * +----------------------------------------+ * |DATA3 5 10 Strobe 0/0x08 | * |-ACK 10 5 1/0x40 | * +----------------------------------------+ * |DATA4 6 11 Data 0/0x10 | * |BUSY 11 6 1/~0x80 | * +----------------------------------------+ * |GND 18-25 18-25 GND - | * +----------------------------------------+ * * Expect transfer-rates up to 75 kbyte/sec. * * If GCC could correctly grok * register int port asm("edx") * the code would be cleaner * * Poul-Henning Kamp <phk@freebsd.org> */#include "lpt.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/conf.h>#include <sys/proc.h>#include <sys/buf.h>#include <sys/kernel.h>#include <sys/ioctl.h>#include <sys/uio.h>#include <sys/syslog.h>#include <sys/devconf.h>#ifdef DEVFS#include <sys/devfsext.h>#endif /*DEVFS*/#include <machine/clock.h>#include <machine/lpt.h>#include <vm/vm.h>#include <vm/vm_param.h>#include <vm/pmap.h>#include <i386/isa/isa.h>#include <i386/isa/isa_device.h>#include <i386/isa/lptreg.h>#ifdef INET#include <sys/mbuf.h>#include <sys/socket.h>#include <net/if.h>#include <net/if_types.h>#include <net/netisr.h>#include <net/route.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/in_var.h>#include <netinet/ip.h>#include <netinet/if_ether.h>#include "bpfilter.h"#if NBPFILTER > 0#include <net/bpf.h>#include <net/bpfdesc.h>#endif#endif /* INET */#define LPINITRDY 4 /* wait up to 4 seconds for a ready */#define LPTOUTINITIAL 10 /* initial timeout to wait for ready 1/10 s */#define LPTOUTMAX 1 /* maximal timeout 1 s */#define LPPRI (PZERO+8)#define BUFSIZE 1024#ifdef INET#ifndef LPMTU /* MTU for the lp# interfaces */#define LPMTU 1500#endif#ifndef LPMAXSPIN1 /* DELAY factor for the lp# interfaces */#define LPMAXSPIN1 8000 /* Spinning for remote intr to happen */#endif#ifndef LPMAXSPIN2 /* DELAY factor for the lp# interfaces */#define LPMAXSPIN2 500 /* Spinning for remote handshake to happen */#endif#ifndef LPMAXERRS /* Max errors before !RUNNING */#define LPMAXERRS 100#endif#define CLPIPHDRLEN 14 /* We send dummy ethernet addresses (two) + packet type in front of packet */#define CLPIP_SHAKE 0x80 /* This bit toggles between nibble reception */#define MLPIPHDRLEN CLPIPHDRLEN#define LPIPHDRLEN 2 /* We send 0x08, 0x00 in front of packet */#define LPIP_SHAKE 0x40 /* This bit toggles between nibble reception */#if !defined(MLPIPHDRLEN) || LPIPHDRLEN > MLPIPHDRLEN#define MLPIPHDRLEN LPIPHDRLEN#endif#define LPIPTBLSIZE 256 /* Size of octet translation table */#endif /* INET *//* BIOS printer list - used by BIOS probe*/#define BIOS_LPT_PORTS 0x408#define BIOS_PORTS (short *)(KERNBASE+BIOS_LPT_PORTS)#define BIOS_MAX_LPT 4#ifndef DEBUG#define lprintf (void)#else#define lprintf if (lptflag) printfint lptflag = 1;#endif#define LPTUNIT(s) ((s)&0x03)#define LPTFLAGS(s) ((s)&0xfc)static struct lpt_softc { short sc_port; short sc_state; /* default case: negative prime, negative ack, handshake strobe, prime once */ u_char sc_control; char sc_flags;#define LP_POS_INIT 0x04 /* if we are a postive init signal */#define LP_POS_ACK 0x08 /* if we are a positive going ack */#define LP_NO_PRIME 0x10 /* don't prime the printer at all */#define LP_PRIMEOPEN 0x20 /* prime on every open */#define LP_AUTOLF 0x40 /* tell printer to do an automatic lf */#define LP_BYPASS 0x80 /* bypass printer ready checks */ struct buf *sc_inbuf; short sc_xfercnt ; char sc_primed; char *sc_cp ; u_char sc_irq ; /* IRQ status of port */#define LP_HAS_IRQ 0x01 /* we have an irq available */#define LP_USE_IRQ 0x02 /* we are using our irq */#define LP_ENABLE_IRQ 0x04 /* enable IRQ on open */ u_char sc_backoff ; /* time to call lptout() again */#ifdef INET struct ifnet sc_if; u_char *sc_ifbuf; int sc_iferrs;#endif /* ENDIF */#ifdef DEVFS void *devfs_token;#endif} lpt_sc[NLPT] ;/* bits for state */#define OPEN (1<<0) /* device is open */#define ASLP (1<<1) /* awaiting draining of printer */#define ERROR (1<<2) /* error was received from printer */#define OBUSY (1<<3) /* printer is busy doing output */#define LPTOUT (1<<4) /* timeout while not selected */#define TOUT (1<<5) /* timeout while not selected */#define INIT (1<<6) /* waiting to initialize for open */#define INTERRUPTED (1<<7) /* write call was interrupted *//* status masks to interrogate printer status */#define RDY_MASK (LPS_SEL|LPS_OUT|LPS_NBSY|LPS_NERR) /* ready ? */#define LP_READY (LPS_SEL|LPS_NBSY|LPS_NERR)/* Printer Ready condition - from lpa.c *//* Only used in polling code */#define LPS_INVERT (LPS_NBSY | LPS_NACK | LPS_SEL | LPS_NERR)#define LPS_MASK (LPS_NBSY | LPS_NACK | LPS_OUT | LPS_SEL | LPS_NERR)#define NOT_READY(x) ((inb(x)^LPS_INVERT)&LPS_MASK)#define MAX_SLEEP (hz*5) /* Timeout while waiting for device ready */#define MAX_SPIN 20 /* Max delay for device ready in usecs */static void lptout (struct lpt_softc * sc);static int lptprobe (struct isa_device *dvp);static int lptattach (struct isa_device *isdp);#ifdef INET/* Tables for the lp# interface */static u_char *txmith;#define txmitl (txmith+(1*LPIPTBLSIZE))#define trecvh (txmith+(2*LPIPTBLSIZE))#define trecvl (txmith+(3*LPIPTBLSIZE))static u_char *ctxmith;#define ctxmitl (ctxmith+(1*LPIPTBLSIZE))#define ctrecvh (ctxmith+(2*LPIPTBLSIZE))#define ctrecvl (ctxmith+(3*LPIPTBLSIZE))/* Functions for the lp# interface */static void lpattach(struct lpt_softc *,int);static int lpinittables(void);static int lpioctl(struct ifnet *, int, caddr_t);static int lpoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *);static void lpintr(int);#endif /* INET */struct isa_driver lptdriver = { lptprobe, lptattach, "lpt"};d_open_t lptopen;d_close_t lptclose;d_write_t lptwrite;d_ioctl_t lptioctl;void lptintr(int unit);#define CDEV_MAJOR 16#if 0static struct cdevsw lpt_cdevsw = { lptopen, lptclose, noread, lptwrite, /*16*/ lptioctl, nullstop, nullreset, nodevtotty,/* lpt */ seltrue, nommap, nostrat, "lpt", NULL, -1 };#endifstatic struct kern_devconf kdc_lpt[NLPT] = { { 0, 0, 0, /* filled in by dev_attach */ "lpt", 0, { MDDT_ISA, 0, "tty" }, isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, &kdc_isa0, /* parent */ 0, /* parentdata */ DC_UNCONFIGURED, /* state */ "Parallel printer adapter", DC_CLS_PARALLEL | DC_CLS_NETIF /* class */} };static inline voidlpt_registerdev(struct isa_device *id){ if(id->id_unit) kdc_lpt[id->id_unit] = kdc_lpt[0]; kdc_lpt[id->id_unit].kdc_unit = id->id_unit; kdc_lpt[id->id_unit].kdc_isa = id; dev_attach(&kdc_lpt[id->id_unit]);}/* * Internal routine to lptprobe to do port tests of one byte value */static intlpt_port_test (short port, u_char data, u_char mask){ int temp, timeout; data = data & mask; outb(port, data); timeout = 10000; do { DELAY(10); temp = inb(port) & mask; } while (temp != data && --timeout); lprintf("Port 0x%x\tout=%x\tin=%x\ttout=%d\n", port, data, temp, timeout); return (temp == data);}/* * New lpt port probe Geoff Rehmet - Rhodes University - 14/2/94 * Based partially on Rod Grimes' printer probe * * Logic: * 1) If no port address was given, use the bios detected ports * and autodetect what ports the printers are on. * 2) Otherwise, probe the data port at the address given, * using the method in Rod Grimes' port probe. * (Much code ripped off directly from Rod's probe.) * * Comments from Rod's probe: * Logic: * 1) You should be able to write to and read back the same value * to the data port. Do an alternating zeros, alternating ones, * walking zero, and walking one test to check for stuck bits. * * 2) You should be able to write to and read back the same value * to the control port lower 5 bits, the upper 3 bits are reserved * per the IBM PC technical reference manauls and different boards * do different things with them. Do an alternating zeros, alternating * ones, walking zero, and walking one test to check for stuck bits. * * Some printers drag the strobe line down when the are powered off * so this bit has been masked out of the control port test. * * XXX Some printers may not like a fast pulse on init or strobe, I * don't know at this point, if that becomes a problem these bits * should be turned off in the mask byte for the control port test. * * We are finally left with a mask of 0x14, due to some printers * being adamant about holding other bits high ........ * * Before probing the control port, we write a 0 to the data port - * If not, some printers chuck out garbage when the strobe line * gets toggled. * * 3) Set the data and control ports to a value of 0 * * This probe routine has been tested on Epson Lx-800, HP LJ3P, * Epson FX-1170 and C.Itoh 8510RM * printers. * Quick exit on fail added. */intlptprobe(struct isa_device *dvp){ short port; static short next_bios_lpt = 0; int status; u_char data; u_char mask; int i; lpt_registerdev(dvp); /* * Make sure there is some way for lptopen to see that * the port is not configured * This 0 will remain if the port isn't attached */ (lpt_sc + dvp->id_unit)->sc_port = 0; status = IO_LPTSIZE; /* If port not specified, use bios list */ if(dvp->id_iobase < 0) { /* port? */ if((next_bios_lpt < BIOS_MAX_LPT) && (*(BIOS_PORTS+next_bios_lpt) != 0) ) { dvp->id_iobase = *(BIOS_PORTS+next_bios_lpt++); goto end_probe; } else return (0); } /* Port was explicitly specified */ /* This allows probing of ports unknown to the BIOS */ port = dvp->id_iobase + lpt_data; mask = 0xff; data = 0x55; /* Alternating zeros */ if (!lpt_port_test(port, data, mask)) { status = 0 ; goto end_probe ; } data = 0xaa; /* Alternating ones */ if (!lpt_port_test(port, data, mask)) { status = 0 ; goto end_probe ; } for (i = 0; i < 8; i++) { /* Walking zero */ data = ~(1 << i); if (!lpt_port_test(port, data, mask)) { status = 0 ; goto end_probe ; } } for (i = 0; i < 8; i++) { /* Walking one */ data = (1 << i); if (!lpt_port_test(port, data, mask)) { status = 0 ; goto end_probe ; } }end_probe: /* write 0's to control and data ports */ outb(dvp->id_iobase+lpt_data, 0); outb(dvp->id_iobase+lpt_control, 0); return (status);}/* XXX Todo - try and detect if interrupt is working */intlptattach(struct isa_device *isdp){ struct lpt_softc *sc; int unit; char name[32]; unit = isdp->id_unit; sc = lpt_sc + unit; sc->sc_port = isdp->id_iobase; sc->sc_primed = 0; /* not primed yet */ outb(sc->sc_port+lpt_control, LPC_NINIT);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?