diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/file.c | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 70898716dd9a..f65b193cde3d 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c | |||
@@ -61,33 +61,66 @@ static struct file_operations usb_fops = { | |||
61 | .open = usb_open, | 61 | .open = usb_open, |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static struct class *usb_class; | 64 | static struct usb_class { |
65 | struct kref kref; | ||
66 | struct class *class; | ||
67 | } *usb_class; | ||
65 | 68 | ||
66 | int usb_major_init(void) | 69 | static int init_usb_class(void) |
67 | { | 70 | { |
68 | int error; | 71 | int result = 0; |
69 | 72 | ||
70 | error = register_chrdev(USB_MAJOR, "usb", &usb_fops); | 73 | if (usb_class != NULL) { |
71 | if (error) { | 74 | kref_get(&usb_class->kref); |
72 | err("unable to get major %d for usb devices", USB_MAJOR); | 75 | goto exit; |
73 | goto out; | 76 | } |
77 | |||
78 | usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL); | ||
79 | if (!usb_class) { | ||
80 | result = -ENOMEM; | ||
81 | goto exit; | ||
74 | } | 82 | } |
75 | 83 | ||
76 | usb_class = class_create(THIS_MODULE, "usb"); | 84 | kref_init(&usb_class->kref); |
77 | if (IS_ERR(usb_class)) { | 85 | usb_class->class = class_create(THIS_MODULE, "usb"); |
78 | error = PTR_ERR(usb_class); | 86 | if (IS_ERR(usb_class->class)) { |
87 | result = IS_ERR(usb_class->class); | ||
79 | err("class_create failed for usb devices"); | 88 | err("class_create failed for usb devices"); |
80 | unregister_chrdev(USB_MAJOR, "usb"); | 89 | kfree(usb_class); |
81 | goto out; | 90 | usb_class = NULL; |
82 | } | 91 | } |
83 | 92 | ||
84 | out: | 93 | exit: |
94 | return result; | ||
95 | } | ||
96 | |||
97 | static void release_usb_class(struct kref *kref) | ||
98 | { | ||
99 | /* Ok, we cheat as we know we only have one usb_class */ | ||
100 | class_destroy(usb_class->class); | ||
101 | kfree(usb_class); | ||
102 | usb_class = NULL; | ||
103 | } | ||
104 | |||
105 | static void destroy_usb_class(void) | ||
106 | { | ||
107 | if (usb_class) | ||
108 | kref_put(&usb_class->kref, release_usb_class); | ||
109 | } | ||
110 | |||
111 | int usb_major_init(void) | ||
112 | { | ||
113 | int error; | ||
114 | |||
115 | error = register_chrdev(USB_MAJOR, "usb", &usb_fops); | ||
116 | if (error) | ||
117 | err("unable to get major %d for usb devices", USB_MAJOR); | ||
118 | |||
85 | return error; | 119 | return error; |
86 | } | 120 | } |
87 | 121 | ||
88 | void usb_major_cleanup(void) | 122 | void usb_major_cleanup(void) |
89 | { | 123 | { |
90 | class_destroy(usb_class); | ||
91 | unregister_chrdev(USB_MAJOR, "usb"); | 124 | unregister_chrdev(USB_MAJOR, "usb"); |
92 | } | 125 | } |
93 | 126 | ||
@@ -149,6 +182,10 @@ int usb_register_dev(struct usb_interface *intf, | |||
149 | if (retval) | 182 | if (retval) |
150 | goto exit; | 183 | goto exit; |
151 | 184 | ||
185 | retval = init_usb_class(); | ||
186 | if (retval) | ||
187 | goto exit; | ||
188 | |||
152 | intf->minor = minor; | 189 | intf->minor = minor; |
153 | 190 | ||
154 | /* create a usb class device for this usb interface */ | 191 | /* create a usb class device for this usb interface */ |
@@ -158,7 +195,7 @@ int usb_register_dev(struct usb_interface *intf, | |||
158 | ++temp; | 195 | ++temp; |
159 | else | 196 | else |
160 | temp = name; | 197 | temp = name; |
161 | intf->usb_dev = device_create(usb_class, &intf->dev, | 198 | intf->usb_dev = device_create(usb_class->class, &intf->dev, |
162 | MKDEV(USB_MAJOR, minor), "%s", temp); | 199 | MKDEV(USB_MAJOR, minor), "%s", temp); |
163 | if (IS_ERR(intf->usb_dev)) { | 200 | if (IS_ERR(intf->usb_dev)) { |
164 | spin_lock (&minor_lock); | 201 | spin_lock (&minor_lock); |
@@ -205,9 +242,10 @@ void usb_deregister_dev(struct usb_interface *intf, | |||
205 | spin_unlock (&minor_lock); | 242 | spin_unlock (&minor_lock); |
206 | 243 | ||
207 | snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); | 244 | snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base); |
208 | device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor)); | 245 | device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor)); |
209 | intf->usb_dev = NULL; | 246 | intf->usb_dev = NULL; |
210 | intf->minor = -1; | 247 | intf->minor = -1; |
248 | destroy_usb_class(); | ||
211 | } | 249 | } |
212 | EXPORT_SYMBOL(usb_deregister_dev); | 250 | EXPORT_SYMBOL(usb_deregister_dev); |
213 | 251 | ||