|
@@ -59,6 +59,8 @@
|
|
#define USB_PRODUCT_LABPRO 0x0001
|
|
#define USB_PRODUCT_LABPRO 0x0001
|
|
#define USB_PRODUCT_LABQUEST 0x0005
|
|
#define USB_PRODUCT_LABQUEST 0x0005
|
|
|
|
|
|
|
|
+#define VST_MAXBUFFER (64*1024)
|
|
|
|
+
|
|
static struct usb_device_id id_table[] = {
|
|
static struct usb_device_id id_table[] = {
|
|
{ USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
|
|
{ USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
|
|
{ USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
|
|
{ USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
|
|
@@ -73,6 +75,7 @@ static struct usb_device_id id_table[] = {
|
|
MODULE_DEVICE_TABLE(usb, id_table);
|
|
MODULE_DEVICE_TABLE(usb, id_table);
|
|
|
|
|
|
struct vstusb_device {
|
|
struct vstusb_device {
|
|
|
|
+ struct kref kref;
|
|
struct mutex lock;
|
|
struct mutex lock;
|
|
struct usb_device *usb_dev;
|
|
struct usb_device *usb_dev;
|
|
char present;
|
|
char present;
|
|
@@ -83,9 +86,18 @@ struct vstusb_device {
|
|
int wr_pipe;
|
|
int wr_pipe;
|
|
int wr_timeout_ms;
|
|
int wr_timeout_ms;
|
|
};
|
|
};
|
|
|
|
+#define to_vst_dev(d) container_of(d, struct vstusb_device, kref)
|
|
|
|
|
|
static struct usb_driver vstusb_driver;
|
|
static struct usb_driver vstusb_driver;
|
|
|
|
|
|
|
|
+static void vstusb_delete(struct kref *kref)
|
|
|
|
+{
|
|
|
|
+ struct vstusb_device *vstdev = to_vst_dev(kref);
|
|
|
|
+
|
|
|
|
+ usb_put_dev(vstdev->usb_dev);
|
|
|
|
+ kfree(vstdev);
|
|
|
|
+}
|
|
|
|
+
|
|
static int vstusb_open(struct inode *inode, struct file *file)
|
|
static int vstusb_open(struct inode *inode, struct file *file)
|
|
{
|
|
{
|
|
struct vstusb_device *vstdev;
|
|
struct vstusb_device *vstdev;
|
|
@@ -114,6 +126,9 @@ static int vstusb_open(struct inode *inode, struct file *file)
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* increment our usage count */
|
|
|
|
+ kref_get(&vstdev->kref);
|
|
|
|
+
|
|
vstdev->isopen = 1;
|
|
vstdev->isopen = 1;
|
|
|
|
|
|
/* save device in the file's private structure */
|
|
/* save device in the file's private structure */
|
|
@@ -126,7 +141,7 @@ static int vstusb_open(struct inode *inode, struct file *file)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static int vstusb_close(struct inode *inode, struct file *file)
|
|
|
|
|
|
+static int vstusb_release(struct inode *inode, struct file *file)
|
|
{
|
|
{
|
|
struct vstusb_device *vstdev;
|
|
struct vstusb_device *vstdev;
|
|
|
|
|
|
@@ -138,14 +153,12 @@ static int vstusb_close(struct inode *inode, struct file *file)
|
|
mutex_lock(&vstdev->lock);
|
|
mutex_lock(&vstdev->lock);
|
|
|
|
|
|
vstdev->isopen = 0;
|
|
vstdev->isopen = 0;
|
|
- file->private_data = NULL;
|
|
|
|
|
|
|
|
- /* if device is no longer present */
|
|
|
|
- if (!vstdev->present) {
|
|
|
|
- mutex_unlock(&vstdev->lock);
|
|
|
|
- kfree(vstdev);
|
|
|
|
- } else
|
|
|
|
- mutex_unlock(&vstdev->lock);
|
|
|
|
|
|
+ dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__);
|
|
|
|
+
|
|
|
|
+ mutex_unlock(&vstdev->lock);
|
|
|
|
+
|
|
|
|
+ kref_put(&vstdev->kref, vstusb_delete);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -268,7 +281,7 @@ static ssize_t vstusb_read(struct file *file, char __user *buffer,
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
/* verify that we actually want to read some data */
|
|
/* verify that we actually want to read some data */
|
|
- if (count == 0)
|
|
|
|
|
|
+ if ((count == 0) || (count > VST_MAXBUFFER))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
/* lock this object */
|
|
/* lock this object */
|
|
@@ -354,7 +367,7 @@ static ssize_t vstusb_write(struct file *file, const char __user *buffer,
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
|
|
|
|
/* verify that we actually have some data to write */
|
|
/* verify that we actually have some data to write */
|
|
- if (count == 0)
|
|
|
|
|
|
+ if ((count == 0) || (count > VST_MAXBUFFER))
|
|
return retval;
|
|
return retval;
|
|
|
|
|
|
/* lock this object */
|
|
/* lock this object */
|
|
@@ -498,7 +511,7 @@ static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
|
|
|
case IOCTL_VSTUSB_SEND_PIPE:
|
|
case IOCTL_VSTUSB_SEND_PIPE:
|
|
|
|
|
|
- if (usb_data.count == 0) {
|
|
|
|
|
|
+ if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
|
|
mutex_unlock(&vstdev->lock);
|
|
mutex_unlock(&vstdev->lock);
|
|
retval = -EINVAL;
|
|
retval = -EINVAL;
|
|
goto exit;
|
|
goto exit;
|
|
@@ -551,7 +564,7 @@ static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
break;
|
|
break;
|
|
case IOCTL_VSTUSB_RECV_PIPE:
|
|
case IOCTL_VSTUSB_RECV_PIPE:
|
|
|
|
|
|
- if (usb_data.count == 0) {
|
|
|
|
|
|
+ if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
|
|
mutex_unlock(&vstdev->lock);
|
|
mutex_unlock(&vstdev->lock);
|
|
retval = -EINVAL;
|
|
retval = -EINVAL;
|
|
goto exit;
|
|
goto exit;
|
|
@@ -633,7 +646,7 @@ static const struct file_operations vstusb_fops = {
|
|
.unlocked_ioctl = vstusb_ioctl,
|
|
.unlocked_ioctl = vstusb_ioctl,
|
|
.compat_ioctl = vstusb_ioctl,
|
|
.compat_ioctl = vstusb_ioctl,
|
|
.open = vstusb_open,
|
|
.open = vstusb_open,
|
|
- .release = vstusb_close,
|
|
|
|
|
|
+ .release = vstusb_release,
|
|
};
|
|
};
|
|
|
|
|
|
static struct usb_class_driver usb_vstusb_class = {
|
|
static struct usb_class_driver usb_vstusb_class = {
|
|
@@ -656,6 +669,10 @@ static int vstusb_probe(struct usb_interface *intf,
|
|
if (vstdev == NULL)
|
|
if (vstdev == NULL)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
+ /* must do usb_get_dev() prior to kref_init() since the kref_put()
|
|
|
|
+ * release function will do a usb_put_dev() */
|
|
|
|
+ usb_get_dev(dev);
|
|
|
|
+ kref_init(&vstdev->kref);
|
|
mutex_init(&vstdev->lock);
|
|
mutex_init(&vstdev->lock);
|
|
|
|
|
|
i = dev->descriptor.bcdDevice;
|
|
i = dev->descriptor.bcdDevice;
|
|
@@ -676,7 +693,7 @@ static int vstusb_probe(struct usb_interface *intf,
|
|
"%s: Not able to get a minor for this device.\n",
|
|
"%s: Not able to get a minor for this device.\n",
|
|
__func__);
|
|
__func__);
|
|
usb_set_intfdata(intf, NULL);
|
|
usb_set_intfdata(intf, NULL);
|
|
- kfree(vstdev);
|
|
|
|
|
|
+ kref_put(&vstdev->kref, vstusb_delete);
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -704,14 +721,11 @@ static void vstusb_disconnect(struct usb_interface *intf)
|
|
|
|
|
|
usb_kill_anchored_urbs(&vstdev->submitted);
|
|
usb_kill_anchored_urbs(&vstdev->submitted);
|
|
|
|
|
|
- /* if the device is not opened, then we clean up right now */
|
|
|
|
- if (!vstdev->isopen) {
|
|
|
|
- mutex_unlock(&vstdev->lock);
|
|
|
|
- kfree(vstdev);
|
|
|
|
- } else
|
|
|
|
- mutex_unlock(&vstdev->lock);
|
|
|
|
|
|
+ mutex_unlock(&vstdev->lock);
|
|
|
|
|
|
|
|
+ kref_put(&vstdev->kref, vstusb_delete);
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)
|
|
static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)
|