| /* 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 | |
| * Software emulated EPP fixes, Fred Barnes, 04/2001. | |
| */ | |
| #include <linux/module.h> | |
| #include <linux/parport.h> | |
| #include <linux/delay.h> | |
| #include <linux/sched.h> | |
| #include <asm/uaccess.h> | |
| #undef 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; | |
| } | |
| port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; | |
| parport_write_control (port, ctl); | |
| parport_data_forward (port); | |
| while (count < len) { | |
| unsigned long expire = jiffies + dev->timeout; | |
| long wait = msecs_to_jiffies(10); | |
| 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); | |
| schedule_timeout_interruptible(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) | |
| && 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)) { | |
| goto end_of_data; | |
| } | |
| /* 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); | |
| parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); | |
| 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; | |
| } | |
| if (i == len) { | |
| /* Read the last nibble without checking data avail. */ | |
| if (parport_read_status (port) & PARPORT_STATUS_ERROR) { | |
| end_of_data: | |
| 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; | |
| } | |
| else | |
| port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; | |
| } | |
| return i/2; | |
| #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) { | |
| goto end_of_data; | |
| } | |
| /* 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. */ | |
| if (parport_read_status (port) & PARPORT_STATUS_ERROR) { | |
| end_of_data: | |
| 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; | |
| } | |
| else | |
| port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL; | |
| } | |
| return count; | |
| #endif /* IEEE1284 support */ | |
| } | |
| /*** * | |
| * ECP Functions. * | |
| * ***/ | |
| #ifdef CONFIG_PARPORT_1284 | |
| static inline | |
| int 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; | |
| } else { | |
| DPRINTK (KERN_DEBUG "%s: ECP direction: failed to reverse\n", | |
| port->name); | |
| port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN; | |
| } | |
| return retval; | |
| } | |
| static inline | |
| int 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; | |
| } else { | |
| DPRINTK (KERN_DEBUG | |
| "%s: ECP direction: failed to switch forward\n", | |
| port->name); | |
| port->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN; | |
| } | |
| 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++) { | |
| unsigned 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, | |
| PARPORT_CONTROL_STROBE, | |
| 0); | |
| break; | |
| } | |
| } | |
| /* Time for Host Transfer Recovery (page 41 of IEEE1284) */ | |
| DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name); | |
| parport_frob_control (port, PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_INIT); | |
| udelay (50); | |
| if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) { | |
| /* It's buggered. */ | |
| parport_frob_control (port, PARPORT_CONTROL_INIT, 0); | |
| break; | |
| } | |
| parport_frob_control (port, PARPORT_CONTROL_INIT, 0); | |
| udelay (50); | |
| if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT)) | |
| break; | |
| DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n", | |
| port->name); | |
| if (time_after_eq (jiffies, expire)) break; | |
| goto try_again; | |
| success: | |
| parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); | |
| udelay (5); | |
| if (parport_wait_peripheral (port, | |
| PARPORT_STATUS_BUSY, | |
| PARPORT_STATUS_BUSY)) | |
| /* Peripheral hasn't accepted the data. */ | |
| break; | |
| } | |
| port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; | |
| return written; | |
| #endif /* IEEE1284 support */ | |
| } | |
| /* ECP mode, reverse channel, data. */ | |
| size_t parport_ieee1284_ecp_read_data (struct parport *port, | |
| void *buffer, size_t len, int flags) | |
| { | |
| #ifndef CONFIG_PARPORT_1284 | |
| return 0; | |
| #else | |
| struct pardevice *dev = port->cad; | |
| unsigned char *buf = buffer; | |
| int rle_count = 0; /* shut gcc up */ | |
| unsigned char ctl; | |
| int rle = 0; | |
| ssize_t count = 0; | |
| port = port->physport; | |
| if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) | |
| if (ecp_forward_to_reverse (port)) | |
| return 0; | |
| port->ieee1284.phase = IEEE1284_PH_REV_DATA; | |
| /* Set HostAck low to start accepting data. */ | |
| ctl = parport_read_control (port); | |
| ctl &= ~(PARPORT_CONTROL_STROBE | PARPORT_CONTROL_INIT | | |
| PARPORT_CONTROL_AUTOFD); | |
| parport_write_control (port, | |
| ctl | PARPORT_CONTROL_AUTOFD); | |
| while (count < len) { | |
| unsigned long expire = jiffies + dev->timeout; | |
| unsigned char byte; | |
| int command; | |
| /* Event 43: Peripheral sets nAck low. It can take as | |
| long as it wants. */ | |
| while (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) { | |
| /* The peripheral hasn't given us data in | |
| 35ms. If we have data to give back to the | |
| caller, do it now. */ | |
| if (count) | |
| goto out; | |
| /* If we've used up all the time we were allowed, | |
| give up altogether. */ | |
| if (!time_before (jiffies, expire)) | |
| goto out; | |
| /* Yield the port for a while. */ | |
| if (count && dev->port->irq != PARPORT_IRQ_NONE) { | |
| parport_release (dev); | |
| schedule_timeout_interruptible(msecs_to_jiffies(40)); | |
| parport_claim_or_block (dev); | |
| } | |
| else | |
| /* We must have the device claimed here. */ | |
| parport_wait_event (port, msecs_to_jiffies(40)); | |
| /* Is there a signal pending? */ | |
| if (signal_pending (current)) | |
| goto out; | |
| } | |
| /* Is this a command? */ | |
| if (rle) | |
| /* The last byte was a run-length count, so | |
| this can't be as well. */ | |
| command = 0; | |
| else | |
| command = (parport_read_status (port) & | |
| PARPORT_STATUS_BUSY) ? 1 : 0; | |
| /* Read the data. */ | |
| byte = parport_read_data (port); | |
| /* If this is a channel command, rather than an RLE | |
| command or a normal data byte, don't accept it. */ | |
| if (command) { | |
| if (byte & 0x80) { | |
| DPRINTK (KERN_DEBUG "%s: stopping short at " | |
| "channel command (%02x)\n", | |
| port->name, byte); | |
| goto out; | |
| } | |
| else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE) | |
| DPRINTK (KERN_DEBUG "%s: device illegally " | |
| "using RLE; accepting anyway\n", | |
| port->name); | |
| rle_count = byte + 1; | |
| /* Are we allowed to read that many bytes? */ | |
| if (rle_count > (len - count)) { | |
| DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes " | |
| "for next time\n", port->name, | |
| rle_count); | |
| break; | |
| } | |
| rle = 1; | |
| } | |
| /* Event 44: Set HostAck high, acknowledging handshake. */ | |
| parport_write_control (port, ctl); | |
| /* Event 45: The peripheral has 35ms to set nAck high. */ | |
| if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, | |
| PARPORT_STATUS_ACK)) { | |
| /* It's gone wrong. Return what data we have | |
| to the caller. */ | |
| DPRINTK (KERN_DEBUG "ECP read timed out at 45\n"); | |
| if (command) | |
| printk (KERN_WARNING | |
| "%s: command ignored (%02x)\n", | |
| port->name, byte); | |
| break; | |
| } | |
| /* Event 46: Set HostAck low and accept the data. */ | |
| parport_write_control (port, | |
| ctl | PARPORT_CONTROL_AUTOFD); | |
| /* If we just read a run-length count, fetch the data. */ | |
| if (command) | |
| continue; | |
| /* If this is the byte after a run-length count, decompress. */ | |
| if (rle) { | |
| rle = 0; | |
| memset (buf, byte, rle_count); | |
| buf += rle_count; | |
| count += rle_count; | |
| DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n", | |
| port->name, rle_count); | |
| } else { | |
| /* Normal data byte. */ | |
| *buf = byte; | |
| buf++, count++; | |
| } | |
| } | |
| out: | |
| port->ieee1284.phase = IEEE1284_PH_REV_IDLE; | |
| return count; | |
| #endif /* IEEE1284 support */ | |
| } | |
| /* ECP mode, forward channel, commands. */ | |
| size_t parport_ieee1284_ecp_write_addr (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 low (command, not data) */ | |
| parport_frob_control (port, | |
| PARPORT_CONTROL_AUTOFD | |
| | PARPORT_CONTROL_STROBE | |
| | PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_AUTOFD | |
| | PARPORT_CONTROL_INIT); | |
| for (written = 0; written < len; written++, buf++) { | |
| unsigned 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, | |
| PARPORT_CONTROL_STROBE, | |
| 0); | |
| break; | |
| } | |
| } | |
| /* Time for Host Transfer Recovery (page 41 of IEEE1284) */ | |
| DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name); | |
| parport_frob_control (port, PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_INIT); | |
| udelay (50); | |
| if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) { | |
| /* It's buggered. */ | |
| parport_frob_control (port, PARPORT_CONTROL_INIT, 0); | |
| break; | |
| } | |
| parport_frob_control (port, PARPORT_CONTROL_INIT, 0); | |
| udelay (50); | |
| if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT)) | |
| break; | |
| DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n", | |
| port->name); | |
| if (time_after_eq (jiffies, expire)) break; | |
| goto try_again; | |
| success: | |
| parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); | |
| udelay (5); | |
| if (parport_wait_peripheral (port, | |
| PARPORT_STATUS_BUSY, | |
| PARPORT_STATUS_BUSY)) | |
| /* Peripheral hasn't accepted the data. */ | |
| break; | |
| } | |
| port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; | |
| return written; | |
| #endif /* IEEE1284 support */ | |
| } | |
| /*** * | |
| * EPP functions. * | |
| * ***/ | |
| /* EPP mode, forward channel, data. */ | |
| size_t parport_ieee1284_epp_write_data (struct parport *port, | |
| const void *buffer, size_t len, | |
| int flags) | |
| { | |
| unsigned char *bp = (unsigned char *) buffer; | |
| size_t ret = 0; | |
| /* set EPP idle state (just to make sure) with strobe low */ | |
| parport_frob_control (port, | |
| PARPORT_CONTROL_STROBE | | |
| PARPORT_CONTROL_AUTOFD | | |
| PARPORT_CONTROL_SELECT | | |
| PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_STROBE | | |
| PARPORT_CONTROL_INIT); | |
| port->ops->data_forward (port); | |
| for (; len > 0; len--, bp++) { | |
| /* Event 62: Write data and set autofd low */ | |
| parport_write_data (port, *bp); | |
| parport_frob_control (port, PARPORT_CONTROL_AUTOFD, | |
| PARPORT_CONTROL_AUTOFD); | |
| /* Event 58: wait for busy (nWait) to go high */ | |
| if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) | |
| break; | |
| /* Event 63: set nAutoFd (nDStrb) high */ | |
| parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); | |
| /* Event 60: wait for busy (nWait) to go low */ | |
| if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, | |
| PARPORT_STATUS_BUSY, 5)) | |
| break; | |
| ret++; | |
| } | |
| /* Event 61: set strobe (nWrite) high */ | |
| parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); | |
| return ret; | |
| } | |
| /* EPP mode, reverse channel, data. */ | |
| size_t parport_ieee1284_epp_read_data (struct parport *port, | |
| void *buffer, size_t len, | |
| int flags) | |
| { | |
| unsigned char *bp = (unsigned char *) buffer; | |
| unsigned ret = 0; | |
| /* set EPP idle state (just to make sure) with strobe high */ | |
| parport_frob_control (port, | |
| PARPORT_CONTROL_STROBE | | |
| PARPORT_CONTROL_AUTOFD | | |
| PARPORT_CONTROL_SELECT | | |
| PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_INIT); | |
| port->ops->data_reverse (port); | |
| for (; len > 0; len--, bp++) { | |
| /* Event 67: set nAutoFd (nDStrb) low */ | |
| parport_frob_control (port, | |
| PARPORT_CONTROL_AUTOFD, | |
| PARPORT_CONTROL_AUTOFD); | |
| /* Event 58: wait for Busy to go high */ | |
| if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) { | |
| break; | |
| } | |
| *bp = parport_read_data (port); | |
| /* Event 63: set nAutoFd (nDStrb) high */ | |
| parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); | |
| /* Event 60: wait for Busy to go low */ | |
| if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, | |
| PARPORT_STATUS_BUSY, 5)) { | |
| break; | |
| } | |
| ret++; | |
| } | |
| port->ops->data_forward (port); | |
| return ret; | |
| } | |
| /* EPP mode, forward channel, addresses. */ | |
| size_t parport_ieee1284_epp_write_addr (struct parport *port, | |
| const void *buffer, size_t len, | |
| int flags) | |
| { | |
| unsigned char *bp = (unsigned char *) buffer; | |
| size_t ret = 0; | |
| /* set EPP idle state (just to make sure) with strobe low */ | |
| parport_frob_control (port, | |
| PARPORT_CONTROL_STROBE | | |
| PARPORT_CONTROL_AUTOFD | | |
| PARPORT_CONTROL_SELECT | | |
| PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_STROBE | | |
| PARPORT_CONTROL_INIT); | |
| port->ops->data_forward (port); | |
| for (; len > 0; len--, bp++) { | |
| /* Event 56: Write data and set nAStrb low. */ | |
| parport_write_data (port, *bp); | |
| parport_frob_control (port, PARPORT_CONTROL_SELECT, | |
| PARPORT_CONTROL_SELECT); | |
| /* Event 58: wait for busy (nWait) to go high */ | |
| if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) | |
| break; | |
| /* Event 59: set nAStrb high */ | |
| parport_frob_control (port, PARPORT_CONTROL_SELECT, 0); | |
| /* Event 60: wait for busy (nWait) to go low */ | |
| if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, | |
| PARPORT_STATUS_BUSY, 5)) | |
| break; | |
| ret++; | |
| } | |
| /* Event 61: set strobe (nWrite) high */ | |
| parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); | |
| return ret; | |
| } | |
| /* EPP mode, reverse channel, addresses. */ | |
| size_t parport_ieee1284_epp_read_addr (struct parport *port, | |
| void *buffer, size_t len, | |
| int flags) | |
| { | |
| unsigned char *bp = (unsigned char *) buffer; | |
| unsigned ret = 0; | |
| /* Set EPP idle state (just to make sure) with strobe high */ | |
| parport_frob_control (port, | |
| PARPORT_CONTROL_STROBE | | |
| PARPORT_CONTROL_AUTOFD | | |
| PARPORT_CONTROL_SELECT | | |
| PARPORT_CONTROL_INIT, | |
| PARPORT_CONTROL_INIT); | |
| port->ops->data_reverse (port); | |
| for (; len > 0; len--, bp++) { | |
| /* Event 64: set nSelectIn (nAStrb) low */ | |
| parport_frob_control (port, PARPORT_CONTROL_SELECT, | |
| PARPORT_CONTROL_SELECT); | |
| /* Event 58: wait for Busy to go high */ | |
| if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0)) { | |
| break; | |
| } | |
| *bp = parport_read_data (port); | |
| /* Event 59: set nSelectIn (nAStrb) high */ | |
| parport_frob_control (port, PARPORT_CONTROL_SELECT, | |
| 0); | |
| /* Event 60: wait for Busy to go low */ | |
| if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, | |
| PARPORT_STATUS_BUSY, 5)) | |
| break; | |
| ret++; | |
| } | |
| port->ops->data_forward (port); | |
| return ret; | |
| } | |
| EXPORT_SYMBOL(parport_ieee1284_ecp_write_data); | |
| EXPORT_SYMBOL(parport_ieee1284_ecp_read_data); | |
| EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr); | |
| EXPORT_SYMBOL(parport_ieee1284_write_compat); | |
| EXPORT_SYMBOL(parport_ieee1284_read_nibble); | |
| EXPORT_SYMBOL(parport_ieee1284_read_byte); | |
| EXPORT_SYMBOL(parport_ieee1284_epp_write_data); | |
| EXPORT_SYMBOL(parport_ieee1284_epp_read_data); | |
| EXPORT_SYMBOL(parport_ieee1284_epp_write_addr); | |
| EXPORT_SYMBOL(parport_ieee1284_epp_read_addr); |