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.

260 lines
6.2 KiB

6 years ago
  1. /* gc_n64_usb : Gamecube or N64 controller to USB firmware
  2. Copyright (C) 2007-2016 Raphael Assenat <raph@raphnet.net>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include "requests.h"
  17. #include "config.h"
  18. #include "hiddata.h"
  19. #include "usbpad.h"
  20. #include "bootloader.h"
  21. #include "gcn64_protocol.h"
  22. #include "version.h"
  23. #include "main.h"
  24. // dataHidReport is 63 bytes. Endpoint is 64 bytes.
  25. #define CMDBUF_SIZE 64
  26. #define STATE_IDLE 0
  27. #define STATE_NEW_COMMAND 1 // New command in buffer
  28. #define STATE_COMMAND_DONE 2 // Result in buffer
  29. //#define DEBUG
  30. extern char g_polling_suspended;
  31. static volatile uint8_t state = STATE_IDLE;
  32. static unsigned char cmdbuf[CMDBUF_SIZE];
  33. static volatile unsigned char cmdbuf_len = 0;
  34. /*** Get/Set report called from interrupt context! */
  35. uint16_t hiddata_get_report(void *ctx, struct usb_request *rq, const uint8_t **dat)
  36. {
  37. // printf("Get data\n");
  38. if (state == STATE_COMMAND_DONE) {
  39. *dat = cmdbuf;
  40. state = STATE_IDLE;
  41. #ifdef DEBUG
  42. printf_P(PSTR("hiddata idle, sent %d bytes\r\n"), cmdbuf_len);
  43. #endif
  44. return cmdbuf_len;
  45. }
  46. return 0;
  47. }
  48. /*** Get/Set report called from interrupt context! */
  49. uint8_t hiddata_set_report(void *ctx, const struct usb_request *rq, const uint8_t *dat, uint16_t len)
  50. {
  51. #ifdef DEBUG
  52. int i;
  53. printf_P(PSTR("Set data %d\n"), len);
  54. for (i=0; i<len; i++) {
  55. printf_P(PSTR("%02x "), dat[i]);
  56. }
  57. printf_P(PSTR("\r\n"));
  58. #endif
  59. state = STATE_NEW_COMMAND;
  60. memcpy(cmdbuf, dat, len);
  61. cmdbuf_len = len;
  62. return 0;
  63. }
  64. static uint8_t processBlockIO(void)
  65. {
  66. uint8_t requestCopy[CMDBUF_SIZE];
  67. int i, rx_offset = 0, rx;
  68. uint8_t chn, n_tx, n_rx;
  69. memcpy(requestCopy, cmdbuf, CMDBUF_SIZE);
  70. memset(cmdbuf + 1, 0xff, CMDBUF_SIZE-1);
  71. for (rx_offset = 1, i=1; i<CMDBUF_SIZE; ) {
  72. if (i + 3 >= CMDBUF_SIZE)
  73. break;
  74. chn = requestCopy[i];
  75. if (chn == 0xff)
  76. break;
  77. i++;
  78. n_tx = requestCopy[i];
  79. i++;
  80. n_rx = requestCopy[i];
  81. i++;
  82. if (n_tx == 0)
  83. continue;
  84. if (rx_offset + 1 + n_rx >= CMDBUF_SIZE) {
  85. break;
  86. }
  87. rx = gcn64_transaction(chn, requestCopy + i, n_tx, cmdbuf + rx_offset + 1, n_rx);
  88. cmdbuf[rx_offset] = n_rx;
  89. if (rx <= 0) {
  90. // timeout
  91. cmdbuf[rx_offset] |= 0x80;
  92. } else if (rx < n_rx) {
  93. // less than expected
  94. cmdbuf[rx_offset] |= 0x40;
  95. }
  96. rx_offset += n_rx + 1;
  97. i += n_tx;
  98. }
  99. return 63;
  100. }
  101. static void hiddata_processCommandBuffer(struct hiddata_ops *ops)
  102. {
  103. unsigned char channel;
  104. #ifdef DEBUG
  105. int i;
  106. #endif
  107. if (cmdbuf_len < 1) {
  108. state = STATE_IDLE;
  109. return;
  110. }
  111. // printf("Process cmd 0x%02x\r\n", cmdbuf[0]);
  112. switch(cmdbuf[0])
  113. {
  114. case RQ_GCN64_ECHO:
  115. // Cmd : RQ, data[]
  116. // Answer: RQ, data[]
  117. break;
  118. case RQ_GCN64_JUMP_TO_BOOTLOADER:
  119. enterBootLoader();
  120. break;
  121. case RQ_RNT_RESET_FIRMWARE:
  122. resetFirmware();
  123. break;
  124. case RQ_GCN64_RAW_SI_COMMAND:
  125. // TODO : Range checking
  126. // cmdbuf[] : RQ, CHN, LEN, data[]
  127. channel = cmdbuf[1];
  128. if (channel >= NUM_CHANNELS)
  129. break;
  130. cmdbuf_len = gcn64_transaction(channel, cmdbuf+3, cmdbuf[2], cmdbuf + 3, CMDBUF_SIZE-3);
  131. cmdbuf[2] = cmdbuf_len;
  132. cmdbuf_len += 3; // Answer: RQ, CHN, LEN, data[]
  133. break;
  134. case RQ_GCN64_GET_CONFIG_PARAM:
  135. // Cmd : RQ, PARAM
  136. // Answer: RQ, PARAM, data[]
  137. cmdbuf_len = config_getParam(cmdbuf[1], cmdbuf + 2, CMDBUF_SIZE-2);
  138. cmdbuf_len += 2; // Datalen + RQ + PARAM
  139. break;
  140. case RQ_GCN64_SET_CONFIG_PARAM:
  141. // Cmd: RQ, PARAM, data[]
  142. config_setParam(cmdbuf[1], cmdbuf+2);
  143. // Answer: RQ, PARAM
  144. cmdbuf_len = 2;
  145. break;
  146. case RQ_GCN64_SUSPEND_POLLING:
  147. // CMD: RQ, PARAM
  148. if (ops && ops->suspendPolling) {
  149. ops->suspendPolling(cmdbuf[1]);
  150. }
  151. break;
  152. case RQ_GCN64_GET_VERSION:
  153. // CMD: RQ
  154. // Answer: RQ, version string (zero-terminated)
  155. strcpy((char*)(cmdbuf + 1), g_version);
  156. cmdbuf_len = 1 + strlen(g_version) + 1;
  157. break;
  158. case RQ_GCN64_GET_SIGNATURE:
  159. strcpy_P((char*)(cmdbuf + 1), g_signature);
  160. cmdbuf_len = 1 + strlen_P(g_signature) + 1;
  161. break;
  162. case RQ_GCN64_GET_CONTROLLER_TYPE:
  163. // CMD : RQ, CHN
  164. // Answer: RQ, CHN, TYPE
  165. channel = cmdbuf[1];
  166. if (channel >= NUM_CHANNELS)
  167. break;
  168. cmdbuf[2] = current_pad_type[channel];
  169. cmdbuf_len = 3;
  170. break;
  171. case RQ_GCN64_SET_VIBRATION:
  172. // CMD : RQ, CHN, Vibrate
  173. // Answer: RQ, CHN, Vibrate
  174. if (ops && ops->forceVibration) {
  175. ops->forceVibration(cmdbuf[1], cmdbuf[2]);
  176. }
  177. cmdbuf_len = 3;
  178. break;
  179. case RQ_GCN64_BLOCK_IO:
  180. cmdbuf_len = processBlockIO();
  181. break;
  182. case RQ_RNT_GET_SUPPORTED_REQUESTS:
  183. cmdbuf[1] = RQ_GCN64_JUMP_TO_BOOTLOADER;
  184. cmdbuf[2] = RQ_GCN64_RAW_SI_COMMAND;
  185. cmdbuf[3] = RQ_GCN64_GET_CONFIG_PARAM;
  186. cmdbuf[4] = RQ_GCN64_SET_CONFIG_PARAM;
  187. cmdbuf[5] = RQ_GCN64_SUSPEND_POLLING;
  188. cmdbuf[6] = RQ_GCN64_GET_VERSION;
  189. cmdbuf[7] = RQ_GCN64_GET_SIGNATURE;
  190. cmdbuf[8] = RQ_GCN64_GET_CONTROLLER_TYPE;
  191. cmdbuf[9] = RQ_GCN64_SET_VIBRATION;
  192. cmdbuf[10] = RQ_GCN64_BLOCK_IO;
  193. cmdbuf[11] = RQ_RNT_GET_SUPPORTED_CFG_PARAMS;
  194. cmdbuf[12] = RQ_RNT_GET_SUPPORTED_MODES;
  195. cmdbuf[13] = RQ_RNT_GET_SUPPORTED_REQUESTS;
  196. cmdbuf_len = 14;
  197. break;
  198. case RQ_RNT_GET_SUPPORTED_CFG_PARAMS:
  199. cmdbuf_len = 1 + config_getSupportedParams(cmdbuf + 1);
  200. break;
  201. case RQ_RNT_GET_SUPPORTED_MODES:
  202. cmdbuf_len = 1;
  203. if (ops && ops->getSupportedModes) {
  204. cmdbuf_len += ops->getSupportedModes(cmdbuf + 1);
  205. }
  206. break;
  207. }
  208. #ifdef DEBUG
  209. printf("Pending data %d\n", cmdbuf_len);
  210. for (i=0; i<cmdbuf_len; i++) {
  211. printf("%02x ", cmdbuf[i]);
  212. }
  213. printf("\r\n");
  214. #endif
  215. state = STATE_COMMAND_DONE;
  216. }
  217. void hiddata_doTask(struct hiddata_ops *ops)
  218. {
  219. switch (state)
  220. {
  221. default:
  222. state = STATE_IDLE;
  223. case STATE_IDLE:
  224. break;
  225. case STATE_NEW_COMMAND:
  226. hiddata_processCommandBuffer(ops);
  227. break;
  228. case STATE_COMMAND_DONE:
  229. break;
  230. }
  231. }