usbd_cdc_ecm.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * Copyright (c) 2023, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbd_core.h"
  7. #include "usbd_cdc_ecm.h"
  8. #define CDC_ECM_OUT_EP_IDX 0
  9. #define CDC_ECM_IN_EP_IDX 1
  10. #define CDC_ECM_INT_EP_IDX 2
  11. /* Ethernet Maximum Segment size, typically 1514 bytes */
  12. #define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1536U
  13. /* Describe EndPoints configuration */
  14. static struct usbd_endpoint cdc_ecm_ep_data[3];
  15. #ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
  16. static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
  17. static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE];
  18. #endif
  19. static USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16];
  20. volatile uint32_t g_cdc_ecm_rx_data_length = 0;
  21. volatile uint32_t g_cdc_ecm_tx_data_length = 0;
  22. static volatile uint8_t g_current_net_status = 0;
  23. static volatile uint8_t g_cmd_intf = 0;
  24. static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM,
  25. CDC_ECM_CONNECT_SPEED_DOWNSTREAM };
  26. void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed)
  27. {
  28. struct cdc_eth_notification *notify = (struct cdc_eth_notification *)g_cdc_ecm_notify_buf;
  29. uint8_t bytes2send = 0;
  30. notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM;
  31. notify->bNotificationType = notifycode;
  32. switch (notifycode) {
  33. case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION:
  34. notify->wValue = value;
  35. notify->wIndex = g_cmd_intf;
  36. notify->wLength = 0U;
  37. for (uint8_t i = 0U; i < 8U; i++) {
  38. notify->data[i] = 0U;
  39. }
  40. bytes2send = 8U;
  41. break;
  42. case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE:
  43. notify->wValue = 0U;
  44. notify->wIndex = g_cmd_intf;
  45. notify->wLength = 0U;
  46. for (uint8_t i = 0U; i < 8U; i++) {
  47. notify->data[i] = 0U;
  48. }
  49. bytes2send = 8U;
  50. break;
  51. case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE:
  52. notify->wValue = 0U;
  53. notify->wIndex = g_cmd_intf;
  54. notify->wLength = 0x0008U;
  55. bytes2send = 16U;
  56. memcpy(notify->data, speed, 8);
  57. break;
  58. default:
  59. break;
  60. }
  61. if (usb_device_is_configured(0)) {
  62. if (bytes2send) {
  63. usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send);
  64. }
  65. }
  66. }
  67. static int cdc_ecm_class_interface_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
  68. {
  69. USB_LOG_DBG("CDC ECM Class request: "
  70. "bRequest 0x%02x\r\n",
  71. setup->bRequest);
  72. (void)busid;
  73. (void)data;
  74. (void)len;
  75. g_cmd_intf = LO_BYTE(setup->wIndex);
  76. switch (setup->bRequest) {
  77. case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER:
  78. /* bit0 Promiscuous
  79. * bit1 ALL Multicast
  80. * bit2 Directed
  81. * bit3 Broadcast
  82. * bit4 Multicast
  83. */
  84. #ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
  85. g_connect_speed_table[0] = 100000000; /* 100 Mbps */
  86. g_connect_speed_table[1] = 100000000; /* 100 Mbps */
  87. usbd_cdc_ecm_set_connect(true, g_connect_speed_table);
  88. #endif
  89. break;
  90. default:
  91. USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest);
  92. return -1;
  93. }
  94. return 0;
  95. }
  96. void cdc_ecm_notify_handler(uint8_t busid, uint8_t event, void *arg)
  97. {
  98. (void)busid;
  99. (void)arg;
  100. switch (event) {
  101. case USBD_EVENT_RESET:
  102. g_current_net_status = 0;
  103. g_cdc_ecm_rx_data_length = 0;
  104. g_cdc_ecm_tx_data_length = 0;
  105. break;
  106. case USBD_EVENT_CONFIGURED:
  107. #ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
  108. usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
  109. #endif
  110. break;
  111. default:
  112. break;
  113. }
  114. }
  115. void cdc_ecm_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
  116. {
  117. (void)busid;
  118. g_cdc_ecm_rx_data_length = nbytes;
  119. usbd_cdc_ecm_data_recv_done(g_cdc_ecm_rx_data_length);
  120. }
  121. void cdc_ecm_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
  122. {
  123. (void)busid;
  124. if ((nbytes % usbd_get_ep_mps(0, ep)) == 0 && nbytes) {
  125. /* send zlp */
  126. usbd_ep_start_write(0, ep, NULL, 0);
  127. } else {
  128. usbd_cdc_ecm_data_send_done(g_cdc_ecm_tx_data_length);
  129. g_cdc_ecm_tx_data_length = 0;
  130. }
  131. }
  132. void cdc_ecm_int_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
  133. {
  134. (void)busid;
  135. (void)ep;
  136. (void)nbytes;
  137. if (g_current_net_status == 2) {
  138. g_current_net_status = 3;
  139. usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE, 0, g_connect_speed_table);
  140. } else {
  141. g_current_net_status = 0;
  142. }
  143. }
  144. int usbd_cdc_ecm_start_write(uint8_t *buf, uint32_t len)
  145. {
  146. if (!usb_device_is_configured(0)) {
  147. return -USB_ERR_NODEV;
  148. }
  149. if (g_cdc_ecm_tx_data_length > 0) {
  150. return -USB_ERR_BUSY;
  151. }
  152. g_cdc_ecm_tx_data_length = len;
  153. USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length);
  154. return usbd_ep_start_write(0, cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, buf, len);
  155. }
  156. int usbd_cdc_ecm_start_read(uint8_t *buf, uint32_t len)
  157. {
  158. if (!usb_device_is_configured(0)) {
  159. return -USB_ERR_NODEV;
  160. }
  161. g_cdc_ecm_rx_data_length = 0;
  162. return usbd_ep_start_read(0, cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, buf, len);
  163. }
  164. #ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP
  165. struct pbuf *usbd_cdc_ecm_eth_rx(void)
  166. {
  167. struct pbuf *p;
  168. if (g_cdc_ecm_rx_data_length == 0) {
  169. return NULL;
  170. }
  171. p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL);
  172. if (p == NULL) {
  173. usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
  174. return NULL;
  175. }
  176. usb_memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length);
  177. p->len = g_cdc_ecm_rx_data_length;
  178. USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length);
  179. usbd_cdc_ecm_start_read(g_cdc_ecm_rx_buffer, CONFIG_CDC_ECM_ETH_MAX_SEGSZE);
  180. return p;
  181. }
  182. int usbd_cdc_ecm_eth_tx(struct pbuf *p)
  183. {
  184. struct pbuf *q;
  185. uint8_t *buffer;
  186. if (g_cdc_ecm_tx_data_length > 0) {
  187. return -USB_ERR_BUSY;
  188. }
  189. if (p->tot_len > sizeof(g_cdc_ecm_tx_buffer)) {
  190. p->tot_len = sizeof(g_cdc_ecm_tx_buffer);
  191. }
  192. buffer = g_cdc_ecm_tx_buffer;
  193. for (q = p; q != NULL; q = q->next) {
  194. usb_memcpy(buffer, q->payload, q->len);
  195. buffer += q->len;
  196. }
  197. return usbd_cdc_ecm_start_write(g_cdc_ecm_tx_buffer, p->tot_len);
  198. }
  199. #endif
  200. struct usbd_interface *usbd_cdc_ecm_init_intf(struct usbd_interface *intf, const uint8_t int_ep, const uint8_t out_ep, const uint8_t in_ep)
  201. {
  202. intf->class_interface_handler = cdc_ecm_class_interface_request_handler;
  203. intf->class_endpoint_handler = NULL;
  204. intf->vendor_handler = NULL;
  205. intf->notify_handler = cdc_ecm_notify_handler;
  206. cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr = out_ep;
  207. cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_cb = cdc_ecm_bulk_out;
  208. cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr = in_ep;
  209. cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_cb = cdc_ecm_bulk_in;
  210. cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr = int_ep;
  211. cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_cb = cdc_ecm_int_in;
  212. usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]);
  213. usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]);
  214. usbd_add_endpoint(0, &cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]);
  215. return intf;
  216. }
  217. void usbd_cdc_ecm_set_connect(bool connect, uint32_t speed[2])
  218. {
  219. if (connect) {
  220. g_current_net_status = 2;
  221. memcpy(g_connect_speed_table, speed, 8);
  222. usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL);
  223. } else {
  224. g_current_net_status = 1;
  225. usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_DISCONNECTED, NULL);
  226. }
  227. }
  228. __WEAK void usbd_cdc_ecm_data_recv_done(uint32_t len)
  229. {
  230. (void)len;
  231. }
  232. __WEAK void usbd_cdc_ecm_data_send_done(uint32_t len)
  233. {
  234. (void)len;
  235. }