rlink: read only the expected number of bytes
[openocd.git] / src / jtag / drivers / rlink.c
index 7111a20f44cd4547a0e2aaca7efadbe67cab2f65..f524b5c9c3fd088e1bb59f1e2bac3b33417041ce 100644 (file)
@@ -500,11 +500,11 @@ dtc_run_download(
                uint8_t *reply_buffer,
                int     reply_buffer_size
 ) {
-       uint8_t ep2_buffer[USB_EP2IN_SIZE];
+       char dtc_status;
        int     usb_err;
        int     i;
 
-       LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size);
+       LOG_DEBUG("%d/%d", command_buffer_size, reply_buffer_size);
 
        usb_err = usb_bulk_write(
                        pHDev_param,
@@ -530,40 +530,34 @@ dtc_run_download(
                usb_err = usb_bulk_read(
                                pHDev_param,
                                USB_EP1IN_ADDR,
-                               (char *)ep2_buffer, 1,
+                               &dtc_status, 1,
                                USB_TIMEOUT_MS
                );
                if (usb_err < 0) return(usb_err);
 
-               if (ep2_buffer[0] & 0x01) break;
+               if (dtc_status & 0x01) break;
 
                if (!--i) {
-                       LOG_ERROR("%s, %d: too many retries waiting for DTC status",
-                                       __FILE__, __LINE__
-                       );
+                       LOG_ERROR("too many retries waiting for DTC status");
                        return(-ETIMEDOUT);
                }
        }
 
 
-       if (!reply_buffer) reply_buffer_size = 0;
-       if (reply_buffer_size) {
+       if (reply_buffer && reply_buffer_size) {
                usb_err = usb_bulk_read(
                                pHDev_param,
                                USB_EP2IN_ADDR,
-                               (char *)ep2_buffer, sizeof(ep2_buffer),
+                               (char *)reply_buffer, reply_buffer_size,
                                USB_TIMEOUT_MS
                );
 
-               if (usb_err < (int)sizeof(ep2_buffer)) {
-                       LOG_ERROR("%s, %d: Read of endpoint 2 returned %d",
-                                       __FILE__, __LINE__, usb_err
+               if (usb_err < reply_buffer_size) {
+                       LOG_ERROR("Read of endpoint 2 returned %d, expected %d",
+                                       usb_err, reply_buffer_size
                        );
                        return(usb_err);
                }
-
-               memcpy(reply_buffer, ep2_buffer, reply_buffer_size);
-
        }
 
        return(usb_err);
@@ -678,126 +672,119 @@ dtc_queue_run(void) {
        uint8_t                 dtc_mask, tdo_mask;
        uint8_t                 reply_buffer[USB_EP2IN_SIZE];
 
+       assert((dtc_queue.rq_head != 0) == (dtc_queue.reply_index > 0));
+       assert(dtc_queue.cmd_index < USB_EP2BANK_SIZE);
+       assert(dtc_queue.reply_index <= USB_EP2IN_SIZE);
+
        retval = ERROR_OK;
 
        if (dtc_queue.cmd_index < 1) return(retval);
 
        dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = DTC_CMD_STOP;
 
-       /* run the cmd */
-       if (dtc_queue.rq_head == NULL) {
-               usb_err = dtc_run_download(pHDev,
-                               dtc_queue.cmd_buffer, dtc_queue.cmd_index,
-                               NULL, 0
-               );
-               if (usb_err < 0) {
-                       LOG_ERROR("dtc_run_download: %s", usb_strerror());
-                       exit(1);
-               }
-       } else {
-               usb_err = dtc_run_download(pHDev,
-                               dtc_queue.cmd_buffer, dtc_queue.cmd_index,
-                               reply_buffer, dtc_queue.reply_index
-               );
-               if (usb_err < 0) {
-                       LOG_ERROR("dtc_run_download: %s", usb_strerror());
-                       exit(1);
-               } else {
-                       /* process the reply, which empties the reply queue and frees its entries */
-                       dtc_p = reply_buffer;
+       usb_err = dtc_run_download(pHDev,
+                       dtc_queue.cmd_buffer, dtc_queue.cmd_index,
+                       reply_buffer, dtc_queue.reply_index
+       );
+       if (usb_err < 0) {
+               LOG_ERROR("dtc_run_download: %s", usb_strerror());
+               exit(1);
+       }
 
-                       /* The rigamarole with the masks and doing it bit-by-bit is due to the fact that the scan buffer is LSb-first and the DTC code is MSb-first for hardware reasons.   It was that or craft a function to do the reversal, and that wouldn't work with bit-stuffing (supplying extra bits to use mostly byte operations), or any other scheme which would throw the byte alignment off. */
+       if (dtc_queue.rq_head != NULL) {
+               /* process the reply, which empties the reply queue and frees its entries */
+               dtc_p = reply_buffer;
 
-                       for (
-                                       rq_p = dtc_queue.rq_head;
-                                       rq_p != NULL;
-                                       rq_p = rq_next
-                       ) {
-                               tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8);
-                               tdo_mask = 1 << (rq_p->scan.offset % 8);
+               /* The rigamarole with the masks and doing it bit-by-bit is due to the fact that the scan buffer is LSb-first and the DTC code is MSb-first for hardware reasons.   It was that or craft a function to do the reversal, and that wouldn't work with bit-stuffing (supplying extra bits to use mostly byte operations), or any other scheme which would throw the byte alignment off. */
 
+               for (
+                               rq_p = dtc_queue.rq_head;
+                               rq_p != NULL;
+                               rq_p = rq_next
+               ) {
+                       tdo_p = rq_p->scan.buffer + (rq_p->scan.offset / 8);
+                       tdo_mask = 1 << (rq_p->scan.offset % 8);
 
-                               bit_cnt = rq_p->scan.length;
-                               if (bit_cnt >= 8) {
-                                       /* bytes */
 
-                                       dtc_mask = 1 << (8 - 1);
+                       bit_cnt = rq_p->scan.length;
+                       if (bit_cnt >= 8) {
+                               /* bytes */
 
-                                       for (
-                                                       ;
-                                                       bit_cnt;
-                                                       bit_cnt--
-                                       ) {
-                                               if (*dtc_p & dtc_mask) {
-                                                       *tdo_p |= tdo_mask;
-                                               } else {
-                                                       *tdo_p &=~ tdo_mask;
-                                               }
-
-                                               dtc_mask >>= 1;
-                                               if (dtc_mask == 0) {
-                                                       dtc_p++;
-                                                       dtc_mask = 1 << (8 - 1);
-                                               }
-
-                                               tdo_mask <<= 1;
-                                               if (tdo_mask == 0) {
-                                                       tdo_p++;
-                                                       tdo_mask = 1;
-                                               }
-                                       }
-                               } else {
-                                       /*  extra bits or last bit */
-
-                                       x = *dtc_p++;
-                                       if ((
-                                                       rq_p->scan.type == SCAN_IN
-                                       ) && (
-                                                       rq_p->scan.offset != rq_p->scan.size - 1
-                                       )) {
-                                               /* extra bits were sent as a full byte with padding on the end */
-                                               dtc_mask = 1 << (8 - 1);
+                               dtc_mask = 1 << (8 - 1);
+
+                               for (
+                                               ;
+                                               bit_cnt;
+                                               bit_cnt--
+                               ) {
+                                       if (*dtc_p & dtc_mask) {
+                                               *tdo_p |= tdo_mask;
                                        } else {
-                                               dtc_mask = 1 << (bit_cnt - 1);
+                                               *tdo_p &=~ tdo_mask;
                                        }
 
-                                       for (
-                                                       ;
-                                                       bit_cnt;
-                                                       bit_cnt--
-                                       ) {
-                                               if (x & dtc_mask) {
-                                                       *tdo_p |= tdo_mask;
-                                               } else {
-                                                       *tdo_p &=~ tdo_mask;
-                                               }
-
-                                               dtc_mask >>= 1;
-
-                                               tdo_mask <<= 1;
-                                               if (tdo_mask == 0) {
-                                                       tdo_p++;
-                                                       tdo_mask = 1;
-                                               }
+                                       dtc_mask >>= 1;
+                                       if (dtc_mask == 0) {
+                                               dtc_p++;
+                                               dtc_mask = 1 << (8 - 1);
+                                       }
 
+                                       tdo_mask <<= 1;
+                                       if (tdo_mask == 0) {
+                                               tdo_p++;
+                                               tdo_mask = 1;
                                        }
                                }
+                       } else {
+                               /*  extra bits or last bit */
+
+                               x = *dtc_p++;
+                               if ((
+                                               rq_p->scan.type == SCAN_IN
+                               ) && (
+                                               rq_p->scan.offset != rq_p->scan.size - 1
+                               )) {
+                                       /* extra bits were sent as a full byte with padding on the end */
+                                       dtc_mask = 1 << (8 - 1);
+                               } else {
+                                       dtc_mask = 1 << (bit_cnt - 1);
+                               }
+
+                               for (
+                                               ;
+                                               bit_cnt;
+                                               bit_cnt--
+                               ) {
+                                       if (x & dtc_mask) {
+                                               *tdo_p |= tdo_mask;
+                                       } else {
+                                               *tdo_p &=~ tdo_mask;
+                                       }
+
+                                       dtc_mask >>= 1;
 
-                               if ((rq_p->scan.offset + rq_p->scan.length) >= rq_p->scan.size) {
-                                       /* feed scan buffer back into openocd and free it */
-                                       if (jtag_read_buffer(rq_p->scan.buffer, rq_p->cmd->cmd.scan) != ERROR_OK) {
-                                               retval = ERROR_JTAG_QUEUE_FAILED;
+                                       tdo_mask <<= 1;
+                                       if (tdo_mask == 0) {
+                                               tdo_p++;
+                                               tdo_mask = 1;
                                        }
-                                       free(rq_p->scan.buffer);
+
                                }
+                       }
 
-                               rq_next = rq_p->next;
-                               free(rq_p);
+                       if ((rq_p->scan.offset + rq_p->scan.length) >= rq_p->scan.size) {
+                               /* feed scan buffer back into openocd and free it */
+                               if (jtag_read_buffer(rq_p->scan.buffer, rq_p->cmd->cmd.scan) != ERROR_OK) {
+                                       retval = ERROR_JTAG_QUEUE_FAILED;
+                               }
+                               free(rq_p->scan.buffer);
                        }
-                       dtc_queue.rq_head = NULL;
-                       dtc_queue.rq_tail = NULL;
-               }
 
+                       rq_next = rq_p->next;
+                       free(rq_p);
+               }
+               dtc_queue.rq_head = NULL;
+               dtc_queue.rq_tail = NULL;
        }
 
 
@@ -808,7 +795,23 @@ dtc_queue_run(void) {
        return(retval);
 }
 
+/* runs the queue if it cannot take reserved_cmd bytes of command data
+ * or reserved_reply bytes of reply data */
+static
+int
+dtc_queue_run_if_full(
+               int reserved_cmd,
+               int reserved_reply
+) {
+       /* reserve one additional byte for the STOP cmd appended during run */
+       if (dtc_queue.cmd_index + reserved_cmd + 1 > USB_EP2BANK_SIZE)
+               return dtc_queue_run();
 
+       if (dtc_queue.reply_index + reserved_reply > USB_EP2IN_SIZE)
+               return dtc_queue_run();
+
+       return ERROR_OK;
+}
 
 static
 int
@@ -840,12 +843,8 @@ tap_state_queue_run(void) {
                if ((bits >= 8) || !i) {
                        byte_param <<= (8 - bits);
 
-                       /* make sure there's room for stop, byte op, and one byte */
-                       if (dtc_queue.cmd_index >= (sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1))) {
-                               dtc_queue.cmd_buffer[dtc_queue.cmd_index++] =
-                                               DTC_CMD_STOP;
-                               dtc_queue_run();
-                       }
+                       /* make sure there's room for two cmd bytes */
+                       dtc_queue_run_if_full(2, 0);
 
 #ifdef USE_HARDWARE_SHIFTER_FOR_TMS
                        if (bits == 8) {
@@ -1156,12 +1155,9 @@ rlink_scan(
        if (extra_bits && (type == SCAN_OUT)) {
                /* Schedule any extra bits into the DTC command buffer, padding as needed */
                /* For SCAN_OUT, this comes before the full bytes so the (leading) padding bits will fall off the end */
-               /* make sure there's room for stop, byte op, and one byte */
-               if (
-                               (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1))
-               ) {
-                       dtc_queue_run();
-               }
+
+               /* make sure there's room for two cmd bytes */
+               dtc_queue_run_if_full(2, 0);
 
                x = 0;
                dtc_mask = 1 << (extra_bits - 1);
@@ -1188,22 +1184,9 @@ rlink_scan(
 
        /* Loop scheduling full bytes into the DTC command buffer */
        while (byte_bits) {
-               if (type == SCAN_IN) {
-                       /* make sure there's room for stop and byte op */
-                       x = (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1));
-               } else {
-                       /* make sure there's room for stop, byte op, and at least one byte */
-                       x = (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1));
-               }
-
-               if (type != SCAN_OUT) {
-                       /* make sure there's room for at least one reply byte */
-                       x |= (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1));
-               }
-
-               if (x) {
-                       dtc_queue_run();
-               }
+               /* make sure there's room for one (for in scans) or two cmd bytes and
+                * at least one reply byte for in or inout scans*/
+               dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, type != SCAN_OUT ? 1 : 0);
 
                chunk_bits = byte_bits;
                /* we can only use up to 16 bytes at a time */
@@ -1233,6 +1216,7 @@ rlink_scan(
                                LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno));
                                exit(1);
                        }
+                       dtc_queue.reply_index += (chunk_bits + 7) / 8;
 
                        tdi_bit_offset += chunk_bits;
                }
@@ -1265,7 +1249,6 @@ rlink_scan(
                                dtc_mask >>= 1;
                                if (dtc_mask == 0) {
                                        dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x;
-                                       dtc_queue.reply_index++;
                                        x = 0;
                                        dtc_mask = 1 << (8 - 1);
                                }
@@ -1281,14 +1264,10 @@ rlink_scan(
 
        if (extra_bits && (type != SCAN_OUT)) {
                /* Schedule any extra bits into the DTC command buffer */
-               /* make sure there's room for stop, byte op, and one byte */
-               if (
-                               (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1 + 1))
-                               ||
-                               (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1))
-               ) {
-                       dtc_queue_run();
-               }
+
+               /* make sure there's room for one (for in scans) or two cmd bytes
+                * and one reply byte */
+               dtc_queue_run_if_full(type == SCAN_IN ? 1 : 2, 1);
 
                if (dtc_queue_enqueue_reply(
                                type, buffer, scan_size, tdi_bit_offset,
@@ -1299,6 +1278,8 @@ rlink_scan(
                        exit(1);
                }
 
+               dtc_queue.reply_index++;
+
                tdi_bit_offset += extra_bits;
 
                if (type == SCAN_IN) {
@@ -1328,40 +1309,32 @@ rlink_scan(
 
                        dtc_queue.cmd_buffer[dtc_queue.cmd_index++] = x;
                }
-
-               dtc_queue.reply_index++;
        }
 
        /* Schedule the last bit into the DTC command buffer */
-       {
-               /* make sure there's room for stop, and bit pair command */
-               if (
-                               (dtc_queue.cmd_index >= sizeof(dtc_queue.cmd_buffer) - (1 + 1))
-                               ||
-                               (dtc_queue.reply_index >= USB_EP2IN_SIZE - (1))
-               ) {
-                       dtc_queue_run();
-               }
 
-               if (type == SCAN_OUT) {
-                       dtc_queue.cmd_buffer[dtc_queue.cmd_index++] =
-                                       DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0);
-
-               } else {
-                       if (dtc_queue_enqueue_reply(
-                                       type, buffer, scan_size, tdi_bit_offset,
-                                       1,
-                                       cmd
-                       ) == NULL) {
-                               LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno));
-                               exit(1);
-                       }
+       /* make sure there's room for one cmd byte and one reply byte
+        * for in or inout scans*/
+       dtc_queue_run_if_full(1, type == SCAN_OUT ? 0 : 1);
 
-                       dtc_queue.cmd_buffer[dtc_queue.cmd_index++] =
-                                       DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 1);
+       if (type == SCAN_OUT) {
+               dtc_queue.cmd_buffer[dtc_queue.cmd_index++] =
+                               DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 0);
 
-                       dtc_queue.reply_index++;
+       } else {
+               if (dtc_queue_enqueue_reply(
+                               type, buffer, scan_size, tdi_bit_offset,
+                               1,
+                               cmd
+               ) == NULL) {
+                       LOG_ERROR("enqueuing DTC reply entry: %s", strerror(errno));
+                       exit(1);
                }
+
+               dtc_queue.reply_index++;
+
+               dtc_queue.cmd_buffer[dtc_queue.cmd_index++] =
+                               DTC_CMD_SHIFT_TMS_TDI_BIT_PAIR(1, (*tdi_p & tdi_mask), 1);
        }
 
        /* Move to pause state */
@@ -1508,10 +1481,7 @@ int rlink_speed(int speed)
                        }
 
                        if (dtc_start_download() < 0) {
-                               LOG_ERROR("%s, %d: starting DTC: %s",
-                                               __FILE__, __LINE__,
-                                               usb_strerror()
-                               );
+                               LOG_ERROR("starting DTC: %s", usb_strerror());
                                exit(1);
                        }
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)