1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /* IEEE-1284 operations for parport.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * This file is for generic IEEE 1284 operations.  The idea is that
51da177e4SLinus Torvalds  * they are used by the low-level drivers.  If they have a special way
61da177e4SLinus Torvalds  * of doing something, they can provide their own routines (and put
71da177e4SLinus Torvalds  * the function pointers in port->ops); if not, they can just use these
81da177e4SLinus Torvalds  * as a fallback.
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Note: Make no assumptions about hardware or architecture in this file!
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
131da177e4SLinus Torvalds  * Fixed AUTOFD polarity in ecp_forward_to_reverse().  Fred Barnes, 1999
141da177e4SLinus Torvalds  * Software emulated EPP fixes, Fred Barnes, 04/2001.
151da177e4SLinus Torvalds  */
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds #include <linux/parport.h>
201da177e4SLinus Torvalds #include <linux/delay.h>
21174cd4b1SIngo Molnar #include <linux/sched/signal.h>
227c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #undef DEBUG /* undef me for production */
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #ifdef CONFIG_LP_CONSOLE
271da177e4SLinus Torvalds #undef DEBUG /* Don't want a garbled console */
281da177e4SLinus Torvalds #endif
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /***                                *
311da177e4SLinus Torvalds  * One-way data transfer functions. *
321da177e4SLinus Torvalds  *                                ***/
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds /* Compatibility mode. */
parport_ieee1284_write_compat(struct parport * port,const void * buffer,size_t len,int flags)351da177e4SLinus Torvalds size_t parport_ieee1284_write_compat (struct parport *port,
361da177e4SLinus Torvalds 				      const void *buffer, size_t len,
371da177e4SLinus Torvalds 				      int flags)
381da177e4SLinus Torvalds {
391da177e4SLinus Torvalds 	int no_irq = 1;
401da177e4SLinus Torvalds 	ssize_t count = 0;
411da177e4SLinus Torvalds 	const unsigned char *addr = buffer;
421da177e4SLinus Torvalds 	unsigned char byte;
431da177e4SLinus Torvalds 	struct pardevice *dev = port->physport->cad;
441da177e4SLinus Torvalds 	unsigned char ctl = (PARPORT_CONTROL_SELECT
451da177e4SLinus Torvalds 			     | PARPORT_CONTROL_INIT);
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	if (port->irq != PARPORT_IRQ_NONE) {
481da177e4SLinus Torvalds 		parport_enable_irq (port);
491da177e4SLinus Torvalds 		no_irq = 0;
501da177e4SLinus Torvalds 	}
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
531da177e4SLinus Torvalds 	parport_write_control (port, ctl);
541da177e4SLinus Torvalds 	parport_data_forward (port);
551da177e4SLinus Torvalds 	while (count < len) {
561da177e4SLinus Torvalds 		unsigned long expire = jiffies + dev->timeout;
577b4ccf8dSNishanth Aravamudan 		long wait = msecs_to_jiffies(10);
581da177e4SLinus Torvalds 		unsigned char mask = (PARPORT_STATUS_ERROR
591da177e4SLinus Torvalds 				      | PARPORT_STATUS_BUSY);
601da177e4SLinus Torvalds 		unsigned char val = (PARPORT_STATUS_ERROR
611da177e4SLinus Torvalds 				     | PARPORT_STATUS_BUSY);
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 		/* Wait until the peripheral's ready */
641da177e4SLinus Torvalds 		do {
651da177e4SLinus Torvalds 			/* Is the peripheral ready yet? */
661da177e4SLinus Torvalds 			if (!parport_wait_peripheral (port, mask, val))
671da177e4SLinus Torvalds 				/* Skip the loop */
681da177e4SLinus Torvalds 				goto ready;
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 			/* Is the peripheral upset? */
711da177e4SLinus Torvalds 			if ((parport_read_status (port) &
721da177e4SLinus Torvalds 			     (PARPORT_STATUS_PAPEROUT |
731da177e4SLinus Torvalds 			      PARPORT_STATUS_SELECT |
741da177e4SLinus Torvalds 			      PARPORT_STATUS_ERROR))
751da177e4SLinus Torvalds 			    != (PARPORT_STATUS_SELECT |
761da177e4SLinus Torvalds 				PARPORT_STATUS_ERROR))
771da177e4SLinus Torvalds 				/* If nFault is asserted (i.e. no
781da177e4SLinus Torvalds 				 * error) and PAPEROUT and SELECT are
791da177e4SLinus Torvalds 				 * just red herrings, give the driver
801da177e4SLinus Torvalds 				 * a chance to check it's happy with
811da177e4SLinus Torvalds 				 * that before continuing. */
821da177e4SLinus Torvalds 				goto stop;
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 			/* Have we run out of time? */
851da177e4SLinus Torvalds 			if (!time_before (jiffies, expire))
861da177e4SLinus Torvalds 				break;
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds 			/* Yield the port for a while.  If this is the
891da177e4SLinus Torvalds                            first time around the loop, don't let go of
901da177e4SLinus Torvalds                            the port.  This way, we find out if we have
911da177e4SLinus Torvalds                            our interrupt handler called. */
921da177e4SLinus Torvalds 			if (count && no_irq) {
931da177e4SLinus Torvalds 				parport_release (dev);
947b4ccf8dSNishanth Aravamudan 				schedule_timeout_interruptible(wait);
951da177e4SLinus Torvalds 				parport_claim_or_block (dev);
961da177e4SLinus Torvalds 			}
971da177e4SLinus Torvalds 			else
981da177e4SLinus Torvalds 				/* We must have the device claimed here */
991da177e4SLinus Torvalds 				parport_wait_event (port, wait);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 			/* Is there a signal pending? */
1021da177e4SLinus Torvalds 			if (signal_pending (current))
1031da177e4SLinus Torvalds 				break;
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 			/* Wait longer next time. */
1061da177e4SLinus Torvalds 			wait *= 2;
1071da177e4SLinus Torvalds 		} while (time_before (jiffies, expire));
1081da177e4SLinus Torvalds 
1091da177e4SLinus Torvalds 		if (signal_pending (current))
1101da177e4SLinus Torvalds 			break;
1111da177e4SLinus Torvalds 
112d98ce9feSJoe Perches 		pr_debug("%s: Timed out\n", port->name);
1131da177e4SLinus Torvalds 		break;
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 	ready:
1161da177e4SLinus Torvalds 		/* Write the character to the data lines. */
1171da177e4SLinus Torvalds 		byte = *addr++;
1181da177e4SLinus Torvalds 		parport_write_data (port, byte);
1191da177e4SLinus Torvalds 		udelay (1);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds 		/* Pulse strobe. */
1221da177e4SLinus Torvalds 		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
1231da177e4SLinus Torvalds 		udelay (1); /* strobe */
1241da177e4SLinus Torvalds 
1251da177e4SLinus Torvalds 		parport_write_control (port, ctl);
1261da177e4SLinus Torvalds 		udelay (1); /* hold */
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 		/* Assume the peripheral received it. */
1291da177e4SLinus Torvalds 		count++;
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds                 /* Let another process run if it needs to. */
1321da177e4SLinus Torvalds 		if (time_before (jiffies, expire))
1331da177e4SLinus Torvalds 			if (!parport_yield_blocking (dev)
1341da177e4SLinus Torvalds 			    && need_resched())
1351da177e4SLinus Torvalds 				schedule ();
1361da177e4SLinus Torvalds 	}
1371da177e4SLinus Torvalds  stop:
1381da177e4SLinus Torvalds 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds 	return count;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds 
1431da177e4SLinus Torvalds /* Nibble mode. */
parport_ieee1284_read_nibble(struct parport * port,void * buffer,size_t len,int flags)1441da177e4SLinus Torvalds size_t parport_ieee1284_read_nibble (struct parport *port,
1451da177e4SLinus Torvalds 				     void *buffer, size_t len,
1461da177e4SLinus Torvalds 				     int flags)
1471da177e4SLinus Torvalds {
1481da177e4SLinus Torvalds #ifndef CONFIG_PARPORT_1284
1491da177e4SLinus Torvalds 	return 0;
1501da177e4SLinus Torvalds #else
1511da177e4SLinus Torvalds 	unsigned char *buf = buffer;
1521da177e4SLinus Torvalds 	int i;
1531da177e4SLinus Torvalds 	unsigned char byte = 0;
1541da177e4SLinus Torvalds 
1551da177e4SLinus Torvalds 	len *= 2; /* in nibbles */
1561da177e4SLinus Torvalds 	for (i=0; i < len; i++) {
1571da177e4SLinus Torvalds 		unsigned char nibble;
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 		/* Does the error line indicate end of data? */
1601da177e4SLinus Torvalds 		if (((i & 1) == 0) &&
1611da177e4SLinus Torvalds 		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
162742ec650SMarko Kohtala 			goto end_of_data;
1631da177e4SLinus Torvalds 		}
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 		/* Event 7: Set nAutoFd low. */
1661da177e4SLinus Torvalds 		parport_frob_control (port,
1671da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD,
1681da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD);
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 		/* Event 9: nAck goes low. */
1711da177e4SLinus Torvalds 		port->ieee1284.phase = IEEE1284_PH_REV_DATA;
1721da177e4SLinus Torvalds 		if (parport_wait_peripheral (port,
1731da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK, 0)) {
1741da177e4SLinus Torvalds 			/* Timeout -- no more data? */
175d98ce9feSJoe Perches 			pr_debug("%s: Nibble timeout at event 9 (%d bytes)\n",
1761da177e4SLinus Torvalds 				 port->name, i / 2);
1771da177e4SLinus Torvalds 			parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
1781da177e4SLinus Torvalds 			break;
1791da177e4SLinus Torvalds 		}
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds 		/* Read a nibble. */
1831da177e4SLinus Torvalds 		nibble = parport_read_status (port) >> 3;
1841da177e4SLinus Torvalds 		nibble &= ~8;
1851da177e4SLinus Torvalds 		if ((nibble & 0x10) == 0)
1861da177e4SLinus Torvalds 			nibble |= 8;
1871da177e4SLinus Torvalds 		nibble &= 0xf;
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds 		/* Event 10: Set nAutoFd high. */
1901da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
1911da177e4SLinus Torvalds 
1921da177e4SLinus Torvalds 		/* Event 11: nAck goes high. */
1931da177e4SLinus Torvalds 		if (parport_wait_peripheral (port,
1941da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK,
1951da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK)) {
1961da177e4SLinus Torvalds 			/* Timeout -- no more data? */
197d98ce9feSJoe Perches 			pr_debug("%s: Nibble timeout at event 11\n",
1981da177e4SLinus Torvalds 				 port->name);
1991da177e4SLinus Torvalds 			break;
2001da177e4SLinus Torvalds 		}
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 		if (i & 1) {
2031da177e4SLinus Torvalds 			/* Second nibble */
2041da177e4SLinus Torvalds 			byte |= nibble << 4;
2051da177e4SLinus Torvalds 			*buf++ = byte;
2061da177e4SLinus Torvalds 		} else
2071da177e4SLinus Torvalds 			byte = nibble;
2081da177e4SLinus Torvalds 	}
2091da177e4SLinus Torvalds 
2101da177e4SLinus Torvalds 	if (i == len) {
2111da177e4SLinus Torvalds 		/* Read the last nibble without checking data avail. */
212742ec650SMarko Kohtala 		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
213742ec650SMarko Kohtala 		end_of_data:
214d98ce9feSJoe Perches 			pr_debug("%s: No more nibble data (%d bytes)\n",
215742ec650SMarko Kohtala 				 port->name, i / 2);
216742ec650SMarko Kohtala 
217742ec650SMarko Kohtala 			/* Go to reverse idle phase. */
218742ec650SMarko Kohtala 			parport_frob_control (port,
219742ec650SMarko Kohtala 					      PARPORT_CONTROL_AUTOFD,
220742ec650SMarko Kohtala 					      PARPORT_CONTROL_AUTOFD);
221742ec650SMarko Kohtala 			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
222742ec650SMarko Kohtala 		}
2231da177e4SLinus Torvalds 		else
224742ec650SMarko Kohtala 			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
2251da177e4SLinus Torvalds 	}
2261da177e4SLinus Torvalds 
227742ec650SMarko Kohtala 	return i/2;
2281da177e4SLinus Torvalds #endif /* IEEE1284 support */
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds /* Byte mode. */
parport_ieee1284_read_byte(struct parport * port,void * buffer,size_t len,int flags)2321da177e4SLinus Torvalds size_t parport_ieee1284_read_byte (struct parport *port,
2331da177e4SLinus Torvalds 				   void *buffer, size_t len,
2341da177e4SLinus Torvalds 				   int flags)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds #ifndef CONFIG_PARPORT_1284
2371da177e4SLinus Torvalds 	return 0;
2381da177e4SLinus Torvalds #else
2391da177e4SLinus Torvalds 	unsigned char *buf = buffer;
2401da177e4SLinus Torvalds 	ssize_t count = 0;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	for (count = 0; count < len; count++) {
2431da177e4SLinus Torvalds 		unsigned char byte;
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 		/* Data available? */
2461da177e4SLinus Torvalds 		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
247742ec650SMarko Kohtala 			goto end_of_data;
2481da177e4SLinus Torvalds 		}
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 		/* Event 14: Place data bus in high impedance state. */
2511da177e4SLinus Torvalds 		parport_data_reverse (port);
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 		/* Event 7: Set nAutoFd low. */
2541da177e4SLinus Torvalds 		parport_frob_control (port,
2551da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD,
2561da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD);
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 		/* Event 9: nAck goes low. */
2591da177e4SLinus Torvalds 		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
2601da177e4SLinus Torvalds 		if (parport_wait_peripheral (port,
2611da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK,
2621da177e4SLinus Torvalds 					     0)) {
2631da177e4SLinus Torvalds 			/* Timeout -- no more data? */
2641da177e4SLinus Torvalds 			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
2651da177e4SLinus Torvalds 						 0);
266d98ce9feSJoe Perches 			pr_debug("%s: Byte timeout at event 9\n", port->name);
2671da177e4SLinus Torvalds 			break;
2681da177e4SLinus Torvalds 		}
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 		byte = parport_read_data (port);
2711da177e4SLinus Torvalds 		*buf++ = byte;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 		/* Event 10: Set nAutoFd high */
2741da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds 		/* Event 11: nAck goes high. */
2771da177e4SLinus Torvalds 		if (parport_wait_peripheral (port,
2781da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK,
2791da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK)) {
2801da177e4SLinus Torvalds 			/* Timeout -- no more data? */
281d98ce9feSJoe Perches 			pr_debug("%s: Byte timeout at event 11\n", port->name);
2821da177e4SLinus Torvalds 			break;
2831da177e4SLinus Torvalds 		}
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds 		/* Event 16: Set nStrobe low. */
2861da177e4SLinus Torvalds 		parport_frob_control (port,
2871da177e4SLinus Torvalds 				      PARPORT_CONTROL_STROBE,
2881da177e4SLinus Torvalds 				      PARPORT_CONTROL_STROBE);
2891da177e4SLinus Torvalds 		udelay (5);
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 		/* Event 17: Set nStrobe high. */
2921da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
2931da177e4SLinus Torvalds 	}
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 	if (count == len) {
2961da177e4SLinus Torvalds 		/* Read the last byte without checking data avail. */
297742ec650SMarko Kohtala 		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
298742ec650SMarko Kohtala 		end_of_data:
299d98ce9feSJoe Perches 			pr_debug("%s: No more byte data (%zd bytes)\n",
300742ec650SMarko Kohtala 				 port->name, count);
301742ec650SMarko Kohtala 
302742ec650SMarko Kohtala 			/* Go to reverse idle phase. */
303742ec650SMarko Kohtala 			parport_frob_control (port,
304742ec650SMarko Kohtala 					      PARPORT_CONTROL_AUTOFD,
305742ec650SMarko Kohtala 					      PARPORT_CONTROL_AUTOFD);
306742ec650SMarko Kohtala 			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
307742ec650SMarko Kohtala 		}
3081da177e4SLinus Torvalds 		else
309742ec650SMarko Kohtala 			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
3101da177e4SLinus Torvalds 	}
3111da177e4SLinus Torvalds 
3121da177e4SLinus Torvalds 	return count;
3131da177e4SLinus Torvalds #endif /* IEEE1284 support */
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds /***              *
3171da177e4SLinus Torvalds  * ECP Functions. *
3181da177e4SLinus Torvalds  *              ***/
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds #ifdef CONFIG_PARPORT_1284
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds static inline
ecp_forward_to_reverse(struct parport * port)3231da177e4SLinus Torvalds int ecp_forward_to_reverse (struct parport *port)
3241da177e4SLinus Torvalds {
3251da177e4SLinus Torvalds 	int retval;
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds 	/* Event 38: Set nAutoFd low */
3281da177e4SLinus Torvalds 	parport_frob_control (port,
3291da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD,
3301da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD);
3311da177e4SLinus Torvalds 	parport_data_reverse (port);
3321da177e4SLinus Torvalds 	udelay (5);
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	/* Event 39: Set nInit low to initiate bus reversal */
3351da177e4SLinus Torvalds 	parport_frob_control (port,
3361da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT,
3371da177e4SLinus Torvalds 			      0);
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	/* Event 40: PError goes low */
3401da177e4SLinus Torvalds 	retval = parport_wait_peripheral (port,
3411da177e4SLinus Torvalds 					  PARPORT_STATUS_PAPEROUT, 0);
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	if (!retval) {
344d98ce9feSJoe Perches 		pr_debug("%s: ECP direction: reverse\n", port->name);
3451da177e4SLinus Torvalds 		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
3461da177e4SLinus Torvalds 	} else {
347d98ce9feSJoe Perches 		pr_debug("%s: ECP direction: failed to reverse\n", port->name);
3481da177e4SLinus Torvalds 		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
3491da177e4SLinus Torvalds 	}
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds 	return retval;
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds static inline
ecp_reverse_to_forward(struct parport * port)3551da177e4SLinus Torvalds int ecp_reverse_to_forward (struct parport *port)
3561da177e4SLinus Torvalds {
3571da177e4SLinus Torvalds 	int retval;
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	/* Event 47: Set nInit high */
3601da177e4SLinus Torvalds 	parport_frob_control (port,
3611da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT
3621da177e4SLinus Torvalds 			      | PARPORT_CONTROL_AUTOFD,
3631da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT
3641da177e4SLinus Torvalds 			      | PARPORT_CONTROL_AUTOFD);
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	/* Event 49: PError goes high */
3671da177e4SLinus Torvalds 	retval = parport_wait_peripheral (port,
3681da177e4SLinus Torvalds 					  PARPORT_STATUS_PAPEROUT,
3691da177e4SLinus Torvalds 					  PARPORT_STATUS_PAPEROUT);
3701da177e4SLinus Torvalds 
3711da177e4SLinus Torvalds 	if (!retval) {
3721da177e4SLinus Torvalds 		parport_data_forward (port);
373d98ce9feSJoe Perches 		pr_debug("%s: ECP direction: forward\n", port->name);
3741da177e4SLinus Torvalds 		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
3751da177e4SLinus Torvalds 	} else {
376d98ce9feSJoe Perches 		pr_debug("%s: ECP direction: failed to switch forward\n",
3771da177e4SLinus Torvalds 			 port->name);
3781da177e4SLinus Torvalds 		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
3791da177e4SLinus Torvalds 	}
3801da177e4SLinus Torvalds 
3811da177e4SLinus Torvalds 
3821da177e4SLinus Torvalds 	return retval;
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds #endif /* IEEE1284 support */
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds /* ECP mode, forward channel, data. */
parport_ieee1284_ecp_write_data(struct parport * port,const void * buffer,size_t len,int flags)3881da177e4SLinus Torvalds size_t parport_ieee1284_ecp_write_data (struct parport *port,
3891da177e4SLinus Torvalds 					const void *buffer, size_t len,
3901da177e4SLinus Torvalds 					int flags)
3911da177e4SLinus Torvalds {
3921da177e4SLinus Torvalds #ifndef CONFIG_PARPORT_1284
3931da177e4SLinus Torvalds 	return 0;
3941da177e4SLinus Torvalds #else
3951da177e4SLinus Torvalds 	const unsigned char *buf = buffer;
3961da177e4SLinus Torvalds 	size_t written;
3971da177e4SLinus Torvalds 	int retry;
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	port = port->physport;
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds 	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
4021da177e4SLinus Torvalds 		if (ecp_reverse_to_forward (port))
4031da177e4SLinus Torvalds 			return 0;
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds 	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	/* HostAck high (data, not command) */
4081da177e4SLinus Torvalds 	parport_frob_control (port,
4091da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD
4101da177e4SLinus Torvalds 			      | PARPORT_CONTROL_STROBE
4111da177e4SLinus Torvalds 			      | PARPORT_CONTROL_INIT,
4121da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT);
4131da177e4SLinus Torvalds 	for (written = 0; written < len; written++, buf++) {
4141da177e4SLinus Torvalds 		unsigned long expire = jiffies + port->cad->timeout;
4151da177e4SLinus Torvalds 		unsigned char byte;
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds 		byte = *buf;
4181da177e4SLinus Torvalds 	try_again:
4191da177e4SLinus Torvalds 		parport_write_data (port, byte);
4201da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_STROBE,
4211da177e4SLinus Torvalds 				      PARPORT_CONTROL_STROBE);
4221da177e4SLinus Torvalds 		udelay (5);
4231da177e4SLinus Torvalds 		for (retry = 0; retry < 100; retry++) {
4241da177e4SLinus Torvalds 			if (!parport_wait_peripheral (port,
4251da177e4SLinus Torvalds 						      PARPORT_STATUS_BUSY, 0))
4261da177e4SLinus Torvalds 				goto success;
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 			if (signal_pending (current)) {
4291da177e4SLinus Torvalds 				parport_frob_control (port,
4301da177e4SLinus Torvalds 						      PARPORT_CONTROL_STROBE,
4311da177e4SLinus Torvalds 						      0);
4321da177e4SLinus Torvalds 				break;
4331da177e4SLinus Torvalds 			}
4341da177e4SLinus Torvalds 		}
4351da177e4SLinus Torvalds 
4361da177e4SLinus Torvalds 		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
437d98ce9feSJoe Perches 		pr_debug("%s: ECP transfer stalled!\n", port->name);
4381da177e4SLinus Torvalds 
4391da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_INIT,
4401da177e4SLinus Torvalds 				      PARPORT_CONTROL_INIT);
4411da177e4SLinus Torvalds 		udelay (50);
4421da177e4SLinus Torvalds 		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
4431da177e4SLinus Torvalds 			/* It's buggered. */
4441da177e4SLinus Torvalds 			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
4451da177e4SLinus Torvalds 			break;
4461da177e4SLinus Torvalds 		}
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
4491da177e4SLinus Torvalds 		udelay (50);
4501da177e4SLinus Torvalds 		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
4511da177e4SLinus Torvalds 			break;
4521da177e4SLinus Torvalds 
453d98ce9feSJoe Perches 		pr_debug("%s: Host transfer recovered\n", port->name);
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds 		if (time_after_eq (jiffies, expire)) break;
4561da177e4SLinus Torvalds 		goto try_again;
4571da177e4SLinus Torvalds 	success:
4581da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
4591da177e4SLinus Torvalds 		udelay (5);
4601da177e4SLinus Torvalds 		if (parport_wait_peripheral (port,
4611da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY,
4621da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY))
4631da177e4SLinus Torvalds 			/* Peripheral hasn't accepted the data. */
4641da177e4SLinus Torvalds 			break;
4651da177e4SLinus Torvalds 	}
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds 	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
4681da177e4SLinus Torvalds 
4691da177e4SLinus Torvalds 	return written;
4701da177e4SLinus Torvalds #endif /* IEEE1284 support */
4711da177e4SLinus Torvalds }
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds /* ECP mode, reverse channel, data. */
parport_ieee1284_ecp_read_data(struct parport * port,void * buffer,size_t len,int flags)4741da177e4SLinus Torvalds size_t parport_ieee1284_ecp_read_data (struct parport *port,
4751da177e4SLinus Torvalds 				       void *buffer, size_t len, int flags)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds #ifndef CONFIG_PARPORT_1284
4781da177e4SLinus Torvalds 	return 0;
4791da177e4SLinus Torvalds #else
4801da177e4SLinus Torvalds 	struct pardevice *dev = port->cad;
4811da177e4SLinus Torvalds 	unsigned char *buf = buffer;
4821da177e4SLinus Torvalds 	int rle_count = 0; /* shut gcc up */
4831da177e4SLinus Torvalds 	unsigned char ctl;
4841da177e4SLinus Torvalds 	int rle = 0;
4851da177e4SLinus Torvalds 	ssize_t count = 0;
4861da177e4SLinus Torvalds 
4871da177e4SLinus Torvalds 	port = port->physport;
4881da177e4SLinus Torvalds 
4891da177e4SLinus Torvalds 	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
4901da177e4SLinus Torvalds 		if (ecp_forward_to_reverse (port))
4911da177e4SLinus Torvalds 			return 0;
4921da177e4SLinus Torvalds 
4931da177e4SLinus Torvalds 	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
4941da177e4SLinus Torvalds 
4951da177e4SLinus Torvalds 	/* Set HostAck low to start accepting data. */
4961da177e4SLinus Torvalds 	ctl = parport_read_control (port);
4971da177e4SLinus Torvalds 	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT |
4981da177e4SLinus Torvalds 		 PARPORT_CONTROL_AUTOFD);
4991da177e4SLinus Torvalds 	parport_write_control (port,
5001da177e4SLinus Torvalds 			       ctl | PARPORT_CONTROL_AUTOFD);
5011da177e4SLinus Torvalds 	while (count < len) {
5021da177e4SLinus Torvalds 		unsigned long expire = jiffies + dev->timeout;
5031da177e4SLinus Torvalds 		unsigned char byte;
5041da177e4SLinus Torvalds 		int command;
5051da177e4SLinus Torvalds 
5061da177e4SLinus Torvalds 		/* Event 43: Peripheral sets nAck low. It can take as
5071da177e4SLinus Torvalds                    long as it wants. */
5081da177e4SLinus Torvalds 		while (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
5091da177e4SLinus Torvalds 			/* The peripheral hasn't given us data in
5101da177e4SLinus Torvalds 			   35ms.  If we have data to give back to the
5111da177e4SLinus Torvalds 			   caller, do it now. */
5121da177e4SLinus Torvalds 			if (count)
5131da177e4SLinus Torvalds 				goto out;
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 			/* If we've used up all the time we were allowed,
5161da177e4SLinus Torvalds 			   give up altogether. */
5171da177e4SLinus Torvalds 			if (!time_before (jiffies, expire))
5181da177e4SLinus Torvalds 				goto out;
5191da177e4SLinus Torvalds 
5201da177e4SLinus Torvalds 			/* Yield the port for a while. */
521*0be883a0SColin Ian King 			if (dev->port->irq != PARPORT_IRQ_NONE) {
5221da177e4SLinus Torvalds 				parport_release (dev);
5237b4ccf8dSNishanth Aravamudan 				schedule_timeout_interruptible(msecs_to_jiffies(40));
5241da177e4SLinus Torvalds 				parport_claim_or_block (dev);
5251da177e4SLinus Torvalds 			}
5261da177e4SLinus Torvalds 			else
5271da177e4SLinus Torvalds 				/* We must have the device claimed here. */
5287b4ccf8dSNishanth Aravamudan 				parport_wait_event (port, msecs_to_jiffies(40));
5291da177e4SLinus Torvalds 
5301da177e4SLinus Torvalds 			/* Is there a signal pending? */
5311da177e4SLinus Torvalds 			if (signal_pending (current))
5321da177e4SLinus Torvalds 				goto out;
5331da177e4SLinus Torvalds 		}
5341da177e4SLinus Torvalds 
5351da177e4SLinus Torvalds 		/* Is this a command? */
5361da177e4SLinus Torvalds 		if (rle)
5371da177e4SLinus Torvalds 			/* The last byte was a run-length count, so
5381da177e4SLinus Torvalds                            this can't be as well. */
5391da177e4SLinus Torvalds 			command = 0;
5401da177e4SLinus Torvalds 		else
5411da177e4SLinus Torvalds 			command = (parport_read_status (port) &
5421da177e4SLinus Torvalds 				   PARPORT_STATUS_BUSY) ? 1 : 0;
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 		/* Read the data. */
5451da177e4SLinus Torvalds 		byte = parport_read_data (port);
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds 		/* If this is a channel command, rather than an RLE
5481da177e4SLinus Torvalds                    command or a normal data byte, don't accept it. */
5491da177e4SLinus Torvalds 		if (command) {
5501da177e4SLinus Torvalds 			if (byte & 0x80) {
551d98ce9feSJoe Perches 				pr_debug("%s: stopping short at channel command (%02x)\n",
5521da177e4SLinus Torvalds 					 port->name, byte);
5531da177e4SLinus Torvalds 				goto out;
5541da177e4SLinus Torvalds 			}
5551da177e4SLinus Torvalds 			else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
556d98ce9feSJoe Perches 				pr_debug("%s: device illegally using RLE; accepting anyway\n",
5571da177e4SLinus Torvalds 					 port->name);
5581da177e4SLinus Torvalds 
5591da177e4SLinus Torvalds 			rle_count = byte + 1;
5601da177e4SLinus Torvalds 
5611da177e4SLinus Torvalds 			/* Are we allowed to read that many bytes? */
5621da177e4SLinus Torvalds 			if (rle_count > (len - count)) {
563d98ce9feSJoe Perches 				pr_debug("%s: leaving %d RLE bytes for next time\n",
564d98ce9feSJoe Perches 					 port->name, rle_count);
5651da177e4SLinus Torvalds 				break;
5661da177e4SLinus Torvalds 			}
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds 			rle = 1;
5691da177e4SLinus Torvalds 		}
5701da177e4SLinus Torvalds 
5711da177e4SLinus Torvalds 		/* Event 44: Set HostAck high, acknowledging handshake. */
5721da177e4SLinus Torvalds 		parport_write_control (port, ctl);
5731da177e4SLinus Torvalds 
5741da177e4SLinus Torvalds 		/* Event 45: The peripheral has 35ms to set nAck high. */
5751da177e4SLinus Torvalds 		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK,
5761da177e4SLinus Torvalds 					     PARPORT_STATUS_ACK)) {
5771da177e4SLinus Torvalds 			/* It's gone wrong.  Return what data we have
5781da177e4SLinus Torvalds                            to the caller. */
579d98ce9feSJoe Perches 			pr_debug("ECP read timed out at 45\n");
5801da177e4SLinus Torvalds 
5811da177e4SLinus Torvalds 			if (command)
582decf26f6SJoe Perches 				pr_warn("%s: command ignored (%02x)\n",
5831da177e4SLinus Torvalds 					port->name, byte);
5841da177e4SLinus Torvalds 
5851da177e4SLinus Torvalds 			break;
5861da177e4SLinus Torvalds 		}
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 		/* Event 46: Set HostAck low and accept the data. */
5891da177e4SLinus Torvalds 		parport_write_control (port,
5901da177e4SLinus Torvalds 				       ctl | PARPORT_CONTROL_AUTOFD);
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 		/* If we just read a run-length count, fetch the data. */
5931da177e4SLinus Torvalds 		if (command)
5941da177e4SLinus Torvalds 			continue;
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 		/* If this is the byte after a run-length count, decompress. */
5971da177e4SLinus Torvalds 		if (rle) {
5981da177e4SLinus Torvalds 			rle = 0;
5991da177e4SLinus Torvalds 			memset (buf, byte, rle_count);
6001da177e4SLinus Torvalds 			buf += rle_count;
6011da177e4SLinus Torvalds 			count += rle_count;
602d98ce9feSJoe Perches 			pr_debug("%s: decompressed to %d bytes\n",
6031da177e4SLinus Torvalds 				 port->name, rle_count);
6041da177e4SLinus Torvalds 		} else {
6051da177e4SLinus Torvalds 			/* Normal data byte. */
6061da177e4SLinus Torvalds 			*buf = byte;
6071da177e4SLinus Torvalds 			buf++, count++;
6081da177e4SLinus Torvalds 		}
6091da177e4SLinus Torvalds 	}
6101da177e4SLinus Torvalds 
6111da177e4SLinus Torvalds  out:
6121da177e4SLinus Torvalds 	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
6131da177e4SLinus Torvalds 	return count;
6141da177e4SLinus Torvalds #endif /* IEEE1284 support */
6151da177e4SLinus Torvalds }
6161da177e4SLinus Torvalds 
6171da177e4SLinus Torvalds /* ECP mode, forward channel, commands. */
parport_ieee1284_ecp_write_addr(struct parport * port,const void * buffer,size_t len,int flags)6181da177e4SLinus Torvalds size_t parport_ieee1284_ecp_write_addr (struct parport *port,
6191da177e4SLinus Torvalds 					const void *buffer, size_t len,
6201da177e4SLinus Torvalds 					int flags)
6211da177e4SLinus Torvalds {
6221da177e4SLinus Torvalds #ifndef CONFIG_PARPORT_1284
6231da177e4SLinus Torvalds 	return 0;
6241da177e4SLinus Torvalds #else
6251da177e4SLinus Torvalds 	const unsigned char *buf = buffer;
6261da177e4SLinus Torvalds 	size_t written;
6271da177e4SLinus Torvalds 	int retry;
6281da177e4SLinus Torvalds 
6291da177e4SLinus Torvalds 	port = port->physport;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
6321da177e4SLinus Torvalds 		if (ecp_reverse_to_forward (port))
6331da177e4SLinus Torvalds 			return 0;
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 	/* HostAck low (command, not data) */
6381da177e4SLinus Torvalds 	parport_frob_control (port,
6391da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD
6401da177e4SLinus Torvalds 			      | PARPORT_CONTROL_STROBE
6411da177e4SLinus Torvalds 			      | PARPORT_CONTROL_INIT,
6421da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD
6431da177e4SLinus Torvalds 			      | PARPORT_CONTROL_INIT);
6441da177e4SLinus Torvalds 	for (written = 0; written < len; written++, buf++) {
6451da177e4SLinus Torvalds 		unsigned long expire = jiffies + port->cad->timeout;
6461da177e4SLinus Torvalds 		unsigned char byte;
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 		byte = *buf;
6491da177e4SLinus Torvalds 	try_again:
6501da177e4SLinus Torvalds 		parport_write_data (port, byte);
6511da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_STROBE,
6521da177e4SLinus Torvalds 				      PARPORT_CONTROL_STROBE);
6531da177e4SLinus Torvalds 		udelay (5);
6541da177e4SLinus Torvalds 		for (retry = 0; retry < 100; retry++) {
6551da177e4SLinus Torvalds 			if (!parport_wait_peripheral (port,
6561da177e4SLinus Torvalds 						      PARPORT_STATUS_BUSY, 0))
6571da177e4SLinus Torvalds 				goto success;
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds 			if (signal_pending (current)) {
6601da177e4SLinus Torvalds 				parport_frob_control (port,
6611da177e4SLinus Torvalds 						      PARPORT_CONTROL_STROBE,
6621da177e4SLinus Torvalds 						      0);
6631da177e4SLinus Torvalds 				break;
6641da177e4SLinus Torvalds 			}
6651da177e4SLinus Torvalds 		}
6661da177e4SLinus Torvalds 
6671da177e4SLinus Torvalds 		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
668d98ce9feSJoe Perches 		pr_debug("%s: ECP transfer stalled!\n", port->name);
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_INIT,
6711da177e4SLinus Torvalds 				      PARPORT_CONTROL_INIT);
6721da177e4SLinus Torvalds 		udelay (50);
6731da177e4SLinus Torvalds 		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
6741da177e4SLinus Torvalds 			/* It's buggered. */
6751da177e4SLinus Torvalds 			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
6761da177e4SLinus Torvalds 			break;
6771da177e4SLinus Torvalds 		}
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
6801da177e4SLinus Torvalds 		udelay (50);
6811da177e4SLinus Torvalds 		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
6821da177e4SLinus Torvalds 			break;
6831da177e4SLinus Torvalds 
684d98ce9feSJoe Perches 		pr_debug("%s: Host transfer recovered\n", port->name);
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 		if (time_after_eq (jiffies, expire)) break;
6871da177e4SLinus Torvalds 		goto try_again;
6881da177e4SLinus Torvalds 	success:
6891da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
6901da177e4SLinus Torvalds 		udelay (5);
6911da177e4SLinus Torvalds 		if (parport_wait_peripheral (port,
6921da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY,
6931da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY))
6941da177e4SLinus Torvalds 			/* Peripheral hasn't accepted the data. */
6951da177e4SLinus Torvalds 			break;
6961da177e4SLinus Torvalds 	}
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds 	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	return written;
7011da177e4SLinus Torvalds #endif /* IEEE1284 support */
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds /***              *
7051da177e4SLinus Torvalds  * EPP functions. *
7061da177e4SLinus Torvalds  *              ***/
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds /* EPP mode, forward channel, data. */
parport_ieee1284_epp_write_data(struct parport * port,const void * buffer,size_t len,int flags)7091da177e4SLinus Torvalds size_t parport_ieee1284_epp_write_data (struct parport *port,
7101da177e4SLinus Torvalds 					const void *buffer, size_t len,
7111da177e4SLinus Torvalds 					int flags)
7121da177e4SLinus Torvalds {
7131da177e4SLinus Torvalds 	unsigned char *bp = (unsigned char *) buffer;
7141da177e4SLinus Torvalds 	size_t ret = 0;
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	/* set EPP idle state (just to make sure) with strobe low */
7171da177e4SLinus Torvalds 	parport_frob_control (port,
7181da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE |
7191da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD |
7201da177e4SLinus Torvalds 			      PARPORT_CONTROL_SELECT |
7211da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT,
7221da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE |
7231da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT);
7241da177e4SLinus Torvalds 	port->ops->data_forward (port);
7251da177e4SLinus Torvalds 	for (; len > 0; len--, bp++) {
7261da177e4SLinus Torvalds 		/* Event 62: Write data and set autofd low */
7271da177e4SLinus Torvalds 		parport_write_data (port, *bp);
7281da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
7291da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD);
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 		/* Event 58: wait for busy (nWait) to go high */
7321da177e4SLinus Torvalds 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
7331da177e4SLinus Torvalds 			break;
7341da177e4SLinus Torvalds 
7351da177e4SLinus Torvalds 		/* Event 63: set nAutoFd (nDStrb) high */
7361da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
7371da177e4SLinus Torvalds 
7381da177e4SLinus Torvalds 		/* Event 60: wait for busy (nWait) to go low */
7391da177e4SLinus Torvalds 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
7401da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY, 5))
7411da177e4SLinus Torvalds 			break;
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 		ret++;
7441da177e4SLinus Torvalds 	}
7451da177e4SLinus Torvalds 
7461da177e4SLinus Torvalds 	/* Event 61: set strobe (nWrite) high */
7471da177e4SLinus Torvalds 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
7481da177e4SLinus Torvalds 
7491da177e4SLinus Torvalds 	return ret;
7501da177e4SLinus Torvalds }
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds /* EPP mode, reverse channel, data. */
parport_ieee1284_epp_read_data(struct parport * port,void * buffer,size_t len,int flags)7531da177e4SLinus Torvalds size_t parport_ieee1284_epp_read_data (struct parport *port,
7541da177e4SLinus Torvalds 				       void *buffer, size_t len,
7551da177e4SLinus Torvalds 				       int flags)
7561da177e4SLinus Torvalds {
7571da177e4SLinus Torvalds 	unsigned char *bp = (unsigned char *) buffer;
7581da177e4SLinus Torvalds 	unsigned ret = 0;
7591da177e4SLinus Torvalds 
7601da177e4SLinus Torvalds 	/* set EPP idle state (just to make sure) with strobe high */
7611da177e4SLinus Torvalds 	parport_frob_control (port,
7621da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE |
7631da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD |
7641da177e4SLinus Torvalds 			      PARPORT_CONTROL_SELECT |
7651da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT,
7661da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT);
7671da177e4SLinus Torvalds 	port->ops->data_reverse (port);
7681da177e4SLinus Torvalds 	for (; len > 0; len--, bp++) {
7691da177e4SLinus Torvalds 		/* Event 67: set nAutoFd (nDStrb) low */
7701da177e4SLinus Torvalds 		parport_frob_control (port,
7711da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD,
7721da177e4SLinus Torvalds 				      PARPORT_CONTROL_AUTOFD);
7731da177e4SLinus Torvalds 		/* Event 58: wait for Busy to go high */
7741da177e4SLinus Torvalds 		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
7751da177e4SLinus Torvalds 			break;
7761da177e4SLinus Torvalds 		}
7771da177e4SLinus Torvalds 
7781da177e4SLinus Torvalds 		*bp = parport_read_data (port);
7791da177e4SLinus Torvalds 
7801da177e4SLinus Torvalds 		/* Event 63: set nAutoFd (nDStrb) high */
7811da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
7821da177e4SLinus Torvalds 
7831da177e4SLinus Torvalds 		/* Event 60: wait for Busy to go low */
7841da177e4SLinus Torvalds 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
7851da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY, 5)) {
7861da177e4SLinus Torvalds 			break;
7871da177e4SLinus Torvalds 		}
7881da177e4SLinus Torvalds 
7891da177e4SLinus Torvalds 		ret++;
7901da177e4SLinus Torvalds 	}
7911da177e4SLinus Torvalds 	port->ops->data_forward (port);
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 	return ret;
7941da177e4SLinus Torvalds }
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds /* EPP mode, forward channel, addresses. */
parport_ieee1284_epp_write_addr(struct parport * port,const void * buffer,size_t len,int flags)7971da177e4SLinus Torvalds size_t parport_ieee1284_epp_write_addr (struct parport *port,
7981da177e4SLinus Torvalds 					const void *buffer, size_t len,
7991da177e4SLinus Torvalds 					int flags)
8001da177e4SLinus Torvalds {
8011da177e4SLinus Torvalds 	unsigned char *bp = (unsigned char *) buffer;
8021da177e4SLinus Torvalds 	size_t ret = 0;
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	/* set EPP idle state (just to make sure) with strobe low */
8051da177e4SLinus Torvalds 	parport_frob_control (port,
8061da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE |
8071da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD |
8081da177e4SLinus Torvalds 			      PARPORT_CONTROL_SELECT |
8091da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT,
8101da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE |
8111da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT);
8121da177e4SLinus Torvalds 	port->ops->data_forward (port);
8131da177e4SLinus Torvalds 	for (; len > 0; len--, bp++) {
8141da177e4SLinus Torvalds 		/* Event 56: Write data and set nAStrb low. */
8151da177e4SLinus Torvalds 		parport_write_data (port, *bp);
8161da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
8171da177e4SLinus Torvalds 				      PARPORT_CONTROL_SELECT);
8181da177e4SLinus Torvalds 
8191da177e4SLinus Torvalds 		/* Event 58: wait for busy (nWait) to go high */
8201da177e4SLinus Torvalds 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
8211da177e4SLinus Torvalds 			break;
8221da177e4SLinus Torvalds 
8231da177e4SLinus Torvalds 		/* Event 59: set nAStrb high */
8241da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
8251da177e4SLinus Torvalds 
8261da177e4SLinus Torvalds 		/* Event 60: wait for busy (nWait) to go low */
8271da177e4SLinus Torvalds 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
8281da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY, 5))
8291da177e4SLinus Torvalds 			break;
8301da177e4SLinus Torvalds 
8311da177e4SLinus Torvalds 		ret++;
8321da177e4SLinus Torvalds 	}
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 	/* Event 61: set strobe (nWrite) high */
8351da177e4SLinus Torvalds 	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	return ret;
8381da177e4SLinus Torvalds }
8391da177e4SLinus Torvalds 
8401da177e4SLinus Torvalds /* EPP mode, reverse channel, addresses. */
parport_ieee1284_epp_read_addr(struct parport * port,void * buffer,size_t len,int flags)8411da177e4SLinus Torvalds size_t parport_ieee1284_epp_read_addr (struct parport *port,
8421da177e4SLinus Torvalds 				       void *buffer, size_t len,
8431da177e4SLinus Torvalds 				       int flags)
8441da177e4SLinus Torvalds {
8451da177e4SLinus Torvalds 	unsigned char *bp = (unsigned char *) buffer;
8461da177e4SLinus Torvalds 	unsigned ret = 0;
8471da177e4SLinus Torvalds 
8481da177e4SLinus Torvalds 	/* Set EPP idle state (just to make sure) with strobe high */
8491da177e4SLinus Torvalds 	parport_frob_control (port,
8501da177e4SLinus Torvalds 			      PARPORT_CONTROL_STROBE |
8511da177e4SLinus Torvalds 			      PARPORT_CONTROL_AUTOFD |
8521da177e4SLinus Torvalds 			      PARPORT_CONTROL_SELECT |
8531da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT,
8541da177e4SLinus Torvalds 			      PARPORT_CONTROL_INIT);
8551da177e4SLinus Torvalds 	port->ops->data_reverse (port);
8561da177e4SLinus Torvalds 	for (; len > 0; len--, bp++) {
8571da177e4SLinus Torvalds 		/* Event 64: set nSelectIn (nAStrb) low */
8581da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
8591da177e4SLinus Torvalds 				      PARPORT_CONTROL_SELECT);
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 		/* Event 58: wait for Busy to go high */
8621da177e4SLinus Torvalds 		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
8631da177e4SLinus Torvalds 			break;
8641da177e4SLinus Torvalds 		}
8651da177e4SLinus Torvalds 
8661da177e4SLinus Torvalds 		*bp = parport_read_data (port);
8671da177e4SLinus Torvalds 
8681da177e4SLinus Torvalds 		/* Event 59: set nSelectIn (nAStrb) high */
8691da177e4SLinus Torvalds 		parport_frob_control (port, PARPORT_CONTROL_SELECT,
87013050d89SStephan Boettcher 				      0);
8711da177e4SLinus Torvalds 
8721da177e4SLinus Torvalds 		/* Event 60: wait for Busy to go low */
8731da177e4SLinus Torvalds 		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
8741da177e4SLinus Torvalds 					     PARPORT_STATUS_BUSY, 5))
8751da177e4SLinus Torvalds 			break;
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 		ret++;
8781da177e4SLinus Torvalds 	}
8791da177e4SLinus Torvalds 	port->ops->data_forward (port);
8801da177e4SLinus Torvalds 
8811da177e4SLinus Torvalds 	return ret;
8821da177e4SLinus Torvalds }
8831da177e4SLinus Torvalds 
8841da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
8851da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
8861da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
8871da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_write_compat);
8881da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_read_nibble);
8891da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_read_byte);
8901da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
8911da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
8921da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
8931da177e4SLinus Torvalds EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
894