aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/class/usbtmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/class/usbtmc.c')
-rw-r--r--drivers/usb/class/usbtmc.c366
1 files changed, 230 insertions, 136 deletions
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 6a54634ab82..103a6e9ee49 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -19,7 +19,8 @@
* http://www.gnu.org/copyleft/gpl.html.
*/
-#include <linux/init.h>
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -31,6 +32,8 @@
#include <linux/usb/tmc.h>
+#define RIGOL 1
+#define USBTMC_HEADER_SIZE 12
#define USBTMC_MINOR_BASE 176
/*
@@ -84,6 +87,8 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read; /* needed for abort */
+ u8 rigol_quirk;
+
/* attributes from the USB TMC spec for this device */
u8 TermChar;
bool TermCharEnabled;
@@ -97,6 +102,16 @@ struct usbtmc_device_data {
};
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
+struct usbtmc_ID_rigol_quirk {
+ __u16 idVendor;
+ __u16 idProduct;
+};
+
+static const struct usbtmc_ID_rigol_quirk usbtmc_id_quirk[] = {
+ { 0x1ab1, 0x0588 },
+ { 0, 0 }
+};
+
/* Forward declarations */
static struct usb_driver usbtmc_driver;
@@ -105,7 +120,6 @@ static void usbtmc_delete(struct kref *kref)
struct usbtmc_device_data *data = to_usbtmc_data(kref);
usb_put_dev(data->usb_dev);
- kfree(data);
}
static int usbtmc_open(struct inode *inode, struct file *filp)
@@ -116,10 +130,8 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
intf = usb_find_interface(&usbtmc_driver, iminor(inode));
if (!intf) {
- printk(KERN_ERR KBUILD_MODNAME
- ": can not find device for minor %d", iminor(inode));
- retval = -ENODEV;
- goto exit;
+ pr_err("can not find device for minor %d", iminor(inode));
+ return -ENODEV;
}
data = usb_get_intfdata(intf);
@@ -128,7 +140,6 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
/* Store pointer in file structure's private data field */
filp->private_data = data;
-exit:
return retval;
}
@@ -186,8 +197,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
if (current_setting->endpoint[n].desc.bEndpointAddress ==
data->bulk_in)
- max_size = le16_to_cpu(current_setting->endpoint[n].
- desc.wMaxPacketSize);
+ max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);
if (max_size == 0) {
dev_err(dev, "Couldn't get wMaxPacketSize\n");
@@ -268,7 +278,7 @@ usbtmc_abort_bulk_in_status:
dev_err(dev, "usb_bulk_msg returned %d\n", rv);
goto exit;
}
- } while ((actual = max_size) &&
+ } while ((actual == max_size) &&
(n < USBTMC_MAX_READS_TO_CLEAR_BULK_IN));
if (actual == max_size) {
@@ -362,6 +372,63 @@ exit:
return rv;
}
+/*
+ * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint.
+ * @transfer_size: number of bytes to request from the device.
+ *
+ * See the USBTMC specification, Table 4.
+ *
+ * Also updates bTag_last_write.
+ */
+static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size)
+{
+ int retval;
+ u8 *buffer;
+ int actual;
+
+ buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+ /* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message
+ * Refer to class specs for details
+ */
+ buffer[0] = 2;
+ buffer[1] = data->bTag;
+ buffer[2] = ~data->bTag;
+ buffer[3] = 0; /* Reserved */
+ buffer[4] = transfer_size >> 0;
+ buffer[5] = transfer_size >> 8;
+ buffer[6] = transfer_size >> 16;
+ buffer[7] = transfer_size >> 24;
+ buffer[8] = data->TermCharEnabled * 2;
+ /* Use term character? */
+ buffer[9] = data->TermChar;
+ buffer[10] = 0; /* Reserved */
+ buffer[11] = 0; /* Reserved */
+
+ /* Send bulk URB */
+ retval = usb_bulk_msg(data->usb_dev,
+ usb_sndbulkpipe(data->usb_dev,
+ data->bulk_out),
+ buffer, USBTMC_HEADER_SIZE, &actual, USBTMC_TIMEOUT);
+
+ /* Store bTag (in case we need to abort) */
+ data->bTag_last_write = data->bTag;
+
+ /* Increment bTag -- and increment again if zero */
+ data->bTag++;
+ if (!data->bTag)
+ data->bTag++;
+
+ kfree(buffer);
+ if (retval < 0) {
+ dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);
+ return retval;
+ }
+
+ return 0;
+}
+
static ssize_t usbtmc_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
@@ -389,51 +456,39 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
goto exit;
}
- remaining = count;
- done = 0;
+ if (data->rigol_quirk) {
+ dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
- while (remaining > 0) {
- if (remaining > USBTMC_SIZE_IOBUFFER - 12 - 3)
- this_part = USBTMC_SIZE_IOBUFFER - 12 - 3;
- else
- this_part = remaining;
+ retval = send_request_dev_dep_msg_in(data, count);
- /* Setup IO buffer for DEV_DEP_MSG_IN message
- * Refer to class specs for details
- */
- buffer[0] = 2;
- buffer[1] = data->bTag;
- buffer[2] = ~(data->bTag);
- buffer[3] = 0; /* Reserved */
- buffer[4] = (this_part) & 255;
- buffer[5] = ((this_part) >> 8) & 255;
- buffer[6] = ((this_part) >> 16) & 255;
- buffer[7] = ((this_part) >> 24) & 255;
- buffer[8] = data->TermCharEnabled * 2;
- /* Use term character? */
- buffer[9] = data->TermChar;
- buffer[10] = 0; /* Reserved */
- buffer[11] = 0; /* Reserved */
+ if (retval < 0) {
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_out(data);
+ goto exit;
+ }
+ }
- /* Send bulk URB */
- retval = usb_bulk_msg(data->usb_dev,
- usb_sndbulkpipe(data->usb_dev,
- data->bulk_out),
- buffer, 12, &actual, USBTMC_TIMEOUT);
+ /* Loop until we have fetched everything we requested */
+ remaining = count;
+ this_part = remaining;
+ done = 0;
- /* Store bTag (in case we need to abort) */
- data->bTag_last_write = data->bTag;
+ while (remaining > 0) {
+ if (!data->rigol_quirk) {
+ dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count);
- /* Increment bTag -- and increment again if zero */
- data->bTag++;
- if (!data->bTag)
- (data->bTag)++;
+ if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3)
+ this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3;
+ else
+ this_part = remaining;
- if (retval < 0) {
+ retval = send_request_dev_dep_msg_in(data, this_part);
+ if (retval < 0) {
dev_err(dev, "usb_bulk_msg returned %d\n", retval);
- if (data->auto_abort)
- usbtmc_ioctl_abort_bulk_out(data);
- goto exit;
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_out(data);
+ goto exit;
+ }
}
/* Send bulk URB */
@@ -443,51 +498,109 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
buffer, USBTMC_SIZE_IOBUFFER, &actual,
USBTMC_TIMEOUT);
+ dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
+
/* Store bTag (in case we need to abort) */
data->bTag_last_read = data->bTag;
if (retval < 0) {
- dev_err(dev, "Unable to read data, error %d\n", retval);
+ dev_dbg(dev, "Unable to read data, error %d\n", retval);
if (data->auto_abort)
usbtmc_ioctl_abort_bulk_in(data);
goto exit;
}
- /* How many characters did the instrument send? */
- n_characters = buffer[4] +
- (buffer[5] << 8) +
- (buffer[6] << 16) +
- (buffer[7] << 24);
+ /* Parse header in first packet */
+ if ((done == 0) || !data->rigol_quirk) {
+ /* Sanity checks for the header */
+ if (actual < USBTMC_HEADER_SIZE) {
+ dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- /* Ensure the instrument doesn't lie about it */
- if(n_characters > actual - 12) {
- dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12);
- n_characters = actual - 12;
- }
+ if (buffer[0] != 2) {
+ dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- /* Ensure the instrument doesn't send more back than requested */
- if(n_characters > this_part) {
- dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
- n_characters = this_part;
- }
+ if (buffer[1] != data->bTag_last_write) {
+ dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
- /* Bound amount of data received by amount of data requested */
- if (n_characters > this_part)
- n_characters = this_part;
+ /* How many characters did the instrument send? */
+ n_characters = buffer[4] +
+ (buffer[5] << 8) +
+ (buffer[6] << 16) +
+ (buffer[7] << 24);
- /* Copy buffer to user space */
- if (copy_to_user(buf + done, &buffer[12], n_characters)) {
- /* There must have been an addressing problem */
- retval = -EFAULT;
- goto exit;
+ if (n_characters > this_part) {
+ dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count);
+ if (data->auto_abort)
+ usbtmc_ioctl_abort_bulk_in(data);
+ goto exit;
+ }
+
+ /* Remove the USBTMC header */
+ actual -= USBTMC_HEADER_SIZE;
+
+ /* Check if the message is smaller than requested */
+ if (data->rigol_quirk) {
+ if (remaining > n_characters)
+ remaining = n_characters;
+ /* Remove padding if it exists */
+ if (actual > remaining)
+ actual = remaining;
+ }
+ else {
+ if (this_part > n_characters)
+ this_part = n_characters;
+ /* Remove padding if it exists */
+ if (actual > this_part)
+ actual = this_part;
+ }
+
+ dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]);
+
+ remaining -= actual;
+
+ /* Terminate if end-of-message bit received from device */
+ if ((buffer[8] & 0x01) && (actual >= n_characters))
+ remaining = 0;
+
+ dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done);
+
+
+ /* Copy buffer to user space */
+ if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) {
+ /* There must have been an addressing problem */
+ retval = -EFAULT;
+ goto exit;
+ }
+ done += actual;
}
+ else {
+ if (actual > remaining)
+ actual = remaining;
- done += n_characters;
- /* Terminate if end-of-message bit recieved from device */
- if ((buffer[8] & 0x01) && (actual >= n_characters + 12))
- remaining = 0;
- else
- remaining -= n_characters;
+ remaining -= actual;
+
+ dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer);
+
+ /* Copy buffer to user space */
+ if (copy_to_user(buf + done, buffer, actual)) {
+ /* There must have been an addressing problem */
+ retval = -EFAULT;
+ goto exit;
+ }
+ done += actual;
+ }
}
/* Update file position value */
@@ -528,8 +641,8 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
done = 0;
while (remaining > 0) {
- if (remaining > USBTMC_SIZE_IOBUFFER - 12) {
- this_part = USBTMC_SIZE_IOBUFFER - 12;
+ if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) {
+ this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE;
buffer[8] = 0;
} else {
this_part = remaining;
@@ -539,24 +652,24 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
/* Setup IO buffer for DEV_DEP_MSG_OUT message */
buffer[0] = 1;
buffer[1] = data->bTag;
- buffer[2] = ~(data->bTag);
+ buffer[2] = ~data->bTag;
buffer[3] = 0; /* Reserved */
- buffer[4] = this_part & 255;
- buffer[5] = (this_part >> 8) & 255;
- buffer[6] = (this_part >> 16) & 255;
- buffer[7] = (this_part >> 24) & 255;
+ buffer[4] = this_part >> 0;
+ buffer[5] = this_part >> 8;
+ buffer[6] = this_part >> 16;
+ buffer[7] = this_part >> 24;
/* buffer[8] is set above... */
buffer[9] = 0; /* Reserved */
buffer[10] = 0; /* Reserved */
buffer[11] = 0; /* Reserved */
- if (copy_from_user(&buffer[12], buf + done, this_part)) {
+ if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf + done, this_part)) {
retval = -EFAULT;
goto exit;
}
- n_bytes = roundup(12 + this_part, 4);
- memset(buffer + 12 + this_part, 0, n_bytes - (12 + this_part));
+ n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4);
+ memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - (USBTMC_HEADER_SIZE + this_part));
do {
retval = usb_bulk_msg(data->usb_dev,
@@ -636,7 +749,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
desc = &current_setting->endpoint[n].desc;
if (desc->bEndpointAddress == data->bulk_in)
- max_size = le16_to_cpu(desc->wMaxPacketSize);
+ max_size = usb_endpoint_maxp(desc);
}
if (max_size == 0) {
@@ -719,50 +832,32 @@ exit:
static int usbtmc_ioctl_clear_out_halt(struct usbtmc_device_data *data)
{
- u8 *buffer;
int rv;
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
rv = usb_clear_halt(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, data->bulk_out));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
- goto exit;
+ return rv;
}
- rv = 0;
-
-exit:
- kfree(buffer);
- return rv;
+ return 0;
}
static int usbtmc_ioctl_clear_in_halt(struct usbtmc_device_data *data)
{
- u8 *buffer;
int rv;
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
rv = usb_clear_halt(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev, data->bulk_in));
if (rv < 0) {
dev_err(&data->usb_dev->dev, "usb_control_msg returned %d\n",
rv);
- goto exit;
+ return rv;
}
- rv = 0;
-
-exit:
- kfree(buffer);
- return rv;
+ return 0;
}
static int get_capabilities(struct usbtmc_device_data *data)
@@ -807,7 +902,7 @@ err_out:
}
#define capability_attribute(name) \
-static ssize_t show_##name(struct device *dev, \
+static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@@ -815,7 +910,7 @@ static ssize_t show_##name(struct device *dev, \
\
return sprintf(buf, "%d\n", data->capabilities.name); \
} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR_RO(name)
capability_attribute(interface_capabilities);
capability_attribute(device_capabilities);
@@ -834,7 +929,7 @@ static struct attribute_group capability_attr_grp = {
.attrs = capability_attrs,
};
-static ssize_t show_TermChar(struct device *dev,
+static ssize_t TermChar_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
@@ -843,7 +938,7 @@ static ssize_t show_TermChar(struct device *dev,
return sprintf(buf, "%c\n", data->TermChar);
}
-static ssize_t store_TermChar(struct device *dev,
+static ssize_t TermChar_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
@@ -855,10 +950,10 @@ static ssize_t store_TermChar(struct device *dev,
data->TermChar = buf[0];
return count;
}
-static DEVICE_ATTR(TermChar, S_IRUGO, show_TermChar, store_TermChar);
+static DEVICE_ATTR_RW(TermChar);
#define data_attribute(name) \
-static ssize_t show_##name(struct device *dev, \
+static ssize_t name##_show(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
@@ -866,7 +961,7 @@ static ssize_t show_##name(struct device *dev, \
\
return sprintf(buf, "%d\n", data->name); \
} \
-static ssize_t store_##name(struct device *dev, \
+static ssize_t name##_store(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
@@ -884,7 +979,7 @@ static ssize_t store_##name(struct device *dev, \
else \
return count; \
} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, store_##name)
+static DEVICE_ATTR_RW(name)
data_attribute(TermCharEnabled);
data_attribute(auto_abort);
@@ -1008,7 +1103,7 @@ static int usbtmc_probe(struct usb_interface *intf,
dev_dbg(&intf->dev, "%s called\n", __func__);
- data = kmalloc(sizeof(struct usbtmc_device_data), GFP_KERNEL);
+ data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&intf->dev, "Unable to allocate kernel memory\n");
return -ENOMEM;
@@ -1022,6 +1117,20 @@ static int usbtmc_probe(struct usb_interface *intf,
mutex_init(&data->io_mutex);
data->zombie = 0;
+ /* Determine if it is a Rigol or not */
+ data->rigol_quirk = 0;
+ dev_dbg(&intf->dev, "Trying to find if device Vendor 0x%04X Product 0x%04X has the RIGOL quirk\n",
+ le16_to_cpu(data->usb_dev->descriptor.idVendor),
+ le16_to_cpu(data->usb_dev->descriptor.idProduct));
+ for(n = 0; usbtmc_id_quirk[n].idVendor > 0; n++) {
+ if ((usbtmc_id_quirk[n].idVendor == le16_to_cpu(data->usb_dev->descriptor.idVendor)) &&
+ (usbtmc_id_quirk[n].idProduct == le16_to_cpu(data->usb_dev->descriptor.idProduct))) {
+ dev_dbg(&intf->dev, "Setting this device as having the RIGOL quirk\n");
+ data->rigol_quirk = 1;
+ break;
+ }
+ }
+
/* Initialize USBTMC bTag and other fields */
data->bTag = 1;
data->TermCharEnabled = 0;
@@ -1117,21 +1226,6 @@ static struct usb_driver usbtmc_driver = {
.resume = usbtmc_resume,
};
-static int __init usbtmc_init(void)
-{
- int retcode;
-
- retcode = usb_register(&usbtmc_driver);
- if (retcode)
- printk(KERN_ERR KBUILD_MODNAME": Unable to register driver\n");
- return retcode;
-}
-module_init(usbtmc_init);
-
-static void __exit usbtmc_exit(void)
-{
- usb_deregister(&usbtmc_driver);
-}
-module_exit(usbtmc_exit);
+module_usb_driver(usbtmc_driver);
MODULE_LICENSE("GPL");