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