summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorPreetham Chandru R <pchandru@nvidia.com>2012-10-22 15:25:45 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-11-22 10:26:07 -0800
commit7673b44859c2c97ecb464c9aaadb0bc3d6850215 (patch)
tree9f656cde98e9cf2d4fa45c35b7850ef1ce8e7ad3 /drivers/usb
parent6f9b140166b6af54defc1317a821638f8182616c (diff)
usb:class:nv-usb: driver to measure usb throughput
a class driver to measure usb throughput Change-Id: Ibadfb7f5722e6969c93064fcf4ca79139fd08728 Signed-off-by: Preetham Chandru R <pchandru@nvidia.com> Reviewed-on: http://git-master/r/138994 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/class/Kconfig10
-rw-r--r--drivers/usb/class/Makefile1
-rw-r--r--drivers/usb/class/nv-usb.c564
-rw-r--r--drivers/usb/class/nv-usb.h100
5 files changed, 676 insertions, 0 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 53a7bc07dd8d..97a540e9aeaf 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
obj-$(CONFIG_USB_WDM) += class/
obj-$(CONFIG_USB_TMC) += class/
+obj-$(CONFIG_USB_KPI) += class/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-$(CONFIG_USB) += storage/
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 2519e320098f..d63944903cc3 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -50,3 +50,13 @@ config USB_TMC
To compile this driver as a module, choose M here: the
module will be called usbtmc.
+
+config USB_KPI
+ tristate "USB KPI Measurement"
+ depends on USB
+ help
+ Say Y here if you want to measure the usb write and read
+ throughput.
+
+ To compile this driver as a module, choose M here: the
+ module will be called nv-usb.
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 32e85277b5cf..49d0913a241b 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_USB_ACM) += cdc-acm.o
obj-$(CONFIG_USB_PRINTER) += usblp.o
obj-$(CONFIG_USB_WDM) += cdc-wdm.o
obj-$(CONFIG_USB_TMC) += usbtmc.o
+obj-$(CONFIG_USB_KPI) += nv-usb.o
diff --git a/drivers/usb/class/nv-usb.c b/drivers/usb/class/nv-usb.c
new file mode 100644
index 000000000000..96b64bb65091
--- /dev/null
+++ b/drivers/usb/class/nv-usb.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/time.h>
+
+#include "nv-usb.h"
+
+#ifdef DEBUG
+#define INFO(stuff...) pr_info("nv-usb: " stuff)
+#else
+#define INFO(stuff...) do {} while (0)
+#endif
+
+
+#define NV_USB_BULK_VENDOR_ID 0x0955
+#define NV_USB_BULK_PRODUCT_ID 0xffff
+
+/* table of devices that work with this driver */
+static const struct usb_device_id nv_usb_table[] = {
+ { USB_DEVICE(NV_USB_BULK_VENDOR_ID, NV_USB_BULK_PRODUCT_ID) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, nv_usb_table);
+
+/* Need to check if the below minor id is ok */
+#define NV_USB_BULK_MINOR_BASE 192
+
+static struct usb_driver nv_usb_driver;
+
+static void nv_usb_delete(struct kref *kref)
+{
+ struct nv_usb *dev = to_nv_usb_dev(kref);
+
+ usb_put_dev(dev->udev);
+}
+
+static int nv_usb_open(struct inode *inode, struct file *file)
+{
+ struct nv_usb *dev;
+ struct usb_interface *interface;
+ int subminor;
+
+ subminor = iminor(inode);
+
+ interface = usb_find_interface(&nv_usb_driver, subminor);
+ if (interface == NULL) {
+ INFO("%s(%d) failed to get interface\n", __func__, __LINE__);
+ return -ENODEV;
+ }
+
+ dev = usb_get_intfdata(interface);
+ if (dev == NULL) {
+ INFO("%s(%d) failed to get interface\n", __func__, __LINE__);
+ return -ENODEV;
+ }
+
+ kref_get(&dev->kref);
+
+ mutex_lock(&dev->mutex);
+ file->private_data = dev;
+ mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static int nv_usb_release(struct inode *inode, struct file *file)
+{
+ struct nv_usb *dev;
+
+ dev = file->private_data;
+ if (dev == NULL) {
+ INFO("%s(%d) failed to get interface\n", __func__, __LINE__);
+ return -ENODEV;
+ }
+
+ kref_put(&dev->kref, nv_usb_delete);
+ return 0;
+}
+
+static int nv_usb_flush(struct file *file, fl_owner_t id)
+{
+ return 0;
+}
+
+static int nv_usb_transfer(struct bulk_data *data);
+
+static ssize_t nv_usb_read(struct file *file, char *buffer, size_t count,
+ loff_t *ppos)
+{
+ return 0;
+}
+
+unsigned long
+nv_usb_calc_time(struct timeval g_sttime, struct timeval g_entime)
+{
+
+ unsigned int num_sec = g_entime.tv_sec - g_sttime.tv_sec;
+
+ if (num_sec)
+ return (g_entime.tv_usec +
+ (1000000 - g_sttime.tv_usec) +
+ ((num_sec - 1) * 1000000));
+ else
+ return g_entime.tv_usec - g_sttime.tv_usec;
+
+}
+
+static void nv_usb_callback(struct urb *urb)
+{
+ struct completion *urb_done_ptr = urb->context;
+
+ complete(urb_done_ptr);
+}
+
+static int nv_usb_transfer(struct bulk_data *data)
+{
+ struct nv_usb *dev = data->dev;
+ struct nvusb_cb_wrap *bcb = NULL;
+ struct nvusb_cs_wrap *bcs = NULL;
+ struct urb *urb = NULL;
+ unsigned int transfer_length = data->length;
+ struct completion urb_done;
+ int retval = 0;
+ unsigned int cbwlen = US_BULK_CB_WRAP_LEN;
+ unsigned int cswlen = US_BULK_CS_WRAP_LEN;
+ char *buf = NULL;
+ struct timeval g_sttime, g_entime;
+ unsigned long data_transfer_time = 0;
+
+ init_completion(&urb_done);
+
+ mutex_lock(&dev->mutex);
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ INFO("%s(%d) failed to alloc urb\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ bcb = usb_alloc_coherent(dev->udev, cbwlen, GFP_KERNEL,
+ &urb->transfer_dma);
+
+ if (!bcb) {
+ INFO("%s(%d) failed to alloc bcb\n", __func__, __LINE__);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
+ bcb->DataTransferLength = cpu_to_le32(transfer_length);
+ /*0 --> write 1 --> read*/
+ bcb->Flags = data->data_direction ? 1 << 7 : 0;
+ bcb->Tag = ++dev->tag;
+ bcb->Length = data->sub_cmd_length;
+
+ memset(bcb->CDB, 0, sizeof(bcb->CDB));
+ memcpy(bcb->CDB, data->sub_cmd, bcb->Length);
+
+ if (!dev->interface) {
+ INFO("%s(%d) interface disconnected\n", __func__, __LINE__);
+ usb_free_coherent(dev->udev, cbwlen, bcb, urb->transfer_dma);
+ retval = -ENODEV;
+ goto out;
+ }
+
+ INFO("cbwlen = %d\n", cbwlen);
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+ bcb, cbwlen, nv_usb_callback, dev);
+
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ urb->context = &urb_done;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+
+ if (retval) {
+ usb_free_coherent(dev->udev, cbwlen, bcb, urb->transfer_dma);
+ INFO("%s(%d) urb submit failed\n", __func__, __LINE__);
+ goto out;
+ }
+
+ wait_for_completion_interruptible_timeout(
+ &urb_done, 20000);
+
+
+ usb_free_coherent(dev->udev, cbwlen, bcb, urb->transfer_dma);
+ INFO("%s(%d)\n", __func__, __LINE__);
+
+
+ if (transfer_length) {
+ INFO("%s(%d) Transfering Data = %d\n",
+ __func__, __LINE__, transfer_length);
+ buf = usb_alloc_coherent(dev->udev, transfer_length, GFP_KERNEL,
+ &urb->transfer_dma);
+
+ if (!buf) {
+ INFO("%s(%d)failed to alloc buffer for data transfer\n",
+ __func__, __LINE__);
+ retval = -ENOMEM;
+ goto out;
+ }
+
+ if (!data->data_direction) {
+ memset(buf, data->write_char, transfer_length);
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+ buf, transfer_length, nv_usb_callback, dev);
+ } else {
+ memset(buf, 0, transfer_length);
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+ buf, transfer_length, nv_usb_callback, dev);
+ }
+
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ urb->context = &urb_done;
+
+ do_gettimeofday(&g_sttime);
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ usb_free_coherent(dev->udev, transfer_length, buf,
+ urb->transfer_dma);
+ INFO("%s(%d) urb submit failed\n", __func__, __LINE__);
+ goto out;
+ }
+
+ wait_for_completion_interruptible_timeout(
+ &urb_done, 20000);
+ do_gettimeofday(&g_entime);
+ if (data->data_direction)
+ memcpy(data->buf, buf , transfer_length);
+
+ usb_free_coherent(dev->udev,
+ transfer_length, buf, urb->transfer_dma);
+ data_transfer_time = nv_usb_calc_time(g_sttime, g_entime);
+ }
+
+ bcs = usb_alloc_coherent(dev->udev, cswlen, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!bcs) {
+ INFO("%s(%d) failed to alloc bcs\n", __func__, __LINE__);
+ retval = -ENOMEM;
+ goto out;
+ }
+ memset(bcs, 0, cswlen);
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+ bcs, cswlen, nv_usb_callback, dev);
+
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ urb->context = &urb_done;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ usb_free_coherent(dev->udev, cswlen, bcs, urb->transfer_dma);
+ INFO("%s(%d) urb submit failed\n", __func__, __LINE__);
+ goto out;
+ }
+
+ wait_for_completion_interruptible_timeout(
+ &urb_done, 20000);
+
+ INFO(
+ "%s(%d) dCSWSignature = %x dCSWTag = %x Dataresidur = %d status = %d\n",
+ __func__, __LINE__, bcs->Signature,
+ bcs->Tag, bcs->Residue, bcs->Status);
+
+ if (bcs->Status)
+ data_transfer_time = 0;
+
+ INFO("time taken is %lu\n", data_transfer_time);
+
+ data->data_transfer_time = data_transfer_time;
+ data->g_data_transfer_time = bcs->Residue;
+
+ usb_free_coherent(dev->udev, cswlen, bcs, urb->transfer_dma);
+ usb_free_urb(urb);
+ mutex_unlock(&dev->mutex);
+ return 0;
+out:
+ usb_free_urb(urb);
+ mutex_unlock(&dev->mutex);
+ return retval;
+}
+
+static ssize_t nv_usb_write(struct file *file, const char *user_buffer,
+ size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+static long nv_usb_ioctl(struct file *file, unsigned int cmd_in,
+ unsigned long arg, struct nv_usb *dev)
+{
+ void __user *p = (void __user *)arg;
+ struct bulk_data *data = NULL;
+ struct user_bulk_data *user_data = NULL;
+ int ret = 0;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ INFO("%s(%d) No Memory\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ user_data = kzalloc(sizeof(*user_data), GFP_KERNEL);
+ if (!user_data) {
+ INFO("%s(%d) No Memory\n", __func__, __LINE__);
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ if (__copy_from_user(user_data, p, sizeof(*user_data))) {
+ INFO("%s(%d) copy from user failed\n", __func__, __LINE__);
+ kfree(user_data);
+ kfree(data);
+ return -EFAULT;
+ }
+
+ data->dev = file->private_data;
+ data->sub_cmd_length = user_data->sub_cmd_length;
+
+ data->sub_cmd = kzalloc(data->sub_cmd_length, GFP_KERNEL);
+ if (!data->sub_cmd) {
+ INFO("%s(%d) No Memory\n", __func__, __LINE__);
+ kfree(user_data);
+ kfree(data);
+ return -ENOMEM;
+ }
+ if (__copy_from_user(data->sub_cmd,
+ user_data->sub_cmd, data->sub_cmd_length)) {
+ INFO("%s(%d) copy from user failed\n", __func__, __LINE__);
+ kfree(data->sub_cmd);
+ kfree(user_data);
+ kfree(data);
+ return -EFAULT;
+ }
+
+ data->length = user_data->length;
+ data->buf = kzalloc(data->length, GFP_KERNEL);
+ if (!data->buf) {
+ INFO("%s(%d) No Memory\n", __func__, __LINE__);
+ kfree(data->sub_cmd);
+ kfree(user_data);
+ kfree(data);
+ return -ENOMEM;
+ }
+
+ data->write_char = user_data->write_char;
+
+ switch (cmd_in) {
+ case NVUSB_BULK_WRITE:
+ if (__copy_from_user(data->buf, user_data->buf, data->length)) {
+ INFO("%s(%d) copy from user failed\n",
+ __func__, __LINE__);
+ ret = -EFAULT;
+ goto error;
+ }
+ data->data_direction = 0;
+ ret = nv_usb_transfer(data);
+ if (ret) {
+ INFO("%s(%d) nv_usb_transfer failed\n",
+ __func__, __LINE__);
+ goto error;
+ }
+ break;
+ case NVUSB_BULK_READ:
+ data->data_direction = 1;
+ INFO("%s(%d)\n", __func__, __LINE__);
+ ret = nv_usb_transfer(data);
+ if (ret) {
+ INFO("%s(%d) nv_usb_transfer failed\n",
+ __func__, __LINE__);
+ goto error;
+ }
+
+ if (__copy_to_user(user_data->buf, data->buf, data->length)) {
+ INFO("%s(%d) copy to user failed\n",
+ __func__, __LINE__);
+ ret = -EFAULT;
+ goto error;
+ }
+ break;
+ default:
+ INFO("%s(%d) Invalid ioctl command %x\n",
+ __func__, __LINE__, cmd_in);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ user_data->data_transfer_time = data->data_transfer_time;
+ user_data->g_data_transfer_time = data->g_data_transfer_time;
+
+ if (copy_to_user(p, user_data, sizeof(*user_data))) {
+ INFO("%s(%d) copy to user failed\n", __func__, __LINE__);
+ ret = -EFAULT;
+ }
+
+error:
+ kfree(data->buf);
+ kfree(data->sub_cmd);
+ kfree(user_data);
+ kfree(data);
+
+ return ret;
+
+}
+static long nv_usb_unlocked_ioctl(struct file *file, unsigned int cmd_in,
+ unsigned long arg)
+{
+ int ret;
+ struct nv_usb *dev;
+
+ dev = file->private_data;
+
+ ret = nv_usb_ioctl(file, cmd_in, arg, dev);
+
+ return ret;
+}
+
+static const struct file_operations nv_usb_fops = {
+ .owner = THIS_MODULE,
+ .read = nv_usb_read,
+ .write = nv_usb_write,
+ .open = nv_usb_open,
+ .unlocked_ioctl = nv_usb_unlocked_ioctl,
+ .release = nv_usb_release,
+ .flush = nv_usb_flush,
+ .llseek = noop_llseek,
+};
+
+static struct usb_class_driver nv_usb_class = {
+ .name = "nvbulk%d",
+ .fops = &nv_usb_fops,
+ .minor_base = NV_USB_BULK_MINOR_BASE,
+};
+
+static int nv_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct nv_usb *dev;
+ struct usb_device *udev;
+ int retval = 0;
+ int i;
+
+ udev = usb_get_dev(interface_to_usbdev(interface));
+ /* allocate memory for our device state and initialize it */
+ dev = devm_kzalloc(&udev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ INFO("%s(%d) Out of Memory\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ kref_init(&dev->kref);
+ init_usb_anchor(&dev->submitted);
+ mutex_init(&dev->mutex);
+
+ dev->udev = udev;
+ dev->interface = interface;
+
+ /*Set up the Endpoint Information */
+ /* use only the first bulk-in and bulk-out endpoints*/
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_bulk_in(endpoint)) {
+ /*We found a bulk_in endpoint */
+ dev->bulk_in_size = usb_endpoint_maxp(endpoint);
+ dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ }
+
+ if (usb_endpoint_is_bulk_out(endpoint)) {
+ /*We found a buld_out endpoint */
+ dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+ }
+ }
+
+ if (dev->bulk_in_endpointAddr == 0
+ || dev->bulk_out_endpointAddr == 0) {
+ INFO("%s(%d) Count not find bulk point infomations\n",
+ __func__, __LINE__);
+ goto error;
+ }
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ /* we can register the device now, as it is ready */
+ retval = usb_register_dev(interface, &nv_usb_class);
+
+ if (retval) {
+ INFO("%s(%d) usb_register_dev failed\n", __func__, __LINE__);
+ usb_set_intfdata(interface, NULL);
+ goto error;
+ }
+
+ INFO("%s(%d) device now attached to USB\n", __func__, __LINE__);
+ return 0;
+error:
+ if (dev) {
+ kref_put(&dev->kref, nv_usb_delete);
+ retval = -EFAULT;
+ }
+
+ return retval;
+
+}
+
+static void nv_usb_disconnect(struct usb_interface *interface)
+{
+ struct nv_usb *dev;
+ int minor = interface->minor;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ usb_deregister_dev(interface, &nv_usb_class);
+
+ mutex_lock(&dev->mutex);
+ dev->interface = NULL;
+ mutex_unlock(&dev->mutex);
+
+ usb_kill_anchored_urbs(&dev->submitted);
+
+ kref_put(&dev->kref, nv_usb_delete);
+
+ INFO("%s(%d) disconnected minor = %d\n", __func__, __LINE__, minor);
+
+}
+
+static struct usb_driver nv_usb_driver = {
+ .name = "nv-usb",
+ .probe = nv_usb_probe,
+ .disconnect = nv_usb_disconnect,
+ .id_table = nv_usb_table,
+};
+
+module_usb_driver(nv_usb_driver);
+MODULE_AUTHOR("NVIDIA");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/class/nv-usb.h b/drivers/usb/class/nv-usb.h
new file mode 100644
index 000000000000..83922cc583e8
--- /dev/null
+++ b/drivers/usb/class/nv-usb.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __LINUX_USB_NV_USB_BULK_H
+#define __LINUX_USB_NV_USB_BULK_H
+
+
+#define NVUSB_BULK_WRITE 0X2000
+#define NVUSB_BULK_READ 0X2001
+
+/* command block wrapper */
+struct nvusb_cb_wrap {
+ __le32 Signature;
+ __u32 Tag;
+ __le32 DataTransferLength;
+ __u8 Flags;
+ __u8 Length;
+ __u8 CDB[16];
+};
+
+#define US_BULK_CB_WRAP_LEN 31
+#define US_BULK_CB_SIGN 0x43425355
+#define US_BULK_FLAG_IN (1 << 7)
+#define US_BULK_FLAG_OUT 0
+
+/* command status wrapper */
+struct nvusb_cs_wrap {
+ __le32 Signature;
+ __u32 Tag;
+ __le32 Residue;
+ __u8 Status;
+};
+
+#define US_BULK_CS_WRAP_LEN 13
+#define US_BULK_CS_SIGN 0x53425355
+#define US_BULK_STAT_OK 0
+#define US_BULK_STAT_FAIL 1
+#define US_BULK_STAT_BAD_DATA 2
+
+struct bulk_data {
+ struct nv_usb *dev;
+ __u8 data_direction;
+ __u8 sub_cmd_length;
+ __u8 *sub_cmd;
+ __u32 length;
+ __u8 *buf;
+ __u8 write_char;
+ __u32 data_transfer_time;
+ __u32 g_data_transfer_time;
+};
+
+struct user_bulk_data {
+ __u8 sub_cmd_length;
+ __u8 __user *sub_cmd;
+ __u32 length;
+ __u8 __user *buf;
+ __u8 write_char;
+ __u32 data_transfer_time;
+ __u32 g_data_transfer_time;
+
+};
+
+
+/* Structure to hold all of our device specific stuff */
+struct nv_usb {
+ /* the usb device for this device */
+ struct usb_device *udev;
+ /* the interface for this device */
+ struct usb_interface *interface;
+ /* in case we need to retract our submissions */
+ struct usb_anchor submitted;
+ /* the size of the receive buffer */
+ size_t bulk_in_size;
+ /* the address of the bulk in endpoint */
+ __u8 bulk_in_endpointAddr;
+ /* the address of the bulk out endpoint */
+ __u8 bulk_out_endpointAddr;
+ __u32 tag;
+ struct kref kref;
+ struct mutex mutex;
+};
+#define to_nv_usb_dev(d) container_of(d, struct nv_usb, kref)
+
+#endif
+
+
+