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

📄 ieee1284_ops.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* IEEE-1284 operations for parport. * * This file is for generic IEEE 1284 operations.  The idea is that * they are used by the low-level drivers.  If they have a special way * of doing something, they can provide their own routines (and put * the function pointers in port->ops); if not, they can just use these * as a fallback. * * Note: Make no assumptions about hardware or architecture in this file! * * Author: Tim Waugh <tim@cyberelk.demon.co.uk> * Fixed AUTOFD polarity in ecp_forward_to_reverse().  Fred Barnes, 1999 */#include <linux/config.h>#include <linux/parport.h>#include <linux/delay.h>#include <asm/uaccess.h>#define DEBUG /* undef me for production */#ifdef CONFIG_LP_CONSOLE#undef DEBUG /* Don't want a garbled console */#endif#ifdef DEBUG#define DPRINTK(stuff...) printk (stuff)#else#define DPRINTK(stuff...)#endif/***                                * * One-way data transfer functions. * *                                ***//* Compatibility mode. */size_t parport_ieee1284_write_compat (struct parport *port,				      const void *buffer, size_t len,				      int flags){	int no_irq = 1;	ssize_t count = 0;	const unsigned char *addr = buffer;	unsigned char byte;	struct pardevice *dev = port->physport->cad;	unsigned char ctl = (PARPORT_CONTROL_SELECT			     | PARPORT_CONTROL_INIT);	if (port->irq != PARPORT_IRQ_NONE) {		parport_enable_irq (port);		no_irq = 0;		/* Clear out previous irqs. */		while (!down_trylock (&port->physport->ieee1284.irq));	}	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;	parport_write_control (port, ctl);	parport_data_forward (port);	while (count < len) {		long expire = jiffies + dev->timeout;		long wait = (HZ + 99) / 100;		unsigned char mask = (PARPORT_STATUS_ERROR				      | PARPORT_STATUS_BUSY);		unsigned char val = (PARPORT_STATUS_ERROR				     | PARPORT_STATUS_BUSY);		/* Wait until the peripheral's ready */		do {			/* Is the peripheral ready yet? */			if (!parport_wait_peripheral (port, mask, val))				/* Skip the loop */				goto ready;			/* Is the peripheral upset? */			if ((parport_read_status (port) &			     (PARPORT_STATUS_PAPEROUT |			      PARPORT_STATUS_SELECT |			      PARPORT_STATUS_ERROR))			    != (PARPORT_STATUS_SELECT |				PARPORT_STATUS_ERROR))				/* If nFault is asserted (i.e. no				 * error) and PAPEROUT and SELECT are				 * just red herrings, give the driver				 * a chance to check it's happy with				 * that before continuing. */				goto stop;			/* Have we run out of time? */			if (!time_before (jiffies, expire))				break;			/* Yield the port for a while.  If this is the                           first time around the loop, don't let go of                           the port.  This way, we find out if we have                           our interrupt handler called. */			if (count && no_irq) {				parport_release (dev);				__set_current_state (TASK_INTERRUPTIBLE);				schedule_timeout (wait);				parport_claim_or_block (dev);			}			else				/* We must have the device claimed here */				parport_wait_event (port, wait);			/* Is there a signal pending? */			if (signal_pending (current))				break;			/* Wait longer next time. */			wait *= 2;		} while (time_before (jiffies, expire));		if (signal_pending (current))			break;		DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);		break;	ready:		/* Write the character to the data lines. */		byte = *addr++;		parport_write_data (port, byte);		udelay (1);		/* Pulse strobe. */		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);		udelay (1); /* strobe */		parport_write_control (port, ctl);		udelay (1); /* hold */		/* Assume the peripheral received it. */		count++;                /* Let another process run if it needs to. */		if (time_before (jiffies, expire))			if (!parport_yield_blocking (dev)			    && current->need_resched)				schedule ();	} stop:	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;	return count;}/* Nibble mode. */size_t parport_ieee1284_read_nibble (struct parport *port, 				     void *buffer, size_t len,				     int flags){#ifndef CONFIG_PARPORT_1284	return 0;#else	unsigned char *buf = buffer;	int i;	unsigned char byte = 0;	len *= 2; /* in nibbles */	for (i=0; i < len; i++) {		unsigned char nibble;		/* Does the error line indicate end of data? */		if (((i & 1) == 0) &&		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;			DPRINTK (KERN_DEBUG				"%s: No more nibble data (%d bytes)\n",				port->name, i/2);			/* Go to reverse idle phase. */			parport_frob_control (port,					      PARPORT_CONTROL_AUTOFD,					      PARPORT_CONTROL_AUTOFD);			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;			break;		}		/* Event 7: Set nAutoFd low. */		parport_frob_control (port,				      PARPORT_CONTROL_AUTOFD,				      PARPORT_CONTROL_AUTOFD);		/* Event 9: nAck goes low. */		port->ieee1284.phase = IEEE1284_PH_REV_DATA;		if (parport_wait_peripheral (port,					     PARPORT_STATUS_ACK, 0)) {			/* Timeout -- no more data? */			DPRINTK (KERN_DEBUG				 "%s: Nibble timeout at event 9 (%d bytes)\n",				 port->name, i/2);			break;		}		/* Read a nibble. */		nibble = parport_read_status (port) >> 3;		nibble &= ~8;		if ((nibble & 0x10) == 0)			nibble |= 8;		nibble &= 0xf;		/* Event 10: Set nAutoFd high. */		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);		/* Event 11: nAck goes high. */		if (parport_wait_peripheral (port,					     PARPORT_STATUS_ACK,					     PARPORT_STATUS_ACK)) {			/* Timeout -- no more data? */			DPRINTK (KERN_DEBUG				 "%s: Nibble timeout at event 11\n",				 port->name);			break;		}		if (i & 1) {			/* Second nibble */			byte |= nibble << 4;			*buf++ = byte;		} else 			byte = nibble;	}	i /= 2; /* i is now in bytes */	if (i == len) {		/* Read the last nibble without checking data avail. */		port = port->physport;		if (parport_read_status (port) & PARPORT_STATUS_ERROR)			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;		else			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;	}	return i;#endif /* IEEE1284 support */}/* Byte mode. */size_t parport_ieee1284_read_byte (struct parport *port,				   void *buffer, size_t len,				   int flags){#ifndef CONFIG_PARPORT_1284	return 0;#else	unsigned char *buf = buffer;	ssize_t count = 0;	for (count = 0; count < len; count++) {		unsigned char byte;		/* Data available? */		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;			DPRINTK (KERN_DEBUG				 "%s: No more byte data (%Zd bytes)\n",				 port->name, count);			/* Go to reverse idle phase. */			parport_frob_control (port,					      PARPORT_CONTROL_AUTOFD,					      PARPORT_CONTROL_AUTOFD);			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;			break;		}		/* Event 14: Place data bus in high impedance state. */		parport_data_reverse (port);		/* Event 7: Set nAutoFd low. */		parport_frob_control (port,				      PARPORT_CONTROL_AUTOFD,				      PARPORT_CONTROL_AUTOFD);		/* Event 9: nAck goes low. */		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;		if (parport_wait_peripheral (port,					     PARPORT_STATUS_ACK,					     0)) {			/* Timeout -- no more data? */			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,						 0);			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",				 port->name);			break;		}		byte = parport_read_data (port);		*buf++ = byte;		/* Event 10: Set nAutoFd high */		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);		/* Event 11: nAck goes high. */		if (parport_wait_peripheral (port,					     PARPORT_STATUS_ACK,					     PARPORT_STATUS_ACK)) {			/* Timeout -- no more data? */			DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",				 port->name);			break;		}		/* Event 16: Set nStrobe low. */		parport_frob_control (port,				      PARPORT_CONTROL_STROBE,				      PARPORT_CONTROL_STROBE);		udelay (5);		/* Event 17: Set nStrobe high. */		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);	}	if (count == len) {		/* Read the last byte without checking data avail. */		port = port->physport;		if (parport_read_status (port) & PARPORT_STATUS_ERROR)			port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;		else			port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;	}	return count;#endif /* IEEE1284 support */}/***              * * ECP Functions. * *              ***/#ifdef CONFIG_PARPORT_1284static inlineint ecp_forward_to_reverse (struct parport *port){	int retval;	/* Event 38: Set nAutoFd low */	parport_frob_control (port,			      PARPORT_CONTROL_AUTOFD,			      PARPORT_CONTROL_AUTOFD);	parport_data_reverse (port);	udelay (5);	/* Event 39: Set nInit low to initiate bus reversal */	parport_frob_control (port,			      PARPORT_CONTROL_INIT,			      0);	/* Event 40: PError goes low */	retval = parport_wait_peripheral (port,					  PARPORT_STATUS_PAPEROUT, 0);	if (!retval) {		DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",			 port->name);		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;	}	return retval;}static inlineint ecp_reverse_to_forward (struct parport *port){	int retval;	/* Event 47: Set nInit high */	parport_frob_control (port,			      PARPORT_CONTROL_INIT			      | PARPORT_CONTROL_AUTOFD,			      PARPORT_CONTROL_INIT			      | PARPORT_CONTROL_AUTOFD);	/* Event 49: PError goes high */	retval = parport_wait_peripheral (port,					  PARPORT_STATUS_PAPEROUT,					  PARPORT_STATUS_PAPEROUT);	if (!retval) {		parport_data_forward (port);		DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",			 port->name);		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;	}	return retval;}#endif /* IEEE1284 support *//* ECP mode, forward channel, data. */size_t parport_ieee1284_ecp_write_data (struct parport *port,					const void *buffer, size_t len,					int flags){#ifndef CONFIG_PARPORT_1284	return 0;#else	const unsigned char *buf = buffer;	size_t written;	int retry;	port = port->physport;	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)		if (ecp_reverse_to_forward (port))			return 0;	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;	/* HostAck high (data, not command) */	parport_frob_control (port,			      PARPORT_CONTROL_AUTOFD			      | PARPORT_CONTROL_STROBE			      | PARPORT_CONTROL_INIT,			      PARPORT_CONTROL_INIT);	for (written = 0; written < len; written++, buf++) {		long expire = jiffies + port->cad->timeout;		unsigned char byte;		byte = *buf;	try_again:		parport_write_data (port, byte);		parport_frob_control (port, PARPORT_CONTROL_STROBE,				      PARPORT_CONTROL_STROBE);		udelay (5);		for (retry = 0; retry < 100; retry++) {			if (!parport_wait_peripheral (port,						      PARPORT_STATUS_BUSY, 0))				goto success;			if (signal_pending (current)) {				parport_frob_control (port,

⌨️ 快捷键说明

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