diff options
-rw-r--r-- | drivers/usb/misc/usblcd.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 887ef953f3d8..12bad8a205a7 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c | |||
@@ -42,10 +42,14 @@ struct usb_lcd { | |||
42 | size_t bulk_in_size; /* the size of the receive buffer */ | 42 | size_t bulk_in_size; /* the size of the receive buffer */ |
43 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ | 43 | __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ |
44 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ | 44 | __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ |
45 | struct kref kref; | 45 | struct kref kref; |
46 | struct semaphore limit_sem; /* to stop writes at full throttle from | ||
47 | * using up all RAM */ | ||
46 | }; | 48 | }; |
47 | #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) | 49 | #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) |
48 | 50 | ||
51 | #define USB_LCD_CONCURRENT_WRITES 5 | ||
52 | |||
49 | static struct usb_driver lcd_driver; | 53 | static struct usb_driver lcd_driver; |
50 | static DEFINE_MUTEX(usb_lcd_open_mutex); | 54 | static DEFINE_MUTEX(usb_lcd_open_mutex); |
51 | 55 | ||
@@ -186,12 +190,13 @@ static void lcd_write_bulk_callback(struct urb *urb) | |||
186 | /* free up our allocated buffer */ | 190 | /* free up our allocated buffer */ |
187 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, | 191 | usb_buffer_free(urb->dev, urb->transfer_buffer_length, |
188 | urb->transfer_buffer, urb->transfer_dma); | 192 | urb->transfer_buffer, urb->transfer_dma); |
193 | up(&dev->limit_sem); | ||
189 | } | 194 | } |
190 | 195 | ||
191 | static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) | 196 | static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) |
192 | { | 197 | { |
193 | struct usb_lcd *dev; | 198 | struct usb_lcd *dev; |
194 | int retval = 0; | 199 | int retval = 0, r; |
195 | struct urb *urb = NULL; | 200 | struct urb *urb = NULL; |
196 | char *buf = NULL; | 201 | char *buf = NULL; |
197 | 202 | ||
@@ -201,10 +206,16 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz | |||
201 | if (count == 0) | 206 | if (count == 0) |
202 | goto exit; | 207 | goto exit; |
203 | 208 | ||
209 | r = down_interruptible(&dev->limit_sem); | ||
210 | if (r < 0) | ||
211 | return -EINTR; | ||
212 | |||
204 | /* create a urb, and a buffer for it, and copy the data to the urb */ | 213 | /* create a urb, and a buffer for it, and copy the data to the urb */ |
205 | urb = usb_alloc_urb(0, GFP_KERNEL); | 214 | urb = usb_alloc_urb(0, GFP_KERNEL); |
206 | if (!urb) | 215 | if (!urb) { |
207 | return -ENOMEM; | 216 | retval = -ENOMEM; |
217 | goto err_no_buf; | ||
218 | } | ||
208 | 219 | ||
209 | buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); | 220 | buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma); |
210 | if (!buf) { | 221 | if (!buf) { |
@@ -239,6 +250,8 @@ exit: | |||
239 | error: | 250 | error: |
240 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); | 251 | usb_buffer_free(dev->udev, count, buf, urb->transfer_dma); |
241 | usb_free_urb(urb); | 252 | usb_free_urb(urb); |
253 | err_no_buf: | ||
254 | up(&dev->limit_sem); | ||
242 | return retval; | 255 | return retval; |
243 | } | 256 | } |
244 | 257 | ||
@@ -277,6 +290,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id | |||
277 | goto error; | 290 | goto error; |
278 | } | 291 | } |
279 | kref_init(&dev->kref); | 292 | kref_init(&dev->kref); |
293 | sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); | ||
280 | 294 | ||
281 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); | 295 | dev->udev = usb_get_dev(interface_to_usbdev(interface)); |
282 | dev->interface = interface; | 296 | dev->interface = interface; |