From a04b1fa55122f03ad3ebbd27f089776da2f263e8 Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Sat, 4 Nov 2023 16:44:02 +0800 Subject: [PATCH] add cdc ecm device --- class/cdc/usb_cdc.h | 132 +++++++++++++++++++ class/cdc/usbd_cdc_ecm.c | 237 +++++++++++++++++++++++++++++++++ class/cdc/usbd_cdc_ecm.h | 36 +++++ demo/cdc_ecm_template.c | 274 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 679 insertions(+) create mode 100644 class/cdc/usbd_cdc_ecm.c create mode 100644 class/cdc/usbd_cdc_ecm.h create mode 100644 demo/cdc_ecm_template.c diff --git a/class/cdc/usb_cdc.h b/class/cdc/usb_cdc.h index 027e08d6..de0e794f 100644 --- a/class/cdc/usb_cdc.h +++ b/class/cdc/usb_cdc.h @@ -212,6 +212,57 @@ #define CDC_SERIAL_STATE_RX_CARRIER_Pos (0) #define CDC_SERIAL_STATE_RX_CARRIER_Msk (1 << CDC_SERIAL_STATE_RX_CARRIER_Pos) +#define CDC_ECM_XMIT_OK (1 << 0) +#define CDC_ECM_RVC_OK (1 << 1) +#define CDC_ECM_XMIT_ERROR (1 << 2) +#define CDC_ECM_RCV_ERROR (1 << 3) +#define CDC_ECM_RCV_NO_BUFFER (1 << 4) +#define CDC_ECM_DIRECTED_BYTES_XMIT (1 << 5) +#define CDC_ECM_DIRECTED_FRAMES_XMIT (1 << 6) +#define CDC_ECM_MULTICAST_BYTES_XMIT (1 << 7) +#define CDC_ECM_MULTICAST_FRAMES_XMIT (1 << 8) +#define CDC_ECM_BROADCAST_BYTES_XMIT (1 << 9) +#define CDC_ECM_BROADCAST_FRAMES_XMIT (1 << 10) +#define CDC_ECM_DIRECTED_BYTES_RCV (1 << 11) +#define CDC_ECM_DIRECTED_FRAMES_RCV (1 << 12) +#define CDC_ECM_MULTICAST_BYTES_RCV (1 << 13) +#define CDC_ECM_MULTICAST_FRAMES_RCV (1 << 14) +#define CDC_ECM_BROADCAST_BYTES_RCV (1 << 15) +#define CDC_ECM_BROADCAST_FRAMES_RCV (1 << 16) +#define CDC_ECM_RCV_CRC_ERROR (1 << 17) +#define CDC_ECM_TRANSMIT_QUEUE_LENGTH (1 << 18) +#define CDC_ECM_RCV_ERROR_ALIGNMENT (1 << 19) +#define CDC_ECM_XMIT_ONE_COLLISION (1 << 20) +#define CDC_ECM_XMIT_MORE_COLLISIONS (1 << 21) +#define CDC_ECM_XMIT_DEFERRED (1 << 22) +#define CDC_ECM_XMIT_MAX_COLLISIONS (1 << 23) +#define CDC_ECM_RCV_OVERRUN (1 << 24) +#define CDC_ECM_XMIT_UNDERRUN (1 << 25) +#define CDC_ECM_XMIT_HEARTBEAT_FAILURE (1 << 26) +#define CDC_ECM_XMIT_TIMES_CRS_LOST (1 << 27) +#define CDC_ECM_XMIT_LATE_COLLISIONS (1 << 28) + +#define CDC_ECM_MAC_STR_DESC (uint8_t *)"010202030000" +#define CDC_ECM_MAC_ADDR0 0x00U /* 01 */ +#define CDC_ECM_MAC_ADDR1 0x02U /* 02 */ +#define CDC_ECM_MAC_ADDR2 0x02U /* 03 */ +#define CDC_ECM_MAC_ADDR3 0x03U /* 00 */ +#define CDC_ECM_MAC_ADDR4 0x00U /* 00 */ +#define CDC_ECM_MAC_ADDR5 0x00U /* 00 */ + +#define CDC_ECM_NET_DISCONNECTED 0x00U +#define CDC_ECM_NET_CONNECTED 0x01U + +#define CDC_ECM_ETH_STATS_RESERVED 0xE0U +#define CDC_ECM_BMREQUEST_TYPE_ECM 0xA1U + +#define CDC_ECM_CONNECT_SPEED_UPSTREAM 0x004C4B40U /* 5Mbps */ +#define CDC_ECM_CONNECT_SPEED_DOWNSTREAM 0x004C4B40U /* 5Mbps */ + +#define CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION 0x00 +#define CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE 0x01 +#define CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE 0x2A + /*------------------------------------------------------------------------------ * Structures based on usbcdc11.pdf (www.usb.org) *----------------------------------------------------------------------------*/ @@ -299,6 +350,15 @@ struct cdc_ecm_descriptor { uint8_t bNumberPowerFilters; } __PACKED; +struct cdc_ecm_notification { + uint8_t bmRequestType; + uint8_t bNotificationType; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint8_t data[8]; +} __PACKED; + /*Length of template descriptor: 66 bytes*/ #define CDC_ACM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7) // clang-format off @@ -437,4 +497,76 @@ struct cdc_ecm_descriptor { 0x00 /* bInterval */ // clang-format on +#define DBVAL_BE(x) ((x >> 24) & 0xFF), ((x >> 16) & 0xFF), ((x >> 8) & 0xFF), (x & 0xFF) + +/*Length of template descriptor: 66 bytes*/ +#define CDC_ECM_DESCRIPTOR_LEN (8 + 9 + 5 + 5 + 13 + 7 + 9 + 7 + 7) +// clang-format off +#define CDC_ECM_DESCRIPTOR_INIT(bFirstInterface, int_ep, out_ep, in_ep, wMaxPacketSize, \ +eth_statistics, wMaxSegmentSize, wNumberMCFilters, bNumberPowerFilters, str_idx) \ + /* Interface Associate */ \ + 0x08, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, /* bDescriptorType */ \ + bFirstInterface, /* bFirstInterface */ \ + 0x02, /* bInterfaceCount */ \ + USB_DEVICE_CLASS_CDC, /* bFunctionClass */ \ + CDC_ETHERNET_NETWORKING_CONTROL_MODEL, /* bFunctionSubClass */ \ + CDC_COMMON_PROTOCOL_NONE, /* bFunctionProtocol */ \ + 0x00, /* iFunction */ \ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + bFirstInterface, /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + 0x01, /* bNumEndpoints */ \ + USB_DEVICE_CLASS_CDC, /* bInterfaceClass */ \ + CDC_ETHERNET_NETWORKING_CONTROL_MODEL, /* bInterfaceSubClass */ \ + CDC_COMMON_PROTOCOL_NONE, /* bInterfaceProtocol */ \ + str_idx, /* iInterface */ \ + 0x05, /* bLength */ \ + CDC_CS_INTERFACE, /* bDescriptorType */ \ + CDC_FUNC_DESC_HEADER, /* bDescriptorSubtype */ \ + WBVAL(CDC_V1_10), /* bcdCDC */ \ + 0x05, /* bLength */ \ + CDC_CS_INTERFACE, /* bDescriptorType */ \ + CDC_FUNC_DESC_UNION, /* bDescriptorSubtype */ \ + bFirstInterface, /* bMasterInterface */ \ + (uint8_t)(bFirstInterface + 1), /* bSlaveInterface0 */ \ + /* CDC_ECM Functional Descriptor */ \ + 0x0D, /* bFunctionLength */\ + CDC_CS_INTERFACE, /* bDescriptorType: CS_INTERFACE */\ + CDC_FUNC_DESC_ETHERNET_NETWORKING, /* Ethernet Networking functional descriptor subtype */\ + str_idx, /* Device's MAC string index */\ + DBVAL_BE(eth_statistics), /* Ethernet statistics (bitmap) */\ + WBVAL(wMaxPacketSize),/* wMaxSegmentSize: Ethernet Maximum Segment size, typically 1514 bytes */\ + WBVAL(wNumberMCFilters), /* wNumberMCFilters: the number of multicast filters */\ + bNumberPowerFilters, /* bNumberPowerFilters: the number of wakeup power filters */\ + 0x07, /* bLength */ \ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \ + int_ep, /* bEndpointAddress */ \ + 0x03, /* bmAttributes */ \ + 0x10, 0x00, /* wMaxPacketSize */ \ + 0x10, /* bInterval */ \ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + (uint8_t)(bFirstInterface + 1), /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + 0x02, /* bNumEndpoints */ \ + CDC_DATA_INTERFACE_CLASS, /* bInterfaceClass */ \ + 0x00, /* bInterfaceSubClass */ \ + 0x00, /* bInterfaceProtocol */ \ + 0x00, /* iInterface */ \ + 0x07, /* bLength */ \ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \ + out_ep, /* bEndpointAddress */ \ + 0x02, /* bmAttributes */ \ + WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \ + 0x00, /* bInterval */ \ + 0x07, /* bLength */ \ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \ + in_ep, /* bEndpointAddress */ \ + 0x02, /* bmAttributes */ \ + WBVAL(wMaxPacketSize), /* wMaxPacketSize */ \ + 0x00 /* bInterval */ +// clang-format on + #endif /* USB_CDC_H */ diff --git a/class/cdc/usbd_cdc_ecm.c b/class/cdc/usbd_cdc_ecm.c new file mode 100644 index 00000000..1ebdecf6 --- /dev/null +++ b/class/cdc/usbd_cdc_ecm.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbd_core.h" +#include "usbd_cdc_ecm.h" + +#define CDC_ECM_OUT_EP_IDX 0 +#define CDC_ECM_IN_EP_IDX 1 +#define CDC_ECM_INT_EP_IDX 2 + +/* Describe EndPoints configuration */ +static struct usbd_endpoint cdc_ecm_ep_data[3]; + +#ifdef CONFIG_USB_HS +#define CDC_ECM_MAX_PACKET_SIZE 512 +#else +#define CDC_ECM_MAX_PACKET_SIZE 64 +#endif + +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_CDC_ECM_ETH_MAX_SEGSZE]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_notify_buf[16]; + +volatile uint8_t *g_cdc_ecm_rx_data_buffer = NULL; +volatile uint32_t g_cdc_ecm_rx_data_length = 0; +volatile uint32_t g_cdc_ecm_tx_data_length = 0; + +static volatile uint8_t g_current_net_status = 0; +static volatile uint8_t g_cmd_intf = 0; + +static uint32_t g_connect_speed_table[2] = { CDC_ECM_CONNECT_SPEED_UPSTREAM, + CDC_ECM_CONNECT_SPEED_DOWNSTREAM }; + +void usbd_cdc_ecm_send_notify(uint8_t notifycode, uint8_t value, uint32_t *speed) +{ + struct cdc_ecm_notification *notify = (struct cdc_ecm_notification *)g_cdc_ecm_notify_buf; + uint8_t bytes2send = 0; + + notify->bmRequestType = CDC_ECM_BMREQUEST_TYPE_ECM; + notify->bNotificationType = notifycode; + + switch (notifycode) { + case CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION: + notify->wValue = value; + notify->wIndex = g_cmd_intf; + notify->wLength = 0U; + + for (uint8_t i = 0U; i < 8U; i++) { + notify->data[i] = 0U; + } + bytes2send = 8U; + break; + case CDC_ECM_NOTIFY_CODE_RESPONSE_AVAILABLE: + notify->wValue = 0U; + notify->wIndex = g_cmd_intf; + notify->wLength = 0U; + for (uint8_t i = 0U; i < 8U; i++) { + notify->data[i] = 0U; + } + bytes2send = 8U; + break; + case CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE: + notify->wValue = 0U; + notify->wIndex = g_cmd_intf; + notify->wLength = 0x0008U; + bytes2send = 16U; + + memcpy(notify->data, speed, 8); + break; + + default: + break; + } + + if (bytes2send) { + usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr, g_cdc_ecm_notify_buf, bytes2send); + } +} + +static int cdc_ecm_class_interface_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len) +{ + USB_LOG_DBG("CDC ECM Class request: " + "bRequest 0x%02x\r\n", + setup->bRequest); + + g_cmd_intf = LO_BYTE(setup->wIndex); + + switch (setup->bRequest) { + case CDC_REQUEST_SET_ETHERNET_PACKET_FILTER: + /* bit0 Promiscuous + * bit1 ALL Multicast + * bit2 Directed + * bit3 Broadcast + * bit4 Multicast + */ + if (g_current_net_status == 0) { + g_current_net_status = 1; + usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, NULL); + } + + break; + default: + USB_LOG_WRN("Unhandled CDC ECM Class bRequest 0x%02x\r\n", setup->bRequest); + return -1; + } + + return 0; +} + +void cdc_ecm_notify_handler(uint8_t event, void *arg) +{ + switch (event) { + case USBD_EVENT_RESET: + g_current_net_status = 0; + g_cdc_ecm_rx_data_length = 0; + g_cdc_ecm_tx_data_length = 0; + g_cdc_ecm_rx_data_buffer = NULL; + break; + case USBD_EVENT_CONFIGURED: + usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE); + break; + + default: + break; + } +} + +void cdc_ecm_bulk_out(uint8_t ep, uint32_t nbytes) +{ + g_cdc_ecm_rx_data_length += nbytes; + + if (nbytes < CDC_ECM_MAX_PACKET_SIZE) { + g_cdc_ecm_rx_data_buffer = g_cdc_ecm_rx_buffer; + usbd_cdc_ecm_data_recv_done(); + } else { + usbd_ep_start_read(ep, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_data_length], CDC_ECM_MAX_PACKET_SIZE); + } +} + +void cdc_ecm_bulk_in(uint8_t ep, uint32_t nbytes) +{ + if ((nbytes % CDC_ECM_MAX_PACKET_SIZE) == 0 && nbytes) { + /* send zlp */ + usbd_ep_start_write(ep, NULL, 0); + } else { + g_cdc_ecm_tx_data_length = 0; + } +} + +void cdc_ecm_int_in(uint8_t ep, uint32_t nbytes) +{ + if (g_current_net_status == 1) { + g_current_net_status = 2; + usbd_cdc_ecm_send_notify(CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION, CDC_ECM_NET_CONNECTED, g_connect_speed_table); + } +} + +#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP +struct pbuf *usbd_cdc_ecm_eth_rx(void) +{ + struct pbuf *p; + + if (g_cdc_ecm_rx_data_buffer == NULL) { + return NULL; + } + p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_data_length, PBUF_POOL); + if (p == NULL) { + return NULL; + } + memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_data_length); + p->len = g_cdc_ecm_rx_data_length; + + USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_data_length); + g_cdc_ecm_rx_data_length = 0; + g_cdc_ecm_rx_data_buffer = NULL; + usbd_ep_start_read(cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr, g_cdc_ecm_rx_buffer, CDC_ECM_MAX_PACKET_SIZE); + + return p; +} + +int usbd_cdc_ecm_eth_tx(struct pbuf *p) +{ + struct pbuf *q; + uint8_t *buffer; + + if (g_cdc_ecm_tx_data_length > 0) { + return -EBUSY; + } + + if (p->tot_len > sizeof(g_cdc_ecm_tx_buffer)) { + p->tot_len = sizeof(g_cdc_ecm_tx_buffer); + } + + buffer = g_cdc_ecm_tx_buffer; + for (q = p; q != NULL; q = q->next) { + memcpy(buffer, q->payload, q->len); + buffer += q->len; + } + + g_cdc_ecm_tx_data_length = p->tot_len; + + USB_LOG_DBG("txlen:%d\r\n", g_cdc_ecm_tx_data_length); + return usbd_ep_start_write(cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr, g_cdc_ecm_tx_buffer, g_cdc_ecm_tx_data_length); +} +#endif + +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) +{ + intf->class_interface_handler = cdc_ecm_class_interface_request_handler; + intf->class_endpoint_handler = NULL; + intf->vendor_handler = NULL; + intf->notify_handler = cdc_ecm_notify_handler; + + cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_addr = out_ep; + cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX].ep_cb = cdc_ecm_bulk_out; + cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_addr = in_ep; + cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX].ep_cb = cdc_ecm_bulk_in; + cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_addr = int_ep; + cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX].ep_cb = cdc_ecm_int_in; + + usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_OUT_EP_IDX]); + usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_IN_EP_IDX]); + usbd_add_endpoint(&cdc_ecm_ep_data[CDC_ECM_INT_EP_IDX]); + + return intf; +} + +void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2]) +{ + memcpy(g_connect_speed_table, speed, 8); +} + +__WEAK void usbd_cdc_ecm_data_recv_done(void) +{ +} \ No newline at end of file diff --git a/class/cdc/usbd_cdc_ecm.h b/class/cdc/usbd_cdc_ecm.h new file mode 100644 index 00000000..8381b1a5 --- /dev/null +++ b/class/cdc/usbd_cdc_ecm.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USBD_CDC_ECM_H +#define USBD_CDC_ECM_H + +#include "usb_cdc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ethernet Maximum Segment size, typically 1514 bytes */ +#define CONFIG_CDC_ECM_ETH_MAX_SEGSZE 1514U +#define CONFIG_USBDEV_CDC_ECM_USING_LWIP + +/* Init cdc ecm interface driver */ +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); + +/* Setup request command callback api */ +void usbd_cdc_ecm_set_connect_speed(uint32_t speed[2]); +void usbd_cdc_ecm_data_recv_done(void); + +#ifdef CONFIG_USBDEV_CDC_ECM_USING_LWIP +#include +struct pbuf *usbd_cdc_ecm_eth_rx(void); +int usbd_cdc_ecm_eth_tx(struct pbuf *p); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* USBD_CDC_ECM_H */ diff --git a/demo/cdc_ecm_template.c b/demo/cdc_ecm_template.c new file mode 100644 index 00000000..8eb6d03f --- /dev/null +++ b/demo/cdc_ecm_template.c @@ -0,0 +1,274 @@ +#include "usbd_core.h" +#include "usbd_cdc_ecm.h" + +/*!< endpoint address */ +#define CDC_IN_EP 0x81 +#define CDC_OUT_EP 0x02 +#define CDC_INT_EP 0x83 + +#define USBD_VID 0xFFFF +#define USBD_PID 0xFFFF +#define USBD_MAX_POWER 100 +#define USBD_LANGID_STRING 1033 + +/*!< config descriptor size */ +#define USB_CONFIG_SIZE (9 + CDC_ECM_DESCRIPTOR_LEN) + +#ifdef CONFIG_USB_HS +#define CDC_MAX_MPS 512 +#else +#define CDC_MAX_MPS 64 +#endif + +#define CDC_ECM_ETH_STATISTICS_BITMAP 0x00000000 + +/* str idx = 4 is for mac address: aa:bb:cc:dd:ee:ff*/ +#define CDC_ECM_MAC_STRING_INDEX 4 + +/*!< global descriptor */ +static const uint8_t cdc_ecm_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0xEF, 0x02, 0x01, USBD_VID, USBD_PID, 0x0100, 0x01), + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x02, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + CDC_ECM_DESCRIPTOR_INIT(0x00, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP, CDC_MAX_MPS, CDC_ECM_ETH_STATISTICS_BITMAP, CONFIG_CDC_ECM_ETH_MAX_SEGSZE, 0, 0, CDC_ECM_MAC_STRING_INDEX), + /////////////////////////////////////// + /// string0 descriptor + /////////////////////////////////////// + USB_LANGID_INIT(USBD_LANGID_STRING), + /////////////////////////////////////// + /// string1 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string2 descriptor + /////////////////////////////////////// + 0x2E, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + ' ', 0x00, /* wcChar9 */ + 'C', 0x00, /* wcChar10 */ + 'D', 0x00, /* wcChar11 */ + 'C', 0x00, /* wcChar12 */ + ' ', 0x00, /* wcChar13 */ + 'E', 0x00, /* wcChar14 */ + 'C', 0x00, /* wcChar15 */ + 'M', 0x00, /* wcChar16 */ + ' ', 0x00, /* wcChar17 */ + 'D', 0x00, /* wcChar18 */ + 'E', 0x00, /* wcChar19 */ + 'M', 0x00, /* wcChar20 */ + 'O', 0x00, /* wcChar21 */ + /////////////////////////////////////// + /// string3 descriptor + /////////////////////////////////////// + 0x16, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + '2', 0x00, /* wcChar0 */ + '0', 0x00, /* wcChar1 */ + '2', 0x00, /* wcChar2 */ + '2', 0x00, /* wcChar3 */ + '1', 0x00, /* wcChar4 */ + '2', 0x00, /* wcChar5 */ + '3', 0x00, /* wcChar6 */ + '4', 0x00, /* wcChar7 */ + '5', 0x00, /* wcChar8 */ + '6', 0x00, /* wcChar9 */ + /////////////////////////////////////// + /// string4 descriptor + /////////////////////////////////////// + 0x1A, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'a', 0x00, /* wcChar0 */ + 'a', 0x00, /* wcChar1 */ + 'b', 0x00, /* wcChar2 */ + 'b', 0x00, /* wcChar3 */ + 'c', 0x00, /* wcChar4 */ + 'c', 0x00, /* wcChar5 */ + 'd', 0x00, /* wcChar6 */ + 'd', 0x00, /* wcChar7 */ + 'e', 0x00, /* wcChar8 */ + 'e', 0x00, /* wcChar9 */ + 'f', 0x00, /* wcChar10 */ + 'f', 0x00, /* wcChar11 */ +#ifdef CONFIG_USB_HS + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x02, + 0x02, + 0x01, + 0x40, + 0x01, + 0x00, +#endif + 0x00 +}; + +const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + +/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */ +#define IP_ADDR0 (uint8_t)192 +#define IP_ADDR1 (uint8_t)168 +#define IP_ADDR2 (uint8_t)123 +#define IP_ADDR3 (uint8_t)100 + +/*NETMASK*/ +#define NETMASK_ADDR0 (uint8_t)255 +#define NETMASK_ADDR1 (uint8_t)255 +#define NETMASK_ADDR2 (uint8_t)255 +#define NETMASK_ADDR3 (uint8_t)0 + +/*Gateway Address*/ +#define GW_ADDR0 (uint8_t)192 +#define GW_ADDR1 (uint8_t)168 +#define GW_ADDR2 (uint8_t)123 +#define GW_ADDR3 (uint8_t)1 + +#include "netif/etharp.h" +#include "lwip/init.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3); +const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3); +const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3); + +static struct netif cdc_ecm_netif; //network interface + +/* Network interface name */ +#define IFNAME0 'E' +#define IFNAME1 'X' + +static err_t linkoutput_fn(struct netif *netif, struct pbuf *p) +{ + static int ret; + + ret = usbd_cdc_ecm_eth_tx(p); + if (ret == 0) + return ERR_OK; + else + return ERR_BUF; +} + +err_t cdc_ecm_if_init(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + netif->mtu = 1500; + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP; + netif->state = NULL; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + netif->output = etharp_output; + netif->linkoutput = linkoutput_fn; + return ERR_OK; +} + +err_t cdc_ecm_if_input(struct netif *netif) +{ + static err_t err; + static struct pbuf *p; + + p = usbd_cdc_ecm_eth_rx(); + if (p != NULL) { + err = netif->input(p, netif); + if (err != ERR_OK) { + pbuf_free(p); + } + } else { + return ERR_BUF; + } + return err; +} + +void cdc_ecm_lwip_init(void) +{ + struct netif *netif = &cdc_ecm_netif; + + lwip_init(); + + netif->hwaddr_len = 6; + memcpy(netif->hwaddr, mac, 6); + + netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, cdc_ecm_if_init, netif_input); + netif_set_default(netif); + while (!netif_is_up(netif)) { + } + + // while (dhserv_init(&dhcp_config)) {} + + // while (dnserv_init(&ipaddr, PORT_DNS, dns_query_proc)) {} +} + +void usbd_cdc_ecm_data_recv_done(void) +{ +} + +void cdc_ecm_input_poll(void) +{ + cdc_ecm_if_input(&cdc_ecm_netif); +} + +void usbd_event_handler(uint8_t event) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: + break; + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +struct usbd_interface intf0; +struct usbd_interface intf1; + +/* ecm only supports in linux, and you should input the following command + * + * sudo ifconfig enxaabbccddeeff up + * sudo dhcpclient enxaabbccddeeff +*/ +void cdc_ecm_init(void) +{ + cdc_ecm_lwip_init(); + + usbd_desc_register(cdc_ecm_descriptor); + usbd_add_interface(usbd_cdc_ecm_init_intf(&intf0, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP)); + usbd_add_interface(usbd_cdc_ecm_init_intf(&intf1, CDC_INT_EP, CDC_OUT_EP, CDC_IN_EP)); + usbd_initialize(); +} \ No newline at end of file