ChangeSet 1.872, 2002/12/12 12:39:31-08:00, khaho@koti.soon.fi

[PATCH] USB: start to remove static minor based arrays in drivers

Here are minimal usb_find_interface() patches for the core, usblp and
scanner.

Basic design is:
- device major (USB_MAJOR for now) and minor are stored in probe()
   function to struct usb_interface as kdev_t
- open() can use new core function usb_find_interface() to find matching
  device in drivers device list
- disconnect() will set kdev_t struct usb_interface to NODEV, so open
  wont open it anymore without new probe()

I tested these patches and they work for me. I will work on small patches
of other work in these drivers (like removal of lock_kernel/unlock_kernel
in usblp, fixing the disconnect problems in both drivers etc.). Those
patches would be very small too, but there will be quite many.


diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
--- a/drivers/usb/class/usblp.c	Fri Dec 13 17:18:56 2002
+++ b/drivers/usb/class/usblp.c	Fri Dec 13 17:18:56 2002
@@ -188,8 +188,6 @@
 
 extern devfs_handle_t usb_devfs_handle;			/* /dev/usb dir. */
 
-static struct usblp *usblp_table[USBLP_MINORS];
-
 /* Quirks: various printer quirks are handled by this table & its flags. */
 
 struct quirk_printer_struct {
@@ -325,17 +323,22 @@
 
 static int usblp_open(struct inode *inode, struct file *file)
 {
-	int minor = minor(inode->i_rdev) - USBLP_MINOR_BASE;
+	int minor = minor(inode->i_rdev);
 	struct usblp *usblp;
+	struct usb_interface *intf;
 	int retval;
 
 	if (minor < 0 || minor >= USBLP_MINORS)
 		return -ENODEV;
 
 	lock_kernel();
-	usblp  = usblp_table[minor];
 
 	retval = -ENODEV;
+	intf = usb_find_interface(&usblp_driver, mk_kdev(USB_MAJOR,minor));
+	if (!intf) {
+		goto out;
+	}
+	usblp = dev_get_drvdata (&intf->dev);
 	if (!usblp || !usblp->dev)
 		goto out;
 
@@ -382,7 +385,6 @@
 static void usblp_cleanup (struct usblp *usblp)
 {
 	devfs_unregister (usblp->devfs);
-	usblp_table [usblp->minor] = NULL;
 	usb_deregister_dev (1, usblp->minor);
 	info("usblp%d: removed", usblp->minor);
 
@@ -905,14 +907,11 @@
 	usblp_check_status(usblp, 0);
 #endif
 
-	/* add a table entry so the device works when advertised */
-	usblp_table[usblp->minor] = usblp;
-
 	/* If we have devfs, create with perms=660. */
 	sprintf(name, "lp%d", usblp->minor);
 	usblp->devfs = devfs_register(usb_devfs_handle, name,
 				      DEVFS_FL_DEFAULT, USB_MAJOR,
-				      USBLP_MINOR_BASE + usblp->minor,
+				      usblp->minor,
 				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
 				      S_IWGRP, &usblp_fops, NULL);
 
@@ -925,6 +924,10 @@
 		usblp->dev->descriptor.idProduct);
 
 	dev_set_drvdata (&intf->dev, usblp);
+
+	/* add device id so the device works when advertised */
+	intf->kdev = mk_kdev(USB_MAJOR,usblp->minor);
+
 	return 0;
 
 abort_minor:
@@ -1108,6 +1111,9 @@
 static void usblp_disconnect(struct usb_interface *intf)
 {
 	struct usblp *usblp = dev_get_drvdata (&intf->dev);
+
+	/* remove device id to disable open() */
+	intf->kdev = NODEV;
 
 	if (!usblp || !usblp->dev) {
 		err("bogus disconnect");
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Fri Dec 13 17:18:56 2002
+++ b/drivers/usb/core/usb.c	Fri Dec 13 17:18:56 2002
@@ -470,6 +470,40 @@
 	return NULL;
 }
 
+/**
+ * usb_find_interface - find usb_interface pointer for driver and device
+ * @drv: the driver whose current configuration is considered
+ * @kdev: the desired device
+ *
+ * This walks the driver device list and returns a pointer to the interface 
+ * with the matching kdev_t.
+ */
+struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev)
+{
+	struct list_head *entry;
+	struct device *dev;
+	struct usb_interface *intf;
+
+	list_for_each(entry, &drv->driver.devices) {
+		dev = container_of(entry, struct device, driver_list);
+
+		/* can't look at usb devices, only interfaces */
+		if (dev->driver == &usb_generic_driver)
+			continue;
+
+		intf = to_usb_interface(dev);
+		if (!intf)
+			continue;
+
+		if (kdev_same(intf->kdev,kdev)) {
+			return intf;
+		}
+	}
+
+	/* no device found that matches */
+	return NULL;	
+}
+
 static int usb_device_match (struct device *dev, struct device_driver *drv)
 {
 	struct usb_interface *intf;
@@ -1445,6 +1479,7 @@
 EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
 EXPORT_SYMBOL(usb_match_id);
+EXPORT_SYMBOL(usb_find_interface);
 
 EXPORT_SYMBOL(usb_new_device);
 EXPORT_SYMBOL(usb_reset_device);
diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
--- a/drivers/usb/image/scanner.c	Fri Dec 13 17:18:56 2002
+++ b/drivers/usb/image/scanner.c	Fri Dec 13 17:18:56 2002
@@ -398,6 +398,7 @@
 {
 	struct scn_usb_data *scn;
 	struct usb_device *dev;
+	struct usb_interface *intf;
 
 	int scn_minor;
 
@@ -409,13 +410,13 @@
 
 	dbg("open_scanner: scn_minor:%d", scn_minor);
 
-	if (!p_scn_table[scn_minor]) {
+	intf = usb_find_interface(&scanner_driver, mk_kdev(USB_MAJOR,scn_minor));
+	if (!intf) {
 		up(&scn_mutex);
 		err("open_scanner(%d): Unable to access minor data", scn_minor);
 		return -ENODEV;
 	}
-
-	scn = p_scn_table[scn_minor];
+	scn = dev_get_drvdata (&intf->dev);
 
 	dev = scn->scn_dev;
 
@@ -458,7 +459,7 @@
 static int
 close_scanner(struct inode * inode, struct file * file)
 {
-	struct scn_usb_data *scn;
+	struct scn_usb_data *scn = file->private_data;
 
 	int scn_minor;
 
@@ -466,15 +467,9 @@
 
 	dbg("close_scanner: scn_minor:%d", scn_minor);
 
-	if (!p_scn_table[scn_minor]) {
-		err("close_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENODEV;
-	}
-
 	down(&scn_mutex);
-
-	scn = p_scn_table[scn_minor];
 	down(&(scn->sem));
+
 	scn->isopen = 0;
 
 	file->private_data = NULL;
@@ -695,17 +690,12 @@
 	      unsigned int cmd, unsigned long arg)
 {
 	struct usb_device *dev;
-
+	struct scn_usb_data *scn = file->private_data;
 	int scn_minor;
 
 	scn_minor = USB_SCN_MINOR(inode);
 
-	if (!p_scn_table[scn_minor]) {
-		err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
-		return -ENODEV;
-	}
-
-	dev = p_scn_table[scn_minor]->scn_dev;
+	dev = scn->scn_dev;
 
 	switch (cmd)
 	{
@@ -987,13 +977,6 @@
 		return -ENOMEM;
 	}
 
-/* Check to make sure that the last slot isn't already taken */
-	if (p_scn_table[scn_minor]) {
-		err("probe_scanner: No more minor devices remaining.");
-		up(&scn_mutex);
-		return -ENOMEM;
-	}
-
 	dbg("probe_scanner: Allocated minor:%d", scn_minor);
 
 	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
@@ -1082,17 +1065,19 @@
 	
 	scn->devfs = devfs_register(usb_devfs_handle, name,
 				    DEVFS_FL_DEFAULT, USB_MAJOR,
-				    SCN_BASE_MNR + scn->scn_minor,
+				    scn->scn_minor,
 				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
 				    S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
 	if (scn->devfs == NULL)
 		dbg("scanner%d: device node registration failed", scn_minor);
 
-	p_scn_table[scn_minor] = scn;
-
 	up(&scn_mutex);
 
 	dev_set_drvdata(&intf->dev, scn);
+
+	/* add device id so the device works when advertised */
+	intf->kdev = mk_kdev(USB_MAJOR,scn->scn_minor);
+
 	return 0;
 }
 
@@ -1101,6 +1086,9 @@
 {
 	struct scn_usb_data *scn = dev_get_drvdata(&intf->dev);
 
+	/* remove device id to disable open() */
+	intf->kdev = NODEV;
+
 	dev_set_drvdata(&intf->dev, NULL);
 	if (scn) {
 		down (&scn_mutex);
@@ -1119,7 +1107,6 @@
 		dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
 		devfs_unregister(scn->devfs);
 		usb_deregister_dev(1, scn->scn_minor);
-		p_scn_table[scn->scn_minor] = NULL;
 		usb_free_urb(scn->scn_irq);
 		up (&(scn->sem));
 		kfree (scn);
diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
--- a/drivers/usb/image/scanner.h	Fri Dec 13 17:18:56 2002
+++ b/drivers/usb/image/scanner.h	Fri Dec 13 17:18:56 2002
@@ -216,7 +216,7 @@
 #define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
 #define IS_EP_INTR(ep) ((ep)->bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
 
-#define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
+#define USB_SCN_MINOR(X) minor((X)->i_rdev)
 
 #ifdef DEBUG
 #define SCN_DEBUG(X) X
@@ -273,7 +273,5 @@
 };
 
 extern devfs_handle_t usb_devfs_handle;
-
-static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
 
 static struct usb_driver scanner_driver;
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Fri Dec 13 17:18:56 2002
+++ b/include/linux/usb.h	Fri Dec 13 17:18:56 2002
@@ -117,6 +117,7 @@
 	unsigned max_altsetting;	/* total memory allocated */
 
 	struct usb_driver *driver;	/* driver */
+	kdev_t kdev;			/* node this interface is bound to */
 	struct device dev;		/* interface specific device info */
 	void *private_data;
 };
@@ -270,6 +271,8 @@
 			struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 					 const struct usb_device_id *id);
+
+struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev);
 
 /**
  * usb_make_path - returns stable device path in the usb tree
