[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);