aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Bailey <saharabeara@gmail.com>2006-11-19 01:30:16 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2006-12-01 17:25:52 -0500
commit7e27780ffdf5fcf8675dfb278ca316a1f2b7e179 (patch)
tree0e65f7afd10ef3fae8daac86a4327a1b3bd481dc /drivers/usb
parent10c8211c634f759633ffcdc3b0e2913963b32abc (diff)
USB: added dynamic major number for USB endpoints
This patch is an update for Greg K-H's proposed usbfs2: http://sourceforge.net/mailarchive/message.php?msg_id=19295229 It creates a dynamic major for USB endpoints and fixes the endpoint minor calculation. Signed-off-by: Sarah Bailey <saharabeara@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/endpoint.c98
1 files changed, 85 insertions, 13 deletions
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 3b2d137912be..c505b767cee1 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -10,15 +10,20 @@
10 */ 10 */
11 11
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/spinlock.h>
14#include <linux/idr.h>
13#include <linux/usb.h> 15#include <linux/usb.h>
14#include "usb.h" 16#include "usb.h"
15 17
16/* endpoint stuff */ 18#define MAX_ENDPOINT_MINORS (64*128*32)
19static int usb_endpoint_major;
20static DEFINE_IDR(endpoint_idr);
17 21
18struct ep_device { 22struct ep_device {
19 struct usb_endpoint_descriptor *desc; 23 struct usb_endpoint_descriptor *desc;
20 struct usb_device *udev; 24 struct usb_device *udev;
21 struct device dev; 25 struct device dev;
26 int minor;
22}; 27};
23#define to_ep_device(_dev) \ 28#define to_ep_device(_dev) \
24 container_of(_dev, struct ep_device, dev) 29 container_of(_dev, struct ep_device, dev)
@@ -152,6 +157,55 @@ static struct attribute_group ep_dev_attr_grp = {
152 .attrs = ep_dev_attrs, 157 .attrs = ep_dev_attrs,
153}; 158};
154 159
160static int usb_endpoint_major_init(void)
161{
162 dev_t dev;
163 int error;
164
165 error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS,
166 "usb_endpoint");
167 if (error) {
168 err("unable to get a dynamic major for usb endpoints");
169 return error;
170 }
171 usb_endpoint_major = MAJOR(dev);
172
173 return error;
174}
175
176static void usb_endpoint_major_cleanup(void)
177{
178 unregister_chrdev_region(MKDEV(usb_endpoint_major, 0),
179 MAX_ENDPOINT_MINORS);
180}
181
182static int endpoint_get_minor(struct ep_device *ep_dev)
183{
184 static DEFINE_MUTEX(minor_lock);
185 int retval = -ENOMEM;
186 int id;
187
188 mutex_lock(&minor_lock);
189 if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0)
190 goto exit;
191
192 retval = idr_get_new(&endpoint_idr, ep_dev, &id);
193 if (retval < 0) {
194 if (retval == -EAGAIN)
195 retval = -ENOMEM;
196 goto exit;
197 }
198 ep_dev->minor = id & MAX_ID_MASK;
199exit:
200 mutex_unlock(&minor_lock);
201 return retval;
202}
203
204static void endpoint_free_minor(struct ep_device *ep_dev)
205{
206 idr_remove(&endpoint_idr, ep_dev->minor);
207}
208
155static struct endpoint_class { 209static struct endpoint_class {
156 struct kref kref; 210 struct kref kref;
157 struct class *class; 211 struct class *class;
@@ -176,11 +230,20 @@ static int init_endpoint_class(void)
176 ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); 230 ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
177 if (IS_ERR(ep_class->class)) { 231 if (IS_ERR(ep_class->class)) {
178 result = IS_ERR(ep_class->class); 232 result = IS_ERR(ep_class->class);
179 kfree(ep_class); 233 goto class_create_error;
180 ep_class = NULL;
181 goto exit;
182 } 234 }
183 235
236 result = usb_endpoint_major_init();
237 if (result)
238 goto endpoint_major_error;
239
240 goto exit;
241
242endpoint_major_error:
243 class_destroy(ep_class->class);
244class_create_error:
245 kfree(ep_class);
246 ep_class = NULL;
184exit: 247exit:
185 return result; 248 return result;
186} 249}
@@ -191,6 +254,7 @@ static void release_endpoint_class(struct kref *kref)
191 class_destroy(ep_class->class); 254 class_destroy(ep_class->class);
192 kfree(ep_class); 255 kfree(ep_class);
193 ep_class = NULL; 256 ep_class = NULL;
257 usb_endpoint_major_cleanup();
194} 258}
195 259
196static void destroy_endpoint_class(void) 260static void destroy_endpoint_class(void)
@@ -213,7 +277,6 @@ int usb_create_ep_files(struct device *parent,
213{ 277{
214 char name[8]; 278 char name[8];
215 struct ep_device *ep_dev; 279 struct ep_device *ep_dev;
216 int minor;
217 int retval; 280 int retval;
218 281
219 retval = init_endpoint_class(); 282 retval = init_endpoint_class();
@@ -226,12 +289,16 @@ int usb_create_ep_files(struct device *parent,
226 goto error_alloc; 289 goto error_alloc;
227 } 290 }
228 291
229 /* fun calculation to determine the minor of this endpoint */ 292 retval = endpoint_get_minor(ep_dev);
230 minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1); 293 if (retval) {
294 dev_err(parent, "can not allocate minor number for %s",
295 ep_dev->dev.bus_id);
296 goto error_register;
297 }
231 298
232 ep_dev->desc = &endpoint->desc; 299 ep_dev->desc = &endpoint->desc;
233 ep_dev->udev = udev; 300 ep_dev->udev = udev;
234 ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number... 301 ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
235 ep_dev->dev.class = ep_class->class; 302 ep_dev->dev.class = ep_class->class;
236 ep_dev->dev.parent = parent; 303 ep_dev->dev.parent = parent;
237 ep_dev->dev.release = ep_device_release; 304 ep_dev->dev.release = ep_device_release;
@@ -241,7 +308,7 @@ int usb_create_ep_files(struct device *parent,
241 308
242 retval = device_register(&ep_dev->dev); 309 retval = device_register(&ep_dev->dev);
243 if (retval) 310 if (retval)
244 goto error_register; 311 goto error_chrdev;
245 retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); 312 retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
246 if (retval) 313 if (retval)
247 goto error_group; 314 goto error_group;
@@ -261,6 +328,9 @@ error_group:
261 destroy_endpoint_class(); 328 destroy_endpoint_class();
262 return retval; 329 return retval;
263 330
331error_chrdev:
332 endpoint_free_minor(ep_dev);
333
264error_register: 334error_register:
265 kfree(ep_dev); 335 kfree(ep_dev);
266error_alloc: 336error_alloc:
@@ -271,14 +341,16 @@ exit:
271 341
272void usb_remove_ep_files(struct usb_host_endpoint *endpoint) 342void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
273{ 343{
344 struct ep_device *ep_dev = endpoint->ep_dev;
274 345
275 if (endpoint->ep_dev) { 346 if (ep_dev) {
276 char name[8]; 347 char name[8];
277 348
278 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); 349 sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
279 sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name); 350 sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
280 sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); 351 sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
281 device_unregister(&endpoint->ep_dev->dev); 352 endpoint_free_minor(ep_dev);
353 device_unregister(&ep_dev->dev);
282 endpoint->ep_dev = NULL; 354 endpoint->ep_dev = NULL;
283 destroy_endpoint_class(); 355 destroy_endpoint_class();
284 } 356 }