X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fusb_blaster%2Fusb_blaster.c;h=48534a26f78bc920bf00f91f296ba0c87865ea80;hp=3400ca58a39c4d2b747856fbbb972c3a354a24ff;hb=433333968079c69aede528e2fb30ab71ccb1f294;hpb=8890ce34696d2e6a18eeda4a410724d24ad57360 diff --git a/src/jtag/drivers/usb_blaster/usb_blaster.c b/src/jtag/drivers/usb_blaster/usb_blaster.c index 3400ca58a3..48534a26f7 100644 --- a/src/jtag/drivers/usb_blaster/usb_blaster.c +++ b/src/jtag/drivers/usb_blaster/usb_blaster.c @@ -4,6 +4,7 @@ * Inspired from original code from Kolja Waschk's USB-JTAG project * (http://www.ixo.de/info/usb_jtag/), and from openocd project. * + * Copyright (C) 2013 Franck Jullien franck.jullien@gmail.com * Copyright (C) 2012 Robert Jarzmik robert.jarzmik@free.fr * Copyright (C) 2011 Ali Lown ali@lown.me.uk * Copyright (C) 2009 Catalin Patulea cat@vv.carleton.ca @@ -19,6 +20,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * */ /* @@ -48,6 +52,16 @@ * | 6 MHz XTAL | | 24 MHz Osc. | * |_____________| |_____________| * + * USB-JTAG, Altera USB-Blaster II are typically implemented as a Cypress + * EZ-USB FX2LP followed by a CPLD. + * _____________ _________ + * | | | | + * USB__| EZ-USB FX2 |__| EPM570 |__JTAG (B_TDO,B_TDI,B_TMS,B_TCK) + * |_____________| |_________| + * __|__________ + * | | + * | 24 MHz XTAL | + * |_____________| */ #ifdef HAVE_CONFIG_H @@ -82,11 +96,23 @@ */ #define BUF_LEN 4096 +/* USB-Blaster II specific command */ +#define CMD_COPY_TDO_BUFFER 0x5F + +enum gpio_steer { + FIXED_0 = 0, + FIXED_1, + SRST, + TRST, +}; + struct ublast_info { - int pin6; - int pin8; + enum gpio_steer pin6; + enum gpio_steer pin8; int tms; int tdi; + bool trst_asserted; + bool srst_asserted; uint8_t buf[BUF_LEN]; int bufidx; @@ -94,6 +120,9 @@ struct ublast_info { struct ublast_lowlevel *drv; char *ublast_device_desc; uint16_t ublast_vid, ublast_pid; + uint16_t ublast_vid_uninit, ublast_pid_uninit; + int flags; + char *firmware_path; }; /* @@ -103,6 +132,10 @@ static struct ublast_info info = { .ublast_vid = 0x09fb, /* Altera */ .ublast_pid = 0x6001, /* USB-Blaster */ .lowlevel_name = NULL, + .srst_asserted = false, + .trst_asserted = false, + .pin6 = FIXED_1, + .pin8 = FIXED_1, }; /* @@ -114,11 +147,11 @@ struct drvs_map { }; static struct drvs_map lowlevel_drivers_map[] = { -#if BUILD_USB_BLASTER_LIBFTDI +#if BUILD_USB_BLASTER { .name = "ftdi", .drv_register = ublast_register_ftdi }, #endif -#if BUILD_USB_BLASTER_FTD2XX - { .name = "ftd2xx", .drv_register = ublast_register_ftd2xx }, +#if BUILD_USB_BLASTER_2 + { .name = "ublast2", .drv_register = ublast2_register_libusb }, #endif { NULL, NULL }, }; @@ -141,7 +174,7 @@ static int ublast_buf_read(uint8_t *buf, unsigned size, uint32_t *bytes_read) int ret = info.drv->read(info.drv, buf, size, bytes_read); char *str = hexdump(buf, *bytes_read); - DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str, + LOG_DEBUG_IO("(size=%d, buf=[%s]) -> %u", size, str, *bytes_read); free(str); return ret; @@ -152,7 +185,7 @@ static int ublast_buf_write(uint8_t *buf, int size, uint32_t *bytes_written) int ret = info.drv->write(info.drv, buf, size, bytes_written); char *str = hexdump(buf, *bytes_written); - DEBUG_JTAG_IO("(size=%d, buf=[%s]) -> %u", size, str, + LOG_DEBUG_IO("(size=%d, buf=[%s]) -> %u", size, str, *bytes_written); free(str); return ret; @@ -218,20 +251,6 @@ static void ublast_flush_buffer(void) #define SHMODE (1 << 7) #define READ_TDO (1 << 0) -/** - * ublast_reset - reset the JTAG device is possible - * @trst: 1 if TRST is to be asserted - * @srst: 1 if SRST is to be asserted - * - * This is not implemented yet. If pin6 or pin8 controlls the TRST/SRST, code - * should be added so that this function makes use of it. - */ -static void ublast_reset(int trst, int srst) -{ - DEBUG_JTAG_IO("TODO: ublast_reset(%d,%d) isn't implemented!", - trst, srst); -} - /** * ublast_queue_byte - queue one 'bitbang mode' byte for USB Blaster * @abyte: the byte to queue @@ -247,7 +266,29 @@ static void ublast_queue_byte(uint8_t abyte) info.buf[info.bufidx++] = abyte; if (nb_buf_remaining() == 0) ublast_flush_buffer(); - DEBUG_JTAG_IO("(byte=0x%02x)", abyte); + LOG_DEBUG_IO("(byte=0x%02x)", abyte); +} + +/** + * ublast_compute_pin - compute if gpio should be asserted + * @steer: control (ie. TRST driven, SRST driven, of fixed) + * + * Returns pin value (1 means driven high, 0 mean driven low) + */ +bool ublast_compute_pin(enum gpio_steer steer) +{ + switch (steer) { + case FIXED_0: + return 0; + case FIXED_1: + return 1; + case SRST: + return !info.srst_asserted; + case TRST: + return !info.trst_asserted; + default: + return 1; + } } /** @@ -261,8 +302,8 @@ static uint8_t ublast_build_out(enum scan_type type) uint8_t abyte = 0; abyte |= info.tms ? TMS : 0; - abyte |= info.pin6 ? NCE : 0; - abyte |= info.pin8 ? NCS : 0; + abyte |= ublast_compute_pin(info.pin6) ? NCE : 0; + abyte |= ublast_compute_pin(info.pin8) ? NCS : 0; abyte |= info.tdi ? TDI : 0; abyte |= LED; if (type == SCAN_IN || type == SCAN_IO) @@ -270,6 +311,22 @@ static uint8_t ublast_build_out(enum scan_type type) return abyte; } +/** + * ublast_reset - reset the JTAG device is possible + * @trst: 1 if TRST is to be asserted + * @srst: 1 if SRST is to be asserted + */ +static void ublast_reset(int trst, int srst) +{ + uint8_t out_value; + + info.trst_asserted = trst; + info.srst_asserted = srst; + out_value = ublast_build_out(SCAN_OUT); + ublast_queue_byte(out_value); + ublast_flush_buffer(); +} + /** * ublast_clock_tms - clock a TMS transition * @tms: the TMS to be sent @@ -280,7 +337,7 @@ static void ublast_clock_tms(int tms) { uint8_t out; - DEBUG_JTAG_IO("(tms=%d)", !!tms); + LOG_DEBUG_IO("(tms=%d)", !!tms); info.tms = !!tms; info.tdi = 0; out = ublast_build_out(SCAN_OUT); @@ -297,7 +354,7 @@ static void ublast_idle_clock(void) { uint8_t out = ublast_build_out(SCAN_OUT); - DEBUG_JTAG_IO("."); + LOG_DEBUG_IO("."); ublast_queue_byte(out); } @@ -318,7 +375,7 @@ static void ublast_clock_tdi(int tdi, enum scan_type type) { uint8_t out; - DEBUG_JTAG_IO("(tdi=%d)", !!tdi); + LOG_DEBUG_IO("(tdi=%d)", !!tdi); info.tdi = !!tdi; out = ublast_build_out(SCAN_OUT); @@ -343,7 +400,7 @@ static void ublast_clock_tdi_flip_tms(int tdi, enum scan_type type) { uint8_t out; - DEBUG_JTAG_IO("(tdi=%d)", !!tdi); + LOG_DEBUG_IO("(tdi=%d)", !!tdi); info.tdi = !!tdi; info.tms = !info.tms; @@ -373,7 +430,7 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) info.bufidx + nb_bytes); exit(-1); } - DEBUG_JTAG_IO("(nb_bytes=%d, bytes=[0x%02x, ...])", nb_bytes, + LOG_DEBUG_IO("(nb_bytes=%d, bytes=[0x%02x, ...])", nb_bytes, bytes ? bytes[0] : 0); if (bytes) memcpy(&info.buf[info.bufidx], bytes, nb_bytes); @@ -388,6 +445,7 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) * ublast_tms_seq - write a TMS sequence transition to JTAG * @bits: TMS bits to be written (bit0, bit1 .. bitN) * @nb_bits: number of TMS bits (between 1 and 8) + * @skip: number of TMS bits to skip at the beginning of the series * * Write a serie of TMS transitions, where each transition consists in : * - writing out TCK=0, TMS=, TDI= @@ -395,12 +453,12 @@ static void ublast_queue_bytes(uint8_t *bytes, int nb_bytes) * The function ensures that at the end of the sequence, the clock (TCK) is put * low. */ -static void ublast_tms_seq(const uint8_t *bits, int nb_bits) +static void ublast_tms_seq(const uint8_t *bits, int nb_bits, int skip) { int i; - DEBUG_JTAG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits); - for (i = 0; i < nb_bits; i++) + LOG_DEBUG_IO("(bits=%02x..., nb_bits=%d)", bits[0], nb_bits); + for (i = skip; i < nb_bits; i++) ublast_clock_tms((bits[i / 8] >> (i % 8)) & 0x01); ublast_idle_clock(); } @@ -411,8 +469,8 @@ static void ublast_tms_seq(const uint8_t *bits, int nb_bits) */ static void ublast_tms(struct tms_command *cmd) { - DEBUG_JTAG_IO("(num_bits=%d)", cmd->num_bits); - ublast_tms_seq(cmd->bits, cmd->num_bits); + LOG_DEBUG_IO("(num_bits=%d)", cmd->num_bits); + ublast_tms_seq(cmd->bits, cmd->num_bits, 0); } /** @@ -429,7 +487,7 @@ static void ublast_path_move(struct pathmove_command *cmd) { int i; - DEBUG_JTAG_IO("(num_states=%d, last_state=%d)", + LOG_DEBUG_IO("(num_states=%d, last_state=%d)", cmd->num_states, cmd->path[cmd->num_states - 1]); for (i = 0; i < cmd->num_states; i++) { if (tap_state_transition(tap_get_state(), false) == cmd->path[i]) @@ -444,22 +502,23 @@ static void ublast_path_move(struct pathmove_command *cmd) /** * ublast_state_move - move JTAG state to the target state * @state: the target state + * @skip: number of bits to skip at the beginning of the path * * Input the correct TMS sequence to the JTAG TAP so that we end up in the * target state. This assumes the current state (tap_get_state()) is correct. */ -static void ublast_state_move(tap_state_t state) +static void ublast_state_move(tap_state_t state, int skip) { uint8_t tms_scan; int tms_len; - DEBUG_JTAG_IO("(from %s to %s)", tap_state_name(tap_get_state()), + LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()), tap_state_name(state)); if (tap_get_state() == state) return; tms_scan = tap_get_tms_path(tap_get_state(), state); tms_len = tap_get_tms_path_len(tap_get_state(), state); - ublast_tms_seq(&tms_scan, tms_len); + ublast_tms_seq(&tms_scan, tms_len, skip); tap_set_state(state); } @@ -482,7 +541,7 @@ static int ublast_read_byteshifted_tdos(uint8_t *buf, int nb_bytes) unsigned int retlen; int ret = ERROR_OK; - DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bytes * 8); + LOG_DEBUG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bytes * 8); ublast_flush_buffer(); while (ret == ERROR_OK && nb_bytes > 0) { ret = ublast_buf_read(buf, nb_bytes, &retlen); @@ -514,7 +573,7 @@ static int ublast_read_bitbang_tdos(uint8_t *buf, int nb_bits) unsigned int retlen; uint8_t tmp[8]; - DEBUG_JTAG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bits); + LOG_DEBUG_IO("%s(buf=%p, num_bits=%d)", __func__, buf, nb_bits); /* * Ensure all previous bitbang writes were issued to the dongle, so that @@ -594,8 +653,11 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) ublast_queue_bytes(&bits[i], trans); else ublast_queue_bytes(byte0, trans); - if (read_tdos) + if (read_tdos) { + if (info.flags & COPY_TDO_BUFFER) + ublast_queue_byte(CMD_COPY_TDO_BUFFER); ublast_read_byteshifted_tdos(&tdos[i], trans); + } } /* @@ -608,8 +670,11 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) else ublast_clock_tdi(tdi, scan); } - if (nb1 && read_tdos) + if (nb1 && read_tdos) { + if (info.flags & COPY_TDO_BUFFER) + ublast_queue_byte(CMD_COPY_TDO_BUFFER); ublast_read_bitbang_tdos(&tdos[nb8], nb1); + } if (bits) memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8)); @@ -623,16 +688,16 @@ static void ublast_queue_tdi(uint8_t *bits, int nb_bits, enum scan_type scan) static void ublast_runtest(int cycles, tap_state_t state) { - DEBUG_JTAG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); + LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state); - ublast_state_move(TAP_IDLE); + ublast_state_move(TAP_IDLE, 0); ublast_queue_tdi(NULL, cycles, SCAN_OUT); - ublast_state_move(state); + ublast_state_move(state, 0); } static void ublast_stableclocks(int cycles) { - DEBUG_JTAG_IO("%s(cycles=%i)", __func__, cycles); + LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles); ublast_queue_tdi(NULL, cycles, SCAN_OUT); } @@ -657,12 +722,12 @@ static int ublast_scan(struct scan_command *cmd) scan_bits = jtag_build_buffer(cmd, &buf); if (cmd->ir_scan) - ublast_state_move(TAP_IRSHIFT); + ublast_state_move(TAP_IRSHIFT, 0); else - ublast_state_move(TAP_DRSHIFT); + ublast_state_move(TAP_DRSHIFT, 0); log_buf = hexdump(buf, DIV_ROUND_UP(scan_bits, 8)); - DEBUG_JTAG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, + LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", __func__, cmd->ir_scan ? "IRSCAN" : "DRSCAN", type2str[type], scan_bits, log_buf, cmd->end_state); @@ -670,34 +735,59 @@ static int ublast_scan(struct scan_command *cmd) ublast_queue_tdi(buf, scan_bits, type); - /* - * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it - * forward to a stable IRPAUSE or DRPAUSE. - */ - ublast_clock_tms(0); - if (cmd->ir_scan) - tap_set_state(TAP_IRPAUSE); - else - tap_set_state(TAP_DRPAUSE); - ret = jtag_read_buffer(buf, cmd); if (buf) free(buf); - ublast_state_move(cmd->end_state); + /* + * ublast_queue_tdi sends the last bit with TMS=1. We are therefore + * already in Exit1-DR/IR and have to skip the first step on our way + * to end_state. + */ + ublast_state_move(cmd->end_state, 1); return ret; } -static void ublast_msleep(int ms) +static void ublast_usleep(int us) { - DEBUG_JTAG_IO("%s(ms=%d)", __func__, ms); - jtag_sleep(ms); + LOG_DEBUG_IO("%s(us=%d)", __func__, us); + jtag_sleep(us); +} + +static void ublast_initial_wipeout(void) +{ + static uint8_t tms_reset = 0xff; + uint8_t out_value; + uint32_t retlen; + int i; + + out_value = ublast_build_out(SCAN_OUT); + for (i = 0; i < BUF_LEN; i++) + info.buf[i] = out_value | ((i % 2) ? TCK : 0); + + /* + * Flush USB-Blaster queue fifos + * - empty the write FIFO (128 bytes) + * - empty the read FIFO (384 bytes) + */ + ublast_buf_write(info.buf, BUF_LEN, &retlen); + /* + * Put JTAG in RESET state (five 1 on TMS) + */ + ublast_tms_seq(&tms_reset, 5, 0); + tap_set_state(TAP_RESET); } static int ublast_execute_queue(void) { struct jtag_command *cmd; + static int first_call = 1; int ret = ERROR_OK; + if (first_call) { + first_call--; + ublast_initial_wipeout(); + } + for (cmd = jtag_command_queue; ret == ERROR_OK && cmd != NULL; cmd = cmd->next) { switch (cmd->type) { @@ -712,7 +802,7 @@ static int ublast_execute_queue(void) ublast_stableclocks(cmd->cmd.stableclocks->num_cycles); break; case JTAG_TLR_RESET: - ublast_state_move(cmd->cmd.statemove->end_state); + ublast_state_move(cmd->cmd.statemove->end_state, 0); break; case JTAG_PATHMOVE: ublast_path_move(cmd->cmd.pathmove); @@ -721,11 +811,16 @@ static int ublast_execute_queue(void) ublast_tms(cmd->cmd.tms); break; case JTAG_SLEEP: - ublast_msleep(cmd->cmd.sleep->us); + ublast_usleep(cmd->cmd.sleep->us); break; case JTAG_SCAN: ret = ublast_scan(cmd->cmd.scan); break; + default: + LOG_ERROR("BUG: unknown JTAG command type 0x%X", + cmd->type); + ret = ERROR_FAIL; + break; } } @@ -738,57 +833,60 @@ static int ublast_execute_queue(void) * * Initialize the device : * - open the USB device - * - empty the write FIFO (128 bytes) - * - empty the read FIFO (384 bytes) + * - pretend it's initialized while actual init is delayed until first jtag command * * Returns ERROR_OK if USB device found, error if not. */ static int ublast_init(void) { - static uint8_t tms_reset = 0xff; int ret, i; - if (info.lowlevel_name) { - for (i = 0; lowlevel_drivers_map[i].name; i++) - if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name)) + for (i = 0; lowlevel_drivers_map[i].name; i++) { + if (info.lowlevel_name) { + if (!strcmp(lowlevel_drivers_map[i].name, info.lowlevel_name)) { + info.drv = lowlevel_drivers_map[i].drv_register(); + if (!info.drv) { + LOG_ERROR("Error registering lowlevel driver \"%s\"", + info.lowlevel_name); + return ERROR_JTAG_DEVICE_ERROR; + } break; - if (lowlevel_drivers_map[i].name) - info.drv = lowlevel_drivers_map[i].drv_register(); - if (!info.drv) { - LOG_ERROR("no lowlevel driver found for %s or lowlevel driver opening error", - info.lowlevel_name); - return ERROR_JTAG_DEVICE_ERROR; - } - } else { - LOG_INFO("No lowlevel driver configured, will try them all"); - for (i = 0; !info.drv && lowlevel_drivers_map[i].name; i++) + } + } else { info.drv = lowlevel_drivers_map[i].drv_register(); - if (!info.drv) { - LOG_ERROR("no lowlevel driver found"); - return ERROR_JTAG_DEVICE_ERROR; + if (info.drv) { + info.lowlevel_name = strdup(lowlevel_drivers_map[i].name); + LOG_INFO("No lowlevel driver configured, using %s", info.lowlevel_name); + break; + } } } + if (!info.drv) { + LOG_ERROR("No lowlevel driver available"); + return ERROR_JTAG_DEVICE_ERROR; + } + /* * Register the lowlevel driver */ info.drv->ublast_vid = info.ublast_vid; info.drv->ublast_pid = info.ublast_pid; + info.drv->ublast_vid_uninit = info.ublast_vid_uninit; + info.drv->ublast_pid_uninit = info.ublast_pid_uninit; info.drv->ublast_device_desc = info.ublast_device_desc; + info.drv->firmware_path = info.firmware_path; + + info.flags |= info.drv->flags; ret = info.drv->open(info.drv); - if (ret == ERROR_OK) { - /* - * Flush USB-Blaster queue fifos - */ - uint32_t retlen; - ublast_buf_write(info.buf, BUF_LEN, &retlen); - /* - * Put JTAG in RESET state (five 1 on TMS) - */ - ublast_tms_seq(&tms_reset, 5); - tap_set_state(TAP_RESET); - } + + /* + * Let lie here : the TAP is in an unknown state, but the first + * execute_queue() will trigger a ublast_initial_wipeout(), which will + * put the TAP in RESET. + */ + tap_set_state(TAP_RESET); return ret; } @@ -812,53 +910,93 @@ static int ublast_quit(void) COMMAND_HANDLER(ublast_handle_device_desc_command) { - if (CMD_ARGC == 1) - info.ublast_device_desc = strdup(CMD_ARGV[0]); - else - LOG_ERROR("require exactly one argument to " - "ublast_device_desc "); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + info.ublast_device_desc = strdup(CMD_ARGV[0]); return ERROR_OK; } COMMAND_HANDLER(ublast_handle_vid_pid_command) { - if (CMD_ARGC > 2) { + if (CMD_ARGC > 4) { LOG_WARNING("ignoring extra IDs in ublast_vid_pid " - "(maximum is 1 pair)"); - CMD_ARGC = 2; + "(maximum is 2 pairs)"); + CMD_ARGC = 4; } - if (CMD_ARGC == 2) { + + if (CMD_ARGC >= 2) { COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], info.ublast_vid); COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], info.ublast_pid); } else { LOG_WARNING("incomplete ublast_vid_pid configuration"); } + if (CMD_ARGC == 4) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], info.ublast_vid_uninit); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], info.ublast_pid_uninit); + } else { + LOG_WARNING("incomplete ublast_vid_pid configuration"); + } + return ERROR_OK; } COMMAND_HANDLER(ublast_handle_pin_command) { uint8_t out_value; + const char * const pin_name = CMD_ARGV[0]; + enum gpio_steer *steer = NULL; + static const char * const pin_val_str[] = { + [FIXED_0] = "0", + [FIXED_1] = "1", + [SRST] = "SRST driven", + [TRST] = "TRST driven", + }; - if (CMD_ARGC == 2) { - const char * const pin_name = CMD_ARGV[0]; - unsigned int state; + if (CMD_ARGC > 2) { + LOG_ERROR("%s takes exactly one or two arguments", CMD_NAME); + return ERROR_COMMAND_SYNTAX_ERROR; + } - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], state); - if ((state != 0) && (state != 1)) { - LOG_ERROR("%s: pin state must be 0 or 1", CMD_NAME); - return ERROR_COMMAND_SYNTAX_ERROR; - } + if (!strcmp(pin_name, "pin6")) + steer = &info.pin6; + if (!strcmp(pin_name, "pin8")) + steer = &info.pin8; + if (!steer) { + LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"", + CMD_NAME); + return ERROR_COMMAND_SYNTAX_ERROR; + } - if (!strcmp(pin_name, "pin6")) { - info.pin6 = state; - } else if (!strcmp(pin_name, "pin8")) { - info.pin8 = state; - } else { - LOG_ERROR("%s: pin name must be \"pin6\" or \"pin8\"", - CMD_NAME); + if (CMD_ARGC == 1) { + LOG_INFO("%s: %s is set as %s\n", CMD_NAME, pin_name, + pin_val_str[*steer]); + } + + if (CMD_ARGC == 2) { + const char * const pin_value = CMD_ARGV[1]; + char val = pin_value[0]; + + if (strlen(pin_value) > 1) + val = '?'; + switch (tolower((unsigned char)val)) { + case '0': + *steer = FIXED_0; + break; + case '1': + *steer = FIXED_1; + break; + case 't': + *steer = TRST; + break; + case 's': + *steer = SRST; + break; + default: + LOG_ERROR("%s: pin value must be 0, 1, s (SRST) or t (TRST)", + pin_value); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -867,23 +1005,31 @@ COMMAND_HANDLER(ublast_handle_pin_command) ublast_queue_byte(out_value); ublast_flush_buffer(); } - return ERROR_OK; - } else { - LOG_ERROR("%s takes exactly two arguments", CMD_NAME); - return ERROR_COMMAND_SYNTAX_ERROR; } + return ERROR_OK; } COMMAND_HANDLER(ublast_handle_lowlevel_drv_command) { - if (CMD_ARGC == 1) - info.lowlevel_name = strdup(CMD_ARGV[0]); - else - LOG_ERROR("require exactly one argument to " - "usb_blaster_lowlevel_driver (ftdi|ftd2xx)"); + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + info.lowlevel_name = strdup(CMD_ARGV[0]); + return ERROR_OK; } +COMMAND_HANDLER(ublast_firmware_command) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + info.firmware_path = strdup(CMD_ARGV[0]); + + return ERROR_OK; +} + + static const struct command_registration ublast_command_handlers[] = { { .name = "usb_blaster_device_desc", @@ -896,28 +1042,38 @@ static const struct command_registration ublast_command_handlers[] = { .name = "usb_blaster_vid_pid", .handler = ublast_handle_vid_pid_command, .mode = COMMAND_CONFIG, - .help = "the vendor ID and product ID of the USB-Blaster", - .usage = "vid pid", + .help = "the vendor ID and product ID of the USB-Blaster and " \ + "vendor ID and product ID of the uninitialized device " \ + "for USB-Blaster II", + .usage = "vid pid vid_uninit pid_uninit", }, { .name = "usb_blaster_lowlevel_driver", .handler = ublast_handle_lowlevel_drv_command, .mode = COMMAND_CONFIG, - .help = "set the lowlevel access for the USB Blaster (ftdi, ftd2xx)", - .usage = "(ftdi|ftd2xx)", + .help = "set the lowlevel access for the USB Blaster (ftdi, ublast2)", + .usage = "(ftdi|ublast2)", }, { - .name = "usb_blaster", + .name = "usb_blaster_pin", .handler = ublast_handle_pin_command, .mode = COMMAND_ANY, - .help = "set pin state for the unused GPIO pins", - .usage = "(pin6|pin8) (0|1)", + .help = "show or set pin state for the unused GPIO pins", + .usage = "(pin6|pin8) (0|1|s|t)", + }, + { + .name = "usb_blaster_firmware", + .handler = &ublast_firmware_command, + .mode = COMMAND_CONFIG, + .help = "configure the USB-Blaster II firmware location", + .usage = "path/to/blaster_xxxx.hex", }, COMMAND_REGISTRATION_DONE }; struct jtag_interface usb_blaster_interface = { .name = "usb_blaster", + .transports = jtag_only, .commands = ublast_command_handlers, .supported = DEBUG_CAP_TMS_SEQ,