aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/class
diff options
context:
space:
mode:
authorDave Penkler <dpenkler@gmail.com>2016-01-27 13:09:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-03 16:54:06 -0500
commitdbf3e7f654c0f06a932b8fcafac78de9d0b81d68 (patch)
treefb6c595d04dc1893afdc164b870d41a9776e257f /drivers/usb/class
parent21619792d1eca7e772ca190ba68588e57f29595b (diff)
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>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r--drivers/usb/class/usbtmc.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 7a11a8263171..c2eb6fe9f4c8 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -87,6 +87,19 @@ struct usbtmc_device_data {
87 u8 bTag_last_write; /* needed for abort */ 87 u8 bTag_last_write; /* needed for abort */
88 u8 bTag_last_read; /* needed for abort */ 88 u8 bTag_last_read; /* needed for abort */
89 89
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
90 u8 rigol_quirk; 103 u8 rigol_quirk;
91 104
92 /* attributes from the USB TMC spec for this device */ 105 /* attributes from the USB TMC spec for this device */
@@ -99,6 +112,7 @@ struct usbtmc_device_data {
99 struct usbtmc_dev_capabilities capabilities; 112 struct usbtmc_dev_capabilities capabilities;
100 struct kref kref; 113 struct kref kref;
101 struct mutex io_mutex; /* only one i/o function running at a time */ 114 struct mutex io_mutex; /* only one i/o function running at a time */
115 wait_queue_head_t waitq;
102}; 116};
103#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref) 117#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
104 118
@@ -373,6 +387,84 @@ exit:
373 return rv; 387 return rv;
374} 388}
375 389
390static 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
376/* 468/*
377 * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint. 469 * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-IN endpoint.
378 * @transfer_size: number of bytes to request from the device. 470 * @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)
1069 case USBTMC_IOCTL_ABORT_BULK_IN: 1161 case USBTMC_IOCTL_ABORT_BULK_IN:
1070 retval = usbtmc_ioctl_abort_bulk_in(data); 1162 retval = usbtmc_ioctl_abort_bulk_in(data);
1071 break; 1163 break;
1164
1165 case USBTMC488_IOCTL_READ_STB:
1166 retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg);
1167 break;
1072 } 1168 }
1073 1169
1074skip_io_on_zombie: 1170skip_io_on_zombie:
@@ -1092,6 +1188,57 @@ static struct usb_class_driver usbtmc_class = {
1092 .minor_base = USBTMC_MINOR_BASE, 1188 .minor_base = USBTMC_MINOR_BASE,
1093}; 1189};
1094 1190
1191static 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 }
1227exit:
1228 rv = usb_submit_urb(urb, GFP_ATOMIC);
1229 if (rv)
1230 dev_err(dev, "usb_submit_urb failed: %d\n", rv);
1231}
1232
1233static 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}
1095 1242
1096static int usbtmc_probe(struct usb_interface *intf, 1243static int usbtmc_probe(struct usb_interface *intf,
1097 const struct usb_device_id *id) 1244 const struct usb_device_id *id)
@@ -1114,6 +1261,8 @@ static int usbtmc_probe(struct usb_interface *intf,
1114 usb_set_intfdata(intf, data); 1261 usb_set_intfdata(intf, data);
1115 kref_init(&data->kref); 1262 kref_init(&data->kref);
1116 mutex_init(&data->io_mutex); 1263 mutex_init(&data->io_mutex);
1264 init_waitqueue_head(&data->waitq);
1265 atomic_set(&data->iin_data_valid, 0);
1117 data->zombie = 0; 1266 data->zombie = 0;
1118 1267
1119 /* Determine if it is a Rigol or not */ 1268 /* Determine if it is a Rigol or not */
@@ -1134,9 +1283,12 @@ static int usbtmc_probe(struct usb_interface *intf,
1134 data->bTag = 1; 1283 data->bTag = 1;
1135 data->TermCharEnabled = 0; 1284 data->TermCharEnabled = 0;
1136 data->TermChar = '\n'; 1285 data->TermChar = '\n';
1286 /* 2 <= bTag <= 127 USBTMC-USB488 subclass specification 4.3.1 */
1287 data->iin_bTag = 2;
1137 1288
1138 /* USBTMC devices have only one setting, so use that */ 1289 /* USBTMC devices have only one setting, so use that */
1139 iface_desc = data->intf->cur_altsetting; 1290 iface_desc = data->intf->cur_altsetting;
1291 data->ifnum = iface_desc->desc.bInterfaceNumber;
1140 1292
1141 /* Find bulk in endpoint */ 1293 /* Find bulk in endpoint */
1142 for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) { 1294 for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
@@ -1161,6 +1313,20 @@ static int usbtmc_probe(struct usb_interface *intf,
1161 break; 1313 break;
1162 } 1314 }
1163 } 1315 }
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 }
1164 1330
1165 retcode = get_capabilities(data); 1331 retcode = get_capabilities(data);
1166 if (retcode) 1332 if (retcode)
@@ -1169,6 +1335,39 @@ static int usbtmc_probe(struct usb_interface *intf,
1169 retcode = sysfs_create_group(&intf->dev.kobj, 1335 retcode = sysfs_create_group(&intf->dev.kobj,
1170 &capability_attr_grp); 1336 &capability_attr_grp);
1171 1337
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
1172 retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp); 1371 retcode = sysfs_create_group(&intf->dev.kobj, &data_attr_grp);
1173 1372
1174 retcode = usb_register_dev(intf, &usbtmc_class); 1373 retcode = usb_register_dev(intf, &usbtmc_class);
@@ -1185,6 +1384,7 @@ static int usbtmc_probe(struct usb_interface *intf,
1185error_register: 1384error_register:
1186 sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 1385 sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
1187 sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 1386 sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
1387 usbtmc_free_int(data);
1188 kref_put(&data->kref, usbtmc_delete); 1388 kref_put(&data->kref, usbtmc_delete);
1189 return retcode; 1389 return retcode;
1190} 1390}
@@ -1196,6 +1396,7 @@ static void usbtmc_disconnect(struct usb_interface *intf)
1196 dev_dbg(&intf->dev, "usbtmc_disconnect called\n"); 1396 dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
1197 1397
1198 data = usb_get_intfdata(intf); 1398 data = usb_get_intfdata(intf);
1399 usbtmc_free_int(data);
1199 usb_deregister_dev(intf, &usbtmc_class); 1400 usb_deregister_dev(intf, &usbtmc_class);
1200 sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); 1401 sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
1201 sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); 1402 sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);