diff options
| author | sakumisu <[email protected]> | 2023-11-04 16:44:02 +0800 |
|---|---|---|
| committer | sakumisu <[email protected]> | 2023-11-04 16:44:02 +0800 |
| commit | a04b1fa55122f03ad3ebbd27f089776da2f263e8 (patch) | |
| tree | 8f3a395ac7311c390356ded6a4e55fd1c7111aa4 /class | |
| parent | c37c60c7c7b07d3356a5b55a06640437662e5ef2 (diff) | |
add cdc ecm device
Diffstat (limited to 'class')
| -rw-r--r-- | class/cdc/usb_cdc.h | 132 | ||||
| -rw-r--r-- | class/cdc/usbd_cdc_ecm.c | 237 | ||||
| -rw-r--r-- | class/cdc/usbd_cdc_ecm.h | 36 |
3 files changed, 405 insertions, 0 deletions
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 <lwip/pbuf.h> +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 */ |
