X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fscpi%2Fscpi_usbtmc_libusb.c;h=cd9ade47c18ff736bb1dab1e583be160d7380860;hb=98654c99daf85bd2a81a9c87f517e800c31e34f2;hp=c4470b5db6dee0d98b4983a8a79b2627bf9e5f08;hpb=155b680da482cea2381becb73c51cfb838bff31e;p=libsigrok.git
diff --git a/src/scpi/scpi_usbtmc_libusb.c b/src/scpi/scpi_usbtmc_libusb.c
index c4470b5d..cd9ade47 100644
--- a/src/scpi/scpi_usbtmc_libusb.c
+++ b/src/scpi/scpi_usbtmc_libusb.c
@@ -17,9 +17,11 @@
* along with this program. If not, see .
*/
+#include
#include
-#include "libsigrok.h"
+#include
#include "libsigrok-internal.h"
+#include "scpi.h"
#define LOG_PREFIX "scpi_usbtmc"
@@ -43,7 +45,6 @@ struct scpi_usbtmc_libusb {
int response_length;
int response_bytes_read;
int remaining_length;
- int rigol_ds1000;
};
/* Some USBTMC-specific enums, as defined in the USBTMC standard. */
@@ -68,6 +69,9 @@ enum {
LOCAL_LOCKOUT = 162,
};
+/* USBTMC status codes */
+#define USBTMC_STATUS_SUCCESS 0x01
+
/* USBTMC capabilities */
#define USBTMC_INT_CAP_LISTEN_ONLY 0x01
#define USBTMC_INT_CAP_TALK_ONLY 0x02
@@ -92,6 +96,18 @@ enum {
#define EOM 0x01
#define TERM_CHAR_ENABLED 0x02
+struct usbtmc_blacklist {
+ uint16_t vid;
+ uint16_t pid;
+};
+
+static struct usbtmc_blacklist blacklist_remote[] = {
+ /* Rigol DS1000 series publishes RL1 support, but doesn't support it. */
+ { 0x1ab1, 0x0588 },
+ /* Agilent DSO1000 series are rebadged versions of the Rigol DS1000. */
+ { 0x0957, 0x0588 },
+ ALL_ZERO
+};
static GSList *scpi_usbtmc_libusb_scan(struct drv_context *drvc)
{
@@ -110,11 +126,7 @@ 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) {
@@ -174,9 +186,113 @@ static int scpi_usbtmc_libusb_dev_inst_new(void *priv, struct drv_context *drvc,
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)
+{
+ int i;
+
+ for (i = 0; blacklist[i].vid; i++) {
+ if (blacklist[i].vid == vid && blacklist[i].pid == pid)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int scpi_usbtmc_remote(struct scpi_usbtmc_libusb *uscpi)
{
- struct scpi_usbtmc_libusb *uscpi = priv;
+ 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, 1,
+ 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, 1,
+ 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;
@@ -194,11 +310,7 @@ static int scpi_usbtmc_libusb_open(void *priv)
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) {
@@ -213,9 +325,8 @@ static int scpi_usbtmc_libusb_open(void *priv)
intfdes->bInterfaceProtocol != USBTMC_USB488)
continue;
uscpi->interface = intfdes->bInterfaceNumber;
- sr_dbg("Interface %d", uscpi->interface);
config = confdes->bConfigurationValue;
- sr_dbg("Configuration %d", config);
+ sr_dbg("Interface %d configuration %d.", uscpi->interface, config);
for (epidx = 0; epidx < intfdes->bNumEndpoints; epidx++) {
ep = &intfdes->endpoint[epidx];
if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
@@ -226,17 +337,15 @@ static int scpi_usbtmc_libusb_open(void *priv)
if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
uscpi->bulk_in_ep = ep->bEndpointAddress;
- sr_dbg("Bulk IN EP %d", uscpi->bulk_in_ep);
+ sr_dbg("Bulk IN EP %d", uscpi->bulk_in_ep & 0x7f);
}
if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
uscpi->interrupt_ep = ep->bEndpointAddress;
- sr_dbg("Interrupt EP %d", uscpi->interrupt_ep);
+ sr_dbg("Interrupt EP %d", uscpi->interrupt_ep & 0x7f);
}
}
found = 1;
- uscpi->rigol_ds1000 = des.idVendor == 0x1ab1 &&
- des.idProduct == 0x0588;
}
libusb_free_config_descriptor(confdes);
if (found)
@@ -270,24 +379,6 @@ static int scpi_usbtmc_libusb_open(void *priv)
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 |
@@ -313,6 +404,8 @@ static int scpi_usbtmc_libusb_open(void *priv)
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;
}
@@ -522,27 +615,32 @@ static int scpi_usbtmc_libusb_read_complete(void *priv)
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;
+ struct libusb_device *dev;
+ struct libusb_device_descriptor des;
+ 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));
+ dev = libusb_get_device(usb->devhdl);
+ libusb_get_device_descriptor(dev, &des);
+ if (des.idVendor == 0x1ab1 && des.idProduct == 0x0588
+ && scpi->firmware_version >= 24) {
+ /* Rigol DS1000 with firmware > 0.2.4 needs this. */
+ 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_out_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));
}
+ scpi_usbtmc_local(uscpi);
+
if ((ret = libusb_release_interface(usb->devhdl, uscpi->interface)) < 0)
sr_err("Failed to release interface: %s.",
libusb_error_name(ret));
@@ -555,8 +653,7 @@ static int scpi_usbtmc_libusb_close(void *priv)
uscpi->detached_kernel_driver = 0;
}
- libusb_close(usb->devhdl);
- usb->devhdl = NULL;
+ sr_usb_close(usb);
return SR_OK;
}