+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2011 by Martin Schmoelzer *
* <martin.schmoelzer@student.tuwien.ac.at> *
- * *
- * 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, write to the *
- * Free Software Foundation, Inc., *
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "protocol.h"
#include "reg_ezusb.h"
/**
- * @file Implementation of the OpenULINK communication protocol.
+ * @file
+ * Implementation of the OpenULINK communication protocol.
*
* The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints
* are configured to use the maximum packet size for full-speed transfers,
* 64 bytes. Commands always start with a command ID (see msgtypes.h for
* command ID definitions) and contain zero or more payload data bytes in both
- * transfer directions (IN and OUT). The payload
+ * transfer directions (IN and OUT). The payload
*
* Almost all commands contain a fixed number of payload data bytes. The number
* of payload data bytes for the IN and OUT direction does not need to be the
* same.
- *
+ *
* Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the
* OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets,
* the host MUST ensure that the commands sent in the OUT packet require a
*/
/** Index in EP2 Bulk-OUT data buffer that contains the current command ID */
-volatile u8 cmd_id_index;
+volatile uint8_t cmd_id_index;
/** Number of data bytes already in EP2 Bulk-IN buffer */
-volatile u8 payload_index_in;
+volatile uint8_t payload_index_in;
/**
* Execute a SET_LEDS command.
*/
void execute_set_led_command(void)
{
- u8 led_state = OUT2BUF[cmd_id_index + 1];
+ uint8_t led_state = OUT2BUF[cmd_id_index + 1];
- if (led_state & RUN_LED_ON) {
- SET_RUN_LED();
- }
+ if (led_state & RUN_LED_ON)
+ SET_RUN_LED();
- if (led_state & COM_LED_ON) {
- SET_COM_LED();
- }
+ if (led_state & COM_LED_ON)
+ SET_COM_LED();
- if (led_state & RUN_LED_OFF) {
- CLEAR_RUN_LED();
- }
+ if (led_state & RUN_LED_OFF)
+ CLEAR_RUN_LED();
- if (led_state & COM_LED_OFF) {
- CLEAR_COM_LED();
- }
+ if (led_state & COM_LED_OFF)
+ CLEAR_COM_LED();
}
/**
* Executes one command and updates global command indexes.
*
- * @param index the index of the Bulk EP2-OUT data buffer at which the
- * command ID is stored.
* @return true if this command was the last command.
* @return false if there are more commands within the current contents of the
- * Bulk EP2-OUT data buffer.
+ * Bulk EP2-OUT data buffer.
*/
bool execute_command(void)
{
- u8 usb_out_bytecount, usb_in_bytecount;
- u16 signal_state;
- u16 count;
-
- /* Most commands do not transfer IN data. To save code space, we write 0 to
- * usb_in_bytecount here, then modify it in the switch statement below where
- * neccessary */
- usb_in_bytecount = 0;
-
- switch (OUT2BUF[cmd_id_index] /* Command ID */) {
- case CMD_SCAN_IN:
- usb_out_bytecount = 5;
- usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
- jtag_scan_in(cmd_id_index + 1, payload_index_in);
- break;
- case CMD_SCAN_OUT:
- usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
- jtag_scan_out(cmd_id_index + 1);
- break;
- case CMD_SCAN_IO:
- usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
- usb_out_bytecount = usb_in_bytecount + 5;
- jtag_scan_io(cmd_id_index + 1, payload_index_in);
- break;
- case CMD_CLOCK_TMS:
- usb_out_bytecount = 2;
- jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
- break;
- case CMD_CLOCK_TCK:
- usb_out_bytecount = 2;
- count = (u16)OUT2BUF[cmd_id_index + 1];
- count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
- jtag_clock_tck(count);
- break;
- case CMD_SLOW_SCAN_IN:
- usb_out_bytecount = 5;
- usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
- jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
- break;
- case CMD_SLOW_SCAN_OUT:
- usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
- jtag_slow_scan_out(cmd_id_index + 1);
- break;
- case CMD_SLOW_SCAN_IO:
- usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
- usb_out_bytecount = usb_in_bytecount + 5;
- jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
- break;
- case CMD_SLOW_CLOCK_TMS:
- usb_out_bytecount = 2;
- jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
- break;
- case CMD_SLOW_CLOCK_TCK:
- usb_out_bytecount = 2;
- count = (u16)OUT2BUF[cmd_id_index + 1];
- count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
- jtag_slow_clock_tck(count);
- break;
- case CMD_SLEEP_US:
- usb_out_bytecount = 2;
- count = (u16)OUT2BUF[cmd_id_index + 1];
- count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
- delay_us(count);
- break;
- case CMD_SLEEP_MS:
- usb_out_bytecount = 2;
- count = (u16)OUT2BUF[cmd_id_index + 1];
- count |= ((u16)OUT2BUF[cmd_id_index + 2]) << 8;
- delay_ms(count);
- break;
- case CMD_GET_SIGNALS:
- usb_out_bytecount = 0;
- usb_in_bytecount = 2;
- signal_state = jtag_get_signals();
- IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
- IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
- break;
- case CMD_SET_SIGNALS:
- usb_out_bytecount = 2;
- jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
- break;
- case CMD_CONFIGURE_TCK_FREQ:
- usb_out_bytecount = 5;
- jtag_configure_tck_delay(
- OUT2BUF[cmd_id_index + 1], /* scan_in */
- OUT2BUF[cmd_id_index + 2], /* scan_out */
- OUT2BUF[cmd_id_index + 3], /* scan_io */
- OUT2BUF[cmd_id_index + 4], /* clock_tck */
- OUT2BUF[cmd_id_index + 5]); /* clock_tms */
- break;
- case CMD_SET_LEDS:
- usb_out_bytecount = 1;
- execute_set_led_command();
- break;
- case CMD_TEST:
- usb_out_bytecount = 1;
- /* Do nothing... This command is only used to test if the device is ready
- * to accept new commands */
- break;
- default:
- /* Should never be reached */
- usb_out_bytecount = 0;
- break;
- }
-
- /* Update EP2 Bulk-IN data byte count */
- payload_index_in += usb_in_bytecount;
-
- /* Determine if this was the last command */
- if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC) {
- return true;
- }
- else {
- /* Not the last command, update cmd_id_index */
- cmd_id_index += (usb_out_bytecount + 1);
- return false;
- }
+ uint8_t usb_out_bytecount, usb_in_bytecount;
+ uint16_t signal_state;
+ uint16_t count;
+
+ /* Most commands do not transfer IN data. To save code space, we write 0 to
+ * usb_in_bytecount here, then modify it in the switch statement below where
+ * necessary */
+ usb_in_bytecount = 0;
+
+ switch (OUT2BUF[cmd_id_index] /* Command ID */) {
+ case CMD_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
+ jtag_scan_in(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SCAN_OUT:
+ usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
+ jtag_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SCAN_IO:
+ usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
+ usb_out_bytecount = usb_in_bytecount + 5;
+ jtag_scan_io(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_CLOCK_TMS:
+ usb_out_bytecount = 2;
+ jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
+ break;
+ case CMD_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (uint16_t)OUT2BUF[cmd_id_index + 1];
+ count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
+ jtag_clock_tck(count);
+ break;
+ case CMD_SLOW_SCAN_IN:
+ usb_out_bytecount = 5;
+ usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
+ jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SLOW_SCAN_OUT:
+ usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
+ jtag_slow_scan_out(cmd_id_index + 1);
+ break;
+ case CMD_SLOW_SCAN_IO:
+ usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
+ usb_out_bytecount = usb_in_bytecount + 5;
+ jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
+ break;
+ case CMD_SLOW_CLOCK_TMS:
+ usb_out_bytecount = 2;
+ jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
+ break;
+ case CMD_SLOW_CLOCK_TCK:
+ usb_out_bytecount = 2;
+ count = (uint16_t)OUT2BUF[cmd_id_index + 1];
+ count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
+ jtag_slow_clock_tck(count);
+ break;
+ case CMD_SLEEP_US:
+ usb_out_bytecount = 2;
+ count = (uint16_t)OUT2BUF[cmd_id_index + 1];
+ count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
+ delay_us(count);
+ break;
+ case CMD_SLEEP_MS:
+ usb_out_bytecount = 2;
+ count = (uint16_t)OUT2BUF[cmd_id_index + 1];
+ count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
+ delay_ms(count);
+ break;
+ case CMD_GET_SIGNALS:
+ usb_out_bytecount = 0;
+ usb_in_bytecount = 2;
+ signal_state = jtag_get_signals();
+ IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
+ IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
+ break;
+ case CMD_SET_SIGNALS:
+ usb_out_bytecount = 2;
+ jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
+ break;
+ case CMD_CONFIGURE_TCK_FREQ:
+ usb_out_bytecount = 5;
+ jtag_configure_tck_delay(
+ OUT2BUF[cmd_id_index + 1], /* scan_in */
+ OUT2BUF[cmd_id_index + 2], /* scan_out */
+ OUT2BUF[cmd_id_index + 3], /* scan_io */
+ OUT2BUF[cmd_id_index + 4], /* clock_tck */
+ OUT2BUF[cmd_id_index + 5]); /* clock_tms */
+ break;
+ case CMD_SET_LEDS:
+ usb_out_bytecount = 1;
+ execute_set_led_command();
+ break;
+ case CMD_TEST:
+ usb_out_bytecount = 1;
+ /* Do nothing... This command is only used to test if the device is ready
+ * to accept new commands */
+ break;
+ default:
+ /* Should never be reached */
+ usb_out_bytecount = 0;
+ break;
+ }
+
+ /* Update EP2 Bulk-IN data byte count */
+ payload_index_in += usb_in_bytecount;
+
+ /* Determine if this was the last command */
+ if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC)
+ return true;
+ else {
+ /* Not the last command, update cmd_id_index */
+ cmd_id_index += (usb_out_bytecount + 1);
+ return false;
+ }
}
/**
*/
void command_loop(void)
{
- bool last_command;
-
- while (1) {
- cmd_id_index = 0;
- payload_index_in = 0;
-
- /* Wait until host sends EP2 Bulk-OUT packet */
- while (!EP2_out);
- EP2_out = 0;
-
- /* Turn on COM LED to indicate command execution */
- SET_COM_LED();
-
- /* Execute the commands */
- last_command = false;
- while (last_command == false) {
- last_command = execute_command();
- }
-
- CLEAR_COM_LED();
-
- /* Send back EP2 Bulk-IN packet if required */
- if (payload_index_in > 0) {
- IN2BC = payload_index_in;
- while (!EP2_in);
- EP2_in = 0;
- }
-
- /* Re-arm EP2-OUT after command execution */
- OUT2BC = 0;
- }
+ bool last_command;
+
+ while (1) {
+ cmd_id_index = 0;
+ payload_index_in = 0;
+
+ /* Wait until host sends EP2 Bulk-OUT packet */
+ while (!EP2_out)
+ ;
+ EP2_out = 0;
+
+ /* Turn on COM LED to indicate command execution */
+ SET_COM_LED();
+
+ /* Execute the commands */
+ last_command = false;
+ while (last_command == false)
+ last_command = execute_command();
+
+ CLEAR_COM_LED();
+
+ /* Send back EP2 Bulk-IN packet if required */
+ if (payload_index_in > 0) {
+ IN2BC = payload_index_in;
+ while (!EP2_in)
+ ;
+ EP2_in = 0;
+ }
+
+ /* Re-arm EP2-OUT after command execution */
+ OUT2BC = 0;
+ }
}