X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Ffile.c;h=8de4f8c99d61f3a7cb01696bde29202ed814b160;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=db26eda94dbbb0a0e1eb23dc524cd9292ea3e56d;hpb=6a77f38946aaee1cd85eeec6cf4229b204c15071;p=linux-2.6.git diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index db26eda94..8de4f8c99 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -15,29 +15,23 @@ * */ -#include #include -#include #include #include - -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif #include +#include "usb.h" + #define MAX_USB_MINORS 256 -static struct file_operations *usb_minors[MAX_USB_MINORS]; +static const struct file_operations *usb_minors[MAX_USB_MINORS]; static DEFINE_SPINLOCK(minor_lock); static int usb_open(struct inode * inode, struct file * file) { int minor = iminor(inode); - struct file_operations *c; + const struct file_operations *c; int err = -ENODEV; - struct file_operations *old_fops, *new_fops = NULL; + const struct file_operations *old_fops, *new_fops = NULL; spin_lock (&minor_lock); c = usb_minors[minor]; @@ -66,54 +60,69 @@ static struct file_operations usb_fops = { .open = usb_open, }; -static void release_usb_class_dev(struct class_device *class_dev) +static struct usb_class { + struct kref kref; + struct class *class; +} *usb_class; + +static int init_usb_class(void) +{ + int result = 0; + + if (usb_class != NULL) { + kref_get(&usb_class->kref); + goto exit; + } + + usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL); + if (!usb_class) { + result = -ENOMEM; + goto exit; + } + + kref_init(&usb_class->kref); + usb_class->class = class_create(THIS_MODULE, "usb"); + if (IS_ERR(usb_class->class)) { + result = IS_ERR(usb_class->class); + err("class_create failed for usb devices"); + kfree(usb_class); + usb_class = NULL; + } + +exit: + return result; +} + +static void release_usb_class(struct kref *kref) { - dbg("%s - %s", __FUNCTION__, class_dev->class_id); - kfree(class_dev); + /* Ok, we cheat as we know we only have one usb_class */ + class_destroy(usb_class->class); + kfree(usb_class); + usb_class = NULL; } -static struct class usb_class = { - .name = "usb", - .release = &release_usb_class_dev, -}; +static void destroy_usb_class(void) +{ + if (usb_class) + kref_put(&usb_class->kref, release_usb_class); +} int usb_major_init(void) { int error; error = register_chrdev(USB_MAJOR, "usb", &usb_fops); - if (error) { + if (error) err("unable to get major %d for usb devices", USB_MAJOR); - goto out; - } - - error = class_register(&usb_class); - if (error) { - err("class_register failed for usb devices"); - unregister_chrdev(USB_MAJOR, "usb"); - goto out; - } - devfs_mk_dir("usb"); - -out: return error; } void usb_major_cleanup(void) { - class_unregister(&usb_class); - devfs_remove("usb"); unregister_chrdev(USB_MAJOR, "usb"); } -static ssize_t show_dev(struct class_device *class_dev, char *buf) -{ - int minor = (int)(long)class_get_devdata(class_dev); - return print_dev_t(buf, MKDEV(USB_MAJOR, minor)); -} -static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); - /** * usb_register_dev - register a USB device, and ask for a minor number * @intf: pointer to the usb_interface that is being registered @@ -125,8 +134,7 @@ static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL); * enabled, the minor number will be based on the next available free minor, * starting at the class_driver->minor_base. * - * This function also creates the devfs file for the usb device, if devfs - * is enabled, and creates a usb class device in the sysfs tree. + * This function also creates a usb class device in the sysfs tree. * * usb_deregister_dev() must be called when the driver is done with * the minor numbers given out by this function. @@ -141,7 +149,6 @@ int usb_register_dev(struct usb_interface *intf, int minor_base = class_driver->minor_base; int minor = 0; char name[BUS_ID_SIZE]; - struct class_device *class_dev; char *temp; #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -174,29 +181,27 @@ int usb_register_dev(struct usb_interface *intf, if (retval) goto exit; - intf->minor = minor; + retval = init_usb_class(); + if (retval) + goto exit; - /* handle the devfs registration */ - snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); - devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name); + intf->minor = minor; /* create a usb class device for this usb interface */ - class_dev = kmalloc(sizeof(*class_dev), GFP_KERNEL); - if (class_dev) { - memset(class_dev, 0x00, sizeof(struct class_device)); - class_dev->class = &usb_class; - class_dev->dev = &intf->dev; - - temp = strrchr(name, '/'); - if (temp && (temp[1] != 0x00)) - ++temp; - else - temp = name; - snprintf(class_dev->class_id, BUS_ID_SIZE, "%s", temp); - class_set_devdata(class_dev, (void *)(long)intf->minor); - class_device_register(class_dev); - class_device_create_file(class_dev, &class_device_attr_dev); - intf->class_dev = class_dev; + snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base); + temp = strrchr(name, '/'); + if (temp && (temp[1] != 0x00)) + ++temp; + else + temp = name; + intf->class_dev = class_device_create(usb_class->class, NULL, + MKDEV(USB_MAJOR, minor), + &intf->dev, "%s", temp); + if (IS_ERR(intf->class_dev)) { + spin_lock (&minor_lock); + usb_minors[intf->minor] = NULL; + spin_unlock (&minor_lock); + retval = PTR_ERR(intf->class_dev); } exit: return retval; @@ -213,9 +218,8 @@ EXPORT_SYMBOL(usb_register_dev); * call to usb_register_dev() (usually when the device is disconnected * from the system.) * - * This function also cleans up the devfs file for the usb device, if devfs - * is enabled, and removes the usb class device from the sysfs tree. - * + * This function also removes the usb class device from the sysfs tree. + * * This should be called by all drivers that use the USB major number. */ void usb_deregister_dev(struct usb_interface *intf, @@ -238,13 +242,10 @@ void usb_deregister_dev(struct usb_interface *intf, spin_unlock (&minor_lock); snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); - devfs_remove (name); - - if (intf->class_dev) { - class_device_unregister(intf->class_dev); - intf->class_dev = NULL; - } + class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); + intf->class_dev = NULL; intf->minor = -1; + destroy_usb_class(); } EXPORT_SYMBOL(usb_deregister_dev);