📄 ieee1284_ops.c
字号:
/* IEEE-1284 operations for parport. * * This file is for generic IEEE 1284 operations. The idea is that * they are used by the low-level drivers. If they have a special way * of doing something, they can provide their own routines (and put * the function pointers in port->ops); if not, they can just use these * as a fallback. * * Note: Make no assumptions about hardware or architecture in this file! * * Author: Tim Waugh <tim@cyberelk.demon.co.uk> * Fixed AUTOFD polarity in ecp_forward_to_reverse(). Fred Barnes, 1999 */#include <linux/config.h>#include <linux/parport.h>#include <linux/delay.h>#include <asm/uaccess.h>#define DEBUG /* undef me for production */#ifdef CONFIG_LP_CONSOLE#undef DEBUG /* Don't want a garbled console */#endif#ifdef DEBUG#define DPRINTK(stuff...) printk (stuff)#else#define DPRINTK(stuff...)#endif/*** * * One-way data transfer functions. * * ***//* Compatibility mode. */size_t parport_ieee1284_write_compat (struct parport *port, const void *buffer, size_t len, int flags){ int no_irq = 1; ssize_t count = 0; const unsigned char *addr = buffer; unsigned char byte; struct pardevice *dev = port->physport->cad; unsigned char ctl = (PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT); if (port->irq != PARPORT_IRQ_NONE) { parport_enable_irq (port); no_irq = 0; /* Clear out previous irqs. */ while (!down_trylock (&port->physport->ieee1284.irq)); } port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; parport_write_control (port, ctl); parport_data_forward (port); while (count < len) { long expire = jiffies + dev->timeout; long wait = (HZ + 99) / 100; unsigned char mask = (PARPORT_STATUS_ERROR | PARPORT_STATUS_BUSY); unsigned char val = (PARPORT_STATUS_ERROR | PARPORT_STATUS_BUSY); /* Wait until the peripheral's ready */ do { /* Is the peripheral ready yet? */ if (!parport_wait_peripheral (port, mask, val)) /* Skip the loop */ goto ready; /* Is the peripheral upset? */ if ((parport_read_status (port) & (PARPORT_STATUS_PAPEROUT | PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) /* If nFault is asserted (i.e. no * error) and PAPEROUT and SELECT are * just red herrings, give the driver * a chance to check it's happy with * that before continuing. */ goto stop; /* Have we run out of time? */ if (!time_before (jiffies, expire)) break; /* Yield the port for a while. If this is the first time around the loop, don't let go of the port. This way, we find out if we have our interrupt handler called. */ if (count && no_irq) { parport_release (dev); __set_current_state (TASK_INTERRUPTIBLE); schedule_timeout (wait); parport_claim_or_block (dev); } else /* We must have the device claimed here */ parport_wait_event (port, wait); /* Is there a signal pending? */ if (signal_pending (current)) break; /* Wait longer next time. */ wait *= 2; } while (time_before (jiffies, expire)); if (signal_pending (current)) break; DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name); break; ready: /* Write the character to the data lines. */ byte = *addr++; parport_write_data (port, byte); udelay (1); /* Pulse strobe. */ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE); udelay (1); /* strobe */ parport_write_control (port, ctl); udelay (1); /* hold */ /* Assume the peripheral received it. */ count++; /* Let another process run if it needs to. */ if (time_before (jiffies, expire)) if (!parport_yield_blocking (dev) && current->need_resched) schedule (); } stop: port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; return count;}/* Nibble mode. */size_t parport_ieee1284_read_nibble (struct parport *port, void *buffer, size_t len, int flags){#ifndef CONFIG_PARPORT_1284 return 0;#else unsigned char *buf = buffer; int i; unsigned char byte = 0; len *= 2; /* in nibbles */ for (i=0; i < len; i++) { unsigned char nibble; /* Does the error line indicate end of data? */ if (((i & 1) == 0) && (parport_read_status(port) & PARPORT_STATUS_ERROR)) { port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; DPRINTK (KERN_DEBUG "%s: No more nibble data (%d bytes)\n", port->name, i/2); /* Go to reverse idle phase. */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE; break; } /* Event 7: Set nAutoFd low. */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); /* Event 9: nAck goes low. */ port->ieee1284.phase = IEEE1284_PH_REV_DATA; if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { /* Timeout -- no more data? */ DPRINTK (KERN_DEBUG "%s: Nibble timeout at event 9 (%d bytes)\n", port->name, i/2); break; } /* Read a nibble. */ nibble = parport_read_status (port) >> 3; nibble &= ~8; if ((nibble & 0x10) == 0) nibble |= 8; nibble &= 0xf; /* Event 10: Set nAutoFd high. */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); /* Event 11: nAck goes high. */ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { /* Timeout -- no more data? */ DPRINTK (KERN_DEBUG "%s: Nibble timeout at event 11\n", port->name); break; } if (i & 1) { /* Second nibble */ byte |= nibble << 4; *buf++ = byte; } else byte = nibble; } i /= 2; /* i is now in bytes */ if (i == len) { /* Read the last nibble without checking data avail. */ port = port->physport; if (parport_read_status (port) & PARPORT_STATUS_ERROR) port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; else port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; } return i;#endif /* IEEE1284 support */}/* Byte mode. */size_t parport_ieee1284_read_byte (struct parport *port, void *buffer, size_t len, int flags){#ifndef CONFIG_PARPORT_1284 return 0;#else unsigned char *buf = buffer; ssize_t count = 0; for (count = 0; count < len; count++) { unsigned char byte; /* Data available? */ if (parport_read_status (port) & PARPORT_STATUS_ERROR) { port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; DPRINTK (KERN_DEBUG "%s: No more byte data (%Zd bytes)\n", port->name, count); /* Go to reverse idle phase. */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE; break; } /* Event 14: Place data bus in high impedance state. */ parport_data_reverse (port); /* Event 7: Set nAutoFd low. */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); /* Event 9: nAck goes low. */ port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA; if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { /* Timeout -- no more data? */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n", port->name); break; } byte = parport_read_data (port); *buf++ = byte; /* Event 10: Set nAutoFd high */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); /* Event 11: nAck goes high. */ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK)) { /* Timeout -- no more data? */ DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n", port->name); break; } /* Event 16: Set nStrobe low. */ parport_frob_control (port, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); udelay (5); /* Event 17: Set nStrobe high. */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); } if (count == len) { /* Read the last byte without checking data avail. */ port = port->physport; if (parport_read_status (port) & PARPORT_STATUS_ERROR) port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA; else port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; } return count;#endif /* IEEE1284 support */}/*** * * ECP Functions. * * ***/#ifdef CONFIG_PARPORT_1284static inlineint ecp_forward_to_reverse (struct parport *port){ int retval; /* Event 38: Set nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_AUTOFD); parport_data_reverse (port); udelay (5); /* Event 39: Set nInit low to initiate bus reversal */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); /* Event 40: PError goes low */ retval = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); if (!retval) { DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n", port->name); port->ieee1284.phase = IEEE1284_PH_REV_IDLE; } return retval;}static inlineint ecp_reverse_to_forward (struct parport *port){ int retval; /* Event 47: Set nInit high */ parport_frob_control (port, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD, PARPORT_CONTROL_INIT | PARPORT_CONTROL_AUTOFD); /* Event 49: PError goes high */ retval = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); if (!retval) { parport_data_forward (port); DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", port->name); port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; } return retval;}#endif /* IEEE1284 support *//* ECP mode, forward channel, data. */size_t parport_ieee1284_ecp_write_data (struct parport *port, const void *buffer, size_t len, int flags){#ifndef CONFIG_PARPORT_1284 return 0;#else const unsigned char *buf = buffer; size_t written; int retry; port = port->physport; if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) if (ecp_reverse_to_forward (port)) return 0; port->ieee1284.phase = IEEE1284_PH_FWD_DATA; /* HostAck high (data, not command) */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); for (written = 0; written < len; written++, buf++) { long expire = jiffies + port->cad->timeout; unsigned char byte; byte = *buf; try_again: parport_write_data (port, byte); parport_frob_control (port, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); udelay (5); for (retry = 0; retry < 100; retry++) { if (!parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) goto success; if (signal_pending (current)) { parport_frob_control (port,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -