diff options
Diffstat (limited to 'drivers/usb/class/usbtmc.c')
-rw-r--r-- | drivers/usb/class/usbtmc.c | 84 |
1 files changed, 69 insertions, 15 deletions
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index b09a527f7341..333ee02e7b2b 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c | |||
@@ -57,7 +57,9 @@ MODULE_DEVICE_TABLE(usb, usbtmc_devices); | |||
57 | 57 | ||
58 | /* | 58 | /* |
59 | * This structure is the capabilities for the device | 59 | * This structure is the capabilities for the device |
60 | * See section 4.2.1.8 of the USBTMC specification for details. | 60 | * See section 4.2.1.8 of the USBTMC specification, |
61 | * and section 4.2.2 of the USBTMC usb488 subclass | ||
62 | * specification for details. | ||
61 | */ | 63 | */ |
62 | struct usbtmc_dev_capabilities { | 64 | struct usbtmc_dev_capabilities { |
63 | __u8 interface_capabilities; | 65 | __u8 interface_capabilities; |
@@ -86,6 +88,8 @@ struct usbtmc_device_data { | |||
86 | bool TermCharEnabled; | 88 | bool TermCharEnabled; |
87 | bool auto_abort; | 89 | bool auto_abort; |
88 | 90 | ||
91 | bool zombie; /* fd of disconnected device */ | ||
92 | |||
89 | struct usbtmc_dev_capabilities capabilities; | 93 | struct usbtmc_dev_capabilities capabilities; |
90 | struct kref kref; | 94 | struct kref kref; |
91 | struct mutex io_mutex; /* only one i/o function running at a time */ | 95 | struct mutex io_mutex; /* only one i/o function running at a time */ |
@@ -367,13 +371,13 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
367 | { | 371 | { |
368 | struct usbtmc_device_data *data; | 372 | struct usbtmc_device_data *data; |
369 | struct device *dev; | 373 | struct device *dev; |
370 | unsigned long int n_characters; | 374 | u32 n_characters; |
371 | u8 *buffer; | 375 | u8 *buffer; |
372 | int actual; | 376 | int actual; |
373 | int done; | 377 | size_t done; |
374 | int remaining; | 378 | size_t remaining; |
375 | int retval; | 379 | int retval; |
376 | int this_part; | 380 | size_t this_part; |
377 | 381 | ||
378 | /* Get pointer to private data structure */ | 382 | /* Get pointer to private data structure */ |
379 | data = filp->private_data; | 383 | data = filp->private_data; |
@@ -384,6 +388,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
384 | return -ENOMEM; | 388 | return -ENOMEM; |
385 | 389 | ||
386 | mutex_lock(&data->io_mutex); | 390 | mutex_lock(&data->io_mutex); |
391 | if (data->zombie) { | ||
392 | retval = -ENODEV; | ||
393 | goto exit; | ||
394 | } | ||
387 | 395 | ||
388 | remaining = count; | 396 | remaining = count; |
389 | done = 0; | 397 | done = 0; |
@@ -401,10 +409,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
401 | buffer[1] = data->bTag; | 409 | buffer[1] = data->bTag; |
402 | buffer[2] = ~(data->bTag); | 410 | buffer[2] = ~(data->bTag); |
403 | buffer[3] = 0; /* Reserved */ | 411 | buffer[3] = 0; /* Reserved */ |
404 | buffer[4] = (this_part - 12 - 3) & 255; | 412 | buffer[4] = (this_part) & 255; |
405 | buffer[5] = ((this_part - 12 - 3) >> 8) & 255; | 413 | buffer[5] = ((this_part) >> 8) & 255; |
406 | buffer[6] = ((this_part - 12 - 3) >> 16) & 255; | 414 | buffer[6] = ((this_part) >> 16) & 255; |
407 | buffer[7] = ((this_part - 12 - 3) >> 24) & 255; | 415 | buffer[7] = ((this_part) >> 24) & 255; |
408 | buffer[8] = data->TermCharEnabled * 2; | 416 | buffer[8] = data->TermCharEnabled * 2; |
409 | /* Use term character? */ | 417 | /* Use term character? */ |
410 | buffer[9] = data->TermChar; | 418 | buffer[9] = data->TermChar; |
@@ -455,6 +463,22 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
455 | (buffer[6] << 16) + | 463 | (buffer[6] << 16) + |
456 | (buffer[7] << 24); | 464 | (buffer[7] << 24); |
457 | 465 | ||
466 | /* Ensure the instrument doesn't lie about it */ | ||
467 | if(n_characters > actual - 12) { | ||
468 | dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12); | ||
469 | n_characters = actual - 12; | ||
470 | } | ||
471 | |||
472 | /* Ensure the instrument doesn't send more back than requested */ | ||
473 | if(n_characters > this_part) { | ||
474 | dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part); | ||
475 | n_characters = this_part; | ||
476 | } | ||
477 | |||
478 | /* Bound amount of data received by amount of data requested */ | ||
479 | if (n_characters > this_part) | ||
480 | n_characters = this_part; | ||
481 | |||
458 | /* Copy buffer to user space */ | 482 | /* Copy buffer to user space */ |
459 | if (copy_to_user(buf + done, &buffer[12], n_characters)) { | 483 | if (copy_to_user(buf + done, &buffer[12], n_characters)) { |
460 | /* There must have been an addressing problem */ | 484 | /* There must have been an addressing problem */ |
@@ -463,8 +487,11 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf, | |||
463 | } | 487 | } |
464 | 488 | ||
465 | done += n_characters; | 489 | done += n_characters; |
466 | if (n_characters < USBTMC_SIZE_IOBUFFER) | 490 | /* Terminate if end-of-message bit recieved from device */ |
491 | if ((buffer[8] & 0x01) && (actual >= n_characters + 12)) | ||
467 | remaining = 0; | 492 | remaining = 0; |
493 | else | ||
494 | remaining -= n_characters; | ||
468 | } | 495 | } |
469 | 496 | ||
470 | /* Update file position value */ | 497 | /* Update file position value */ |
@@ -496,6 +523,10 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf, | |||
496 | return -ENOMEM; | 523 | return -ENOMEM; |
497 | 524 | ||
498 | mutex_lock(&data->io_mutex); | 525 | mutex_lock(&data->io_mutex); |
526 | if (data->zombie) { | ||
527 | retval = -ENODEV; | ||
528 | goto exit; | ||
529 | } | ||
499 | 530 | ||
500 | remaining = count; | 531 | remaining = count; |
501 | done = 0; | 532 | done = 0; |
@@ -767,20 +798,21 @@ static int get_capabilities(struct usbtmc_device_data *data) | |||
767 | } | 798 | } |
768 | 799 | ||
769 | dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); | 800 | dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); |
770 | dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); | ||
771 | dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); | ||
772 | dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); | ||
773 | dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); | ||
774 | if (buffer[0] != USBTMC_STATUS_SUCCESS) { | 801 | if (buffer[0] != USBTMC_STATUS_SUCCESS) { |
775 | dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); | 802 | dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); |
776 | rv = -EPERM; | 803 | rv = -EPERM; |
777 | goto err_out; | 804 | goto err_out; |
778 | } | 805 | } |
806 | dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]); | ||
807 | dev_dbg(dev, "Device capabilities are %x\n", buffer[5]); | ||
808 | dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]); | ||
809 | dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]); | ||
779 | 810 | ||
780 | data->capabilities.interface_capabilities = buffer[4]; | 811 | data->capabilities.interface_capabilities = buffer[4]; |
781 | data->capabilities.device_capabilities = buffer[5]; | 812 | data->capabilities.device_capabilities = buffer[5]; |
782 | data->capabilities.usb488_interface_capabilities = buffer[14]; | 813 | data->capabilities.usb488_interface_capabilities = buffer[14]; |
783 | data->capabilities.usb488_device_capabilities = buffer[15]; | 814 | data->capabilities.usb488_device_capabilities = buffer[15]; |
815 | rv = 0; | ||
784 | 816 | ||
785 | err_out: | 817 | err_out: |
786 | kfree(buffer); | 818 | kfree(buffer); |
@@ -925,6 +957,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
925 | 957 | ||
926 | data = file->private_data; | 958 | data = file->private_data; |
927 | mutex_lock(&data->io_mutex); | 959 | mutex_lock(&data->io_mutex); |
960 | if (data->zombie) { | ||
961 | retval = -ENODEV; | ||
962 | goto skip_io_on_zombie; | ||
963 | } | ||
928 | 964 | ||
929 | switch (cmd) { | 965 | switch (cmd) { |
930 | case USBTMC_IOCTL_CLEAR_OUT_HALT: | 966 | case USBTMC_IOCTL_CLEAR_OUT_HALT: |
@@ -952,6 +988,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
952 | break; | 988 | break; |
953 | } | 989 | } |
954 | 990 | ||
991 | skip_io_on_zombie: | ||
955 | mutex_unlock(&data->io_mutex); | 992 | mutex_unlock(&data->io_mutex); |
956 | return retval; | 993 | return retval; |
957 | } | 994 | } |
@@ -995,6 +1032,7 @@ static int usbtmc_probe(struct usb_interface *intf, | |||
995 | usb_set_intfdata(intf, data); | 1032 | usb_set_intfdata(intf, data); |
996 | kref_init(&data->kref); | 1033 | kref_init(&data->kref); |
997 | mutex_init(&data->io_mutex); | 1034 | mutex_init(&data->io_mutex); |
1035 | data->zombie = 0; | ||
998 | 1036 | ||
999 | /* Initialize USBTMC bTag and other fields */ | 1037 | /* Initialize USBTMC bTag and other fields */ |
1000 | data->bTag = 1; | 1038 | data->bTag = 1; |
@@ -1065,14 +1103,30 @@ static void usbtmc_disconnect(struct usb_interface *intf) | |||
1065 | usb_deregister_dev(intf, &usbtmc_class); | 1103 | usb_deregister_dev(intf, &usbtmc_class); |
1066 | sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); | 1104 | sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); |
1067 | sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); | 1105 | sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); |
1106 | mutex_lock(&data->io_mutex); | ||
1107 | data->zombie = 1; | ||
1108 | mutex_unlock(&data->io_mutex); | ||
1068 | kref_put(&data->kref, usbtmc_delete); | 1109 | kref_put(&data->kref, usbtmc_delete); |
1069 | } | 1110 | } |
1070 | 1111 | ||
1112 | static int usbtmc_suspend (struct usb_interface *intf, pm_message_t message) | ||
1113 | { | ||
1114 | /* this driver does not have pending URBs */ | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static int usbtmc_resume (struct usb_interface *intf) | ||
1119 | { | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1071 | static struct usb_driver usbtmc_driver = { | 1123 | static struct usb_driver usbtmc_driver = { |
1072 | .name = "usbtmc", | 1124 | .name = "usbtmc", |
1073 | .id_table = usbtmc_devices, | 1125 | .id_table = usbtmc_devices, |
1074 | .probe = usbtmc_probe, | 1126 | .probe = usbtmc_probe, |
1075 | .disconnect = usbtmc_disconnect | 1127 | .disconnect = usbtmc_disconnect, |
1128 | .suspend = usbtmc_suspend, | ||
1129 | .resume = usbtmc_resume, | ||
1076 | }; | 1130 | }; |
1077 | 1131 | ||
1078 | static int __init usbtmc_init(void) | 1132 | static int __init usbtmc_init(void) |