int response_length;
int response_bytes_read;
int remaining_length;
- int rigol_ds1000;
};
/* Some USBTMC-specific enums, as defined in the USBTMC standard. */
-#define SUBCLASS_USBTMC 0x03
-#define USBTMC_USB488 0x01
+#define SUBCLASS_USBTMC 0x03
+#define USBTMC_USB488 0x01
enum {
/* USBTMC control requests */
#define USB488_DEV_CAP_SCPI 0x08
/* Bulk messages constants */
-#define USBTMC_BULK_HEADER_SIZE 12
+#define USBTMC_BULK_HEADER_SIZE 12
/* Bulk MsgID values */
-#define DEV_DEP_MSG_OUT 1
-#define REQUEST_DEV_DEP_MSG_IN 2
-#define DEV_DEP_MSG_IN 2
+#define DEV_DEP_MSG_OUT 1
+#define REQUEST_DEV_DEP_MSG_IN 2
+#define DEV_DEP_MSG_IN 2
/* bmTransferAttributes */
-#define EOM 0x01
-#define TERM_CHAR_ENABLED 0x02
+#define EOM 0x01
+#define TERM_CHAR_ENABLED 0x02
+
+struct usbtmc_blacklist {
+ uint16_t vid;
+ uint16_t pid;
+};
+
+/* Devices that publish RL1 support, but don't support it. */
+static struct usbtmc_blacklist blacklist_remote[] = {
+ { 0x1ab1, 0x0588 }, /* Rigol DS1000 series */
+ { 0x1ab1, 0x04b0 }, /* Rigol DS2000 series */
+ { 0x0957, 0x0588 }, /* Agilent DSO1000 series (rebadged Rigol DS1000) */
+ { 0x0b21, 0xffff }, /* All Yokogawa devices */
+ ALL_ZERO
+};
static GSList *scpi_usbtmc_libusb_scan(struct drv_context *drvc)
{
return NULL;
}
for (i = 0; devlist[i]; i++) {
- if ((ret = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
- sr_err("Failed to get device descriptor: %s.",
- libusb_error_name(ret));
- continue;
- }
+ libusb_get_device_descriptor(devlist[i], &des);
for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
if ((ret = libusb_get_config_descriptor(devlist[i], confidx, &confdes)) < 0) {
return SR_OK;
}
-static int scpi_usbtmc_libusb_open(void *priv)
+static int check_usbtmc_blacklist(struct usbtmc_blacklist *blacklist,
+ uint16_t vid, uint16_t pid)
{
- struct scpi_usbtmc_libusb *uscpi = priv;
+ int i;
+
+ for (i = 0; blacklist[i].vid; i++) {
+ if ((blacklist[i].vid == vid && blacklist[i].pid == 0xFFFF) ||
+ (blacklist[i].vid == vid && blacklist[i].pid == pid))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int scpi_usbtmc_remote(struct scpi_usbtmc_libusb *uscpi)
+{
+ struct sr_usb_dev_inst *usb = uscpi->usb;
+ struct libusb_device *dev;
+ struct libusb_device_descriptor des;
+ int ret;
+ uint8_t status;
+
+ if (!(uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1))
+ return SR_OK;
+
+ dev = libusb_get_device(usb->devhdl);
+ libusb_get_device_descriptor(dev, &des);
+ if (check_usbtmc_blacklist(blacklist_remote, des.idVendor, des.idProduct))
+ return SR_OK;
+
+ sr_dbg("Locking out local control.");
+ ret = libusb_control_transfer(usb->devhdl, LIBUSB_ENDPOINT_IN |
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ REN_CONTROL, 1, uscpi->interface, &status, 1, TRANSFER_TIMEOUT);
+ if (ret < 0 || status != USBTMC_STATUS_SUCCESS) {
+ if (ret < 0)
+ sr_dbg("Failed to enter REN state: %s.", libusb_error_name(ret));
+ else
+ sr_dbg("Failed to enter REN state: USBTMC status %d.", status);
+ return SR_ERR;
+ }
+
+ ret = libusb_control_transfer(usb->devhdl, LIBUSB_ENDPOINT_IN |
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ LOCAL_LOCKOUT, 0, uscpi->interface, &status, 1,
+ TRANSFER_TIMEOUT);
+ if (ret < 0 || status != USBTMC_STATUS_SUCCESS) {
+ if (ret < 0)
+ sr_dbg("Failed to enter local lockout state: %s.",
+ libusb_error_name(ret));
+ else
+ sr_dbg("Failed to enter local lockout state: USBTMC "
+ "status %d.", status);
+ return SR_ERR;
+ }
+
+ return SR_OK;
+}
+
+static void scpi_usbtmc_local(struct scpi_usbtmc_libusb *uscpi)
+{
+ struct sr_usb_dev_inst *usb = uscpi->usb;
+ struct libusb_device *dev;
+ struct libusb_device_descriptor des;
+ int ret;
+ uint8_t status;
+
+ if (!(uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1))
+ return;
+
+ dev = libusb_get_device(usb->devhdl);
+ libusb_get_device_descriptor(dev, &des);
+ if (check_usbtmc_blacklist(blacklist_remote, des.idVendor, des.idProduct))
+ return;
+
+ sr_dbg("Returning local control.");
+ ret = libusb_control_transfer(usb->devhdl, LIBUSB_ENDPOINT_IN |
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ GO_TO_LOCAL, 0, uscpi->interface, &status, 1, TRANSFER_TIMEOUT);
+ if (ret < 0 || status != USBTMC_STATUS_SUCCESS) {
+ if (ret < 0)
+ sr_dbg("Failed to clear local lockout state: %s.",
+ libusb_error_name(ret));
+ else
+ sr_dbg("Failed to clear local lockout state: USBTMC "
+ "status %d.", status);
+ }
+
+ return;
+}
+
+static int scpi_usbtmc_libusb_open(struct sr_scpi_dev_inst *scpi)
+{
+ struct scpi_usbtmc_libusb *uscpi = scpi->priv;
struct sr_usb_dev_inst *usb = uscpi->usb;
struct libusb_device *dev;
struct libusb_device_descriptor des;
struct libusb_config_descriptor *confdes;
const struct libusb_interface_descriptor *intfdes;
const struct libusb_endpoint_descriptor *ep;
- int confidx, intfidx, epidx, config = 0;
- uint8_t capabilities[24], status;
+ int confidx, intfidx, epidx, config = 0, current_config;
+ uint8_t capabilities[24];
int ret, found = 0;
if (usb->devhdl)
return SR_ERR;
dev = libusb_get_device(usb->devhdl);
- if ((ret = libusb_get_device_descriptor(dev, &des)) < 0) {
- sr_err("Failed to get device descriptor: %s.",
- libusb_error_name(ret));
- return SR_ERR;
- }
+ libusb_get_device_descriptor(dev, &des);
for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
if ((ret = libusb_get_config_descriptor(dev, confidx, &confdes)) < 0) {
for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
intfdes = confdes->interface[intfidx].altsetting;
if (intfdes->bInterfaceClass != LIBUSB_CLASS_APPLICATION ||
- intfdes->bInterfaceSubClass != SUBCLASS_USBTMC ||
+ intfdes->bInterfaceSubClass != SUBCLASS_USBTMC ||
intfdes->bInterfaceProtocol != USBTMC_USB488)
continue;
uscpi->interface = intfdes->bInterfaceNumber;
}
}
found = 1;
- uscpi->rigol_ds1000 = des.idVendor == 0x1ab1 &&
- des.idProduct == 0x0588;
}
libusb_free_config_descriptor(confdes);
if (found)
uscpi->detached_kernel_driver = 1;
}
- if ((ret = libusb_set_configuration(usb->devhdl, config)) < 0) {
- sr_err("Failed to set configuration: %s.",
- libusb_error_name(ret));
- return SR_ERR;
+ if (libusb_get_configuration(usb->devhdl, ¤t_config) == 0
+ && current_config != config) {
+ if ((ret = libusb_set_configuration(usb->devhdl, config)) < 0) {
+ sr_err("Failed to set configuration: %s.",
+ libusb_error_name(ret));
+ return SR_ERR;
+ }
}
if ((ret = libusb_claim_interface(usb->devhdl, uscpi->interface)) < 0) {
return SR_ERR;
}
- if (!uscpi->rigol_ds1000) {
- if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0) {
- sr_err("Failed to clear halt/stall condition for EP %d: %s.",
- uscpi->bulk_in_ep, libusb_error_name(ret));
- return SR_ERR;
- }
- if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0) {
- sr_err("Failed to clear halt/stall condition for EP %d: %s.",
- uscpi->bulk_out_ep, libusb_error_name(ret));
- return SR_ERR;
- }
- if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0) {
- sr_err("Failed to clear halt/stall condition for EP %d: %s.",
- uscpi->interrupt_ep, libusb_error_name(ret));
- return SR_ERR;
- }
- }
-
/* Get capabilities. */
- ret = libusb_control_transfer(usb->devhdl,
- LIBUSB_ENDPOINT_IN |
- LIBUSB_REQUEST_TYPE_CLASS |
- LIBUSB_RECIPIENT_INTERFACE,
- GET_CAPABILITIES, 0,
- uscpi->interface,
- capabilities, sizeof(capabilities),
- TRANSFER_TIMEOUT);
+ ret = libusb_control_transfer(usb->devhdl, LIBUSB_ENDPOINT_IN |
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
+ GET_CAPABILITIES, 0, uscpi->interface, capabilities,
+ sizeof(capabilities), TRANSFER_TIMEOUT);
if (ret == sizeof(capabilities)) {
uscpi->usbtmc_int_cap = capabilities[ 4];
uscpi->usbtmc_dev_cap = capabilities[ 5];
uscpi->usb488_dev_cap = capabilities[15];
}
sr_dbg("Device capabilities: %s%s%s%s%s, %s, %s",
- uscpi->usb488_dev_cap & USB488_DEV_CAP_SCPI ? "SCPI, " : "",
- uscpi->usbtmc_dev_cap & USBTMC_DEV_CAP_TERMCHAR ? "TermChar, ": "",
- uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? "L3, " :
- uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY ? "" : "L4, ",
- uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY ? "T5, " :
- uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? "" : "T6, ",
- uscpi->usb488_dev_cap & USB488_DEV_CAP_SR1 ? "SR1" : "SR0",
- uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1 ? "RL1" : "RL0",
- uscpi->usb488_dev_cap & USB488_DEV_CAP_DT1 ? "DT1" : "DT0");
-
- if (uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1) {
- sr_dbg("Locking out local control.");
- ret = libusb_control_transfer(usb->devhdl,
- LIBUSB_ENDPOINT_IN |
- LIBUSB_REQUEST_TYPE_CLASS |
- LIBUSB_RECIPIENT_INTERFACE,
- REN_CONTROL, 1,
- uscpi->interface,
- &status, 1,
- TRANSFER_TIMEOUT);
- if (ret < 0 || status != USBTMC_STATUS_SUCCESS) {
- sr_dbg("Failed to enter REN state.");
- return SR_OK;
- }
- ret = libusb_control_transfer(usb->devhdl,
- LIBUSB_ENDPOINT_IN |
- LIBUSB_REQUEST_TYPE_CLASS |
- LIBUSB_RECIPIENT_INTERFACE,
- LOCAL_LOCKOUT, 1,
- uscpi->interface,
- &status, 1,
- TRANSFER_TIMEOUT);
- if (ret < 0 || status != USBTMC_STATUS_SUCCESS)
- sr_dbg("Failed to enter local lockout state.");
- }
+ uscpi->usb488_dev_cap & USB488_DEV_CAP_SCPI ? "SCPI, " : "",
+ uscpi->usbtmc_dev_cap & USBTMC_DEV_CAP_TERMCHAR ? "TermChar, ": "",
+ uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY ? "L3, " :
+ uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY ? "" : "L4, ",
+ uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY ? "T5, " :
+ uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY ? "" : "T6, ",
+ uscpi->usb488_dev_cap & USB488_DEV_CAP_SR1 ? "SR1" : "SR0",
+ uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1 ? "RL1" : "RL0",
+ uscpi->usb488_dev_cap & USB488_DEV_CAP_DT1 ? "DT1" : "DT0");
+
+ scpi_usbtmc_remote(uscpi);
return SR_OK;
}
uint8_t bmTransferAttributes,
char TermChar)
{
- W8(header+ 0, MsgID);
- W8(header+ 1, bTag);
- W8(header+ 2, ~bTag);
- W8(header+ 3, 0);
- WL32(header+ 4, TransferSize);
- W8(header+ 8, bmTransferAttributes);
- W8(header+ 9, TermChar);
- WL16(header+10, 0);
+ W8(header + 0, MsgID);
+ W8(header + 1, bTag);
+ W8(header + 2, ~bTag);
+ W8(header + 3, 0);
+ WL32(header + 4, TransferSize);
+ W8(header + 8, bmTransferAttributes);
+ W8(header + 9, TermChar);
+ WL16(header + 10, 0);
}
static int usbtmc_bulk_in_header_read(void *header, uint8_t MsgID,
int32_t *TransferSize,
uint8_t *bmTransferAttributes)
{
- if (R8(header+0) != MsgID ||
- R8(header+1) != bTag ||
- R8(header+2) != (unsigned char)~bTag)
+ if (R8(header + 0) != MsgID ||
+ R8(header + 1) != bTag ||
+ R8(header + 2) != (unsigned char)~bTag)
return SR_ERR;
if (TransferSize)
- *TransferSize = RL32(header+4);
+ *TransferSize = RL32(header + 4);
if (bmTransferAttributes)
- *bmTransferAttributes = R8(header+8);
+ *bmTransferAttributes = R8(header + 8);
+
return SR_OK;
}
struct sr_usb_dev_inst *usb = uscpi->usb;
int padded_size, ret, transferred;
- if (data && size+USBTMC_BULK_HEADER_SIZE+3 > (int)sizeof(uscpi->buffer)) {
+ if (data && (size + USBTMC_BULK_HEADER_SIZE + 3) > (int)sizeof(uscpi->buffer)) {
sr_err("USBTMC bulk out transfer is too big.");
return SR_ERR;
}
uscpi->bTag++;
- uscpi->bTag += !uscpi->bTag; /* bTag == 0 is invalid so avoid it. */
+ uscpi->bTag += !uscpi->bTag; /* bTag == 0 is invalid so avoid it. */
usbtmc_bulk_out_header_write(uscpi->buffer, msg_id, uscpi->bTag,
size, transfer_attributes, 0);
if (data)
- memcpy(uscpi->buffer+USBTMC_BULK_HEADER_SIZE, data, size);
+ memcpy(uscpi->buffer + USBTMC_BULK_HEADER_SIZE, data, size);
else
size = 0;
size += USBTMC_BULK_HEADER_SIZE;
padded_size = (size + 3) & ~0x3;
- memset(uscpi->buffer+size, 0, padded_size - size);
+ memset(uscpi->buffer + size, 0, padded_size - size);
ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_out_ep,
uscpi->buffer, padded_size, &transferred,
uscpi->bulkin_attributes & EOM;
}
-static int scpi_usbtmc_libusb_close(void *priv)
+static int scpi_usbtmc_libusb_close(struct sr_scpi_dev_inst *scpi)
{
- int ret;
- struct scpi_usbtmc_libusb *uscpi = priv;
+ struct scpi_usbtmc_libusb *uscpi = scpi->priv;
struct sr_usb_dev_inst *usb = uscpi->usb;
- uint8_t status;
+ int ret;
if (!usb->devhdl)
return SR_ERR;
- if (!uscpi->rigol_ds1000) {
- if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0)
- sr_err("Failed to clear halt/stall condition for EP %d: %s.",
- uscpi->bulk_in_ep, libusb_error_name(ret));
- if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0)
- sr_err("Failed to clear halt/stall condition for EP %d: %s.",
- uscpi->bulk_out_ep, libusb_error_name(ret));
- if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0)
- sr_err("Failed to clear halt/stall condition for EP %d: %s.",
- uscpi->interrupt_ep, libusb_error_name(ret));
- }
-
- if (uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1) {
- sr_dbg("Returning local control.");
- ret = libusb_control_transfer(usb->devhdl,
- LIBUSB_ENDPOINT_IN |
- LIBUSB_REQUEST_TYPE_CLASS |
- LIBUSB_RECIPIENT_INTERFACE,
- GO_TO_LOCAL, 1,
- uscpi->interface,
- &status, 1,
- TRANSFER_TIMEOUT);
- if (ret < 0 || status != USBTMC_STATUS_SUCCESS)
- sr_dbg("Failed to clear local lockout state.");
- }
+ scpi_usbtmc_local(uscpi);
if ((ret = libusb_release_interface(usb->devhdl, uscpi->interface)) < 0)
sr_err("Failed to release interface: %s.",