X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fcore%2Ffile.c;h=f794f07cfb3330f92ebfb135f1f0b8e601613594;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=37b13368c8145c9ca8522aab5d074d30dc3eb42f;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 37b13368c..f794f07cf 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -1,5 +1,5 @@ /* - * drivers/usb/file.c + * drivers/usb/core/file.c * * (C) Copyright Linus Torvalds 1999 * (C) Copyright Johannes Erdfelt 1999-2001 @@ -15,7 +15,6 @@ * */ -#include #include #include #include @@ -24,15 +23,15 @@ #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]; @@ -56,38 +55,71 @@ static int usb_open(struct inode * inode, struct file * file) return err; } -static struct file_operations usb_fops = { +static const struct file_operations usb_fops = { .owner = THIS_MODULE, .open = usb_open, }; -static struct class *usb_class; +static struct usb_class { + struct kref kref; + struct class *class; +} *usb_class; -int usb_major_init(void) +static int init_usb_class(void) { - int error; + int result = 0; - error = register_chrdev(USB_MAJOR, "usb", &usb_fops); - if (error) { - err("unable to get major %d for usb devices", USB_MAJOR); - goto out; + 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; } - usb_class = class_create(THIS_MODULE, "usb"); - if (IS_ERR(usb_class)) { - error = PTR_ERR(usb_class); + 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"); - unregister_chrdev(USB_MAJOR, "usb"); - goto out; + kfree(usb_class); + usb_class = NULL; } -out: +exit: + return result; +} + +static void release_usb_class(struct kref *kref) +{ + /* Ok, we cheat as we know we only have one usb_class */ + class_destroy(usb_class->class); + kfree(usb_class); + usb_class = NULL; +} + +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) + err("unable to get major %d for usb devices", USB_MAJOR); + return error; } void usb_major_cleanup(void) { - class_destroy(usb_class); unregister_chrdev(USB_MAJOR, "usb"); } @@ -146,6 +178,10 @@ int usb_register_dev(struct usb_interface *intf, } spin_unlock (&minor_lock); + if (retval) + goto exit; + + retval = init_usb_class(); if (retval) goto exit; @@ -158,7 +194,7 @@ int usb_register_dev(struct usb_interface *intf, ++temp; else temp = name; - intf->class_dev = class_device_create(usb_class, NULL, + intf->class_dev = class_device_create(usb_class->class, NULL, MKDEV(USB_MAJOR, minor), &intf->dev, "%s", temp); if (IS_ERR(intf->class_dev)) { @@ -206,9 +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); - class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); + 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);