X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fstlink-usb.c;h=98654129eccdca57b5a20ebaca2b5d525f48d873;hb=refs%2Fheads%2Fdebian;hp=4a62d9dd5ff12d4f27e0b63df13c4f685d2ef0b4;hpb=3c3b02e83e358edee5e704eb61b96d7d1561ff42;p=fw%2Fstlink diff --git a/src/stlink-usb.c b/src/stlink-usb.c index 4a62d9d..9865412 100644 --- a/src/stlink-usb.c +++ b/src/stlink-usb.c @@ -5,37 +5,21 @@ #include #include #include +#include +#include #include "stlink-common.h" #include "stlink-usb.h" -#include "uglylogging.h" - -/* code from bsd timersub.h -http://www.gnu-darwin.org/www001/src/ports/net/libevnet/work/libevnet-0.3.8/libnostd/bsd/sys/time/timersub.h.html -*/ -#if !defined timersub -#define timersub(a, b, r) do { \ - (r)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (r)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((r)->tv_usec < 0) { \ - --(r)->tv_sec; \ - (r)->tv_usec += 1000000; \ - } \ -} while (0) -#endif enum SCSI_Generic_Direction {SG_DXFER_TO_DEV=0, SG_DXFER_FROM_DEV=0x80}; void _stlink_usb_close(stlink_t* sl) { + if (!sl) + return; + struct stlink_libusb * const handle = sl->backend_data; // maybe we couldn't even get the usb device? if (handle != NULL) { - if (handle->req_trans != NULL) - libusb_free_transfer(handle->req_trans); - - if (handle->rep_trans != NULL) - libusb_free_transfer(handle->rep_trans); - if (handle->usb_handle != NULL) { libusb_close(handle->usb_handle); } @@ -45,111 +29,42 @@ void _stlink_usb_close(stlink_t* sl) { } } - -struct trans_ctx { -#define TRANS_FLAGS_IS_DONE (1 << 0) -#define TRANS_FLAGS_HAS_ERROR (1 << 1) - volatile unsigned long flags; -}; - -#ifndef LIBUSB_CALL -# define LIBUSB_CALL -#endif - -static void LIBUSB_CALL on_trans_done(struct libusb_transfer * trans) { - struct trans_ctx * const ctx = trans->user_data; - - if (trans->status != LIBUSB_TRANSFER_COMPLETED) - ctx->flags |= TRANS_FLAGS_HAS_ERROR; - - ctx->flags |= TRANS_FLAGS_IS_DONE; -} - -int submit_wait(struct stlink_libusb *slu, struct libusb_transfer * trans) { - struct timeval start; - struct timeval now; - struct timeval diff; - struct trans_ctx trans_ctx; - enum libusb_error error; - - trans_ctx.flags = 0; - - /* brief intrusion inside the libusb interface */ - trans->callback = on_trans_done; - trans->user_data = &trans_ctx; - - if ((error = libusb_submit_transfer(trans))) { - printf("libusb_submit_transfer(%d)\n", error); - return -1; - } - - gettimeofday(&start, NULL); - - while (trans_ctx.flags == 0) { - struct timeval timeout; - timeout.tv_sec = 3; - timeout.tv_usec = 0; - if (libusb_handle_events_timeout(slu->libusb_ctx, &timeout)) { - printf("libusb_handle_events()\n"); - return -1; - } - - gettimeofday(&now, NULL); - timersub(&now, &start, &diff); - if (diff.tv_sec >= 3) { - printf("libusb_handle_events() timeout\n"); - return -1; - } - } - - if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) { - printf("libusb_handle_events() | has_error\n"); - return -1; - } - - return 0; -} - ssize_t send_recv(struct stlink_libusb* handle, int terminate, unsigned char* txbuf, size_t txsize, unsigned char* rxbuf, size_t rxsize) { /* note: txbuf and rxbuf can point to the same area */ int res = 0; - libusb_fill_bulk_transfer(handle->req_trans, handle->usb_handle, - handle->ep_req, - txbuf, txsize, - NULL, NULL, - 0 - ); - - if (submit_wait(handle, handle->req_trans)) return -1; + if (libusb_bulk_transfer(handle->usb_handle, handle->ep_req, + txbuf, + txsize, + &res, + 3000)) + return -1; - /* send_only */ if (rxsize != 0) { - - /* read the response */ - - libusb_fill_bulk_transfer(handle->rep_trans, handle->usb_handle, - handle->ep_rep, rxbuf, rxsize, NULL, NULL, 0); - - if (submit_wait(handle, handle->rep_trans)) return -1; - res = handle->rep_trans->actual_length; + if (libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, + rxbuf, + rxsize, + &res, + 3000)) + return -1; } if ((handle->protocoll == 1) && terminate) { /* Read the SG reply */ unsigned char sg_buf[13]; - libusb_fill_bulk_transfer - (handle->rep_trans, handle->usb_handle, - handle->ep_rep, sg_buf, 13, NULL, NULL, 0); - res = submit_wait(handle, handle->rep_trans); + if (libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, + sg_buf, + 13, + &res, + 3000)) + return -1; /* The STLink doesn't seem to evaluate the sequence number */ handle->sg_transfer_idx++; - if (res ) return -1; } - return handle->rep_trans->actual_length; + return res; } static inline int send_only @@ -180,7 +95,7 @@ static int fill_command return i; } -void _stlink_usb_version(stlink_t *sl) { +int _stlink_usb_version(stlink_t *sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -193,8 +108,10 @@ void _stlink_usb_version(stlink_t *sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } int32_t _stlink_usb_target_voltage(stlink_t *sl) { @@ -225,7 +142,7 @@ int32_t _stlink_usb_target_voltage(stlink_t *sl) { return voltage; } -uint32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr) { +int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const rdata = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -239,12 +156,13 @@ uint32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr) { size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return 0; + return size; } - return read_uint32(rdata, 4); + *data = read_uint32(rdata, 4); + return 0; } -void _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { +int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const rdata = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -259,37 +177,54 @@ void _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } -void _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { +int _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; + int i, ret; - int i = fill_command(sl, SG_DXFER_TO_DEV, len); + i = fill_command(sl, SG_DXFER_TO_DEV, len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_WRITEMEM_32BIT; write_uint32(&cmd[i], addr); write_uint16(&cmd[i + 4], len); - send_only(slu, 0, cmd, slu->cmd_len); + ret = send_only(slu, 0, cmd, slu->cmd_len); + if (ret == -1) + return ret; - send_only(slu, 1, data, len); + ret = send_only(slu, 1, data, len); + if (ret == -1) + return ret; + + return 0; } -void _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { +int _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; + int i, ret; - int i = fill_command(sl, SG_DXFER_TO_DEV, 0); + i = fill_command(sl, SG_DXFER_TO_DEV, 0); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_WRITEMEM_8BIT; write_uint32(&cmd[i], addr); write_uint16(&cmd[i + 4], len); - send_only(slu, 0, cmd, slu->cmd_len); - send_only(slu, 1, data, len); + ret = send_only(slu, 0, cmd, slu->cmd_len); + if (ret == -1) + return ret; + + ret = send_only(slu, 1, data, len); + if (ret == -1) + return ret; + + return 0; } @@ -310,7 +245,7 @@ int _stlink_usb_current_mode(stlink_t * sl) { return sl->q_buf[0]; } -void _stlink_usb_core_id(stlink_t * sl) { +int _stlink_usb_core_id(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; unsigned char* const data = sl->q_buf; @@ -324,13 +259,14 @@ void _stlink_usb_core_id(stlink_t * sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return -1; } sl->core_id = read_uint32(data, 0); + return 0; } -void _stlink_usb_status(stlink_t * sl) { +int _stlink_usb_status(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -344,11 +280,14 @@ void _stlink_usb_status(stlink_t * sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + sl->q_len = (size_t) size; + + return 0; } -void _stlink_usb_force_debug(stlink_t *sl) { +int _stlink_usb_force_debug(stlink_t *sl) { struct stlink_libusb *slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -361,11 +300,13 @@ void _stlink_usb_force_debug(stlink_t *sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } -void _stlink_usb_enter_swd_mode(stlink_t * sl) { +int _stlink_usb_enter_swd_mode(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; ssize_t size; @@ -379,11 +320,13 @@ void _stlink_usb_enter_swd_mode(stlink_t * sl) { size = send_only(slu, 1, cmd, slu->cmd_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } -void _stlink_usb_exit_dfu_mode(stlink_t* sl) { +int _stlink_usb_exit_dfu_mode(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; ssize_t size; @@ -395,15 +338,17 @@ void _stlink_usb_exit_dfu_mode(stlink_t* sl) { size = send_only(slu, 1, cmd, slu->cmd_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } /** * TODO - not convinced this does anything... * @param sl */ -void _stlink_usb_reset(stlink_t * sl) { +int _stlink_usb_reset(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -417,12 +362,14 @@ void _stlink_usb_reset(stlink_t * sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } -void _stlink_usb_jtag_reset(stlink_t * sl, int value) { +int _stlink_usb_jtag_reset(stlink_t * sl, int value) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -432,17 +379,19 @@ void _stlink_usb_jtag_reset(stlink_t * sl, int value) { cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_JTAG_DRIVE_NRST; - cmd[i++] = (value)?0:1; + cmd[i++] = value; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } -void _stlink_usb_step(stlink_t* sl) { +int _stlink_usb_step(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -456,15 +405,17 @@ void _stlink_usb_step(stlink_t* sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } /** * This seems to do a good job of restarting things from the beginning? * @param sl */ -void _stlink_usb_run(stlink_t* sl) { +int _stlink_usb_run(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -478,11 +429,13 @@ void _stlink_usb_run(stlink_t* sl) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } + + return 0; } -void _stlink_usb_exit_debug_mode(stlink_t *sl) { +int _stlink_usb_exit_debug_mode(stlink_t *sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; ssize_t size; @@ -494,11 +447,13 @@ void _stlink_usb_exit_debug_mode(stlink_t *sl) { size = send_only(slu, 1, cmd, slu->cmd_len); if (size == -1) { printf("[!] send_only\n"); - return; + return size; } + + return 0; } -void _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { +int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -513,15 +468,16 @@ void _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } sl->q_len = (size_t) size; stlink_print_data(sl); + return 0; } -void _stlink_usb_read_all_regs(stlink_t *sl, reg *regp) { +int _stlink_usb_read_all_regs(stlink_t *sl, reg *regp) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; unsigned char* const data = sl->q_buf; @@ -534,7 +490,7 @@ void _stlink_usb_read_all_regs(stlink_t *sl, reg *regp) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } sl->q_len = (size_t) size; stlink_print_data(sl); @@ -546,16 +502,18 @@ void _stlink_usb_read_all_regs(stlink_t *sl, reg *regp) { regp->rw = read_uint32(sl->q_buf, 76); regp->rw2 = read_uint32(sl->q_buf, 80); if (sl->verbose < 2) - return; + return 0; DLOG("xpsr = 0x%08x\n", read_uint32(sl->q_buf, 64)); DLOG("main_sp = 0x%08x\n", read_uint32(sl->q_buf, 68)); DLOG("process_sp = 0x%08x\n", read_uint32(sl->q_buf, 72)); DLOG("rw = 0x%08x\n", read_uint32(sl->q_buf, 76)); DLOG("rw2 = 0x%08x\n", read_uint32(sl->q_buf, 80)); + + return 0; } -void _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { +int _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -570,7 +528,7 @@ void _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } sl->q_len = (size_t) size; stlink_print_data(sl); @@ -596,19 +554,27 @@ void _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { default: regp->r[r_idx] = r; } + + return 0; } /* See section C1.6 of the ARMv7-M Architecture Reference Manual */ -void _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) { +int _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) { uint32_t r; + int ret; sl->q_buf[0] = (unsigned char) r_idx; for (int i = 1; i < 4; i++) { sl->q_buf[i] = 0; } - _stlink_usb_write_mem32(sl, DCRSR, 4); + ret = _stlink_usb_write_mem32(sl, DCRSR, 4); + if (ret == -1) + return ret; + _stlink_usb_read_mem32(sl, DCRDR, 4); + if (ret == -1) + return ret; r = read_uint32(sl->q_buf, 0); DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); @@ -627,22 +593,39 @@ void _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) { regp->s[r_idx - 0x40] = r; break; } + + return 0; } -void _stlink_usb_read_all_unsupported_regs(stlink_t *sl, reg *regp) { - _stlink_usb_read_unsupported_reg(sl, 0x14, regp); - _stlink_usb_read_unsupported_reg(sl, 0x21, regp); +int _stlink_usb_read_all_unsupported_regs(stlink_t *sl, reg *regp) { + int ret; + + ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp); + if (ret == -1) + return ret; + + ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp); + if (ret == -1) + return ret; for (int i = 0; i < 32; i++) { - _stlink_usb_read_unsupported_reg(sl, 0x40+i, regp); + ret = _stlink_usb_read_unsupported_reg(sl, 0x40+i, regp); + if (ret == -1) + return ret; } + + return 0; } /* See section C1.6 of the ARMv7-M Architecture Reference Manual */ -void _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) { +int _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) { + int ret; + if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ /* These are held in the same register */ - _stlink_usb_read_unsupported_reg(sl, 0x14, regp); + ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp); + if (ret == -1) + return ret; val = (uint8_t) (val>>24); @@ -666,17 +649,19 @@ void _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, re write_uint32(sl->q_buf, val); - _stlink_usb_write_mem32(sl, DCRDR, 4); + ret = _stlink_usb_write_mem32(sl, DCRDR, 4); + if (ret == -1) + return ret; sl->q_buf[0] = (unsigned char) r_idx; sl->q_buf[1] = 0; sl->q_buf[2] = 0x01; sl->q_buf[3] = 0; - _stlink_usb_write_mem32(sl, DCRSR, 4); + return _stlink_usb_write_mem32(sl, DCRSR, 4); } -void _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) { +int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; @@ -691,10 +676,12 @@ void _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) { size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); if (size == -1) { printf("[!] send_recv\n"); - return; + return size; } sl->q_len = (size_t) size; stlink_print_data(sl); + + return 0; } stlink_backend_t _stlink_usb_backend = { @@ -726,27 +713,25 @@ stlink_backend_t _stlink_usb_backend = { _stlink_usb_target_voltage }; - -stlink_t* stlink_open_usb(const int verbose, int reset) { +stlink_t *stlink_open_usb(enum ugly_loglevel verbose, bool reset, char serial[16]) +{ stlink_t* sl = NULL; struct stlink_libusb* slu = NULL; - int error = -1; - libusb_device** devs = NULL; + int ret = -1; int config; - sl = malloc(sizeof (stlink_t)); - slu = malloc(sizeof (struct stlink_libusb)); - if (sl == NULL) goto on_error; - if (slu == NULL) goto on_error; - memset(sl, 0, sizeof (stlink_t)); - memset(slu, 0, sizeof (struct stlink_libusb)); + sl = calloc(1, sizeof (stlink_t)); + slu = calloc(1, sizeof (struct stlink_libusb)); + if (sl == NULL) + goto on_malloc_error; + if (slu == NULL) + goto on_malloc_error; ugly_init(verbose); sl->backend = &_stlink_usb_backend; sl->backend_data = slu; sl->core_stat = STLINK_CORE_STAT_UNKNOWN; - if (libusb_init(&(slu->libusb_ctx))) { WLOG("failed to init libusb context, wrong version of libraries?\n"); goto on_error; @@ -758,6 +743,10 @@ stlink_t* stlink_open_usb(const int verbose, int reset) { int devBus =0; int devAddr=0; + /* @TODO: Reading a environment variable in a usb open function is not very nice, this + should be refactored and moved into the CLI tools, and instead of giving USB_BUS:USB_ADDR a real stlink + serial string should be passed to this function. Probably people are using this but this is very odd because + as programmer can change to multiple busses and it is better to detect them based on serial. */ char *device = getenv("STLINK_DEVICE"); if (device) { char *c = strchr(device,':'); @@ -770,13 +759,39 @@ stlink_t* stlink_open_usb(const int verbose, int reset) { devAddr=atoi(c); ILOG("bus %03d dev %03d\n",devBus, devAddr); } - while (cnt){ - cnt--; + + while (cnt--) { libusb_get_device_descriptor( list[cnt], &desc ); - if (desc.idVendor!=USB_ST_VID) continue; - if (devBus && devAddr) - if ((libusb_get_bus_number(list[cnt])!=devBus) || (libusb_get_device_address(list[cnt])!=devAddr)) continue; - if ( (desc.idProduct == USB_STLINK_32L_PID) || (desc.idProduct == USB_STLINK_NUCLEO_PID) ) break; + if (desc.idVendor != USB_ST_VID) + continue; + + if (devBus && devAddr) { + if ((libusb_get_bus_number(list[cnt]) != devBus) + || (libusb_get_device_address(list[cnt]) != devAddr)) { + continue; + } + } + + if ((desc.idProduct == USB_STLINK_32L_PID) || (desc.idProduct == USB_STLINK_NUCLEO_PID)) { + struct libusb_device_handle *handle; + + libusb_open(list[cnt], &handle); + sl->serial_size = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, + (unsigned char *)sl->serial, sizeof(sl->serial)); + libusb_close(handle); + + if ((serial == NULL) || (*serial == 0)) + break; + + if (sl->serial_size < 0) + continue; + + if (memcmp(serial, &sl->serial, sl->serial_size) == 0) + break; + + continue; + } + if (desc.idProduct == USB_STLINK_PID) { slu->protocoll = 1; break; @@ -787,22 +802,20 @@ stlink_t* stlink_open_usb(const int verbose, int reset) { WLOG ("Couldn't find %s ST-Link/V2 devices\n",(devBus && devAddr)?"matched":"any"); goto on_error; } else { - int error = libusb_open(list[cnt], &slu->usb_handle); - if( error !=0 ) { - WLOG("Error %d opening ST-Link/V2 device %03d:%03d\n", error, libusb_get_bus_number(list[cnt]), libusb_get_device_address(list[cnt])); + ret = libusb_open(list[cnt], &slu->usb_handle); + if (ret != 0) { + WLOG("Error %d (%s) opening ST-Link/V2 device %03d:%03d\n", + ret, strerror (errno), libusb_get_bus_number(list[cnt]), libusb_get_device_address(list[cnt])); goto on_error; } } libusb_free_device_list(list, 1); - if (libusb_kernel_driver_active(slu->usb_handle, 0) == 1) { - int r; - - r = libusb_detach_kernel_driver(slu->usb_handle, 0); - if (r<0) { - WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-r)); + ret = libusb_detach_kernel_driver(slu->usb_handle, 0); + if (ret < 0) { + WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-ret)); goto on_libusb_error; } } @@ -823,19 +836,7 @@ stlink_t* stlink_open_usb(const int verbose, int reset) { } if (libusb_claim_interface(slu->usb_handle, 0)) { - WLOG("libusb_claim_interface() failed\n"); - goto on_libusb_error; - } - - slu->req_trans = libusb_alloc_transfer(0); - if (slu->req_trans == NULL) { - WLOG("libusb_alloc_transfer failed\n"); - goto on_libusb_error; - } - - slu->rep_trans = libusb_alloc_transfer(0); - if (slu->rep_trans == NULL) { - WLOG("libusb_alloc_transfer failed\n"); + WLOG("Stlink usb device found, but unable to claim (probably already in use?)\n"); goto on_libusb_error; } @@ -851,8 +852,6 @@ stlink_t* stlink_open_usb(const int verbose, int reset) { // TODO - never used at the moment, always CMD_SIZE slu->cmd_len = (slu->protocoll == 1)? STLINK_SG_SIZE: STLINK_CMD_SIZE; - /* success */ - if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) { ILOG("-- exit_dfu_mode\n"); stlink_exit_dfu_mode(sl); @@ -864,30 +863,145 @@ stlink_t* stlink_open_usb(const int verbose, int reset) { if (reset) { stlink_reset(sl); + usleep(10000); } - stlink_load_device_params(sl); - stlink_version(sl); - error = 0; + stlink_version(sl); + ret = stlink_load_device_params(sl); on_libusb_error: - if (devs != NULL) { - libusb_free_device_list(devs, 1); - } - - if (error == -1) { + if (ret == -1) { stlink_close(sl); return NULL; } - /* success */ return sl; on_error: - if( slu->libusb_ctx) + if (slu->libusb_ctx) libusb_exit(slu->libusb_ctx); - if (sl != NULL) free(sl); - if (slu != NULL) free(slu); - return 0; + +on_malloc_error: + if (sl != NULL) + free(sl); + if (slu != NULL) + free(slu); + + return NULL; } +static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[]) { + stlink_t **_sldevs; + libusb_device *dev; + int i = 0; + int ret = 0; + size_t slcnt = 0; + size_t slcur = 0; + + /* Count stlink */ + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor desc; + int r = libusb_get_device_descriptor(dev, &desc); + if (r < 0) { + WLOG("failed to get libusb device descriptor\n"); + break; + } + + if (desc.idProduct != USB_STLINK_32L_PID && + desc.idProduct != USB_STLINK_NUCLEO_PID) + continue; + + slcnt++; + } + + /* Allocate list of pointers */ + _sldevs = calloc(slcnt, sizeof(stlink_t *)); + if (!_sldevs) { + *sldevs = NULL; + return 0; + } + + /* Open stlinks and attach to list */ + i = 0; + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor desc; + ret = libusb_get_device_descriptor(dev, &desc); + if (ret < 0) { + WLOG("failed to get libusb device descriptor\n"); + break; + } + + if (desc.idProduct != USB_STLINK_32L_PID && + desc.idProduct != USB_STLINK_NUCLEO_PID) + continue; + + struct libusb_device_handle* handle; + char serial[13]; + memset(serial, 0, sizeof(serial)); + + ret = libusb_open(dev, &handle); + if (ret < 0) { + WLOG("failed to get libusb device descriptor\n"); + break; + } + + ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)&serial, sizeof(serial)); + if (ret < 0) + *serial = NULL; + + libusb_close(handle); + + stlink_t *sl = NULL; + sl = stlink_open_usb(0, 1, serial); + if (!sl) + continue; + + _sldevs[slcur] = sl; + slcur++; + } + + /* Something went wrong */ + if (ret < 0) { + free(_sldevs); + *sldevs = NULL; + return 0; + } + + *sldevs = _sldevs; + return slcnt; +} + +size_t stlink_probe_usb(stlink_t **stdevs[]) { + libusb_device **devs; + stlink_t **sldevs; + + size_t slcnt = 0; + int r; + ssize_t cnt; + + r = libusb_init(NULL); + if (r < 0) + return 0; + + cnt = libusb_get_device_list(NULL, &devs); + if (cnt < 0) + return 0; + + slcnt = stlink_probe_usb_devs(devs, &sldevs); + libusb_free_device_list(devs, 1); + + libusb_exit(NULL); + + *stdevs = sldevs; + return slcnt; +} + +void stlink_probe_usb_free(stlink_t ***stdevs, size_t size) { + if (stdevs == NULL || *stdevs == NULL || size == 0) + return; + + for (size_t n = 0; n < size; n++) + stlink_close((*stdevs)[n]); + free(*stdevs); + *stdevs = NULL; +}