diff options
Diffstat (limited to 'drivers/usb/usb-skeleton.c')
-rw-r--r-- | drivers/usb/usb-skeleton.c | 29 |
1 files changed, 21 insertions, 8 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index 6c3a53f8f26c..5d02f16b7d0e 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c | |||
@@ -39,10 +39,15 @@ MODULE_DEVICE_TABLE (usb, skel_table); | |||
39 | /* Get a minor range for your devices from the usb maintainer */ | 39 | /* Get a minor range for your devices from the usb maintainer */ |
40 | #define USB_SKEL_MINOR_BASE 192 | 40 | #define USB_SKEL_MINOR_BASE 192 |
41 | 41 | ||
42 | /* our private defines. if this grows any larger, use your own .h file */ | ||
43 | #define MAX_TRANSFER ( PAGE_SIZE - 512 ) | ||
44 | #define WRITES_IN_FLIGHT 8 | ||
45 | |||
42 | /* Structure to hold all of our device specific stuff */ | 46 | /* Structure to hold all of our device specific stuff */ |
43 | struct usb_skel { | 47 | struct usb_skel { |
44 | struct usb_device * udev; /* the usb device for this device */ | 48 | struct usb_device * udev; /* the usb device for this device */ |
45 | struct usb_interface * interface; /* the interface for this device */ | 49 | struct usb_interface * interface; /* the interface for this device */ |
50 | struct semaphore limit_sem; /* limiting the number of writes in progress */ | ||
46 | unsigned char * bulk_in_buffer; /* the buffer to receive data */ | 51 | unsigned char * bulk_in_buffer; /* the buffer to receive data */ |
47 | size_t bulk_in_size; /* the size of the receive buffer */ | 52 | size_t bulk_in_size; /* the size of the receive buffer */ |
48 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | 53 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ |
@@ -152,6 +157,7 @@ static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs) | |||
152 | /* free up our allocated buffer */ | 157 | /* free up our allocated buffer */ |
153 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, | 158 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, |
154 | urb->transfer_buffer, urb->transfer_dma); | 159 | urb->transfer_buffer, urb->transfer_dma); |
160 | up(&dev->limit_sem); | ||
155 | } | 161 | } |
156 | 162 | ||
157 | static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) | 163 | static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) |
@@ -160,6 +166,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
160 | int retval = 0; | 166 | int retval = 0; |
161 | struct urb *urb = NULL; | 167 | struct urb *urb = NULL; |
162 | char *buf = NULL; | 168 | char *buf = NULL; |
169 | size_t writesize = min(count, (size_t)MAX_TRANSFER); | ||
163 | 170 | ||
164 | dev = (struct usb_skel *)file->private_data; | 171 | dev = (struct usb_skel *)file->private_data; |
165 | 172 | ||
@@ -167,6 +174,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
167 | if (count == 0) | 174 | if (count == 0) |
168 | goto exit; | 175 | goto exit; |
169 | 176 | ||
177 | /* limit the number of URBs in flight to stop a user from using up all RAM */ | ||
178 | if (down_interruptible(&dev->limit_sem)) { | ||
179 | retval = -ERESTARTSYS; | ||
180 | goto exit; | ||
181 | } | ||
182 | |||
170 | /* create a urb, and a buffer for it, and copy the data to the urb */ | 183 | /* create a urb, and a buffer for it, and copy the data to the urb */ |
171 | urb = usb_alloc_urb(0, GFP_KERNEL); | 184 | urb = usb_alloc_urb(0, GFP_KERNEL); |
172 | if (!urb) { | 185 | if (!urb) { |
@@ -174,13 +187,13 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
174 | goto error; | 187 | goto error; |
175 | } | 188 | } |
176 | 189 | ||
177 | buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); | 190 | buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma); |
178 | if (!buf) { | 191 | if (!buf) { |
179 | retval = -ENOMEM; | 192 | retval = -ENOMEM; |
180 | goto error; | 193 | goto error; |
181 | } | 194 | } |
182 | 195 | ||
183 | if (copy_from_user(buf, user_buffer, count)) { | 196 | if (copy_from_user(buf, user_buffer, writesize)) { |
184 | retval = -EFAULT; | 197 | retval = -EFAULT; |
185 | goto error; | 198 | goto error; |
186 | } | 199 | } |
@@ -188,7 +201,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
188 | /* initialize the urb properly */ | 201 | /* initialize the urb properly */ |
189 | usb_fill_bulk_urb(urb, dev->udev, | 202 | usb_fill_bulk_urb(urb, dev->udev, |
190 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), | 203 | usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), |
191 | buf, count, skel_write_bulk_callback, dev); | 204 | buf, writesize, skel_write_bulk_callback, dev); |
192 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 205 | urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
193 | 206 | ||
194 | /* send the data out the bulk port */ | 207 | /* send the data out the bulk port */ |
@@ -202,11 +215,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou | |||
202 | usb_free_urb(urb); | 215 | usb_free_urb(urb); |
203 | 216 | ||
204 | exit: | 217 | exit: |
205 | return count; | 218 | return writesize; |
206 | 219 | ||
207 | error: | 220 | error: |
208 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); | 221 | usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); |
209 | usb_free_urb(urb); | 222 | usb_free_urb(urb); |
223 | up(&dev->limit_sem); | ||
210 | return retval; | 224 | return retval; |
211 | } | 225 | } |
212 | 226 | ||
@@ -238,13 +252,13 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i | |||
238 | int retval = -ENOMEM; | 252 | int retval = -ENOMEM; |
239 | 253 | ||
240 | /* allocate memory for our device state and initialize it */ | 254 | /* allocate memory for our device state and initialize it */ |
241 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | 255 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
242 | if (dev == NULL) { | 256 | if (dev == NULL) { |
243 | err("Out of memory"); | 257 | err("Out of memory"); |
244 | goto error; | 258 | goto error; |
245 | } | 259 | } |
246 | memset(dev, 0x00, sizeof(*dev)); | ||
247 | kref_init(&dev->kref); | 260 | kref_init(&dev->kref); |
261 | sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); | ||
248 | 262 | ||
249 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); | 263 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); |
250 | dev->interface = interface; | 264 | dev->interface = interface; |
@@ -330,7 +344,6 @@ static void skel_disconnect(struct usb_interface *interface) | |||
330 | } | 344 | } |
331 | 345 | ||
332 | static struct usb_driver skel_driver = { | 346 | static struct usb_driver skel_driver = { |
333 | .owner = THIS_MODULE, | ||
334 | .name = "skeleton", | 347 | .name = "skeleton", |
335 | .probe = skel_probe, | 348 | .probe = skel_probe, |
336 | .disconnect = skel_disconnect, | 349 | .disconnect = skel_disconnect, |