From: Marc Schink Date: Mon, 10 Jun 2013 08:10:13 +0000 (+0200) Subject: Initial driver for IKALOGIC Scanalogic-2 X-Git-Tag: libsigrok-0.2.1~71 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=e52e712d05419e4387704262a07e00904b2acbed;p=libsigrok.git Initial driver for IKALOGIC Scanalogic-2 --- diff --git a/hardware/ikalogic-scanalogic2/api.c b/hardware/ikalogic-scanalogic2/api.c index 924bc3c4..44036163 100644 --- a/hardware/ikalogic-scanalogic2/api.c +++ b/hardware/ikalogic-scanalogic2/api.c @@ -19,28 +19,176 @@ #include "protocol.h" +static const int hwcaps[] = { + SR_CONF_LOGIC_ANALYZER, + SR_CONF_SAMPLERATE, + SR_CONF_LIMIT_SAMPLES, + SR_CONF_TRIGGER_TYPE, + SR_CONF_CAPTURE_RATIO +}; + +SR_PRIV const uint64_t ikalogic_scanalogic2_samplerates[NUM_SAMPLERATES] = { + SR_KHZ(1.25), + SR_KHZ(10), + SR_KHZ(50), + SR_KHZ(100), + SR_KHZ(250), + SR_KHZ(500), + SR_MHZ(1), + SR_MHZ(2.5), + SR_MHZ(5), + SR_MHZ(10), + SR_MHZ(20) +}; + +static const char *probe_names[NUM_PROBES + 1] = { + "0", "1", "2", "3", + NULL +}; + SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info; static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info; - static int init(struct sr_context *sr_ctx) { - return std_hw_init(sr_ctx, di, LOG_PREFIX); + return std_init(sr_ctx, di, LOG_PREFIX); } static GSList *scan(GSList *options) { + GSList *usb_devices, *devices, *l; struct drv_context *drvc; - GSList *devices; + struct sr_dev_inst *sdi; + struct sr_probe *probe; + struct dev_context *devc; + struct sr_usb_dev_inst *usb; + struct device_info dev_info; + int ret, device_index, i; + char *fw_ver_str; (void)options; devices = NULL; drvc = di->priv; drvc->instances = NULL; + device_index = 0; + + usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_VID_PID); + + if (usb_devices == NULL) + return NULL; + + for (l = usb_devices; l; l = l->next) + { + usb = l->data; + + ret = ikalogic_scanalogic2_get_device_info(*usb, &dev_info); + + if (ret != SR_OK) { + sr_warn("Failed to get device information.\n"); + sr_usb_dev_inst_free(usb); + continue; + } + + devc = g_try_malloc(sizeof(struct dev_context)); + + if (!devc) { + sr_err("Device instance malloc failed."); + sr_usb_dev_inst_free(usb); + continue; + } + + if (!(devc->xfer_in = libusb_alloc_transfer(0))) { + sr_err("Transfer malloc failed."); + sr_usb_dev_inst_free(usb); + g_free(devc); + continue; + } + + if (!(devc->xfer_out = libusb_alloc_transfer(0))) { + sr_err("Transfer malloc failed."); + sr_usb_dev_inst_free(usb); + libusb_free_transfer(devc->xfer_in); + g_free(devc); + continue; + } + + fw_ver_str = g_strdup_printf("%u.%u", dev_info.fw_ver_major, + dev_info.fw_ver_minor); + + if (!fw_ver_str) { + sr_err("Firmware string malloc failed."); + sr_usb_dev_inst_free(usb); + libusb_free_transfer(devc->xfer_in); + libusb_free_transfer(devc->xfer_out); + g_free(devc); + continue; + } + + sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, VENDOR_NAME, + MODEL_NAME, fw_ver_str); + + g_free(fw_ver_str); + + if (!sdi) { + sr_err("sr_dev_inst_new failed."); + sr_usb_dev_inst_free(usb); + libusb_free_transfer(devc->xfer_in); + libusb_free_transfer(devc->xfer_out); + g_free(devc); + continue; + } + + sdi->priv = devc; + sdi->driver = di; + sdi->inst_type = SR_INST_USB; + sdi->conn = usb; + + for (i = 0; probe_names[i]; i++) { + probe = sr_probe_new(i, SR_PROBE_LOGIC, TRUE, + probe_names[i]); + sdi->probes = g_slist_append(sdi->probes, probe); + devc->probes[i] = probe; + } + + devc->state = STATE_IDLE; + devc->next_state = STATE_IDLE; + + /* Set default samplerate. */ + ikalogic_scanalogic2_set_samplerate(sdi, DEFAULT_SAMPLERATE); + + /* Set default capture ratio. */ + devc->capture_ratio = 0; + + /* Set default after trigger delay. */ + devc->after_trigger_delay = 0; + + memset(devc->xfer_buf_in, 0, LIBUSB_CONTROL_SETUP_SIZE + + PACKET_LENGTH); + memset(devc->xfer_buf_out, 0, LIBUSB_CONTROL_SETUP_SIZE + + PACKET_LENGTH); + + libusb_fill_control_setup(devc->xfer_buf_in, + USB_REQUEST_TYPE_IN, USB_HID_SET_REPORT, + USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, + PACKET_LENGTH); + libusb_fill_control_setup(devc->xfer_buf_out, + USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT, + USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, + PACKET_LENGTH); + + devc->xfer_data_in = devc->xfer_buf_in + + LIBUSB_CONTROL_SETUP_SIZE; + devc->xfer_data_out = devc->xfer_buf_out + + LIBUSB_CONTROL_SETUP_SIZE; + + drvc->instances = g_slist_append(drvc->instances, sdi); + devices = g_slist_append(devices, sdi); + + device_index++; + } - /* TODO: scan for devices, either based on a SR_CONF_CONN option - * or on a USB scan. */ + g_slist_free(usb_devices); return devices; } @@ -54,16 +202,94 @@ static GSList *dev_list(void) return drvc->instances; } +static void clear_dev_context(void *priv) +{ + struct dev_context *devc = priv; + + sr_dbg("Device context cleard."); + + libusb_free_transfer(devc->xfer_in); + libusb_free_transfer(devc->xfer_out); + g_free(devc); +} + static int dev_clear(void) { - return std_dev_clear(di, NULL); + return std_dev_clear(di, &clear_dev_context); } static int dev_open(struct sr_dev_inst *sdi) { - (void)sdi; + struct drv_context *drvc; + struct dev_context *devc; + struct sr_usb_dev_inst *usb; + uint8_t buffer[PACKET_LENGTH]; + int ret; + + if (!(drvc = di->priv)) { + sr_err("Driver was not initialized."); + return SR_ERR; + } + + usb = sdi->conn; + devc = sdi->priv; - /* TODO: get handle from sdi->conn and open it. */ + if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK) + return SR_ERR; + + /* + * Determine if a kernel driver is active on this interface and, if so, + * detach it. + */ + if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) { + ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE); + + if (ret < 0) { + sr_err("Failed to detach kernel driver: %i.", + libusb_error_name(ret)); + return SR_ERR; + } + } + + ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE); + + if (ret) { + sr_err("Failed to claim interface: %s.", + libusb_error_name(ret)); + return SR_ERR; + } + + libusb_fill_control_transfer(devc->xfer_in, usb->devhdl, + devc->xfer_buf_in, ikalogic_scanalogic2_receive_transfer_in, + sdi, USB_TIMEOUT); + + libusb_fill_control_transfer(devc->xfer_out, usb->devhdl, + devc->xfer_buf_out, ikalogic_scanalogic2_receive_transfer_out, + sdi, USB_TIMEOUT); + + memset(buffer, 0, sizeof(buffer)); + + buffer[0] = CMD_RESET; + ret = ikalogic_scanalogic2_transfer_out(usb->devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Device reset failed: %s.", libusb_error_name(ret)); + return SR_ERR; + } + + /* + * Set the device to idle state. If the device is not in idle state it + * possibly will reset itself after a few seconds without being used and + * thereby close the connection. + */ + buffer[0] = CMD_IDLE; + ret = ikalogic_scanalogic2_transfer_out(usb->devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Failed to set device in idle state: %s.", + libusb_error_name(ret)); + return SR_ERR; + } sdi->status = SR_ST_ACTIVE; @@ -72,10 +298,22 @@ static int dev_open(struct sr_dev_inst *sdi) static int dev_close(struct sr_dev_inst *sdi) { - (void)sdi; + struct sr_usb_dev_inst *usb; + + if (!di->priv) { + sr_err("Driver was not initialized."); + return SR_ERR; + } + + usb = sdi->conn; + + if (!usb->devhdl) + return SR_OK; - /* TODO: get handle from sdi->conn and close it. */ + libusb_release_interface(usb->devhdl, USB_INTERFACE); + libusb_close(usb->devhdl); + usb->devhdl = NULL; sdi->status = SR_ST_INACTIVE; return SR_OK; @@ -85,21 +323,24 @@ static int cleanup(void) { dev_clear(); - /* TODO: free other driver resources, if any. */ - return SR_OK; } static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi) { + struct dev_context *devc; int ret; - (void)sdi; - (void)data; - ret = SR_OK; + devc = sdi->priv; + switch (key) { - /* TODO */ + case SR_CONF_SAMPLERATE: + *data = g_variant_new_uint64(devc->samplerate); + break; + case SR_CONF_CAPTURE_RATIO: + *data = g_variant_new_uint64(devc->capture_ratio); + break; default: return SR_ERR_NA; } @@ -109,18 +350,31 @@ static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi) static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi) { + uint64_t samplerate, limit_samples, capture_ratio; int ret; - (void)data; - if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; ret = SR_OK; + switch (key) { - /* TODO */ + case SR_CONF_LIMIT_SAMPLES: + limit_samples = g_variant_get_uint64(data); + ret = ikalogic_scanalogic2_set_limit_samples(sdi, + limit_samples); + break; + case SR_CONF_SAMPLERATE: + samplerate = g_variant_get_uint64(data); + ret = ikalogic_scanalogic2_set_samplerate(sdi, samplerate); + break; + case SR_CONF_CAPTURE_RATIO: + capture_ratio = g_variant_get_uint64(data); + ret = ikalogic_scanalogic2_set_capture_ratio(sdi, + capture_ratio); + break; default: - ret = SR_ERR_NA; + return SR_ERR_NA; } return ret; @@ -128,14 +382,31 @@ static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi) static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) { + GVariant *gvar; + GVariantBuilder gvb; int ret; (void)sdi; - (void)data; ret = SR_OK; + switch (key) { - /* TODO */ + case SR_CONF_DEVICE_OPTIONS: + *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps, + ARRAY_SIZE(hwcaps), sizeof(int32_t)); + break; + case SR_CONF_SAMPLERATE: + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), + ikalogic_scanalogic2_samplerates, + ARRAY_SIZE(ikalogic_scanalogic2_samplerates), + sizeof(uint64_t)); + g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); + *data = g_variant_builder_end(&gvb); + break; + case SR_CONF_TRIGGER_TYPE: + *data = g_variant_new_string(TRIGGER_TYPES); + break; default: return SR_ERR_NA; } @@ -143,17 +414,115 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi) return ret; } -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) { - (void)sdi; - (void)cb_data; + const struct libusb_pollfd **pfd; + struct drv_context *drvc; + struct dev_context *devc; + uint16_t trigger_bytes, tmp; + unsigned int i, j; + int ret; if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; - /* TODO: configure hardware, reset acquisition state, set up - * callbacks and send header packet. */ + devc = sdi->priv; + drvc = di->priv; + + devc->cb_data = cb_data; + devc->wait_data_ready_locked = TRUE; + devc->stopping_in_progress = FALSE; + devc->transfer_error = FALSE; + devc->samples_processed = 0; + devc->channel = 0; + devc->sample_packet = 0; + + /* + * The trigger must be configured first because the calculation of the + * pre and post trigger samples depends on a configured trigger. + */ + ikalogic_scanalogic2_configure_trigger(sdi); + ikalogic_scanalogic2_calculate_trigger_samples(sdi); + + trigger_bytes = devc->pre_trigger_bytes + devc->post_trigger_bytes; + + /* Calculate the number of expected sample packets. */ + devc->num_sample_packets = trigger_bytes / PACKET_NUM_SAMPLE_BYTES; + + /* Round up the number of expected sample packets. */ + if (trigger_bytes % PACKET_NUM_SAMPLE_BYTES != 0) + devc->num_sample_packets++; + + devc->num_enabled_probes = 0; + + /* + * Count the number of enabled probes and number them for a sequential + * access. + */ + for (i = 0, j = 0; i < NUM_PROBES; i++) { + if (devc->probes[i]->enabled) { + devc->num_enabled_probes++; + devc->probe_map[j] = i; + j++; + } + } + + sr_dbg("Number of enabled probes: %i.", devc->num_enabled_probes); + + /* Set up the transfer buffer for the acquisition. */ + devc->xfer_data_out[0] = CMD_SAMPLE; + devc->xfer_data_out[1] = 0x00; + + tmp = GUINT16_TO_LE(devc->pre_trigger_bytes); + memcpy(devc->xfer_data_out + 2, &tmp, sizeof(tmp)); + + tmp = GUINT16_TO_LE(devc->post_trigger_bytes); + memcpy(devc->xfer_data_out + 4, &tmp, sizeof(tmp)); + + devc->xfer_data_out[6] = devc->samplerate_id; + devc->xfer_data_out[7] = devc->trigger_type; + devc->xfer_data_out[8] = devc->trigger_channel; + devc->xfer_data_out[9] = 0x00; + + tmp = GUINT16_TO_LE(devc->after_trigger_delay); + memcpy(devc->xfer_data_out + 10, &tmp, sizeof(tmp)); + + if (!(pfd = libusb_get_pollfds(drvc->sr_ctx->libusb_ctx))) { + sr_err("libusb_get_pollfds failed."); + return SR_ERR; + } + + /* Count the number of file descriptors. */ + for (devc->num_usbfd = 0; pfd[devc->num_usbfd]; devc->num_usbfd++); + + if (!(devc->usbfd = g_try_malloc(devc->num_usbfd * sizeof(int)))) { + sr_err("File descriptor array malloc failed."); + free(pfd); + + return SR_ERR_MALLOC; + } + + if ((ret = libusb_submit_transfer(devc->xfer_out)) != 0) { + sr_err("Submit transfer failed: %s", libusb_error_name(ret)); + g_free(devc->usbfd); + return SR_ERR; + } + + for (i = 0; i < devc->num_usbfd; i++) { + sr_source_add(pfd[i]->fd, pfd[i]->events, 100, + ikalogic_scanalogic2_receive_data, (void *)sdi); + + devc->usbfd[i] = pfd[i]->fd; + } + + free(pfd); + + sr_dbg("Acquisition started successfully."); + + /* Send header packet to the session bus. */ + std_session_send_df_header(cb_data, LOG_PREFIX); + + devc->next_state = STATE_SAMPLE; return SR_OK; } @@ -165,14 +534,16 @@ static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data) if (sdi->status != SR_ST_ACTIVE) return SR_ERR_DEV_CLOSED; - /* TODO: stop acquisition. */ + sr_dbg("Stopping acquisition."); + + sdi->status = SR_ST_STOPPING; return SR_OK; } SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info = { .name = "ikalogic-scanalogic2", - .longname = "IKALOGIC Scanalogic2", + .longname = "IKALOGIC Scanalogic-2", .api_version = 1, .init = init, .cleanup = cleanup, diff --git a/hardware/ikalogic-scanalogic2/protocol.c b/hardware/ikalogic-scanalogic2/protocol.c index 2f587956..f6c0b278 100644 --- a/hardware/ikalogic-scanalogic2/protocol.c +++ b/hardware/ikalogic-scanalogic2/protocol.c @@ -19,12 +19,202 @@ #include "protocol.h" -SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data) +extern struct sr_dev_driver ikalogic_scanalogic2_driver_info; +static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info; + +extern uint64_t ikalogic_scanalogic2_samplerates[NUM_SAMPLERATES]; + +static void stop_acquisition(struct sr_dev_inst *sdi) { - (void)fd; + struct dev_context *devc; + struct sr_datafeed_packet packet; + unsigned int i; + + devc = sdi->priv; + + /* Remove USB file descriptors from polling. */ + for (i = 0; i < devc->num_usbfd; i++) + sr_source_remove(devc->usbfd[i]); + + g_free(devc->usbfd); - const struct sr_dev_inst *sdi; + packet.type = SR_DF_END; + sr_session_send(devc->cb_data, &packet); + + sdi->status = SR_ST_ACTIVE; +} + +static void abort_acquisition(struct sr_dev_inst *sdi) +{ struct dev_context *devc; + struct sr_datafeed_packet packet; + unsigned int i; + + devc = sdi->priv; + + /* Remove USB file descriptors from polling. */ + for (i = 0; i < devc->num_usbfd; i++) + sr_source_remove(devc->usbfd[i]); + + g_free(devc->usbfd); + + packet.type = SR_DF_END; + sr_session_send(devc->cb_data, &packet); + + sdi->driver->dev_close(sdi); +} + +static void buffer_sample_data(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + unsigned int offset, packet_length; + + devc = sdi->priv; + + if (devc->probes[devc->channel]->enabled) { + offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES; + + /* + * Determine the packet length to ensure that the last packet + * will not exceed the buffer size. + */ + packet_length = MIN(PACKET_NUM_SAMPLE_BYTES, + MAX_DEV_SAMPLE_BYTES - offset); + + /* + * Skip the first 4 bytes of the source buffer because they + * contain channel and packet information only. + */ + memcpy(devc->sample_buffer[devc->channel] + offset, + devc->xfer_data_in + 4, packet_length); + } +} + +static void process_sample_data(const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; + uint8_t i, j, tmp, buffer[PACKET_NUM_SAMPLES], *ptr[NUM_PROBES]; + uint16_t offset, n = 0; + int8_t k; + + devc = sdi->priv; + offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES; + + /* + * Array of pointers to the sample data of all channels up to the last + * enabled one for an uniform access to them. Note that the currently + * received samples always belong to the last enabled channel. + */ + for (i = 0; i < devc->num_enabled_probes - 1; i++) + ptr[i] = devc->sample_buffer[devc->probe_map[i]] + offset; + + /* + * Skip the first 4 bytes of the buffer because they contain channel and + * packet information only. + */ + ptr[i] = devc->xfer_data_in + 4; + + for (i = 0; i < PACKET_NUM_SAMPLE_BYTES; i++) { + /* Stop processing if all requested samples are processed. */ + if (devc->samples_processed == devc->limit_samples) + break; + + k = 7; + + if (devc->samples_processed == 0) { + /* + * Adjust the position of the first sample to be + * processed because possibly more samples than + * necessary might have been aquired. This is because + * the number of aquired samples is always rounded up to + * a multiple of 8. + */ + k = k - (devc->pre_trigger_bytes * 8) + + devc->pre_trigger_samples; + + sr_dbg("Start processing at sample: %" PRIu8 ".", + 7 - k); + + /* + * Send the trigger before the first sample is processed + * if no pre trigger samples were calculated through the + * capture ratio. + */ + if (devc->trigger_type != TRIGGER_TYPE_NONE && + devc->pre_trigger_samples == 0) { + packet.type = SR_DF_TRIGGER; + sr_session_send(devc->cb_data, &packet); + } + } + + for (; k >= 0; k--) { + /* + * Stop processing if all requested samples are + * processed. + */ + if (devc->samples_processed == devc->limit_samples) + break; + + buffer[n] = 0; + + /* + * Extract the current sample for each enabled channel + * and store them in the buffer. + */ + for (j = 0; j < devc->num_enabled_probes; j++) { + tmp = (ptr[j][i] & (1 << k)) >> k; + buffer[n] |= tmp << devc->probe_map[j]; + } + + n++; + devc->samples_processed++; + + /* + * Send all processed samples and the trigger if the + * number of processed samples reaches the calculated + * number of pre trigger samples. + */ + if (devc->samples_processed == devc->pre_trigger_samples && + devc->trigger_type != TRIGGER_TYPE_NONE) { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.length = n; + logic.unitsize = 1; + logic.data = buffer; + sr_session_send(devc->cb_data, &packet); + + packet.type = SR_DF_TRIGGER; + sr_session_send(devc->cb_data, &packet); + + n = 0; + } + } + } + + if (n > 0) { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.length = n; + logic.unitsize = 1; + logic.data = buffer; + sr_session_send(devc->cb_data, &packet); + } +} + +SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, + void *cb_data) +{ + struct sr_dev_inst *sdi; + struct dev_context *devc; + struct drv_context *drvc; + struct timeval tv; + int64_t current_time, time_elapsed; + int ret = 0; + + (void)fd; + (void)revents; if (!(sdi = cb_data)) return TRUE; @@ -32,9 +222,558 @@ SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data if (!(devc = sdi->priv)) return TRUE; - if (revents == G_IO_IN) { - /* TODO */ + drvc = di->priv; + current_time = g_get_monotonic_time(); + + if (devc->state == STATE_WAIT_DATA_READY && + !devc->wait_data_ready_locked) { + time_elapsed = current_time - devc->wait_data_ready_time; + + /* + * Check here for stopping in addition to the transfer callback + * functions to avoid waiting until the WAIT_DATA_READY_INTERVAL + * has expired. + */ + if (sdi->status == SR_ST_STOPPING) { + if (!devc->stopping_in_progress) { + devc->next_state = STATE_RESET_AND_IDLE; + devc->stopping_in_progress = TRUE; + ret = libusb_submit_transfer(devc->xfer_in); + } + } else if (time_elapsed >= WAIT_DATA_READY_INTERVAL) { + devc->wait_data_ready_locked = TRUE; + ret = libusb_submit_transfer(devc->xfer_in); + } + } + + if (ret != 0) { + sr_err("Submit transfer failed: %s", libusb_error_name(ret)); + abort_acquisition(sdi); + return TRUE; + } + + tv.tv_sec = 0; + tv.tv_usec = 0; + + libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv, + NULL); + + /* Check if an error occurred on a transfer. */ + if (devc->transfer_error) { + abort_acquisition(sdi); } return TRUE; } + +SR_PRIV void ikalogic_scanalogic2_receive_transfer_in( + struct libusb_transfer *transfer) +{ + struct sr_dev_inst *sdi; + struct dev_context *devc; + uint8_t last_channel; + int ret = 0; + + sdi = transfer->user_data; + devc = sdi->priv; + + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + sr_err("Transfer to device failed: %i", transfer->status); + devc->transfer_error = TRUE; + return; + } + + if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) { + devc->next_state = STATE_RESET_AND_IDLE; + devc->stopping_in_progress = TRUE; + + if (libusb_submit_transfer(devc->xfer_in) != 0) { + sr_err("Submit transfer failed: %s", + libusb_error_name(ret)); + devc->transfer_error = TRUE; + } + + return; + } + + sr_dbg("State changed from %i to %i.", devc->state, devc->next_state); + devc->state = devc->next_state; + + if (devc->state == STATE_WAIT_DATA_READY) { + /* Check if the received data are a valid device status. */ + if (devc->xfer_data_in[0] == 0x05) { + if (devc->xfer_data_in[1] == STATUS_WAITING_FOR_TRIGGER) + sr_dbg("Waiting for trigger."); + else if (devc->xfer_data_in[1] == STATUS_SAMPLING) + sr_dbg("Sampling in progress."); + } + + /* + * Check if the received data are a valid device status and the + * sample data are ready. + */ + if (devc->xfer_data_in[0] == 0x05 && + devc->xfer_data_in[1] == STATUS_DATA_READY) { + devc->next_state = STATE_RECEIVE_DATA; + ret = libusb_submit_transfer(transfer); + } else { + devc->wait_data_ready_locked = FALSE; + devc->wait_data_ready_time = g_get_monotonic_time(); + } + } else if (devc->state == STATE_RECEIVE_DATA) { + last_channel = devc->probe_map[devc->num_enabled_probes - 1]; + + if (devc->channel < last_channel) { + buffer_sample_data(sdi); + } else if (devc->channel == last_channel) { + process_sample_data(sdi); + } else { + /* + * Stop acquisition because all samples of enabled + * probes are processed. + */ + devc->next_state = STATE_RESET_AND_IDLE; + } + + devc->sample_packet++; + devc->sample_packet %= devc->num_sample_packets; + + if (devc->sample_packet == 0) + devc->channel++; + + ret = libusb_submit_transfer(transfer); + } else if (devc->state == STATE_RESET_AND_IDLE) { + /* Check if the received data are a valid device status. */ + if (devc->xfer_data_in[0] == 0x05) { + if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) { + devc->next_state = STATE_IDLE; + devc->xfer_data_out[0] = CMD_IDLE; + } else { + devc->next_state = STATE_WAIT_DEVICE_READY; + devc->xfer_data_out[0] = CMD_RESET; + } + + ret = libusb_submit_transfer(devc->xfer_out); + } else { + /* + * The received device status is invalid which indicates + * that the device is not ready to accept commands. + * Request a new device status until a valid device + * status is received. + */ + ret = libusb_submit_transfer(transfer); + } + } else if (devc->state == STATE_WAIT_DEVICE_READY) { + /* Check if the received data are a valid device status. */ + if (devc->xfer_data_in[0] == 0x05) { + if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) { + devc->next_state = STATE_IDLE; + devc->xfer_data_out[0] = CMD_IDLE; + } else { + /* + * The received device status is valid but the + * device is not ready. Probably the device did + * not recognize the last reset. Reset the + * device again. + */ + devc->xfer_data_out[0] = CMD_RESET; + } + + ret = libusb_submit_transfer(devc->xfer_out); + } else { + /* + * The device is not ready and therefore not able to + * change to the idle state. Request a new device status + * until the device is ready. + */ + ret = libusb_submit_transfer(transfer); + } + } + + if (ret != 0) { + sr_err("Submit transfer failed: %s", libusb_error_name(ret)); + devc->transfer_error = TRUE; + } +} + +SR_PRIV void ikalogic_scanalogic2_receive_transfer_out( + struct libusb_transfer *transfer) +{ + struct sr_dev_inst *sdi; + struct dev_context *devc; + int ret = 0; + + sdi = transfer->user_data; + devc = sdi->priv; + + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + sr_err("Transfer to device failed: %i", transfer->status); + devc->transfer_error = TRUE; + return; + } + + if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) { + devc->next_state = STATE_RESET_AND_IDLE; + devc->stopping_in_progress = TRUE; + + if (libusb_submit_transfer(devc->xfer_in) != 0) { + sr_err("Submit transfer failed: %s", + libusb_error_name(ret)); + + devc->transfer_error = TRUE; + } + + return; + } + + sr_dbg("State changed from %i to %i.", devc->state, devc->next_state); + devc->state = devc->next_state; + + if (devc->state == STATE_IDLE) { + stop_acquisition(sdi); + } else if (devc->state == STATE_SAMPLE) { + devc->next_state = STATE_WAIT_DATA_READY; + ret = libusb_submit_transfer(devc->xfer_in); + } else if (devc->state == STATE_WAIT_DEVICE_READY) { + ret = libusb_submit_transfer(devc->xfer_in); + } + + if (ret != 0) { + sr_err("Submit transfer failed: %s", libusb_error_name(ret)); + devc->transfer_error = TRUE; + } +} + +SR_PRIV int ikalogic_scanalogic2_set_samplerate(const struct sr_dev_inst *sdi, + uint64_t samplerate) +{ + struct dev_context *devc; + unsigned int i; + + devc = sdi->priv; + + for (i = 0; i < NUM_SAMPLERATES; i++) { + if (ikalogic_scanalogic2_samplerates[i] == samplerate) { + devc->samplerate = samplerate; + devc->samplerate_id = NUM_SAMPLERATES - i - 1; + return SR_OK; + } + } + + return SR_ERR_ARG; +} + +SR_PRIV int ikalogic_scanalogic2_set_limit_samples( + const struct sr_dev_inst *sdi, uint64_t limit_samples) +{ + struct dev_context *devc; + + devc = sdi->priv; + + if (limit_samples == 0) { + sr_err("Invalid number of limit samples: %" PRIu64 ".", + limit_samples); + return SR_ERR_ARG; + } + + if (limit_samples > MAX_SAMPLES) + limit_samples = MAX_SAMPLES; + + sr_info("Limit samples set to %" PRIu64 ".", limit_samples); + + devc->limit_samples = limit_samples; + + return SR_OK; +} + +SR_PRIV void ikalogic_scanalogic2_configure_trigger( + const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + struct sr_probe *probe; + uint8_t trigger_type; + int probe_index, num_triggers_anyedge; + char *trigger; + GSList *l; + + devc = sdi->priv; + + /* Disable the trigger by default. */ + devc->trigger_channel = TRIGGER_CHANNEL_0; + devc->trigger_type = TRIGGER_TYPE_NONE; + + num_triggers_anyedge = 0; + + for (l = sdi->probes, probe_index = 0; l; l = l->next, probe_index++) { + probe = l->data; + trigger = probe->trigger; + + if (!trigger || !probe->enabled) + continue; + + switch (*trigger) { + case 'r': + trigger_type = TRIGGER_TYPE_POSEDGE; + break; + case 'f': + trigger_type = TRIGGER_TYPE_NEGEDGE; + break; + case 'c': + trigger_type = TRIGGER_TYPE_ANYEDGE; + num_triggers_anyedge++; + break; + default: + continue; + } + + devc->trigger_channel = probe_index + 1; + devc->trigger_type = trigger_type; + } + + /* + * Set trigger to any edge on all channels if the trigger for each + * channel is set to any edge. + */ + if (num_triggers_anyedge == NUM_PROBES) { + devc->trigger_channel = TRIGGER_CHANNEL_ALL; + devc->trigger_type = TRIGGER_TYPE_ANYEDGE; + } + + sr_dbg("Trigger set to channel %" PRIu8 " and type %" PRIu8 ".", + devc->trigger_channel, devc->trigger_type); +} + +SR_PRIV int ikalogic_scanalogic2_set_capture_ratio( + const struct sr_dev_inst *sdi, uint64_t capture_ratio) +{ + struct dev_context *devc; + + devc = sdi->priv; + + if (capture_ratio > 100) { + sr_err("Invalid capture ratio: %" PRIu64 " %%.", capture_ratio); + return SR_ERR_ARG; + } + + sr_info("Capture ratio set to %" PRIu64 " %%.", capture_ratio); + + devc->capture_ratio = capture_ratio; + + return SR_OK; +} + +SR_PRIV int ikaloigc_scanalogic2_set_after_trigger_delay( + const struct sr_dev_inst *sdi, uint64_t after_trigger_delay) +{ + struct dev_context *devc; + + devc = sdi->priv; + + if (after_trigger_delay > MAX_AFTER_TRIGGER_DELAY) { + sr_err("Invalid after trigger delay: %" PRIu64 " ms.", + after_trigger_delay); + return SR_ERR_ARG; + } + + sr_info("After trigger delay set to %" PRIu64 " ms.", + after_trigger_delay); + + devc->after_trigger_delay = after_trigger_delay; + + return SR_OK; +} + +SR_PRIV void ikalogic_scanalogic2_calculate_trigger_samples( + const struct sr_dev_inst *sdi) +{ + struct dev_context *devc; + uint64_t pre_trigger_samples, post_trigger_samples; + uint16_t pre_trigger_bytes, post_trigger_bytes; + uint8_t cr; + + devc = sdi->priv; + cr = devc->capture_ratio; + + /* Ignore the capture ratio if no trigger is enabled. */ + if (devc->trigger_type == TRIGGER_TYPE_NONE) + cr = 0; + + pre_trigger_samples = (devc->limit_samples * cr) / 100; + post_trigger_samples = (devc->limit_samples * (100 - cr)) / 100; + + /* + * Increase the number of post trigger samples by one to compensate the + * possible loss of a sample through integer rounding. + */ + if (pre_trigger_samples + post_trigger_samples != devc->limit_samples) + post_trigger_samples++; + + /* + * The device requires the number of samples in multiples of 8 which + * will also be called sample bytes in the following. + */ + pre_trigger_bytes = pre_trigger_samples / 8; + post_trigger_bytes = post_trigger_samples / 8; + + /* + * Round up the number of sample bytes to ensure that at least the + * requested number of samples will be acquired. Note that due to this + * rounding the buffer to store these sample bytes needs to be at least + * one sample byte larger than the minimal number of sample bytes needed + * to store the requested samples. + */ + if (pre_trigger_samples % 8 != 0) + pre_trigger_bytes++; + + if (post_trigger_samples % 8 != 0) + post_trigger_bytes++; + + sr_info("Pre trigger samples: %" PRIu64 ".", pre_trigger_samples); + sr_info("Post trigger samples: %" PRIu64 ".", post_trigger_samples); + sr_dbg("Pre trigger sample bytes: %" PRIu16 ".", pre_trigger_bytes); + sr_dbg("Post trigger sample bytes: %" PRIu16 ".", post_trigger_bytes); + + devc->pre_trigger_samples = pre_trigger_samples; + devc->pre_trigger_bytes = pre_trigger_bytes; + devc->post_trigger_bytes = post_trigger_bytes; +} + +SR_PRIV int ikalogic_scanalogic2_get_device_info(struct sr_usb_dev_inst usb, + struct device_info *dev_info) +{ + struct drv_context *drvc; + uint8_t buffer[PACKET_LENGTH]; + int ret; + + drvc = di->priv; + + if (!dev_info) + return SR_ERR_ARG; + + if (sr_usb_open(drvc->sr_ctx->libusb_ctx, &usb) != SR_OK) + return SR_ERR; + + /* + * Determine if a kernel driver is active on this interface and, if so, + * detach it. + */ + if (libusb_kernel_driver_active(usb.devhdl, USB_INTERFACE) == 1) { + ret = libusb_detach_kernel_driver(usb.devhdl, + USB_INTERFACE); + + if (ret < 0) { + sr_err("Failed to detach kernel driver: %i.", + libusb_error_name(ret)); + libusb_close(usb.devhdl); + return SR_ERR; + } + } + + ret = libusb_claim_interface(usb.devhdl, USB_INTERFACE); + + if (ret) { + sr_err("Failed to claim interface: %s.", + libusb_error_name(ret)); + libusb_close(usb.devhdl); + return SR_ERR; + } + + memset(buffer, 0, sizeof(buffer)); + + /* + * Reset the device to ensure it is in a proper state to request the + * device information. + */ + buffer[0] = CMD_RESET; + ret = ikalogic_scanalogic2_transfer_out(usb.devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Resetting of device failed: %s.", + libusb_error_name(ret)); + libusb_release_interface(usb.devhdl, USB_INTERFACE); + libusb_close(usb.devhdl); + return SR_ERR; + } + + buffer[0] = CMD_INFO; + ret = ikalogic_scanalogic2_transfer_out(usb.devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Requesting of device information failed: %s.", + libusb_error_name(ret)); + libusb_release_interface(usb.devhdl, USB_INTERFACE); + libusb_close(usb.devhdl); + return SR_ERR; + } + + ret = ikalogic_scanalogic2_transfer_in(usb.devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Receiving of device information failed: %s.", + libusb_error_name(ret)); + libusb_release_interface(usb.devhdl, USB_INTERFACE); + libusb_close(usb.devhdl); + return SR_ERR; + } + + memcpy(&(dev_info->serial), buffer + 1, sizeof(uint32_t)); + dev_info->serial = GUINT32_FROM_LE(dev_info->serial); + + dev_info->fw_ver_major = buffer[5]; + dev_info->fw_ver_minor = buffer[6]; + + buffer[0] = CMD_RESET; + ret = ikalogic_scanalogic2_transfer_out(usb.devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Device reset failed: %s.", libusb_error_name(ret)); + libusb_release_interface(usb.devhdl, USB_INTERFACE); + libusb_close(usb.devhdl); + return SR_ERR; + } + + /* + * Set the device to idle state. If the device is not in idle state it + * possibly will reset itself after a few seconds without being used and + * thereby close the connection. + */ + buffer[0] = CMD_IDLE; + ret = ikalogic_scanalogic2_transfer_out(usb.devhdl, buffer); + + if (ret != PACKET_LENGTH) { + sr_err("Failed to set device in idle state: %s.", + libusb_error_name(ret)); + libusb_release_interface(usb.devhdl, USB_INTERFACE); + libusb_close(usb.devhdl); + return SR_ERR; + } + + ret = libusb_release_interface(usb.devhdl, USB_INTERFACE); + + if (ret < 0) { + sr_err("Failed to release interface: %i.", + libusb_error_name(ret)); + libusb_close(usb.devhdl); + return SR_ERR; + } + + libusb_close(usb.devhdl); + + return SR_OK; +} + +SR_PRIV int ikalogic_scanalogic2_transfer_in(libusb_device_handle *dev_handle, + unsigned char *data) +{ + return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_IN, + USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, + data, PACKET_LENGTH, USB_TIMEOUT); +} + +SR_PRIV int ikalogic_scanalogic2_transfer_out(libusb_device_handle *dev_handle, + unsigned char *data) +{ + return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_OUT, + USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE, + data, PACKET_LENGTH, USB_TIMEOUT); +} diff --git a/hardware/ikalogic-scanalogic2/protocol.h b/hardware/ikalogic-scanalogic2/protocol.h index 8f8faf54..4265f54c 100644 --- a/hardware/ikalogic-scanalogic2/protocol.h +++ b/hardware/ikalogic-scanalogic2/protocol.h @@ -20,6 +20,8 @@ #ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H #define LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H +#include +#include #include #include #include "libsigrok.h" @@ -34,18 +36,220 @@ #define sr_warn(s, args...) sr_warn(LOG_PREFIX s, ## args) #define sr_err(s, args...) sr_err(LOG_PREFIX s, ## args) +#define VENDOR_NAME "IKALOGIC" +#define MODEL_NAME "Scanalogic-2" + +#define USB_VID_PID "20a0.4123" +#define USB_INTERFACE 0 +#define USB_TIMEOUT 5000 + +#define USB_REQUEST_TYPE_IN (LIBUSB_REQUEST_TYPE_CLASS | \ + LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN) + +#define USB_REQUEST_TYPE_OUT (LIBUSB_REQUEST_TYPE_CLASS | \ + LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT) + +#define USB_HID_SET_REPORT 0x09 +#define USB_HID_REPORT_TYPE_FEATURE 0x300 + +#define NUM_SAMPLERATES 11 +#define NUM_PROBES 4 + +#define TRIGGER_TYPES "rfc" + +/* + * Number of sample bytes and samples the device can acquire. Note that the + * vendor software can acquire 32736 sample bytes only but the device is capable + * to acquire up to 32766 sample bytes. + */ +#define MAX_DEV_SAMPLE_BYTES 32766 +#define MAX_DEV_SAMPLES (MAX_INT_SAMPLE_BYTES * 8) + +/* Number of sample bytes and samples the driver can acquire. */ +#define MAX_SAMPLE_BYTES (MAX_DEV_SAMPLE_BYTES - 1) +#define MAX_SAMPLES (MAX_SAMPLE_BYTES * 8) + +/* Maximum time that the trigger can be delayed in milliseconds. */ +#define MAX_AFTER_TRIGGER_DELAY 65000 + +#define PACKET_LENGTH 128 + +/* Number of sample bytes per packet where a sample byte contains 8 samples. */ +#define PACKET_NUM_SAMPLE_BYTES 124 + +/* Number of samples per packet. */ +#define PACKET_NUM_SAMPLES (PACKET_NUM_SAMPLE_BYTES * 8) + +#define DEFAULT_SAMPLERATE SR_KHZ(1.25) + +/* + * Time interval between the last status of available data received and the + * moment when the next status request will be sent in microseconds. + */ +#define WAIT_DATA_READY_INTERVAL 1500000 + +#define CMD_SAMPLE 0x01 +#define CMD_RESET 0x02 +#define CMD_IDLE 0x07 +#define CMD_INFO 0x0a + +#define TRIGGER_CHANNEL_ALL 0x00 +#define TRIGGER_CHANNEL_0 0x01 +#define TRIGGER_CHANNEL_1 0x02 +#define TRIGGER_CHANNEL_2 0x03 + +#define TRIGGER_TYPE_NEGEDGE 0x00 +#define TRIGGER_TYPE_POSEDGE 0x01 +#define TRIGGER_TYPE_ANYEDGE 0x02 +#define TRIGGER_TYPE_NONE 0x03 + +#define STATUS_DATA_READY 0x60 +#define STATUS_WAITING_FOR_TRIGGER 0x61 +#define STATUS_SAMPLING 0x62 +#define STATUS_DEVICE_READY 0x63 + +struct device_info { + /* Serial number of the device. */ + uint32_t serial; + + /* Major version of the firmware. */ + uint8_t fw_ver_major; + + /* Minor version of the firmware. */ + uint8_t fw_ver_minor; +}; + +enum { + STATE_IDLE = 0, + STATE_SAMPLE, + STATE_WAIT_DATA_READY, + STATE_RECEIVE_DATA, + STATE_RESET_AND_IDLE, + STATE_WAIT_DEVICE_READY +}; + /** Private, per-device-instance driver context. */ struct dev_context { - /* Model-specific information */ + /* Current selected samplerate. */ + uint64_t samplerate; + + /* Device specific identifier for the current samplerate. */ + uint8_t samplerate_id; + + /* Current sampling limit. */ + uint64_t limit_samples; + + /* Calculated number of pre-trigger samples. */ + uint64_t pre_trigger_samples; + + /* Number of pre- and post-trigger sample bytes to acquire. */ + uint16_t pre_trigger_bytes; + uint16_t post_trigger_bytes; + + /* Device specific settings for the trigger. */ + uint8_t trigger_channel; + uint8_t trigger_type; + + unsigned int capture_ratio; + + /* Time that the trigger will be delayed in milliseconds. */ + uint16_t after_trigger_delay; + + void *cb_data; + + /* Array to provide an index based access to all probes. */ + const struct sr_probe *probes[NUM_PROBES]; + + unsigned int num_usbfd; + int *usbfd; + + struct libusb_transfer *xfer_in, *xfer_out; + + /* + * Buffer to store setup and payload data for incoming and outgoing + * transfers. + */ + uint8_t xfer_buf_in[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH]; + uint8_t xfer_buf_out[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH]; + + /* Pointers to the payload of incoming and outgoing transfers. */ + uint8_t *xfer_data_in, *xfer_data_out; + + /* Current state of the state machine */ + unsigned int state; + + /* Next state of the state machine. */ + unsigned int next_state; + + /* + * Locking variable to ensure that no status about available data will + * be requested until the last status was received. + */ + gboolean wait_data_ready_locked; + + /* + * Time when the last response about the status of available data was + * received. + */ + int64_t wait_data_ready_time; + + /* + * Indicates that stopping of the acquisition is currently in progress. + */ + gboolean stopping_in_progress; + + /* + * Buffer which contains the samples received from the device for each + * channel except the last one. The samples of the last channel will be + * processed directly after they will be received. + */ + uint8_t sample_buffer[NUM_PROBES - 1][MAX_DEV_SAMPLE_BYTES]; + + /* Expected number of sample packets for each channel. */ + uint16_t num_sample_packets; + + /* Number of samples already processed. */ + uint64_t samples_processed; + + /* Sample packet number that is currently processed. */ + uint16_t sample_packet; - /* Acquisition settings */ + /* Channel number that is currently processed. */ + uint8_t channel; - /* Operational state */ + /* Number of enabled probes. */ + unsigned int num_enabled_probes; - /* Temporary state across callbacks */ + /* Array to provide a sequential access to all enabled probe indices. */ + uint8_t probe_map[NUM_PROBES]; + /* Indicates whether a transfer failed. */ + gboolean transfer_error; }; -SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data); +SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, + void *cb_data); +SR_PRIV void ikalogic_scanalogic2_receive_transfer_in( + struct libusb_transfer *transfer); +SR_PRIV void ikalogic_scanalogic2_receive_transfer_out( + struct libusb_transfer *transfer); +SR_PRIV int ikalogic_scanalogic2_set_samplerate(const struct sr_dev_inst *sdi, + uint64_t samplerate); +SR_PRIV int ikalogic_scanalogic2_set_limit_samples( + const struct sr_dev_inst *sdi, uint64_t limit_samples); +SR_PRIV void ikalogic_scanalogic2_configure_trigger( + const struct sr_dev_inst *sdi); +SR_PRIV int ikalogic_scanalogic2_set_capture_ratio( + const struct sr_dev_inst *sdi, uint64_t capture_ratio); +SR_PRIV int ikaloigc_scanalogic2_set_after_trigger_delay( + const struct sr_dev_inst *sdi, uint64_t after_trigger_delay); +SR_PRIV void ikalogic_scanalogic2_calculate_trigger_samples( + const struct sr_dev_inst *sdi); +SR_PRIV int ikalogic_scanalogic2_get_device_info(struct sr_usb_dev_inst usb, + struct device_info *dev_info); +SR_PRIV int ikalogic_scanalogic2_transfer_in(libusb_device_handle *dev_handle, + unsigned char *data); +SR_PRIV int ikalogic_scanalogic2_transfer_out(libusb_device_handle *dev_handle, + unsigned char *data); #endif