usb_dc_rp2040.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. /*
  2. * Copyright (c) 2022, HaiMianBBao
  3. * Copyright (c) 2025, sakumisu
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. #include "usbd_core.h"
  8. #include "hardware/resets.h"
  9. #include "hardware/irq.h"
  10. #include "hardware/structs/usb.h"
  11. #if CHERRYUSB_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
  12. #include "pico/fix/rp2040_usb_device_enumeration.h"
  13. #endif
  14. #define usb_hw_set hw_set_alias(usb_hw)
  15. #define usb_hw_clear hw_clear_alias(usb_hw)
  16. #ifndef CONFIG_USBDEV_EP_NUM
  17. #define CONFIG_USBDEV_EP_NUM 16
  18. #endif
  19. #ifndef FORCE_VBUS_DETECT
  20. #define FORCE_VBUS_DETECT 1
  21. #endif
  22. /* Endpoint state */
  23. struct rp2040_ep_state {
  24. uint16_t ep_mps; /* Endpoint max packet size */
  25. uint8_t ep_type; /* Endpoint type */
  26. uint8_t ep_stalled; /* Endpoint stall flag */
  27. uint8_t ep_enable; /* Endpoint enable */
  28. uint8_t ep_addr; /* Endpoint address */
  29. uint8_t *xfer_buf;
  30. uint32_t xfer_len;
  31. uint32_t actual_xfer_len;
  32. volatile uint32_t *endpoint_control; /*!< Endpoint control register */
  33. volatile uint32_t *buffer_control; /*!< Buffer control register */
  34. uint8_t *data_buffer; /*!< Buffer pointer in usb dpram */
  35. uint8_t next_pid; /*!< Toggle after each packet (unless replying to a SETUP) */
  36. };
  37. /* Driver state */
  38. struct rp2040_udc {
  39. volatile uint8_t dev_addr;
  40. struct rp2040_ep_state in_ep[CONFIG_USBDEV_EP_NUM]; /*!< IN endpoint parameters*/
  41. struct rp2040_ep_state out_ep[CONFIG_USBDEV_EP_NUM]; /*!< OUT endpoint parameters */
  42. struct usb_setup_packet setup; /*!< Setup package that may be used in interrupt processing (outside the protocol stack) */
  43. } g_rp2040_udc;
  44. void rp2040_usbd_irq(void);
  45. /**
  46. * @brief Take a buffer pointer located in the USB RAM and return as an offset of the RAM.
  47. *
  48. * @param buf
  49. * @return uint32_t
  50. */
  51. static inline uint32_t usb_buffer_offset(volatile uint8_t *buf)
  52. {
  53. return (uint32_t)buf ^ (uint32_t)usb_dpram;
  54. }
  55. /**
  56. * @brief Set up the endpoint control register for an endpoint (if applicable. Not valid for EP0).
  57. *
  58. * @param ep
  59. */
  60. void usb_setup_endpoint(const struct rp2040_ep_state *ep)
  61. {
  62. // EP0 doesn't have one so return if that is the case
  63. if (!ep->endpoint_control) {
  64. return;
  65. }
  66. // Get the data buffer as an offset of the USB controller's DPRAM
  67. uint32_t dpram_offset = usb_buffer_offset(ep->data_buffer);
  68. uint32_t reg = EP_CTRL_ENABLE_BITS |
  69. EP_CTRL_INTERRUPT_PER_BUFFER |
  70. (ep->ep_type << EP_CTRL_BUFFER_TYPE_LSB) |
  71. dpram_offset;
  72. *ep->endpoint_control = reg;
  73. }
  74. /**
  75. * @brief Starts a transfer on a given endpoint.
  76. *
  77. * @param ep, the endpoint configuration.
  78. * @param buf, the data buffer to send. Only applicable if the endpoint is TX
  79. * @param len, the length of the data in buf (this example limits max len to one packet - 64 bytes)
  80. */
  81. static void usb_start_transfer(struct rp2040_ep_state *ep, uint8_t *buf, uint16_t len)
  82. {
  83. /*!< Prepare buffer control register value */
  84. uint32_t val = len | USB_BUF_CTRL_AVAIL;
  85. if (len < ep->ep_mps) {
  86. val |= USB_BUF_CTRL_LAST;
  87. }
  88. if (USB_EP_DIR_IS_IN(ep->ep_addr)) {
  89. /*!< Need to copy the data from the user buffer to the usb memory */
  90. if (buf != NULL) {
  91. memcpy((void *)ep->data_buffer, (void *)buf, len);
  92. }
  93. /*!< Mark as full */
  94. val |= USB_BUF_CTRL_FULL;
  95. }
  96. /*!< Set pid and flip for next transfer */
  97. val |= ep->next_pid ? USB_BUF_CTRL_DATA1_PID : USB_BUF_CTRL_DATA0_PID;
  98. ep->next_pid ^= 1u;
  99. *ep->buffer_control = val;
  100. }
  101. int usb_dc_init(uint8_t busid)
  102. {
  103. uint8_t *next_buffer_ptr;
  104. memset(&g_rp2040_udc, 0, sizeof(struct rp2040_udc));
  105. g_rp2040_udc.in_ep[0].endpoint_control = NULL;
  106. g_rp2040_udc.in_ep[0].data_buffer = &usb_dpram->ep0_buf_a[0];
  107. g_rp2040_udc.out_ep[0].endpoint_control = NULL;
  108. g_rp2040_udc.out_ep[0].data_buffer = &usb_dpram->ep0_buf_a[0];
  109. for (uint32_t i = 0; i < CONFIG_USBDEV_EP_NUM; i++) {
  110. g_rp2040_udc.in_ep[i].buffer_control = &usb_dpram->ep_buf_ctrl[i].in;
  111. g_rp2040_udc.out_ep[i].buffer_control = &usb_dpram->ep_buf_ctrl[i].out;
  112. if (i != 0) {
  113. g_rp2040_udc.in_ep[i].endpoint_control = &usb_dpram->ep_ctrl[i - 1].in;
  114. g_rp2040_udc.out_ep[i].endpoint_control = &usb_dpram->ep_ctrl[i - 1].out;
  115. }
  116. }
  117. next_buffer_ptr = &usb_dpram->epx_data[0];
  118. for (uint32_t i = 1; i < CONFIG_USBDEV_EP_NUM; i++) {
  119. g_rp2040_udc.in_ep[i].data_buffer = next_buffer_ptr;
  120. if (i == 1) {
  121. next_buffer_ptr += 1024; /* for iso video */
  122. } else {
  123. next_buffer_ptr += 64;
  124. }
  125. g_rp2040_udc.out_ep[i].data_buffer = next_buffer_ptr;
  126. next_buffer_ptr += 64;
  127. }
  128. // Remove shared irq if it was previously added so as not to fill up shared irq slots
  129. irq_remove_handler(USBCTRL_IRQ, rp2040_usbd_irq);
  130. irq_add_shared_handler(USBCTRL_IRQ, rp2040_usbd_irq, PICO_SHARED_IRQ_HANDLER_HIGHEST_ORDER_PRIORITY);
  131. // Reset usb controller
  132. reset_unreset_block_num_wait_blocking(RESET_USBCTRL);
  133. /*!< Clear any previous state just in case */
  134. memset(usb_hw, 0, sizeof(*usb_hw));
  135. memset(usb_dpram, 0, sizeof(*usb_dpram));
  136. /*!< Mux the controller to the onboard usb phy */
  137. usb_hw->muxing = USB_USB_MUXING_TO_PHY_BITS | USB_USB_MUXING_SOFTCON_BITS;
  138. #if FORCE_VBUS_DETECT
  139. // Force VBUS detect so the device thinks it is plugged into a host
  140. usb_hw->pwr = USB_USB_PWR_VBUS_DETECT_BITS | USB_USB_PWR_VBUS_DETECT_OVERRIDE_EN_BITS;
  141. #endif
  142. // Enable the USB controller in device mode.
  143. usb_hw->main_ctrl = USB_MAIN_CTRL_CONTROLLER_EN_BITS;
  144. // Enable an interrupt per EP0 transaction
  145. usb_hw->sie_ctrl = USB_SIE_CTRL_EP0_INT_1BUF_BITS; // <2>
  146. // Enable interrupts for when a buffer is done, when the bus is reset,
  147. // and when a setup packet is received
  148. usb_hw->inte = USB_INTS_BUFF_STATUS_BITS | USB_INTS_BUS_RESET_BITS | USB_INTS_SETUP_REQ_BITS |
  149. USB_INTS_DEV_SUSPEND_BITS | USB_INTS_DEV_RESUME_FROM_HOST_BITS |
  150. (FORCE_VBUS_DETECT ? 0 : USB_INTS_DEV_CONN_DIS_BITS);
  151. // Enable USB interrupt at processor
  152. irq_set_enabled(USBCTRL_IRQ, true);
  153. usb_hw_set->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
  154. return 0;
  155. }
  156. int usb_dc_deinit(uint8_t busid)
  157. {
  158. irq_set_enabled(USBCTRL_IRQ, false);
  159. // Remove shared irq if it was previously added so as not to fill up shared irq slots
  160. irq_remove_handler(USBCTRL_IRQ, rp2040_usbd_irq);
  161. usb_hw_clear->sie_ctrl = USB_SIE_CTRL_PULLUP_EN_BITS;
  162. memset(&g_rp2040_udc, 0, sizeof(struct rp2040_udc));
  163. return 0;
  164. }
  165. int usbd_set_address(uint8_t busid, const uint8_t addr)
  166. {
  167. g_rp2040_udc.dev_addr = addr;
  168. return 0;
  169. }
  170. int usbd_set_remote_wakeup(uint8_t busid)
  171. {
  172. return -1;
  173. }
  174. uint8_t usbd_get_port_speed(uint8_t busid)
  175. {
  176. return USB_SPEED_FULL;
  177. }
  178. int usbd_ep_open(uint8_t busid, const struct usb_endpoint_descriptor *ep)
  179. {
  180. uint8_t ep_idx = USB_EP_GET_IDX(ep->bEndpointAddress);
  181. if (USB_EP_DIR_IS_OUT(ep->bEndpointAddress)) {
  182. g_rp2040_udc.out_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
  183. g_rp2040_udc.out_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
  184. g_rp2040_udc.out_ep[ep_idx].ep_addr = ep->bEndpointAddress;
  185. g_rp2040_udc.out_ep[ep_idx].ep_enable = true;
  186. /*!< Clear control reg */
  187. *(g_rp2040_udc.out_ep[ep_idx].buffer_control) = 0;
  188. usb_setup_endpoint(&g_rp2040_udc.out_ep[ep_idx]);
  189. } else {
  190. g_rp2040_udc.in_ep[ep_idx].ep_mps = USB_GET_MAXPACKETSIZE(ep->wMaxPacketSize);
  191. g_rp2040_udc.in_ep[ep_idx].ep_type = USB_GET_ENDPOINT_TYPE(ep->bmAttributes);
  192. g_rp2040_udc.in_ep[ep_idx].ep_addr = ep->bEndpointAddress;
  193. g_rp2040_udc.in_ep[ep_idx].ep_enable = true;
  194. /*!< Clear control reg */
  195. *(g_rp2040_udc.in_ep[ep_idx].buffer_control) = 0;
  196. usb_setup_endpoint(&g_rp2040_udc.in_ep[ep_idx]);
  197. }
  198. return 0;
  199. }
  200. int usbd_ep_close(uint8_t busid, const uint8_t ep)
  201. {
  202. if (USB_EP_DIR_IS_IN(ep)) {
  203. } else if (USB_EP_DIR_IS_OUT(ep)) {
  204. }
  205. return 0;
  206. }
  207. int usbd_ep_set_stall(uint8_t busid, const uint8_t ep)
  208. {
  209. if (USB_EP_GET_IDX(ep) == 0) {
  210. /**
  211. * A stall on EP0 has to be armed so it can be cleared on the next setup packet
  212. */
  213. usb_hw_set->ep_stall_arm = (USB_EP_DIR_IS_IN(ep)) ? USB_EP_STALL_ARM_EP0_IN_BITS : USB_EP_STALL_ARM_EP0_OUT_BITS;
  214. }
  215. if (USB_EP_DIR_IS_OUT(ep)) {
  216. *(g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].buffer_control) = USB_BUF_CTRL_STALL;
  217. } else {
  218. *(g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].buffer_control) = USB_BUF_CTRL_STALL;
  219. }
  220. return 0;
  221. }
  222. int usbd_ep_clear_stall(uint8_t busid, const uint8_t ep)
  223. {
  224. uint8_t ep_idx = USB_EP_GET_IDX(ep);
  225. if (ep_idx != 0) {
  226. if (USB_EP_DIR_IS_OUT(ep)) {
  227. g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].next_pid = 0;
  228. *(g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].buffer_control) = ~USB_BUF_CTRL_STALL;
  229. } else {
  230. g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].next_pid = 0;
  231. *(g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].buffer_control) = ~USB_BUF_CTRL_STALL;
  232. }
  233. }
  234. return 0;
  235. }
  236. int usbd_ep_is_stalled(uint8_t busid, const uint8_t ep, uint8_t *stalled)
  237. {
  238. if (USB_EP_DIR_IS_OUT(ep)) {
  239. if (*(g_rp2040_udc.out_ep[USB_EP_GET_IDX(ep)].buffer_control) & USB_BUF_CTRL_STALL) {
  240. *stalled = 1;
  241. } else {
  242. *stalled = 0;
  243. }
  244. } else {
  245. if (*(g_rp2040_udc.in_ep[USB_EP_GET_IDX(ep)].buffer_control) & USB_BUF_CTRL_STALL) {
  246. *stalled = 1;
  247. } else {
  248. *stalled = 0;
  249. }
  250. }
  251. return 0;
  252. }
  253. int usbd_ep_start_write(uint8_t busid, const uint8_t ep, const uint8_t *data, uint32_t data_len)
  254. {
  255. uint8_t ep_idx = USB_EP_GET_IDX(ep);
  256. if (!data && data_len) {
  257. return -1;
  258. }
  259. if (!g_rp2040_udc.in_ep[ep_idx].ep_enable) {
  260. return -2;
  261. }
  262. g_rp2040_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
  263. g_rp2040_udc.in_ep[ep_idx].xfer_len = data_len;
  264. g_rp2040_udc.in_ep[ep_idx].actual_xfer_len = 0;
  265. if (data_len == 0) {
  266. usb_start_transfer(&g_rp2040_udc.in_ep[ep_idx], NULL, 0);
  267. } else {
  268. data_len = MIN(data_len, g_rp2040_udc.in_ep[ep_idx].ep_mps);
  269. usb_start_transfer(&g_rp2040_udc.in_ep[ep_idx], g_rp2040_udc.in_ep[ep_idx].xfer_buf, data_len);
  270. }
  271. return 0;
  272. }
  273. int usbd_ep_start_read(uint8_t busid, const uint8_t ep, uint8_t *data, uint32_t data_len)
  274. {
  275. uint8_t ep_idx = USB_EP_GET_IDX(ep);
  276. if (!data && data_len) {
  277. return -1;
  278. }
  279. if (!g_rp2040_udc.out_ep[ep_idx].ep_enable) {
  280. return -2;
  281. }
  282. g_rp2040_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
  283. g_rp2040_udc.out_ep[ep_idx].xfer_len = data_len;
  284. g_rp2040_udc.out_ep[ep_idx].actual_xfer_len = 0;
  285. if (data_len == 0) {
  286. usb_start_transfer(&g_rp2040_udc.out_ep[ep_idx], NULL, 0);
  287. } else {
  288. /*!< Not zlp */
  289. data_len = MIN(data_len, g_rp2040_udc.out_ep[ep_idx].ep_mps);
  290. usb_start_transfer(&g_rp2040_udc.out_ep[ep_idx], g_rp2040_udc.out_ep[ep_idx].xfer_buf, data_len);
  291. }
  292. return 0;
  293. }
  294. /**
  295. * @brief Notify an endpoint that a transfer has completed.
  296. *
  297. * @param ep, the endpoint to notify.
  298. */
  299. static void usb_handle_ep_buff_done(struct rp2040_ep_state *ep)
  300. {
  301. uint32_t buffer_control = *ep->buffer_control;
  302. /*!< Get the transfer length for this endpoint */
  303. uint16_t read_count = buffer_control & USB_BUF_CTRL_LEN_MASK;
  304. /*!< Call that endpoints buffer done handler */
  305. if (ep->ep_addr == 0x80) {
  306. /*!< EP0 In */
  307. /**
  308. * Determine the current setup direction
  309. */
  310. switch (g_rp2040_udc.setup.bmRequestType >> USB_REQUEST_DIR_SHIFT) {
  311. case 1:
  312. /*!< Get */
  313. if (g_rp2040_udc.in_ep[0].xfer_len > g_rp2040_udc.in_ep[0].ep_mps) {
  314. g_rp2040_udc.in_ep[0].xfer_len -= g_rp2040_udc.in_ep[0].ep_mps;
  315. g_rp2040_udc.in_ep[0].actual_xfer_len += g_rp2040_udc.in_ep[0].ep_mps;
  316. usbd_event_ep_in_complete_handler(0, 0 | 0x80, g_rp2040_udc.in_ep[0].actual_xfer_len);
  317. } else {
  318. g_rp2040_udc.in_ep[0].actual_xfer_len += g_rp2040_udc.in_ep[0].xfer_len;
  319. g_rp2040_udc.in_ep[0].xfer_len = 0;
  320. /**
  321. * EP0 In complete and host will send a out token to get 0 length packet
  322. * In the next usbd_event_ep_in_complete_handler, stack will start read 0 length packet
  323. * and host must send data1 packet.We resest the ep0 next_pid = 1 in setup interrupt head.
  324. */
  325. usbd_event_ep_in_complete_handler(0, 0 | 0x80, g_rp2040_udc.in_ep[0].actual_xfer_len);
  326. }
  327. break;
  328. case 0:
  329. /*!< Set */
  330. if (g_rp2040_udc.dev_addr > 0) {
  331. usb_hw->dev_addr_ctrl = g_rp2040_udc.dev_addr;
  332. g_rp2040_udc.dev_addr = 0;
  333. } else {
  334. /*!< Normal status stage // Setup out...out in */
  335. /**
  336. * Perpar for next setup
  337. */
  338. }
  339. break;
  340. }
  341. } else if (ep->ep_addr == 0x00) {
  342. /*!< EP0 Out */
  343. memcpy(g_rp2040_udc.out_ep[0].xfer_buf, g_rp2040_udc.out_ep[0].data_buffer, read_count);
  344. if (read_count == 0) {
  345. /*!< Normal status stage // Setup in...in out */
  346. /**
  347. * Perpar for next setup
  348. */
  349. }
  350. g_rp2040_udc.out_ep[0].actual_xfer_len += read_count;
  351. g_rp2040_udc.out_ep[0].xfer_len -= read_count;
  352. usbd_event_ep_out_complete_handler(0, 0x00, g_rp2040_udc.out_ep[0].actual_xfer_len);
  353. } else {
  354. /*!< Others ep */
  355. uint16_t data_len = 0;
  356. if (USB_EP_DIR_IS_OUT(ep->ep_addr)) {
  357. /*!< flip the pid */
  358. memcpy(g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_buf, g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].data_buffer, read_count);
  359. g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_buf += read_count;
  360. g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].actual_xfer_len += read_count;
  361. g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_len -= read_count;
  362. if (read_count < g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].ep_mps || g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_len == 0) {
  363. /*!< Out complete */
  364. usbd_event_ep_out_complete_handler(0, ep->ep_addr, g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].actual_xfer_len);
  365. } else {
  366. /*!< Need read again */
  367. data_len = MIN(g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].xfer_len, g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f].ep_mps);
  368. usb_start_transfer(&g_rp2040_udc.out_ep[(ep->ep_addr) & 0x0f], NULL, data_len);
  369. }
  370. } else {
  371. if (g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len > g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps) {
  372. /*!< Need tx again */
  373. g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len -= g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps;
  374. g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_buf += g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps;
  375. g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].actual_xfer_len += g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps;
  376. data_len = MIN(g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len, g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].ep_mps);
  377. usb_start_transfer(&g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f], g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_buf, data_len);
  378. } else {
  379. /*!< In complete */
  380. g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].actual_xfer_len += g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len;
  381. g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].xfer_len = 0;
  382. usbd_event_ep_in_complete_handler(0, ep->ep_addr, g_rp2040_udc.in_ep[(ep->ep_addr) & 0x0f].actual_xfer_len);
  383. }
  384. }
  385. }
  386. }
  387. /**
  388. * @brief Find the endpoint configuration for a specified endpoint number and
  389. * direction and notify it that a transfer has completed.
  390. *
  391. * @param ep_num
  392. * @param in
  393. */
  394. static void usb_handle_buff_done(uint8_t ep_num, bool in)
  395. {
  396. uint8_t ep_addr = ep_num | (in ? USB_EP_DIR_IN : 0);
  397. if (USB_EP_DIR_IS_OUT(ep_addr)) {
  398. usb_handle_ep_buff_done(&g_rp2040_udc.out_ep[ep_num]);
  399. } else {
  400. usb_handle_ep_buff_done(&g_rp2040_udc.in_ep[ep_num]);
  401. }
  402. }
  403. /**
  404. * @brief Handle a "buffer status" irq. This means that one or more
  405. * buffers have been sent / received. Notify each endpoint where this
  406. * is the case.
  407. */
  408. static void usb_handle_buff_status(void)
  409. {
  410. uint32_t remaining_buffers = usb_hw->buf_status;
  411. uint32_t bit = 1u;
  412. for (uint8_t i = 0; remaining_buffers && i < USB_NUM_ENDPOINTS * 2; i++) {
  413. if (remaining_buffers & bit) {
  414. /*!< clear this in advance */
  415. usb_hw_clear->buf_status = bit;
  416. /*!< IN transfer for even i, OUT transfer for odd i */
  417. usb_handle_buff_done(i >> 1u, !(i & 1u));
  418. remaining_buffers &= ~bit;
  419. }
  420. bit <<= 1u;
  421. }
  422. }
  423. void USBD_IRQHandler(uint8_t busid)
  424. {
  425. uint32_t const status = usb_hw->ints;
  426. uint32_t handled = 0;
  427. if (status & USB_INTS_BUFF_STATUS_BITS) {
  428. handled |= USB_INTS_BUFF_STATUS_BITS;
  429. usb_handle_buff_status();
  430. }
  431. if (status & USB_INTS_SETUP_REQ_BITS) {
  432. handled |= USB_INTS_SETUP_REQ_BITS;
  433. memcpy((uint8_t *)&g_rp2040_udc.setup, (uint8_t const *)&usb_dpram->setup_packet, 8);
  434. /**
  435. * reset pid to both 1 (data and ack)
  436. */
  437. g_rp2040_udc.in_ep[0].next_pid = 1;
  438. g_rp2040_udc.out_ep[0].next_pid = 1;
  439. usbd_event_ep0_setup_complete_handler(0, (uint8_t *)&g_rp2040_udc.setup);
  440. usb_hw_clear->sie_status = USB_SIE_STATUS_SETUP_REC_BITS;
  441. }
  442. #if FORCE_VBUS_DETECT == 0
  443. /**
  444. * Since we force VBUS detect On, device will always think it is connected and
  445. * couldn't distinguish between disconnect and suspend
  446. */
  447. if (status & USB_INTS_DEV_CONN_DIS_BITS) {
  448. handled |= USB_INTS_DEV_CONN_DIS_BITS;
  449. if (usb_hw->sie_status & USB_SIE_STATUS_CONNECTED_BITS) {
  450. /*!< Connected: nothing to do */
  451. usbd_event_connect_handler(0);
  452. } else {
  453. /*!< Disconnected */
  454. usbd_event_disconnect_handler(0);
  455. }
  456. usb_hw_clear->sie_status = USB_SIE_STATUS_CONNECTED_BITS;
  457. }
  458. #endif
  459. /**
  460. * SE0 for 2.5 us or more (will last at least 10ms)
  461. */
  462. if (status & USB_INTS_BUS_RESET_BITS) {
  463. handled |= USB_INTS_BUS_RESET_BITS;
  464. usb_hw_clear->sie_status = USB_SIE_STATUS_BUS_RESET_BITS;
  465. usb_hw->dev_addr_ctrl = 0;
  466. for (uint8_t i = 0; i < CONFIG_USBDEV_EP_NUM - 1; i++) {
  467. /*!< Start at ep1 */
  468. usb_dpram->ep_ctrl[i].in = 0;
  469. usb_dpram->ep_ctrl[i].out = 0;
  470. }
  471. usbd_event_reset_handler(0);
  472. #if CHERRYUSB_OPT_RP2040_USB_DEVICE_ENUMERATION_FIX
  473. /**
  474. * Only run enumeration walk-around if pull up is enabled
  475. */
  476. if (usb_hw->sie_ctrl & USB_SIE_CTRL_PULLUP_EN_BITS)
  477. rp2040_usb_device_enumeration_fix();
  478. #endif
  479. }
  480. /**
  481. * Note from pico datasheet 4.1.2.6.4 (v1.2)
  482. * If you enable the suspend interrupt, it is likely you will see a suspend interrupt when
  483. * the device is first connected but the bus is idle. The bus can be idle for a few ms before
  484. * the host begins sending start of frame packets. You will also see a suspend interrupt
  485. * when the device is disconnected if you do not have a VBUS detect circuit connected. This is
  486. * because without VBUS detection, it is impossible to tell the difference between
  487. * being disconnected and suspended.
  488. */
  489. if (status & USB_INTS_DEV_SUSPEND_BITS) {
  490. handled |= USB_INTS_DEV_SUSPEND_BITS;
  491. /*!< Suspend */
  492. usb_hw_clear->sie_status = USB_SIE_STATUS_SUSPENDED_BITS;
  493. usbd_event_suspend_handler(0);
  494. }
  495. if (status & USB_INTS_DEV_RESUME_FROM_HOST_BITS) {
  496. handled |= USB_INTS_DEV_RESUME_FROM_HOST_BITS;
  497. /*!< Resume */
  498. usb_hw_clear->sie_status = USB_SIE_STATUS_RESUME_BITS;
  499. usbd_event_resume_handler(0);
  500. }
  501. if (status ^ handled) {
  502. USB_LOG_INFO("Unhandled IRQ 0x%x\n", (uint32_t)(status ^ handled));
  503. }
  504. }
  505. void rp2040_usbd_irq(void)
  506. {
  507. USBD_IRQHandler(0);
  508. }