X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fserial_hid.c;h=759a58c487499aeb5f82d18c5ef779166dfc7610;hb=HEAD;hp=86361d92b4ba218b47976b0b838a53602f622ff2;hpb=60117e6e9aa22d8da1f34ccfa1b819300bad7bf0;p=libsigrok.git diff --git a/src/serial_hid.c b/src/serial_hid.c index 86361d92..759a58c4 100644 --- a/src/serial_hid.c +++ b/src/serial_hid.c @@ -31,9 +31,7 @@ #include /* for HANDLE */ #endif -/** @cond PRIVATE */ #define LOG_PREFIX "serial-hid" -/** @endcond */ #ifdef HAVE_SERIAL_COMM @@ -74,6 +72,8 @@ static void ser_hid_mask_databits(struct sr_serial_dev_inst *serial, /* }}} */ /* {{{ open/close/list/find HIDAPI connection, exchange HID requests and data */ +#define IOKIT_PATH_PREFIX "IOService:" + /* * Convert a HIDAPI path (which depends on the target platform, and may * depend on one of several available API variants on that platform) to @@ -96,22 +96,49 @@ static char *get_hidapi_path_copy(const char *path) int has_colon; int is_hex_colon; - char *name; + const char *parse, *remain; + char *copy; - has_colon = strchr(path, ':') != NULL; - is_hex_colon = strspn(path, accept) == strlen(path); - if (has_colon && !is_hex_colon) { - sr_err("Unsupported HIDAPI path format: %s", path); - return NULL; - } + parse = path; + has_colon = strchr(parse, ':') != NULL; + is_hex_colon = strspn(parse, accept) == strlen(parse); if (is_hex_colon) { - name = g_strdup_printf("%s%s", SER_HID_USB_PREFIX, path); - g_strcanon(name + strlen(SER_HID_USB_PREFIX), keep, '.'); - } else { - name = g_strdup_printf("%s%s", SER_HID_RAW_PREFIX, path); + /* All hex digits and colon only. Simple substitution. */ + copy = g_strdup_printf("%s%s", SER_HID_USB_PREFIX, parse); + g_strcanon(copy + strlen(SER_HID_USB_PREFIX), keep, '.'); + return copy; } - - return name; + if (!has_colon) { + /* "Something raw" and no colon. Add raw= prefix. */ + copy = g_strdup_printf("%s%s", SER_HID_RAW_PREFIX, parse); + return copy; + } + if (g_str_has_prefix(parse, IOKIT_PATH_PREFIX)) do { + /* + * Path starts with Mac IOKit literal which contains the + * colon. Drop that literal from the start of the path, + * and check whether any colon remains which we cannot + * deal with. Fall though to other approaches which could + * be more generic, or to the error path. + */ + remain = &parse[strlen(IOKIT_PATH_PREFIX)]; + if (strchr(remain, ':')) + break; + copy = g_strdup_printf("%s%s", SER_HID_IOKIT_PREFIX, remain); + return copy; + } while (0); + + /* TODO + * Consider adding support for more of the currently unhandled + * cases. When we get here, the HIDAPI path could be arbitrarily + * complex, none of the above "straight" approaches took effect. + * Proper escaping or other transformations could get applied, + * though they decrease usability the more they obfuscate the + * resulting port name. Ideally users remain able to recognize + * their device or cable or port after the manipulation. + */ + sr_err("Unsupported HIDAPI path format: %s", path); + return NULL; } /* @@ -122,33 +149,42 @@ static char *get_hidapi_path_copy(const char *path) * Strip off the "raw" prefix, or undo colon substitution. See @ref * get_hidapi_path_copy() for details. */ -static const char *extract_hidapi_path(char *buffer) +static char *extract_hidapi_path(const char *copy) { static const char *keep = "0123456789abcdefABCDEF:"; const char *p; + char *path; - p = buffer; + p = copy; if (!p || !*p) return NULL; - if (strncmp(p, SER_HID_RAW_PREFIX, strlen(SER_HID_RAW_PREFIX)) == 0) { + if (g_str_has_prefix(p, SER_HID_IOKIT_PREFIX)) { + p += strlen(SER_HID_IOKIT_PREFIX); + path = g_strdup_printf("%s%s", IOKIT_PATH_PREFIX, p); + return path; + } + if (g_str_has_prefix(p, SER_HID_RAW_PREFIX)) { p += strlen(SER_HID_RAW_PREFIX); - return p; + path = g_strdup(p); + return path; } - if (strncmp(p, SER_HID_USB_PREFIX, strlen(SER_HID_USB_PREFIX)) == 0) { + if (g_str_has_prefix(p, SER_HID_USB_PREFIX)) { p += strlen(SER_HID_USB_PREFIX); - g_strcanon(buffer, keep, ':'); - return p; + path = g_strdup(p); + g_strcanon(path, keep, ':'); + return path; } return NULL; } /* - * The HIDAPI specific list() callback, invoked by common serial.c code. - * Enumerate all devices (no VID:PID is involved). - * Invoke an 'append' callback with "path" and "name". + * Enumerate all devices (no VID:PID is involved). Invoke an 'append' + * callback with "path" and "name". Exclusively list connections that + * involve supported chip types, because mice and keyboards etc are not + * too useful to communicate to measurement equipment. */ static GSList *ser_hid_hidapi_list(GSList *list, sr_ser_list_append_t append) { @@ -162,14 +198,14 @@ static GSList *ser_hid_hidapi_list(GSList *list, sr_ser_list_append_t append) devs = hid_enumerate(0x0000, 0x0000); for (curdev = devs; curdev; curdev = curdev->next) { /* - * Determine the chip name from VID:PID (if it's one of - * the supported types with an ID known to us). + * Determine the chip name from VID:PID. Exlusively list + * supported connection types (known chips). */ vid = curdev->vendor_id; pid = curdev->product_id; chipname = ser_hid_chip_find_name_vid_pid(vid, pid); if (!chipname) - chipname = ""; + continue; /* * Prefix port names such that open() calls with this @@ -215,19 +251,36 @@ static GSList *ser_hid_hidapi_list(GSList *list, sr_ser_list_append_t append) } /* - * The HIDAPI specific find_usb() callback, invoked by common serial.c code. - * Enumerate devices for the specified VID:PID pair. - * Invoke an "append" callback with 'path' for the device. + * Enumerate devices for the specified VID:PID pair. Invoke an "append" + * callback with 'path' for found devices. Exclusively finds supported + * chip types, skips unknown VID:PID pairs (even if caller specified). */ static GSList *ser_hid_hidapi_find_usb(GSList *list, sr_ser_find_append_t append, uint16_t vendor_id, uint16_t product_id) { + const char *caller_chip; + const char *dev_chip; struct hid_device_info *devs, *curdev; const char *name; + char *path; + + caller_chip = ser_hid_chip_find_name_vid_pid(vendor_id, product_id); devs = hid_enumerate(vendor_id, product_id); for (curdev = devs; curdev; curdev = curdev->next) { - name = curdev->path; + dev_chip = caller_chip; + if (!dev_chip) { + dev_chip = ser_hid_chip_find_name_vid_pid( + curdev->vendor_id, curdev->product_id); + } + if (!dev_chip) + continue; + path = get_hidapi_path_copy(curdev->path); + if (!path) + continue; + name = g_strdup_printf("%s/%s/%s", + SER_HID_CONN_PREFIX, dev_chip, path); + g_free(path); list = append(list, name); } hid_free_enumeration(devs); @@ -238,18 +291,16 @@ static GSList *ser_hid_hidapi_find_usb(GSList *list, sr_ser_find_append_t append /* Get the serial number of a device specified by path. */ static int ser_hid_hidapi_get_serno(const char *path, char *buf, size_t blen) { - char *usbpath; - const char *hidpath; + char *hidpath; hid_device *dev; wchar_t *serno_wch; int rc; if (!path || !*path) return SR_ERR_ARG; - usbpath = g_strdup(path); - hidpath = extract_hidapi_path(usbpath); + hidpath = extract_hidapi_path(path); dev = hidpath ? hid_open_path(hidpath) : NULL; - g_free(usbpath); + g_free(hidpath); if (!dev) return SR_ERR_IO; @@ -303,17 +354,13 @@ static int ser_hid_hidapi_get_vid_pid(const char *path, * its meaning are said to be OS specific, which is why we may * not assume anything about it... */ - char *usbpath; - const char *hidpath; + char *hidpath; struct hid_device_info *devs, *dev; int found; - usbpath = g_strdup(path); - hidpath = extract_hidapi_path(usbpath); - if (!hidpath) { - g_free(usbpath); + hidpath = extract_hidapi_path(path); + if (!hidpath) return SR_ERR_NA; - } devs = hid_enumerate(0x0000, 0x0000); found = 0; @@ -328,7 +375,7 @@ static int ser_hid_hidapi_get_vid_pid(const char *path, break; } hid_free_enumeration(devs); - g_free(usbpath); + g_free(hidpath); return found ? SR_OK : SR_ERR_NA; #endif @@ -350,6 +397,7 @@ static int ser_hid_hidapi_open_dev(struct sr_serial_dev_inst *serial) serial->hid_path = extract_hidapi_path(serial->usb_path); hid_dev = hid_open_path(serial->hid_path); if (!hid_dev) { + g_free((void *)serial->hid_path); serial->hid_path = NULL; return SR_ERR_IO; } @@ -365,6 +413,7 @@ static void ser_hid_hidapi_close_dev(struct sr_serial_dev_inst *serial) if (serial->hid_dev) { hid_close(serial->hid_dev); serial->hid_dev = NULL; + g_free((void *)serial->hid_path); serial->hid_path = NULL; } g_slist_free_full(serial->hid_source_args, g_free); @@ -665,8 +714,6 @@ static int try_open_path(struct sr_serial_dev_inst *serial, const char *path) * @return 0 upon success, non-zero upon failure. Fills the *_ref output * values. * - * @internal - * * Summary of parsing rules as they are implemented: * - Insist on the "hid" prefix. Accept "hid" alone without any other * additional field. @@ -736,6 +783,12 @@ static int ser_hid_parse_conn_spec( return rc; path = g_strdup(p); p += strlen(p); + } else if (g_str_has_prefix(p, SER_HID_IOKIT_PREFIX)) { + rc = try_open_path(serial, p); + if (rc != SR_OK) + return rc; + path = g_strdup(p); + p += strlen(p); } else if (g_str_has_prefix(p, SER_HID_RAW_PREFIX)) { rc = try_open_path(serial, p); if (rc != SR_OK) @@ -781,15 +834,13 @@ static int ser_hid_parse_conn_spec( /* Get and compare serial number. Boolean return value. */ static int check_serno(const char *path, const char *serno_want) { - char *usb_path; - const char *hid_path; + char *hid_path; char serno_got[128]; int rc; - usb_path = g_strdup(path); - hid_path = extract_hidapi_path(usb_path); + hid_path = extract_hidapi_path(path); rc = ser_hid_hidapi_get_serno(hid_path, serno_got, sizeof(serno_got)); - g_free(usb_path); + g_free(hid_path); if (rc) { sr_dbg("DBG: %s(), could not get serial number", __func__); return 0; @@ -845,8 +896,6 @@ static GSList *list_paths_for_vids_pids(const struct vid_pid_item *vid_pids) * @retval SR_OK upon success * @retval SR_ERR_* upon failure. * - * @internal - * * This routine fills in blanks which the conn= spec parser left open. * When not specified yet, the HID chip type gets determined. When a * serial number was specified, then search the corresponding device. @@ -994,6 +1043,7 @@ static int ser_hid_chip_search(enum ser_hid_chip_t *chip_ref, return SR_ERR_NA; have_chip = 1; } + (void)have_chip; if (chip_ref) *chip_ref = chip; @@ -1309,6 +1359,7 @@ static struct ser_lib_functions serlib_hid = { .write = ser_hid_write, .read = ser_hid_read, .set_params = ser_hid_set_params, + .set_handshake = std_dummy_set_handshake, .setup_source_add = ser_hid_setup_source_add, .setup_source_remove = ser_hid_setup_source_remove, .list = ser_hid_list,