]> git.sur5r.net Git - openocd/blobdiff - src/jtag/drivers/stlink_usb.c
stlink: avoid null pointer dereference in stlink_usb_close()
[openocd] / src / jtag / drivers / stlink_usb.c
index 77448d508245e8e704cb9272ed70f52faaf270ce..554ffc1edcbfc2e76e6fe9fd558a3dce37f988b1 100644 (file)
@@ -204,6 +204,7 @@ struct stlink_usb_handle_s {
 #define STLINK_DEBUG_APIV2_START_TRACE_RX  0x40
 #define STLINK_DEBUG_APIV2_STOP_TRACE_RX   0x41
 #define STLINK_DEBUG_APIV2_GET_TRACE_NB    0x42
+#define STLINK_DEBUG_APIV2_SWD_SET_FREQ    0x43
 
 #define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW   0x00
 #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH  0x01
@@ -226,6 +227,24 @@ enum stlink_mode {
 #define REQUEST_SENSE        0x03
 #define REQUEST_SENSE_LENGTH 18
 
+static const struct {
+       int speed;
+       int speed_divisor;
+} stlink_khz_to_speed_map[] = {
+       {4000, 0},
+       {1800, 1}, /* default */
+       {1200, 2},
+       {950,  3},
+       {480,  7},
+       {240, 15},
+       {125, 31},
+       {100, 40},
+       {50,  79},
+       {25, 158},
+       {15, 265},
+       {5,  798}
+};
+
 static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size);
 
 /** */
@@ -534,6 +553,31 @@ static int stlink_usb_check_voltage(void *handle, float *target_voltage)
        return ERROR_OK;
 }
 
+static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor)
+{
+       struct stlink_usb_handle_s *h = handle;
+
+       assert(handle != NULL);
+
+       /* only supported by stlink/v2 and for firmware >= 22 */
+       if (h->version.stlink == 1 || h->version.jtag < 22)
+               return ERROR_COMMAND_NOTFOUND;
+
+       stlink_usb_init_buffer(handle, h->rx_ep, 2);
+
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
+       h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
+       h_u16_to_le(h->cmdbuf+h->cmdidx, clk_divisor);
+       h->cmdidx += 2;
+
+       int result = stlink_cmd_allow_retry(handle, h->databuf, 2);
+
+       if (result != ERROR_OK)
+               return result;
+
+       return ERROR_OK;
+}
+
 /** */
 static int stlink_usb_current_mode(void *handle, uint8_t *mode)
 {
@@ -1034,7 +1078,7 @@ static void stlink_usb_trace_disable(void *handle)
 
        assert(h->version.jtag >= STLINK_TRACE_MIN_VERSION);
 
-       LOG_DEBUG("Tracing: disable\n");
+       LOG_DEBUG("Tracing: disable");
 
        stlink_usb_init_buffer(handle, h->rx_ep, 2);
        h->cmdbuf[h->cmdidx++] = STLINK_DEBUG_COMMAND;
@@ -1061,7 +1105,7 @@ static int stlink_usb_trace_enable(void *handle)
 
                res = stlink_configure_target_trace_port(handle);
                if (res != ERROR_OK)
-                       LOG_ERROR("Unable to configure tracing on target\n");
+                       LOG_ERROR("Unable to configure tracing on target");
 
                trace_hz = h->trace.prescale > 0 ?
                        h->trace.source_hz / (h->trace.prescale + 1) :
@@ -1080,7 +1124,7 @@ static int stlink_usb_trace_enable(void *handle)
 
                if (res == ERROR_OK)  {
                        h->trace.enabled = true;
-                       LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz\n", trace_hz);
+                       LOG_DEBUG("Tracing: recording at %" PRIu32 "Hz", trace_hz);
                        /* We need the trace read function to be called at a
                         * high-enough frequency to ensure reasonable
                         * "timeliness" in processing ITM/DWT data.
@@ -1112,9 +1156,9 @@ static int stlink_usb_run(void *handle)
                /* Try to start tracing, if requested */
                if (res == ERROR_OK && h->trace.source_hz && !h->trace.enabled) {
                        if (stlink_usb_trace_enable(handle) == ERROR_OK)
-                               LOG_DEBUG("Tracing: enabled\n");
+                               LOG_DEBUG("Tracing: enabled");
                        else
-                               LOG_ERROR("Tracing: enable failed\n");
+                               LOG_ERROR("Tracing: enable failed");
                }
 
                return res;
@@ -1567,15 +1611,67 @@ static int stlink_usb_override_target(const char *targetname)
        return !strcmp(targetname, "cortex_m");
 }
 
+static int stlink_speed(void *handle, int khz, bool query)
+{
+       unsigned i;
+       int speed_index = -1;
+       int speed_diff = INT_MAX;
+       struct stlink_usb_handle_s *h = handle;
+
+       /* only supported by stlink/v2 and for firmware >= 22 */
+       if (h && (h->version.stlink == 1 || h->version.jtag < 22))
+               return khz;
+
+       for (i = 0; i < ARRAY_SIZE(stlink_khz_to_speed_map); i++) {
+               if (khz == stlink_khz_to_speed_map[i].speed) {
+                       speed_index = i;
+                       break;
+               } else {
+                       int current_diff = khz - stlink_khz_to_speed_map[i].speed;
+                       /* get abs value for comparison */
+                       current_diff = (current_diff > 0) ? current_diff : -current_diff;
+                       if ((current_diff < speed_diff) && khz >= stlink_khz_to_speed_map[i].speed) {
+                               speed_diff = current_diff;
+                               speed_index = i;
+                       }
+               }
+       }
+
+       bool match = true;
+
+       if (speed_index == -1) {
+               /* this will only be here if we cannot match the slow speed.
+                * use the slowest speed we support.*/
+               speed_index = ARRAY_SIZE(stlink_khz_to_speed_map) - 1;
+               match = false;
+       } else if (i == ARRAY_SIZE(stlink_khz_to_speed_map))
+               match = false;
+
+       if (!match && query) {
+               LOG_INFO("Unable to match requested speed %d kHz, using %d kHz", \
+                               khz, stlink_khz_to_speed_map[speed_index].speed);
+       }
+
+       if (h && !query) {
+               int result = stlink_usb_set_swdclk(h, stlink_khz_to_speed_map[speed_index].speed_divisor);
+               if (result != ERROR_OK) {
+                       LOG_ERROR("Unable to set adapter speed");
+                       return khz;
+               }
+       }
+
+       return stlink_khz_to_speed_map[speed_index].speed;
+}
+
 /** */
-static int stlink_usb_close(void *fd)
+static int stlink_usb_close(void *handle)
 {
-       struct stlink_usb_handle_s *h = fd;
+       struct stlink_usb_handle_s *h = handle;
 
-       if (h->fd)
+       if (h && h->fd)
                jtag_libusb_close(h->fd);
 
-       free(fd);
+       free(h);
 
        return ERROR_OK;
 }
@@ -1600,9 +1696,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
 
        const uint16_t vids[] = { param->vid, 0 };
        const uint16_t pids[] = { param->pid, 0 };
+       const char *serial = param->serial;
 
-       LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport,
-               param->vid, param->pid);
+       LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s",
+                       param->transport, param->vid, param->pid,
+                       param->serial ? param->serial : "");
 
        /*
          On certain host USB configurations(e.g. MacBook Air)
@@ -1614,7 +1712,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
          in order to become operational.
         */
        do {
-               if (jtag_libusb_open(vids, pids, &h->fd) != ERROR_OK) {
+               if (jtag_libusb_open(vids, pids, serial, &h->fd) != ERROR_OK) {
                        LOG_ERROR("open failed");
                        goto error_open;
                }
@@ -1733,10 +1831,20 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
        err = stlink_usb_init_mode(h, param->connect_under_reset);
 
        if (err != ERROR_OK) {
-               LOG_ERROR("init mode failed");
+               LOG_ERROR("init mode failed (unable to connect to the target)");
                goto error_open;
        }
 
+       /* clock speed only supported by stlink/v2 and for firmware >= 22 */
+       if (h->version.stlink >= 2 && h->version.jtag >= 22) {
+               LOG_DEBUG("Supported clock speeds are:");
+
+               for (unsigned i = 0; i < ARRAY_SIZE(stlink_khz_to_speed_map); i++)
+                       LOG_DEBUG("%d kHz", stlink_khz_to_speed_map[i].speed);
+
+               stlink_speed(h, param->initial_interface_speed, false);
+       }
+
        /* get cpuid, so we can determine the max page size
         * start with a safe default */
        h->max_mem_packet = (1 << 10);
@@ -1798,4 +1906,6 @@ struct hl_layout_api_s stlink_usb_layout_api = {
        .write_debug_reg = stlink_usb_write_debug_reg,
        /** */
        .override_target = stlink_usb_override_target,
+       /** */
+       .speed = stlink_speed,
 };