diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/usb/class/cdc-wdm.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/usb/class/cdc-wdm.c')
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 408 |
1 files changed, 155 insertions, 253 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 5f0cb417b73..90581a85134 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/usb/cdc.h> | 23 | #include <linux/usb/cdc.h> |
24 | #include <asm/byteorder.h> | 24 | #include <asm/byteorder.h> |
25 | #include <asm/unaligned.h> | 25 | #include <asm/unaligned.h> |
26 | #include <linux/usb/cdc-wdm.h> | ||
27 | 26 | ||
28 | /* | 27 | /* |
29 | * Version Information | 28 | * Version Information |
@@ -55,7 +54,6 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); | |||
55 | #define WDM_POLL_RUNNING 6 | 54 | #define WDM_POLL_RUNNING 6 |
56 | #define WDM_RESPONDING 7 | 55 | #define WDM_RESPONDING 7 |
57 | #define WDM_SUSPENDING 8 | 56 | #define WDM_SUSPENDING 8 |
58 | #define WDM_RESETTING 9 | ||
59 | 57 | ||
60 | #define WDM_MAX 16 | 58 | #define WDM_MAX 16 |
61 | 59 | ||
@@ -63,8 +61,6 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); | |||
63 | #define WDM_DEFAULT_BUFSIZE 256 | 61 | #define WDM_DEFAULT_BUFSIZE 256 |
64 | 62 | ||
65 | static DEFINE_MUTEX(wdm_mutex); | 63 | static DEFINE_MUTEX(wdm_mutex); |
66 | static DEFINE_SPINLOCK(wdm_device_list_lock); | ||
67 | static LIST_HEAD(wdm_device_list); | ||
68 | 64 | ||
69 | /* --- method tables --- */ | 65 | /* --- method tables --- */ |
70 | 66 | ||
@@ -86,6 +82,7 @@ struct wdm_device { | |||
86 | u16 bufsize; | 82 | u16 bufsize; |
87 | u16 wMaxCommand; | 83 | u16 wMaxCommand; |
88 | u16 wMaxPacketSize; | 84 | u16 wMaxPacketSize; |
85 | u16 bMaxPacketSize0; | ||
89 | __le16 inum; | 86 | __le16 inum; |
90 | int reslength; | 87 | int reslength; |
91 | int length; | 88 | int length; |
@@ -99,44 +96,10 @@ struct wdm_device { | |||
99 | struct work_struct rxwork; | 96 | struct work_struct rxwork; |
100 | int werr; | 97 | int werr; |
101 | int rerr; | 98 | int rerr; |
102 | |||
103 | struct list_head device_list; | ||
104 | int (*manage_power)(struct usb_interface *, int); | ||
105 | }; | 99 | }; |
106 | 100 | ||
107 | static struct usb_driver wdm_driver; | 101 | static struct usb_driver wdm_driver; |
108 | 102 | ||
109 | /* return intfdata if we own the interface, else look up intf in the list */ | ||
110 | static struct wdm_device *wdm_find_device(struct usb_interface *intf) | ||
111 | { | ||
112 | struct wdm_device *desc; | ||
113 | |||
114 | spin_lock(&wdm_device_list_lock); | ||
115 | list_for_each_entry(desc, &wdm_device_list, device_list) | ||
116 | if (desc->intf == intf) | ||
117 | goto found; | ||
118 | desc = NULL; | ||
119 | found: | ||
120 | spin_unlock(&wdm_device_list_lock); | ||
121 | |||
122 | return desc; | ||
123 | } | ||
124 | |||
125 | static struct wdm_device *wdm_find_device_by_minor(int minor) | ||
126 | { | ||
127 | struct wdm_device *desc; | ||
128 | |||
129 | spin_lock(&wdm_device_list_lock); | ||
130 | list_for_each_entry(desc, &wdm_device_list, device_list) | ||
131 | if (desc->intf->minor == minor) | ||
132 | goto found; | ||
133 | desc = NULL; | ||
134 | found: | ||
135 | spin_unlock(&wdm_device_list_lock); | ||
136 | |||
137 | return desc; | ||
138 | } | ||
139 | |||
140 | /* --- callbacks --- */ | 103 | /* --- callbacks --- */ |
141 | static void wdm_out_callback(struct urb *urb) | 104 | static void wdm_out_callback(struct urb *urb) |
142 | { | 105 | { |
@@ -145,9 +108,8 @@ static void wdm_out_callback(struct urb *urb) | |||
145 | spin_lock(&desc->iuspin); | 108 | spin_lock(&desc->iuspin); |
146 | desc->werr = urb->status; | 109 | desc->werr = urb->status; |
147 | spin_unlock(&desc->iuspin); | 110 | spin_unlock(&desc->iuspin); |
148 | kfree(desc->outbuf); | ||
149 | desc->outbuf = NULL; | ||
150 | clear_bit(WDM_IN_USE, &desc->flags); | 111 | clear_bit(WDM_IN_USE, &desc->flags); |
112 | kfree(desc->outbuf); | ||
151 | wake_up(&desc->wait); | 113 | wake_up(&desc->wait); |
152 | } | 114 | } |
153 | 115 | ||
@@ -200,9 +162,11 @@ static void wdm_int_callback(struct urb *urb) | |||
200 | int rv = 0; | 162 | int rv = 0; |
201 | int status = urb->status; | 163 | int status = urb->status; |
202 | struct wdm_device *desc; | 164 | struct wdm_device *desc; |
165 | struct usb_ctrlrequest *req; | ||
203 | struct usb_cdc_notification *dr; | 166 | struct usb_cdc_notification *dr; |
204 | 167 | ||
205 | desc = urb->context; | 168 | desc = urb->context; |
169 | req = desc->irq; | ||
206 | dr = (struct usb_cdc_notification *)desc->sbuf; | 170 | dr = (struct usb_cdc_notification *)desc->sbuf; |
207 | 171 | ||
208 | if (status) { | 172 | if (status) { |
@@ -249,6 +213,24 @@ static void wdm_int_callback(struct urb *urb) | |||
249 | goto exit; | 213 | goto exit; |
250 | } | 214 | } |
251 | 215 | ||
216 | req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); | ||
217 | req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; | ||
218 | req->wValue = 0; | ||
219 | req->wIndex = desc->inum; | ||
220 | req->wLength = cpu_to_le16(desc->wMaxCommand); | ||
221 | |||
222 | usb_fill_control_urb( | ||
223 | desc->response, | ||
224 | interface_to_usbdev(desc->intf), | ||
225 | /* using common endpoint 0 */ | ||
226 | usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), | ||
227 | (unsigned char *)req, | ||
228 | desc->inbuf, | ||
229 | desc->wMaxCommand, | ||
230 | wdm_in_callback, | ||
231 | desc | ||
232 | ); | ||
233 | desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
252 | spin_lock(&desc->iuspin); | 234 | spin_lock(&desc->iuspin); |
253 | clear_bit(WDM_READ, &desc->flags); | 235 | clear_bit(WDM_READ, &desc->flags); |
254 | set_bit(WDM_RESPONDING, &desc->flags); | 236 | set_bit(WDM_RESPONDING, &desc->flags); |
@@ -297,8 +279,14 @@ static void free_urbs(struct wdm_device *desc) | |||
297 | 279 | ||
298 | static void cleanup(struct wdm_device *desc) | 280 | static void cleanup(struct wdm_device *desc) |
299 | { | 281 | { |
300 | kfree(desc->sbuf); | 282 | usb_free_coherent(interface_to_usbdev(desc->intf), |
301 | kfree(desc->inbuf); | 283 | desc->wMaxPacketSize, |
284 | desc->sbuf, | ||
285 | desc->validity->transfer_dma); | ||
286 | usb_free_coherent(interface_to_usbdev(desc->intf), | ||
287 | desc->bMaxPacketSize0, | ||
288 | desc->inbuf, | ||
289 | desc->response->transfer_dma); | ||
302 | kfree(desc->orq); | 290 | kfree(desc->orq); |
303 | kfree(desc->irq); | 291 | kfree(desc->irq); |
304 | kfree(desc->ubuf); | 292 | kfree(desc->ubuf); |
@@ -324,7 +312,7 @@ static ssize_t wdm_write | |||
324 | if (we < 0) | 312 | if (we < 0) |
325 | return -EIO; | 313 | return -EIO; |
326 | 314 | ||
327 | buf = kmalloc(count, GFP_KERNEL); | 315 | desc->outbuf = buf = kmalloc(count, GFP_KERNEL); |
328 | if (!buf) { | 316 | if (!buf) { |
329 | rv = -ENOMEM; | 317 | rv = -ENOMEM; |
330 | goto outnl; | 318 | goto outnl; |
@@ -354,7 +342,6 @@ static ssize_t wdm_write | |||
354 | r = usb_autopm_get_interface(desc->intf); | 342 | r = usb_autopm_get_interface(desc->intf); |
355 | if (r < 0) { | 343 | if (r < 0) { |
356 | kfree(buf); | 344 | kfree(buf); |
357 | rv = usb_translate_errors(r); | ||
358 | goto outnp; | 345 | goto outnp; |
359 | } | 346 | } |
360 | 347 | ||
@@ -364,13 +351,8 @@ static ssize_t wdm_write | |||
364 | else | 351 | else |
365 | if (test_bit(WDM_IN_USE, &desc->flags)) | 352 | if (test_bit(WDM_IN_USE, &desc->flags)) |
366 | r = -EAGAIN; | 353 | r = -EAGAIN; |
367 | |||
368 | if (test_bit(WDM_RESETTING, &desc->flags)) | ||
369 | r = -EIO; | ||
370 | |||
371 | if (r < 0) { | 354 | if (r < 0) { |
372 | kfree(buf); | 355 | kfree(buf); |
373 | rv = r; | ||
374 | goto out; | 356 | goto out; |
375 | } | 357 | } |
376 | 358 | ||
@@ -394,15 +376,12 @@ static ssize_t wdm_write | |||
394 | req->wIndex = desc->inum; | 376 | req->wIndex = desc->inum; |
395 | req->wLength = cpu_to_le16(count); | 377 | req->wLength = cpu_to_le16(count); |
396 | set_bit(WDM_IN_USE, &desc->flags); | 378 | set_bit(WDM_IN_USE, &desc->flags); |
397 | desc->outbuf = buf; | ||
398 | 379 | ||
399 | rv = usb_submit_urb(desc->command, GFP_KERNEL); | 380 | rv = usb_submit_urb(desc->command, GFP_KERNEL); |
400 | if (rv < 0) { | 381 | if (rv < 0) { |
401 | kfree(buf); | 382 | kfree(buf); |
402 | desc->outbuf = NULL; | ||
403 | clear_bit(WDM_IN_USE, &desc->flags); | 383 | clear_bit(WDM_IN_USE, &desc->flags); |
404 | dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); | 384 | dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); |
405 | rv = usb_translate_errors(rv); | ||
406 | } else { | 385 | } else { |
407 | dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", | 386 | dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", |
408 | req->wIndex); | 387 | req->wIndex); |
@@ -418,7 +397,7 @@ outnl: | |||
418 | static ssize_t wdm_read | 397 | static ssize_t wdm_read |
419 | (struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 398 | (struct file *file, char __user *buffer, size_t count, loff_t *ppos) |
420 | { | 399 | { |
421 | int rv, cntr; | 400 | int rv, cntr = 0; |
422 | int i = 0; | 401 | int i = 0; |
423 | struct wdm_device *desc = file->private_data; | 402 | struct wdm_device *desc = file->private_data; |
424 | 403 | ||
@@ -427,8 +406,7 @@ static ssize_t wdm_read | |||
427 | if (rv < 0) | 406 | if (rv < 0) |
428 | return -ERESTARTSYS; | 407 | return -ERESTARTSYS; |
429 | 408 | ||
430 | cntr = ACCESS_ONCE(desc->length); | 409 | if (desc->length == 0) { |
431 | if (cntr == 0) { | ||
432 | desc->read = 0; | 410 | desc->read = 0; |
433 | retry: | 411 | retry: |
434 | if (test_bit(WDM_DISCONNECTING, &desc->flags)) { | 412 | if (test_bit(WDM_DISCONNECTING, &desc->flags)) { |
@@ -452,10 +430,6 @@ retry: | |||
452 | rv = -ENODEV; | 430 | rv = -ENODEV; |
453 | goto err; | 431 | goto err; |
454 | } | 432 | } |
455 | if (test_bit(WDM_RESETTING, &desc->flags)) { | ||
456 | rv = -EIO; | ||
457 | goto err; | ||
458 | } | ||
459 | usb_mark_last_busy(interface_to_usbdev(desc->intf)); | 433 | usb_mark_last_busy(interface_to_usbdev(desc->intf)); |
460 | if (rv < 0) { | 434 | if (rv < 0) { |
461 | rv = -ERESTARTSYS; | 435 | rv = -ERESTARTSYS; |
@@ -479,35 +453,29 @@ retry: | |||
479 | goto retry; | 453 | goto retry; |
480 | } | 454 | } |
481 | if (!desc->reslength) { /* zero length read */ | 455 | if (!desc->reslength) { /* zero length read */ |
482 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); | ||
483 | clear_bit(WDM_READ, &desc->flags); | ||
484 | spin_unlock_irq(&desc->iuspin); | 456 | spin_unlock_irq(&desc->iuspin); |
485 | goto retry; | 457 | goto retry; |
486 | } | 458 | } |
487 | cntr = desc->length; | 459 | clear_bit(WDM_READ, &desc->flags); |
488 | spin_unlock_irq(&desc->iuspin); | 460 | spin_unlock_irq(&desc->iuspin); |
489 | } | 461 | } |
490 | 462 | ||
491 | if (cntr > count) | 463 | cntr = count > desc->length ? desc->length : count; |
492 | cntr = count; | ||
493 | rv = copy_to_user(buffer, desc->ubuf, cntr); | 464 | rv = copy_to_user(buffer, desc->ubuf, cntr); |
494 | if (rv > 0) { | 465 | if (rv > 0) { |
495 | rv = -EFAULT; | 466 | rv = -EFAULT; |
496 | goto err; | 467 | goto err; |
497 | } | 468 | } |
498 | 469 | ||
499 | spin_lock_irq(&desc->iuspin); | ||
500 | |||
501 | for (i = 0; i < desc->length - cntr; i++) | 470 | for (i = 0; i < desc->length - cntr; i++) |
502 | desc->ubuf[i] = desc->ubuf[i + cntr]; | 471 | desc->ubuf[i] = desc->ubuf[i + cntr]; |
503 | 472 | ||
473 | spin_lock_irq(&desc->iuspin); | ||
504 | desc->length -= cntr; | 474 | desc->length -= cntr; |
475 | spin_unlock_irq(&desc->iuspin); | ||
505 | /* in case we had outstanding data */ | 476 | /* in case we had outstanding data */ |
506 | if (!desc->length) | 477 | if (!desc->length) |
507 | clear_bit(WDM_READ, &desc->flags); | 478 | clear_bit(WDM_READ, &desc->flags); |
508 | |||
509 | spin_unlock_irq(&desc->iuspin); | ||
510 | |||
511 | rv = cntr; | 479 | rv = cntr; |
512 | 480 | ||
513 | err: | 481 | err: |
@@ -520,13 +488,11 @@ static int wdm_flush(struct file *file, fl_owner_t id) | |||
520 | struct wdm_device *desc = file->private_data; | 488 | struct wdm_device *desc = file->private_data; |
521 | 489 | ||
522 | wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); | 490 | wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); |
523 | 491 | if (desc->werr < 0) | |
524 | /* cannot dereference desc->intf if WDM_DISCONNECTING */ | ||
525 | if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags)) | ||
526 | dev_err(&desc->intf->dev, "Error in flush path: %d\n", | 492 | dev_err(&desc->intf->dev, "Error in flush path: %d\n", |
527 | desc->werr); | 493 | desc->werr); |
528 | 494 | ||
529 | return usb_translate_errors(desc->werr); | 495 | return desc->werr; |
530 | } | 496 | } |
531 | 497 | ||
532 | static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) | 498 | static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) |
@@ -537,7 +503,7 @@ static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) | |||
537 | 503 | ||
538 | spin_lock_irqsave(&desc->iuspin, flags); | 504 | spin_lock_irqsave(&desc->iuspin, flags); |
539 | if (test_bit(WDM_DISCONNECTING, &desc->flags)) { | 505 | if (test_bit(WDM_DISCONNECTING, &desc->flags)) { |
540 | mask = POLLHUP | POLLERR; | 506 | mask = POLLERR; |
541 | spin_unlock_irqrestore(&desc->iuspin, flags); | 507 | spin_unlock_irqrestore(&desc->iuspin, flags); |
542 | goto desc_out; | 508 | goto desc_out; |
543 | } | 509 | } |
@@ -563,11 +529,11 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
563 | struct wdm_device *desc; | 529 | struct wdm_device *desc; |
564 | 530 | ||
565 | mutex_lock(&wdm_mutex); | 531 | mutex_lock(&wdm_mutex); |
566 | desc = wdm_find_device_by_minor(minor); | 532 | intf = usb_find_interface(&wdm_driver, minor); |
567 | if (!desc) | 533 | if (!intf) |
568 | goto out; | 534 | goto out; |
569 | 535 | ||
570 | intf = desc->intf; | 536 | desc = usb_get_intfdata(intf); |
571 | if (test_bit(WDM_DISCONNECTING, &desc->flags)) | 537 | if (test_bit(WDM_DISCONNECTING, &desc->flags)) |
572 | goto out; | 538 | goto out; |
573 | file->private_data = desc; | 539 | file->private_data = desc; |
@@ -577,6 +543,7 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
577 | dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); | 543 | dev_err(&desc->intf->dev, "Error autopm - %d\n", rv); |
578 | goto out; | 544 | goto out; |
579 | } | 545 | } |
546 | intf->needs_remote_wakeup = 1; | ||
580 | 547 | ||
581 | /* using write lock to protect desc->count */ | 548 | /* using write lock to protect desc->count */ |
582 | mutex_lock(&desc->wlock); | 549 | mutex_lock(&desc->wlock); |
@@ -588,14 +555,11 @@ static int wdm_open(struct inode *inode, struct file *file) | |||
588 | desc->count--; | 555 | desc->count--; |
589 | dev_err(&desc->intf->dev, | 556 | dev_err(&desc->intf->dev, |
590 | "Error submitting int urb - %d\n", rv); | 557 | "Error submitting int urb - %d\n", rv); |
591 | rv = usb_translate_errors(rv); | ||
592 | } | 558 | } |
593 | } else { | 559 | } else { |
594 | rv = 0; | 560 | rv = 0; |
595 | } | 561 | } |
596 | mutex_unlock(&desc->wlock); | 562 | mutex_unlock(&desc->wlock); |
597 | if (desc->count == 1) | ||
598 | desc->manage_power(intf, 1); | ||
599 | usb_autopm_put_interface(desc->intf); | 563 | usb_autopm_put_interface(desc->intf); |
600 | out: | 564 | out: |
601 | mutex_unlock(&wdm_mutex); | 565 | mutex_unlock(&wdm_mutex); |
@@ -614,15 +578,10 @@ static int wdm_release(struct inode *inode, struct file *file) | |||
614 | mutex_unlock(&desc->wlock); | 578 | mutex_unlock(&desc->wlock); |
615 | 579 | ||
616 | if (!desc->count) { | 580 | if (!desc->count) { |
617 | if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { | 581 | dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); |
618 | dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); | 582 | kill_urbs(desc); |
619 | kill_urbs(desc); | 583 | if (!test_bit(WDM_DISCONNECTING, &desc->flags)) |
620 | desc->manage_power(desc->intf, 0); | 584 | desc->intf->needs_remote_wakeup = 0; |
621 | } else { | ||
622 | /* must avoid dev_printk here as desc->intf is invalid */ | ||
623 | pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); | ||
624 | cleanup(desc); | ||
625 | } | ||
626 | } | 585 | } |
627 | mutex_unlock(&wdm_mutex); | 586 | mutex_unlock(&wdm_mutex); |
628 | return 0; | 587 | return 0; |
@@ -669,31 +628,71 @@ static void wdm_rxwork(struct work_struct *work) | |||
669 | 628 | ||
670 | /* --- hotplug --- */ | 629 | /* --- hotplug --- */ |
671 | 630 | ||
672 | static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, | 631 | static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) |
673 | u16 bufsize, int (*manage_power)(struct usb_interface *, int)) | ||
674 | { | 632 | { |
675 | int rv = -ENOMEM; | 633 | int rv = -EINVAL; |
634 | struct usb_device *udev = interface_to_usbdev(intf); | ||
676 | struct wdm_device *desc; | 635 | struct wdm_device *desc; |
636 | struct usb_host_interface *iface; | ||
637 | struct usb_endpoint_descriptor *ep; | ||
638 | struct usb_cdc_dmm_desc *dmhd; | ||
639 | u8 *buffer = intf->altsetting->extra; | ||
640 | int buflen = intf->altsetting->extralen; | ||
641 | u16 maxcom = WDM_DEFAULT_BUFSIZE; | ||
677 | 642 | ||
643 | if (!buffer) | ||
644 | goto out; | ||
645 | |||
646 | while (buflen > 2) { | ||
647 | if (buffer [1] != USB_DT_CS_INTERFACE) { | ||
648 | dev_err(&intf->dev, "skipping garbage\n"); | ||
649 | goto next_desc; | ||
650 | } | ||
651 | |||
652 | switch (buffer [2]) { | ||
653 | case USB_CDC_HEADER_TYPE: | ||
654 | break; | ||
655 | case USB_CDC_DMM_TYPE: | ||
656 | dmhd = (struct usb_cdc_dmm_desc *)buffer; | ||
657 | maxcom = le16_to_cpu(dmhd->wMaxCommand); | ||
658 | dev_dbg(&intf->dev, | ||
659 | "Finding maximum buffer length: %d", maxcom); | ||
660 | break; | ||
661 | default: | ||
662 | dev_err(&intf->dev, | ||
663 | "Ignoring extra header, type %d, length %d\n", | ||
664 | buffer[2], buffer[0]); | ||
665 | break; | ||
666 | } | ||
667 | next_desc: | ||
668 | buflen -= buffer[0]; | ||
669 | buffer += buffer[0]; | ||
670 | } | ||
671 | |||
672 | rv = -ENOMEM; | ||
678 | desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); | 673 | desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); |
679 | if (!desc) | 674 | if (!desc) |
680 | goto out; | 675 | goto out; |
681 | INIT_LIST_HEAD(&desc->device_list); | ||
682 | mutex_init(&desc->rlock); | 676 | mutex_init(&desc->rlock); |
683 | mutex_init(&desc->wlock); | 677 | mutex_init(&desc->wlock); |
684 | spin_lock_init(&desc->iuspin); | 678 | spin_lock_init(&desc->iuspin); |
685 | init_waitqueue_head(&desc->wait); | 679 | init_waitqueue_head(&desc->wait); |
686 | desc->wMaxCommand = bufsize; | 680 | desc->wMaxCommand = maxcom; |
687 | /* this will be expanded and needed in hardware endianness */ | 681 | /* this will be expanded and needed in hardware endianness */ |
688 | desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); | 682 | desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber); |
689 | desc->intf = intf; | 683 | desc->intf = intf; |
690 | INIT_WORK(&desc->rxwork, wdm_rxwork); | 684 | INIT_WORK(&desc->rxwork, wdm_rxwork); |
691 | 685 | ||
692 | rv = -EINVAL; | 686 | rv = -EINVAL; |
693 | if (!usb_endpoint_is_int_in(ep)) | 687 | iface = intf->cur_altsetting; |
688 | if (iface->desc.bNumEndpoints != 1) | ||
689 | goto err; | ||
690 | ep = &iface->endpoint[0].desc; | ||
691 | if (!ep || !usb_endpoint_is_int_in(ep)) | ||
694 | goto err; | 692 | goto err; |
695 | 693 | ||
696 | desc->wMaxPacketSize = usb_endpoint_maxp(ep); | 694 | desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize); |
695 | desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0; | ||
697 | 696 | ||
698 | desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); | 697 | desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); |
699 | if (!desc->orq) | 698 | if (!desc->orq) |
@@ -718,13 +717,19 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor | |||
718 | if (!desc->ubuf) | 717 | if (!desc->ubuf) |
719 | goto err; | 718 | goto err; |
720 | 719 | ||
721 | desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL); | 720 | desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf), |
721 | desc->wMaxPacketSize, | ||
722 | GFP_KERNEL, | ||
723 | &desc->validity->transfer_dma); | ||
722 | if (!desc->sbuf) | 724 | if (!desc->sbuf) |
723 | goto err; | 725 | goto err; |
724 | 726 | ||
725 | desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL); | 727 | desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf), |
728 | desc->wMaxCommand, | ||
729 | GFP_KERNEL, | ||
730 | &desc->response->transfer_dma); | ||
726 | if (!desc->inbuf) | 731 | if (!desc->inbuf) |
727 | goto err; | 732 | goto err2; |
728 | 733 | ||
729 | usb_fill_int_urb( | 734 | usb_fill_int_urb( |
730 | desc->validity, | 735 | desc->validity, |
@@ -736,152 +741,45 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor | |||
736 | desc, | 741 | desc, |
737 | ep->bInterval | 742 | ep->bInterval |
738 | ); | 743 | ); |
744 | desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
739 | 745 | ||
740 | desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE); | 746 | usb_set_intfdata(intf, desc); |
741 | desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE; | ||
742 | desc->irq->wValue = 0; | ||
743 | desc->irq->wIndex = desc->inum; | ||
744 | desc->irq->wLength = cpu_to_le16(desc->wMaxCommand); | ||
745 | |||
746 | usb_fill_control_urb( | ||
747 | desc->response, | ||
748 | interface_to_usbdev(intf), | ||
749 | /* using common endpoint 0 */ | ||
750 | usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0), | ||
751 | (unsigned char *)desc->irq, | ||
752 | desc->inbuf, | ||
753 | desc->wMaxCommand, | ||
754 | wdm_in_callback, | ||
755 | desc | ||
756 | ); | ||
757 | |||
758 | desc->manage_power = manage_power; | ||
759 | |||
760 | spin_lock(&wdm_device_list_lock); | ||
761 | list_add(&desc->device_list, &wdm_device_list); | ||
762 | spin_unlock(&wdm_device_list_lock); | ||
763 | |||
764 | rv = usb_register_dev(intf, &wdm_class); | 747 | rv = usb_register_dev(intf, &wdm_class); |
765 | if (rv < 0) | 748 | if (rv < 0) |
766 | goto err; | 749 | goto err3; |
767 | else | 750 | else |
768 | dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev)); | 751 | dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n", |
752 | intf->minor - WDM_MINOR_BASE); | ||
769 | out: | 753 | out: |
770 | return rv; | 754 | return rv; |
755 | err3: | ||
756 | usb_set_intfdata(intf, NULL); | ||
757 | usb_free_coherent(interface_to_usbdev(desc->intf), | ||
758 | desc->bMaxPacketSize0, | ||
759 | desc->inbuf, | ||
760 | desc->response->transfer_dma); | ||
761 | err2: | ||
762 | usb_free_coherent(interface_to_usbdev(desc->intf), | ||
763 | desc->wMaxPacketSize, | ||
764 | desc->sbuf, | ||
765 | desc->validity->transfer_dma); | ||
771 | err: | 766 | err: |
772 | spin_lock(&wdm_device_list_lock); | 767 | free_urbs(desc); |
773 | list_del(&desc->device_list); | 768 | kfree(desc->ubuf); |
774 | spin_unlock(&wdm_device_list_lock); | 769 | kfree(desc->orq); |
775 | cleanup(desc); | 770 | kfree(desc->irq); |
776 | return rv; | 771 | kfree(desc); |
777 | } | ||
778 | |||
779 | static int wdm_manage_power(struct usb_interface *intf, int on) | ||
780 | { | ||
781 | /* need autopm_get/put here to ensure the usbcore sees the new value */ | ||
782 | int rv = usb_autopm_get_interface(intf); | ||
783 | if (rv < 0) | ||
784 | goto err; | ||
785 | |||
786 | intf->needs_remote_wakeup = on; | ||
787 | usb_autopm_put_interface(intf); | ||
788 | err: | ||
789 | return rv; | ||
790 | } | ||
791 | |||
792 | static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
793 | { | ||
794 | int rv = -EINVAL; | ||
795 | struct usb_host_interface *iface; | ||
796 | struct usb_endpoint_descriptor *ep; | ||
797 | struct usb_cdc_dmm_desc *dmhd; | ||
798 | u8 *buffer = intf->altsetting->extra; | ||
799 | int buflen = intf->altsetting->extralen; | ||
800 | u16 maxcom = WDM_DEFAULT_BUFSIZE; | ||
801 | |||
802 | if (!buffer) | ||
803 | goto err; | ||
804 | while (buflen > 2) { | ||
805 | if (buffer[1] != USB_DT_CS_INTERFACE) { | ||
806 | dev_err(&intf->dev, "skipping garbage\n"); | ||
807 | goto next_desc; | ||
808 | } | ||
809 | |||
810 | switch (buffer[2]) { | ||
811 | case USB_CDC_HEADER_TYPE: | ||
812 | break; | ||
813 | case USB_CDC_DMM_TYPE: | ||
814 | dmhd = (struct usb_cdc_dmm_desc *)buffer; | ||
815 | maxcom = le16_to_cpu(dmhd->wMaxCommand); | ||
816 | dev_dbg(&intf->dev, | ||
817 | "Finding maximum buffer length: %d", maxcom); | ||
818 | break; | ||
819 | default: | ||
820 | dev_err(&intf->dev, | ||
821 | "Ignoring extra header, type %d, length %d\n", | ||
822 | buffer[2], buffer[0]); | ||
823 | break; | ||
824 | } | ||
825 | next_desc: | ||
826 | buflen -= buffer[0]; | ||
827 | buffer += buffer[0]; | ||
828 | } | ||
829 | |||
830 | iface = intf->cur_altsetting; | ||
831 | if (iface->desc.bNumEndpoints != 1) | ||
832 | goto err; | ||
833 | ep = &iface->endpoint[0].desc; | ||
834 | |||
835 | rv = wdm_create(intf, ep, maxcom, &wdm_manage_power); | ||
836 | |||
837 | err: | ||
838 | return rv; | 772 | return rv; |
839 | } | 773 | } |
840 | 774 | ||
841 | /** | ||
842 | * usb_cdc_wdm_register - register a WDM subdriver | ||
843 | * @intf: usb interface the subdriver will associate with | ||
844 | * @ep: interrupt endpoint to monitor for notifications | ||
845 | * @bufsize: maximum message size to support for read/write | ||
846 | * | ||
847 | * Create WDM usb class character device and associate it with intf | ||
848 | * without binding, allowing another driver to manage the interface. | ||
849 | * | ||
850 | * The subdriver will manage the given interrupt endpoint exclusively | ||
851 | * and will issue control requests referring to the given intf. It | ||
852 | * will otherwise avoid interferring, and in particular not do | ||
853 | * usb_set_intfdata/usb_get_intfdata on intf. | ||
854 | * | ||
855 | * The return value is a pointer to the subdriver's struct usb_driver. | ||
856 | * The registering driver is responsible for calling this subdriver's | ||
857 | * disconnect, suspend, resume, pre_reset and post_reset methods from | ||
858 | * its own. | ||
859 | */ | ||
860 | struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf, | ||
861 | struct usb_endpoint_descriptor *ep, | ||
862 | int bufsize, | ||
863 | int (*manage_power)(struct usb_interface *, int)) | ||
864 | { | ||
865 | int rv = -EINVAL; | ||
866 | |||
867 | rv = wdm_create(intf, ep, bufsize, manage_power); | ||
868 | if (rv < 0) | ||
869 | goto err; | ||
870 | |||
871 | return &wdm_driver; | ||
872 | err: | ||
873 | return ERR_PTR(rv); | ||
874 | } | ||
875 | EXPORT_SYMBOL(usb_cdc_wdm_register); | ||
876 | |||
877 | static void wdm_disconnect(struct usb_interface *intf) | 775 | static void wdm_disconnect(struct usb_interface *intf) |
878 | { | 776 | { |
879 | struct wdm_device *desc; | 777 | struct wdm_device *desc; |
880 | unsigned long flags; | 778 | unsigned long flags; |
881 | 779 | ||
882 | usb_deregister_dev(intf, &wdm_class); | 780 | usb_deregister_dev(intf, &wdm_class); |
883 | desc = wdm_find_device(intf); | ||
884 | mutex_lock(&wdm_mutex); | 781 | mutex_lock(&wdm_mutex); |
782 | desc = usb_get_intfdata(intf); | ||
885 | 783 | ||
886 | /* the spinlock makes sure no new urbs are generated in the callbacks */ | 784 | /* the spinlock makes sure no new urbs are generated in the callbacks */ |
887 | spin_lock_irqsave(&desc->iuspin, flags); | 785 | spin_lock_irqsave(&desc->iuspin, flags); |
@@ -897,35 +795,27 @@ static void wdm_disconnect(struct usb_interface *intf) | |||
897 | cancel_work_sync(&desc->rxwork); | 795 | cancel_work_sync(&desc->rxwork); |
898 | mutex_unlock(&desc->wlock); | 796 | mutex_unlock(&desc->wlock); |
899 | mutex_unlock(&desc->rlock); | 797 | mutex_unlock(&desc->rlock); |
900 | |||
901 | /* the desc->intf pointer used as list key is now invalid */ | ||
902 | spin_lock(&wdm_device_list_lock); | ||
903 | list_del(&desc->device_list); | ||
904 | spin_unlock(&wdm_device_list_lock); | ||
905 | |||
906 | if (!desc->count) | 798 | if (!desc->count) |
907 | cleanup(desc); | 799 | cleanup(desc); |
908 | else | ||
909 | dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count); | ||
910 | mutex_unlock(&wdm_mutex); | 800 | mutex_unlock(&wdm_mutex); |
911 | } | 801 | } |
912 | 802 | ||
913 | #ifdef CONFIG_PM | 803 | #ifdef CONFIG_PM |
914 | static int wdm_suspend(struct usb_interface *intf, pm_message_t message) | 804 | static int wdm_suspend(struct usb_interface *intf, pm_message_t message) |
915 | { | 805 | { |
916 | struct wdm_device *desc = wdm_find_device(intf); | 806 | struct wdm_device *desc = usb_get_intfdata(intf); |
917 | int rv = 0; | 807 | int rv = 0; |
918 | 808 | ||
919 | dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); | 809 | dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); |
920 | 810 | ||
921 | /* if this is an autosuspend the caller does the locking */ | 811 | /* if this is an autosuspend the caller does the locking */ |
922 | if (!PMSG_IS_AUTO(message)) { | 812 | if (!(message.event & PM_EVENT_AUTO)) { |
923 | mutex_lock(&desc->rlock); | 813 | mutex_lock(&desc->rlock); |
924 | mutex_lock(&desc->wlock); | 814 | mutex_lock(&desc->wlock); |
925 | } | 815 | } |
926 | spin_lock_irq(&desc->iuspin); | 816 | spin_lock_irq(&desc->iuspin); |
927 | 817 | ||
928 | if (PMSG_IS_AUTO(message) && | 818 | if ((message.event & PM_EVENT_AUTO) && |
929 | (test_bit(WDM_IN_USE, &desc->flags) | 819 | (test_bit(WDM_IN_USE, &desc->flags) |
930 | || test_bit(WDM_RESPONDING, &desc->flags))) { | 820 | || test_bit(WDM_RESPONDING, &desc->flags))) { |
931 | spin_unlock_irq(&desc->iuspin); | 821 | spin_unlock_irq(&desc->iuspin); |
@@ -938,7 +828,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) | |||
938 | kill_urbs(desc); | 828 | kill_urbs(desc); |
939 | cancel_work_sync(&desc->rxwork); | 829 | cancel_work_sync(&desc->rxwork); |
940 | } | 830 | } |
941 | if (!PMSG_IS_AUTO(message)) { | 831 | if (!(message.event & PM_EVENT_AUTO)) { |
942 | mutex_unlock(&desc->wlock); | 832 | mutex_unlock(&desc->wlock); |
943 | mutex_unlock(&desc->rlock); | 833 | mutex_unlock(&desc->rlock); |
944 | } | 834 | } |
@@ -963,7 +853,7 @@ static int recover_from_urb_loss(struct wdm_device *desc) | |||
963 | #ifdef CONFIG_PM | 853 | #ifdef CONFIG_PM |
964 | static int wdm_resume(struct usb_interface *intf) | 854 | static int wdm_resume(struct usb_interface *intf) |
965 | { | 855 | { |
966 | struct wdm_device *desc = wdm_find_device(intf); | 856 | struct wdm_device *desc = usb_get_intfdata(intf); |
967 | int rv; | 857 | int rv; |
968 | 858 | ||
969 | dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); | 859 | dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor); |
@@ -977,7 +867,11 @@ static int wdm_resume(struct usb_interface *intf) | |||
977 | 867 | ||
978 | static int wdm_pre_reset(struct usb_interface *intf) | 868 | static int wdm_pre_reset(struct usb_interface *intf) |
979 | { | 869 | { |
980 | struct wdm_device *desc = wdm_find_device(intf); | 870 | struct wdm_device *desc = usb_get_intfdata(intf); |
871 | |||
872 | mutex_lock(&desc->rlock); | ||
873 | mutex_lock(&desc->wlock); | ||
874 | kill_urbs(desc); | ||
981 | 875 | ||
982 | /* | 876 | /* |
983 | * we notify everybody using poll of | 877 | * we notify everybody using poll of |
@@ -986,25 +880,17 @@ static int wdm_pre_reset(struct usb_interface *intf) | |||
986 | * message from the device is lost | 880 | * message from the device is lost |
987 | */ | 881 | */ |
988 | spin_lock_irq(&desc->iuspin); | 882 | spin_lock_irq(&desc->iuspin); |
989 | set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */ | ||
990 | set_bit(WDM_READ, &desc->flags); /* unblock read */ | ||
991 | clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */ | ||
992 | desc->rerr = -EINTR; | 883 | desc->rerr = -EINTR; |
993 | spin_unlock_irq(&desc->iuspin); | 884 | spin_unlock_irq(&desc->iuspin); |
994 | wake_up_all(&desc->wait); | 885 | wake_up_all(&desc->wait); |
995 | mutex_lock(&desc->rlock); | ||
996 | mutex_lock(&desc->wlock); | ||
997 | kill_urbs(desc); | ||
998 | cancel_work_sync(&desc->rxwork); | ||
999 | return 0; | 886 | return 0; |
1000 | } | 887 | } |
1001 | 888 | ||
1002 | static int wdm_post_reset(struct usb_interface *intf) | 889 | static int wdm_post_reset(struct usb_interface *intf) |
1003 | { | 890 | { |
1004 | struct wdm_device *desc = wdm_find_device(intf); | 891 | struct wdm_device *desc = usb_get_intfdata(intf); |
1005 | int rv; | 892 | int rv; |
1006 | 893 | ||
1007 | clear_bit(WDM_RESETTING, &desc->flags); | ||
1008 | rv = recover_from_urb_loss(desc); | 894 | rv = recover_from_urb_loss(desc); |
1009 | mutex_unlock(&desc->wlock); | 895 | mutex_unlock(&desc->wlock); |
1010 | mutex_unlock(&desc->rlock); | 896 | mutex_unlock(&desc->rlock); |
@@ -1024,10 +910,26 @@ static struct usb_driver wdm_driver = { | |||
1024 | .post_reset = wdm_post_reset, | 910 | .post_reset = wdm_post_reset, |
1025 | .id_table = wdm_ids, | 911 | .id_table = wdm_ids, |
1026 | .supports_autosuspend = 1, | 912 | .supports_autosuspend = 1, |
1027 | .disable_hub_initiated_lpm = 1, | ||
1028 | }; | 913 | }; |
1029 | 914 | ||
1030 | module_usb_driver(wdm_driver); | 915 | /* --- low level module stuff --- */ |
916 | |||
917 | static int __init wdm_init(void) | ||
918 | { | ||
919 | int rv; | ||
920 | |||
921 | rv = usb_register(&wdm_driver); | ||
922 | |||
923 | return rv; | ||
924 | } | ||
925 | |||
926 | static void __exit wdm_exit(void) | ||
927 | { | ||
928 | usb_deregister(&wdm_driver); | ||
929 | } | ||
930 | |||
931 | module_init(wdm_init); | ||
932 | module_exit(wdm_exit); | ||
1031 | 933 | ||
1032 | MODULE_AUTHOR(DRIVER_AUTHOR); | 934 | MODULE_AUTHOR(DRIVER_AUTHOR); |
1033 | MODULE_DESCRIPTION(DRIVER_DESC); | 935 | MODULE_DESCRIPTION(DRIVER_DESC); |