X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fsysclk-lwla%2Fapi.c;h=6055b83d4da6b6a46a65218c82918e7e75c6df43;hb=697fb6ddfc2522b2e6d35511c7837e2c61d8ae73;hp=36c9ee608bfc7dc05796437cae9728707ee8e023;hpb=786485772ffd28dfb1ca7375ca64118ccd7af25c;p=libsigrok.git diff --git a/src/hardware/sysclk-lwla/api.c b/src/hardware/sysclk-lwla/api.c index 36c9ee60..6055b83d 100644 --- a/src/hardware/sysclk-lwla/api.c +++ b/src/hardware/sysclk-lwla/api.c @@ -26,20 +26,14 @@ #include #include "protocol.h" -/* Supported device scan options. - */ static const uint32_t scanopts[] = { SR_CONF_CONN, }; -/* Driver capabilities. - */ static const uint32_t drvopts[] = { SR_CONF_LOGIC_ANALYZER, }; -/* Supported trigger match conditions. - */ static const int32_t trigger_matches[] = { SR_TRIGGER_ZERO, SR_TRIGGER_ONE, @@ -47,29 +41,16 @@ static const int32_t trigger_matches[] = { SR_TRIGGER_FALLING, }; -/* Names assigned to available trigger sources. - */ -static const char *const trigger_source_names[] = { +static const char *trigger_source_names[] = { [TRIGGER_CHANNELS] = "CH", [TRIGGER_EXT_TRG] = "TRG", }; -/* Names assigned to available edge slope choices. - */ -static const char *const signal_edge_names[] = { +static const char *signal_edge_names[] = { [EDGE_POSITIVE] = "r", [EDGE_NEGATIVE] = "f", }; -/* Initialize the SysClk LWLA driver. - */ -static int init(struct sr_dev_driver *di, struct sr_context *sr_ctx) -{ - return std_init(sr_ctx, di, LOG_PREFIX); -} - -/* Create a new sigrok device instance for the indicated LWLA model. - */ static struct sr_dev_inst *dev_inst_new(const struct model_info *model) { struct sr_dev_inst *sdi; @@ -77,7 +58,6 @@ static struct sr_dev_inst *dev_inst_new(const struct model_info *model) int i; char name[8]; - /* Initialize private device context. */ devc = g_malloc0(sizeof(struct dev_context)); devc->model = model; devc->active_fpga_config = FPGA_NOCONF; @@ -85,16 +65,13 @@ static struct sr_dev_inst *dev_inst_new(const struct model_info *model) devc->samplerate = model->samplerates[0]; devc->channel_mask = (UINT64_C(1) << model->num_channels) - 1; - /* Create sigrok device instance. */ sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi->status = SR_ST_INACTIVE; - sdi->vendor = g_strdup(VENDOR_NAME); + sdi->vendor = g_strdup("SysClk"); sdi->model = g_strdup(model->name); sdi->priv = devc; - /* Generate list of logic channels. */ for (i = 0; i < model->num_channels; i++) { - /* The LWLA series simply number channels from CH1 to CHxx. */ g_snprintf(name, sizeof(name), "CH%d", i + 1); sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, name); } @@ -113,9 +90,8 @@ static struct sr_dev_inst *dev_inst_new_matching(GSList *conn_matches, const struct model_info *model; struct sr_dev_inst *sdi; struct libusb_device_descriptor des; - int bus, address; + int bus, address, ret; unsigned int vid, pid; - int ret; bus = libusb_get_bus_number(dev); address = libusb_get_device_address(dev); @@ -156,8 +132,6 @@ static struct sr_dev_inst *dev_inst_new_matching(GSList *conn_matches, return sdi; } -/* Scan for SysClk LWLA devices and create a device instance for each one. - */ static GSList *scan(struct sr_dev_driver *di, GSList *options) { GSList *conn_devices, *devices, *node; @@ -202,50 +176,13 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) continue; /* no match */ /* Register device instance with driver. */ - sdi->driver = di; - drvc->instances = g_slist_append(drvc->instances, sdi); devices = g_slist_append(devices, sdi); } libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)&sr_usb_dev_inst_free); - return devices; -} - -/* Return the list of devices found during scan. - */ -static GSList *dev_list(const struct sr_dev_driver *di) -{ - struct drv_context *drvc; - - drvc = di->context; - - return drvc->instances; -} - -/* Destroy the private device context. - */ -static void clear_dev_context(void *priv) -{ - struct dev_context *devc; - - devc = priv; - - if (devc->acquisition) { - sr_err("Cannot clear device context during acquisition!"); - return; /* leak and pray */ - } - sr_dbg("Device context cleared."); - - g_free(devc); -} - -/* Destroy all device instances. - */ -static int dev_clear(const struct sr_dev_driver *di) -{ - return std_dev_clear(di, &clear_dev_context); + return std_scan_complete(di, devices); } /* Drain any pending data from the USB transfer buffers on the device. @@ -254,10 +191,8 @@ static int dev_clear(const struct sr_dev_driver *di) */ static int drain_usb(struct sr_usb_dev_inst *usb, unsigned int endpoint) { - int drained, xfer_len; - int ret; + int drained, xfer_len, ret; unsigned char buf[512]; - const unsigned int drain_timeout_ms = 10; drained = 0; @@ -279,102 +214,81 @@ static int drain_usb(struct sr_usb_dev_inst *usb, unsigned int endpoint) sr_warn("Drained %d bytes from USB endpoint %u.", drained, endpoint & (LIBUSB_ENDPOINT_IN - 1)); } + return SR_OK; } -/* Open and initialize device. - */ static int dev_open(struct sr_dev_inst *sdi) { struct drv_context *drvc; struct dev_context *devc; struct sr_usb_dev_inst *usb; - int ret; + int i, ret; drvc = sdi->driver->context; devc = sdi->priv; usb = sdi->conn; - if (!drvc) { - sr_err("Driver was not initialized."); - return SR_ERR; - } - if (sdi->status != SR_ST_INACTIVE) { - sr_err("Device already open."); - return SR_ERR; - } - - ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb); - if (ret != SR_OK) - return ret; - - ret = libusb_set_configuration(usb->devhdl, USB_CONFIG); - if (ret != LIBUSB_SUCCESS) { - sr_err("Failed to set USB configuration: %s.", - libusb_error_name(ret)); - sr_usb_close(usb); - return SR_ERR; - } - - ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); - if (ret != LIBUSB_SUCCESS) { - sr_err("Failed to claim interface: %s.", - libusb_error_name(ret)); - sr_usb_close(usb); - return SR_ERR; - } + /* Try the whole shebang three times, fingers crossed. */ + for (i = 0; i < 3; i++) { + ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb); + if (ret != SR_OK) + return ret; + + ret = libusb_set_configuration(usb->devhdl, USB_CONFIG); + if (ret != LIBUSB_SUCCESS) { + sr_err("Failed to set USB configuration: %s.", + libusb_error_name(ret)); + sr_usb_close(usb); + return SR_ERR; + } - ret = drain_usb(usb, EP_REPLY); - if (ret != SR_OK) { - sr_usb_close(usb); - return ret; - } - /* This delay appears to be necessary for reliable operation. */ - g_usleep(30 * 1000); + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); + if (ret != LIBUSB_SUCCESS) { + sr_err("Failed to claim interface: %s.", + libusb_error_name(ret)); + sr_usb_close(usb); + return SR_ERR; + } - sdi->status = SR_ST_ACTIVE; + ret = drain_usb(usb, EP_REPLY); + if (ret != SR_OK) { + sr_usb_close(usb); + return ret; + } + /* This delay appears to be necessary for reliable operation. */ + g_usleep(30 * 1000); - devc->active_fpga_config = FPGA_NOCONF; - devc->short_transfer_quirk = FALSE; - devc->state = STATE_IDLE; + devc->active_fpga_config = FPGA_NOCONF; + devc->short_transfer_quirk = FALSE; + devc->state = STATE_IDLE; - ret = (*devc->model->apply_fpga_config)(sdi); + ret = (*devc->model->apply_fpga_config)(sdi); - if (ret == SR_OK) - ret = (*devc->model->device_init_check)(sdi); + if (ret == SR_OK) + ret = (*devc->model->device_init_check)(sdi); + if (ret == SR_OK) + break; - if (ret != SR_OK) { - sdi->status = SR_ST_INACTIVE; + /* Rinse and repeat. */ sr_usb_close(usb); - return ret; } - if (devc->short_transfer_quirk) + + if (ret == SR_OK && devc->short_transfer_quirk) sr_warn("Short transfer quirk detected! " "Memory reads will be slow."); - return SR_OK; + return ret; } -/* Shutdown and close device. - */ static int dev_close(struct sr_dev_inst *sdi) { - struct drv_context *drvc; struct dev_context *devc; struct sr_usb_dev_inst *usb; int ret; - drvc = sdi->driver->context; devc = sdi->priv; usb = sdi->conn; - if (!drvc) { - sr_err("Driver was not initialized."); - return SR_ERR; - } - if (sdi->status == SR_ST_INACTIVE) { - sr_dbg("Device already closed."); - return SR_OK; - } if (devc->acquisition) { sr_err("Cannot close device during acquisition!"); /* Request stop, leak handle, and prepare for the worst. */ @@ -382,17 +296,16 @@ static int dev_close(struct sr_dev_inst *sdi) return SR_ERR_BUG; } - sdi->status = SR_ST_INACTIVE; - /* Download of the shutdown bitstream, if any. */ ret = (*devc->model->apply_fpga_config)(sdi); if (ret != SR_OK) sr_warn("Unable to shut down device."); libusb_release_interface(usb->devhdl, USB_INTERFACE); + sr_usb_close(usb); - return ret; + return SR_OK; } /* Check whether the device options contain a specific key. @@ -406,13 +319,12 @@ static int has_devopt(const struct model_info *model, uint32_t key) if ((model->devopts[i] & (SR_CONF_MASK | key)) == key) return TRUE; } + return FALSE; } -/* Read device configuration setting. - */ -static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *sdi, - const struct sr_channel_group *cg) +static int config_get(uint32_t key, GVariant **data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; unsigned int idx; @@ -470,30 +382,8 @@ static int config_get(uint32_t key, GVariant **data, const struct sr_dev_inst *s return SR_OK; } -/* Helper for mapping a string-typed configuration value to an index - * within a table of possible values. - */ -static int lookup_index(GVariant *value, const char *const *table, int len) -{ - const char *entry; - int i; - - entry = g_variant_get_string(value, NULL); - if (!entry) - return -1; - - /* Linear search is fine for very small tables. */ - for (i = 0; i < len; ++i) { - if (strcmp(entry, table[i]) == 0) - return i; - } - return -1; -} - -/* Write device configuration setting. - */ -static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sdi, - const struct sr_channel_group *cg) +static int config_set(uint32_t key, GVariant *data, + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { uint64_t value; struct dev_context *devc; @@ -537,23 +427,17 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd ? CLOCK_EXT_CLK : CLOCK_INTERNAL; break; case SR_CONF_CLOCK_EDGE: - idx = lookup_index(data, signal_edge_names, - ARRAY_SIZE(signal_edge_names)); - if (idx < 0) + if ((idx = std_str_idx(data, ARRAY_AND_SIZE(signal_edge_names))) < 0) return SR_ERR_ARG; devc->cfg_clock_edge = idx; break; case SR_CONF_TRIGGER_SOURCE: - idx = lookup_index(data, trigger_source_names, - ARRAY_SIZE(trigger_source_names)); - if (idx < 0) + if ((idx = std_str_idx(data, ARRAY_AND_SIZE(trigger_source_names))) < 0) return SR_ERR_ARG; devc->cfg_trigger_source = idx; break; case SR_CONF_TRIGGER_SLOPE: - idx = lookup_index(data, signal_edge_names, - ARRAY_SIZE(signal_edge_names)); - if (idx < 0) + if ((idx = std_str_idx(data, ARRAY_AND_SIZE(signal_edge_names))) < 0) return SR_ERR_ARG; devc->cfg_trigger_slope = idx; break; @@ -565,10 +449,8 @@ static int config_set(uint32_t key, GVariant *data, const struct sr_dev_inst *sd return SR_OK; } -/* Apply channel configuration change. - */ static int config_channel_set(const struct sr_dev_inst *sdi, - struct sr_channel *ch, unsigned int changes) + struct sr_channel *ch, unsigned int changes) { uint64_t channel_bit; struct dev_context *devc; @@ -596,13 +478,10 @@ static int config_channel_set(const struct sr_dev_inst *sdi, return SR_OK; } -/* Derive trigger masks from the session's trigger configuration. - */ +/* Derive trigger masks from the session's trigger configuration. */ static int prepare_trigger_masks(const struct sr_dev_inst *sdi) { - uint64_t trigger_mask; - uint64_t trigger_values; - uint64_t trigger_edge_mask; + uint64_t trigger_mask, trigger_values, trigger_edge_mask; uint64_t level_bit, type_bit; struct dev_context *devc; struct sr_trigger *trigger; @@ -632,14 +511,14 @@ static int prepare_trigger_masks(const struct sr_dev_inst *sdi) match = node->data; if (!match->channel->enabled) - continue; /* ignore disabled channel */ + continue; /* Ignore disabled channel. */ idx = match->channel->index; trg = match->match; if (idx < 0 || idx >= devc->model->num_channels) { sr_err("Channel index %d out of range.", idx); - return SR_ERR_BUG; /* should not happen */ + return SR_ERR_BUG; /* Should not happen. */ } if (trg != SR_TRIGGER_ZERO && trg != SR_TRIGGER_ONE @@ -664,8 +543,6 @@ static int prepare_trigger_masks(const struct sr_dev_inst *sdi) return SR_OK; } -/* Apply current device configuration to the hardware. - */ static int config_commit(const struct sr_dev_inst *sdi) { struct dev_context *devc; @@ -673,9 +550,6 @@ static int config_commit(const struct sr_dev_inst *sdi) devc = sdi->priv; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - if (devc->acquisition) { sr_err("Acquisition still in progress?"); return SR_ERR; @@ -694,44 +568,20 @@ static int config_commit(const struct sr_dev_inst *sdi) return SR_OK; } -/* List available choices for a configuration setting. - */ static int config_list(uint32_t key, GVariant **data, - const struct sr_dev_inst *sdi, - const struct sr_channel_group *cg) + const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { struct dev_context *devc; - GVariant *gvar; - GVariantBuilder gvb; - - (void)cg; - if (key == SR_CONF_SCAN_OPTIONS) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - scanopts, ARRAY_SIZE(scanopts), - sizeof(scanopts[0])); - return SR_OK; - } - if (!sdi) { - if (key != SR_CONF_DEVICE_OPTIONS) - return SR_ERR_ARG; + devc = (sdi) ? sdi->priv : NULL; - /* List driver capabilities. */ - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - drvopts, ARRAY_SIZE(drvopts), - sizeof(drvopts[0])); - return SR_OK; - } - - devc = sdi->priv; - - /* List the model's device options. */ - if (key == SR_CONF_DEVICE_OPTIONS) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - devc->model->devopts, - devc->model->num_devopts, - sizeof(devc->model->devopts[0])); - return SR_OK; + switch (key) { + case SR_CONF_SCAN_OPTIONS: + case SR_CONF_DEVICE_OPTIONS: + return std_opts_config_list(key, data, sdi, cg, + ARRAY_AND_SIZE(scanopts), ARRAY_AND_SIZE(drvopts), + (devc) ? devc->model->devopts : NULL, + (devc) ? devc->model->num_devopts : 0); } if (!has_devopt(devc->model, key | SR_CONF_LIST)) @@ -739,28 +589,17 @@ static int config_list(uint32_t key, GVariant **data, switch (key) { case SR_CONF_SAMPLERATE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE_VARDICT); - gvar = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64, - devc->model->samplerates, - devc->model->num_samplerates, - sizeof(devc->model->samplerates[0])); - g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); - *data = g_variant_builder_end(&gvb); + *data = std_gvar_samplerates(devc->model->samplerates, devc->model->num_samplerates); break; case SR_CONF_TRIGGER_MATCH: - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, - trigger_matches, - ARRAY_SIZE(trigger_matches), - sizeof(trigger_matches[0])); + *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); break; case SR_CONF_TRIGGER_SOURCE: - *data = g_variant_new_strv(trigger_source_names, - ARRAY_SIZE(trigger_source_names)); + *data = g_variant_new_strv(ARRAY_AND_SIZE(trigger_source_names)); break; case SR_CONF_TRIGGER_SLOPE: case SR_CONF_CLOCK_EDGE: - *data = g_variant_new_strv(signal_edge_names, - ARRAY_SIZE(signal_edge_names)); + *data = g_variant_new_strv(ARRAY_AND_SIZE(signal_edge_names)); break; default: /* Must not happen for a key listed in devopts. */ @@ -774,48 +613,34 @@ static int config_list(uint32_t key, GVariant **data, * configured trigger conditions are met, or immediately if no triggers * are configured. */ -static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data) +static int dev_acquisition_start(const struct sr_dev_inst *sdi) { - (void)cb_data; - - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - - sr_info("Starting acquisition."); - return lwla_start_acquisition(sdi); } -/* Request that a running capture operation be stopped. - */ -static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) +static int dev_acquisition_stop(struct sr_dev_inst *sdi) { struct dev_context *devc; - (void)cb_data; devc = sdi->priv; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; - if (devc->state != STATE_IDLE && !devc->cancel_requested) { devc->cancel_requested = TRUE; - sr_dbg("Stopping acquisition."); + sr_dbg("Requesting cancel."); } + return SR_OK; } -/* SysClk LWLA driver descriptor. - */ -SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = { +static struct sr_dev_driver sysclk_lwla_driver_info = { .name = "sysclk-lwla", .longname = "SysClk LWLA series", .api_version = 1, - .init = init, - .cleanup = dev_clear, + .init = std_init, + .cleanup = std_cleanup, .scan = scan, - .dev_list = dev_list, - .dev_clear = dev_clear, + .dev_list = std_dev_list, + .dev_clear = std_dev_clear, .config_get = config_get, .config_set = config_set, .config_channel_set = config_channel_set, @@ -827,3 +652,4 @@ SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = { .dev_acquisition_stop = dev_acquisition_stop, .context = NULL, }; +SR_REGISTER_DEV_DRIVER(sysclk_lwla_driver_info);