⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parport_pc.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/* Low-level parallel-port routines for 8255-based PC-style hardware. *  * Authors: Phil Blundell <Philip.Blundell@pobox.com> *          Tim Waugh <tim@cyberelk.demon.co.uk> *	    Jose Renau <renau@acm.org> *          David Campbell <campbell@torque.net> *          Andrea Arcangeli * * based on work by Grant Guenther <grant@torque.net> and Phil Blundell. * * Cleaned up include files - Russell King <linux@arm.uk.linux.org> * DMA support - Bert De Jonghe <bert@sophis.be> * Many ECP bugs fixed.  Fred Barnes & Jamie Lokier, 1999 * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G.  * Various hacks, Fred Barnes, 04/2001 *//* This driver should work with any hardware that is broadly compatible * with that in the IBM PC.  This applies to the majority of integrated * I/O chipsets that are commonly available.  The expected register * layout is: * *	base+0		data *	base+1		status *	base+2		control * * In addition, there are some optional registers: * *	base+3		EPP address *	base+4		EPP data *	base+0x400	ECP config A *	base+0x401	ECP config B *	base+0x402	ECP control * * All registers are 8 bits wide and read/write.  If your hardware differs * only in register addresses (eg because your registers are on 32-bit * word boundaries) then you can alter the constants in parport_pc.h to * accomodate this. * * Note that the ECP registers may not start at offset 0x400 for PCI cards, * but rather will start at port->base_hi. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/sysctl.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/uaccess.h>#include <linux/parport.h>#include <linux/parport_pc.h>#include <asm/parport.h>#define PARPORT_PC_MAX_PORTS PARPORT_MAX/* ECR modes */#define ECR_SPP 00#define ECR_PS2 01#define ECR_PPF 02#define ECR_ECP 03#define ECR_EPP 04#define ECR_VND 05#define ECR_TST 06#define ECR_CNF 07#define ECR_MODE_MASK 0xe0#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))#undef DEBUG#ifdef DEBUG#define DPRINTK  printk#else#define DPRINTK(stuff...)#endif#define NR_SUPERIOS 3static struct superio_struct {	/* For Super-IO chips autodetection */	int io;	int irq;	int dma;} superios[NR_SUPERIOS] __devinitdata = { {0,},};static int user_specified __devinitdata = 0;#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)static int verbose_probing;#endifstatic int registered_parport;/* frob_control, but for ECR */static void frob_econtrol (struct parport *pb, unsigned char m,			   unsigned char v){	unsigned char ectr = 0;	if (m != 0xff)		ectr = inb (ECONTROL (pb));	DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",		m, v, ectr, (ectr & ~m) ^ v);	outb ((ectr & ~m) ^ v, ECONTROL (pb));}static void __inline__ frob_set_mode (struct parport *p, int mode){	frob_econtrol (p, ECR_MODE_MASK, mode << 5);}#ifdef CONFIG_PARPORT_PC_FIFO/* Safely change the mode bits in the ECR    Returns:	    0    : Success	   -EBUSY: Could not drain FIFO in some finite amount of time,		   mode not changed! */static int change_mode(struct parport *p, int m){	const struct parport_pc_private *priv = p->physport->private_data;	unsigned char oecr;	int mode;	DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m);	if (!priv->ecr) {		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");		return 0;	}	/* Bits <7:5> contain the mode. */	oecr = inb (ECONTROL (p));	mode = (oecr >> 5) & 0x7;	if (mode == m) return 0;	if (mode >= 2 && !(priv->ctr & 0x20)) {		/* This mode resets the FIFO, so we may		 * have to wait for it to drain first. */		long expire = jiffies + p->physport->cad->timeout;		int counter;		switch (mode) {		case ECR_PPF: /* Parallel Port FIFO mode */		case ECR_ECP: /* ECP Parallel Port mode */			/* Busy wait for 200us */			for (counter = 0; counter < 40; counter++) {				if (inb (ECONTROL (p)) & 0x01)					break;				if (signal_pending (current)) break;				udelay (5);			}			/* Poll slowly. */			while (!(inb (ECONTROL (p)) & 0x01)) {				if (time_after_eq (jiffies, expire))					/* The FIFO is stuck. */					return -EBUSY;				__set_current_state (TASK_INTERRUPTIBLE);				schedule_timeout ((HZ + 99) / 100);				if (signal_pending (current))					break;			}		}	}	if (mode >= 2 && m >= 2) {		/* We have to go through mode 001 */		oecr &= ~(7 << 5);		oecr |= ECR_PS2 << 5;		ECR_WRITE (p, oecr);	}	/* Set the mode. */	oecr &= ~(7 << 5);	oecr |= m << 5;	ECR_WRITE (p, oecr);	return 0;}#ifdef CONFIG_PARPORT_1284/* Find FIFO lossage; FIFO is reset */static int get_fifo_residue (struct parport *p){	int residue;	int cnfga;	const struct parport_pc_private *priv = p->physport->private_data;	/* Adjust for the contents of the FIFO. */	for (residue = priv->fifo_depth; ; residue--) {		if (inb (ECONTROL (p)) & 0x2)				/* Full up. */			break;		outb (0, FIFO (p));	}	printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,		residue);	/* Reset the FIFO. */	frob_set_mode (p, ECR_PS2);	/* Now change to config mode and clean up. FIXME */	frob_set_mode (p, ECR_CNF);	cnfga = inb (CONFIGA (p));	printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);	if (!(cnfga & (1<<2))) {		printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name);		residue++;	}	/* Don't care about partial PWords until support is added for	 * PWord != 1 byte. */	/* Back to PS2 mode. */	frob_set_mode (p, ECR_PS2);	DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p)));	return residue;}#endif /* IEEE 1284 support */#endif /* FIFO support *//* * Clear TIMEOUT BIT in EPP MODE * * This is also used in SPP detection. */static int clear_epp_timeout(struct parport *pb){	unsigned char r;	if (!(parport_pc_read_status(pb) & 0x01))		return 1;	/* To clear timeout some chips require double read */	parport_pc_read_status(pb);	r = parport_pc_read_status(pb);	outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */	outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */	r = parport_pc_read_status(pb);	return !(r & 0x01);}/* * Access functions. * * Most of these aren't static because they may be used by the * parport_xxx_yyy macros.  extern __inline__ versions of several * of these are in parport_pc.h. */static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs){	parport_generic_irq(irq, (struct parport *) dev_id, regs);}void parport_pc_write_data(struct parport *p, unsigned char d){	outb (d, DATA (p));}unsigned char parport_pc_read_data(struct parport *p){	return inb (DATA (p));}void parport_pc_write_control(struct parport *p, unsigned char d){	const unsigned char wm = (PARPORT_CONTROL_STROBE |				  PARPORT_CONTROL_AUTOFD |				  PARPORT_CONTROL_INIT |				  PARPORT_CONTROL_SELECT);	/* Take this out when drivers have adapted to the newer interface. */	if (d & 0x20) {		printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",			p->name, p->cad->name);		parport_pc_data_reverse (p);	}	__parport_pc_frob_control (p, wm, d & wm);}unsigned char parport_pc_read_control(struct parport *p){	const unsigned char wm = (PARPORT_CONTROL_STROBE |				  PARPORT_CONTROL_AUTOFD |				  PARPORT_CONTROL_INIT |				  PARPORT_CONTROL_SELECT);	const struct parport_pc_private *priv = p->physport->private_data;	return priv->ctr & wm; /* Use soft copy */}unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,				       unsigned char val){	const unsigned char wm = (PARPORT_CONTROL_STROBE |				  PARPORT_CONTROL_AUTOFD |				  PARPORT_CONTROL_INIT |				  PARPORT_CONTROL_SELECT);	/* Take this out when drivers have adapted to the newer interface. */	if (mask & 0x20) {		printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",			p->name, p->cad->name,			(val & 0x20) ? "reverse" : "forward");		if (val & 0x20)			parport_pc_data_reverse (p);		else			parport_pc_data_forward (p);	}	/* Restrict mask and val to control lines. */	mask &= wm;	val &= wm;	return __parport_pc_frob_control (p, mask, val);}unsigned char parport_pc_read_status(struct parport *p){	return inb (STATUS (p));}void parport_pc_disable_irq(struct parport *p){	__parport_pc_frob_control (p, 0x10, 0);}void parport_pc_enable_irq(struct parport *p){	if (p->irq != PARPORT_IRQ_NONE)		__parport_pc_frob_control (p, 0x10, 0x10);}void parport_pc_data_forward (struct parport *p){	__parport_pc_frob_control (p, 0x20, 0);}void parport_pc_data_reverse (struct parport *p){	__parport_pc_frob_control (p, 0x20, 0x20);}void parport_pc_init_state(struct pardevice *dev, struct parport_state *s){	s->u.pc.ctr = 0xc;	if (dev->irq_func &&	    dev->port->irq != PARPORT_IRQ_NONE)		/* Set ackIntEn */		s->u.pc.ctr |= 0x10;	s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24;			     * D.Gruszka VScom */}void parport_pc_save_state(struct parport *p, struct parport_state *s){	const struct parport_pc_private *priv = p->physport->private_data;	s->u.pc.ctr = priv->ctr;	if (priv->ecr)		s->u.pc.ecr = inb (ECONTROL (p));}void parport_pc_restore_state(struct parport *p, struct parport_state *s){	struct parport_pc_private *priv = p->physport->private_data;	register unsigned char c = s->u.pc.ctr & priv->ctr_writable;	outb (c, CONTROL (p));	priv->ctr = c;	if (priv->ecr)		ECR_WRITE (p, s->u.pc.ecr);}#ifdef CONFIG_PARPORT_1284static size_t parport_pc_epp_read_data (struct parport *port, void *buf,					size_t length, int flags){	size_t got = 0;	if (flags & PARPORT_W91284PIC) {		unsigned char status;		size_t left = length;		/* use knowledge about data lines..:		 *  nFault is 0 if there is at least 1 byte in the Warp's FIFO		 *  pError is 1 if there are 16 bytes in the Warp's FIFO		 */		status = inb (STATUS (port));		while (!(status & 0x08) && (got < length)) {			if ((left >= 16) && (status & 0x20) && !(status & 0x08)) {				/* can grab 16 bytes from warp fifo */				if (!((long)buf & 0x03)) {					insl (EPPDATA (port), buf, 4);				} else {					insb (EPPDATA (port), buf, 16);				}				buf += 16;				got += 16;				left -= 16;			} else {				/* grab single byte from the warp fifo */				*((char *)buf)++ = inb (EPPDATA (port));				got++;				left--;			}			status = inb (STATUS (port));			if (status & 0x01) {				/* EPP timeout should never occur... */				printk (KERN_DEBUG "%s: EPP timeout occured while talking to "					"w91284pic (should not have done)\n", port->name);				clear_epp_timeout (port);			}		}		return got;	}	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {		if (!(((long)buf | length) & 0x03)) {			insl (EPPDATA (port), buf, (length >> 2));		} else {			insb (EPPDATA (port), buf, length);		}		if (inb (STATUS (port)) & 0x01) {			clear_epp_timeout (port);			return -EIO;		}		return length;	}	for (; got < length; got++) {		*((char*)buf)++ = inb (EPPDATA(port));		if (inb (STATUS (port)) & 0x01) {			/* EPP timeout */			clear_epp_timeout (port);			break;		}	}	return got;}static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,					 size_t length, int flags){	size_t written = 0;	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {		if (!(((long)buf | length) & 0x03)) {			outsl (EPPDATA (port), buf, (length >> 2));		} else {			outsb (EPPDATA (port), buf, length);		}		if (inb (STATUS (port)) & 0x01) {			clear_epp_timeout (port);			return -EIO;		}		return length;	}	for (; written < length; written++) {		outb (*((char*)buf)++, EPPDATA(port));		if (inb (STATUS(port)) & 0x01) {			clear_epp_timeout (port);			break;		}	}	return written;}static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,					size_t length, int flags){	size_t got = 0;	if ((flags & PARPORT_EPP_FAST) && (length > 1)) {		insb (EPPADDR (port), buf, length);		if (inb (STATUS (port)) & 0x01) {			clear_epp_timeout (port);			return -EIO;		}		return length;	}	for (; got < length; got++) {		*((char*)buf)++ = inb (EPPADDR (port));		if (inb (STATUS (port)) & 0x01) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -