diff options
Diffstat (limited to 'drivers/usb/usb-skeleton.c')
-rw-r--r-- | drivers/usb/usb-skeleton.c | 88 |
1 files changed, 59 insertions, 29 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index ce310170829..e24ce312307 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c | |||
@@ -60,6 +60,7 @@ struct usb_skel { | |||
60 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | 60 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ |
61 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ | 61 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ |
62 | int errors; /* the last request tanked */ | 62 | int errors; /* the last request tanked */ |
63 | int open_count; /* count the number of openers */ | ||
63 | bool ongoing_read; /* a read is going on */ | 64 | bool ongoing_read; /* a read is going on */ |
64 | bool processed_urb; /* indicates we haven't processed the urb */ | 65 | bool processed_urb; /* indicates we haven't processed the urb */ |
65 | spinlock_t err_lock; /* lock for errors */ | 66 | spinlock_t err_lock; /* lock for errors */ |
@@ -93,8 +94,8 @@ static int skel_open(struct inode *inode, struct file *file) | |||
93 | 94 | ||
94 | interface = usb_find_interface(&skel_driver, subminor); | 95 | interface = usb_find_interface(&skel_driver, subminor); |
95 | if (!interface) { | 96 | if (!interface) { |
96 | pr_err("%s - error, can't find device for minor %d\n", | 97 | err("%s - error, can't find device for minor %d", |
97 | __func__, subminor); | 98 | __func__, subminor); |
98 | retval = -ENODEV; | 99 | retval = -ENODEV; |
99 | goto exit; | 100 | goto exit; |
100 | } | 101 | } |
@@ -105,15 +106,33 @@ static int skel_open(struct inode *inode, struct file *file) | |||
105 | goto exit; | 106 | goto exit; |
106 | } | 107 | } |
107 | 108 | ||
108 | retval = usb_autopm_get_interface(interface); | ||
109 | if (retval) | ||
110 | goto exit; | ||
111 | |||
112 | /* increment our usage count for the device */ | 109 | /* increment our usage count for the device */ |
113 | kref_get(&dev->kref); | 110 | kref_get(&dev->kref); |
114 | 111 | ||
112 | /* lock the device to allow correctly handling errors | ||
113 | * in resumption */ | ||
114 | mutex_lock(&dev->io_mutex); | ||
115 | |||
116 | if (!dev->open_count++) { | ||
117 | retval = usb_autopm_get_interface(interface); | ||
118 | if (retval) { | ||
119 | dev->open_count--; | ||
120 | mutex_unlock(&dev->io_mutex); | ||
121 | kref_put(&dev->kref, skel_delete); | ||
122 | goto exit; | ||
123 | } | ||
124 | } /* else { //uncomment this block if you want exclusive open | ||
125 | retval = -EBUSY; | ||
126 | dev->open_count--; | ||
127 | mutex_unlock(&dev->io_mutex); | ||
128 | kref_put(&dev->kref, skel_delete); | ||
129 | goto exit; | ||
130 | } */ | ||
131 | /* prevent the device from being autosuspended */ | ||
132 | |||
115 | /* save our object in the file's private structure */ | 133 | /* save our object in the file's private structure */ |
116 | file->private_data = dev; | 134 | file->private_data = dev; |
135 | mutex_unlock(&dev->io_mutex); | ||
117 | 136 | ||
118 | exit: | 137 | exit: |
119 | return retval; | 138 | return retval; |
@@ -129,7 +148,7 @@ static int skel_release(struct inode *inode, struct file *file) | |||
129 | 148 | ||
130 | /* allow the device to be autosuspended */ | 149 | /* allow the device to be autosuspended */ |
131 | mutex_lock(&dev->io_mutex); | 150 | mutex_lock(&dev->io_mutex); |
132 | if (dev->interface) | 151 | if (!--dev->open_count && dev->interface) |
133 | usb_autopm_put_interface(dev->interface); | 152 | usb_autopm_put_interface(dev->interface); |
134 | mutex_unlock(&dev->io_mutex); | 153 | mutex_unlock(&dev->io_mutex); |
135 | 154 | ||
@@ -174,9 +193,8 @@ static void skel_read_bulk_callback(struct urb *urb) | |||
174 | if (!(urb->status == -ENOENT || | 193 | if (!(urb->status == -ENOENT || |
175 | urb->status == -ECONNRESET || | 194 | urb->status == -ECONNRESET || |
176 | urb->status == -ESHUTDOWN)) | 195 | urb->status == -ESHUTDOWN)) |
177 | dev_err(&dev->interface->dev, | 196 | err("%s - nonzero write bulk status received: %d", |
178 | "%s - nonzero write bulk status received: %d\n", | 197 | __func__, urb->status); |
179 | __func__, urb->status); | ||
180 | 198 | ||
181 | dev->errors = urb->status; | 199 | dev->errors = urb->status; |
182 | } else { | 200 | } else { |
@@ -209,8 +227,7 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count) | |||
209 | /* do it */ | 227 | /* do it */ |
210 | rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); | 228 | rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); |
211 | if (rv < 0) { | 229 | if (rv < 0) { |
212 | dev_err(&dev->interface->dev, | 230 | err("%s - failed submitting read urb, error %d", |
213 | "%s - failed submitting read urb, error %d\n", | ||
214 | __func__, rv); | 231 | __func__, rv); |
215 | dev->bulk_in_filled = 0; | 232 | dev->bulk_in_filled = 0; |
216 | rv = (rv == -ENOMEM) ? rv : -EIO; | 233 | rv = (rv == -ENOMEM) ? rv : -EIO; |
@@ -361,9 +378,8 @@ static void skel_write_bulk_callback(struct urb *urb) | |||
361 | if (!(urb->status == -ENOENT || | 378 | if (!(urb->status == -ENOENT || |
362 | urb->status == -ECONNRESET || | 379 | urb->status == -ECONNRESET || |
363 | urb->status == -ESHUTDOWN)) | 380 | urb->status == -ESHUTDOWN)) |
364 | dev_err(&dev->interface->dev, | 381 | err("%s - nonzero write bulk status received: %d", |
365 | "%s - nonzero write bulk status received: %d\n", | 382 | __func__, urb->status); |
366 | __func__, urb->status); | ||
367 | 383 | ||
368 | spin_lock(&dev->err_lock); | 384 | spin_lock(&dev->err_lock); |
369 | dev->errors = urb->status; | 385 | dev->errors = urb->status; |
@@ -457,9 +473,8 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, | |||
457 | retval = usb_submit_urb(urb, GFP_KERNEL); | 473 | retval = usb_submit_urb(urb, GFP_KERNEL); |
458 | mutex_unlock(&dev->io_mutex); | 474 | mutex_unlock(&dev->io_mutex); |
459 | if (retval) { | 475 | if (retval) { |
460 | dev_err(&dev->interface->dev, | 476 | err("%s - failed submitting write urb, error %d", __func__, |
461 | "%s - failed submitting write urb, error %d\n", | 477 | retval); |
462 | __func__, retval); | ||
463 | goto error_unanchor; | 478 | goto error_unanchor; |
464 | } | 479 | } |
465 | 480 | ||
@@ -518,7 +533,7 @@ static int skel_probe(struct usb_interface *interface, | |||
518 | /* allocate memory for our device state and initialize it */ | 533 | /* allocate memory for our device state and initialize it */ |
519 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 534 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
520 | if (!dev) { | 535 | if (!dev) { |
521 | dev_err(&interface->dev, "Out of memory\n"); | 536 | err("Out of memory"); |
522 | goto error; | 537 | goto error; |
523 | } | 538 | } |
524 | kref_init(&dev->kref); | 539 | kref_init(&dev->kref); |
@@ -540,19 +555,17 @@ static int skel_probe(struct usb_interface *interface, | |||
540 | if (!dev->bulk_in_endpointAddr && | 555 | if (!dev->bulk_in_endpointAddr && |
541 | usb_endpoint_is_bulk_in(endpoint)) { | 556 | usb_endpoint_is_bulk_in(endpoint)) { |
542 | /* we found a bulk in endpoint */ | 557 | /* we found a bulk in endpoint */ |
543 | buffer_size = usb_endpoint_maxp(endpoint); | 558 | buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); |
544 | dev->bulk_in_size = buffer_size; | 559 | dev->bulk_in_size = buffer_size; |
545 | dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; | 560 | dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; |
546 | dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); | 561 | dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); |
547 | if (!dev->bulk_in_buffer) { | 562 | if (!dev->bulk_in_buffer) { |
548 | dev_err(&interface->dev, | 563 | err("Could not allocate bulk_in_buffer"); |
549 | "Could not allocate bulk_in_buffer\n"); | ||
550 | goto error; | 564 | goto error; |
551 | } | 565 | } |
552 | dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); | 566 | dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); |
553 | if (!dev->bulk_in_urb) { | 567 | if (!dev->bulk_in_urb) { |
554 | dev_err(&interface->dev, | 568 | err("Could not allocate bulk_in_urb"); |
555 | "Could not allocate bulk_in_urb\n"); | ||
556 | goto error; | 569 | goto error; |
557 | } | 570 | } |
558 | } | 571 | } |
@@ -564,8 +577,7 @@ static int skel_probe(struct usb_interface *interface, | |||
564 | } | 577 | } |
565 | } | 578 | } |
566 | if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { | 579 | if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { |
567 | dev_err(&interface->dev, | 580 | err("Could not find both bulk-in and bulk-out endpoints"); |
568 | "Could not find both bulk-in and bulk-out endpoints\n"); | ||
569 | goto error; | 581 | goto error; |
570 | } | 582 | } |
571 | 583 | ||
@@ -576,8 +588,7 @@ static int skel_probe(struct usb_interface *interface, | |||
576 | retval = usb_register_dev(interface, &skel_class); | 588 | retval = usb_register_dev(interface, &skel_class); |
577 | if (retval) { | 589 | if (retval) { |
578 | /* something prevented us from registering this driver */ | 590 | /* something prevented us from registering this driver */ |
579 | dev_err(&interface->dev, | 591 | err("Not able to get a minor for this device."); |
580 | "Not able to get a minor for this device.\n"); | ||
581 | usb_set_intfdata(interface, NULL); | 592 | usb_set_intfdata(interface, NULL); |
582 | goto error; | 593 | goto error; |
583 | } | 594 | } |
@@ -677,6 +688,25 @@ static struct usb_driver skel_driver = { | |||
677 | .supports_autosuspend = 1, | 688 | .supports_autosuspend = 1, |
678 | }; | 689 | }; |
679 | 690 | ||
680 | module_usb_driver(skel_driver); | 691 | static int __init usb_skel_init(void) |
692 | { | ||
693 | int result; | ||
694 | |||
695 | /* register this driver with the USB subsystem */ | ||
696 | result = usb_register(&skel_driver); | ||
697 | if (result) | ||
698 | err("usb_register failed. Error number %d", result); | ||
699 | |||
700 | return result; | ||
701 | } | ||
702 | |||
703 | static void __exit usb_skel_exit(void) | ||
704 | { | ||
705 | /* deregister this driver with the USB subsystem */ | ||
706 | usb_deregister(&skel_driver); | ||
707 | } | ||
708 | |||
709 | module_init(usb_skel_init); | ||
710 | module_exit(usb_skel_exit); | ||
681 | 711 | ||
682 | MODULE_LICENSE("GPL"); | 712 | MODULE_LICENSE("GPL"); |