X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fstlink-usb.c;h=fa2bd7e081c50154fbd3164ce7250ed334b737fe;hb=e886396e0e0ee27f8df2182f4d1a96bf59efedfb;hp=57a4a2fddff510c8b653893cbf8f58fe3161c473;hpb=076f1086fa9c0dfa043300fb1776bc10e8eaa77f;p=fw%2Fstlink diff --git a/src/stlink-usb.c b/src/stlink-usb.c index 57a4a2f..fa2bd7e 100644 --- a/src/stlink-usb.c +++ b/src/stlink-usb.c @@ -2,11 +2,33 @@ #include #include #include -#include +#include #include -#include +#include + #include "stlink-common.h" #include "stlink-usb.h" +#include "uglylogging.h" + +#define LOG_TAG __FILE__ +#define DLOG(format, args...) ugly_log(UDEBUG, LOG_TAG, format, ## args) +#define ILOG(format, args...) ugly_log(UINFO, LOG_TAG, format, ## args) +#define WLOG(format, args...) ugly_log(UWARN, LOG_TAG, format, ## args) +#define fatal(format, args...) ugly_log(UFATAL, LOG_TAG, format, ## args) + +/* 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}; @@ -36,7 +58,11 @@ struct trans_ctx { volatile unsigned long flags; }; -static void on_trans_done(struct libusb_transfer * trans) { +#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) @@ -116,6 +142,7 @@ ssize_t send_recv(struct stlink_libusb* handle, int terminate, if (submit_wait(handle, handle->rep_trans)) return -1; res = handle->rep_trans->actual_length; } + if ((handle->protocoll == 1) && terminate) { /* Read the SG reply */ unsigned char sg_buf[13]; @@ -138,33 +165,6 @@ static inline int send_only } -/* Search for a STLINK device, either any or teh one with the given PID - * Return the protocoll version - */ -static int is_stlink_device(libusb_device * dev, uint16_t pid) { - struct libusb_device_descriptor desc; - int version; - - if (libusb_get_device_descriptor(dev, &desc)) - return 0; - - if (desc.idVendor != USB_ST_VID) - return 0; - - if ((desc.idProduct != USB_STLINK_32L_PID) && - (desc.idProduct != USB_STLINK_PID )) - return 0; - - if(pid && (pid != desc.idProduct)) - return 0; - if (desc.idProduct == USB_STLINK_PID ) - version = 1; - else - version = 2; - - return version; -} - static int fill_command (stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len) { struct stlink_libusb * const slu = sl->backend_data; @@ -203,6 +203,72 @@ void _stlink_usb_version(stlink_t *sl) { } } +int _stlink_usb_target_voltage(stlink_t *sl) { + struct stlink_libusb * const slu = sl->backend_data; + unsigned char* const rdata = sl->q_buf; + unsigned char* const cmd = sl->c_buf; + ssize_t size; + uint32_t rep_len = 8; + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + uint32_t factor, reading; + int voltage; + + cmd[i++] = STLINK_GET_TARGET_VOLTAGE; + + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); + if (size == -1) { + printf("[!] send_recv\n"); + return -1; + } else if (size != 8) { + printf("[!] wrong length\n"); + return -1; + } + + factor = (rdata[3] << 24) | (rdata[2] << 16) | (rdata[1] << 8) | (rdata[0] << 0); + reading = (rdata[7] << 24) | (rdata[6] << 16) | (rdata[5] << 8) | (rdata[4] << 0); + voltage = 2400 * reading / factor; + + return voltage; +} + +uint32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr) { + struct stlink_libusb * const slu = sl->backend_data; + unsigned char* const rdata = sl->q_buf; + unsigned char* const cmd = sl->c_buf; + ssize_t size; + const int rep_len = 8; + + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_JTAG_READDEBUG_32BIT; + write_uint32(&cmd[i], addr); + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); + if (size == -1) { + printf("[!] send_recv\n"); + return 0; + } + return read_uint32(rdata, 4); +} + +void _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; + ssize_t size; + const int rep_len = 2; + + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_JTAG_WRITEDEBUG_32BIT; + write_uint32(&cmd[i], addr); + write_uint32(&cmd[i + 4], data); + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len); + if (size == -1) { + printf("[!] send_recv\n"); + return; + } +} + void _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; @@ -362,6 +428,26 @@ void _stlink_usb_reset(stlink_t * sl) { } +void _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; + ssize_t size; + int rep_len = 2; + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_JTAG_DRIVE_NRST; + cmd[i++] = (value)?0:1; + + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len); + if (size == -1) { + printf("[!] send_recv\n"); + return; + } +} + + void _stlink_usb_step(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; @@ -468,11 +554,11 @@ void _stlink_usb_read_all_regs(stlink_t *sl, reg *regp) { if (sl->verbose < 2) return; - DD(sl, "xpsr = 0x%08x\n", read_uint32(sl->q_buf, 64)); - DD(sl, "main_sp = 0x%08x\n", read_uint32(sl->q_buf, 68)); - DD(sl, "process_sp = 0x%08x\n", read_uint32(sl->q_buf, 72)); - DD(sl, "rw = 0x%08x\n", read_uint32(sl->q_buf, 76)); - DD(sl, "rw2 = 0x%08x\n", read_uint32(sl->q_buf, 80)); + 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)); } void _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { @@ -495,7 +581,7 @@ void _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { sl->q_len = (size_t) size; stlink_print_data(sl); r = read_uint32(sl->q_buf, 0); - DD(sl, "r_idx (%2d) = 0x%08x\n", r_idx, r); + DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); switch (r_idx) { case 16: @@ -518,6 +604,84 @@ void _stlink_usb_read_reg(stlink_t *sl, int r_idx, reg *regp) { } } +/* 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) { + uint32_t r; + + 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); + _stlink_usb_read_mem32(sl, DCRDR, 4); + + r = read_uint32(sl->q_buf, 0); + DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); + + switch (r_idx) { + case 0x14: + regp->primask = (uint8_t) (r & 0xFF); + regp->basepri = (uint8_t) ((r>>8) & 0xFF); + regp->faultmask = (uint8_t) ((r>>16) & 0xFF); + regp->control = (uint8_t) ((r>>24) & 0xFF); + break; + case 0x21: + regp->fpscr = r; + break; + default: + regp->s[r_idx - 0x40] = r; + break; + } +} + +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); + + for (int i = 0; i < 32; i++) { + _stlink_usb_read_unsupported_reg(sl, 0x40+i, regp); + } +} + +/* 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) { + 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); + + val = (uint8_t) (val>>24); + + switch (r_idx) { + case 0x1C: /* control */ + val = (((uint32_t) val) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask); + break; + case 0x1D: /* faultmask */ + val = (((uint32_t) regp->control) << 24) | (((uint32_t) val) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask); + break; + case 0x1E: /* basepri */ + val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) val) << 8) | ((uint32_t) regp->primask); + break; + case 0x1F: /* primask */ + val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) val); + break; + } + + r_idx = 0x14; + } + + write_uint32(sl->q_buf, val); + + _stlink_usb_write_mem32(sl, DCRDR, 4); + + 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); +} + void _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; @@ -547,31 +711,34 @@ stlink_backend_t _stlink_usb_backend = { _stlink_usb_exit_dfu_mode, _stlink_usb_core_id, _stlink_usb_reset, + _stlink_usb_jtag_reset, _stlink_usb_run, _stlink_usb_status, _stlink_usb_version, + _stlink_usb_read_debug32, _stlink_usb_read_mem32, + _stlink_usb_write_debug32, _stlink_usb_write_mem32, _stlink_usb_write_mem8, _stlink_usb_read_all_regs, _stlink_usb_read_reg, + _stlink_usb_read_all_unsupported_regs, + _stlink_usb_read_unsupported_reg, + _stlink_usb_write_unsupported_reg, _stlink_usb_write_reg, _stlink_usb_step, _stlink_usb_current_mode, - _stlink_usb_force_debug + _stlink_usb_force_debug, + _stlink_usb_target_voltage }; -stlink_t* stlink_open_usb(const int verbose) { +stlink_t* stlink_open_usb(const int verbose, int reset) { stlink_t* sl = NULL; struct stlink_libusb* slu = NULL; int error = -1; libusb_device** devs = NULL; - libusb_device* dev; - ssize_t i; - ssize_t count; int config; - char *iSerial = NULL; sl = malloc(sizeof (stlink_t)); slu = malloc(sizeof (struct stlink_libusb)); @@ -580,50 +747,74 @@ stlink_t* stlink_open_usb(const int verbose) { memset(sl, 0, sizeof (stlink_t)); memset(slu, 0, sizeof (struct stlink_libusb)); - sl->verbose = verbose; + ugly_init(verbose); sl->backend = &_stlink_usb_backend; sl->backend_data = slu; sl->core_stat = STLINK_CORE_STAT_UNKNOWN; - /* flash memory settings */ - sl->flash_base = STM32_FLASH_BASE; - sl->flash_size = STM32_FLASH_SIZE; - sl->flash_pgsz = STM32_FLASH_PGSZ; - - /* system memory */ - sl->sys_base = STM32_SYSTEM_BASE; - sl->sys_size = STM32_SYSTEM_SIZE; - - /* sram memory settings */ - sl->sram_base = STM32_SRAM_BASE; - sl->sram_size = STM32L_SRAM_SIZE; - if (libusb_init(&(slu->libusb_ctx))) { - fprintf(stderr, "failed to init libusb context, wrong version of libraries?\n"); - goto on_error; + WLOG("failed to init libusb context, wrong version of libraries?\n"); + goto on_error; } - slu->usb_handle = libusb_open_device_with_vid_pid(slu->libusb_ctx, USB_ST_VID, USB_STLINK_32L_PID); - if (slu->usb_handle == NULL) { - // TODO - free usb context too... - free(slu); - fprintf(stderr, "Couldn't find any ST-Link/V2 devices"); - return NULL; + libusb_device **list; + int cnt = libusb_get_device_list(slu->libusb_ctx, &list); + struct libusb_device_descriptor desc; + int devBus =0; + int devAddr=0; + + char *device = getenv("STLINK_DEVICE"); + if (device) { + char *c = strchr(device,':'); + if (c==NULL) { + WLOG("STLINK_DEVICE must be : format\n"); + goto on_error; + } + devBus=atoi(device); + *c++=0; + devAddr=atoi(c); + ILOG("bus %03d dev %03d\n",devBus, devAddr); + } + while (cnt){ + 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) break; + if (desc.idProduct == USB_STLINK_PID) { + slu->protocoll = 1; + break; + } } + if (cnt < 0) { + WLOG ("Couldn't find %s ST-Link/V2 devices\n",(devBus && devAddr)?"matched":"any"); + goto on_error; + } else { + if( libusb_open(list[cnt], &slu->usb_handle) !=0){ + WLOG("Couldn't open ST-Link/V2 device %03d:%03d\n",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) - printf("libusb_detach_kernel_driver(() error %s\n", strerror(-r)); - goto on_libusb_error; + if (r<0) { + WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-r)); + goto on_libusb_error; + } } if (libusb_get_configuration(slu->usb_handle, &config)) { /* this may fail for a previous configured device */ - printf("libusb_get_configuration()\n"); + WLOG("libusb_get_configuration()\n"); goto on_libusb_error; } @@ -631,40 +822,52 @@ stlink_t* stlink_open_usb(const int verbose) { printf("setting new configuration (%d -> 1)\n", config); if (libusb_set_configuration(slu->usb_handle, 1)) { /* this may fail for a previous configured device */ - printf("libusb_set_configuration()\n"); + WLOG("libusb_set_configuration() failed\n"); goto on_libusb_error; } } if (libusb_claim_interface(slu->usb_handle, 0)) { - printf("libusb_claim_interface()\n"); + WLOG("libusb_claim_interface() failed\n"); goto on_libusb_error; } slu->req_trans = libusb_alloc_transfer(0); if (slu->req_trans == NULL) { - printf("libusb_alloc_transfer\n"); + WLOG("libusb_alloc_transfer failed\n"); goto on_libusb_error; } slu->rep_trans = libusb_alloc_transfer(0); if (slu->rep_trans == NULL) { - printf("libusb_alloc_transfer\n"); + WLOG("libusb_alloc_transfer failed\n"); goto on_libusb_error; } - + // TODO - could use the scanning techniq from stm8 code here... slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN; slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT; slu->sg_transfer_idx = 0; + // 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) { - printf("-- exit_dfu_mode\n"); + ILOG("-- exit_dfu_mode\n"); stlink_exit_dfu_mode(sl); } + + if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { + stlink_enter_swd_mode(sl); + } + + if (reset) { + stlink_reset(sl); + } + stlink_load_device_params(sl); stlink_version(sl); + error = 0; on_libusb_error: @@ -681,6 +884,8 @@ on_libusb_error: return sl; on_error: + if( slu->libusb_ctx) + libusb_exit(slu->libusb_ctx); if (sl != NULL) free(sl); if (slu != NULL) free(slu); return 0;