serial_hid: add iokit= prefix for the Mac IOKit special case
Rephrase the logic which turns HIDAPI paths returned from enumerations into something that can be used with conn= device options. Rearrange code paths and rename variables to hopefully increase readability, and to prepare support for more conditions in future implementations. Replace the "IOService:" prefix on recent Mac versions with the "iokit=" literal, to eliminate the previously unhandled colon in path names. This resolves bug #1586. Move the allocation of a writable buffer from the callers to the callee, to simplify multiple call sites, and most of all because the caller need not be aware of the buffer's required size (input and output size can differ in either direction). Update the conn=hid/ section in README.devices, add the iokit= prefix.
This commit is contained in:
parent
4feb6ec9a2
commit
d7df9dc738
|
@ -185,6 +185,7 @@ Formal syntax for serial communication:
|
||||||
conn=hid[/<chip>]/usb=<bus>.<dev>[.<if>]
|
conn=hid[/<chip>]/usb=<bus>.<dev>[.<if>]
|
||||||
conn=hid[/<chip>]/raw=<path>
|
conn=hid[/<chip>]/raw=<path>
|
||||||
conn=hid[/<chip>]/sn=<serno>
|
conn=hid[/<chip>]/sn=<serno>
|
||||||
|
conn=hid[/<chip>]/iokit=<path>
|
||||||
chip can be: bu86x, ch9325, cp2110, victor
|
chip can be: bu86x, ch9325, cp2110, victor
|
||||||
path may contain slashes
|
path may contain slashes
|
||||||
path and serno are "greedy" (span to the end of the spec)
|
path and serno are "greedy" (span to the end of the spec)
|
||||||
|
|
115
src/serial_hid.c
115
src/serial_hid.c
|
@ -72,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 */
|
/* {{{ 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
|
* Convert a HIDAPI path (which depends on the target platform, and may
|
||||||
* depend on one of several available API variants on that platform) to
|
* depend on one of several available API variants on that platform) to
|
||||||
|
@ -94,23 +96,50 @@ static char *get_hidapi_path_copy(const char *path)
|
||||||
|
|
||||||
int has_colon;
|
int has_colon;
|
||||||
int is_hex_colon;
|
int is_hex_colon;
|
||||||
char *name;
|
const char *parse, *remain;
|
||||||
|
char *copy;
|
||||||
|
|
||||||
has_colon = strchr(path, ':') != NULL;
|
parse = path;
|
||||||
is_hex_colon = strspn(path, accept) == strlen(path);
|
has_colon = strchr(parse, ':') != NULL;
|
||||||
if (has_colon && !is_hex_colon) {
|
is_hex_colon = strspn(parse, accept) == strlen(parse);
|
||||||
|
if (is_hex_colon) {
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
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);
|
sr_err("Unsupported HIDAPI path format: %s", path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Undo the port name construction that was done during scan. Extract
|
* Undo the port name construction that was done during scan. Extract
|
||||||
|
@ -120,24 +149,32 @@ static char *get_hidapi_path_copy(const char *path)
|
||||||
* Strip off the "raw" prefix, or undo colon substitution. See @ref
|
* Strip off the "raw" prefix, or undo colon substitution. See @ref
|
||||||
* get_hidapi_path_copy() for details.
|
* 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:";
|
static const char *keep = "0123456789abcdefABCDEF:";
|
||||||
|
|
||||||
const char *p;
|
const char *p;
|
||||||
|
char *path;
|
||||||
|
|
||||||
p = buffer;
|
p = copy;
|
||||||
if (!p || !*p)
|
if (!p || !*p)
|
||||||
return NULL;
|
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_RAW_PREFIX);
|
p += strlen(SER_HID_IOKIT_PREFIX);
|
||||||
return p;
|
path = g_strdup_printf("%s%s", IOKIT_PATH_PREFIX, p);
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
if (strncmp(p, SER_HID_USB_PREFIX, strlen(SER_HID_USB_PREFIX)) == 0) {
|
if (g_str_has_prefix(p, SER_HID_RAW_PREFIX)) {
|
||||||
|
p += strlen(SER_HID_RAW_PREFIX);
|
||||||
|
path = g_strdup(p);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
if (g_str_has_prefix(p, SER_HID_USB_PREFIX)) {
|
||||||
p += strlen(SER_HID_USB_PREFIX);
|
p += strlen(SER_HID_USB_PREFIX);
|
||||||
g_strcanon(buffer, keep, ':');
|
path = g_strdup(p);
|
||||||
return p;
|
g_strcanon(path, keep, ':');
|
||||||
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -236,18 +273,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. */
|
/* 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)
|
static int ser_hid_hidapi_get_serno(const char *path, char *buf, size_t blen)
|
||||||
{
|
{
|
||||||
char *usbpath;
|
char *hidpath;
|
||||||
const char *hidpath;
|
|
||||||
hid_device *dev;
|
hid_device *dev;
|
||||||
wchar_t *serno_wch;
|
wchar_t *serno_wch;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (!path || !*path)
|
if (!path || !*path)
|
||||||
return SR_ERR_ARG;
|
return SR_ERR_ARG;
|
||||||
usbpath = g_strdup(path);
|
hidpath = extract_hidapi_path(path);
|
||||||
hidpath = extract_hidapi_path(usbpath);
|
|
||||||
dev = hidpath ? hid_open_path(hidpath) : NULL;
|
dev = hidpath ? hid_open_path(hidpath) : NULL;
|
||||||
g_free(usbpath);
|
g_free(hidpath);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return SR_ERR_IO;
|
return SR_ERR_IO;
|
||||||
|
|
||||||
|
@ -301,17 +336,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
|
* its meaning are said to be OS specific, which is why we may
|
||||||
* not assume anything about it...
|
* not assume anything about it...
|
||||||
*/
|
*/
|
||||||
char *usbpath;
|
char *hidpath;
|
||||||
const char *hidpath;
|
|
||||||
struct hid_device_info *devs, *dev;
|
struct hid_device_info *devs, *dev;
|
||||||
int found;
|
int found;
|
||||||
|
|
||||||
usbpath = g_strdup(path);
|
hidpath = extract_hidapi_path(path);
|
||||||
hidpath = extract_hidapi_path(usbpath);
|
if (!hidpath)
|
||||||
if (!hidpath) {
|
|
||||||
g_free(usbpath);
|
|
||||||
return SR_ERR_NA;
|
return SR_ERR_NA;
|
||||||
}
|
|
||||||
|
|
||||||
devs = hid_enumerate(0x0000, 0x0000);
|
devs = hid_enumerate(0x0000, 0x0000);
|
||||||
found = 0;
|
found = 0;
|
||||||
|
@ -326,7 +357,7 @@ static int ser_hid_hidapi_get_vid_pid(const char *path,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
hid_free_enumeration(devs);
|
hid_free_enumeration(devs);
|
||||||
g_free(usbpath);
|
g_free(hidpath);
|
||||||
|
|
||||||
return found ? SR_OK : SR_ERR_NA;
|
return found ? SR_OK : SR_ERR_NA;
|
||||||
#endif
|
#endif
|
||||||
|
@ -348,6 +379,7 @@ static int ser_hid_hidapi_open_dev(struct sr_serial_dev_inst *serial)
|
||||||
serial->hid_path = extract_hidapi_path(serial->usb_path);
|
serial->hid_path = extract_hidapi_path(serial->usb_path);
|
||||||
hid_dev = hid_open_path(serial->hid_path);
|
hid_dev = hid_open_path(serial->hid_path);
|
||||||
if (!hid_dev) {
|
if (!hid_dev) {
|
||||||
|
g_free((void *)serial->hid_path);
|
||||||
serial->hid_path = NULL;
|
serial->hid_path = NULL;
|
||||||
return SR_ERR_IO;
|
return SR_ERR_IO;
|
||||||
}
|
}
|
||||||
|
@ -363,6 +395,7 @@ static void ser_hid_hidapi_close_dev(struct sr_serial_dev_inst *serial)
|
||||||
if (serial->hid_dev) {
|
if (serial->hid_dev) {
|
||||||
hid_close(serial->hid_dev);
|
hid_close(serial->hid_dev);
|
||||||
serial->hid_dev = NULL;
|
serial->hid_dev = NULL;
|
||||||
|
g_free((void *)serial->hid_path);
|
||||||
serial->hid_path = NULL;
|
serial->hid_path = NULL;
|
||||||
}
|
}
|
||||||
g_slist_free_full(serial->hid_source_args, g_free);
|
g_slist_free_full(serial->hid_source_args, g_free);
|
||||||
|
@ -732,6 +765,12 @@ static int ser_hid_parse_conn_spec(
|
||||||
return rc;
|
return rc;
|
||||||
path = g_strdup(p);
|
path = g_strdup(p);
|
||||||
p += strlen(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)) {
|
} else if (g_str_has_prefix(p, SER_HID_RAW_PREFIX)) {
|
||||||
rc = try_open_path(serial, p);
|
rc = try_open_path(serial, p);
|
||||||
if (rc != SR_OK)
|
if (rc != SR_OK)
|
||||||
|
@ -777,15 +816,13 @@ static int ser_hid_parse_conn_spec(
|
||||||
/* Get and compare serial number. Boolean return value. */
|
/* Get and compare serial number. Boolean return value. */
|
||||||
static int check_serno(const char *path, const char *serno_want)
|
static int check_serno(const char *path, const char *serno_want)
|
||||||
{
|
{
|
||||||
char *usb_path;
|
char *hid_path;
|
||||||
const char *hid_path;
|
|
||||||
char serno_got[128];
|
char serno_got[128];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
usb_path = g_strdup(path);
|
hid_path = extract_hidapi_path(path);
|
||||||
hid_path = extract_hidapi_path(usb_path);
|
|
||||||
rc = ser_hid_hidapi_get_serno(hid_path, serno_got, sizeof(serno_got));
|
rc = ser_hid_hidapi_get_serno(hid_path, serno_got, sizeof(serno_got));
|
||||||
g_free(usb_path);
|
g_free(hid_path);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
sr_dbg("DBG: %s(), could not get serial number", __func__);
|
sr_dbg("DBG: %s(), could not get serial number", __func__);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define SER_HID_CONN_PREFIX "hid"
|
#define SER_HID_CONN_PREFIX "hid"
|
||||||
#define SER_HID_USB_PREFIX "usb="
|
#define SER_HID_USB_PREFIX "usb="
|
||||||
#define SER_HID_RAW_PREFIX "raw="
|
#define SER_HID_RAW_PREFIX "raw="
|
||||||
|
#define SER_HID_IOKIT_PREFIX "iokit="
|
||||||
#define SER_HID_SNR_PREFIX "sn="
|
#define SER_HID_SNR_PREFIX "sn="
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue