summaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
committerRalf Baechle <ralf@linux-mips.org>1999-09-28 22:25:29 +0000
commit0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch)
tree5085c389f09da78182b899d19fe1068b619a69dd /drivers/misc
parent273767781288c35c9d679e908672b9996cda4c34 (diff)
Merge with 2.3.10.
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Config.in37
-rw-r--r--drivers/misc/Makefile13
-rw-r--r--drivers/misc/parport_arc.c56
-rw-r--r--drivers/misc/parport_atari.c3
-rw-r--r--drivers/misc/parport_ax.c137
-rw-r--r--drivers/misc/parport_daisy.c473
-rw-r--r--drivers/misc/parport_ieee1284.c526
-rw-r--r--drivers/misc/parport_ieee1284_ops.c848
-rw-r--r--drivers/misc/parport_init.c40
-rw-r--r--drivers/misc/parport_pc.c1542
-rw-r--r--drivers/misc/parport_probe.c212
-rw-r--r--drivers/misc/parport_procfs.c20
-rw-r--r--drivers/misc/parport_share.c179
13 files changed, 3444 insertions, 642 deletions
diff --git a/drivers/misc/Config.in b/drivers/misc/Config.in
new file mode 100644
index 000000000..e2d96d0fa
--- /dev/null
+++ b/drivers/misc/Config.in
@@ -0,0 +1,37 @@
+#
+# For a description of the syntax of this configuration file,
+# see the Configure script.
+#
+# Parport configuration.
+#
+
+tristate 'Parallel port support' CONFIG_PARPORT
+if [ "$CONFIG_PARPORT" != "n" ]; then
+ dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+ bool ' Use FIFO/DMA if available' CONFIG_PARPORT_PC_FIFO
+ fi
+ if [ "$CONFIG_ARM" = "y" ]; then
+ dep_tristate ' Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
+ fi
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate ' Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+ if [ "$CONFIG_ZORRO" != "n" ]; then
+ dep_tristate ' Multiface III parallel port' CONFIG_PARPORT_MFC3 $CONFIG_PARPORT
+ fi
+ else
+ define_bool CONFIG_PARPORT_AMIGA n
+ define_bool CONFIG_PARPORT_MFC3 n
+ fi
+ if [ "$CONFIG_ATARI" = "y" ]; then
+ dep_tristate ' Atari hardware' CONFIG_PARPORT_ATARI $CONFIG_PARPORT
+ else
+ define_bool CONFIG_PARPORT_ATARI n
+ fi
+
+ # If exactly one hardware type is selected then parport will optimise away
+ # support for loading any others. Defeat this if the user is keen.
+ bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
+
+ bool ' IEEE 1284 transfer modes' CONFIG_PARPORT_1284
+fi
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 4036ac94c..505a9d100 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -23,7 +23,13 @@ MI_OBJS :=
MIX_OBJS :=
ifeq ($(CONFIG_PARPORT),y)
- L_OBJS += parport_share.o parport_ieee1284.o parport_procfs.o
+ L_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o \
+ parport_procfs.o
+
+ ifeq ($(CONFIG_PARPORT_1284),y)
+ L_OBJS += parport_daisy.o parport_probe.o
+ endif
+
ifeq ($(CONFIG_PARPORT_PC),y)
LX_OBJS += parport_pc.o
else
@@ -62,7 +68,10 @@ ifeq ($(CONFIG_PARPORT),y)
LX_OBJS += parport_init.o
else
ifeq ($(CONFIG_PARPORT),m)
- MI_OBJS += parport_share.o parport_ieee1284.o
+ MI_OBJS += parport_share.o parport_ieee1284.o parport_ieee1284_ops.o
+ ifeq ($(CONFIG_PARPORT_1284),y)
+ MI_OBJS += parport_daisy.o parport_probe.o
+ endif
ifneq ($(CONFIG_PROC_FS),n)
MI_OBJS += parport_procfs.o
endif
diff --git a/drivers/misc/parport_arc.c b/drivers/misc/parport_arc.c
index 26fca9c97..11581e253 100644
--- a/drivers/misc/parport_arc.c
+++ b/drivers/misc/parport_arc.c
@@ -98,41 +98,36 @@ static struct parport_operations parport_arc_ops =
arc_read_control,
arc_frob_control,
- NULL, /* write_econtrol */
- NULL, /* read_econtrol */
- NULL, /* frob_econtrol */
-
- arc_write_status,
arc_read_status,
- NULL, /* write_fifo */
- NULL, /* read_fifo */
-
- NULL, /* change_mode */
-
- NULL, /* epp_write_data */
- NULL, /* epp_read_data */
- NULL, /* epp_write_addr */
- NULL, /* epp_read_addr */
- NULL, /* epp_check_timeout */
+ arc_enable_irq,
+ arc_disable_irq,
- NULL, /* epp_write_block */
- NULL, /* epp_read_block */
+ arc_data_forward,
+ arc_data_reverse,
+
+ arc_interrupt,
- NULL, /* ecp_write_block */
- NULL, /* epp_write_block */
-
arc_init_state,
arc_save_state,
arc_restore_state,
- arc_enable_irq,
- arc_disable_irq,
- arc_interrupt,
-
arc_inc_use_count,
arc_dec_use_count,
- arc_fill_inode
+ arc_fill_inode,
+
+ parport_ieee1284_epp_write_data,
+ parport_ieee1284_epp_read_data,
+ parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr,
+
+ parport_ieee1284_ecp_write_data,
+ parport_ieee1284_ecp_read_data,
+ parport_ieee1284_ecp_write_addr,
+
+ parport_ieee1284_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
};
/* --- Initialisation code -------------------------------- */
@@ -142,11 +137,11 @@ int parport_arc_init(void)
/* Archimedes hardware provides only one port, at a fixed address */
struct parport *p;
- if (check_region(PORT_BASE, 4))
+ if (check_region(PORT_BASE, 1))
return 0;
-
- p = parport_register_port(base, IRQ_PRINTERACK,
- PARPORT_DMA_NONE, &parport_arc_ops);
+
+ p = parport_register_port (PORT_BASE, IRQ_PRINTERACK,
+ PARPORT_DMA_NONE, &parport_arc_ops);
if (!p)
return 0;
@@ -158,9 +153,6 @@ int parport_arc_init(void)
p->irq);
parport_proc_register(p);
- if (parport_probe_hook)
- (*parport_probe_hook)(p);
-
/* Tell the high-level drivers about the port. */
parport_announce_port (p);
diff --git a/drivers/misc/parport_atari.c b/drivers/misc/parport_atari.c
index 5aed4994b..122213033 100644
--- a/drivers/misc/parport_atari.c
+++ b/drivers/misc/parport_atari.c
@@ -221,9 +221,6 @@ parport_atari_init(void)
printk(KERN_INFO "%s: Atari built-in port using irq\n", p->name);
parport_proc_register(p);
- if (parport_probe_hook)
- (*parport_probe_hook)(p);
-
parport_announce_port (p);
return 1;
diff --git a/drivers/misc/parport_ax.c b/drivers/misc/parport_ax.c
index 5baf7d25e..dfa057fee 100644
--- a/drivers/misc/parport_ax.c
+++ b/drivers/misc/parport_ax.c
@@ -1,4 +1,4 @@
-/* $Id: parport_ax.c,v 1.19 1999/06/09 08:24:40 davem Exp $
+/* $Id: parport_ax.c,v 1.20 1999/07/03 08:56:21 davem Exp $
* Parallel-port routines for Sun Ultra/AX architecture
*
* Author: Eddie C. Dost <ecd@skynet.be>
@@ -164,6 +164,7 @@ parport_ax_frob_econtrol(struct parport *p, unsigned char mask, unsigned char va
void
parport_ax_change_mode(struct parport *p, int m)
{
+ /* FIXME */
parport_ax_frob_econtrol(p, 0xe0, m << 5);
}
@@ -201,58 +202,40 @@ parport_ax_enable_irq(struct parport *p)
writel(dcsr, (unsigned long)&dma->dcsr);
}
-int
-parport_ax_claim_resources(struct parport *p)
-{
-}
-
void
-parport_ax_init_state(struct parport_state *s)
+parport_ax_init_state(struct pardevice *dev, struct parport_state *s)
{
- s->u.pc.ctr = 0xc;
- s->u.pc.ecr = 0x0;
+ struct linux_ebus_dma *dma = dev->port->private_data;
+
+ s->u.ax.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+ s->u.ax.ecr = 0x0;
+
+ if (dev->irq_func)
+ s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+ | EBUS_DCSR_INT_EN);
+ else
+ s->u.ax.dcsr = (readl((unsigned long)&dma->dcsr)
+ & ~EBUS_DCSR_INT_EN);
}
void
parport_ax_save_state(struct parport *p, struct parport_state *s)
{
- s->u.pc.ctr = parport_ax_read_control(p);
- s->u.pc.ecr = parport_ax_read_econtrol(p);
+ struct linux_ebus_dma *dma = p->private_data;
+
+ s->u.ax.ctr = parport_ax_read_control(p);
+ s->u.ax.ecr = parport_ax_read_econtrol(p);
+ s->u.ax.dcsr = readl((unsigned long)&dma->dcsr);
}
void
parport_ax_restore_state(struct parport *p, struct parport_state *s)
{
- parport_ax_write_control(p, s->u.pc.ctr);
- parport_ax_write_econtrol(p, s->u.pc.ecr);
-}
-
-size_t
-parport_ax_epp_read_block(struct parport *p, void *buf, size_t length)
-{
- return 0; /* FIXME */
-}
-
-size_t
-parport_ax_epp_write_block(struct parport *p, void *buf, size_t length)
-{
- return 0; /* FIXME */
-}
-
-int
-parport_ax_ecp_read_block(struct parport *p, void *buf, size_t length,
- void (*fn)(struct parport *, void *, size_t),
- void *handle)
-{
- return 0; /* FIXME */
-}
+ struct linux_ebus_dma *dma = p->private_data;
-int
-parport_ax_ecp_write_block(struct parport *p, void *buf, size_t length,
- void (*fn)(struct parport *, void *, size_t),
- void *handle)
-{
- return 0; /* FIXME */
+ parport_ax_write_control(p, s->u.ax.ctr);
+ parport_ax_write_econtrol(p, s->u.ax.ecr);
+ writel(s->u.ax.dcsr, (unsigned long)&dma->dcsr);
}
void
@@ -290,41 +273,36 @@ static struct parport_operations parport_ax_ops =
parport_ax_read_control,
parport_ax_frob_control,
- parport_ax_write_econtrol,
- parport_ax_read_econtrol,
- parport_ax_frob_econtrol,
-
- parport_ax_write_status,
parport_ax_read_status,
- parport_ax_write_fifo,
- parport_ax_read_fifo,
-
- parport_ax_change_mode,
-
- parport_ax_write_epp,
- parport_ax_read_epp,
- parport_ax_write_epp_addr,
- parport_ax_read_epp_addr,
- parport_ax_check_epp_timeout,
+ parport_ax_enable_irq,
+ parport_ax_disable_irq,
- parport_ax_epp_write_block,
- parport_ax_epp_read_block,
+ parport_ax_data_forward,
+ parport_ax_data_reverse,
+
+ parport_ax_interrupt,
- parport_ax_ecp_write_block,
- parport_ax_ecp_read_block,
-
parport_ax_init_state,
parport_ax_save_state,
parport_ax_restore_state,
- parport_ax_enable_irq,
- parport_ax_disable_irq,
- parport_ax_interrupt,
-
parport_ax_inc_use_count,
parport_ax_dec_use_count,
- parport_ax_fill_inode
+ parport_ax_fill_inode,
+
+ parport_ieee1284_epp_write_data,
+ parport_ieee1284_epp_read_data,
+ parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr,
+
+ parport_ieee1284_ecp_write_data,
+ parport_ieee1284_ecp_read_data,
+ parport_ieee1284_ecp_write_addr,
+
+ parport_ieee1284_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
};
@@ -539,20 +517,6 @@ init_one_port(struct linux_ebus_device *dev)
if (p->dma == PARPORT_DMA_AUTO)
p->dma = (p->modes & PARPORT_MODE_PCECP) ? 0 : PARPORT_DMA_NONE;
- if (p->irq != PARPORT_IRQ_NONE) {
- int err;
- if ((err = request_irq(p->irq, parport_ax_interrupt,
- 0, p->name, p)) != 0)
- return err;
- else
- parport_ax_enable_irq(p);
- }
- request_region(p->base, p->size, p->name);
- if (p->modes & PARPORT_MODE_PCECR)
- request_region(p->base+0x400, 3, p->name);
- request_region((unsigned long)p->private_data,
- sizeof(struct linux_ebus_dma), p->name);
-
printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
if (p->irq != PARPORT_IRQ_NONE)
printk(", irq %s", __irq_itoa(p->irq));
@@ -569,12 +533,21 @@ init_one_port(struct linux_ebus_device *dev)
printk("]\n");
parport_proc_register(p);
+ if (p->irq != PARPORT_IRQ_NONE)
+ if ((err = request_irq(p->irq, parport_ax_interrupt,
+ 0, p->name, p)) != 0)
+ return 0; /* @@@ FIXME */
+
+ request_region(p->base, p->size, p->name);
+ if (p->modes & PARPORT_MODE_PCECR)
+ request_region(p->base+0x400, 3, p->name);
+ request_region((unsigned long)p->private_data,
+ sizeof(struct linux_ebus_dma), p->name);
+
p->ops->write_control(p, 0x0c);
p->ops->write_data(p, 0);
- if (parport_probe_hook)
- (*parport_probe_hook)(p);
-
+ /* Tell the high-level drivers about the port. */
parport_announce_port (p);
return 1;
diff --git a/drivers/misc/parport_daisy.c b/drivers/misc/parport_daisy.c
new file mode 100644
index 000000000..830d9d400
--- /dev/null
+++ b/drivers/misc/parport_daisy.c
@@ -0,0 +1,473 @@
+/*
+ * IEEE 1284.3 Parallel port daisy chain and multiplexor code
+ *
+ * Copyright (C) 1999 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * ??-12-1998: Initial implementation.
+ * 31-01-1999: Make port-cloning transparent.
+ * 13-02-1999: Move DeviceID technique from parport_probe.
+ * 13-03-1999: Get DeviceID from non-IEEE 1284.3 devices too.
+ *
+ */
+
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+static struct daisydev {
+ struct daisydev *next;
+ struct parport *port;
+ int daisy;
+ int devnum;
+} *topology = NULL;
+
+static int numdevs = 0;
+
+/* Forward-declaration of lower-level functions. */
+static int mux_present (struct parport *port);
+static int num_mux_ports (struct parport *port);
+static int select_port (struct parport *port);
+static int assign_addrs (struct parport *port);
+
+/* Add a device to the discovered topology. */
+static void add_dev (int devnum, struct parport *port, int daisy)
+{
+ struct daisydev *newdev;
+ newdev = kmalloc (GFP_KERNEL, sizeof (struct daisydev));
+ if (newdev) {
+ newdev->port = port;
+ newdev->daisy = daisy;
+ newdev->devnum = devnum;
+ newdev->next = topology;
+ if (!topology || topology->devnum >= devnum)
+ topology = newdev;
+ else {
+ struct daisydev *prev = topology;
+ while (prev->next && prev->next->devnum < devnum)
+ prev = prev->next;
+ newdev->next = prev->next;
+ prev->next = newdev;
+ }
+ }
+}
+
+/* Clone a parport (actually, make an alias). */
+static struct parport *clone_parport (struct parport *real, int muxport)
+{
+ struct parport *extra = parport_register_port (real->base,
+ real->irq,
+ real->dma,
+ real->ops);
+ if (extra) {
+ extra->portnum = real->portnum;
+ extra->physport = real;
+ extra->muxport = muxport;
+ }
+
+ return extra;
+}
+
+/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains. */
+int parport_daisy_init (struct parport *port)
+{
+ char *deviceid;
+ static const char *th[] = { /*0*/"th", "st", "nd", "rd", "th" };
+ int num_ports;
+ int i;
+
+ /* Because this is called before any other devices exist,
+ * we don't have to claim exclusive access. */
+
+ /* If mux present on normal port, need to create new
+ * parports for each extra port. */
+ if (port->muxport < 0 && mux_present (port) &&
+ /* don't be fooled: a mux must have 2 or 4 ports. */
+ ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
+ /* Leave original as port zero. */
+ port->muxport = 0;
+ printk (KERN_INFO
+ "%s: 1st (default) port of %d-way multiplexor\n",
+ port->name, num_ports);
+ for (i = 1; i < num_ports; i++) {
+ /* Clone the port. */
+ struct parport *extra = clone_parport (port, i);
+ if (!extra) {
+ if (signal_pending (current))
+ break;
+
+ schedule ();
+ continue;
+ }
+
+ printk (KERN_INFO
+ "%s: %d%s port of %d-way multiplexor on %s\n",
+ extra->name, i + 1, th[i + 1], num_ports,
+ port->name);
+
+ /* Analyse that port too. We won't recurse
+ forever because of the 'port->muxport < 0'
+ test above. */
+ parport_announce_port (extra);
+ }
+ }
+
+ if (port->muxport >= 0)
+ select_port (port);
+
+ parport_daisy_deselect_all (port);
+ assign_addrs (port);
+
+ /* Count the potential legacy device at the end. */
+ add_dev (numdevs++, port, -1);
+
+ /* Find out the legacy device's IEEE 1284 device ID. */
+ deviceid = kmalloc (1000, GFP_KERNEL);
+ if (deviceid) {
+ parport_device_id (numdevs - 1, deviceid, 1000);
+ kfree (deviceid);
+ }
+
+ return 0;
+}
+
+/* Forget about devices on a physical port. */
+void parport_daisy_fini (struct parport *port)
+{
+ struct daisydev *dev, *prev = topology;
+ while (prev && prev->port == port)
+ prev = topology = topology->next;
+
+ while (prev) {
+ dev = prev->next;
+ if (dev && dev->port == port)
+ prev->next = dev->next;
+
+ prev = prev->next;
+ }
+
+ /* Gaps in the numbering could be handled better. How should
+ someone enumerate through all IEEE1284.3 devices in the
+ topology?. */
+ if (!topology) numdevs = 0;
+ return; }
+
+/* Find a device by canonical device number. */
+struct pardevice *parport_open (int devnum, const char *name,
+ int (*pf) (void *), void (*kf) (void *),
+ void (*irqf) (int, void *, struct pt_regs *),
+ int flags, void *handle)
+{
+ struct parport *port = parport_enumerate ();
+ struct pardevice *dev;
+ int portnum;
+ int muxnum;
+ int daisynum;
+
+ if (parport_device_coords (devnum, &portnum, &muxnum, &daisynum))
+ return NULL;
+
+ while (port && ((port->portnum != portnum) ||
+ (port->muxport != muxnum)))
+ port = port->next;
+
+ if (!port)
+ /* No corresponding parport. */
+ return NULL;
+
+ dev = parport_register_device (port, name, pf, kf,
+ irqf, flags, handle);
+ if (dev)
+ dev->daisy = daisynum;
+
+ /* Check that there really is a device to select. */
+ if (daisynum >= 0) {
+ int selected;
+ parport_claim_or_block (dev);
+ selected = port->daisy;
+ parport_release (dev);
+
+ if (selected != port->daisy) {
+ /* No corresponding device. */
+ parport_unregister_device (dev);
+ return NULL;
+ }
+ }
+
+ return dev;
+}
+
+/* The converse of parport_open. */
+void parport_close (struct pardevice *dev)
+{
+ parport_unregister_device (dev);
+}
+
+/* Convert device coordinates into a canonical device number. */
+int parport_device_num (int parport, int mux, int daisy)
+{
+ struct daisydev *dev = topology;
+
+ while (dev && dev->port->portnum != parport &&
+ dev->port->muxport != mux && dev->daisy != daisy)
+ dev = dev->next;
+
+ if (!dev)
+ return -ENXIO;
+
+ return dev->devnum;
+}
+
+/* Convert a canonical device number into device coordinates. */
+int parport_device_coords (int devnum, int *parport, int *mux, int *daisy)
+{
+ struct daisydev *dev = topology;
+
+ while (dev && dev->devnum != devnum)
+ dev = dev->next;
+
+ if (!dev)
+ return -ENXIO;
+
+ if (parport) *parport = dev->port->portnum;
+ if (mux) *mux = dev->port->muxport;
+ if (daisy) *daisy = dev->daisy;
+ return 0;
+}
+
+/* Send a daisy-chain-style CPP command packet. */
+static int cpp_daisy (struct parport *port, int cmd)
+{
+ unsigned char s;
+
+ parport_write_data (port, 0xaa); udelay (2);
+ parport_write_data (port, 0x55); udelay (2);
+ parport_write_data (port, 0x00); udelay (2);
+ parport_write_data (port, 0xff); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x87); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x78); udelay (2);
+ parport_write_data (port, cmd); udelay (2);
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+ udelay (1);
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ udelay (1);
+ s = parport_read_status (port);
+ parport_write_data (port, 0xff); udelay (2);
+
+ return s;
+}
+
+/* Send a mux-style CPP command packet. */
+static int cpp_mux (struct parport *port, int cmd)
+{
+ unsigned char s;
+ int rc;
+
+ parport_write_data (port, 0xaa); udelay (2);
+ parport_write_data (port, 0x55); udelay (2);
+ parport_write_data (port, 0xf0); udelay (2);
+ parport_write_data (port, 0x0f); udelay (2);
+ parport_write_data (port, 0x52); udelay (2);
+ parport_write_data (port, 0xad); udelay (2);
+ parport_write_data (port, cmd); udelay (2);
+
+ s = parport_read_status (port);
+ if (!(s & PARPORT_STATUS_ACK)) {
+ DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+ port->name, cmd, s);
+ return -EIO;
+ }
+
+ rc = (((s & PARPORT_STATUS_SELECT ? 1 : 0) << 0) |
+ ((s & PARPORT_STATUS_PAPEROUT ? 1 : 0) << 1) |
+ ((s & PARPORT_STATUS_BUSY ? 0 : 1) << 2) |
+ ((s & PARPORT_STATUS_ERROR ? 0 : 1) << 3));
+
+ return rc;
+}
+
+void parport_daisy_deselect_all (struct parport *port)
+{
+ cpp_daisy (port, 0x30);
+}
+
+int parport_daisy_select (struct parport *port, int daisy, int mode)
+{
+ /* mode is currently ignored. FIXME? */
+ return cpp_daisy (port, 0xe0 + daisy) & PARPORT_STATUS_ERROR;
+}
+
+static int mux_present (struct parport *port)
+{
+ return cpp_mux (port, 0x51) == 3;
+}
+
+static int num_mux_ports (struct parport *port)
+{
+ return cpp_mux (port, 0x58);
+}
+
+static int select_port (struct parport *port)
+{
+ int muxport = port->muxport;
+ return cpp_mux (port, 0x60 + muxport) == muxport;
+}
+
+static int assign_addrs (struct parport *port)
+{
+ unsigned char s, last_dev;
+ unsigned char daisy;
+ int thisdev = numdevs;
+ char *deviceid;
+
+ parport_write_data (port, 0xaa); udelay (2);
+ parport_write_data (port, 0x55); udelay (2);
+ parport_write_data (port, 0x00); udelay (2);
+ parport_write_data (port, 0xff); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x87); udelay (2);
+ s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_ERROR);
+ if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
+ DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+ port->name, s);
+ return -ENXIO;
+ }
+
+ parport_write_data (port, 0x78); udelay (2);
+ last_dev = 0; /* We've just been speaking to a device, so we
+ know there must be at least _one_ out there. */
+
+ for (daisy = 0; daisy < 4; daisy++) {
+ parport_write_data (port, daisy);
+ udelay (2);
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+ udelay (1);
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ udelay (1);
+
+ if (last_dev)
+ /* No more devices. */
+ break;
+
+ last_dev = !(parport_read_status (port)
+ & PARPORT_STATUS_BUSY);
+
+ add_dev (numdevs++, port, daisy);
+ }
+
+ parport_write_data (port, 0xff); udelay (2);
+ DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+ numdevs - thisdev);
+
+ /* Ask the new devices to introduce themselves. */
+ deviceid = kmalloc (1000, GFP_KERNEL);
+ if (!deviceid) return 0;
+
+ for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
+ parport_device_id (thisdev, deviceid, 1000);
+
+ kfree (deviceid);
+ return 0;
+}
+
+/* Find a device with a particular manufacturer and model string,
+ starting from a given device number. Like the PCI equivalent,
+ 'from' itself is skipped. */
+int parport_find_device (const char *mfg, const char *mdl, int from)
+{
+ struct daisydev *d = topology; /* sorted by devnum */
+
+ /* Find where to start. */
+ while (d && d->devnum <= from)
+ d = d->next;
+
+ /* Search. */
+ while (d) {
+ struct parport_device_info *info;
+ info = &d->port->probe_info[1 + d->daisy];
+ if ((!mfg || !strcmp (mfg, info->mfr)) &&
+ (!mdl || !strcmp (mdl, info->model)))
+ break;
+
+ d = d->next;
+ }
+
+ if (d)
+ return d->devnum;
+
+ return -1;
+}
+
+/* Find a device in a particular class. Like the PCI equivalent,
+ 'from' itself is skipped. */
+int parport_find_class (parport_device_class cls, int from)
+{
+ struct daisydev *d = topology; /* sorted by devnum */
+
+ /* Find where to start. */
+ while (d && d->devnum <= from)
+ d = d->next;
+
+ /* Search. */
+ while (d && d->port->probe_info[1 + d->daisy].class != cls)
+ d = d->next;
+
+ if (d)
+ return d->devnum;
+
+ return -1;
+}
diff --git a/drivers/misc/parport_ieee1284.c b/drivers/misc/parport_ieee1284.c
index 3b86633bc..461ff358b 100644
--- a/drivers/misc/parport_ieee1284.c
+++ b/drivers/misc/parport_ieee1284.c
@@ -1,15 +1,76 @@
-/* $Id: parport_ieee1284.c,v 1.6 1999/02/15 02:18:17 ralf Exp $
+/* $Id: parport_ieee1284.c,v 1.11 1999/09/27 20:56:21 ralf Exp $
* IEEE-1284 implementation for parport.
*
* Authors: Phil Blundell <Philip.Blundell@pobox.com>
* Carsten Gross <carsten@sol.wohnheim.uni-ulm.de>
* Jose Renau <renau@acm.org>
+ * Tim Waugh <tim@cyberelk.demon.co.uk> (largely rewritten)
+ *
+ * This file is responsible for IEEE 1284 negotiation, and for handing
+ * read/write requests to low-level drivers.
*/
+#include <linux/config.h>
#include <linux/tasks.h>
#include <linux/parport.h>
#include <linux/delay.h>
#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#undef DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/* Make parport_wait_peripheral wake up.
+ * It will be useful to call this from an interrupt handler. */
+void parport_ieee1284_wakeup (struct parport *port)
+{
+ up (&port->physport->ieee1284.irq);
+}
+
+static struct parport *port_from_cookie[PARPORT_MAX];
+static void timeout_waiting_on_port (unsigned long cookie)
+{
+ parport_ieee1284_wakeup (port_from_cookie[cookie % PARPORT_MAX]);
+}
+
+/* Wait for a parport_ieee1284_wakeup.
+ * 0: success
+ * <0: error (exit as soon as possible)
+ * >0: timed out
+ */
+int parport_wait_event (struct parport *port, signed long timeout)
+{
+ int ret;
+ struct timer_list timer;
+
+ if (!port->physport->cad->timeout)
+ /* Zero timeout is special, and we can't down() the
+ semaphore. */
+ return 1;
+
+ init_timer (&timer);
+ timer.expires = jiffies + timeout;
+ timer.function = timeout_waiting_on_port;
+ port_from_cookie[port->number % PARPORT_MAX] = port;
+ timer.data = port->number;
+
+ add_timer (&timer);
+ ret = down_interruptible (&port->physport->ieee1284.irq);
+ if (!del_timer (&timer) && !ret)
+ /* Timed out. */
+ ret = 1;
+
+ return ret;
+}
/* Wait for Status line(s) to change in 35 ms - see IEEE1284-1994 page 24 to
* 25 for this. After this time we can create a timeout because the
@@ -19,53 +80,446 @@
* are able to eat the time up to 40ms.
*/
-int parport_wait_peripheral(struct parport *port, unsigned char mask,
- unsigned char result)
+int parport_wait_peripheral(struct parport *port,
+ unsigned char mask,
+ unsigned char result)
{
int counter;
- unsigned char status;
-
- for (counter = 0; counter < 20; counter++) {
- status = parport_read_status(port);
+ long deadline;
+ unsigned char status;
+
+ counter = port->physport->spintime; /* usecs of fast polling */
+ if (!port->physport->cad->timeout)
+ /* A zero timeout is "special": busy wait for the
+ entire 35ms. */
+ counter = 35000;
+
+ /* Fast polling.
+ *
+ * This should be adjustable.
+ * How about making a note (in the device structure) of how long
+ * it takes, so we know for next time?
+ */
+ for (counter /= 5; counter > 0; counter--) {
+ status = parport_read_status (port);
if ((status & mask) == result)
return 0;
- udelay(25);
+ if (signal_pending (current))
+ return -EINTR;
if (current->need_resched)
- schedule();
+ break;
+ udelay(5);
+ }
+
+ if (!port->physport->cad->timeout)
+ /* We may be in an interrupt handler, so we can't poll
+ * slowly anyway. */
+ return 1;
+
+ /* 40ms of slow polling. */
+ deadline = jiffies + (HZ + 24) / 25;
+ while (time_before (jiffies, deadline)) {
+ int ret;
+
+ if (signal_pending (current))
+ return -EINTR;
+
+ /* Wait for 10ms (or until an interrupt occurs if
+ * the handler is set) */
+ if ((ret = parport_wait_event (port, (HZ + 99) / 100)) < 0)
+ return ret;
+
+ status = parport_read_status (port);
+ if ((status & mask) == result)
+ return 0;
+
+ if (!ret) {
+ /* parport_wait_event didn't time out, but the
+ * peripheral wasn't actually ready either.
+ * Wait for another 10ms. */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout ((HZ+ 99) / 100);
+ }
+ }
+
+ return 1;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Terminate a negotiated mode. */
+static void parport_ieee1284_terminate (struct parport *port)
+{
+ port = port->physport;
+
+ port->ieee1284.phase = IEEE1284_PH_TERMINATE;
+
+ /* EPP terminates differently. */
+ switch (port->ieee1284.mode) {
+ case IEEE1284_MODE_EPP:
+ case IEEE1284_MODE_EPPSL:
+ case IEEE1284_MODE_EPPSWE:
+ /* Terminate from EPP mode. */
+
+ /* Event 68: Set nInit low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+ udelay (50);
+
+ /* Event 69: Set nInit high, nSelectIn low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+ break;
+
+ default:
+ /* Terminate from all other modes. */
+
+ /* Event 22: Set nSelectIn low, nAutoFd high */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_SELECT);
+
+ /* Event 24: nAck goes low */
+ parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0);
+
+ /* Event 25: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 27: nAck goes high */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK);
+
+ /* Event 29: Set nAutoFd high */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
}
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/25); /* wait for 40ms */
- status = parport_read_status(port);
- return ((status & mask) == result)?0:1;
+
+ port->ieee1284.mode = IEEE1284_MODE_COMPAT;
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ DPRINTK (KERN_DEBUG "%s: In compatibility (forward idle) mode\n",
+ port->name);
}
+#endif /* IEEE1284 support */
-/* Test if the peripheral is IEEE 1284 compliant.
+/* Negotiate an IEEE 1284 mode.
* return values are:
- * 0 - handshake failed; peripheral is not compliant (or none present)
- * 1 - handshake OK; IEEE1284 peripheral present but no data available
- * 2 - handshake OK; IEEE1284 peripheral and data available
+ * 0 - handshake OK; IEEE1284 peripheral and mode available
+ * -1 - handshake failed; peripheral is not compliant (or none present)
+ * 1 - handshake OK; IEEE1284 peripheral present but mode not available
*/
-int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode)
+int parport_negotiate (struct parport *port, int mode)
{
- /* make sure it's a valid state, set nStrobe & nAutoFeed high */
- parport_frob_control (port, (1|2), 0);
- udelay(1);
- parport_write_data(port, mode);
- udelay(400);
- /* nSelectIn high, nAutoFd low */
- parport_frob_control(port, (2|8), 2);
- if (parport_wait_peripheral(port, 0x78, 0x38)) {
- parport_frob_control(port, (2|8), 8);
+#ifndef CONFIG_PARPORT_1284
+ if (mode == IEEE1284_MODE_COMPAT)
+ return 0;
+ printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+ return -1;
+#else
+ int m = mode;
+ unsigned char xflag;
+
+ port = port->physport;
+
+ /* Is there anything to do? */
+ if (port->ieee1284.mode == mode)
+ return 0;
+
+ /* Go to compability forward idle mode */
+ if (port->ieee1284.mode != IEEE1284_MODE_COMPAT)
+ parport_ieee1284_terminate (port);
+
+ if (mode == IEEE1284_MODE_COMPAT)
+ /* Compatibility mode: no negotiation. */
return 0;
+
+ switch (mode) {
+ case IEEE1284_MODE_ECPSWE:
+ m = IEEE1284_MODE_ECP;
+ break;
+ case IEEE1284_MODE_EPPSL:
+ case IEEE1284_MODE_EPPSWE:
+ m = IEEE1284_MODE_EPP;
+ break;
+ case IEEE1284_MODE_BECP:
+ return -ENOSYS; /* FIXME (implement BECP) */
}
- /* nStrobe low */
- parport_frob_control (port, 1, 1);
- udelay(1); /* Strobe wait */
- /* nStrobe high, nAutoFeed low, last step before transferring
- * reverse data */
- parport_frob_control (port, (1|2), 0);
+
+ port->ieee1284.phase = IEEE1284_PH_NEGOTIATION;
+
+ /* Start off with nStrobe and nAutoFd high, and nSelectIn low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE
+ | PARPORT_CONTROL_AUTOFD
+ | PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
udelay(1);
- /* Data available? */
- parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
- return (parport_read_status(port) & PARPORT_STATUS_ERROR)?1:2;
+
+ /* Event 0: Set data */
+ parport_write_data (port, m);
+ udelay (400); /* Shouldn't need to wait this long. */
+
+ /* Event 1: Set nSelectIn high, nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 2: PError, Select, nFault go high, nAck goes low */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_PAPEROUT
+ | PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_SELECT
+ | PARPORT_STATUS_PAPEROUT)) {
+ /* Timeout */
+ parport_frob_control (port,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_SELECT);
+ DPRINTK (KERN_DEBUG
+ "%s: Peripheral not IEEE1284 compliant (0x%02X)\n",
+ port->name, parport_read_status (port));
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ return -1; /* Not IEEE1284 compliant */
+ }
+
+ /* Event 3: Set nStrobe low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* Event 4: Set nStrobe and nAutoFd high */
+ udelay (5);
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE
+ | PARPORT_CONTROL_AUTOFD,
+ 0);
+
+ /* Event 6: nAck goes high */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK
+ | PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_ACK)) {
+ if (parport_read_status (port) & PARPORT_STATUS_ACK)
+ printk (KERN_DEBUG
+ "%s: working around buggy peripheral: tell "
+ "Tim what make it is\n", port->name);
+ DPRINTK (KERN_DEBUG
+ "%s: Mode 0x%02x not supported? (0x%02x)\n",
+ port->name, mode, port->ops->read_status (port));
+ parport_ieee1284_terminate (port);
+ return 1;
+ }
+
+ xflag = parport_read_status (port) & PARPORT_STATUS_SELECT;
+
+ /* xflag should be high for all modes other than nibble (0). */
+ if (mode && !xflag) {
+ /* Mode not supported. */
+ DPRINTK (KERN_DEBUG "%s: Mode 0x%02x not supported\n",
+ port->name, mode);
+ parport_ieee1284_terminate (port);
+ return 1;
+ }
+
+ /* Mode is supported */
+ DPRINTK (KERN_DEBUG "%s: In mode 0x%02x\n", port->name, mode);
+ port->ieee1284.mode = mode;
+
+ /* But ECP is special */
+ if (mode & IEEE1284_MODE_ECP) {
+ port->ieee1284.phase = IEEE1284_PH_ECP_SETUP;
+
+ /* Event 30: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 31: PError goes high. */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ /* (Should check that this works..) */
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+ port->name);
+ } else switch (mode) {
+ case IEEE1284_MODE_NIBBLE:
+ case IEEE1284_MODE_BYTE:
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ break;
+ default:
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ }
+
+
+ return 0;
+#endif /* IEEE1284 support */
+}
+
+/* Acknowledge that the peripheral has data available.
+ * Events 18-20, in order to get from Reverse Idle phase
+ * to Host Busy Data Available.
+ * This will most likely be called from an interrupt.
+ * Returns zero if data was available.
+ */
+#ifdef CONFIG_PARPORT_1284
+static int parport_ieee1284_ack_data_avail (struct parport *port)
+{
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+ /* Event 18 didn't happen. */
+ return -1;
+
+ /* Event 20: nAutoFd goes high. */
+ port->ops->frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ return 0;
+}
+#endif /* IEEE1284 support */
+
+/* Handle an interrupt. */
+void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
+{
+ struct parport *port = handle;
+ parport_ieee1284_wakeup (port);
+
+#ifdef CONFIG_PARPORT_1284
+ if (port->ieee1284.phase == IEEE1284_PH_REV_IDLE) {
+ /* An interrupt in this phase means that data
+ * is now available. */
+ DPRINTK (KERN_DEBUG "%s: Data available\n", port->name);
+ parport_ieee1284_ack_data_avail (port);
+ }
+#endif /* IEEE1284 support */
+}
+
+/* Write a block of data. */
+ssize_t parport_write (struct parport *port, const void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+ return port->ops->compat_write_data (port, buffer, len, 0);
+#else
+ ssize_t retval;
+ int mode = port->ieee1284.mode;
+ size_t (*fn) (struct parport *, const void *, size_t, int);
+
+ /* Ignore the device-ID-request bit. */
+ mode &= ~IEEE1284_DEVICEID;
+
+ /* Use the mode we're in. */
+ switch (mode) {
+ case IEEE1284_MODE_NIBBLE:
+ parport_negotiate (port, IEEE1284_MODE_COMPAT);
+ case IEEE1284_MODE_COMPAT:
+ DPRINTK (KERN_DEBUG "%s: Using compatibility mode\n",
+ port->name);
+ fn = port->ops->compat_write_data;
+ break;
+
+ case IEEE1284_MODE_EPP:
+ DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+ fn = port->ops->epp_write_data;
+ break;
+
+ case IEEE1284_MODE_ECP:
+ case IEEE1284_MODE_ECPRLE:
+ DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+ fn = port->ops->ecp_write_data;
+ break;
+
+ case IEEE1284_MODE_ECPSWE:
+ DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+ port->name);
+ /* The caller has specified that it must be emulated,
+ * even if we have ECP hardware! */
+ fn = parport_ieee1284_ecp_write_data;
+ break;
+
+ default:
+ DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+ port->ieee1284.mode);
+ return -ENOSYS;
+ }
+
+ retval = (*fn) (port, buffer, len, 0);
+ DPRINTK (KERN_DEBUG "%s: wrote %d/%d bytes\n", port->name, retval,
+ len);
+ return retval;
+#endif /* IEEE1284 support */
+}
+
+/* Read a block of data. */
+ssize_t parport_read (struct parport *port, void *buffer, size_t len)
+{
+#ifndef CONFIG_PARPORT_1284
+ printk (KERN_ERR "parport: IEEE1284 not supported in this kernel\n");
+ return -ENODEV;
+#else
+ int mode = port->physport->ieee1284.mode;
+ size_t (*fn) (struct parport *, void *, size_t, int);
+
+ /* Ignore the device-ID-request bit. */
+ mode &= ~IEEE1284_DEVICEID;
+
+ /* Use the mode we're in. */
+ switch (mode) {
+ case IEEE1284_MODE_COMPAT:
+ if (parport_negotiate (port, IEEE1284_MODE_NIBBLE))
+ return -EIO;
+ case IEEE1284_MODE_NIBBLE:
+ DPRINTK (KERN_DEBUG "%s: Using nibble mode\n", port->name);
+ fn = port->ops->nibble_read_data;
+ break;
+
+ case IEEE1284_MODE_BYTE:
+ DPRINTK (KERN_DEBUG "%s: Using byte mode\n", port->name);
+ fn = port->ops->byte_read_data;
+ break;
+
+ case IEEE1284_MODE_EPP:
+ DPRINTK (KERN_DEBUG "%s: Using EPP mode\n", port->name);
+ fn = port->ops->epp_read_data;
+ break;
+
+ case IEEE1284_MODE_ECP:
+ case IEEE1284_MODE_ECPRLE:
+ DPRINTK (KERN_DEBUG "%s: Using ECP mode\n", port->name);
+ fn = port->ops->ecp_read_data;
+ break;
+
+ case IEEE1284_MODE_ECPSWE:
+ DPRINTK (KERN_DEBUG "%s: Using software-emulated ECP mode\n",
+ port->name);
+ fn = parport_ieee1284_ecp_read_data;
+ break;
+
+ default:
+ DPRINTK (KERN_DEBUG "%s: Unknown mode 0x%02x\n", port->name,
+ port->physport->ieee1284.mode);
+ return -ENOSYS;
+ }
+
+ return (*fn) (port, buffer, len, 0);
+#endif /* IEEE1284 support */
+}
+
+/* Set the amount of time we wait while nothing's happening. */
+long parport_set_timeout (struct pardevice *dev, long inactivity)
+{
+ long int old = dev->timeout;
+
+ dev->timeout = inactivity;
+
+ if (dev->port->physport->cad == dev)
+ parport_ieee1284_wakeup (dev->port);
+
+ return old;
}
diff --git a/drivers/misc/parport_ieee1284_ops.c b/drivers/misc/parport_ieee1284_ops.c
new file mode 100644
index 000000000..4fbeba668
--- /dev/null
+++ b/drivers/misc/parport_ieee1284_ops.c
@@ -0,0 +1,848 @@
+/* IEEE-1284 operations for parport.
+ *
+ * This file is for generic IEEE 1284 operations. The idea is that
+ * they are used by the low-level drivers. If they have a special way
+ * of doing something, they can provide their own routines (and put
+ * the function pointers in port->ops); if not, they can just use these
+ * as a fallback.
+ *
+ * Note: Make no assumptions about hardware or architecture in this file!
+ *
+ * Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ */
+
+#include <linux/config.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#define DEBUG /* undef me for production */
+
+#ifdef CONFIG_LP_CONSOLE
+#undef DEBUG /* Don't want a garbled console */
+#endif
+
+#ifdef DEBUG
+#define DPRINTK(stuff...) printk (stuff)
+#else
+#define DPRINTK(stuff...)
+#endif
+
+/*** *
+ * One-way data transfer functions. *
+ * ***/
+
+static inline
+int polling (struct pardevice *dev)
+{
+ return dev->port->irq == PARPORT_IRQ_NONE;
+}
+
+/* Compatibility mode. */
+size_t parport_ieee1284_write_compat (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+ ssize_t count = 0;
+ const unsigned char *addr = buffer;
+ unsigned char byte;
+ struct pardevice *dev = port->physport->cad;
+ unsigned char ctl = (PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
+
+ if (port->irq != PARPORT_IRQ_NONE)
+ parport_enable_irq (port);
+
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+ while (count < len) {
+ long expire = jiffies + dev->timeout;
+ long wait = (HZ + 99) / 100;
+ unsigned char mask = (PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_BUSY);
+ unsigned char val = (PARPORT_STATUS_ERROR
+ | PARPORT_STATUS_BUSY);
+ int i;
+
+ /* Write the character to the data lines. */
+ byte = *addr++;
+ parport_write_data (port, byte);
+ udelay (1);
+
+ /* Wait until the peripheral's ready */
+ do {
+ /* Is the peripheral ready yet? */
+ if (!parport_wait_peripheral (port, mask, val))
+ /* Skip the loop */
+ goto ready;
+
+ /* Is the peripheral upset? */
+ if ((parport_read_status (port) &
+ (PARPORT_STATUS_PAPEROUT |
+ PARPORT_STATUS_SELECT |
+ PARPORT_STATUS_ERROR))
+ != (PARPORT_STATUS_SELECT |
+ PARPORT_STATUS_ERROR))
+ /* If nFault is asserted (i.e. no
+ * error) and PAPEROUT and SELECT are
+ * just red herrings, give the driver
+ * a chance to check it's happy with
+ * that before continuing. */
+ goto stop;
+
+ /* Have we run out of time? */
+ if (!time_before (jiffies, expire))
+ break;
+
+ /* Yield the port for a while. If this is the
+ first time around the loop, don't let go of
+ the port. This way, we find out if we have
+ our interrupt handler called. */
+ if (count && polling (dev)) {
+ parport_release (dev);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout (wait);
+ parport_claim_or_block (dev);
+ }
+ else
+ /* We must have the device claimed here */
+ parport_wait_event (port, wait);
+
+ /* Is there a signal pending? */
+ if (signal_pending (current))
+ goto stop;
+
+ /* Wait longer next time. */
+ wait *= 2;
+ } while (time_before (jiffies, expire));
+
+ DPRINTK (KERN_DEBUG "%s: Timed out\n", port->name);
+ break;
+
+ ready:
+ /* Clear out previous irqs. */
+ while (!down_trylock (&port->physport->ieee1284.irq));
+
+ /* Pulse strobe. */
+ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+ udelay (1); /* strobe */
+
+ parport_write_control (port, ctl);
+ udelay (1); /* hold */
+
+ /* Wait until it's received (up to 20us). */
+ for (i = 0; i < 20; i++) {
+ if (!down_trylock (&port->physport->ieee1284.irq) ||
+ !(parport_read_status (port) & PARPORT_STATUS_ACK))
+ break;
+ udelay (1);
+ }
+
+ count++;
+
+ /* Let another process run if it needs to. */
+ if (time_before (jiffies, expire))
+ if (!parport_yield_blocking (dev)
+ && current->need_resched)
+ schedule ();
+ }
+ stop:
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return count;
+}
+
+/* Nibble mode. */
+size_t parport_ieee1284_read_nibble (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ unsigned char *buf = buffer;
+ int i;
+ unsigned char byte = 0;
+
+ len *= 2; /* in nibbles */
+ for (i=0; i < len; i++) {
+ unsigned char nibble;
+
+ /* Does the error line indicate end of data? */
+ if (((i & 1) == 0) &&
+ (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
+ port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ DPRINTK (KERN_DEBUG
+ "%s: No more nibble data (%d bytes)\n",
+ port->name, i/2);
+
+ /* Go to reverse idle phase. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ break;
+ }
+
+ /* Event 7: Set nAutoFd low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 9: nAck goes low. */
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK, 0)) {
+ /* Timeout -- no more data? */
+ DPRINTK (KERN_DEBUG
+ "%s: Nibble timeout at event 9 (%d bytes)\n",
+ port->name, i/2);
+ break;
+ }
+
+
+ /* Read a nibble. */
+ nibble = parport_read_status (port) >> 3;
+ nibble &= ~8;
+ if ((nibble & 0x10) == 0)
+ nibble |= 8;
+ nibble &= 0xf;
+
+ /* Event 10: Set nAutoFd high. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 11: nAck goes high. */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* Timeout -- no more data? */
+ DPRINTK (KERN_DEBUG
+ "%s: Nibble timeout at event 11\n",
+ port->name);
+ break;
+ }
+
+ if (i & 1) {
+ /* Second nibble */
+ byte |= nibble << 4;
+ *buf++ = byte;
+ } else
+ byte = nibble;
+ }
+
+ i /= 2; /* i is now in bytes */
+
+ if (i == len) {
+ /* Read the last nibble without checking data avail. */
+ port = port->physport;
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ else
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ }
+
+ return i;
+#endif /* IEEE1284 support */
+}
+
+/* Byte mode. */
+size_t parport_ieee1284_read_byte (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ unsigned char *buf = buffer;
+ ssize_t count = 0;
+
+ for (count = 0; count < len; count++) {
+ unsigned char byte;
+
+ /* Data available? */
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
+ port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ DPRINTK (KERN_DEBUG
+ "%s: No more byte data (%d bytes)\n",
+ port->name, count);
+
+ /* Go to reverse idle phase. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ break;
+ }
+
+ /* Event 7: Set nAutoFd low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* Event 9: nAck goes low. */
+ port->physport->ieee1284.phase = IEEE1284_PH_REV_DATA;
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ 0)) {
+ /* Timeout -- no more data? */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ 0);
+ DPRINTK (KERN_DEBUG "%s: Byte timeout at event 9\n",
+ port->name);
+ break;
+ }
+
+ byte = parport_read_data (port);
+ *buf++ = byte;
+
+ /* Event 10: Set nAutoFd high */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 11: nAck goes high. */
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* Timeout -- no more data? */
+ DPRINTK (KERN_DEBUG "%s: Byte timeout at event 11\n",
+ port->name);
+ break;
+ }
+
+ /* Event 16: Set nStrobe low. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+ udelay (5);
+
+ /* Event 17: Set nStrobe high. */
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+ }
+
+ if (count == len) {
+ /* Read the last byte without checking data avail. */
+ port = port->physport;
+ if (parport_read_status (port) & PARPORT_STATUS_ERROR)
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DNA;
+ else
+ port->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
+ }
+
+ return count;
+#endif /* IEEE1284 support */
+}
+
+/*** *
+ * ECP Functions. *
+ * ***/
+
+#ifdef CONFIG_PARPORT_1284
+
+static inline
+int ecp_forward_to_reverse (struct parport *port)
+{
+ int retval;
+
+ /* Event 38: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ parport_data_reverse (port);
+ udelay (5);
+
+ /* Event 39: Set nInit low to initiate bus reversal */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+
+ /* Event 40: PError goes low */
+ retval = parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT, 0);
+
+ if (!retval) {
+ DPRINTK (KERN_DEBUG "%s: ECP direction: reverse\n",
+ port->name);
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+ }
+
+ return retval;
+}
+
+static inline
+int ecp_reverse_to_forward (struct parport *port)
+{
+ int retval;
+
+ /* Event 47: Set nInit high */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+ parport_data_reverse (port);
+
+ /* Event 49: PError goes high */
+ retval = parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+
+ if (!retval) {
+ parport_data_forward (port);
+ DPRINTK (KERN_DEBUG "%s: ECP direction: forward\n",
+ port->name);
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ }
+
+ return retval;
+}
+
+#endif /* IEEE1284 support */
+
+/* ECP mode, forward channel, data. */
+size_t parport_ieee1284_ecp_write_data (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ const unsigned char *buf = buffer;
+ size_t written;
+ int ctl = parport_read_control (port) & ~PARPORT_CONTROL_AUTOFD;
+ int retry;
+
+ port = port->physport;
+
+ if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+ if (ecp_reverse_to_forward (port))
+ return 0;
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* HostAck high (data, not command) */
+ parport_write_control (port, ctl);
+ for (written = 0; written < len; written++, buf++) {
+ long expire = jiffies + port->cad->timeout;
+ unsigned char byte;
+
+ byte = *buf;
+ try_again:
+ parport_write_data (port, byte);
+ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+ udelay (5);
+ for (retry = 0; retry < 100; retry++) {
+ if (!parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY, 0))
+ goto success;
+
+ if (signal_pending (current)) {
+ parport_write_control (port, ctl);
+ break;
+ }
+ }
+
+ /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+ DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+ parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+ udelay (50);
+ if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+ /* It's buggered. */
+ parport_write_control (port, ctl);
+ break;
+ }
+
+ parport_write_control (port, ctl);
+ udelay (50);
+ if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+ break;
+
+ DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+ port->name);
+
+ if (time_after_eq (jiffies, expire)) break;
+ goto try_again;
+ success:
+ parport_write_control (port, ctl);
+ udelay (5);
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ /* Peripheral hasn't accepted the data. */
+ break;
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, reverse channel, data. */
+size_t parport_ieee1284_ecp_read_data (struct parport *port,
+ void *buffer, size_t len, int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ struct pardevice *dev = port->cad;
+ unsigned char *buf = buffer;
+ int rle_count = 0; /* shut gcc up */
+ int rle = 0;
+ ssize_t count = 0;
+
+ port = port->physport;
+
+ if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE)
+ if (ecp_forward_to_reverse (port))
+ return 0;
+
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+ /* Set HostAck low to start accepting data. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ while (count < len) {
+ long expire = jiffies + dev->timeout;
+ unsigned char byte;
+ int command;
+
+ /* Event 43: Peripheral sets nAck low. It can take as
+ long as it wants. */
+ while (parport_wait_peripheral (port,
+ PARPORT_STATUS_ACK,
+ PARPORT_STATUS_ACK)) {
+ /* The peripheral hasn't given us data in
+ 35ms. If we have data to give back to the
+ caller, do it now. */
+ if (count)
+ goto out;
+
+ /* If we've used up all the time we were allowed,
+ give up altogether. */
+ if (!time_before (jiffies, expire))
+ goto out;
+
+ /* Yield the port for a while. */
+ if (count && polling (dev)) {
+ parport_release (dev);
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout ((HZ + 99) / 25);
+ parport_claim_or_block (dev);
+ }
+ else
+ /* We must have the device claimed here. */
+ parport_wait_event (port, (HZ + 99) / 25);
+
+ /* Is there a signal pending? */
+ if (signal_pending (current))
+ goto out;
+ }
+
+ /* Is this a command? */
+ if (rle)
+ /* The last byte was a run-length count, so
+ this can't be as well. */
+ command = 0;
+ else
+ command = (parport_read_status (port) &
+ PARPORT_STATUS_BUSY) ? 1 : 0;
+
+ /* Read the data. */
+ byte = parport_read_data (port);
+
+ /* If this is a channel command, rather than an RLE
+ command or a normal data byte, don't accept it. */
+ if (command) {
+ if (byte & 0x80) {
+ DPRINTK (KERN_DEBUG "%s: stopping short at "
+ "channel command (%02x)\n",
+ port->name, byte);
+ goto out;
+ }
+ else if (port->ieee1284.mode != IEEE1284_MODE_ECPRLE)
+ DPRINTK (KERN_DEBUG "%s: device illegally "
+ "using RLE; accepting anyway\n",
+ port->name);
+
+ rle_count = byte + 1;
+
+ /* Are we allowed to read that many bytes? */
+ if (rle_count > (len - count)) {
+ DPRINTK (KERN_DEBUG "%s: leaving %d RLE bytes "
+ "for next time\n", port->name,
+ rle_count);
+ break;
+ }
+
+ rle = 1;
+ }
+
+ /* Event 44: Set HostAck high, acknowledging handshake. */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+
+ /* Event 45: The peripheral has 35ms to set nAck high. */
+ if (parport_wait_peripheral (port, PARPORT_STATUS_ACK, 0)) {
+ /* It's gone wrong. Return what data we have
+ to the caller. */
+ DPRINTK (KERN_DEBUG "ECP read timed out at 45\n");
+
+ if (command)
+ printk (KERN_WARNING
+ "%s: command ignored (%02x)\n",
+ port->name, byte);
+
+ break;
+ }
+
+ /* Event 46: Set HostAck low and accept the data. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ /* If we just read a run-length count, fetch the data. */
+ if (command)
+ continue;
+
+ /* If this is the byte after a run-length count, decompress. */
+ if (rle) {
+ rle = 0;
+ memset (buf, byte, rle_count);
+ buf += rle_count;
+ count += rle_count;
+ DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
+ port->name, rle_count);
+ }
+ else
+ /* Normal data byte. */
+ *buf++ = byte, count++;
+ }
+
+ out:
+ return count;
+#endif /* IEEE1284 support */
+}
+
+/* ECP mode, forward channel, commands. */
+size_t parport_ieee1284_ecp_write_addr (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+#ifndef CONFIG_PARPORT_1284
+ return 0;
+#else
+ const unsigned char *buf = buffer;
+ size_t written;
+ int ctl = parport_read_control (port) | PARPORT_CONTROL_AUTOFD;
+ int retry;
+
+ port = port->physport;
+
+ if (port->ieee1284.phase != IEEE1284_PH_FWD_IDLE)
+ if (ecp_reverse_to_forward (port))
+ return 0;
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* HostAck low (command, not data) */
+ parport_write_control (port, ctl);
+ for (written = 0; written < len; written++, buf++) {
+ long expire = jiffies + port->cad->timeout;
+ unsigned char byte;
+
+ byte = *buf;
+ try_again:
+ parport_write_data (port, byte);
+ parport_write_control (port, ctl | PARPORT_CONTROL_STROBE);
+ udelay (5);
+ for (retry = 0; retry < 100; retry++) {
+ if (!parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY, 0))
+ goto success;
+
+ if (signal_pending (current)) {
+ parport_write_control (port, ctl);
+ break;
+ }
+ }
+
+ /* Time for Host Transfer Recovery (page 41 of IEEE1284) */
+ DPRINTK (KERN_DEBUG "%s: ECP transfer stalled!\n", port->name);
+
+ parport_write_control (port, ctl | PARPORT_CONTROL_INIT);
+ udelay (50);
+ if (parport_read_status (port) & PARPORT_STATUS_PAPEROUT) {
+ /* It's buggered. */
+ parport_write_control (port, ctl);
+ break;
+ }
+
+ parport_write_control (port, ctl);
+ udelay (50);
+ if (!(parport_read_status (port) & PARPORT_STATUS_PAPEROUT))
+ break;
+
+ DPRINTK (KERN_DEBUG "%s: Host transfer recovered\n",
+ port->name);
+
+ if (time_after_eq (jiffies, expire)) break;
+ goto try_again;
+ success:
+ parport_write_control (port, ctl);
+ udelay (5);
+ if (parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ /* Peripheral hasn't accepted the data. */
+ break;
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+#endif /* IEEE1284 support */
+}
+
+/*** *
+ * EPP functions. *
+ * ***/
+
+/* EPP mode, forward channel, data. */
+size_t parport_ieee1284_epp_write_data (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested */
+ unsigned char *bp = (unsigned char *) buffer;
+ size_t ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT);
+ port->ops->data_forward (port);
+ for (; len > 0; len--, bp++) {
+ parport_write_data (port, *bp);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ /* Strobe data */
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ ret++;
+ }
+
+ return ret;
+}
+
+/* EPP mode, reverse channel, data. */
+size_t parport_ieee1284_epp_read_data (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested. */
+ unsigned char *bp = (unsigned char *) buffer;
+ unsigned ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_SELECT, 0);
+ port->ops->data_reverse (port);
+ for (; len > 0; len--, bp++) {
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ *bp = parport_read_data (port);
+
+ parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
+ ret++;
+ }
+ port->ops->data_forward (port);
+
+ return ret;
+}
+
+/* EPP mode, forward channel, addresses. */
+size_t parport_ieee1284_epp_write_addr (struct parport *port,
+ const void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested */
+ unsigned char *bp = (unsigned char *) buffer;
+ size_t ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT);
+ port->ops->data_forward (port);
+ for (; len > 0; len--, bp++) {
+ parport_write_data (port, *bp);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ /* Strobe data */
+ parport_frob_control (port, PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+ ret++;
+ }
+
+ return ret;
+}
+
+/* EPP mode, reverse channel, addresses. */
+size_t parport_ieee1284_epp_read_addr (struct parport *port,
+ void *buffer, size_t len,
+ int flags)
+{
+ /* This is untested. */
+ unsigned char *bp = (unsigned char *) buffer;
+ unsigned ret = 0;
+
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_SELECT |
+ PARPORT_CONTROL_AUTOFD, 0);
+ port->ops->data_reverse (port);
+ for (; len > 0; len--, bp++) {
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY))
+ break;
+
+ parport_frob_control (port, PARPORT_CONTROL_SELECT,
+ PARPORT_CONTROL_SELECT);
+
+ if (parport_wait_peripheral (port, PARPORT_STATUS_BUSY, 0))
+ break;
+
+ *bp = parport_read_data (port);
+
+ parport_frob_control (port, PARPORT_CONTROL_SELECT, 0);
+ ret++;
+ }
+ port->ops->data_forward (port);
+
+ return ret;
+}
diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c
index c250c77a7..18c3fde0d 100644
--- a/drivers/misc/parport_init.c
+++ b/drivers/misc/parport_init.c
@@ -22,7 +22,7 @@
static int io[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
static int io_hi[PARPORT_MAX+1] __initdata = { [0 ... PARPORT_MAX] = 0 };
static int irq[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_IRQ_PROBEONLY };
-static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_AUTO };
+static int dma[PARPORT_MAX] __initdata = { [0 ... PARPORT_MAX-1] = PARPORT_DMA_NONE };
extern int parport_pc_init(int *io, int *io_hi, int *irq, int *dma);
extern int parport_ax_init(void);
@@ -119,10 +119,7 @@ __initfunc(int parport_init(void))
if (io[0] == PARPORT_DISABLE)
return 1;
-#ifdef CONFIG_PNP_PARPORT
- parport_probe_hook = &parport_probe_one;
-#endif
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL
parport_default_proc_register ();
#endif
@@ -161,13 +158,42 @@ EXPORT_SYMBOL(parport_unregister_driver);
EXPORT_SYMBOL(parport_register_device);
EXPORT_SYMBOL(parport_unregister_device);
EXPORT_SYMBOL(parport_enumerate);
-EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
+EXPORT_SYMBOL(parport_negotiate);
+EXPORT_SYMBOL(parport_write);
+EXPORT_SYMBOL(parport_read);
+EXPORT_SYMBOL(parport_ieee1284_wakeup);
EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_wait_event);
+EXPORT_SYMBOL(parport_set_timeout);
+EXPORT_SYMBOL(parport_ieee1284_interrupt);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_ecp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_write_compat);
+EXPORT_SYMBOL(parport_ieee1284_read_nibble);
+EXPORT_SYMBOL(parport_ieee1284_read_byte);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_data);
+EXPORT_SYMBOL(parport_ieee1284_epp_write_addr);
+EXPORT_SYMBOL(parport_ieee1284_epp_read_addr);
EXPORT_SYMBOL(parport_proc_register);
EXPORT_SYMBOL(parport_proc_unregister);
-EXPORT_SYMBOL(parport_probe_hook);
+EXPORT_SYMBOL(parport_device_proc_register);
+EXPORT_SYMBOL(parport_device_proc_unregister);
+EXPORT_SYMBOL(parport_default_proc_register);
+EXPORT_SYMBOL(parport_default_proc_unregister);
EXPORT_SYMBOL(parport_parse_irqs);
EXPORT_SYMBOL(parport_parse_dmas);
+#ifdef CONFIG_PARPORT_1284
+EXPORT_SYMBOL(parport_open);
+EXPORT_SYMBOL(parport_close);
+EXPORT_SYMBOL(parport_device_id);
+EXPORT_SYMBOL(parport_device_num);
+EXPORT_SYMBOL(parport_device_coords);
+EXPORT_SYMBOL(parport_daisy_deselect_all);
+EXPORT_SYMBOL(parport_daisy_select);
+EXPORT_SYMBOL(parport_daisy_init);
+#endif
void inc_parport_count(void)
{
diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c
index 63b67f3ba..6023b4400 100644
--- a/drivers/misc/parport_pc.c
+++ b/drivers/misc/parport_pc.c
@@ -9,6 +9,7 @@
* 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>
* Better EPP probing - Carlos Henrique Bauer <chbauer@acm.org>
*/
@@ -46,9 +47,11 @@
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <linux/pci.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>
@@ -57,12 +60,138 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
+/* 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
+
static int user_specified __initdata = 0;
+/* frob_control, but for ECR */
+static void frob_econtrol (struct parport *pb, unsigned char m,
+ unsigned char v)
+{
+ outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Safely change the mode bits in the ECR */
+static int change_mode(struct parport *p, int m)
+{
+ const struct parport_pc_private *priv = p->physport->private_data;
+ int ecr = ECONTROL(p);
+ unsigned char oecr;
+ int mode;
+
+ if (!priv->ecr) {
+ printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
+ return 0;
+ }
+
+ /* Bits <7:5> contain the mode. */
+ oecr = inb (ecr);
+ mode = (oecr >> 5) & 0x7;
+ if (mode == m) return 0;
+ if (mode && m)
+ /* We have to go through mode 000 */
+ change_mode (p, ECR_SPP);
+
+ if (m < 2 && !(parport_read_control (p) & 0x20)) {
+ /* This mode resets the FIFO, so we may
+ * have to wait for it to drain first. */
+ 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;
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout ((HZ + 99) / 100);
+ if (signal_pending (current))
+ break;
+ }
+ }
+ }
+
+ /* Set the mode. */
+ oecr &= ~(7 << 5);
+ oecr |= m << 5;
+ outb (oecr, ecr);
+ return 0;
+}
+
+/* Find FIFO lossage; FIFO is reset */
+static int get_fifo_residue (struct parport *p)
+{
+ int residue;
+ int cnfga;
+ const struct parport_pc_private *priv = p->physport->private_data;
+
+ /* Prevent further data transfer. */
+ parport_frob_control (p,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* 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_econtrol (p, 0xe0, 0x20);
+ parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
+
+ /* Now change to config mode and clean up. FIXME */
+ frob_econtrol (p, 0xe0, 0xe0);
+ 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_econtrol (p, 0xe0, 0x20);
+
+ return residue;
+}
+
+#endif /* IEEE 1284 support */
+
/*
* Clear TIMEOUT BIT in EPP MODE
+ *
+ * This is also used in SPP detection.
*/
-int parport_pc_epp_clear_timeout(struct parport *pb)
+static int clear_epp_timeout(struct parport *pb)
{
unsigned char r;
@@ -72,187 +201,719 @@ int parport_pc_epp_clear_timeout(struct parport *pb)
/* To clear timeout some chips require double read */
parport_pc_read_status(pb);
r = parport_pc_read_status(pb);
- parport_pc_write_status(pb, r | 0x01); /* Some reset by writing 1 */
- parport_pc_write_status(pb, r & 0xfe); /* Others by writing 0 */
+ 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.
+ *
+ * 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 void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
parport_generic_irq(irq, (struct parport *) dev_id, regs);
}
-void parport_pc_write_epp(struct parport *p, unsigned char d)
+void parport_pc_write_data(struct parport *p, unsigned char d)
{
- outb(d, EPPDATA(p));
+ outb (d, DATA (p));
}
-unsigned char parport_pc_read_epp(struct parport *p)
+unsigned char parport_pc_read_data(struct parport *p)
{
- return inb(EPPDATA(p));
+ return inb (DATA (p));
}
-void parport_pc_write_epp_addr(struct parport *p, unsigned char d)
+unsigned char __frob_control (struct parport *p, unsigned char mask,
+ unsigned char val)
{
- outb(d, EPPADDR(p));
+ struct parport_pc_private *priv = p->physport->private_data;
+ unsigned char ctr = priv->ctr;
+ ctr = (ctr & ~mask) ^ val;
+ ctr &= priv->ctr_writable; /* only write writable bits. */
+ outb (ctr, CONTROL (p));
+ return priv->ctr = ctr; /* update soft copy */
}
-unsigned char parport_pc_read_epp_addr(struct parport *p)
+void parport_pc_write_control(struct parport *p, unsigned char d)
{
- return inb(EPPADDR(p));
-}
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
+
+ /* Take this out when drivers have adapted to the newer interface. */
+ if (d & 0x20) {
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
+ }
-int parport_pc_check_epp_timeout(struct parport *p)
-{
- if (!(inb(STATUS(p)) & 1))
- return 0;
- parport_pc_epp_clear_timeout(p);
- return 1;
+ __frob_control (p, wm, d & wm);
}
-unsigned char parport_pc_read_configb(struct parport *p)
+unsigned char parport_pc_read_control(struct parport *p)
{
- return inb(CONFIGB(p));
+ const struct parport_pc_private *priv = p->physport->private_data;
+ return priv->ctr; /* Use soft copy */
}
-void parport_pc_write_data(struct parport *p, unsigned char d)
+unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
+ unsigned char val)
{
- outb(d, DATA(p));
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
+
+ /* Take this out when drivers have adapted to the newer interface. */
+ if (mask & 0x20) {
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
+ }
+
+ /* Restrict mask and val to control lines. */
+ mask &= wm;
+ val &= wm;
+
+ return __frob_control (p, mask, val);
}
-unsigned char parport_pc_read_data(struct parport *p)
+unsigned char parport_pc_read_status(struct parport *p)
{
- return inb(DATA(p));
+ return inb (STATUS (p));
}
-void parport_pc_write_control(struct parport *p, unsigned char d)
+void parport_pc_disable_irq(struct parport *p)
{
- struct parport_pc_private *priv = p->private_data;
- priv->ctr = d;/* update soft copy */
- outb(d, CONTROL(p));
+ __frob_control (p, 0x10, 0);
}
-unsigned char parport_pc_read_control(struct parport *p)
+void parport_pc_enable_irq(struct parport *p)
{
- struct parport_pc_private *priv = p->private_data;
- return priv->ctr;
+ __frob_control (p, 0x10, 0x10);
}
-unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
+void parport_pc_data_forward (struct parport *p)
{
- struct parport_pc_private *priv = p->private_data;
- unsigned char ctr = priv->ctr;
- ctr = (ctr & ~mask) ^ val;
- outb (ctr, CONTROL(p));
- return priv->ctr = ctr; /* update soft copy */
+ __frob_control (p, 0x20, 0);
}
-void parport_pc_write_status(struct parport *p, unsigned char d)
+void parport_pc_data_reverse (struct parport *p)
{
- outb(d, STATUS(p));
+ __frob_control (p, 0x20, 0x20);
}
-unsigned char parport_pc_read_status(struct parport *p)
+void parport_pc_init_state(struct pardevice *dev, struct parport_state *s)
{
- return inb(STATUS(p));
+ struct parport_pc_private *priv = dev->port->physport->private_data;
+ priv->ctr = s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0);
+ s->u.pc.ecr = 0x24;
}
-void parport_pc_write_econtrol(struct parport *p, unsigned char d)
+void parport_pc_save_state(struct parport *p, struct parport_state *s)
{
- outb(d, ECONTROL(p));
+ const struct parport_pc_private *priv = p->physport->private_data;
+ s->u.pc.ctr = inb (CONTROL (p));
+ if (priv->ecr)
+ s->u.pc.ecr = inb (ECONTROL (p));
}
-unsigned char parport_pc_read_econtrol(struct parport *p)
+void parport_pc_restore_state(struct parport *p, struct parport_state *s)
{
- return inb(ECONTROL(p));
+ const struct parport_pc_private *priv = p->physport->private_data;
+ outb (s->u.pc.ctr, CONTROL (p));
+ if (priv->ecr)
+ outb (s->u.pc.ecr, ECONTROL (p));
}
-unsigned char parport_pc_frob_econtrol(struct parport *p, unsigned char mask, unsigned char val)
+#ifdef CONFIG_PARPORT_1284
+static size_t parport_pc_epp_read_data (struct parport *port, void *buf,
+ size_t length, int flags)
{
- unsigned char old = inb(ECONTROL(p));
- outb(((old & ~mask) ^ val), ECONTROL(p));
- return old;
+ size_t got = 0;
+ for (; got < length; got++) {
+ *((char*)buf)++ = inb (EPPDATA(port));
+ if (inb (STATUS(port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return got;
}
-void parport_pc_change_mode(struct parport *p, int m)
+static size_t parport_pc_epp_write_data (struct parport *port, const void *buf,
+ size_t length, int flags)
{
- /* FIXME */
+ size_t written = 0;
+ for (; written < length; written++) {
+ outb (*((char*)buf)++, EPPDATA(port));
+ if (inb (STATUS(port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return written;
}
-void parport_pc_write_fifo(struct parport *p, unsigned char v)
+static size_t parport_pc_epp_read_addr (struct parport *port, void *buf,
+ size_t length, int flags)
{
- outb (v, CONFIGA(p));
+ size_t got = 0;
+ for (; got < length; got++) {
+ *((char*)buf)++ = inb (EPPADDR (port));
+ if (inb (STATUS (port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return got;
}
-unsigned char parport_pc_read_fifo(struct parport *p)
+static size_t parport_pc_epp_write_addr (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
{
- return inb (CONFIGA(p));
+ size_t written = 0;
+ for (; written < length; written++) {
+ outb (*((char*)buf)++, EPPADDR (port));
+ if (inb (STATUS (port)) & 0x01) {
+ clear_epp_timeout (port);
+ break;
+ }
+ }
+
+ return written;
}
-void parport_pc_disable_irq(struct parport *p)
+static size_t parport_pc_ecpepp_read_data (struct parport *port, void *buf,
+ size_t length, int flags)
{
- parport_pc_frob_control(p, 0x10, 0);
+ size_t got;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ got = parport_pc_epp_read_data (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return got;
}
-void parport_pc_enable_irq(struct parport *p)
+static size_t parport_pc_ecpepp_write_data (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
{
- parport_pc_frob_control(p, 0x10, 0x10);
+ size_t written;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ written = parport_pc_epp_write_data (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return written;
}
-void parport_pc_init_state(struct parport_state *s)
+static size_t parport_pc_ecpepp_read_addr (struct parport *port, void *buf,
+ size_t length, int flags)
{
- s->u.pc.ctr = 0xc;
- s->u.pc.ecr = 0x0;
+ size_t got;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ got = parport_pc_epp_read_addr (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return got;
}
-void parport_pc_save_state(struct parport *p, struct parport_state *s)
+static size_t parport_pc_ecpepp_write_addr (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
{
- s->u.pc.ctr = parport_pc_read_control(p);
- if (p->modes & PARPORT_MODE_PCECR)
- s->u.pc.ecr = parport_pc_read_econtrol(p);
+ size_t written;
+
+ frob_econtrol (port, 0xe0, ECR_EPP << 5);
+ written = parport_pc_epp_write_addr (port, buf, length, flags);
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ return written;
}
+#endif /* IEEE 1284 support */
-void parport_pc_restore_state(struct parport *p, struct parport_state *s)
+#ifdef CONFIG_PARPORT_PC_FIFO
+static size_t parport_pc_fifo_write_block_pio (struct parport *port,
+ const void *buf, size_t length)
{
- parport_pc_write_control(p, s->u.pc.ctr);
- if (p->modes & PARPORT_MODE_PCECR)
- parport_pc_write_econtrol(p, s->u.pc.ecr);
+ int ret = 0;
+ const unsigned char *bufp = buf;
+ size_t left = length;
+ 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);
+ frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+ /* Forward mode. */
+ parport_pc_data_forward (port);
+
+ while (left) {
+ unsigned char byte;
+ unsigned char ecrval = inb (ECONTROL (port));
+ int i = 0;
+
+ if (current->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 */
+ outb (ecrval & ~(1<<2), ECONTROL (port));
+ false_alarm:
+ ret = parport_wait_event (port, HZ);
+ if (ret < 0) break;
+ ret = 0;
+ if (!time_before (jiffies, expire)) {
+ /* Timed out. */
+ printk (KERN_DEBUG "Timed out\n");
+ break;
+ }
+ ecrval = inb (ECONTROL (port));
+ if (!(ecrval & (1<<2))) {
+ if (current->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--;
+ }
+
+ return length - left;
}
-size_t parport_pc_epp_read_block(struct parport *p, void *buf, size_t length)
+static size_t parport_pc_fifo_write_block_dma (struct parport *port,
+ const void *buf, size_t length)
{
- size_t got = 0;
- for (; got < length; got++) {
- *((char*)buf)++ = inb (EPPDATA(p));
- if (inb (STATUS(p)) & 0x01)
+ int ret = 0;
+ unsigned long dmaflag;
+ size_t left = length;
+ const struct parport_pc_private *priv = port->physport->private_data;
+
+ port = port->physport;
+
+ /* We don't want to be interrupted every character. */
+ parport_pc_disable_irq (port);
+ frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
+
+ /* Forward mode. */
+ parport_pc_data_forward (port);
+
+ while (left) {
+ long expire = jiffies + port->physport->cad->timeout;
+
+ size_t count = left;
+
+ if (count > PAGE_SIZE)
+ count = PAGE_SIZE;
+
+ 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, virt_to_bus((volatile char *) priv->dma_buf));
+ 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;
+
+ /* 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 "Timed out\n");
+ break;
+ }
+ /* Is serviceIntr set? */
+ if (!(inb (ECONTROL (port)) & (1<<2))) {
+ if (current->need_resched)
+ schedule ();
+
+ 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);
+
+ if (current->need_resched)
+ /* Can't yield the port. */
+ schedule ();
+
+ /* 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;
}
- return got;
+
+ /* 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);
+
+ return length - left;
}
-size_t parport_pc_epp_write_block(struct parport *p, void *buf, size_t length)
+/* Parallel Port FIFO mode (ECP chipsets) */
+size_t parport_pc_compat_write_block_pio (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
{
- size_t written = 0;
- for (; written < length; written++) {
- outb (*((char*)buf)++, EPPDATA(p));
- if (inb (STATUS(p)) & 0x01)
- break;
+ size_t written;
+
+ /* Special case: a timeout of zero means we cannot call schedule(). */
+ if (!port->physport->cad->timeout)
+ return parport_ieee1284_write_compat (port, buf,
+ length, flags);
+
+ /* Set up parallel port FIFO mode.*/
+ change_mode (port, ECR_PPF); /* Parallel port FIFO */
+ parport_pc_data_forward (port);
+ 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. */
+ if (change_mode (port, ECR_PS2) == -EBUSY) {
+ const struct parport_pc_private *priv =
+ port->physport->private_data;
+
+ printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+ /* Prevent further data transfer. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* 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. */
+ frob_econtrol (port, 0xe0, 0);
+
+ /* De-assert strobe. */
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
}
+
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY);
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
return written;
}
-int parport_pc_ecp_read_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
+/* ECP */
+#ifdef CONFIG_PARPORT_1284
+size_t parport_pc_ecp_write_block_pio (struct parport *port,
+ const void *buf, size_t length,
+ int flags)
{
- return -ENOSYS; /* FIXME */
+ size_t written;
+
+ /* Special case: a timeout of zero means we cannot call schedule(). */
+ if (!port->physport->cad->timeout)
+ 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, 0);
+
+ /* Event 40: PError goes high. */
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ }
+
+ /* Set up ECP parallel port mode.*/
+ change_mode (port, ECR_ECP); /* ECP FIFO */
+ parport_pc_data_forward (port);
+ 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. */
+ if (change_mode (port, ECR_PS2) == -EBUSY) {
+ const struct parport_pc_private *priv =
+ port->physport->private_data;
+
+ printk (KERN_DEBUG "%s: FIFO is stuck\n", port->name);
+
+ /* Prevent further data transfer. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_STROBE,
+ PARPORT_CONTROL_STROBE);
+
+ /* 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. */
+ frob_econtrol (port, 0xe0, 0);
+ parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
+
+ /* Host transfer recovery. */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+ parport_pc_data_reverse (port);
+ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_PAPEROUT,
+ PARPORT_STATUS_PAPEROUT);
+ }
+
+ parport_wait_peripheral (port,
+ PARPORT_STATUS_BUSY,
+ PARPORT_STATUS_BUSY);
+ port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
}
-int parport_pc_ecp_write_block(struct parport *p, void *buf, size_t length, void (*fn)(struct parport *, void *, size_t), void *handle)
+size_t parport_pc_ecp_read_block_pio (struct parport *port,
+ void *buf, size_t length, int flags)
{
- return -ENOSYS; /* FIXME */
+ size_t left = length;
+ size_t fifofull;
+ 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;
+
+ /* 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 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;
+
+ /* If the caller wants less than a full FIFO's worth of data,
+ * go through software emulation. Otherwise we may have to through
+ * 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) {
+ /* Event 38: Set nAutoFd low */
+ parport_frob_control (port,
+ PARPORT_CONTROL_AUTOFD,
+ PARPORT_CONTROL_AUTOFD);
+ parport_pc_data_reverse (port);
+ udelay (5);
+
+ /* Event 39: Set nInit low to initiate bus reversal */
+ parport_frob_control (port,
+ PARPORT_CONTROL_INIT,
+ PARPORT_CONTROL_INIT);
+
+ /* Event 40: PError goes low */
+ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
+ }
+
+ /* Set up ECP parallel port mode.*/
+ change_mode (port, ECR_ECP); /* ECP FIFO */
+ parport_pc_data_reverse (port);
+ port->ieee1284.phase = IEEE1284_PH_REV_DATA;
+
+ /* Do the transfer. */
+ while (left > fifofull) {
+ int ret;
+ long int expire = jiffies + port->cad->timeout;
+ unsigned char ecrval = inb (ECONTROL (port));
+
+ if (current->need_resched && time_before (jiffies, expire))
+ /* Can't yield the port. */
+ schedule ();
+
+ /* At this point, the FIFO may already be full.
+ * Ideally, we'd be able to tell the port to hold on
+ * for a second while we empty the FIFO, and we'd be
+ * able to ensure that no data is lost. I'm not sure
+ * that's the case. :-( It might be that you can play
+ * games with STB, as in the forward case; someone should
+ * look at a datasheet. */
+
+ if (ecrval & 0x01) {
+ /* FIFO is empty. Wait for interrupt. */
+
+ /* Anyone else waiting for the port? */
+ if (port->waithead) {
+ printk (KERN_DEBUG
+ "Somebody wants the port\n");
+ break;
+ }
+
+ /* Clear serviceIntr */
+ outb (ecrval & ~(1<<2), ECONTROL (port));
+ false_alarm:
+ ret = parport_wait_event (port, HZ);
+ if (ret < 0) break;
+ ret = 0;
+ if (!time_before (jiffies, expire)) {
+ /* Timed out. */
+ printk (KERN_DEBUG "Timed out\n");
+ break;
+ }
+ ecrval = inb (ECONTROL (port));
+ if (!(ecrval & (1<<2))) {
+ if (current->need_resched &&
+ time_before (jiffies, expire))
+ schedule ();
+
+ goto false_alarm;
+ }
+
+ continue;
+ }
+
+ if (ecrval & 0x02) {
+ /* FIFO is full. */
+ insb (fifo, bufp, fifo_depth);
+ bufp += fifo_depth;
+ left -= fifo_depth;
+ continue;
+ }
+
+ *bufp++ = inb (fifo);
+ left--;
+ }
+
+ /* Finish up. */
+ if (change_mode (port, ECR_PS2) == -EBUSY) {
+ int lost = get_fifo_residue (port);
+ printk (KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n", port->name,
+ lost);
+ }
+
+ port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
+
+ return length - left;
}
+#endif /* IEEE 1284 support */
+
+#endif /* Allowed to use FIFO/DMA */
+
void parport_pc_inc_use_count(void)
{
#ifdef MODULE
@@ -269,6 +930,7 @@ void parport_pc_dec_use_count(void)
static void parport_pc_fill_inode(struct inode *inode, int fill)
{
+ /* Is this still needed? -tim */
#ifdef MODULE
if (fill)
MOD_INC_USE_COUNT;
@@ -286,46 +948,39 @@ struct parport_operations parport_pc_ops =
parport_pc_read_control,
parport_pc_frob_control,
- parport_pc_write_econtrol,
- parport_pc_read_econtrol,
- parport_pc_frob_econtrol,
-
- parport_pc_write_status,
parport_pc_read_status,
- parport_pc_write_fifo,
- parport_pc_read_fifo,
-
- parport_pc_change_mode,
-
- parport_pc_write_epp,
- parport_pc_read_epp,
- parport_pc_write_epp_addr,
- parport_pc_read_epp_addr,
- parport_pc_check_epp_timeout,
+ parport_pc_enable_irq,
+ parport_pc_disable_irq,
- parport_pc_epp_write_block,
- parport_pc_epp_read_block,
+ parport_pc_data_forward,
+ parport_pc_data_reverse,
- parport_pc_ecp_write_block,
- parport_pc_ecp_read_block,
-
+ parport_pc_interrupt,
parport_pc_init_state,
parport_pc_save_state,
parport_pc_restore_state,
- parport_pc_enable_irq,
- parport_pc_disable_irq,
- parport_pc_interrupt,
-
parport_pc_inc_use_count,
parport_pc_dec_use_count,
- parport_pc_fill_inode
+ parport_pc_fill_inode,
+
+ parport_ieee1284_epp_write_data,
+ parport_ieee1284_epp_read_data,
+ parport_ieee1284_epp_write_addr,
+ parport_ieee1284_epp_read_addr,
+
+ parport_ieee1284_ecp_write_data,
+ parport_ieee1284_ecp_read_data,
+ parport_ieee1284_ecp_write_addr,
+
+ parport_ieee1284_write_compat,
+ parport_ieee1284_read_nibble,
+ parport_ieee1284_read_byte,
};
/* --- Mode detection ------------------------------------- */
-
/*
* Checks for port existence, all ports support SPP MODE
*/
@@ -339,22 +994,23 @@ static int __init parport_SPP_supported(struct parport *pb)
* that does not even respond to SPP cycles if an EPP
* timeout is pending
*/
- parport_pc_epp_clear_timeout(pb);
+ clear_epp_timeout(pb);
/* Do a simple read-write test to make sure the port exists. */
w = 0xc;
- parport_pc_write_control(pb, w);
+ outb (w, CONTROL (pb));
- /* Can we read from the control register? Some ports don't
- * allow reads, so read_control just returns a software
- * copy. Some ports _do_ allow reads, so bypass the software
- * copy here. In addition, some bits aren't writable. */
+ /* Is there a control register that we can read from? Some
+ * ports don't allow reads, so read_control just returns a
+ * software copy. Some ports _do_ allow reads, so bypass the
+ * software copy here. In addition, some bits aren't
+ * writable. */
r = inb (CONTROL (pb));
if ((r & 0xf) == w) {
w = 0xe;
- parport_pc_write_control (pb, w);
- r = inb (CONTROL(pb));
- parport_pc_write_control (pb, 0xc);
+ outb (w, CONTROL (pb));
+ r = inb (CONTROL (pb));
+ outb (0xc, CONTROL (pb));
if ((r & 0xf) == w)
return PARPORT_MODE_PCSPP;
}
@@ -379,20 +1035,20 @@ static int __init parport_SPP_supported(struct parport *pb)
}
if (user_specified)
- /* Didn't work with 0xaa, but the user is convinced
- * this is the place. */
+ /* Didn't work, but the user is convinced this is the
+ * place. */
printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
pb->base, w, r);
/* It's possible that we can't read the control register or
- the data register. In that case just believe the user. */
+ * the data register. In that case just believe the user. */
if (user_specified)
return PARPORT_MODE_PCSPP;
return 0;
}
-/* Check for ECP
+/* Check for ECR
*
* Old style XT ports alias io ports every 0x400, hence accessing ECR
* on these cards actually accesses the CTR.
@@ -401,82 +1057,225 @@ static int __init parport_SPP_supported(struct parport *pb)
* regardless of what is written here if the card does NOT support
* ECP.
*
- * We will write 0x2c to ECR and 0xcc to CTR since both of these
- * values are "safe" on the CTR since bits 6-7 of CTR are unused.
+ * We first check to see if ECR is the same as CTR. If not, the low
+ * two bits of ECR aren't writable, so we check by writing ECR and
+ * reading it back to see if it's what we expect.
*/
static int __init parport_ECR_present(struct parport *pb)
{
- unsigned char r;
+ struct parport_pc_private *priv = pb->private_data;
+ unsigned char r = 0xc;
- parport_pc_write_control (pb, 0xc);
- r = parport_pc_read_control(pb);
- if ((parport_pc_read_econtrol(pb) & 0x3) == (r & 0x3)) {
- parport_pc_write_control(pb, r ^ 0x2 ); /* Toggle bit 1 */
+ priv->ecr = 0;
+ outb (r, CONTROL (pb));
+ if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
+ outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
- r = parport_pc_read_control(pb);
- if ((parport_pc_read_econtrol(pb) & 0x2) == (r & 0x2))
+ r = inb (CONTROL (pb));
+ if ((inb (ECONTROL (pb)) & 0x2) == (r & 0x2))
goto no_reg; /* Sure that no ECR register exists */
}
- if ((parport_pc_read_econtrol(pb) & 0x3 ) != 0x1)
+ if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
goto no_reg;
- parport_pc_write_econtrol(pb, 0x34);
- if (parport_pc_read_econtrol(pb) != 0x35)
+ outb (0x34, ECONTROL (pb));
+ if (inb (ECONTROL (pb)) != 0x35)
goto no_reg;
- parport_pc_write_control(pb, 0xc);
-
- /* Go to mode 000; SPP, reset FIFO */
- parport_pc_frob_econtrol (pb, 0xe0, 0x00);
+ priv->ecr = 1;
+ outb (0xc, CONTROL (pb));
- return PARPORT_MODE_PCECR;
+ /* Go to mode 000 */
+ frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+
+ return 1;
no_reg:
- parport_pc_write_control (pb, 0xc);
- return 0;
+ outb (0xc, CONTROL (pb));
+ return 0;
+}
+
+#ifdef CONFIG_PARPORT_1284
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines. In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero. So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present.
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal. Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic.
+ */
+
+static int __init parport_PS2_supported(struct parport *pb)
+{
+ int ok = 0;
+
+ clear_epp_timeout(pb);
+
+ /* try to tri-state the buffer */
+ parport_pc_data_reverse (pb);
+
+ parport_pc_write_data(pb, 0x55);
+ if (parport_pc_read_data(pb) != 0x55) ok++;
+
+ parport_pc_write_data(pb, 0xaa);
+ if (parport_pc_read_data(pb) != 0xaa) ok++;
+
+ /* cancel input mode */
+ parport_pc_data_forward (pb);
+
+ if (ok)
+ pb->modes |= PARPORT_MODE_TRISTATE;
+ else {
+ struct parport_pc_private *priv = pb->private_data;
+ priv->ctr_writable &= ~0x20;
+ }
+
+ return ok;
}
static int __init parport_ECP_supported(struct parport *pb)
{
int i;
- unsigned char oecr;
-
+ int config;
+ int pword;
+ struct parport_pc_private *priv = pb->private_data;
+
/* If there is no ECR, we have no hope of supporting ECP. */
- if (!(pb->modes & PARPORT_MODE_PCECR))
+ if (!priv->ecr)
return 0;
- oecr = parport_pc_read_econtrol(pb);
+ /* Find out FIFO depth */
+ outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+ outb (ECR_TST << 5, ECONTROL (pb)); /* TEST FIFO */
+ for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02); i++)
+ outb (0xaa, FIFO (pb));
+
/*
* Using LGS chipset it uses ECR register, but
* it doesn't support ECP or FIFO MODE
*/
+ if (i == 1024) {
+ outb (ECR_SPP << 5, ECONTROL (pb));
+ return 0;
+ }
+
+ priv->fifo_depth = i;
+ printk (KERN_INFO "0x%lx: FIFO is %d bytes\n", pb->base, i);
+
+ /* Find out writeIntrThreshold */
+ frob_econtrol (pb, 1<<2, 1<<2);
+ frob_econtrol (pb, 1<<2, 0);
+ for (i = 1; i <= priv->fifo_depth; i++) {
+ inb (FIFO (pb));
+ udelay (50);
+ if (inb (ECONTROL (pb)) & (1<<2))
+ break;
+ }
+
+ if (i <= priv->fifo_depth)
+ printk (KERN_INFO "0x%lx: writeIntrThreshold is %d\n",
+ pb->base, i);
+ else
+ /* Number of bytes we know we can write if we get an
+ interrupt. */
+ i = 0;
+
+ priv->writeIntrThreshold = i;
+
+ /* Find out readIntrThreshold */
+ frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
+ parport_pc_data_reverse (pb);
+ frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
+ frob_econtrol (pb, 1<<2, 1<<2);
+ frob_econtrol (pb, 1<<2, 0);
+ for (i = 1; i <= priv->fifo_depth; i++) {
+ outb (0xaa, FIFO (pb));
+ if (inb (ECONTROL (pb)) & (1<<2))
+ break;
+ }
+
+ if (i <= priv->fifo_depth)
+ printk (KERN_INFO "0x%lx: readIntrThreshold is %d\n",
+ pb->base, i);
+ else
+ /* Number of bytes we can read if we get an interrupt. */
+ i = 0;
+
+ priv->readIntrThreshold = i;
+
+ outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+ outb (0xf4, ECONTROL (pb)); /* Configuration mode */
+ config = inb (FIFO (pb));
+ pword = (config >> 4) & 0x7;
+ switch (pword) {
+ case 0:
+ pword = 2;
+ printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+ pb->base);
+ break;
+ case 2:
+ pword = 4;
+ printk (KERN_WARNING "0x%lx: Unsupported pword size!\n",
+ pb->base);
+ break;
+ default:
+ printk (KERN_WARNING "0x%lx: Unknown implementation ID\n",
+ pb->base);
+ /* Assume 1 */
+ case 1:
+ pword = 1;
+ }
+ priv->pword = pword;
+ printk (KERN_DEBUG "0x%lx: PWord is %d bits\n", pb->base, 8 * pword);
+
+ config = inb (CONFIGB (pb));
+ printk (KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", pb->base,
+ config & 0x80 ? "Level" : "Pulses");
+
+ if (!(config & 0x40)) {
+ printk (KERN_WARNING "0x%lx: IRQ conflict!\n", pb->base);
+ pb->irq = PARPORT_IRQ_NONE;
+ }
+
+ /* Go back to mode 000 */
+ frob_econtrol (pb, 0xe0, ECR_SPP << 5);
+ pb->modes |= PARPORT_MODE_ECP;
+
+ return 1;
+}
+
+static int __init parport_ECPPS2_supported(struct parport *pb)
+{
+ const struct parport_pc_private *priv = pb->private_data;
+ int result;
+ unsigned char oecr;
+
+ if (!priv->ecr)
+ return 0;
+
+ oecr = inb (ECONTROL (pb));
+ outb (ECR_PS2 << 5, ECONTROL (pb));
- parport_pc_write_econtrol(pb, 0xc0); /* TEST FIFO */
- for (i=0; i < 1024 && (parport_pc_read_econtrol(pb) & 0x01); i++)
- parport_pc_write_fifo(pb, 0xaa);
+ result = parport_PS2_supported(pb);
- parport_pc_write_econtrol(pb, oecr);
- return (i==1024)?0:PARPORT_MODE_PCECP;
+ outb (oecr, ECONTROL (pb));
+ return result;
}
-/* EPP mode detection
- * Theory:
- * Bit 0 of STR is the EPP timeout bit, this bit is 0
- * when EPP is possible and is set high when an EPP timeout
- * occurs (EPP uses the HALT line to stop the CPU while it does
- * the byte transfer, an EPP timeout occurs if the attached
- * device fails to respond after 10 micro seconds).
- *
- * This bit is cleared by either reading it (National Semi)
- * or writing a 1 to the bit (SMC, UMC, WinBond), others ???
- * This bit is always high in non EPP modes.
- */
+/* EPP mode detection */
+
static int __init parport_EPP_supported(struct parport *pb)
{
- /* If EPP timeout bit clear then EPP available */
- if (!parport_pc_epp_clear_timeout(pb))
- return 0; /* No way to clear timeout */
+ const struct parport_pc_private *priv = pb->private_data;
/*
* Theory:
@@ -491,132 +1290,70 @@ static int __init parport_EPP_supported(struct parport *pb)
* This bit is always high in non EPP modes.
*/
- parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x20);
- parport_pc_write_control(pb, parport_pc_read_control(pb) | 0x10);
- parport_pc_epp_clear_timeout(pb);
-
- parport_pc_read_epp(pb);
- udelay(30); /* Wait for possible EPP timeout */
-
- if (parport_pc_read_status(pb) & 0x01) {
- parport_pc_epp_clear_timeout(pb);
- return PARPORT_MODE_PCEPP;
- }
-
- /*
- * Theory:
- * Write two values to the EPP address register and
- * read them back. When the transfer times out, the state of
- * the EPP register is undefined in some cases (EPP 1.9?) but
- * in others (EPP 1.7, ECPEPP?) it is possible to read back
- * its value.
- */
- parport_pc_epp_clear_timeout(pb);
- udelay(30); /* Wait for possible EPP timeout */
-
- /* Previous test left outputs disabled. */
- outb (0x55, EPPADDR (pb));
-
- parport_pc_epp_clear_timeout(pb);
- udelay(30); /* Wait for possible EPP timeout */
-
- /* We must enable the outputs to be able to read the address
- register. */
- parport_pc_frob_control (pb, 0x20, 0x00);
-
- if (inb (EPPADDR (pb)) == 0x55) {
-
- /* wash ... */
- parport_pc_frob_control (pb, 0x20, 0x20);
- outb (0xaa, EPPADDR (pb));
-
- parport_pc_epp_clear_timeout(pb);
- udelay(30); /* Wait for possible EPP timeout */
-
- /* ... and repeat */
- parport_pc_frob_control (pb, 0x20, 0x00);
+ /* If EPP timeout bit clear then EPP available */
+ if (!clear_epp_timeout(pb))
+ return 0; /* No way to clear timeout */
- if (inb (EPPADDR (pb)) == 0xaa) {
- parport_pc_epp_clear_timeout (pb);
- return PARPORT_MODE_PCEPP;
+ /* Check for Intel bug. */
+ if (priv->ecr) {
+ unsigned char i;
+ for (i = 0x00; i < 0x80; i += 0x20) {
+ outb (i, ECONTROL (pb));
+ if (clear_epp_timeout (pb))
+ /* Phony EPP in ECP. */
+ return 0;
}
}
- return 0;
+ pb->modes |= PARPORT_MODE_EPP;
+
+ /* Set up access functions to use EPP hardware. */
+ parport_pc_ops.epp_read_data = parport_pc_epp_read_data;
+ parport_pc_ops.epp_write_data = parport_pc_epp_write_data;
+ parport_pc_ops.epp_read_addr = parport_pc_epp_read_addr;
+ parport_pc_ops.epp_write_addr = parport_pc_epp_write_addr;
+
+ return 1;
}
static int __init parport_ECPEPP_supported(struct parport *pb)
{
- int mode;
+ struct parport_pc_private *priv = pb->private_data;
+ int result;
unsigned char oecr;
- if (!(pb->modes & PARPORT_MODE_PCECR))
+ if (!priv->ecr)
return 0;
- oecr = parport_pc_read_econtrol(pb);
+ oecr = inb (ECONTROL (pb));
/* Search for SMC style EPP+ECP mode */
- parport_pc_write_econtrol(pb, 0x80);
-
- mode = parport_EPP_supported(pb);
-
- parport_pc_write_econtrol(pb, oecr);
+ outb (0x80, ECONTROL (pb));
- return mode?PARPORT_MODE_PCECPEPP:0;
-}
-
-/* Detect PS/2 support.
- *
- * Bit 5 (0x20) sets the PS/2 data direction; setting this high
- * allows us to read data from the data lines. In theory we would get back
- * 0xff but any peripheral attached to the port may drag some or all of the
- * lines down to zero. So if we get back anything that isn't the contents
- * of the data register we deem PS/2 support to be present.
- *
- * Some SPP ports have "half PS/2" ability - you can't turn off the line
- * drivers, but an external peripheral with sufficiently beefy drivers of
- * its own can overpower them and assert its own levels onto the bus, from
- * where they can then be read back as normal. Ports with this property
- * and the right type of device attached are likely to fail the SPP test,
- * (as they will appear to have stuck bits) and so the fact that they might
- * be misdetected here is rather academic.
- */
+ result = parport_EPP_supported(pb);
-static int __init parport_PS2_supported(struct parport *pb)
-{
- int ok = 0;
- unsigned char octr = parport_pc_read_control(pb);
-
- parport_pc_epp_clear_timeout(pb);
-
- parport_pc_write_control(pb, octr | 0x20); /* try to tri-state the buffer */
-
- parport_pc_write_data(pb, 0x55);
- if (parport_pc_read_data(pb) != 0x55) ok++;
+ outb (oecr, ECONTROL (pb));
- parport_pc_write_data(pb, 0xaa);
- if (parport_pc_read_data(pb) != 0xaa) ok++;
-
- parport_pc_write_control(pb, octr); /* cancel input mode */
+ if (result) {
+ /* Set up access functions to use ECP+EPP hardware. */
+ parport_pc_ops.epp_read_data = parport_pc_ecpepp_read_data;
+ parport_pc_ops.epp_write_data = parport_pc_ecpepp_write_data;
+ parport_pc_ops.epp_read_addr = parport_pc_ecpepp_read_addr;
+ parport_pc_ops.epp_write_addr = parport_pc_ecpepp_write_addr;
+ }
- return ok?PARPORT_MODE_PCPS2:0;
+ return result;
}
-static int __init parport_ECPPS2_supported(struct parport *pb)
-{
- int mode;
- unsigned char oecr;
-
- if (!(pb->modes & PARPORT_MODE_PCECR))
- return 0;
+#else /* No IEEE 1284 support */
- oecr = parport_pc_read_econtrol(pb);
- parport_pc_write_econtrol(pb, 0x20);
-
- mode = parport_PS2_supported(pb);
+/* Don't bother probing for modes we know we won't use. */
+static int __init parport_PS2_supported(struct parport *pb) { return 0; }
+static int __init parport_ECP_supported(struct parport *pb) { return 0; }
+static int __init parport_EPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPEPP_supported(struct parport *pb) { return 0; }
+static int __init parport_ECPPS2_supported(struct parport *pb) { return 0; }
- parport_pc_write_econtrol(pb, oecr);
- return mode?PARPORT_MODE_PCECPPS2:0;
-}
+#endif /* No IEEE 1284 support */
/* --- IRQ detection -------------------------------------- */
@@ -624,17 +1361,17 @@ static int __init parport_ECPPS2_supported(struct parport *pb)
static int __init programmable_irq_support(struct parport *pb)
{
int irq, intrLine;
- unsigned char oecr = parport_pc_read_econtrol(pb);
+ unsigned char oecr = inb (ECONTROL (pb));
static const int lookup[8] = {
PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5
};
- parport_pc_write_econtrol(pb,0xE0); /* Configuration MODE */
-
- intrLine = (parport_pc_read_configb(pb) >> 3) & 0x07;
+ outb (ECR_CNF << 5, ECONTROL (pb)); /* Configuration MODE */
+
+ intrLine = (inb (CONFIGB (pb)) >> 3) & 0x07;
irq = lookup[intrLine];
- parport_pc_write_econtrol(pb, oecr);
+ outb (oecr, ECONTROL (pb));
return irq;
}
@@ -645,15 +1382,16 @@ static int __init irq_probe_ECP(struct parport *pb)
sti();
irqs = probe_irq_on();
- parport_pc_write_econtrol(pb, 0x00); /* Reset FIFO */
- parport_pc_write_econtrol(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
+ outb (ECR_SPP << 5, ECONTROL (pb)); /* Reset FIFO */
+ outb ((ECR_TST << 5) | 0x04, ECONTROL (pb));
+ outb (ECR_TST << 5, ECONTROL (pb));
- /* If Full FIFO sure that WriteIntrThresold is generated */
- for (i=0; i < 1024 && !(parport_pc_read_econtrol(pb) & 0x02) ; i++)
- parport_pc_write_fifo(pb, 0xaa);
+ /* If Full FIFO sure that writeIntrThreshold is generated */
+ for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++)
+ outb (0xaa, FIFO (pb));
pb->irq = probe_irq_off(irqs);
- parport_pc_write_econtrol(pb, 0x00);
+ outb (ECR_SPP << 5, ECONTROL (pb));
if (pb->irq <= 0)
pb->irq = PARPORT_IRQ_NONE;
@@ -671,22 +1409,21 @@ static int __init irq_probe_EPP(struct parport *pb)
return PARPORT_IRQ_NONE;
#else
int irqs;
- unsigned char octr = parport_pc_read_control(pb);
unsigned char oecr;
if (pb->modes & PARPORT_MODE_PCECR)
- oecr = parport_pc_read_econtrol(pb);
+ oecr = inb (ECONTROL (pb));
sti();
irqs = probe_irq_on();
if (pb->modes & PARPORT_MODE_PCECR)
- parport_pc_frob_econtrol (pb, 0x10, 0x10);
+ frob_econtrol (pb, 0x10, 0x10);
- parport_pc_epp_clear_timeout(pb);
+ clear_epp_timeout(pb);
parport_pc_frob_control (pb, 0x20, 0x20);
parport_pc_frob_control (pb, 0x10, 0x10);
- parport_pc_epp_clear_timeout(pb);
+ clear_epp_timeout(pb);
/* Device isn't expecting an EPP read
* and generates an IRQ.
@@ -696,56 +1433,20 @@ static int __init irq_probe_EPP(struct parport *pb)
pb->irq = probe_irq_off (irqs);
if (pb->modes & PARPORT_MODE_PCECR)
- parport_pc_write_econtrol(pb, oecr);
- parport_pc_write_control(pb, octr);
+ outb (oecr, ECONTROL (pb));
+ parport_pc_write_control(pb, 0xc);
if (pb->irq <= 0)
pb->irq = PARPORT_IRQ_NONE;
return pb->irq;
-#endif /* Advanced detection. */
+#endif /* Advanced detection */
}
static int __init irq_probe_SPP(struct parport *pb)
{
-#ifndef ADVANCED_DETECT
/* Don't even try to do this. */
return PARPORT_IRQ_NONE;
-#else
- int irqs;
- unsigned char octr = parport_pc_read_control(pb);
- unsigned char oecr;
-
- if (pb->modes & PARPORT_MODE_PCECR)
- oecr = parport_pc_read_econtrol(pb);
- probe_irq_off(probe_irq_on()); /* Clear any interrupts */
- irqs = probe_irq_on();
-
- if (pb->modes & PARPORT_MODE_PCECR)
- parport_pc_write_econtrol(pb, 0x10);
-
- parport_pc_write_data(pb,0x00);
- parport_pc_write_control(pb,0x00);
- parport_pc_write_control(pb,0x0c);
- udelay(5);
- parport_pc_write_control(pb,0x0d);
- udelay(5);
- parport_pc_write_control(pb,0x0c);
- udelay(25);
- parport_pc_write_control(pb,0x08);
- udelay(25);
- parport_pc_write_control(pb,0x0c);
- udelay(50);
-
- pb->irq = probe_irq_off(irqs);
- if (pb->irq <= 0)
- pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */
-
- if (pb->modes & PARPORT_MODE_PCECR)
- parport_pc_write_econtrol(pb, oecr);
- parport_pc_write_control(pb, octr);
- return pb->irq;
-#endif /* Advanced detection. */
}
/* We will attempt to share interrupt requests since other devices
@@ -757,25 +1458,27 @@ static int __init irq_probe_SPP(struct parport *pb)
*/
static int __init parport_irq_probe(struct parport *pb)
{
- if (pb->modes & PARPORT_MODE_PCECR) {
+ const struct parport_pc_private *priv = pb->private_data;
+
+ if (priv->ecr) {
pb->irq = programmable_irq_support(pb);
if (pb->irq != PARPORT_IRQ_NONE)
goto out;
}
- if (pb->modes & PARPORT_MODE_PCECP)
+ if (pb->modes & PARPORT_MODE_ECP)
pb->irq = irq_probe_ECP(pb);
- if (pb->irq == PARPORT_IRQ_NONE &&
- (pb->modes & PARPORT_MODE_PCECPEPP))
+ if (pb->irq == PARPORT_IRQ_NONE && priv->ecr &&
+ (pb->modes & PARPORT_MODE_EPP))
pb->irq = irq_probe_EPP(pb);
- parport_pc_epp_clear_timeout(pb);
+ clear_epp_timeout(pb);
- if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_PCEPP))
+ if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
pb->irq = irq_probe_EPP(pb);
- parport_pc_epp_clear_timeout(pb);
+ clear_epp_timeout(pb);
if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = irq_probe_SPP(pb);
@@ -784,6 +1487,33 @@ out:
return pb->irq;
}
+/* --- DMA detection -------------------------------------- */
+
+/* Only if supports ECP mode */
+static int __init programmable_dma_support (struct parport *p)
+{
+ unsigned char oecr = inb (ECONTROL (p));
+ int dma;
+
+ frob_econtrol (p, 0xe0, ECR_CNF << 5);
+
+ dma = inb (CONFIGB(p)) & 0x03;
+ if (!dma)
+ dma = PARPORT_DMA_NONE;
+
+ outb (oecr, ECONTROL (p));
+ return dma;
+}
+
+static int __init parport_dma_probe (struct parport *p)
+{
+ const struct parport_pc_private *priv = p->private_data;
+ if (priv->ecr)
+ p->dma = programmable_dma_support(p);
+
+ return p->dma;
+}
+
/* --- Initialisation code -------------------------------- */
static int __init probe_one_port(unsigned long int base,
@@ -801,6 +1531,10 @@ static int __init probe_one_port(unsigned long int base,
return 0;
}
priv->ctr = 0xc;
+ priv->ctr_writable = 0xff;
+ priv->ecr = 0;
+ priv->fifo_depth = 0;
+ priv->dma_buf = 0;
p->base = base;
p->base_hi = base_hi;
p->irq = irq;
@@ -808,39 +1542,41 @@ static int __init probe_one_port(unsigned long int base,
p->modes = PARPORT_MODE_PCSPP;
p->ops = &parport_pc_ops;
p->private_data = priv;
- if (base_hi && !check_region (base_hi, 3)) {
- p->modes |= parport_ECR_present (p);
- p->modes |= parport_ECP_supported (p);
- p->modes |= parport_ECPPS2_supported (p);
+ p->physport = p;
+ if (base_hi && !check_region(base_hi,3)) {
+ parport_ECR_present(p);
+ parport_ECP_supported(p);
+ parport_ECPPS2_supported(p);
}
- if (p->base != 0x3bc) {
+ if (base != 0x3bc) {
if (!check_region(base+0x3, 5)) {
- p->modes |= parport_EPP_supported (p);
- p->modes |= parport_ECPEPP_supported (p);
+ parport_EPP_supported(p);
+ if (!(p->modes & PARPORT_MODE_EPP))
+ parport_ECPEPP_supported(p);
}
}
- if (!parport_SPP_supported(p)) {
+ if (!parport_SPP_supported (p)) {
/* No port. */
kfree (priv);
return 0;
}
- p->modes |= parport_PS2_supported(p);
+ parport_PS2_supported (p);
- if (!(p = parport_register_port (base, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, &parport_pc_ops))) {
+ if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
+ PARPORT_DMA_NONE, &parport_pc_ops))) {
kfree (priv);
return 0;
}
p->base_hi = base_hi;
p->modes = tmp.modes;
- p->size = (p->modes & PARPORT_MODE_PCEPP) ? 8 : 3;
+ p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
p->private_data = priv;
printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
- if (p->base_hi && (p->modes & PARPORT_MODE_PCECR))
- printk (" (0x%lx)", p->base_hi);
+ if (p->base_hi && (p->modes & PARPORT_MODE_ECP))
+ printk(" (0x%lx)", p->base_hi);
p->irq = irq;
p->dma = dma;
if (p->irq == PARPORT_IRQ_AUTO) {
@@ -852,33 +1588,54 @@ static int __init probe_one_port(unsigned long int base,
probedirq = p->irq;
p->irq = PARPORT_IRQ_NONE;
}
- if (p->irq != PARPORT_IRQ_NONE)
+ if (p->irq != PARPORT_IRQ_NONE) {
printk(", irq %d", p->irq);
+
+ if (p->dma == PARPORT_DMA_AUTO) {
+ p->dma = PARPORT_DMA_NONE;
+ parport_dma_probe(p);
+ }
+ }
if (p->dma == PARPORT_DMA_AUTO)
p->dma = PARPORT_DMA_NONE;
- if (p->dma != PARPORT_DMA_NONE)
+ if (p->dma != PARPORT_DMA_NONE)
printk(", dma %d", p->dma);
+
+#ifdef CONFIG_PARPORT_PC_FIFO
+ if (priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) {
+ parport_pc_ops.compat_write_data =
+ parport_pc_compat_write_block_pio;
+#ifdef CONFIG_PARPORT_1284
+ parport_pc_ops.ecp_write_data =
+ parport_pc_ecp_write_block_pio;
+#endif /* IEEE 1284 support */
+ if (p->dma != PARPORT_DMA_NONE)
+ p->modes |= PARPORT_MODE_DMA;
+ printk(", using FIFO");
+ }
+#endif /* Allowed to use FIFO/DMA */
+
printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}}
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
{
int f = 0;
- printmode(SPP);
- printmode(PS2);
+ printmode(PCSPP);
+ printmode(TRISTATE);
+ printmode(COMPAT)
printmode(EPP);
printmode(ECP);
- printmode(ECPEPP);
- printmode(ECPPS2);
+ printmode(DMA);
}
#undef printmode
printk("]\n");
-#ifdef CONFIG_PROC_FS
if (probedirq != PARPORT_IRQ_NONE)
- printk("%s: detected irq %d; use procfs to enable interrupt-driven operation.\n", p->name, probedirq);
-#endif
+ printk("%s: irq %d detected\n", p->name, probedirq);
parport_proc_register(p);
- request_region (p->base, p->size, p->name);
- if (p->modes & PARPORT_MODE_PCECR)
+ request_region (p->base, 3, p->name);
+ if (p->size > 3)
+ request_region (p->base + 3, p->size - 3, p->name);
+ if (p->modes & PARPORT_MODE_ECP)
request_region (p->base_hi, 3, p->name);
if (p->irq != PARPORT_IRQ_NONE) {
@@ -897,25 +1654,38 @@ static int __init probe_one_port(unsigned long int base,
"resorting to PIO operation\n",
p->name, p->dma);
p->dma = PARPORT_DMA_NONE;
+ } else {
+ priv->dma_buf = (char *) __get_dma_pages(GFP_KERNEL, 1);
+ if (! priv->dma_buf) {
+ printk (KERN_WARNING "%s: "
+ "cannot get buffer for DMA, "
+ "resorting to PIO operation\n",
+ p->name);
+ free_dma(p->dma);
+ p->dma = PARPORT_DMA_NONE;
+ }
}
}
}
- /* Done probing. Now put the port into a sensible start-up state. */
- if (p->modes & PARPORT_MODE_PCECR)
+ /* Done probing. Now put the port into a sensible start-up state.
+ * SELECT | INIT also puts IEEE1284-compliant devices into
+ * compatibility mode. */
+ if (p->modes & PARPORT_MODE_ECP)
/*
* Put the ECP detected port in PS2 mode.
*/
- parport_pc_write_econtrol(p, 0x24);
+ outb (0x24, ECONTROL (p));
+
parport_pc_write_data(p, 0);
- parport_pc_write_control(p, 0x8);
+ parport_pc_data_forward (p);
+ parport_pc_write_control(p, PARPORT_CONTROL_SELECT);
udelay (50);
- parport_pc_write_control(p, 0xc);
+ parport_pc_write_control(p,
+ PARPORT_CONTROL_SELECT
+ | PARPORT_CONTROL_INIT);
udelay (50);
- if (parport_probe_hook)
- (*parport_probe_hook)(p);
-
/* Now that we've told the sharing engine about the port, and
found out its characteristics, let the high-level drivers
know about it. */
@@ -953,11 +1723,8 @@ static int __init parport_pc_init_pci (int irq, int dma)
#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000
#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8001 /* The Lava Dual Parallel is */
#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8002 /* two PCI devices on a card */
-#endif /* IDs not defined */
+#endif
- int count = 0;
-#ifdef CONFIG_PCI
- int i;
struct {
unsigned int vendor;
unsigned int device;
@@ -1014,6 +1781,9 @@ static int __init parport_pc_init_pci (int irq, int dma)
{ 0, }
};
+ int count = 0;
+ int i;
+
if (!pci_present ())
return 0;
@@ -1036,7 +1806,6 @@ static int __init parport_pc_init_pci (int irq, int dma)
}
}
}
-#endif /* CONFIG_PCI */
return count;
}
@@ -1070,17 +1839,9 @@ static int dmaval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PAR
static int irqval[PARPORT_PC_MAX_PORTS] = { [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY };
static const char *irq[PARPORT_PC_MAX_PORTS] = { NULL, };
static const char *dma[PARPORT_PC_MAX_PORTS] = { NULL, };
-
-MODULE_PARM_DESC(io, "base address");
MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-
-MODULE_PARM_DESC(io_hi, "base address for ECR");
MODULE_PARM(io_hi, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "i");
-
-MODULE_PARM_DESC(irq, "irq line to use (or 'auto' or 'none')");
MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-
-MODULE_PARM_DESC(dma, "dma channel to use (or 'auto' or 'none')");
MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
int init_module(void)
@@ -1120,15 +1881,20 @@ void cleanup_module(void)
struct parport *p = parport_enumerate(), *tmp;
while (p) {
tmp = p->next;
- if (p->modes & PARPORT_MODE_PCSPP) {
+ if (p->modes & PARPORT_MODE_PCSPP) {
+ struct parport_pc_private *priv = p->private_data;
if (p->dma != PARPORT_DMA_NONE)
- free_dma (p->dma);
+ free_dma(p->dma);
if (p->irq != PARPORT_IRQ_NONE)
- free_irq (p->irq, p);
- release_region (p->base, p->size);
- if (p->modes & PARPORT_MODE_PCECP)
- release_region (p->base_hi, 3);
+ free_irq(p->irq, p);
+ release_region(p->base, 3);
+ if (p->size > 3);
+ release_region(p->base + 3, p->size - 3);
+ if (p->modes & PARPORT_MODE_ECP)
+ release_region(p->base_hi, 3);
parport_proc_unregister(p);
+ if (priv->dma_buf)
+ free_page((unsigned long) priv->dma_buf);
kfree (p->private_data);
parport_unregister_port(p);
}
diff --git a/drivers/misc/parport_probe.c b/drivers/misc/parport_probe.c
new file mode 100644
index 000000000..a3c24c989
--- /dev/null
+++ b/drivers/misc/parport_probe.c
@@ -0,0 +1,212 @@
+/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
+ * Parallel port device probing code
+ *
+ * Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
+ * Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <linux/parport.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+
+static struct {
+ char *token;
+ char *descr;
+} classes[] = {
+ { "", "Legacy device" },
+ { "PRINTER", "Printer" },
+ { "MODEM", "Modem" },
+ { "NET", "Network device" },
+ { "HDC", "Hard disk" },
+ { "PCMCIA", "PCMCIA" },
+ { "MEDIA", "Multimedia device" },
+ { "FDC", "Floppy disk" },
+ { "PORTS", "Ports" },
+ { "SCANNER", "Scanner" },
+ { "DIGICAM", "Digital camera" },
+ { "", "Unknown device" },
+ { "", "Unspecified" },
+ { "SCSIADAPTER", "SCSI adapter" },
+ { NULL, NULL }
+};
+
+static void pretty_print(struct parport *port, int device)
+{
+ struct parport_device_info *info = &port->probe_info[device + 1];
+
+ printk(KERN_INFO "%s", port->name);
+
+ if (device >= 0)
+ printk (" (addr %d)", device);
+
+ printk (": %s", classes[info->class].descr);
+ if (info->class)
+ printk(", %s %s", info->mfr, info->model);
+
+ printk("\n");
+}
+
+static char *strdup(char *str)
+{
+ int n = strlen(str)+1;
+ char *s = kmalloc(n, GFP_KERNEL);
+ if (!s) return NULL;
+ return strcpy(s, str);
+}
+
+static void parse_data(struct parport *port, int device, char *str)
+{
+ char *txt = kmalloc(strlen(str)+1, GFP_KERNEL);
+ char *p = txt, *q;
+ int guessed_class = PARPORT_CLASS_UNSPEC;
+ struct parport_device_info *info = &port->probe_info[device + 1];
+
+ if (!txt) {
+ printk("%s probe: memory squeeze\n", port->name);
+ return;
+ }
+ strcpy(txt, str);
+ while (p) {
+ char *sep;
+ q = strchr(p, ';');
+ if (q) *q = 0;
+ sep = strchr(p, ':');
+ if (sep) {
+ char *u = p;
+ *(sep++) = 0;
+ while (*u) {
+ *u = toupper(*u);
+ u++;
+ }
+ if (!strcmp(p, "MFG") || !strcmp(p, "MANUFACTURER")) {
+ if (info->mfr)
+ kfree (info->mfr);
+ info->mfr = strdup(sep);
+ } else if (!strcmp(p, "MDL") || !strcmp(p, "MODEL")) {
+ if (info->model)
+ kfree (info->model);
+ info->model = strdup(sep);
+ } else if (!strcmp(p, "CLS") || !strcmp(p, "CLASS")) {
+ int i;
+ if (info->class_name)
+ kfree (info->class_name);
+ info->class_name = strdup(sep);
+ for (u = sep; *u; u++)
+ *u = toupper(*u);
+ for (i = 0; classes[i].token; i++) {
+ if (!strcmp(classes[i].token, sep)) {
+ info->class = i;
+ goto rock_on;
+ }
+ }
+ printk(KERN_WARNING "%s probe: warning, class '%s' not understood.\n", port->name, sep);
+ info->class = PARPORT_CLASS_OTHER;
+ } else if (!strcmp(p, "CMD") ||
+ !strcmp(p, "COMMAND SET")) {
+ if (info->cmdset)
+ kfree (info->cmdset);
+ info->cmdset = strdup(sep);
+ /* if it speaks printer language, it's
+ probably a printer */
+ if (strstr(sep, "PJL") || strstr(sep, "PCL"))
+ guessed_class = PARPORT_CLASS_PRINTER;
+ } else if (!strcmp(p, "DES") || !strcmp(p, "DESCRIPTION")) {
+ if (info->description)
+ kfree (info->description);
+ info->description = strdup(sep);
+ }
+ }
+ rock_on:
+ if (q) p = q+1; else p=NULL;
+ }
+
+ /* If the device didn't tell us its class, maybe we have managed to
+ guess one from the things it did say. */
+ if (info->class == PARPORT_CLASS_UNSPEC)
+ info->class = guessed_class;
+
+ pretty_print (port, device);
+
+ kfree(txt);
+}
+
+/* Get Std 1284 Device ID. */
+ssize_t parport_device_id (int devnum, char *buffer, size_t len)
+{
+ ssize_t retval = -ENXIO;
+ struct pardevice *dev = parport_open (devnum, "Device ID probe",
+ NULL, NULL, NULL, 0, NULL);
+ if (!dev)
+ return -ENXIO;
+
+ parport_claim_or_block (dev);
+
+ /* Negotiate to compatibility mode, and then to device ID mode.
+ * (This is in case we are already in device ID mode.) */
+ parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+ retval = parport_negotiate (dev->port,
+ IEEE1284_MODE_NIBBLE | IEEE1284_DEVICEID);
+
+ if (!retval) {
+ int idlen;
+ unsigned char length[2];
+ mm_segment_t oldfs = get_fs ();
+ set_fs (get_ds ());
+
+ /* First two bytes are MSB,LSB of inclusive length. */
+ retval = parport_read (dev->port, length, 2);
+
+ if (retval != 2) goto restore_fs;
+
+ idlen = (length[0] << 8) + length[1] - 2;
+ if (idlen < len)
+ len = idlen;
+ retval = parport_read (dev->port, buffer, len);
+
+ if (retval != len) {
+ printk (KERN_DEBUG "%s: only read %d of %d ID bytes\n",
+ dev->port->name, retval, len);
+ goto restore_fs;
+ }
+
+ /* Some printer manufacturers mistakenly believe that
+ the length field is supposed to be _exclusive_. */
+ /* In addition, there are broken devices out there
+ that don't even finish off with a semi-colon. */
+ if (idlen == len && buffer[len - 1] != ';') {
+ ssize_t diff;
+ diff = parport_read (dev->port, buffer + len, 2);
+ retval += diff;
+
+ if (diff)
+ printk (KERN_DEBUG
+ "%s: device reported incorrect "
+ "length field (%d, should be %d)\n",
+ dev->port->name, idlen, retval);
+ else {
+ /* One semi-colon short of a device ID. */
+ buffer[len++] = ';';
+ buffer[len] = '\0';
+ printk (KERN_DEBUG "%s: faking semi-colon\n",
+ dev->port->name);
+
+ /* If we get here, I don't think we
+ need to worry about the possible
+ standard violation of having read
+ more than we were told to. The
+ device is non-compliant anyhow. */
+ }
+ }
+
+ restore_fs:
+ set_fs (oldfs);
+ parport_negotiate (dev->port, IEEE1284_MODE_COMPAT);
+ }
+ parport_release (dev);
+
+ if (retval > 0)
+ parse_data (dev->port, dev->daisy, buffer);
+
+ parport_close (dev);
+ return retval;
+}
diff --git a/drivers/misc/parport_procfs.c b/drivers/misc/parport_procfs.c
index f3dc63c46..0c7be433c 100644
--- a/drivers/misc/parport_procfs.c
+++ b/drivers/misc/parport_procfs.c
@@ -62,7 +62,7 @@ static int do_active_device(ctl_table *table, int write, struct file *filp,
return copy_to_user(result, buffer, len) ? -EFAULT : 0;
}
-#if 0 && defined (CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
static int do_autoprobe(ctl_table *table, int write, struct file *filp,
void *result, size_t *lenp)
{
@@ -146,9 +146,11 @@ static int do_hardware(ctl_table *table, int write, struct file *filp,
#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
int f = 0;
printmode(PCSPP);
- printmode(PCPS2);
- printmode(PCEPP);
- printmode(PCECP);
+ printmode(TRISTATE);
+ printmode(COMPAT);
+ printmode(EPP);
+ printmode(ECP);
+ printmode(DMA);
#undef printmode
}
buffer[len++] = '\n';
@@ -190,7 +192,7 @@ static const struct parport_sysctl_table parport_sysctl_template = {
NULL, 0, 0444, NULL,
&do_hardware },
PARPORT_DEVICES_ROOT_DIR,
-#if 0 && defined(CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
{ DEV_PARPORT_AUTOPROBE, "autoprobe",
NULL, 0, 0444, NULL,
&do_autoprobe },
@@ -292,17 +294,11 @@ int parport_proc_register(struct parport *port)
for (i = 0; i < 8; i++)
t->vars[i].extra1 = port;
-#if 0 /* Wait for IEEE 1284 support */
t->vars[0].data = &port->spintime;
-#endif
t->vars[2].child = t->device_dir;
for (i = 0; i < 5; i++)
-#if 0
t->vars[3 + i].extra2 = &port->probe_info[i];
-#else
- t->vars[3 + i].extra2 = &port->probe_info;
-#endif
t->port_dir[0].procname = port->name;
t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
@@ -348,7 +344,7 @@ int parport_device_proc_register(struct pardevice *device)
t->port_dir[0].child = t->devices_root_dir;
t->devices_root_dir[0].child = t->device_dir;
-#if 0 && defined(CONFIG_PARPORT_1284)
+#ifdef CONFIG_PARPORT_1284
t->device_dir[0].ctl_name =
parport_device_num(port->number, port->muxport,
diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c
index 773091002..acf8b64a4 100644
--- a/drivers/misc/parport_share.c
+++ b/drivers/misc/parport_share.c
@@ -14,11 +14,8 @@
#undef PARPORT_DEBUG_SHARING /* undef for production */
#include <linux/config.h>
-
#include <linux/string.h>
-
#include <linux/tasks.h>
-
#include <linux/parport.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -31,18 +28,12 @@
#include <asm/spinlock.h>
#include <asm/irq.h>
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
#undef PARPORT_PARANOID
#define PARPORT_DEFAULT_TIMESLICE (HZ/5)
unsigned long parport_default_timeslice = PARPORT_DEFAULT_TIMESLICE;
-
-/* This doesn't do anything yet. */
-int parport_default_spintime;
+int parport_default_spintime = DEFAULT_SPIN_TIME;
static struct parport *portlist = NULL, *portlist_tail = NULL;
spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
@@ -50,7 +41,7 @@ spinlock_t parportlist_lock = SPIN_LOCK_UNLOCKED;
static struct parport_driver *driver_chain = NULL;
spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
-static void call_driver_chain (int attach, struct parport *port)
+static void call_driver_chain(int attach, struct parport *port)
{
struct parport_driver *drv;
@@ -96,19 +87,9 @@ void parport_unregister_driver (struct parport_driver *arg)
}
}
-void (*parport_probe_hook)(struct parport *port) = NULL;
-
/* Return a list of all the ports we know about. */
struct parport *parport_enumerate(void)
{
-#ifdef CONFIG_KMOD
- if (portlist == NULL) {
- request_module("parport_lowlevel");
-#ifdef CONFIG_PNP_PARPORT_MODULE
- request_module("parport_probe");
-#endif /* CONFIG_PNP_PARPORT_MODULE */
- }
-#endif /* CONFIG_KMOD */
return portlist;
}
@@ -117,16 +98,9 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
{
struct parport *tmp;
int portnum;
+ int device;
char *name;
- /* Check for a previously registered port.
- NOTE: we will ignore irq and dma if we find a previously
- registered device. */
- for (tmp = portlist; tmp; tmp = tmp->next) {
- if (tmp->base == base)
- return tmp;
- }
-
tmp = kmalloc(sizeof(struct parport), GFP_KERNEL);
if (!tmp) {
printk(KERN_WARNING "parport: memory squeeze\n");
@@ -154,16 +128,22 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
tmp->base = base;
tmp->irq = irq;
tmp->dma = dma;
+ tmp->muxport = tmp->daisy = tmp->muxsel = -1;
tmp->modes = 0;
tmp->next = NULL;
tmp->devices = tmp->cad = NULL;
tmp->flags = 0;
tmp->ops = ops;
- tmp->number = portnum;
- memset (&tmp->probe_info, 0, sizeof (struct parport_device_info));
+ tmp->portnum = tmp->number = portnum;
+ tmp->physport = tmp;
+ memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info));
tmp->cad_lock = RW_LOCK_UNLOCKED;
spin_lock_init(&tmp->waitlist_lock);
spin_lock_init(&tmp->pardevice_lock);
+ tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
+ tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+ init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
+ tmp->spintime = parport_default_spintime;
name = kmalloc(15, GFP_KERNEL);
if (!name) {
@@ -188,7 +168,10 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
portlist = tmp;
spin_unlock(&parportlist_lock);
- tmp->probe_info.class = PARPORT_CLASS_LEGACY; /* assume the worst */
+ for (device = 0; device < 5; device++)
+ /* assume the worst */
+ tmp->probe_info[device].class = PARPORT_CLASS_LEGACY;
+
tmp->waithead = tmp->waittail = NULL;
return tmp;
@@ -196,6 +179,11 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
void parport_announce_port (struct parport *port)
{
+#ifdef CONFIG_PARPORT_1284
+ /* Analyse the IEEE1284.3 topology of the port. */
+ parport_daisy_init (port);
+#endif
+
/* Let drivers know that a new port has arrived. */
call_driver_chain (1, port);
}
@@ -203,10 +191,16 @@ void parport_announce_port (struct parport *port)
void parport_unregister_port(struct parport *port)
{
struct parport *p;
+ int d;
/* Spread the word. */
call_driver_chain (0, port);
+#ifdef CONFIG_PARPORT_1284
+ /* Forget the IEEE1284.3 topology of the port. */
+ parport_daisy_fini (port);
+#endif
+
spin_lock(&parportlist_lock);
if (portlist == port) {
if ((portlist = port->next) == NULL)
@@ -222,16 +216,20 @@ void parport_unregister_port(struct parport *port)
"%s not found in port list!\n", port->name);
}
spin_unlock(&parportlist_lock);
- if (port->probe_info.class_name)
- kfree (port->probe_info.class_name);
- if (port->probe_info.mfr)
- kfree (port->probe_info.mfr);
- if (port->probe_info.model)
- kfree (port->probe_info.model);
- if (port->probe_info.cmdset)
- kfree (port->probe_info.cmdset);
- if (port->probe_info.description)
- kfree (port->probe_info.description);
+
+ for (d = 0; d < 5; d++) {
+ if (port->probe_info[d].class_name)
+ kfree (port->probe_info[d].class_name);
+ if (port->probe_info[d].mfr)
+ kfree (port->probe_info[d].mfr);
+ if (port->probe_info[d].model)
+ kfree (port->probe_info[d].model);
+ if (port->probe_info[d].cmdset)
+ kfree (port->probe_info[d].cmdset);
+ if (port->probe_info[d].description)
+ kfree (port->probe_info[d].description);
+ }
+
kfree(port->name);
kfree(port);
}
@@ -243,7 +241,7 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
{
struct pardevice *tmp;
- if (port->flags & PARPORT_FLAG_EXCL) {
+ if (port->physport->flags & PARPORT_FLAG_EXCL) {
/* An exclusive device is registered. */
printk (KERN_DEBUG "%s: no more devices allowed\n",
port->name);
@@ -272,13 +270,14 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
tmp->name = name;
tmp->port = port;
+ tmp->daisy = -1;
tmp->preempt = pf;
tmp->wakeup = kf;
tmp->private = handle;
tmp->flags = flags;
tmp->irq_func = irq_func;
- port->ops->init_state(tmp->state);
tmp->waiting = 0;
+ tmp->timeout = 5 * HZ;
/* Chain this onto the list */
tmp->prev = NULL;
@@ -286,11 +285,11 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
* This function must not run from an irq handler so we don' t need
* to clear irq on the local CPU. -arca
*/
- spin_lock(&port->pardevice_lock);
+ spin_lock(&port->physport->pardevice_lock);
if (flags & PARPORT_DEV_EXCL) {
- if (port->devices) {
- spin_unlock (&port->pardevice_lock);
+ if (port->physport->devices) {
+ spin_unlock (&port->physport->pardevice_lock);
kfree (tmp->state);
kfree (tmp);
printk (KERN_DEBUG
@@ -301,11 +300,11 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
port->flags |= PARPORT_FLAG_EXCL;
}
- tmp->next = port->devices;
- if (port->devices)
- port->devices->prev = tmp;
- port->devices = tmp;
- spin_unlock(&port->pardevice_lock);
+ tmp->next = port->physport->devices;
+ if (port->physport->devices)
+ port->physport->devices->prev = tmp;
+ port->physport->devices = tmp;
+ spin_unlock(&port->physport->pardevice_lock);
inc_parport_count();
port->ops->inc_use_count();
@@ -314,6 +313,12 @@ struct pardevice *parport_register_device(struct parport *port, const char *name
tmp->timeslice = parport_default_timeslice;
tmp->waitnext = tmp->waitprev = NULL;
+ /*
+ * This has to be run as last thing since init_state may need other
+ * pardevice fields. -arca
+ */
+ port->ops->init_state(tmp, tmp->state);
+ parport_device_proc_register(tmp);
return tmp;
}
@@ -328,7 +333,9 @@ void parport_unregister_device(struct pardevice *dev)
}
#endif
- port = dev->port;
+ parport_device_proc_unregister(dev);
+
+ port = dev->port->physport;
if (port->cad == dev) {
printk(KERN_DEBUG "%s: %s forgot to release port\n",
@@ -354,19 +361,17 @@ void parport_unregister_device(struct pardevice *dev)
dec_parport_count();
port->ops->dec_use_count();
-
- return;
}
int parport_claim(struct pardevice *dev)
{
struct pardevice *oldcad;
- struct parport *port = dev->port;
+ struct parport *port = dev->port->physport;
unsigned long flags;
if (port->cad == dev) {
printk(KERN_INFO "%s: %s already owner\n",
- dev->port->name,dev->name);
+ dev->port->name,dev->name);
return 0;
}
@@ -407,24 +412,27 @@ try_again:
dev->waitprev = dev->waitnext = NULL;
}
- if (oldcad && port->irq != PARPORT_IRQ_NONE && !oldcad->irq_func)
- /*
- * If there was an irq pending it should hopefully happen
- * before return from enable_irq(). -arca
- */
- enable_irq(port->irq);
-
- /*
- * Avoid running irq handlers if the pardevice doesn' t use it. -arca
- */
- if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
- disable_irq(port->irq);
-
/* Now we do the change of devices */
write_lock_irqsave(&port->cad_lock, flags);
port->cad = dev;
write_unlock_irqrestore(&port->cad_lock, flags);
+#ifdef CONFIG_PARPORT_1284
+ /* If it's a mux port, select it. */
+ if (dev->port->muxport >= 0) {
+ /* FIXME */
+ port->muxsel = dev->port->muxport;
+ }
+
+ /* If it's a daisy chain device, select it. */
+ if (dev->daisy >= 0) {
+ /* This could be lazier. */
+ if (!parport_daisy_select (port, dev->daisy,
+ IEEE1284_MODE_COMPAT))
+ port->daisy = dev->daisy;
+ }
+#endif /* IEEE1284.3 support */
+
/* Restore control registers */
port->ops->restore_state(port, dev->state);
dev->time = jiffies;
@@ -487,8 +495,11 @@ int parport_claim_or_block(struct pardevice *dev)
}
restore_flags(flags);
#ifdef PARPORT_DEBUG_SHARING
- if (dev->port->cad != dev)
- printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", dev->name, dev->port->cad?dev->port->cad->name:"nobody");
+ if (dev->port->physport->cad != dev)
+ printk(KERN_DEBUG "%s: exiting parport_claim_or_block "
+ "but %s owns port!\n", dev->name,
+ dev->port->physport->cad ?
+ dev->port->physport->cad->name:"nobody");
#endif
}
dev->waiting = 0;
@@ -497,7 +508,7 @@ int parport_claim_or_block(struct pardevice *dev)
void parport_release(struct pardevice *dev)
{
- struct parport *port = dev->port;
+ struct parport *port = dev->port->physport;
struct pardevice *pd;
unsigned long flags;
@@ -507,17 +518,25 @@ void parport_release(struct pardevice *dev)
"when not owner\n", port->name, dev->name);
return;
}
+
+#ifdef CONFIG_PARPORT_1284
+ /* If this is on a mux port, deselect it. */
+ if (dev->port->muxport >= 0) {
+ /* FIXME */
+ port->muxsel = -1;
+ }
+
+ /* If this is a daisy device, deselect it. */
+ if (dev->daisy >= 0) {
+ parport_daisy_deselect_all (port);
+ port->daisy = -1;
+ }
+#endif
+
write_lock_irqsave(&port->cad_lock, flags);
port->cad = NULL;
write_unlock_irqrestore(&port->cad_lock, flags);
- /*
- * Reenable irq and so discard the eventually pending irq while
- * cad is NULL. -arca
- */
- if (port->irq != PARPORT_IRQ_NONE && !dev->irq_func)
- enable_irq(port->irq);
-
/* Save control registers */
port->ops->save_state(port, dev->state);