[PARPORT] various fixes/additions to parport (2.4.0)

From: Fred Barnes (frmb2@ukc.ac.uk)
Date: Thu Feb 08 2001 - 09:18:59 EST

  • Next message: Edith Giohanna Mendez Patarroyo: "[PARPORT] CD HP7200e in HP Vectra VE"

    Hi Tim,

    Here's a patch against the 2.4.0 parport code which fixes some bugs that
    were present. Appologies for the large amount of un-necessary debugging
    crap in this, but I'm still poking around with it..

    Regards,
      Fred

    -- 
    Fred Barnes, PhD research student, UKC.   http://frmb.home.cern.ch/frmb/
    frmb2@ukc.ac.uk                http://www.cs.ukc.ac.uk/people/rpg/frmb2/
    

    diff -u -p linux.2.4.0/CREDITS.orig linux.2.4.0/CREDITS --- linux.2.4.0/CREDITS.orig Fri Jan 5 03:02:27 2001 +++ linux.2.4.0/CREDITS Fri Jan 5 03:03:43 2001 @@ -193,6 +193,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+) @@ -1595,6 +1603,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.0/drivers/char/ppdev.c.orig linux.2.4.0/drivers/char/ppdev.c --- linux.2.4.0/drivers/char/ppdev.c.orig Fri Jan 5 03:02:39 2001 +++ linux.2.4.0/drivers/char/ppdev.c Sat Jan 6 13:33:09 2001 @@ -35,17 +35,22 @@ * 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 * 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. */ #include <linux/module.h> @@ -342,6 +347,20 @@ static int pp_ioctl(struct inode *inode, return 0; } + if (cmd == PPGETMODE) { + int mode; + + 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; + } + if (cmd == PPSETPHASE) { int phase; if (copy_from_user (&phase, (int *) arg, sizeof (phase))) @@ -355,6 +374,30 @@ static int pp_ioctl(struct inode *inode, return 0; } + if (cmd == 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; + } + + if (cmd == PPGETMODES) { + unsigned int modes; + + modes = pp->pdev->port->modes; + if (copy_to_user ((unsigned int *)arg, &modes, sizeof (port->modes))) { + return -EFAULT; + } + return 0; + } + /* Everything else requires the port to be claimed, so check * that now. */ if ((pp->flags & PP_CLAIMED) == 0) { @@ -537,13 +580,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 +609,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.0/drivers/parport/ieee1284.c.orig linux.2.4.0/drivers/parport/ieee1284.c --- linux.2.4.0/drivers/parport/ieee1284.c.orig Fri Jan 5 03:02:46 2001 +++ linux.2.4.0/drivers/parport/ieee1284.c Sun Jan 7 23:48:35 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>, 03/01/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", @@ -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", @@ -628,7 +632,15 @@ ssize_t parport_write (struct parport *p 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); @@ -696,8 +708,17 @@ ssize_t parport_read (struct parport *po /* Use the mode we're in. */ switch (mode) { case IEEE1284_MODE_COMPAT: + /* if we can tri-state use BYTE mode instead of NIBBLE mode, + if that fails, revert to NIBBLE mode */ + 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; @@ -715,7 +736,15 @@ ssize_t parport_read (struct parport *po 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.0/drivers/parport/ieee1284_ops.c.orig linux.2.4.0/drivers/parport/ieee1284_ops.c --- linux.2.4.0/drivers/parport/ieee1284_ops.c.orig Fri Jan 5 03:02:55 2001 +++ linux.2.4.0/drivers/parport/ieee1284_ops.c Sun Jan 7 23:48:52 2001 @@ -18,7 +18,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 */ @@ -47,6 +47,7 @@ size_t parport_ieee1284_write_compat (st unsigned char ctl = (PARPORT_CONTROL_SELECT | PARPORT_CONTROL_INIT); +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_write_compat\n"); if (port->irq != PARPORT_IRQ_NONE) { parport_enable_irq (port); no_irq = 0; @@ -159,6 +160,7 @@ size_t parport_ieee1284_read_nibble (str int i; unsigned char byte = 0; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_read_nibble\n"); len *= 2; /* in nibbles */ for (i=0; i < len; i++) { unsigned char nibble; @@ -251,6 +253,7 @@ size_t parport_ieee1284_read_byte (struc unsigned char *buf = buffer; ssize_t count = 0; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_read_byte\n"); for (count = 0; count < len; count++) { unsigned char byte; @@ -406,6 +409,7 @@ size_t parport_ieee1284_ecp_write_data ( size_t written; int retry; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_ecp_write_data\n"); port = port->physport; if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) @@ -496,6 +500,7 @@ size_t parport_ieee1284_ecp_read_data (s port = port->physport; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_ecp_read_data\n"); if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) if (ecp_forward_to_reverse (port)) return 0; @@ -642,6 +647,7 @@ size_t parport_ieee1284_ecp_write_addr ( size_t written; int retry; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_ecp_write_addr\n"); port = port->physport; if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE) @@ -731,6 +737,7 @@ size_t parport_ieee1284_epp_write_data ( unsigned char *bp = (unsigned char *) buffer; size_t ret = 0; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_epp_write_data\n"); parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD | @@ -774,6 +781,7 @@ size_t parport_ieee1284_epp_read_data (s unsigned char *bp = (unsigned char *) buffer; unsigned ret = 0; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_epp_read_data\n"); parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_SELECT, 0); @@ -810,6 +818,7 @@ size_t parport_ieee1284_epp_write_addr ( unsigned char *bp = (unsigned char *) buffer; size_t ret = 0; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_epp_write_addr\n"); parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_SELECT | @@ -849,6 +858,7 @@ size_t parport_ieee1284_epp_read_addr (s unsigned char *bp = (unsigned char *) buffer; unsigned ret = 0; +DPRINTK (KERN_DEBUG "ieee1284_ops: parport_ieee1284_epp_read_addr\n"); parport_frob_control (port, PARPORT_CONTROL_STROBE | PARPORT_CONTROL_AUTOFD, 0); diff -u -p linux.2.4.0/drivers/parport/parport_pc.c.orig linux.2.4.0/drivers/parport/parport_pc.c --- linux.2.4.0/drivers/parport/parport_pc.c.orig Fri Jan 5 03:03:04 2001 +++ linux.2.4.0/drivers/parport/parport_pc.c Sun Jan 7 23:48:22 2001 @@ -191,7 +191,7 @@ static int get_fifo_residue (struct parp residue); /* Reset the FIFO. */ - frob_econtrol (p, 0xe0, ECR_PS2 << 5); + frob_econtrol (p, 0xe0, ECR_SPP << 5); /* Now change to config mode and clean up. FIXME */ frob_econtrol (p, 0xe0, ECR_CNF << 5); @@ -209,6 +209,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 */ @@ -364,6 +365,7 @@ static size_t parport_pc_epp_read_data ( size_t length, int flags) { size_t got = 0; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_epp_read_data\n"); for (; got < length; got++) { *((char*)buf)++ = inb (EPPDATA(port)); if (inb (STATUS(port)) & 0x01) { @@ -379,6 +381,7 @@ static size_t parport_pc_epp_write_data size_t length, int flags) { size_t written = 0; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_epp_write_data\n"); for (; written < length; written++) { outb (*((char*)buf)++, EPPDATA(port)); if (inb (STATUS(port)) & 0x01) { @@ -394,6 +397,7 @@ static size_t parport_pc_epp_read_addr ( size_t length, int flags) { size_t got = 0; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_epp_read_addr\n"); for (; got < length; got++) { *((char*)buf)++ = inb (EPPADDR (port)); if (inb (STATUS (port)) & 0x01) { @@ -410,6 +414,7 @@ static size_t parport_pc_epp_write_addr int flags) { size_t written = 0; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_epp_write_addr\n"); for (; written < length; written++) { outb (*((char*)buf)++, EPPADDR (port)); if (inb (STATUS (port)) & 0x01) { @@ -426,6 +431,7 @@ static size_t parport_pc_ecpepp_read_dat { size_t got; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecpepp_read_data\n"); frob_econtrol (port, 0xe0, ECR_EPP << 5); parport_pc_data_reverse (port); parport_pc_write_control (port, 0x4); @@ -441,6 +447,7 @@ static size_t parport_pc_ecpepp_write_da { size_t written; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecpepp_write_data\n"); frob_econtrol (port, 0xe0, ECR_EPP << 5); parport_pc_write_control (port, 0x4); parport_pc_data_forward (port); @@ -455,6 +462,7 @@ static size_t parport_pc_ecpepp_read_add { size_t got; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecpepp_read_addr\n"); frob_econtrol (port, 0xe0, ECR_EPP << 5); parport_pc_data_reverse (port); parport_pc_write_control (port, 0x4); @@ -470,6 +478,7 @@ static size_t parport_pc_ecpepp_write_ad { size_t written; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecpepp_write_addr\n"); frob_econtrol (port, 0xe0, ECR_EPP << 5); parport_pc_write_control (port, 0x4); parport_pc_data_forward (port); @@ -495,6 +504,7 @@ static size_t parport_pc_fifo_write_bloc port = port->physport; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_fifo_write_block_pio\n"); /* We don't want to be interrupted every character. */ parport_pc_disable_irq (port); frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */ @@ -587,6 +597,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) @@ -605,7 +616,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 */ @@ -695,6 +707,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; } @@ -706,6 +719,7 @@ size_t parport_pc_compat_write_block_pio size_t written; int r; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_compat_write_block_pio"); /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->physport->cad->timeout) return parport_ieee1284_write_compat (port, buf, @@ -770,6 +784,7 @@ size_t parport_pc_ecp_write_block_pio (s size_t written; int r; +DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_write_block_pio\n"); /* Special case: a timeout of zero means we cannot call schedule(). */ if (!port->physport->cad->timeout) return parport_ieee1284_ecp_write_data (port, buf, @@ -876,6 +891,8 @@ 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) @@ -890,44 +907,84 @@ size_t parport_pc_ecp_read_block_pio (st fifofull = 128; /* 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)) { + if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) { + /* change to reverse-idle phase (must be in forward-idle) */ + /* Event 38: Set nAutoFd low */ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 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 */ 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; + /* set HostAck low to start accepting data */ + parport_pc_frob_control (port, + PARPORT_CONTROL_AUTOFD + | PARPORT_CONTROL_STROBE, + PARPORT_CONTROL_AUTOFD); + + /* 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; @@ -948,6 +1005,7 @@ 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) { @@ -959,11 +1017,15 @@ size_t parport_pc_ecp_read_block_pio (st /* 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; } @@ -972,29 +1034,47 @@ size_t parport_pc_ecp_read_block_pio (st if (current->need_resched && time_before (jiffies, expire)) schedule (); - +dump_parport_state ("false alarm", port); goto false_alarm; } +dump_parport_state ("got something", port); continue; } 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"); + *bufp++ = inb (fifo); + left--; + } + + /* scoop up what got left in the FIFO */ + while (left) { + if (inb (ECONTROL (port)) & 0x01) { + /* empty (< 1 PWord) */ + break; + } *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 48: PError goes high */ r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, PARPORT_STATUS_PAPEROUT); @@ -1014,6 +1094,7 @@ size_t parport_pc_ecp_read_block_pio (st port->name, lost); } +dump_parport_state ("fwd idle", port); return length - left; } @@ -1927,10 +2008,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); @@ -2089,6 +2171,8 @@ struct parport *__devinit parport_pc_pro 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.0/include/linux/parport_pc.h.orig linux.2.4.0/include/linux/parport_pc.h --- linux.2.4.0/include/linux/parport_pc.h.orig Sat Jan 6 17:18:35 2001 +++ linux.2.4.0/include/linux/parport_pc.h Sun Jan 7 23:43:02 2001 @@ -59,6 +59,44 @@ extern __inline__ unsigned char parport_ return val; } +#ifdef DEBUG_PARPORT +extern __inline__ void dump_parport_state (char *str, struct parport *p) +{ + 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"}; + + 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"); + printk ("] dcr=["); + 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.0/include/linux/ppdev.h.orig linux.2.4.0/include/linux/ppdev.h --- linux.2.4.0/include/linux/ppdev.h.orig Fri Jan 5 03:03:14 2001 +++ linux.2.4.0/include/linux/ppdev.h Fri Jan 5 03:03:43 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,12 @@ 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)

    -- 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 : Thu Feb 08 2001 - 15:47:26 EST