Commit 69bd145b authored by Ari Juhani Hämeenaho's avatar Ari Juhani Hämeenaho Committed by Greg Kroah-Hartman

[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.
parent 3e5db7aa
...@@ -188,8 +188,6 @@ static void usblp_dump(struct usblp *usblp) { ...@@ -188,8 +188,6 @@ static void usblp_dump(struct usblp *usblp) {
extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */ 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. */ /* Quirks: various printer quirks are handled by this table & its flags. */
struct quirk_printer_struct { struct quirk_printer_struct {
...@@ -325,17 +323,22 @@ static int usblp_check_status(struct usblp *usblp, int err) ...@@ -325,17 +323,22 @@ static int usblp_check_status(struct usblp *usblp, int err)
static int usblp_open(struct inode *inode, struct file *file) 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 usblp *usblp;
struct usb_interface *intf;
int retval; int retval;
if (minor < 0 || minor >= USBLP_MINORS) if (minor < 0 || minor >= USBLP_MINORS)
return -ENODEV; return -ENODEV;
lock_kernel(); lock_kernel();
usblp = usblp_table[minor];
retval = -ENODEV; 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) if (!usblp || !usblp->dev)
goto out; goto out;
...@@ -382,7 +385,6 @@ static int usblp_open(struct inode *inode, struct file *file) ...@@ -382,7 +385,6 @@ static int usblp_open(struct inode *inode, struct file *file)
static void usblp_cleanup (struct usblp *usblp) static void usblp_cleanup (struct usblp *usblp)
{ {
devfs_unregister (usblp->devfs); devfs_unregister (usblp->devfs);
usblp_table [usblp->minor] = NULL;
usb_deregister_dev (1, usblp->minor); usb_deregister_dev (1, usblp->minor);
info("usblp%d: removed", usblp->minor); info("usblp%d: removed", usblp->minor);
...@@ -905,14 +907,11 @@ static int usblp_probe(struct usb_interface *intf, ...@@ -905,14 +907,11 @@ static int usblp_probe(struct usb_interface *intf,
usblp_check_status(usblp, 0); usblp_check_status(usblp, 0);
#endif #endif
/* add a table entry so the device works when advertised */
usblp_table[usblp->minor] = usblp;
/* If we have devfs, create with perms=660. */ /* If we have devfs, create with perms=660. */
sprintf(name, "lp%d", usblp->minor); sprintf(name, "lp%d", usblp->minor);
usblp->devfs = devfs_register(usb_devfs_handle, name, usblp->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR, DEVFS_FL_DEFAULT, USB_MAJOR,
USBLP_MINOR_BASE + usblp->minor, usblp->minor,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP, &usblp_fops, NULL); S_IWGRP, &usblp_fops, NULL);
...@@ -925,6 +924,10 @@ static int usblp_probe(struct usb_interface *intf, ...@@ -925,6 +924,10 @@ static int usblp_probe(struct usb_interface *intf,
usblp->dev->descriptor.idProduct); usblp->dev->descriptor.idProduct);
dev_set_drvdata (&intf->dev, usblp); 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; return 0;
abort_minor: abort_minor:
...@@ -1109,6 +1112,9 @@ static void usblp_disconnect(struct usb_interface *intf) ...@@ -1109,6 +1112,9 @@ static void usblp_disconnect(struct usb_interface *intf)
{ {
struct usblp *usblp = dev_get_drvdata (&intf->dev); struct usblp *usblp = dev_get_drvdata (&intf->dev);
/* remove device id to disable open() */
intf->kdev = NODEV;
if (!usblp || !usblp->dev) { if (!usblp || !usblp->dev) {
err("bogus disconnect"); err("bogus disconnect");
BUG (); BUG ();
......
...@@ -470,6 +470,40 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id) ...@@ -470,6 +470,40 @@ usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
return NULL; 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) static int usb_device_match (struct device *dev, struct device_driver *drv)
{ {
struct usb_interface *intf; struct usb_interface *intf;
...@@ -1445,6 +1479,7 @@ EXPORT_SYMBOL(usb_driver_claim_interface); ...@@ -1445,6 +1479,7 @@ EXPORT_SYMBOL(usb_driver_claim_interface);
EXPORT_SYMBOL(usb_interface_claimed); EXPORT_SYMBOL(usb_interface_claimed);
EXPORT_SYMBOL(usb_driver_release_interface); EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_match_id); EXPORT_SYMBOL(usb_match_id);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_new_device); EXPORT_SYMBOL(usb_new_device);
EXPORT_SYMBOL(usb_reset_device); EXPORT_SYMBOL(usb_reset_device);
......
...@@ -398,6 +398,7 @@ open_scanner(struct inode * inode, struct file * file) ...@@ -398,6 +398,7 @@ open_scanner(struct inode * inode, struct file * file)
{ {
struct scn_usb_data *scn; struct scn_usb_data *scn;
struct usb_device *dev; struct usb_device *dev;
struct usb_interface *intf;
int scn_minor; int scn_minor;
...@@ -409,13 +410,13 @@ open_scanner(struct inode * inode, struct file * file) ...@@ -409,13 +410,13 @@ open_scanner(struct inode * inode, struct file * file)
dbg("open_scanner: scn_minor:%d", scn_minor); 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); up(&scn_mutex);
err("open_scanner(%d): Unable to access minor data", scn_minor); err("open_scanner(%d): Unable to access minor data", scn_minor);
return -ENODEV; return -ENODEV;
} }
scn = dev_get_drvdata (&intf->dev);
scn = p_scn_table[scn_minor];
dev = scn->scn_dev; dev = scn->scn_dev;
...@@ -458,7 +459,7 @@ open_scanner(struct inode * inode, struct file * file) ...@@ -458,7 +459,7 @@ open_scanner(struct inode * inode, struct file * file)
static int static int
close_scanner(struct inode * inode, struct file * file) close_scanner(struct inode * inode, struct file * file)
{ {
struct scn_usb_data *scn; struct scn_usb_data *scn = file->private_data;
int scn_minor; int scn_minor;
...@@ -466,15 +467,9 @@ close_scanner(struct inode * inode, struct file * file) ...@@ -466,15 +467,9 @@ close_scanner(struct inode * inode, struct file * file)
dbg("close_scanner: scn_minor:%d", scn_minor); 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); down(&scn_mutex);
scn = p_scn_table[scn_minor];
down(&(scn->sem)); down(&(scn->sem));
scn->isopen = 0; scn->isopen = 0;
file->private_data = NULL; file->private_data = NULL;
...@@ -695,17 +690,12 @@ ioctl_scanner(struct inode *inode, struct file *file, ...@@ -695,17 +690,12 @@ ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct usb_device *dev; struct usb_device *dev;
struct scn_usb_data *scn = file->private_data;
int scn_minor; int scn_minor;
scn_minor = USB_SCN_MINOR(inode); scn_minor = USB_SCN_MINOR(inode);
if (!p_scn_table[scn_minor]) { dev = scn->scn_dev;
err("ioctl_scanner(%d): invalid scn_minor", scn_minor);
return -ENODEV;
}
dev = p_scn_table[scn_minor]->scn_dev;
switch (cmd) switch (cmd)
{ {
...@@ -987,13 +977,6 @@ probe_scanner(struct usb_interface *intf, ...@@ -987,13 +977,6 @@ probe_scanner(struct usb_interface *intf,
return -ENOMEM; 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); dbg("probe_scanner: Allocated minor:%d", scn_minor);
if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) { if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
...@@ -1082,17 +1065,19 @@ probe_scanner(struct usb_interface *intf, ...@@ -1082,17 +1065,19 @@ probe_scanner(struct usb_interface *intf,
scn->devfs = devfs_register(usb_devfs_handle, name, scn->devfs = devfs_register(usb_devfs_handle, name,
DEVFS_FL_DEFAULT, USB_MAJOR, DEVFS_FL_DEFAULT, USB_MAJOR,
SCN_BASE_MNR + scn->scn_minor, scn->scn_minor,
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL); S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
if (scn->devfs == NULL) if (scn->devfs == NULL)
dbg("scanner%d: device node registration failed", scn_minor); dbg("scanner%d: device node registration failed", scn_minor);
p_scn_table[scn_minor] = scn;
up(&scn_mutex); up(&scn_mutex);
dev_set_drvdata(&intf->dev, scn); 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; return 0;
} }
...@@ -1101,6 +1086,9 @@ disconnect_scanner(struct usb_interface *intf) ...@@ -1101,6 +1086,9 @@ disconnect_scanner(struct usb_interface *intf)
{ {
struct scn_usb_data *scn = dev_get_drvdata(&intf->dev); 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); dev_set_drvdata(&intf->dev, NULL);
if (scn) { if (scn) {
down (&scn_mutex); down (&scn_mutex);
...@@ -1119,7 +1107,6 @@ disconnect_scanner(struct usb_interface *intf) ...@@ -1119,7 +1107,6 @@ disconnect_scanner(struct usb_interface *intf)
dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor); dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
devfs_unregister(scn->devfs); devfs_unregister(scn->devfs);
usb_deregister_dev(1, scn->scn_minor); usb_deregister_dev(1, scn->scn_minor);
p_scn_table[scn->scn_minor] = NULL;
usb_free_urb(scn->scn_irq); usb_free_urb(scn->scn_irq);
up (&(scn->sem)); up (&(scn->sem));
kfree (scn); kfree (scn);
......
...@@ -216,7 +216,7 @@ MODULE_DEVICE_TABLE (usb, scanner_device_ids); ...@@ -216,7 +216,7 @@ MODULE_DEVICE_TABLE (usb, scanner_device_ids);
#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep)->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) #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 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 #ifdef DEBUG
#define SCN_DEBUG(X) X #define SCN_DEBUG(X) X
...@@ -274,6 +274,4 @@ struct scn_usb_data { ...@@ -274,6 +274,4 @@ struct scn_usb_data {
extern devfs_handle_t usb_devfs_handle; 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; static struct usb_driver scanner_driver;
...@@ -117,6 +117,7 @@ struct usb_interface { ...@@ -117,6 +117,7 @@ struct usb_interface {
unsigned max_altsetting; /* total memory allocated */ unsigned max_altsetting; /* total memory allocated */
struct usb_driver *driver; /* driver */ struct usb_driver *driver; /* driver */
kdev_t kdev; /* node this interface is bound to */
struct device dev; /* interface specific device info */ struct device dev; /* interface specific device info */
void *private_data; void *private_data;
}; };
...@@ -271,6 +272,8 @@ extern void usb_driver_release_interface(struct usb_driver *driver, ...@@ -271,6 +272,8 @@ extern void usb_driver_release_interface(struct usb_driver *driver,
const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *usb_match_id(struct usb_interface *interface,
const struct usb_device_id *id); 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 * usb_make_path - returns stable device path in the usb tree
* @dev: the device whose path is being constructed * @dev: the device whose path is being constructed
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment