1154 lines
41 KiB
C
1154 lines
41 KiB
C
#ifdef ENABLE_USB
|
||
#include "libusb-1.0/libusb.h"
|
||
#include "e502api_private.h"
|
||
#include "lboot_req.h"
|
||
#include "e502_fpga_regs.h"
|
||
#include "osspec.h"
|
||
#include "ltimer.h"
|
||
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
#define E502_USB_VID 0x2A52
|
||
#define E502_USB_PID 0xE502
|
||
#define E502_USB_REQ_TOUT 3000
|
||
|
||
#define E440_USB_VID 0x0471
|
||
#define E440_USB_PID 0x0440
|
||
|
||
#define E16_USB_VID 0x2A52
|
||
#define E16_USB_PID 0x0E16
|
||
|
||
#define USB_CTL_REQ_MAX_SIZE 512
|
||
|
||
|
||
#define MUTEX_STREAM_LOCK_TOUT 2000
|
||
|
||
|
||
#define STREAM_STOP_TOUT 1000
|
||
|
||
#define USB_IN_STREAM_BUF_MIN 64
|
||
|
||
|
||
#define USB_BULK_RX_MAX_TRANSF_CNT 20
|
||
#define USB_BULK_RX_MAX_TRANSF_SIZE (32*1024)
|
||
#define USB_BULK_RX_TRANSFER_TOUT -1
|
||
|
||
#define USB_BULK_TX_MAX_TRANSF_CNT 20
|
||
#define USB_BULK_TX_MAX_TRANSF_SIZE (32*1024)
|
||
#define USB_BULK_TX_TRANSFER_TOUT -1
|
||
|
||
#ifndef LIBUSB_CALL
|
||
#define LIBUSB_CALL
|
||
#endif
|
||
|
||
static int f_lusb_init_done = 0;
|
||
|
||
|
||
struct st_transf_info;
|
||
|
||
|
||
typedef enum {
|
||
TRANSF_CPL_BUSY = 0,
|
||
TRANSF_CPL_COMPLETED = 1,
|
||
TRANSF_CPL_IDLE = 2
|
||
} t_transf_state;
|
||
|
||
typedef struct {
|
||
uint32_t *addr;
|
||
uint32_t size;
|
||
uint32_t transf_pos;
|
||
volatile enum {
|
||
RX_STATE_IDLE,
|
||
RX_STATE_BUSY,
|
||
RX_STATE_RDY,
|
||
RX_STATE_ERR
|
||
} state;
|
||
} t_rx_cpl_part; /* результат выполнения запросов */
|
||
|
||
typedef struct st_transf_info {
|
||
t_x502_hnd dev;
|
||
uint8_t addr; /* адрес конечной точки */
|
||
uint16_t pkt_size;
|
||
t_mutex mutex;
|
||
t_thread thread;
|
||
t_event user_wake_evt;
|
||
t_event usb_wake_evt;
|
||
|
||
volatile int stop_req;
|
||
int usb_rdy;
|
||
uint32_t *data; /* промежуточный буфер, используемый во всех запросах */
|
||
unsigned buf_size;
|
||
|
||
|
||
int err;
|
||
|
||
union {
|
||
struct {
|
||
t_rx_cpl_part *cpls;
|
||
uint32_t cpl_cnt;
|
||
uint32_t cpl_get_pos;
|
||
uint32_t transf_size;
|
||
uint32_t buf_get_rdy;
|
||
} rx;
|
||
struct {
|
||
uint32_t buf_pos_put;
|
||
uint32_t buf_put_rdy;
|
||
uint32_t busy_size;
|
||
} tx;
|
||
};
|
||
} t_transf_info;
|
||
|
||
|
||
typedef struct {
|
||
libusb_device_handle *devhnd;
|
||
t_transf_info streams[X502_STREAM_CH_CNT];
|
||
} t_usb_iface_data;
|
||
|
||
|
||
static int32_t f_ioreq(libusb_device_handle *handle, uint32_t cmd_code, uint32_t param,
|
||
const void* snd_data, uint32_t snd_size,
|
||
void* rcv_data, uint32_t recv_size, uint32_t* recvd_size, uint32_t tout);
|
||
|
||
static int32_t f_iface_free_devinfo_ptr(t_x502_devrec_inptr *devinfo_ptr);
|
||
static int32_t f_iface_open(t_x502_hnd hnd, const t_x502_devrec *devrec);
|
||
static int32_t f_iface_close(t_x502_hnd hnd);
|
||
static int32_t f_iface_stream_cfg(t_x502_hnd hnd, uint32_t ch, t_x502_stream_ch_params *params);
|
||
static int32_t f_iface_stream_start(t_x502_hnd hnd, uint32_t ch, uint32_t flags);
|
||
static int32_t f_iface_stream_stop(t_x502_hnd hnd, uint32_t ch, uint32_t flags);
|
||
static int32_t f_iface_stream_free(t_x502_hnd hnd, uint32_t ch, uint32_t flags);
|
||
static int32_t f_iface_stream_read(t_x502_hnd hnd, uint32_t *buf, uint32_t size, uint32_t tout);
|
||
static int32_t f_iface_stream_write(t_x502_hnd hnd, const uint32_t *buf, uint32_t size, uint32_t tout) ;
|
||
static int32_t f_iface_stream_get_rdy_cnt(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_cnt);
|
||
|
||
static int32_t f_iface_gen_ioctl(t_x502_hnd hnd, uint32_t cmd_code, uint32_t param,
|
||
const void* snd_data, uint32_t snd_size,
|
||
void* rcv_data, uint32_t recv_size, uint32_t* recvd_size,
|
||
uint32_t tout);
|
||
|
||
static const t_x502_dev_iface f_usb_iface = {
|
||
E502_REGS_ARM_HARD_ID,
|
||
USB_IN_STREAM_BUF_MIN,
|
||
USB_CTL_REQ_MAX_SIZE,
|
||
USB_CTL_REQ_MAX_SIZE/4,
|
||
USB_CTL_REQ_MAX_SIZE, //flash rd size
|
||
USB_CTL_REQ_MAX_SIZE, //flash wr size
|
||
f_iface_free_devinfo_ptr,
|
||
f_iface_open,
|
||
f_iface_close,
|
||
e502_iface_fpga_read,
|
||
e502_iface_fpga_write,
|
||
f_iface_stream_cfg,
|
||
f_iface_stream_start,
|
||
f_iface_stream_stop,
|
||
f_iface_stream_free,
|
||
e502_iface_stream_running,
|
||
f_iface_stream_read,
|
||
f_iface_stream_write,
|
||
f_iface_stream_get_rdy_cnt,
|
||
e502_iface_bf_mem_block_rd,
|
||
e502_iface_bf_mem_block_wr,
|
||
e502_iface_bf_firm_load,
|
||
e502_iface_flash_rd,
|
||
e502_iface_flash_wr,
|
||
e502_iface_flash_erase,
|
||
e502_iface_flash_set_prot,
|
||
e502_iface_reload_dev_info,
|
||
e502_iface_cycle_load_start,
|
||
e502_iface_cycle_setup,
|
||
e502_iface_cycle_stop,
|
||
e502_iface_cycle_check_setup,
|
||
e502_iface_fpga_mode_init,
|
||
f_iface_gen_ioctl,
|
||
e502_iface_check_feature
|
||
};
|
||
|
||
|
||
|
||
|
||
|
||
|
||
static int32_t f_iface_open(t_x502_hnd hnd, const t_x502_devrec *devrec) {
|
||
int32_t err, usberr;
|
||
libusb_device *dev = (libusb_device *)devrec->internal->iface_data;
|
||
libusb_device_handle *devhnd = NULL;
|
||
|
||
|
||
usberr = libusb_open(dev, &devhnd);
|
||
if (!usberr) {
|
||
usberr = libusb_claim_interface(devhnd, 0);
|
||
}
|
||
|
||
err = usberr == LIBUSB_SUCCESS ? X502_ERR_OK :
|
||
usberr == LIBUSB_ERROR_BUSY ? X502_ERR_ALREADY_OPENED :
|
||
usberr == LIBUSB_ERROR_ACCESS ? X502_ERR_DEVICE_ACCESS_DENIED :
|
||
usberr == LIBUSB_ERROR_NO_DEVICE ? X502_ERR_DEVICE_DISCONNECTED :
|
||
X502_ERR_DEVICE_OPEN;
|
||
|
||
if (err == X502_ERR_OK) {
|
||
t_lboot_devinfo lboot_info;
|
||
|
||
err = f_ioreq(devhnd, E502_CM4_CMD_GET_MODULE_INFO, 0, NULL, 0, &lboot_info,
|
||
sizeof(lboot_info), NULL, 0);
|
||
if (err == X502_ERR_OK) {
|
||
if (strcmp(lboot_info.devname, devrec->devname)) {
|
||
err = X502_ERR_INVALID_DEVICE;
|
||
} else {
|
||
e502_devinfo_init(&hnd->info, &lboot_info);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (err == X502_ERR_OK) {
|
||
t_usb_iface_data *usb_data = calloc(1, sizeof(t_usb_iface_data));
|
||
unsigned stream;
|
||
struct libusb_config_descriptor* cfg;
|
||
|
||
usb_data->devhnd = devhnd;
|
||
|
||
/* Чтобы определить номера используемых конечных точек, получаем
|
||
* конфигурацию устройства и находим по одной конечной точки типа
|
||
* bulk на каждое направление (in/out) */
|
||
usberr = libusb_get_config_descriptor(dev, 0, &cfg);
|
||
if (!usberr) {
|
||
int intf_idx, s, fnd_in=0, fnd_out=0;
|
||
for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; intf_idx++) {
|
||
for (s=0; s < cfg->interface[intf_idx].num_altsetting; s++) {
|
||
int e;
|
||
for (e=0; e < cfg->interface[intf_idx].altsetting[s].bNumEndpoints; e++) {
|
||
const struct libusb_endpoint_descriptor *ep_descr =
|
||
&cfg->interface[intf_idx].altsetting[s].endpoint[e];
|
||
if ((ep_descr->bmAttributes & 0x3)==
|
||
LIBUSB_TRANSFER_TYPE_BULK ) {
|
||
if ((ep_descr->bEndpointAddress & 0x80)
|
||
== LIBUSB_ENDPOINT_IN) {
|
||
if (!fnd_in) {
|
||
usb_data->streams[X502_STREAM_CH_IN].addr = ep_descr->bEndpointAddress;
|
||
usb_data->streams[X502_STREAM_CH_IN].pkt_size = ep_descr->wMaxPacketSize;
|
||
fnd_in = 1;
|
||
}
|
||
} else {
|
||
if (!fnd_out) {
|
||
usb_data->streams[X502_STREAM_CH_OUT].addr = ep_descr->bEndpointAddress;
|
||
usb_data->streams[X502_STREAM_CH_OUT].pkt_size = ep_descr->wMaxPacketSize;
|
||
fnd_out = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
libusb_free_config_descriptor(cfg);
|
||
if (!fnd_in || !fnd_out)
|
||
err = X502_ERR_INVALID_USB_CONFIGURATION;
|
||
} else {
|
||
err = X502_ERR_INVALID_USB_CONFIGURATION;
|
||
}
|
||
|
||
for (stream=0; stream < X502_STREAM_CH_CNT; stream++) {
|
||
usb_data->streams[stream].mutex = osspec_mutex_create();
|
||
usb_data->streams[stream].user_wake_evt = osspec_event_create(0);
|
||
usb_data->streams[stream].usb_wake_evt = osspec_event_create(0);
|
||
usb_data->streams[stream].dev = hnd;
|
||
usb_data->streams[stream].thread = OSSPEC_INVALID_THREAD;
|
||
|
||
if ((usb_data->streams[stream].mutex == OSSPEC_INVALID_MUTEX) ||
|
||
(usb_data->streams[stream].user_wake_evt == OSSPEC_INVALID_EVENT) ||
|
||
(usb_data->streams[stream].usb_wake_evt == OSSPEC_INVALID_EVENT)) {
|
||
err = X502_ERR_MUTEX_CREATE;
|
||
}
|
||
}
|
||
|
||
if (err == X502_ERR_OK) {
|
||
hnd->iface_data = usb_data;
|
||
} else {
|
||
for (stream=0; stream < X502_STREAM_CH_CNT; stream++) {
|
||
if (usb_data->streams[stream].mutex != OSSPEC_INVALID_MUTEX)
|
||
osspec_mutex_destroy(usb_data->streams[stream].mutex);
|
||
if (usb_data->streams[stream].user_wake_evt != OSSPEC_INVALID_EVENT)
|
||
osspec_event_destroy(usb_data->streams[stream].user_wake_evt);
|
||
if (usb_data->streams[stream].usb_wake_evt != OSSPEC_INVALID_EVENT)
|
||
osspec_event_destroy(usb_data->streams[stream].usb_wake_evt);
|
||
}
|
||
free(usb_data);
|
||
}
|
||
}
|
||
|
||
if (err != X502_ERR_OK) {
|
||
if (devhnd != NULL) {
|
||
libusb_release_interface(devhnd, 0);
|
||
libusb_close(devhnd);
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
static int32_t f_iface_close(t_x502_hnd hnd) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data*)hnd->iface_data;
|
||
int32_t err = 0;
|
||
if (usb_data != NULL) {
|
||
unsigned ch;
|
||
|
||
for (ch=0; ch < sizeof(usb_data->streams)/sizeof(usb_data->streams[0]); ch++) {
|
||
if (usb_data->streams[ch].mutex != OSSPEC_INVALID_MUTEX) {
|
||
osspec_mutex_destroy(usb_data->streams[ch].mutex);
|
||
usb_data->streams[ch].mutex = OSSPEC_INVALID_MUTEX;
|
||
}
|
||
if (usb_data->streams[ch].user_wake_evt != OSSPEC_INVALID_EVENT) {
|
||
osspec_event_destroy(usb_data->streams[ch].user_wake_evt);
|
||
usb_data->streams[ch].user_wake_evt = OSSPEC_INVALID_EVENT;
|
||
}
|
||
if (usb_data->streams[ch].usb_wake_evt != OSSPEC_INVALID_EVENT) {
|
||
osspec_event_destroy(usb_data->streams[ch].usb_wake_evt);
|
||
usb_data->streams[ch].usb_wake_evt = OSSPEC_INVALID_EVENT;
|
||
}
|
||
}
|
||
|
||
libusb_release_interface(usb_data->devhnd, 0);
|
||
libusb_close(usb_data->devhnd);
|
||
|
||
|
||
free(hnd->iface_data);
|
||
hnd->iface_data = NULL;
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
static int32_t f_iface_free_devinfo_ptr(t_x502_devrec_inptr *devinfo_ptr) {
|
||
libusb_device *dev = (libusb_device*)devinfo_ptr->iface_data;
|
||
libusb_unref_device(dev);
|
||
free(devinfo_ptr);
|
||
return X502_ERR_OK;
|
||
}
|
||
|
||
|
||
|
||
static void LIBUSB_CALL f_usb_transf_cb(struct libusb_transfer *transfer) {
|
||
*((int*)transfer->user_data) = TRANSF_CPL_COMPLETED;
|
||
}
|
||
|
||
|
||
static OSSPEC_THREAD_FUNC_RET OSSPEC_THREAD_FUNC_CALL f_usb_rx_thread_func(void *arg) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data*)arg;
|
||
struct libusb_transfer *transfers[USB_BULK_RX_MAX_TRANSF_CNT]; /* запросы usb */
|
||
volatile int transf_completed[USB_BULK_RX_MAX_TRANSF_CNT];
|
||
t_transf_info *info = &usb_data->streams[X502_STREAM_CH_IN];
|
||
unsigned transf_pos=0;
|
||
unsigned cpl_pos = 0;
|
||
unsigned transf_check_pos=0;
|
||
unsigned cpl_check_pos=0;
|
||
|
||
unsigned idx;
|
||
int err = 0;
|
||
info->err = 0;
|
||
|
||
for (idx = 0; idx < USB_BULK_RX_MAX_TRANSF_CNT; idx++) {
|
||
transfers[idx] = libusb_alloc_transfer(0);
|
||
transf_completed[idx] = TRANSF_CPL_IDLE;
|
||
if (transfers[idx]==NULL) {
|
||
err = X502_ERR_MEMORY_ALLOC;
|
||
}
|
||
}
|
||
|
||
while (!err && !info->stop_req) {
|
||
/* обрабатываем завершенные передачи в порядке добавления */
|
||
while (transf_completed[transf_check_pos] == TRANSF_CPL_COMPLETED) {
|
||
t_rx_cpl_part *cpl = &info->rx.cpls[cpl_check_pos];
|
||
struct libusb_transfer *transfer = transfers[transf_check_pos];
|
||
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED)
|
||
|| (transfer->status == LIBUSB_TRANSFER_TIMED_OUT)
|
||
|| (transfer->status == LIBUSB_TRANSFER_CANCELLED)) {
|
||
cpl->size = transfer->actual_length/sizeof(uint32_t);
|
||
info->rx.buf_get_rdy += cpl->size;
|
||
cpl->state = RX_STATE_RDY;
|
||
} else {
|
||
cpl->state = RX_STATE_ERR;
|
||
}
|
||
transf_completed[transf_check_pos] = TRANSF_CPL_IDLE;
|
||
osspec_event_set(info->user_wake_evt);
|
||
|
||
if (++transf_check_pos == USB_BULK_RX_MAX_TRANSF_CNT)
|
||
transf_check_pos = 0;
|
||
if (++cpl_check_pos == info->rx.cpl_cnt)
|
||
cpl_check_pos = 0;
|
||
|
||
osspec_mutex_release(info->mutex);
|
||
}
|
||
|
||
|
||
/* пробуем запустить новые трансферы на передачу */
|
||
while ((transf_completed[transf_pos] == TRANSF_CPL_IDLE) &&
|
||
(info->rx.cpls[cpl_pos].state == RX_STATE_IDLE) && !err) {
|
||
|
||
info->rx.cpls[cpl_pos].addr = &info->data[info->rx.transf_size*cpl_pos];
|
||
libusb_fill_bulk_transfer(transfers[transf_pos], usb_data->devhnd, info->addr,
|
||
(unsigned char*)info->rx.cpls[cpl_pos].addr,
|
||
info->rx.transf_size*sizeof(info->data[0]),
|
||
f_usb_transf_cb, (void*)&transf_completed[transf_pos],
|
||
USB_BULK_RX_TRANSFER_TOUT);
|
||
info->rx.cpls[cpl_pos].state = RX_STATE_BUSY;
|
||
transf_completed[transf_pos] = TRANSF_CPL_BUSY;
|
||
|
||
if (libusb_submit_transfer(transfers[transf_pos])==0) {
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
osspec_mutex_release(info->mutex);
|
||
if (++transf_pos == USB_BULK_RX_MAX_TRANSF_CNT)
|
||
transf_pos = 0;
|
||
} else {
|
||
err = X502_ERR_RECV;
|
||
transf_completed[transf_pos] = TRANSF_CPL_IDLE;
|
||
info->rx.cpls[cpl_pos].state = RX_STATE_ERR;
|
||
}
|
||
|
||
if (++cpl_pos == info->rx.cpl_cnt)
|
||
cpl_pos = 0;
|
||
}
|
||
|
||
if (!err) {
|
||
int wt_buf_rdy = 0;
|
||
|
||
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
if (info->rx.cpls[cpl_pos].state != RX_STATE_IDLE) {
|
||
wt_buf_rdy = 1;
|
||
osspec_event_clear(info->usb_wake_evt);
|
||
}
|
||
osspec_mutex_release(info->mutex);
|
||
|
||
|
||
if (transf_completed[transf_check_pos] != TRANSF_CPL_IDLE) {
|
||
int lusberr;
|
||
/* иначе ждем событий от USB */
|
||
struct timeval tv;
|
||
tv.tv_sec =0;
|
||
tv.tv_usec = 200 * 1000;
|
||
lusberr = libusb_handle_events_timeout_completed(NULL, &tv, (int*)&transf_completed[transf_check_pos]);
|
||
|
||
if ((lusberr != LIBUSB_SUCCESS) && (lusberr != LIBUSB_ERROR_INTERRUPTED)) {
|
||
err = X502_ERR_RECV;
|
||
}
|
||
|
||
} else if (wt_buf_rdy) {
|
||
/* если буфер занят - ждем события от потока чтения */
|
||
osspec_event_wait(info->usb_wake_evt, OSSPEC_TIMEOUT_INFINITY);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* отменяем все поставленные запросы */
|
||
for (idx = 0; idx < USB_BULK_RX_MAX_TRANSF_CNT; idx++) {
|
||
unsigned pos = (transf_check_pos + idx) % USB_BULK_RX_MAX_TRANSF_CNT;
|
||
if (transf_completed[pos] == TRANSF_CPL_BUSY) {
|
||
if (libusb_cancel_transfer(transfers[pos]) !=LIBUSB_SUCCESS)
|
||
transf_completed[pos] = TRANSF_CPL_COMPLETED;
|
||
}
|
||
}
|
||
|
||
/* ждем завершения всех запросов */
|
||
while (transf_completed[transf_check_pos] != TRANSF_CPL_IDLE) {
|
||
if (transf_completed[transf_check_pos] == TRANSF_CPL_BUSY) {
|
||
struct timeval ztv = {0,0};
|
||
libusb_handle_events_timeout(NULL, &ztv);
|
||
} else {
|
||
transf_completed[transf_check_pos] = TRANSF_CPL_IDLE;
|
||
if (++transf_check_pos == USB_BULK_RX_MAX_TRANSF_CNT)
|
||
transf_check_pos = 0;
|
||
}
|
||
}
|
||
|
||
/* очищаем ресурсы */
|
||
for (idx = 0; idx < USB_BULK_RX_MAX_TRANSF_CNT; idx++) {
|
||
if (transfers[idx] != NULL) {
|
||
libusb_free_transfer(transfers[idx]);
|
||
}
|
||
}
|
||
|
||
if (info->err == X502_ERR_OK)
|
||
info->err = err;
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
static OSSPEC_THREAD_FUNC_RET OSSPEC_THREAD_FUNC_CALL f_usb_tx_thread_func(void *arg) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data*)arg;
|
||
struct libusb_transfer *transfers[USB_BULK_TX_MAX_TRANSF_CNT]; /* запросы usb */
|
||
t_transf_info *info = &usb_data->streams[X502_STREAM_CH_OUT];
|
||
volatile int transf_completed[USB_BULK_RX_MAX_TRANSF_CNT];
|
||
unsigned transf_pos=0;
|
||
unsigned transf_check_pos=0;
|
||
unsigned idx;
|
||
int err = 0;
|
||
int last_full_packet = 0; /* признак, что последний пакет был полный, чтобы
|
||
послять нулевой пакет */
|
||
unsigned snd_pos = 0;
|
||
|
||
|
||
info->err = 0;
|
||
info->tx.busy_size = 0;
|
||
|
||
for (idx = 0; (idx < USB_BULK_TX_MAX_TRANSF_CNT) && (err == X502_ERR_OK); idx++) {
|
||
transfers[idx] = libusb_alloc_transfer(0);
|
||
transf_completed[idx] = TRANSF_CPL_IDLE;
|
||
if (transfers[idx]==NULL) {
|
||
err = X502_ERR_MEMORY_ALLOC;
|
||
}
|
||
}
|
||
|
||
while (!err && !info->stop_req) {
|
||
uint32_t snd_rdy_size;
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
snd_rdy_size = info->buf_size - info->tx.buf_put_rdy - info->tx.busy_size;
|
||
|
||
if (snd_rdy_size == 0)
|
||
osspec_event_clear(info->usb_wake_evt);
|
||
osspec_mutex_release(info->mutex);
|
||
|
||
/* обрабатываем завершенные передачи */
|
||
while (transf_completed[transf_check_pos] == TRANSF_CPL_COMPLETED) {
|
||
struct libusb_transfer *transfer = transfers[transf_check_pos];
|
||
if ((transfer->status != LIBUSB_TRANSFER_COMPLETED)
|
||
&& (transfer->status != LIBUSB_TRANSFER_CANCELLED)) {
|
||
err = X502_ERR_SEND;
|
||
}
|
||
|
||
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
info->tx.buf_put_rdy += transfer->length/sizeof(info->data[0]);
|
||
info->tx.busy_size -= transfer->length/sizeof(info->data[0]);
|
||
osspec_event_set(info->user_wake_evt);
|
||
osspec_mutex_release(info->mutex);
|
||
|
||
transf_completed[transf_check_pos] = TRANSF_CPL_IDLE;
|
||
|
||
if (++transf_check_pos == USB_BULK_RX_MAX_TRANSF_CNT)
|
||
transf_check_pos = 0;
|
||
}
|
||
|
||
|
||
while (((snd_rdy_size != 0) || (last_full_packet && (info->tx.busy_size==0)))
|
||
&& (transf_completed[transf_pos] == TRANSF_CPL_IDLE)
|
||
&& (err == X502_ERR_OK)) {
|
||
uint32_t snd_size = snd_rdy_size;
|
||
if (snd_size > USB_BULK_TX_MAX_TRANSF_SIZE)
|
||
snd_size = USB_BULK_TX_MAX_TRANSF_SIZE;
|
||
if (snd_size > (info->buf_size - snd_pos))
|
||
snd_size = info->buf_size - snd_pos;
|
||
|
||
libusb_fill_bulk_transfer(transfers[transf_pos], usb_data->devhnd, info->addr,
|
||
(unsigned char*)&info->data[snd_pos],
|
||
snd_size*sizeof(info->data[0]),
|
||
f_usb_transf_cb,
|
||
(void*)&transf_completed[transf_pos],
|
||
USB_BULK_TX_TRANSFER_TOUT);
|
||
|
||
|
||
|
||
transf_completed[transf_pos] = TRANSF_CPL_BUSY;
|
||
if (libusb_submit_transfer(transfers[transf_pos])==0) {
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
info->tx.busy_size+=snd_size;
|
||
osspec_mutex_release(info->mutex);
|
||
if (++transf_pos == USB_BULK_TX_MAX_TRANSF_CNT)
|
||
transf_pos = 0;
|
||
snd_pos+=snd_size;
|
||
if (snd_pos==info->buf_size)
|
||
snd_pos = 0;
|
||
snd_rdy_size-=snd_size;
|
||
|
||
last_full_packet = (snd_size != 0) && ((snd_size % (info->pkt_size/sizeof(info->data[0]))) == 0);
|
||
} else {
|
||
transf_completed[transf_pos] = TRANSF_CPL_IDLE;
|
||
err = X502_ERR_SEND;
|
||
}
|
||
}
|
||
|
||
|
||
if (err == X502_ERR_OK) {
|
||
if (info->tx.busy_size!=0) {
|
||
/* иначе ждем событий от USB */
|
||
struct timeval tv;
|
||
tv.tv_sec =0;
|
||
tv.tv_usec = 200 * 1000;
|
||
libusb_handle_events_timeout_completed(NULL, &tv,
|
||
(int*)&transf_completed[transf_check_pos]);
|
||
} else if ((snd_rdy_size==0) && !last_full_packet) {
|
||
/* если буфер занят - ждем события от потока чтения */
|
||
osspec_event_wait(info->usb_wake_evt, OSSPEC_TIMEOUT_INFINITY);
|
||
}
|
||
}
|
||
}
|
||
|
||
/* отменяем все поставленные запросы */
|
||
for (idx = 0; idx < USB_BULK_RX_MAX_TRANSF_CNT; idx++) {
|
||
unsigned pos = (transf_check_pos + idx) % USB_BULK_RX_MAX_TRANSF_CNT;
|
||
if (transf_completed[pos] == TRANSF_CPL_BUSY) {
|
||
if (libusb_cancel_transfer(transfers[pos]) !=LIBUSB_SUCCESS)
|
||
transf_completed[pos] = TRANSF_CPL_COMPLETED;
|
||
}
|
||
}
|
||
|
||
/* ждем завершения всех запросов */
|
||
while (transf_completed[transf_check_pos] != TRANSF_CPL_IDLE) {
|
||
if (transf_completed[transf_check_pos] == TRANSF_CPL_BUSY) {
|
||
struct timeval ztv = {0,0};
|
||
libusb_handle_events_timeout(NULL, &ztv);
|
||
} else {
|
||
transf_completed[transf_check_pos] = TRANSF_CPL_IDLE;
|
||
if (++transf_check_pos == USB_BULK_RX_MAX_TRANSF_CNT)
|
||
transf_check_pos = 0;
|
||
}
|
||
}
|
||
|
||
/* очищаем ресурсы */
|
||
for (idx = 0; idx < USB_BULK_RX_MAX_TRANSF_CNT; idx++) {
|
||
if (transfers[idx] != NULL) {
|
||
libusb_free_transfer(transfers[idx]);
|
||
}
|
||
}
|
||
|
||
if (info->err == X502_ERR_OK)
|
||
info->err = err;
|
||
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
static void f_stream_init(uint32_t ch, t_transf_info *info) {
|
||
info->stop_req = 0;
|
||
info->err = 0;
|
||
if (ch==X502_STREAM_CH_IN) {
|
||
unsigned i;
|
||
info->rx.cpl_get_pos = 0;
|
||
info->rx.buf_get_rdy = 0;
|
||
|
||
|
||
for (i=0; i < info->rx.cpl_cnt; i++) {
|
||
info->rx.cpls[i].state = RX_STATE_IDLE;
|
||
}
|
||
} else {
|
||
info->tx.buf_pos_put = 0;
|
||
info->tx.buf_put_rdy = info->buf_size;
|
||
}
|
||
}
|
||
|
||
static int32_t f_iface_stream_cfg(t_x502_hnd hnd, uint32_t ch, t_x502_stream_ch_params *params) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
t_transf_info *info = &usb_data->streams[ch];
|
||
int err = 0;
|
||
|
||
/** @todo вариант изменения размеров буфера в работе */
|
||
if (info->data == NULL) {
|
||
info->buf_size = params->buf_size;
|
||
|
||
|
||
if (ch==X502_STREAM_CH_IN) {
|
||
info->rx.transf_size = ((params->step+127)/128)*128;
|
||
if (info->rx.transf_size > USB_BULK_RX_MAX_TRANSF_SIZE)
|
||
info->rx.transf_size = USB_BULK_RX_MAX_TRANSF_SIZE;
|
||
|
||
info->rx.cpl_cnt = info->buf_size/info->rx.transf_size;
|
||
/* буфер разбиваем на столько частей, чтобы можно было запустить
|
||
* в параллель все USB_BULK_RX_MAX_TRANSF_CNT трансферов */
|
||
if (info->rx.cpl_cnt < USB_BULK_RX_MAX_TRANSF_CNT)
|
||
info->rx.cpl_cnt = USB_BULK_RX_MAX_TRANSF_CNT;
|
||
info->buf_size = info->rx.cpl_cnt*info->rx.transf_size;
|
||
|
||
info->rx.cpls = malloc(info->rx.cpl_cnt * sizeof(info->rx.cpls[0]));
|
||
if (info->rx.cpls == NULL) {
|
||
err = X502_ERR_MEMORY_ALLOC;
|
||
}
|
||
}
|
||
|
||
if (err == X502_ERR_OK) {
|
||
info->data = malloc(info->buf_size*sizeof(info->data[0]));
|
||
if (info->data == NULL) {
|
||
err = X502_ERR_MEMORY_ALLOC;
|
||
}
|
||
}
|
||
|
||
if (err == X502_ERR_OK) {
|
||
f_stream_init(ch, info);
|
||
}
|
||
|
||
if (err == X502_ERR_OK) {
|
||
uint16_t send_step = params->step > 0xFFFF ? 0xFFFF : params->step;
|
||
err = f_ioreq(usb_data->devhnd, E502_CM4_CMD_STREAM_SET_STEP,
|
||
(ch<<16) | send_step, NULL, 0, NULL, 0, NULL, 0);
|
||
}
|
||
|
||
|
||
if (err != X502_ERR_OK) {
|
||
f_iface_stream_free(hnd, ch, 0);
|
||
}
|
||
}
|
||
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
static int32_t f_iface_stream_start(t_x502_hnd hnd, uint32_t ch, uint32_t flags) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
int32_t err = X502_ERR_OK;
|
||
|
||
if (err == X502_ERR_OK) {
|
||
t_transf_info *info = &usb_data->streams[ch];
|
||
f_stream_init(ch, info);
|
||
info->thread = osspec_thread_create(ch == X502_STREAM_CH_IN ?
|
||
f_usb_rx_thread_func : f_usb_tx_thread_func,
|
||
usb_data, 0);
|
||
if (info->thread == OSSPEC_INVALID_THREAD) {
|
||
err = X502_ERR_THREAD_START;
|
||
}
|
||
}
|
||
|
||
if (!err && !(flags & X502_STREAM_FLAG_NO_REQUEST)) {
|
||
err = f_ioreq(usb_data->devhnd, E502_CM4_CMD_STREAM_START, (ch<<16),
|
||
NULL, 0, NULL, 0, NULL, 0);
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
static int32_t f_iface_stream_stop(t_x502_hnd hnd, uint32_t ch, uint32_t flags) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
t_transf_info *info = &usb_data->streams[ch];
|
||
int err = X502_ERR_OK;
|
||
int ioctl_err = X502_ERR_OK;
|
||
int32_t running;
|
||
|
||
if (!(flags & X502_STREAM_FLAG_NO_REQUEST)) {
|
||
ioctl_err = hnd->iface_hnd->stream_running(hnd, ch, &running);
|
||
if (!ioctl_err && running) {
|
||
ioctl_err = f_ioreq(usb_data->devhnd, E502_CM4_CMD_STREAM_STOP, (ch << 16),
|
||
NULL, 0, NULL, 0, NULL, 0);
|
||
}
|
||
}
|
||
|
||
|
||
if (info->thread != OSSPEC_INVALID_THREAD) {
|
||
info->stop_req = 1;
|
||
osspec_event_set(info->usb_wake_evt);
|
||
err = osspec_thread_wait(info->thread, STREAM_STOP_TOUT);
|
||
info->thread = OSSPEC_INVALID_THREAD;
|
||
}
|
||
|
||
return err != X502_ERR_OK ? err : ioctl_err;
|
||
}
|
||
|
||
|
||
static int32_t f_iface_stream_free(t_x502_hnd hnd, uint32_t ch, uint32_t flags) {
|
||
int32_t err;
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
t_transf_info *info = &usb_data->streams[ch];
|
||
|
||
err = hnd->iface_hnd->stream_stop(hnd, ch, flags);
|
||
|
||
free(info->data);
|
||
info->data = NULL;
|
||
|
||
if (ch==X502_STREAM_CH_IN) {
|
||
free(info->rx.cpls);
|
||
info->rx.cpls = NULL;
|
||
info->rx.cpl_cnt = 0;
|
||
info->rx.transf_size = 0;
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
|
||
static int32_t f_iface_stream_read(t_x502_hnd hnd, uint32_t *buf, uint32_t size, uint32_t tout) {
|
||
int32_t recvd = 0;
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
t_transf_info *info = &usb_data->streams[X502_STREAM_CH_IN];
|
||
t_ltimer tmr;
|
||
int32_t err = info->data == NULL ? X502_ERR_STREAM_IS_NOT_RUNNING : X502_ERR_OK;
|
||
|
||
if (err == X502_ERR_OK) {
|
||
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout));
|
||
|
||
do {
|
||
int check_next = 1;
|
||
err = info->err;
|
||
|
||
while (!err && check_next) {
|
||
t_rx_cpl_part *cpl = &info->rx.cpls[info->rx.cpl_get_pos];
|
||
int cur_state = cpl->state;
|
||
check_next = 0;
|
||
|
||
if (cur_state == RX_STATE_ERR) {
|
||
err = X502_ERR_RECV;
|
||
} else if (cur_state == RX_STATE_RDY) {
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
|
||
if (cpl->size) {
|
||
uint32_t cpy_size = cpl->size;
|
||
if (cpy_size > size)
|
||
cpy_size = size;
|
||
if (cpy_size) {
|
||
memcpy(&buf[recvd], cpl->addr, cpy_size*sizeof(buf[0]));
|
||
recvd+=cpy_size;
|
||
size-=cpy_size;
|
||
cpl->size -= cpy_size;
|
||
cpl->addr += cpy_size;
|
||
info->rx.buf_get_rdy -= cpy_size;
|
||
}
|
||
}
|
||
|
||
if (cpl->size==0) {
|
||
cpl->state = RX_STATE_IDLE;
|
||
osspec_event_set(info->usb_wake_evt);
|
||
check_next = 1;
|
||
}
|
||
osspec_mutex_release(info->mutex);
|
||
}
|
||
|
||
if (check_next) {
|
||
if (++info->rx.cpl_get_pos==info->rx.cpl_cnt)
|
||
info->rx.cpl_get_pos = 0;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
if (!err && (size!=0)) {
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
if ((info->rx.cpls[info->rx.cpl_get_pos].state == RX_STATE_IDLE)
|
||
|| ((info->rx.cpls[info->rx.cpl_get_pos].state == RX_STATE_BUSY))) {
|
||
osspec_event_clear(info->user_wake_evt);
|
||
}
|
||
osspec_mutex_release(info->mutex);
|
||
|
||
osspec_event_wait(info->user_wake_evt, LTIMER_CLOCK_TICKS_TO_MS(ltimer_expiration(&tmr)));
|
||
}
|
||
} while (!err && (size!=0) && !ltimer_expired(&tmr));
|
||
}
|
||
|
||
return err == X502_ERR_OK ? recvd : err;
|
||
}
|
||
|
||
|
||
|
||
static int32_t f_iface_stream_write(t_x502_hnd hnd, const uint32_t *buf, uint32_t size, uint32_t tout) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
t_transf_info *info = &usb_data->streams[X502_STREAM_CH_OUT];
|
||
t_ltimer tmr;
|
||
int32_t sent = 0;
|
||
int32_t err = info->data == NULL ? X502_ERR_STREAM_IS_NOT_RUNNING : X502_ERR_OK;
|
||
|
||
if (err == X502_ERR_OK) {
|
||
ltimer_set(&tmr, LTIMER_MS_TO_CLOCK_TICKS(tout));
|
||
|
||
do {
|
||
uint32_t rdy_size, snd_size;
|
||
snd_size = rdy_size = info->tx.buf_put_rdy;
|
||
err = info->err;
|
||
|
||
if (!err) {
|
||
if (rdy_size == 0) {
|
||
osspec_event_wait(info->user_wake_evt,
|
||
LTIMER_CLOCK_TICKS_TO_MS(ltimer_expiration(&tmr)));
|
||
} else {
|
||
uint32_t end_size;
|
||
uint32_t put_pos;
|
||
if (snd_size > size)
|
||
snd_size = size;
|
||
end_size = info->buf_size - info->tx.buf_pos_put;
|
||
if (snd_size >= end_size) {
|
||
memcpy(&info->data[info->tx.buf_pos_put], &buf[sent], end_size*sizeof(buf[0]));
|
||
if (snd_size!=end_size) {
|
||
memcpy(&info->data[0], &buf[sent+end_size], (snd_size-end_size)*sizeof(buf[0]));
|
||
}
|
||
put_pos = snd_size-end_size;
|
||
} else {
|
||
memcpy(&info->data[info->tx.buf_pos_put], &buf[sent], snd_size*sizeof(buf[0]));
|
||
put_pos = info->tx.buf_pos_put + snd_size;
|
||
}
|
||
|
||
osspec_mutex_lock(info->mutex, MUTEX_STREAM_LOCK_TOUT);
|
||
info->tx.buf_pos_put = put_pos;
|
||
info->tx.buf_put_rdy -= snd_size;
|
||
|
||
if (info->tx.buf_put_rdy==0) {
|
||
osspec_event_clear(info->user_wake_evt);
|
||
}
|
||
|
||
osspec_event_set(info->usb_wake_evt);
|
||
|
||
osspec_mutex_release(info->mutex);
|
||
|
||
|
||
sent+=snd_size;
|
||
size-=snd_size;
|
||
}
|
||
}
|
||
} while (!err && (size!=0) && !ltimer_expired(&tmr));
|
||
}
|
||
return err == X502_ERR_OK ? sent : err;
|
||
}
|
||
|
||
|
||
|
||
static int32_t f_iface_stream_get_rdy_cnt(t_x502_hnd hnd, uint32_t ch, uint32_t *rdy_cnt) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
int32_t err=0;
|
||
if (ch == X502_STREAM_CH_IN) {
|
||
*rdy_cnt = usb_data->streams[X502_STREAM_CH_IN].rx.buf_get_rdy;
|
||
} else if (ch == X502_STREAM_CH_OUT) {
|
||
*rdy_cnt = usb_data->streams[X502_STREAM_CH_OUT].tx.buf_put_rdy;
|
||
} else {
|
||
err = X502_ERR_INVALID_STREAM_CH;
|
||
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
static int32_t f_ioreq(libusb_device_handle *handle, uint32_t cmd_code, uint32_t param,
|
||
const void* snd_data, uint32_t snd_size,
|
||
void* rcv_data, uint32_t recv_size, uint32_t* recvd_size, uint32_t tout) {
|
||
int32_t err = 0;
|
||
uint8_t req_type = LIBUSB_REQUEST_TYPE_VENDOR;
|
||
uint16_t len;
|
||
uint8_t* iobuf;
|
||
int usbres = 0;
|
||
if (tout == 0)
|
||
tout = E502_USB_REQ_TOUT;
|
||
|
||
if (recv_size > 0) {
|
||
req_type |= LIBUSB_ENDPOINT_IN;
|
||
len = recv_size;
|
||
iobuf = rcv_data;
|
||
} else {
|
||
req_type |= LIBUSB_ENDPOINT_OUT;
|
||
len = snd_size;
|
||
iobuf = (uint8_t*)snd_data;
|
||
}
|
||
|
||
if (!err) {
|
||
usbres = libusb_control_transfer(handle,
|
||
req_type, cmd_code & 0xFF,
|
||
param & 0xFFFF,
|
||
(param >> 16) & 0xFFFF,
|
||
iobuf, len, tout);
|
||
if (usbres < 0) {
|
||
err = (usbres == LIBUSB_ERROR_NO_DEVICE ? X502_ERR_DEVICE_DISCONNECTED :
|
||
X502_ERR_IOCTL_FAILD);
|
||
} else {
|
||
if (recvd_size!=NULL) {
|
||
*recvd_size = usbres;
|
||
} else if (usbres != len) {
|
||
err = X502_ERR_IOCTL_INVALID_RESP_SIZE;
|
||
}
|
||
}
|
||
|
||
//если управляющий запрос не выполнен успешно, то пытаемся получить
|
||
//код ошибки из устройства
|
||
if (err == X502_ERR_IOCTL_FAILD) {
|
||
uint32_t devres;
|
||
usbres = libusb_control_transfer(handle,
|
||
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
|
||
E502_CM4_CMD_GET_LAST_ERROR,
|
||
0, 0,
|
||
(uint8_t*)&devres, sizeof(devres),
|
||
E502_USB_REQ_TOUT);
|
||
|
||
//если успешно получили код ошибки устройства - то возвращаем его в качестве результата
|
||
if ((usbres == sizeof(devres)) && (devres !=0)) {
|
||
err = devres;
|
||
}
|
||
}
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
static int32_t f_iface_gen_ioctl(t_x502_hnd hnd, uint32_t cmd_code, uint32_t param,
|
||
const void* snd_data, uint32_t snd_size,
|
||
void* rcv_data, uint32_t recv_size, uint32_t* recvd_size,
|
||
uint32_t tout) {
|
||
t_usb_iface_data *usb_data = (t_usb_iface_data *)hnd->iface_data;
|
||
return f_ioreq(usb_data->devhnd, cmd_code, param, snd_data, snd_size,
|
||
rcv_data, recv_size, recvd_size, tout);
|
||
}
|
||
|
||
static int32_t f_fill_devlist(libusb_device_handle *hnd, t_x502_devrec *info) {
|
||
int32_t err = X502_ERR_OK;
|
||
t_x502_devrec_inptr *devinfo_ptr = calloc(1, sizeof(t_x502_devrec_inptr));
|
||
if (devinfo_ptr==NULL) {
|
||
err = X502_ERR_MEMORY_ALLOC;
|
||
}
|
||
|
||
if (err == X502_ERR_OK) {
|
||
t_lboot_devinfo lboot_info;
|
||
|
||
|
||
//получаем информацию о устройстве
|
||
err = f_ioreq(hnd, E502_CM4_CMD_GET_MODULE_INFO, 0, NULL, 0, &lboot_info,
|
||
sizeof(lboot_info), NULL, 0);
|
||
|
||
if (err == X502_ERR_OK) {
|
||
uint32_t devflags;
|
||
|
||
|
||
strcpy(info->devname, lboot_info.devname);
|
||
strcpy(info->serial, lboot_info.serial);
|
||
|
||
devinfo_ptr->iface = &f_usb_iface;
|
||
devinfo_ptr->iface_data = libusb_ref_device(libusb_get_device(hnd));
|
||
info->internal = devinfo_ptr;
|
||
info->iface = X502_IFACE_USB;
|
||
info->flags = X502_DEVFLAGS_IFACE_SUPPORT_USB;
|
||
|
||
if (f_ioreq(hnd, E502_CM4_CMD_GET_DEVFLAGS, 0,
|
||
NULL, 0, &devflags, sizeof(devflags), NULL, 0) == X502_ERR_OK) {
|
||
info->flags &= ~E502_CM4_DEVFLAGS;
|
||
info->flags |= devflags;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (err != X502_ERR_OK) {
|
||
free(devinfo_ptr);
|
||
}
|
||
return err;
|
||
}
|
||
|
||
|
||
|
||
X502_EXPORT(int32_t) E502_UsbGetDevRecordsList2(t_x502_devrec *list, uint32_t size,
|
||
uint32_t flags, uint32_t *devcnt, uint16_t idVendor, uint16_t idProduct) {
|
||
uint32_t curcnt=0;
|
||
int32_t err = X502_ERR_OK;
|
||
libusb_device **usb_devlist;
|
||
ssize_t usb_devlist_size, i;
|
||
|
||
if (!f_lusb_init_done) {
|
||
libusb_init(NULL);
|
||
#ifdef LIBUSB_DEBUG
|
||
libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_DEBUG);
|
||
#endif
|
||
f_lusb_init_done = 1;
|
||
}
|
||
|
||
|
||
//получаем список устройств
|
||
usb_devlist_size = libusb_get_device_list(NULL, &usb_devlist);
|
||
for (i=0; i < usb_devlist_size; i++) {
|
||
//получаем дескриптор устройства для проверки vid, pid
|
||
struct libusb_device_descriptor devdescr;
|
||
libusb_device_handle* usbhnd = NULL;
|
||
|
||
if (libusb_get_device_descriptor (usb_devlist[i], &devdescr) == 0) {
|
||
//сравниваем VID, PID с индентификаторами загрузочного устройства
|
||
if ((devdescr.idVendor == idVendor)
|
||
&& (devdescr.idProduct == idProduct)) {
|
||
int32_t cur_err;
|
||
cur_err = libusb_open(usb_devlist[i], &usbhnd);
|
||
if (cur_err == X502_ERR_OK) {
|
||
t_x502_devrec info;
|
||
int info_used = 0;
|
||
X502_DevRecordInit(&info);
|
||
|
||
|
||
if (f_fill_devlist(usbhnd, &info) == X502_ERR_OK) {
|
||
/* если нужны только не открытые, то уже открытое
|
||
* устройство пропускаем */
|
||
if (!(flags & X502_GETDEVS_FLAGS_ONLY_NOT_OPENED) ||
|
||
!(info.flags & X502_DEVFLAGS_DEVREC_OPENED)) {
|
||
/* если есть место в списке - то сохраняем
|
||
* полученную информацию */
|
||
if ((list!=NULL) && (curcnt < size)) {
|
||
list[curcnt] = info;
|
||
info_used = 1;
|
||
}
|
||
curcnt++;
|
||
}
|
||
}
|
||
|
||
if (!info_used)
|
||
X502_FreeDevRecordList(&info,1);
|
||
|
||
libusb_close(usbhnd);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
libusb_free_device_list(usb_devlist, 1);
|
||
|
||
|
||
if (devcnt != NULL)
|
||
*devcnt = curcnt;
|
||
|
||
return err != X502_ERR_OK ? err : curcnt > (uint32_t)size ? (int32_t)size : (int32_t)curcnt ;
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E440_UsbGetDevRecordsList(t_x502_devrec* list, uint32_t size,
|
||
uint32_t flags, uint32_t* devcnt) {
|
||
return E502_UsbGetDevRecordsList2(list, size, flags, devcnt, E440_USB_VID, E440_USB_PID);
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E502_UsbGetDevRecordsList(t_x502_devrec *list, uint32_t size,
|
||
uint32_t flags, uint32_t *devcnt) {
|
||
return E502_UsbGetDevRecordsList2(list, size, flags, devcnt, E502_USB_VID, E502_USB_PID);
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E502_OpenUsb(t_x502_hnd hnd, const char* serial) {
|
||
return X502_Open(hnd, serial, E502_DEVICE_NAME, E502_UsbGetDevRecordsList);
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E502_UsbGetSerialList(char serials[][X502_SERIAL_SIZE], uint32_t size,
|
||
uint32_t flags, uint32_t *devcnt) {
|
||
return X502_GetSerialList(serials, size, flags, devcnt, E502_DEVICE_NAME, E502_UsbGetDevRecordsList);
|
||
}
|
||
|
||
|
||
X502_EXPORT(int32_t) E16_UsbGetDevRecordsList(t_x502_devrec *list, uint32_t size,
|
||
uint32_t flags, uint32_t *devcnt) {
|
||
return E502_UsbGetDevRecordsList2(list, size, flags, devcnt, E16_USB_VID, E16_USB_PID);
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E16_OpenUsb(t_x502_hnd hnd, const char* serial) {
|
||
return X502_Open(hnd, serial, E16_DEVICE_NAME, E16_UsbGetDevRecordsList);
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E16_UsbGetSerialList(char serials[][X502_SERIAL_SIZE], uint32_t size,
|
||
uint32_t flags, uint32_t *devcnt) {
|
||
return X502_GetSerialList(serials, size, flags, devcnt, E16_DEVICE_NAME, E16_UsbGetDevRecordsList);
|
||
}
|
||
#else
|
||
#include "e502api.h"
|
||
X502_EXPORT(int32_t) E502_OpenUsb(t_x502_hnd hnd, const char* serial) {
|
||
return X502_ERR_NOT_IMPLEMENTED;
|
||
}
|
||
|
||
X502_EXPORT(int32_t) E502_UsbGetSerialList(char serials[][X502_SERIAL_SIZE], uint32_t size,
|
||
uint32_t flags, uint32_t *devcnt) {
|
||
return X502_ERR_NOT_IMPLEMENTED;
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
|