162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* IEEE-1284 operations for parport.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is for generic IEEE 1284 operations.  The idea is that
562306a36Sopenharmony_ci * they are used by the low-level drivers.  If they have a special way
662306a36Sopenharmony_ci * of doing something, they can provide their own routines (and put
762306a36Sopenharmony_ci * the function pointers in port->ops); if not, they can just use these
862306a36Sopenharmony_ci * as a fallback.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Note: Make no assumptions about hardware or architecture in this file!
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
1362306a36Sopenharmony_ci * Fixed AUTOFD polarity in ecp_forward_to_reverse().  Fred Barnes, 1999
1462306a36Sopenharmony_ci * Software emulated EPP fixes, Fred Barnes, 04/2001.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/module.h>
1962306a36Sopenharmony_ci#include <linux/parport.h>
2062306a36Sopenharmony_ci#include <linux/delay.h>
2162306a36Sopenharmony_ci#include <linux/sched/signal.h>
2262306a36Sopenharmony_ci#include <linux/uaccess.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#undef DEBUG /* undef me for production */
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#ifdef CONFIG_LP_CONSOLE
2762306a36Sopenharmony_ci#undef DEBUG /* Don't want a garbled console */
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/***                                *
3162306a36Sopenharmony_ci * One-way data transfer functions. *
3262306a36Sopenharmony_ci *                                ***/
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Compatibility mode. */
3562306a36Sopenharmony_cisize_t parport_ieee1284_write_compat (struct parport *port,
3662306a36Sopenharmony_ci				      const void *buffer, size_t len,
3762306a36Sopenharmony_ci				      int flags)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	int no_irq = 1;
4062306a36Sopenharmony_ci	ssize_t count = 0;
4162306a36Sopenharmony_ci	const unsigned char *addr = buffer;
4262306a36Sopenharmony_ci	unsigned char byte;
4362306a36Sopenharmony_ci	struct pardevice *dev = port->physport->cad;
4462306a36Sopenharmony_ci	unsigned char ctl = (PARPORT_CONTROL_SELECT
4562306a36Sopenharmony_ci			     | PARPORT_CONTROL_INIT);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (port->irq != PARPORT_IRQ_NONE) {
4862306a36Sopenharmony_ci		parport_enable_irq (port);
4962306a36Sopenharmony_ci		no_irq = 0;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
5362306a36Sopenharmony_ci	parport_write_control (port, ctl);
5462306a36Sopenharmony_ci	parport_data_forward (port);
5562306a36Sopenharmony_ci	while (count < len) {
5662306a36Sopenharmony_ci		unsigned long expire = jiffies + dev->timeout;
5762306a36Sopenharmony_ci		long wait = msecs_to_jiffies(10);
5862306a36Sopenharmony_ci		unsigned char mask = (PARPORT_STATUS_ERROR
5962306a36Sopenharmony_ci				      | PARPORT_STATUS_BUSY);
6062306a36Sopenharmony_ci		unsigned char val = (PARPORT_STATUS_ERROR
6162306a36Sopenharmony_ci				     | PARPORT_STATUS_BUSY);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci		/* Wait until the peripheral's ready */
6462306a36Sopenharmony_ci		do {
6562306a36Sopenharmony_ci			/* Is the peripheral ready yet? */
6662306a36Sopenharmony_ci			if (!parport_wait_peripheral (port, mask, val))
6762306a36Sopenharmony_ci				/* Skip the loop */
6862306a36Sopenharmony_ci				goto ready;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci			/* Is the peripheral upset? */
7162306a36Sopenharmony_ci			if ((parport_read_status (port) &
7262306a36Sopenharmony_ci			     (PARPORT_STATUS_PAPEROUT |
7362306a36Sopenharmony_ci			      PARPORT_STATUS_SELECT |
7462306a36Sopenharmony_ci			      PARPORT_STATUS_ERROR))
7562306a36Sopenharmony_ci			    != (PARPORT_STATUS_SELECT |
7662306a36Sopenharmony_ci				PARPORT_STATUS_ERROR))
7762306a36Sopenharmony_ci				/* If nFault is asserted (i.e. no
7862306a36Sopenharmony_ci				 * error) and PAPEROUT and SELECT are
7962306a36Sopenharmony_ci				 * just red herrings, give the driver
8062306a36Sopenharmony_ci				 * a chance to check it's happy with
8162306a36Sopenharmony_ci				 * that before continuing. */
8262306a36Sopenharmony_ci				goto stop;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci			/* Have we run out of time? */
8562306a36Sopenharmony_ci			if (!time_before (jiffies, expire))
8662306a36Sopenharmony_ci				break;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci			/* Yield the port for a while.  If this is the
8962306a36Sopenharmony_ci                           first time around the loop, don't let go of
9062306a36Sopenharmony_ci                           the port.  This way, we find out if we have
9162306a36Sopenharmony_ci                           our interrupt handler called. */
9262306a36Sopenharmony_ci			if (count && no_irq) {
9362306a36Sopenharmony_ci				parport_release (dev);
9462306a36Sopenharmony_ci				schedule_timeout_interruptible(wait);
9562306a36Sopenharmony_ci				parport_claim_or_block (dev);
9662306a36Sopenharmony_ci			}
9762306a36Sopenharmony_ci			else
9862306a36Sopenharmony_ci				/* We must have the device claimed here */
9962306a36Sopenharmony_ci				parport_wait_event (port, wait);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci			/* Is there a signal pending? */
10262306a36Sopenharmony_ci			if (signal_pending (current))
10362306a36Sopenharmony_ci				break;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci			/* Wait longer next time. */
10662306a36Sopenharmony_ci			wait *= 2;
10762306a36Sopenharmony_ci		} while (time_before (jiffies, expire));
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		if (signal_pending (current))
11062306a36Sopenharmony_ci			break;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		pr_debug("%s: Timed out\n", port->name);
11362306a36Sopenharmony_ci		break;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	ready:
11662306a36Sopenharmony_ci		/* Write the character to the data lines. */
11762306a36Sopenharmony_ci		byte = *addr++;
11862306a36Sopenharmony_ci		parport_write_data (port, byte);
11962306a36Sopenharmony_ci		udelay (1);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci		/* Pulse strobe. */
12262306a36Sopenharmony_ci		parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
12362306a36Sopenharmony_ci		udelay (1); /* strobe */
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		parport_write_control (port, ctl);
12662306a36Sopenharmony_ci		udelay (1); /* hold */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		/* Assume the peripheral received it. */
12962306a36Sopenharmony_ci		count++;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci                /* Let another process run if it needs to. */
13262306a36Sopenharmony_ci		if (time_before (jiffies, expire))
13362306a36Sopenharmony_ci			if (!parport_yield_blocking (dev)
13462306a36Sopenharmony_ci			    && need_resched())
13562306a36Sopenharmony_ci				schedule ();
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci stop:
13862306a36Sopenharmony_ci	port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return count;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci/* Nibble mode. */
14462306a36Sopenharmony_cisize_t parport_ieee1284_read_nibble (struct parport *port,
14562306a36Sopenharmony_ci				     void *buffer, size_t len,
14662306a36Sopenharmony_ci				     int flags)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci#else
15162306a36Sopenharmony_ci	unsigned char *buf = buffer;
15262306a36Sopenharmony_ci	int i;
15362306a36Sopenharmony_ci	unsigned char byte = 0;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	len *= 2; /* in nibbles */
15662306a36Sopenharmony_ci	for (i=0; i < len; i++) {
15762306a36Sopenharmony_ci		unsigned char nibble;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		/* Does the error line indicate end of data? */
16062306a36Sopenharmony_ci		if (((i & 1) == 0) &&
16162306a36Sopenharmony_ci		    (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
16262306a36Sopenharmony_ci			goto end_of_data;
16362306a36Sopenharmony_ci		}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		/* Event 7: Set nAutoFd low. */
16662306a36Sopenharmony_ci		parport_frob_control (port,
16762306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
16862306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		/* Event 9: nAck goes low. */
17162306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_REV_DATA;
17262306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
17362306a36Sopenharmony_ci					     PARPORT_STATUS_ACK, 0)) {
17462306a36Sopenharmony_ci			/* Timeout -- no more data? */
17562306a36Sopenharmony_ci			pr_debug("%s: Nibble timeout at event 9 (%d bytes)\n",
17662306a36Sopenharmony_ci				 port->name, i / 2);
17762306a36Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
17862306a36Sopenharmony_ci			break;
17962306a36Sopenharmony_ci		}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		/* Read a nibble. */
18362306a36Sopenharmony_ci		nibble = parport_read_status (port) >> 3;
18462306a36Sopenharmony_ci		nibble &= ~8;
18562306a36Sopenharmony_ci		if ((nibble & 0x10) == 0)
18662306a36Sopenharmony_ci			nibble |= 8;
18762306a36Sopenharmony_ci		nibble &= 0xf;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		/* Event 10: Set nAutoFd high. */
19062306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		/* Event 11: nAck goes high. */
19362306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
19462306a36Sopenharmony_ci					     PARPORT_STATUS_ACK,
19562306a36Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
19662306a36Sopenharmony_ci			/* Timeout -- no more data? */
19762306a36Sopenharmony_ci			pr_debug("%s: Nibble timeout at event 11\n",
19862306a36Sopenharmony_ci				 port->name);
19962306a36Sopenharmony_ci			break;
20062306a36Sopenharmony_ci		}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		if (i & 1) {
20362306a36Sopenharmony_ci			/* Second nibble */
20462306a36Sopenharmony_ci			byte |= nibble << 4;
20562306a36Sopenharmony_ci			*buf++ = byte;
20662306a36Sopenharmony_ci		} else
20762306a36Sopenharmony_ci			byte = nibble;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (i == len) {
21162306a36Sopenharmony_ci		/* Read the last nibble without checking data avail. */
21262306a36Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
21362306a36Sopenharmony_ci		end_of_data:
21462306a36Sopenharmony_ci			pr_debug("%s: No more nibble data (%d bytes)\n",
21562306a36Sopenharmony_ci				 port->name, i / 2);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci			/* Go to reverse idle phase. */
21862306a36Sopenharmony_ci			parport_frob_control (port,
21962306a36Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD,
22062306a36Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD);
22162306a36Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
22262306a36Sopenharmony_ci		}
22362306a36Sopenharmony_ci		else
22462306a36Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return i/2;
22862306a36Sopenharmony_ci#endif /* IEEE1284 support */
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/* Byte mode. */
23262306a36Sopenharmony_cisize_t parport_ieee1284_read_byte (struct parport *port,
23362306a36Sopenharmony_ci				   void *buffer, size_t len,
23462306a36Sopenharmony_ci				   int flags)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
23762306a36Sopenharmony_ci	return 0;
23862306a36Sopenharmony_ci#else
23962306a36Sopenharmony_ci	unsigned char *buf = buffer;
24062306a36Sopenharmony_ci	ssize_t count = 0;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	for (count = 0; count < len; count++) {
24362306a36Sopenharmony_ci		unsigned char byte;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		/* Data available? */
24662306a36Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
24762306a36Sopenharmony_ci			goto end_of_data;
24862306a36Sopenharmony_ci		}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		/* Event 14: Place data bus in high impedance state. */
25162306a36Sopenharmony_ci		parport_data_reverse (port);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci		/* Event 7: Set nAutoFd low. */
25462306a36Sopenharmony_ci		parport_frob_control (port,
25562306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
25662306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		/* Event 9: nAck goes low. */
25962306a36Sopenharmony_ci		port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
26062306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
26162306a36Sopenharmony_ci					     PARPORT_STATUS_ACK,
26262306a36Sopenharmony_ci					     0)) {
26362306a36Sopenharmony_ci			/* Timeout -- no more data? */
26462306a36Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
26562306a36Sopenharmony_ci						 0);
26662306a36Sopenharmony_ci			pr_debug("%s: Byte timeout at event 9\n", port->name);
26762306a36Sopenharmony_ci			break;
26862306a36Sopenharmony_ci		}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		byte = parport_read_data (port);
27162306a36Sopenharmony_ci		*buf++ = byte;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci		/* Event 10: Set nAutoFd high */
27462306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci		/* Event 11: nAck goes high. */
27762306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
27862306a36Sopenharmony_ci					     PARPORT_STATUS_ACK,
27962306a36Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
28062306a36Sopenharmony_ci			/* Timeout -- no more data? */
28162306a36Sopenharmony_ci			pr_debug("%s: Byte timeout at event 11\n", port->name);
28262306a36Sopenharmony_ci			break;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci		/* Event 16: Set nStrobe low. */
28662306a36Sopenharmony_ci		parport_frob_control (port,
28762306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE,
28862306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
28962306a36Sopenharmony_ci		udelay (5);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		/* Event 17: Set nStrobe high. */
29262306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (count == len) {
29662306a36Sopenharmony_ci		/* Read the last byte without checking data avail. */
29762306a36Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
29862306a36Sopenharmony_ci		end_of_data:
29962306a36Sopenharmony_ci			pr_debug("%s: No more byte data (%zd bytes)\n",
30062306a36Sopenharmony_ci				 port->name, count);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci			/* Go to reverse idle phase. */
30362306a36Sopenharmony_ci			parport_frob_control (port,
30462306a36Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD,
30562306a36Sopenharmony_ci					      PARPORT_CONTROL_AUTOFD);
30662306a36Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
30762306a36Sopenharmony_ci		}
30862306a36Sopenharmony_ci		else
30962306a36Sopenharmony_ci			port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return count;
31362306a36Sopenharmony_ci#endif /* IEEE1284 support */
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/***              *
31762306a36Sopenharmony_ci * ECP Functions. *
31862306a36Sopenharmony_ci *              ***/
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic inline
32362306a36Sopenharmony_ciint ecp_forward_to_reverse (struct parport *port)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	int retval;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	/* Event 38: Set nAutoFd low */
32862306a36Sopenharmony_ci	parport_frob_control (port,
32962306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD,
33062306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD);
33162306a36Sopenharmony_ci	parport_data_reverse (port);
33262306a36Sopenharmony_ci	udelay (5);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* Event 39: Set nInit low to initiate bus reversal */
33562306a36Sopenharmony_ci	parport_frob_control (port,
33662306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT,
33762306a36Sopenharmony_ci			      0);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* Event 40: PError goes low */
34062306a36Sopenharmony_ci	retval = parport_wait_peripheral (port,
34162306a36Sopenharmony_ci					  PARPORT_STATUS_PAPEROUT, 0);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (!retval) {
34462306a36Sopenharmony_ci		pr_debug("%s: ECP direction: reverse\n", port->name);
34562306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
34662306a36Sopenharmony_ci	} else {
34762306a36Sopenharmony_ci		pr_debug("%s: ECP direction: failed to reverse\n", port->name);
34862306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
34962306a36Sopenharmony_ci	}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	return retval;
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_cistatic inline
35562306a36Sopenharmony_ciint ecp_reverse_to_forward (struct parport *port)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	int retval;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* Event 47: Set nInit high */
36062306a36Sopenharmony_ci	parport_frob_control (port,
36162306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT
36262306a36Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD,
36362306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT
36462306a36Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* Event 49: PError goes high */
36762306a36Sopenharmony_ci	retval = parport_wait_peripheral (port,
36862306a36Sopenharmony_ci					  PARPORT_STATUS_PAPEROUT,
36962306a36Sopenharmony_ci					  PARPORT_STATUS_PAPEROUT);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (!retval) {
37262306a36Sopenharmony_ci		parport_data_forward (port);
37362306a36Sopenharmony_ci		pr_debug("%s: ECP direction: forward\n", port->name);
37462306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
37562306a36Sopenharmony_ci	} else {
37662306a36Sopenharmony_ci		pr_debug("%s: ECP direction: failed to switch forward\n",
37762306a36Sopenharmony_ci			 port->name);
37862306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	return retval;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci#endif /* IEEE1284 support */
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/* ECP mode, forward channel, data. */
38862306a36Sopenharmony_cisize_t parport_ieee1284_ecp_write_data (struct parport *port,
38962306a36Sopenharmony_ci					const void *buffer, size_t len,
39062306a36Sopenharmony_ci					int flags)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
39362306a36Sopenharmony_ci	return 0;
39462306a36Sopenharmony_ci#else
39562306a36Sopenharmony_ci	const unsigned char *buf = buffer;
39662306a36Sopenharmony_ci	size_t written;
39762306a36Sopenharmony_ci	int retry;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	port = port->physport;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
40262306a36Sopenharmony_ci		if (ecp_reverse_to_forward (port))
40362306a36Sopenharmony_ci			return 0;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	/* HostAck high (data, not command) */
40862306a36Sopenharmony_ci	parport_frob_control (port,
40962306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD
41062306a36Sopenharmony_ci			      | PARPORT_CONTROL_STROBE
41162306a36Sopenharmony_ci			      | PARPORT_CONTROL_INIT,
41262306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT);
41362306a36Sopenharmony_ci	for (written = 0; written < len; written++, buf++) {
41462306a36Sopenharmony_ci		unsigned long expire = jiffies + port->cad->timeout;
41562306a36Sopenharmony_ci		unsigned char byte;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci		byte = *buf;
41862306a36Sopenharmony_ci	try_again:
41962306a36Sopenharmony_ci		parport_write_data (port, byte);
42062306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE,
42162306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
42262306a36Sopenharmony_ci		udelay (5);
42362306a36Sopenharmony_ci		for (retry = 0; retry < 100; retry++) {
42462306a36Sopenharmony_ci			if (!parport_wait_peripheral (port,
42562306a36Sopenharmony_ci						      PARPORT_STATUS_BUSY, 0))
42662306a36Sopenharmony_ci				goto success;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci			if (signal_pending (current)) {
42962306a36Sopenharmony_ci				parport_frob_control (port,
43062306a36Sopenharmony_ci						      PARPORT_CONTROL_STROBE,
43162306a36Sopenharmony_ci						      0);
43262306a36Sopenharmony_ci				break;
43362306a36Sopenharmony_ci			}
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
43762306a36Sopenharmony_ci		pr_debug("%s: ECP transfer stalled!\n", port->name);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT,
44062306a36Sopenharmony_ci				      PARPORT_CONTROL_INIT);
44162306a36Sopenharmony_ci		udelay (50);
44262306a36Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
44362306a36Sopenharmony_ci			/* It's buggered. */
44462306a36Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
44562306a36Sopenharmony_ci			break;
44662306a36Sopenharmony_ci		}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
44962306a36Sopenharmony_ci		udelay (50);
45062306a36Sopenharmony_ci		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
45162306a36Sopenharmony_ci			break;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci		pr_debug("%s: Host transfer recovered\n", port->name);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		if (time_after_eq (jiffies, expire)) break;
45662306a36Sopenharmony_ci		goto try_again;
45762306a36Sopenharmony_ci	success:
45862306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
45962306a36Sopenharmony_ci		udelay (5);
46062306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
46162306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY,
46262306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY))
46362306a36Sopenharmony_ci			/* Peripheral hasn't accepted the data. */
46462306a36Sopenharmony_ci			break;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	return written;
47062306a36Sopenharmony_ci#endif /* IEEE1284 support */
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci/* ECP mode, reverse channel, data. */
47462306a36Sopenharmony_cisize_t parport_ieee1284_ecp_read_data (struct parport *port,
47562306a36Sopenharmony_ci				       void *buffer, size_t len, int flags)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
47862306a36Sopenharmony_ci	return 0;
47962306a36Sopenharmony_ci#else
48062306a36Sopenharmony_ci	struct pardevice *dev = port->cad;
48162306a36Sopenharmony_ci	unsigned char *buf = buffer;
48262306a36Sopenharmony_ci	int rle_count = 0; /* shut gcc up */
48362306a36Sopenharmony_ci	unsigned char ctl;
48462306a36Sopenharmony_ci	int rle = 0;
48562306a36Sopenharmony_ci	ssize_t count = 0;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	port = port->physport;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
49062306a36Sopenharmony_ci		if (ecp_forward_to_reverse (port))
49162306a36Sopenharmony_ci			return 0;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_REV_DATA;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Set HostAck low to start accepting data. */
49662306a36Sopenharmony_ci	ctl = parport_read_control (port);
49762306a36Sopenharmony_ci	ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT |
49862306a36Sopenharmony_ci		 PARPORT_CONTROL_AUTOFD);
49962306a36Sopenharmony_ci	parport_write_control (port,
50062306a36Sopenharmony_ci			       ctl | PARPORT_CONTROL_AUTOFD);
50162306a36Sopenharmony_ci	while (count < len) {
50262306a36Sopenharmony_ci		unsigned long expire = jiffies + dev->timeout;
50362306a36Sopenharmony_ci		unsigned char byte;
50462306a36Sopenharmony_ci		int command;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		/* Event 43: Peripheral sets nAck low. It can take as
50762306a36Sopenharmony_ci                   long as it wants. */
50862306a36Sopenharmony_ci		while (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
50962306a36Sopenharmony_ci			/* The peripheral hasn't given us data in
51062306a36Sopenharmony_ci			   35ms.  If we have data to give back to the
51162306a36Sopenharmony_ci			   caller, do it now. */
51262306a36Sopenharmony_ci			if (count)
51362306a36Sopenharmony_ci				goto out;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci			/* If we've used up all the time we were allowed,
51662306a36Sopenharmony_ci			   give up altogether. */
51762306a36Sopenharmony_ci			if (!time_before (jiffies, expire))
51862306a36Sopenharmony_ci				goto out;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci			/* Yield the port for a while. */
52162306a36Sopenharmony_ci			if (dev->port->irq != PARPORT_IRQ_NONE) {
52262306a36Sopenharmony_ci				parport_release (dev);
52362306a36Sopenharmony_ci				schedule_timeout_interruptible(msecs_to_jiffies(40));
52462306a36Sopenharmony_ci				parport_claim_or_block (dev);
52562306a36Sopenharmony_ci			}
52662306a36Sopenharmony_ci			else
52762306a36Sopenharmony_ci				/* We must have the device claimed here. */
52862306a36Sopenharmony_ci				parport_wait_event (port, msecs_to_jiffies(40));
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci			/* Is there a signal pending? */
53162306a36Sopenharmony_ci			if (signal_pending (current))
53262306a36Sopenharmony_ci				goto out;
53362306a36Sopenharmony_ci		}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		/* Is this a command? */
53662306a36Sopenharmony_ci		if (rle)
53762306a36Sopenharmony_ci			/* The last byte was a run-length count, so
53862306a36Sopenharmony_ci                           this can't be as well. */
53962306a36Sopenharmony_ci			command = 0;
54062306a36Sopenharmony_ci		else
54162306a36Sopenharmony_ci			command = (parport_read_status (port) &
54262306a36Sopenharmony_ci				   PARPORT_STATUS_BUSY) ? 1 : 0;
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		/* Read the data. */
54562306a36Sopenharmony_ci		byte = parport_read_data (port);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/* If this is a channel command, rather than an RLE
54862306a36Sopenharmony_ci                   command or a normal data byte, don't accept it. */
54962306a36Sopenharmony_ci		if (command) {
55062306a36Sopenharmony_ci			if (byte & 0x80) {
55162306a36Sopenharmony_ci				pr_debug("%s: stopping short at channel command (%02x)\n",
55262306a36Sopenharmony_ci					 port->name, byte);
55362306a36Sopenharmony_ci				goto out;
55462306a36Sopenharmony_ci			}
55562306a36Sopenharmony_ci			else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
55662306a36Sopenharmony_ci				pr_debug("%s: device illegally using RLE; accepting anyway\n",
55762306a36Sopenharmony_ci					 port->name);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci			rle_count = byte + 1;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci			/* Are we allowed to read that many bytes? */
56262306a36Sopenharmony_ci			if (rle_count > (len - count)) {
56362306a36Sopenharmony_ci				pr_debug("%s: leaving %d RLE bytes for next time\n",
56462306a36Sopenharmony_ci					 port->name, rle_count);
56562306a36Sopenharmony_ci				break;
56662306a36Sopenharmony_ci			}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci			rle = 1;
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci		/* Event 44: Set HostAck high, acknowledging handshake. */
57262306a36Sopenharmony_ci		parport_write_control (port, ctl);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		/* Event 45: The peripheral has 35ms to set nAck high. */
57562306a36Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK,
57662306a36Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
57762306a36Sopenharmony_ci			/* It's gone wrong.  Return what data we have
57862306a36Sopenharmony_ci                           to the caller. */
57962306a36Sopenharmony_ci			pr_debug("ECP read timed out at 45\n");
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci			if (command)
58262306a36Sopenharmony_ci				pr_warn("%s: command ignored (%02x)\n",
58362306a36Sopenharmony_ci					port->name, byte);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci			break;
58662306a36Sopenharmony_ci		}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci		/* Event 46: Set HostAck low and accept the data. */
58962306a36Sopenharmony_ci		parport_write_control (port,
59062306a36Sopenharmony_ci				       ctl | PARPORT_CONTROL_AUTOFD);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		/* If we just read a run-length count, fetch the data. */
59362306a36Sopenharmony_ci		if (command)
59462306a36Sopenharmony_ci			continue;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		/* If this is the byte after a run-length count, decompress. */
59762306a36Sopenharmony_ci		if (rle) {
59862306a36Sopenharmony_ci			rle = 0;
59962306a36Sopenharmony_ci			memset (buf, byte, rle_count);
60062306a36Sopenharmony_ci			buf += rle_count;
60162306a36Sopenharmony_ci			count += rle_count;
60262306a36Sopenharmony_ci			pr_debug("%s: decompressed to %d bytes\n",
60362306a36Sopenharmony_ci				 port->name, rle_count);
60462306a36Sopenharmony_ci		} else {
60562306a36Sopenharmony_ci			/* Normal data byte. */
60662306a36Sopenharmony_ci			*buf = byte;
60762306a36Sopenharmony_ci			buf++, count++;
60862306a36Sopenharmony_ci		}
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci out:
61262306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
61362306a36Sopenharmony_ci	return count;
61462306a36Sopenharmony_ci#endif /* IEEE1284 support */
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci/* ECP mode, forward channel, commands. */
61862306a36Sopenharmony_cisize_t parport_ieee1284_ecp_write_addr (struct parport *port,
61962306a36Sopenharmony_ci					const void *buffer, size_t len,
62062306a36Sopenharmony_ci					int flags)
62162306a36Sopenharmony_ci{
62262306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci#else
62562306a36Sopenharmony_ci	const unsigned char *buf = buffer;
62662306a36Sopenharmony_ci	size_t written;
62762306a36Sopenharmony_ci	int retry;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	port = port->physport;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
63262306a36Sopenharmony_ci		if (ecp_reverse_to_forward (port))
63362306a36Sopenharmony_ci			return 0;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	/* HostAck low (command, not data) */
63862306a36Sopenharmony_ci	parport_frob_control (port,
63962306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD
64062306a36Sopenharmony_ci			      | PARPORT_CONTROL_STROBE
64162306a36Sopenharmony_ci			      | PARPORT_CONTROL_INIT,
64262306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD
64362306a36Sopenharmony_ci			      | PARPORT_CONTROL_INIT);
64462306a36Sopenharmony_ci	for (written = 0; written < len; written++, buf++) {
64562306a36Sopenharmony_ci		unsigned long expire = jiffies + port->cad->timeout;
64662306a36Sopenharmony_ci		unsigned char byte;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci		byte = *buf;
64962306a36Sopenharmony_ci	try_again:
65062306a36Sopenharmony_ci		parport_write_data (port, byte);
65162306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE,
65262306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
65362306a36Sopenharmony_ci		udelay (5);
65462306a36Sopenharmony_ci		for (retry = 0; retry < 100; retry++) {
65562306a36Sopenharmony_ci			if (!parport_wait_peripheral (port,
65662306a36Sopenharmony_ci						      PARPORT_STATUS_BUSY, 0))
65762306a36Sopenharmony_ci				goto success;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci			if (signal_pending (current)) {
66062306a36Sopenharmony_ci				parport_frob_control (port,
66162306a36Sopenharmony_ci						      PARPORT_CONTROL_STROBE,
66262306a36Sopenharmony_ci						      0);
66362306a36Sopenharmony_ci				break;
66462306a36Sopenharmony_ci			}
66562306a36Sopenharmony_ci		}
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci		/* Time for Host Transfer Recovery (page 41 of IEEE1284) */
66862306a36Sopenharmony_ci		pr_debug("%s: ECP transfer stalled!\n", port->name);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT,
67162306a36Sopenharmony_ci				      PARPORT_CONTROL_INIT);
67262306a36Sopenharmony_ci		udelay (50);
67362306a36Sopenharmony_ci		if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
67462306a36Sopenharmony_ci			/* It's buggered. */
67562306a36Sopenharmony_ci			parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
67662306a36Sopenharmony_ci			break;
67762306a36Sopenharmony_ci		}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
68062306a36Sopenharmony_ci		udelay (50);
68162306a36Sopenharmony_ci		if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
68262306a36Sopenharmony_ci			break;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci		pr_debug("%s: Host transfer recovered\n", port->name);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		if (time_after_eq (jiffies, expire)) break;
68762306a36Sopenharmony_ci		goto try_again;
68862306a36Sopenharmony_ci	success:
68962306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
69062306a36Sopenharmony_ci		udelay (5);
69162306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
69262306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY,
69362306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY))
69462306a36Sopenharmony_ci			/* Peripheral hasn't accepted the data. */
69562306a36Sopenharmony_ci			break;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return written;
70162306a36Sopenharmony_ci#endif /* IEEE1284 support */
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci/***              *
70562306a36Sopenharmony_ci * EPP functions. *
70662306a36Sopenharmony_ci *              ***/
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci/* EPP mode, forward channel, data. */
70962306a36Sopenharmony_cisize_t parport_ieee1284_epp_write_data (struct parport *port,
71062306a36Sopenharmony_ci					const void *buffer, size_t len,
71162306a36Sopenharmony_ci					int flags)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
71462306a36Sopenharmony_ci	size_t ret = 0;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	/* set EPP idle state (just to make sure) with strobe low */
71762306a36Sopenharmony_ci	parport_frob_control (port,
71862306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
71962306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
72062306a36Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
72162306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT,
72262306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
72362306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT);
72462306a36Sopenharmony_ci	port->ops->data_forward (port);
72562306a36Sopenharmony_ci	for (; len > 0; len--, bp++) {
72662306a36Sopenharmony_ci		/* Event 62: Write data and set autofd low */
72762306a36Sopenharmony_ci		parport_write_data (port, *bp);
72862306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
72962306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		/* Event 58: wait for busy (nWait) to go high */
73262306a36Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
73362306a36Sopenharmony_ci			break;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		/* Event 63: set nAutoFd (nDStrb) high */
73662306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		/* Event 60: wait for busy (nWait) to go low */
73962306a36Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
74062306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5))
74162306a36Sopenharmony_ci			break;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci		ret++;
74462306a36Sopenharmony_ci	}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/* Event 61: set strobe (nWrite) high */
74762306a36Sopenharmony_ci	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return ret;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci/* EPP mode, reverse channel, data. */
75362306a36Sopenharmony_cisize_t parport_ieee1284_epp_read_data (struct parport *port,
75462306a36Sopenharmony_ci				       void *buffer, size_t len,
75562306a36Sopenharmony_ci				       int flags)
75662306a36Sopenharmony_ci{
75762306a36Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
75862306a36Sopenharmony_ci	unsigned ret = 0;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	/* set EPP idle state (just to make sure) with strobe high */
76162306a36Sopenharmony_ci	parport_frob_control (port,
76262306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
76362306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
76462306a36Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
76562306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT,
76662306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT);
76762306a36Sopenharmony_ci	port->ops->data_reverse (port);
76862306a36Sopenharmony_ci	for (; len > 0; len--, bp++) {
76962306a36Sopenharmony_ci		/* Event 67: set nAutoFd (nDStrb) low */
77062306a36Sopenharmony_ci		parport_frob_control (port,
77162306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
77262306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
77362306a36Sopenharmony_ci		/* Event 58: wait for Busy to go high */
77462306a36Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
77562306a36Sopenharmony_ci			break;
77662306a36Sopenharmony_ci		}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci		*bp = parport_read_data (port);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci		/* Event 63: set nAutoFd (nDStrb) high */
78162306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci		/* Event 60: wait for Busy to go low */
78462306a36Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
78562306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5)) {
78662306a36Sopenharmony_ci			break;
78762306a36Sopenharmony_ci		}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci		ret++;
79062306a36Sopenharmony_ci	}
79162306a36Sopenharmony_ci	port->ops->data_forward (port);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	return ret;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci/* EPP mode, forward channel, addresses. */
79762306a36Sopenharmony_cisize_t parport_ieee1284_epp_write_addr (struct parport *port,
79862306a36Sopenharmony_ci					const void *buffer, size_t len,
79962306a36Sopenharmony_ci					int flags)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
80262306a36Sopenharmony_ci	size_t ret = 0;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	/* set EPP idle state (just to make sure) with strobe low */
80562306a36Sopenharmony_ci	parport_frob_control (port,
80662306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
80762306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
80862306a36Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
80962306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT,
81062306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
81162306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT);
81262306a36Sopenharmony_ci	port->ops->data_forward (port);
81362306a36Sopenharmony_ci	for (; len > 0; len--, bp++) {
81462306a36Sopenharmony_ci		/* Event 56: Write data and set nAStrb low. */
81562306a36Sopenharmony_ci		parport_write_data (port, *bp);
81662306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT,
81762306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		/* Event 58: wait for busy (nWait) to go high */
82062306a36Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10))
82162306a36Sopenharmony_ci			break;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci		/* Event 59: set nAStrb high */
82462306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci		/* Event 60: wait for busy (nWait) to go low */
82762306a36Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
82862306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5))
82962306a36Sopenharmony_ci			break;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci		ret++;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	/* Event 61: set strobe (nWrite) high */
83562306a36Sopenharmony_ci	parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	return ret;
83862306a36Sopenharmony_ci}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci/* EPP mode, reverse channel, addresses. */
84162306a36Sopenharmony_cisize_t parport_ieee1284_epp_read_addr (struct parport *port,
84262306a36Sopenharmony_ci				       void *buffer, size_t len,
84362306a36Sopenharmony_ci				       int flags)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	unsigned char *bp = (unsigned char *) buffer;
84662306a36Sopenharmony_ci	unsigned ret = 0;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* Set EPP idle state (just to make sure) with strobe high */
84962306a36Sopenharmony_ci	parport_frob_control (port,
85062306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE |
85162306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD |
85262306a36Sopenharmony_ci			      PARPORT_CONTROL_SELECT |
85362306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT,
85462306a36Sopenharmony_ci			      PARPORT_CONTROL_INIT);
85562306a36Sopenharmony_ci	port->ops->data_reverse (port);
85662306a36Sopenharmony_ci	for (; len > 0; len--, bp++) {
85762306a36Sopenharmony_ci		/* Event 64: set nSelectIn (nAStrb) low */
85862306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT,
85962306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT);
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		/* Event 58: wait for Busy to go high */
86262306a36Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) {
86362306a36Sopenharmony_ci			break;
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci		*bp = parport_read_data (port);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		/* Event 59: set nSelectIn (nAStrb) high */
86962306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_SELECT,
87062306a36Sopenharmony_ci				      0);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		/* Event 60: wait for Busy to go low */
87362306a36Sopenharmony_ci		if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY,
87462306a36Sopenharmony_ci					     PARPORT_STATUS_BUSY, 5))
87562306a36Sopenharmony_ci			break;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci		ret++;
87862306a36Sopenharmony_ci	}
87962306a36Sopenharmony_ci	port->ops->data_forward (port);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	return ret;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
88562306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
88662306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
88762306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_write_compat);
88862306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_read_nibble);
88962306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_read_byte);
89062306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_write_data);
89162306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_read_data);
89262306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
89362306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
894