[parisc-linux-cvs] DIFF unregister_driver() support
Grant Grundler
grundler@cup.hp.com
Mon, 26 Feb 2001 16:41:24 -0800 (PST)
here's the diff for Matthieu Delahaye's patch.
It's not exactly what he submitted originally.
I've fixed two other problems and agree with willy
about the "if (ptr) continue;" code.
grant
Index: arch/parisc/kernel/drivers.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/drivers.c,v
retrieving revision 1.13
diff -u -p -r1.13 drivers.c
--- drivers.c 2001/02/03 19:36:57 1.13
+++ drivers.c 2001/02/27 00:20:24
@@ -53,6 +53,12 @@ int register_driver(struct pa_iodc_drive
struct hp_device * device;
for(;driver->check;driver++) {
+ if(driver->next) {
+ BUG();
+ printk(KERN_WARNING "BUG: Skipping previously registered driver: %s %s\n", driver->name, driver->version);
+ continue;
+ }
+
/* link driver to the head of the global list.
** The list gets built in reverse order...ideally, it shouldn't
** matter but reality will eventually rear it's ugly head.
@@ -63,11 +69,11 @@ int register_driver(struct pa_iodc_drive
for (i=0; i < num_devices; i++) {
device = &pa_devices[i];
- if (device->managed) continue;
+ if (device->driver) continue;
if (0 == compare_spec(device, driver)) continue;
- if ( (*driver->callback)(device,driver) ==0) {
- device->managed=1;
+ if ( (*driver->callback)(device,driver) == 0) {
+ device->driver=driver;
} else {
printk("Warning : device (%d, 0x%x, 0x%x, 0x%x, 0x%x) NOT claimed by %s %s\n",
device->hw_type,
@@ -77,10 +83,53 @@ int register_driver(struct pa_iodc_drive
}
}
}
+
return 0;
}
+
+int unregister_driver(struct pa_iodc_driver *driver)
+{
+ int i;
+
+/*
+** SMP_REVISIT: code is NOT SMP safe. Need to use a spinlock
+** around *all* references to pa_drivers list.
+*/
+ for(;driver->check;driver++) {
+
+ if(pa_drivers==driver) {
+ /* was head of list - update head */
+ pa_drivers=driver->next;
+ } else {
+ struct pa_iodc_driver * prev = pa_drivers;
+
+ while(prev && driver!=prev->next) {
+ prev = prev->next;
+ }
+
+ if(prev==NULL) {
+ printk(KERN_WARNING "unregister_driver: %s %s wasn't registered\n", driver->name, driver->version);
+ continue;
+ } else {
+ /* Drop driver from list */
+ prev->next=driver->next;
+ driver->next=NULL;
+ }
+
+ }
+
+ for (i=0; i < num_devices; i++) {
+ if (pa_devices[i].driver == driver)
+ pa_devices[i].driver = NULL;
+ }
+
+ }
+ return 0;
+}
+
+
/* this function adds an address to the list of additional addresses of a module */
int add_pa_dev_addr(struct hp_device *hp_device, unsigned long addr)
{
@@ -127,7 +176,7 @@ struct hp_device *alloc_pa_dev(unsigned
d->sversion_rev = iodc_data[4]>>4;
d->opt = iodc_data[7];
d->hpa = (void *) hpa;
- d->managed = 0;
+ d->driver = NULL;
d->reference = parisc_get_reference(d->hw_type,
d->hversion, d->sversion);
@@ -139,29 +188,31 @@ struct hp_device *alloc_pa_dev(unsigned
return d;
}
-
/* Return status if device is managed */
int register_pa_dev(struct hp_device *hp_dev)
{
struct pa_iodc_driver *driver = pa_drivers;
-
- while ((0 == hp_dev->managed) && (NULL != driver)) {
- if (compare_spec(hp_dev,driver))
- hp_dev->managed =
- ((*driver->callback)(hp_dev,driver) == 0);
-
+ /*
+ ** Locate a driver which agrees to manage this device.
+ */
+ while ((NULL == hp_dev->driver) && (NULL != driver)) {
+
+ if (compare_spec(hp_dev,driver)) {
+ hp_dev->driver = (*driver->callback)(hp_dev,driver)==0
+ ? driver : NULL;
+ }
driver = driver->next;
}
- return hp_dev->managed;
+ return (NULL != hp_dev->driver);
}
struct hp_device *get_pa_dev(unsigned int index)
{
if (index >= num_devices)
return NULL;
-
+
return &pa_devices[index];
}
Index: include/asm-parisc/hardware.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/asm-parisc/hardware.h,v
retrieving revision 1.14
diff -u -p -r1.14 hardware.h
--- hardware.h 2001/02/01 02:06:08 1.14
+++ hardware.h 2001/02/27 00:20:24
@@ -22,7 +22,7 @@ struct hp_device {
unsigned int sversion_rev;
struct hp_hardware *reference; /* This is a pointer to the
reference */
- unsigned int managed; /* this is if the device has a driver for it */
+ struct pa_iodc_driver *driver; /* this is if the device has a driver for it */
unsigned int num_addrs; /* some devices have additional address ranges, */
unsigned long addr[MAX_ADD_ADDRS]; /* which will be stored here */
@@ -113,6 +113,7 @@ extern int add_pa_dev_addr(struct hp_dev
extern struct hp_device *get_pa_dev(unsigned int index);
extern void print_pa_devices(char * buf);
extern int register_driver(struct pa_iodc_driver *driver);
+extern int unregister_driver(struct pa_iodc_driver *driver);
/* inventory.c: */
extern void do_inventory(void);