Skip to content

Commit dbf3e7f

Browse files
dpenklergregkh
authored andcommitted
Implement an ioctl to support the USMTMC-USB488 READ_STATUS_BYTE operation.
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 referred to in instrument application notes on synchronizing acquisitions for other platforms. Signed-off-by: Dave Penkler <dpenkler@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2161979 commit dbf3e7f

File tree

2 files changed

+203
-0
lines changed

2 files changed

+203
-0
lines changed

drivers/usb/class/usbtmc.c

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ struct usbtmc_device_data {
8787
u8 bTag_last_write; /* needed for abort */
8888
u8 bTag_last_read; /* needed for abort */
8989

90+
/* data for interrupt in endpoint handling */
91+
u8 bNotify1;
92+
u8 bNotify2;
93+
u16 ifnum;
94+
u8 iin_bTag;
95+
u8 *iin_buffer;
96+
atomic_t iin_data_valid;
97+
unsigned int iin_ep;
98+
int iin_ep_present;
99+
int iin_interval;
100+
struct urb *iin_urb;
101+
u16 iin_wMaxPacketSize;
102+
90103
u8 rigol_quirk;
91104

92105
/* attributes from the USB TMC spec for this device */
@@ -99,6 +112,7 @@ struct usbtmc_device_data {
99112
struct usbtmc_dev_capabilities capabilities;
100113
struct kref kref;
101114
struct mutex io_mutex; /* only one i/o function running at a time */
115+
wait_queue_head_t waitq;
102116
};
103117
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
104118

@@ -373,6 +387,84 @@ static int usbtmc_ioctl_abort_bulk_out(struct usbtmc_device_data *data)
373387
return rv;
374388
}
375389

390+
static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
391+
void __user *arg)
392+
{
393+
struct device *dev = &data->intf->dev;
394+
u8 *buffer;
395+
u8 tag;
396+
__u8 stb;
397+
int rv;
398+
399+
dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
400+
data->iin_ep_present);
401+
402+
buffer = kmalloc(8, GFP_KERNEL);
403+
if (!buffer)
404+
return -ENOMEM;
405+
406+
atomic_set(&data->iin_data_valid, 0);
407+
408+
rv = usb_control_msg(data->usb_dev,
409+
usb_rcvctrlpipe(data->usb_dev, 0),
410+
USBTMC488_REQUEST_READ_STATUS_BYTE,
411+
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
412+
data->iin_bTag,
413+
data->ifnum,
414+
buffer, 0x03, USBTMC_TIMEOUT);
415+
if (rv < 0) {
416+
dev_err(dev, "stb usb_control_msg returned %d\n", rv);
417+
goto exit;
418+
}
419+
420+
if (buffer[0] != USBTMC_STATUS_SUCCESS) {
421+
dev_err(dev, "control status returned %x\n", buffer[0]);
422+
rv = -EIO;
423+
goto exit;
424+
}
425+
426+
if (data->iin_ep_present) {
427+
rv = wait_event_interruptible_timeout(
428+
data->waitq,
429+
atomic_read(&data->iin_data_valid) != 0,
430+
USBTMC_TIMEOUT);
431+
if (rv < 0) {
432+
dev_dbg(dev, "wait interrupted %d\n", rv);
433+
goto exit;
434+
}
435+
436+
if (rv == 0) {
437+
dev_dbg(dev, "wait timed out\n");
438+
rv = -ETIME;
439+
goto exit;
440+
}
441+
442+
tag = data->bNotify1 & 0x7f;
443+
if (tag != data->iin_bTag) {
444+
dev_err(dev, "expected bTag %x got %x\n",
445+
data->iin_bTag, tag);
446+
}
447+
448+
stb = data->bNotify2;
449+
} else {
450+
stb = buffer[2];
451+
}
452+
453+
rv = copy_to_user(arg, &stb, sizeof(stb));
454+
if (rv)
455+
rv = -EFAULT;
456+
457+
exit:
458+
/* bump interrupt bTag */
459+
data->iin_bTag += 1;
460+
if (data->iin_bTag > 127)
461+
/* 1 is for SRQ see USBTMC-USB488 subclass spec section 4.3.1 */
462+
data->iin_bTag = 2;
463+
464+
kfree(buffer);
465+
return rv;
466+
}
467+
376468
/*
377469
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint.
378470
* @transfer_size: number of bytes to request from the device.
@@ -1069,6 +1161,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
10691161
case USBTMC_IOCTL_ABORT_BULK_IN:
10701162
retval = usbtmc_ioctl_abort_bulk_in(data);
10711163
break;
1164+
1165+
case USBTMC488_IOCTL_READ_STB:
1166+
retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg);
1167+
break;
10721168
}
10731169

10741170
skip_io_on_zombie:
@@ -1092,6 +1188,57 @@ static struct usb_class_driver usbtmc_class = {
10921188
.minor_base = USBTMC_MINOR_BASE,
10931189
};
10941190

1191+
static void usbtmc_interrupt(struct urb *urb)
1192+
{
1193+
struct usbtmc_device_data *data = urb->context;
1194+
struct device *dev = &data->intf->dev;
1195+
int status = urb->status;
1196+
int rv;
1197+
1198+
dev_dbg(&data->intf->dev, "int status: %d len %d\n",
1199+
status, urb->actual_length);
1200+
1201+
switch (status) {
1202+
case 0: /* SUCCESS */
1203+
/* check for valid STB notification */
1204+
if (data->iin_buffer[0] > 0x81) {
1205+
data->bNotify1 = data->iin_buffer[0];
1206+
data->bNotify2 = data->iin_buffer[1];
1207+
atomic_set(&data->iin_data_valid, 1);
1208+
wake_up_interruptible(&data->waitq);
1209+
goto exit;
1210+
}
1211+
dev_warn(dev, "invalid notification: %x\n", data->iin_buffer[0]);
1212+
break;
1213+
case -EOVERFLOW:
1214+
dev_err(dev, "overflow with length %d, actual length is %d\n",
1215+
data->iin_wMaxPacketSize, urb->actual_length);
1216+
case -ECONNRESET:
1217+
case -ENOENT:
1218+
case -ESHUTDOWN:
1219+
case -EILSEQ:
1220+
case -ETIME:
1221+
/* urb terminated, clean up */
1222+
dev_dbg(dev, "urb terminated, status: %d\n", status);
1223+
return;
1224+
default:
1225+
dev_err(dev, "unknown status received: %d\n", status);
1226+
}
1227+
exit:
1228+
rv = usb_submit_urb(urb, GFP_ATOMIC);
1229+
if (rv)
1230+
dev_err(dev, "usb_submit_urb failed: %d\n", rv);
1231+
}
1232+
1233+
static void usbtmc_free_int(struct usbtmc_device_data *data)
1234+
{
1235+
if (!data->iin_ep_present || !data->iin_urb)
1236+
return;
1237+
usb_kill_urb(data->iin_urb);
1238+
kfree(data->iin_buffer);
1239+
usb_free_urb(data->iin_urb);
1240+
kref_put(&data->kref, usbtmc_delete);
1241+
}
10951242

10961243
static int usbtmc_probe(struct usb_interface *intf,
10971244
const struct usb_device_id *id)
@@ -1114,6 +1261,8 @@ static int usbtmc_probe(struct usb_interface *intf,
11141261
usb_set_intfdata(intf, data);
11151262
kref_init(&data->kref);
11161263
mutex_init(&data->io_mutex);
1264+
init_waitqueue_head(&data->waitq);
1265+
atomic_set(&data->iin_data_valid, 0);
11171266
data->zombie = 0;
11181267

11191268
/* Determine if it is a Rigol or not */
@@ -1134,9 +1283,12 @@ static int usbtmc_probe(struct usb_interface *intf,
11341283
data->bTag = 1;
11351284
data->TermCharEnabled = 0;
11361285
data->TermChar = '\n';
1286+
/* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
1287+
data->iin_bTag = 2;
11371288

11381289
/* USBTMC devices have only one setting, so use that */
11391290
iface_desc = data->intf->cur_altsetting;
1291+
data->ifnum = iface_desc->desc.bInterfaceNumber;
11401292

11411293
/* Find bulk in endpoint */
11421294
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
@@ -1161,6 +1313,20 @@ static int usbtmc_probe(struct usb_interface *intf,
11611313
break;
11621314
}
11631315
}
1316+
/* Find int endpoint */
1317+
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
1318+
endpoint = &iface_desc->endpoint[n].desc;
1319+
1320+
if (usb_endpoint_is_int_in(endpoint)) {
1321+
data->iin_ep_present = 1;
1322+
data->iin_ep = endpoint->bEndpointAddress;
1323+
data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
1324+
data->iin_interval = endpoint->bInterval;
1325+
dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
1326+
data->iin_ep);
1327+
break;
1328+
}
1329+
}
11641330

11651331
retcode = get_capabilities(data);
11661332
if (retcode)
@@ -1169,6 +1335,39 @@ static int usbtmc_probe(struct usb_interface *intf,
11691335
retcode = sysfs_create_group(&intf->dev.kobj,
11701336
&capability_attr_grp);
11711337

1338+
if (data->iin_ep_present) {
1339+
/* allocate int urb */
1340+
data->iin_urb = usb_alloc_urb(0, GFP_KERNEL);
1341+
if (!data->iin_urb) {
1342+
dev_err(&intf->dev, "Failed to allocate int urb\n");
1343+
goto error_register;
1344+
}
1345+
1346+
/* will reference data in int urb */
1347+
kref_get(&data->kref);
1348+
1349+
/* allocate buffer for interrupt in */
1350+
data->iin_buffer = kmalloc(data->iin_wMaxPacketSize,
1351+
GFP_KERNEL);
1352+
if (!data->iin_buffer) {
1353+
dev_err(&intf->dev, "Failed to allocate int buf\n");
1354+
goto error_register;
1355+
}
1356+
1357+
/* fill interrupt urb */
1358+
usb_fill_int_urb(data->iin_urb, data->usb_dev,
1359+
usb_rcvintpipe(data->usb_dev, data->iin_ep),
1360+
data->iin_buffer, data->iin_wMaxPacketSize,
1361+
usbtmc_interrupt,
1362+
data, data->iin_interval);
1363+
1364+
retcode = usb_submit_urb(data->iin_urb, GFP_KERNEL);
1365+
if (retcode) {
1366+
dev_err(&intf->dev, "Failed to submit iin_urb\n");
1367+
goto error_register;
1368+
}
1369+
}
1370+
11721371
retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
11731372

11741373
retcode = usb_register_dev(intf, &usbtmc_class);
@@ -1185,6 +1384,7 @@ static int usbtmc_probe(struct usb_interface *intf,
11851384
error_register:
11861385
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
11871386
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
1387+
usbtmc_free_int(data);
11881388
kref_put(&data->kref, usbtmc_delete);
11891389
return retcode;
11901390
}
@@ -1196,6 +1396,7 @@ static void usbtmc_disconnect(struct usb_interface *intf)
11961396
dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
11971397

11981398
data = usb_get_intfdata(intf);
1399+
usbtmc_free_int(data);
11991400
usb_deregister_dev(intf, &usbtmc_class);
12001401
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
12011402
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);

include/uapi/linux/usb/tmc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define USBTMC_REQUEST_CHECK_CLEAR_STATUS 6
3131
#define USBTMC_REQUEST_GET_CAPABILITIES 7
3232
#define USBTMC_REQUEST_INDICATOR_PULSE 64
33+
#define USBTMC488_REQUEST_READ_STATUS_BYTE 128
3334

3435
/* Request values for USBTMC driver's ioctl entry point */
3536
#define USBTMC_IOC_NR 91
@@ -39,5 +40,6 @@
3940
#define USBTMC_IOCTL_ABORT_BULK_IN _IO(USBTMC_IOC_NR, 4)
4041
#define USBTMC_IOCTL_CLEAR_OUT_HALT _IO(USBTMC_IOC_NR, 6)
4142
#define USBTMC_IOCTL_CLEAR_IN_HALT _IO(USBTMC_IOC_NR, 7)
43+
#define USBTMC488_IOCTL_READ_STB _IOR(USBTMC_IOC_NR, 18, unsigned char)
4244

4345
#endif

0 commit comments

Comments
 (0)