diff options
Diffstat (limited to 'drivers/usb/usb-skeleton.c')
-rw-r--r-- | drivers/usb/usb-skeleton.c | 31 |
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 */ |
46 | struct usb_skel { | 50 | struct 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 | ||
247 | error: | 254 | error: |
@@ -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 | ||
255 | exit: | 261 | exit: |
@@ -344,6 +350,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i | |||
344 | 350 | ||
345 | error: | 351 | error: |
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 | ||
385 | static int __init usb_skel_init(void) | 394 | static int __init usb_skel_init(void) |