18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* IEEE-1284 operations for parport.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This file is for generic IEEE 1284 operations.  The idea is that
58c2ecf20Sopenharmony_ci * they are used by the low-level drivers.  If they have a special way
68c2ecf20Sopenharmony_ci * of doing something, they can provide their own routines (and put
78c2ecf20Sopenharmony_ci * the function pointers in port->ops); if not, they can just use these
88c2ecf20Sopenharmony_ci * as a fallback.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Note: Make no assumptions about hardware or architecture in this file!
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
138c2ecf20Sopenharmony_ci * Fixed AUTOFD polarity in ecp_forward_to_reverse().  Fred Barnes, 1999
148c2ecf20Sopenharmony_ci * Software emulated EPP fixes, Fred Barnes, 04/2001.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/parport.h>
208c2ecf20Sopenharmony_ci#include <linux/delay.h>
218c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
228c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#undef DEBUG /* undef me for production */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#ifdef CONFIG_LP_CONSOLE
278c2ecf20Sopenharmony_ci#undef DEBUG /* Don't want a garbled console */
288c2ecf20Sopenharmony_ci#endif
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/***                                *
318c2ecf20Sopenharmony_ci * One-way data transfer functions. *
328c2ecf20Sopenharmony_ci *                                ***/
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci/* Compatibility mode. */
358c2ecf20Sopenharmony_cisize_t parport_ieee1284_write_compat (struct parport *port,
368c2ecf20Sopenharmony_ci				      const void *buffer, size_t len,
378c2ecf20Sopenharmony_ci				      int flags)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	int no_irq = 1;
408c2ecf20Sopenharmony_ci	ssize_t count = 0;
418c2ecf20Sopenharmony_ci	const unsigned char *addr = buffer;
428c2ecf20Sopenharmony_ci	unsigned char byte;
438c2ecf20Sopenharmony_ci	struct pardevice *dev = port->physport->cad;
448c2ecf20Sopenharmony_ci	unsigned char ctl = (PARPORT_CONTROL_SELECT
458c2ecf20Sopenharmony_ci			     | PARPORT_CONTROL_INIT);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	if (port->irq != PARPORT_IRQ_NONE) {
488c2ecf20Sopenharmony_ci		parport_enable_irq (port);
498c2ecf20Sopenharmony_ci		no_irq = 0;
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
538c2ecf20Sopenharmony_ci	parport_write_control (port, ctl);
548c2ecf20Sopenharmony_ci	parport_data_forward (port);
558c2ecf20Sopenharmony_ci	while (count < len) {
568c2ecf20Sopenharmony_ci		unsigned long expire = jiffies + dev->timeout;
578c2ecf20Sopenharmony_ci		long wait = msecs_to_jiffies(10);
588c2ecf20Sopenharmony_ci		unsigned char mask = (PARPORT_STATUS_ERROR
598c2ecf20Sopenharmony_ci				      | PARPORT_STATUS_BUSY);
608c2ecf20Sopenharmony_ci		unsigned char val = (PARPORT_STATUS_ERROR
618c2ecf20Sopenharmony_ci				     | PARPORT_STATUS_BUSY);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		/* Wait until the peripheral's ready */
648c2ecf20Sopenharmony_ci		do {
658c2ecf20Sopenharmony_ci			/* Is the peripheral ready yet? */
668c2ecf20Sopenharmony_ci			if (!parport_wait_peripheral (port, mask, val))
678c2ecf20Sopenharmony_ci				/* Skip the loop */
688c2ecf20Sopenharmony_ci				goto ready;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci			/* Is the peripheral upset? */
718c2ecf20Sopenharmony_ci			if ((parport_read_status (port) &
728c2ecf20Sopenharmony_ci			     (PARPORT_STATUS_PAPEROUT |
738c2ecf20Sopenharmony_ci			      PARPORT_STATUS_SELECT |
748c2ecf20Sopenharmony_ci			      PARPORT_STATUS_ERROR))
758c2ecf20Sopenharmony_ci			    != (PARPORT_STATUS_SELECT |
768c2ecf20Sopenharmony_ci				PARPORT_STATUS_ERROR))
778c2ecf20Sopenharmony_ci				/* If nFault is asserted (i.e. no
788c2ecf20Sopenharmony_ci				 * error) and PAPEROUT and SELECT are
798c2ecf20Sopenharmony_ci				 * just red herrings, give the driver
808c2ecf20Sopenharmony_ci				 * a chance to check it's happy with
818c2ecf20Sopenharmony_ci				 * that before continuing. */
828c2ecf20Sopenharmony_ci				goto stop;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci			/* Have we run out of time? */
858c2ecf20Sopenharmony_ci			if (!time_before (jiffies, expire))
868c2ecf20Sopenharmony_ci				break;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci			/* Yield the port for a while.  If this is the
898c2ecf20Sopenharmony_ci                           first time around the loop, don't let go of
908c2ecf20Sopenharmony_ci                           the port.  This way, we find out if we have
918c2ecf20Sopenharmony_ci                           our interrupt handler called. */
928c2ecf20Sopenharmony_ci			if (count && no_irq) {
938c2ecf20Sopenharmony_ci				parport_release (dev);
948c2ecf20Sopenharmony_ci				schedule_timeout_interruptible(wait);
958c2ecf20Sopenharmony_ci				parport_claim_or_block (dev);
968c2ecf20Sopenharmony_ci			}
978c2ecf20Sopenharmony_ci			else
988c2ecf20Sopenharmony_ci				/* We must have the device claimed here */
998c2ecf20Sopenharmony_ci				parport_wait_event (port, wait);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci			/* Is there a signal pending? */
1028c2ecf20Sopenharmony_ci			if (signal_pending (current))
1038c2ecf20Sopenharmony_ci				break;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci			/* Wait longer next time. */
1068c2ecf20Sopenharmony_ci			wait *= 2;
1078c2ecf20Sopenharmony_ci		} while (time_before (jiffies, expire));
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci		if (signal_pending (current))
1108c2ecf20Sopenharmony_ci			break;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci		pr_debug("%s: Timed out\n", port->name);
1138c2ecf20Sopenharmony_ci		break;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	ready:
1168c2ecf20Sopenharmony_ci		/* Write the character to the data lines. */
1178c2ecf20Sopenharmony_ci		byte = *addr++;
1188c2ecf20Sopenharmony_ci		parport_write_data (port, byte);
1198c2ecf20Sopenharmony_ci		udelay (1);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci		/* Pulse strobe. */
1228c2ecf20Sopenharmony_ci		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
1238c2ecf20Sopenharmony_ci		udelay (1); /* strobe */
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci		parport_write_control (port, ctl);
1268c2ecf20Sopenharmony_ci		udelay (1); /* hold */
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci		/* Assume the peripheral received it. */
1298c2ecf20Sopenharmony_ci		count++;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci                /* Let another process run if it needs to. */
1328c2ecf20Sopenharmony_ci		if (time_before (jiffies, expire))
1338c2ecf20Sopenharmony_ci			if (!parport_yield_blocking (dev)
1348c2ecf20Sopenharmony_ci			    && need_resched())
1358c2ecf20Sopenharmony_ci				schedule ();
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci stop:
1388c2ecf20Sopenharmony_ci	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return count;
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci/* Nibble mode. */
1448c2ecf20Sopenharmony_cisize_t parport_ieee1284_read_nibble (struct parport *port,
1458c2ecf20Sopenharmony_ci				     void *buffer, size_t len,
1468c2ecf20Sopenharmony_ci				     int flags)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
1498c2ecf20Sopenharmony_ci	return 0;
1508c2ecf20Sopenharmony_ci#else
1518c2ecf20Sopenharmony_ci	unsigned char *buf = buffer;
1528c2ecf20Sopenharmony_ci	int i;
1538c2ecf20Sopenharmony_ci	unsigned char byte = 0;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	len *= 2; /* in nibbles */
1568c2ecf20Sopenharmony_ci	for (i=0; i < len; i++) {
1578c2ecf20Sopenharmony_ci		unsigned char nibble;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci		/* Does the error line indicate end of data? */
1608c2ecf20Sopenharmony_ci		if (((i & 1) == 0) &&
1618c2ecf20Sopenharmony_ci		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
1628c2ecf20Sopenharmony_ci			goto end_of_data;
1638c2ecf20Sopenharmony_ci		}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		/* Event 7: Set nAutoFd low. */
1668c2ecf20Sopenharmony_ci		parport_frob_control (port,
1678c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
1688c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci		/* Event 9: nAck goes low. */
1718c2ecf20Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_REV_DATA;
1728c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port,
1738c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK, 0)) {
1748c2ecf20Sopenharmony_ci			/* Timeout -- no more data? */
1758c2ecf20Sopenharmony_ci			pr_debug("%s: Nibble timeout at event 9 (%d bytes)\n",
1768c2ecf20Sopenharmony_ci				 port->name, i / 2);
1778c2ecf20Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
1788c2ecf20Sopenharmony_ci			break;
1798c2ecf20Sopenharmony_ci		}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		/* Read a nibble. */
1838c2ecf20Sopenharmony_ci		nibble = parport_read_status (port) >> 3;
1848c2ecf20Sopenharmony_ci		nibble &= ~8;
1858c2ecf20Sopenharmony_ci		if ((nibble & 0x10) == 0)
1868c2ecf20Sopenharmony_ci			nibble |= 8;
1878c2ecf20Sopenharmony_ci		nibble &= 0xf;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		/* Event 10: Set nAutoFd high. */
1908c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		/* Event 11: nAck goes high. */
1938c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port,
1948c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK,
1958c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
1968c2ecf20Sopenharmony_ci			/* Timeout -- no more data? */
1978c2ecf20Sopenharmony_ci			pr_debug("%s: Nibble timeout at event 11\n",
1988c2ecf20Sopenharmony_ci				 port->name);
1998c2ecf20Sopenharmony_ci			break;
2008c2ecf20Sopenharmony_ci		}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci		if (i & 1) {
2038c2ecf20Sopenharmony_ci			/* Second nibble */
2048c2ecf20Sopenharmony_ci			byte |= nibble << 4;
2058c2ecf20Sopenharmony_ci			*buf++ = byte;
2068c2ecf20Sopenharmony_ci		} else
2078c2ecf20Sopenharmony_ci			byte = nibble;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	if (i == len) {
2118c2ecf20Sopenharmony_ci		/* Read the last nibble without checking data avail. */
2128c2ecf20Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
2138c2ecf20Sopenharmony_ci		end_of_data:
2148c2ecf20Sopenharmony_ci			pr_debug("%s: No more nibble data (%d bytes)\n",
2158c2ecf20Sopenharmony_ci				 port->name, i / 2);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci			/* Go to reverse idle phase. */
2188c2ecf20Sopenharmony_ci			parport_frob_control (port,
2198c2ecf20Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD,
2208c2ecf20Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD);
2218c2ecf20Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci		else
2248c2ecf20Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return i/2;
2288c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci/* Byte mode. */
2328c2ecf20Sopenharmony_cisize_t parport_ieee1284_read_byte (struct parport *port,
2338c2ecf20Sopenharmony_ci				   void *buffer, size_t len,
2348c2ecf20Sopenharmony_ci				   int flags)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
2378c2ecf20Sopenharmony_ci	return 0;
2388c2ecf20Sopenharmony_ci#else
2398c2ecf20Sopenharmony_ci	unsigned char *buf = buffer;
2408c2ecf20Sopenharmony_ci	ssize_t count = 0;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	for (count = 0; count < len; count++) {
2438c2ecf20Sopenharmony_ci		unsigned char byte;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci		/* Data available? */
2468c2ecf20Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
2478c2ecf20Sopenharmony_ci			goto end_of_data;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		/* Event 14: Place data bus in high impedance state. */
2518c2ecf20Sopenharmony_ci		parport_data_reverse (port);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci		/* Event 7: Set nAutoFd low. */
2548c2ecf20Sopenharmony_ci		parport_frob_control (port,
2558c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
2568c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		/* Event 9: nAck goes low. */
2598c2ecf20Sopenharmony_ci		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
2608c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port,
2618c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK,
2628c2ecf20Sopenharmony_ci					     0)) {
2638c2ecf20Sopenharmony_ci			/* Timeout -- no more data? */
2648c2ecf20Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
2658c2ecf20Sopenharmony_ci						 0);
2668c2ecf20Sopenharmony_ci			pr_debug("%s: Byte timeout at event 9\n", port->name);
2678c2ecf20Sopenharmony_ci			break;
2688c2ecf20Sopenharmony_ci		}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci		byte = parport_read_data (port);
2718c2ecf20Sopenharmony_ci		*buf++ = byte;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci		/* Event 10: Set nAutoFd high */
2748c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		/* Event 11: nAck goes high. */
2778c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port,
2788c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK,
2798c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
2808c2ecf20Sopenharmony_ci			/* Timeout -- no more data? */
2818c2ecf20Sopenharmony_ci			pr_debug("%s: Byte timeout at event 11\n", port->name);
2828c2ecf20Sopenharmony_ci			break;
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci		/* Event 16: Set nStrobe low. */
2868c2ecf20Sopenharmony_ci		parport_frob_control (port,
2878c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_STROBE,
2888c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
2898c2ecf20Sopenharmony_ci		udelay (5);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci		/* Event 17: Set nStrobe high. */
2928c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (count == len) {
2968c2ecf20Sopenharmony_ci		/* Read the last byte without checking data avail. */
2978c2ecf20Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
2988c2ecf20Sopenharmony_ci		end_of_data:
2998c2ecf20Sopenharmony_ci			pr_debug("%s: No more byte data (%zd bytes)\n",
3008c2ecf20Sopenharmony_ci				 port->name, count);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci			/* Go to reverse idle phase. */
3038c2ecf20Sopenharmony_ci			parport_frob_control (port,
3048c2ecf20Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD,
3058c2ecf20Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD);
3068c2ecf20Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
3078c2ecf20Sopenharmony_ci		}
3088c2ecf20Sopenharmony_ci		else
3098c2ecf20Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return count;
3138c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/***              *
3178c2ecf20Sopenharmony_ci * ECP Functions. *
3188c2ecf20Sopenharmony_ci *              ***/
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic inline
3238c2ecf20Sopenharmony_ciint ecp_forward_to_reverse (struct parport *port)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	int retval;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Event 38: Set nAutoFd low */
3288c2ecf20Sopenharmony_ci	parport_frob_control (port,
3298c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD,
3308c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD);
3318c2ecf20Sopenharmony_ci	parport_data_reverse (port);
3328c2ecf20Sopenharmony_ci	udelay (5);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* Event 39: Set nInit low to initiate bus reversal */
3358c2ecf20Sopenharmony_ci	parport_frob_control (port,
3368c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT,
3378c2ecf20Sopenharmony_ci			      0);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* Event 40: PError goes low */
3408c2ecf20Sopenharmony_ci	retval = parport_wait_peripheral (port,
3418c2ecf20Sopenharmony_ci					  PARPORT_STATUS_PAPEROUT, 0);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!retval) {
3448c2ecf20Sopenharmony_ci		pr_debug("%s: ECP direction: reverse\n", port->name);
3458c2ecf20Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
3468c2ecf20Sopenharmony_ci	} else {
3478c2ecf20Sopenharmony_ci		pr_debug("%s: ECP direction: failed to reverse\n", port->name);
3488c2ecf20Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	return retval;
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_cistatic inline
3558c2ecf20Sopenharmony_ciint ecp_reverse_to_forward (struct parport *port)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	int retval;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* Event 47: Set nInit high */
3608c2ecf20Sopenharmony_ci	parport_frob_control (port,
3618c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT
3628c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD,
3638c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT
3648c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	/* Event 49: PError goes high */
3678c2ecf20Sopenharmony_ci	retval = parport_wait_peripheral (port,
3688c2ecf20Sopenharmony_ci					  PARPORT_STATUS_PAPEROUT,
3698c2ecf20Sopenharmony_ci					  PARPORT_STATUS_PAPEROUT);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (!retval) {
3728c2ecf20Sopenharmony_ci		parport_data_forward (port);
3738c2ecf20Sopenharmony_ci		pr_debug("%s: ECP direction: forward\n", port->name);
3748c2ecf20Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
3758c2ecf20Sopenharmony_ci	} else {
3768c2ecf20Sopenharmony_ci		pr_debug("%s: ECP direction: failed to switch forward\n",
3778c2ecf20Sopenharmony_ci			 port->name);
3788c2ecf20Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return retval;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci/* ECP mode, forward channel, data. */
3888c2ecf20Sopenharmony_cisize_t parport_ieee1284_ecp_write_data (struct parport *port,
3898c2ecf20Sopenharmony_ci					const void *buffer, size_t len,
3908c2ecf20Sopenharmony_ci					int flags)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci#else
3958c2ecf20Sopenharmony_ci	const unsigned char *buf = buffer;
3968c2ecf20Sopenharmony_ci	size_t written;
3978c2ecf20Sopenharmony_ci	int retry;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	port = port->physport;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
4028c2ecf20Sopenharmony_ci		if (ecp_reverse_to_forward (port))
4038c2ecf20Sopenharmony_ci			return 0;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* HostAck high (data, not command) */
4088c2ecf20Sopenharmony_ci	parport_frob_control (port,
4098c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD
4108c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_STROBE
4118c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_INIT,
4128c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT);
4138c2ecf20Sopenharmony_ci	for (written = 0; written < len; written++, buf++) {
4148c2ecf20Sopenharmony_ci		unsigned long expire = jiffies + port->cad->timeout;
4158c2ecf20Sopenharmony_ci		unsigned char byte;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		byte = *buf;
4188c2ecf20Sopenharmony_ci	try_again:
4198c2ecf20Sopenharmony_ci		parport_write_data (port, byte);
4208c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE,
4218c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
4228c2ecf20Sopenharmony_ci		udelay (5);
4238c2ecf20Sopenharmony_ci		for (retry = 0; retry < 100; retry++) {
4248c2ecf20Sopenharmony_ci			if (!parport_wait_peripheral (port,
4258c2ecf20Sopenharmony_ci						      PARPORT_STATUS_BUSY, 0))
4268c2ecf20Sopenharmony_ci				goto success;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci			if (signal_pending (current)) {
4298c2ecf20Sopenharmony_ci				parport_frob_control (port,
4308c2ecf20Sopenharmony_ci						      PARPORT_CONTROL_STROBE,
4318c2ecf20Sopenharmony_ci						      0);
4328c2ecf20Sopenharmony_ci				break;
4338c2ecf20Sopenharmony_ci			}
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
4378c2ecf20Sopenharmony_ci		pr_debug("%s: ECP transfer stalled!\n", port->name);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT,
4408c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_INIT);
4418c2ecf20Sopenharmony_ci		udelay (50);
4428c2ecf20Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
4438c2ecf20Sopenharmony_ci			/* It's buggered. */
4448c2ecf20Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
4458c2ecf20Sopenharmony_ci			break;
4468c2ecf20Sopenharmony_ci		}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
4498c2ecf20Sopenharmony_ci		udelay (50);
4508c2ecf20Sopenharmony_ci		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
4518c2ecf20Sopenharmony_ci			break;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci		pr_debug("%s: Host transfer recovered\n", port->name);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		if (time_after_eq (jiffies, expire)) break;
4568c2ecf20Sopenharmony_ci		goto try_again;
4578c2ecf20Sopenharmony_ci	success:
4588c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
4598c2ecf20Sopenharmony_ci		udelay (5);
4608c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port,
4618c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY,
4628c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY))
4638c2ecf20Sopenharmony_ci			/* Peripheral hasn't accepted the data. */
4648c2ecf20Sopenharmony_ci			break;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return written;
4708c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci/* ECP mode, reverse channel, data. */
4748c2ecf20Sopenharmony_cisize_t parport_ieee1284_ecp_read_data (struct parport *port,
4758c2ecf20Sopenharmony_ci				       void *buffer, size_t len, int flags)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci#else
4808c2ecf20Sopenharmony_ci	struct pardevice *dev = port->cad;
4818c2ecf20Sopenharmony_ci	unsigned char *buf = buffer;
4828c2ecf20Sopenharmony_ci	int rle_count = 0; /* shut gcc up */
4838c2ecf20Sopenharmony_ci	unsigned char ctl;
4848c2ecf20Sopenharmony_ci	int rle = 0;
4858c2ecf20Sopenharmony_ci	ssize_t count = 0;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	port = port->physport;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
4908c2ecf20Sopenharmony_ci		if (ecp_forward_to_reverse (port))
4918c2ecf20Sopenharmony_ci			return 0;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/* Set HostAck low to start accepting data. */
4968c2ecf20Sopenharmony_ci	ctl = parport_read_control (port);
4978c2ecf20Sopenharmony_ci	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT |
4988c2ecf20Sopenharmony_ci		 PARPORT_CONTROL_AUTOFD);
4998c2ecf20Sopenharmony_ci	parport_write_control (port,
5008c2ecf20Sopenharmony_ci			       ctl | PARPORT_CONTROL_AUTOFD);
5018c2ecf20Sopenharmony_ci	while (count < len) {
5028c2ecf20Sopenharmony_ci		unsigned long expire = jiffies + dev->timeout;
5038c2ecf20Sopenharmony_ci		unsigned char byte;
5048c2ecf20Sopenharmony_ci		int command;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci		/* Event 43: Peripheral sets nAck low. It can take as
5078c2ecf20Sopenharmony_ci                   long as it wants. */
5088c2ecf20Sopenharmony_ci		while (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
5098c2ecf20Sopenharmony_ci			/* The peripheral hasn't given us data in
5108c2ecf20Sopenharmony_ci			   35ms.  If we have data to give back to the
5118c2ecf20Sopenharmony_ci			   caller, do it now. */
5128c2ecf20Sopenharmony_ci			if (count)
5138c2ecf20Sopenharmony_ci				goto out;
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci			/* If we've used up all the time we were allowed,
5168c2ecf20Sopenharmony_ci			   give up altogether. */
5178c2ecf20Sopenharmony_ci			if (!time_before (jiffies, expire))
5188c2ecf20Sopenharmony_ci				goto out;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci			/* Yield the port for a while. */
5218c2ecf20Sopenharmony_ci			if (dev->port->irq != PARPORT_IRQ_NONE) {
5228c2ecf20Sopenharmony_ci				parport_release (dev);
5238c2ecf20Sopenharmony_ci				schedule_timeout_interruptible(msecs_to_jiffies(40));
5248c2ecf20Sopenharmony_ci				parport_claim_or_block (dev);
5258c2ecf20Sopenharmony_ci			}
5268c2ecf20Sopenharmony_ci			else
5278c2ecf20Sopenharmony_ci				/* We must have the device claimed here. */
5288c2ecf20Sopenharmony_ci				parport_wait_event (port, msecs_to_jiffies(40));
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci			/* Is there a signal pending? */
5318c2ecf20Sopenharmony_ci			if (signal_pending (current))
5328c2ecf20Sopenharmony_ci				goto out;
5338c2ecf20Sopenharmony_ci		}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci		/* Is this a command? */
5368c2ecf20Sopenharmony_ci		if (rle)
5378c2ecf20Sopenharmony_ci			/* The last byte was a run-length count, so
5388c2ecf20Sopenharmony_ci                           this can't be as well. */
5398c2ecf20Sopenharmony_ci			command = 0;
5408c2ecf20Sopenharmony_ci		else
5418c2ecf20Sopenharmony_ci			command = (parport_read_status (port) &
5428c2ecf20Sopenharmony_ci				   PARPORT_STATUS_BUSY) ? 1 : 0;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci		/* Read the data. */
5458c2ecf20Sopenharmony_ci		byte = parport_read_data (port);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		/* If this is a channel command, rather than an RLE
5488c2ecf20Sopenharmony_ci                   command or a normal data byte, don't accept it. */
5498c2ecf20Sopenharmony_ci		if (command) {
5508c2ecf20Sopenharmony_ci			if (byte & 0x80) {
5518c2ecf20Sopenharmony_ci				pr_debug("%s: stopping short at channel command (%02x)\n",
5528c2ecf20Sopenharmony_ci					 port->name, byte);
5538c2ecf20Sopenharmony_ci				goto out;
5548c2ecf20Sopenharmony_ci			}
5558c2ecf20Sopenharmony_ci			else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
5568c2ecf20Sopenharmony_ci				pr_debug("%s: device illegally using RLE; accepting anyway\n",
5578c2ecf20Sopenharmony_ci					 port->name);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci			rle_count = byte + 1;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci			/* Are we allowed to read that many bytes? */
5628c2ecf20Sopenharmony_ci			if (rle_count > (len - count)) {
5638c2ecf20Sopenharmony_ci				pr_debug("%s: leaving %d RLE bytes for next time\n",
5648c2ecf20Sopenharmony_ci					 port->name, rle_count);
5658c2ecf20Sopenharmony_ci				break;
5668c2ecf20Sopenharmony_ci			}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci			rle = 1;
5698c2ecf20Sopenharmony_ci		}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		/* Event 44: Set HostAck high, acknowledging handshake. */
5728c2ecf20Sopenharmony_ci		parport_write_control (port, ctl);
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci		/* Event 45: The peripheral has 35ms to set nAck high. */
5758c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK,
5768c2ecf20Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
5778c2ecf20Sopenharmony_ci			/* It's gone wrong.  Return what data we have
5788c2ecf20Sopenharmony_ci                           to the caller. */
5798c2ecf20Sopenharmony_ci			pr_debug("ECP read timed out at 45\n");
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci			if (command)
5828c2ecf20Sopenharmony_ci				pr_warn("%s: command ignored (%02x)\n",
5838c2ecf20Sopenharmony_ci					port->name, byte);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci			break;
5868c2ecf20Sopenharmony_ci		}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci		/* Event 46: Set HostAck low and accept the data. */
5898c2ecf20Sopenharmony_ci		parport_write_control (port,
5908c2ecf20Sopenharmony_ci				       ctl | PARPORT_CONTROL_AUTOFD);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci		/* If we just read a run-length count, fetch the data. */
5938c2ecf20Sopenharmony_ci		if (command)
5948c2ecf20Sopenharmony_ci			continue;
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci		/* If this is the byte after a run-length count, decompress. */
5978c2ecf20Sopenharmony_ci		if (rle) {
5988c2ecf20Sopenharmony_ci			rle = 0;
5998c2ecf20Sopenharmony_ci			memset (buf, byte, rle_count);
6008c2ecf20Sopenharmony_ci			buf += rle_count;
6018c2ecf20Sopenharmony_ci			count += rle_count;
6028c2ecf20Sopenharmony_ci			pr_debug("%s: decompressed to %d bytes\n",
6038c2ecf20Sopenharmony_ci				 port->name, rle_count);
6048c2ecf20Sopenharmony_ci		} else {
6058c2ecf20Sopenharmony_ci			/* Normal data byte. */
6068c2ecf20Sopenharmony_ci			*buf = byte;
6078c2ecf20Sopenharmony_ci			buf++, count++;
6088c2ecf20Sopenharmony_ci		}
6098c2ecf20Sopenharmony_ci	}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci out:
6128c2ecf20Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
6138c2ecf20Sopenharmony_ci	return count;
6148c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci/* ECP mode, forward channel, commands. */
6188c2ecf20Sopenharmony_cisize_t parport_ieee1284_ecp_write_addr (struct parport *port,
6198c2ecf20Sopenharmony_ci					const void *buffer, size_t len,
6208c2ecf20Sopenharmony_ci					int flags)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
6238c2ecf20Sopenharmony_ci	return 0;
6248c2ecf20Sopenharmony_ci#else
6258c2ecf20Sopenharmony_ci	const unsigned char *buf = buffer;
6268c2ecf20Sopenharmony_ci	size_t written;
6278c2ecf20Sopenharmony_ci	int retry;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	port = port->physport;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
6328c2ecf20Sopenharmony_ci		if (ecp_reverse_to_forward (port))
6338c2ecf20Sopenharmony_ci			return 0;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* HostAck low (command, not data) */
6388c2ecf20Sopenharmony_ci	parport_frob_control (port,
6398c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD
6408c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_STROBE
6418c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_INIT,
6428c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD
6438c2ecf20Sopenharmony_ci			      | PARPORT_CONTROL_INIT);
6448c2ecf20Sopenharmony_ci	for (written = 0; written < len; written++, buf++) {
6458c2ecf20Sopenharmony_ci		unsigned long expire = jiffies + port->cad->timeout;
6468c2ecf20Sopenharmony_ci		unsigned char byte;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci		byte = *buf;
6498c2ecf20Sopenharmony_ci	try_again:
6508c2ecf20Sopenharmony_ci		parport_write_data (port, byte);
6518c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE,
6528c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
6538c2ecf20Sopenharmony_ci		udelay (5);
6548c2ecf20Sopenharmony_ci		for (retry = 0; retry < 100; retry++) {
6558c2ecf20Sopenharmony_ci			if (!parport_wait_peripheral (port,
6568c2ecf20Sopenharmony_ci						      PARPORT_STATUS_BUSY, 0))
6578c2ecf20Sopenharmony_ci				goto success;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci			if (signal_pending (current)) {
6608c2ecf20Sopenharmony_ci				parport_frob_control (port,
6618c2ecf20Sopenharmony_ci						      PARPORT_CONTROL_STROBE,
6628c2ecf20Sopenharmony_ci						      0);
6638c2ecf20Sopenharmony_ci				break;
6648c2ecf20Sopenharmony_ci			}
6658c2ecf20Sopenharmony_ci		}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
6688c2ecf20Sopenharmony_ci		pr_debug("%s: ECP transfer stalled!\n", port->name);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT,
6718c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_INIT);
6728c2ecf20Sopenharmony_ci		udelay (50);
6738c2ecf20Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
6748c2ecf20Sopenharmony_ci			/* It's buggered. */
6758c2ecf20Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
6768c2ecf20Sopenharmony_ci			break;
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
6808c2ecf20Sopenharmony_ci		udelay (50);
6818c2ecf20Sopenharmony_ci		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
6828c2ecf20Sopenharmony_ci			break;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		pr_debug("%s: Host transfer recovered\n", port->name);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci		if (time_after_eq (jiffies, expire)) break;
6878c2ecf20Sopenharmony_ci		goto try_again;
6888c2ecf20Sopenharmony_ci	success:
6898c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
6908c2ecf20Sopenharmony_ci		udelay (5);
6918c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port,
6928c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY,
6938c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY))
6948c2ecf20Sopenharmony_ci			/* Peripheral hasn't accepted the data. */
6958c2ecf20Sopenharmony_ci			break;
6968c2ecf20Sopenharmony_ci	}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	return written;
7018c2ecf20Sopenharmony_ci#endif /* IEEE1284 support */
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/***              *
7058c2ecf20Sopenharmony_ci * EPP functions. *
7068c2ecf20Sopenharmony_ci *              ***/
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci/* EPP mode, forward channel, data. */
7098c2ecf20Sopenharmony_cisize_t parport_ieee1284_epp_write_data (struct parport *port,
7108c2ecf20Sopenharmony_ci					const void *buffer, size_t len,
7118c2ecf20Sopenharmony_ci					int flags)
7128c2ecf20Sopenharmony_ci{
7138c2ecf20Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
7148c2ecf20Sopenharmony_ci	size_t ret = 0;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	/* set EPP idle state (just to make sure) with strobe low */
7178c2ecf20Sopenharmony_ci	parport_frob_control (port,
7188c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
7198c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
7208c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
7218c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT,
7228c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
7238c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT);
7248c2ecf20Sopenharmony_ci	port->ops->data_forward (port);
7258c2ecf20Sopenharmony_ci	for (; len > 0; len--, bp++) {
7268c2ecf20Sopenharmony_ci		/* Event 62: Write data and set autofd low */
7278c2ecf20Sopenharmony_ci		parport_write_data (port, *bp);
7288c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
7298c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		/* Event 58: wait for busy (nWait) to go high */
7328c2ecf20Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
7338c2ecf20Sopenharmony_ci			break;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci		/* Event 63: set nAutoFd (nDStrb) high */
7368c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		/* Event 60: wait for busy (nWait) to go low */
7398c2ecf20Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
7408c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5))
7418c2ecf20Sopenharmony_ci			break;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci		ret++;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/* Event 61: set strobe (nWrite) high */
7478c2ecf20Sopenharmony_ci	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return ret;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci/* EPP mode, reverse channel, data. */
7538c2ecf20Sopenharmony_cisize_t parport_ieee1284_epp_read_data (struct parport *port,
7548c2ecf20Sopenharmony_ci				       void *buffer, size_t len,
7558c2ecf20Sopenharmony_ci				       int flags)
7568c2ecf20Sopenharmony_ci{
7578c2ecf20Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
7588c2ecf20Sopenharmony_ci	unsigned ret = 0;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	/* set EPP idle state (just to make sure) with strobe high */
7618c2ecf20Sopenharmony_ci	parport_frob_control (port,
7628c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
7638c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
7648c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
7658c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT,
7668c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT);
7678c2ecf20Sopenharmony_ci	port->ops->data_reverse (port);
7688c2ecf20Sopenharmony_ci	for (; len > 0; len--, bp++) {
7698c2ecf20Sopenharmony_ci		/* Event 67: set nAutoFd (nDStrb) low */
7708c2ecf20Sopenharmony_ci		parport_frob_control (port,
7718c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
7728c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
7738c2ecf20Sopenharmony_ci		/* Event 58: wait for Busy to go high */
7748c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
7758c2ecf20Sopenharmony_ci			break;
7768c2ecf20Sopenharmony_ci		}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci		*bp = parport_read_data (port);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci		/* Event 63: set nAutoFd (nDStrb) high */
7818c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci		/* Event 60: wait for Busy to go low */
7848c2ecf20Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
7858c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5)) {
7868c2ecf20Sopenharmony_ci			break;
7878c2ecf20Sopenharmony_ci		}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci		ret++;
7908c2ecf20Sopenharmony_ci	}
7918c2ecf20Sopenharmony_ci	port->ops->data_forward (port);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return ret;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci/* EPP mode, forward channel, addresses. */
7978c2ecf20Sopenharmony_cisize_t parport_ieee1284_epp_write_addr (struct parport *port,
7988c2ecf20Sopenharmony_ci					const void *buffer, size_t len,
7998c2ecf20Sopenharmony_ci					int flags)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
8028c2ecf20Sopenharmony_ci	size_t ret = 0;
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	/* set EPP idle state (just to make sure) with strobe low */
8058c2ecf20Sopenharmony_ci	parport_frob_control (port,
8068c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
8078c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
8088c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
8098c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT,
8108c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
8118c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT);
8128c2ecf20Sopenharmony_ci	port->ops->data_forward (port);
8138c2ecf20Sopenharmony_ci	for (; len > 0; len--, bp++) {
8148c2ecf20Sopenharmony_ci		/* Event 56: Write data and set nAStrb low. */
8158c2ecf20Sopenharmony_ci		parport_write_data (port, *bp);
8168c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT,
8178c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_SELECT);
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci		/* Event 58: wait for busy (nWait) to go high */
8208c2ecf20Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
8218c2ecf20Sopenharmony_ci			break;
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci		/* Event 59: set nAStrb high */
8248c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci		/* Event 60: wait for busy (nWait) to go low */
8278c2ecf20Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
8288c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5))
8298c2ecf20Sopenharmony_ci			break;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci		ret++;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	/* Event 61: set strobe (nWrite) high */
8358c2ecf20Sopenharmony_ci	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	return ret;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci/* EPP mode, reverse channel, addresses. */
8418c2ecf20Sopenharmony_cisize_t parport_ieee1284_epp_read_addr (struct parport *port,
8428c2ecf20Sopenharmony_ci				       void *buffer, size_t len,
8438c2ecf20Sopenharmony_ci				       int flags)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
8468c2ecf20Sopenharmony_ci	unsigned ret = 0;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* Set EPP idle state (just to make sure) with strobe high */
8498c2ecf20Sopenharmony_ci	parport_frob_control (port,
8508c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
8518c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
8528c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
8538c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT,
8548c2ecf20Sopenharmony_ci			      PARPORT_CONTROL_INIT);
8558c2ecf20Sopenharmony_ci	port->ops->data_reverse (port);
8568c2ecf20Sopenharmony_ci	for (; len > 0; len--, bp++) {
8578c2ecf20Sopenharmony_ci		/* Event 64: set nSelectIn (nAStrb) low */
8588c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT,
8598c2ecf20Sopenharmony_ci				      PARPORT_CONTROL_SELECT);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		/* Event 58: wait for Busy to go high */
8628c2ecf20Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
8638c2ecf20Sopenharmony_ci			break;
8648c2ecf20Sopenharmony_ci		}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		*bp = parport_read_data (port);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci		/* Event 59: set nSelectIn (nAStrb) high */
8698c2ecf20Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT,
8708c2ecf20Sopenharmony_ci				      0);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		/* Event 60: wait for Busy to go low */
8738c2ecf20Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
8748c2ecf20Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5))
8758c2ecf20Sopenharmony_ci			break;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci		ret++;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci	port->ops->data_forward (port);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return ret;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
8858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
8868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
8878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_write_compat);
8888c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_read_nibble);
8898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_read_byte);
8908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_write_data);
8918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_read_data);
8928c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
8938c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
894