2012-11-02 20:04:21 +00:00
|
|
|
/*
|
2013-04-23 20:24:30 +00:00
|
|
|
* This file is part of the libsigrok project.
|
2012-11-02 20:04:21 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Uwe Hermann <uwe@hermann-uwe.de>
|
|
|
|
* Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2014-09-22 21:08:17 +00:00
|
|
|
#include <memory.h>
|
2012-11-02 20:04:21 +00:00
|
|
|
#include <glib.h>
|
|
|
|
#include <libusb.h>
|
2015-08-12 23:18:51 +00:00
|
|
|
#include <libsigrok/libsigrok.h>
|
2012-11-02 20:04:21 +00:00
|
|
|
#include "libsigrok-internal.h"
|
|
|
|
|
2013-01-21 22:22:47 +00:00
|
|
|
/* SR_CONF_CONN takes one of these: */
|
2013-04-15 21:47:04 +00:00
|
|
|
#define CONN_USB_VIDPID "^([0-9a-z]{4})\\.([0-9a-z]{4})$"
|
2012-11-02 20:04:21 +00:00
|
|
|
#define CONN_USB_BUSADDR "^(\\d+)\\.(\\d+)$"
|
|
|
|
|
2013-12-23 03:38:35 +00:00
|
|
|
#define LOG_PREFIX "usb"
|
2012-11-02 20:04:21 +00:00
|
|
|
|
2012-12-04 22:25:11 +00:00
|
|
|
/**
|
|
|
|
* Find USB devices according to a connection string.
|
|
|
|
*
|
|
|
|
* @param usb_ctx libusb context to use while scanning.
|
|
|
|
* @param conn Connection string specifying the device(s) to match. This
|
|
|
|
* can be of the form "<bus>.<address>", or "<vendorid>.<productid>".
|
|
|
|
*
|
|
|
|
* @return A GSList of struct sr_usb_dev_inst, with bus and address fields
|
|
|
|
* matching the device that matched the connection string. The GSList and
|
|
|
|
* its contents must be freed by the caller.
|
|
|
|
*/
|
|
|
|
SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
|
2012-11-02 20:04:21 +00:00
|
|
|
{
|
2012-12-04 22:25:11 +00:00
|
|
|
struct sr_usb_dev_inst *usb;
|
2012-11-02 20:04:21 +00:00
|
|
|
struct libusb_device **devlist;
|
|
|
|
struct libusb_device_descriptor des;
|
|
|
|
GSList *devices;
|
|
|
|
GRegex *reg;
|
|
|
|
GMatchInfo *match;
|
|
|
|
int vid, pid, bus, addr, b, a, ret, i;
|
|
|
|
char *mstr;
|
|
|
|
|
|
|
|
vid = pid = bus = addr = 0;
|
|
|
|
reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL);
|
|
|
|
if (g_regex_match(reg, conn, 0, &match)) {
|
2012-12-09 13:39:17 +00:00
|
|
|
if ((mstr = g_match_info_fetch(match, 1)))
|
2012-11-02 20:04:21 +00:00
|
|
|
vid = strtoul(mstr, NULL, 16);
|
|
|
|
g_free(mstr);
|
|
|
|
|
2012-12-09 13:39:17 +00:00
|
|
|
if ((mstr = g_match_info_fetch(match, 2)))
|
2012-11-02 20:04:21 +00:00
|
|
|
pid = strtoul(mstr, NULL, 16);
|
|
|
|
g_free(mstr);
|
|
|
|
sr_dbg("Trying to find USB device with VID:PID = %04x:%04x.",
|
|
|
|
vid, pid);
|
|
|
|
} else {
|
|
|
|
g_match_info_unref(match);
|
|
|
|
g_regex_unref(reg);
|
|
|
|
reg = g_regex_new(CONN_USB_BUSADDR, 0, 0, NULL);
|
|
|
|
if (g_regex_match(reg, conn, 0, &match)) {
|
2012-12-09 13:39:17 +00:00
|
|
|
if ((mstr = g_match_info_fetch(match, 1)))
|
2013-04-15 21:47:04 +00:00
|
|
|
bus = strtoul(mstr, NULL, 10);
|
2012-11-02 20:04:21 +00:00
|
|
|
g_free(mstr);
|
|
|
|
|
2012-12-09 13:39:17 +00:00
|
|
|
if ((mstr = g_match_info_fetch(match, 2)))
|
2013-04-15 21:47:04 +00:00
|
|
|
addr = strtoul(mstr, NULL, 10);
|
2012-11-02 20:04:21 +00:00
|
|
|
g_free(mstr);
|
|
|
|
sr_dbg("Trying to find USB device with bus.address = "
|
|
|
|
"%d.%d.", bus, addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
g_match_info_unref(match);
|
|
|
|
g_regex_unref(reg);
|
|
|
|
|
|
|
|
if (vid + pid + bus + addr == 0) {
|
2012-12-09 13:39:17 +00:00
|
|
|
sr_err("Neither VID:PID nor bus.address was specified.");
|
2012-11-02 20:04:21 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bus > 64) {
|
|
|
|
sr_err("Invalid bus specified: %d.", bus);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr > 127) {
|
|
|
|
sr_err("Invalid address specified: %d.", addr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Looks like a valid USB device specification, but is it connected? */
|
|
|
|
devices = NULL;
|
|
|
|
libusb_get_device_list(usb_ctx, &devlist);
|
|
|
|
for (i = 0; devlist[i]; i++) {
|
|
|
|
if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
|
2012-12-04 20:11:25 +00:00
|
|
|
sr_err("Failed to get device descriptor: %s.",
|
|
|
|
libusb_error_name(ret));
|
2012-11-02 20:04:21 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-12-04 22:25:11 +00:00
|
|
|
if (vid + pid && (des.idVendor != vid || des.idProduct != pid))
|
2012-11-02 20:04:21 +00:00
|
|
|
continue;
|
|
|
|
|
2012-12-04 22:25:11 +00:00
|
|
|
b = libusb_get_bus_number(devlist[i]);
|
|
|
|
a = libusb_get_device_address(devlist[i]);
|
|
|
|
if (bus + addr && (b != bus || a != addr))
|
2012-11-02 20:04:21 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = "
|
|
|
|
"%d.%d).", des.idVendor, des.idProduct, b, a);
|
|
|
|
|
2012-12-04 22:25:11 +00:00
|
|
|
usb = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
|
|
|
|
libusb_get_device_address(devlist[i]), NULL);
|
|
|
|
devices = g_slist_append(devices, usb);
|
2012-11-02 20:04:21 +00:00
|
|
|
}
|
|
|
|
libusb_free_device_list(devlist, 1);
|
|
|
|
|
|
|
|
sr_dbg("Found %d device(s).", g_slist_length(devices));
|
|
|
|
|
|
|
|
return devices;
|
|
|
|
}
|
|
|
|
|
|
|
|
SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb)
|
|
|
|
{
|
|
|
|
struct libusb_device **devlist;
|
|
|
|
struct libusb_device_descriptor des;
|
|
|
|
int ret, r, cnt, i, a, b;
|
|
|
|
|
2012-12-09 14:19:39 +00:00
|
|
|
sr_dbg("Trying to open USB device %d.%d.", usb->bus, usb->address);
|
2012-11-02 20:04:21 +00:00
|
|
|
|
|
|
|
if ((cnt = libusb_get_device_list(usb_ctx, &devlist)) < 0) {
|
|
|
|
sr_err("Failed to retrieve device list: %s.",
|
|
|
|
libusb_error_name(cnt));
|
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = SR_ERR;
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
|
|
if ((r = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
|
|
|
|
sr_err("Failed to get device descriptor: %s.",
|
|
|
|
libusb_error_name(r));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
b = libusb_get_bus_number(devlist[i]);
|
|
|
|
a = libusb_get_device_address(devlist[i]);
|
2012-12-09 14:19:39 +00:00
|
|
|
if (b != usb->bus || a != usb->address)
|
2012-11-02 20:04:21 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((r = libusb_open(devlist[i], &usb->devhdl)) < 0) {
|
|
|
|
sr_err("Failed to open device: %s.",
|
|
|
|
libusb_error_name(r));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_dbg("Opened USB device (VID:PID = %04x:%04x, bus.address = "
|
|
|
|
"%d.%d).", des.idVendor, des.idProduct, b, a);
|
|
|
|
|
|
|
|
ret = SR_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
libusb_free_device_list(devlist, 1);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2013-12-21 23:03:24 +00:00
|
|
|
|
2015-08-16 18:00:26 +00:00
|
|
|
SR_PRIV void sr_usb_close(struct sr_usb_dev_inst *usb)
|
|
|
|
{
|
|
|
|
libusb_close(usb->devhdl);
|
|
|
|
usb->devhdl = NULL;
|
|
|
|
sr_dbg("Closed USB device %d.%d.", usb->bus, usb->address);
|
|
|
|
}
|
|
|
|
|
2014-07-21 12:35:27 +00:00
|
|
|
SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx,
|
|
|
|
int timeout, sr_receive_data_callback cb, void *cb_data)
|
2013-12-21 23:03:24 +00:00
|
|
|
{
|
2015-09-04 21:47:08 +00:00
|
|
|
const struct libusb_pollfd **lupfd;
|
|
|
|
GPollFD *pollfds;
|
|
|
|
int i;
|
|
|
|
int num_fds = 0;
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
int ret;
|
|
|
|
|
2013-12-22 17:27:13 +00:00
|
|
|
if (ctx->usb_source_present) {
|
|
|
|
sr_err("A USB event source is already present.");
|
|
|
|
return SR_ERR;
|
|
|
|
}
|
2013-12-21 23:03:24 +00:00
|
|
|
lupfd = libusb_get_pollfds(ctx->libusb_ctx);
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
if (!lupfd || !lupfd[0]) {
|
|
|
|
free(lupfd);
|
|
|
|
sr_err("Failed to get libusb file descriptors.");
|
|
|
|
return SR_ERR;
|
|
|
|
}
|
|
|
|
while (lupfd[num_fds])
|
|
|
|
++num_fds;
|
|
|
|
pollfds = g_new(GPollFD, num_fds);
|
|
|
|
|
|
|
|
for (i = 0; i < num_fds; ++i) {
|
2015-09-04 21:47:08 +00:00
|
|
|
#if defined(G_OS_WIN32) && (GLIB_SIZEOF_VOID_P == 4)
|
|
|
|
/* Avoid a warning on 32-bit Windows. */
|
|
|
|
pollfds[i].fd = (gintptr)lupfd[i]->fd;
|
|
|
|
#else
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
pollfds[i].fd = lupfd[i]->fd;
|
2015-09-04 21:47:08 +00:00
|
|
|
#endif
|
2015-09-07 06:50:29 +00:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
pollfds[i].events = G_IO_IN;
|
|
|
|
#else
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
pollfds[i].events = lupfd[i]->events;
|
2015-09-07 06:50:29 +00:00
|
|
|
#endif
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
pollfds[i].revents = 0;
|
2015-08-30 19:43:30 +00:00
|
|
|
}
|
2013-12-21 23:03:24 +00:00
|
|
|
free(lupfd);
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
ret = sr_session_source_add_internal(session, pollfds, num_fds,
|
|
|
|
timeout, cb, cb_data, (gintptr)ctx->libusb_ctx);
|
|
|
|
g_free(pollfds);
|
2015-09-04 21:47:08 +00:00
|
|
|
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
ctx->usb_source_present = (ret == SR_OK);
|
2013-12-21 23:03:24 +00:00
|
|
|
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
return ret;
|
2013-12-21 23:03:24 +00:00
|
|
|
}
|
|
|
|
|
2014-07-21 12:35:27 +00:00
|
|
|
SR_PRIV int usb_source_remove(struct sr_session *session, struct sr_context *ctx)
|
2013-12-21 23:03:24 +00:00
|
|
|
{
|
2015-09-05 01:56:16 +00:00
|
|
|
return sr_session_source_remove_internal(session,
|
session: Allow multiple poll FDs per event source
Turns out that having one event source per libusb poll FD is
a bad idea. There is only a single callback for all poll FDs,
and libusb expects to be called only once per poll iteration,
no matter how many FDs triggered.
Also, they should all share the same timeout, which should get
reset on events from any polled FD. The new timeout handling made
this problem apparent, as it caused the callback to be invoked
multiple times on timeouts, once for each separate event source.
In order to fix this, change the implementation to allow for an
arbitrary number of poll FDs per event source. This number is
zero for timer FDs, one for normal I/O sources, and one or more
for libusb sources (Unix only).
Also, on Windows, do not get an additional timeout from libusb
in the event loop. This is only appropriate when polling the
libusb FDs directly, which we aren't doing on Windows.
2015-09-01 01:36:03 +00:00
|
|
|
(gintptr)ctx->libusb_ctx);
|
2013-12-21 23:03:24 +00:00
|
|
|
}
|
2014-09-22 21:08:17 +00:00
|
|
|
|
2014-10-06 22:02:10 +00:00
|
|
|
SR_PRIV int usb_get_port_path(libusb_device *dev, char *path, int path_len)
|
2014-09-22 21:08:17 +00:00
|
|
|
{
|
2014-10-06 22:02:10 +00:00
|
|
|
uint8_t port_numbers[8];
|
|
|
|
int i, n, len;
|
|
|
|
|
2015-01-22 00:11:22 +00:00
|
|
|
/*
|
|
|
|
* FreeBSD requires that devices prior to calling libusb_get_port_numbers()
|
|
|
|
* have been opened with libusb_open().
|
|
|
|
*/
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
struct libusb_device_handle *devh;
|
|
|
|
if (libusb_open(dev, &devh) != 0)
|
|
|
|
return SR_ERR;
|
|
|
|
#endif
|
2014-10-06 22:02:10 +00:00
|
|
|
n = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers));
|
2015-01-22 00:11:22 +00:00
|
|
|
#ifdef __FreeBSD__
|
|
|
|
libusb_close(devh);
|
|
|
|
#endif
|
2014-10-06 22:02:10 +00:00
|
|
|
|
2015-01-22 00:11:22 +00:00
|
|
|
/* Workaround FreeBSD libusb_get_port_numbers() returning 0. */
|
|
|
|
#ifdef __FreeBSD__
|
|
|
|
if (n == 0) {
|
|
|
|
port_numbers[0] = libusb_get_device_address(dev);
|
|
|
|
n = 1;
|
|
|
|
}
|
|
|
|
#endif
|
2014-11-10 16:17:07 +00:00
|
|
|
if (n < 1)
|
|
|
|
return SR_ERR;
|
|
|
|
|
2014-10-06 22:02:10 +00:00
|
|
|
len = snprintf(path, path_len, "usb/%d-%d",
|
|
|
|
libusb_get_bus_number(dev), port_numbers[0]);
|
2014-09-22 21:08:17 +00:00
|
|
|
|
2014-10-06 22:02:10 +00:00
|
|
|
for (i = 1; i < n; i++)
|
|
|
|
len += snprintf(path+len, path_len-len, ".%d", port_numbers[i]);
|
2014-09-22 21:08:17 +00:00
|
|
|
|
|
|
|
return SR_OK;
|
|
|
|
}
|