diff options
Diffstat (limited to 'drivers/usb/misc/vstusb.c')
-rw-r--r-- | drivers/usb/misc/vstusb.c | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/drivers/usb/misc/vstusb.c b/drivers/usb/misc/vstusb.c index 5ad75e4a0323..8648470c81ca 100644 --- a/drivers/usb/misc/vstusb.c +++ b/drivers/usb/misc/vstusb.c | |||
@@ -59,6 +59,8 @@ | |||
59 | #define USB_PRODUCT_LABPRO 0x0001 | 59 | #define USB_PRODUCT_LABPRO 0x0001 |
60 | #define USB_PRODUCT_LABQUEST 0x0005 | 60 | #define USB_PRODUCT_LABQUEST 0x0005 |
61 | 61 | ||
62 | #define VST_MAXBUFFER (64*1024) | ||
63 | |||
62 | static struct usb_device_id id_table[] = { | 64 | static struct usb_device_id id_table[] = { |
63 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)}, | 65 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)}, |
64 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)}, | 66 | { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)}, |
@@ -73,6 +75,7 @@ static struct usb_device_id id_table[] = { | |||
73 | MODULE_DEVICE_TABLE(usb, id_table); | 75 | MODULE_DEVICE_TABLE(usb, id_table); |
74 | 76 | ||
75 | struct vstusb_device { | 77 | struct vstusb_device { |
78 | struct kref kref; | ||
76 | struct mutex lock; | 79 | struct mutex lock; |
77 | struct usb_device *usb_dev; | 80 | struct usb_device *usb_dev; |
78 | char present; | 81 | char present; |
@@ -83,9 +86,18 @@ struct vstusb_device { | |||
83 | int wr_pipe; | 86 | int wr_pipe; |
84 | int wr_timeout_ms; | 87 | int wr_timeout_ms; |
85 | }; | 88 | }; |
89 | #define to_vst_dev(d) container_of(d, struct vstusb_device, kref) | ||
86 | 90 | ||
87 | static struct usb_driver vstusb_driver; | 91 | static struct usb_driver vstusb_driver; |
88 | 92 | ||
93 | static void vstusb_delete(struct kref *kref) | ||
94 | { | ||
95 | struct vstusb_device *vstdev = to_vst_dev(kref); | ||
96 | |||
97 | usb_put_dev(vstdev->usb_dev); | ||
98 | kfree(vstdev); | ||
99 | } | ||
100 | |||
89 | static int vstusb_open(struct inode *inode, struct file *file) | 101 | static int vstusb_open(struct inode *inode, struct file *file) |
90 | { | 102 | { |
91 | struct vstusb_device *vstdev; | 103 | struct vstusb_device *vstdev; |
@@ -114,6 +126,9 @@ static int vstusb_open(struct inode *inode, struct file *file) | |||
114 | return -EBUSY; | 126 | return -EBUSY; |
115 | } | 127 | } |
116 | 128 | ||
129 | /* increment our usage count */ | ||
130 | kref_get(&vstdev->kref); | ||
131 | |||
117 | vstdev->isopen = 1; | 132 | vstdev->isopen = 1; |
118 | 133 | ||
119 | /* save device in the file's private structure */ | 134 | /* save device in the file's private structure */ |
@@ -126,7 +141,7 @@ static int vstusb_open(struct inode *inode, struct file *file) | |||
126 | return 0; | 141 | return 0; |
127 | } | 142 | } |
128 | 143 | ||
129 | static int vstusb_close(struct inode *inode, struct file *file) | 144 | static int vstusb_release(struct inode *inode, struct file *file) |
130 | { | 145 | { |
131 | struct vstusb_device *vstdev; | 146 | struct vstusb_device *vstdev; |
132 | 147 | ||
@@ -138,14 +153,12 @@ static int vstusb_close(struct inode *inode, struct file *file) | |||
138 | mutex_lock(&vstdev->lock); | 153 | mutex_lock(&vstdev->lock); |
139 | 154 | ||
140 | vstdev->isopen = 0; | 155 | vstdev->isopen = 0; |
141 | file->private_data = NULL; | ||
142 | 156 | ||
143 | /* if device is no longer present */ | 157 | dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__); |
144 | if (!vstdev->present) { | 158 | |
145 | mutex_unlock(&vstdev->lock); | 159 | mutex_unlock(&vstdev->lock); |
146 | kfree(vstdev); | 160 | |
147 | } else | 161 | kref_put(&vstdev->kref, vstusb_delete); |
148 | mutex_unlock(&vstdev->lock); | ||
149 | 162 | ||
150 | return 0; | 163 | return 0; |
151 | } | 164 | } |
@@ -268,7 +281,7 @@ static ssize_t vstusb_read(struct file *file, char __user *buffer, | |||
268 | return -ENODEV; | 281 | return -ENODEV; |
269 | 282 | ||
270 | /* verify that we actually want to read some data */ | 283 | /* verify that we actually want to read some data */ |
271 | if (count == 0) | 284 | if ((count == 0) || (count > VST_MAXBUFFER)) |
272 | return -EINVAL; | 285 | return -EINVAL; |
273 | 286 | ||
274 | /* lock this object */ | 287 | /* lock this object */ |
@@ -354,7 +367,7 @@ static ssize_t vstusb_write(struct file *file, const char __user *buffer, | |||
354 | return -ENODEV; | 367 | return -ENODEV; |
355 | 368 | ||
356 | /* verify that we actually have some data to write */ | 369 | /* verify that we actually have some data to write */ |
357 | if (count == 0) | 370 | if ((count == 0) || (count > VST_MAXBUFFER)) |
358 | return retval; | 371 | return retval; |
359 | 372 | ||
360 | /* lock this object */ | 373 | /* lock this object */ |
@@ -498,7 +511,7 @@ static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
498 | 511 | ||
499 | case IOCTL_VSTUSB_SEND_PIPE: | 512 | case IOCTL_VSTUSB_SEND_PIPE: |
500 | 513 | ||
501 | if (usb_data.count == 0) { | 514 | if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) { |
502 | mutex_unlock(&vstdev->lock); | 515 | mutex_unlock(&vstdev->lock); |
503 | retval = -EINVAL; | 516 | retval = -EINVAL; |
504 | goto exit; | 517 | goto exit; |
@@ -551,7 +564,7 @@ static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
551 | break; | 564 | break; |
552 | case IOCTL_VSTUSB_RECV_PIPE: | 565 | case IOCTL_VSTUSB_RECV_PIPE: |
553 | 566 | ||
554 | if (usb_data.count == 0) { | 567 | if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) { |
555 | mutex_unlock(&vstdev->lock); | 568 | mutex_unlock(&vstdev->lock); |
556 | retval = -EINVAL; | 569 | retval = -EINVAL; |
557 | goto exit; | 570 | goto exit; |
@@ -633,7 +646,7 @@ static const struct file_operations vstusb_fops = { | |||
633 | .unlocked_ioctl = vstusb_ioctl, | 646 | .unlocked_ioctl = vstusb_ioctl, |
634 | .compat_ioctl = vstusb_ioctl, | 647 | .compat_ioctl = vstusb_ioctl, |
635 | .open = vstusb_open, | 648 | .open = vstusb_open, |
636 | .release = vstusb_close, | 649 | .release = vstusb_release, |
637 | }; | 650 | }; |
638 | 651 | ||
639 | static struct usb_class_driver usb_vstusb_class = { | 652 | static struct usb_class_driver usb_vstusb_class = { |
@@ -656,6 +669,10 @@ static int vstusb_probe(struct usb_interface *intf, | |||
656 | if (vstdev == NULL) | 669 | if (vstdev == NULL) |
657 | return -ENOMEM; | 670 | return -ENOMEM; |
658 | 671 | ||
672 | /* must do usb_get_dev() prior to kref_init() since the kref_put() | ||
673 | * release function will do a usb_put_dev() */ | ||
674 | usb_get_dev(dev); | ||
675 | kref_init(&vstdev->kref); | ||
659 | mutex_init(&vstdev->lock); | 676 | mutex_init(&vstdev->lock); |
660 | 677 | ||
661 | i = dev->descriptor.bcdDevice; | 678 | i = dev->descriptor.bcdDevice; |
@@ -676,7 +693,7 @@ static int vstusb_probe(struct usb_interface *intf, | |||
676 | "%s: Not able to get a minor for this device.\n", | 693 | "%s: Not able to get a minor for this device.\n", |
677 | __func__); | 694 | __func__); |
678 | usb_set_intfdata(intf, NULL); | 695 | usb_set_intfdata(intf, NULL); |
679 | kfree(vstdev); | 696 | kref_put(&vstdev->kref, vstusb_delete); |
680 | return retval; | 697 | return retval; |
681 | } | 698 | } |
682 | 699 | ||
@@ -704,14 +721,11 @@ static void vstusb_disconnect(struct usb_interface *intf) | |||
704 | 721 | ||
705 | usb_kill_anchored_urbs(&vstdev->submitted); | 722 | usb_kill_anchored_urbs(&vstdev->submitted); |
706 | 723 | ||
707 | /* if the device is not opened, then we clean up right now */ | 724 | mutex_unlock(&vstdev->lock); |
708 | if (!vstdev->isopen) { | ||
709 | mutex_unlock(&vstdev->lock); | ||
710 | kfree(vstdev); | ||
711 | } else | ||
712 | mutex_unlock(&vstdev->lock); | ||
713 | 725 | ||
726 | kref_put(&vstdev->kref, vstusb_delete); | ||
714 | } | 727 | } |
728 | |||
715 | } | 729 | } |
716 | 730 | ||
717 | static int vstusb_suspend(struct usb_interface *intf, pm_message_t message) | 731 | static int vstusb_suspend(struct usb_interface *intf, pm_message_t message) |