diff options
| -rw-r--r-- | drivers/usb/usb-skeleton.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index b362039792b3..33f0e81c58d3 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * USB Skeleton driver - 2.0 | 2 | * USB Skeleton driver - 2.1 |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) | 4 | * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) |
| 5 | * | 5 | * |
| @@ -8,8 +8,7 @@ | |||
| 8 | * published by the Free Software Foundation, version 2. | 8 | * published by the Free Software Foundation, version 2. |
| 9 | * | 9 | * |
| 10 | * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c | 10 | * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c |
| 11 | * but has been rewritten to be easy to read and use, as no locks are now | 11 | * but has been rewritten to be easier to read and use. |
| 12 | * needed anymore. | ||
| 13 | * | 12 | * |
| 14 | */ | 13 | */ |
| 15 | 14 | ||
| @@ -21,6 +20,7 @@ | |||
| 21 | #include <linux/kref.h> | 20 | #include <linux/kref.h> |
| 22 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
| 23 | #include <linux/usb.h> | 22 | #include <linux/usb.h> |
| 23 | #include <linux/mutex.h> | ||
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | /* Define these values to match your devices */ | 26 | /* Define these values to match your devices */ |
| @@ -52,6 +52,7 @@ struct usb_skel { | |||
| 52 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | 52 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ |
| 53 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ | 53 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ |
| 54 | struct kref kref; | 54 | struct kref kref; |
| 55 | struct mutex io_mutex; /* synchronize I/O with disconnect */ | ||
| 55 | }; | 56 | }; |
| 56 | #define to_skel_dev(d) container_of(d, struct usb_skel, kref) | 57 | #define to_skel_dev(d) container_of(d, struct usb_skel, kref) |
| 57 | 58 | ||
| @@ -119,7 +120,13 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t * | |||
| 119 | int bytes_read; | 120 | int bytes_read; |
| 120 | 121 | ||
| 121 | dev = (struct usb_skel *)file->private_data; | 122 | dev = (struct usb_skel *)file->private_data; |
| 122 | 123 | ||
| 124 | mutex_lock(&dev->io_mutex); | ||
| 125 | if (!dev->interface) { /* disconnect() was called */ | ||
| 126 | retval = -ENODEV; | ||
| 127 | goto exit; | ||
| 128 | } | ||
| 129 | |||
| 123 | /* do a blocking bulk read to get data from the device */ | 130 | /* do a blocking bulk read to get data from the device */ |
| 124 | retval = usb_bulk_msg(dev->udev, | 131 | retval = usb_bulk_msg(dev->udev, |
| 125 | usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), | 132 | usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), |
| @@ -135,6 +142,8 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t * | |||
| 135 | retval = bytes_read; | 142 | retval = bytes_read; |
| 136 | } | 143 | } |
| 137 | 144 | ||
| 145 | exit: | ||
| 146 | mutex_unlock(&dev->io_mutex); | ||
| 138 | return retval; | 147 | return retval; |
| 139 | } | 148 | } |
| 140 | 149 | ||
| @@ -179,6 +188,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 179 | goto exit; | 188 | goto exit; |
| 180 | } | 189 | } |
| 181 | 190 | ||
| 191 | mutex_lock(&dev->io_mutex); | ||
| 192 | if (!dev->interface) { /* disconnect() was called */ | ||
| 193 | retval = -ENODEV; | ||
| 194 | goto error; | ||
| 195 | } | ||
| 196 | |||
| 182 | /* create a urb, and a buffer for it, and copy the data to the urb */ | 197 | /* create a urb, and a buffer for it, and copy the data to the urb */ |
| 183 | urb = usb_alloc_urb(0, GFP_KERNEL); | 198 | urb = usb_alloc_urb(0, GFP_KERNEL); |
| 184 | if (!urb) { | 199 | if (!urb) { |
| @@ -213,13 +228,18 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
| 213 | /* release our reference to this urb, the USB core will eventually free it entirely */ | 228 | /* release our reference to this urb, the USB core will eventually free it entirely */ |
| 214 | usb_free_urb(urb); | 229 | usb_free_urb(urb); |
| 215 | 230 | ||
| 216 | exit: | 231 | mutex_unlock(&dev->io_mutex); |
| 217 | return writesize; | 232 | return writesize; |
| 218 | 233 | ||
| 219 | error: | 234 | error: |
| 220 | usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); | 235 | if (urb) { |
| 221 | usb_free_urb(urb); | 236 | usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); |
| 237 | usb_free_urb(urb); | ||
| 238 | } | ||
| 239 | mutex_unlock(&dev->io_mutex); | ||
| 222 | up(&dev->limit_sem); | 240 | up(&dev->limit_sem); |
| 241 | |||
| 242 | exit: | ||
| 223 | return retval; | 243 | return retval; |
| 224 | } | 244 | } |
| 225 | 245 | ||
| @@ -258,6 +278,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i | |||
| 258 | } | 278 | } |
| 259 | kref_init(&dev->kref); | 279 | kref_init(&dev->kref); |
| 260 | sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); | 280 | sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); |
| 281 | mutex_init(&dev->io_mutex); | ||
| 261 | 282 | ||
| 262 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); | 283 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); |
| 263 | dev->interface = interface; | 284 | dev->interface = interface; |
| @@ -334,6 +355,11 @@ static void skel_disconnect(struct usb_interface *interface) | |||
| 334 | /* give back our minor */ | 355 | /* give back our minor */ |
| 335 | usb_deregister_dev(interface, &skel_class); | 356 | usb_deregister_dev(interface, &skel_class); |
| 336 | 357 | ||
| 358 | /* prevent more I/O from starting */ | ||
| 359 | mutex_lock(&dev->io_mutex); | ||
| 360 | dev->interface = NULL; | ||
| 361 | mutex_unlock(&dev->io_mutex); | ||
| 362 | |||
| 337 | unlock_kernel(); | 363 | unlock_kernel(); |
| 338 | 364 | ||
| 339 | /* decrement our usage count */ | 365 | /* decrement our usage count */ |
