aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/usb-skeleton.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/usb-skeleton.c')
-rw-r--r--drivers/usb/usb-skeleton.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 46929a1b6f24..962b28cd3a79 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -40,12 +40,16 @@ MODULE_DEVICE_TABLE(usb, skel_table);
40 40
41/* our private defines. if this grows any larger, use your own .h file */ 41/* our private defines. if this grows any larger, use your own .h file */
42#define MAX_TRANSFER (PAGE_SIZE - 512) 42#define MAX_TRANSFER (PAGE_SIZE - 512)
43/* MAX_TRANSFER is chosen so that the VM is not stressed by
44 allocations > PAGE_SIZE and the number of packets in a page
45 is an integer 512 is the largest possible packet on EHCI */
43#define WRITES_IN_FLIGHT 8 46#define WRITES_IN_FLIGHT 8
47/* arbitrarily chosen */
44 48
45/* Structure to hold all of our device specific stuff */ 49/* Structure to hold all of our device specific stuff */
46struct usb_skel { 50struct usb_skel {
47 struct usb_device *dev; /* the usb device for this device */ 51 struct usb_device *udev; /* the usb device for this device */
48 struct usb_interface *interface; /* the interface for this device */ 52 struct usb_interface *interface; /* the interface for this device */
49 struct semaphore limit_sem; /* limiting the number of writes in progress */ 53 struct semaphore limit_sem; /* limiting the number of writes in progress */
50 unsigned char *bulk_in_buffer; /* the buffer to receive data */ 54 unsigned char *bulk_in_buffer; /* the buffer to receive data */
51 size_t bulk_in_size; /* the size of the receive buffer */ 55 size_t bulk_in_size; /* the size of the receive buffer */
@@ -201,12 +205,6 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
201 goto exit; 205 goto exit;
202 } 206 }
203 207
204 mutex_lock(&dev->io_mutex);
205 if (!dev->interface) { /* disconnect() was called */
206 retval = -ENODEV;
207 goto error;
208 }
209
210 /* create a urb, and a buffer for it, and copy the data to the urb */ 208 /* create a urb, and a buffer for it, and copy the data to the urb */
211 urb = usb_alloc_urb(0, GFP_KERNEL); 209 urb = usb_alloc_urb(0, GFP_KERNEL);
212 if (!urb) { 210 if (!urb) {
@@ -225,6 +223,14 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
225 goto error; 223 goto error;
226 } 224 }
227 225
226 /* this lock makes sure we don't submit URBs to gone devices */
227 mutex_lock(&dev->io_mutex);
228 if (!dev->interface) { /* disconnect() was called */
229 mutex_unlock(&dev->io_mutex);
230 retval = -ENODEV;
231 goto error;
232 }
233
228 /* initialize the urb properly */ 234 /* initialize the urb properly */
229 usb_fill_bulk_urb(urb, dev->udev, 235 usb_fill_bulk_urb(urb, dev->udev,
230 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 236 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
@@ -233,6 +239,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
233 239
234 /* send the data out the bulk port */ 240 /* send the data out the bulk port */
235 retval = usb_submit_urb(urb, GFP_KERNEL); 241 retval = usb_submit_urb(urb, GFP_KERNEL);
242 mutex_unlock(&dev->io_mutex);
236 if (retval) { 243 if (retval) {
237 err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); 244 err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
238 goto error; 245 goto error;
@@ -241,7 +248,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
241 /* release our reference to this urb, the USB core will eventually free it entirely */ 248 /* release our reference to this urb, the USB core will eventually free it entirely */
242 usb_free_urb(urb); 249 usb_free_urb(urb);
243 250
244 mutex_unlock(&dev->io_mutex); 251
245 return writesize; 252 return writesize;
246 253
247error: 254error:
@@ -249,7 +256,6 @@ error:
249 usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); 256 usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
250 usb_free_urb(urb); 257 usb_free_urb(urb);
251 } 258 }
252 mutex_unlock(&dev->io_mutex);
253 up(&dev->limit_sem); 259 up(&dev->limit_sem);
254 260
255exit: 261exit:
@@ -344,6 +350,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
344 350
345error: 351error:
346 if (dev) 352 if (dev)
353 /* this frees allocated memory */
347 kref_put(&dev->kref, skel_delete); 354 kref_put(&dev->kref, skel_delete);
348 return retval; 355 return retval;
349} 356}
@@ -361,13 +368,14 @@ static void skel_disconnect(struct usb_interface *interface)
361 368
362 /* give back our minor */ 369 /* give back our minor */
363 usb_deregister_dev(interface, &skel_class); 370 usb_deregister_dev(interface, &skel_class);
371 unlock_kernel();
364 372
365 /* prevent more I/O from starting */ 373 /* prevent more I/O from starting */
366 mutex_lock(&dev->io_mutex); 374 mutex_lock(&dev->io_mutex);
367 dev->interface = NULL; 375 dev->interface = NULL;
368 mutex_unlock(&dev->io_mutex); 376 mutex_unlock(&dev->io_mutex);
369 377
370 unlock_kernel(); 378
371 379
372 /* decrement our usage count */ 380 /* decrement our usage count */
373 kref_put(&dev->kref, skel_delete); 381 kref_put(&dev->kref, skel_delete);
@@ -380,6 +388,7 @@ static struct usb_driver skel_driver = {
380 .probe = skel_probe, 388 .probe = skel_probe,
381 .disconnect = skel_disconnect, 389 .disconnect = skel_disconnect,
382 .id_table = skel_table, 390 .id_table = skel_table,
391 .supports_autosuspend = 1,
383}; 392};
384 393
385static int __init usb_skel_init(void) 394static int __init usb_skel_init(void)