diff --git a/src/ezusb.c b/src/ezusb.c index c2d270c4f..62cdd1a11 100644 --- a/src/ezusb.c +++ b/src/ezusb.c @@ -54,7 +54,7 @@ SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear) SR_PRIV int ezusb_install_firmware(struct sr_context *ctx, libusb_device_handle *hdl, - const char *name) + const char *name, gboolean fx3) { unsigned char *firmware; size_t length, offset, chunksize; @@ -64,7 +64,7 @@ SR_PRIV int ezusb_install_firmware(struct sr_context *ctx, * which holds the firmware offset, is only 16 bit wide. */ firmware = sr_resource_load(ctx, SR_RESOURCE_FIRMWARE, - name, &length, 1 << 16); + name, &length, (fx3? 536 << 10 : 1 << 16)); if (!firmware) return SR_ERR; @@ -72,31 +72,74 @@ SR_PRIV int ezusb_install_firmware(struct sr_context *ctx, result = SR_OK; offset = 0; - while (offset < length) { - chunksize = MIN(length - offset, FW_CHUNKSIZE); - - ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR | - LIBUSB_ENDPOINT_OUT, 0xa0, offset, - 0x0000, firmware + offset, - chunksize, 100); - if (ret < 0) { - sr_err("Unable to send firmware to device: %s.", - libusb_error_name(ret)); + if (fx3) { + if (length < 4 || + firmware[0] != 'C' || firmware[1] != 'Y' || + firmware[3] != 0xb0) { + sr_err("Invalid signature on firmware"); g_free(firmware); return SR_ERR; } - sr_info("Uploaded %zu bytes.", chunksize); - offset += chunksize; + offset = 4; + } + while (offset < length) { + size_t addr, sublength, suboffset; + + if (fx3) { + if (offset + 4 == length) { + /* Skip checksum */ + offset += 4; + break; + } + if (length < offset + 8) { + break; + } + sublength = RL32(firmware + offset) << 2; + offset += 4; + addr = RL32(firmware + offset); + offset += 4; + if (sublength > length - offset) { + break; + } + } else { + sublength = length - offset; + addr = 0; + } + suboffset = 0; + + do { + chunksize = MIN(sublength - suboffset, FW_CHUNKSIZE); + + ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR | + LIBUSB_ENDPOINT_OUT, 0xa0, (addr + suboffset) & 0xffff, + (addr + suboffset) >> 16, firmware + offset + suboffset, + chunksize, 100); + if (ret < 0) { + sr_err("Unable to send firmware to device: %s.", + libusb_error_name(ret)); + g_free(firmware); + return SR_ERR; + } + sr_info("Uploaded %zu bytes.", chunksize); + suboffset += chunksize; + } while (suboffset < sublength); + + offset += sublength; } g_free(firmware); + if (offset < length) { + sr_err("Firmware file is truncated."); + return SR_ERR; + } + sr_info("Firmware upload done."); return result; } SR_PRIV int ezusb_upload_firmware(struct sr_context *ctx, libusb_device *dev, - int configuration, const char *name) + int configuration, const char *name, gboolean fx3) { struct libusb_device_handle *hdl; int ret; @@ -129,13 +172,13 @@ SR_PRIV int ezusb_upload_firmware(struct sr_context *ctx, libusb_device *dev, return SR_ERR; } - if ((ezusb_reset(hdl, 1)) < 0) + if (!fx3 && (ezusb_reset(hdl, 1)) < 0) return SR_ERR; - if (ezusb_install_firmware(ctx, hdl, name) < 0) + if (ezusb_install_firmware(ctx, hdl, name, fx3) < 0) return SR_ERR; - if ((ezusb_reset(hdl, 0)) < 0) + if (!fx3 && (ezusb_reset(hdl, 0)) < 0) return SR_ERR; libusb_close(hdl); diff --git a/src/hardware/dreamsourcelab-dslogic/api.c b/src/hardware/dreamsourcelab-dslogic/api.c index 98f4acdb1..29c0054af 100644 --- a/src/hardware/dreamsourcelab-dslogic/api.c +++ b/src/hardware/dreamsourcelab-dslogic/api.c @@ -268,7 +268,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], - USB_CONFIGURATION, prof->firmware) == SR_OK) { + USB_CONFIGURATION, prof->firmware, FALSE) == SR_OK) { /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); } else { diff --git a/src/hardware/fx2lafw/api.c b/src/hardware/fx2lafw/api.c index 5acb0016d..658db3677 100644 --- a/src/hardware/fx2lafw/api.c +++ b/src/hardware/fx2lafw/api.c @@ -112,6 +112,13 @@ static const struct fx2lafw_profile supported_fx2[] = { "fx2lafw-usb-c-grok.fw", 0, NULL, NULL}, + /* + * Cypress SuperSpeed Explorer Kit (CYUSB3KIT-003) + */ + { 0x04b4, 0x00f3, "Cypress", "SuperSpeed Explorer Kit", NULL, + "fx3lafw-cypress-fx3.fw", + DEV_CAPS_FX3 | DEV_CAPS_32BIT, NULL, NULL }, + ALL_ZERO }; @@ -158,7 +165,13 @@ static const uint64_t samplerates[] = { SR_MHZ(12), SR_MHZ(16), SR_MHZ(24), + /* FX3 only rates below here */ + SR_MHZ(32), SR_MHZ(48), + SR_MHZ(64), + SR_MHZ(96), + SR_MHZ(192), +#define NUM_FX3_RATES 5 }; static gboolean is_plausible(const struct libusb_device_descriptor *des) @@ -302,7 +315,10 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) sdi->connection_id = g_strdup(connection_id); /* Fill in channellist according to this device's profile. */ - num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8; + num_logic_channels = + prof->dev_caps & DEV_CAPS_32BIT ? 32 : + (prof->dev_caps & DEV_CAPS_24BIT ? 24 : + (prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8)); num_analog_channels = prof->dev_caps & DEV_CAPS_AX_ANALOG ? 1 : 0; /* Logic channels, all in one channel group. */ @@ -335,6 +351,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) devc->samplerates = samplerates; devc->num_samplerates = ARRAY_SIZE(samplerates); + if (!(prof->dev_caps & DEV_CAPS_FX3)) + devc->num_samplerates -= NUM_FX3_RATES; has_firmware = usb_match_manuf_prod(devlist[i], "sigrok", "fx2lafw"); @@ -347,7 +365,8 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], - USB_CONFIGURATION, prof->firmware) == SR_OK) { + USB_CONFIGURATION, prof->firmware, + (prof->dev_caps & DEV_CAPS_FX3) != 0) == SR_OK) { /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); } else { diff --git a/src/hardware/fx2lafw/protocol.c b/src/hardware/fx2lafw/protocol.c index 963d0336e..d1bc7f954 100644 --- a/src/hardware/fx2lafw/protocol.c +++ b/src/hardware/fx2lafw/protocol.c @@ -89,7 +89,8 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi) samplerate = devc->cur_samplerate; /* Compute the sample rate. */ - if (devc->sample_wide && samplerate > MAX_16BIT_SAMPLE_RATE) { + if (!(devc->profile->dev_caps & DEV_CAPS_FX3) && + devc->unitsize > 1 && samplerate > MAX_16BIT_SAMPLE_RATE) { sr_err("Unable to sample at %" PRIu64 "Hz " "when collecting 16-bit samples.", samplerate); return SR_ERR; @@ -97,7 +98,16 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi) delay = 0; cmd.flags = cmd.sample_delay_h = cmd.sample_delay_l = 0; - if ((SR_MHZ(48) % samplerate) == 0) { + + if ((devc->profile->dev_caps & DEV_CAPS_FX3) && + (SR_MHZ(192) % samplerate) == 0) { + cmd.flags = CMD_START_FLAGS_CLK_192MHZ; + delay = SR_MHZ(192) / samplerate - 1; + if (delay > 0xffff) + delay = 0; + } + + if (delay == 0 && (SR_MHZ(48) % samplerate) == 0) { cmd.flags = CMD_START_FLAGS_CLK_48MHZ; delay = SR_MHZ(48) / samplerate - 1; if (delay > MAX_SAMPLE_DELAY) @@ -110,7 +120,8 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi) } sr_dbg("GPIF delay = %d, clocksource = %sMHz.", delay, - (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30"); + (cmd.flags & CMD_START_FLAGS_CLK_192MHZ? "192" : + (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30")); if (delay < 0 || delay > MAX_SAMPLE_DELAY) { sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate); @@ -121,8 +132,10 @@ static int command_start_acquisition(const struct sr_dev_inst *sdi) cmd.sample_delay_l = delay & 0xff; /* Select the sampling width. */ - cmd.flags |= devc->sample_wide ? CMD_START_FLAGS_SAMPLE_16BIT : - CMD_START_FLAGS_SAMPLE_8BIT; + cmd.flags |= devc->unitsize == 4 ? CMD_START_FLAGS_SAMPLE_32BIT : + (devc->unitsize == 3 ? CMD_START_FLAGS_SAMPLE_24BIT : + (devc->unitsize == 2 ? CMD_START_FLAGS_SAMPLE_16BIT : + CMD_START_FLAGS_SAMPLE_8BIT)); /* Enable CTL2 clock. */ cmd.flags |= (g_slist_length(devc->enabled_analog_channels) > 0) ? CMD_START_FLAGS_CLK_CTL2 : 0; @@ -177,9 +190,19 @@ SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di) if (usb_get_port_path(devlist[i], connection_id, sizeof(connection_id)) < 0) continue; - if (strcmp(sdi->connection_id, connection_id)) + char const * _sdi_connection_id = sdi->connection_id; + char const * _connection_id = connection_id; + + if (devc->profile->dev_caps & DEV_CAPS_FX3) { + _sdi_connection_id = strchr(_sdi_connection_id, '-'); + _connection_id = strchr(connection_id, '-'); + } + + if (strcmp(_sdi_connection_id, _connection_id)) { /* This is not the one. */ + sr_info("Connection mismatch: %s vs. %s", sdi->connection_id, connection_id); continue; + } } if (!(ret = libusb_open(devlist[i], &usb->devhdl))) { @@ -260,7 +283,7 @@ SR_PRIV struct dev_context *fx2lafw_dev_new(void) devc->limit_frames = 1; devc->limit_samples = 0; devc->capture_ratio = 0; - devc->sample_wide = FALSE; + devc->unitsize = 1; devc->num_frames = 0; devc->stl = NULL; @@ -435,7 +458,7 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer) libusb_error_name(transfer->status), transfer->actual_length); /* Save incoming transfer before reusing the transfer struct. */ - unitsize = devc->sample_wide ? 2 : 1; + unitsize = devc->unitsize; cur_sample_count = transfer->actual_length / unitsize; processed_samples = 0; @@ -476,6 +499,8 @@ static void LIBUSB_CALL receive_transfer(struct libusb_transfer *transfer) num_samples = cur_sample_count - processed_samples; if (devc->limit_samples && devc->sent_samples + num_samples > devc->limit_samples) num_samples = devc->limit_samples - devc->sent_samples; + else + num_samples = cur_sample_count; devc->send_data_proc(sdi, (uint8_t *)transfer->buffer + processed_samples * unitsize, num_samples * unitsize, unitsize); @@ -564,14 +589,16 @@ static int configure_channels(const struct sr_dev_inst *sdi) * Use wide sampling if either any of the LA channels 8..15 is enabled, * and/or at least one analog channel is enabled. */ - devc->sample_wide = channel_mask > 0xff || num_analog > 0; + devc->unitsize = channel_mask > 0xffffff? 4 : + (channel_mask > 0xffff? 3 : + (channel_mask > 0xff || num_analog > 0? 2 : 1)); return SR_OK; } -static unsigned int to_bytes_per_ms(unsigned int samplerate) +static unsigned int to_bytes_per_ms(unsigned int samplerate, unsigned int unitsize) { - return samplerate / 1000; + return samplerate * unitsize / 1000; } static size_t get_buffer_size(struct dev_context *devc) @@ -580,10 +607,16 @@ static size_t get_buffer_size(struct dev_context *devc) /* * The buffer should be large enough to hold 10ms of data and - * a multiple of 512. + * a multiple of 1024. */ - s = 10 * to_bytes_per_ms(devc->cur_samplerate); - return (s + 511) & ~511; + s = 10 * to_bytes_per_ms(devc->cur_samplerate, devc->unitsize); + if (devc->unitsize == 3) { + /* Make it a multiple of 3K, to make sure we have an + integral number of samples */ + s += 3*1024; + s -= s % (3*1024); + } + return (s + 1023) & ~1023; } static unsigned int get_number_of_transfers(struct dev_context *devc) @@ -591,9 +624,14 @@ static unsigned int get_number_of_transfers(struct dev_context *devc) unsigned int n; /* Total buffer size should be able to hold about 500ms of data. */ - n = (500 * to_bytes_per_ms(devc->cur_samplerate) / + n = (500 * to_bytes_per_ms(devc->cur_samplerate, devc->unitsize) / get_buffer_size(devc)); + /* But no larger than 16M */ + unsigned int nmax = MAX_BULK_REQUEST_SIZE / get_buffer_size(devc); + if (n > nmax) + n = nmax; + if (n > NUM_SIMUL_TRANSFERS) return NUM_SIMUL_TRANSFERS; @@ -607,7 +645,7 @@ static unsigned int get_timeout(struct dev_context *devc) total_size = get_buffer_size(devc) * get_number_of_transfers(devc); - timeout = total_size / to_bytes_per_ms(devc->cur_samplerate); + timeout = total_size / to_bytes_per_ms(devc->cur_samplerate, devc->unitsize); return timeout + timeout / 4; /* Leave a headroom of 25% percent. */ } diff --git a/src/hardware/fx2lafw/protocol.h b/src/hardware/fx2lafw/protocol.h index 2c56b02ca..45d0f92af 100644 --- a/src/hardware/fx2lafw/protocol.h +++ b/src/hardware/fx2lafw/protocol.h @@ -38,6 +38,7 @@ #define MAX_RENUM_DELAY_MS 3000 #define NUM_SIMUL_TRANSFERS 32 #define MAX_EMPTY_TRANSFERS (NUM_SIMUL_TRANSFERS * 2) +#define MAX_BULK_REQUEST_SIZE 16000000 #define NUM_CHANNELS 16 @@ -51,15 +52,22 @@ #define DEV_CAPS_16BIT_POS 0 #define DEV_CAPS_AX_ANALOG_POS 1 +#define DEV_CAPS_FX3_POS 2 +#define DEV_CAPS_24BIT_POS 3 +#define DEV_CAPS_32BIT_POS 4 #define DEV_CAPS_16BIT (1 << DEV_CAPS_16BIT_POS) #define DEV_CAPS_AX_ANALOG (1 << DEV_CAPS_AX_ANALOG_POS) +#define DEV_CAPS_FX3 (1 << DEV_CAPS_FX3_POS) +#define DEV_CAPS_24BIT (1 << DEV_CAPS_24BIT_POS) +#define DEV_CAPS_32BIT (1 << DEV_CAPS_32BIT_POS) /* Protocol commands */ #define CMD_GET_FW_VERSION 0xb0 #define CMD_START 0xb1 #define CMD_GET_REVID_VERSION 0xb2 +#define CMD_START_FLAGS_SUPERWIDE_POS 3 #define CMD_START_FLAGS_CLK_CTL2_POS 4 #define CMD_START_FLAGS_WIDE_POS 5 #define CMD_START_FLAGS_CLK_SRC_POS 6 @@ -67,9 +75,11 @@ #define CMD_START_FLAGS_CLK_CTL2 (1 << CMD_START_FLAGS_CLK_CTL2_POS) #define CMD_START_FLAGS_SAMPLE_8BIT (0 << CMD_START_FLAGS_WIDE_POS) #define CMD_START_FLAGS_SAMPLE_16BIT (1 << CMD_START_FLAGS_WIDE_POS) - +#define CMD_START_FLAGS_SAMPLE_24BIT ((0 << CMD_START_FLAGS_WIDE_POS) | (1 << CMD_START_FLAGS_SUPERWIDE_POS)) +#define CMD_START_FLAGS_SAMPLE_32BIT ((1 << CMD_START_FLAGS_WIDE_POS) | (1 << CMD_START_FLAGS_SUPERWIDE_POS)) #define CMD_START_FLAGS_CLK_30MHZ (0 << CMD_START_FLAGS_CLK_SRC_POS) #define CMD_START_FLAGS_CLK_48MHZ (1 << CMD_START_FLAGS_CLK_SRC_POS) +#define CMD_START_FLAGS_CLK_192MHZ (2 << CMD_START_FLAGS_CLK_SRC_POS) struct fx2lafw_profile { uint16_t vid; @@ -108,7 +118,7 @@ struct dev_context { gboolean trigger_fired; gboolean acq_aborted; - gboolean sample_wide; + uint8_t unitsize; struct soft_trigger_logic *stl; uint64_t num_frames; diff --git a/src/hardware/hantek-6xxx/api.c b/src/hardware/hantek-6xxx/api.c index 408d1fcdc..3af62bb23 100644 --- a/src/hardware/hantek-6xxx/api.c +++ b/src/hardware/hantek-6xxx/api.c @@ -267,7 +267,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) devices = g_slist_append(devices, sdi); devc = sdi->priv; if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], - USB_CONFIGURATION, prof->firmware) == SR_OK) { + USB_CONFIGURATION, prof->firmware, FALSE) == SR_OK) { /* Remember when the firmware on this device was updated. */ devc->fw_updated = g_get_monotonic_time(); } else { diff --git a/src/hardware/hantek-dso/api.c b/src/hardware/hantek-dso/api.c index a3cc8a283..a334c53e8 100644 --- a/src/hardware/hantek-dso/api.c +++ b/src/hardware/hantek-dso/api.c @@ -330,7 +330,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) devices = g_slist_append(devices, sdi); devc = sdi->priv; if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], - USB_CONFIGURATION, prof->firmware) == SR_OK) { + USB_CONFIGURATION, prof->firmware, FALSE) == SR_OK) { /* Remember when the firmware on this device was updated */ devc->fw_updated = g_get_monotonic_time(); } else { diff --git a/src/hardware/kingst-la2016/protocol.c b/src/hardware/kingst-la2016/protocol.c index 0e4d94552..0e81c28f2 100644 --- a/src/hardware/kingst-la2016/protocol.c +++ b/src/hardware/kingst-la2016/protocol.c @@ -527,7 +527,7 @@ SR_PRIV int la2016_upload_firmware(struct sr_context *sr_ctx, libusb_device *dev { char fw_file[1024]; snprintf(fw_file, sizeof(fw_file) - 1, UC_FIRMWARE, product_id); - return ezusb_upload_firmware(sr_ctx, dev, USB_CONFIGURATION, fw_file); + return ezusb_upload_firmware(sr_ctx, dev, USB_CONFIGURATION, fw_file, FALSE); } SR_PRIV int la2016_setup_acquisition(const struct sr_dev_inst *sdi) diff --git a/src/hardware/lecroy-logicstudio/api.c b/src/hardware/lecroy-logicstudio/api.c index 6425e0f5f..c4ee51ccd 100644 --- a/src/hardware/lecroy-logicstudio/api.c +++ b/src/hardware/lecroy-logicstudio/api.c @@ -148,7 +148,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) break; case LOGICSTUDIO16_PID_LACK_FIRMWARE: r = ezusb_upload_firmware(drvc->sr_ctx, devlist[i], - USB_CONFIGURATION, FX2_FIRMWARE); + USB_CONFIGURATION, FX2_FIRMWARE, FALSE); if (r != SR_OK) { /* * An error message has already been logged by diff --git a/src/hardware/saleae-logic16/api.c b/src/hardware/saleae-logic16/api.c index 99916e44e..a027e7b5e 100644 --- a/src/hardware/saleae-logic16/api.c +++ b/src/hardware/saleae-logic16/api.c @@ -219,7 +219,7 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) libusb_get_device_address(devlist[i]), NULL); } else { if (ezusb_upload_firmware(drvc->sr_ctx, devlist[i], - USB_CONFIGURATION, FX2_FIRMWARE) == SR_OK) { + USB_CONFIGURATION, FX2_FIRMWARE, FALSE) == SR_OK) { /* Store when this device's FW was updated. */ devc->fw_updated = g_get_monotonic_time(); } else { diff --git a/src/libsigrok-internal.h b/src/libsigrok-internal.h index 1c37ee275..5c3b52100 100644 --- a/src/libsigrok-internal.h +++ b/src/libsigrok-internal.h @@ -2040,9 +2040,9 @@ SR_PRIV int sr_bt_check_notify(struct sr_bt_desc *desc); #ifdef HAVE_LIBUSB_1_0 SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear); SR_PRIV int ezusb_install_firmware(struct sr_context *ctx, libusb_device_handle *hdl, - const char *name); + const char *name, gboolean fx3); SR_PRIV int ezusb_upload_firmware(struct sr_context *ctx, libusb_device *dev, - int configuration, const char *name); + int configuration, const char *name, gboolean fx3); #endif /*--- usb.c -----------------------------------------------------------------*/