add cdc ecm device
This commit is contained in:
@@ -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 */
|
||||
|
||||
237
class/cdc/usbd_cdc_ecm.c
Normal file
237
class/cdc/usbd_cdc_ecm.c
Normal file
@@ -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)
|
||||
{
|
||||
}
|
||||
36
class/cdc/usbd_cdc_ecm.h
Normal file
36
class/cdc/usbd_cdc_ecm.h
Normal file
@@ -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 */
|
||||
274
demo/cdc_ecm_template.c
Normal file
274
demo/cdc_ecm_template.c
Normal file
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user