X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fjtag%2Fdrivers%2Fjlink.c;h=e5bfd322fa2f2597e9cf3f6671126bfec1db9bc8;hp=e93a3c12d0ca14c88256463632599fb36ad1c91f;hb=2e0e11b76645d6b38bc4986d8000e4e47e391596;hpb=ae8cdc139e12a851107e8f882c5a166a21103ad4 diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index e93a3c12d0..e5bfd322fa 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -25,8 +25,7 @@ * 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, write to the * - * Free Software Foundation, Inc., * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -51,9 +50,9 @@ static uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE]; static uint32_t serial_number; static bool use_serial_number; -static uint8_t usb_address; +static enum jaylink_usb_address usb_address; static bool use_usb_address; -static uint8_t iface = JAYLINK_TIF_JTAG; +static enum jaylink_target_interface iface = JAYLINK_TIF_JTAG; static bool trace_enabled; #define JLINK_MAX_SPEED 12000 @@ -218,7 +217,7 @@ static void jlink_execute_scan(struct jtag_command *cmd) field->num_bits - 1, 1); tap_set_state(tap_state_transition(tap_get_state(), 1)); - jlink_clock_data(&last_bit, + jlink_clock_data(NULL, 0, &tms_bits, 1, @@ -315,12 +314,11 @@ static int jlink_execute_queue(void) static int jlink_speed(int speed) { int ret; - uint32_t freq; - uint16_t divider; + struct jaylink_speed tmp; int max_speed; if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_SPEEDS)) { - ret = jaylink_get_speeds(devh, &freq, ÷r); + ret = jaylink_get_speeds(devh, &tmp); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_speeds() failed: %s.", @@ -328,8 +326,8 @@ static int jlink_speed(int speed) return ERROR_JTAG_DEVICE_ERROR; } - freq = freq / 1000; - max_speed = freq / divider; + tmp.freq /= 1000; + max_speed = tmp.freq / tmp.div; } else { max_speed = JLINK_MAX_SPEED; } @@ -420,7 +418,7 @@ static int select_interface(void) return ERROR_JTAG_INIT_FAILED; } - ret = jaylink_select_interface(devh, iface); + ret = jaylink_select_interface(devh, iface, NULL); if (ret < 0) { LOG_ERROR("jaylink_select_interface() failed: %s.", @@ -434,15 +432,16 @@ static int select_interface(void) static int jlink_register(void) { int ret; - int i; + size_t i; bool handle_found; + size_t count; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) return ERROR_OK; - ret = jaylink_register(devh, &conn, connlist, NULL, NULL); + ret = jaylink_register(devh, &conn, connlist, &count); - if (ret < 0) { + if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror_name(ret)); return ERROR_FAIL; @@ -450,7 +449,7 @@ static int jlink_register(void) handle_found = false; - for (i = 0; i < ret; i++) { + for (i = 0; i < count; i++) { if (connlist[i].handle == conn.handle) { handle_found = true; break; @@ -503,6 +502,36 @@ static bool adjust_swd_buffer_size(void) return true; } +static int jaylink_log_handler(const struct jaylink_context *ctx, + enum jaylink_log_level level, const char *format, va_list args, + void *user_data) +{ + enum log_levels tmp; + + switch (level) { + case JAYLINK_LOG_LEVEL_ERROR: + tmp = LOG_LVL_ERROR; + break; + case JAYLINK_LOG_LEVEL_WARNING: + tmp = LOG_LVL_WARNING; + break; + /* + * Forward info messages to the debug output because they are more verbose + * than info messages of OpenOCD. + */ + case JAYLINK_LOG_LEVEL_INFO: + case JAYLINK_LOG_LEVEL_DEBUG: + tmp = LOG_LVL_DEBUG; + break; + default: + tmp = LOG_LVL_WARNING; + } + + log_vprintf_lf(tmp, __FILE__, __LINE__, __func__, format, args); + + return 0; +} + static int jlink_init(void) { int ret; @@ -513,6 +542,8 @@ static int jlink_init(void) char *firmware_version; struct jaylink_hardware_version hwver; struct jaylink_hardware_status hwstatus; + enum jaylink_usb_address address; + size_t length; ret = jaylink_init(&jayctx); @@ -522,10 +553,28 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - ret = jaylink_get_device_list(jayctx, &devs); + ret = jaylink_log_set_callback(jayctx, &jaylink_log_handler, NULL); - if (ret < 0) { - LOG_ERROR("jaylink_get_device_list() failed: %s.", + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_log_set_callback() failed: %s.", + jaylink_strerror_name(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + ret = jaylink_discovery_scan(jayctx, 0); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_discovery_scan() failed: %s.", + jaylink_strerror_name(ret)); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } + + ret = jaylink_get_devices(jayctx, &devs, NULL); + + if (ret != JAYLINK_OK) { + LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror_name(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -537,27 +586,45 @@ static int jlink_init(void) LOG_INFO("No device selected, using first device."); for (i = 0; devs[i]; i++) { - jaylink_device_get_serial_number(devs[i], &tmp); - ret = jaylink_device_get_usb_address(devs[i]); + if (use_serial_number) { + ret = jaylink_device_get_serial_number(devs[i], &tmp); + + if (ret == JAYLINK_ERR_NOT_AVAILABLE) { + continue; + } else if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_serial_number() failed: %s.", + jaylink_strerror_name(ret)); + continue; + } + + if (serial_number != tmp) + continue; + } - if (use_usb_address && usb_address != ret) - continue; + if (use_usb_address) { + ret = jaylink_device_get_usb_address(devs[i], &address); - if (use_serial_number && tmp != serial_number) - continue; + if (ret != JAYLINK_OK) { + LOG_WARNING("jaylink_device_get_usb_address() failed: %s.", + jaylink_strerror_name(ret)); + continue; + } + + if (usb_address != address) + continue; + } ret = jaylink_open(devs[i], &devh); - if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret)); - continue; + if (ret == JAYLINK_OK) { + found_device = true; + break; } - found_device = true; - break; + LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret)); } - jaylink_free_device_list(devs, 1); + jaylink_free_devices(devs, true); if (!found_device) { LOG_ERROR("No J-Link device found."); @@ -570,19 +637,19 @@ static int jlink_init(void) * some devices are known to be sensitive regarding the order. */ - ret = jaylink_get_firmware_version(devh, &firmware_version); + ret = jaylink_get_firmware_version(devh, &firmware_version, &length); - if (ret > 0) { - LOG_INFO("%s", firmware_version); - free(firmware_version); - } else if (!ret) { - LOG_WARNING("Device responds empty firmware version string."); - } else { + if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_firmware_version() failed: %s.", jaylink_strerror_name(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; + } else if (length > 0) { + LOG_INFO("%s", firmware_version); + free(firmware_version); + } else { + LOG_WARNING("Device responds empty firmware version string."); } memset(caps, 0, JAYLINK_DEV_EXT_CAPS_SIZE); @@ -666,7 +733,7 @@ static int jlink_init(void) conn.handle = 0; conn.pid = 0; - conn.hid = 0; + strcpy(conn.hid, "0.0.0.0"); conn.iid = 0; conn.cid = 0; @@ -710,6 +777,7 @@ static int jlink_init(void) static int jlink_quit(void) { int ret; + size_t count; if (trace_enabled) { ret = jaylink_swo_stop(devh); @@ -720,9 +788,9 @@ static int jlink_quit(void) } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { - ret = jaylink_unregister(devh, &conn, connlist, NULL, NULL); + ret = jaylink_unregister(devh, &conn, connlist, &count); - if (ret < 0) + if (ret != JAYLINK_OK) LOG_ERROR("jaylink_unregister() failed: %s.", jaylink_strerror_name(ret)); } @@ -832,21 +900,25 @@ static void jlink_reset(int trst, int srst) COMMAND_HANDLER(jlink_usb_command) { + int tmp; + if (CMD_ARGC != 1) { command_print(CMD_CTX, "Need exactly one argument for jlink usb."); return ERROR_COMMAND_SYNTAX_ERROR; } - if (sscanf(CMD_ARGV[0], "%" SCNd8, &usb_address) != 1) { + if (sscanf(CMD_ARGV[0], "%i", &tmp) != 1) { command_print(CMD_CTX, "Invalid USB address: %s.", CMD_ARGV[0]); return ERROR_FAIL; } - if (usb_address > JAYLINK_USB_ADDRESS_3) { + if (tmp < JAYLINK_USB_ADDRESS_0 || tmp > JAYLINK_USB_ADDRESS_3) { command_print(CMD_CTX, "Invalid USB address: %s.", CMD_ARGV[0]); return ERROR_FAIL; } + usb_address = tmp; + use_serial_number = false; use_usb_address = true; @@ -855,14 +927,22 @@ COMMAND_HANDLER(jlink_usb_command) COMMAND_HANDLER(jlink_serial_command) { + int ret; + if (CMD_ARGC != 1) { command_print(CMD_CTX, "Need exactly one argument for jlink serial."); return ERROR_COMMAND_SYNTAX_ERROR; } - if (sscanf(CMD_ARGV[0], "%" SCNd32, &serial_number) != 1) { + ret = jaylink_parse_serial_number(CMD_ARGV[0], &serial_number); + + if (ret == JAYLINK_ERR) { command_print(CMD_CTX, "Invalid serial number: %s.", CMD_ARGV[0]); return ERROR_FAIL; + } else if (ret != JAYLINK_OK) { + command_print(CMD_CTX, "jaylink_parse_serial_number() failed: %s.", + jaylink_strerror_name(ret)); + return ERROR_FAIL; } use_serial_number = true; @@ -1133,15 +1213,17 @@ static uint32_t calculate_trace_buffer_size(void) return tmp & 0xffffff00; } -static bool check_trace_freq(uint32_t freq, uint32_t divider, uint32_t trace_freq) +static bool check_trace_freq(struct jaylink_swo_speed speed, + uint32_t trace_freq) { double min; double deviation; + uint32_t divider; - min = fabs(1.0 - (freq / ((double)trace_freq * divider))); + min = fabs(1.0 - (speed.freq / ((double)trace_freq * speed.min_div))); - while (freq / divider > 0) { - deviation = fabs(1.0 - (freq / ((double)trace_freq * divider))); + for (divider = speed.min_div; divider < speed.max_div; divider++) { + deviation = fabs(1.0 - (speed.freq / ((double)trace_freq * divider))); if (deviation < 0.03) { LOG_DEBUG("Found suitable frequency divider %u with deviation of " @@ -1151,8 +1233,6 @@ static bool check_trace_freq(uint32_t freq, uint32_t divider, uint32_t trace_fre if (deviation < min) min = deviation; - - divider++; } LOG_ERROR("Selected trace frequency is not supported by the device. " @@ -1168,8 +1248,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, { int ret; uint32_t buffer_size; - uint32_t freq; - uint32_t divider; + struct jaylink_swo_speed speed; if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SWO)) { LOG_ERROR("Trace capturing is not supported by the device."); @@ -1208,7 +1287,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, return ERROR_FAIL; } - ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &freq, ÷r); + ret = jaylink_swo_get_speeds(devh, JAYLINK_SWO_MODE_UART, &speed); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swo_get_speeds() failed: %s.", @@ -1217,9 +1296,9 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, } if (!*trace_freq) - *trace_freq = freq / divider; + *trace_freq = speed.freq / speed.min_div; - if (!check_trace_freq(freq, divider, *trace_freq)) + if (!check_trace_freq(speed, *trace_freq)) return ERROR_FAIL; LOG_DEBUG("Using %u bytes device memory for trace capturing.", buffer_size); @@ -1523,6 +1602,125 @@ COMMAND_HANDLER(jlink_handle_config_command) return ERROR_OK; } +COMMAND_HANDLER(jlink_handle_emucom_write_command) +{ + int ret; + size_t tmp; + uint32_t channel; + uint32_t length; + uint8_t *buf; + size_t dummy; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { + LOG_ERROR("Device does not support EMUCOM."); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel); + + tmp = strlen(CMD_ARGV[1]); + + if (tmp % 2 != 0) { + LOG_ERROR("Data must be encoded as hexadecimal pairs."); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + buf = malloc(tmp / 2); + + if (!buf) { + LOG_ERROR("Failed to allocate buffer."); + return ERROR_FAIL; + } + + dummy = unhexify(buf, CMD_ARGV[1], tmp / 2); + + if (dummy != (tmp / 2)) { + LOG_ERROR("Data must be encoded as hexadecimal pairs."); + free(buf); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + length = tmp / 2; + ret = jaylink_emucom_write(devh, channel, buf, &length); + + free(buf); + + if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { + LOG_ERROR("Channel not supported by the device."); + return ERROR_FAIL; + } else if (ret != JAYLINK_OK) { + LOG_ERROR("Failed to write to channel: %s.", + jaylink_strerror_name(ret)); + return ERROR_FAIL; + } + + if (length != (tmp / 2)) + LOG_WARNING("Only %" PRIu32 " bytes written to the channel.", length); + + return ERROR_OK; +} + +COMMAND_HANDLER(jlink_handle_emucom_read_command) +{ + int ret; + uint32_t channel; + uint32_t length; + uint8_t *buf; + size_t tmp; + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_EMUCOM)) { + LOG_ERROR("Device does not support EMUCOM."); + return ERROR_FAIL; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], channel); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); + + buf = malloc(length * 3 + 1); + + if (!buf) { + LOG_ERROR("Failed to allocate buffer."); + return ERROR_FAIL; + } + + ret = jaylink_emucom_read(devh, channel, buf, &length); + + if (ret == JAYLINK_ERR_DEV_NOT_SUPPORTED) { + LOG_ERROR("Channel is not supported by the device."); + free(buf); + return ERROR_FAIL; + } else if (ret == JAYLINK_ERR_DEV_NOT_AVAILABLE) { + LOG_ERROR("Channel is not available for the requested amount of data. " + "%" PRIu32 " bytes are avilable.", length); + free(buf); + return ERROR_FAIL; + } else if (ret != JAYLINK_OK) { + LOG_ERROR("Failed to read from channel: %s.", + jaylink_strerror_name(ret)); + free(buf); + return ERROR_FAIL; + } + + tmp = hexify((char *)buf + length, buf, length, 2 * length + 1); + + if (tmp != 2 * length) { + LOG_ERROR("Failed to convert data into hexadecimal string."); + free(buf); + return ERROR_FAIL; + } + + command_print(CMD_CTX, "%s", buf + length); + free(buf); + + return ERROR_OK; +} + static const struct command_registration jlink_config_subcommand_handlers[] = { { .name = "usb", @@ -1568,6 +1766,24 @@ static const struct command_registration jlink_config_subcommand_handlers[] = { COMMAND_REGISTRATION_DONE }; +static const struct command_registration jlink_emucom_subcommand_handlers[] = { + { + .name = "write", + .handler = &jlink_handle_emucom_write_command, + .mode = COMMAND_EXEC, + .help = "write to a channel", + .usage = " ", + }, + { + .name = "read", + .handler = &jlink_handle_emucom_read_command, + .mode = COMMAND_EXEC, + .help = "read from a channel", + .usage = " " + }, + COMMAND_REGISTRATION_DONE +}; + static const struct command_registration jlink_subcommand_handlers[] = { { .name = "jtag", @@ -1617,6 +1833,12 @@ static const struct command_registration jlink_subcommand_handlers[] = { "this will show the device configuration", .chain = jlink_config_subcommand_handlers, }, + { + .name = "emucom", + .mode = COMMAND_EXEC, + .help = "access EMUCOM channel", + .chain = jlink_emucom_subcommand_handlers + }, COMMAND_REGISTRATION_DONE }; @@ -1686,7 +1908,8 @@ static void jlink_tap_init(void) { tap_length = 0; pending_scan_results_length = 0; - memset(tms_buffer, 0, sizeof(tdi_buffer)); + memset(tms_buffer, 0, sizeof(tms_buffer)); + memset(tdi_buffer, 0, sizeof(tdi_buffer)); } static void jlink_clock_data(const uint8_t *out, unsigned out_offset,