xiaoxiang781216 commented on code in PR #18815:
URL: https://github.com/apache/nuttx/pull/18815#discussion_r3155914569


##########
drivers/usbhost/usbhost_enumerate.c:
##########
@@ -454,14 +455,22 @@ int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
   DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, hport->funcaddr,
                     hport->speed, maxpacketsize);
 
-  /* Get the configuration descriptor (only), index == 0.  Should not be
-   * hard-coded! More logic is needed in order to handle devices with
-   * multiple configurations.
+#ifdef CONFIG_USBHOST_CONFIGURATION_SELECTION
+  /* Board specific callback to choose which configuration to use for
+   * this device. Supplied by board file
    */
 
+  cfgidx = usbhost_select_configuration(hport,
+             (struct usb_devdesc_s *)buffer, &id);
+#else
+  cfgidx = 0;

Review Comment:
   merge to line 298



##########
drivers/usbhost/usbhost_cdcecm.c:
##########
@@ -0,0 +1,2160 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcecm.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+
+#ifdef CONFIG_NET_PKT
+  #include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM

Review Comment:
   delete



##########
drivers/usbhost/usbhost_cdcecm.c:
##########
@@ -0,0 +1,2160 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcecm.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+
+#ifdef CONFIG_NET_PKT
+  #include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Default max segment size if not specified by device */
+
+#define CDCECM_DEFAULT_MAXSEG   1514
+
+/* ECM control requests */
+
+#define ECM_SET_PACKET_FILTER_REQUEST 0x43
+
+/* ECM packet filter bits */
+
+#define ECM_PACKET_TYPE_PROMISCUOUS    (1 << 0)
+#define ECM_PACKET_TYPE_ALL_MULTICAST  (1 << 1)
+#define ECM_PACKET_TYPE_DIRECTED       (1 << 2)
+#define ECM_PACKET_TYPE_BROADCAST      (1 << 3)
+#define ECM_PACKET_TYPE_MULTICAST      (1 << 4)
+
+/* Default packet filter: unicast + broadcast */
+
+#define ECM_DEFAULT_PACKET_FILTER      (ECM_PACKET_TYPE_DIRECTED | \
+                                        ECM_PACKET_TYPE_BROADCAST)
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+#  warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+#ifndef CONFIG_USBHOST_ASYNCH
+#  warning Asynchronous transfer support is required (CONFIG_USBHOST_ASYNCH)
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM_NTDELAY
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(CONFIG_USBHOST_CDCECM_NTDELAY)
+#else
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(200)
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_RXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_RXBUFSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_TXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_TXBUFSIZE 2048
+#endif
+
+/* Used in usbhost_cfgdesc() */
+
+#define USBHOST_CTRLIFFOUND 0x01
+#define USBHOST_DATAIFFOUND 0x02
+#define USBHOST_INTRIFFOUND 0x04
+#define USBHOST_BINFOUND    0x08
+#define USBHOST_BOUTFOUND   0x10
+#define USBHOST_ECMFOUND    0x20
+#define USBHOST_ALLFOUND    0x3f
+
+#define USBHOST_MAX_CREFS   0x7fff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct usb_csifdesc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+};
+
+/* This structure contains the internal, private state of the USB host class
+ * driver.
+ */
+
+struct usbhost_cdcecm_s
+{
+  /* This is the externally visible portion of the state */
+
+  struct usbhost_class_s  usbclass;
+
+  /* The remainder of the fields are provided to the class driver */
+
+  volatile bool           disconnected; /* TRUE: Device has been disconnected 
*/
+  uint16_t                ctrlif;       /* Control interface number */
+  uint16_t                dataif;       /* Data interface number */
+  int16_t                 crefs;        /* Reference count on the driver 
instance */
+  mutex_t                 lock;         /* Used to maintain mutual exclusive 
access */
+  struct work_s           ntwork;       /* Notification work */
+  struct work_s           bulk_rxwork;
+  struct work_s           txpollwork;
+  struct work_s           destroywork;
+  int16_t                 nnbytes;      /* Number of bytes received in 
notification */
+  int16_t                 bulkinbytes;
+  uint16_t                maxintsize;   /* Maximum size of interrupt IN packet 
*/
+  FAR uint8_t            *ctrlreq;      /* Allocated ctrl request structure */
+  FAR uint8_t            *notification; /* Allocated RX buffer for async 
notifications */
+  FAR uint8_t            *bulkinbuf;    /* Allocated RX buffer for bulk IN */
+  FAR uint8_t            *bulkoutbuf;   /* Allocated TX buffer for bulk OUT */
+  usbhost_ep_t            intin;        /* Interrupt endpoint */
+  usbhost_ep_t            bulkin;       /* Bulk IN endpoint */
+  usbhost_ep_t            bulkout;      /* Bulk OUT endpoint */
+  uint16_t                bulkmxpacket; /* Max packet size for Bulk OUT 
endpoint */
+
+  /* Device info from ECM descriptor */
+
+  uint16_t                maxsegment;    /* Max Ethernet frame size */
+  uint8_t                 macstridx;     /* MAC address string index */
+  uint8_t                 macaddr[6];    /* Device MAC address */
+
+  /* Network device members */
+
+  bool                    registered;   /* true if the device was registered */
+  bool                    bifup;        /* true:ifup false:ifdown */
+  struct net_driver_s     netdev;       /* Interface understood by the network 
*/
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Memory allocation services */
+
+static inline FAR struct usbhost_cdcecm_s *usbhost_allocclass(void);
+static inline void usbhost_freeclass(FAR struct usbhost_cdcecm_s *usbclass);
+
+/* Worker thread actions */
+
+static void usbhost_notification_work(FAR void *arg);
+static void usbhost_notification_callback(FAR void *arg, ssize_t nbytes);
+static void usbhost_bulkin_work(FAR void *arg);
+
+static void usbhost_destroy(FAR void *arg);
+
+/* Helpers for usbhost_connect() */
+
+static int usbhost_cfgdesc(FAR struct usbhost_cdcecm_s *priv,
+                           FAR const uint8_t *configdesc, int desclen);
+static inline int usbhost_devinit(FAR struct usbhost_cdcecm_s *priv);
+
+/* (Little Endian) Data helpers */
+
+static inline uint16_t usbhost_getle16(const uint8_t *val);
+static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
+static inline uint32_t usbhost_getle32(const uint8_t *val);
+
+/* Buffer memory management */
+
+static int usbhost_alloc_buffers(FAR struct usbhost_cdcecm_s *priv);
+static void usbhost_free_buffers(FAR struct usbhost_cdcecm_s *priv);
+
+/* struct usbhost_registry_s methods */
+
+static struct usbhost_class_s
+              *usbhost_create(FAR struct usbhost_hubport_s *hport,
+                              FAR const struct usbhost_id_s *id);
+
+/* struct usbhost_class_s methods */
+
+static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
+                           FAR const uint8_t *configdesc, int desclen);
+static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
+
+/* NuttX network callback functions */
+
+static int cdcecm_ifup(struct net_driver_s *dev);
+static int cdcecm_ifdown(struct net_driver_s *dev);
+static int cdcecm_txavail(struct net_driver_s *dev);
+
+/* Network support functions */
+
+static void cdcecm_receive(struct usbhost_cdcecm_s *priv);
+
+static int cdcecm_txpoll(struct net_driver_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This structure provides the registry entry ID information that will  be
+ * used to associate the USB class driver to a connected USB device.
+ */
+
+static const struct usbhost_id_s g_id[] =

Review Comment:
   g_cdcecm_id



##########
drivers/usbhost/usbhost_cdcecm.c:
##########
@@ -0,0 +1,2160 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcecm.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+
+#ifdef CONFIG_NET_PKT
+  #include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Default max segment size if not specified by device */
+
+#define CDCECM_DEFAULT_MAXSEG   1514
+
+/* ECM control requests */
+
+#define ECM_SET_PACKET_FILTER_REQUEST 0x43
+
+/* ECM packet filter bits */
+
+#define ECM_PACKET_TYPE_PROMISCUOUS    (1 << 0)
+#define ECM_PACKET_TYPE_ALL_MULTICAST  (1 << 1)
+#define ECM_PACKET_TYPE_DIRECTED       (1 << 2)
+#define ECM_PACKET_TYPE_BROADCAST      (1 << 3)
+#define ECM_PACKET_TYPE_MULTICAST      (1 << 4)
+
+/* Default packet filter: unicast + broadcast */
+
+#define ECM_DEFAULT_PACKET_FILTER      (ECM_PACKET_TYPE_DIRECTED | \
+                                        ECM_PACKET_TYPE_BROADCAST)
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+#  warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+#ifndef CONFIG_USBHOST_ASYNCH
+#  warning Asynchronous transfer support is required (CONFIG_USBHOST_ASYNCH)
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM_NTDELAY
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(CONFIG_USBHOST_CDCECM_NTDELAY)
+#else
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(200)
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_RXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_RXBUFSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_TXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_TXBUFSIZE 2048
+#endif
+
+/* Used in usbhost_cfgdesc() */
+
+#define USBHOST_CTRLIFFOUND 0x01
+#define USBHOST_DATAIFFOUND 0x02
+#define USBHOST_INTRIFFOUND 0x04
+#define USBHOST_BINFOUND    0x08
+#define USBHOST_BOUTFOUND   0x10
+#define USBHOST_ECMFOUND    0x20
+#define USBHOST_ALLFOUND    0x3f
+
+#define USBHOST_MAX_CREFS   0x7fff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct usb_csifdesc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+};
+
+/* This structure contains the internal, private state of the USB host class
+ * driver.
+ */
+
+struct usbhost_cdcecm_s
+{
+  /* This is the externally visible portion of the state */
+
+  struct usbhost_class_s  usbclass;
+
+  /* The remainder of the fields are provided to the class driver */
+
+  volatile bool           disconnected; /* TRUE: Device has been disconnected 
*/
+  uint16_t                ctrlif;       /* Control interface number */
+  uint16_t                dataif;       /* Data interface number */
+  int16_t                 crefs;        /* Reference count on the driver 
instance */
+  mutex_t                 lock;         /* Used to maintain mutual exclusive 
access */
+  struct work_s           ntwork;       /* Notification work */
+  struct work_s           bulk_rxwork;
+  struct work_s           txpollwork;
+  struct work_s           destroywork;
+  int16_t                 nnbytes;      /* Number of bytes received in 
notification */
+  int16_t                 bulkinbytes;
+  uint16_t                maxintsize;   /* Maximum size of interrupt IN packet 
*/
+  FAR uint8_t            *ctrlreq;      /* Allocated ctrl request structure */
+  FAR uint8_t            *notification; /* Allocated RX buffer for async 
notifications */
+  FAR uint8_t            *bulkinbuf;    /* Allocated RX buffer for bulk IN */
+  FAR uint8_t            *bulkoutbuf;   /* Allocated TX buffer for bulk OUT */
+  usbhost_ep_t            intin;        /* Interrupt endpoint */
+  usbhost_ep_t            bulkin;       /* Bulk IN endpoint */
+  usbhost_ep_t            bulkout;      /* Bulk OUT endpoint */
+  uint16_t                bulkmxpacket; /* Max packet size for Bulk OUT 
endpoint */
+
+  /* Device info from ECM descriptor */
+
+  uint16_t                maxsegment;    /* Max Ethernet frame size */
+  uint8_t                 macstridx;     /* MAC address string index */
+  uint8_t                 macaddr[6];    /* Device MAC address */
+
+  /* Network device members */
+
+  bool                    registered;   /* true if the device was registered */
+  bool                    bifup;        /* true:ifup false:ifdown */
+  struct net_driver_s     netdev;       /* Interface understood by the network 
*/
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Memory allocation services */
+
+static inline FAR struct usbhost_cdcecm_s *usbhost_allocclass(void);
+static inline void usbhost_freeclass(FAR struct usbhost_cdcecm_s *usbclass);
+
+/* Worker thread actions */
+
+static void usbhost_notification_work(FAR void *arg);
+static void usbhost_notification_callback(FAR void *arg, ssize_t nbytes);
+static void usbhost_bulkin_work(FAR void *arg);
+
+static void usbhost_destroy(FAR void *arg);
+
+/* Helpers for usbhost_connect() */
+
+static int usbhost_cfgdesc(FAR struct usbhost_cdcecm_s *priv,
+                           FAR const uint8_t *configdesc, int desclen);
+static inline int usbhost_devinit(FAR struct usbhost_cdcecm_s *priv);
+
+/* (Little Endian) Data helpers */
+
+static inline uint16_t usbhost_getle16(const uint8_t *val);
+static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
+static inline uint32_t usbhost_getle32(const uint8_t *val);
+
+/* Buffer memory management */
+
+static int usbhost_alloc_buffers(FAR struct usbhost_cdcecm_s *priv);
+static void usbhost_free_buffers(FAR struct usbhost_cdcecm_s *priv);
+
+/* struct usbhost_registry_s methods */
+
+static struct usbhost_class_s
+              *usbhost_create(FAR struct usbhost_hubport_s *hport,
+                              FAR const struct usbhost_id_s *id);
+
+/* struct usbhost_class_s methods */
+
+static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
+                           FAR const uint8_t *configdesc, int desclen);
+static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
+
+/* NuttX network callback functions */
+
+static int cdcecm_ifup(struct net_driver_s *dev);
+static int cdcecm_ifdown(struct net_driver_s *dev);
+static int cdcecm_txavail(struct net_driver_s *dev);
+
+/* Network support functions */
+
+static void cdcecm_receive(struct usbhost_cdcecm_s *priv);
+
+static int cdcecm_txpoll(struct net_driver_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This structure provides the registry entry ID information that will  be
+ * used to associate the USB class driver to a connected USB device.
+ */
+
+static const struct usbhost_id_s g_id[] =
+{
+  {
+    USB_CLASS_CDC,          /* base - CDC class */
+    CDC_SUBCLASS_NONE,      /* subclass */
+    CDC_PROTO_NONE,         /* proto    */
+    0,                      /* vid      */
+    0                       /* pid      */
+  },
+  {
+    USB_CLASS_CDC,          /* base - CDC class */
+    CDC_SUBCLASS_ECM,       /* subclass - Ethernet Control Model */
+    CDC_PROTO_NONE,         /* proto - No class specific protocol */
+    0,                      /* vid - Any vendor */
+    0                       /* pid - Any product */
+  }
+};
+
+/* This is the USB host storage class's registry entry */
+
+static struct usbhost_registry_s g_cdcecm =
+{
+  NULL,                           /* flink */
+  usbhost_create,                 /* create */
+  sizeof(g_id) / sizeof(g_id[0]), /* nids */
+  g_id                            /* id[] */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#if defined(CONFIG_DEBUG_USB) && defined(USBHOST_CDCECM_PACKET_PRINT)
+static void cdcecm_print_packet(const char * dir, const uint8_t * buf,
+                                size_t len)
+{
+  char * str = kmm_malloc(len * 2 + 1);
+  if (str == NULL)
+    {
+      uerr("Failed to dump ECM %s packet\n", dir);
+    }
+  else
+    {
+      for (size_t i = 0; i < len; ++i)
+        {
+          sprintf(&str[i * 2], "%02X", buf[i]);
+        }
+
+      str[len * 2] = '\0';
+      uinfo("ECM %s packet: %s\n", dir, str);
+      kmm_free(str);
+    }
+}
+#else
+#  define cdcecm_print_packet(dir, buf, len) {}
+#endif
+
+static int usbhost_ctrl_cmd(FAR struct usbhost_cdcecm_s *priv,
+                            uint8_t type, uint8_t req, uint16_t value,
+                            uint16_t index, uint8_t *payload, uint16_t len)
+{
+  FAR struct usbhost_hubport_s *hport;
+  struct usb_ctrlreq_s *ctrlreq;
+  int ret;
+
+  hport = priv->usbclass.hport;
+
+  ctrlreq       = (struct usb_ctrlreq_s *)priv->ctrlreq;
+  ctrlreq->type = type;
+  ctrlreq->req  = req;
+
+  usbhost_putle16(ctrlreq->value, value);
+  usbhost_putle16(ctrlreq->index, index);
+  usbhost_putle16(ctrlreq->len,   len);
+
+  if (type & USB_REQ_DIR_IN)
+    {
+      ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, payload);
+    }
+  else
+    {
+      ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, payload);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_allocclass
+ *
+ * Description:
+ *   This is really part of the logic that implements the create() method
+ *   of struct usbhost_registry_s.  This function allocates memory for one
+ *   new class instance.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success, this function will return a non-NULL instance of struct
+ *   usbhost_class_s.  NULL is returned on failure; this function will
+ *   will fail only if there are insufficient resources to create another
+ *   USB host class instance.
+ *
+ ****************************************************************************/
+
+static inline FAR struct usbhost_cdcecm_s *usbhost_allocclass(void)
+{
+  FAR struct usbhost_cdcecm_s *priv;
+
+  DEBUGASSERT(!up_interrupt_context());
+  priv = (FAR struct usbhost_cdcecm_s *)kmm_malloc(
+                                         sizeof(struct usbhost_cdcecm_s));
+  uinfo("Allocated: %p\n", priv);
+  return priv;
+}
+
+/****************************************************************************
+ * Name: usbhost_freeclass
+ *
+ * Description:
+ *   Free a class instance previously allocated by usbhost_allocclass().
+ *
+ * Input Parameters:
+ *   usbclass - A reference to the class instance to be freed.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void usbhost_freeclass(FAR struct usbhost_cdcecm_s *usbclass)
+{
+  DEBUGASSERT(usbclass != NULL);
+
+  /* Free the class instance (perhaps calling sched_kmm_free() in case we are
+   * executing from an interrupt handler.
+   */
+
+  uinfo("Freeing: %p\n", usbclass);
+  kmm_free(usbclass);
+}
+
+static void usbhost_bulkin_callback(FAR void *arg, ssize_t nbytes)
+{
+  struct usbhost_cdcecm_s *priv = (struct usbhost_cdcecm_s *)arg;
+  uint32_t delay = 0;
+
+  DEBUGASSERT(priv);
+
+  /* We can't lock the mutex from an interrupt context */
+
+  if (priv->disconnected)
+    {
+      return;
+    }
+
+  priv->bulkinbytes = (int16_t)nbytes;
+
+  if (nbytes < 0)
+    {
+      if (nbytes != -EAGAIN)
+        {
+          uerr("ERROR: Transfer failed: %d\n", nbytes);
+        }
+
+      delay = MSEC2TICK(30);

Review Comment:
   why delay



##########
drivers/usbhost/CMakeLists.txt:
##########
@@ -47,6 +47,10 @@ if(CONFIG_USBHOST)
     list(APPEND SRCS usbhost_cdcacm.c)
   endif()
 
+  if(CONFIG_USBHOST_CDCECM)
+    list(APPEND SRCS usbhost_cdcacm.c)

Review Comment:
   usbhost_cdcecm.c



##########
drivers/usbhost/usbhost_cdcecm.c:
##########
@@ -0,0 +1,2160 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcecm.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+
+#ifdef CONFIG_NET_PKT
+  #include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Default max segment size if not specified by device */
+
+#define CDCECM_DEFAULT_MAXSEG   1514
+
+/* ECM control requests */
+
+#define ECM_SET_PACKET_FILTER_REQUEST 0x43
+
+/* ECM packet filter bits */
+
+#define ECM_PACKET_TYPE_PROMISCUOUS    (1 << 0)
+#define ECM_PACKET_TYPE_ALL_MULTICAST  (1 << 1)
+#define ECM_PACKET_TYPE_DIRECTED       (1 << 2)
+#define ECM_PACKET_TYPE_BROADCAST      (1 << 3)
+#define ECM_PACKET_TYPE_MULTICAST      (1 << 4)
+
+/* Default packet filter: unicast + broadcast */
+
+#define ECM_DEFAULT_PACKET_FILTER      (ECM_PACKET_TYPE_DIRECTED | \
+                                        ECM_PACKET_TYPE_BROADCAST)
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+#  warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+#ifndef CONFIG_USBHOST_ASYNCH
+#  warning Asynchronous transfer support is required (CONFIG_USBHOST_ASYNCH)
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM_NTDELAY
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(CONFIG_USBHOST_CDCECM_NTDELAY)
+#else
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(200)
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_RXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_RXBUFSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_TXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_TXBUFSIZE 2048
+#endif
+
+/* Used in usbhost_cfgdesc() */
+
+#define USBHOST_CTRLIFFOUND 0x01
+#define USBHOST_DATAIFFOUND 0x02
+#define USBHOST_INTRIFFOUND 0x04
+#define USBHOST_BINFOUND    0x08
+#define USBHOST_BOUTFOUND   0x10
+#define USBHOST_ECMFOUND    0x20
+#define USBHOST_ALLFOUND    0x3f
+
+#define USBHOST_MAX_CREFS   0x7fff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct usb_csifdesc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+};
+
+/* This structure contains the internal, private state of the USB host class
+ * driver.
+ */
+
+struct usbhost_cdcecm_s
+{
+  /* This is the externally visible portion of the state */
+
+  struct usbhost_class_s  usbclass;
+
+  /* The remainder of the fields are provided to the class driver */
+
+  volatile bool           disconnected; /* TRUE: Device has been disconnected 
*/
+  uint16_t                ctrlif;       /* Control interface number */
+  uint16_t                dataif;       /* Data interface number */
+  int16_t                 crefs;        /* Reference count on the driver 
instance */
+  mutex_t                 lock;         /* Used to maintain mutual exclusive 
access */
+  struct work_s           ntwork;       /* Notification work */
+  struct work_s           bulk_rxwork;
+  struct work_s           txpollwork;
+  struct work_s           destroywork;
+  int16_t                 nnbytes;      /* Number of bytes received in 
notification */
+  int16_t                 bulkinbytes;
+  uint16_t                maxintsize;   /* Maximum size of interrupt IN packet 
*/
+  FAR uint8_t            *ctrlreq;      /* Allocated ctrl request structure */
+  FAR uint8_t            *notification; /* Allocated RX buffer for async 
notifications */
+  FAR uint8_t            *bulkinbuf;    /* Allocated RX buffer for bulk IN */
+  FAR uint8_t            *bulkoutbuf;   /* Allocated TX buffer for bulk OUT */
+  usbhost_ep_t            intin;        /* Interrupt endpoint */
+  usbhost_ep_t            bulkin;       /* Bulk IN endpoint */
+  usbhost_ep_t            bulkout;      /* Bulk OUT endpoint */
+  uint16_t                bulkmxpacket; /* Max packet size for Bulk OUT 
endpoint */
+
+  /* Device info from ECM descriptor */
+
+  uint16_t                maxsegment;    /* Max Ethernet frame size */
+  uint8_t                 macstridx;     /* MAC address string index */
+  uint8_t                 macaddr[6];    /* Device MAC address */
+
+  /* Network device members */
+
+  bool                    registered;   /* true if the device was registered */
+  bool                    bifup;        /* true:ifup false:ifdown */
+  struct net_driver_s     netdev;       /* Interface understood by the network 
*/

Review Comment:
   why not use netdev upperhalf to simplify the code



##########
boards/arm/stm32h5/nucleo-h563zi/src/stm32_usb.c:
##########
@@ -226,11 +226,32 @@ void stm32h5_usbhost_vbusdrive(int port, bool enable)
   /* The Nucleo-h563zi doesn't have hardware for a vbus drive.
    * Instead to get host working, you need to put an extra jumper
    * on the "PWR SEL" to jump "STLK" and "USB USER".
-   * This effectively supplies 5V power form the STLink to the USB device.
-   * The power output is limited so only relatively low power
+   * This effectively supplies 5V power from the STLink to the USB device.
+   * The power output is limited, so only relatively low power
    * devices can work.
    */
 }
 #endif
 
+#ifdef CONFIG_USBHOST_CONFIGURATION_SELECTION
+int usbhost_select_configuration(FAR struct usbhost_hubport_s *hport,
+                                 FAR const struct usb_devdesc_s *devdesc,
+                                 FAR const struct usbhost_id_s *id)
+{
+  if (id->vid == 0x0bda && id->pid == 0x8153)

Review Comment:
   should we add a callback to usbhost_registry_s or usbhost_class_s  to select



##########
include/nuttx/usb/usbhost.h:
##########
@@ -1326,6 +1326,32 @@ int usbhost_waiter_initialize(FAR struct 
usbhost_connection_s *conn);
 void usbhost_drivers_initialize(void);
 #endif
 
+#ifdef CONFIG_USBHOST_CONFIGURATION_SELECTION
+
+/****************************************************************************
+ * Name: usbhost_select_configuration
+ *
+ * Description:
+ *   Board specific function to select the correct USB configuration
+ *   for a given device. The function may use the device descriptor
+ *   or make additional requests using the hport to decide which
+ *   configuration to use.
+ *
+ * Input Parameters:
+ *   hport - The port for the USB device
+ *   devdesc - The device descriptor of the USB device
+ *   id - device identification
+ *
+ * Returned Value:
+ *   USB configuration index to use.
+ *
+ ****************************************************************************/
+
+int usbhost_select_configuration(FAR struct usbhost_hubport_s *hport,

Review Comment:
   should prefix by board_xxx and move to nuttx/include/nuttx/board.h



##########
drivers/usbhost/usbhost_cdcecm.c:
##########
@@ -0,0 +1,2160 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcecm.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+
+#ifdef CONFIG_NET_PKT
+  #include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Default max segment size if not specified by device */
+
+#define CDCECM_DEFAULT_MAXSEG   1514
+
+/* ECM control requests */
+
+#define ECM_SET_PACKET_FILTER_REQUEST 0x43
+
+/* ECM packet filter bits */
+
+#define ECM_PACKET_TYPE_PROMISCUOUS    (1 << 0)
+#define ECM_PACKET_TYPE_ALL_MULTICAST  (1 << 1)
+#define ECM_PACKET_TYPE_DIRECTED       (1 << 2)
+#define ECM_PACKET_TYPE_BROADCAST      (1 << 3)
+#define ECM_PACKET_TYPE_MULTICAST      (1 << 4)
+
+/* Default packet filter: unicast + broadcast */
+
+#define ECM_DEFAULT_PACKET_FILTER      (ECM_PACKET_TYPE_DIRECTED | \
+                                        ECM_PACKET_TYPE_BROADCAST)
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+#  warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+#ifndef CONFIG_USBHOST_ASYNCH
+#  warning Asynchronous transfer support is required (CONFIG_USBHOST_ASYNCH)
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM_NTDELAY
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(CONFIG_USBHOST_CDCECM_NTDELAY)
+#else
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(200)
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_RXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_RXBUFSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_TXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_TXBUFSIZE 2048
+#endif
+
+/* Used in usbhost_cfgdesc() */
+
+#define USBHOST_CTRLIFFOUND 0x01
+#define USBHOST_DATAIFFOUND 0x02
+#define USBHOST_INTRIFFOUND 0x04
+#define USBHOST_BINFOUND    0x08
+#define USBHOST_BOUTFOUND   0x10
+#define USBHOST_ECMFOUND    0x20
+#define USBHOST_ALLFOUND    0x3f
+
+#define USBHOST_MAX_CREFS   0x7fff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct usb_csifdesc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+};
+
+/* This structure contains the internal, private state of the USB host class
+ * driver.
+ */
+
+struct usbhost_cdcecm_s
+{
+  /* This is the externally visible portion of the state */
+
+  struct usbhost_class_s  usbclass;
+
+  /* The remainder of the fields are provided to the class driver */
+
+  volatile bool           disconnected; /* TRUE: Device has been disconnected 
*/
+  uint16_t                ctrlif;       /* Control interface number */
+  uint16_t                dataif;       /* Data interface number */
+  int16_t                 crefs;        /* Reference count on the driver 
instance */
+  mutex_t                 lock;         /* Used to maintain mutual exclusive 
access */
+  struct work_s           ntwork;       /* Notification work */
+  struct work_s           bulk_rxwork;
+  struct work_s           txpollwork;
+  struct work_s           destroywork;
+  int16_t                 nnbytes;      /* Number of bytes received in 
notification */
+  int16_t                 bulkinbytes;
+  uint16_t                maxintsize;   /* Maximum size of interrupt IN packet 
*/
+  FAR uint8_t            *ctrlreq;      /* Allocated ctrl request structure */
+  FAR uint8_t            *notification; /* Allocated RX buffer for async 
notifications */
+  FAR uint8_t            *bulkinbuf;    /* Allocated RX buffer for bulk IN */
+  FAR uint8_t            *bulkoutbuf;   /* Allocated TX buffer for bulk OUT */
+  usbhost_ep_t            intin;        /* Interrupt endpoint */
+  usbhost_ep_t            bulkin;       /* Bulk IN endpoint */
+  usbhost_ep_t            bulkout;      /* Bulk OUT endpoint */
+  uint16_t                bulkmxpacket; /* Max packet size for Bulk OUT 
endpoint */
+
+  /* Device info from ECM descriptor */
+
+  uint16_t                maxsegment;    /* Max Ethernet frame size */
+  uint8_t                 macstridx;     /* MAC address string index */
+  uint8_t                 macaddr[6];    /* Device MAC address */
+
+  /* Network device members */
+
+  bool                    registered;   /* true if the device was registered */
+  bool                    bifup;        /* true:ifup false:ifdown */
+  struct net_driver_s     netdev;       /* Interface understood by the network 
*/
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Memory allocation services */
+
+static inline FAR struct usbhost_cdcecm_s *usbhost_allocclass(void);
+static inline void usbhost_freeclass(FAR struct usbhost_cdcecm_s *usbclass);
+
+/* Worker thread actions */
+
+static void usbhost_notification_work(FAR void *arg);
+static void usbhost_notification_callback(FAR void *arg, ssize_t nbytes);
+static void usbhost_bulkin_work(FAR void *arg);
+
+static void usbhost_destroy(FAR void *arg);
+
+/* Helpers for usbhost_connect() */
+
+static int usbhost_cfgdesc(FAR struct usbhost_cdcecm_s *priv,
+                           FAR const uint8_t *configdesc, int desclen);
+static inline int usbhost_devinit(FAR struct usbhost_cdcecm_s *priv);
+
+/* (Little Endian) Data helpers */
+
+static inline uint16_t usbhost_getle16(const uint8_t *val);
+static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
+static inline uint32_t usbhost_getle32(const uint8_t *val);
+
+/* Buffer memory management */
+
+static int usbhost_alloc_buffers(FAR struct usbhost_cdcecm_s *priv);
+static void usbhost_free_buffers(FAR struct usbhost_cdcecm_s *priv);
+
+/* struct usbhost_registry_s methods */
+
+static struct usbhost_class_s
+              *usbhost_create(FAR struct usbhost_hubport_s *hport,
+                              FAR const struct usbhost_id_s *id);
+
+/* struct usbhost_class_s methods */
+
+static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
+                           FAR const uint8_t *configdesc, int desclen);
+static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
+
+/* NuttX network callback functions */
+
+static int cdcecm_ifup(struct net_driver_s *dev);
+static int cdcecm_ifdown(struct net_driver_s *dev);
+static int cdcecm_txavail(struct net_driver_s *dev);
+
+/* Network support functions */
+
+static void cdcecm_receive(struct usbhost_cdcecm_s *priv);
+
+static int cdcecm_txpoll(struct net_driver_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This structure provides the registry entry ID information that will  be
+ * used to associate the USB class driver to a connected USB device.
+ */
+
+static const struct usbhost_id_s g_id[] =
+{
+  {
+    USB_CLASS_CDC,          /* base - CDC class */
+    CDC_SUBCLASS_NONE,      /* subclass */
+    CDC_PROTO_NONE,         /* proto    */
+    0,                      /* vid      */
+    0                       /* pid      */
+  },
+  {
+    USB_CLASS_CDC,          /* base - CDC class */
+    CDC_SUBCLASS_ECM,       /* subclass - Ethernet Control Model */
+    CDC_PROTO_NONE,         /* proto - No class specific protocol */
+    0,                      /* vid - Any vendor */
+    0                       /* pid - Any product */
+  }
+};
+
+/* This is the USB host storage class's registry entry */
+
+static struct usbhost_registry_s g_cdcecm =
+{
+  NULL,                           /* flink */
+  usbhost_create,                 /* create */
+  sizeof(g_id) / sizeof(g_id[0]), /* nids */
+  g_id                            /* id[] */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#if defined(CONFIG_DEBUG_USB) && defined(USBHOST_CDCECM_PACKET_PRINT)
+static void cdcecm_print_packet(const char * dir, const uint8_t * buf,

Review Comment:
   call dump function in debug.h



##########
drivers/usbhost/usbhost_cdcecm.c:
##########
@@ -0,0 +1,2160 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcecm.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+#include <poll.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/signal.h>
+#include <nuttx/net/netdev.h>
+
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/usb.h>
+#include <nuttx/usb/usbhost.h>
+
+#ifdef CONFIG_NET_PKT
+  #include <nuttx/net/pkt.h>
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Default max segment size if not specified by device */
+
+#define CDCECM_DEFAULT_MAXSEG   1514
+
+/* ECM control requests */
+
+#define ECM_SET_PACKET_FILTER_REQUEST 0x43
+
+/* ECM packet filter bits */
+
+#define ECM_PACKET_TYPE_PROMISCUOUS    (1 << 0)
+#define ECM_PACKET_TYPE_ALL_MULTICAST  (1 << 1)
+#define ECM_PACKET_TYPE_DIRECTED       (1 << 2)
+#define ECM_PACKET_TYPE_BROADCAST      (1 << 3)
+#define ECM_PACKET_TYPE_MULTICAST      (1 << 4)
+
+/* Default packet filter: unicast + broadcast */
+
+#define ECM_DEFAULT_PACKET_FILTER      (ECM_PACKET_TYPE_DIRECTED | \
+                                        ECM_PACKET_TYPE_BROADCAST)
+
+/* Configuration ************************************************************/
+
+#ifndef CONFIG_SCHED_WORKQUEUE
+#  warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
+#endif
+
+#ifndef CONFIG_USBHOST_ASYNCH
+#  warning Asynchronous transfer support is required (CONFIG_USBHOST_ASYNCH)
+#endif
+
+#ifdef CONFIG_USBHOST_CDCECM_NTDELAY
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(CONFIG_USBHOST_CDCECM_NTDELAY)
+#else
+#  define USBHOST_CDCECM_NTDELAY MSEC2TICK(200)
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_RXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_RXBUFSIZE 2048
+#endif
+
+#ifndef CONFIG_USBHOST_CDCECM_TXBUFSIZE
+  #define CONFIG_USBHOST_CDCECM_TXBUFSIZE 2048
+#endif
+
+/* Used in usbhost_cfgdesc() */
+
+#define USBHOST_CTRLIFFOUND 0x01
+#define USBHOST_DATAIFFOUND 0x02
+#define USBHOST_INTRIFFOUND 0x04
+#define USBHOST_BINFOUND    0x08
+#define USBHOST_BOUTFOUND   0x10
+#define USBHOST_ECMFOUND    0x20
+#define USBHOST_ALLFOUND    0x3f
+
+#define USBHOST_MAX_CREFS   0x7fff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct usb_csifdesc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+};
+
+/* This structure contains the internal, private state of the USB host class
+ * driver.
+ */
+
+struct usbhost_cdcecm_s
+{
+  /* This is the externally visible portion of the state */
+
+  struct usbhost_class_s  usbclass;
+
+  /* The remainder of the fields are provided to the class driver */
+
+  volatile bool           disconnected; /* TRUE: Device has been disconnected 
*/
+  uint16_t                ctrlif;       /* Control interface number */
+  uint16_t                dataif;       /* Data interface number */
+  int16_t                 crefs;        /* Reference count on the driver 
instance */
+  mutex_t                 lock;         /* Used to maintain mutual exclusive 
access */
+  struct work_s           ntwork;       /* Notification work */
+  struct work_s           bulk_rxwork;
+  struct work_s           txpollwork;
+  struct work_s           destroywork;
+  int16_t                 nnbytes;      /* Number of bytes received in 
notification */
+  int16_t                 bulkinbytes;
+  uint16_t                maxintsize;   /* Maximum size of interrupt IN packet 
*/
+  FAR uint8_t            *ctrlreq;      /* Allocated ctrl request structure */
+  FAR uint8_t            *notification; /* Allocated RX buffer for async 
notifications */
+  FAR uint8_t            *bulkinbuf;    /* Allocated RX buffer for bulk IN */
+  FAR uint8_t            *bulkoutbuf;   /* Allocated TX buffer for bulk OUT */
+  usbhost_ep_t            intin;        /* Interrupt endpoint */
+  usbhost_ep_t            bulkin;       /* Bulk IN endpoint */
+  usbhost_ep_t            bulkout;      /* Bulk OUT endpoint */
+  uint16_t                bulkmxpacket; /* Max packet size for Bulk OUT 
endpoint */
+
+  /* Device info from ECM descriptor */
+
+  uint16_t                maxsegment;    /* Max Ethernet frame size */
+  uint8_t                 macstridx;     /* MAC address string index */
+  uint8_t                 macaddr[6];    /* Device MAC address */
+
+  /* Network device members */
+
+  bool                    registered;   /* true if the device was registered */
+  bool                    bifup;        /* true:ifup false:ifdown */
+  struct net_driver_s     netdev;       /* Interface understood by the network 
*/
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Memory allocation services */
+
+static inline FAR struct usbhost_cdcecm_s *usbhost_allocclass(void);
+static inline void usbhost_freeclass(FAR struct usbhost_cdcecm_s *usbclass);
+
+/* Worker thread actions */
+
+static void usbhost_notification_work(FAR void *arg);
+static void usbhost_notification_callback(FAR void *arg, ssize_t nbytes);
+static void usbhost_bulkin_work(FAR void *arg);
+
+static void usbhost_destroy(FAR void *arg);
+
+/* Helpers for usbhost_connect() */
+
+static int usbhost_cfgdesc(FAR struct usbhost_cdcecm_s *priv,
+                           FAR const uint8_t *configdesc, int desclen);
+static inline int usbhost_devinit(FAR struct usbhost_cdcecm_s *priv);
+
+/* (Little Endian) Data helpers */
+
+static inline uint16_t usbhost_getle16(const uint8_t *val);
+static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
+static inline uint32_t usbhost_getle32(const uint8_t *val);
+
+/* Buffer memory management */
+
+static int usbhost_alloc_buffers(FAR struct usbhost_cdcecm_s *priv);
+static void usbhost_free_buffers(FAR struct usbhost_cdcecm_s *priv);
+
+/* struct usbhost_registry_s methods */
+
+static struct usbhost_class_s
+              *usbhost_create(FAR struct usbhost_hubport_s *hport,
+                              FAR const struct usbhost_id_s *id);
+
+/* struct usbhost_class_s methods */
+
+static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
+                           FAR const uint8_t *configdesc, int desclen);
+static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
+
+/* NuttX network callback functions */
+
+static int cdcecm_ifup(struct net_driver_s *dev);
+static int cdcecm_ifdown(struct net_driver_s *dev);
+static int cdcecm_txavail(struct net_driver_s *dev);
+
+/* Network support functions */
+
+static void cdcecm_receive(struct usbhost_cdcecm_s *priv);
+
+static int cdcecm_txpoll(struct net_driver_s *dev);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* This structure provides the registry entry ID information that will  be
+ * used to associate the USB class driver to a connected USB device.
+ */
+
+static const struct usbhost_id_s g_id[] =
+{
+  {
+    USB_CLASS_CDC,          /* base - CDC class */
+    CDC_SUBCLASS_NONE,      /* subclass */
+    CDC_PROTO_NONE,         /* proto    */
+    0,                      /* vid      */
+    0                       /* pid      */
+  },
+  {
+    USB_CLASS_CDC,          /* base - CDC class */
+    CDC_SUBCLASS_ECM,       /* subclass - Ethernet Control Model */
+    CDC_PROTO_NONE,         /* proto - No class specific protocol */
+    0,                      /* vid - Any vendor */
+    0                       /* pid - Any product */
+  }
+};
+
+/* This is the USB host storage class's registry entry */
+
+static struct usbhost_registry_s g_cdcecm =
+{
+  NULL,                           /* flink */
+  usbhost_create,                 /* create */
+  sizeof(g_id) / sizeof(g_id[0]), /* nids */
+  g_id                            /* id[] */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#if defined(CONFIG_DEBUG_USB) && defined(USBHOST_CDCECM_PACKET_PRINT)
+static void cdcecm_print_packet(const char * dir, const uint8_t * buf,
+                                size_t len)
+{
+  char * str = kmm_malloc(len * 2 + 1);
+  if (str == NULL)
+    {
+      uerr("Failed to dump ECM %s packet\n", dir);
+    }
+  else
+    {
+      for (size_t i = 0; i < len; ++i)
+        {
+          sprintf(&str[i * 2], "%02X", buf[i]);
+        }
+
+      str[len * 2] = '\0';
+      uinfo("ECM %s packet: %s\n", dir, str);
+      kmm_free(str);
+    }
+}
+#else
+#  define cdcecm_print_packet(dir, buf, len) {}
+#endif
+
+static int usbhost_ctrl_cmd(FAR struct usbhost_cdcecm_s *priv,
+                            uint8_t type, uint8_t req, uint16_t value,
+                            uint16_t index, uint8_t *payload, uint16_t len)
+{
+  FAR struct usbhost_hubport_s *hport;
+  struct usb_ctrlreq_s *ctrlreq;
+  int ret;
+
+  hport = priv->usbclass.hport;
+
+  ctrlreq       = (struct usb_ctrlreq_s *)priv->ctrlreq;
+  ctrlreq->type = type;
+  ctrlreq->req  = req;
+
+  usbhost_putle16(ctrlreq->value, value);
+  usbhost_putle16(ctrlreq->index, index);
+  usbhost_putle16(ctrlreq->len,   len);
+
+  if (type & USB_REQ_DIR_IN)
+    {
+      ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, payload);
+    }
+  else
+    {
+      ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, payload);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_allocclass
+ *
+ * Description:
+ *   This is really part of the logic that implements the create() method
+ *   of struct usbhost_registry_s.  This function allocates memory for one
+ *   new class instance.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success, this function will return a non-NULL instance of struct
+ *   usbhost_class_s.  NULL is returned on failure; this function will
+ *   will fail only if there are insufficient resources to create another
+ *   USB host class instance.
+ *
+ ****************************************************************************/
+
+static inline FAR struct usbhost_cdcecm_s *usbhost_allocclass(void)
+{
+  FAR struct usbhost_cdcecm_s *priv;
+
+  DEBUGASSERT(!up_interrupt_context());
+  priv = (FAR struct usbhost_cdcecm_s *)kmm_malloc(
+                                         sizeof(struct usbhost_cdcecm_s));
+  uinfo("Allocated: %p\n", priv);
+  return priv;
+}
+
+/****************************************************************************
+ * Name: usbhost_freeclass
+ *
+ * Description:
+ *   Free a class instance previously allocated by usbhost_allocclass().
+ *
+ * Input Parameters:
+ *   usbclass - A reference to the class instance to be freed.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline void usbhost_freeclass(FAR struct usbhost_cdcecm_s *usbclass)
+{
+  DEBUGASSERT(usbclass != NULL);
+
+  /* Free the class instance (perhaps calling sched_kmm_free() in case we are
+   * executing from an interrupt handler.
+   */
+
+  uinfo("Freeing: %p\n", usbclass);
+  kmm_free(usbclass);
+}
+
+static void usbhost_bulkin_callback(FAR void *arg, ssize_t nbytes)
+{
+  struct usbhost_cdcecm_s *priv = (struct usbhost_cdcecm_s *)arg;
+  uint32_t delay = 0;
+
+  DEBUGASSERT(priv);
+
+  /* We can't lock the mutex from an interrupt context */
+
+  if (priv->disconnected)
+    {
+      return;
+    }
+
+  priv->bulkinbytes = (int16_t)nbytes;
+
+  if (nbytes < 0)
+    {
+      if (nbytes != -EAGAIN)
+        {
+          uerr("ERROR: Transfer failed: %d\n", nbytes);
+        }
+
+      delay = MSEC2TICK(30);
+    }
+
+  if (work_available(&priv->bulk_rxwork))
+    {
+      work_queue(LPWORK, &priv->bulk_rxwork,
+                 usbhost_bulkin_work, priv, delay);
+    }
+}
+
+static void usbhost_bulkin_work(FAR void *arg)
+{
+  struct usbhost_cdcecm_s *priv;
+  struct usbhost_hubport_s *hport;
+  struct iob_s *iob = NULL;
+
+  priv = (struct usbhost_cdcecm_s *)arg;
+  DEBUGASSERT(priv);
+
+  /* We need net_lock and need priv->mutex.
+   * Since the TX path (cdcecm_txpoll) gets net_lock then priv->lock,
+   * we need to follow the same order to prevent a deadlock if there
+   * is more than 1 LPWORK thread
+   */
+
+  net_lock();
+
+  nxmutex_lock(&priv->lock);
+
+  hport = priv->usbclass.hport;
+  DEBUGASSERT(hport);
+
+  if (priv->disconnected || !priv->bifup)
+    {
+      nxmutex_unlock(&priv->lock);
+      net_unlock();
+      return;
+    }
+
+  /* Copy incoming data into IOB buffer and
+   * start a new RX as soon as possible
+   */
+
+  if (priv->bulkinbytes > 0)
+    {
+      uinfo("received packet: %d len\n", priv->bulkinbytes);
+      cdcecm_print_packet("RX", priv->bulkinbuf, priv->bulkinbytes);
+
+      /* ECM sends raw Ethernet frames - no additional framing */
+
+      if (priv->bulkinbytes <= iob_navail(true) * CONFIG_IOB_BUFSIZE)
+        {
+          iob = iob_tryalloc(true);
+          if (iob != NULL)
+            {
+              iob_reserve(iob, CONFIG_NET_LL_GUARDSIZE);
+              int ret = iob_trycopyin(iob, priv->bulkinbuf,
+                                      priv->bulkinbytes,
+                                      -NET_LL_HDRLEN(&priv->netdev), true);
+              if (ret != priv->bulkinbytes)
+                {
+                  iob_free_chain(iob);
+                  iob = NULL;
+                }
+            }
+        }
+
+      if (iob == NULL)
+        {
+          NETDEV_RXDROPPED(&priv->netdev);
+        }
+      else
+        {
+          priv->netdev.d_iob = iob;
+          priv->netdev.d_len = priv->bulkinbytes;
+        }
+    }
+  else if (priv->bulkinbytes < 0 && priv->bulkinbytes != -EAGAIN)
+    {
+      uerr("Bulk IN error: %d\n", priv->bulkinbytes);
+    }
+
+  DRVR_ASYNCH(hport->drvr, priv->bulkin,
+              (uint8_t *)priv->bulkinbuf, CONFIG_USBHOST_CDCECM_RXBUFSIZE,
+              usbhost_bulkin_callback, priv);
+
+  if (iob != NULL)
+    {
+      cdcecm_receive(priv);
+      netdev_iob_release(&priv->netdev);
+    }
+
+  nxmutex_unlock(&priv->lock);
+  net_unlock();
+}
+
+/****************************************************************************
+ * Name: usbhost_notification_work
+ *
+ * Description:
+ *   Handle receipt of an asynchronous notification from the CDC device
+ *
+ * Input Parameters:
+ *   arg - The argument provided with the asynchronous I/O was setup
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Probably called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static void usbhost_notification_work(FAR void *arg)
+{
+  FAR struct usbhost_cdcecm_s *priv;
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct cdc_notification_s *inmsg;
+  int ret;
+
+  priv = (FAR struct usbhost_cdcecm_s *)arg;
+  DEBUGASSERT(priv);
+
+  nxmutex_lock(&priv->lock);
+
+  hport = priv->usbclass.hport;
+  DEBUGASSERT(hport);
+
+  /* Are we still connected? */
+
+  if (!priv->disconnected && priv->intin)
+    {
+      /* Yes.. Was an interrupt IN message received correctly? */
+
+      if (priv->nnbytes >= 0)
+        {
+          /* Yes.. decode the notification */
+
+          inmsg = (FAR struct cdc_notification_s *)priv->notification;
+
+          if ((inmsg->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)
+            {
+              switch (inmsg->notification)
+              {
+                case ECM_NETWORK_CONNECTION:
+
+                  /* Link state changed. This is supposed to be sent only
+                   * on-change, but I found some devices send it repeatedly.
+                   * So only update on-change to avoid a spam of prints
+                   */
+
+                  if (inmsg->value[0] &&
+                      !IFF_IS_RUNNING(priv->netdev.d_flags))
+                  {
+                    uinfo("Network connected\n");
+                    netdev_carrier_on(&priv->netdev);
+                  }
+                  else if (!inmsg->value[0] &&
+                           IFF_IS_RUNNING(priv->netdev.d_flags))
+                  {
+                    uinfo("Network disconnected\n");
+                    netdev_carrier_off(&priv->netdev);
+                  }
+                  break;
+
+                case ECM_SPEED_CHANGE:
+
+                  /* Connection speed changed - informational only */
+
+                  uinfo("Speed change notification\n");
+                  break;
+
+                default:
+                  uinfo("Unknown notification: 0x%02x\n",
+                        inmsg->notification);
+                  break;
+              }
+            }
+        }
+
+      /* Setup to receive the next notification */
+
+      ret = DRVR_ASYNCH(hport->drvr, priv->intin,
+                        (FAR uint8_t *)priv->notification,
+                        SIZEOF_NOTIFICATION_S(0),
+                        usbhost_notification_callback,
+                        priv);
+      if (ret < 0)
+        {
+          uerr("ERROR: DRVR_ASYNCH failed: %d\n", ret);
+        }
+    }
+
+  nxmutex_unlock(&priv->lock);
+}
+
+/****************************************************************************
+ * Name: usbhost_notification_callback
+ *
+ * Description:
+ *   Handle receipt of Response Available from the CDC/ECM device
+ *
+ * Input Parameters:
+ *   arg - The argument provided with the asynchronous I/O was setup
+ *   nbytes - The number of bytes actually transferred (or a negated errno
+ *     value;
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Probably called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static void usbhost_notification_callback(FAR void *arg, ssize_t nbytes)
+{
+  FAR struct usbhost_cdcecm_s *priv = (FAR struct usbhost_cdcecm_s *)arg;
+  uint32_t delay = 0;
+
+  DEBUGASSERT(priv);
+
+  /* We can't lock the mutex from an interrupt context */
+
+  /* Are we still connected? */
+
+  if (!priv->disconnected)
+    {
+      /* Check for a failure.  On higher end host controllers, the
+       * asynchronous transfer will pend until data is available (OHCI and
+       * EHCI).  On lower end host controllers (like STM32 and EFM32), the
+       * transfer will fail immediately when the device NAKs the first
+       * attempted interrupt IN transfer (with nbytes == -EAGAIN).  In that
+       * case (or in the case of other errors), we must fall back to
+       * polling.
+       */
+
+      DEBUGASSERT(nbytes >= INT16_MIN && nbytes <= INT16_MAX);
+      priv->nnbytes = (int16_t)nbytes;
+
+      if (nbytes < 0)
+        {
+          /* This debug output is good to know, but really a nuisance for
+           * those configurations where we have to fall back to polling.
+           * FIX:  Don't output the message is the result is -EAGAIN.
+           */
+
+#if defined(CONFIG_DEBUG_USB) && !defined(CONFIG_DEBUG_INFO)
+          if (nbytes != -EAGAIN)
+#endif
+            {
+              uerr("ERROR: Transfer failed: %d\n", nbytes);
+            }
+
+          /* We don't know the nature of the failure, but we need to do all
+           * that we can do to avoid a CPU hog error loop.
+           *
+           * Use the low-priority work queue and delay polling for the next
+           * event.  We want to use as little CPU bandwidth as possible in
+           * this case.
+           */
+
+          delay = USBHOST_CDCECM_NTDELAY;

Review Comment:
   why delay



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to