Sfoglia il codice sorgente

[Components][Drivers][USB] Add CDC-ECM class (LWIP on USB)

Windows下没驱动 linux和mac下免驱
uestczyh222 7 anni fa
parent
commit
bd566e6a37

+ 8 - 0
components/drivers/KConfig

@@ -132,6 +132,10 @@ menu "Using USB"
                     config _RT_USB_DEVICE_HID
                         bool "Enable to use device as HID device"
                         select RT_USB_DEVICE_HID
+                    config _RT_USB_DEVICE_ECM
+                        bool "Enable to use device as ecm device"
+                        select RT_USB_DEVICE_ECM
+                        depends on RT_USING_LWIP
                 endchoice
                 if RT_USB_DEVICE_COMPOSITE
                     config RT_USB_DEVICE_CDC
@@ -143,6 +147,10 @@ menu "Using USB"
                     config RT_USB_DEVICE_HID
                         bool "Enable to use device as HID device"
                         default n
+                    config RT_USB_DEVICE_ECM
+                        bool "Enable to use device as ecm device"
+                        default n
+                        depends on RT_USING_LWIP
                 endif
 
                 if RT_USB_DEVICE_HID

+ 3 - 0
components/drivers/usb/usbdevice/SConscript

@@ -16,6 +16,9 @@ if GetDepend('RT_USB_DEVICE_HID'):
 if GetDepend('RT_USB_DEVICE_MSTORAGE'):
 	src += Glob('class/mstorage.c')
 
+if GetDepend('RT_USB_DEVICE_ECM'):
+	src += Glob('class/ecm.c')
+
 CPPPATH = [cwd]
 
 group = DefineGroup('rt_usbd', src, depend = ['RT_USING_USB_DEVICE'], CPPPATH = CPPPATH)

+ 62 - 2
components/drivers/usb/usbdevice/class/cdc.h

@@ -31,6 +31,7 @@
 #define USB_CDC_CLASS_COMM              0x02
 #define USB_CDC_CLASS_DATA              0x0A
 
+#define USB_CDC_SUBCLASS_NONE           0x00
 #define USB_CDC_SUBCLASS_DLCM           0x01
 #define USB_CDC_SUBCLASS_ACM            0x02
 #define USB_CDC_SUBCLASS_TCM            0x03
@@ -38,9 +39,10 @@
 #define USB_CDC_SUBCLASS_CCM            0x05
 #define USB_CDC_SUBCLASS_ETH            0x06
 #define USB_CDC_SUBCLASS_ATM            0x07
+#define USB_CDC_SUBCLASS_EEM            0x0C
 
+#define USB_CDC_PROTOCOL_NONE           0x00
 #define USB_CDC_PROTOCOL_V25TER         0x01
-
 #define USB_CDC_PROTOCOL_I430           0x30
 #define USB_CDC_PROTOCOL_HDLC           0x31
 #define USB_CDC_PROTOCOL_TRANS          0x32
@@ -54,6 +56,7 @@
 #define USB_CDC_PROTOCOL_HOST           0xFD
 #define USB_CDC_PROTOCOL_PUFD           0xFE
 #define USB_CDC_PROTOCOL_VENDOR         0xFF
+#define USB_CDC_PROTOCOL_EEM            0x07
 
 #define USB_CDC_CS_INTERFACE            0x24
 #define USB_CDC_CS_ENDPOINT             0x25
@@ -62,6 +65,7 @@
 #define USB_CDC_SCS_CALL_MGMT           0x01
 #define USB_CDC_SCS_ACM                 0x02
 #define USB_CDC_SCS_UNION               0x06
+#define USB_CDC_SCS_ETH                 0x0F
 
 #define CDC_SEND_ENCAPSULATED_COMMAND   0x00
 #define CDC_GET_ENCAPSULATED_RESPONSE   0x01
@@ -153,6 +157,30 @@ struct ucdc_comm_descriptor
 };
 typedef struct ucdc_comm_descriptor* ucdc_comm_desc_t;
 
+struct ucdc_enet_descriptor
+{
+  rt_uint8_t    bFunctionLength;
+  rt_uint8_t    bDescriptorType;
+  rt_uint8_t    bDescriptorSubtype;
+  rt_uint8_t    iMACAddress;
+  rt_uint8_t    bmEthernetStatistics[4];
+  rt_uint16_t   wMaxSegmentSize;
+  rt_uint16_t   wMCFilters;
+  rt_uint8_t    bNumberPowerFilters;
+};
+struct ucdc_eth_descriptor
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+    struct uiad_descriptor iad_desc;
+#endif
+    struct uinterface_descriptor    intf_desc;
+    struct ucdc_header_descriptor   hdr_desc;
+    struct ucdc_union_descriptor    union_desc;
+    struct ucdc_enet_descriptor     enet_desc;
+    struct uendpoint_descriptor     ep_desc;
+};
+typedef struct ucdc_eth_descriptor* ucdc_eth_desc_t;
+
 struct ucdc_data_descriptor
 {
     struct uinterface_descriptor intf_desc;
@@ -177,7 +205,39 @@ struct cdc_eps
     uep_t ep_cmd;
 };
 typedef struct cdc_eps* cdc_eps_t;
- 
+
+
+
+struct ucdc_management_element_notifications
+{
+    rt_uint8_t bmRequestType;
+    rt_uint8_t bNotificatinCode;
+    rt_uint16_t wValue;
+    rt_uint16_t wIndex;
+    rt_uint16_t wLength;
+};
+typedef struct ucdc_management_element_notifications * ucdc_mg_notifications_t;
+
+struct ucdc_connection_speed_change_data
+{
+    rt_uint32_t down_bit_rate;
+    rt_uint32_t up_bit_rate;
+};
+typedef struct connection_speed_change_data * connect_speed_data_t;
+
+enum ucdc_notification_code
+{
+    UCDC_NOTIFI_NETWORK_CONNECTION      = 0x00,
+    UCDC_NOTIFI_RESPONSE_AVAILABLE      = 0x01,
+    UCDC_NOTIFI_AUX_JACK_HOOK_STATE     = 0x08,
+    UCDC_NOTIFI_RING_DETECT             = 0x09,
+    UCDC_NOTIFI_SERIAL_STATE            = 0x20,
+    UCDC_NOTIFI_CALL_STATE_CHANGE       = 0x28,
+    UCDC_NOTIFI_LINE_STATE_CHANGE       = 0x29,
+    UCDC_NOTIFI_CONNECTION_SPEED_CHANGE = 0x2A,
+};
+typedef enum ucdc_notification_code ucdc_notification_code_t;
+
 #pragma pack()
 
 #endif

+ 602 - 0
components/drivers/usb/usbdevice/class/ecm.c

@@ -0,0 +1,602 @@
+/*
+ * File      : ecm.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2006-2013, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author            Notes
+ * 2017-11-19     ZYH               first version
+ */
+
+#include <rtdevice.h>
+#include "cdc.h"
+
+
+#ifdef  ECM_DEBUG
+#define ECM_PRINTF                rt_kprintf("[ECM] "); rt_kprintf
+#else
+#define ECM_PRINTF(...)
+#endif /* ECM_DEBUG */
+
+/* RT-Thread LWIP ethernet interface */
+#include <netif/ethernetif.h>
+
+#ifndef USB_ETH_MTU
+#define USB_ETH_MTU     1514
+#endif
+#define MAX_ADDR_LEN    6
+
+struct rt_ecm_eth
+{
+    /* inherit from ethernet device */
+    struct eth_device       parent;
+    struct ufunction *      func;
+    struct cdc_eps          eps;
+    /* interface address info */
+    rt_uint8_t              host_addr[MAX_ADDR_LEN];
+    rt_uint8_t              dev_addr[MAX_ADDR_LEN];
+
+    ALIGN(4)
+    rt_uint8_t              rx_pool[64];
+    ALIGN(4)
+    rt_size_t               rx_size;
+    ALIGN(4)
+    rt_size_t               rx_offset;
+    ALIGN(4)
+    char                    rx_buffer[USB_ETH_MTU];
+    char                    tx_buffer[USB_ETH_MTU];
+    
+    struct rt_semaphore     tx_buffer_free;
+    
+};
+typedef struct rt_ecm_eth * rt_ecm_eth_t;
+
+ALIGN(4)
+static struct udevice_descriptor _dev_desc =
+{
+    USB_DESC_LENGTH_DEVICE,     /* bLength */
+    USB_DESC_TYPE_DEVICE,       /* type */
+    USB_BCD_VERSION,            /* bcdUSB */
+    USB_CLASS_CDC,              /* bDeviceClass */
+    USB_CDC_SUBCLASS_ETH,       /* bDeviceSubClass */
+    USB_CDC_PROTOCOL_NONE,      /* bDeviceProtocol */
+    0x40,                       /* bMaxPacketSize0 */
+    _VENDOR_ID,                 /* idVendor */
+    _PRODUCT_ID,                /* idProduct */
+    USB_BCD_DEVICE,             /* bcdDevice */
+    USB_STRING_MANU_INDEX,      /* iManufacturer */
+    USB_STRING_PRODUCT_INDEX,   /* iProduct */
+    USB_STRING_SERIAL_INDEX,    /* iSerialNumber */
+    USB_DYNAMIC                 /* bNumConfigurations */
+};
+
+/* communcation interface descriptor */
+ALIGN(4)
+const static struct ucdc_eth_descriptor _comm_desc =
+{
+#ifdef RT_USB_DEVICE_COMPOSITE
+    /* Interface Association Descriptor */
+    USB_DESC_LENGTH_IAD,
+    USB_DESC_TYPE_IAD,
+    USB_DYNAMIC,
+    0x02,
+    USB_CDC_CLASS_COMM,
+    USB_CDC_SUBCLASS_ETH,
+    USB_CDC_PROTOCOL_NONE,
+    0x00,
+#endif
+    /* Interface Descriptor */
+    USB_DESC_LENGTH_INTERFACE,
+    USB_DESC_TYPE_INTERFACE,
+    USB_DYNAMIC,
+    0x00,
+    0x01,
+    USB_CDC_CLASS_COMM,
+    USB_CDC_SUBCLASS_ETH,
+    USB_CDC_PROTOCOL_NONE,
+    0x00,
+    /* Header Functional Descriptor */
+    sizeof(struct ucdc_header_descriptor),
+    USB_CDC_CS_INTERFACE,
+    USB_CDC_SCS_HEADER,
+    0x0110,
+    /* Union Functional Descriptor */
+    sizeof(struct ucdc_union_descriptor),
+    USB_CDC_CS_INTERFACE,
+    USB_CDC_SCS_UNION,
+    USB_DYNAMIC,
+    USB_DYNAMIC,
+    /* Abstract Control Management Functional Descriptor */
+    sizeof(struct ucdc_enet_descriptor),
+    USB_CDC_CS_INTERFACE,
+    USB_CDC_SCS_ETH,
+    USB_STRING_SERIAL_INDEX,
+    {0,0,0,0},
+    USB_ETH_MTU,
+    0x00,
+    0x00,
+    /* Endpoint Descriptor */
+    USB_DESC_LENGTH_ENDPOINT,
+    USB_DESC_TYPE_ENDPOINT,
+    USB_DIR_IN | USB_DYNAMIC,
+    USB_EP_ATTR_INT,
+    0x08,
+    0xFF,
+};
+
+/* data interface descriptor */
+ALIGN(4)
+const static struct ucdc_data_descriptor _data_desc =
+{
+    /* interface descriptor */
+    USB_DESC_LENGTH_INTERFACE,
+    USB_DESC_TYPE_INTERFACE,
+    USB_DYNAMIC,
+    0x00,
+    0x02,
+    USB_CDC_CLASS_DATA,
+    USB_CDC_SUBCLASS_ETH,
+    0x00,
+    0x00,
+    /* endpoint, bulk out */
+    USB_DESC_LENGTH_ENDPOINT,
+    USB_DESC_TYPE_ENDPOINT,
+    USB_DIR_OUT | USB_DYNAMIC,
+    USB_EP_ATTR_BULK,
+    USB_CDC_BUFSIZE,
+    0x00,
+    /* endpoint, bulk in */
+    USB_DESC_LENGTH_ENDPOINT,
+    USB_DESC_TYPE_ENDPOINT,
+    USB_DYNAMIC | USB_DIR_IN,
+    USB_EP_ATTR_BULK,
+    USB_CDC_BUFSIZE,
+    0x00,
+};
+
+ALIGN(4)
+const static char* _ustring[] =
+{
+    "Language",                 /* LANGID */
+    "RT-Thread Team.",          /* MANU */
+    "RT-Thread ECM device",     /* PRODUCT */
+    "3497F694ECAB",             /* SERIAL (MAC)*/
+    "Configuration",            /* CONFIG */
+    "Interface",                /* INTERFACE */
+};
+
+ALIGN(4)
+static struct usb_qualifier_descriptor dev_qualifier =
+{
+    sizeof(dev_qualifier),
+    USB_DESC_TYPE_DEVICEQUALIFIER,
+    0x0200,
+    USB_CLASS_CDC,
+    0x00,
+    64,
+    0x01,
+    0,
+};
+static rt_err_t _cdc_send_notifi(ufunction_t func,ucdc_notification_code_t notifi,rt_uint16_t wValue,rt_uint16_t wLength)
+{
+    static struct ucdc_management_element_notifications _notifi;
+    cdc_eps_t eps;
+    RT_ASSERT(func!=RT_NULL)
+    eps = &((rt_ecm_eth_t)func->user_data)->eps;
+    _notifi.bmRequestType = 0xA1;
+    _notifi.bNotificatinCode = notifi;
+    _notifi.wValue = wValue;
+    _notifi.wLength = wLength;
+    
+    eps->ep_cmd->request.buffer = (void *)&_notifi;
+    eps->ep_cmd->request.size = 8;
+    eps->ep_cmd->request.req_type = UIO_REQUEST_WRITE;
+    rt_usbd_io_request(func->device, eps->ep_cmd, &eps->ep_cmd->request);
+    return RT_EOK;
+}
+
+static rt_err_t _ecm_set_eth_packet_filter(ufunction_t func, ureq_t setup)
+{
+    rt_ecm_eth_t _ecm_eth = (rt_ecm_eth_t)func->user_data;
+    dcd_ep0_send_status(func->device->dcd);
+    
+
+    /* send link up. */
+    eth_device_linkchange(&_ecm_eth->parent, RT_TRUE);
+    _cdc_send_notifi(func,UCDC_NOTIFI_NETWORK_CONNECTION,1,0);
+    return RT_EOK;
+}
+/**
+ * This function will handle rndis interface request.
+ *
+ * @param device the usb device object.
+ * @param setup the setup request.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _interface_handler(ufunction_t func, ureq_t setup)
+{
+    RT_ASSERT(func != RT_NULL);
+    RT_ASSERT(setup != RT_NULL);
+
+    switch(setup->bRequest)
+    {
+    case CDC_SET_ETH_PACKET_FILTER:
+        _ecm_set_eth_packet_filter(func, setup);
+        break;
+    default:
+        rt_kprintf("setup->bRequest:0x%02X",setup->bRequest);
+        break;
+    }
+    return RT_EOK;
+}
+
+/**
+ * This function will handle rndis bulk in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+
+static rt_err_t _ep_in_handler(ufunction_t func, rt_size_t size)
+{
+    rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
+    rt_sem_release(&ecm_device->tx_buffer_free);
+    return RT_EOK;
+}
+
+/**
+ * This function will handle RNDIS bulk out endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_out_handler(ufunction_t func, rt_size_t size)
+{
+    rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
+    rt_memcpy((void *)(ecm_device->rx_buffer + ecm_device->rx_offset),ecm_device->rx_pool,size);
+    ecm_device->rx_offset += size;
+    if(size < EP_MAXPACKET(ecm_device->eps.ep_out))
+    {
+        ecm_device->rx_size = ecm_device->rx_offset;
+        ecm_device->rx_offset = 0;
+        eth_device_ready(&ecm_device->parent);
+        
+    }else
+    {
+        ecm_device->eps.ep_out->request.buffer = ecm_device->eps.ep_out->buffer;
+        ecm_device->eps.ep_out->request.size = EP_MAXPACKET(ecm_device->eps.ep_out);
+        ecm_device->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+        rt_usbd_io_request(ecm_device->func->device, ecm_device->eps.ep_out, &ecm_device->eps.ep_out->request);
+    }
+
+
+    return RT_EOK;
+}
+static rt_err_t rt_ecm_eth_init(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_err_t rt_ecm_eth_open(rt_device_t dev, rt_uint16_t oflag)
+{
+    return RT_EOK;
+}
+
+static rt_err_t rt_ecm_eth_close(rt_device_t dev)
+{
+    return RT_EOK;
+}
+
+static rt_size_t rt_ecm_eth_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+
+static rt_size_t rt_ecm_eth_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
+{
+    rt_set_errno(-RT_ENOSYS);
+    return 0;
+}
+static rt_err_t rt_ecm_eth_control(rt_device_t dev, int cmd, void *args)
+{
+    rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
+    switch(cmd)
+    {
+    case NIOCTL_GADDR:
+        /* get mac address */
+        if(args) rt_memcpy(args, ecm_eth_dev->dev_addr, MAX_ADDR_LEN);
+        else return -RT_ERROR;
+        break;
+
+    default :
+        break;
+    }
+
+    return RT_EOK;
+}
+struct pbuf *rt_ecm_eth_rx(rt_device_t dev)
+{
+    struct pbuf* p = RT_NULL;
+    rt_uint32_t offset = 0;
+    rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
+    if(ecm_eth_dev->rx_size != 0)
+    {
+        /* allocate buffer */
+        p = pbuf_alloc(PBUF_RAW, ecm_eth_dev->rx_size, PBUF_RAM);
+        if (p != RT_NULL)
+        {
+            struct pbuf* q;
+
+            for (q = p; q != RT_NULL; q= q->next)
+            {
+                /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
+                rt_memcpy(q->payload,
+                        (rt_uint8_t *)((ecm_eth_dev->rx_buffer) + offset),
+                        q->len);
+                offset += q->len;
+            }
+        }
+    }
+
+    {
+        if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
+        {
+            ecm_eth_dev->rx_size = 0;
+            ecm_eth_dev->rx_offset = 0;
+            ecm_eth_dev->eps.ep_out->request.buffer = ecm_eth_dev->eps.ep_out->buffer;
+            ecm_eth_dev->eps.ep_out->request.size = EP_MAXPACKET(ecm_eth_dev->eps.ep_out);
+            ecm_eth_dev->eps.ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+            rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_out, &ecm_eth_dev->eps.ep_out->request);
+        }
+    }
+
+    return p;
+}
+
+rt_err_t rt_ecm_eth_tx(rt_device_t dev, struct pbuf* p)
+{
+    struct pbuf* q;
+    char * pbuffer;
+    rt_err_t result = RT_EOK;
+    rt_ecm_eth_t ecm_eth_dev = (rt_ecm_eth_t)dev;
+
+    if(!ecm_eth_dev->parent.link_status)
+    {
+        ECM_PRINTF("linkdown, drop pkg\r\n");
+        return RT_EOK;
+    }
+
+    // RT_ASSERT(p->tot_len < USB_ETH_MTU);
+    if(p->tot_len > USB_ETH_MTU)
+    {
+        ECM_PRINTF("RNDIS MTU is:%d, but the send packet size is %d\r\n",
+                     USB_ETH_MTU, p->tot_len);
+        p->tot_len = USB_ETH_MTU;
+    }
+    result = rt_sem_take(&ecm_eth_dev->tx_buffer_free, RT_WAITING_FOREVER);
+    if(result != RT_EOK)
+    {
+        return result;
+    }
+    pbuffer = (char *)&ecm_eth_dev->tx_buffer;
+    for (q = p; q != NULL; q = q->next)
+    {
+        rt_memcpy(pbuffer, q->payload, q->len);
+        pbuffer += q->len;
+    }
+
+    {
+        if(ecm_eth_dev->func->device->state == USB_STATE_CONFIGURED)
+        {
+            ecm_eth_dev->eps.ep_in->request.buffer = (void *)&ecm_eth_dev->tx_buffer;
+            ecm_eth_dev->eps.ep_in->request.size = p->tot_len;
+            ecm_eth_dev->eps.ep_in->request.req_type = UIO_REQUEST_WRITE;
+            rt_usbd_io_request(ecm_eth_dev->func->device, ecm_eth_dev->eps.ep_in, &ecm_eth_dev->eps.ep_in->request);
+        }
+    }
+
+    return result;
+}
+/**
+ * This function will handle RNDIS interrupt in endpoint request.
+ *
+ * @param device the usb device object.
+ * @param size request size.
+ *
+ * @return RT_EOK.
+ */
+static rt_err_t _ep_cmd_handler(ufunction_t func, rt_size_t size)
+{
+    return RT_EOK;
+}
+
+/**
+ * This function will run cdc class, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_enable(ufunction_t func)
+{
+    cdc_eps_t eps;
+    rt_ecm_eth_t ecm_device = (rt_ecm_eth_t)func->user_data;
+    eps = (cdc_eps_t)&ecm_device->eps;
+    eps->ep_out->buffer = ecm_device->rx_pool;
+    ecm_device->rx_size = 0;
+    ecm_device->rx_offset = 0;
+    
+    eps->ep_out->request.buffer = (void *)eps->ep_out->buffer;
+    eps->ep_out->request.size = EP_MAXPACKET(eps->ep_out);
+    eps->ep_out->request.req_type = UIO_REQUEST_READ_BEST;
+    rt_usbd_io_request(func->device, eps->ep_out, &eps->ep_out->request);
+    return RT_EOK;
+}
+
+/**
+ * This function will stop cdc class, it will be called on handle set configuration request.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _function_disable(ufunction_t func)
+{
+    eth_device_linkchange(&((rt_ecm_eth_t)func->user_data)->parent, RT_FALSE);
+    return RT_EOK;
+}
+
+
+static struct ufunction_ops ops =
+{
+    _function_enable,
+    _function_disable,
+    RT_NULL,
+};
+
+/**
+ * This function will configure cdc descriptor.
+ *
+ * @param comm the communication interface number.
+ * @param data the data interface number.
+ *
+ * @return RT_EOK on successful.
+ */
+static rt_err_t _cdc_descriptor_config(ucdc_comm_desc_t comm, rt_uint8_t cintf_nr, ucdc_data_desc_t data, rt_uint8_t dintf_nr)
+{
+    comm->call_mgmt_desc.data_interface = dintf_nr;
+    comm->union_desc.master_interface = cintf_nr;
+    comm->union_desc.slave_interface0 = dintf_nr;
+#ifdef RT_USB_DEVICE_COMPOSITE
+    comm->iad_desc.bFirstInterface = cintf_nr;
+#endif
+
+    return RT_EOK;
+}
+
+
+
+/**
+ * This function will create a cdc ecm class instance.
+ *
+ * @param device the usb device object.
+ *
+ * @return RT_EOK on successful.
+ */
+ufunction_t rt_usbd_function_ecm_create(udevice_t device)
+{
+    ufunction_t cdc;
+    rt_ecm_eth_t _ecm_eth;
+    cdc_eps_t eps;
+    uintf_t intf_comm, intf_data;
+    ualtsetting_t comm_setting, data_setting;
+    ucdc_data_desc_t data_desc;
+    ucdc_eth_desc_t comm_desc;
+    
+    /* parameter check */
+    RT_ASSERT(device != RT_NULL);
+
+    /* set usb device string description */
+    rt_usbd_device_set_string(device, _ustring);
+
+    /* create a cdc class */
+    cdc = rt_usbd_function_new(device, &_dev_desc, &ops);
+    rt_usbd_device_set_qualifier(device, &dev_qualifier);
+    _ecm_eth= rt_malloc(sizeof(struct rt_ecm_eth)); 
+    rt_memset(_ecm_eth, 0, sizeof(struct rt_ecm_eth));
+    cdc->user_data = _ecm_eth;
+
+    _ecm_eth->func = cdc;
+    /* create a cdc class endpoints collection */
+    eps = &_ecm_eth->eps;
+    /* create a cdc communication interface and a cdc data interface */
+    intf_comm = rt_usbd_interface_new(device, _interface_handler);
+    intf_data = rt_usbd_interface_new(device, _interface_handler);
+
+    /* create a communication alternate setting and a data alternate setting */
+    comm_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_eth_descriptor));
+    data_setting = rt_usbd_altsetting_new(sizeof(struct ucdc_data_descriptor));
+
+    /* config desc in alternate setting */
+    rt_usbd_altsetting_config_descriptor(comm_setting, &_comm_desc,
+                                         (rt_off_t)&((ucdc_eth_desc_t)0)->intf_desc);
+    rt_usbd_altsetting_config_descriptor(data_setting, &_data_desc, 0);
+    /* configure the cdc interface descriptor */
+    _cdc_descriptor_config(comm_setting->desc, intf_comm->intf_num, data_setting->desc, intf_data->intf_num);
+
+    /* create a command endpoint */
+    comm_desc = (ucdc_eth_desc_t)comm_setting->desc;
+    eps->ep_cmd = rt_usbd_endpoint_new(&comm_desc->ep_desc, _ep_cmd_handler);
+    /* add the command endpoint to the cdc communication interface */
+    rt_usbd_altsetting_add_endpoint(comm_setting, eps->ep_cmd);
+
+    /* add the communication alternate setting to the communication interface,
+       then set default setting of the interface */
+    rt_usbd_interface_add_altsetting(intf_comm, comm_setting);
+    rt_usbd_set_altsetting(intf_comm, 0);
+    /* add the communication interface to the cdc class */
+    rt_usbd_function_add_interface(cdc, intf_comm);
+    
+    /* create a bulk in and a bulk out endpoint */
+    data_desc = (ucdc_data_desc_t)data_setting->desc;
+    eps->ep_out = rt_usbd_endpoint_new(&data_desc->ep_out_desc, _ep_out_handler);
+    eps->ep_in = rt_usbd_endpoint_new(&data_desc->ep_in_desc, _ep_in_handler);
+
+    /* add the bulk out and bulk in endpoints to the data alternate setting */
+    rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_in);
+    rt_usbd_altsetting_add_endpoint(data_setting, eps->ep_out);
+
+    /* add the data alternate setting to the data interface
+            then set default setting of the interface */
+    rt_usbd_interface_add_altsetting(intf_data, data_setting);
+    rt_usbd_set_altsetting(intf_data, 0);
+
+    /* add the cdc data interface to cdc class */
+    rt_usbd_function_add_interface(cdc, intf_data);
+
+    rt_sem_init(&_ecm_eth->tx_buffer_free, "ue_tx", 1, RT_IPC_FLAG_FIFO);
+    /* OUI 00-00-00, only for test. */
+    _ecm_eth->dev_addr[0] = 0x34;
+    _ecm_eth->dev_addr[1] = 0x97;
+    _ecm_eth->dev_addr[2] = 0xF6;
+    /* generate random MAC. */
+    _ecm_eth->dev_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
+    _ecm_eth->dev_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
+    _ecm_eth->dev_addr[5] = 0xAC;//(const rt_uint8_t *)(0x1fff7a18);
+    /* OUI 00-00-00, only for test. */
+    _ecm_eth->host_addr[0] = 0x34;
+    _ecm_eth->host_addr[1] = 0x97;
+    _ecm_eth->host_addr[2] = 0xF6;
+    /* generate random MAC. */
+    _ecm_eth->host_addr[3] = 0x94;//*(const rt_uint8_t *)(0x1fff7a10);
+    _ecm_eth->host_addr[4] = 0xEC;//*(const rt_uint8_t *)(0x1fff7a14);
+    _ecm_eth->host_addr[5] = 0xAB;//*(const rt_uint8_t *)(0x1fff7a18);
+
+    _ecm_eth->parent.parent.init       = rt_ecm_eth_init;
+    _ecm_eth->parent.parent.open       = rt_ecm_eth_open;
+    _ecm_eth->parent.parent.close      = rt_ecm_eth_close;
+    _ecm_eth->parent.parent.read       = rt_ecm_eth_read;
+    _ecm_eth->parent.parent.write      = rt_ecm_eth_write;
+    _ecm_eth->parent.parent.control    = rt_ecm_eth_control;
+    _ecm_eth->parent.parent.user_data  = device;
+
+    _ecm_eth->parent.eth_rx     = rt_ecm_eth_rx;
+    _ecm_eth->parent.eth_tx     = rt_ecm_eth_tx;
+    /* register eth device */
+    eth_device_init(&_ecm_eth->parent, "u0");
+    
+    /* send link up. */
+    eth_device_linkchange(&_ecm_eth->parent, RT_FALSE);
+   
+    return cdc;
+}

+ 11 - 0
components/drivers/usb/usbdevice/core/usbdevice.c

@@ -132,6 +132,17 @@ rt_err_t rt_usb_device_init(void)
     }
 #endif
 
+#ifdef RT_USB_DEVICE_ECM
+    {
+        extern ufunction_t rt_usbd_function_ecm_create(udevice_t device);
+        /* create a rndis function object */
+        func = rt_usbd_function_ecm_create(udevice);
+
+        /* add the function to the configuration */
+        rt_usbd_config_add_function(cfg, func);
+    }
+#endif
+
     /* set device descriptor to the device */
 #ifdef RT_USB_DEVICE_COMPOSITE
     rt_usbd_device_set_descriptor(udevice, &compsit_desc);