summaryrefslogtreecommitdiffstats
path: root/drivers/parport
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-19 22:45:37 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-19 22:45:37 +0000
commit6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch)
tree0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /drivers/parport
parentecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff)
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine status unknown.
Diffstat (limited to 'drivers/parport')
-rw-r--r--drivers/parport/BUGS-parport5
-rw-r--r--drivers/parport/ChangeLog24
-rw-r--r--drivers/parport/Config.in2
-rw-r--r--drivers/parport/TODO-parport2
-rw-r--r--drivers/parport/daisy.c6
-rw-r--r--drivers/parport/parport_amiga.c11
-rw-r--r--drivers/parport/parport_pc.c5
-rw-r--r--drivers/parport/procfs.c123
-rw-r--r--drivers/parport/share.c40
9 files changed, 182 insertions, 36 deletions
diff --git a/drivers/parport/BUGS-parport b/drivers/parport/BUGS-parport
index 2329adde6..a41276a62 100644
--- a/drivers/parport/BUGS-parport
+++ b/drivers/parport/BUGS-parport
@@ -1,5 +1,6 @@
Currently known (or at least suspected) bugs in parport:
-o lp doesn't allow you to read status while printing is in progress.
+o lp doesn't allow you to read status while printing is in progress (is
+ this still true?).
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
+See <URL:http://people.redhat.com/twaugh/parport/>.
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index 97b7c53c9..1dd9a4ae2 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -1,3 +1,27 @@
+2000-06-13 Tim Waugh <twaugh@redhat.com>
+
+ * procfs.c: Break 'hardware' out into separate files.
+
+2000-05-28 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de>
+
+ * Fix PCI ID printk for non-superio PCI cards.
+
+2000-05-28 Tim Waugh <twaugh@redhat.com>
+
+ * share.c (call_driver_chain): Get the driverlist_lock.
+ (parport_register_device): Make sure that port->devices always
+ looks consistent.
+ (parport_register_driver): Ensure that parport drivers are given
+ parameters that are valid for the duration of the callback by
+ locking the portlist against changes.
+ (parport_unregister_driver): Likewise.
+ (parport_claim): Don't overwrite flags.
+
+2000-05-28 Tim Waugh <twaugh@redhat.com>
+
+ * daisy.c (assign_addrs): Avoid double-probing daisy-chain devices
+ if the first probe succeeds.
+
2000-05-16 Tim Waugh <twaugh@redhat.com>
* share.c (parport_claim): Fix SMP race.
diff --git a/drivers/parport/Config.in b/drivers/parport/Config.in
index 1e486c6b3..5cf05e85a 100644
--- a/drivers/parport/Config.in
+++ b/drivers/parport/Config.in
@@ -1,6 +1,6 @@
#
# For a description of the syntax of this configuration file,
-# see the Configure script.
+# see Documentation/kbuild/config-language.txt.
#
# Parport configuration.
#
diff --git a/drivers/parport/TODO-parport b/drivers/parport/TODO-parport
index bf91351ea..089b14ee4 100644
--- a/drivers/parport/TODO-parport
+++ b/drivers/parport/TODO-parport
@@ -17,4 +17,4 @@ Things to be done.
4. A better PLIP (make use of bidirectional/ECP/EPP ports).
-See <URL:http://www.cyberelk.demon.co.uk/parport.html>.
+See <URL:http://people.redhat.com/twaugh/parport/>.
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index b99d5a344..e2f681c3a 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -428,6 +428,7 @@ static int assign_addrs (struct parport *port)
unsigned char s, last_dev;
unsigned char daisy;
int thisdev = numdevs;
+ int detected;
char *deviceid;
parport_data_forward (port);
@@ -484,8 +485,9 @@ static int assign_addrs (struct parport *port)
}
parport_write_data (port, 0xff); udelay (2);
+ detected = numdevs - thisdev;
DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
- numdevs - thisdev);
+ detected);
/* Ask the new devices to introduce themselves. */
deviceid = kmalloc (1000, GFP_KERNEL);
@@ -495,7 +497,7 @@ static int assign_addrs (struct parport *port)
parport_device_id (thisdev, deviceid, 1000);
kfree (deviceid);
- return numdevs - thisdev;
+ return detected;
}
/* Find a device with a particular manufacturer and model string,
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index dc4fc6945..3c675b88e 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/parport.h>
+#include <linux/ioport.h>
#include <asm/setup.h>
#include <asm/amigahw.h>
#include <asm/irq.h>
@@ -239,14 +240,19 @@ int __init parport_amiga_init(void)
struct parport *p;
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(AMI_PARALLEL)) {
+ if (!request_mem_region(CIAA_PHYSADDR+0x100, 1, "parallel"))
+ return 0;
ciaa.ddrb = 0xff;
ciab.ddra &= 0xf8;
if (!(p = parport_register_port((unsigned long)&ciaa.prb,
IRQ_AMIGA_CIAA_FLG, PARPORT_DMA_NONE,
- &pp_amiga_ops)))
+ &pp_amiga_ops))) {
+ release_mem_region(CIAA_PHYSADDR+0x100, 1);
return 0;
+ }
if (!request_irq(IRQ_AMIGA_CIAA_FLG, amiga_interrupt, 0, p->name, p)) {
parport_unregister_port (p);
+ release_mem_region(CIAA_PHYSADDR+0x100, 1);
return 0;
}
@@ -277,9 +283,10 @@ int init_module(void)
void cleanup_module(void)
{
if (this_port->irq != PARPORT_IRQ_NONE)
- free_irq(IRQ_MFP_BUSY, this_port);
+ free_irq(IRQ_AMIGA_CIAA_FLG, this_port);
parport_proc_unregister(this_port);
parport_unregister_port(this_port);
+ release_mem_region(CIAA_PHYSADDR+0x100, 1);
}
#endif
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index a759b2d74..13a4faea4 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2430,8 +2430,9 @@ static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
def.) */
/* TODO: test if sharing interrupts works */
printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
- "I/O at %#lx(%#lx)\n", parport_pc_pci_tbl[i].vendor,
- parport_pc_pci_tbl[i].device, io_lo, io_hi);
+ "I/O at %#lx(%#lx)\n",
+ parport_pc_pci_tbl[i + last_sio].vendor,
+ parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi);
if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
PARPORT_DMA_NONE, dev))
count++;
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index 07b30b009..15efdd657 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -109,38 +109,106 @@ static int do_autoprobe(ctl_table *table, int write, struct file *filp,
}
#endif /* IEEE1284.3 support. */
-static int do_hardware(ctl_table *table, int write, struct file *filp,
- void *result, size_t *lenp)
+static int do_hardware_base_addr (ctl_table *table, int write,
+ struct file *filp, void *result,
+ size_t *lenp)
{
struct parport *port = (struct parport *)table->extra1;
- char buffer[256];
+ char buffer[20];
int len = 0;
if (filp->f_pos) {
*lenp = 0;
return 0;
}
-
- if (write) /* can't happen anyway */
+
+ if (write) /* permissions prevent this anyway */
return -EACCES;
-
- len += sprintf(buffer+len, "base:\t0x%lx", port->base);
- if (port->base_hi)
- len += sprintf(buffer+len, " (0x%lx)", port->base_hi);
- buffer[len++] = '\n';
- if (port->irq == PARPORT_IRQ_NONE) {
- len += sprintf(buffer+len, "irq:\tnone\n");
- } else {
- len += sprintf(buffer+len, "irq:\t%d\n", port->irq);
+ len += sprintf (buffer, "%lu\t%lu\n", port->base, port->base_hi);
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+static int do_hardware_irq (ctl_table *table, int write,
+ struct file *filp, void *result,
+ size_t *lenp)
+{
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[20];
+ int len = 0;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
}
- if (port->dma == PARPORT_DMA_NONE)
- len += sprintf(buffer+len, "dma:\tnone\n");
+ if (write) /* permissions prevent this anyway */
+ return -EACCES;
+
+ len += sprintf (buffer, "%d\n", port->irq);
+
+ if (len > *lenp)
+ len = *lenp;
else
- len += sprintf(buffer+len, "dma:\t%d\n", port->dma);
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+static int do_hardware_dma (ctl_table *table, int write,
+ struct file *filp, void *result,
+ size_t *lenp)
+{
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[20];
+ int len = 0;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if (write) /* permissions prevent this anyway */
+ return -EACCES;
+
+ len += sprintf (buffer, "%d\n", port->dma);
+
+ if (len > *lenp)
+ len = *lenp;
+ else
+ *lenp = len;
+
+ filp->f_pos += len;
+
+ return copy_to_user(result, buffer, len) ? -EFAULT : 0;
+}
+
+static int do_hardware_modes (ctl_table *table, int write,
+ struct file *filp, void *result,
+ size_t *lenp)
+{
+ struct parport *port = (struct parport *)table->extra1;
+ char buffer[20];
+ int len = 0;
+
+ if (filp->f_pos) {
+ *lenp = 0;
+ return 0;
+ }
+
+ if (write) /* permissions prevent this anyway */
+ return -EACCES;
- len += sprintf(buffer+len, "modes:\t");
{
#define printmode(x) {if(port->modes&PARPORT_MODE_##x){len+=sprintf(buffer+len,"%s%s",f?",":"",#x);f++;}}
int f = 0;
@@ -186,7 +254,7 @@ PARPORT_MAX_SPINTIME_VALUE;
struct parport_sysctl_table {
struct ctl_table_header *sysctl_header;
- ctl_table vars[9];
+ ctl_table vars[12];
ctl_table device_dir[2];
ctl_table port_dir[2];
ctl_table parport_dir[2];
@@ -201,9 +269,18 @@ static const struct parport_sysctl_table parport_sysctl_template = {
&proc_dointvec_minmax, NULL, NULL,
(void*) &parport_min_spintime_value,
(void*) &parport_max_spintime_value },
- { DEV_PARPORT_HARDWARE, "hardware",
+ { DEV_PARPORT_BASE_ADDR, "base-addr",
+ NULL, 0, 0444, NULL,
+ &do_hardware_base_addr },
+ { DEV_PARPORT_IRQ, "irq",
+ NULL, 0, 0444, NULL,
+ &do_hardware_irq },
+ { DEV_PARPORT_DMA, "dma",
+ NULL, 0, 0444, NULL,
+ &do_hardware_dma },
+ { DEV_PARPORT_MODES, "modes",
NULL, 0, 0444, NULL,
- &do_hardware },
+ &do_hardware_modes },
PARPORT_DEVICES_ROOT_DIR,
#ifdef CONFIG_PARPORT_1284
{ DEV_PARPORT_AUTOPROBE, "autoprobe",
@@ -314,10 +391,10 @@ int parport_proc_register(struct parport *port)
t->vars[i].extra1 = port;
t->vars[0].data = &port->spintime;
- t->vars[2].child = t->device_dir;
+ t->vars[5].child = t->device_dir;
for (i = 0; i < 5; i++)
- t->vars[3 + i].extra2 = &port->probe_info[i];
+ t->vars[6 + i].extra2 = &port->probe_info[i];
t->port_dir[0].procname = port->name;
t->port_dir[0].ctl_name = port->number + 1; /* nb 0 isn't legal here */
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index c85addc56..5ada06a83 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -87,12 +87,14 @@ static void call_driver_chain(int attach, struct parport *port)
{
struct parport_driver *drv;
+ spin_lock (&driverlist_lock);
for (drv = driver_chain; drv; drv = drv->next) {
if (attach)
drv->attach (port);
else
drv->detach (port);
}
+ spin_unlock (&driverlist_lock);
}
/* Ask kmod for some lowlevel drivers. */
@@ -126,8 +128,12 @@ int parport_register_driver (struct parport_driver *drv)
driver_chain = drv;
spin_unlock (&driverlist_lock);
+ /* We have to take the portlist lock for this to be sure
+ * that port is valid for the duration of the callback. */
+ spin_lock (&parportlist_lock);
for (port = portlist; port; port = port->next)
drv->attach (port);
+ spin_unlock (&parportlist_lock);
if (!portlist)
get_lowlevel_driver ();
@@ -171,8 +177,10 @@ void parport_unregister_driver (struct parport_driver *arg)
/* Call the driver's detach routine for each
* port to clean up any resources that the
* attach routine acquired. */
+ spin_lock (&parportlist_lock);
for (port = portlist; port; port = port->next)
drv->detach (port);
+ spin_unlock (&parportlist_lock);
return;
}
@@ -195,6 +203,8 @@ void parport_unregister_driver (struct parport_driver *arg)
struct parport *parport_enumerate(void)
{
+ /* Don't use this: use parport_register_driver instead. */
+
if (!portlist)
get_lowlevel_driver ();
@@ -297,7 +307,18 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
* This function must not run from an irq handler so we don' t need
* to clear irq on the local CPU. -arca
*/
+
spin_lock(&parportlist_lock);
+
+ /* We are locked against anyone else performing alterations, but
+ * because of parport_enumerate people can still _read_ the list
+ * while we are changing it; so be careful..
+ *
+ * It's okay to have portlist_tail a little bit out of sync
+ * since it's only used for changing the list, not for reading
+ * from it.
+ */
+
if (portlist_tail)
portlist_tail->next = tmp;
portlist_tail = tmp;
@@ -403,6 +424,10 @@ void parport_unregister_port(struct parport *port)
#endif
spin_lock(&parportlist_lock);
+
+ /* We are protected from other people changing the list, but
+ * they can see see it (using parport_enumerate). So be
+ * careful about the order of writes.. */
if (portlist == port) {
if ((portlist = port->next) == NULL)
portlist_tail = NULL;
@@ -418,6 +443,7 @@ void parport_unregister_port(struct parport *port)
}
spin_unlock(&parportlist_lock);
+ /* Yes, parport_enumerate _is_ unsafe. Don't use it. */
if (!port->devices)
free_port (port);
}
@@ -565,6 +591,9 @@ parport_register_device(struct parport *port, const char *name,
}
tmp->next = port->physport->devices;
+ wmb(); /* Make sure that tmp->next is written before it's
+ added to the list; see comments marked 'no locking
+ required' */
if (port->physport->devices)
port->physport->devices->prev = tmp;
port->physport->devices = tmp;
@@ -647,6 +676,11 @@ void parport_unregister_device(struct pardevice *dev)
* free up the resources. */
if (port->ops == &dead_ops && !port->devices)
free_port (port);
+
+ /* Yes, that's right, someone _could_ still have a pointer to
+ * port, if they used parport_enumerate. That's why they
+ * shouldn't use it (and use parport_register_driver instead)..
+ */
}
/**
@@ -702,7 +736,7 @@ int parport_claim(struct pardevice *dev)
dev->waiting = 0;
/* Take ourselves out of the wait list again. */
- spin_lock_irqsave (&port->waitlist_lock, flags);
+ spin_lock_irq (&port->waitlist_lock);
if (dev->waitprev)
dev->waitprev->waitnext = dev->waitnext;
else
@@ -711,7 +745,7 @@ int parport_claim(struct pardevice *dev)
dev->waitnext->waitprev = dev->waitprev;
else
port->waittail = dev->waitprev;
- spin_unlock_irqrestore (&port->waitlist_lock, flags);
+ spin_unlock_irq (&port->waitlist_lock);
dev->waitprev = dev->waitnext = NULL;
}
@@ -878,7 +912,7 @@ void parport_release(struct pardevice *dev)
}
/* Nobody was waiting, so walk the list to see if anyone is
- interested in being woken up. */
+ interested in being woken up. (Note: no locking required) */
for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) {
if (pd->wakeup && pd != dev)
pd->wakeup(pd->private);