aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/misc/usblcd.c22
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
49static struct usb_driver lcd_driver; 53static struct usb_driver lcd_driver;
50static DEFINE_MUTEX(usb_lcd_open_mutex); 54static 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
191static ssize_t lcd_write(struct file *file, const char __user * user_buffer, size_t count, loff_t *ppos) 196static 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:
239error: 250error:
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);
253err_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;