From 9f8b17e643fe6aa505629658445849397bda4e4f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Tue, 13 Mar 2007 15:59:31 +0100 Subject: USB: make usbdevices export their device nodes instead of using a separate class o The "real" usb-devices export now a device node which can populate /dev/bus/usb. o The usb_device class is optional now and can be disabled in the kernel config. Major/minor of the "real" devices and class devices are the same. o The environment of the usb-device event contains DEVNUM and BUSNUM to help udev and get rid of the ugly udev rule we need for the class devices. o The usb-devices and usb-interfaces share the same bus, so I used the new "struct device_type" to let these devices identify themselves. This also removes the current logic of using a magic platform-pointer. The name of the device_type is also added to the environment which makes it easier to distinguish the different kinds of devices on the same subsystem. It looks like this: add@/devices/pci0000:00/0000:00:1d.1/usb2/2-1 ACTION=add DEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/2-1 SUBSYSTEM=usb SEQNUM=1533 MAJOR=189 MINOR=131 DEVTYPE=usb_device PRODUCT=46d/c03e/2000 TYPE=0/0/0 BUSNUM=002 DEVNUM=004 This udev rule works as a replacement for usb_device class devices: SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" Updated patch, which needs the device_type patches in Greg's tree. I also got a bugzilla assigned for this. :) https://bugzilla.novell.com/show_bug.cgi?id=250659 Signed-off-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 94 ++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 43 deletions(-) (limited to 'drivers/usb/core/devio.c') diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fc3545ddb06..e023f3d5624 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -57,7 +57,6 @@ #define USB_MAXBUS 64 #define USB_DEVICE_MAX USB_MAXBUS * 128 -static struct class *usb_device_class; /* Mutual exclusion for removal, open, and release */ DEFINE_MUTEX(usbfs_mutex); @@ -514,22 +513,25 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig return ret; } -static struct usb_device *usbdev_lookup_minor(int minor) +static int __match_minor(struct device *dev, void *data) { - struct device *device; - struct usb_device *udev = NULL; + int minor = *((int *)data); - down(&usb_device_class->sem); - list_for_each_entry(device, &usb_device_class->devices, node) { - if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) { - udev = device->platform_data; - break; - } - } - up(&usb_device_class->sem); + if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) + return 1; + return 0; +} - return udev; -}; +static struct usb_device *usbdev_lookup_by_minor(int minor) +{ + struct device *dev; + + dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor); + if (!dev) + return NULL; + put_device(dev); + return container_of(dev, struct usb_device, dev); +} /* * file operations @@ -548,11 +550,14 @@ static int usbdev_open(struct inode *inode, struct file *file) goto out; ret = -ENOENT; - /* check if we are called from a real node or usbfs */ + /* usbdev device-node */ if (imajor(inode) == USB_DEVICE_MAJOR) - dev = usbdev_lookup_minor(iminor(inode)); + dev = usbdev_lookup_by_minor(iminor(inode)); +#ifdef CONFIG_USB_DEVICEFS + /* procfs file */ if (!dev) dev = inode->i_private; +#endif if (!dev) goto out; ret = usb_autoresume_device(dev); @@ -1570,7 +1575,7 @@ static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wai return mask; } -const struct file_operations usbfs_device_file_operations = { +const struct file_operations usbdev_file_operations = { .llseek = usbdev_lseek, .read = usbdev_read, .poll = usbdev_poll, @@ -1579,50 +1584,53 @@ const struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -static int usbdev_add(struct usb_device *dev) +#ifdef CONFIG_USB_DEVICE_CLASS +static struct class *usb_classdev_class; + +static int usb_classdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); - dev->usbfs_dev = device_create(usb_device_class, &dev->dev, + dev->usb_classdev = device_create(usb_classdev_class, &dev->dev, MKDEV(USB_DEVICE_MAJOR, minor), "usbdev%d.%d", dev->bus->busnum, dev->devnum); - if (IS_ERR(dev->usbfs_dev)) - return PTR_ERR(dev->usbfs_dev); + if (IS_ERR(dev->usb_classdev)) + return PTR_ERR(dev->usb_classdev); - dev->usbfs_dev->platform_data = dev; return 0; } -static void usbdev_remove(struct usb_device *dev) +static void usb_classdev_remove(struct usb_device *dev) { - device_unregister(dev->usbfs_dev); + device_unregister(dev->usb_classdev); } -static int usbdev_notify(struct notifier_block *self, unsigned long action, - void *dev) +static int usb_classdev_notify(struct notifier_block *self, + unsigned long action, void *dev) { switch (action) { case USB_DEVICE_ADD: - if (usbdev_add(dev)) + if (usb_classdev_add(dev)) return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: - usbdev_remove(dev); + usb_classdev_remove(dev); break; } return NOTIFY_OK; } static struct notifier_block usbdev_nb = { - .notifier_call = usbdev_notify, + .notifier_call = usb_classdev_notify, }; +#endif static struct cdev usb_device_cdev = { .kobj = {.name = "usb_device", }, .owner = THIS_MODULE, }; -int __init usbdev_init(void) +int __init usb_devio_init(void) { int retval; @@ -1632,38 +1640,38 @@ int __init usbdev_init(void) err("unable to register minors for usb_device"); goto out; } - cdev_init(&usb_device_cdev, &usbfs_device_file_operations); + cdev_init(&usb_device_cdev, &usbdev_file_operations); retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); if (retval) { err("unable to get usb_device major %d", USB_DEVICE_MAJOR); goto error_cdev; } - usb_device_class = class_create(THIS_MODULE, "usb_device"); - if (IS_ERR(usb_device_class)) { +#ifdef CONFIG_USB_DEVICE_CLASS + usb_classdev_class = class_create(THIS_MODULE, "usb_device"); + if (IS_ERR(usb_classdev_class)) { err("unable to register usb_device class"); - retval = PTR_ERR(usb_device_class); - goto error_class; + retval = PTR_ERR(usb_classdev_class); + cdev_del(&usb_device_cdev); + usb_classdev_class = NULL; + goto out; } usb_register_notify(&usbdev_nb); - +#endif out: return retval; -error_class: - usb_device_class = NULL; - cdev_del(&usb_device_cdev); - error_cdev: unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); goto out; } -void usbdev_cleanup(void) +void usb_devio_cleanup(void) { +#ifdef CONFIG_USB_DEVICE_CLASS usb_unregister_notify(&usbdev_nb); - class_destroy(usb_device_class); + class_destroy(usb_classdev_class); +#endif cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); } - -- cgit v1.2.3