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

📄 parport_pc.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 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 *//* 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/malloc.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#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;/* frob_control, but for ECR */static void frob_econtrol (struct parport *pb, unsigned char m,			   unsigned char v){	unsigned char 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));}#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;	int ecr = ECONTROL(p);	unsigned char oecr;	int mode;	DPRINTK("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 (ecr);	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;		outb (oecr, ecr);	}	/* Set the mode. */	oecr &= ~(7 << 5);	oecr |= m << 5;	outb (oecr, ecr);	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_econtrol (p, 0xe0, ECR_PS2 << 5);	/* Now change to config mode and clean up. FIXME */	frob_econtrol (p, 0xe0, ECR_CNF << 5);	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_econtrol (p, 0xe0, ECR_PS2 << 5);	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){	__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 | (dev->irq_func ? 0x10 : 0x0);	s->u.pc.ecr = 0x24;}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 = inb (CONTROL (p));	if (priv->ecr)		s->u.pc.ecr = inb (ECONTROL (p));}void parport_pc_restore_state(struct parport *p, struct parport_state *s){	const struct parport_pc_private *priv = p->physport->private_data;	outb (s->u.pc.ctr, CONTROL (p));	if (priv->ecr)		outb (s->u.pc.ecr, ECONTROL (p));}#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;	for (; got < length; got++) {		*((char*)buf)++ = inb (EPPDATA(port));		if (inb (STATUS(port)) & 0x01) {			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;	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;	for (; got < length; got++) {		*((char*)buf)++ = inb (EPPADDR (port));		if (inb (STATUS (port)) & 0x01) {			clear_epp_timeout (port);			break;		}	}	return got;}static size_t parport_pc_epp_write_addr (struct parport *port,					 const void *buf, size_t length,					 int flags){	size_t written = 0;	for (; written < length; written++) {		outb (*((char*)buf)++, EPPADDR (port));		if (inb (STATUS (port)) & 0x01) {			clear_epp_timeout (port);			break;		}	}	return written;}static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,					   size_t length, int flags){	size_t got;	frob_econtrol (port, 0xe0, ECR_EPP << 5);	parport_pc_data_reverse (port);	parport_pc_write_control (port, 0x4);	got = parport_pc_epp_read_data (port, buf, length, flags);	frob_econtrol (port, 0xe0, ECR_PS2 << 5);	return got;}static size_t parport_pc_ecpepp_write_data (struct parport *port,					    const void *buf, size_t length,					    int flags){	size_t written;	frob_econtrol (port, 0xe0, ECR_EPP << 5);	parport_pc_write_control (port, 0x4);	parport_pc_data_forward (port);	written = parport_pc_epp_write_data (port, buf, length, flags);	frob_econtrol (port, 0xe0, ECR_PS2 << 5);	return written;}static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,					   size_t length, int flags){	size_t got;	frob_econtrol (port, 0xe0, ECR_EPP << 5);	parport_pc_data_reverse (port);	parport_pc_write_control (port, 0x4);	got = parport_pc_epp_read_addr (port, buf, length, flags);	frob_econtrol (port, 0xe0, ECR_PS2 << 5);	return got;}static size_t parport_pc_ecpepp_write_addr (struct parport *port,					    const void *buf, size_t length,					    int flags){	size_t written;	frob_econtrol (port, 0xe0, ECR_EPP << 5);	parport_pc_write_control (port, 0x4);	parport_pc_data_forward (port);	written = parport_pc_epp_write_addr (port, buf, length, flags);	frob_econtrol (port, 0xe0, ECR_PS2 << 5);	return written;}#endif /* IEEE 1284 support */#ifdef CONFIG_PARPORT_PC_FIFOstatic size_t parport_pc_fifo_write_block_pio (struct parport *port,					       const void *buf, size_t length){	int ret = 0;	const unsigned char *bufp = buf;	size_t left = length;	long expire = jiffies + port->physport->cad->timeout;

⌨️ 快捷键说明

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