aboutsummaryrefslogtreecommitdiffstats
path: root/src/usb/osmo_libusb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usb/osmo_libusb.c')
-rw-r--r--src/usb/osmo_libusb.c159
1 files changed, 157 insertions, 2 deletions
diff --git a/src/usb/osmo_libusb.c b/src/usb/osmo_libusb.c
index 5b012b86..3c8a22a8 100644
--- a/src/usb/osmo_libusb.c
+++ b/src/usb/osmo_libusb.c
@@ -86,6 +86,7 @@ static void osmo_usb_added_cb(int fd, short events, void *user_data)
struct osmo_fd *ofd = talloc_zero(OTC_GLOBAL, struct osmo_fd);
libusb_context *luctx = user_data;
unsigned int when = 0;
+ int rc;
if (events & POLLIN)
when |= OSMO_FD_READ;
@@ -93,7 +94,9 @@ static void osmo_usb_added_cb(int fd, short events, void *user_data)
when |= OSMO_FD_WRITE;
osmo_fd_setup(ofd, fd, when, osmo_usb_fd_cb, luctx, 0);
- osmo_fd_register(ofd);
+ rc = osmo_fd_register(ofd);
+ if (rc)
+ LOGP(DLUSB, LOGL_ERROR, "osmo_fd_register() failed with rc=%d\n", rc);
}
/* called by libusb if it wants to remove a file-descriptor */
@@ -220,6 +223,158 @@ libusb_device **osmo_libusb_find_matching_usb_devs(void *ctx, struct libusb_cont
return out;
}
+/*! Find a USB device of matching VendorID/ProductID at given path.
+ * \param[in] luctx libusb context on which to operate
+ * \param[in] dev_ids zer-oterminated array of VendorId/ProductId tuples
+ * \param[in] path string representation of USB path
+ * \returns libusb_device if there was exactly one match; NULL otherwise */
+libusb_device *osmo_libusb_find_matching_dev_path(struct libusb_context *luctx,
+ const struct dev_id *dev_ids,
+ const char *path)
+{
+ libusb_device **list;
+ libusb_device *match = NULL;
+ unsigned int i;
+ int rc;
+
+ rc = libusb_get_device_list(luctx, &list);
+ if (rc <= 0)
+ return NULL;
+
+ for (i = 0; list[i] != NULL; i++) {
+ struct libusb_device_descriptor dev_desc;
+ libusb_device *dev = list[i];
+ char pathbuf[128];
+
+ rc = libusb_get_device_descriptor(dev, &dev_desc);
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "couldn't get device descriptor\n");
+ continue;
+ }
+
+ /* check if device doesn't match */
+ if (!match_dev_ids(&dev_desc, dev_ids))
+ continue;
+
+ /* check if path doesn't match */
+ if (path) {
+ osmo_libusb_dev_get_path_buf(pathbuf, sizeof(pathbuf), dev);
+ if (strcmp(pathbuf, path))
+ continue;
+ }
+
+ if (match) {
+ /* we already have a match, but now found a second -> FAIL */
+ libusb_free_device_list(list, 1);
+ LOGP(DLUSB, LOGL_ERROR, "Found more than one matching USB device\n");
+ return NULL;
+ } else
+ match = dev;
+ }
+
+ if (!match) {
+ /* no match: free the list with automatic unref of all devices */
+ libusb_free_device_list(list, 1);
+ return NULL;
+ }
+
+ /* unref all devices *except* the match we found */
+ for (i = 0; list[i] != NULL; i++) {
+ libusb_device *dev = list[i];
+ if (dev != match)
+ libusb_unref_device(dev);
+ }
+ /* free the list *without* automatic unref of all devices */
+ libusb_free_device_list(list, 0);
+ return match;
+}
+
+/*! Find a USB device of matching VendorID/ProductID and given iSerial string.
+ * \param[in] luctx libusb context on which to operate
+ * \param[in] dev_ids zer-oterminated array of VendorId/ProductId tuples
+ * \param[in] serial string representation of serial number
+ * \returns libusb_device if there was exactly one match; NULL otherwise */
+libusb_device *osmo_libusb_find_matching_dev_serial(struct libusb_context *luctx,
+ const struct dev_id *dev_ids,
+ const char *serial)
+{
+ libusb_device **list;
+ libusb_device *match = NULL;
+ unsigned int i;
+ int rc;
+
+ rc = libusb_get_device_list(luctx, &list);
+ if (rc <= 0)
+ return NULL;
+
+ for (i = 0; list[i] != NULL; i++) {
+ struct libusb_device_descriptor dev_desc;
+ libusb_device *dev = list[i];
+
+ rc = libusb_get_device_descriptor(dev, &dev_desc);
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "couldn't get device descriptor\n");
+ continue;
+ }
+
+ /* check if device doesn't match */
+ if (!match_dev_ids(&dev_desc, dev_ids))
+ continue;
+
+ /* check if serial number string doesn't match */
+ if (serial) {
+ char strbuf[256];
+ libusb_device_handle *devh;
+ rc = libusb_open(dev, &devh);
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "Cannot open USB Device: %s\n",
+ libusb_strerror(rc));
+ /* there's no point in continuing here, as we don't know if there
+ * are multiple matches if we cannot read the iSerial string of all
+ * devices with matching vid/pid */
+ libusb_free_device_list(list, 1);
+ return NULL;
+ }
+ rc = libusb_get_string_descriptor_ascii(devh, dev_desc.iSerialNumber,
+ (uint8_t *) strbuf, sizeof(strbuf));
+ if (rc < 0) {
+ LOGP(DLUSB, LOGL_ERROR, "Cannot read USB Descriptor: %s\n",
+ libusb_strerror(rc));
+ libusb_close(devh);
+ continue;
+ }
+ libusb_close(devh);
+ if (strcmp(strbuf, serial))
+ continue;
+ }
+
+ if (match) {
+ /* we already have a match, but now found a second -> FAIL */
+ libusb_free_device_list(list, 1);
+ LOGP(DLUSB, LOGL_ERROR, "Found more than one matching USB device\n");
+ return NULL;
+ } else
+ match = dev;
+ }
+
+ if (!match) {
+ /* no match: free the list with automatic unref of all devices */
+ libusb_free_device_list(list, 1);
+ return NULL;
+ }
+
+ /* unref all devices *except* the match we found */
+ for (i = 0; list[i] != NULL; i++) {
+ libusb_device *dev = list[i];
+ if (dev != match)
+ libusb_unref_device(dev);
+ }
+ /* free the list *without* automatic unref of all devices */
+ libusb_free_device_list(list, 0);
+ return match;
+}
+
+
/*! find a matching interface among all interfaces of the given USB device.
* \param[in] dev USB device in which we shall search
* \param[in] class USB Interface Class to look for
@@ -276,7 +431,7 @@ int osmo_libusb_dev_find_matching_interfaces(libusb_device *dev, int class, int
out[out_idx].vendor = dev_desc.idVendor;
out[out_idx].product = dev_desc.idProduct;
out[out_idx].addr = addr;
- strncpy(out[out_idx].path, path, sizeof(out[out_idx].path)-1);
+ OSMO_STRLCPY_ARRAY(out[out_idx].path, path);
out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
out[out_idx].configuration = conf_desc->bConfigurationValue;
out[out_idx].interface = if_desc->bInterfaceNumber;