X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fhardware%2Fsaleae-logic-pro%2Fapi.c;h=0a2a2728633e3cf42c9e463153c65d060aa5eb6c;hb=7d0f52f7e5cb16d204490ca4006983237bf3df7d;hp=f448533ef9be8b6a2c7242f44c477eda2ff66006;hpb=f670835f1fbc03525e995d6970a5495976ab7c1a;p=libsigrok.git diff --git a/src/hardware/saleae-logic-pro/api.c b/src/hardware/saleae-logic-pro/api.c index f448533e..0a2a2728 100644 --- a/src/hardware/saleae-logic-pro/api.c +++ b/src/hardware/saleae-logic-pro/api.c @@ -22,20 +22,18 @@ #include #include "protocol.h" -#define BUF_COUNT 8 +#define BUF_COUNT 512 #define BUF_SIZE (16 * 1024) -#define BUF_TIMEOUT (1000 * 1000) +#define BUF_TIMEOUT 1000 -SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info; +static const uint32_t scanopts[] = { + SR_CONF_CONN, +}; static const uint32_t drvopts[] = { SR_CONF_LOGIC_ANALYZER, }; -static const uint32_t scanopts[] = { - SR_CONF_CONN, -}; - static const uint32_t devopts[] = { SR_CONF_CONTINUOUS, SR_CONF_CONN | SR_CONF_GET, @@ -56,6 +54,78 @@ static const uint64_t samplerates[] = { SR_MHZ(50), }; +#define FW_HEADER_SIZE 7 +#define FW_MAX_PART_SIZE (4 * 1024) + +static int upload_firmware(struct sr_context *ctx, libusb_device *dev, const char *name) +{ + struct libusb_device_handle *hdl = NULL; + unsigned char *firmware = NULL; + int ret = SR_ERR; + size_t fw_size, fw_offset = 0; + uint32_t part_address = 0; + uint16_t part_size = 0; + uint8_t part_final = 0; + + firmware = sr_resource_load(ctx, SR_RESOURCE_FIRMWARE, + name, &fw_size, 256 * 1024); + if (!firmware) + goto out; + + sr_info("Uploading firmware '%s'.", name); + + if (libusb_open(dev, &hdl) != 0) + goto out; + + while ((fw_offset + FW_HEADER_SIZE) <= fw_size) { + part_size = GUINT16_FROM_LE(*(uint16_t*)(firmware + fw_offset)); + part_address = GUINT32_FROM_LE(*(uint32_t*)(firmware + fw_offset + 2)); + part_final = *(uint8_t*)(firmware + fw_offset + 6); + if (part_size > FW_MAX_PART_SIZE) { + sr_err("Part too large (%d).", part_size); + goto out; + } + fw_offset += FW_HEADER_SIZE; + if ((fw_offset + part_size) > fw_size) { + sr_err("Truncated firmware file."); + goto out; + } + ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_OUT, 0xa0, + part_address & 0xffff, part_address >> 16, + firmware + fw_offset, part_size, + 100); + if (ret < 0) { + sr_err("Unable to send firmware to device: %s.", + libusb_error_name(ret)); + ret = SR_ERR; + goto out; + } + if (part_size) + sr_spew("Uploaded %d bytes.", part_size); + else + sr_info("Started firmware at 0x%x.", part_address); + fw_offset += part_size; + } + + if ((!part_final) || (part_size != 0)) { + sr_err("Missing final part."); + goto out; + } + + ret = SR_OK; + + sr_info("Firmware upload done."); + + out: + if (hdl) + libusb_close(hdl); + + g_free(firmware); + + return ret; +} + static gboolean scan_firmware(libusb_device *dev) { struct libusb_device_descriptor des; @@ -102,8 +172,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) struct libusb_device_descriptor des; const char *conn; char connection_id[64]; + gboolean fw_loaded = FALSE; devices = NULL; + conn_devices = NULL; drvc = di->context; drvc->instances = NULL; @@ -118,14 +190,36 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) } } + libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + for (unsigned int i = 0; devlist[i]; i++) { + libusb_get_device_descriptor(devlist[i], &des); + + if (des.idVendor != 0x21a9 || des.idProduct != 0x1006) + continue; + + if (!scan_firmware(devlist[i])) { + const char *fwname; + sr_info("Found a Logic Pro 16 device (no firmware loaded)."); + fwname = "saleae-logicpro16-fx3.fw"; + if (upload_firmware(drvc->sr_ctx, devlist[i], + fwname) != SR_OK) { + sr_err("Firmware upload failed, name %s.", fwname); + continue; + }; + fw_loaded = TRUE; + } + + } + if (fw_loaded) { + /* Give the device some time to come back and scan again */ + libusb_free_device_list(devlist, 1); + g_usleep(500 * 1000); + libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); + } if (conn) conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn); - else - conn_devices = NULL; - - libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); for (unsigned int i = 0; devlist[i]; i++) { - if (conn) { + if (conn_devices) { struct sr_usb_dev_inst *usb = NULL; GSList *l; @@ -143,15 +237,11 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) libusb_get_device_descriptor(devlist[i], &des); - usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)); - if (des.idVendor != 0x21a9 || des.idProduct != 0x1006) continue; - if (!scan_firmware(devlist[i])) { - sr_err("Found a Logic Pro device, but firmware is not loaded (use Saleae application)."); + if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0) continue; - } sdi = g_malloc0(sizeof(struct sr_dev_inst)); sdi->status = SR_ST_INITIALIZING; @@ -174,17 +264,12 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) devices = g_slist_append(devices, sdi); } - libusb_free_device_list(devlist, 1); g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free); + libusb_free_device_list(devlist, 1); return std_scan_complete(di, devices); } -static int dev_clear(const struct sr_dev_driver *di) -{ - return std_dev_clear(di, NULL); -} - static int dev_open(struct sr_dev_inst *sdi) { struct sr_dev_driver *di = sdi->driver; @@ -205,32 +290,24 @@ static int dev_open(struct sr_dev_inst *sdi) if (devc->dig_samplerate == 0) devc->dig_samplerate = samplerates[3]; - sdi->status = SR_ST_ACTIVE; - - return SR_OK; + return saleae_logic_pro_init(sdi); } static int dev_close(struct sr_dev_inst *sdi) { - struct sr_usb_dev_inst *usb = sdi->conn; - - sr_usb_close(usb); - - sdi->status = SR_ST_INACTIVE; + sr_usb_close(sdi->conn); return SR_OK; } static int config_get(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 sr_usb_dev_inst *usb; struct dev_context *devc; - int ret; (void)cg; - ret = SR_OK; switch (key) { case SR_CONF_CONN: if (!sdi || !sdi->conn) @@ -248,70 +325,44 @@ static int config_get(uint32_t key, GVariant **data, return SR_ERR_NA; } - return ret; + return SR_OK; } static int config_set(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; - int ret; (void)cg; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; devc = sdi->priv; - ret = SR_OK; switch (key) { case SR_CONF_SAMPLERATE: devc->dig_samplerate = g_variant_get_uint64(data); break; default: - ret = SR_ERR_NA; + return SR_ERR_NA; } - return ret; + return SR_OK; } 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) { - GVariant *gvar; - GVariantBuilder gvb; - int ret; - - (void)sdi; - (void)cg; - - ret = SR_OK; switch (key) { case SR_CONF_SCAN_OPTIONS: - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - scanopts, ARRAY_SIZE(scanopts), sizeof(uint32_t)); - break; case SR_CONF_DEVICE_OPTIONS: - if (!sdi) { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - drvopts, ARRAY_SIZE(drvopts), sizeof(uint32_t)); - } else { - *data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32, - devopts, ARRAY_SIZE(devopts), sizeof(uint32_t)); - } - break; + return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); case SR_CONF_SAMPLERATE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); - gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), - samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t)); - g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); - *data = g_variant_builder_end(&gvb); + *data = std_gvar_samplerates(ARRAY_AND_SIZE(samplerates)); break; default: return SR_ERR_NA; } - return ret; + return SR_OK; } static void dev_acquisition_abort(const struct sr_dev_inst *sdi) @@ -332,10 +383,13 @@ static int dev_acquisition_handle(int fd, int revents, void *cb_data) struct timeval tv = ALL_ZERO; (void)fd; - (void)revents; libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv); + /* Handle timeout */ + if (!revents) + sr_dev_acquisition_stop(sdi); + return TRUE; } @@ -348,10 +402,6 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) uint8_t *buf; unsigned int i, ret; - ret = saleae_logic_pro_init(sdi); - if (ret != SR_OK) - return ret; - ret = saleae_logic_pro_prepare(sdi); if (ret != SR_OK) return ret; @@ -367,7 +417,7 @@ static int dev_acquisition_start(const struct sr_dev_inst *sdi) transfer = libusb_alloc_transfer(0); libusb_fill_bulk_transfer(transfer, usb->devhdl, 2 | LIBUSB_ENDPOINT_IN, buf, BUF_SIZE, - saleae_logic_pro_receive_data, (void *)sdi, BUF_TIMEOUT); + saleae_logic_pro_receive_data, (void *)sdi, 0); if ((ret = libusb_submit_transfer(transfer)) != 0) { sr_err("Failed to submit transfer: %s.", libusb_error_name(ret)); @@ -407,7 +457,7 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi) return SR_OK; } -SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info = { +static struct sr_dev_driver saleae_logic_pro_driver_info = { .name = "saleae-logic-pro", .longname = "Saleae Logic Pro", .api_version = 1, @@ -415,7 +465,7 @@ SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info = { .cleanup = std_cleanup, .scan = scan, .dev_list = std_dev_list, - .dev_clear = dev_clear, + .dev_clear = std_dev_clear, .config_get = config_get, .config_set = config_set, .config_list = config_list, @@ -425,5 +475,4 @@ SR_PRIV struct sr_dev_driver saleae_logic_pro_driver_info = { .dev_acquisition_stop = dev_acquisition_stop, .context = NULL, }; - SR_REGISTER_DEV_DRIVER(saleae_logic_pro_driver_info);