summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsakumisu <[email protected]>2023-11-11 13:59:59 +0800
committersakumisu <[email protected]>2023-11-13 19:49:27 +0800
commit40a019e0632e5325a4f837e5fe29e9222f956e7d (patch)
treed31db89a1dfdda4b1c4059d9d884f1b71b7dd56e
parent2080cf1206569a3b2407f793a1920970ea281660 (diff)
add ecm host demo
-rw-r--r--class/cdc/usbh_cdc_ecm.c199
-rw-r--r--class/cdc/usbh_cdc_ecm.h18
-rw-r--r--demo/usb_host.c67
3 files changed, 225 insertions, 59 deletions
diff --git a/class/cdc/usbh_cdc_ecm.c b/class/cdc/usbh_cdc_ecm.c
index f7321037..d78ff1fb 100644
--- a/class/cdc/usbh_cdc_ecm.c
+++ b/class/cdc/usbh_cdc_ecm.c
@@ -6,47 +6,27 @@
#include "usbh_core.h"
#include "usbh_cdc_ecm.h"
-#define DEV_FORMAT "/dev/cdc_ether"
+#define DEV_FORMAT "/dev/cdc_ether"
/* general descriptor field offsets */
-#define DESC_bLength 0 /** Length offset */
-#define DESC_bDescriptorType 1 /** Descriptor type offset */
-#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
+#define DESC_bLength 0 /** Length offset */
+#define DESC_bDescriptorType 1 /** Descriptor type offset */
+#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
/* interface descriptor field offsets */
-#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
-#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
+#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
+#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
-#define CONFIG_USBHOST_MAX_CDC_ECM_CLASS 1
-static struct usbh_cdc_ecm g_cdc_ecm_class[CONFIG_USBHOST_MAX_CDC_ECM_CLASS];
-static uint32_t g_devinuse = 0;
+#define CONFIG_USBHOST_CDC_ECM_PKT_FILTER 0x000C
+#define CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE 1514U
-static struct usbh_cdc_ecm *usbh_cdc_ecm_class_alloc(void)
-{
- int devno;
-
- for (devno = 0; devno < CONFIG_USBHOST_MAX_CDC_ECM_CLASS; devno++) {
- if ((g_devinuse & (1 << devno)) == 0) {
- g_devinuse |= (1 << devno);
- memset(&g_cdc_ecm_class[devno], 0, sizeof(struct usbh_cdc_ecm));
- g_cdc_ecm_class[devno].minor = devno;
- return &g_cdc_ecm_class[devno];
- }
- }
- return NULL;
-}
-
-static void usbh_cdc_ecm_class_free(struct usbh_cdc_ecm *cdc_ecm_class)
-{
- int devno = cdc_ecm_class->minor;
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_rx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_tx_buffer[CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE];
+USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_cdc_ecm_inttx_buffer[16];
- if (devno >= 0 && devno < 32) {
- g_devinuse &= ~(1 << devno);
- }
- memset(cdc_ecm_class, 0, sizeof(struct usbh_cdc_ecm));
-}
+static struct usbh_cdc_ecm g_cdc_ecm_class;
-int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t filter_value)
+static int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t filter_value)
{
struct usb_setup_packet *setup = cdc_ecm_class->hport->setup;
@@ -59,17 +39,22 @@ int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint1
return usbh_control_transfer(cdc_ecm_class->hport->ep0, setup, NULL);
}
-int usbh_cdc_ecm_select_altsetting(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t alt_setting)
+int usbh_cdc_ecm_get_notification(struct usbh_cdc_ecm *cdc_ecm_class)
{
- struct usb_setup_packet *setup = cdc_ecm_class->hport->setup;
+ int ret;
- setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
- setup->bRequest = USB_REQUEST_SET_INTERFACE;
- setup->wValue = alt_setting;
- setup->wIndex = cdc_ecm_class->data_intf;
- setup->wLength = 0;
+ usbh_int_urb_fill(&cdc_ecm_class->intin_urb, cdc_ecm_class->intin, g_cdc_ecm_inttx_buffer, 16, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ ret = usbh_submit_urb(&cdc_ecm_class->intin_urb);
+ if (ret < 0) {
+ return ret;
+ }
- return usbh_control_transfer(cdc_ecm_class->hport->ep0, setup, NULL);
+ if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_NETWORK_CONNECTION) {
+ cdc_ecm_class->connect_status = g_cdc_ecm_inttx_buffer[2];
+ } else if (g_cdc_ecm_inttx_buffer[1] == CDC_ECM_NOTIFY_CODE_CONNECTION_SPEED_CHANGE) {
+ memcpy(cdc_ecm_class->speed, &g_cdc_ecm_inttx_buffer[8], 8);
+ }
+ return 0;
}
static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
@@ -77,16 +62,12 @@ static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
struct usb_endpoint_descriptor *ep_desc;
int ret;
uint8_t altsetting = 0;
- uint8_t mac_buffer[32];
+ char mac_buffer[8];
uint8_t *p;
uint8_t cur_iface = 0xff;
uint8_t mac_str_idx = 0xff;
- struct usbh_cdc_ecm *cdc_ecm_class = usbh_cdc_ecm_class_alloc();
- if (cdc_ecm_class == NULL) {
- USB_LOG_ERR("Fail to alloc cdc_ecm_class\r\n");
- return -ENOMEM;
- }
+ struct usbh_cdc_ecm *cdc_ecm_class = &g_cdc_ecm_class;
cdc_ecm_class->hport = hport;
cdc_ecm_class->ctrl_intf = intf;
@@ -104,7 +85,9 @@ static int usbh_cdc_ecm_connect(struct usbh_hubport *hport, uint8_t intf)
break;
case CDC_CS_INTERFACE:
if ((cur_iface == cdc_ecm_class->ctrl_intf) && p[DESC_bDescriptorSubType] == CDC_FUNC_DESC_ETHERNET_NETWORKING) {
- mac_str_idx = p[3];
+ struct cdc_ecm_descriptor *desc = (struct cdc_ecm_descriptor *)p;
+ mac_str_idx = desc->iMACAddress;
+ cdc_ecm_class->max_segment_size = desc->wMaxSegmentSize;
goto get_mac;
}
break;
@@ -122,8 +105,8 @@ get_mac:
return -1;
}
- memset(mac_buffer, 0, 32);
- ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, mac_buffer);
+ memset(mac_buffer, 0, 8);
+ ret = usbh_get_string_desc(cdc_ecm_class->hport, mac_str_idx, (uint8_t *)mac_buffer);
if (ret < 0) {
return ret;
}
@@ -148,6 +131,12 @@ get_mac:
cdc_ecm_class->mac[4],
cdc_ecm_class->mac[5]);
+ if (cdc_ecm_class->max_segment_size > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE) {
+ USB_LOG_ERR("CDC ECM Max Segment Size is overflow, default is %u, but now %u\r\n", CONFIG_USBHOST_CDC_ECM_ETH_MAX_SEGSZE, cdc_ecm_class->max_segment_size);
+ } else {
+ USB_LOG_INFO("CDC ECM Max Segment Size:%u\r\n", cdc_ecm_class->max_segment_size);
+ }
+
/* enable int ep */
ep_desc = &hport->config.intf[intf].altsetting[0].ep[0].ep_desc;
usbh_hport_activate_epx(&cdc_ecm_class->intin, hport, ep_desc);
@@ -166,7 +155,7 @@ get_mac:
}
USB_LOG_INFO("Select cdc ecm altsetting: %d\r\n", altsetting);
- usbh_cdc_ecm_select_altsetting(cdc_ecm_class, altsetting);
+ usbh_set_interface(cdc_ecm_class->hport, cdc_ecm_class->data_intf, altsetting);
} else {
for (uint8_t i = 0; i < hport->config.intf[intf + 1].altsetting[0].intf_desc.bNumEndpoints; i++) {
ep_desc = &hport->config.intf[intf + 1].altsetting[0].ep[i].ep_desc;
@@ -179,12 +168,19 @@ get_mac:
}
}
- // ret = usbh_cdc_ecm_set_eth_packet_filter(cdc_ecm_class, 0x000c);
- // if (ret < 0) {
- // return ret;
- // }
+ /* bit0 Promiscuous
+ * bit1 ALL Multicast
+ * bit2 Directed
+ * bit3 Broadcast
+ * bit4 Multicast
+ */
+ ret = usbh_cdc_ecm_set_eth_packet_filter(cdc_ecm_class, CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
+ if (ret < 0) {
+ return ret;
+ }
+ USB_LOG_INFO("Set CDC ECM packet filter:%04x\r\n", CONFIG_USBHOST_CDC_ECM_PKT_FILTER);
- snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, cdc_ecm_class->minor);
+ memcpy(hport->config.intf[intf].devname, DEV_FORMAT, CONFIG_USBHOST_DEV_NAMELEN);
USB_LOG_INFO("Register CDC ECM Class:%s\r\n", hport->config.intf[intf].devname);
@@ -216,12 +212,101 @@ static int usbh_cdc_ecm_disconnect(struct usbh_hubport *hport, uint8_t intf)
usbh_cdc_ecm_stop(cdc_ecm_class);
}
- usbh_cdc_ecm_class_free(cdc_ecm_class);
+ memset(cdc_ecm_class, 0, sizeof(struct usbh_cdc_ecm));
}
return ret;
}
+static void usbh_cdc_ecm_rx_thread(void *argument)
+{
+ uint32_t g_cdc_ecm_rx_length;
+ int ret;
+ err_t err;
+ struct pbuf *p;
+ struct netif *netif = (struct netif *)argument;
+ uint16_t ep_mps;
+
+ // clang-format off
+find_class:
+ // clang-format on
+ while (usbh_find_class_instance("/dev/cdc_ether") == NULL) {
+ usb_osal_msleep(1000);
+ }
+
+ while (g_cdc_ecm_class.connect_status == CDC_ECM_NET_DISCONNECTED) {
+ ret = usbh_cdc_ecm_get_notification(&g_cdc_ecm_class);
+ if (ret < 0) {
+ goto find_class;
+ }
+ }
+
+ if (g_cdc_ecm_class.hport->speed == USB_SPEED_FULL) {
+ ep_mps = 64;
+ } else {
+ ep_mps = 512;
+ }
+ g_cdc_ecm_rx_length = 0;
+ while (1) {
+ usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkin_urb, g_cdc_ecm_class.bulkin, &g_cdc_ecm_rx_buffer[g_cdc_ecm_rx_length], ep_mps, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ ret = usbh_submit_urb(&g_cdc_ecm_class.bulkin_urb);
+ if (ret < 0) {
+ goto find_class;
+ }
+
+ g_cdc_ecm_rx_length += g_cdc_ecm_class.bulkin_urb.actual_length;
+
+ if (g_cdc_ecm_rx_length % ep_mps) {
+ USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
+
+ p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_length, PBUF_POOL);
+ if (p != NULL) {
+ memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
+ g_cdc_ecm_rx_length = 0;
+ err = netif->input(p, netif);
+ if (err != ERR_OK) {
+ pbuf_free(p);
+ }
+ } else {
+ g_cdc_ecm_rx_length = 0;
+ USB_LOG_ERR("No memory to alloc pbuf for cdc ecm rx\r\n");
+ }
+ } else {
+ }
+ }
+}
+
+err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ int ret;
+ struct pbuf *q;
+ uint8_t *buffer = g_cdc_ecm_tx_buffer;
+
+ if (g_cdc_ecm_class.connect_status == CDC_ECM_NET_DISCONNECTED) {
+ return ERR_BUF;
+ }
+
+ for (q = p; q != NULL; q = q->next) {
+ memcpy(buffer, q->payload, q->len);
+ buffer += q->len;
+ }
+
+ USB_LOG_DBG("txlen:%d\r\n", p->tot_len);
+
+ usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, p->tot_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ ret = usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
+ if (ret < 0) {
+ return ERR_BUF;
+ }
+
+ return ERR_OK;
+}
+
+void usbh_cdc_ecm_lwip_thread_init(struct netif *netif)
+{
+ usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, netif);
+}
+
__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
{
}
diff --git a/class/cdc/usbh_cdc_ecm.h b/class/cdc/usbh_cdc_ecm.h
index 1b3be821..7e0e96c3 100644
--- a/class/cdc/usbh_cdc_ecm.h
+++ b/class/cdc/usbh_cdc_ecm.h
@@ -8,6 +8,9 @@
#include "usb_cdc.h"
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+
struct usbh_cdc_ecm {
struct usbh_hubport *hport;
@@ -15,20 +18,31 @@ struct usbh_cdc_ecm {
uint8_t data_intf; /* Data interface number */
uint8_t minor;
uint8_t mac[6];
+ uint32_t max_segment_size;
+ uint8_t connect_status;
+ uint32_t speed[2];
usbh_pipe_t bulkin; /* Bulk IN endpoint */
usbh_pipe_t bulkout; /* Bulk OUT endpoint */
usbh_pipe_t intin; /* Interrupt IN endpoint */
+ struct usbh_urb bulkout_urb;
+ struct usbh_urb bulkin_urb;
+ struct usbh_urb intin_urb;
+
+ ip_addr_t ipaddr;
+ ip_addr_t netmask;
+ ip_addr_t gateway;
};
#ifdef __cplusplus
extern "C" {
#endif
-int usbh_cdc_ecm_set_eth_packet_filter(struct usbh_cdc_ecm *cdc_ecm_class, uint16_t filter_value);
-
void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class);
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class);
+err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p);
+void usbh_cdc_ecm_lwip_thread_init(struct netif *netif);
+
#ifdef __cplusplus
}
#endif
diff --git a/demo/usb_host.c b/demo/usb_host.c
index ee842d03..9d156fc3 100644
--- a/demo/usb_host.c
+++ b/demo/usb_host.c
@@ -11,6 +11,7 @@
#define TEST_USBH_MSC_FATFS 0
#define TEST_USBH_AUDIO 0
#define TEST_USBH_VIDEO 0
+#define TEST_USBH_CDC_ECM 0
#if TEST_USBH_CDC_ACM
USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t cdc_buffer[512];
@@ -380,6 +381,66 @@ void usbh_videostreaming_parse_yuyv2(struct usbh_urb *urb, struct usbh_videostre
}
#endif
+#if TEST_USBH_CDC_ECM
+#include "usbh_cdc_ecm.h"
+
+#include "netif/etharp.h"
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+#include "lwip/tcpip.h"
+#if LWIP_DHCP
+#include "lwip/dhcp.h"
+#endif
+
+struct netif g_cdc_ecm_netif;
+
+static err_t usbh_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] = 'E';
+ netif->name[1] = 'X';
+ netif->output = etharp_output;
+ netif->linkoutput = usbh_cdc_ecm_linkoutput;
+ return ERR_OK;
+}
+
+void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+ struct netif *netif = &g_cdc_ecm_netif;
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, cdc_ecm_class->mac, 6);
+
+ IP4_ADDR(&cdc_ecm_class->ipaddr, 0, 0, 0, 0);
+ IP4_ADDR(&cdc_ecm_class->netmask, 0, 0, 0, 0);
+ IP4_ADDR(&cdc_ecm_class->gateway, 0, 0, 0, 0);
+
+ netif = netif_add(netif, &cdc_ecm_class->ipaddr, &cdc_ecm_class->netmask, &cdc_ecm_class->gateway, NULL, usbh_cdc_ecm_if_init, tcpip_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+#if LWIP_DHCP
+ dhcp_start(netif);
+#endif
+}
+
+void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+ struct netif *netif = &g_cdc_ecm_netif;
+#if LWIP_DHCP
+ dhcp_stop(netif);
+ dhcp_cleanup(netif);
+#endif
+ netif_set_down(netif);
+ netif_remove(netif);
+}
+#endif
+
void usbh_cdc_acm_run(struct usbh_cdc_acm *cdc_acm_class)
{
}
@@ -439,4 +500,10 @@ void usbh_class_test(void)
#error "if you want to use iso, please contact with me"
usb_osal_thread_create("usbh_video", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_video_thread, NULL);
#endif
+#if TEST_USBH_CDC_ECM
+ /* Initialize the LwIP stack */
+ tcpip_init(NULL, NULL);
+
+ usbh_cdc_ecm_lwip_thread_init(&g_cdc_ecm_netif);
+#endif
} \ No newline at end of file