diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
commit | 6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch) | |
tree | 0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /drivers/parport | |
parent | ecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (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-parport | 5 | ||||
-rw-r--r-- | drivers/parport/ChangeLog | 24 | ||||
-rw-r--r-- | drivers/parport/Config.in | 2 | ||||
-rw-r--r-- | drivers/parport/TODO-parport | 2 | ||||
-rw-r--r-- | drivers/parport/daisy.c | 6 | ||||
-rw-r--r-- | drivers/parport/parport_amiga.c | 11 | ||||
-rw-r--r-- | drivers/parport/parport_pc.c | 5 | ||||
-rw-r--r-- | drivers/parport/procfs.c | 123 | ||||
-rw-r--r-- | drivers/parport/share.c | 40 |
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); |