Hi,
Here's a 2.4.4 version of the patch I sent earlier. In addition to
what was there before, I tweaked PARPORT_EPP_FAST to do 32-bit reads/
writes for data (if possible) and to not-go-fast in the 1-byte cases.
I've put support for fast reads/writes into the EPP address functions,
if this is meaningful in any way.
Chunk of drivers/parport/ChangeLog:
* parport_pc.c (parport_pc_epp_{read,write}_{data,addr}): support
for fast reads/writes using the PARPORT_EPP_FAST flag.
* ieee1284.c (parport_{read,write}): added code to handle software
EPP mode (IEEE1284_MODE_EPPSWE). Added code to allow BYTE mode
reverse transfers (previously always went for NIBBLE mode).
* ieee1284_ops.c (parport_ieee1284_epp_{read,write}_data): fixed
various polarity problems. Also (theoretically) fixed address
versions (.._addr), but no hardware to test this on.
* parport_pc.h: added parport_dump_state() function for debugging.
Needs to have DEBUG_PARPORT to be defined for it to be included.
Also for ppdev (no ChangeLog file for this I guess..?):
* various new IOCTLs added to ppdev, to:
- get hardware supported modes of parport
- get the current IEEE mode/phase
- enable/disable fast reads/writes as described above
* change in ppdev, so that if a device releases the port while
in non-compatability mode, it will be put back into compatability
mode when close()d. This caused some problems with our
hardware, as it was still in EPP/ECP the next time we ran the
client software.
Chunk from drivers/parport/BUGS-parport:
* parport_pc_ecp_read_block_pio() is broken. parport will revert
to the software-driven mode in ieee1284_ops.c
Cheers,
Fred.
--diff -u -p linux-2.4.4/CREDITS.orig linux-2.4.4/CREDITS --- linux-2.4.4/CREDITS.orig Sat Apr 28 14:15:04 2001 +++ linux-2.4.4/CREDITS Sat Apr 28 14:16:55 2001 @@ -221,6 +221,14 @@ S: ul. Koscielna 12a S: 62-300 Wrzesnia S: Poland +N: Fred Barnes +E: frmb2@ukc.ac.uk +D: Various parport/ppdev hacks and fixes +S: Computing Lab, The University +S: Canterbury, KENT +S: CT2 7NF +S: England + N: Paul Barton-Davis E: pbd@op.net D: Driver for WaveFront soundcards (Turtle Beach Maui, Tropez, Tropez+) @@ -1663,6 +1671,7 @@ S: Ecole Nationale Superieure des Teleco N: Jamie Lokier E: jamie@imbolc.ucc.ie D: Reboot-through-BIOS for broken 486 motherboards +D: Some parport fixes S: 11 Goodson Walk S: Marston S: Oxford diff -u -p linux-2.4.4/drivers/char/ppdev.c.orig linux-2.4.4/drivers/char/ppdev.c --- linux-2.4.4/drivers/char/ppdev.c.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/drivers/char/ppdev.c Sat Apr 28 14:16:55 2001 @@ -35,17 +35,25 @@ * WCTLONIRQ on interrupt, set control lines * CLRIRQ clear (and return) interrupt count * SETTIME sets device timeout (struct timeval) - * GETTIME gets device timeout (struct timeval) + * GETTIME gets device timeout (struct timeval) + * GETMODES gets hardware supported modes (unsigned int) + * GETMODE gets the current IEEE1284 mode + * GETPHASE gets the current IEEE1284 phase + * GETFLAGS gets current (user-visible) flags + * SETFLAGS sets current (user-visible) flags * read/write read or write in current IEEE 1284 protocol * select wait for interrupt (in readfds) * * Changes: - * Added SETTIME/GETTIME ioctl, Fred Barnes 1999. + * Added SETTIME/GETTIME ioctl, Fred Barnes, 1999. * * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 2000/08/25 * - On error, copy_from_user and copy_to_user do not return -EFAULT, * They return the positive number of bytes *not* copied due to address * space errors. + * + * Added GETMODES/GETMODE/GETPHASE ioctls, Fred Barnes <frmb2@ukc.ac.uk>, 03/01/2001. + * Added GETFLAGS/SETFLAGS ioctls, Fred Barnes, 04/2001 */ #include <linux/module.h> @@ -109,6 +117,8 @@ static ssize_t pp_read (struct file * fi char * kbuffer; ssize_t bytes_read = 0; ssize_t got = 0; + struct parport *pport; + int mode; if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ @@ -118,18 +128,32 @@ static ssize_t pp_read (struct file * fi } kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL); - if (!kbuffer) + if (!kbuffer) { return -ENOMEM; + } + pport = pp->pdev->port; + mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); while (bytes_read < count) { ssize_t need = min(count - bytes_read, PP_BUFFER_SIZE); - got = parport_read (pp->pdev->port, kbuffer, need); + if ((pp->flags & PP_FASTREAD) && (mode == IEEE1284_MODE_EPP)) { + /* do a fast EPP read */ + if (pport->ieee1284.mode & IEEE1284_ADDR) { + got = pport->ops->epp_read_addr (pport, kbuffer, + need, PARPORT_EPP_FAST); + } else { + got = pport->ops->epp_read_data (pport, kbuffer, + need, PARPORT_EPP_FAST); + } + } else { + got = parport_read (pport, kbuffer, need); + } if (got <= 0) { - if (!bytes_read) + if (!bytes_read) { bytes_read = got; - + } break; } @@ -141,13 +165,15 @@ static ssize_t pp_read (struct file * fi bytes_read += got; if (signal_pending (current)) { - if (!bytes_read) + if (!bytes_read) { bytes_read = -EINTR; + } break; } - if (current->need_resched) + if (current->need_resched) { schedule (); + } } kfree (kbuffer); @@ -163,6 +189,8 @@ static ssize_t pp_write (struct file * f char * kbuffer; ssize_t bytes_written = 0; ssize_t wrote; + int mode; + struct parport *pport; if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ @@ -172,8 +200,11 @@ static ssize_t pp_write (struct file * f } kbuffer = kmalloc (min (count, PP_BUFFER_SIZE), GFP_KERNEL); - if (!kbuffer) + if (!kbuffer) { return -ENOMEM; + } + pport = pp->pdev->port; + mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); while (bytes_written < count) { ssize_t n = min(count - bytes_written, PP_BUFFER_SIZE); @@ -183,24 +214,38 @@ static ssize_t pp_write (struct file * f break; } - wrote = parport_write (pp->pdev->port, kbuffer, n); + if ((pp->flags & PP_FASTWRITE) && (mode == IEEE1284_MODE_EPP)) { + /* do a fast EPP write */ + if (pport->ieee1284.mode & IEEE1284_ADDR) { + wrote = pport->ops->epp_write_addr (pport, + kbuffer, n, PARPORT_EPP_FAST); + } else { + wrote = pport->ops->epp_write_data (pport, + kbuffer, n, PARPORT_EPP_FAST); + } + } else { + wrote = parport_write (pp->pdev->port, kbuffer, n); + } if (wrote <= 0) { - if (!bytes_written) + if (!bytes_written) { bytes_written = wrote; + } break; } bytes_written += wrote; if (signal_pending (current)) { - if (!bytes_written) + if (!bytes_written) { bytes_written = -EINTR; + } break; } - if (current->need_resched) + if (current->need_resched) { schedule (); + } } kfree (kbuffer); @@ -276,7 +321,9 @@ static int pp_ioctl(struct inode *inode, struct parport * port; /* First handle the cases that don't take arguments. */ - if (cmd == PPCLAIM) { + switch (cmd) { + case PPCLAIM: + { struct ieee1284_info *info; if (pp->flags & PP_CLAIMED) { @@ -288,8 +335,9 @@ static int pp_ioctl(struct inode *inode, /* Deferred device registration. */ if (!pp->pdev) { int err = register_device (minor, pp); - if (err) + if (err) { return err; + } } parport_claim_or_block (pp->pdev); @@ -307,9 +355,8 @@ static int pp_ioctl(struct inode *inode, info->phase = pp->state.phase; return 0; - } - - if (cmd == PPEXCL) { + } + case PPEXCL: if (pp->pdev) { printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; " "already registered\n", minor); @@ -324,9 +371,8 @@ static int pp_ioctl(struct inode *inode, * when we finally do the registration. */ pp->flags |= PP_EXCL; return 0; - } - - if (cmd == PPSETMODE) { + case PPSETMODE: + { int mode; if (copy_from_user (&mode, (int *) arg, sizeof (mode))) return -EFAULT; @@ -340,20 +386,82 @@ static int pp_ioctl(struct inode *inode, } return 0; - } + } + case PPGETMODE: + { + int mode; - if (cmd == PPSETPHASE) { + if (pp->flags & PP_CLAIMED) { + mode = pp->pdev->port->ieee1284.mode; + } else { + mode = pp->state.mode; + } + if (copy_to_user ((int *)arg, &mode, sizeof (mode))) { + return -EFAULT; + } + return 0; + } + case PPSETPHASE: + { int phase; - if (copy_from_user (&phase, (int *) arg, sizeof (phase))) + if (copy_from_user (&phase, (int *) arg, sizeof (phase))) { return -EFAULT; + } /* FIXME: validate phase */ pp->state.phase = phase; - if (pp->flags & PP_CLAIMED) + if (pp->flags & PP_CLAIMED) { pp->pdev->port->ieee1284.phase = phase; + } return 0; - } + } + case PPGETPHASE: + { + int phase; + + if (pp->flags & PP_CLAIMED) { + phase = pp->pdev->port->ieee1284.phase; + } else { + phase = pp->state.phase; + } + if (copy_to_user ((int *)arg, &phase, sizeof (phase))) { + return -EFAULT; + } + return 0; + } + case PPGETMODES: + { + unsigned int modes; + + modes = pp->pdev->port->modes; + if (copy_to_user ((unsigned int *)arg, &modes, sizeof (port->modes))) { + return -EFAULT; + } + return 0; + } + case PPSETFLAGS: + { + int uflags; + + if (copy_from_user (&uflags, (int *)arg, sizeof (uflags))) { + return -EFAULT; + } + pp->flags &= ~PP_FLAGMASK; + pp->flags |= (uflags & PP_FLAGMASK); + return 0; + } + case PPGETFLAGS: + { + int uflags; + + uflags = pp->flags & PP_FLAGMASK; + if (copy_to_user ((int *)arg, &uflags, sizeof (uflags))) { + return -EFAULT; + } + return 0; + } + } /* end switch() */ /* Everything else requires the port to be claimed, so check * that now. */ @@ -537,13 +645,28 @@ static int pp_release (struct inode * in { unsigned int minor = MINOR (inode->i_rdev); struct pp_struct *pp = file->private_data; + int compat_negot; lock_kernel(); - if (pp->pdev && pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) { - if (!(pp->flags & PP_CLAIMED)) { - parport_claim_or_block (pp->pdev); - pp->flags |= PP_CLAIMED; - } + compat_negot = 0; + if (!(pp->flags & PP_CLAIMED) && pp->pdev && + (pp->state.mode != IEEE1284_MODE_COMPAT)) { + struct ieee1284_info *info; + + /* parport released, but not in compatability mode */ + parport_claim_or_block (pp->pdev); + pp->flags |= PP_CLAIMED; + info = &pp->pdev->port->ieee1284; + pp->saved_state.mode = info->mode; + pp->saved_state.phase = info->phase; + info->mode = pp->state.mode; + info->phase = pp->state.phase; + compat_negot = 1; + } else if ((pp->flags & PP_CLAIMED) && pp->pdev && + (pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT)) { + compat_negot = 2; + } + if (compat_negot) { parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT); printk (KERN_DEBUG CHRDEV "%x: negotiated back to compatibility mode because " @@ -551,9 +674,18 @@ static int pp_release (struct inode * in } if (pp->flags & PP_CLAIMED) { + struct ieee1284_info *info; + + info = &pp->pdev->port->ieee1284; + pp->state.mode = info->mode; + pp->state.phase = info->phase; + info->mode = pp->saved_state.mode; + info->phase = pp->saved_state.phase; parport_release (pp->pdev); - printk (KERN_DEBUG CHRDEV "%x: released pardevice because " - "user-space forgot\n", minor); + if (compat_negot != 1) { + printk (KERN_DEBUG CHRDEV "%x: released pardevice " + "because user-space forgot\n", minor); + } } if (pp->pdev) { diff -u -p linux-2.4.4/drivers/parport/BUGS-parport.orig linux-2.4.4/drivers/parport/BUGS-parport --- linux-2.4.4/drivers/parport/BUGS-parport.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/drivers/parport/BUGS-parport Sat Apr 28 14:16:55 2001 @@ -3,4 +3,7 @@ Currently known (or at least suspected) o lp doesn't allow you to read status while printing is in progress (is this still true?). +o parport_pc_ecp_read_block_pio() is broken. parport will revert to the + software-driven mode in ieee1284_ops.c + See <URL:http://people.redhat.com/twaugh/parport/>. diff -u -p linux-2.4.4/drivers/parport/ChangeLog.orig linux-2.4.4/drivers/parport/ChangeLog --- linux-2.4.4/drivers/parport/ChangeLog.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/drivers/parport/ChangeLog Sat Apr 28 14:24:35 2001 @@ -1,3 +1,19 @@ +2001-04-26 Fred Barnes <frmb2@ukc.ac.uk> + + * parport_pc.c (parport_pc_epp_{read,write}_{data,addr}): support + for fast reads/writes using the PARPORT_EPP_FAST flag. + + * ieee1284.c (parport_{read,write}): added code to handle software + EPP mode (IEEE1284_MODE_EPPSWE). Added code to allow BYTE mode + reverse transfers (previously always went for NIBBLE mode). + + * ieee1284_ops.c (parport_ieee1284_epp_{read,write}_data): fixed + various polarity problems. Also (theoretically) fixed address + versions (.._addr), but no hardware to test this on. + + * parport_pc.h: added parport_dump_state() function for debugging. + Needs to have DEBUG_PARPORT to be defined for it to be included. + 2001-04-20 Paul Gortmaker <p_gortmaker@yahoo.com> * parport_pc.c: Cut down the size quite a bit (more than 4k off diff -u -p linux-2.4.4/drivers/parport/ieee1284.c.orig linux-2.4.4/drivers/parport/ieee1284.c --- linux-2.4.4/drivers/parport/ieee1284.c.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/drivers/parport/ieee1284.c Sat Apr 28 14:16:55 2001 @@ -12,6 +12,8 @@ * Any part of this program may be used in documents licensed under * the GNU Free Documentation License, Version 1.1 or any later version * published by the Free Software Foundation. + * + * Various hacks, Fred Barnes <frmb2@ukc.ac.uk>, 04/2000 */ #include <linux/config.h> @@ -523,9 +525,10 @@ int parport_negotiate (struct parport *p r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) + if (r) { DPRINTK (KERN_INFO "%s: Timeout at event 31\n", - port->name); + port->name); + } port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n", @@ -593,7 +596,7 @@ void parport_ieee1284_interrupt (int whi * * It is the caller's responsibility to ensure that the first * @len bytes of @buffer are valid. - * + * * This function returns the number of bytes transferred (if zero * or positive), or else an error code. */ @@ -614,6 +617,7 @@ ssize_t parport_write (struct parport *p /* Use the mode we're in. */ switch (mode) { case IEEE1284_MODE_NIBBLE: + case IEEE1284_MODE_BYTE: parport_negotiate (port, IEEE1284_MODE_COMPAT); case IEEE1284_MODE_COMPAT: DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n", @@ -623,19 +627,29 @@ ssize_t parport_write (struct parport *p case IEEE1284_MODE_EPP: DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); - if (addr) + if (addr) { fn = port->ops->epp_write_addr; - else + } else { fn = port->ops->epp_write_data; + } + break; + case IEEE1284_MODE_EPPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated EPP mode\n", + port->name); + if (addr) { + fn = parport_ieee1284_epp_write_addr; + } else { + fn = parport_ieee1284_epp_write_data; + } break; - case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); - if (addr) + if (addr) { fn = port->ops->ecp_write_addr; - else + } else { fn = port->ops->ecp_write_data; + } break; case IEEE1284_MODE_ECPSWE: @@ -643,10 +657,11 @@ ssize_t parport_write (struct parport *p port->name); /* The caller has specified that it must be emulated, * even if we have ECP hardware! */ - if (addr) + if (addr) { fn = parport_ieee1284_ecp_write_addr; - else + } else { fn = parport_ieee1284_ecp_write_data; + } break; default: @@ -656,8 +671,7 @@ ssize_t parport_write (struct parport *p } retval = (*fn) (port, buffer, len, 0); - DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, - len); + DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval, len); return retval; #endif /* IEEE1284 support */ } @@ -696,8 +710,22 @@ ssize_t parport_read (struct parport *po /* Use the mode we're in. */ switch (mode) { case IEEE1284_MODE_COMPAT: - if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) + /* if we can tri-state use BYTE mode instead of NIBBLE mode, + * if that fails, revert to NIBBLE mode -- ought to store somewhere + * the device's ability to do BYTE mode reverse transfers, so we don't + * end up needlessly calling negotiate(BYTE) repeately.. (fb) + */ + if ((port->physport->modes & PARPORT_MODE_TRISTATE) && + !parport_negotiate (port, IEEE1284_MODE_BYTE)) { + /* got into BYTE mode OK */ + DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name); + fn = port->ops->byte_read_data; + break; + } + if (parport_negotiate (port, IEEE1284_MODE_NIBBLE)) { return -EIO; + } + /* fall through to NIBBLE */ case IEEE1284_MODE_NIBBLE: DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name); fn = port->ops->nibble_read_data; @@ -710,12 +738,21 @@ ssize_t parport_read (struct parport *po case IEEE1284_MODE_EPP: DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name); - if (addr) + if (addr) { fn = port->ops->epp_read_addr; - else + } else { fn = port->ops->epp_read_data; + } + break; + case IEEE1284_MODE_EPPSWE: + DPRINTK (KERN_DEBUG "%s: Using software-emulated EPP mode\n", + port->name); + if (addr) { + fn = parport_ieee1284_epp_read_addr; + } else { + fn = parport_ieee1284_epp_read_data; + } break; - case IEEE1284_MODE_ECP: case IEEE1284_MODE_ECPRLE: DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name); diff -u -p linux-2.4.4/drivers/parport/ieee1284_ops.c.orig linux-2.4.4/drivers/parport/ieee1284_ops.c --- linux-2.4.4/drivers/parport/ieee1284_ops.c.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/drivers/parport/ieee1284_ops.c Sat Apr 28 14:16:55 2001 @@ -10,6 +10,7 @@ * * 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. */ @@ -18,7 +19,7 @@ #include <linux/delay.h> #include <asm/uaccess.h> -#define DEBUG /* undef me for production */ +#undef DEBUG /* undef me for production */ #ifdef CONFIG_LP_CONSOLE #undef DEBUG /* Don't want a garbled console */ @@ -725,31 +726,32 @@ size_t parport_ieee1284_epp_write_data ( const void *buffer, size_t len, int flags) { - /* This is untested */ 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_SELECT | + PARPORT_CONTROL_INIT, PARPORT_CONTROL_STROBE | - PARPORT_CONTROL_SELECT); + PARPORT_CONTROL_INIT); port->ops->data_forward (port); for (; len > 0; len--, bp++) { - /* Event 62: Write data and strobe data */ + /* 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 */ + /* Event 58: wait for busy (nWait) to go high */ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 10)) break; - /* Event 63 */ + /* Event 63: set nAutoFd (nDStrb) high */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - /* Event 60 */ + /* Event 60: wait for busy (nWait) to go low */ if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, PARPORT_STATUS_BUSY, 5)) break; @@ -757,7 +759,7 @@ size_t parport_ieee1284_epp_write_data ( ret++; } - /* Event 61 */ + /* Event 61: set strobe (nWrite) high */ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0); return ret; @@ -768,29 +770,37 @@ size_t parport_ieee1284_epp_read_data (s void *buffer, size_t len, int flags) { - /* This is untested. */ 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_SELECT, 0); + PARPORT_CONTROL_AUTOFD | + PARPORT_CONTROL_SELECT | + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); port->ops->data_reverse (port); for (; len > 0; len--, bp++) { - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - - /* Event 58 */ - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, - PARPORT_STATUS_BUSY, 10)) + /* 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); - parport_frob_control (port, PARPORT_CONTROL_AUTOFD, - PARPORT_CONTROL_AUTOFD); + /* Event 63: set nAutoFd (nDStrb) high */ + parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0); - if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, 0, 5)) + /* Event 60: wait for Busy to go low */ + if (parport_poll_peripheral (port, PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY, 5)) { break; + } ret++; } @@ -873,3 +883,5 @@ size_t parport_ieee1284_epp_read_addr (s return ret; } + + diff -u -p linux-2.4.4/drivers/parport/parport_pc.c.orig linux-2.4.4/drivers/parport/parport_pc.c --- linux-2.4.4/drivers/parport/parport_pc.c.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/drivers/parport/parport_pc.c Sat Apr 28 14:41:13 2001 @@ -12,6 +12,7 @@ * DMA support - Bert De Jonghe <bert@sophis.be> * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. + * Various hacks, Fred Barnes, 04/2001 */ /* This driver should work with any hardware that is broadly compatible @@ -211,6 +212,7 @@ static int get_fifo_residue (struct parp /* Back to PS2 mode. */ frob_econtrol (p, 0xe0, ECR_PS2 << 5); + DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p))); return residue; } #endif /* IEEE 1284 support */ @@ -367,6 +369,19 @@ static size_t parport_pc_epp_read_data ( size_t length, int flags) { size_t got = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + if (!(((long)buf | length) & 0x03)) { + insl (EPPDATA (port), buf, (length >> 2)); + } else { + insb (EPPDATA (port), buf, length); + } + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; got < length; got++) { *((char*)buf)++ = inb (EPPDATA(port)); if (inb (STATUS(port)) & 0x01) { @@ -382,6 +397,19 @@ static size_t parport_pc_epp_write_data size_t length, int flags) { size_t written = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + if (!(((long)buf | length) & 0x03)) { + outsl (EPPDATA (port), buf, (length >> 2)); + } else { + outsb (EPPDATA (port), buf, length); + } + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; written < length; written++) { outb (*((char*)buf)++, EPPDATA(port)); if (inb (STATUS(port)) & 0x01) { @@ -397,6 +425,15 @@ static size_t parport_pc_epp_read_addr ( size_t length, int flags) { size_t got = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + insb (EPPADDR (port), buf, length); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; got < length; got++) { *((char*)buf)++ = inb (EPPADDR (port)); if (inb (STATUS (port)) & 0x01) { @@ -413,6 +450,15 @@ static size_t parport_pc_epp_write_addr int flags) { size_t written = 0; + + if ((flags & PARPORT_EPP_FAST) && (length > 1)) { + outsb (EPPADDR (port), buf, length); + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + return -EIO; + } + return length; + } for (; written < length; written++) { outb (*((char*)buf)++, EPPADDR (port)); if (inb (STATUS (port)) & 0x01) { @@ -590,6 +636,7 @@ static size_t parport_pc_fifo_write_bloc unsigned long start = (unsigned long) buf; unsigned long end = (unsigned long) buf + length - 1; +dump_parport_state ("enter fifo_write_block_dma", port); if (end < MAX_DMA_ADDRESS) { /* If it would cross a 64k boundary, cap it at the end. */ if ((start ^ end) & ~0xffffUL) @@ -608,7 +655,8 @@ static size_t parport_pc_fifo_write_bloc /* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); - frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ + /* set nErrIntrEn and serviceIntr */ + frob_econtrol (port, (1<<4) | (1<<2), (1<<4) | (1<<2)); /* Forward mode. */ parport_pc_data_forward (port); /* Must be in PS2 mode */ @@ -698,6 +746,7 @@ static size_t parport_pc_fifo_write_bloc if (dma_handle) pci_unmap_single(priv->dev, dma_handle, length, PCI_DMA_TODEVICE); +dump_parport_state ("leave fifo_write_block_dma", port); return length - left; } @@ -791,9 +840,10 @@ size_t parport_pc_ecp_write_block_pio (s r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) + if (r) { printk (KERN_DEBUG "%s: PError timeout (%d) " "in ecp_write_block_pio\n", port->name, r); + } } /* Set up ECP parallel port mode.*/ @@ -824,10 +874,10 @@ size_t parport_pc_ecp_write_block_pio (s /* Adjust for the contents of the FIFO. */ for (written -= priv->fifo_depth; ; written++) { - if (inb (ECONTROL (port)) & 0x2) + if (inb (ECONTROL (port)) & 0x2) { /* Full up. */ break; - + } outb (0, FIFO (port)); } @@ -879,58 +929,99 @@ size_t parport_pc_ecp_read_block_pio (st char *bufp = buf; port = port->physport; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n"); +dump_parport_state ("enter fcn", port); /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->cad->timeout) return parport_ieee1284_ecp_read_data (port, buf, length, flags); - fifofull = fifo_depth; - if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) + if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) { /* If the peripheral is allowed to send RLE compressed * data, it is possible for a byte to expand to 128 * bytes in the FIFO. */ fifofull = 128; + } else { + fifofull = fifo_depth; + } /* If the caller wants less than a full FIFO's worth of data, - * go through software emulation. Otherwise we may have to through + * go through software emulation. Otherwise we may have to throw * away data. */ if (length < fifofull) return parport_ieee1284_ecp_read_data (port, buf, length, flags); - /* Switch to reverse mode if necessary. */ - if ((port->ieee1284.phase != IEEE1284_PH_REV_IDLE) && - (port->ieee1284.phase != IEEE1284_PH_REV_DATA)) { - /* Event 38: Set nAutoFd low */ + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { + /* change to reverse-idle phase (must be in forward-idle) */ + + /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */ parport_frob_control (port, - PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD + | PARPORT_CONTROL_STROBE, PARPORT_CONTROL_AUTOFD); parport_pc_data_reverse (port); /* Must be in PS2 mode */ udelay (5); - /* Event 39: Set nInit low to initiate bus reversal */ parport_frob_control (port, PARPORT_CONTROL_INIT, 0); - - /* Event 40: PError goes low */ + /* Event 40: Wait for nAckReverse (PError) to go low */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); - if (r) + if (r) { printk (KERN_DEBUG "%s: PE timeout Event 40 (%d) " "in ecp_read_block_pio\n", port->name, r); + return 0; + } } /* Set up ECP FIFO mode.*/ - parport_pc_data_reverse (port); /* Must be in PS2 mode */ - parport_pc_frob_control (port, +/* parport_pc_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, - 0); + PARPORT_CONTROL_AUTOFD); */ r = change_mode (port, ECR_ECP); /* ECP FIFO */ if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); + port->ieee1284.phase = IEEE1284_PH_REV_DATA; + /* the first byte must be collected manually */ +dump_parport_state ("pre 43", port); + /* Event 43: Wait for nAck to go low */ + r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0); + if (r) { + /* timed out while reading -- no data */ + printk (KERN_DEBUG "PIO read timed out (initial byte)\n"); + goto out_no_data; + } + /* read byte */ + *bufp++ = inb (DATA (port)); + left--; +dump_parport_state ("43-44", port); + /* Event 44: nAutoFd (HostAck) goes high to acknowledge */ + parport_pc_frob_control (port, + PARPORT_CONTROL_AUTOFD, + 0); +dump_parport_state ("pre 45", port); + /* Event 45: Wait for nAck to go high */ +/* r = parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK); */ +dump_parport_state ("post 45", port); +r = 0; + if (r) { + /* timed out while waiting for peripheral to respond to ack */ + printk (KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n"); + + /* keep hold of the byte we've got already */ + goto out_no_data; + } + /* Event 46: nAutoFd (HostAck) goes low to accept more data */ + parport_pc_frob_control (port, + PARPORT_CONTROL_AUTOFD, + PARPORT_CONTROL_AUTOFD); + + +dump_parport_state ("rev idle", port); /* Do the transfer. */ while (left > fifofull) { int ret; @@ -949,31 +1040,35 @@ size_t parport_pc_ecp_read_block_pio (st if (ecrval & 0x01) { /* FIFO is empty. Wait for interrupt. */ +dump_parport_state ("FIFO empty", port); /* Anyone else waiting for the port? */ if (port->waithead) { - printk (KERN_DEBUG - "Somebody wants the port\n"); + printk (KERN_DEBUG "Somebody wants the port\n"); break; } /* Clear serviceIntr */ outb (ecrval & ~(1<<2), ECONTROL (port)); false_alarm: +dump_parport_state ("waiting", port); ret = parport_wait_event (port, HZ); - if (ret < 0) break; +DPRINTK (KERN_DEBUG "parport_wait_event returned %d\n", ret); + if (ret < 0) + break; ret = 0; if (!time_before (jiffies, expire)) { /* Timed out. */ +dump_parport_state ("timeout", port); printk (KERN_DEBUG "PIO read timed out\n"); break; } ecrval = inb (ECONTROL (port)); if (!(ecrval & (1<<2))) { if (current->need_resched && - time_before (jiffies, expire)) + time_before (jiffies, expire)) { schedule (); - + } goto false_alarm; } @@ -986,12 +1081,15 @@ size_t parport_pc_ecp_read_block_pio (st if (ecrval & 0x02) { /* FIFO is full. */ +dump_parport_state ("FIFO full", port); insb (fifo, bufp, fifo_depth); bufp += fifo_depth; left -= fifo_depth; continue; } +DPRINTK (KERN_DEBUG "*** ecp_read_block_pio: reading one byte from the FIFO\n"); + /* FIFO not filled. We will cycle this loop for a while * and either the peripheral will fill it faster, * tripping a fast empty with insb, or we empty it. */ @@ -999,17 +1097,29 @@ size_t parport_pc_ecp_read_block_pio (st left--; } + /* scoop up anything left in the FIFO */ + while (left && !(inb (ECONTROL (port) & 0x01))) { + *bufp++ = inb (fifo); + left--; + } + port->ieee1284.phase = IEEE1284_PH_REV_IDLE; +dump_parport_state ("rev idle2", port); - /* Go to forward idle mode to shut the peripheral up. */ - parport_frob_control (port, PARPORT_CONTROL_INIT, 0); +out_no_data: + + /* Go to forward idle mode to shut the peripheral up (event 47). */ + parport_frob_control (port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT); + + /* event 49: PError goes high */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); - if (r) + if (r) { printk (KERN_DEBUG "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n", port->name, r); + } port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; @@ -1022,13 +1132,21 @@ size_t parport_pc_ecp_read_block_pio (st port->name, lost); } +dump_parport_state ("fwd idle", port); return length - left; } #endif /* IEEE 1284 support */ - #endif /* Allowed to use FIFO/DMA */ + +/* + * ****************************************** + * INITIALISATION AND MODULE STUFF BELOW HERE + * ****************************************** + */ + + void parport_pc_inc_use_count(void) { #ifdef MODULE @@ -1930,10 +2048,11 @@ static int __devinit parport_irq_probe(s pb->irq = programmable_irq_support(pb); } - if (pb->modes & PARPORT_MODE_ECP) + if (pb->modes & PARPORT_MODE_ECP) { pb->irq = irq_probe_ECP(pb); + } - if (pb->irq == PARPORT_IRQ_NONE && priv->ecr && + if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr && (pb->modes & PARPORT_MODE_EPP)) pb->irq = irq_probe_EPP(pb); @@ -1978,11 +2097,12 @@ static int __devinit parport_dma_probe ( const struct parport_pc_private *priv = p->private_data; if (priv->ecr) p->dma = programmable_dma_support(p); /* ask ECP chipset first */ - if (p->dma == PARPORT_DMA_NONE) + if (p->dma == PARPORT_DMA_NONE) { /* ask known Super-IO chips proper, although these claim ECP compatible, some don't report their DMA conforming to ECP standards */ p->dma = get_superio_dma(p); + } return p->dma; } @@ -2092,6 +2212,8 @@ struct parport *parport_pc_probe_port (u p->ops->compat_write_data = parport_pc_compat_write_block_pio; #ifdef CONFIG_PARPORT_1284 p->ops->ecp_write_data = parport_pc_ecp_write_block_pio; + /* currently broken, but working on it.. (FB) */ + /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */ #endif /* IEEE 1284 support */ if (p->dma != PARPORT_DMA_NONE) { printk(", dma %d", p->dma); diff -u -p linux-2.4.4/include/linux/parport_pc.h.orig linux-2.4.4/include/linux/parport_pc.h --- linux-2.4.4/include/linux/parport_pc.h.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/include/linux/parport_pc.h Sat Apr 28 14:16:55 2001 @@ -59,6 +59,51 @@ extern __inline__ unsigned char parport_ return val; } +#ifdef DEBUG_PARPORT +extern __inline__ void dump_parport_state (char *str, struct parport *p) +{ + /* here's hoping that reading these ports won't side-effect anything underneath */ + unsigned char ecr = inb (ECONTROL (p)); + unsigned char dcr = inb (CONTROL (p)); + unsigned char dsr = inb (STATUS (p)); + static char *ecr_modes[] = {"SPP", "PS2", "PPFIFO", "ECP", "xXx", "yYy", "TST", "CFG"}; + const struct parport_pc_private *priv = (parport_pc_private *)p->physport->private_data; + int i; + + printk (KERN_DEBUG "*** parport state (%s): ecr=[%s", str, ecr_modes[(ecr & 0xe0) >> 5]); + if (ecr & 0x10) printk (",nErrIntrEn"); + if (ecr & 0x08) printk (",dmaEn"); + if (ecr & 0x04) printk (",serviceIntr"); + if (ecr & 0x02) printk (",f_full"); + if (ecr & 0x01) printk (",f_empty"); + for (i=0; i<2; i++) { + printk ("] dcr(%s)=[", i ? "soft" : "hard"); + dcr = i ? priv->ctr : inb (CONTROL (p)); + + if (dcr & 0x20) { + printk ("rev"); + } else { + printk ("fwd"); + } + if (dcr & 0x10) printk (",ackIntEn"); + if (!(dcr & 0x08)) printk (",N-SELECT-IN"); + if (dcr & 0x04) printk (",N-INIT"); + if (!(dcr & 0x02)) printk (",N-AUTOFD"); + if (!(dcr & 0x01)) printk (",N-STROBE"); + } + printk ("] dsr=["); + if (!(dsr & 0x80)) printk ("BUSY"); + if (dsr & 0x40) printk (",N-ACK"); + if (dsr & 0x20) printk (",PERROR"); + if (dsr & 0x10) printk (",SELECT"); + if (dsr & 0x08) printk (",N-FAULT"); + printk ("]\n"); + return; +} +#else /* !DEBUG_PARPORT */ +#define dump_parport_state(args...) +#endif /* !DEBUG_PARPORT */ + /* __parport_pc_frob_control differs from parport_pc_frob_control in that * it doesn't do any extra masking. */ static __inline__ unsigned char __parport_pc_frob_control (struct parport *p, diff -u -p linux-2.4.4/include/linux/ppdev.h.orig linux-2.4.4/include/linux/ppdev.h --- linux-2.4.4/include/linux/ppdev.h.orig Sat Apr 28 14:15:35 2001 +++ linux-2.4.4/include/linux/ppdev.h Sat Apr 28 14:16:55 2001 @@ -11,6 +11,7 @@ * 2 of the License, or (at your option) any later version. * * Added PPGETTIME/PPSETTIME, Fred Barnes, 1999 + * Added PPGETMODES/PPGETMODE/PPGETPHASE, Fred Barnes <frmb2@ukc.ac.uk>, 03/01/2001 */ #define PP_MAJOR 99 @@ -77,5 +78,23 @@ struct ppdev_frob_struct { /* Set and get port timeout (struct timeval's) */ #define PPGETTIME _IOR(PP_IOCTL, 0x95, struct timeval) #define PPSETTIME _IOW(PP_IOCTL, 0x96, struct timeval) + +/* Get available modes (what the hardware can do) */ +#define PPGETMODES _IOR(PP_IOCTL, 0x97, unsigned int) + +/* Get the current mode and phaze */ +#define PPGETMODE _IOR(PP_IOCTL, 0x98, int) +#define PPGETPHASE _IOR(PP_IOCTL, 0x99, int) + +/* get/set flags */ +#define PPGETFLAGS _IOR(PP_IOCTL, 0x9a, int) +#define PPSETFLAGS _IOW(PP_IOCTL, 0x9b, int) + +/* flags visible to the world */ +#define PP_FASTWRITE (1<<2) +#define PP_FASTREAD (1<<3) + +/* only masks user-visible flags */ +#define PP_FLAGMASK (PP_FASTWRITE | PP_FASTREAD)
-- To unsubscribe, send mail to: linux-parport-request@torque.net -- -- with the single word "unsubscribe" in the body of the message. --
This archive was generated by hypermail 2b29 : Sat Apr 28 2001 - 11:32:54 EDT