You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/06/15 13:13:27 UTC

[incubator-nuttx] branch master updated (5785340 -> 089a633)

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git.


    from 5785340  sched/group: Change group_kill_children's argument from task_tcb_s to tcb_s
     new 07c0faf  Add support to CDC-MBIM USB host driver
     new e1be7ac  Fix netdev and add Apache license to the file
     new 6ff18a7  Rename NETDEV_WBIM_FORMAT with NETDEV_WWAM_FORMAT
     new 7609b67  Fix issues reported on PR #1233
     new 3a95c41  Fix devif_timer() function call
     new 089a633  Fix wrong space instead of TAB

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 drivers/usbhost/Kconfig           |   10 +
 drivers/usbhost/Make.defs         |    4 +
 drivers/usbhost/usbhost_cdcmbim.c | 2566 +++++++++++++++++++++++++++++++++++++
 include/nuttx/net/net.h           |    3 +-
 include/nuttx/usb/cdc.h           |  265 ++--
 net/Kconfig                       |    5 +
 net/netdev/netdev_register.c      |    9 +
 7 files changed, 2751 insertions(+), 111 deletions(-)
 create mode 100644 drivers/usbhost/usbhost_cdcmbim.c


[incubator-nuttx] 03/06: Rename NETDEV_WBIM_FORMAT with NETDEV_WWAM_FORMAT

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 6ff18a7f3b44cab10c6850cf0068a6695f97b4e2
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Sun Jun 14 15:52:25 2020 -0300

    Rename NETDEV_WBIM_FORMAT with NETDEV_WWAM_FORMAT
---
 net/netdev/netdev_register.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index de36143..1ca7e54 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -55,7 +55,7 @@
 #define NETDEV_PAN_FORMAT   "pan%d"
 #define NETDEV_WLAN_FORMAT  "wlan%d"
 #define NETDEV_WPAN_FORMAT  "wpan%d"
-#define NETDEV_MBIM_FORMAT  "wwan%d"
+#define NETDEV_WWAN_FORMAT  "wwan%d"
 
 #if defined(CONFIG_DRIVERS_IEEE80211) /* Usually also has CONFIG_NET_ETHERNET */
 #  define NETDEV_DEFAULT_FORMAT NETDEV_WLAN_FORMAT
@@ -317,7 +317,7 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
         case NET_LL_MBIM:
           llhdrlen = 0;
           pktsize  = 1200;
-          devfmt   = NETDEV_MBIM_FORMAT;
+          devfmt   = NETDEV_WWAN_FORMAT;
           break;
 
           default:


[incubator-nuttx] 02/06: Fix netdev and add Apache license to the file

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit e1be7ace4b626932d6788c7ca145b1ecf8b3ff25
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Sun Jun 14 10:48:02 2020 -0300

    Fix netdev and add Apache license to the file
---
 drivers/usbhost/usbhost_cdcmbim.c | 44 ++++++++++++-------------------------
 include/nuttx/usb/cdc.h           | 46 ++++++++++++---------------------------
 net/netdev/netdev_register.c      |  6 ++---
 3 files changed, 31 insertions(+), 65 deletions(-)

diff --git a/drivers/usbhost/usbhost_cdcmbim.c b/drivers/usbhost/usbhost_cdcmbim.c
index 75e5539..eb1f0da 100644
--- a/drivers/usbhost/usbhost_cdcmbim.c
+++ b/drivers/usbhost/usbhost_cdcmbim.c
@@ -1,36 +1,20 @@
 /****************************************************************************
  * drivers/usbhost/usbhost_cdcmbim.c
  *
- *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
- *           Adam Porter <po...@gmail.com>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * 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.
  *
  ****************************************************************************/
 
diff --git a/include/nuttx/usb/cdc.h b/include/nuttx/usb/cdc.h
index 9030ecf..7c3b7fb 100644
--- a/include/nuttx/usb/cdc.h
+++ b/include/nuttx/usb/cdc.h
@@ -1,40 +1,22 @@
-/*****************************************************************************
+/****************************************************************************
  * include/nuttx/usb/cdc.h
  *
- *   Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
- *
- * References: "Universal Serial Bus Class Definitions for Communication
- *   Devices," Version 1.1, January 19, 1999
+ * 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
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
+ * 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.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- *****************************************************************************/
+ ****************************************************************************/
 
 #ifndef __INCLUDE_NUTTX_USB_CDC_H
 #define __INCLUDE_NUTTX_USB_CDC_H
diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index d8ef03f..de36143 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -315,9 +315,9 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
             break;
 #endif
         case NET_LL_MBIM:
-          dev->d_llhdrlen = 0;
-          dev->d_pktsize = 1200;
-          devfmt = NETDEV_MBIM_FORMAT;
+          llhdrlen = 0;
+          pktsize  = 1200;
+          devfmt   = NETDEV_MBIM_FORMAT;
           break;
 
           default:


[incubator-nuttx] 04/06: Fix issues reported on PR #1233

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 7609b6749682afbfa3fbcf4c066dae510ddb2d39
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Sun Jun 14 19:59:38 2020 -0300

    Fix issues reported on PR #1233
---
 drivers/usbhost/Kconfig           |  3 ++-
 drivers/usbhost/usbhost_cdcmbim.c | 39 +++++++++++++++++++++------------------
 include/nuttx/net/net.h           |  2 +-
 include/nuttx/usb/cdc.h           |  8 +++++---
 net/Kconfig                       |  5 +++++
 net/netdev/netdev_register.c      | 13 ++++++++-----
 6 files changed, 42 insertions(+), 28 deletions(-)

diff --git a/drivers/usbhost/Kconfig b/drivers/usbhost/Kconfig
index d9678d1..f57904b 100644
--- a/drivers/usbhost/Kconfig
+++ b/drivers/usbhost/Kconfig
@@ -265,8 +265,9 @@ endif # USBHOST_CDCACM
 config USBHOST_CDCMBIM
 	bool "CDC/MBIM support"
 	default n
-	depends on USBHOST_HAVE_ASYNCH && !USBHOST_BULK_DISABLE && !USBHOST_INT_DISABLE
+	depends on USBHOST_HAVE_ASYNCH && !USBHOST_BULK_DISABLE && !USBHOST_INT_DISABLE && EXPERIMENTAL
 	select USBHOST_ASYNCH
+	select NET_MBIM
 	---help---
 		Select this option to build in host support for CDC/MBIM network
 		devices.
diff --git a/drivers/usbhost/usbhost_cdcmbim.c b/drivers/usbhost/usbhost_cdcmbim.c
index eb1f0da..b0b251c 100644
--- a/drivers/usbhost/usbhost_cdcmbim.c
+++ b/drivers/usbhost/usbhost_cdcmbim.c
@@ -56,6 +56,7 @@
  ****************************************************************************/
 
 /* put in cdc.h */
+
 #define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
 #define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
 #define USB_CDC_GET_NTB_PARAMETERS        0x80
@@ -564,10 +565,10 @@ static ssize_t cdcwdm_write(FAR struct file *filep, FAR const char *buffer,
 static int cdcwdm_poll(FAR struct file *filep, FAR struct pollfd *fds,
                        bool setup)
 {
-  FAR struct inode           *inode;
+  FAR struct inode             *inode;
   FAR struct usbhost_cdcmbim_s *priv;
-  int                         ret = OK;
-  int                         i;
+  int                           ret = OK;
+  int                           i;
 
   DEBUGASSERT(filep && filep->f_inode && fds);
   inode = filep->f_inode;
@@ -803,9 +804,11 @@ static void usbhost_bulkin_work(FAR void *arg)
 {
   struct usbhost_cdcmbim_s *priv;
   struct usbhost_hubport_s *hport;
+  struct usb_cdc_ncm_nth16_s *nth;
   uint16_t ndpoffset;
   uint16_t dgram_len;
   uint16_t dgram_off;
+  uint16_t block_len;
 
   priv = (struct usbhost_cdcmbim_s *)arg;
   DEBUGASSERT(priv);
@@ -828,8 +831,7 @@ static void usbhost_bulkin_work(FAR void *arg)
 
   /* Parse the NTB header */
 
-  struct usb_cdc_ncm_nth16_s *nth =
-    (struct usb_cdc_ncm_nth16_s *)priv->rxnetbuf;
+  nth = (struct usb_cdc_ncm_nth16_s *)priv->rxnetbuf;
 
   if (usbhost_getle32(nth->signature) != USB_CDC_NCM_NTH16_SIGNATURE)
     {
@@ -837,7 +839,7 @@ static void usbhost_bulkin_work(FAR void *arg)
       goto out;
     }
 
-  uint16_t block_len = usbhost_getle16(nth->block_length);
+  block_len = usbhost_getle16(nth->block_length);
 
   if (block_len > priv->bulkinbytes)
     {
@@ -856,6 +858,7 @@ static void usbhost_bulkin_work(FAR void *arg)
 
   do
     {
+      struct usb_cdc_ncm_dpe16_s *dpe;
       struct usb_cdc_ncm_ndp16_s *ndp
         = (struct usb_cdc_ncm_ndp16_s *)(priv->rxnetbuf + ndpoffset);
 
@@ -863,8 +866,6 @@ static void usbhost_bulkin_work(FAR void *arg)
 
       /* Parse each DPE */
 
-      struct usb_cdc_ncm_dpe16_s *dpe;
-
       for (dpe = ndp->dpe16; usbhost_getle16(dpe->index); dpe++)
         {
           dgram_off = usbhost_getle16(dpe->index);
@@ -904,7 +905,17 @@ out:
 
 static void usbhost_rxdata_work(FAR void *arg)
 {
+  /* Would be nice if CTRLIN would return how many bytes it read... */
+
+  struct mbim_header_s
+  {
+    uint8_t type[4];
+    uint8_t len[4];
+  };
+
   FAR struct usbhost_cdcmbim_s *priv;
+  struct mbim_header_s *hdr;
+  uint32_t len;
   int ret;
 
   priv = (FAR struct usbhost_cdcmbim_s *)arg;
@@ -931,16 +942,8 @@ static void usbhost_rxdata_work(FAR void *arg)
       goto errout;
     }
 
-  /* Would be nice if CTRLIN would return how many bytes it read... */
-
-  struct mbim_header_s
-  {
-    uint8_t type[4];
-    uint8_t len[4];
-  };
-
-  struct mbim_header_s *hdr = (struct mbim_header_s *)priv->comm_rxbuf;
-  uint32_t len = usbhost_getle32(hdr->len);
+  hdr = (struct mbim_header_s *)priv->comm_rxbuf;
+  len = usbhost_getle32(hdr->len);
 
   if (len > priv->maxctrlsize)
     {
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index 3bb4808..c2cbb93 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -156,7 +156,7 @@ enum net_lltype_e
   NET_LL_IEEE80211,    /* IEEE 802.11 */
   NET_LL_IEEE802154,   /* IEEE 802.15.4 MAC */
   NET_LL_PKTRADIO,     /* Non-standard packet radio */
-  NET_LL_MBIM
+  NET_LL_MBIM          /* CDC-MBIM USB host driver */
 };
 
 /* This defines a bitmap big enough for one bit for each socket option */
diff --git a/include/nuttx/usb/cdc.h b/include/nuttx/usb/cdc.h
index 7c3b7fb..429fc05 100644
--- a/include/nuttx/usb/cdc.h
+++ b/include/nuttx/usb/cdc.h
@@ -1,4 +1,4 @@
-/****************************************************************************
+/*****************************************************************************
  * include/nuttx/usb/cdc.h
  *
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -16,7 +16,7 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  *
- ****************************************************************************/
+ *****************************************************************************/
 
 #ifndef __INCLUDE_NUTTX_USB_CDC_H
 #define __INCLUDE_NUTTX_USB_CDC_H
@@ -930,7 +930,9 @@ struct cdc_linecoding_s
 struct cdc_linestatus_s
 {
   uint8_t size[2];   /* wLength, Size of this structure, in bytes */
-  uint8_t ringer[4]; /* dwRingerBitmap, Ringer Conf bitmap for this line */
+  uint8_t ringer[4]; /* dwRingerBitmap, Ringer Configuration bitmap for this
+                      * line
+                      */
   uint8_t line[4];   /* dwLineState, Defines current state of the line */
   uint32_t call[1];  /* dwCallStateN, Current state of call N on the line */
 };
diff --git a/net/Kconfig b/net/Kconfig
index fed3d01..0240f1c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -150,6 +150,11 @@ config NET_LOOPBACK_PKTSIZE
 		CONFIG_NET_LOOPBACK_PKTSIZE is zero, meaning that this maximum
 		packet size will be used by loopback driver.
 
+menuconfig NET_MBIM
+        bool "MBIM modem support"
+	depends on USBHOST_CDCMBIM
+	default n
+
 menuconfig NET_SLIP
 	bool "SLIP support"
 	select ARCH_HAVE_NETDEV_STATISTICS
diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index 1ca7e54..4b08efa 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -314,11 +314,14 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
             devfmt   = NETDEV_TUN_FORMAT;
             break;
 #endif
-        case NET_LL_MBIM:
-          llhdrlen = 0;
-          pktsize  = 1200;
-          devfmt   = NETDEV_WWAN_FORMAT;
-          break;
+
+#ifdef CONFIG_NET_MBIM
+          case NET_LL_MBIM:
+            llhdrlen = 0;
+            pktsize  = 1200;
+            devfmt   = NETDEV_WWAN_FORMAT;
+            break;
+#endif
 
           default:
             nerr("ERROR: Unrecognized link type: %d\n", lltype);


[incubator-nuttx] 05/06: Fix devif_timer() function call

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 3a95c41370f2ce957e8ba8223be5724c3404df45
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Sun Jun 14 20:54:57 2020 -0300

    Fix devif_timer() function call
---
 drivers/usbhost/usbhost_cdcmbim.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usbhost/usbhost_cdcmbim.c b/drivers/usbhost/usbhost_cdcmbim.c
index b0b251c..2585980 100644
--- a/drivers/usbhost/usbhost_cdcmbim.c
+++ b/drivers/usbhost/usbhost_cdcmbim.c
@@ -50,6 +50,7 @@
 #include <nuttx/usb/usbhost.h>
 
 #define CDCMBIM_NETBUF_SIZE 8192
+#define CDCMBIM_WDDELAY     (1*CLK_TCK)
 
 /****************************************************************************
  * Pre-processor Definitions
@@ -2316,7 +2317,7 @@ static void cdcmbim_txpoll_work(void *arg)
   net_lock();
   priv->netdev.d_buf = priv->txpktbuf;
 
-  (void)devif_timer(&priv->netdev, cdcmbim_txpoll);
+  (void)devif_timer(&priv->netdev, CDCMBIM_WDDELAY, cdcmbim_txpoll);
 
   /* setup the watchdog poll timer again */
 


[incubator-nuttx] 01/06: Add support to CDC-MBIM USB host driver

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 07c0faff59b4505f48296282f0d403abf0030868
Author: Adam Porter <po...@gmail.com>
AuthorDate: Sun Jun 14 10:10:11 2020 -0300

    Add support to CDC-MBIM USB host driver
    
    This driver was created by Adam Porter and posted on NuttX
    mailing list at Google Group on Nov 14 2019
---
 drivers/usbhost/Kconfig           |    9 +
 drivers/usbhost/Make.defs         |    4 +
 drivers/usbhost/usbhost_cdcmbim.c | 2578 +++++++++++++++++++++++++++++++++++++
 include/nuttx/net/net.h           |    3 +-
 include/nuttx/usb/cdc.h           |  221 ++--
 net/netdev/netdev_register.c      |    6 +
 6 files changed, 2740 insertions(+), 81 deletions(-)

diff --git a/drivers/usbhost/Kconfig b/drivers/usbhost/Kconfig
index 0c389b3..d9678d1 100644
--- a/drivers/usbhost/Kconfig
+++ b/drivers/usbhost/Kconfig
@@ -262,6 +262,15 @@ config USBHOST_CDCACM_TXBUFSIZE
 
 endif # USBHOST_CDCACM
 
+config USBHOST_CDCMBIM
+	bool "CDC/MBIM support"
+	default n
+	depends on USBHOST_HAVE_ASYNCH && !USBHOST_BULK_DISABLE && !USBHOST_INT_DISABLE
+	select USBHOST_ASYNCH
+	---help---
+		Select this option to build in host support for CDC/MBIM network
+		devices.
+
 config USBHOST_HIDKBD
 	bool "HID Keyboard Class Support"
 	default n
diff --git a/drivers/usbhost/Make.defs b/drivers/usbhost/Make.defs
index 332e83c..bf9320a 100644
--- a/drivers/usbhost/Make.defs
+++ b/drivers/usbhost/Make.defs
@@ -58,6 +58,10 @@ ifeq ($(CONFIG_USBHOST_CDCACM),y)
 CSRCS += usbhost_cdcacm.c
 endif
 
+ifeq ($(CONFIG_USBHOST_CDCMBIM),y)
+CSRCS += usbhost_cdcmbim.c
+endif
+
 ifeq ($(CONFIG_USBHOST_HIDKBD),y)
 CSRCS += usbhost_hidkbd.c
 endif
diff --git a/drivers/usbhost/usbhost_cdcmbim.c b/drivers/usbhost/usbhost_cdcmbim.c
new file mode 100644
index 0000000..75e5539
--- /dev/null
+++ b/drivers/usbhost/usbhost_cdcmbim.c
@@ -0,0 +1,2578 @@
+/****************************************************************************
+ * drivers/usbhost/usbhost_cdcmbim.c
+ *
+ *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gn...@nuttx.org>
+ *           Adam Porter <po...@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * 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/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>
+
+#define CDCMBIM_NETBUF_SIZE 8192
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* put in cdc.h */
+#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
+#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
+#define USB_CDC_GET_NTB_PARAMETERS        0x80
+#define USB_CDC_SET_NTB_INPUT_SIZE        0x86
+#define USB_CDC_SET_NTB_FORMAT            0x83
+#define USB_CDC_SET_CRC_MODE              0x8a
+#define USB_CDC_SET_MAX_DATAGRAM_SIZE     0x88
+
+#define USB_CDC_NCM_NTB16_SUPPORTED       (1 << 0)
+#define USB_CDC_NCM_NTB32_SUPPORTED       (1 << 1)
+#define USB_CDC_NCM_NTB16_FORMAT          0x00
+#define USB_CDC_NCM_NTB32_FORMAT          0x01
+#define USB_CDC_NCM_DATAGRAM_FORMAT_CRC   0x30
+#define USB_CDC_NCM_DATAGRAM_FORMAT_NOCRC 0x31
+#define USB_CDC_NCM_CRC_NOT_APPENDED      0x00
+#define USB_CDC_NCM_CRC_APPENDED          0x01
+#define USB_CDC_NCM_NTH16_SIGNATURE       0x484D434E
+
+/* 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_CDCMBIM_NTDELAY
+#  define USBHOST_CDCMBIM_NTDELAY MSEC2TICK(CONFIG_USBHOST_CDCMBIM_NTDELAY)
+#else
+#  define USBHOST_CDCMBIM_NTDELAY MSEC2TICK(200)
+#endif
+
+#ifndef CONFIG_USBHOST_CDCMBIM_NPOLLWAITERS
+#  define CONFIG_USBHOST_CDCMBIM_NPOLLWAITERS 1
+#endif
+
+/* Driver support ***********************************************************/
+
+/* This format is used to construct the /dev/cdc-wdm[n] device driver path.
+ * It defined here so that it will be used consistently in all places.
+ */
+
+#define DEV_FORMAT          "/dev/cdc-wdm%d"
+#define DEV_NAMELEN         16
+
+/* 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_ALLFOUND    0x1f
+
+#define USBHOST_MAX_CREFS   0x7fff
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct usb_cdc_ncm_nth16_s
+{
+  uint8_t signature[4];
+  uint8_t length[2];
+  uint8_t sequence[2];
+  uint8_t block_length[2];
+  uint8_t ndp_index[2];
+};
+
+struct usb_cdc_ncm_dpe16_s
+{
+  uint8_t index[2];
+  uint8_t length[2];
+};
+
+struct usb_cdc_ncm_ndp16_s
+{
+  uint8_t signature[4];
+  uint8_t length[2];
+  uint8_t next_ndp_index[2];
+  struct usb_cdc_ncm_dpe16_s dpe16[0];
+};
+
+struct usb_cdc_ncm_ntb_params_s
+{
+  uint8_t length[2];
+  uint8_t ntb_formats_supported[2];
+  uint8_t ntb_in_max_size[4];
+  uint8_t ndp_in_divisor[2];
+  uint8_t ndp_in_payload_remainder[2];
+  uint8_t ndp_in_alignment[2];
+  uint8_t reserved[2];
+  uint8_t ntb_out_max_size[4];
+  uint8_t ndp_out_divisor[2];
+  uint8_t ndp_out_payload_remainder[2];
+  uint8_t ndp_out_alignment[2];
+  uint8_t ntb_out_max_datagrams[2];
+};
+
+struct usb_csifdesc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+};
+
+struct usb_mbim_desc_s
+{
+  uint8_t len;
+  uint8_t type;
+  uint8_t subtype;
+  uint8_t mbim_version[2];
+  uint8_t max_ctrl_message[2];
+  uint8_t num_filters;
+  uint8_t max_filter_size;
+  uint8_t max_segment_size[2];
+  uint8_t network_capabilities;
+};
+
+/* This structure contains the internal, private state of the USB host class
+ * driver.
+ */
+
+struct usbhost_cdcmbim_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 */
+
+  uint8_t                 minor;        /* Minor number identifying the /dev/cdc-wdm[n] device */
+  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 */
+  sem_t                   exclsem;      /* Used to maintain mutual exclusive access */
+  struct work_s           ntwork;       /* Notification work */
+  struct work_s           comm_rxwork;  /* Communication interface RX 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                comm_rxlen;   /* Number of bytes in the RX buffer */
+  uint16_t                comm_rxmsgs;  /* Number of messages available to be read */
+  uint16_t                comm_rxpos;   /* Read position for input buffer */
+  uint16_t                maxctrlsize;  /* Maximum size of a ctrl request */
+  uint16_t                maxintsize;   /* Maximum size of interrupt IN packet */
+  uint32_t                maxntbin;     /* Maximum size of NTB IN message */
+  uint32_t                maxntbout;    /* Maximum size of NTB OUT message */
+  FAR uint8_t            *ctrlreq;      /* Allocated ctrl request structure */
+  FAR uint8_t            *data_txbuf;   /* Allocated TX buffer for network datagrams */
+  FAR uint8_t            *data_rxbuf;   /* Allocated RX buffer for network datagrams */
+  FAR uint8_t            *comm_rxbuf;   /* Allocated RX buffer comm IN messages */
+  FAR uint8_t            *notification; /* Allocated RX buffer for async notifications */
+  FAR uint8_t            *rxnetbuf;     /* Allocated RX buffer for NTB frames */
+  FAR uint8_t            *txnetbuf;     /* Allocated TX buffer for NTB frames */
+  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 */
+  uint16_t                ntbseq;       /* NTB sequence number */
+
+  struct pollfd *fds[CONFIG_USBHOST_CDCMBIM_NPOLLWAITERS];
+
+  /* Network device members */
+
+  WDOG_ID                 txpoll;       /* TX poll timer */
+  bool                    bifup;        /* true:ifup false:ifdown */
+  struct net_driver_s     netdev;       /* Interface understood by the network */
+  uint8_t                 txpktbuf[MAX_NETDEV_PKTSIZE];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Semaphores */
+
+static void usbhost_takesem(sem_t *sem);
+#define usbhost_givesem(s) nxsem_post(s);
+
+/* Polling support */
+
+static void usbhost_pollnotify(FAR struct usbhost_cdcmbim_s *priv);
+
+/* Memory allocation services */
+
+static inline FAR struct usbhost_cdcmbim_s *usbhost_allocclass(void);
+static inline void usbhost_freeclass(FAR struct usbhost_cdcmbim_s *usbclass);
+
+/* Device name management */
+
+static int usbhost_allocdevno(FAR struct usbhost_cdcmbim_s *priv);
+static void usbhost_freedevno(FAR struct usbhost_cdcmbim_s *priv);
+static inline void usbhost_mkdevname(FAR struct usbhost_cdcmbim_s *priv,
+                                     FAR char *devname);
+
+/* 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_rxdata_work(FAR void *arg);
+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_cdcmbim_s *priv,
+                           FAR const uint8_t *configdesc, int desclen);
+static inline int usbhost_devinit(FAR struct usbhost_cdcmbim_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);
+static void usbhost_putle32(uint8_t *dest, uint32_t val);
+
+/* Buffer memory management */
+
+static int usbhost_alloc_buffers(FAR struct usbhost_cdcmbim_s *priv);
+static void usbhost_free_buffers(FAR struct usbhost_cdcmbim_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);
+
+/* Control interface driver methods */
+
+static ssize_t cdcwdm_read(FAR struct file *filep, FAR char *buffer,
+                           size_t buflen);
+static ssize_t cdcwdm_write(FAR struct file *filep, FAR const char *buffer,
+                            size_t buflen);
+static int     cdcwdm_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                           bool setup);
+
+/* NuttX network callback functions */
+
+static int cdcmbim_ifup(struct net_driver_s *dev);
+static int cdcmbim_ifdown(struct net_driver_s *dev);
+static int cdcmbim_txavail(struct net_driver_s *dev);
+
+/* Network support functions */
+
+static void cdcmbim_receive(struct usbhost_cdcmbim_s *priv, uint8_t *buf,
+                            size_t len);
+
+static int cdcmbim_txpoll(struct net_driver_s *dev);
+static void cdcmbim_txpoll_work(void *arg);
+
+/****************************************************************************
+ * 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_SUBCLASS_MBIM,  /* subclass */
+  0,                  /* proto    */
+  0,                  /* vid      */
+  0                   /* pid      */
+};
+
+/* This is the USB host storage class's registry entry */
+
+static struct usbhost_registry_s g_cdcmbim =
+{
+  NULL,                   /* flink    */
+  usbhost_create,         /* create   */
+  1,                      /* nids     */
+  &g_id                   /* id[]     */
+};
+
+/* File operations for control channel */
+
+static const struct file_operations cdcwdm_fops =
+{
+  NULL,          /* open */
+  NULL,          /* close */
+  cdcwdm_read,   /* read */
+  cdcwdm_write,  /* write */
+  NULL,          /* seek */
+  NULL,          /* ioctl */
+  cdcwdm_poll    /* poll */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  , NULL         /* unlink */
+#endif
+};
+
+/* This is a bitmap that is used to allocate device names /dev/cdc-wdm[n]. */
+
+static uint32_t g_devinuse;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int usbhost_ctrl_cmd(FAR struct usbhost_cdcmbim_s *priv,
+                            uint8_t type, uint8_t req, uint16_t value,
+                            uint16_t iface, 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, iface);
+  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_pollnotify
+ ****************************************************************************/
+
+static void usbhost_pollnotify(FAR struct usbhost_cdcmbim_s *priv)
+{
+  int i;
+
+  for (i = 0; i < CONFIG_USBHOST_CDCMBIM_NPOLLWAITERS; i++)
+    {
+      struct pollfd *fds = priv->fds[i];
+      if (fds)
+        {
+          fds->revents |= (fds->events & POLLIN);
+          if (fds->revents != 0)
+            {
+              uinfo("Report events: %02x\n", fds->revents);
+              nxsem_post(fds->sem);
+            }
+        }
+    }
+}
+
+static ssize_t usbhost_readmessage(FAR struct usbhost_cdcmbim_s *priv,
+                                   FAR char *buffer, size_t buflen)
+{
+  irqstate_t flags;
+  ssize_t ret = -EAGAIN;
+
+  flags = enter_critical_section();
+
+  if (priv->comm_rxlen > 0)
+    {
+      if (buflen > priv->comm_rxlen)
+        {
+          buflen = priv->comm_rxlen;
+        }
+
+      ret = buflen;
+
+      memcpy(buffer, priv->comm_rxbuf + priv->comm_rxpos, buflen);
+      priv->comm_rxlen -= buflen;
+      priv->comm_rxpos += buflen;
+      if (priv->comm_rxlen == 0)
+        {
+          priv->comm_rxpos = 0;
+        }
+    }
+
+  leave_critical_section(flags);
+  return ret;
+}
+
+static ssize_t cdcwdm_read(FAR struct file *filep, FAR char *buffer,
+                           size_t buflen)
+{
+  FAR struct inode *inode;
+  FAR struct usbhost_cdcmbim_s *priv;
+  ssize_t ret;
+
+  inode = filep->f_inode;
+  priv  = inode->i_private;
+
+  usbhost_takesem(&priv->exclsem);
+
+  if (priv->disconnected)
+    {
+      ret = -ENODEV;
+      goto errout;
+    }
+
+  ret = usbhost_readmessage(priv, buffer, buflen);
+  if (ret < 0)
+    {
+      if (filep->f_oflags & O_NONBLOCK)
+        {
+          ret = -EAGAIN;
+          goto errout;
+        }
+
+      /* wait for a message
+       * TODO blocking read
+       */
+
+      ret = 0;
+      goto errout;
+    }
+
+  /* If this message has been completely read and there are more
+   * messages available, read the next message into the input buffer.
+   */
+
+  if (priv->comm_rxlen == 0 && priv->comm_rxmsgs > 0)
+    {
+      uinfo("Reading next message\n");
+      if (work_available(&priv->comm_rxwork))
+        {
+          (void)work_queue(LPWORK, &priv->comm_rxwork,
+                           (worker_t)usbhost_rxdata_work,
+                           priv, 0);
+        }
+    }
+
+errout:
+  usbhost_givesem(&priv->exclsem);
+  return ret;
+}
+
+static ssize_t cdcwdm_write(FAR struct file *filep, FAR const char *buffer,
+                            size_t buflen)
+{
+  FAR struct inode *inode;
+  FAR struct usbhost_cdcmbim_s *priv;
+  int ret;
+
+  inode = filep->f_inode;
+  priv  = inode->i_private;
+
+  if (priv->disconnected)
+    {
+      return -ENODEV;
+    }
+
+  if (buflen > priv->maxctrlsize)
+    {
+      buflen = priv->maxctrlsize;
+    }
+
+  /* Make sure that we have exclusive access to the private data
+   * structure. There may now be other tasks with the character driver
+   * open and actively trying to interact with the class driver.
+   */
+
+  usbhost_takesem(&priv->exclsem);
+
+  ret = usbhost_ctrl_cmd(priv,
+                         USB_REQ_DIR_OUT | USB_REQ_TYPE_CLASS |
+                         USB_REQ_RECIPIENT_INTERFACE,
+                         USB_CDC_SEND_ENCAPSULATED_COMMAND,
+                         0, priv->ctrlif, (uint8_t *)buffer, buflen);
+
+  usbhost_givesem(&priv->exclsem);
+
+  if (ret)
+    {
+      return ret;
+    }
+
+  uinfo("wrote %u bytes\n", buflen);
+
+  return buflen;
+}
+
+/****************************************************************************
+ * Name: usbhost_poll
+ *
+ * Description:
+ *   Standard character driver poll method.
+ *
+ ****************************************************************************/
+
+static int cdcwdm_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                       bool setup)
+{
+  FAR struct inode           *inode;
+  FAR struct usbhost_cdcmbim_s *priv;
+  int                         ret = OK;
+  int                         i;
+
+  DEBUGASSERT(filep && filep->f_inode && fds);
+  inode = filep->f_inode;
+  priv  = inode->i_private;
+
+  /* Make sure that we have exclusive access to the private data structure */
+
+  DEBUGASSERT(priv);
+  usbhost_takesem(&priv->exclsem);
+
+  if (priv->disconnected)
+    {
+      ret = -ENODEV;
+    }
+  else if (setup)
+    {
+      /* This is a request to set up the poll.  Find an available slot for
+       * the poll structure reference
+       */
+
+      for (i = 0; i < CONFIG_USBHOST_CDCMBIM_NPOLLWAITERS; i++)
+        {
+          /* Find an available slot */
+
+          if (!priv->fds[i])
+            {
+              /* Bind the poll structure and this slot */
+
+              priv->fds[i] = fds;
+              fds->priv    = &priv->fds[i];
+              break;
+            }
+        }
+
+      if (i >= CONFIG_USBHOST_CDCMBIM_NPOLLWAITERS)
+        {
+          fds->priv    = NULL;
+          ret          = -EBUSY;
+          goto errout;
+        }
+
+      /* Should we immediately notify on any of the requested events? Notify
+       * the POLLIN event if there is a buffered message.
+       */
+
+      if (priv->comm_rxlen > 0)
+        {
+          usbhost_pollnotify(priv);
+        }
+    }
+  else
+    {
+      /* This is a request to tear down the poll. */
+
+      struct pollfd **slot = (struct pollfd **)fds->priv;
+      DEBUGASSERT(slot);
+
+      /* Remove all memory of the poll setup */
+
+      *slot     = NULL;
+      fds->priv = NULL;
+    }
+
+errout:
+  nxsem_post(&priv->exclsem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_takesem
+ *
+ * Description:
+ *   This is just a wrapper to handle the annoying behavior of semaphore
+ *   waits that return due to the receipt of a signal.
+ *
+ ****************************************************************************/
+
+static void usbhost_takesem(sem_t *sem)
+{
+  int ret;
+
+  do
+    {
+      /* Take the semaphore (perhaps waiting) */
+
+      ret = nxsem_wait(sem);
+
+      /* The only case that an error should occur here is if the wait was
+       * awakened by a signal.
+       */
+
+      DEBUGASSERT(ret == OK || ret == -EINTR);
+    }
+  while (ret == -EINTR);
+}
+
+/****************************************************************************
+ * 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_cdcmbim_s *usbhost_allocclass(void)
+{
+  FAR struct usbhost_cdcmbim_s *priv;
+
+  DEBUGASSERT(!up_interrupt_context());
+  priv = (FAR struct usbhost_cdcmbim_s *)kmm_malloc(
+                                         sizeof(struct usbhost_cdcmbim_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_cdcmbim_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);
+}
+
+/****************************************************************************
+ * Name: Device name management
+ *
+ * Description:
+ *   Some tiny functions to coordinate management of device names.
+ *
+ ****************************************************************************/
+
+static int usbhost_allocdevno(FAR struct usbhost_cdcmbim_s *priv)
+{
+  irqstate_t flags;
+  int devno;
+
+  flags = enter_critical_section();
+  for (devno = 0; devno < 32; devno++)
+    {
+      uint32_t bitno = 1 << devno;
+      if ((g_devinuse & bitno) == 0)
+        {
+          g_devinuse |= bitno;
+          priv->minor = devno;
+          leave_critical_section(flags);
+          return OK;
+        }
+    }
+
+  leave_critical_section(flags);
+  return -EMFILE;
+}
+
+static void usbhost_freedevno(FAR struct usbhost_cdcmbim_s *priv)
+{
+  int devno = priv->minor;
+
+  if (devno >= 0 && devno < 26)
+    {
+      irqstate_t flags = enter_critical_section();
+      g_devinuse &= ~(1 << devno);
+      leave_critical_section(flags);
+    }
+}
+
+static inline void usbhost_mkdevname(FAR struct usbhost_cdcmbim_s *priv,
+                                     FAR char *devname)
+{
+  (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->minor);
+}
+
+static void usbhost_bulkin_callback(FAR void *arg, ssize_t nbytes)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)arg;
+  uint32_t delay = 0;
+
+  DEBUGASSERT(priv);
+
+  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))
+    {
+      (void)work_queue(LPWORK, &priv->bulk_rxwork,
+                       (worker_t)usbhost_bulkin_work, priv, delay);
+    }
+}
+
+static void usbhost_bulkin_work(FAR void *arg)
+{
+  struct usbhost_cdcmbim_s *priv;
+  struct usbhost_hubport_s *hport;
+  uint16_t ndpoffset;
+  uint16_t dgram_len;
+  uint16_t dgram_off;
+
+  priv = (struct usbhost_cdcmbim_s *)arg;
+  DEBUGASSERT(priv);
+
+  hport = priv->usbclass.hport;
+  DEBUGASSERT(hport);
+
+  if (priv->disconnected || !priv->bifup)
+    {
+      return;
+    }
+
+  usbhost_takesem(&priv->exclsem);
+
+  if (priv->bulkinbytes < (int16_t)(sizeof(struct usb_cdc_ncm_nth16_s) +
+                                    sizeof(struct usb_cdc_ncm_ndp16_s)))
+    {
+      goto out;
+    }
+
+  /* Parse the NTB header */
+
+  struct usb_cdc_ncm_nth16_s *nth =
+    (struct usb_cdc_ncm_nth16_s *)priv->rxnetbuf;
+
+  if (usbhost_getle32(nth->signature) != USB_CDC_NCM_NTH16_SIGNATURE)
+    {
+      uerr("Invalid NTH signature\n");
+      goto out;
+    }
+
+  uint16_t block_len = usbhost_getle16(nth->block_length);
+
+  if (block_len > priv->bulkinbytes)
+    {
+      uerr("Block length larger than rx buffer\n");
+      goto out;
+    }
+
+  ndpoffset = usbhost_getle16(nth->ndp_index);
+  if (ndpoffset > priv->bulkinbytes)
+    {
+      uerr("NDP offset too far %u > %u\n", ndpoffset, priv->bulkinbytes);
+      goto out;
+    }
+
+  /* Parse each NDP */
+
+  do
+    {
+      struct usb_cdc_ncm_ndp16_s *ndp
+        = (struct usb_cdc_ncm_ndp16_s *)(priv->rxnetbuf + ndpoffset);
+
+      ndpoffset = usbhost_getle16(ndp->next_ndp_index);
+
+      /* Parse each DPE */
+
+      struct usb_cdc_ncm_dpe16_s *dpe;
+
+      for (dpe = ndp->dpe16; usbhost_getle16(dpe->index); dpe++)
+        {
+          dgram_off = usbhost_getle16(dpe->index);
+          dgram_len = usbhost_getle16(dpe->length);
+
+          if (dgram_off + dgram_len <= priv->bulkinbytes)
+            {
+              cdcmbim_receive(priv, priv->rxnetbuf + dgram_off, dgram_len);
+            }
+        }
+    }
+  while (ndpoffset);
+
+out:
+    DRVR_ASYNCH(hport->drvr, priv->bulkin,
+                (uint8_t *)priv->rxnetbuf, CDCMBIM_NETBUF_SIZE,
+                usbhost_bulkin_callback, priv);
+    usbhost_givesem(&priv->exclsem);
+}
+
+/****************************************************************************
+ * Name: usbhost_rxdata_work
+ *
+ * Description:
+ *   Read an available comm message into the RX buffer
+ *
+ * Input Parameters:
+ *   arg - Driver private data
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_rxdata_work(FAR void *arg)
+{
+  FAR struct usbhost_cdcmbim_s *priv;
+  int ret;
+
+  priv = (FAR struct usbhost_cdcmbim_s *)arg;
+  DEBUGASSERT(priv);
+
+  /* Are we still connected? */
+
+  if (priv->disconnected)
+    {
+      return;
+    }
+
+  usbhost_takesem(&priv->exclsem);
+
+  ret = usbhost_ctrl_cmd(priv,
+                         USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
+                         USB_REQ_RECIPIENT_INTERFACE,
+                         USB_CDC_GET_ENCAPSULATED_RESPONSE,
+                         0, priv->ctrlif, priv->comm_rxbuf,
+                         priv->maxctrlsize);
+  if (ret)
+    {
+      uerr("Failed to read message: %d\n", ret);
+      goto errout;
+    }
+
+  /* Would be nice if CTRLIN would return how many bytes it read... */
+
+  struct mbim_header_s
+  {
+    uint8_t type[4];
+    uint8_t len[4];
+  };
+
+  struct mbim_header_s *hdr = (struct mbim_header_s *)priv->comm_rxbuf;
+  uint32_t len = usbhost_getle32(hdr->len);
+
+  if (len > priv->maxctrlsize)
+    {
+      uerr("Read invalid MBIM packet\n");
+      goto errout;
+    }
+
+  uinfo("Read MBIM message %u bytes\n", len);
+
+  priv->comm_rxlen = len;
+  priv->comm_rxmsgs--;
+
+  /* Notify any poll waiters we have data */
+
+  usbhost_pollnotify(priv);
+
+errout:
+  usbhost_givesem(&priv->exclsem);
+}
+
+/****************************************************************************
+ * 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_cdcmbim_s *priv;
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct cdc_notification_s *inmsg;
+  int ret;
+
+  priv = (FAR struct usbhost_cdcmbim_s *)arg;
+  DEBUGASSERT(priv);
+
+  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;
+
+          /* We care only about the ResponseAvailable notification */
+
+          if ((inmsg->type         == (USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
+                                       USB_REQ_RECIPIENT_INTERFACE)) &&
+              (inmsg->notification == ACM_RESPONSE_AVAILABLE))
+            {
+              priv->comm_rxmsgs++;
+
+              /* If this is the only message available, read it */
+
+              if (priv->comm_rxmsgs == 1)
+                {
+                  if (work_available(&priv->comm_rxwork))
+                    {
+                      (void)work_queue(LPWORK, &priv->comm_rxwork,
+                                       (worker_t)usbhost_rxdata_work,
+                                       priv, 0);
+                    }
+                }
+            }
+        }
+
+      /* 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);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: usbhost_notification_callback
+ *
+ * Description:
+ *   Handle receipt of Response Available from the CDC/MBIM 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_cdcmbim_s *priv = (FAR struct usbhost_cdcmbim_s *)arg;
+  uint32_t delay = 0;
+
+  DEBUGASSERT(priv);
+
+  /* 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_CDCMBIM_NTDELAY;
+        }
+
+      /* Make sure that the work structure available.  There is a remote
+       * chance that this may collide with a device disconnection event.
+       */
+
+      if (work_available(&priv->ntwork))
+        {
+          (void)work_queue(LPWORK, &priv->ntwork,
+                           (worker_t)usbhost_notification_work,
+                           priv, delay);
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: usbhost_destroy
+ *
+ * Description:
+ *   The USB device has been disconnected and the reference count on the USB
+ *   host class instance has gone to 1.. Time to destroy the USB host class
+ *   instance.
+ *
+ * Input Parameters:
+ *   arg - A reference to the class instance to be destroyed.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_destroy(FAR void *arg)
+{
+  FAR struct usbhost_cdcmbim_s *priv = (FAR struct usbhost_cdcmbim_s *)arg;
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct usbhost_driver_s *drvr;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
+  hport = priv->usbclass.hport;
+
+  DEBUGASSERT(hport->drvr);
+  drvr = hport->drvr;
+
+  uinfo("crefs: %d\n", priv->crefs);
+
+  /* Unregister the driver */
+
+  /* Release the device name used by this connection */
+
+  usbhost_freedevno(priv);
+
+  /* Free the endpoints */
+
+  if (priv->intin)
+    {
+      DRVR_EPFREE(hport->drvr, priv->intin);
+    }
+
+  if (priv->bulkin)
+    {
+      DRVR_EPFREE(hport->drvr, priv->bulkin);
+    }
+
+  if (priv->bulkout)
+    {
+      DRVR_EPFREE(hport->drvr, priv->bulkout);
+    }
+
+  /* Free any transfer buffers */
+
+  usbhost_free_buffers(priv);
+
+  /* Free the function address assigned to this device */
+
+  usbhost_devaddr_destroy(hport, hport->funcaddr);
+  hport->funcaddr = 0;
+
+  /* Destroy the semaphores */
+
+  /* Disconnect the USB host device */
+
+  DRVR_DISCONNECT(drvr, hport);
+
+  /* And free the class instance.  Hmmm.. this may execute on the worker
+   * thread and the work structure is part of what is getting freed.  That
+   * should be okay because once the work contained is removed from the
+   * queue, it should not longer be accessed by the worker thread.
+   */
+
+  usbhost_freeclass(priv);
+}
+
+/****************************************************************************
+ * Name: usbhost_cfgdesc
+ *
+ * Description:
+ *   This function implements the connect() method of struct
+ *   usbhost_class_s.  This method is a callback into the class
+ *   implementation.  It is used to provide the device's configuration
+ *   descriptor to the class so that the class may initialize properly
+ *
+ * Input Parameters:
+ *   priv - The USB host class instance.
+ *   configdesc - A pointer to a uint8_t buffer container the configuration
+ *     descriptor.
+ *   desclen - The length in bytes of the configuration descriptor.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int usbhost_cfgdesc(FAR struct usbhost_cdcmbim_s *priv,
+                           FAR const uint8_t *configdesc, int desclen)
+{
+  FAR struct usbhost_hubport_s *hport;
+  FAR struct usb_cfgdesc_s *cfgdesc;
+  FAR struct usb_desc_s *desc;
+  FAR struct usbhost_epdesc_s bindesc;
+  FAR struct usbhost_epdesc_s boutdesc;
+  FAR struct usbhost_epdesc_s iindesc;
+  int remaining;
+  uint8_t found = 0;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport &&
+              configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
+  hport = priv->usbclass.hport;
+
+  /* Verify that we were passed a configuration descriptor */
+
+  cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
+  if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
+    {
+      return -EINVAL;
+    }
+
+  /* Get the total length of the configuration descriptor (little endian).
+   * It might be a good check to get the number of interfaces here too.
+   */
+
+  remaining = (int)usbhost_getle16(cfgdesc->totallen);
+
+  /* Skip to the next entry descriptor */
+
+  configdesc += cfgdesc->len;
+  remaining  -= cfgdesc->len;
+
+  /* Loop where there are more descriptors to examine */
+
+  while (remaining >= sizeof(struct usb_desc_s))
+    {
+      /* What is the next descriptor? */
+
+      desc = (FAR struct usb_desc_s *)configdesc;
+      switch (desc->type)
+        {
+        case USB_DESC_TYPE_CSINTERFACE:
+          {
+            FAR struct usb_csifdesc_s *csdesc = (FAR struct usb_csifdesc_s *)
+                                                desc;
+
+            /* MBIM functional descriptor */
+
+            if (csdesc->subtype == CDC_DSUBTYPE_MBIM)
+              {
+                FAR struct usb_mbim_desc_s *mbim =
+                                (FAR struct usb_mbim_desc_s *)desc;
+
+                priv->maxctrlsize = usbhost_getle16(mbim->max_ctrl_message);
+                uinfo("MBIM max control size: %u\n", priv->maxctrlsize);
+                uinfo("MBIM max segment size: %u\n",
+                                usbhost_getle16(mbim->max_segment_size));
+              }
+          }
+          break;
+
+        /* Interface descriptor. We really should get the number of endpoints
+         * from this descriptor too.
+         */
+
+        case USB_DESC_TYPE_INTERFACE:
+          {
+            FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)
+                                              configdesc;
+
+            uinfo("Interface descriptor\n");
+            DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
+
+            /* Is this the control interface? */
+
+            if (ifdesc->classid  == CDC_CLASS_COMM &&
+                ifdesc->subclass == CDC_SUBCLASS_MBIM &&
+                ifdesc->protocol == CDC_PROTO_NONE)
+              {
+                priv->ctrlif  = ifdesc->ifno;
+                found        |= USBHOST_CTRLIFFOUND;
+              }
+
+            /* Is this the data interface? */
+
+            else if (ifdesc->classid  == USB_CLASS_CDC_DATA &&
+                     ifdesc->subclass == CDC_SUBCLASS_NONE &&
+                     ifdesc->protocol == CDC_DATA_PROTO_NTB)
+              {
+                priv->dataif  = ifdesc->ifno;
+                found        |= USBHOST_DATAIFFOUND;
+              }
+          }
+          break;
+
+        /* Endpoint descriptor.  Here, we expect two bulk endpoints, an IN
+         * and an OUT.
+         */
+
+        case USB_DESC_TYPE_ENDPOINT:
+          {
+            FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)
+                                              configdesc;
+
+            uinfo("Endpoint descriptor\n");
+            DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
+
+            /* Check for interrupt endpoint */
+
+            if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) ==
+                USB_EP_ATTR_XFER_INT)
+              {
+                if (USB_ISEPIN(epdesc->addr))
+                  {
+                    found |= USBHOST_INTRIFFOUND;
+                    iindesc.hport        = hport;
+                    iindesc.addr         = epdesc->addr &
+                                           USB_EP_ADDR_NUMBER_MASK;
+                    iindesc.in           = true;
+                    iindesc.xfrtype      = USB_EP_ATTR_XFER_INT;
+                    iindesc.interval     = epdesc->interval;
+                    iindesc.mxpacketsize =
+                                usbhost_getle16(epdesc->mxpacketsize);
+                    uinfo("Interrupt IN EP addr:%d mxpacketsize:%d\n",
+                          iindesc.addr, iindesc.mxpacketsize);
+
+                    priv->maxintsize = iindesc.mxpacketsize;
+                  }
+              }
+
+            /* Check for a bulk endpoint. */
+
+            else if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) ==
+                     USB_EP_ATTR_XFER_BULK)
+              {
+                /* Yes.. it is a bulk endpoint.  IN or OUT? */
+
+                if (USB_ISEPOUT(epdesc->addr))
+                  {
+                    /* It is an OUT bulk endpoint.  There should be only one
+                     * bulk OUT endpoint.
+                     */
+
+                    if ((found & USBHOST_BOUTFOUND) != 0)
+                      {
+                        /* Oops.. more than one endpoint.  We don't know
+                         * what to do with this.
+                         */
+
+                        return -EINVAL;
+                      }
+
+                    found |= USBHOST_BOUTFOUND;
+
+                    /* Save the bulk OUT endpoint information */
+
+                    boutdesc.hport        = hport;
+                    boutdesc.addr         = epdesc->addr &
+                                            USB_EP_ADDR_NUMBER_MASK;
+                    boutdesc.in           = false;
+                    boutdesc.xfrtype      = USB_EP_ATTR_XFER_BULK;
+                    boutdesc.interval     = epdesc->interval;
+                    boutdesc.mxpacketsize =
+                                usbhost_getle16(epdesc->mxpacketsize);
+                    uinfo("Bulk OUT EP addr:%d mxpacketsize:%d\n",
+                          boutdesc.addr, boutdesc.mxpacketsize);
+
+                    priv->bulkmxpacket = boutdesc.mxpacketsize;
+                  }
+                else
+                  {
+                    /* It is an IN bulk endpoint.  There should be only one
+                     * bulk IN endpoint.
+                     */
+
+                    if ((found & USBHOST_BINFOUND) != 0)
+                      {
+                        /* Oops.. more than one endpoint.  We don't know
+                         * what to do with this.
+                         */
+
+                        return -EINVAL;
+                      }
+
+                    found |= USBHOST_BINFOUND;
+
+                    /* Save the bulk IN endpoint information */
+
+                    bindesc.hport        = hport;
+                    bindesc.addr         = epdesc->addr &
+                                           USB_EP_ADDR_NUMBER_MASK;
+                    bindesc.in           = 1;
+                    bindesc.xfrtype      = USB_EP_ATTR_XFER_BULK;
+                    bindesc.interval     = epdesc->interval;
+                    bindesc.mxpacketsize =
+                                usbhost_getle16(epdesc->mxpacketsize);
+                    uinfo("Bulk IN EP addr:%d mxpacketsize:%d\n",
+                          bindesc.addr, bindesc.mxpacketsize);
+                  }
+              }
+          }
+          break;
+
+        /* Other descriptors are just ignored for now */
+
+        default:
+          break;
+        }
+
+      /* If we found everything we need with this interface, then break out
+       * of the loop early.
+       */
+
+      if (found == USBHOST_ALLFOUND)
+        {
+          break;
+        }
+
+      /* Increment the address of the next descriptor */
+
+      configdesc += desc->len;
+      remaining  -= desc->len;
+    }
+
+  /* Sanity checking... did we find all of things that we need? */
+
+  if (found != USBHOST_ALLFOUND)
+    {
+      uerr("ERROR: Found CTRLIF:%s DATAIF: %s BIN:%s BOUT:%s\n",
+           (found & USBHOST_CTRLIFFOUND) != 0 ? "YES" : "NO",
+           (found & USBHOST_DATAIFFOUND) != 0 ? "YES" : "NO",
+           (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
+           (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
+      return -EINVAL;
+    }
+
+  /* We are good... Allocate the endpoints */
+
+  ret = DRVR_EPALLOC(hport->drvr, &boutdesc, &priv->bulkout);
+  if (ret < 0)
+    {
+      uerr("ERROR: Failed to allocate Bulk OUT endpoint\n");
+      return ret;
+    }
+
+  ret = DRVR_EPALLOC(hport->drvr, &bindesc, &priv->bulkin);
+  if (ret < 0)
+    {
+      uerr("ERROR: Failed to allocate Bulk IN endpoint\n");
+      (void)DRVR_EPFREE(hport->drvr, priv->bulkout);
+      return ret;
+    }
+
+  ret = DRVR_EPALLOC(hport->drvr, &iindesc, &priv->intin);
+  if (ret < 0)
+    {
+      uerr("ERROR: Failed to allocate Interrupt IN endpoint\n");
+      (void)DRVR_EPFREE(hport->drvr, priv->bulkout);
+      (void)DRVR_EPFREE(hport->drvr, priv->bulkin);
+      return ret;
+    }
+
+  uinfo("Endpoints allocated\n");
+  return OK;
+}
+
+static int usbhost_setinterface(FAR struct usbhost_cdcmbim_s *priv,
+                                uint16_t iface, uint16_t setting)
+{
+  return usbhost_ctrl_cmd(priv,
+                          USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_INTERFACE,
+                          USB_REQ_SETINTERFACE, setting, iface, NULL, 0);
+}
+
+static int cdc_ncm_set_ntb_input_size(FAR struct usbhost_cdcmbim_s *priv,
+                                      uint32_t size)
+{
+  uint8_t buf[4];
+
+  usbhost_putle32(buf, size);
+
+  return usbhost_ctrl_cmd(priv,
+                          USB_REQ_DIR_OUT | USB_REQ_TYPE_CLASS |
+                          USB_REQ_RECIPIENT_INTERFACE,
+                          USB_CDC_SET_NTB_INPUT_SIZE,
+                          0, priv->ctrlif, buf, 4);
+}
+
+#if 0
+static int cdc_ncm_set_max_dgram_size(FAR struct usbhost_cdcmbim_s *priv,
+                                      uint16_t size)
+{
+  uint8_t buf[2];
+
+  usbhost_putle16(buf, size);
+
+  return usbhost_ctrl_cmd(priv,
+                          USB_REQ_DIR_OUT | USB_REQ_TYPE_CLASS |
+                          USB_REQ_RECIPIENT_INTERFACE,
+                          USB_CDC_SET_MAX_DATAGRAM_SIZE,
+                          0, priv->ctrlif, buf, 2);
+}
+#endif
+
+static int cdc_ncm_read_parameters(FAR struct usbhost_cdcmbim_s *priv)
+{
+  struct usb_cdc_ncm_ntb_params_s params;
+  int ret;
+
+  ret = usbhost_ctrl_cmd(priv,
+                         USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
+                         USB_REQ_RECIPIENT_INTERFACE,
+                         USB_CDC_GET_NTB_PARAMETERS,
+                         0, priv->ctrlif, (uint8_t *)&params,
+                         sizeof(params));
+  if (ret == OK)
+    {
+      priv->maxntbin  = usbhost_getle32(params.ntb_in_max_size);
+      priv->maxntbout = usbhost_getle32(params.ntb_out_max_size);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_devinit
+ *
+ * Description:
+ *   The USB device has been successfully connected.  This completes the
+ *   initialization operations.  It is first called after the
+ *   configuration descriptor has been received.
+ *
+ *   This function is called from the connect() method.  This function always
+ *   executes on the thread of the caller of connect().
+ *
+ * Input Parameters:
+ *   priv - A reference to the class instance.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline int usbhost_devinit(FAR struct usbhost_cdcmbim_s *priv)
+{
+  FAR struct usbhost_hubport_s *hport;
+  int ret = OK;
+
+  hport = priv->usbclass.hport;
+
+  /* Increment the reference count.  This will prevent usbhost_destroy() from
+   * being called asynchronously if the device is removed.
+   */
+
+  priv->crefs++;
+  DEBUGASSERT(priv->crefs == 2);
+
+  /* Configure the device */
+
+  /* Set aside transfer buffers for exclusive use by the class driver */
+
+  ret = usbhost_alloc_buffers(priv);
+  if (ret)
+    {
+      uerr("ERROR: failed to allocate buffers\n");
+      return ret;
+    }
+
+  priv->ntbseq = 0;
+
+  /* Read NCM parameters */
+
+  ret = cdc_ncm_read_parameters(priv);
+  if (ret)
+    {
+      uerr("ERROR: failed to read NCM parameters: %d\n", ret);
+    }
+
+  /* Set alternate setting 1 on data interface */
+
+  usbhost_setinterface(priv, priv->dataif, 1);
+
+  /* Set NTB Input size to length of rx buffer */
+
+  ret = cdc_ncm_set_ntb_input_size(priv, CDCMBIM_NETBUF_SIZE);
+  if (ret)
+    {
+      printf("set NTB input size failed: %d\n", ret);
+    }
+
+  #if 0
+  /* Set max datagram size to MTU */
+
+  ret = cdc_ncm_set_max_dgram_size(priv, 2048);
+  if (ret)
+    {
+      printf("Failed to set max dgram size: %d\n", ret);
+    }
+  #endif
+
+  /* Register the driver */
+
+  if (ret >= 0)
+    {
+      char devname[DEV_NAMELEN];
+
+      uinfo("Register character driver\n");
+      usbhost_mkdevname(priv, devname);
+      ret = register_driver(devname, &cdcwdm_fops, 0666, priv);
+    }
+
+  if (priv->intin)
+    {
+      /* Begin monitoring of message available events */
+
+      uinfo("Start notification monitoring\n");
+      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 on intin: %d\n", ret);
+        }
+    }
+
+  /* Setup the network interface */
+
+  memset(&priv->netdev, 0, sizeof(struct net_driver_s));
+  priv->netdev.d_ifup    = cdcmbim_ifup;
+  priv->netdev.d_ifdown  = cdcmbim_ifdown;
+  priv->netdev.d_txavail = cdcmbim_txavail;
+  priv->netdev.d_private = priv;
+  priv->txpoll           = wd_create();
+
+  /* Register the network device */
+
+  (void)netdev_register(&priv->netdev, NET_LL_MBIM);
+
+  /* Check if we successfully initialized. We now have to be concerned
+   * about asynchronous modification of crefs because the character
+   * driver has been registerd.
+   */
+
+  if (ret >= 0)
+    {
+      usbhost_takesem(&priv->exclsem);
+      DEBUGASSERT(priv->crefs >= 2);
+
+      /* Handle a corner case where (1) open() has been called so the
+       * reference count is > 2, but the device has been disconnected.
+       * In this case, the class instance needs to persist until close()
+       * is called.
+       */
+
+      if (priv->crefs <= 2 && priv->disconnected)
+        {
+          /* We don't have to give the semaphore because it will be
+           * destroyed when usb_destroy is called.
+           */
+
+          ret = -ENODEV;
+        }
+      else
+        {
+          /* Ready for normal operation */
+
+          uinfo("Successfully initialized\n");
+          priv->crefs--;
+          usbhost_givesem(&priv->exclsem);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_getle16
+ *
+ * Description:
+ *   Get a (possibly unaligned) 16-bit little endian value.
+ *
+ * Input Parameters:
+ *   val - A pointer to the first byte of the little endian value.
+ *
+ * Returned Value:
+ *   A uint16_t representing the whole 16-bit integer value
+ *
+ ****************************************************************************/
+
+static inline uint16_t usbhost_getle16(const uint8_t *val)
+{
+  return (uint16_t)val[1] << 8 | (uint16_t)val[0];
+}
+
+/****************************************************************************
+ * Name: usbhost_putle16
+ *
+ * Description:
+ *   Put a (possibly unaligned) 16-bit little endian value.
+ *
+ * Input Parameters:
+ *   dest - A pointer to the first byte to save the little endian value.
+ *   val - The 16-bit value to be saved.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_putle16(uint8_t *dest, uint16_t val)
+{
+  dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
+  dest[1] = val >> 8;
+}
+
+/****************************************************************************
+ * Name: usbhost_getle32
+ *
+ * Description:
+ *   Get a (possibly unaligned) 32-bit little endian value.
+ *
+ * Input Parameters:
+ *   dest - A pointer to the first byte to save the big endian value.
+ *   val - The 32-bit value to be saved.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline uint32_t usbhost_getle32(const uint8_t *val)
+{
+  /* Little endian means LS halfword first in byte stream */
+
+  return (uint32_t)usbhost_getle16(&val[2]) << 16 |
+                                   (uint32_t)usbhost_getle16(val);
+}
+
+/****************************************************************************
+ * Name: usbhost_putle32
+ *
+ * Description:
+ *   Put a (possibly unaligned) 32-bit little endian value.
+ *
+ * Input Parameters:
+ *   dest - A pointer to the first byte to save the little endian value.
+ *   val - The 32-bit value to be saved.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_putle32(uint8_t *dest, uint32_t val)
+{
+  /* Little endian means LS halfword first in byte stream */
+
+  usbhost_putle16(dest, (uint16_t)(val & 0xffff));
+  usbhost_putle16(dest + 2, (uint16_t)(val >> 16));
+}
+
+/****************************************************************************
+ * Name: usbhost_alloc_buffers
+ *
+ * Description:
+ *   Allocate transfer buffer memory.
+ *
+ * Input Parameters:
+ *   priv - A reference to the class instance.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned.  On failure, an negated errno value
+ *   is returned to indicate the nature of the failure.
+ *
+ ****************************************************************************/
+
+static int usbhost_alloc_buffers(FAR struct usbhost_cdcmbim_s *priv)
+{
+  FAR struct usbhost_hubport_s *hport;
+  size_t maxlen;
+  int ret;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL &&
+              priv->ctrlreq == NULL);
+  hport = priv->usbclass.hport;
+
+  /* Allocate memory for control requests */
+
+  ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_ALLOC of ctrlreq failed: %d\n", ret);
+      goto errout;
+    }
+
+  DEBUGASSERT(maxlen >= sizeof(struct usb_ctrlreq_s));
+
+  /* Allocate buffer for receiving encapsulated data */
+
+  ret = DRVR_IOALLOC(hport->drvr, &priv->comm_rxbuf, priv->maxctrlsize);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_IOALLOC of comm_rxbuf failed: %d (%d bytes)\n", ret,
+           priv->maxctrlsize);
+      goto errout;
+    }
+
+  /* Allocate buffer for interrupt IN notifications */
+
+  ret = DRVR_IOALLOC(hport->drvr, &priv->notification, priv->maxintsize);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_IOALLOC of notification buf failed: %d (%d bytes)\n",
+           ret, priv->maxintsize);
+      goto errout;
+    }
+
+  ret = DRVR_IOALLOC(hport->drvr, &priv->rxnetbuf, CDCMBIM_NETBUF_SIZE);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_IOALLOC of net rx buf failed: %d (%d bytes)\n",
+           ret, 2048);
+      goto errout;
+    }
+
+  ret = DRVR_IOALLOC(hport->drvr, &priv->txnetbuf, 2048);
+  if (ret < 0)
+    {
+      uerr("ERROR: DRVR_IOALLOC of net tx buf failed: %d (%d bytes)\n",
+           ret, 2048);
+      goto errout;
+    }
+
+  return OK;
+
+errout:
+  usbhost_free_buffers(priv);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_free_buffers
+ *
+ * Description:
+ *   Free transfer buffer memory.
+ *
+ * Input Parameters:
+ *   priv - A reference to the class instance.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void usbhost_free_buffers(FAR struct usbhost_cdcmbim_s *priv)
+{
+  FAR struct usbhost_hubport_s *hport;
+
+  DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
+  hport = priv->usbclass.hport;
+
+  if (priv->ctrlreq)
+    {
+      (void)DRVR_FREE(hport->drvr, priv->ctrlreq);
+    }
+
+  if (priv->comm_rxbuf)
+    {
+      (void)DRVR_IOFREE(hport->drvr, priv->comm_rxbuf);
+    }
+
+  if (priv->notification)
+    {
+      (void)DRVR_IOFREE(hport->drvr, priv->notification);
+    }
+
+  if (priv->rxnetbuf)
+    {
+      (void)DRVR_IOFREE(hport->drvr, priv->rxnetbuf);
+    }
+
+  if (priv->txnetbuf)
+    {
+      (void)DRVR_IOFREE(hport->drvr, priv->txnetbuf);
+    }
+
+  priv->ctrlreq      = NULL;
+  priv->comm_rxbuf   = NULL;
+  priv->notification = NULL;
+  priv->rxnetbuf     = NULL;
+  priv->txnetbuf     = NULL;
+}
+
+/****************************************************************************
+ * struct usbhost_registry_s methods
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_create
+ *
+ * Description:
+ *   This function implements the create() method of struct
+ *   usbhost_registry_s.
+ *   The create() method is a callback into the class implementation.  It is
+ *   used to (1) create a new instance of the USB host class state and to (2)
+ *   bind a USB host driver "session" to the class instance.  Use of this
+ *   create() method will support environments where there may be multiple
+ *   USB ports and multiple USB devices simultaneously connected.
+ *
+ * Input Parameters:
+ *   hport - The hub hat manages the new class instance.
+ *   id - In the case where the device supports multiple base classes,
+ *     subclasses, or protocols, this specifies which to configure for.
+ *
+ * Returned Value:
+ *   On success, this function will return a non-NULL instance of struct
+ *   usbhost_class_s that can be used by the USB host driver to communicate
+ *   with the USB host class.  NULL is returned on failure; this function
+ *   will fail only if the hport input parameter is NULL or if there are
+ *   insufficient resources to create another USB host class instance.
+ *
+ ****************************************************************************/
+
+static FAR struct usbhost_class_s
+                  *usbhost_create(FAR struct usbhost_hubport_s *hport,
+                                  FAR const struct usbhost_id_s *id)
+{
+  FAR struct usbhost_cdcmbim_s *priv;
+
+  /* Allocate a USB host class instance */
+
+  priv = usbhost_allocclass();
+  if (priv)
+    {
+      /* Initialize the allocated storage class instance */
+
+      memset(priv, 0, sizeof(struct usbhost_cdcmbim_s));
+
+      /* Assign a device number to this class instance */
+
+      if (usbhost_allocdevno(priv) == OK)
+        {
+          /* Initialize class method function pointers */
+
+          priv->usbclass.hport        = hport;
+          priv->usbclass.connect      = usbhost_connect;
+          priv->usbclass.disconnected = usbhost_disconnected;
+
+          /* The initial reference count is 1... One reference is held by
+           * the driver.
+           */
+
+          priv->crefs = 1;
+
+          /* Initialize semaphores (this works in the interrupt context) */
+
+          nxsem_init(&priv->exclsem, 0, 1);
+
+          /* Return the instance of the USB class driver */
+
+          return &priv->usbclass;
+        }
+    }
+
+  /* An error occurred. Free the allocation and return NULL on all failures */
+
+  if (priv)
+    {
+      usbhost_freeclass(priv);
+    }
+
+  return NULL;
+}
+
+/****************************************************************************
+ * struct usbhost_class_s methods
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_connect
+ *
+ * Description:
+ *   This function implements the connect() method of struct
+ *   usbhost_class_s.  This method is a callback into the class
+ *   implementation.  It is used to provide the device's configuration
+ *   descriptor to the class so that the class may initialize properly
+ *
+ * Input Parameters:
+ *   usbclass - The USB host class entry previously obtained from a call to
+ *     create().
+ *   configdesc - A pointer to a uint8_t buffer container the configuration
+ *     descriptor.
+ *   desclen - The length in bytes of the configuration descriptor.
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ *   NOTE that the class instance remains valid upon return with a failure.
+ *   It is the responsibility of the higher level enumeration logic to call
+ *   CLASS_DISCONNECTED to free up the class driver resources.
+ *
+ * Assumptions:
+ *   - This function will *not* be called from an interrupt handler.
+ *   - If this function returns an error, the USB host controller driver
+ *     must call to DISCONNECTED method to recover from the error
+ *
+ ****************************************************************************/
+
+static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
+                           FAR const uint8_t *configdesc, int desclen)
+{
+  FAR struct usbhost_cdcmbim_s *priv = (FAR struct usbhost_cdcmbim_s *)
+                                       usbclass;
+  int ret;
+
+  DEBUGASSERT(priv != NULL &&
+              configdesc != NULL &&
+              desclen >= sizeof(struct usb_cfgdesc_s));
+
+  /* Parse the configuration descriptor to get the endpoints */
+
+  ret = usbhost_cfgdesc(priv, configdesc, desclen);
+  if (ret < 0)
+    {
+      uerr("ERROR: usbhost_cfgdesc() failed: %d\n", ret);
+    }
+  else
+    {
+      /* Now configure the device and register the NuttX driver */
+
+      ret = usbhost_devinit(priv);
+      if (ret < 0)
+        {
+          uerr("ERROR: usbhost_devinit() failed: %d\n", ret);
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: usbhost_disconnected
+ *
+ * Description:
+ *   This function implements the disconnected() method of struct
+ *   usbhost_class_s.  This method is a callback into the class
+ *   implementation.  It is used to inform the class that the USB device has
+ *   been disconnected.
+ *
+ * Input Parameters:
+ *   usbclass - The USB host class entry previously obtained from a call to
+ *     create().
+ *
+ * Returned Value:
+ *   On success, zero (OK) is returned. On a failure, a negated errno value
+ *   is returned indicating the nature of the failure
+ *
+ * Assumptions:
+ *   This function may be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static int usbhost_disconnected(struct usbhost_class_s *usbclass)
+{
+  FAR struct usbhost_cdcmbim_s *priv = (FAR struct usbhost_cdcmbim_s *)
+                                       usbclass;
+  irqstate_t flags;
+
+  DEBUGASSERT(priv != NULL);
+
+  /* Set an indication to any users of the device that the device is no
+   * longer available.
+   */
+
+  flags              = enter_critical_section();
+  priv->disconnected = true;
+
+  /* Now check the number of references on the class instance.  If it is one,
+   * then we can free the class instance now.  Otherwise, we will have to
+   * wait until the holders of the references free them by closing the
+   * block driver.
+   */
+
+  uinfo("crefs: %d\n", priv->crefs);
+  if (priv->crefs == 1)
+    {
+      /* Destroy the class instance.  If we are executing from an interrupt
+       * handler, then defer the destruction to the worker thread.
+       * Otherwise, destroy the instance now.
+       */
+
+      if (up_interrupt_context())
+        {
+          /* Destroy the instance on the worker thread. */
+
+          uinfo("Queuing destruction: worker %p->%p\n",
+                priv->destroywork.worker, usbhost_destroy);
+          DEBUGASSERT(priv->destroywork.worker == NULL);
+          (void)work_queue(LPWORK, &priv->destroywork,
+                           usbhost_destroy, priv, 0);
+        }
+      else
+        {
+          /* Do the work now */
+
+          usbhost_destroy(priv);
+        }
+    }
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcmbim_transmit
+ *
+ * Description:
+ *   Start hardware transmission.  Called either from the txdone interrupt
+ *   handling or from watchdog based polling.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static int cdcmbim_transmit(struct usbhost_cdcmbim_s *priv)
+{
+  struct usbhost_hubport_s *hport;
+  struct usb_cdc_ncm_nth16_s *nth;
+  struct usb_cdc_ncm_ndp16_s *ndp;
+  struct usb_cdc_ncm_dpe16_s *dpe;
+  ssize_t ret;
+  uint16_t len = 0;
+
+  hport = priv->usbclass.hport;
+
+  uinfo("transmit packet: %d bytes\n", priv->netdev.d_len);
+
+  /* Increment statistics */
+
+  NETDEV_TXPACKETS(&priv->netdev);
+
+  len = sizeof(struct usb_cdc_ncm_nth16_s);
+  nth = (struct usb_cdc_ncm_nth16_s *)priv->txnetbuf;
+
+  /* Begin filling NTH */
+
+  usbhost_putle32(nth->signature, USB_CDC_NCM_NTH16_SIGNATURE);
+  usbhost_putle16(nth->length, sizeof(struct usb_cdc_ncm_nth16_s));
+  usbhost_putle16(nth->sequence, priv->ntbseq++);
+
+  /* Payload directly after NTH */
+
+  memcpy(priv->txnetbuf + len, priv->netdev.d_buf, priv->netdev.d_len);
+  len += priv->netdev.d_len;
+
+  /* NDP after payload */
+
+  ndp = (struct usb_cdc_ncm_ndp16_s *)(priv->txnetbuf + len);
+  usbhost_putle16(ndp->next_ndp_index, 0);
+  usbhost_putle32(ndp->signature, 0x00535049);
+  usbhost_putle16(ndp->length, 16); /* NDP + (2 * DPE) */
+
+  /* Fill NDP and block info in NTH */
+
+  usbhost_putle16(nth->ndp_index, len);
+  len += 16;
+  usbhost_putle16(nth->block_length, len);
+
+  /* Fill first DPE */
+
+  dpe = ndp->dpe16;
+  usbhost_putle16(dpe->index, 0x0c);
+  usbhost_putle16(dpe->length, priv->netdev.d_len);
+
+  /* NULL DPE */
+
+  dpe++;
+  usbhost_putle16(dpe->index, 0);
+  usbhost_putle16(dpe->length, 0);
+
+  ret = DRVR_TRANSFER(hport->drvr, priv->bulkout, priv->txnetbuf, len);
+  if (ret < 0)
+    {
+      uerr("transfer returned error: %d\n", ret);
+      return ret;
+    }
+
+  /* If frame is multiple of wMaxPacketSize we must send a ZLP */
+
+  if ((len % priv->bulkmxpacket) == 0)
+    {
+      ret = DRVR_TRANSFER(hport->drvr, priv->bulkout,
+                          priv->txnetbuf, 0);
+      if (ret < 0)
+        {
+          uerr("ERROR: DRVR_TRANSFER for ZLP failed: %d\n", (int)ret);
+        }
+    }
+
+  NETDEV_TXDONE(&priv->netdev);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcmbim_receive
+ *
+ * Description:
+ *   Handle a received packet.
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ ****************************************************************************/
+
+static void cdcmbim_receive(struct usbhost_cdcmbim_s *priv,
+                            uint8_t *buf, size_t len)
+{
+  uinfo("received packet: %d len\n", len);
+
+  net_lock();
+
+  NETDEV_RXPACKETS(&priv->netdev);
+
+  /* Any ACK or other response packet generated by the network stack
+   * will always be shorter than the received packet, therefore it is
+   * safe to pass the received frame buffer directly.
+   */
+
+  priv->netdev.d_buf = buf;
+  priv->netdev.d_len = len;
+
+  switch (((struct ipv4_hdr_s *)buf)->vhl & IP_VERSION_MASK)
+    {
+#ifdef CONFIG_NET_IPv4
+    case IPv4_VERSION:
+      NETDEV_RXIPV4(&priv->netdev);
+      ipv4_input(&priv->netdev);
+
+      if (priv->netdev.d_len > 0)
+        {
+          cdcmbim_transmit(priv);
+        }
+      break;
+#endif
+#ifdef CONFIG_NET_IPv6
+    case IPv6_VERSION:
+      NETDEV_RXIPV6(&priv->netdev);
+      ipv6_input(&priv->netdev);
+
+      if (priv->dev.d_len > 0)
+        {
+          cdcmbim_transmit(priv);
+        }
+      break;
+#endif
+    default:
+      NETDEV_RXERRORS(dev);
+    }
+
+  net_unlock();
+}
+
+static void cdcmbim_txpoll_expiry(int argc, wdparm_t arg, ...)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)arg;
+
+  work_queue(LPWORK, &priv->txpollwork, cdcmbim_txpoll_work, priv, 0);
+}
+
+static void cdcmbim_txpoll_work(void *arg)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)arg;
+
+  net_lock();
+  priv->netdev.d_buf = priv->txpktbuf;
+
+  (void)devif_timer(&priv->netdev, cdcmbim_txpoll);
+
+  /* setup the watchdog poll timer again */
+
+  (void)wd_start(priv->txpoll, (1 * CLK_TCK),
+                 cdcmbim_txpoll_expiry, 1, priv);
+  net_unlock();
+}
+
+/****************************************************************************
+ * Name: cdcmbim_txpoll
+ *
+ * Description:
+ *   The transmitter is available, check if the network has any outgoing
+ *   packets ready to send.  This is a callback from devif_poll().
+ *   devif_poll() may be called:
+ *
+ *   1. When the preceding TX packet send is complete,
+ *   2. When the preceding TX packet send timesout and the interface is reset
+ *   3. During normal TX polling
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static int cdcmbim_txpoll(struct net_driver_s *dev)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)
+                                   dev->d_private;
+
+  /* If the polling resulted in data that should be sent out on the network,
+   * the field d_len is set to a value > 0.
+   */
+
+  DEBUGASSERT(priv->netdev.d_buf == priv->txpktbuf);
+
+  usbhost_takesem(&priv->exclsem);
+
+  if (priv->netdev.d_len > 0)
+    {
+      if (!devif_loopback(&priv->netdev))
+        {
+          /* Send the packet */
+
+          cdcmbim_transmit(priv);
+        }
+    }
+
+  usbhost_givesem(&priv->exclsem);
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: cdcmbim_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the MBIM interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int cdcmbim_ifup(struct net_driver_s *dev)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)
+                                   dev->d_private;
+  struct usbhost_hubport_s *hport = priv->usbclass.hport;
+  int ret;
+
+#ifdef CONFIG_NET_IPv4
+  ninfo("Bringing up: %d.%d.%d.%d\n",
+        dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
+        (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
+#endif
+#ifdef CONFIG_NET_IPv6
+  ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+        dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2],
+        dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5],
+        dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
+#endif
+
+  /* Start RX asynch on bulk in */
+
+  if (priv->bulkin)
+    {
+      ret = DRVR_ASYNCH(hport->drvr, priv->bulkin,
+                        priv->rxnetbuf, CDCMBIM_NETBUF_SIZE,
+                        usbhost_bulkin_callback, priv);
+      if (ret < 0)
+        {
+          uerr("ERROR: DRVR_ASYNCH failed on bulkin: %d\n", ret);
+        }
+    }
+
+  /* Start network TX poll */
+
+  (void)wd_start(priv->txpoll, (1 * CLK_TCK), cdcmbim_txpoll_expiry, 1,
+                 (wdparm_t)priv);
+  priv->bifup = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcmbim_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int cdcmbim_ifdown(struct net_driver_s *dev)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)
+                                   dev->d_private;
+  irqstate_t flags;
+
+  flags = enter_critical_section();
+
+  wd_cancel(priv->txpoll);
+
+  /* Mark the device "down" */
+
+  priv->bifup = false;
+
+  leave_critical_section(flags);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcmbim_txavail_work
+ *
+ * Description:
+ *   Driver callback invoked when new TX data is available.  This is a
+ *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ *   latency.
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called in normal user mode
+ *
+ ****************************************************************************/
+
+static void cdcmbim_txavail_work(void *arg)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)arg;
+
+  net_lock();
+
+  priv->netdev.d_buf = priv->txpktbuf;
+
+  if (priv->bifup)
+    {
+      (void)devif_poll(&priv->netdev, cdcmbim_txpoll);
+    }
+
+  net_unlock();
+}
+
+/****************************************************************************
+ * Name: cdcmbim_txavail
+ *
+ * Description:
+ *   Driver callback invoked when new TX data is available.  This is a
+ *   stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ *   latency.
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   Called from the network stack with the network locked.
+ *
+ ****************************************************************************/
+
+static int cdcmbim_txavail(struct net_driver_s *dev)
+{
+  struct usbhost_cdcmbim_s *priv = (struct usbhost_cdcmbim_s *)
+                                   dev->d_private;
+
+  if (work_available(&priv->txpollwork))
+    {
+      work_queue(LPWORK, &priv->txpollwork, cdcmbim_txavail_work, priv, 0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: usbhost_cdcmbim_initialize
+ *
+ * Description:
+ *   Initialize the USB class driver.  This function should be called
+ *   be platform-specific code in order to initialize and register support
+ *   for the USB host class device.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   On success this function will return zero (OK);  A negated errno value
+ *   will be returned on failure.
+ *
+ ****************************************************************************/
+
+int usbhost_cdcmbim_initialize(void)
+{
+  /* Perform any one-time initialization of the class implementation */
+
+  /* Advertise our availability to support CDC MBIM devices */
+
+  return usbhost_registerclass(&g_cdcmbim);
+}
diff --git a/include/nuttx/net/net.h b/include/nuttx/net/net.h
index 8218c0c..3bb4808 100644
--- a/include/nuttx/net/net.h
+++ b/include/nuttx/net/net.h
@@ -155,7 +155,8 @@ enum net_lltype_e
   NET_LL_BLUETOOTH,    /* Bluetooth */
   NET_LL_IEEE80211,    /* IEEE 802.11 */
   NET_LL_IEEE802154,   /* IEEE 802.15.4 MAC */
-  NET_LL_PKTRADIO      /* Non-standard packet radio */
+  NET_LL_PKTRADIO,     /* Non-standard packet radio */
+  NET_LL_MBIM
 };
 
 /* This defines a bitmap big enough for one bit for each socket option */
diff --git a/include/nuttx/usb/cdc.h b/include/nuttx/usb/cdc.h
index e2b13a1..9030ecf 100644
--- a/include/nuttx/usb/cdc.h
+++ b/include/nuttx/usb/cdc.h
@@ -1,4 +1,4 @@
-/********************************************************************************************
+/*****************************************************************************
  * include/nuttx/usb/cdc.h
  *
  *   Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved.
@@ -34,30 +34,38 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ********************************************************************************************/
+ *****************************************************************************/
 
 #ifndef __INCLUDE_NUTTX_USB_CDC_H
 #define __INCLUDE_NUTTX_USB_CDC_H
 
-/********************************************************************************************
+/*****************************************************************************
  * Included Files
- ********************************************************************************************/
+ *****************************************************************************/
 
 #include <nuttx/config.h>
 
-/********************************************************************************************
+/*****************************************************************************
  * Pre-processor Definitions
- ********************************************************************************************/
-/* Device Class Codes ***********************************************************************/
-/* Table 14: Communication Device Class Code (see definition USB_CLASS_CDC in usb.h) */
-/* Table 18: Data Interface Class Code  (see definition USB_CLASS_CDC_DATA in usb.h) */
+ *****************************************************************************/
+
+/* Device Class Codes ********************************************************/
+
+/* Table 14: Communication Device Class Code (see definition USB_CLASS_CDC in
+ *           usb.h)
+ */
+
+/* Table 18: Data Interface Class Code  (see definition USB_CLASS_CDC_DATA in
+ *           usb.h)
+ */
+
+/* Communication Interface Class Codes ***************************************/
 
-/* Communication Interface Class Codes ******************************************************/
 /* Table 15: Communication Interface Class Code */
 
 #define CDC_CLASS_COMM          0x02 /* Communication Interface Class */
 
-/* Communication Interface Sub-Class Codes **************************************************/
+/* Communication Interface Sub-Class Codes ***********************************/
 
 #define CDC_SUBCLASS_NONE       0x00 /* Reserved */
 #define CDC_SUBCLASS_DLC        0x01 /* Direct Line Control Model */
@@ -67,26 +75,35 @@
 #define CDC_SUBCLASS_CAPI       0x05 /* CAPI Control Model */
 #define CDC_SUBCLASS_ECM        0x06 /* Ethernet Networking Control Model */
 #define CDC_SUBCLASS_ATM        0x07 /* ATM Networking Control Model */
-                                     /* 0x08-0x7f Reserved (future use) */
+                                     /* 0x08-0x0d Reserved (future use) */
+#define CDC_SUBCLASS_MBIM       0x0e /* MBIM Control Model */
+                                     /* 0x0f-0x7f Reserved (future use) */
                                      /* 0x80-0xfe Reserved (vendor specific) */
-/* Communication Interface Class Protocol Codes ********************************************/
+
+/* Communication Interface Class Protocol Codes ******************************/
+
 /* Table 17: Communication Interface Class Control Protocol Codes */
 
 #define CDC_PROTO_NONE          0x00 /* No class specific protocol required */
-#define CDC_PROTO_ATM           0x01 /* Common AT commands (also known as Hayes compatible) */
+#define CDC_PROTO_ATM           0x01 /* Common AT commands (also known as Hayes
+                                      * compatible)
+                                      */
                                      /* 0x02-0xfe Reserved (future use) */
 #define CDC_PROTO_VENDOR        0xff /* Vendor-specific */
 
-/* Data Interface Sub-Class Codes ***********************************************************/
+/* Data Interface Sub-Class Codes ********************************************/
+
 /* None defined, should be zero */
 
 #define CDC_DATA_SUBCLASS_NONE  0x00
 
-/* Date Interface Class Protocol Codes ******************************************************/
+/* Date Interface Class Protocol Codes ***************************************/
+
 /* Table 19: Data Interface Class Protocol Codes */
 
 #define CDC_DATA_PROTO_NONE     0x00 /* No class specific protocol required */
                                      /* 0x01-0x2f Reserved (future use) */
+#define CDC_DATA_PROTO_NTB      0x02 /* Network Transfer Block protocol */
 #define CDC_DATA_PROTO_ISDN     0x30 /* Physical interface protocol for ISDN BRI */
 #define CDC_DATA_PROTO_HDLC     0x31 /* HDLC */
 #define CDC_DATA_PROTO_TRANSP   0x32 /* Transparent */
@@ -107,7 +124,8 @@
                                       */
 #define CDC_DATA_PROTO_VENDOR   0xff /* Vendor-specific */
 
-/* Requests and Notifications ***************************************************************/
+/* Requests and Notifications ************************************************/
+
 /* Table 2: Requests, Direct Line Control Model */
 
 #define DLC_SET_AUX_LINE_STATE  0x10 /* Request to connect or disconnect secondary jack from
@@ -128,6 +146,7 @@
 #define DLC_RING_AUX_JACK       0x15 /* Request for a ring signal to be generated on secondary
                                       * phone jack. (Optional)
                                       */
+
 /* Table 3: Notifications, Direct Line Control Model */
 
 #define DLC_AUX_JACK_HOOK_STATE 0x08 /* Indicates hook state of secondary device plugged
@@ -136,6 +155,7 @@
 #define DLC_RING_DETECT         0x09 /* Message to notify host that ring voltage was
                                       * detected on POTS interface. (Required)
                                       */
+
 /* Table 4: Requests, Abstract Control Model */
 
 #define ACM_SEND_COMMAND        0x00 /* Issues a command in the format of the supported
@@ -164,6 +184,7 @@
                                       */
 #define ACM_SEND_BREAK          0x23 /* Sends special carrier
                                       */
+
 /* Table 5: Notifications, Abstract Control Model */
 
 #define ACM_NETWORK_CONNECTION  0x00 /* Notification to host of network connection status.
@@ -175,6 +196,7 @@
 #define ACM_SERIAL_STATE        0x20 /* Returns the current state of the carrier detect, DSR,
                                       * break, and ring signal. (Optional)
                                       */
+
 /* Table 6: Requests, Telephone Control Model */
 
 #define TCM_SET_COMM_FEATURE    0x02 /* Used to set a unique communication feature, which is
@@ -208,12 +230,14 @@
                                       */
 #define TCM_DIAL_DIGITS         0x36 /* Dials digits on the network connection. (Required)
                                       */
+
 /* Table 7: Notifications, Telephone Control Model */
 
 #define TCM_CALL_STATE_CHANGE   0x28 /* DReports a state change on a call. (Required)
                                       */
 #define TCM_LINE_STATE_CHANGE   0x29 /* DReports a state change on a line. (Optional)
                                       */
+
 /* Table 8: Requests, Multi-Channel Model */
 
 #define MCM_SET_UNIT_PARAM      0x37 /* Used to set a Unit specific parameter (Optional)
@@ -223,11 +247,13 @@
 #define MCM_CLEAR_UNIT_PARAM    0x39 /* Used to set a Unit specific parameter to its default
                                       * state. (Optional)
                                       */
+
 /* Table 9: Request, CAPI Control Model */
 
 #define CAPI_GET_PROFILE        0x3a /* Returns the implemented capabilities of the device
                                       * (Required)
                                       */
+
 /* Table 10: Requests, Ethernet Networking Control Model */
 
 #define ECM_SEND_COMMAND        0x00 /* Issues a command in the format of the supported
@@ -267,6 +293,7 @@
                                       * transmitted, frames received, and bad frames received.
                                       * (Optional)
                                       */
+
 /* Table 11: Notifications, Ethernet Networking Control Model */
 
 #define ECM_NETWORK_CONNECTION  0x00 /* Reports whether or not the physical layer (modem,
@@ -277,6 +304,7 @@
                                       */
 #define ECM_SPEED_CHANGE        0x2a /* Reports a change in upstream or downstream (Required)
                                       */
+
 /* Table 12: Requests, ATM Networking Control Model */
 
 #define ATM_SEND_COMMAND        0x00 /* Issues a command in the format of the supported control
@@ -302,6 +330,7 @@
 #define ATM_GET_VC_STATISTICS   0x53 /* Retrieves statistics from the ATM Networking device for
                                       * a particular VPI/VCI. (Optional)
                                       */
+
 /* Table 13: Requests, Ethernet and ATM Networking Control Model */
 
 #define ATM_NETWORK_CONNECTION  0x00 /* Reports whether or not the physical layer (modem,
@@ -317,7 +346,8 @@
                                       */
 #define ECM_SPEED_CHANGE        ATM_SPEED_CHANGE
 
-/* Descriptors ******************************************************************************/
+/* Descriptors ***************************************************************/
+
 /* Table 25: bDescriptor SubType in Functional Descriptors */
 
 #define CDC_DSUBTYPE_HDR        0x00 /* Header Functional Descriptor, which marks the
@@ -340,6 +370,7 @@
 #define CDC_DSUBTYPE_CAPI       0x0e /* CAPI Control Management Functional Descriptor */
 #define CDC_DSUBTYPE_ECM        0x0f /* Ethernet Networking Functional Descriptor */
 #define CDC_DSUBTYPE_ATM        0x10 /* ATM Networking Functional Descriptor */
+#define CDC_DSUBTYPE_MBIM       0x1b /* MBIM Functional Descriptor */
                                      /* 0x11-0xff Reserved (future use) */
 
 /* Table 42: Ethernet Statistics Capabilities */
@@ -390,6 +421,7 @@
 #define FEATURE_COUNTRY_SETTING 0x02 /* Country code in hexadecimal format as defined in
                                       * ISO 3166
                                       */
+
 /* Table 49: POTS Relay Configuration Values */
 
 #define POTS_ON_HOOK            0x0000
@@ -515,18 +547,22 @@
                                             * been detected with HEC errors in the cell
                                             * header and successfully corrected.
                                             */
+
 /* Table 66: ATM VC Selector Codes */
 
-#define VC_US_CELLS_SENT        0x01 /* The number of cells that have been sent upstream to
-                                      * the WAN link for the specified VPI/VCI since the
-                                      * device has been powered on or reset
+#define VC_US_CELLS_SENT        0x01 /* The number of cells that have been
+                                      * sent upstream to the WAN link for the
+                                      * specified VPI/VCI since the device
+                                      * has been powered on or reset
                                       */
-#define VC_DS_CELLS_RECEIVED    0x02 /* The number of cells that have been received
-                                      * downstream from the WAN link for the specified
-                                      * VPI/VCI since the device has been
-                                      * powered on or reset
+#define VC_DS_CELLS_RECEIVED    0x02 /* The number of cells that have been
+                                      * received downstream from the WAN link
+                                      * for the specified VPI/VCI since the
+                                      * device has been powered on or reset
                                       */
-/* Notifications ****************************************************************************/
+
+/* Notifications *************************************************************/
+
 /* Table 69: UART State Bitmap Values */
 
 #define CDC_UART_RXCARRIER      (1 << 0) /* bRxCarrier State of receiver carrier detection
@@ -554,12 +590,14 @@
 #define CDCACM_UART_DCD          CDC_UART_RXCARRIER
 #define CDCACM_UART_DSR          CDC_UART_TXCARRIER
 
-/* "SerialState is used like a real interrupt status register. Once a notification has been
- *  sent, the device will reset and reevaluate the different signals.  For the consistent
- *  signals like carrier detect or transmission carrier, this will mean another notification
- *  will not be generated until there is a state change.  For the irregular signals like
- *  break, the incoming ring signal, or the overrun error state, this will reset their values
- *  to zero and again will not send another notification until their state changes."
+/* "SerialState is used like a real interrupt status register. Once a
+ *  notification has been sent, the device will reset and reevaluate the
+ *  different signals.  For the consistent signals like carrier detect or
+ *  transmission carrier, this will mean another notification will not be
+ *  generated until there is a state change.  For the irregular signals like
+ *  break, the incoming ring signal, or the overrun error state, this will
+ *  reset their values to zero and again will not send another notification
+ *  until their state changes."
  */
 
 #define CDC_UART_CONSISTENT     (CDC_UART_RXCARRIER | CDC_UART_TXCARRIER)
@@ -583,9 +621,9 @@
 #define CDC_LINEST_OFFHOOK      0x0002 /* Hook-switch has gone off hook */
 #define CDC_LINEST_ONHOOK       0x0003 /* Hook-switch has gone on hook */
 
-/********************************************************************************************
+/*****************************************************************************
  * Public Types
- ********************************************************************************************/
+ *****************************************************************************/
 
 /* Table 1: Data Class Protocol Wrapper */
 
@@ -594,10 +632,13 @@ struct cdc_protowrapper_s
   uint8_t size[2];   /* Size of wrapper in bytes */
   uint8_t dstproto;  /* bDstProtocol, Destination protocol ID */
   uint8_t srcproto;  /* bSrcProtocol, Source protocol ID */
-  uint8_t data[1];   /* Data payload, actual size depends of size of the wrapper */
+  uint8_t data[1];   /* Data payload, actual size depends of size of the
+                      * wrapper
+                      */
 };
 
-/* Functional Descriptors *******************************************************************/
+/* Functional Descriptors ****************************************************/
+
 /* Table 23: Functional Descriptor General Format */
 
 struct cdc_funcdesc_s
@@ -758,14 +799,18 @@ struct cdc_usbterm_funcdesc_s
 struct cdc_netchan_funcdesc_s
 {
   uint8_t size;     /* bFunctionLength, Size of this descriptor */
-  uint8_t type;      /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */
-  uint8_t subtype;   /* bDescriptorSubType, CDC_DSUBTYPE_NETCHAN as defined in Table 25 */
-  uint8_t id;        /* bEntityId, Constant uniquely identifying the Terminal */
-  uint8_t name;      /* iName, Index of string descriptor, describing the name of the Network
-                      * Channel Terminal
-                      */
-  uint8_t index;     /* bChannelIndex, The channel index of the associated network channel */
-  uint8_t phyif;     /* bPhysicalInterface, Type of physical interface */
+  uint8_t type;     /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */
+  uint8_t subtype;  /* bDescriptorSubType, CDC_DSUBTYPE_NETCHAN as defined in
+                     * Table 25 */
+  uint8_t id;       /* bEntityId, Constant uniquely identifying the
+                     * Terminal */
+  uint8_t name;     /* iName, Index of string descriptor, describing the name
+                     * of the Network Channel Terminal
+                     */
+  uint8_t index;    /* bChannelIndex, The channel index of the associated
+                     * network channel
+                     */
+  uint8_t phyif;    /* bPhysicalInterface, Type of physical interface */
 };
 
 #define SIZEOF_NETCHAN_FUNCDESC 7
@@ -827,22 +872,28 @@ struct cdc_capi_funcdesc_s
 
 struct cdc_ecm_funcdesc_s
 {
-  uint8_t size;      /* bFunctionLength, Size of this descriptor */
-  uint8_t type;      /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */
-  uint8_t subtype;   /* bDescriptorSubType, CDC_DSUBTYPE_ECM as defined in Table 25 */
-  uint8_t mac;       /* iMACAddress, Index of the 48bit Ethernet MAC address string descriptor */
-  uint8_t stats[4];  /* bmEthernetStatistics, Indicates which Ethernet statistics functions
-                      * the device collects.  See Table 42.
-                      */
-  uint8_t maxseg[2];   /* wMaxSegmentSize, The maximum segment size that the Ethernet device is
-                      * capable of supporting.
-                      */
-  uint8_t nmcflts[2];  /* wNumberMCFilters, Contains the number of multicast filters that can be
-                      * configured by the host.
-                      */
-  uint8_t  npwrflts; /* bNumberPowerFilters, Contains the number of pattern filters that are
-                      * available for causing wake-up of the host.
-                      */
+  uint8_t size;       /* bFunctionLength, Size of this descriptor */
+  uint8_t type;       /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */
+  uint8_t subtype;    /* bDescriptorSubType, CDC_DSUBTYPE_ECM as defined in
+                       * Table 25.
+                       */
+  uint8_t mac;        /* iMACAddress, Index of the 48bit Ethernet MAC address
+                       * string descriptor.
+                       */
+  uint8_t stats[4];   /* bmEthernetStatistics, Indicates which Ethernet
+                       * statistics functions the device collects.
+                       * See Table 42.
+                       */
+  uint8_t maxseg[2];  /* wMaxSegmentSize, The maximum segment size that the
+                       * Ethernet device is capable of supporting.
+                       */
+  uint8_t nmcflts[2]; /* wNumberMCFilters, Contains the number of multicast
+                       * filters that can be configured by the host.
+                       */
+  uint8_t  npwrflts;  /* bNumberPowerFilters, Contains the number of pattern
+                       * filters that are available for causing wake-up of
+                       * the host.
+                       */
 };
 
 #define SIZEOF_ECM_FUNCDESC 13
@@ -853,26 +904,33 @@ struct cdc_atm_funcdesc_s
 {
   uint8_t size;      /* bFunctionLength, Size of this descriptor */
   uint8_t type;      /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */
-  uint8_t subtype;   /* bDescriptorSubType, CDC_DSUBTYPE_ATM as defined in Table 25 */
-  uint8_t endid;     /* iEndSystemIdentifier, Index of End System Identifier string descriptor */
-  uint8_t datacaps;  /* bmDataCapabilities, The ATM data types the device supports */
-  uint8_t devstats;  /* bmATMDeviceStatistics, Indicates which optional statistics functions the
-                      * device collects.
+  uint8_t subtype;   /* bDescriptorSubType, CDC_DSUBTYPE_ATM as defined in
+                      * Table 25.
+                      */
+  uint8_t endid;     /* iEndSystemIdentifier, Index of End System Identifier
+                      * string descriptor.
                       */
-  uint8_t mxseg2[2]; /* wType2MaxSegmentSize, The maximum segment size that the Type 2 device is
-                      * capable of supporting.
+  uint8_t datacaps;  /* bmDataCapabilities, The ATM data types the device
+                      * supports.
                       */
-  uint8_t mxseg3[2];  /* wType3MaxSegmentSize, The maximum segment size that the Type 3 device is
-                      * capable of supporting
+  uint8_t devstats;  /* bmATMDeviceStatistics, Indicates which optional
+                      * statistics functions the device collects.
                       */
-  uint8_t mxvc[2];    /* wMaxVC, The maximum number of simultaneous virtual circuits the device is
-                      * capable of supporting
+  uint8_t mxseg2[2]; /* wType2MaxSegmentSize, The maximum segment size that
+                      * the Type 2 device is capable of supporting.
+                      */
+  uint8_t mxseg3[2]; /* wType3MaxSegmentSize, The maximum segment size that
+                      * the Type 3 device is capable of supporting
+                      */
+  uint8_t mxvc[2];   /* wMaxVC, The maximum number of simultaneous virtual
+                      * circuits the device is capable of supporting
                       */
 };
 
 #define SIZEOF_ATM_FUNCDESC 12
 
-/* Descriptor Data Structures ***************************************************************/
+/* Descriptor Data Structures ************************************************/
+
 /* Table 50: Line Coding Structure */
 
 struct cdc_linecoding_s
@@ -890,15 +948,15 @@ struct cdc_linecoding_s
 struct cdc_linestatus_s
 {
   uint8_t size[2];   /* wLength, Size of this structure, in bytes */
-  uint8_t ringer[4]; /* dwRingerBitmap, Ringer Configuration bitmap for this line */
+  uint8_t ringer[4]; /* dwRingerBitmap, Ringer Conf bitmap for this line */
   uint8_t line[4];   /* dwLineState, Defines current state of the line */
-  uint32_t call[1];  /* dwCallStateN, Defines current state of call N on the line */
+  uint32_t call[1];  /* dwCallStateN, Current state of call N on the line */
 };
 
-/* Messages are formatted as a standardized 8-byte header, followed by a variable-length
- * data field. The header identifies the kind of notification, and the interface associated
- * with the notification; it also indicates the length of the variable length portion of
- * the message
+/* Messages are formatted as a standardized 8-byte header, followed by a
+ * variable-length data field. The header identifies the kind of notification,
+ * and the interface associated with the notification; it also indicates the
+ * length of the variable length portion of the message
  */
 
 struct cdc_notification_s
@@ -918,12 +976,15 @@ struct cdc_notification_s
 struct cdc_unitparm_s
 {
   uint8_t id;        /* bEntityId, Unit ID */
-  uint8_t index;     /* bParameterIndex, A zero based value indicating Unit parameter index */
+  uint8_t index;     /* bParameterIndex, A zero based value indicating Unit
+                      * parameter index
+                      */
 };
 
 /* Table 61: Power Management Pattern Filter Structure */
 
-/* Notification Data Structures *************************************************************/
+/* Notification Data Structures **********************************************/
+
 /* Table 72: ConnectionSpeedChange Data Structure */
 
 struct cdc_speedchange_s
diff --git a/net/netdev/netdev_register.c b/net/netdev/netdev_register.c
index 85483dc..d8ef03f 100644
--- a/net/netdev/netdev_register.c
+++ b/net/netdev/netdev_register.c
@@ -55,6 +55,7 @@
 #define NETDEV_PAN_FORMAT   "pan%d"
 #define NETDEV_WLAN_FORMAT  "wlan%d"
 #define NETDEV_WPAN_FORMAT  "wpan%d"
+#define NETDEV_MBIM_FORMAT  "wwan%d"
 
 #if defined(CONFIG_DRIVERS_IEEE80211) /* Usually also has CONFIG_NET_ETHERNET */
 #  define NETDEV_DEFAULT_FORMAT NETDEV_WLAN_FORMAT
@@ -313,6 +314,11 @@ int netdev_register(FAR struct net_driver_s *dev, enum net_lltype_e lltype)
             devfmt   = NETDEV_TUN_FORMAT;
             break;
 #endif
+        case NET_LL_MBIM:
+          dev->d_llhdrlen = 0;
+          dev->d_pktsize = 1200;
+          devfmt = NETDEV_MBIM_FORMAT;
+          break;
 
           default:
             nerr("ERROR: Unrecognized link type: %d\n", lltype);


[incubator-nuttx] 06/06: Fix wrong space instead of TAB

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 089a633c76fa23316d3cb41b98598b7f0c23d819
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Sun Jun 14 21:08:20 2020 -0300

    Fix wrong space instead of TAB
---
 net/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/Kconfig b/net/Kconfig
index 0240f1c..bedf933 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -151,7 +151,7 @@ config NET_LOOPBACK_PKTSIZE
 		packet size will be used by loopback driver.
 
 menuconfig NET_MBIM
-        bool "MBIM modem support"
+	bool "MBIM modem support"
 	depends on USBHOST_CDCMBIM
 	default n