X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fstlink-sg.c;h=3d4a9b79882a9d3959732253b8d4dede9a82da27;hb=40c9d08c6072237b1fb0a8bc86668de81d9068b8;hp=64f182022da3cfdece24bc3951537b557d83436d;hpb=0f376a74a51cf3e3134b0e6f2ad0415f43968ed1;p=fw%2Fstlink diff --git a/src/stlink-sg.c b/src/stlink-sg.c index 64f1820..3d4a9b7 100644 --- a/src/stlink-sg.c +++ b/src/stlink-sg.c @@ -12,7 +12,6 @@ The stlink related constants kindly provided by Oliver Spencer (OpenOCD) for use in a GPL compatible license. - Code format ~ TAB = 8, K&R, linux kernel source, golang oriented Tested compatibility: linux, gcc >= 4.3.3 The communication is based on standard USB mass storage device @@ -31,10 +30,18 @@ CBW - Command Block Wrapper CSW - Command Status Wrapper RFU - Reserved for Future Use - scsi_pt - SCSI pass-through - sg - SCSI generic - * usb-storage.quirks + Originally, this driver used scsi pass through commands, which required the + usb-storage module to be loaded, providing the /dev/sgX links. The USB mass + storage implementation on the STLinkv1 is however terribly broken, and it can + take many minutes for the kernel to give up. + + However, in Nov 2011, the scsi pass through was replaced by raw libusb, so + instead of having to let usb-storage struggle with the device, and also greatly + limiting the portability of the driver, you can now tell usb-storage to simply + ignore this device completely. + + usb-storage.quirks http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding @@ -54,18 +61,17 @@ Example: quirks=0419:aaf5:rl,0421:0433:rc http://permalink.gmane.org/gmane.linux.usb.general/35053 + + For the stlinkv1, you just want the following - modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:l + modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i Equivalently, you can add a line saying - options usb-storage quirks=483:3744:l + options usb-storage quirks=483:3744:i to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..." part to an existing options line for usb-storage). - - https://wiki.kubuntu.org/Kernel/Debugging/USB explains the protocoll and - would allow to replace the sg access to pure libusb access */ @@ -91,14 +97,6 @@ #define WLOG(format, args...) ugly_log(UWARN, LOG_TAG, format, ## args) #define fatal(format, args...) ugly_log(UFATAL, LOG_TAG, format, ## args) -// Suspends execution of the calling process for -// (at least) ms milliseconds. - -static void delay(int ms) { - //fprintf(stderr, "*** wait %d ms\n", ms); - usleep(1000 * ms); -} - static void clear_cdb(struct stlink_libsg *sl) { for (size_t i = 0; i < sizeof (sl->cdb_cmd_blk); i++) sl->cdb_cmd_blk[i] = 0; @@ -107,113 +105,54 @@ static void clear_cdb(struct stlink_libsg *sl) { sl->q_data_dir = Q_DATA_IN; } -// E.g. make the valgrind happy. - -static void clear_buf(stlink_t *sl) { - DLOG("*** clear_buf ***\n"); - for (size_t i = 0; i < sizeof (sl->q_buf); i++) - sl->q_buf[i] = 0; - -} - -// close the device, free the allocated memory - -void _stlink_sg_close(stlink_t *sl) { +/** + * Close and free any _backend_ related information... + * @param sl + */void _stlink_sg_close(stlink_t *sl) { if (sl) { -#if FINISHED_WITH_SG struct stlink_libsg *slsg = sl->backend_data; - scsi_pt_close_device(slsg->sg_fd); + libusb_close(slsg->usb_handle); + libusb_exit(slsg->libusb_ctx); free(slsg); -#endif } } - -//TODO rewrite/cleanup, save the error in sl - -#if FINISHED_WITH_SG -static void stlink_confirm_inq(stlink_t *stl, struct sg_pt_base *ptvp) { - struct stlink_libsg *sl = stl->backend_data; - const int e = sl->do_scsi_pt_err; - if (e < 0) { - fprintf(stderr, "scsi_pt error: pass through os error: %s\n", - safe_strerror(-e)); - return; - } else if (e == SCSI_PT_DO_BAD_PARAMS) { - fprintf(stderr, "scsi_pt error: bad pass through setup\n"); - return; - } else if (e == SCSI_PT_DO_TIMEOUT) { - fprintf(stderr, " pass through timeout\n"); - return; +static int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag) +{ + unsigned char csw[13]; + memset(csw, 0, sizeof(csw)); + int transferred; + int ret; + int try = 0; + do { + ret = libusb_bulk_transfer(handle, endpoint, (unsigned char *)&csw, sizeof(csw), + &transferred, SG_TIMEOUT_MSEC); + if (ret == LIBUSB_ERROR_PIPE) { + libusb_clear_halt(handle, endpoint); + } + try++; + } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); + if (ret != LIBUSB_SUCCESS) { + WLOG("%s: receiving failed: %d\n", __func__, ret); + return -1; } - const int duration = get_scsi_pt_duration_ms(ptvp); - if ((stl->verbose > 1) && (duration >= 0)) - DLOG(" duration=%d ms\n", duration); - - // XXX stlink fw sends broken residue, so ignore it and use the known q_len - // "usb-storage quirks=483:3744:r" - // forces residue to be ignored and calculated, but this causes aboard if - // data_len = 0 and by some other data_len values. - - const int resid = get_scsi_pt_resid(ptvp); - const int dsize = stl->q_len - resid; - - const int cat = get_scsi_pt_result_category(ptvp); - char buf[512]; - unsigned int slen; - - switch (cat) { - case SCSI_PT_RESULT_GOOD: - if (stl->verbose && (resid > 0)) - DLOG(" notice: requested %d bytes but " - "got %d bytes, ignore [broken] residue = %d\n", - stl->q_len, dsize, resid); - break; - case SCSI_PT_RESULT_STATUS: - if (stl->verbose) { - sg_get_scsi_status_str( - get_scsi_pt_status_response(ptvp), sizeof (buf), - buf); - DLOG(" scsi status: %s\n", buf); - } - return; - case SCSI_PT_RESULT_SENSE: - slen = get_scsi_pt_sense_len(ptvp); - if (stl->verbose) { - sg_get_sense_str("", sl->sense_buf, slen, (stl->verbose - > 1), sizeof (buf), buf); - DLOG("%s", buf); - } - if (stl->verbose && (resid > 0)) { - if ((stl->verbose) || (stl->q_len > 0)) - DLOG(" requested %d bytes but " - "got %d bytes\n", stl->q_len, dsize); - } - return; - case SCSI_PT_RESULT_TRANSPORT_ERR: - if (stl->verbose) { - get_scsi_pt_transport_err_str(ptvp, sizeof (buf), buf); - // http://tldp.org/HOWTO/SCSI-Generic-HOWTO/x291.html - // These codes potentially come from the firmware on a host adapter - // or from one of several hosts that an adapter driver controls. - // The 'host_status' field has the following values: - // [0x07] Internal error detected in the host adapter. - // This may not be fatal (and the command may have succeeded). - DLOG(" transport: %s", buf); - } - return; - case SCSI_PT_RESULT_OS_ERR: - if (stl->verbose) { - get_scsi_pt_os_err_str(ptvp, sizeof (buf), buf); - DLOG(" os: %s", buf); - } - return; - default: - fprintf(stderr, " unknown pass through result " - "category (%d)\n", cat); + if (transferred != sizeof(csw)) { + WLOG("%s: received unexpected amount: %d\n", __func__, transferred); + return -1; + } + + uint32_t rsig = read_uint32(csw, 0); + uint32_t rtag = read_uint32(csw, 4); + /* uint32_t residue = read_uint32(csw, 8); */ +#define USB_CSW_SIGNATURE 0x53425355 // 'U' 'S' 'B' 'S' (reversed) + if (rsig != USB_CSW_SIGNATURE) { + WLOG("status signature was invalid: %#x\n", rsig); + return -1; } + *tag = rtag; + uint8_t rstatus = csw[12]; + return rstatus; } -#endif static int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) { char dbugblah[100]; @@ -274,11 +213,9 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint memcpy(&(c_buf[i]), cdb, cdb_length); int sending_length = STLINK_SG_SIZE; - DLOG("sending length set to: %d\n", sending_length); // send.... do { - DLOG("attempting tx...\n"); ret = libusb_bulk_transfer(handle, endpoint_out, c_buf, sending_length, &real_transferred, SG_TIMEOUT_MSEC); if (ret == LIBUSB_ERROR_PIPE) { @@ -290,50 +227,10 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint WLOG("sending failed: %d\n", ret); return -1; } - DLOG("Actually sent: %d, returning tag: %d\n", real_transferred, tag); return this_tag; } -static int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag) -{ - unsigned char csw[13]; - memset(csw, 0, sizeof(csw)); - int transferred; - int ret; - int try = 0; - do { - ret = libusb_bulk_transfer(handle, endpoint, (unsigned char *)&csw, sizeof(csw), - &transferred, SG_TIMEOUT_MSEC); - if (ret == LIBUSB_ERROR_PIPE) { - libusb_clear_halt(handle, endpoint); - } - try++; - } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); - if (ret != LIBUSB_SUCCESS) { - fprintf(stderr, "%s: receiving failed: %d\n", __func__, ret); - return -1; - } - if (transferred != sizeof(csw)) { - fprintf(stderr, "%s: received unexpected amount: %d\n", __func__, transferred); - return -1; - } - - uint32_t rsig = read_uint32(csw, 0); - uint32_t rtag = read_uint32(csw, 4); - uint32_t residue = read_uint32(csw, 8); -#define USB_CSW_SIGNATURE 0x53425355 // 'U' 'S' 'B' 'S' (reversed) - if (rsig != USB_CSW_SIGNATURE) { - WLOG("status signature was invalid: %#x\n", rsig); - return -1; - } - DLOG("residue was= %#x\n", residue); - *tag = rtag; - uint8_t rstatus = csw[12]; - DLOG("rstatus = %x\n", rstatus); - return rstatus; -} - /** * Straight from stm8 stlink code... * @param handle @@ -388,6 +285,54 @@ get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_ou } } +/** + * Just send a buffer on an endpoint, no questions asked. + * Handles repeats, and time outs. Also handles reading status reports and sense + * @param handle libusb device * + * @param endpoint_out sends + * @param endpoint_in used to read status reports back in + * @param cbuf what to send + * @param length how much to send + * @return number of bytes actually sent, or -1 for failures. + */ +int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out, + unsigned char endpoint_in, unsigned char *cbuf, unsigned int length) { + int ret; + int real_transferred; + int try = 0; + do { + ret = libusb_bulk_transfer(handle, endpoint_out, cbuf, length, + &real_transferred, SG_TIMEOUT_MSEC); + if (ret == LIBUSB_ERROR_PIPE) { + libusb_clear_halt(handle, endpoint_out); + } + try++; + } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); + if (ret != LIBUSB_SUCCESS) { + WLOG("sending failed: %d\n", ret); + return -1; + } + + // now, swallow up the status, so that things behave nicely... + uint32_t received_tag; + // -ve is for my errors, 0 is good, +ve is libusb sense status bytes + int status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag); + if (status < 0) { + WLOG("receiving status failed: %d\n", status); + return -1; + } + if (status != 0) { + WLOG("receiving status not passed :(: %02x\n", status); + } + if (status == 1) { + get_sense(handle, endpoint_in, endpoint_out); + return -1; + } + + return real_transferred; +} + + int stlink_q(stlink_t *sl) { struct stlink_libsg* sg = sl->backend_data; //uint8_t cdb_len = 6; // FIXME varies!!! @@ -405,7 +350,6 @@ int stlink_q(stlink_t *sl) { int ret; if (rx_length > 0) { do { - DLOG("attempting rx\n"); ret = libusb_bulk_transfer(sg->usb_handle, sg->ep_rep, sl->q_buf, rx_length, &real_transferred, SG_TIMEOUT_MSEC); if (ret == LIBUSB_ERROR_PIPE) { @@ -446,40 +390,6 @@ int stlink_q(stlink_t *sl) { return -1; } return 0; - - - DLOG("Actually received: %d\n", real_transferred); - -#if FINISHED_WITH_SG - // Get control command descriptor of scsi structure, - // (one object per command!!) - struct sg_pt_base *ptvp = construct_scsi_pt_obj(); - if (NULL == ptvp) { - fprintf(stderr, "construct_scsi_pt_obj: out of memory\n"); - return; - } - - set_scsi_pt_cdb(ptvp, sg->cdb_cmd_blk, sizeof (sg->cdb_cmd_blk)); - - // set buffer for sense (error information) data - set_scsi_pt_sense(ptvp, sg->sense_buf, sizeof (sg->sense_buf)); - - // Set a buffer to be used for data transferred from device - if (sg->q_data_dir == Q_DATA_IN) { - //clear_buf(sl); - set_scsi_pt_data_in(ptvp, sl->q_buf, sl->q_len); - } else { - set_scsi_pt_data_out(ptvp, sl->q_buf, sl->q_len); - } - // Executes SCSI command (or at least forwards it to lower layers). - sg->do_scsi_pt_err = do_scsi_pt(ptvp, sg->sg_fd, SG_TIMEOUT_SEC, - sl->verbose); - - // check for scsi errors - stlink_confirm_inq(sl, ptvp); - // TODO recycle: clear_scsi_pt_obj(struct sg_pt_base * objp); - destruct_scsi_pt_obj(ptvp); -#endif } // TODO thinking, cleanup @@ -505,14 +415,11 @@ void stlink_stat(stlink_t *stl, char *txt) { void _stlink_sg_version(stlink_t *stl) { struct stlink_libsg *sl = stl->backend_data; - DLOG("\n*** stlink_version ***\n"); clear_cdb(sl); sl->cdb_cmd_blk[0] = STLINK_GET_VERSION; stl->q_len = 6; sl->q_addr = 0; stlink_q(stl); - // HACK use my own private version right now... - } // Get stlink mode: @@ -554,7 +461,7 @@ void _stlink_sg_enter_jtag_mode(stlink_t *sl) { } // XXX kernel driver performs reset, the device temporally disappears - +// Suspect this is no longer the case when we have ignore on? RECHECK void _stlink_sg_exit_dfu_mode(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; DLOG("\n*** stlink_exit_dfu_mode ***\n"); @@ -630,11 +537,23 @@ void _stlink_sg_reset(stlink_t *sl) { stlink_stat(sl, "core reset"); } +// Arm-core reset -> halted state. + +void _stlink_sg_jtag_reset(stlink_t *sl, int value) { + struct stlink_libsg *sg = sl->backend_data; + clear_cdb(sg); + sg->cdb_cmd_blk[1] = STLINK_JTAG_DRIVE_NRST; + sg->cdb_cmd_blk[2] = (value)?0:1; + sl->q_len = 3; + sg->q_addr = 2; + stlink_q(sl); + stlink_stat(sl, "core reset"); +} + // Arm-core status: halted or running. void _stlink_sg_status(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; - DLOG("\n*** stlink_status ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_GETSTATUS; sl->q_len = 2; @@ -646,7 +565,6 @@ void _stlink_sg_status(stlink_t *sl) { void _stlink_sg_force_debug(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; - DLOG("\n*** stlink_force_debug ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_FORCEDEBUG; sl->q_len = 2; @@ -660,9 +578,6 @@ void _stlink_sg_force_debug(stlink_t *sl) { void _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) { struct stlink_libsg *sg = sl->backend_data; - /* unused */ - regp = regp; - clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_READALLREGS; sl->q_len = 84; @@ -675,23 +590,23 @@ void _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) { // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83 // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 for (int i = 0; i < 16; i++) { - sg->reg.r[i] = read_uint32(sl->q_buf, 4 * i); + regp->r[i] = read_uint32(sl->q_buf, 4 * i); if (sl->verbose > 1) - DLOG("r%2d = 0x%08x\n", i, sg->reg.r[i]); + DLOG("r%2d = 0x%08x\n", i, regp->r[i]); } - sg->reg.xpsr = read_uint32(sl->q_buf, 64); - sg->reg.main_sp = read_uint32(sl->q_buf, 68); - sg->reg.process_sp = read_uint32(sl->q_buf, 72); - sg->reg.rw = read_uint32(sl->q_buf, 76); - sg->reg.rw2 = read_uint32(sl->q_buf, 80); + regp->xpsr = read_uint32(sl->q_buf, 64); + regp->main_sp = read_uint32(sl->q_buf, 68); + regp->process_sp = read_uint32(sl->q_buf, 72); + regp->rw = read_uint32(sl->q_buf, 76); + regp->rw2 = read_uint32(sl->q_buf, 80); if (sl->verbose < 2) return; - DLOG("xpsr = 0x%08x\n", sg->reg.xpsr); - DLOG("main_sp = 0x%08x\n", sg->reg.main_sp); - DLOG("process_sp = 0x%08x\n", sg->reg.process_sp); - DLOG("rw = 0x%08x\n", sg->reg.rw); - DLOG("rw2 = 0x%08x\n", sg->reg.rw2); + DLOG("xpsr = 0x%08x\n", regp->xpsr); + DLOG("main_sp = 0x%08x\n", regp->main_sp); + DLOG("process_sp = 0x%08x\n", regp->process_sp); + DLOG("rw = 0x%08x\n", regp->rw); + DLOG("rw2 = 0x%08x\n", regp->rw2); } // Read an arm-core register, the index must be in the range 0..20. @@ -776,7 +691,6 @@ void stlink_write_dreg(stlink_t *sl, uint32_t reg, uint32_t addr) { void _stlink_sg_run(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; - DLOG("\n*** stlink_run ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_RUNCORE; sl->q_len = 2; @@ -865,11 +779,10 @@ void _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint16(sg->cdb_cmd_blk + 6, len); - // data_out 0-len - sl->q_len = len; - sg->q_addr = addr; - sg->q_data_dir = Q_DATA_OUT; - stlink_q(sl); + // this sends the command... + send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0); + // This sends the data... + send_usb_data_only(sg->usb_handle, sg->ep_req, sg->ep_rep, sl->q_buf, len); stlink_print_data(sl); } @@ -884,46 +797,41 @@ void _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint16(sg->cdb_cmd_blk + 6, len); - // data_out 0-0x40-...-len - sl->q_len = len; - sg->q_addr = addr; - sg->q_data_dir = Q_DATA_OUT; - stlink_q(sl); + // this sends the command... + send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0); + // This sends the data... + send_usb_data_only(sg->usb_handle, sg->ep_req, sg->ep_rep, sl->q_buf, len); + stlink_print_data(sl); } -#if 0 /* not working */ - -static int write_flash_mem16 -(struct stlink* sl, uint32_t addr, uint16_t val) { - /* half word writes */ - if (addr % 2) return -1; - - /* unlock if locked */ - unlock_flash_if(sl); - - /* set flash programming chosen bit */ - set_flash_cr_pg(sl); +// Write one DWORD data to memory - write_uint16(sl->q_buf, val); - stlink_write_mem16(sl, addr, 2); +void _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { + struct stlink_libsg *sg = sl->backend_data; + clear_cdb(sg); + sg->cdb_cmd_blk[1] = STLINK_JTAG_WRITEDEBUG_32BIT; + // 2-5: addr + write_uint32(sg->cdb_cmd_blk + 2, addr); + write_uint32(sg->cdb_cmd_blk + 6, data); + sl->q_len = 2; + stlink_q(sl); - /* wait for non business */ - wait_flash_busy(sl); +} - lock_flash(sl); +// Read one DWORD data from memory - /* check the programmed value back */ - stlink_read_mem16(sl, addr, 2); - if (*(const uint16_t*) sl->q_buf != val) { - /* values differ at i * sizeof(uint16_t) */ - return -1; - } +uint32_t _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr) { + struct stlink_libsg *sg = sl->backend_data; + clear_cdb(sg); + sg->cdb_cmd_blk[1] = STLINK_JTAG_READDEBUG_32BIT; + // 2-5: addr + write_uint32(sg->cdb_cmd_blk + 2, addr); + sl->q_len = 8; + stlink_q(sl); - /* success */ - return 0; + return read_uint32(sl->q_buf, 4); } -#endif /* not working */ // Exit the jtag or swd mode and enter the mass mode. @@ -953,10 +861,13 @@ stlink_backend_t _stlink_sg_backend = { _stlink_sg_exit_dfu_mode, _stlink_sg_core_id, _stlink_sg_reset, + _stlink_sg_jtag_reset, _stlink_sg_run, _stlink_sg_status, _stlink_sg_version, + _stlink_sg_read_debug32, _stlink_sg_read_mem32, + _stlink_sg_write_debug32, _stlink_sg_write_mem32, _stlink_sg_write_mem8, _stlink_sg_read_all_regs, @@ -970,6 +881,7 @@ stlink_backend_t _stlink_sg_backend = { static stlink_t* stlink_open(const int verbose) { stlink_t *sl = malloc(sizeof (stlink_t)); + memset(sl, 0, sizeof(stlink_t)); struct stlink_libsg *slsg = malloc(sizeof (struct stlink_libsg)); if (sl == NULL || slsg == NULL) { WLOG("Couldn't malloc stlink and stlink_sg structures out of memory!\n"); @@ -989,6 +901,7 @@ static stlink_t* stlink_open(const int verbose) { if (slsg->usb_handle == NULL) { WLOG("Failed to find an stlink v1 by VID:PID\n"); libusb_close(slsg->usb_handle); + libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return NULL; @@ -1003,6 +916,7 @@ static stlink_t* stlink_open(const int verbose) { if (r < 0) { WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-r)); libusb_close(slsg->usb_handle); + libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return NULL; @@ -1015,6 +929,7 @@ static stlink_t* stlink_open(const int verbose) { /* this may fail for a previous configured device */ WLOG("libusb_get_configuration()\n"); libusb_close(slsg->usb_handle); + libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return NULL; @@ -1029,6 +944,7 @@ static stlink_t* stlink_open(const int verbose) { /* this may fail for a previous configured device */ WLOG("libusb_set_configuration() failed\n"); libusb_close(slsg->usb_handle); + libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return NULL; @@ -1038,6 +954,7 @@ static stlink_t* stlink_open(const int verbose) { if (libusb_claim_interface(slsg->usb_handle, 0)) { WLOG("libusb_claim_interface() failed\n"); libusb_close(slsg->usb_handle); + libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return NULL; @@ -1055,27 +972,12 @@ static stlink_t* stlink_open(const int verbose) { sl->core_stat = STLINK_CORE_STAT_UNKNOWN; slsg->q_addr = 0; - clear_buf(sl); - - /* 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 = STM32_SRAM_SIZE; return sl; } - -stlink_t* stlink_v1_open(const int verbose) { +stlink_t* stlink_v1_open_inner(const int verbose) { ugly_init(verbose); stlink_t *sl = stlink_open(verbose); if (sl == NULL) { @@ -1084,7 +986,6 @@ stlink_t* stlink_v1_open(const int verbose) { } stlink_version(sl); - if ((sl->version.st_vid != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) { ugly_log(UERROR, LOG_TAG, "WTF? successfully opened, but unable to read version details. BROKEN!\n"); @@ -1093,44 +994,41 @@ stlink_t* stlink_v1_open(const int verbose) { DLOG("Reading current mode...\n"); switch (stlink_current_mode(sl)) { - case STLINK_DEV_MASS_MODE: - return sl; - case STLINK_DEV_DEBUG_MODE: - // TODO go to mass? + case STLINK_DEV_MASS_MODE: return sl; + case STLINK_DEV_DEBUG_MODE: + // TODO go to mass? + return sl; + default: + ILOG("Current mode unusable, trying to get back to a useful state...\n"); + break; } DLOG("Attempting to exit DFU mode\n"); _stlink_sg_exit_dfu_mode(sl); - // exit the dfu mode -> the device is gone - DLOG("\n*** reopen the stlink device ***\n"); - delay(1000); - stlink_close(sl); - delay(5000); - - DLOG("Attempting to reopen the stlink...\n"); - sl = stlink_open(verbose); - if (sl == NULL) { - fputs("Error: could not open stlink device\n", stderr); + // re-query device info (and retest) + stlink_version(sl); + if ((sl->version.st_vid != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) { + ugly_log(UERROR, LOG_TAG, + "WTF? successfully opened, but unable to read version details. BROKEN!\n"); return NULL; } - // re-query device info - stlink_version(sl); + return sl; } -static void __attribute__((unused)) mark_buf(stlink_t *sl) { - clear_buf(sl); - sl->q_buf[0] = 0x12; - sl->q_buf[1] = 0x34; - sl->q_buf[2] = 0x56; - sl->q_buf[3] = 0x78; - sl->q_buf[4] = 0x90; - sl->q_buf[15] = 0x42; - sl->q_buf[16] = 0x43; - sl->q_buf[63] = 0x42; - sl->q_buf[64] = 0x43; - sl->q_buf[1024 * 6 - 1] = 0x42; //6kB - sl->q_buf[1024 * 8 - 1] = 0x42; //8kB +stlink_t* stlink_v1_open(const int verbose) { + stlink_t *sl = stlink_v1_open_inner(verbose); + if (sl == NULL) { + fputs("Error: could not open stlink device\n", stderr); + return NULL; + } + // by now, it _must_ be fully open and in a useful mode.... + stlink_enter_swd_mode(sl); + /* Now we are ready to read the parameters */ + stlink_reset(sl); + stlink_load_device_params(sl); + ILOG("Successfully opened a stlink v1 debugger\n"); + return sl; }