lpt.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,383 行 · 第 1/3 页
C
1,383 行
/* * 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.72.2.1 1999/02/15 02:51:18 des 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 "opt_devfs.h"#include "opt_inet.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/conf.h>#include <sys/buf.h>#include <sys/kernel.h>#include <sys/uio.h>#include <sys/syslog.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/malloc.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <net/if.h>#include <net/if_types.h>#include <net/netisr.h>#include <netinet/in.h>#include <netinet/in_var.h>#include "bpfilter.h"#if NBPFILTER > 0#include <net/bpf.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(args)#else#define lprintf(args) do { \ if (lptflag) \ printf args; \ } while (0)static int volatile lptflag = 1;#endif#define LPTUNIT(s) ((s)&0x03)#define LPTFLAGS(s) ((s)&0xfc)static struct lpt_softc { int 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#ifdef DEVFS void *devfs_token; void *devfs_token_ctl;#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 timeout_t lptout;static int lptprobe (struct isa_device *dvp);static int lptattach (struct isa_device *isdp);static ointhand2_t lptintr;#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 *, u_long, 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"};static d_open_t lptopen;static d_close_t lptclose;static d_write_t lptwrite;static d_ioctl_t lptioctl;#define CDEV_MAJOR 16static struct cdevsw lpt_cdevsw = { lptopen, lptclose, noread, lptwrite, /*16*/ lptioctl, nullstop, nullreset, nodevtotty,/* lpt */ seltrue, nommap, nostrat, "lpt", NULL, -1 };/* * Internal routine to lptprobe to do port tests of one byte value */static intlpt_port_test (int 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){ int port; static short next_bios_lpt = 0; int status; static u_char testbyte[18] = { 0x55, /* alternating zeros */ 0xaa, /* alternating ones */ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f, /* walking zero */ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 /* walking one */ }; int i; /* * 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; for (i = 0; i < 18; i++) { if (!lpt_port_test(port, testbyte[i], 0xff)) { 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; isdp->id_ointr = lptintr; 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); /* check if we can use interrupt */ lprintf(("oldirq %x\n", sc->sc_irq)); if (isdp->id_irq) { sc->sc_irq = LP_HAS_IRQ | LP_USE_IRQ | LP_ENABLE_IRQ; printf("lpt%d: Interrupt-driven port\n", unit);#ifdef INET lpattach(sc, unit);#endif } else { sc->sc_irq = 0; lprintf(("lpt%d: Polled port\n", unit)); } lprintf(("irq %x\n", sc->sc_irq));#ifdef DEVFS /* XXX what to do about the flags in the minor number? */ sc->devfs_token = devfs_add_devswf(&lpt_cdevsw, unit, DV_CHR, UID_ROOT, GID_WHEEL, 0600, "lpt%d", unit); sc->devfs_token_ctl = devfs_add_devswf(&lpt_cdevsw, unit | LP_BYPASS, DV_CHR, UID_ROOT, GID_WHEEL, 0600, "lpctl%d", unit);#endif printf("lpt%d: this driver is deprecated; use ppbus instead.\n"); return (1);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?