aboutsummaryrefslogtreecommitdiff
path: root/drivers/parport/parport_pc.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /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.c3415
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 */
+
+
+/*
+ * ******************************************