cdc_ecm_template.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. * Copyright (c) 2024, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbd_core.h"
  7. #include "usbd_cdc_ecm.h"
  8. #ifndef CONFIG_USBDEV_CDC_ECM_USING_LWIP
  9. #error "Please enable CONFIG_USBDEV_CDC_ECM_USING_LWIP for this demo"
  10. #endif
  11. /*!< endpoint address */
  12. #define CDC_IN_EP 0x81
  13. #define CDC_OUT_EP 0x02
  14. #define CDC_INT_EP 0x83
  15. #define USBD_VID 0xFFFF
  16. #define USBD_PID 0xFFFF
  17. #define USBD_MAX_POWER 100
  18. #define USBD_LANGID_STRING 1033
  19. /*!< config descriptor size */
  20. #define USB_CONFIG_SIZE (9 + CDC_ECM_DESCRIPTOR_LEN)
  21. #ifdef CONFIG_USB_HS
  22. #define CDC_MAX_MPS 512
  23. #else
  24. #define CDC_MAX_MPS 64
  25. #endif
  26. /* str idx = 4 is for mac address: aa:bb:cc:dd:ee:ff*/
  27. #define CDC_ECM_MAC_STRING_INDEX 4
  28. static const uint8_t device_descriptor[] = {
  29. USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01)
  30. };
  31. static const uint8_t config_descriptor[] = {
  32. USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER),
  33. CDC_ECM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, CDC_ECM_MAC_STRING_INDEX)
  34. };
  35. static const uint8_t device_quality_descriptor[] = {
  36. ///////////////////////////////////////
  37. /// device qualifier descriptor
  38. ///////////////////////////////////////
  39. 0x0a,
  40. USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER,
  41. 0x00,
  42. 0x02,
  43. 0x00,
  44. 0x00,
  45. 0x00,
  46. 0x40,
  47. 0x00,
  48. 0x00,
  49. };
  50. static const char *string_descriptors[] = {
  51. (const char[]){ 0x09, 0x04 }, /* Langid */
  52. "CherryUSB", /* Manufacturer */
  53. "CherryUSB CDC ECM DEMO", /* Product */
  54. "2022123456", /* Serial Number */
  55. "aabbccddeeff", /* ecm mac address */
  56. };
  57. static const uint8_t *device_descriptor_callback(uint8_t speed)
  58. {
  59. return device_descriptor;
  60. }
  61. static const uint8_t *config_descriptor_callback(uint8_t speed)
  62. {
  63. return config_descriptor;
  64. }
  65. static const uint8_t *device_quality_descriptor_callback(uint8_t speed)
  66. {
  67. return device_quality_descriptor;
  68. }
  69. static const char *string_descriptor_callback(uint8_t speed, uint8_t index)
  70. {
  71. if (index > 4) {
  72. return NULL;
  73. }
  74. return string_descriptors[index];
  75. }
  76. const struct usb_descriptor cdc_ecm_descriptor = {
  77. .device_descriptor_callback = device_descriptor_callback,
  78. .config_descriptor_callback = config_descriptor_callback,
  79. .device_quality_descriptor_callback = device_quality_descriptor_callback,
  80. .string_descriptor_callback = string_descriptor_callback
  81. };
  82. const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
  83. volatile bool cdc_ecm_tx_done = false;
  84. void usbd_cdc_ecm_data_send_done(uint32_t len)
  85. {
  86. cdc_ecm_tx_done = true; // suggest you to use semaphore in os
  87. }
  88. #ifdef RT_USING_LWIP
  89. #ifndef RT_LWIP_DHCP
  90. #error cdc_ecm must enable RT_LWIP_DHCP
  91. #endif
  92. #ifndef LWIP_USING_DHCPD
  93. #error cdc_ecm must enable LWIP_USING_DHCPD
  94. #endif
  95. #include <rtthread.h>
  96. #include <rtdevice.h>
  97. #include <netif/ethernetif.h>
  98. #include <dhcp_server.h>
  99. struct eth_device cdc_ecm_dev;
  100. static rt_err_t rt_usbd_cdc_ecm_control(rt_device_t dev, int cmd, void *args)
  101. {
  102. switch (cmd) {
  103. case NIOCTL_GADDR:
  104. /* get mac address */
  105. if (args) {
  106. uint8_t *mac_dev = (uint8_t *)args;
  107. rt_memcpy(mac_dev, mac, 6);
  108. mac_dev[5] = ~mac_dev[5]; /* device mac can't same as host. */
  109. } else
  110. return -RT_ERROR;
  111. break;
  112. default:
  113. break;
  114. }
  115. return RT_EOK;
  116. }
  117. struct pbuf *rt_usbd_cdc_ecm_eth_rx(rt_device_t dev)
  118. {
  119. return usbd_cdc_ecm_eth_rx();
  120. }
  121. rt_err_t rt_usbd_cdc_ecm_eth_tx(rt_device_t dev, struct pbuf *p)
  122. {
  123. int ret;
  124. cdc_ecm_tx_done = false;
  125. ret = usbd_cdc_ecm_eth_tx(p);
  126. if (ret == 0) {
  127. while (!cdc_ecm_tx_done) {
  128. }
  129. return RT_EOK;
  130. } else
  131. return -RT_ERROR;
  132. }
  133. void cdc_ecm_lwip_init(void)
  134. {
  135. cdc_ecm_dev.parent.control = rt_usbd_cdc_ecm_control;
  136. cdc_ecm_dev.eth_rx = rt_usbd_cdc_ecm_eth_rx;
  137. cdc_ecm_dev.eth_tx = rt_usbd_cdc_ecm_eth_tx;
  138. eth_device_init(&cdc_ecm_dev, "u0");
  139. eth_device_linkchange(&cdc_ecm_dev, RT_TRUE);
  140. dhcpd_start("u0");
  141. }
  142. void usbd_cdc_ecm_data_recv_done(uint32_t len)
  143. {
  144. eth_device_ready(&cdc_ecm_dev);
  145. }
  146. #else
  147. #include "netif/etharp.h"
  148. #include "lwip/init.h"
  149. #include "lwip/netif.h"
  150. #include "lwip/pbuf.h"
  151. #include "dhserver.h"
  152. #include "dnserver.h"
  153. /*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
  154. #define IP_ADDR0 (uint8_t)192
  155. #define IP_ADDR1 (uint8_t)168
  156. #define IP_ADDR2 (uint8_t)7
  157. #define IP_ADDR3 (uint8_t)1
  158. /*NETMASK*/
  159. #define NETMASK_ADDR0 (uint8_t)255
  160. #define NETMASK_ADDR1 (uint8_t)255
  161. #define NETMASK_ADDR2 (uint8_t)255
  162. #define NETMASK_ADDR3 (uint8_t)0
  163. /*Gateway Address*/
  164. #define GW_ADDR0 (uint8_t)0
  165. #define GW_ADDR1 (uint8_t)0
  166. #define GW_ADDR2 (uint8_t)0
  167. #define GW_ADDR3 (uint8_t)0
  168. const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
  169. const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
  170. const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
  171. #define NUM_DHCP_ENTRY 3
  172. static dhcp_entry_t entries[NUM_DHCP_ENTRY] = {
  173. /* mac ip address subnet mask lease time */
  174. { { 0 }, { 192, 168, 7, 2 }, { 255, 255, 255, 0 }, 24 * 60 * 60 },
  175. { { 0 }, { 192, 168, 7, 3 }, { 255, 255, 255, 0 }, 24 * 60 * 60 },
  176. { { 0 }, { 192, 168, 7, 4 }, { 255, 255, 255, 0 }, 24 * 60 * 60 }
  177. };
  178. static dhcp_config_t dhcp_config = {
  179. { 192, 168, 7, 1 }, /* server address */
  180. 67, /* port */
  181. { 192, 168, 7, 1 }, /* dns server */
  182. "cherry", /* dns suffix */
  183. NUM_DHCP_ENTRY, /* num entry */
  184. entries /* entries */
  185. };
  186. static bool dns_query_proc(const char *name, ip_addr_t *addr)
  187. {
  188. if (strcmp(name, "cdc_ecm.cherry") == 0 || strcmp(name, "www.cdc_ecm.cherry") == 0) {
  189. addr->addr = ipaddr.addr;
  190. return true;
  191. }
  192. return false;
  193. }
  194. static struct netif cdc_ecm_netif; //network interface
  195. /* Network interface name */
  196. #define IFNAME0 'E'
  197. #define IFNAME1 'X'
  198. err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
  199. {
  200. int ret;
  201. cdc_ecm_tx_done = false;
  202. ret = usbd_cdc_ecm_eth_tx(p);
  203. if (ret == 0) {
  204. while (!cdc_ecm_tx_done) {
  205. }
  206. return ERR_OK;
  207. } else
  208. return ERR_BUF;
  209. }
  210. err_t cdc_ecm_if_init(struct netif *netif)
  211. {
  212. LWIP_ASSERT("netif != NULL", (netif != NULL));
  213. netif->mtu = 1500;
  214. netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
  215. netif->state = NULL;
  216. netif->name[0] = IFNAME0;
  217. netif->name[1] = IFNAME1;
  218. netif->output = etharp_output;
  219. netif->linkoutput = linkoutput_fn;
  220. return ERR_OK;
  221. }
  222. err_t cdc_ecm_if_input(struct netif *netif)
  223. {
  224. err_t err;
  225. struct pbuf *p;
  226. p = usbd_cdc_ecm_eth_rx();
  227. if (p != NULL) {
  228. err = netif->input(p, netif);
  229. if (err != ERR_OK) {
  230. pbuf_free(p);
  231. }
  232. } else {
  233. return ERR_BUF;
  234. }
  235. return err;
  236. }
  237. void cdc_ecm_lwip_init(void)
  238. {
  239. struct netif *netif = &cdc_ecm_netif;
  240. lwip_init();
  241. netif->hwaddr_len = 6;
  242. memcpy(netif->hwaddr, mac, 6);
  243. netif->hwaddr[5] = ~netif->hwaddr[5]; /* device mac can't same as host. */
  244. netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, cdc_ecm_if_init, netif_input);
  245. netif_set_default(netif);
  246. while (!netif_is_up(netif)) {
  247. }
  248. while (dhserv_init(&dhcp_config)) {
  249. }
  250. while (dnserv_init(IP_ADDR_ANY, 53, dns_query_proc)) {
  251. }
  252. }
  253. void usbd_cdc_ecm_data_recv_done(uint32_t len)
  254. {
  255. }
  256. void cdc_ecm_input_poll(void)
  257. {
  258. cdc_ecm_if_input(&cdc_ecm_netif);
  259. }
  260. #endif
  261. static void usbd_event_handler(uint8_t busid, uint8_t event)
  262. {
  263. switch (event) {
  264. case USBD_EVENT_RESET:
  265. break;
  266. case USBD_EVENT_CONNECTED:
  267. break;
  268. case USBD_EVENT_DISCONNECTED:
  269. break;
  270. case USBD_EVENT_RESUME:
  271. break;
  272. case USBD_EVENT_SUSPEND:
  273. break;
  274. case USBD_EVENT_CONFIGURED:
  275. break;
  276. case USBD_EVENT_SET_REMOTE_WAKEUP:
  277. break;
  278. case USBD_EVENT_CLR_REMOTE_WAKEUP:
  279. break;
  280. default:
  281. break;
  282. }
  283. }
  284. struct usbd_interface intf0;
  285. struct usbd_interface intf1;
  286. /* ecm only supports in linux, and you should input the following command
  287. *
  288. * sudo ifconfig enxaabbccddeeff up
  289. * sudo dhcpclient enxaabbccddeeff
  290. */
  291. void cdc_ecm_init(uint8_t busid, uintptr_t reg_base)
  292. {
  293. cdc_ecm_lwip_init();
  294. usbd_desc_register(busid, &cdc_ecm_descriptor);
  295. usbd_add_interface(busid, usbd_cdc_ecm_init_intf(&intf0, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP));
  296. usbd_add_interface(busid, usbd_cdc_ecm_init_intf(&intf1, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP));
  297. usbd_initialize(busid, reg_base, usbd_event_handler);
  298. }