| From kay.sievers@vrfy.org Thu Mar 22 15:21:28 2007 |
| From: Kay Sievers <kay.sievers@vrfy.org> |
| To: Greg KH <greg@kroah.com> |
| Cc: David Zeuthen <david@fubar.dk> |
| Subject: USB: make usbdevices export their device nodes instead of using a separate class |
| Date: Tue, 13 Mar 2007 15:59:31 +0100 |
| Message-Id: <1173797971.3823.1.camel@pim.off.vrfy.org> |
| Mime-Version: 1.0 |
| |
| From: Kay Sievers <kay.sievers@vrfy.org> |
| |
| |
| 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 <kay.sievers@vrfy.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| |
| --- |
| drivers/usb/core/Kconfig | 25 +++++++++++ |
| drivers/usb/core/devio.c | 94 ++++++++++++++++++++++++--------------------- |
| drivers/usb/core/driver.c | 58 ++++++--------------------- |
| drivers/usb/core/hub.c | 10 +++- |
| drivers/usb/core/inode.c | 2 |
| drivers/usb/core/message.c | 65 ++++++++++++++++++++++++++++++- |
| drivers/usb/core/usb.c | 20 +++++---- |
| drivers/usb/core/usb.h | 14 ++---- |
| include/linux/usb.h | 10 +++- |
| 9 files changed, 183 insertions(+), 115 deletions(-) |
| |
| --- a/drivers/usb/core/Kconfig |
| +++ b/drivers/usb/core/Kconfig |
| @@ -31,7 +31,30 @@ config USB_DEVICEFS |
| For the format of the various /proc/bus/usb/ files, please read |
| <file:Documentation/usb/proc_usb_info.txt>. |
| |
| - Most users want to say Y here. |
| + Usbfs files can't handle Access Control Lists (ACL), which are the |
| + default way to grant access to USB devices for untrusted users of a |
| + desktop system. The usbfs functionality is replaced by real |
| + device-nodes managed by udev. These nodes live in /dev/bus/usb and |
| + are used by libusb. |
| + |
| +config USB_DEVICE_CLASS |
| + bool "USB device class-devices (DEPRECATED)" |
| + depends on USB |
| + default n |
| + ---help--- |
| + Userspace access to USB devices is granted by device-nodes exported |
| + directly from the usbdev in sysfs. Old versions of the driver |
| + core and udev needed additional class devices to export device nodes. |
| + |
| + These additional devices are difficult to handle in userspace, if |
| + information about USB interfaces must be available. One device contains |
| + the device node, the other device contains the interface data. Both |
| + devices are at the same level in sysfs (siblings) and one can't access |
| + the other. The device node created directly by the usbdev is the parent |
| + device of the interface and therefore easily accessible from the interface |
| + event. |
| + |
| + This option provides backward compatibility if needed. |
| |
| config USB_DYNAMIC_MINORS |
| bool "Dynamic USB minor allocation (EXPERIMENTAL)" |
| --- 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_st |
| 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 *ino |
| 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 f |
| 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_devic |
| .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); |
| } |
| - |
| --- a/drivers/usb/core/driver.c |
| +++ b/drivers/usb/core/driver.c |
| @@ -574,23 +574,10 @@ static int usb_device_match(struct devic |
| } |
| |
| #ifdef CONFIG_HOTPLUG |
| - |
| -/* |
| - * This sends an uevent to userspace, typically helping to load driver |
| - * or other modules, configure the device, and more. Drivers can provide |
| - * a MODULE_DEVICE_TABLE to help with module loading subtasks. |
| - * |
| - * We're called either from khubd (the typical case) or from root hub |
| - * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle |
| - * delays in event delivery. Use sysfs (and DEVPATH) to make sure the |
| - * device (and this configuration!) are still present. |
| - */ |
| static int usb_uevent(struct device *dev, char **envp, int num_envp, |
| char *buffer, int buffer_size) |
| { |
| - struct usb_interface *intf; |
| struct usb_device *usb_dev; |
| - struct usb_host_interface *alt; |
| int i = 0; |
| int length = 0; |
| |
| @@ -600,13 +587,11 @@ static int usb_uevent(struct device *dev |
| /* driver is often null here; dev_dbg() would oops */ |
| pr_debug ("usb %s: uevent\n", dev->bus_id); |
| |
| - if (is_usb_device(dev)) { |
| + if (is_usb_device(dev)) |
| usb_dev = to_usb_device(dev); |
| - alt = NULL; |
| - } else { |
| - intf = to_usb_interface(dev); |
| + else { |
| + struct usb_interface *intf = to_usb_interface(dev); |
| usb_dev = interface_to_usbdev(intf); |
| - alt = intf->cur_altsetting; |
| } |
| |
| if (usb_dev->devnum < 0) { |
| @@ -621,9 +606,7 @@ static int usb_uevent(struct device *dev |
| #ifdef CONFIG_USB_DEVICEFS |
| /* If this is available, userspace programs can directly read |
| * all the device descriptors we don't tell them about. Or |
| - * even act as usermode drivers. |
| - * |
| - * FIXME reduce hardwired intelligence here |
| + * act as usermode drivers. |
| */ |
| if (add_uevent_var(envp, num_envp, &i, |
| buffer, buffer_size, &length, |
| @@ -650,44 +633,29 @@ static int usb_uevent(struct device *dev |
| usb_dev->descriptor.bDeviceProtocol)) |
| return -ENOMEM; |
| |
| - if (!is_usb_device(dev)) { |
| - |
| - if (add_uevent_var(envp, num_envp, &i, |
| + if (add_uevent_var(envp, num_envp, &i, |
| buffer, buffer_size, &length, |
| - "INTERFACE=%d/%d/%d", |
| - alt->desc.bInterfaceClass, |
| - alt->desc.bInterfaceSubClass, |
| - alt->desc.bInterfaceProtocol)) |
| - return -ENOMEM; |
| + "BUSNUM=%03d", |
| + usb_dev->bus->busnum)) |
| + return -ENOMEM; |
| |
| - if (add_uevent_var(envp, num_envp, &i, |
| + if (add_uevent_var(envp, num_envp, &i, |
| buffer, buffer_size, &length, |
| - "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", |
| - le16_to_cpu(usb_dev->descriptor.idVendor), |
| - le16_to_cpu(usb_dev->descriptor.idProduct), |
| - le16_to_cpu(usb_dev->descriptor.bcdDevice), |
| - usb_dev->descriptor.bDeviceClass, |
| - usb_dev->descriptor.bDeviceSubClass, |
| - usb_dev->descriptor.bDeviceProtocol, |
| - alt->desc.bInterfaceClass, |
| - alt->desc.bInterfaceSubClass, |
| - alt->desc.bInterfaceProtocol)) |
| - return -ENOMEM; |
| - } |
| + "DEVNUM=%03d", |
| + usb_dev->devnum)) |
| + return -ENOMEM; |
| |
| envp[i] = NULL; |
| - |
| return 0; |
| } |
| |
| #else |
| |
| static int usb_uevent(struct device *dev, char **envp, |
| - int num_envp, char *buffer, int buffer_size) |
| + int num_envp, char *buffer, int buffer_size) |
| { |
| return -ENODEV; |
| } |
| - |
| #endif /* CONFIG_HOTPLUG */ |
| |
| /** |
| --- a/drivers/usb/core/hub.c |
| +++ b/drivers/usb/core/hub.c |
| @@ -1367,11 +1367,15 @@ int usb_new_device(struct usb_device *ud |
| } |
| #endif |
| |
| + /* export the usbdev device-node for libusb */ |
| + udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, |
| + (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); |
| + |
| /* Register the device. The device driver is responsible |
| - * for adding the device files to usbfs and sysfs and for |
| - * configuring the device. |
| + * for adding the device files to sysfs and for configuring |
| + * the device. |
| */ |
| - err = device_add (&udev->dev); |
| + err = device_add(&udev->dev); |
| if (err) { |
| dev_err(&udev->dev, "can't device_add, error %d\n", err); |
| goto fail; |
| --- a/drivers/usb/core/inode.c |
| +++ b/drivers/usb/core/inode.c |
| @@ -662,7 +662,7 @@ static void usbfs_add_device(struct usb_ |
| sprintf (name, "%03d", dev->devnum); |
| dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, |
| dev->bus->usbfs_dentry, dev, |
| - &usbfs_device_file_operations, |
| + &usbdev_file_operations, |
| devuid, devgid); |
| if (dev->usbfs_dentry == NULL) { |
| err ("error creating usbfs device entry"); |
| --- a/drivers/usb/core/message.c |
| +++ b/drivers/usb/core/message.c |
| @@ -1305,7 +1305,7 @@ int usb_reset_configuration(struct usb_d |
| return 0; |
| } |
| |
| -static void release_interface(struct device *dev) |
| +void usb_release_interface(struct device *dev) |
| { |
| struct usb_interface *intf = to_usb_interface(dev); |
| struct usb_interface_cache *intfc = |
| @@ -1315,6 +1315,67 @@ static void release_interface(struct dev |
| kfree(intf); |
| } |
| |
| +#ifdef CONFIG_HOTPLUG |
| +static int usb_if_uevent(struct device *dev, char **envp, int num_envp, |
| + char *buffer, int buffer_size) |
| +{ |
| + struct usb_device *usb_dev; |
| + struct usb_interface *intf; |
| + struct usb_host_interface *alt; |
| + int i = 0; |
| + int length = 0; |
| + |
| + if (!dev) |
| + return -ENODEV; |
| + |
| + /* driver is often null here; dev_dbg() would oops */ |
| + pr_debug ("usb %s: uevent\n", dev->bus_id); |
| + |
| + intf = to_usb_interface(dev); |
| + usb_dev = interface_to_usbdev(intf); |
| + alt = intf->cur_altsetting; |
| + |
| + if (add_uevent_var(envp, num_envp, &i, |
| + buffer, buffer_size, &length, |
| + "INTERFACE=%d/%d/%d", |
| + alt->desc.bInterfaceClass, |
| + alt->desc.bInterfaceSubClass, |
| + alt->desc.bInterfaceProtocol)) |
| + return -ENOMEM; |
| + |
| + if (add_uevent_var(envp, num_envp, &i, |
| + buffer, buffer_size, &length, |
| + "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", |
| + le16_to_cpu(usb_dev->descriptor.idVendor), |
| + le16_to_cpu(usb_dev->descriptor.idProduct), |
| + le16_to_cpu(usb_dev->descriptor.bcdDevice), |
| + usb_dev->descriptor.bDeviceClass, |
| + usb_dev->descriptor.bDeviceSubClass, |
| + usb_dev->descriptor.bDeviceProtocol, |
| + alt->desc.bInterfaceClass, |
| + alt->desc.bInterfaceSubClass, |
| + alt->desc.bInterfaceProtocol)) |
| + return -ENOMEM; |
| + |
| + envp[i] = NULL; |
| + return 0; |
| +} |
| + |
| +#else |
| + |
| +static int usb_if_uevent(struct device *dev, char **envp, |
| + int num_envp, char *buffer, int buffer_size) |
| +{ |
| + return -ENODEV; |
| +} |
| +#endif /* CONFIG_HOTPLUG */ |
| + |
| +struct device_type usb_if_device_type = { |
| + .name = "usb_interface", |
| + .release = usb_release_interface, |
| + .uevent = usb_if_uevent, |
| +}; |
| + |
| /* |
| * usb_set_configuration - Makes a particular device setting be current |
| * @dev: the device whose configuration is being updated |
| @@ -1478,8 +1539,8 @@ free_interfaces: |
| intf->dev.parent = &dev->dev; |
| intf->dev.driver = NULL; |
| intf->dev.bus = &usb_bus_type; |
| + intf->dev.type = &usb_if_device_type; |
| intf->dev.dma_mask = dev->dev.dma_mask; |
| - intf->dev.release = release_interface; |
| device_initialize (&intf->dev); |
| mark_quiesced(intf); |
| sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", |
| --- a/drivers/usb/core/usb.c |
| +++ b/drivers/usb/core/usb.c |
| @@ -197,6 +197,11 @@ static void usb_release_dev(struct devic |
| kfree(udev); |
| } |
| |
| +struct device_type usb_device_type = { |
| + .name = "usb_device", |
| + .release = usb_release_dev, |
| +}; |
| + |
| #ifdef CONFIG_PM |
| |
| static int ksuspend_usb_init(void) |
| @@ -247,13 +252,10 @@ usb_alloc_dev(struct usb_device *parent, |
| |
| device_initialize(&dev->dev); |
| dev->dev.bus = &usb_bus_type; |
| + dev->dev.type = &usb_device_type; |
| dev->dev.dma_mask = bus->controller->dma_mask; |
| - dev->dev.release = usb_release_dev; |
| dev->state = USB_STATE_ATTACHED; |
| |
| - /* This magic assignment distinguishes devices from interfaces */ |
| - dev->dev.platform_data = &usb_generic_driver; |
| - |
| INIT_LIST_HEAD(&dev->ep0.urb_list); |
| dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE; |
| dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT; |
| @@ -882,9 +884,9 @@ static int __init usb_init(void) |
| retval = usb_register(&usbfs_driver); |
| if (retval) |
| goto driver_register_failed; |
| - retval = usbdev_init(); |
| + retval = usb_devio_init(); |
| if (retval) |
| - goto usbdevice_init_failed; |
| + goto usb_devio_init_failed; |
| retval = usbfs_init(); |
| if (retval) |
| goto fs_init_failed; |
| @@ -899,8 +901,8 @@ static int __init usb_init(void) |
| hub_init_failed: |
| usbfs_cleanup(); |
| fs_init_failed: |
| - usbdev_cleanup(); |
| -usbdevice_init_failed: |
| + usb_devio_cleanup(); |
| +usb_devio_init_failed: |
| usb_deregister(&usbfs_driver); |
| driver_register_failed: |
| usb_major_cleanup(); |
| @@ -927,7 +929,7 @@ static void __exit usb_exit(void) |
| usb_major_cleanup(); |
| usbfs_cleanup(); |
| usb_deregister(&usbfs_driver); |
| - usbdev_cleanup(); |
| + usb_devio_cleanup(); |
| usb_hub_cleanup(); |
| usb_host_cleanup(); |
| bus_unregister(&usb_bus_type); |
| --- a/drivers/usb/core/usb.h |
| +++ b/drivers/usb/core/usb.h |
| @@ -78,15 +78,13 @@ static inline int usb_autoresume_device( |
| |
| extern struct workqueue_struct *ksuspend_usb_wq; |
| extern struct bus_type usb_bus_type; |
| +extern struct device_type usb_device_type; |
| +extern struct device_type usb_if_device_type; |
| extern struct usb_device_driver usb_generic_driver; |
| |
| -/* Here's how we tell apart devices and interfaces. Luckily there's |
| - * no such thing as a platform USB device, so we can steal the use |
| - * of the platform_data field. */ |
| - |
| static inline int is_usb_device(const struct device *dev) |
| { |
| - return dev->platform_data == &usb_generic_driver; |
| + return dev->type == &usb_device_type; |
| } |
| |
| /* Do the same for device drivers and interface drivers. */ |
| @@ -122,11 +120,11 @@ extern const char *usbcore_name; |
| extern struct mutex usbfs_mutex; |
| extern struct usb_driver usbfs_driver; |
| extern const struct file_operations usbfs_devices_fops; |
| -extern const struct file_operations usbfs_device_file_operations; |
| +extern const struct file_operations usbdev_file_operations; |
| extern void usbfs_conn_disc_event(void); |
| |
| -extern int usbdev_init(void); |
| -extern void usbdev_cleanup(void); |
| +extern int usb_devio_init(void); |
| +extern void usb_devio_cleanup(void); |
| |
| struct dev_state { |
| struct list_head list; /* state list */ |
| --- a/include/linux/usb.h |
| +++ b/include/linux/usb.h |
| @@ -299,8 +299,9 @@ struct usb_bus { |
| int bandwidth_int_reqs; /* number of Interrupt requests */ |
| int bandwidth_isoc_reqs; /* number of Isoc. requests */ |
| |
| +#ifdef CONFIG_USB_DEVICEFS |
| struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */ |
| - |
| +#endif |
| struct class_device *class_dev; /* class device for this bus */ |
| |
| #if defined(CONFIG_USB_MON) |
| @@ -373,9 +374,12 @@ struct usb_device { |
| char *serial; /* iSerialNumber string, if present */ |
| |
| struct list_head filelist; |
| - struct device *usbfs_dev; |
| +#ifdef CONFIG_USB_DEVICE_CLASS |
| + struct device *usb_classdev; |
| +#endif |
| +#ifdef CONFIG_USB_DEVICEFS |
| struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */ |
| - |
| +#endif |
| /* |
| * Child devices - these can be either new devices |
| * (if this is a hub device), or different instances |