X-Git-Url: http://sigrok.org/gitweb/?a=blobdiff_plain;f=hardware%2Fgenericdmm%2Fapi.c;h=e83bce16ea967b18da4ca37c0f9bced91fba107c;hb=19b0cce3125f08f961886fb312219c7c6f496ffc;hp=c182b039d1110dea7520d6c70c8c2622e64619f2;hpb=25a0f108f4512ade836fed128c3ad649dedcb788;p=libsigrok.git diff --git a/hardware/genericdmm/api.c b/hardware/genericdmm/api.c index c182b039..e83bce16 100644 --- a/hardware/genericdmm/api.c +++ b/hardware/genericdmm/api.c @@ -28,17 +28,18 @@ extern SR_PRIV struct dmmchip dmmchip_fs9922; +extern SR_PRIV struct dmmchip dmmchip_victor70c; static struct sr_hwopt victor_70c_vidpid[] = { { SR_HWOPT_CONN, "1244.d237" }, { 0, NULL } }; static struct dev_profile dev_profiles[] = { - { "victor-70c", "Victor", "70C", &dmmchip_fs9922, - DMM_TRANSPORT_USBHID, victor_70c_vidpid + { "victor-70c", "Victor", "70C", &dmmchip_victor70c, + DMM_TRANSPORT_USBHID, 1000, victor_70c_vidpid }, - { "mastech-va18b", "Mastech", "VA18B", NULL, DMM_TRANSPORT_SERIAL, NULL}, - { NULL, NULL, NULL, NULL, 0, NULL } + { "mastech-va18b", "Mastech", "VA18B", NULL, DMM_TRANSPORT_SERIAL, 0, NULL}, + { NULL, NULL, NULL, NULL, 0, 0, NULL } }; static const int hwopts[] = { @@ -64,13 +65,17 @@ static const char *probe_names[] = { SR_PRIV struct sr_dev_driver genericdmm_driver_info; static struct sr_dev_driver *gdi = &genericdmm_driver_info; /* TODO need a way to keep this local to the static library */ -SR_PRIV libusb_context *genericdmm_usb_context = NULL; +static libusb_context *genericdmm_usb_context = NULL; +static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, + void *cb_data); static GSList *connect_usb(const char *conn) { struct sr_dev_inst *sdi; - struct context *ctx; + struct drv_context *drvc; + struct dev_context *devc; + struct sr_probe *probe; libusb_device **devlist; struct libusb_device_descriptor des; GSList *devices; @@ -79,6 +84,8 @@ static GSList *connect_usb(const char *conn) int vid, pid, bus, addr, devcnt, err, i; char *mstr; + drvc = gdi->priv; + vid = pid = bus = addr = 0; reg = g_regex_new(DMM_CONN_USB_VIDPID, 0, 0, NULL); if (g_regex_match(reg, conn, 0, &match)) { @@ -143,19 +150,22 @@ static GSList *connect_usb(const char *conn) continue; /* Found one. */ - if (!(ctx = g_try_malloc0(sizeof(struct context)))) { - sr_err("genericdmm: ctx malloc failed."); + if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) { + sr_err("genericdmm: devc malloc failed."); return 0; } - devcnt = g_slist_length(gdi->instances); - if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, + devcnt = g_slist_length(drvc->instances); + if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE, NULL, NULL, NULL))) { sr_err("genericdmm: sr_dev_inst_new returned NULL."); return NULL; } - sdi->priv = ctx; - ctx->usb = sr_usb_dev_inst_new( + sdi->priv = devc; + if (!(probe = sr_probe_new(0, SR_PROBE_ANALOG, TRUE, "P1"))) + return NULL; + sdi->probes = g_slist_append(sdi->probes, probe); + devc->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); @@ -216,14 +226,112 @@ static GSList *default_scan(GSList *options) return devices; } +static int open_usb(struct sr_dev_inst *sdi) +{ + libusb_device **devlist; + struct libusb_device_descriptor des; + struct dev_context *devc; + int ret, tmp, cnt, i; + + devc = sdi->priv; + + if (sdi->status == SR_ST_ACTIVE) + /* already in use */ + return SR_ERR; + + cnt = libusb_get_device_list(genericdmm_usb_context, &devlist); + if (cnt < 0) { + sr_err("genericdmm: Failed to retrieve device list (%d)", cnt); + return SR_ERR; + } + + ret = SR_ERR; + for (i = 0; i < cnt; i++) { + if ((tmp = libusb_get_device_descriptor(devlist[i], &des))) { + sr_err("genericdmm: Failed to get device descriptor: %d.", tmp); + continue; + } + + if (libusb_get_bus_number(devlist[i]) != devc->usb->bus + || libusb_get_device_address(devlist[i]) != devc->usb->address) + /* this is not the one */ + continue; + + if ((tmp = libusb_open(devlist[i], &devc->usb->devhdl))) { + sr_err("genericdmm: Failed to open device: %d.", tmp); + break; + } + + sr_info("genericdmm: Opened device %s on %d.%d ", devc->profile->modelid, + devc->usb->bus, devc->usb->address); + ret = SR_OK; + break; + } + libusb_free_device_list(devlist, 1); + + return ret; +} + +static int clear_instances(void) +{ + GSList *l; + struct sr_dev_inst *sdi; + struct dev_context *devc; + struct drv_context *drvc; + + if (!(drvc = gdi->priv)) + return SR_OK; + + /* Properly close and free all devices. */ + for (l = drvc->instances; l; l = l->next) { + if (!(sdi = l->data)) { + /* Log error, but continue cleaning up the rest. */ + sr_err("genericdmm: sdi was NULL, continuing."); + continue; + } + if (!(devc = sdi->priv)) { + /* Log error, but continue cleaning up the rest. */ + sr_err("genericdmm: sdi->priv was NULL, continuing."); + continue; + } + + if (devc->profile) { + switch (devc->profile->transport) { + case DMM_TRANSPORT_USBHID: + sr_usb_dev_inst_free(devc->usb); + break; + case DMM_TRANSPORT_SERIAL: + if (devc->serial && devc->serial->fd != -1) + serial_close(devc->serial->fd); + sr_serial_dev_inst_free(devc->serial); + break; + } + } + + sr_dev_inst_free(sdi); + } + + g_slist_free(drvc->instances); + drvc->instances = NULL; + + return SR_OK; +} + static int hw_init(void) { + struct drv_context *drvc; + + if (!(drvc = g_try_malloc0(sizeof(struct drv_context)))) { + sr_err("genericdmm: driver context malloc failed."); + return SR_ERR; + } if (libusb_init(&genericdmm_usb_context) != 0) { sr_err("genericdmm: Failed to initialize USB."); return SR_ERR; } + gdi->priv = drvc; return SR_OK; } @@ -234,8 +342,12 @@ static GSList *hw_scan(GSList *options) struct sr_hwopt *opt, *defopt; struct dev_profile *pr, *profile; struct sr_dev_inst *sdi; + struct drv_context *drvc; + struct dev_context *devc; const char *model; + drvc = gdi->priv; + /* Separate model from the options list. */ model = NULL; newopts = NULL; @@ -312,68 +424,80 @@ static GSList *hw_scan(GSList *options) * or model. Do that now. */ sdi = l->data; + devc = sdi->priv; + devc->profile = profile; sdi->driver = gdi; if (!sdi->vendor) sdi->vendor = g_strdup(profile->vendor); if (!sdi->model) sdi->model = g_strdup(profile->model); /* Add a copy of these new devices to the driver instances. */ - gdi->instances = g_slist_append(gdi->instances, l->data); + drvc->instances = g_slist_append(drvc->instances, l->data); } } return devices; } +static GSList *hw_dev_list(void) +{ + struct drv_context *drvc; + + drvc = gdi->priv; + + return drvc->instances; +} + static int hw_dev_open(struct sr_dev_inst *sdi) { - struct context *ctx; + struct dev_context *devc; + int ret; - if (!(ctx = sdi->priv)) { + if (!(devc = sdi->priv)) { sr_err("genericdmm: sdi->priv was NULL."); return SR_ERR_BUG; } - sr_dbg("genericdmm: Opening serial port '%s'.", ctx->serial->port); - - switch (ctx->profile->transport) { + ret = SR_OK; + switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: - /* TODO */ + ret = open_usb(sdi); break; case DMM_TRANSPORT_SERIAL: - /* TODO: O_NONBLOCK? */ - ctx->serial->fd = serial_open(ctx->serial->port, O_RDWR | O_NONBLOCK); - if (ctx->serial->fd == -1) { + sr_dbg("genericdmm: Opening serial port '%s'.", devc->serial->port); + devc->serial->fd = serial_open(devc->serial->port, O_RDWR | O_NONBLOCK); + if (devc->serial->fd == -1) { sr_err("genericdmm: Couldn't open serial port '%s'.", - ctx->serial->port); - return SR_ERR; + devc->serial->port); + ret = SR_ERR; } - // serial_set_params(ctx->serial->fd, 2400, 8, 0, 1, 2); + // serial_set_params(devc->serial->fd, 2400, 8, 0, 1, 2); break; default: sr_err("No transport set."); + ret = SR_ERR; } - return SR_OK; + return ret; } static int hw_dev_close(struct sr_dev_inst *sdi) { - struct context *ctx; + struct dev_context *devc; - if (!(ctx = sdi->priv)) { + if (!(devc = sdi->priv)) { sr_err("genericdmm: %s: sdi->priv was NULL.", __func__); return SR_ERR_BUG; } - switch (ctx->profile->transport) { + switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: /* TODO */ break; case DMM_TRANSPORT_SERIAL: - if (ctx->serial && ctx->serial->fd != -1) { - serial_close(ctx->serial->fd); - ctx->serial->fd = -1; + if (devc->serial && devc->serial->fd != -1) { + serial_close(devc->serial->fd); + devc->serial->fd = -1; sdi->status = SR_ST_INACTIVE; } break; @@ -384,41 +508,8 @@ static int hw_dev_close(struct sr_dev_inst *sdi) static int hw_cleanup(void) { - GSList *l; - struct sr_dev_inst *sdi; - struct context *ctx; - - /* Properly close and free all devices. */ - for (l = gdi->instances; l; l = l->next) { - if (!(sdi = l->data)) { - /* Log error, but continue cleaning up the rest. */ - sr_err("genericdmm: sdi was NULL, continuing."); - continue; - } - if (!(ctx = sdi->priv)) { - /* Log error, but continue cleaning up the rest. */ - sr_err("genericdmm: sdi->priv was NULL, continuing."); - continue; - } - - if (ctx->profile) { - switch (ctx->profile->transport) { - case DMM_TRANSPORT_USBHID: - /* TODO */ - break; - case DMM_TRANSPORT_SERIAL: - if (ctx->serial && ctx->serial->fd != -1) - serial_close(ctx->serial->fd); - sr_serial_dev_inst_free(ctx->serial); - break; - } - } - - sr_dev_inst_free(sdi); - } - g_slist_free(gdi->instances); - gdi->instances = NULL; + clear_instances(); if (genericdmm_usb_context) libusb_exit(genericdmm_usb_context); @@ -426,16 +517,15 @@ static int hw_cleanup(void) return SR_OK; } -static int hw_info_get(int dev_info_id, const void **data, +static int hw_info_get(int info_id, const void **data, const struct sr_dev_inst *sdi) { - struct context *ctx; + struct dev_context *devc; - switch (dev_info_id) { - case SR_DI_INST: - *data = sdi; - sr_spew("genericdmm: Returning sdi."); - break; + (void)sdi; + (void)devc; + + switch (info_id) { case SR_DI_HWOPTS: *data = hwopts; break; @@ -451,6 +541,7 @@ static int hw_info_get(int dev_info_id, const void **data, case SR_DI_CUR_SAMPLERATE: /* TODO get rid of this */ *data = NULL; + return SR_ERR_ARG; break; default: /* Unknown device info ID. */ @@ -460,44 +551,31 @@ static int hw_info_get(int dev_info_id, const void **data, return SR_OK; } -static int hw_dev_status_get(int dev_index) -{ - struct sr_dev_inst *sdi; - - if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { - sr_err("genericdmm: sdi was NULL, device not found."); - return SR_ST_NOT_FOUND; - } - - sr_dbg("genericdmm: Returning status: %d.", sdi->status); - - return sdi->status; -} - static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap, const void *value) { - struct context *ctx; + struct dev_context *devc; - if (!(ctx = sdi->priv)) { + if (!(devc = sdi->priv)) { sr_err("genericdmm: sdi->priv was NULL."); return SR_ERR_BUG; } switch (hwcap) { case SR_HWCAP_LIMIT_MSEC: + /* TODO: not yet implemented */ if (*(const uint64_t *)value == 0) { sr_err("genericdmm: LIMIT_MSEC can't be 0."); return SR_ERR; } - ctx->limit_msec = *(const uint64_t *)value; - sr_dbg("genericdmm: Setting LIMIT_MSEC to %" PRIu64 ".", - ctx->limit_msec); + devc->limit_msec = *(const uint64_t *)value; + sr_dbg("genericdmm: Setting time limit to %" PRIu64 "ms.", + devc->limit_msec); break; case SR_HWCAP_LIMIT_SAMPLES: - ctx->limit_samples = *(const uint64_t *)value; - sr_dbg("genericdmm: Setting LIMIT_SAMPLES to %" PRIu64 ".", - ctx->limit_samples); + devc->limit_samples = *(const uint64_t *)value; + sr_dbg("genericdmm: Setting sample limit to %" PRIu64 ".", + devc->limit_samples); break; default: sr_err("genericdmm: Unknown capability: %d.", hwcap); @@ -511,52 +589,49 @@ static int hw_dev_config_set(const struct sr_dev_inst *sdi, int hwcap, static int receive_data(int fd, int revents, void *cb_data) { struct sr_dev_inst *sdi; - struct context *ctx; + struct dev_context *devc; - if (!(sdi = cb_data)) - return FALSE; + (void)revents; - if (!(ctx = sdi->priv)) - return FALSE; + if (!(sdi = cb_data)) + return TRUE; - if (revents != G_IO_IN) { - sr_err("genericdmm: No data?"); - return FALSE; - } + if (!(devc = sdi->priv)) + return TRUE; - switch (ctx->profile->transport) { + switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: - /* TODO */ + if (devc->profile->chip->data) + devc->profile->chip->data(sdi); break; case DMM_TRANSPORT_SERIAL: /* TODO */ + fd = fd; break; } + if (devc->num_samples >= devc->limit_samples) + hw_dev_acquisition_stop(sdi, cb_data); + return TRUE; } -static int hw_dev_acquisition_start(int dev_index, void *cb_data) +static int hw_dev_acquisition_start(const struct sr_dev_inst *sdi, + void *cb_data) { struct sr_datafeed_packet packet; struct sr_datafeed_header header; struct sr_datafeed_meta_analog meta; - struct sr_dev_inst *sdi; - struct context *ctx; + struct dev_context *devc; - if (!(sdi = sr_dev_inst_get(gdi->instances, dev_index))) { - sr_err("genericdmm: sdi was NULL."); - return SR_ERR_BUG; - } - - if (!(ctx = sdi->priv)) { + if (!(devc = sdi->priv)) { sr_err("genericdmm: sdi->priv was NULL."); return SR_ERR_BUG; } sr_dbg("genericdmm: Starting acquisition."); - ctx->cb_data = cb_data; + devc->cb_data = cb_data; /* Send header packet to the session bus. */ sr_dbg("genericdmm: Sending SR_DF_HEADER."); @@ -564,35 +639,43 @@ static int hw_dev_acquisition_start(int dev_index, void *cb_data) packet.payload = (uint8_t *)&header; header.feed_version = 1; gettimeofday(&header.starttime, NULL); - sr_session_send(ctx->cb_data, &packet); + sr_session_send(devc->cb_data, &packet); /* Send metadata about the SR_DF_ANALOG packets to come. */ sr_dbg("genericdmm: Sending SR_DF_META_ANALOG."); packet.type = SR_DF_META_ANALOG; packet.payload = &meta; meta.num_probes = 1; - sr_session_send(ctx->cb_data, &packet); + sr_session_send(devc->cb_data, &packet); /* Hook up a proxy handler to receive data from the device. */ - switch (ctx->profile->transport) { + switch (devc->profile->transport) { case DMM_TRANSPORT_USBHID: - /* TODO libusb FD setup */ + /* Callously using stdin here. This works because no G_IO_* flags + * are set, but will certainly break when any other driver does + * this, and runs at the same time as genericdmm. + * We'll need a timeout-only source when revamping the whole + * driver source system. + */ + sr_source_add(0, 0, devc->profile->poll_timeout, + receive_data, (void *)sdi); break; case DMM_TRANSPORT_SERIAL: /* TODO serial FD setup */ - // sr_source_add(ctx->serial->fd, G_IO_IN, -1, receive_data, sdi); + // sr_source_add(devc->serial->fd, G_IO_IN, -1, receive_data, sdi); break; } return SR_OK; } -static int hw_dev_acquisition_stop(int dev_index, void *cb_data) +static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, + void *cb_data) { struct sr_datafeed_packet packet; /* Avoid compiler warnings. */ - (void)dev_index; + (void)sdi; sr_dbg("genericdmm: Stopping acquisition."); @@ -601,6 +684,8 @@ static int hw_dev_acquisition_stop(int dev_index, void *cb_data) packet.type = SR_DF_END; sr_session_send(cb_data, &packet); + sr_source_remove(0); + return SR_OK; } @@ -611,12 +696,13 @@ SR_PRIV struct sr_dev_driver genericdmm_driver_info = { .init = hw_init, .cleanup = hw_cleanup, .scan = hw_scan, + .dev_list = hw_dev_list, + .dev_clear = clear_instances, .dev_open = hw_dev_open, .dev_close = hw_dev_close, .info_get = hw_info_get, - .dev_status_get = hw_dev_status_get, .dev_config_set = hw_dev_config_set, .dev_acquisition_start = hw_dev_acquisition_start, .dev_acquisition_stop = hw_dev_acquisition_stop, - .instances = NULL, + .priv = NULL, };