diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/parport/parport_pc.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/parport/parport_pc.c')
-rw-r--r-- | drivers/parport/parport_pc.c | 3415 |
1 files changed, 3415 insertions, 0 deletions
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c new file mode 100644 index 00000000000..c5774e7855d --- /dev/null +++ b/drivers/parport/parport_pc.c @@ -0,0 +1,3415 @@ +/* Low-level parallel-port routines for 8255-based PC-style hardware. + * + * Authors: Phil Blundell <philb@gnu.org> + * Tim Waugh <tim@cyberelk.demon.co.uk> + * Jose Renau <renau@acm.org> + * David Campbell <campbell@torque.net> + * Andrea Arcangeli + * + * based on work by Grant Guenther <grant@torque.net> and Phil Blundell. + * + * Cleaned up include files - Russell King <linux@arm.uk.linux.org> + * 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 + * Updated probing logic - Adam Belay <ambx1@neo.rr.com> + */ + +/* This driver should work with any hardware that is broadly compatible + * with that in the IBM PC. This applies to the majority of integrated + * I/O chipsets that are commonly available. The expected register + * layout is: + * + * base+0 data + * base+1 status + * base+2 control + * + * In addition, there are some optional registers: + * + * base+3 EPP address + * base+4 EPP data + * base+0x400 ECP config A + * base+0x401 ECP config B + * base+0x402 ECP control + * + * All registers are 8 bits wide and read/write. If your hardware differs + * only in register addresses (eg because your registers are on 32-bit + * word boundaries) then you can alter the constants in parport_pc.h to + * accommodate this. + * + * Note that the ECP registers may not start at offset 0x400 for PCI cards, + * but rather will start at port->base_hi. + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/pnp.h> +#include <linux/sysctl.h> + +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/uaccess.h> + +#include <linux/parport.h> +#include <linux/parport_pc.h> +#include <linux/via.h> +#include <asm/parport.h> + +#define PARPORT_PC_MAX_PORTS PARPORT_MAX + +/* ECR modes */ +#define ECR_SPP 00 +#define ECR_PS2 01 +#define ECR_PPF 02 +#define ECR_ECP 03 +#define ECR_EPP 04 +#define ECR_VND 05 +#define ECR_TST 06 +#define ECR_CNF 07 +#define ECR_MODE_MASK 0xe0 +#define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v)) + +#undef DEBUG + +#ifdef DEBUG +#define DPRINTK printk +#else +#define DPRINTK(stuff...) +#endif + + +#define NR_SUPERIOS 3 +static struct superio_struct { /* For Super-IO chips autodetection */ + int io; + int irq; + int dma; +} superios[NR_SUPERIOS] __devinitdata = { {0,},}; + +static int user_specified; +#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ + (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) +static int verbose_probing; +#endif +static int pci_registered_parport; +static int pnp_registered_parport; + +/* frob_control, but for ECR */ +static void frob_econtrol (struct parport *pb, unsigned char m, + unsigned char v) +{ + unsigned char ectr = 0; + + if (m != 0xff) + ectr = inb (ECONTROL (pb)); + + DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n", + m, v, ectr, (ectr & ~m) ^ v); + + outb ((ectr & ~m) ^ v, ECONTROL (pb)); +} + +static __inline__ void frob_set_mode (struct parport *p, int mode) +{ + frob_econtrol (p, ECR_MODE_MASK, mode << 5); +} + +#ifdef CONFIG_PARPORT_PC_FIFO +/* Safely change the mode bits in the ECR + Returns: + 0 : Success + -EBUSY: Could not drain FIFO in some finite amount of time, + mode not changed! + */ +static int change_mode(struct parport *p, int m) +{ + const struct parport_pc_private *priv = p->physport->private_data; + unsigned char oecr; + int mode; + + DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m); + + if (!priv->ecr) { + printk (KERN_DEBUG "change_mode: but there's no ECR!\n"); + return 0; + } + + /* Bits <7:5> contain the mode. */ + oecr = inb (ECONTROL (p)); + mode = (oecr >> 5) & 0x7; + if (mode == m) return 0; + + if (mode >= 2 && !(priv->ctr & 0x20)) { + /* This mode resets the FIFO, so we may + * have to wait for it to drain first. */ + unsigned long expire = jiffies + p->physport->cad->timeout; + int counter; + switch (mode) { + case ECR_PPF: /* Parallel Port FIFO mode */ + case ECR_ECP: /* ECP Parallel Port mode */ + /* Busy wait for 200us */ + for (counter = 0; counter < 40; counter++) { + if (inb (ECONTROL (p)) & 0x01) + break; + if (signal_pending (current)) break; + udelay (5); + } + + /* Poll slowly. */ + while (!(inb (ECONTROL (p)) & 0x01)) { + if (time_after_eq (jiffies, expire)) + /* The FIFO is stuck. */ + return -EBUSY; + __set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout ((HZ + 99) / 100); + if (signal_pending (current)) + break; + } + } + } + + if (mode >= 2 && m >= 2) { + /* We have to go through mode 001 */ + oecr &= ~(7 << 5); + oecr |= ECR_PS2 << 5; + ECR_WRITE (p, oecr); + } + + /* Set the mode. */ + oecr &= ~(7 << 5); + oecr |= m << 5; + ECR_WRITE (p, oecr); + return 0; +} + +#ifdef CONFIG_PARPORT_1284 +/* Find FIFO lossage; FIFO is reset */ +#if 0 +static int get_fifo_residue (struct parport *p) +{ + int residue; + int cnfga; + const struct parport_pc_private *priv = p->physport->private_data; + + /* Adjust for the contents of the FIFO. */ + for (residue = priv->fifo_depth; ; residue--) { + if (inb (ECONTROL (p)) & 0x2) + /* Full up. */ + break; + + outb (0, FIFO (p)); + } + + printk (KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name, + residue); + + /* Reset the FIFO. */ + frob_set_mode (p, ECR_PS2); + + /* Now change to config mode and clean up. FIXME */ + frob_set_mode (p, ECR_CNF); + cnfga = inb (CONFIGA (p)); + printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga); + + if (!(cnfga & (1<<2))) { + printk (KERN_DEBUG "%s: Accounting for extra byte\n", p->name); + residue++; + } + + /* Don't care about partial PWords until support is added for + * PWord != 1 byte. */ + + /* Back to PS2 mode. */ + frob_set_mode (p, ECR_PS2); + + DPRINTK (KERN_DEBUG "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n", inb (ECONTROL (p))); + return residue; +} +#endif /* 0 */ +#endif /* IEEE 1284 support */ +#endif /* FIFO support */ + +/* + * Clear TIMEOUT BIT in EPP MODE + * + * This is also used in SPP detection. + */ +static int clear_epp_timeout(struct parport *pb) +{ + unsigned char r; + + if (!(parport_pc_read_status(pb) & 0x01)) + return 1; + + /* To clear timeout some chips require double read */ + parport_pc_read_status(pb); + r = parport_pc_read_status(pb); + outb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */ + outb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */ + r = parport_pc_read_status(pb); + + return !(r & 0x01); +} + +/* + * Access functions. + * + * Most of these aren't static because they may be used by the + * parport_xxx_yyy macros. extern __inline__ versions of several + * of these are in parport_pc.h. + */ + +static irqreturn_t parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + parport_generic_irq(irq, (struct parport *) dev_id, regs); + /* FIXME! Was it really ours? */ + return IRQ_HANDLED; +} + +static void parport_pc_init_state(struct pardevice *dev, struct parport_state *s) +{ + s->u.pc.ctr = 0xc; + if (dev->irq_func && + dev->port->irq != PARPORT_IRQ_NONE) + /* Set ackIntEn */ + s->u.pc.ctr |= 0x10; + + s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24; + * D.Gruszka VScom */ +} + +static void parport_pc_save_state(struct parport *p, struct parport_state *s) +{ + const struct parport_pc_private *priv = p->physport->private_data; + s->u.pc.ctr = priv->ctr; + if (priv->ecr) + s->u.pc.ecr = inb (ECONTROL (p)); +} + +static void parport_pc_restore_state(struct parport *p, struct parport_state *s) +{ + struct parport_pc_private *priv = p->physport->private_data; + register unsigned char c = s->u.pc.ctr & priv->ctr_writable; + outb (c, CONTROL (p)); + priv->ctr = c; + if (priv->ecr) + ECR_WRITE (p, s->u.pc.ecr); +} + +#ifdef CONFIG_PARPORT_1284 +static size_t parport_pc_epp_read_data (struct parport *port, void *buf, + size_t length, int flags) +{ + size_t got = 0; + + if (flags & PARPORT_W91284PIC) { + unsigned char status; + size_t left = length; + + /* use knowledge about data lines..: + * nFault is 0 if there is at least 1 byte in the Warp's FIFO + * pError is 1 if there are 16 bytes in the Warp's FIFO + */ + status = inb (STATUS (port)); + + while (!(status & 0x08) && (got < length)) { + if ((left >= 16) && (status & 0x20) && !(status & 0x08)) { + /* can grab 16 bytes from warp fifo */ + if (!((long)buf & 0x03)) { + insl (EPPDATA (port), buf, 4); + } else { + insb (EPPDATA (port), buf, 16); + } + buf += 16; + got += 16; + left -= 16; + } else { + /* grab single byte from the warp fifo */ + *((char *)buf) = inb (EPPDATA (port)); + buf++; + got++; + left--; + } + status = inb (STATUS (port)); + if (status & 0x01) { + /* EPP timeout should never occur... */ + printk (KERN_DEBUG "%s: EPP timeout occurred while talking to " + "w91284pic (should not have done)\n", port->name); + clear_epp_timeout (port); + } + } + return got; + } + 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)); + buf++; + if (inb (STATUS (port)) & 0x01) { + /* EPP timeout */ + clear_epp_timeout (port); + break; + } + } + + return got; +} + +static size_t parport_pc_epp_write_data (struct parport *port, const void *buf, + 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)); + buf++; + if (inb (STATUS(port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return written; +} + +static size_t parport_pc_epp_read_addr (struct parport *port, void *buf, + 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)); + buf++; + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return got; +} + +static size_t parport_pc_epp_write_addr (struct parport *port, + const void *buf, size_t length, + 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)); + buf++; + if (inb (STATUS (port)) & 0x01) { + clear_epp_timeout (port); + break; + } + } + + return written; +} + +static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf, + size_t length, int flags) +{ + size_t got; + + frob_set_mode (port, ECR_EPP); + parport_pc_data_reverse (port); + parport_pc_write_control (port, 0x4); + got = parport_pc_epp_read_data (port, buf, length, flags); + frob_set_mode (port, ECR_PS2); + + return got; +} + +static size_t parport_pc_ecpepp_write_data (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + + frob_set_mode (port, ECR_EPP); + parport_pc_write_control (port, 0x4); + parport_pc_data_forward (port); + written = parport_pc_epp_write_data (port, buf, length, flags); + frob_set_mode (port, ECR_PS2); + + return written; +} + +static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf, + size_t length, int flags) +{ + size_t got; + + frob_set_mode (port, ECR_EPP); + parport_pc_data_reverse (port); + parport_pc_write_control (port, 0x4); + got = parport_pc_epp_read_addr (port, buf, length, flags); + frob_set_mode (port, ECR_PS2); + + return got; +} + +static size_t parport_pc_ecpepp_write_addr (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + + frob_set_mode (port, ECR_EPP); + parport_pc_write_control (port, 0x4); + parport_pc_data_forward (port); + written = parport_pc_epp_write_addr (port, buf, length, flags); + frob_set_mode (port, ECR_PS2); + + return written; +} +#endif /* IEEE 1284 support */ + +#ifdef CONFIG_PARPORT_PC_FIFO +static size_t parport_pc_fifo_write_block_pio (struct parport *port, + const void *buf, size_t length) +{ + int ret = 0; + const unsigned char *bufp = buf; + size_t left = length; + unsigned long expire = jiffies + port->physport->cad->timeout; + const int fifo = FIFO (port); + int poll_for = 8; /* 80 usecs */ + const struct parport_pc_private *priv = port->physport->private_data; + const int fifo_depth = priv->fifo_depth; + + port = port->physport; + + /* We don't want to be interrupted every character. */ + parport_pc_disable_irq (port); + /* 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 */ + + while (left) { + unsigned char byte; + unsigned char ecrval = inb (ECONTROL (port)); + int i = 0; + + if (need_resched() && time_before (jiffies, expire)) + /* Can't yield the port. */ + schedule (); + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG "Somebody wants the port\n"); + break; + } + + if (ecrval & 0x02) { + /* FIFO is full. Wait for interrupt. */ + + /* Clear serviceIntr */ + ECR_WRITE (port, ecrval & ~(1<<2)); + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "FIFO write timed out\n"); + break; + } + ecrval = inb (ECONTROL (port)); + if (!(ecrval & (1<<2))) { + if (need_resched() && + time_before (jiffies, expire)) + schedule (); + + goto false_alarm; + } + + continue; + } + + /* Can't fail now. */ + expire = jiffies + port->cad->timeout; + + poll: + if (signal_pending (current)) + break; + + if (ecrval & 0x01) { + /* FIFO is empty. Blast it full. */ + const int n = left < fifo_depth ? left : fifo_depth; + outsb (fifo, bufp, n); + bufp += n; + left -= n; + + /* Adjust the poll time. */ + if (i < (poll_for - 2)) poll_for--; + continue; + } else if (i++ < poll_for) { + udelay (10); + ecrval = inb (ECONTROL (port)); + goto poll; + } + + /* Half-full (call me an optimist) */ + byte = *bufp++; + outb (byte, fifo); + left--; + } + +dump_parport_state ("leave fifo_write_block_pio", port); + return length - left; +} + +static size_t parport_pc_fifo_write_block_dma (struct parport *port, + const void *buf, size_t length) +{ + int ret = 0; + unsigned long dmaflag; + size_t left = length; + const struct parport_pc_private *priv = port->physport->private_data; + dma_addr_t dma_addr, dma_handle; + size_t maxlen = 0x10000; /* max 64k per DMA transfer */ + 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) + maxlen = 0x10000 - (start & 0xffff); + + dma_addr = dma_handle = pci_map_single(priv->dev, (void *)buf, length, + PCI_DMA_TODEVICE); + } else { + /* above 16 MB we use a bounce buffer as ISA-DMA is not possible */ + maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ + dma_addr = priv->dma_handle; + dma_handle = 0; + } + + port = port->physport; + + /* We don't want to be interrupted every character. */ + parport_pc_disable_irq (port); + /* 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 */ + + while (left) { + unsigned long expire = jiffies + port->physport->cad->timeout; + + size_t count = left; + + if (count > maxlen) + count = maxlen; + + if (!dma_handle) /* bounce buffer ! */ + memcpy(priv->dma_buf, buf, count); + + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + set_dma_mode(port->dma, DMA_MODE_WRITE); + set_dma_addr(port->dma, dma_addr); + set_dma_count(port->dma, count); + + /* Set DMA mode */ + frob_econtrol (port, 1<<3, 1<<3); + + /* Clear serviceIntr */ + frob_econtrol (port, 1<<2, 0); + + enable_dma(port->dma); + release_dma_lock(dmaflag); + + /* assume DMA will be successful */ + left -= count; + buf += count; + if (dma_handle) dma_addr += count; + + /* Wait for interrupt. */ + false_alarm: + ret = parport_wait_event (port, HZ); + if (ret < 0) break; + ret = 0; + if (!time_before (jiffies, expire)) { + /* Timed out. */ + printk (KERN_DEBUG "DMA write timed out\n"); + break; + } + /* Is serviceIntr set? */ + if (!(inb (ECONTROL (port)) & (1<<2))) { + cond_resched(); + + goto false_alarm; + } + + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + count = get_dma_residue(port->dma); + release_dma_lock(dmaflag); + + cond_resched(); /* Can't yield the port. */ + + /* Anyone else waiting for the port? */ + if (port->waithead) { + printk (KERN_DEBUG "Somebody wants the port\n"); + break; + } + + /* update for possible DMA residue ! */ + buf -= count; + left += count; + if (dma_handle) dma_addr -= count; + } + + /* Maybe got here through break, so adjust for DMA residue! */ + dmaflag = claim_dma_lock(); + disable_dma(port->dma); + clear_dma_ff(port->dma); + left += get_dma_residue(port->dma); + release_dma_lock(dmaflag); + + /* Turn off DMA mode */ + frob_econtrol (port, 1<<3, 0); + + 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; +} + +/* Parallel Port FIFO mode (ECP chipsets) */ +static size_t parport_pc_compat_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + int r; + unsigned long expire; + const struct parport_pc_private *priv = port->physport->private_data; + + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) + return parport_ieee1284_write_compat (port, buf, + length, flags); + + /* Set up parallel port FIFO mode.*/ + parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, PARPORT_CONTROL_STROBE, 0); + r = change_mode (port, ECR_PPF); /* Parallel port FIFO */ + if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", port->name); + + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Write the data to the FIFO. */ + if (port->dma != PARPORT_DMA_NONE) + written = parport_pc_fifo_write_block_dma (port, buf, length); + else + written = parport_pc_fifo_write_block_pio (port, buf, length); + + /* Finish up. */ + /* For some hardware we don't want to touch the mode until + * the FIFO is empty, so allow 4 seconds for each position + * in the fifo. + */ + expire = jiffies + (priv->fifo_depth * HZ * 4); + do { + /* Wait for the FIFO to empty */ + r = change_mode (port, ECR_PS2); + if (r != -EBUSY) { + break; + } + } while (time_before (jiffies, expire)); + if (r == -EBUSY) { + + printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + + /* Prevent further data transfer. */ + frob_set_mode (port, ECR_TST); + + /* Adjust for the contents of the FIFO. */ + for (written -= priv->fifo_depth; ; written++) { + if (inb (ECONTROL (port)) & 0x2) { + /* Full up. */ + break; + } + outb (0, FIFO (port)); + } + + /* Reset the FIFO and return to PS2 mode. */ + frob_set_mode (port, ECR_PS2); + } + + r = parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + if (r) + printk (KERN_DEBUG + "%s: BUSY timeout (%d) in compat_write_block_pio\n", + port->name, r); + + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +} + +/* ECP */ +#ifdef CONFIG_PARPORT_1284 +static size_t parport_pc_ecp_write_block_pio (struct parport *port, + const void *buf, size_t length, + int flags) +{ + size_t written; + int r; + unsigned long expire; + const struct parport_pc_private *priv = port->physport->private_data; + + /* Special case: a timeout of zero means we cannot call schedule(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) + return parport_ieee1284_ecp_write_data (port, buf, + length, flags); + + /* Switch to forward mode if necessary. */ + if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { + /* 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. */ + r = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + if (r) { + printk (KERN_DEBUG "%s: PError timeout (%d) " + "in ecp_write_block_pio\n", port->name, r); + } + } + + /* Set up ECP parallel port mode.*/ + parport_pc_data_forward (port); /* Must be in PS2 mode */ + parport_pc_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 0); + r = change_mode (port, ECR_ECP); /* ECP FIFO */ + if (r) printk (KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", port->name); + port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; + + /* Write the data to the FIFO. */ + if (port->dma != PARPORT_DMA_NONE) + written = parport_pc_fifo_write_block_dma (port, buf, length); + else + written = parport_pc_fifo_write_block_pio (port, buf, length); + + /* Finish up. */ + /* For some hardware we don't want to touch the mode until + * the FIFO is empty, so allow 4 seconds for each position + * in the fifo. + */ + expire = jiffies + (priv->fifo_depth * (HZ * 4)); + do { + /* Wait for the FIFO to empty */ + r = change_mode (port, ECR_PS2); + if (r != -EBUSY) { + break; + } + } while (time_before (jiffies, expire)); + if (r == -EBUSY) { + + printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name); + + /* Prevent further data transfer. */ + frob_set_mode (port, ECR_TST); + + /* Adjust for the contents of the FIFO. */ + for (written -= priv->fifo_depth; ; written++) { + if (inb (ECONTROL (port)) & 0x2) { + /* Full up. */ + break; + } + outb (0, FIFO (port)); + } + + /* Reset the FIFO and return to PS2 mode. */ + frob_set_mode (port, ECR_PS2); + + /* Host transfer recovery. */ + parport_pc_data_reverse (port); /* Must be in PS2 mode */ + udelay (5); + parport_frob_control (port, PARPORT_CONTROL_INIT, 0); + r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + if (r) + printk (KERN_DEBUG "%s: PE,1 timeout (%d) " + "in ecp_write_block_pio\n", port->name, r); + + parport_frob_control (port, + PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + r = parport_wait_peripheral (port, + PARPORT_STATUS_PAPEROUT, + PARPORT_STATUS_PAPEROUT); + if (r) + printk (KERN_DEBUG "%s: PE,2 timeout (%d) " + "in ecp_write_block_pio\n", port->name, r); + } + + r = parport_wait_peripheral (port, + PARPORT_STATUS_BUSY, + PARPORT_STATUS_BUSY); + if(r) + printk (KERN_DEBUG + "%s: BUSY timeout (%d) in ecp_write_block_pio\n", + port->name, r); + + port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + return written; +} + +#if 0 +static size_t parport_pc_ecp_read_block_pio (struct parport *port, + void *buf, size_t length, + int flags) +{ + size_t left = length; + size_t fifofull; + int r; + const int fifo = FIFO(port); + const struct parport_pc_private *priv = port->physport->private_data; + const int fifo_depth = priv->fifo_depth; + 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(). + * Also if O_NONBLOCK is set then use the default implementation. */ + if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) + return parport_ieee1284_ecp_read_data (port, buf, + length, flags); + + 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 throw + * away data. */ + if (length < fifofull) + return parport_ieee1284_ecp_read_data (port, buf, + length, flags); + + 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_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: Wait for nAckReverse (PError) to go low */ + r = parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0); + 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_frob_control (port, + PARPORT_CONTROL_STROBE | + PARPORT_CONTROL_AUTOFD, + 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; + unsigned long expire = jiffies + port->cad->timeout; + unsigned char ecrval = inb (ECONTROL (port)); + + if (need_resched() && time_before (jiffies, expire)) + /* Can't yield the port. */ + schedule (); + + /* At this point, the FIFO may already be full. In + * that case ECP is already holding back the + * peripheral (assuming proper design) with a delayed + * handshake. Work fast to avoid a peripheral + * timeout. */ + + 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"); + break; + } + + /* Clear serviceIntr */ + ECR_WRITE (port, ecrval & ~(1<<2)); + false_alarm: +dump_parport_state ("waiting", port); + ret = parport_wait_event (port, HZ); +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 (need_resched() && + time_before (jiffies, expire)) { + schedule (); + } + goto false_alarm; + } + + /* Depending on how the FIFO threshold was + * set, how long interrupt service took, and + * how fast the peripheral is, we might be + * lucky and have a just filled FIFO. */ + 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"); + + /* 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. */ + *bufp++ = inb (fifo); + 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); + +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) { + printk (KERN_DEBUG + "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n", + port->name, r); + } + + port->ieee1284.phase = IEEE1284_PH_FWD_IDLE; + + /* Finish up. */ + { + int lost = get_fifo_residue (port); + if (lost) + /* Shouldn't happen with compliant peripherals. */ + printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", + port->name, lost); + } + +dump_parport_state ("fwd idle", port); + return length - left; +} +#endif /* 0 */ +#endif /* IEEE 1284 support */ +#endif /* Allowed to use FIFO/DMA */ + + +/* + * ****************************************** |