162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * IEEE-1284 implementation for parport.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Authors: Phil Blundell <philb@gnu.org>
562306a36Sopenharmony_ci *          Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
662306a36Sopenharmony_ci *	    Jose Renau <renau@acm.org>
762306a36Sopenharmony_ci *          Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * This file is responsible for IEEE 1284 negotiation, and for handing
1062306a36Sopenharmony_ci * read/write requests to low-level drivers.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * Any part of this program may be used in documents licensed under
1362306a36Sopenharmony_ci * the GNU Free Documentation License, Version 1.1 or any later version
1462306a36Sopenharmony_ci * published by the Free Software Foundation.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Various hacks, Fred Barnes <frmb2@ukc.ac.uk>, 04/2000
1762306a36Sopenharmony_ci */
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/module.h>
2062306a36Sopenharmony_ci#include <linux/threads.h>
2162306a36Sopenharmony_ci#include <linux/parport.h>
2262306a36Sopenharmony_ci#include <linux/delay.h>
2362306a36Sopenharmony_ci#include <linux/kernel.h>
2462306a36Sopenharmony_ci#include <linux/interrupt.h>
2562306a36Sopenharmony_ci#include <linux/timer.h>
2662306a36Sopenharmony_ci#include <linux/sched/signal.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#undef DEBUG /* undef me for production */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#ifdef CONFIG_LP_CONSOLE
3162306a36Sopenharmony_ci#undef DEBUG /* Don't want a garbled console */
3262306a36Sopenharmony_ci#endif
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Make parport_wait_peripheral wake up.
3562306a36Sopenharmony_ci * It will be useful to call this from an interrupt handler. */
3662306a36Sopenharmony_cistatic void parport_ieee1284_wakeup (struct parport *port)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	up (&port->physport->ieee1284.irq);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void timeout_waiting_on_port (struct timer_list *t)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct parport *port = from_timer(port, t, timer);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	parport_ieee1284_wakeup (port);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/**
4962306a36Sopenharmony_ci *	parport_wait_event - wait for an event on a parallel port
5062306a36Sopenharmony_ci *	@port: port to wait on
5162306a36Sopenharmony_ci *	@timeout: time to wait (in jiffies)
5262306a36Sopenharmony_ci *
5362306a36Sopenharmony_ci *	This function waits for up to @timeout jiffies for an
5462306a36Sopenharmony_ci *	interrupt to occur on a parallel port.  If the port timeout is
5562306a36Sopenharmony_ci *	set to zero, it returns immediately.
5662306a36Sopenharmony_ci *
5762306a36Sopenharmony_ci *	If an interrupt occurs before the timeout period elapses, this
5862306a36Sopenharmony_ci *	function returns zero immediately.  If it times out, it returns
5962306a36Sopenharmony_ci *	one.  An error code less than zero indicates an error (most
6062306a36Sopenharmony_ci *	likely a pending signal), and the calling code should finish
6162306a36Sopenharmony_ci *	what it's doing as soon as it can.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciint parport_wait_event (struct parport *port, signed long timeout)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	int ret;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (!port->physport->cad->timeout)
6962306a36Sopenharmony_ci		/* Zero timeout is special, and we can't down() the
7062306a36Sopenharmony_ci		   semaphore. */
7162306a36Sopenharmony_ci		return 1;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	timer_setup(&port->timer, timeout_waiting_on_port, 0);
7462306a36Sopenharmony_ci	mod_timer(&port->timer, jiffies + timeout);
7562306a36Sopenharmony_ci	ret = down_interruptible (&port->physport->ieee1284.irq);
7662306a36Sopenharmony_ci	if (!del_timer_sync(&port->timer) && !ret)
7762306a36Sopenharmony_ci		/* Timed out. */
7862306a36Sopenharmony_ci		ret = 1;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return ret;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/**
8462306a36Sopenharmony_ci *	parport_poll_peripheral - poll status lines
8562306a36Sopenharmony_ci *	@port: port to watch
8662306a36Sopenharmony_ci *	@mask: status lines to watch
8762306a36Sopenharmony_ci *	@result: desired values of chosen status lines
8862306a36Sopenharmony_ci *	@usec: timeout
8962306a36Sopenharmony_ci *
9062306a36Sopenharmony_ci *	This function busy-waits until the masked status lines have
9162306a36Sopenharmony_ci *	the desired values, or until the timeout period elapses.  The
9262306a36Sopenharmony_ci *	@mask and @result parameters are bitmasks, with the bits
9362306a36Sopenharmony_ci *	defined by the constants in parport.h: %PARPORT_STATUS_BUSY,
9462306a36Sopenharmony_ci *	and so on.
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci *	This function does not call schedule(); instead it busy-waits
9762306a36Sopenharmony_ci *	using udelay().  It currently has a resolution of 5usec.
9862306a36Sopenharmony_ci *
9962306a36Sopenharmony_ci *	If the status lines take on the desired values before the
10062306a36Sopenharmony_ci *	timeout period elapses, parport_poll_peripheral() returns zero
10162306a36Sopenharmony_ci *	immediately.  A return value greater than zero indicates
10262306a36Sopenharmony_ci *	a timeout.  An error code (less than zero) indicates an error,
10362306a36Sopenharmony_ci *	most likely a signal that arrived, and the caller should
10462306a36Sopenharmony_ci *	finish what it is doing as soon as possible.
10562306a36Sopenharmony_ci*/
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ciint parport_poll_peripheral(struct parport *port,
10862306a36Sopenharmony_ci			    unsigned char mask,
10962306a36Sopenharmony_ci			    unsigned char result,
11062306a36Sopenharmony_ci			    int usec)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	/* Zero return code is success, >0 is timeout. */
11362306a36Sopenharmony_ci	int count = usec / 5 + 2;
11462306a36Sopenharmony_ci	int i;
11562306a36Sopenharmony_ci	unsigned char status;
11662306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
11762306a36Sopenharmony_ci		status = parport_read_status (port);
11862306a36Sopenharmony_ci		if ((status & mask) == result)
11962306a36Sopenharmony_ci			return 0;
12062306a36Sopenharmony_ci		if (signal_pending (current))
12162306a36Sopenharmony_ci			return -EINTR;
12262306a36Sopenharmony_ci		if (need_resched())
12362306a36Sopenharmony_ci			break;
12462306a36Sopenharmony_ci		if (i >= 2)
12562306a36Sopenharmony_ci			udelay (5);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return 1;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/**
13262306a36Sopenharmony_ci *	parport_wait_peripheral - wait for status lines to change in 35ms
13362306a36Sopenharmony_ci *	@port: port to watch
13462306a36Sopenharmony_ci *	@mask: status lines to watch
13562306a36Sopenharmony_ci *	@result: desired values of chosen status lines
13662306a36Sopenharmony_ci *
13762306a36Sopenharmony_ci *	This function waits until the masked status lines have the
13862306a36Sopenharmony_ci *	desired values, or until 35ms have elapsed (see IEEE 1284-1994
13962306a36Sopenharmony_ci *	page 24 to 25 for why this value in particular is hardcoded).
14062306a36Sopenharmony_ci *	The @mask and @result parameters are bitmasks, with the bits
14162306a36Sopenharmony_ci *	defined by the constants in parport.h: %PARPORT_STATUS_BUSY,
14262306a36Sopenharmony_ci *	and so on.
14362306a36Sopenharmony_ci *
14462306a36Sopenharmony_ci *	The port is polled quickly to start off with, in anticipation
14562306a36Sopenharmony_ci *	of a fast response from the peripheral.  This fast polling
14662306a36Sopenharmony_ci *	time is configurable (using /proc), and defaults to 500usec.
14762306a36Sopenharmony_ci *	If the timeout for this port (see parport_set_timeout()) is
14862306a36Sopenharmony_ci *	zero, the fast polling time is 35ms, and this function does
14962306a36Sopenharmony_ci *	not call schedule().
15062306a36Sopenharmony_ci *
15162306a36Sopenharmony_ci *	If the timeout for this port is non-zero, after the fast
15262306a36Sopenharmony_ci *	polling fails it uses parport_wait_event() to wait for up to
15362306a36Sopenharmony_ci *	10ms, waking up if an interrupt occurs.
15462306a36Sopenharmony_ci */
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ciint parport_wait_peripheral(struct parport *port,
15762306a36Sopenharmony_ci			    unsigned char mask,
15862306a36Sopenharmony_ci			    unsigned char result)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	int ret;
16162306a36Sopenharmony_ci	int usec;
16262306a36Sopenharmony_ci	unsigned long deadline;
16362306a36Sopenharmony_ci	unsigned char status;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	usec = port->physport->spintime; /* usecs of fast polling */
16662306a36Sopenharmony_ci	if (!port->physport->cad->timeout)
16762306a36Sopenharmony_ci		/* A zero timeout is "special": busy wait for the
16862306a36Sopenharmony_ci		   entire 35ms. */
16962306a36Sopenharmony_ci		usec = 35000;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Fast polling.
17262306a36Sopenharmony_ci	 *
17362306a36Sopenharmony_ci	 * This should be adjustable.
17462306a36Sopenharmony_ci	 * How about making a note (in the device structure) of how long
17562306a36Sopenharmony_ci	 * it takes, so we know for next time?
17662306a36Sopenharmony_ci	 */
17762306a36Sopenharmony_ci	ret = parport_poll_peripheral (port, mask, result, usec);
17862306a36Sopenharmony_ci	if (ret != 1)
17962306a36Sopenharmony_ci		return ret;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (!port->physport->cad->timeout)
18262306a36Sopenharmony_ci		/* We may be in an interrupt handler, so we can't poll
18362306a36Sopenharmony_ci		 * slowly anyway. */
18462306a36Sopenharmony_ci		return 1;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* 40ms of slow polling. */
18762306a36Sopenharmony_ci	deadline = jiffies + msecs_to_jiffies(40);
18862306a36Sopenharmony_ci	while (time_before (jiffies, deadline)) {
18962306a36Sopenharmony_ci		if (signal_pending (current))
19062306a36Sopenharmony_ci			return -EINTR;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		/* Wait for 10ms (or until an interrupt occurs if
19362306a36Sopenharmony_ci		 * the handler is set) */
19462306a36Sopenharmony_ci		if ((ret = parport_wait_event (port, msecs_to_jiffies(10))) < 0)
19562306a36Sopenharmony_ci			return ret;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		status = parport_read_status (port);
19862306a36Sopenharmony_ci		if ((status & mask) == result)
19962306a36Sopenharmony_ci			return 0;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if (!ret) {
20262306a36Sopenharmony_ci			/* parport_wait_event didn't time out, but the
20362306a36Sopenharmony_ci			 * peripheral wasn't actually ready either.
20462306a36Sopenharmony_ci			 * Wait for another 10ms. */
20562306a36Sopenharmony_ci			schedule_timeout_interruptible(msecs_to_jiffies(10));
20662306a36Sopenharmony_ci		}
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return 1;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
21362306a36Sopenharmony_ci/* Terminate a negotiated mode. */
21462306a36Sopenharmony_cistatic void parport_ieee1284_terminate (struct parport *port)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	int r;
21762306a36Sopenharmony_ci	port = port->physport;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* EPP terminates differently. */
22062306a36Sopenharmony_ci	switch (port->ieee1284.mode) {
22162306a36Sopenharmony_ci	case IEEE1284_MODE_EPP:
22262306a36Sopenharmony_ci	case IEEE1284_MODE_EPPSL:
22362306a36Sopenharmony_ci	case IEEE1284_MODE_EPPSWE:
22462306a36Sopenharmony_ci		/* Terminate from EPP mode. */
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci		/* Event 68: Set nInit low */
22762306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
22862306a36Sopenharmony_ci		udelay (50);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		/* Event 69: Set nInit high, nSelectIn low */
23162306a36Sopenharmony_ci		parport_frob_control (port,
23262306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT
23362306a36Sopenharmony_ci				      | PARPORT_CONTROL_INIT,
23462306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT
23562306a36Sopenharmony_ci				      | PARPORT_CONTROL_INIT);
23662306a36Sopenharmony_ci		break;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	case IEEE1284_MODE_ECP:
23962306a36Sopenharmony_ci	case IEEE1284_MODE_ECPRLE:
24062306a36Sopenharmony_ci	case IEEE1284_MODE_ECPSWE:
24162306a36Sopenharmony_ci		/* In ECP we can only terminate from fwd idle phase. */
24262306a36Sopenharmony_ci		if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
24362306a36Sopenharmony_ci			/* Event 47: Set nInit high */
24462306a36Sopenharmony_ci			parport_frob_control (port,
24562306a36Sopenharmony_ci					      PARPORT_CONTROL_INIT
24662306a36Sopenharmony_ci					      | PARPORT_CONTROL_AUTOFD,
24762306a36Sopenharmony_ci					      PARPORT_CONTROL_INIT
24862306a36Sopenharmony_ci					      | PARPORT_CONTROL_AUTOFD);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci			/* Event 49: PError goes high */
25162306a36Sopenharmony_ci			r = parport_wait_peripheral (port,
25262306a36Sopenharmony_ci						     PARPORT_STATUS_PAPEROUT,
25362306a36Sopenharmony_ci						     PARPORT_STATUS_PAPEROUT);
25462306a36Sopenharmony_ci			if (r)
25562306a36Sopenharmony_ci				pr_debug("%s: Timeout at event 49\n",
25662306a36Sopenharmony_ci					 port->name);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci			parport_data_forward (port);
25962306a36Sopenharmony_ci			pr_debug("%s: ECP direction: forward\n", port->name);
26062306a36Sopenharmony_ci			port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
26162306a36Sopenharmony_ci		}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		fallthrough;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	default:
26662306a36Sopenharmony_ci		/* Terminate from all other modes. */
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		/* Event 22: Set nSelectIn low, nAutoFd high */
26962306a36Sopenharmony_ci		parport_frob_control (port,
27062306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT
27162306a36Sopenharmony_ci				      | PARPORT_CONTROL_AUTOFD,
27262306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci		/* Event 24: nAck goes low */
27562306a36Sopenharmony_ci		r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
27662306a36Sopenharmony_ci		if (r)
27762306a36Sopenharmony_ci			pr_debug("%s: Timeout at event 24\n", port->name);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		/* Event 25: Set nAutoFd low */
28062306a36Sopenharmony_ci		parport_frob_control (port,
28162306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
28262306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci		/* Event 27: nAck goes high */
28562306a36Sopenharmony_ci		r = parport_wait_peripheral (port,
28662306a36Sopenharmony_ci					     PARPORT_STATUS_ACK,
28762306a36Sopenharmony_ci					     PARPORT_STATUS_ACK);
28862306a36Sopenharmony_ci		if (r)
28962306a36Sopenharmony_ci			pr_debug("%s: Timeout at event 27\n", port->name);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		/* Event 29: Set nAutoFd high */
29262306a36Sopenharmony_ci		parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	port->ieee1284.mode = IEEE1284_MODE_COMPAT;
29662306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	pr_debug("%s: In compatibility (forward idle) mode\n", port->name);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci#endif /* IEEE1284 support */
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/**
30362306a36Sopenharmony_ci *	parport_negotiate - negotiate an IEEE 1284 mode
30462306a36Sopenharmony_ci *	@port: port to use
30562306a36Sopenharmony_ci *	@mode: mode to negotiate to
30662306a36Sopenharmony_ci *
30762306a36Sopenharmony_ci *	Use this to negotiate to a particular IEEE 1284 transfer mode.
30862306a36Sopenharmony_ci *	The @mode parameter should be one of the constants in
30962306a36Sopenharmony_ci *	parport.h starting %IEEE1284_MODE_xxx.
31062306a36Sopenharmony_ci *
31162306a36Sopenharmony_ci *	The return value is 0 if the peripheral has accepted the
31262306a36Sopenharmony_ci *	negotiation to the mode specified, -1 if the peripheral is not
31362306a36Sopenharmony_ci *	IEEE 1284 compliant (or not present), or 1 if the peripheral
31462306a36Sopenharmony_ci *	has rejected the negotiation.
31562306a36Sopenharmony_ci */
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciint parport_negotiate (struct parport *port, int mode)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
32062306a36Sopenharmony_ci	if (mode == IEEE1284_MODE_COMPAT)
32162306a36Sopenharmony_ci		return 0;
32262306a36Sopenharmony_ci	pr_err("parport: IEEE1284 not supported in this kernel\n");
32362306a36Sopenharmony_ci	return -1;
32462306a36Sopenharmony_ci#else
32562306a36Sopenharmony_ci	int m = mode & ~IEEE1284_ADDR;
32662306a36Sopenharmony_ci	int r;
32762306a36Sopenharmony_ci	unsigned char xflag;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	port = port->physport;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Is there anything to do? */
33262306a36Sopenharmony_ci	if (port->ieee1284.mode == mode)
33362306a36Sopenharmony_ci		return 0;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* Is the difference just an address-or-not bit? */
33662306a36Sopenharmony_ci	if ((port->ieee1284.mode & ~IEEE1284_ADDR) == (mode & ~IEEE1284_ADDR)){
33762306a36Sopenharmony_ci		port->ieee1284.mode = mode;
33862306a36Sopenharmony_ci		return 0;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Go to compatibility forward idle mode */
34262306a36Sopenharmony_ci	if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
34362306a36Sopenharmony_ci		parport_ieee1284_terminate (port);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (mode == IEEE1284_MODE_COMPAT)
34662306a36Sopenharmony_ci		/* Compatibility mode: no negotiation. */
34762306a36Sopenharmony_ci		return 0;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	switch (mode) {
35062306a36Sopenharmony_ci	case IEEE1284_MODE_ECPSWE:
35162306a36Sopenharmony_ci		m = IEEE1284_MODE_ECP;
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	case IEEE1284_MODE_EPPSL:
35462306a36Sopenharmony_ci	case IEEE1284_MODE_EPPSWE:
35562306a36Sopenharmony_ci		m = IEEE1284_MODE_EPP;
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci	case IEEE1284_MODE_BECP:
35862306a36Sopenharmony_ci		return -ENOSYS; /* FIXME (implement BECP) */
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (mode & IEEE1284_EXT_LINK)
36262306a36Sopenharmony_ci		m = 1<<7; /* request extensibility link */
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* Start off with nStrobe and nAutoFd high, and nSelectIn low */
36762306a36Sopenharmony_ci	parport_frob_control (port,
36862306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE
36962306a36Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD
37062306a36Sopenharmony_ci			      | PARPORT_CONTROL_SELECT,
37162306a36Sopenharmony_ci			      PARPORT_CONTROL_SELECT);
37262306a36Sopenharmony_ci	udelay(1);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	/* Event 0: Set data */
37562306a36Sopenharmony_ci	parport_data_forward (port);
37662306a36Sopenharmony_ci	parport_write_data (port, m);
37762306a36Sopenharmony_ci	udelay (400); /* Shouldn't need to wait this long. */
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Event 1: Set nSelectIn high, nAutoFd low */
38062306a36Sopenharmony_ci	parport_frob_control (port,
38162306a36Sopenharmony_ci			      PARPORT_CONTROL_SELECT
38262306a36Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD,
38362306a36Sopenharmony_ci			      PARPORT_CONTROL_AUTOFD);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Event 2: PError, Select, nFault go high, nAck goes low */
38662306a36Sopenharmony_ci	if (parport_wait_peripheral (port,
38762306a36Sopenharmony_ci				     PARPORT_STATUS_ERROR
38862306a36Sopenharmony_ci				     | PARPORT_STATUS_SELECT
38962306a36Sopenharmony_ci				     | PARPORT_STATUS_PAPEROUT
39062306a36Sopenharmony_ci				     | PARPORT_STATUS_ACK,
39162306a36Sopenharmony_ci				     PARPORT_STATUS_ERROR
39262306a36Sopenharmony_ci				     | PARPORT_STATUS_SELECT
39362306a36Sopenharmony_ci				     | PARPORT_STATUS_PAPEROUT)) {
39462306a36Sopenharmony_ci		/* Timeout */
39562306a36Sopenharmony_ci		parport_frob_control (port,
39662306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT
39762306a36Sopenharmony_ci				      | PARPORT_CONTROL_AUTOFD,
39862306a36Sopenharmony_ci				      PARPORT_CONTROL_SELECT);
39962306a36Sopenharmony_ci		pr_debug("%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
40062306a36Sopenharmony_ci			 port->name, parport_read_status (port));
40162306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
40262306a36Sopenharmony_ci		return -1; /* Not IEEE1284 compliant */
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Event 3: Set nStrobe low */
40662306a36Sopenharmony_ci	parport_frob_control (port,
40762306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE,
40862306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/* Event 4: Set nStrobe and nAutoFd high */
41162306a36Sopenharmony_ci	udelay (5);
41262306a36Sopenharmony_ci	parport_frob_control (port,
41362306a36Sopenharmony_ci			      PARPORT_CONTROL_STROBE
41462306a36Sopenharmony_ci			      | PARPORT_CONTROL_AUTOFD,
41562306a36Sopenharmony_ci			      0);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Event 6: nAck goes high */
41862306a36Sopenharmony_ci	if (parport_wait_peripheral (port,
41962306a36Sopenharmony_ci				     PARPORT_STATUS_ACK,
42062306a36Sopenharmony_ci				     PARPORT_STATUS_ACK)) {
42162306a36Sopenharmony_ci		/* This shouldn't really happen with a compliant device. */
42262306a36Sopenharmony_ci		pr_debug("%s: Mode 0x%02x not supported? (0x%02x)\n",
42362306a36Sopenharmony_ci			 port->name, mode, port->ops->read_status (port));
42462306a36Sopenharmony_ci		parport_ieee1284_terminate (port);
42562306a36Sopenharmony_ci		return 1;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	/* xflag should be high for all modes other than nibble (0). */
43162306a36Sopenharmony_ci	if (mode && !xflag) {
43262306a36Sopenharmony_ci		/* Mode not supported. */
43362306a36Sopenharmony_ci		pr_debug("%s: Mode 0x%02x rejected by peripheral\n",
43462306a36Sopenharmony_ci			 port->name, mode);
43562306a36Sopenharmony_ci		parport_ieee1284_terminate (port);
43662306a36Sopenharmony_ci		return 1;
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* More to do if we've requested extensibility link. */
44062306a36Sopenharmony_ci	if (mode & IEEE1284_EXT_LINK) {
44162306a36Sopenharmony_ci		m = mode & 0x7f;
44262306a36Sopenharmony_ci		udelay (1);
44362306a36Sopenharmony_ci		parport_write_data (port, m);
44462306a36Sopenharmony_ci		udelay (1);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		/* Event 51: Set nStrobe low */
44762306a36Sopenharmony_ci		parport_frob_control (port,
44862306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE,
44962306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE);
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		/* Event 52: nAck goes low */
45262306a36Sopenharmony_ci		if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
45362306a36Sopenharmony_ci			/* This peripheral is _very_ slow. */
45462306a36Sopenharmony_ci			pr_debug("%s: Event 52 didn't happen\n", port->name);
45562306a36Sopenharmony_ci			parport_ieee1284_terminate (port);
45662306a36Sopenharmony_ci			return 1;
45762306a36Sopenharmony_ci		}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci		/* Event 53: Set nStrobe high */
46062306a36Sopenharmony_ci		parport_frob_control (port,
46162306a36Sopenharmony_ci				      PARPORT_CONTROL_STROBE,
46262306a36Sopenharmony_ci				      0);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		/* Event 55: nAck goes high */
46562306a36Sopenharmony_ci		if (parport_wait_peripheral (port,
46662306a36Sopenharmony_ci					     PARPORT_STATUS_ACK,
46762306a36Sopenharmony_ci					     PARPORT_STATUS_ACK)) {
46862306a36Sopenharmony_ci			/* This shouldn't really happen with a compliant
46962306a36Sopenharmony_ci			 * device. */
47062306a36Sopenharmony_ci			pr_debug("%s: Mode 0x%02x not supported? (0x%02x)\n",
47162306a36Sopenharmony_ci				 port->name, mode,
47262306a36Sopenharmony_ci				 port->ops->read_status(port));
47362306a36Sopenharmony_ci			parport_ieee1284_terminate (port);
47462306a36Sopenharmony_ci			return 1;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci		/* Event 54: Peripheral sets XFlag to reflect support */
47862306a36Sopenharmony_ci		xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		/* xflag should be high. */
48162306a36Sopenharmony_ci		if (!xflag) {
48262306a36Sopenharmony_ci			/* Extended mode not supported. */
48362306a36Sopenharmony_ci			pr_debug("%s: Extended mode 0x%02x not supported\n",
48462306a36Sopenharmony_ci				 port->name, mode);
48562306a36Sopenharmony_ci			parport_ieee1284_terminate (port);
48662306a36Sopenharmony_ci			return 1;
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		/* Any further setup is left to the caller. */
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	/* Mode is supported */
49362306a36Sopenharmony_ci	pr_debug("%s: In mode 0x%02x\n", port->name, mode);
49462306a36Sopenharmony_ci	port->ieee1284.mode = mode;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	/* But ECP is special */
49762306a36Sopenharmony_ci	if (!(mode & IEEE1284_EXT_LINK) && (m & IEEE1284_MODE_ECP)) {
49862306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		/* Event 30: Set nAutoFd low */
50162306a36Sopenharmony_ci		parport_frob_control (port,
50262306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD,
50362306a36Sopenharmony_ci				      PARPORT_CONTROL_AUTOFD);
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci		/* Event 31: PError goes high. */
50662306a36Sopenharmony_ci		r = parport_wait_peripheral (port,
50762306a36Sopenharmony_ci					     PARPORT_STATUS_PAPEROUT,
50862306a36Sopenharmony_ci					     PARPORT_STATUS_PAPEROUT);
50962306a36Sopenharmony_ci		if (r) {
51062306a36Sopenharmony_ci			pr_debug("%s: Timeout at event 31\n", port->name);
51162306a36Sopenharmony_ci		}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
51462306a36Sopenharmony_ci		pr_debug("%s: ECP direction: forward\n", port->name);
51562306a36Sopenharmony_ci	} else switch (mode) {
51662306a36Sopenharmony_ci	case IEEE1284_MODE_NIBBLE:
51762306a36Sopenharmony_ci	case IEEE1284_MODE_BYTE:
51862306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
51962306a36Sopenharmony_ci		break;
52062306a36Sopenharmony_ci	default:
52162306a36Sopenharmony_ci		port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return 0;
52662306a36Sopenharmony_ci#endif /* IEEE1284 support */
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/* Acknowledge that the peripheral has data available.
53062306a36Sopenharmony_ci * Events 18-20, in order to get from Reverse Idle phase
53162306a36Sopenharmony_ci * to Host Busy Data Available.
53262306a36Sopenharmony_ci * This will most likely be called from an interrupt.
53362306a36Sopenharmony_ci * Returns zero if data was available.
53462306a36Sopenharmony_ci */
53562306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
53662306a36Sopenharmony_cistatic int parport_ieee1284_ack_data_avail (struct parport *port)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	if (parport_read_status (port) & PARPORT_STATUS_ERROR)
53962306a36Sopenharmony_ci		/* Event 18 didn't happen. */
54062306a36Sopenharmony_ci		return -1;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* Event 20: nAutoFd goes high. */
54362306a36Sopenharmony_ci	port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
54462306a36Sopenharmony_ci	port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
54562306a36Sopenharmony_ci	return 0;
54662306a36Sopenharmony_ci}
54762306a36Sopenharmony_ci#endif /* IEEE1284 support */
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci/* Handle an interrupt. */
55062306a36Sopenharmony_civoid parport_ieee1284_interrupt (void *handle)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	struct parport *port = handle;
55362306a36Sopenharmony_ci	parport_ieee1284_wakeup (port);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284
55662306a36Sopenharmony_ci	if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
55762306a36Sopenharmony_ci		/* An interrupt in this phase means that data
55862306a36Sopenharmony_ci		 * is now available. */
55962306a36Sopenharmony_ci		pr_debug("%s: Data available\n", port->name);
56062306a36Sopenharmony_ci		parport_ieee1284_ack_data_avail (port);
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci#endif /* IEEE1284 support */
56362306a36Sopenharmony_ci}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci/**
56662306a36Sopenharmony_ci *	parport_write - write a block of data to a parallel port
56762306a36Sopenharmony_ci *	@port: port to write to
56862306a36Sopenharmony_ci *	@buffer: data buffer (in kernel space)
56962306a36Sopenharmony_ci *	@len: number of bytes of data to transfer
57062306a36Sopenharmony_ci *
57162306a36Sopenharmony_ci *	This will write up to @len bytes of @buffer to the port
57262306a36Sopenharmony_ci *	specified, using the IEEE 1284 transfer mode most recently
57362306a36Sopenharmony_ci *	negotiated to (using parport_negotiate()), as long as that
57462306a36Sopenharmony_ci *	mode supports forward transfers (host to peripheral).
57562306a36Sopenharmony_ci *
57662306a36Sopenharmony_ci *	It is the caller's responsibility to ensure that the first
57762306a36Sopenharmony_ci *	@len bytes of @buffer are valid.
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci *	This function returns the number of bytes transferred (if zero
58062306a36Sopenharmony_ci *	or positive), or else an error code.
58162306a36Sopenharmony_ci */
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cissize_t parport_write (struct parport *port, const void *buffer, size_t len)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
58662306a36Sopenharmony_ci	return port->ops->compat_write_data (port, buffer, len, 0);
58762306a36Sopenharmony_ci#else
58862306a36Sopenharmony_ci	ssize_t retval;
58962306a36Sopenharmony_ci	int mode = port->ieee1284.mode;
59062306a36Sopenharmony_ci	int addr = mode & IEEE1284_ADDR;
59162306a36Sopenharmony_ci	size_t (*fn) (struct parport *, const void *, size_t, int);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	/* Ignore the device-ID-request bit and the address bit. */
59462306a36Sopenharmony_ci	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* Use the mode we're in. */
59762306a36Sopenharmony_ci	switch (mode) {
59862306a36Sopenharmony_ci	case IEEE1284_MODE_NIBBLE:
59962306a36Sopenharmony_ci	case IEEE1284_MODE_BYTE:
60062306a36Sopenharmony_ci		parport_negotiate (port, IEEE1284_MODE_COMPAT);
60162306a36Sopenharmony_ci		fallthrough;
60262306a36Sopenharmony_ci	case IEEE1284_MODE_COMPAT:
60362306a36Sopenharmony_ci		pr_debug("%s: Using compatibility mode\n", port->name);
60462306a36Sopenharmony_ci		fn = port->ops->compat_write_data;
60562306a36Sopenharmony_ci		break;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	case IEEE1284_MODE_EPP:
60862306a36Sopenharmony_ci		pr_debug("%s: Using EPP mode\n", port->name);
60962306a36Sopenharmony_ci		if (addr) {
61062306a36Sopenharmony_ci			fn = port->ops->epp_write_addr;
61162306a36Sopenharmony_ci		} else {
61262306a36Sopenharmony_ci			fn = port->ops->epp_write_data;
61362306a36Sopenharmony_ci		}
61462306a36Sopenharmony_ci		break;
61562306a36Sopenharmony_ci	case IEEE1284_MODE_EPPSWE:
61662306a36Sopenharmony_ci		pr_debug("%s: Using software-emulated EPP mode\n", port->name);
61762306a36Sopenharmony_ci		if (addr) {
61862306a36Sopenharmony_ci			fn = parport_ieee1284_epp_write_addr;
61962306a36Sopenharmony_ci		} else {
62062306a36Sopenharmony_ci			fn = parport_ieee1284_epp_write_data;
62162306a36Sopenharmony_ci		}
62262306a36Sopenharmony_ci		break;
62362306a36Sopenharmony_ci	case IEEE1284_MODE_ECP:
62462306a36Sopenharmony_ci	case IEEE1284_MODE_ECPRLE:
62562306a36Sopenharmony_ci		pr_debug("%s: Using ECP mode\n", port->name);
62662306a36Sopenharmony_ci		if (addr) {
62762306a36Sopenharmony_ci			fn = port->ops->ecp_write_addr;
62862306a36Sopenharmony_ci		} else {
62962306a36Sopenharmony_ci			fn = port->ops->ecp_write_data;
63062306a36Sopenharmony_ci		}
63162306a36Sopenharmony_ci		break;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	case IEEE1284_MODE_ECPSWE:
63462306a36Sopenharmony_ci		pr_debug("%s: Using software-emulated ECP mode\n", port->name);
63562306a36Sopenharmony_ci		/* The caller has specified that it must be emulated,
63662306a36Sopenharmony_ci		 * even if we have ECP hardware! */
63762306a36Sopenharmony_ci		if (addr) {
63862306a36Sopenharmony_ci			fn = parport_ieee1284_ecp_write_addr;
63962306a36Sopenharmony_ci		} else {
64062306a36Sopenharmony_ci			fn = parport_ieee1284_ecp_write_data;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci		break;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	default:
64562306a36Sopenharmony_ci		pr_debug("%s: Unknown mode 0x%02x\n",
64662306a36Sopenharmony_ci			 port->name, port->ieee1284.mode);
64762306a36Sopenharmony_ci		return -ENOSYS;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	retval = (*fn) (port, buffer, len, 0);
65162306a36Sopenharmony_ci	pr_debug("%s: wrote %zd/%zu bytes\n", port->name, retval, len);
65262306a36Sopenharmony_ci	return retval;
65362306a36Sopenharmony_ci#endif /* IEEE1284 support */
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci/**
65762306a36Sopenharmony_ci *	parport_read - read a block of data from a parallel port
65862306a36Sopenharmony_ci *	@port: port to read from
65962306a36Sopenharmony_ci *	@buffer: data buffer (in kernel space)
66062306a36Sopenharmony_ci *	@len: number of bytes of data to transfer
66162306a36Sopenharmony_ci *
66262306a36Sopenharmony_ci *	This will read up to @len bytes of @buffer to the port
66362306a36Sopenharmony_ci *	specified, using the IEEE 1284 transfer mode most recently
66462306a36Sopenharmony_ci *	negotiated to (using parport_negotiate()), as long as that
66562306a36Sopenharmony_ci *	mode supports reverse transfers (peripheral to host).
66662306a36Sopenharmony_ci *
66762306a36Sopenharmony_ci *	It is the caller's responsibility to ensure that the first
66862306a36Sopenharmony_ci *	@len bytes of @buffer are available to write to.
66962306a36Sopenharmony_ci *
67062306a36Sopenharmony_ci *	This function returns the number of bytes transferred (if zero
67162306a36Sopenharmony_ci *	or positive), or else an error code.
67262306a36Sopenharmony_ci */
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cissize_t parport_read (struct parport *port, void *buffer, size_t len)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284
67762306a36Sopenharmony_ci	pr_err("parport: IEEE1284 not supported in this kernel\n");
67862306a36Sopenharmony_ci	return -ENODEV;
67962306a36Sopenharmony_ci#else
68062306a36Sopenharmony_ci	int mode = port->physport->ieee1284.mode;
68162306a36Sopenharmony_ci	int addr = mode & IEEE1284_ADDR;
68262306a36Sopenharmony_ci	size_t (*fn) (struct parport *, void *, size_t, int);
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* Ignore the device-ID-request bit and the address bit. */
68562306a36Sopenharmony_ci	mode &= ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/* Use the mode we're in. */
68862306a36Sopenharmony_ci	switch (mode) {
68962306a36Sopenharmony_ci	case IEEE1284_MODE_COMPAT:
69062306a36Sopenharmony_ci		/* if we can tri-state use BYTE mode instead of NIBBLE mode,
69162306a36Sopenharmony_ci		 * if that fails, revert to NIBBLE mode -- ought to store somewhere
69262306a36Sopenharmony_ci		 * the device's ability to do BYTE mode reverse transfers, so we don't
69362306a36Sopenharmony_ci		 * end up needlessly calling negotiate(BYTE) repeately..  (fb)
69462306a36Sopenharmony_ci		 */
69562306a36Sopenharmony_ci		if ((port->physport->modes & PARPORT_MODE_TRISTATE) &&
69662306a36Sopenharmony_ci		    !parport_negotiate (port, IEEE1284_MODE_BYTE)) {
69762306a36Sopenharmony_ci			/* got into BYTE mode OK */
69862306a36Sopenharmony_ci			pr_debug("%s: Using byte mode\n", port->name);
69962306a36Sopenharmony_ci			fn = port->ops->byte_read_data;
70062306a36Sopenharmony_ci			break;
70162306a36Sopenharmony_ci		}
70262306a36Sopenharmony_ci		if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) {
70362306a36Sopenharmony_ci			return -EIO;
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci		fallthrough;	/* to NIBBLE */
70662306a36Sopenharmony_ci	case IEEE1284_MODE_NIBBLE:
70762306a36Sopenharmony_ci		pr_debug("%s: Using nibble mode\n", port->name);
70862306a36Sopenharmony_ci		fn = port->ops->nibble_read_data;
70962306a36Sopenharmony_ci		break;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	case IEEE1284_MODE_BYTE:
71262306a36Sopenharmony_ci		pr_debug("%s: Using byte mode\n", port->name);
71362306a36Sopenharmony_ci		fn = port->ops->byte_read_data;
71462306a36Sopenharmony_ci		break;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	case IEEE1284_MODE_EPP:
71762306a36Sopenharmony_ci		pr_debug("%s: Using EPP mode\n", port->name);
71862306a36Sopenharmony_ci		if (addr) {
71962306a36Sopenharmony_ci			fn = port->ops->epp_read_addr;
72062306a36Sopenharmony_ci		} else {
72162306a36Sopenharmony_ci			fn = port->ops->epp_read_data;
72262306a36Sopenharmony_ci		}
72362306a36Sopenharmony_ci		break;
72462306a36Sopenharmony_ci	case IEEE1284_MODE_EPPSWE:
72562306a36Sopenharmony_ci		pr_debug("%s: Using software-emulated EPP mode\n", port->name);
72662306a36Sopenharmony_ci		if (addr) {
72762306a36Sopenharmony_ci			fn = parport_ieee1284_epp_read_addr;
72862306a36Sopenharmony_ci		} else {
72962306a36Sopenharmony_ci			fn = parport_ieee1284_epp_read_data;
73062306a36Sopenharmony_ci		}
73162306a36Sopenharmony_ci		break;
73262306a36Sopenharmony_ci	case IEEE1284_MODE_ECP:
73362306a36Sopenharmony_ci	case IEEE1284_MODE_ECPRLE:
73462306a36Sopenharmony_ci		pr_debug("%s: Using ECP mode\n", port->name);
73562306a36Sopenharmony_ci		fn = port->ops->ecp_read_data;
73662306a36Sopenharmony_ci		break;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	case IEEE1284_MODE_ECPSWE:
73962306a36Sopenharmony_ci		pr_debug("%s: Using software-emulated ECP mode\n", port->name);
74062306a36Sopenharmony_ci		fn = parport_ieee1284_ecp_read_data;
74162306a36Sopenharmony_ci		break;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	default:
74462306a36Sopenharmony_ci		pr_debug("%s: Unknown mode 0x%02x\n",
74562306a36Sopenharmony_ci			 port->name, port->physport->ieee1284.mode);
74662306a36Sopenharmony_ci		return -ENOSYS;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	return (*fn) (port, buffer, len, 0);
75062306a36Sopenharmony_ci#endif /* IEEE1284 support */
75162306a36Sopenharmony_ci}
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci/**
75462306a36Sopenharmony_ci *	parport_set_timeout - set the inactivity timeout for a device
75562306a36Sopenharmony_ci *	@dev: device on a port
75662306a36Sopenharmony_ci *	@inactivity: inactivity timeout (in jiffies)
75762306a36Sopenharmony_ci *
75862306a36Sopenharmony_ci *	This sets the inactivity timeout for a particular device on a
75962306a36Sopenharmony_ci *	port.  This affects functions like parport_wait_peripheral().
76062306a36Sopenharmony_ci *	The special value 0 means not to call schedule() while dealing
76162306a36Sopenharmony_ci *	with this device.
76262306a36Sopenharmony_ci *
76362306a36Sopenharmony_ci *	The return value is the previous inactivity timeout.
76462306a36Sopenharmony_ci *
76562306a36Sopenharmony_ci *	Any callers of parport_wait_event() for this device are woken
76662306a36Sopenharmony_ci *	up.
76762306a36Sopenharmony_ci */
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_cilong parport_set_timeout (struct pardevice *dev, long inactivity)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	long int old = dev->timeout;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	dev->timeout = inactivity;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (dev->port->physport->cad == dev)
77662306a36Sopenharmony_ci		parport_ieee1284_wakeup (dev->port);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return old;
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci/* Exported symbols for modules. */
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ciEXPORT_SYMBOL(parport_negotiate);
78462306a36Sopenharmony_ciEXPORT_SYMBOL(parport_write);
78562306a36Sopenharmony_ciEXPORT_SYMBOL(parport_read);
78662306a36Sopenharmony_ciEXPORT_SYMBOL(parport_wait_peripheral);
78762306a36Sopenharmony_ciEXPORT_SYMBOL(parport_wait_event);
78862306a36Sopenharmony_ciEXPORT_SYMBOL(parport_set_timeout);
78962306a36Sopenharmony_ciEXPORT_SYMBOL(parport_ieee1284_interrupt);
790