+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2007 by Juergen Stuber <juergen@jstuber.net> *
* based on Dominic Rath's and Benedikt Sauter's usbprog.c *
* *
* Copyright (C) 2015-2017 by Forest Crossman *
* cyrozap@gmail.com *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * 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 <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#define HID_COMMAND_CONFIGURE 0x8f
#define HID_COMMAND_BOOTLOADER 0xa0
-/* 512 bytes seems to work reliably */
-#define SWD_MAX_BUFFER_LENGTH 512
+/* 512 bytes seemed to work reliably.
+ * It works with both full queue of mostly reads or mostly writes.
+ *
+ * Unfortunately the commit 88f429ead019fd6df96ec15f0d897385f3cef0d0
+ * 5321: target/cortex_m: faster reading of all CPU registers
+ * revealed a serious Kitprog firmware problem:
+ * If the queue contains more than 63 transactions in the repeated pattern
+ * one write, two reads, the firmware fails badly.
+ * Sending 64 transactions makes the adapter to loose the connection with the
+ * device. Sending 65 or more transactions causes the adapter to stop
+ * receiving USB HID commands, next kitprog_hid_command() stops in hid_write().
+ *
+ * The problem was detected with KitProg v2.12 and v2.16.
+ * We can guess the problem is something like a buffer or stack overflow.
+ *
+ * Use shorter buffer as a workaround. 300 bytes (= 60 transactions) works.
+ */
+#define SWD_MAX_BUFFER_LENGTH 300
struct kitprog {
hid_device *hid_handle;
void *buffer;
};
-static char *kitprog_serial;
static bool kitprog_init_acquire_psoc;
static int pending_transfer_count, pending_queue_len;
free(kitprog_handle->packet_buffer);
free(kitprog_handle->serial);
free(kitprog_handle);
- free(kitprog_serial);
free(pending_transfers);
return ERROR_OK;
const uint16_t vids[] = { VID, 0 };
const uint16_t pids[] = { PID, 0 };
- if (jtag_libusb_open(vids, pids, kitprog_serial,
- &kitprog_handle->usb_handle, NULL) != ERROR_OK) {
+ if (jtag_libusb_open(vids, pids, NULL, &kitprog_handle->usb_handle, NULL) != ERROR_OK) {
LOG_ERROR("Failed to open or find the device");
return ERROR_FAIL;
}
return ERROR_FAIL;
}
- ret = hid_read(kitprog_handle->hid_handle, data, data_length);
- if (ret < 0) {
- LOG_DEBUG("HID read returned %i", ret);
+ ret = hid_read_timeout(kitprog_handle->hid_handle,
+ data, data_length, LIBUSB_TIMEOUT_MS);
+ if (ret == 0) {
+ LOG_ERROR("HID read timed out");
+ return ERROR_TIMEOUT_REACHED;
+ } else if (ret < 0) {
+ LOG_ERROR("HID read error %ls", hid_error(kitprog_handle->hid_handle));
return ERROR_FAIL;
}
int transferred;
char status = PROGRAMMER_NOK_NACK;
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_WRITE,
(CONTROL_MODE_SET_PROGRAMMER_PROTOCOL << 8) | CONTROL_COMMAND_PROGRAM,
- protocol, &status, 1, 0);
+ protocol, &status, 1, 0, &transferred);
- if (transferred == 0) {
+ if (retval != ERROR_OK || transferred == 0) {
LOG_DEBUG("Zero bytes transferred");
return ERROR_FAIL;
}
/* Try a maximum of three times */
for (int i = 0; (i < 3) && (transferred == 0); i++) {
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_READ,
(CONTROL_MODE_POLL_PROGRAMMER_STATUS << 8) | CONTROL_COMMAND_PROGRAM,
- 0, &status, 1, 0);
+ 0, &status, 1, 0, &transferred);
jtag_sleep(1000);
}
int transferred;
char status = PROGRAMMER_NOK_NACK;
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_WRITE,
(0x03 << 8) | 0x04,
- 0, &status, 1, 0);
+ 0, &status, 1, 0, &transferred);
- if (transferred == 0) {
+ if (retval != ERROR_OK || transferred == 0) {
LOG_DEBUG("Zero bytes transferred");
return ERROR_FAIL;
}
int transferred;
char status = PROGRAMMER_NOK_NACK;
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_WRITE,
(CONTROL_MODE_ACQUIRE_SWD_TARGET << 8) | CONTROL_COMMAND_PROGRAM,
- (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0);
+ (max_attempts << 8) | (acquire_mode << 4) | psoc_type, &status, 1, 0, &transferred);
- if (transferred == 0) {
+ if (retval != ERROR_OK || transferred == 0) {
LOG_DEBUG("Zero bytes transferred");
return ERROR_FAIL;
}
int transferred;
char status = PROGRAMMER_NOK_NACK;
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_WRITE,
(CONTROL_MODE_RESET_TARGET << 8) | CONTROL_COMMAND_PROGRAM,
- 0, &status, 1, 0);
+ 0, &status, 1, 0, &transferred);
- if (transferred == 0) {
+ if (retval != ERROR_OK || transferred == 0) {
LOG_DEBUG("Zero bytes transferred");
return ERROR_FAIL;
}
int transferred;
char status = PROGRAMMER_NOK_NACK;
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_WRITE,
(CONTROL_MODE_SYNCHRONIZE_TRANSFER << 8) | CONTROL_COMMAND_PROGRAM,
- 0, &status, 1, 0);
+ 0, &status, 1, 0, &transferred);
- if (transferred == 0) {
+ if (retval != ERROR_OK || transferred == 0) {
LOG_DEBUG("Zero bytes transferred");
return ERROR_FAIL;
}
int transferred;
char status = PROGRAMMER_NOK_NACK;
- transferred = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
+ int retval = jtag_libusb_control_transfer(kitprog_handle->usb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
CONTROL_TYPE_WRITE,
(CONTROL_MODE_SEND_SWD_SEQUENCE << 8) | CONTROL_COMMAND_PROGRAM,
- seq_type, &status, 1, 0);
+ seq_type, &status, 1, 0, &transferred);
- if (transferred == 0) {
+ if (retval != ERROR_OK || transferred == 0) {
LOG_DEBUG("Zero bytes transferred");
return ERROR_FAIL;
}
if (ack != SWD_ACK_OK || (buffer[read_index] & 0x08)) {
LOG_DEBUG("SWD ack not OK: %d %s", i,
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
- queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
+ queued_retval = swd_ack_to_error_code(ack);
break;
}
read_index++;
return retval;
}
-COMMAND_HANDLER(kitprog_handle_serial_command)
-{
- if (CMD_ARGC == 1) {
- kitprog_serial = strdup(CMD_ARGV[0]);
- if (!kitprog_serial) {
- LOG_ERROR("Failed to allocate memory for the serial number");
- return ERROR_FAIL;
- }
- } else {
- LOG_ERROR("expected exactly one argument to kitprog_serial <serial-number>");
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
-}
-
COMMAND_HANDLER(kitprog_handle_init_acquire_psoc_command)
{
kitprog_init_acquire_psoc = true;
.usage = "",
.help = "try to acquire a PSoC",
},
+ {
+ .name = "init_acquire_psoc",
+ .handler = &kitprog_handle_init_acquire_psoc_command,
+ .mode = COMMAND_CONFIG,
+ .help = "try to acquire a PSoC during init",
+ .usage = "",
+ },
COMMAND_REGISTRATION_DONE
};
.usage = "<cmd>",
.chain = kitprog_subcommand_handlers,
},
- {
- .name = "kitprog_serial",
- .handler = &kitprog_handle_serial_command,
- .mode = COMMAND_CONFIG,
- .help = "set the serial number of the adapter",
- .usage = "serial_string",
- },
- {
- .name = "kitprog_init_acquire_psoc",
- .handler = &kitprog_handle_init_acquire_psoc_command,
- .mode = COMMAND_CONFIG,
- .help = "try to acquire a PSoC during init",
- .usage = "",
- },
COMMAND_REGISTRATION_DONE
};