genericdmm: more flexible device discovery
This commit is contained in:
parent
75337758d8
commit
bbb40871c8
|
@ -46,9 +46,9 @@ static const int hwcaps[] = {
|
||||||
SR_HWCAP_LIMIT_SAMPLES,
|
SR_HWCAP_LIMIT_SAMPLES,
|
||||||
SR_HWCAP_LIMIT_MSEC,
|
SR_HWCAP_LIMIT_MSEC,
|
||||||
SR_HWCAP_CONTINUOUS,
|
SR_HWCAP_CONTINUOUS,
|
||||||
SR_HWCAP_MODEL,
|
SR_HWOPT_MODEL,
|
||||||
SR_HWCAP_CONN,
|
SR_HWOPT_CONN,
|
||||||
SR_HWCAP_SERIALCOMM,
|
SR_HWOPT_SERIALCOMM,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -63,6 +63,130 @@ static struct sr_dev_driver *gdi = &genericdmm_driver_info;
|
||||||
SR_PRIV libusb_context *genericdmm_usb_context = NULL;
|
SR_PRIV libusb_context *genericdmm_usb_context = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
static GSList *connect_usb(const char *conn)
|
||||||
|
{
|
||||||
|
struct sr_dev_inst *sdi;
|
||||||
|
struct context *ctx;
|
||||||
|
libusb_device **devlist;
|
||||||
|
struct libusb_device_descriptor des;
|
||||||
|
GSList *devices;
|
||||||
|
GRegex *reg;
|
||||||
|
GMatchInfo *match;
|
||||||
|
int vid, pid, bus, addr, devcnt, err, i;
|
||||||
|
char *mstr;
|
||||||
|
|
||||||
|
vid = pid = bus = addr = 0;
|
||||||
|
reg = g_regex_new(DMM_CONN_USB_VIDPID, 0, 0, NULL);
|
||||||
|
if (g_regex_match(reg, conn, 0, &match)) {
|
||||||
|
/* Extract VID. */
|
||||||
|
if ((mstr = g_match_info_fetch(match, 1)))
|
||||||
|
vid = strtoul(mstr, NULL, 16);
|
||||||
|
g_free(mstr);
|
||||||
|
|
||||||
|
/* Extract PID. */
|
||||||
|
if ((mstr = g_match_info_fetch(match, 2)))
|
||||||
|
pid = strtoul(mstr, NULL, 16);
|
||||||
|
g_free(mstr);
|
||||||
|
} else {
|
||||||
|
g_match_info_unref(match);
|
||||||
|
g_regex_unref(reg);
|
||||||
|
reg = g_regex_new(DMM_CONN_USB_BUSADDR, 0, 0, NULL);
|
||||||
|
if (g_regex_match(reg, conn, 0, &match)) {
|
||||||
|
/* Extract bus. */
|
||||||
|
if ((mstr = g_match_info_fetch(match, 0)))
|
||||||
|
bus = strtoul(mstr, NULL, 16);
|
||||||
|
g_free(mstr);
|
||||||
|
|
||||||
|
/* Extract address. */
|
||||||
|
if ((mstr = g_match_info_fetch(match, 0)))
|
||||||
|
addr = strtoul(mstr, NULL, 16);
|
||||||
|
g_free(mstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_match_info_unref(match);
|
||||||
|
g_regex_unref(reg);
|
||||||
|
|
||||||
|
if (vid + pid + bus + addr == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (bus > 64) {
|
||||||
|
sr_err("invalid bus");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr > 127) {
|
||||||
|
sr_err("invalid address");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Looks like a valid USB device specification, but is it connected? */
|
||||||
|
devices = NULL;
|
||||||
|
libusb_get_device_list(genericdmm_usb_context, &devlist);
|
||||||
|
for (i = 0; devlist[i]; i++) {
|
||||||
|
if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
|
||||||
|
sr_err("genericdmm: failed to get device descriptor: %d", err);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vid + pid && (des.idVendor != vid || des.idProduct != pid))
|
||||||
|
/* VID/PID specified, but no match. */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bus + addr && (
|
||||||
|
libusb_get_bus_number(devlist[i]) != bus
|
||||||
|
|| libusb_get_device_address(devlist[i]) != addr))
|
||||||
|
/* Bus/address specified, but no match. */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Found one. */
|
||||||
|
if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
|
||||||
|
sr_err("genericdmm: ctx malloc failed.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
devcnt = g_slist_length(gdi->instances);
|
||||||
|
if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE,
|
||||||
|
"Generic DMM", NULL, NULL))) {
|
||||||
|
sr_err("genericdmm: sr_dev_inst_new returned NULL.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
sdi->priv = ctx;
|
||||||
|
ctx->usb = sr_usb_dev_inst_new(
|
||||||
|
libusb_get_bus_number(devlist[i]),
|
||||||
|
libusb_get_device_address(devlist[i]), NULL);
|
||||||
|
devices = g_slist_append(devices, sdi);
|
||||||
|
}
|
||||||
|
libusb_free_device_list(devlist, 1);
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSList *connect_serial(const char *conn, const char *serialcomm)
|
||||||
|
{
|
||||||
|
GSList *devices;
|
||||||
|
|
||||||
|
devices = NULL;
|
||||||
|
|
||||||
|
/* TODO */
|
||||||
|
sr_dbg("not yet implemented");
|
||||||
|
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSList *genericdmm_connect(const char *conn, const char *serialcomm)
|
||||||
|
{
|
||||||
|
GSList *devices;
|
||||||
|
|
||||||
|
if (serialcomm)
|
||||||
|
/* Must be a serial port. */
|
||||||
|
return connect_serial(conn, serialcomm);
|
||||||
|
|
||||||
|
if ((devices = connect_usb(conn)))
|
||||||
|
return devices;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int hw_init(void)
|
static int hw_init(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -282,179 +406,10 @@ static const int *hw_hwcap_get_all(void)
|
||||||
return hwcaps;
|
return hwcaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_conn_vidpid(struct sr_dev_inst *sdi, const char *conn)
|
|
||||||
{
|
|
||||||
struct context *ctx;
|
|
||||||
libusb_device **devlist;
|
|
||||||
struct libusb_device_descriptor des;
|
|
||||||
GRegex *reg;
|
|
||||||
GMatchInfo *match;
|
|
||||||
int vid, pid, found, err, i;
|
|
||||||
char *vidstr, *pidstr;
|
|
||||||
|
|
||||||
found = FALSE;
|
|
||||||
|
|
||||||
reg = g_regex_new(DMM_CONN_USB_VIDPID, 0, 0, NULL);
|
|
||||||
if (g_regex_match(reg, conn, 0, &match)) {
|
|
||||||
/* Extract VID. */
|
|
||||||
if (!(vidstr = g_match_info_fetch(match, 0))) {
|
|
||||||
sr_err("failed to fetch VID from regex");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
vid = strtoul(vidstr, NULL, 16);
|
|
||||||
g_free(vidstr);
|
|
||||||
if (vid > 0xffff) {
|
|
||||||
sr_err("invalid VID");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract PID. */
|
|
||||||
if (!(pidstr = g_match_info_fetch(match, 0))) {
|
|
||||||
sr_err("failed to fetch PID from regex");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
pid = strtoul(pidstr, NULL, 16);
|
|
||||||
g_free(pidstr);
|
|
||||||
if (pid > 0xffff) {
|
|
||||||
sr_err("invalid PID");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Looks like a valid VID:PID, but is it connected? */
|
|
||||||
libusb_get_device_list(genericdmm_usb_context, &devlist);
|
|
||||||
for (i = 0; devlist[i]; i++) {
|
|
||||||
if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
|
|
||||||
sr_err("genericdmm: failed to get device descriptor: %d", err);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (des.idVendor == vid && des.idProduct == pid) {
|
|
||||||
ctx = sdi->priv;
|
|
||||||
ctx->usb = sr_usb_dev_inst_new(
|
|
||||||
libusb_get_bus_number(devlist[i]),
|
|
||||||
libusb_get_device_address(devlist[i]), NULL);
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
libusb_free_device_list(devlist, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (match)
|
|
||||||
g_match_info_unref(match);
|
|
||||||
g_regex_unref(reg);
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_conn_busaddr(struct sr_dev_inst *sdi, const char *conn)
|
|
||||||
{
|
|
||||||
struct context *ctx;
|
|
||||||
libusb_device **devlist;
|
|
||||||
struct libusb_device_descriptor des;
|
|
||||||
GRegex *reg;
|
|
||||||
GMatchInfo *match;
|
|
||||||
int bus, addr, found, err, i;
|
|
||||||
char *busstr, *addrstr;
|
|
||||||
|
|
||||||
found = FALSE;
|
|
||||||
|
|
||||||
reg = g_regex_new(DMM_CONN_USB_BUSADDR, 0, 0, NULL);
|
|
||||||
if (g_regex_match(reg, conn, 0, &match)) {
|
|
||||||
/* Extract bus. */
|
|
||||||
if (!(busstr = g_match_info_fetch(match, 0))) {
|
|
||||||
sr_err("failed to fetch bus from regex");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
bus = strtoul(busstr, NULL, 16);
|
|
||||||
g_free(busstr);
|
|
||||||
if (bus > 64) {
|
|
||||||
sr_err("invalid bus");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Extract address. */
|
|
||||||
if (!(addrstr = g_match_info_fetch(match, 0))) {
|
|
||||||
sr_err("failed to fetch address from regex");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
addr = strtoul(addrstr, NULL, 16);
|
|
||||||
g_free(addrstr);
|
|
||||||
if (addr > 127) {
|
|
||||||
sr_err("invalid address");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Looks like a valid bus/address, but is it connected? */
|
|
||||||
libusb_get_device_list(genericdmm_usb_context, &devlist);
|
|
||||||
for (i = 0; devlist[i]; i++) {
|
|
||||||
if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
|
|
||||||
sr_err("genericdmm: failed to get device descriptor: %d", err);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (libusb_get_bus_number(devlist[i]) == bus
|
|
||||||
&& libusb_get_device_address(devlist[i]) == addr) {
|
|
||||||
ctx = sdi->priv;
|
|
||||||
ctx->usb = sr_usb_dev_inst_new(bus, addr, NULL);
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
libusb_free_device_list(devlist, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (match)
|
|
||||||
g_match_info_unref(match);
|
|
||||||
g_regex_unref(reg);
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_conn_serial(struct sr_dev_inst *sdi, const char *conn)
|
|
||||||
{
|
|
||||||
int found;
|
|
||||||
|
|
||||||
found = FALSE;
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_conn(struct sr_dev_inst *sdi, const char *conn)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (parse_conn_vidpid(sdi, conn))
|
|
||||||
return SR_OK;
|
|
||||||
|
|
||||||
if (parse_conn_busaddr(sdi, conn))
|
|
||||||
return SR_OK;
|
|
||||||
|
|
||||||
if (parse_conn_serial(sdi, conn))
|
|
||||||
return SR_OK;
|
|
||||||
|
|
||||||
sr_err("Invalid connection specification");
|
|
||||||
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_serialcomm(struct sr_dev_inst *sdi, const char *conn)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* TODO */
|
|
||||||
/* set ctx->serial_* */
|
|
||||||
|
|
||||||
return SR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
|
static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
|
||||||
{
|
{
|
||||||
struct sr_dev_inst *sdi;
|
struct sr_dev_inst *sdi;
|
||||||
struct context *ctx;
|
struct context *ctx;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
|
if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) {
|
||||||
sr_err("genericdmm: sdi was NULL.");
|
sr_err("genericdmm: sdi was NULL.");
|
||||||
|
@ -483,36 +438,6 @@ static int hw_dev_config_set(int dev_index, int hwcap, const void *value)
|
||||||
sr_dbg("genericdmm: Setting LIMIT_SAMPLES to %" PRIu64 ".",
|
sr_dbg("genericdmm: Setting LIMIT_SAMPLES to %" PRIu64 ".",
|
||||||
ctx->limit_samples);
|
ctx->limit_samples);
|
||||||
break;
|
break;
|
||||||
case SR_HWCAP_MODEL:
|
|
||||||
for (i = 0; dev_profiles[i].model; i++) {
|
|
||||||
if (!strcasecmp(dev_profiles[i].model, value)) {
|
|
||||||
ctx->profile = &dev_profiles[i];
|
|
||||||
/* Frontends access these fields directly, so we
|
|
||||||
* need to copy them over. */
|
|
||||||
sdi->vendor = g_strdup(dev_profiles[i].vendor);
|
|
||||||
sdi->model = g_strdup(dev_profiles[i].model);
|
|
||||||
/* This is the first time we actually know which
|
|
||||||
* DMM chip we're talking to, so let's init
|
|
||||||
* anything specific to it now */
|
|
||||||
if (ctx->profile->chip->init)
|
|
||||||
if (ctx->profile->chip->init(ctx) != SR_OK)
|
|
||||||
return SR_ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!ctx->profile) {
|
|
||||||
sr_err("unknown model %s", value);
|
|
||||||
return SR_ERR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SR_HWCAP_CONN:
|
|
||||||
if (parse_conn(sdi, value) != SR_OK)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
break;
|
|
||||||
case SR_HWCAP_SERIALCOMM:
|
|
||||||
if (parse_serialcomm(sdi, value) != SR_OK)
|
|
||||||
return SR_ERR_ARG;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
sr_err("genericdmm: Unknown capability: %d.", hwcap);
|
sr_err("genericdmm: Unknown capability: %d.", hwcap);
|
||||||
return SR_ERR;
|
return SR_ERR;
|
||||||
|
|
Loading…
Reference in New Issue