diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-09-28 22:25:29 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-09-28 22:25:29 +0000 |
commit | 0ae8dceaebe3659ee0c3352c08125f403e77ebca (patch) | |
tree | 5085c389f09da78182b899d19fe1068b619a69dd /drivers/misc | |
parent | 273767781288c35c9d679e908672b9996cda4c34 (diff) |
Merge with 2.3.10.
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Config.in | 37 | ||||
-rw-r--r-- | drivers/misc/Makefile | 13 | ||||
-rw-r--r-- | drivers/misc/parport_arc.c | 56 | ||||
-rw-r--r-- | drivers/misc/parport_atari.c | 3 | ||||
-rw-r--r-- | drivers/misc/parport_ax.c | 137 | ||||
-rw-r--r-- | drivers/misc/parport_daisy.c | 473 | ||||
-rw-r--r-- | drivers/misc/parport_ieee1284.c | 526 | ||||
-rw-r--r-- | drivers/misc/parport_ieee1284_ops.c | 848 | ||||
-rw-r--r-- | drivers/misc/parport_init.c | 40 | ||||
-rw-r--r-- | drivers/misc/parport_pc.c | 1542 | ||||
-rw-r--r-- | drivers/misc/parport_probe.c | 212 | ||||
-rw-r--r-- | drivers/misc/parport_procfs.c | 20 | ||||
-rw-r--r-- | drivers/misc/parport_share.c | 179 |
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); |