X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fusb.c;h=ec502c97501704f38bed9b2d535374166ff7601e;hb=HEAD;hp=8a8f0ca56dfff018bd6d6828cd267c0c1e5f4a98;hpb=07182332f06e09619b2ae2d61de16fafacd750cd;p=libsigrok.git diff --git a/src/usb.c b/src/usb.c index 8a8f0ca5..feafe9d2 100644 --- a/src/usb.c +++ b/src/usb.c @@ -38,7 +38,6 @@ typedef int libusb_os_handle; #endif /** Custom GLib event source for libusb I/O. - * @internal */ struct usb_source { GSource base; @@ -139,7 +138,7 @@ static gboolean usb_source_dispatch(GSource *source, sr_err("Callback not set, cannot dispatch event."); return G_SOURCE_REMOVE; } - keep = (*(sr_receive_data_callback)callback)(-1, revents, user_data); + keep = (*SR_RECEIVE_DATA_CALLBACK(callback))(-1, revents, user_data); if (G_LIKELY(keep) && G_LIKELY(!g_source_is_destroyed(source))) { if (usource->timeout_us >= 0) @@ -298,68 +297,116 @@ static GSource *usb_source_new(struct sr_session *session, } /** - * Find USB devices according to a connection string. + * Extract VID:PID or bus.addr from 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 ".
", or ".". + * @param[in] conn Connection string. + * @param[out] vid Pointer to extracted vendor ID. Can be #NULL. + * @param[out] pid Pointer to extracted product ID. Can be #NULL. + * @param[out] bus Pointer to extracted bus number. Can be #NULL. + * @param[out] addr Pointer to extracted device number. Can be #NULL. * - * @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. + * @return SR_OK when parsing succeeded, SR_ERR* otherwise. + * + * @private + * + * The routine fills in the result variables, and returns the scan success + * in the return code. Callers can specify #NULL for variable references + * if they are not interested in specific aspects of the USB address. */ -SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn) +SR_PRIV int sr_usb_split_conn(const char *conn, + uint16_t *vid, uint16_t *pid, uint8_t *bus, uint8_t *addr) { - struct sr_usb_dev_inst *usb; - struct libusb_device **devlist; - struct libusb_device_descriptor des; - GSList *devices; + gboolean valid; GRegex *reg; GMatchInfo *match; - int vid, pid, bus, addr, b, a, ret, i; char *mstr; + uint32_t num; + + if (vid) *vid = 0; + if (pid) *pid = 0; + if (bus) *bus = 0; + if (addr) *addr = 0; - vid = pid = bus = addr = 0; + valid = TRUE; reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL); if (g_regex_match(reg, conn, 0, &match)) { - if ((mstr = g_match_info_fetch(match, 1))) - vid = strtoul(mstr, NULL, 16); + /* Found a VID:PID style pattern. */ + if ((mstr = g_match_info_fetch(match, 1))) { + num = strtoul(mstr, NULL, 16); + if (num > 0xffff) + valid = FALSE; + if (vid) + *vid = num & 0xffff; + } g_free(mstr); - if ((mstr = g_match_info_fetch(match, 2))) - pid = strtoul(mstr, NULL, 16); + if ((mstr = g_match_info_fetch(match, 2))) { + num = strtoul(mstr, NULL, 16); + if (num > 0xffff) + valid = FALSE; + if (pid) + *pid = num & 0xffff; + } g_free(mstr); - /* Trying to find USB device via 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)) { - if ((mstr = g_match_info_fetch(match, 1))) - bus = strtoul(mstr, NULL, 10); + /* Found a bus.address style pattern. */ + if ((mstr = g_match_info_fetch(match, 1))) { + num = strtoul(mstr, NULL, 10); + if (num > 255) + valid = FALSE; + if (bus) + *bus = num & 0xff; + } g_free(mstr); - if ((mstr = g_match_info_fetch(match, 2))) - addr = strtoul(mstr, NULL, 10); + if ((mstr = g_match_info_fetch(match, 2))) { + num = strtoul(mstr, NULL, 10); + if (num > 127) + valid = FALSE; + if (addr) + *addr = num & 0x7f; + } g_free(mstr); - /* Trying to find USB device via bus.address. */ } } g_match_info_unref(match); g_regex_unref(reg); - if (vid + pid + bus + addr == 0) { - sr_err("Neither VID:PID nor bus.address was specified."); - return NULL; - } + return valid ? SR_OK : SR_ERR_ARG; +} - if (bus > 255) { - sr_err("Invalid bus specified: %d.", bus); +/** + * 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 ".
", or ".". + * + * @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) +{ + struct sr_usb_dev_inst *usb; + struct libusb_device **devlist; + struct libusb_device_descriptor des; + GSList *devices; + uint16_t vid, pid; + uint8_t bus, addr; + int b, a, ret, i; + + ret = sr_usb_split_conn(conn, &vid, &pid, &bus, &addr); + if (ret != SR_OK) { + sr_err("Invalid input, or neither VID:PID nor bus.address specified."); return NULL; } - - if (addr > 127) { - sr_err("Invalid address specified: %d.", addr); + if (!(vid && pid) && !(bus && addr)) { + sr_err("Could neither determine VID:PID nor bus.address numbers."); return NULL; } @@ -373,12 +420,12 @@ SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn) continue; } - if (vid + pid && (des.idVendor != vid || des.idProduct != pid)) + if (vid && pid && (des.idVendor != vid || des.idProduct != pid)) continue; b = libusb_get_bus_number(devlist[i]); a = libusb_get_device_address(devlist[i]); - if (bus + addr && (b != bus || a != addr)) + if (bus && addr && (b != bus || a != addr)) continue; sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = " @@ -456,7 +503,7 @@ SR_PRIV int usb_source_add(struct sr_session *session, struct sr_context *ctx, if (!source) return SR_ERR; - g_source_set_callback(source, (GSourceFunc)cb, cb_data, NULL); + g_source_set_callback(source, G_SOURCE_FUNC(cb), cb_data, NULL); ret = sr_session_source_add_internal(session, ctx->libusb_ctx, source); g_source_unref(source);