You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

241 lines
7.4 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2011 by Martin Schmoelzer *
  3. * <martin.schmoelzer@student.tuwien.ac.at> *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. #include "protocol.h"
  21. #include "jtag.h"
  22. #include "delay.h"
  23. #include "usb.h"
  24. #include "io.h"
  25. #include "msgtypes.h"
  26. #include "reg_ezusb.h"
  27. /**
  28. * @file
  29. * Implementation of the OpenULINK communication protocol.
  30. *
  31. * The OpenULINK protocol uses one OUT and one IN endpoint. These two endpoints
  32. * are configured to use the maximum packet size for full-speed transfers,
  33. * 64 bytes. Commands always start with a command ID (see msgtypes.h for
  34. * command ID definitions) and contain zero or more payload data bytes in both
  35. * transfer directions (IN and OUT). The payload
  36. *
  37. * Almost all commands contain a fixed number of payload data bytes. The number
  38. * of payload data bytes for the IN and OUT direction does not need to be the
  39. * same.
  40. *
  41. * Multiple commands may be sent in one EP2 Bulk-OUT packet. Because the
  42. * OpenULINK firmware does not perform bounds checking for EP2 Bulk-IN packets,
  43. * the host MUST ensure that the commands sent in the OUT packet require a
  44. * maximum of 64 bytes of IN data.
  45. */
  46. /** Index in EP2 Bulk-OUT data buffer that contains the current command ID */
  47. volatile uint8_t cmd_id_index;
  48. /** Number of data bytes already in EP2 Bulk-IN buffer */
  49. volatile uint8_t payload_index_in;
  50. /**
  51. * Execute a SET_LEDS command.
  52. */
  53. void execute_set_led_command(void)
  54. {
  55. uint8_t led_state = OUT2BUF[cmd_id_index + 1];
  56. if (led_state & RUN_LED_ON)
  57. SET_RUN_LED();
  58. if (led_state & COM_LED_ON)
  59. SET_COM_LED();
  60. if (led_state & RUN_LED_OFF)
  61. CLEAR_RUN_LED();
  62. if (led_state & COM_LED_OFF)
  63. CLEAR_COM_LED();
  64. }
  65. /**
  66. * Executes one command and updates global command indexes.
  67. *
  68. * @return true if this command was the last command.
  69. * @return false if there are more commands within the current contents of the
  70. * Bulk EP2-OUT data buffer.
  71. */
  72. bool execute_command(void)
  73. {
  74. uint8_t usb_out_bytecount, usb_in_bytecount;
  75. uint16_t signal_state;
  76. uint16_t count;
  77. /* Most commands do not transfer IN data. To save code space, we write 0 to
  78. * usb_in_bytecount here, then modify it in the switch statement below where
  79. * neccessary */
  80. usb_in_bytecount = 0;
  81. switch (OUT2BUF[cmd_id_index] /* Command ID */) {
  82. case CMD_SCAN_IN:
  83. usb_out_bytecount = 5;
  84. usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
  85. jtag_scan_in(cmd_id_index + 1, payload_index_in);
  86. break;
  87. case CMD_SCAN_OUT:
  88. usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
  89. jtag_scan_out(cmd_id_index + 1);
  90. break;
  91. case CMD_SCAN_IO:
  92. usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
  93. usb_out_bytecount = usb_in_bytecount + 5;
  94. jtag_scan_io(cmd_id_index + 1, payload_index_in);
  95. break;
  96. case CMD_CLOCK_TMS:
  97. usb_out_bytecount = 2;
  98. jtag_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
  99. break;
  100. case CMD_CLOCK_TCK:
  101. usb_out_bytecount = 2;
  102. count = (uint16_t)OUT2BUF[cmd_id_index + 1];
  103. count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
  104. jtag_clock_tck(count);
  105. break;
  106. case CMD_SLOW_SCAN_IN:
  107. usb_out_bytecount = 5;
  108. usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
  109. jtag_slow_scan_in(cmd_id_index + 1, payload_index_in);
  110. break;
  111. case CMD_SLOW_SCAN_OUT:
  112. usb_out_bytecount = OUT2BUF[cmd_id_index + 1] + 5;
  113. jtag_slow_scan_out(cmd_id_index + 1);
  114. break;
  115. case CMD_SLOW_SCAN_IO:
  116. usb_in_bytecount = OUT2BUF[cmd_id_index + 1];
  117. usb_out_bytecount = usb_in_bytecount + 5;
  118. jtag_slow_scan_io(cmd_id_index + 1, payload_index_in);
  119. break;
  120. case CMD_SLOW_CLOCK_TMS:
  121. usb_out_bytecount = 2;
  122. jtag_slow_clock_tms(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
  123. break;
  124. case CMD_SLOW_CLOCK_TCK:
  125. usb_out_bytecount = 2;
  126. count = (uint16_t)OUT2BUF[cmd_id_index + 1];
  127. count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
  128. jtag_slow_clock_tck(count);
  129. break;
  130. case CMD_SLEEP_US:
  131. usb_out_bytecount = 2;
  132. count = (uint16_t)OUT2BUF[cmd_id_index + 1];
  133. count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
  134. delay_us(count);
  135. break;
  136. case CMD_SLEEP_MS:
  137. usb_out_bytecount = 2;
  138. count = (uint16_t)OUT2BUF[cmd_id_index + 1];
  139. count |= ((uint16_t)OUT2BUF[cmd_id_index + 2]) << 8;
  140. delay_ms(count);
  141. break;
  142. case CMD_GET_SIGNALS:
  143. usb_out_bytecount = 0;
  144. usb_in_bytecount = 2;
  145. signal_state = jtag_get_signals();
  146. IN2BUF[payload_index_in] = (signal_state >> 8) & 0x00FF;
  147. IN2BUF[payload_index_in + 1] = signal_state & 0x00FF;
  148. break;
  149. case CMD_SET_SIGNALS:
  150. usb_out_bytecount = 2;
  151. jtag_set_signals(OUT2BUF[cmd_id_index + 1], OUT2BUF[cmd_id_index + 2]);
  152. break;
  153. case CMD_CONFIGURE_TCK_FREQ:
  154. usb_out_bytecount = 5;
  155. jtag_configure_tck_delay(
  156. OUT2BUF[cmd_id_index + 1], /* scan_in */
  157. OUT2BUF[cmd_id_index + 2], /* scan_out */
  158. OUT2BUF[cmd_id_index + 3], /* scan_io */
  159. OUT2BUF[cmd_id_index + 4], /* clock_tck */
  160. OUT2BUF[cmd_id_index + 5]); /* clock_tms */
  161. break;
  162. case CMD_SET_LEDS:
  163. usb_out_bytecount = 1;
  164. execute_set_led_command();
  165. break;
  166. case CMD_TEST:
  167. usb_out_bytecount = 1;
  168. /* Do nothing... This command is only used to test if the device is ready
  169. * to accept new commands */
  170. break;
  171. default:
  172. /* Should never be reached */
  173. usb_out_bytecount = 0;
  174. break;
  175. }
  176. /* Update EP2 Bulk-IN data byte count */
  177. payload_index_in += usb_in_bytecount;
  178. /* Determine if this was the last command */
  179. if ((cmd_id_index + usb_out_bytecount + 1) >= OUT2BC)
  180. return true;
  181. else {
  182. /* Not the last command, update cmd_id_index */
  183. cmd_id_index += (usb_out_bytecount + 1);
  184. return false;
  185. }
  186. }
  187. /**
  188. * Forever wait for commands and execute them as they arrive.
  189. */
  190. void command_loop(void)
  191. {
  192. bool last_command;
  193. while (1) {
  194. cmd_id_index = 0;
  195. payload_index_in = 0;
  196. /* Wait until host sends EP2 Bulk-OUT packet */
  197. while (!EP2_out)
  198. ;
  199. EP2_out = 0;
  200. /* Turn on COM LED to indicate command execution */
  201. SET_COM_LED();
  202. /* Execute the commands */
  203. last_command = false;
  204. while (last_command == false)
  205. last_command = execute_command();
  206. CLEAR_COM_LED();
  207. /* Send back EP2 Bulk-IN packet if required */
  208. if (payload_index_in > 0) {
  209. IN2BC = payload_index_in;
  210. while (!EP2_in)
  211. ;
  212. EP2_in = 0;
  213. }
  214. /* Re-arm EP2-OUT after command execution */
  215. OUT2BC = 0;
  216. }
  217. }