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