usb_ep0.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * usb_ep0.c
  3. *
  4. * Copyright (C) 2019 Sylvain Munaut
  5. * All rights reserved.
  6. *
  7. * LGPL v3+, see LICENSE.lgpl3
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 3 of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this program; if not, write to the Free Software Foundation,
  21. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. */
  23. #include <stdint.h>
  24. #include <stdbool.h>
  25. #include <string.h>
  26. #include "console.h"
  27. #include "usb_priv.h"
  28. /* Helpers to manipulate BDs */
  29. static inline void
  30. usb_ep0_out_queue_bd(bool setup, int ofs, int len, bool stall)
  31. {
  32. int bdi = setup ? 1 : 0;
  33. usb_ep_regs[0].out.bd[bdi].ptr = ofs;
  34. usb_ep_regs[0].out.bd[bdi].csr = stall ? USB_BD_STATE_RDY_STALL : (USB_BD_STATE_RDY_DATA | USB_BD_LEN(len));
  35. }
  36. static inline void
  37. usb_ep0_in_queue_bd(int ofs, int len, bool stall)
  38. {
  39. usb_ep_regs[0].in.bd[0].ptr = ofs;
  40. usb_ep_regs[0].in.bd[0].csr = stall ? USB_BD_STATE_RDY_STALL : (USB_BD_STATE_RDY_DATA | USB_BD_LEN(len));
  41. }
  42. static inline uint32_t
  43. usb_ep0_out_peek_bd(bool setup)
  44. {
  45. int bdi = setup ? 1 : 0;
  46. return usb_ep_regs[0].out.bd[bdi].csr;
  47. }
  48. static inline uint32_t
  49. usb_ep0_in_peek_bd(void)
  50. {
  51. return usb_ep_regs[0].in.bd[0].csr;
  52. }
  53. static inline void
  54. usb_ep0_out_done_bd(bool setup)
  55. {
  56. int bdi = setup ? 1 : 0;
  57. usb_ep_regs[0].out.bd[bdi].csr = 0;
  58. }
  59. static inline void
  60. usb_ep0_in_done_bd(void)
  61. {
  62. usb_ep_regs[0].in.bd[0].csr = 0;
  63. }
  64. /* Standard control request handling */
  65. /* Handle control transfers */
  66. static void
  67. usb_handle_control_data()
  68. {
  69. /* Handle read requests */
  70. if (g_usb.ctrl.state == DATA_IN) {
  71. /* How much left to do ? */
  72. int xflen = g_usb.ctrl.len - g_usb.ctrl.ofs;
  73. if (xflen > 64)
  74. xflen = 64;
  75. /* Setup descriptor for output */
  76. if (xflen)
  77. usb_data_write(0, &g_usb.ctrl.data.in[g_usb.ctrl.ofs], xflen);
  78. usb_ep0_in_queue_bd(0, xflen, false);
  79. /* Move on */
  80. g_usb.ctrl.ofs += xflen;
  81. /* If we're done, setup the OUT ack */
  82. if (xflen < 64) {
  83. usb_ep0_out_queue_bd(false, 0, 0, false);
  84. g_usb.ctrl.state = STATUS_DONE_OUT;
  85. }
  86. }
  87. /* Handle write requests */
  88. if (g_usb.ctrl.state == DATA_OUT) {
  89. if (g_usb.ctrl.ofs == g_usb.ctrl.len)
  90. {
  91. /* Done, ACK with a ZLP */
  92. usb_ep0_in_queue_bd(0, 0, false);
  93. g_usb.ctrl.state = STATUS_DONE_IN;
  94. }
  95. else
  96. {
  97. /* Fill a BD with as much as we can */
  98. }
  99. }
  100. }
  101. static void
  102. usb_handle_control_request(struct usb_ctrl_req_hdr *req)
  103. {
  104. bool handled = false;
  105. /* Defaults */
  106. g_usb.ctrl.data.in = NULL;
  107. g_usb.ctrl.data.out = NULL;
  108. g_usb.ctrl.len = req->wLength;
  109. g_usb.ctrl.ofs = 0;
  110. /* Process request */
  111. switch (req->bRequest)
  112. {
  113. case USB_REQ_GET_STATUS:
  114. case USB_REQ_CLEAR_FEATURE:
  115. case USB_REQ_SET_FEATURE:
  116. break;
  117. case USB_REQ_SET_ADDRESS:
  118. handled = true;
  119. break;
  120. case USB_REQ_GET_DESCRIPTOR:
  121. {
  122. int idx = req->wValue & 0xff;
  123. switch (req->wValue & 0xff00)
  124. {
  125. case 0x0100: /* Device */
  126. g_usb.ctrl.data.out = usb_get_device_desc(&g_usb.ctrl.len);
  127. break;
  128. case 0x0200: /* Configuration */
  129. g_usb.ctrl.data.out = usb_get_config_desc(&g_usb.ctrl.len, idx);
  130. break;
  131. case 0x0300: /* String */
  132. g_usb.ctrl.data.out = usb_get_string_desc(&g_usb.ctrl.len, idx);
  133. break;
  134. }
  135. handled = g_usb.ctrl.data.out != NULL;
  136. break;
  137. }
  138. case USB_REQ_SET_DESCRIPTOR:
  139. case USB_REQ_GET_CONFIGURATION:
  140. break;
  141. case USB_REQ_SET_CONFIGURATION:
  142. handled = true;
  143. break;
  144. case USB_REQ_GET_INTERFACE:
  145. case USB_REQ_SET_INTERFACE:
  146. case USB_REQ_SYNCHFRAME:
  147. default:
  148. break;
  149. }
  150. /* If the request isn't handled, answer with STALL */
  151. if (!handled) {
  152. if (USB_REQ_IS_READ(req)) {
  153. /* Read request, send a STALL for the DATA IN stage */
  154. g_usb.ctrl.state = STATUS_DONE_IN;
  155. usb_ep0_in_queue_bd(0, 0, true);
  156. } else if (req->wLength) {
  157. /* Write request with some incoming data, send a STALL to next OUT */
  158. g_usb.ctrl.state = STATUS_DONE_OUT;
  159. usb_ep0_out_queue_bd(false, 0, 0, true);
  160. } else {
  161. /* Write request with no data, send a STALL in the STATUS IN stage */
  162. g_usb.ctrl.state = STATUS_DONE_IN;
  163. usb_ep0_in_queue_bd(0, 0, true);
  164. }
  165. return;
  166. }
  167. /* Handle the 'data' stage now */
  168. g_usb.ctrl.state = USB_REQ_IS_READ(req) ? DATA_IN : DATA_OUT;
  169. if (g_usb.ctrl.len > req->wLength)
  170. g_usb.ctrl.len = req->wLength;
  171. usb_handle_control_data();
  172. }
  173. /* Internally exposed "API" */
  174. void
  175. usb_ep0_run(void)
  176. {
  177. uint32_t bds_setup, bds_out, bds_in;
  178. bool acted;
  179. do {
  180. /* Not done anything yet */
  181. acted = false;
  182. /* Grab current EP status */
  183. bds_out = usb_ep0_out_peek_bd(false);
  184. bds_setup = usb_ep0_out_peek_bd(true);
  185. bds_in = usb_ep0_in_peek_bd();
  186. /* Check for status IN stage finishing */
  187. if (g_usb.ctrl.state == STATUS_DONE_IN) {
  188. if ((bds_in & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)
  189. {
  190. g_usb.ctrl.state = IDLE;
  191. usb_ep0_in_done_bd();
  192. acted = true;
  193. continue;
  194. }
  195. }
  196. /* Check for status OUT stage finishing */
  197. if (g_usb.ctrl.state == STATUS_DONE_OUT) {
  198. if ((bds_out & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)
  199. {
  200. if ((bds_out & USB_BD_LEN_MSK) == 2) {
  201. g_usb.ctrl.state = IDLE;
  202. usb_ep0_out_done_bd(false);
  203. acted = true;
  204. continue;
  205. } else {
  206. puts("[!] Got a non ZLP as a status stage packet ?!?\n");
  207. }
  208. }
  209. }
  210. /* Retry any RX error on both setup and data buffers */
  211. if ((bds_setup & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
  212. {
  213. usb_ep0_out_queue_bd(true, 0, 64, false);
  214. acted = true;
  215. continue;
  216. }
  217. if ((bds_out & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_ERR)
  218. {
  219. usb_ep0_out_queue_bd(false, 64, 64, false);
  220. acted = true;
  221. continue;
  222. }
  223. /* Check for SETUP */
  224. if ((bds_setup & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)
  225. {
  226. /* Really setup ? */
  227. if (!(bds_setup & USB_BD_IS_SETUP)) {
  228. puts("[!] Got non-SETUP in the SETUP BD !?!\n");
  229. }
  230. /* Were we waiting for this ? */
  231. if (g_usb.ctrl.state != IDLE) {
  232. puts("[!] Got SETUP while busy !??\n");
  233. }
  234. /* Clear descriptors */
  235. usb_ep0_out_done_bd(false);
  236. usb_ep0_in_done_bd();
  237. /* Make sure DT=1 for IN endpoint after a SETUP */
  238. usb_ep_regs[0].in.status = USB_EP_TYPE_CTRL | USB_EP_DT_BIT; /* Type=Control, single buffered, DT=1 */
  239. /* We acked it, need to handle it */
  240. usb_data_read(&g_usb.ctrl.req, 0, sizeof(struct usb_ctrl_req_hdr));
  241. usb_handle_control_request(&g_usb.ctrl.req);
  242. /* Release the lockout and allow new SETUP */
  243. usb_regs->ar = USB_AR_CEL_RELEASE;
  244. usb_ep0_out_queue_bd(true, 0, 64, false);
  245. return;
  246. }
  247. /* Process data stage */
  248. if (((bds_out & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK)) {
  249. usb_ep0_out_done_bd(false);
  250. if (g_usb.ctrl.state != DATA_OUT) {
  251. puts("[!] Got unexpected DATA !?!\n");
  252. continue;
  253. }
  254. usb_handle_control_data();
  255. acted = true;
  256. }
  257. if ((bds_in & USB_BD_STATE_MSK) == USB_BD_STATE_DONE_OK) {
  258. usb_ep0_in_done_bd();
  259. if (g_usb.ctrl.state == DATA_IN) {
  260. usb_handle_control_data();
  261. acted = true;
  262. }
  263. }
  264. } while (acted);
  265. }
  266. void
  267. usb_ep0_init(void)
  268. {
  269. /* Configure EP0 */
  270. usb_ep_regs[0].out.status = USB_EP_TYPE_CTRL | USB_EP_BD_CTRL; /* Type=Control, control mode buffered */
  271. usb_ep_regs[0].in.status = USB_EP_TYPE_CTRL | USB_EP_DT_BIT; /* Type=Control, single buffered, DT=1 */
  272. /* Queue one buffer for SETUP */
  273. usb_ep0_out_queue_bd(true, 0, 64, false);
  274. }