Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1267106 > unrolled thread
| Started by | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| First post | 2015-11-11 12:10 +0100 |
| Last post | 2015-11-13 10:10 +0100 |
| Articles | 15 — 4 participants |
Back to article view | Back to linux.kernel
[PATCH v3 0/5] usb: usbtmc: Add support for missing functions in USBTMC-USB488 spec Dave Penkler <dpenkler@gmail.com> - 2015-11-11 12:10 +0100
[PATCH v3 3/5] Add support for receiving USBTMC USB488 SRQ notifications via poll/select Dave Penkler <dpenkler@gmail.com> - 2015-11-11 12:20 +0100
Re: [PATCH v3 3/5] Add support for receiving USBTMC USB488 SRQ notifications via poll/select Andy Shevchenko <andy.shevchenko@gmail.com> - 2015-11-11 20:10 +0100
[PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. Dave Penkler <dpenkler@gmail.com> - 2015-11-11 12:20 +0100
Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. Andy Shevchenko <andy.shevchenko@gmail.com> - 2015-11-11 20:10 +0100
Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> - 2015-11-11 20:50 +0100
Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. Andy Shevchenko <andy.shevchenko@gmail.com> - 2015-11-11 21:00 +0100
Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. Greg Kroah-Hartman <gregkh@linuxfoundation.org> - 2015-11-11 22:10 +0100
Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. Andy Shevchenko <andy.shevchenko@gmail.com> - 2015-11-12 10:50 +0100
[PATCH v3 2/5] Add support for USBTMC USB488 SRQ notification with fasync Dave Penkler <dpenkler@gmail.com> - 2015-11-11 12:20 +0100
[PATCH v3 4/5] Add ioctl to retrieve USBTMC-USB488 capabilities Dave Penkler <dpenkler@gmail.com> - 2015-11-11 12:30 +0100
Re: [PATCH v3 4/5] Add ioctl to retrieve USBTMC-USB488 capabilities Andy Shevchenko <andy.shevchenko@gmail.com> - 2015-11-11 20:40 +0100
[PATCH v3 5/5] Add ioctls to enable and disable local controls on an instrument Dave Penkler <dpenkler@gmail.com> - 2015-11-11 12:30 +0100
Re: [PATCH v3 5/5] Add ioctls to enable and disable local controls on an instrument Andy Shevchenko <andy.shevchenko@gmail.com> - 2015-11-11 20:40 +0100
Re: [PATCH v3 5/5] Add ioctls to enable and disable local controls on an instrument Dave Penkler <dpenkler@gmail.com> - 2015-11-13 10:10 +0100
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-11 12:10 +0100 |
| Subject | [PATCH v3 0/5] usb: usbtmc: Add support for missing functions in USBTMC-USB488 spec |
| Message-ID | <qtBrQ-20m-7@gated-at.bofh.it> |
Implement support for the USB488 defined READ_STATUS_BYTE ioctl (1/5)
and SRQ notifications with fasync (2/5) and poll/select (3/5) in order
to be able to synchronize with variable duration instrument operations.
Add ioctls for other USB488 requests: REN_CONTROL, GOTO_LOCAL and
LOCAL_LOCKOUT. (4/5)
Add convenience ioctl to return all device capabilities (5/5)
PATCH Changelog:
v3 - Split into multiple patches as per gregkh request
V2 - Fix V1 bug: not waking sleepers on disconnect.
- Correct sparse warnings.
V1 - Original patch
Testing:
All functions tested ok on an USBTMC-USB488 compliant oscilloscope
Dave Penkler (5):
Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE
operation.
Add support for USBTMC USB488 SRQ notification with fasync
Add support for receiving USBTMC USB488 SRQ notifications via
poll/select
Add ioctl to retrieve USBTMC-USB488 capabilities
Add ioctls to enable and disable local controls on an instrument
drivers/usb/class/usbtmc.c | 358 +++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/usb/tmc.h | 30 +++-
2 files changed, 385 insertions(+), 3 deletions(-)
--
2.5.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-11 12:20 +0100 |
| Subject | [PATCH v3 3/5] Add support for receiving USBTMC USB488 SRQ notifications via poll/select |
| Message-ID | <qtBBw-23F-1@gated-at.bofh.it> |
| In reply to | #1267106 |
Background:
In many situations operations on multiple instruments need to be
synchronized. poll/select provide a convenient way of waiting on a number
of different instruments and other peripherals simultaneously.
Signed-off-by: Dave Penkler <dpenkler@gmail.com>
---
drivers/usb/class/usbtmc.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 2239cd0..bb9a6ab 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -27,6 +27,7 @@
#include <linux/uaccess.h>
#include <linux/kref.h>
#include <linux/slab.h>
+#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/usb.h>
#include <linux/usb/tmc.h>
@@ -1193,6 +1194,27 @@ static int usbtmc_fasync(int fd, struct file *file, int on)
return fasync_helper(fd, file, on, &data->fasync);
}
+static unsigned int usbtmc_poll(struct file *file, poll_table *wait)
+{
+ struct usbtmc_device_data *data = file->private_data;
+ unsigned int mask = 0;
+
+ mutex_lock(&data->io_mutex);
+
+ if (data->zombie) {
+ mask = POLLHUP | POLLERR;
+ goto no_poll;
+ }
+
+ poll_wait(file, &data->waitq, wait);
+
+ mask = (atomic_read(&data->srq_asserted)) ? POLLIN | POLLRDNORM : 0;
+
+no_poll:
+ mutex_unlock(&data->io_mutex);
+ return mask;
+}
+
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = usbtmc_read,
@@ -1201,6 +1223,7 @@ static const struct file_operations fops = {
.release = usbtmc_release,
.unlocked_ioctl = usbtmc_ioctl,
.fasync = usbtmc_fasync,
+ .poll = usbtmc_poll,
.llseek = default_llseek,
};
--
2.5.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2015-11-11 20:10 +0100 |
| Subject | Re: [PATCH v3 3/5] Add support for receiving USBTMC USB488 SRQ notifications via poll/select |
| Message-ID | <qtIWm-6Rf-37@gated-at.bofh.it> |
| In reply to | #1267108 |
On Wed, Nov 11, 2015 at 1:16 PM, Dave Penkler <dpenkler@gmail.com> wrote:
> Background:
> In many situations operations on multiple instruments need to be
> synchronized. poll/select provide a convenient way of waiting on a number
> of different instruments and other peripherals simultaneously.
>
> Signed-off-by: Dave Penkler <dpenkler@gmail.com>
> ---
> drivers/usb/class/usbtmc.c | 23 +++++++++++++++++++++++
> 1 file changed, 23 insertions(+)
>
> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> index 2239cd0..bb9a6ab 100644
> --- a/drivers/usb/class/usbtmc.c
> +++ b/drivers/usb/class/usbtmc.c
> @@ -27,6 +27,7 @@
> #include <linux/uaccess.h>
> #include <linux/kref.h>
> #include <linux/slab.h>
> +#include <linux/poll.h>
> #include <linux/mutex.h>
> #include <linux/usb.h>
> #include <linux/usb/tmc.h>
> @@ -1193,6 +1194,27 @@ static int usbtmc_fasync(int fd, struct file *file, int on)
> return fasync_helper(fd, file, on, &data->fasync);
> }
>
> +static unsigned int usbtmc_poll(struct file *file, poll_table *wait)
> +{
> + struct usbtmc_device_data *data = file->private_data;
> + unsigned int mask = 0;
Redundant assignment.
> +
> + mutex_lock(&data->io_mutex);
> +
> + if (data->zombie) {
> + mask = POLLHUP | POLLERR;
> + goto no_poll;
> + }
> +
> + poll_wait(file, &data->waitq, wait);
> +
> + mask = (atomic_read(&data->srq_asserted)) ? POLLIN | POLLRDNORM : 0;
> +
> +no_poll:
> + mutex_unlock(&data->io_mutex);
> + return mask;
> +}
> +
> static const struct file_operations fops = {
> .owner = THIS_MODULE,
> .read = usbtmc_read,
> @@ -1201,6 +1223,7 @@ static const struct file_operations fops = {
> .release = usbtmc_release,
> .unlocked_ioctl = usbtmc_ioctl,
> .fasync = usbtmc_fasync,
> + .poll = usbtmc_poll,
> .llseek = default_llseek,
> };
>
> --
> 2.5.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-11 12:20 +0100 |
| Subject | [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. |
| Message-ID | <qtBBw-23F-9@gated-at.bofh.it> |
| In reply to | #1267106 |
Background:
When performing a read on an instrument that is executing a function
that runs longer than the USB timeout the instrument may hang and require
a device reset to recover. The READ_STATUS_BYTE operation always returns
even when the instrument is busy permitting to poll for the appropriate
condition. This capability is refered to in instrument application notes
on synchronizing acquisitions for other platforms.
Signed-off-by: Dave Penkler <dpenkler@gmail.com>
---
drivers/usb/class/usbtmc.c | 223 +++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/usb/tmc.h | 2 +
2 files changed, 225 insertions(+)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7a11a82..c1593e7 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -87,6 +87,20 @@ struct usbtmc_device_data {
u8 bTag_last_write; /* needed for abort */
u8 bTag_last_read; /* needed for abort */
+
+ /* data for interrupt in endpoint handling */
+ u8 bNotify1;
+ u8 bNotify2;
+ u16 ifnum;
+ u8 iin_bTag;
+ u8 *iin_buffer;
+ atomic_t iin_data_valid;
+ unsigned int iin_ep;
+ int iin_ep_present;
+ int iin_interval;
+ struct urb *iin_urb;
+ u16 iin_wMaxPacketSize;
+
u8 rigol_quirk;
/* attributes from the USB TMC spec for this device */
@@ -99,6 +113,7 @@ struct usbtmc_device_data {
struct usbtmc_dev_capabilities capabilities;
struct kref kref;
struct mutex io_mutex; /* only one i/o function running at a time */
+ wait_queue_head_t waitq;
};
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
@@ -373,6 +388,91 @@ exit:
return rv;
}
+static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
+ unsigned long arg)
+{
+ u8 *buffer;
+ struct device *dev;
+ int rv;
+ u8 tag, stb;
+
+ dev = &data->intf->dev;
+
+ dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
+ data->iin_ep_present);
+
+ buffer = kmalloc(8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+
+ atomic_set(&data->iin_data_valid, 0);
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ USBTMC488_REQUEST_READ_STATUS_BYTE,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ data->iin_bTag,
+ data->ifnum,
+ buffer, 0x03, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "stb usb_control_msg returned %d\n", rv);
+ goto exit;
+ }
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "control status returned %x\n",
+ buffer[0]);
+ rv = -EIO;
+ goto exit;
+ }
+
+ if (data->iin_ep_present) {
+
+ rv = wait_event_interruptible_timeout(
+ data->waitq,
+ (atomic_read(&data->iin_data_valid) != 0),
+ USBTMC_TIMEOUT
+ );
+
+ if (rv < 0) {
+ dev_dbg(dev, "wait interrupted %d\n", rv);
+ goto exit;
+ }
+
+ if (rv == 0) {
+ dev_dbg(dev, "wait timed out\n");
+ rv = -ETIME;
+ goto exit;
+ }
+
+ tag = data->bNotify1 & 0x7f;
+
+ if (tag != data->iin_bTag) {
+ dev_err(dev, "expected bTag %x got %x\n",
+ data->iin_bTag, tag);
+ }
+
+ stb = data->bNotify2;
+ } else {
+ stb = buffer[2];
+ }
+
+ rv = copy_to_user((void __user *)arg, &stb, sizeof(stb));
+ if (rv)
+ rv = -EFAULT;
+
+ exit:
+ /* bump interrupt bTag */
+ data->iin_bTag += 1;
+ if (data->iin_bTag > 127)
+ data->iin_bTag = 2;
+
+ kfree(buffer);
+ 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.
@@ -1069,6 +1169,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case USBTMC_IOCTL_ABORT_BULK_IN:
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
+
+ case USBTMC488_IOCTL_READ_STB:
+ retval = usbtmc488_ioctl_read_stb(data, arg);
+ break;
+
}
skip_io_on_zombie:
@@ -1092,6 +1197,69 @@ static struct usb_class_driver usbtmc_class = {
.minor_base = USBTMC_MINOR_BASE,
};
+static void usbtmc_interrupt(struct urb *urb)
+{
+ struct usbtmc_device_data *data = urb->context;
+ int status = urb->status;
+ int rv;
+
+ dev_dbg(&data->intf->dev, "int status: %d len %d\n",
+ status, urb->actual_length);
+
+ switch (status) {
+ case 0: /* SUCCESS */
+
+ if (data->iin_buffer[0] & 0x80) {
+ /* check for valid STB notification */
+ if ((data->iin_buffer[0] & 0x7f) > 1) {
+ data->bNotify1 = data->iin_buffer[0];
+ data->bNotify2 = data->iin_buffer[1];
+ atomic_set(&data->iin_data_valid, 1);
+ wake_up_interruptible(&data->waitq);
+ goto exit;
+ }
+ }
+ dev_warn(&data->intf->dev, "invalid notification: %x\n",
+ data->iin_buffer[0]);
+ break;
+ case -EOVERFLOW:
+ dev_err(&data->intf->dev,
+ "%s - overflow with length %d, actual length is %d\n",
+ __func__, data->iin_wMaxPacketSize, urb->actual_length);
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EILSEQ:
+ case -ETIME:
+ /* urb terminated, clean up */
+ dev_dbg(&data->intf->dev,
+ "%s - urb terminated, status: %d\n",
+ __func__, status);
+ return;
+ default:
+ dev_err(&data->intf->dev,
+ "%s - unknown status received: %d\n",
+ __func__, status);
+ }
+exit:
+ rv = usb_submit_urb(urb, GFP_ATOMIC);
+ if (rv) {
+ dev_err(&data->intf->dev, "%s - usb_submit_urb failed: %d\n",
+ __func__, rv);
+ }
+}
+
+static void usbtmc_free_int(struct usbtmc_device_data *data)
+{
+ if (data->iin_ep_present) {
+ if (data->iin_urb) {
+ usb_kill_urb(data->iin_urb);
+ kfree(data->iin_buffer);
+ usb_free_urb(data->iin_urb);
+ kref_put(&data->kref, usbtmc_delete);
+ }
+ }
+}
static int usbtmc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -1114,6 +1282,8 @@ static int usbtmc_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data);
kref_init(&data->kref);
mutex_init(&data->io_mutex);
+ init_waitqueue_head(&data->waitq);
+ atomic_set(&data->iin_data_valid, 0);
data->zombie = 0;
/* Determine if it is a Rigol or not */
@@ -1134,9 +1304,12 @@ static int usbtmc_probe(struct usb_interface *intf,
data->bTag = 1;
data->TermCharEnabled = 0;
data->TermChar = '\n';
+ /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
+ data->iin_bTag = 2;
/* USBTMC devices have only one setting, so use that */
iface_desc = data->intf->cur_altsetting;
+ data->ifnum = iface_desc->desc.bInterfaceNumber;
/* Find bulk in endpoint */
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
@@ -1161,6 +1334,20 @@ static int usbtmc_probe(struct usb_interface *intf,
break;
}
}
+ /* Find int endpoint */
+ for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
+ endpoint = &iface_desc->endpoint[n].desc;
+
+ if (usb_endpoint_is_int_in(endpoint)) {
+ data->iin_ep_present = 1;
+ data->iin_ep = endpoint->bEndpointAddress;
+ data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
+ data->iin_interval = endpoint->bInterval;
+ dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
+ data->iin_ep);
+ break;
+ }
+ }
retcode = get_capabilities(data);
if (retcode)
@@ -1169,6 +1356,40 @@ static int usbtmc_probe(struct usb_interface *intf,
retcode = sysfs_create_group(&intf->dev.kobj,
&capability_attr_grp);
+
+ if (data->iin_ep_present) {
+ /* allocate int urb */
+ data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!data->iin_urb) {
+ dev_err(&intf->dev, "Failed to allocate int urb\n");
+ goto error_register;
+ }
+
+ /* will reference data in int urb */
+ kref_get(&data->kref);
+
+ /* allocate buffer for interrupt in */
+ data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
+ GFP_KERNEL);
+ if (!data->iin_buffer) {
+ dev_err(&intf->dev, "Failed to allocate int buf\n");
+ goto error_register;
+ }
+
+ /* fill interrupt urb */
+ usb_fill_int_urb(data->iin_urb, data->usb_dev,
+ usb_rcvintpipe(data->usb_dev, data->iin_ep),
+ data->iin_buffer, data->iin_wMaxPacketSize,
+ usbtmc_interrupt,
+ data, data->iin_interval);
+
+ if (usb_submit_urb(data->iin_urb, GFP_KERNEL)) {
+ retcode = -EIO;
+ dev_err(&intf->dev, "Failed to submit iin_urb\n");
+ goto error_register;
+ }
+ }
+
retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
retcode = usb_register_dev(intf, &usbtmc_class);
@@ -1185,6 +1406,7 @@ static int usbtmc_probe(struct usb_interface *intf,
error_register:
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
+ usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete);
return retcode;
}
@@ -1196,6 +1418,7 @@ static void usbtmc_disconnect(struct usb_interface *intf)
dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
data = usb_get_intfdata(intf);
+ usbtmc_free_int(data);
usb_deregister_dev(intf, &usbtmc_class);
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index c045ae1..49060ea 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -30,6 +30,7 @@
#define USBTMC_REQUEST_CHECK_CLEAR_STATUS 6
#define USBTMC_REQUEST_GET_CAPABILITIES 7
#define USBTMC_REQUEST_INDICATOR_PULSE 64
+#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
/* Request values for USBTMC driver's ioctl entry point */
#define USBTMC_IOC_NR 91
@@ -39,5 +40,6 @@
#define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
#define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
#define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
+#define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
#endif
--
2.5.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2015-11-11 20:10 +0100 |
| Subject | Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. |
| Message-ID | <qtIWm-6Rf-33@gated-at.bofh.it> |
| In reply to | #1267111 |
On Wed, Nov 11, 2015 at 1:16 PM, Dave Penkler <dpenkler@gmail.com> wrote:
> Background:
> When performing a read on an instrument that is executing a function
> that runs longer than the USB timeout the instrument may hang and require
> a device reset to recover. The READ_STATUS_BYTE operation always returns
> even when the instrument is busy permitting to poll for the appropriate
> condition. This capability is refered to in instrument application notes
> on synchronizing acquisitions for other platforms.
>
Won't comment precisely by line, but common nitpicks about style:
- added empty lines where no need
- redundant parens
- pieces of code takes whole line when they are quite fit tail of previous one.
And why malloc for 8 bytes?
> Signed-off-by: Dave Penkler <dpenkler@gmail.com>
> ---
> drivers/usb/class/usbtmc.c | 223 +++++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/usb/tmc.h | 2 +
> 2 files changed, 225 insertions(+)
>
> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> index 7a11a82..c1593e7 100644
> --- a/drivers/usb/class/usbtmc.c
> +++ b/drivers/usb/class/usbtmc.c
> @@ -87,6 +87,20 @@ struct usbtmc_device_data {
> u8 bTag_last_write; /* needed for abort */
> u8 bTag_last_read; /* needed for abort */
>
> +
> + /* data for interrupt in endpoint handling */
> + u8 bNotify1;
> + u8 bNotify2;
> + u16 ifnum;
> + u8 iin_bTag;
> + u8 *iin_buffer;
> + atomic_t iin_data_valid;
> + unsigned int iin_ep;
> + int iin_ep_present;
> + int iin_interval;
> + struct urb *iin_urb;
> + u16 iin_wMaxPacketSize;
> +
> u8 rigol_quirk;
>
> /* attributes from the USB TMC spec for this device */
> @@ -99,6 +113,7 @@ struct usbtmc_device_data {
> struct usbtmc_dev_capabilities capabilities;
> struct kref kref;
> struct mutex io_mutex; /* only one i/o function running at a time */
> + wait_queue_head_t waitq;
> };
> #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
>
> @@ -373,6 +388,91 @@ exit:
> return rv;
> }
>
> +static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
> + unsigned long arg)
> +{
> + u8 *buffer;
> + struct device *dev;
> + int rv;
> + u8 tag, stb;
> +
> + dev = &data->intf->dev;
> +
> + dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
> + data->iin_ep_present);
> +
> + buffer = kmalloc(8, GFP_KERNEL);
> + if (!buffer)
> + return -ENOMEM;
> +
> +
> + atomic_set(&data->iin_data_valid, 0);
> +
> + rv = usb_control_msg(data->usb_dev,
> + usb_rcvctrlpipe(data->usb_dev, 0),
> + USBTMC488_REQUEST_READ_STATUS_BYTE,
> + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> + data->iin_bTag,
> + data->ifnum,
> + buffer, 0x03, USBTMC_TIMEOUT);
> +
> + if (rv < 0) {
> + dev_err(dev, "stb usb_control_msg returned %d\n", rv);
> + goto exit;
> + }
> +
> + if (buffer[0] != USBTMC_STATUS_SUCCESS) {
> + dev_err(dev, "control status returned %x\n",
> + buffer[0]);
> + rv = -EIO;
> + goto exit;
> + }
> +
> + if (data->iin_ep_present) {
> +
> + rv = wait_event_interruptible_timeout(
> + data->waitq,
> + (atomic_read(&data->iin_data_valid) != 0),
> + USBTMC_TIMEOUT
> + );
> +
> + if (rv < 0) {
> + dev_dbg(dev, "wait interrupted %d\n", rv);
> + goto exit;
> + }
> +
> + if (rv == 0) {
> + dev_dbg(dev, "wait timed out\n");
> + rv = -ETIME;
> + goto exit;
> + }
> +
> + tag = data->bNotify1 & 0x7f;
> +
> + if (tag != data->iin_bTag) {
> + dev_err(dev, "expected bTag %x got %x\n",
> + data->iin_bTag, tag);
> + }
> +
> + stb = data->bNotify2;
> + } else {
> + stb = buffer[2];
> + }
> +
> + rv = copy_to_user((void __user *)arg, &stb, sizeof(stb));
> + if (rv)
> + rv = -EFAULT;
> +
> + exit:
> + /* bump interrupt bTag */
> + data->iin_bTag += 1;
> + if (data->iin_bTag > 127)
> + data->iin_bTag = 2;
> +
> + kfree(buffer);
> + 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.
> @@ -1069,6 +1169,11 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> case USBTMC_IOCTL_ABORT_BULK_IN:
> retval = usbtmc_ioctl_abort_bulk_in(data);
> break;
> +
> + case USBTMC488_IOCTL_READ_STB:
> + retval = usbtmc488_ioctl_read_stb(data, arg);
> + break;
> +
> }
>
> skip_io_on_zombie:
> @@ -1092,6 +1197,69 @@ static struct usb_class_driver usbtmc_class = {
> .minor_base = USBTMC_MINOR_BASE,
> };
>
> +static void usbtmc_interrupt(struct urb *urb)
> +{
> + struct usbtmc_device_data *data = urb->context;
> + int status = urb->status;
> + int rv;
> +
> + dev_dbg(&data->intf->dev, "int status: %d len %d\n",
> + status, urb->actual_length);
> +
> + switch (status) {
> + case 0: /* SUCCESS */
> +
> + if (data->iin_buffer[0] & 0x80) {
> + /* check for valid STB notification */
> + if ((data->iin_buffer[0] & 0x7f) > 1) {
> + data->bNotify1 = data->iin_buffer[0];
> + data->bNotify2 = data->iin_buffer[1];
> + atomic_set(&data->iin_data_valid, 1);
> + wake_up_interruptible(&data->waitq);
> + goto exit;
> + }
> + }
> + dev_warn(&data->intf->dev, "invalid notification: %x\n",
> + data->iin_buffer[0]);
> + break;
> + case -EOVERFLOW:
> + dev_err(&data->intf->dev,
> + "%s - overflow with length %d, actual length is %d\n",
> + __func__, data->iin_wMaxPacketSize, urb->actual_length);
> + case -ECONNRESET:
> + case -ENOENT:
> + case -ESHUTDOWN:
> + case -EILSEQ:
> + case -ETIME:
> + /* urb terminated, clean up */
> + dev_dbg(&data->intf->dev,
> + "%s - urb terminated, status: %d\n",
> + __func__, status);
> + return;
> + default:
> + dev_err(&data->intf->dev,
> + "%s - unknown status received: %d\n",
> + __func__, status);
> + }
> +exit:
> + rv = usb_submit_urb(urb, GFP_ATOMIC);
> + if (rv) {
> + dev_err(&data->intf->dev, "%s - usb_submit_urb failed: %d\n",
> + __func__, rv);
> + }
> +}
> +
> +static void usbtmc_free_int(struct usbtmc_device_data *data)
> +{
> + if (data->iin_ep_present) {
> + if (data->iin_urb) {
> + usb_kill_urb(data->iin_urb);
> + kfree(data->iin_buffer);
> + usb_free_urb(data->iin_urb);
> + kref_put(&data->kref, usbtmc_delete);
> + }
> + }
> +}
>
> static int usbtmc_probe(struct usb_interface *intf,
> const struct usb_device_id *id)
> @@ -1114,6 +1282,8 @@ static int usbtmc_probe(struct usb_interface *intf,
> usb_set_intfdata(intf, data);
> kref_init(&data->kref);
> mutex_init(&data->io_mutex);
> + init_waitqueue_head(&data->waitq);
> + atomic_set(&data->iin_data_valid, 0);
> data->zombie = 0;
>
> /* Determine if it is a Rigol or not */
> @@ -1134,9 +1304,12 @@ static int usbtmc_probe(struct usb_interface *intf,
> data->bTag = 1;
> data->TermCharEnabled = 0;
> data->TermChar = '\n';
> + /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
> + data->iin_bTag = 2;
>
> /* USBTMC devices have only one setting, so use that */
> iface_desc = data->intf->cur_altsetting;
> + data->ifnum = iface_desc->desc.bInterfaceNumber;
>
> /* Find bulk in endpoint */
> for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
> @@ -1161,6 +1334,20 @@ static int usbtmc_probe(struct usb_interface *intf,
> break;
> }
> }
> + /* Find int endpoint */
> + for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
> + endpoint = &iface_desc->endpoint[n].desc;
> +
> + if (usb_endpoint_is_int_in(endpoint)) {
> + data->iin_ep_present = 1;
> + data->iin_ep = endpoint->bEndpointAddress;
> + data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
> + data->iin_interval = endpoint->bInterval;
> + dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
> + data->iin_ep);
> + break;
> + }
> + }
>
> retcode = get_capabilities(data);
> if (retcode)
> @@ -1169,6 +1356,40 @@ static int usbtmc_probe(struct usb_interface *intf,
> retcode = sysfs_create_group(&intf->dev.kobj,
> &capability_attr_grp);
>
> +
> + if (data->iin_ep_present) {
> + /* allocate int urb */
> + data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
> + if (!data->iin_urb) {
> + dev_err(&intf->dev, "Failed to allocate int urb\n");
> + goto error_register;
> + }
> +
> + /* will reference data in int urb */
> + kref_get(&data->kref);
> +
> + /* allocate buffer for interrupt in */
> + data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
> + GFP_KERNEL);
> + if (!data->iin_buffer) {
> + dev_err(&intf->dev, "Failed to allocate int buf\n");
> + goto error_register;
> + }
> +
> + /* fill interrupt urb */
> + usb_fill_int_urb(data->iin_urb, data->usb_dev,
> + usb_rcvintpipe(data->usb_dev, data->iin_ep),
> + data->iin_buffer, data->iin_wMaxPacketSize,
> + usbtmc_interrupt,
> + data, data->iin_interval);
> +
> + if (usb_submit_urb(data->iin_urb, GFP_KERNEL)) {
> + retcode = -EIO;
> + dev_err(&intf->dev, "Failed to submit iin_urb\n");
> + goto error_register;
> + }
> + }
> +
> retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
>
> retcode = usb_register_dev(intf, &usbtmc_class);
> @@ -1185,6 +1406,7 @@ static int usbtmc_probe(struct usb_interface *intf,
> error_register:
> sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
> sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
> + usbtmc_free_int(data);
> kref_put(&data->kref, usbtmc_delete);
> return retcode;
> }
> @@ -1196,6 +1418,7 @@ static void usbtmc_disconnect(struct usb_interface *intf)
> dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
>
> data = usb_get_intfdata(intf);
> + usbtmc_free_int(data);
> usb_deregister_dev(intf, &usbtmc_class);
> sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
> sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
> diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
> index c045ae1..49060ea 100644
> --- a/include/uapi/linux/usb/tmc.h
> +++ b/include/uapi/linux/usb/tmc.h
> @@ -30,6 +30,7 @@
> #define USBTMC_REQUEST_CHECK_CLEAR_STATUS 6
> #define USBTMC_REQUEST_GET_CAPABILITIES 7
> #define USBTMC_REQUEST_INDICATOR_PULSE 64
> +#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
>
> /* Request values for USBTMC driver's ioctl entry point */
> #define USBTMC_IOC_NR 91
> @@ -39,5 +40,6 @@
> #define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
> #define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
> #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
> +#define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
>
> #endif
> --
> 2.5.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> |
|---|---|
| Date | 2015-11-11 20:50 +0100 |
| Subject | Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. |
| Message-ID | <qtJz4-75S-25@gated-at.bofh.it> |
| In reply to | #1267396 |
Hello.
On 11/11/2015 10:03 PM, Andy Shevchenko wrote:
>> Background:
>> When performing a read on an instrument that is executing a function
>> that runs longer than the USB timeout the instrument may hang and require
>> a device reset to recover. The READ_STATUS_BYTE operation always returns
>> even when the instrument is busy permitting to poll for the appropriate
>> condition. This capability is refered to in instrument application notes
Referred.
>> on synchronizing acquisitions for other platforms.
>
> Won't comment precisely by line, but common nitpicks about style:
> - added empty lines where no need
> - redundant parens
> - pieces of code takes whole line when they are quite fit tail of previous one.
>
> And why malloc for 8 bytes?
To be able to do DMA with this buffer, apparently.
>> Signed-off-by: Dave Penkler <dpenkler@gmail.com>
[patch skipped]
It's a good tone to skip the parts you're not commenting on, so others
wouldn't have to scroll in vain.
WBR, Sergei
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2015-11-11 21:00 +0100 |
| Subject | Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. |
| Message-ID | <qtJIJ-79T-3@gated-at.bofh.it> |
| In reply to | #1267417 |
On Wed, Nov 11, 2015 at 9:48 PM, Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> wrote: > On 11/11/2015 10:03 PM, Andy Shevchenko wrote: >> Won't comment precisely by line, but common nitpicks about style: >> - added empty lines where no need >> - redundant parens >> - pieces of code takes whole line when they are quite fit tail of >> previous one. >> >> And why malloc for 8 bytes? > It's a good tone to skip the parts you're not commenting on, so others > wouldn't have to scroll in vain. Isn't obvious from my comment that no scroll is needed? -- With Best Regards, Andy Shevchenko -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
|---|---|
| Date | 2015-11-11 22:10 +0100 |
| Subject | Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. |
| Message-ID | <qtKOt-84p-3@gated-at.bofh.it> |
| In reply to | #1267396 |
On Wed, Nov 11, 2015 at 09:03:14PM +0200, Andy Shevchenko wrote: > On Wed, Nov 11, 2015 at 1:16 PM, Dave Penkler <dpenkler@gmail.com> wrote: > > Background: > > When performing a read on an instrument that is executing a function > > that runs longer than the USB timeout the instrument may hang and require > > a device reset to recover. The READ_STATUS_BYTE operation always returns > > even when the instrument is busy permitting to poll for the appropriate > > condition. This capability is refered to in instrument application notes > > on synchronizing acquisitions for other platforms. > > > > Won't comment precisely by line, but common nitpicks about style: > - added empty lines where no need > - redundant parens > - pieces of code takes whole line when they are quite fit tail of previous one. > > And why malloc for 8 bytes? That's a requirement of the USB stack, any data you send on it has to be malloced. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2015-11-12 10:50 +0100 |
| Subject | Re: [PATCH v3 1/5] Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation. |
| Message-ID | <qtWFY-7bs-23@gated-at.bofh.it> |
| In reply to | #1267451 |
On Thu, Nov 12, 2015 at 11:07 AM, dave penkler <dpenkler@gmail.com> wrote: > Thanks for your comments, I will resubmit taking into account all > suggestions. > >> > - redundant parens Example 1. + (atomic_read(&data->iin_data_valid) != 0), >> > - pieces of code takes whole line when they are quite fit tail of >> > previous one. >> > > > > I have endeavoured to follow the coding style of the original driver and > stick to the kernel coding-style guidelines. > Please point to the specific locations where I have failed to do so. Example 1. + dev_err(dev, "control status returned %x\n", + buffer[0]); example 2. + USBTMC_TIMEOUT + ); -- With Best Regards, Andy Shevchenko -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-11 12:20 +0100 |
| Subject | [PATCH v3 2/5] Add support for USBTMC USB488 SRQ notification with fasync |
| Message-ID | <qtBBw-23F-13@gated-at.bofh.it> |
| In reply to | #1267106 |
Background:
By configuring an instrument's event status register various conditions
can be reported via an SRQ notification. This complements the synchronous
polling approach using the READ_STATUS_BYTE ioctl with an asynchronous
notification.
Signed-off-by: Dave Penkler <dpenkler@gmail.com>
---
drivers/usb/class/usbtmc.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index c1593e7..2239cd0 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -100,6 +100,7 @@ struct usbtmc_device_data {
int iin_interval;
struct urb *iin_urb;
u16 iin_wMaxPacketSize;
+ atomic_t srq_asserted;
u8 rigol_quirk;
@@ -114,6 +115,7 @@ struct usbtmc_device_data {
struct kref kref;
struct mutex io_mutex; /* only one i/o function running at a time */
wait_queue_head_t waitq;
+ struct fasync_struct *fasync;
};
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
@@ -408,6 +410,9 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
atomic_set(&data->iin_data_valid, 0);
+ /* must issue read_stb before using poll or select */
+ atomic_set(&data->srq_asserted, 0);
+
rv = usb_control_msg(data->usb_dev,
usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC488_REQUEST_READ_STATUS_BYTE,
@@ -1181,6 +1186,13 @@ skip_io_on_zombie:
return retval;
}
+static int usbtmc_fasync(int fd, struct file *file, int on)
+{
+ struct usbtmc_device_data *data = file->private_data;
+
+ return fasync_helper(fd, file, on, &data->fasync);
+}
+
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = usbtmc_read,
@@ -1188,6 +1200,7 @@ static const struct file_operations fops = {
.open = usbtmc_open,
.release = usbtmc_release,
.unlocked_ioctl = usbtmc_ioctl,
+ .fasync = usbtmc_fasync,
.llseek = default_llseek,
};
@@ -1218,6 +1231,16 @@ static void usbtmc_interrupt(struct urb *urb)
wake_up_interruptible(&data->waitq);
goto exit;
}
+ /* check for SRQ notification */
+ if ((data->iin_buffer[0] & 0x7f) == 1) {
+ if (data->fasync)
+ kill_fasync(&data->fasync,
+ SIGIO, POLL_IN);
+
+ atomic_set(&data->srq_asserted, 1);
+ wake_up_interruptible(&data->waitq);
+ goto exit;
+ }
}
dev_warn(&data->intf->dev, "invalid notification: %x\n",
data->iin_buffer[0]);
@@ -1284,6 +1307,7 @@ static int usbtmc_probe(struct usb_interface *intf,
mutex_init(&data->io_mutex);
init_waitqueue_head(&data->waitq);
atomic_set(&data->iin_data_valid, 0);
+ atomic_set(&data->srq_asserted, 0);
data->zombie = 0;
/* Determine if it is a Rigol or not */
--
2.5.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-11 12:30 +0100 |
| Subject | [PATCH v3 4/5] Add ioctl to retrieve USBTMC-USB488 capabilities |
| Message-ID | <qtBLb-27c-7@gated-at.bofh.it> |
| In reply to | #1267106 |
This is a convenience function to obtain an instrument's capabilities
from its file descriptor without having to access sysfs from the user
program.
Signed-off-by: Dave Penkler <dpenkler@gmail.com>
---
drivers/usb/class/usbtmc.c | 12 ++++++++++++
include/uapi/linux/usb/tmc.h | 21 ++++++++++++++++++---
2 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index bb9a6ab..deca4b5 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -103,6 +103,9 @@ struct usbtmc_device_data {
u16 iin_wMaxPacketSize;
atomic_t srq_asserted;
+ /* coalesced usb488_caps from usbtmc_dev_capabilities */
+ u8 usb488_caps;
+
u8 rigol_quirk;
/* attributes from the USB TMC spec for this device */
@@ -1001,6 +1004,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
data->capabilities.device_capabilities = buffer[5];
data->capabilities.usb488_interface_capabilities = buffer[14];
data->capabilities.usb488_device_capabilities = buffer[15];
+ data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4);
rv = 0;
err_out:
@@ -1176,6 +1180,14 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
+ case USBTMC488_IOCTL_GET_CAPS:
+ retval = copy_to_user((void __user *)arg,
+ &data->usb488_caps,
+ sizeof(data->usb488_caps));
+ if (retval)
+ retval = -EFAULT;
+ break;
+
case USBTMC488_IOCTL_READ_STB:
retval = usbtmc488_ioctl_read_stb(data, arg);
break;
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 49060ea..2606664 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -2,12 +2,14 @@
* Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
* Copyright (C) 2008 Novell, Inc.
* Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2015 Dave Penkler <dpenkler@gmail.com>
*
* This file holds USB constants defined by the USB Device Class
- * Definition for Test and Measurement devices published by the USB-IF.
+ * and USB488 Subclass Definitions for Test and Measurement devices
+ * published by the USB-IF.
*
- * It also has the ioctl definitions for the usbtmc kernel driver that
- * userspace needs to know about.
+ * It also has the ioctl and capability definitions for the
+ * usbtmc kernel driver that userspace needs to know about.
*/
#ifndef __LINUX_USB_TMC_H
@@ -40,6 +42,19 @@
#define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
#define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
#define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
+#define USBTMC488_IOCTL_GET_CAPS _IO(USBTMC_IOC_NR, 17)
#define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
+/* Driver encoded usb488 capabilities */
+#define USBTMC488_CAPABILITY_TRIGGER 1
+#define USBTMC488_CAPABILITY_SIMPLE 2
+#define USBTMC488_CAPABILITY_REN_CONTROL 2
+#define USBTMC488_CAPABILITY_GOTO_LOCAL 2
+#define USBTMC488_CAPABILITY_LOCAL_LOCKOUT 2
+#define USBTMC488_CAPABILITY_488_DOT_2 4
+#define USBTMC488_CAPABILITY_DT1 16
+#define USBTMC488_CAPABILITY_RL1 32
+#define USBTMC488_CAPABILITY_SR1 64
+#define USBTMC488_CAPABILITY_FULL_SCPI 128
+
#endif
--
2.5.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2015-11-11 20:40 +0100 |
| Subject | Re: [PATCH v3 4/5] Add ioctl to retrieve USBTMC-USB488 capabilities |
| Message-ID | <qtJpo-71V-19@gated-at.bofh.it> |
| In reply to | #1267113 |
On Wed, Nov 11, 2015 at 1:20 PM, Dave Penkler <dpenkler@gmail.com> wrote:
> This is a convenience function to obtain an instrument's capabilities
> from its file descriptor without having to access sysfs from the user
> program.
>
> Signed-off-by: Dave Penkler <dpenkler@gmail.com>
> ---
> drivers/usb/class/usbtmc.c | 12 ++++++++++++
> include/uapi/linux/usb/tmc.h | 21 ++++++++++++++++++---
> 2 files changed, 30 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> index bb9a6ab..deca4b5 100644
> --- a/drivers/usb/class/usbtmc.c
> +++ b/drivers/usb/class/usbtmc.c
> @@ -103,6 +103,9 @@ struct usbtmc_device_data {
> u16 iin_wMaxPacketSize;
> atomic_t srq_asserted;
>
> + /* coalesced usb488_caps from usbtmc_dev_capabilities */
> + u8 usb488_caps;
> +
> u8 rigol_quirk;
>
> /* attributes from the USB TMC spec for this device */
> @@ -1001,6 +1004,7 @@ static int get_capabilities(struct usbtmc_device_data *data)
> data->capabilities.device_capabilities = buffer[5];
> data->capabilities.usb488_interface_capabilities = buffer[14];
> data->capabilities.usb488_device_capabilities = buffer[15];
> + data->usb488_caps = (buffer[14] & 0x07) | ((buffer[15] & 0x0f) << 4);
> rv = 0;
>
> err_out:
> @@ -1176,6 +1180,14 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> retval = usbtmc_ioctl_abort_bulk_in(data);
> break;
>
> + case USBTMC488_IOCTL_GET_CAPS:
> + retval = copy_to_user((void __user *)arg,
> + &data->usb488_caps,
> + sizeof(data->usb488_caps));
> + if (retval)
> + retval = -EFAULT;
> + break;
> +
> case USBTMC488_IOCTL_READ_STB:
> retval = usbtmc488_ioctl_read_stb(data, arg);
> break;
> diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
> index 49060ea..2606664 100644
> --- a/include/uapi/linux/usb/tmc.h
> +++ b/include/uapi/linux/usb/tmc.h
> @@ -2,12 +2,14 @@
> * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
> * Copyright (C) 2008 Novell, Inc.
> * Copyright (C) 2008 Greg Kroah-Hartman <gregkh@suse.de>
> + * Copyright (C) 2015 Dave Penkler <dpenkler@gmail.com>
> *
> * This file holds USB constants defined by the USB Device Class
> - * Definition for Test and Measurement devices published by the USB-IF.
> + * and USB488 Subclass Definitions for Test and Measurement devices
> + * published by the USB-IF.
> *
> - * It also has the ioctl definitions for the usbtmc kernel driver that
> - * userspace needs to know about.
> + * It also has the ioctl and capability definitions for the
> + * usbtmc kernel driver that userspace needs to know about.
Do not see what's changed here.
> */
>
> #ifndef __LINUX_USB_TMC_H
> @@ -40,6 +42,19 @@
> #define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
> #define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
> #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
> +#define USBTMC488_IOCTL_GET_CAPS _IO(USBTMC_IOC_NR, 17)
> #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
>
> +/* Driver encoded usb488 capabilities */
> +#define USBTMC488_CAPABILITY_TRIGGER 1
> +#define USBTMC488_CAPABILITY_SIMPLE 2
> +#define USBTMC488_CAPABILITY_REN_CONTROL 2
> +#define USBTMC488_CAPABILITY_GOTO_LOCAL 2
> +#define USBTMC488_CAPABILITY_LOCAL_LOCKOUT 2
> +#define USBTMC488_CAPABILITY_488_DOT_2 4
> +#define USBTMC488_CAPABILITY_DT1 16
> +#define USBTMC488_CAPABILITY_RL1 32
> +#define USBTMC488_CAPABILITY_SR1 64
> +#define USBTMC488_CAPABILITY_FULL_SCPI 128
> +
> #endif
> --
> 2.5.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-11 12:30 +0100 |
| Subject | [PATCH v3 5/5] Add ioctls to enable and disable local controls on an instrument |
| Message-ID | <qtBLb-27c-11@gated-at.bofh.it> |
| In reply to | #1267106 |
These ioctls provide support for the USBTMC-USB488 control requests
for REN_CONTROL, GO_TO_LOCAL and LOCAL_LOCKOUT
Signed-off-by: Dave Penkler <dpenkler@gmail.com>
---
drivers/usb/class/usbtmc.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/usb/tmc.h | 9 +++++-
2 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index deca4b5..646bfff 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -482,6 +482,68 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
return rv;
}
+static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
+ unsigned long arg,
+ unsigned int cmd)
+{
+ u8 *buffer;
+ struct device *dev;
+ int rv;
+ unsigned int val;
+ u16 wValue;
+
+ dev = &data->intf->dev;
+
+ if (0 == (data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE))
+ return -EINVAL;
+
+ buffer = kmalloc(8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+
+ if (cmd == USBTMC488_REQUEST_REN_CONTROL) {
+ rv = copy_from_user(&val, (void __user *)arg, sizeof(val));
+ if (rv) {
+ rv = -EFAULT;
+ goto exit;
+ }
+ wValue = (val) ? 1 : 0;
+ } else {
+ wValue = 0;
+ }
+
+ rv = usb_control_msg(data->usb_dev,
+ usb_rcvctrlpipe(data->usb_dev, 0),
+ cmd,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ wValue,
+ data->ifnum,
+ buffer, 0x01, USBTMC_TIMEOUT);
+
+ if (rv < 0) {
+ dev_err(dev, "simple usb_control_msg failed %d\n", rv);
+ goto exit;
+ } else if (rv != 1) {
+ dev_warn(dev, "simple usb_control_msg returned %d\n", rv);
+ rv = -EIO;
+ goto exit;
+ }
+
+ if (buffer[0] != USBTMC_STATUS_SUCCESS) {
+ dev_err(dev, "simple control status returned %x\n",
+ buffer[0]);
+ rv = -EIO;
+ goto exit;
+ } else {
+ rv = 0;
+ }
+
+ exit:
+ kfree(buffer);
+ 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.
@@ -1192,6 +1254,20 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = usbtmc488_ioctl_read_stb(data, arg);
break;
+ case USBTMC488_IOCTL_REN_CONTROL:
+ retval = usbtmc488_ioctl_simple(data, arg,
+ USBTMC488_REQUEST_REN_CONTROL);
+ break;
+
+ case USBTMC488_IOCTL_GOTO_LOCAL:
+ retval = usbtmc488_ioctl_simple(data, arg,
+ USBTMC488_REQUEST_GOTO_LOCAL);
+ break;
+
+ case USBTMC488_IOCTL_LOCAL_LOCKOUT:
+ retval = usbtmc488_ioctl_simple(data, arg,
+ USBTMC488_REQUEST_LOCAL_LOCKOUT);
+ break;
}
skip_io_on_zombie:
diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
index 2606664..fe9663f 100644
--- a/include/uapi/linux/usb/tmc.h
+++ b/include/uapi/linux/usb/tmc.h
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
* Copyright (C) 2008 Novell, Inc.
@@ -32,7 +33,10 @@
#define USBTMC_REQUEST_CHECK_CLEAR_STATUS 6
#define USBTMC_REQUEST_GET_CAPABILITIES 7
#define USBTMC_REQUEST_INDICATOR_PULSE 64
-#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
+#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
+#define USBTMC488_REQUEST_REN_CONTROL 160
+#define USBTMC488_REQUEST_GOTO_LOCAL 161
+#define USBTMC488_REQUEST_LOCAL_LOCKOUT 162
/* Request values for USBTMC driver's ioctl entry point */
#define USBTMC_IOC_NR 91
@@ -44,6 +48,9 @@
#define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
#define USBTMC488_IOCTL_GET_CAPS _IO(USBTMC_IOC_NR, 17)
#define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
+#define USBTMC488_IOCTL_REN_CONTROL _IOW(USBTMC_IOC_NR, 19, unsigned char)
+#define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
+#define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21)
/* Driver encoded usb488 capabilities */
#define USBTMC488_CAPABILITY_TRIGGER 1
--
2.5.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Andy Shevchenko <andy.shevchenko@gmail.com> |
|---|---|
| Date | 2015-11-11 20:40 +0100 |
| Subject | Re: [PATCH v3 5/5] Add ioctls to enable and disable local controls on an instrument |
| Message-ID | <qtJpp-71V-29@gated-at.bofh.it> |
| In reply to | #1267115 |
On Wed, Nov 11, 2015 at 1:21 PM, Dave Penkler <dpenkler@gmail.com> wrote:
> These ioctls provide support for the USBTMC-USB488 control requests
> for REN_CONTROL, GO_TO_LOCAL and LOCAL_LOCKOUT
>
> Signed-off-by: Dave Penkler <dpenkler@gmail.com>
> ---
> drivers/usb/class/usbtmc.c | 76 ++++++++++++++++++++++++++++++++++++++++++++
> include/uapi/linux/usb/tmc.h | 9 +++++-
> 2 files changed, 84 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
> index deca4b5..646bfff 100644
> --- a/drivers/usb/class/usbtmc.c
> +++ b/drivers/usb/class/usbtmc.c
> @@ -482,6 +482,68 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
> return rv;
> }
>
> +static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
> + unsigned long arg,
> + unsigned int cmd)
> +{
> + u8 *buffer;
> + struct device *dev;
> + int rv;
> + unsigned int val;
> + u16 wValue;
> +
> + dev = &data->intf->dev;
> +
> + if (0 == (data->usb488_caps & USBTMC488_CAPABILITY_SIMPLE))
Other way around.
> + return -EINVAL;
> +
> + buffer = kmalloc(8, GFP_KERNEL);
> + if (!buffer)
> + return -ENOMEM;
> +
Redundant empty line.
> +
> + if (cmd == USBTMC488_REQUEST_REN_CONTROL) {
> + rv = copy_from_user(&val, (void __user *)arg, sizeof(val));
> + if (rv) {
> + rv = -EFAULT;
> + goto exit;
> + }
> + wValue = (val) ? 1 : 0;
!!val;
> + } else {
> + wValue = 0;
> + }
> +
> + rv = usb_control_msg(data->usb_dev,
> + usb_rcvctrlpipe(data->usb_dev, 0),
> + cmd,
> + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
> + wValue,
> + data->ifnum,
> + buffer, 0x01, USBTMC_TIMEOUT);
> +
> + if (rv < 0) {
> + dev_err(dev, "simple usb_control_msg failed %d\n", rv);
> + goto exit;
> + } else if (rv != 1) {
> + dev_warn(dev, "simple usb_control_msg returned %d\n", rv);
> + rv = -EIO;
> + goto exit;
> + }
> +
> + if (buffer[0] != USBTMC_STATUS_SUCCESS) {
> + dev_err(dev, "simple control status returned %x\n",
> + buffer[0]);
> + rv = -EIO;
> + goto exit;
> + } else {
> + rv = 0;
> + }
> +
> + exit:
> + kfree(buffer);
> + 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.
> @@ -1192,6 +1254,20 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> retval = usbtmc488_ioctl_read_stb(data, arg);
> break;
>
> + case USBTMC488_IOCTL_REN_CONTROL:
> + retval = usbtmc488_ioctl_simple(data, arg,
> + USBTMC488_REQUEST_REN_CONTROL);
> + break;
> +
> + case USBTMC488_IOCTL_GOTO_LOCAL:
> + retval = usbtmc488_ioctl_simple(data, arg,
> + USBTMC488_REQUEST_GOTO_LOCAL);
> + break;
> +
> + case USBTMC488_IOCTL_LOCAL_LOCKOUT:
> + retval = usbtmc488_ioctl_simple(data, arg,
> + USBTMC488_REQUEST_LOCAL_LOCKOUT);
> + break;
> }
>
> skip_io_on_zombie:
> diff --git a/include/uapi/linux/usb/tmc.h b/include/uapi/linux/usb/tmc.h
> index 2606664..fe9663f 100644
> --- a/include/uapi/linux/usb/tmc.h
> +++ b/include/uapi/linux/usb/tmc.h
> @@ -1,3 +1,4 @@
> +
> /*
> * Copyright (C) 2007 Stefan Kopp, Gechingen, Germany
> * Copyright (C) 2008 Novell, Inc.
> @@ -32,7 +33,10 @@
> #define USBTMC_REQUEST_CHECK_CLEAR_STATUS 6
> #define USBTMC_REQUEST_GET_CAPABILITIES 7
> #define USBTMC_REQUEST_INDICATOR_PULSE 64
> -#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
> +#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
> +#define USBTMC488_REQUEST_REN_CONTROL 160
> +#define USBTMC488_REQUEST_GOTO_LOCAL 161
> +#define USBTMC488_REQUEST_LOCAL_LOCKOUT 162
>
> /* Request values for USBTMC driver's ioctl entry point */
> #define USBTMC_IOC_NR 91
> @@ -44,6 +48,9 @@
> #define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
> #define USBTMC488_IOCTL_GET_CAPS _IO(USBTMC_IOC_NR, 17)
> #define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
> +#define USBTMC488_IOCTL_REN_CONTROL _IOW(USBTMC_IOC_NR, 19, unsigned char)
> +#define USBTMC488_IOCTL_GOTO_LOCAL _IO(USBTMC_IOC_NR, 20)
> +#define USBTMC488_IOCTL_LOCAL_LOCKOUT _IO(USBTMC_IOC_NR, 21)
>
> /* Driver encoded usb488 capabilities */
> #define USBTMC488_CAPABILITY_TRIGGER 1
> --
> 2.5.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
With Best Regards,
Andy Shevchenko
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Dave Penkler <dpenkler@gmail.com> |
|---|---|
| Date | 2015-11-13 10:10 +0100 |
| Subject | Re: [PATCH v3 5/5] Add ioctls to enable and disable local controls on an instrument |
| Message-ID | <quiwN-4sk-11@gated-at.bofh.it> |
| In reply to | #1267411 |
Hi Andy, On Wed, Nov 11, 2015 at 09:36:41PM +0200, Andy Shevchenko wrote: > On Wed, Nov 11, 2015 at 1:21 PM, Dave Penkler <dpenkler@gmail.com> wrote: > > These ioctls provide support for the USBTMC-USB488 control requests > > for REN_CONTROL, GO_TO_LOCAL and LOCAL_LOCKOUT snip > > + goto exit; > > + } > > + wValue = (val) ? 1 : 0; > > !!val; I checked by compiling both variants - the compiler emits identical code for both so I prefer to keep the original as it is more obvious for maintainers reading the code. regards, -Dave -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web