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 + -
显示快捷键?