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