diff --git a/boards/sim/sim/sim/configs/usbdev/defconfig b/boards/sim/sim/sim/configs/usbdev/defconfig index a009d80ffe..76f0e07598 100644 --- a/boards/sim/sim/sim/configs/usbdev/defconfig +++ b/boards/sim/sim/sim/configs/usbdev/defconfig @@ -57,6 +57,7 @@ CONFIG_NETUTILS_TELNETD=y CONFIG_NET_BINDTODEVICE=y CONFIG_NET_BROADCAST=y CONFIG_NET_CDCECM=y +CONFIG_NET_CDCMBIM=y CONFIG_NET_CDCNCM=y CONFIG_NET_ETH_PKTSIZE=1518 CONFIG_NET_ICMP_SOCKET=y @@ -71,6 +72,7 @@ CONFIG_NET_IPFORWARD_NSTRUCT=100 CONFIG_NET_IPv6=y CONFIG_NET_MAX_RECV_BUFSIZE=65535 CONFIG_NET_MAX_SEND_BUFSIZE=65535 +CONFIG_NET_MBIM=y CONFIG_NET_NAT=y CONFIG_NET_RECV_BUFSIZE=16384 CONFIG_NET_SEND_BUFSIZE=16384 diff --git a/boards/sim/sim/sim/src/sim_composite.c b/boards/sim/sim/sim/src/sim_composite.c index 8eb8868775..85563ee634 100644 --- a/boards/sim/sim/sim/src/sim_composite.c +++ b/boards/sim/sim/sim/src/sim_composite.c @@ -258,6 +258,53 @@ static void *board_composite2_connect(int port) return composite_initialize(composite_getdevdescs(), dev, dev_idx); } +/**************************************************************************** + * Name: board_composite3_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 3. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static void *board_composite3_connect(int port) +{ + struct composite_devdesc_s dev[1]; + int dev_idx = 0; + +#ifdef CONFIG_NET_CDCMBIM + /* Configure the CDC/NCM device */ + + cdcmbim_get_composite_devdesc(&dev[dev_idx]); + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = 0; + dev[dev_idx].minor = 0; + + /* Strings */ + + dev[dev_idx].devinfo.strbase = COMPOSITE_NSTRIDS - 1; + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[CDCNCM_EP_INTIN_IDX] = 5; + dev[dev_idx].devinfo.epno[CDCNCM_EP_BULKIN_IDX] = 6; + dev[dev_idx].devinfo.epno[CDCNCM_EP_BULKOUT_IDX] = 7; + + dev_idx += 1; +#endif + + return composite_initialize(composite_getdevdescs(), dev, dev_idx); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -303,10 +350,14 @@ void *board_composite_connect(int port, int configid) { return board_composite1_connect(port); } - else + else if (configid == 2) { return board_composite2_connect(port); } + else + { + return board_composite3_connect(port); + } } #endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/drivers/usbdev/Kconfig b/drivers/usbdev/Kconfig index 20d2751303..1573f47653 100644 --- a/drivers/usbdev/Kconfig +++ b/drivers/usbdev/Kconfig @@ -1248,6 +1248,16 @@ menuconfig NET_CDCNCM if NET_CDCNCM +config NET_CDCMBIM + bool "CDC-MBIM Ethernet-over-USB" + default n + ---help--- + This option may require CONFIG_NETDEV_LATEINIT=y, otherwise the + power-up initialization may call the non-existent xxx_netinitialize(). + This option is not automatically selected because it may be that + you have an additional network device that requires the early + xxx_netinitialize() call. + menuconfig CDCNCM_COMPOSITE bool "CDC/NCM composite support" default n @@ -1385,9 +1395,17 @@ config CDCNCM_VENDORSTR default "NuttX" config CDCNCM_PRODUCTSTR - string "Product string" + string "CDCNCM Product string" default "CDC/NCM Ethernet" +if NET_CDCMBIM + +config CDCMBIM_PRODUCTSTR + string "CDCMBIM Product string" + default "CDC/MBIM Ethernet" + +endif # NET_CDCMBIM + endif # !CDCNCM_COMPOSITE config CDCNCM_QUOTA_TX diff --git a/drivers/usbdev/cdcncm.c b/drivers/usbdev/cdcncm.c index a7646d36fe..959a54c4d4 100644 --- a/drivers/usbdev/cdcncm.c +++ b/drivers/usbdev/cdcncm.c @@ -32,18 +32,14 @@ #include #include #include +#include #include -#include -#include -#include +#include -#include #include #include #include -#include #include -#include #ifdef CONFIG_BOARD_USBDEV_SERIALSTR # include @@ -95,6 +91,9 @@ #define CDC_NCM_NDP16_NOCRC_SIGN 0x304D434E /* NCM0 */ #define CDC_NCM_NDP32_NOCRC_SIGN 0x306D636E /* ncm0 */ +#define CDC_MBIM_NDP16_NOCRC_SIGN 0x00535049 /* IPS : IPS0 for now */ +#define CDC_MBIM_NDP32_NOCRC_SIGN 0x00737069 /* ips : ips0 for now */ + #define INIT_NDP16_OPTS { \ .nthsign = CDC_NCM_NTH16_SIGN, \ .ndpsign = CDC_NCM_NDP16_NOCRC_SIGN, \ @@ -125,11 +124,25 @@ .nextndpindex = 4, \ } -#define CDC_NCM_NCAP_ETH_FILTER (1 << 0) -#define NCAPS (CDC_NCM_NCAP_ETH_FILTER) +#define CDC_NCM_NCAP_ETH_FILTER (1 << 0) +#define NCAPS (CDC_NCM_NCAP_ETH_FILTER) -#define NCM_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) -#define NCM_ALIGN(x, a) NCM_ALIGN_MASK((x), ((typeof(x))(a) - 1)) +#define NCM_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define NCM_ALIGN(x, a) NCM_ALIGN_MASK((x), ((typeof(x))(a) - 1)) + +#define CDC_MBIM_DEVFORMAT "/dev/cdc-wdm%d" +#define CDC_MBIM_DEVNAMELEN 16 +#define CDC_MBIM_NPOLLWAITERS 2 + +#define CDCMBIM_MAX_CTRL_MESSAGE 0x1000 + +#ifndef CONFIG_NET_CDCMBIM +# define cdcmbim_mkcfgdesc cdcncm_mkcfgdesc +# define cdcmbim_mkstrdesc cdcncm_mkstrdesc +# define cdcmbim_classobject cdcncm_classobject +# define cdcmbim_uninitialize cdcncm_uninitialize +# define CONFIG_CDCMBIM_PRODUCTSTR CONFIG_CDCNCM_PRODUCTSTR +#endif /**************************************************************************** * Private Types @@ -279,51 +292,77 @@ begin_packed_struct struct usb_cdc_ncm_ntb_parameters_s struct cdcncm_driver_s { - /* USB CDC-ECM device */ + /* USB CDC-NCM device */ - struct usbdevclass_driver_s usbdev; /* USB device class vtable */ - struct usbdev_devinfo_s devinfo; - FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ - FAR struct usbdev_req_s *notifyreq; /* Allocated norify request */ - FAR struct usbdev_ep_s *epint; /* Interrupt IN endpoint */ - FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint */ - FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint */ - uint8_t config; /* Selected configuration number */ + struct usbdevclass_driver_s usbdev; /* USB device class vtable */ + struct usbdev_devinfo_s devinfo; + FAR struct usbdev_req_s *ctrlreq; /* Allocated control request */ + FAR struct usbdev_req_s *notifyreq; /* Allocated norify request */ + FAR struct usbdev_ep_s *epint; /* Interrupt IN endpoint */ + FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint */ + FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint */ + uint8_t config; /* Selected configuration number */ - FAR struct usbdev_req_s *rdreq; /* Single read request */ - bool rxpending; /* Packet available in rdreq */ + FAR struct usbdev_req_s *rdreq; /* Single read request */ + bool rxpending; /* Packet available in rdreq */ - FAR struct usbdev_req_s *wrreq; /* Single write request */ - sem_t wrreq_idle; /* Is the wrreq available? */ - bool txdone; /* Did a write request complete? */ - enum ncm_notify_state_e notify; /* State of notify */ + FAR struct usbdev_req_s *wrreq; /* Single write request */ + sem_t wrreq_idle; /* Is the wrreq available? */ + bool txdone; /* Did a write request complete? */ + enum ncm_notify_state_e notify; /* State of notify */ FAR const struct ndp_parser_opts_s - *parseropts; /* Options currently used to parse NTB */ - uint32_t ndpsign; /* NDP signature */ - int dgramcount; /* The current tx cache dgram count */ - FAR uint8_t *dgramaddr; /* The next tx cache dgram address */ + *parseropts; /* Options currently used to parse NTB */ + uint32_t ndpsign; /* NDP signature */ + int dgramcount; /* The current tx cache dgram count */ + FAR uint8_t *dgramaddr; /* The next tx cache dgram address */ + bool isncm; /* true:NCM false:MBIM */ /* Network device */ - bool bifup; /* true:ifup false:ifdown */ - struct work_s irqwork; /* For deferring interrupt work - * to the work queue */ - struct work_s notifywork; /* For deferring notify work - * to the work queue */ - struct work_s delaywork; /* For deferring tx work - * to the work queue */ + bool bifup; /* true:ifup false:ifdown */ + struct work_s irqwork; /* For deferring interrupt work + * to the work queue */ + struct work_s notifywork; /* For deferring notify work + * to the work queue */ + struct work_s delaywork; /* For deferring tx work + * to the work queue */ /* This holds the information visible to the NuttX network */ - struct netdev_lowerhalf_s dev; /* Interface understood by the - * network */ - netpkt_queue_t rx_queue; /* RX packet queue */ + struct netdev_lowerhalf_s dev; /* Interface understood by the + * network */ + netpkt_queue_t rx_queue; /* RX packet queue */ +}; + +/* The cdcmbim_driver_s encapsulates all state information for a single + * hardware interface + */ + +struct cdcmbim_driver_s +{ + struct cdcncm_driver_s ncmdriver; /* CDC/NCM driver structure, must keep first */ + mutex_t lock; /* Used to maintain mutual exclusive access */ + sem_t read_sem; /* Used to wait for data to be readable */ + FAR struct pollfd *fds[CDC_MBIM_NPOLLWAITERS]; + struct iob_queue_s rx_queue; /* RX control message queue */ + struct iob_queue_s tx_queue; /* TX control message queue */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ +/* Control interface driver methods */ + +#ifdef CONFIG_NET_CDCMBIM +static ssize_t cdcmbim_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t cdcmbim_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int cdcmbim_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup); +#endif + /* Network Device ***********************************************************/ /* Interrupt handling */ @@ -400,8 +439,25 @@ static const struct usbdevclass_driverops_s g_usbdevops = NULL }; +/* File operations for control channel */ + +#ifdef CONFIG_NET_CDCMBIM +static const struct file_operations g_usbdevfops = +{ + NULL, /* open */ + NULL, /* close */ + cdcmbim_read, /* read */ + cdcmbim_write, /* write */ + NULL, /* seek */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* truncate */ + cdcmbim_poll /* poll */ +}; +#endif + #ifndef CONFIG_CDCNCM_COMPOSITE -static const struct usb_devdesc_s g_devdesc = +static const struct usb_devdesc_s g_ncmdevdesc = { USB_SIZEOF_DEVDESC, USB_DESC_TYPE_DEVICE, @@ -425,12 +481,43 @@ static const struct usb_devdesc_s g_devdesc = LSBYTE(CDCECM_VERSIONNO), MSBYTE(CDCECM_VERSIONNO) }, - CDCNCM_MANUFACTURERSTRID, - CDCNCM_PRODUCTSTRID, - CDCNCM_SERIALSTRID, + CDCECM_MANUFACTURERSTRID, + CDCECM_PRODUCTSTRID, + CDCECM_SERIALSTRID, CDCECM_NCONFIGS }; -#endif +# ifdef CONFIG_NET_CDCMBIM +static const struct usb_devdesc_s g_mbimdevdesc = +{ + USB_SIZEOF_DEVDESC, + USB_DESC_TYPE_DEVICE, + { + LSBYTE(0x0200), + MSBYTE(0x0200) + }, + USB_CLASS_CDC, + CDC_SUBCLASS_MBIM, + CDC_PROTO_NONE, + CONFIG_CDCNCM_EP0MAXPACKET, + { + LSBYTE(CONFIG_CDCNCM_VENDORID), + MSBYTE(CONFIG_CDCNCM_VENDORID) + }, + { + LSBYTE(CONFIG_CDCNCM_PRODUCTID), + MSBYTE(CONFIG_CDCNCM_PRODUCTID) + }, + { + LSBYTE(CDCECM_VERSIONNO), + MSBYTE(CDCECM_VERSIONNO) + }, + CDCECM_MANUFACTURERSTRID, + CDCECM_PRODUCTSTRID, + CDCECM_SERIALSTRID, + CDCECM_NCONFIGS +}; +# endif /* CONFIG_NET_CDCMBIM */ +#endif /* CONFIG_CDCNCM_COMPOSITE */ static const struct ndp_parser_opts_s g_ndp16_opts = INIT_NDP16_OPTS; static const struct ndp_parser_opts_s g_ndp32_opts = INIT_NDP32_OPTS; @@ -544,6 +631,184 @@ void cdcncm_put(FAR uint8_t **address, size_t size, uint32_t value) * Private Functions ****************************************************************************/ +/**************************************************************************** + * File operations for control channel + ****************************************************************************/ + +#ifdef CONFIG_NET_CDCMBIM +static ssize_t cdcmbim_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode; + FAR struct cdcmbim_driver_s *self; + FAR struct iob_s *iob; + ssize_t ret; + + inode = filep->f_inode; + self = inode->i_private; + + for (; ; ) + { + nxmutex_lock(&self->lock); + if ((iob = iob_peek_queue(&self->rx_queue)) != NULL) + { + ret = iob_copyout((FAR uint8_t *)buffer, iob, buflen, 0); + if (ret == iob->io_pktlen) + { + iob_remove_queue(&self->rx_queue); + iob_free_chain(iob); + } + else if (ret > 0) + { + iob_trimhead_queue(&self->rx_queue, ret); + } + + break; + } + else + { + if (filep->f_oflags & O_NONBLOCK) + { + ret = -EAGAIN; + break; + } + + nxmutex_unlock(&self->lock); + nxsem_wait(&self->read_sem); + } + } + + nxmutex_unlock(&self->lock); + return ret; +} + +static ssize_t cdcmbim_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct inode *inode; + FAR struct cdcmbim_driver_s *self; + FAR struct iob_s *iob; + int ret; + + inode = filep->f_inode; + self = inode->i_private; + + if (buflen > CDCMBIM_MAX_CTRL_MESSAGE) + { + buflen = CDCMBIM_MAX_CTRL_MESSAGE; + } + + nxmutex_lock(&self->lock); + + iob = iob_tryalloc(true); + if (iob == NULL) + { + ret = -ENOMEM; + goto errout; + } + + ret = iob_copyin(iob, (FAR uint8_t *)buffer, buflen, 0, true); + if (ret < 0) + { + iob_free_chain(iob); + uerr("CDCMBIM copyin failed: %d\n", ret); + goto errout; + } + + ret = iob_tryadd_queue(iob, &self->tx_queue); + if (ret < 0) + { + iob_free_chain(iob); + uerr("CDCMBIM add tx queue failed: %d\n", ret); + goto errout; + } + + uinfo("wrote %zd bytes\n", buflen); + +errout: + nxmutex_unlock(&self->lock); + return ret < 0 ? ret : buflen; +} + +/**************************************************************************** + * Name: usbhost_poll + * + * Description: + * Standard character driver poll method. + * + ****************************************************************************/ + +static int cdcmbim_poll(FAR struct file *filep, FAR struct pollfd *fds, + bool setup) +{ + FAR struct inode *inode; + FAR struct cdcmbim_driver_s *self; + int ret = OK; + int i; + + DEBUGASSERT(fds); + inode = filep->f_inode; + self = inode->i_private; + + /* Make sure that we have exclusive access to the private data structure */ + + DEBUGASSERT(self); + nxmutex_lock(&self->lock); + if (setup) + { + /* This is a request to set up the poll. Find an available slot for + * the poll structure reference + */ + + for (i = 0; i < CDC_MBIM_NPOLLWAITERS; i++) + { + /* Find an available slot */ + + if (!self->fds[i]) + { + /* Bind the poll structure and this slot */ + + self->fds[i] = fds; + fds->priv = &self->fds[i]; + break; + } + } + + if (i >= CDC_MBIM_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 (iob_get_queue_entry_count(&self->rx_queue)) + { + poll_notify(&fds, 1, POLLIN); + } + } + else + { + /* This is a request to tear down the poll. */ + + FAR struct pollfd **slot = (FAR struct pollfd **)fds->priv; + DEBUGASSERT(slot); + + /* Remove all memory of the poll setup */ + + *slot = NULL; + fds->priv = NULL; + } + +errout: + nxmutex_unlock(&self->lock); + return ret; +} +#endif + /**************************************************************************** * Name: cdcncm_transmit_format * @@ -913,6 +1178,8 @@ static void cdcncm_interrupt_work(FAR void *arg) } } +/* NuttX netdev callback functions */ + /**************************************************************************** * Name: cdcncm_ifup * @@ -1257,7 +1524,8 @@ static void cdcncm_resetconfig(FAR struct cdcncm_driver_s *self) } self->parseropts = &g_ndp16_opts; - self->ndpsign = self->parseropts->ndpsign; + self->ndpsign = self->isncm ? self->parseropts->ndpsign : + CDC_MBIM_NDP16_NOCRC_SIGN; self->notify = NCM_NOTIFY_NONE; } @@ -1472,14 +1740,15 @@ static int cdcncm_setinterface(FAR struct cdcncm_driver_s *self, } /**************************************************************************** - * Name: cdcncm_mkstrdesc + * Name: cdcnm_mkstrdesc * * Description: * Construct a string descriptor * ****************************************************************************/ -static int cdcncm_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) +static int cdcnm_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc, + bool isncm) { FAR uint8_t *data = (FAR uint8_t *)(strdesc + 1); FAR const char *str; @@ -1496,20 +1765,20 @@ static int cdcncm_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) strdesc->len = 4; strdesc->type = USB_DESC_TYPE_STRING; - data[0] = LSBYTE(CDCNCM_STR_LANGUAGE); - data[1] = MSBYTE(CDCNCM_STR_LANGUAGE); + data[0] = LSBYTE(CDCECM_STR_LANGUAGE); + data[1] = MSBYTE(CDCECM_STR_LANGUAGE); return 4; } - case CDCNCM_MANUFACTURERSTRID: + case CDCECM_MANUFACTURERSTRID: str = CONFIG_CDCNCM_VENDORSTR; break; - case CDCNCM_PRODUCTSTRID: - str = CONFIG_CDCNCM_PRODUCTSTR; + case CDCECM_PRODUCTSTRID: + str = isncm ? CONFIG_CDCNCM_PRODUCTSTR : CONFIG_CDCMBIM_PRODUCTSTR; break; - case CDCNCM_SERIALSTRID: + case CDCECM_SERIALSTRID: #ifdef CONFIG_BOARD_USBDEV_SERIALSTR str = board_usbdev_serialstr(); #else @@ -1517,7 +1786,7 @@ static int cdcncm_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) #endif break; - case CDCNCM_CONFIGSTRID: + case CDCECM_CONFIGSTRID: str = "Default"; break; #endif @@ -1552,6 +1821,34 @@ static int cdcncm_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) return strdesc->len; } +/**************************************************************************** + * Name: cdcncm_mkstrdesc + * + * Description: + * Construct a string descriptor + * + ****************************************************************************/ + +static int cdcncm_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) +{ + return cdcnm_mkstrdesc(id, strdesc, true); +} + +/**************************************************************************** + * Name: cdcmbim_mkstrdesc + * + * Description: + * Construct a string descriptor + * + ****************************************************************************/ + +#ifdef CONFIG_NET_CDCMBIM +static int cdcmbim_mkstrdesc(uint8_t id, FAR struct usb_strdesc_s *strdesc) +{ + return cdcnm_mkstrdesc(id, strdesc, false); +} +#endif + /**************************************************************************** * Name: cdcncm_mkepdesc * @@ -1623,7 +1920,7 @@ static void cdcncm_mkepdesc(int epidx, FAR struct usb_epdesc_s *epdesc, } /**************************************************************************** - * Name: cdcncm_mkcfgdesc + * Name: cdcnm_mkcfgdesc * * Description: * Construct the config descriptor @@ -1631,12 +1928,13 @@ static void cdcncm_mkepdesc(int epidx, FAR struct usb_epdesc_s *epdesc, ****************************************************************************/ #ifdef CONFIG_USBDEV_DUALSPEED -static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, - FAR struct usbdev_devinfo_s *devinfo, - uint8_t speed, uint8_t type) +static int16_t cdcnm_mkcfgdesc(FAR uint8_t *desc, + FAR struct usbdev_devinfo_s *devinfo, + uint8_t speed, uint8_t type, bool isncm) #else -static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, - FAR struct usbdev_devinfo_s *devinfo) +static int16_t cdcnm_mkcfgdesc(FAR uint8_t *desc, + FAR struct usbdev_devinfo_s *devinfo, + bool isncm) #endif { FAR struct usb_cfgdesc_s *cfgdesc = NULL; @@ -1662,9 +1960,9 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, cfgdesc->type = USB_DESC_TYPE_CONFIG; cfgdesc->ninterfaces = CDCECM_NINTERFACES; cfgdesc->cfgvalue = CDCECM_CONFIGID; - cfgdesc->icfg = devinfo->strbase + CDCNCM_CONFIGSTRID; - cfgdesc->attr = USB_CONFIG_ATTR_ONE | CDCNCM_SELFPOWERED | - CDCNCM_REMOTEWAKEUP; + cfgdesc->icfg = devinfo->strbase + CDCECM_CONFIGSTRID; + cfgdesc->attr = USB_CONFIG_ATTR_ONE | CDCECM_SELFPOWERED | + CDCECM_REMOTEWAKEUP; cfgdesc->mxpower = (CONFIG_USBDEV_MAXPOWER + 1) / 2; desc += USB_SIZEOF_CFGDESC; @@ -1686,7 +1984,8 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, iaddesc->firstif = devinfo->ifnobase; /* Number of first interface of the function */ iaddesc->nifs = devinfo->ninterfaces; /* Number of interfaces associated with the function */ iaddesc->classid = USB_CLASS_CDC; /* Class code */ - iaddesc->subclass = CDC_SUBCLASS_NCM; /* Sub-class code */ + iaddesc->subclass = isncm ? CDC_SUBCLASS_NCM : + CDC_SUBCLASS_MBIM; /* Sub-class code */ iaddesc->protocol = CDC_PROTO_NONE; /* Protocol code */ iaddesc->ifunction = 0; /* Index to string identifying the function */ @@ -1709,7 +2008,7 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, ifdesc->alt = 0; ifdesc->neps = 1; ifdesc->classid = USB_CLASS_CDC; - ifdesc->subclass = CDC_SUBCLASS_NCM; + ifdesc->subclass = isncm ? CDC_SUBCLASS_NCM : CDC_SUBCLASS_MBIM; ifdesc->protocol = CDC_PROTO_NONE; ifdesc->iif = 0; @@ -1774,22 +2073,48 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, len += SIZEOF_ECM_FUNCDESC; - if (desc) + if (isncm) { - FAR struct cdc_ncm_funcdesc_s *ncmdesc; + if (desc) + { + FAR struct cdc_ncm_funcdesc_s *ncmdesc; - ncmdesc = (FAR struct cdc_ncm_funcdesc_s *)desc; - ncmdesc->size = SIZEOF_NCM_FUNCDESC; - ncmdesc->type = USB_DESC_TYPE_CSINTERFACE; - ncmdesc->subtype = CDC_DSUBTYPE_NCM; - ncmdesc->version[0] = LSBYTE(CDCECM_VERSIONNO); - ncmdesc->version[1] = MSBYTE(CDCECM_VERSIONNO); - ncmdesc->netcaps = NCAPS; + ncmdesc = (FAR struct cdc_ncm_funcdesc_s *)desc; + ncmdesc->size = SIZEOF_NCM_FUNCDESC; + ncmdesc->type = USB_DESC_TYPE_CSINTERFACE; + ncmdesc->subtype = CDC_DSUBTYPE_NCM; + ncmdesc->version[0] = LSBYTE(CDCECM_VERSIONNO); + ncmdesc->version[1] = MSBYTE(CDCECM_VERSIONNO); + ncmdesc->netcaps = NCAPS; + desc += SIZEOF_NCM_FUNCDESC; + } - desc += SIZEOF_NCM_FUNCDESC; + len += SIZEOF_NCM_FUNCDESC; } + else + { + if (desc) + { + FAR struct cdc_mbim_funcdesc_s *mbimdesc; - len += SIZEOF_NCM_FUNCDESC; + mbimdesc = (FAR struct cdc_mbim_funcdesc_s *)desc; + mbimdesc->size = SIZEOF_MBIM_FUNCDESC; + mbimdesc->type = USB_DESC_TYPE_CSINTERFACE; + mbimdesc->subtype = CDC_DSUBTYPE_MBIM; + mbimdesc->version[0] = LSBYTE(CDCECM_VERSIONNO); + mbimdesc->version[1] = MSBYTE(CDCECM_VERSIONNO); + mbimdesc->maxctrlmsg[0] = LSBYTE(CDCMBIM_MAX_CTRL_MESSAGE); + mbimdesc->maxctrlmsg[1] = MSBYTE(CDCMBIM_MAX_CTRL_MESSAGE); + mbimdesc->numfilter = 0x20; + mbimdesc->maxfiltersize = 0x80; + mbimdesc->maxsegmentsize[0] = LSBYTE(0x800); + mbimdesc->maxsegmentsize[1] = LSBYTE(0x800); + mbimdesc->netcaps = 0x20; + desc += SIZEOF_MBIM_FUNCDESC; + } + + len += SIZEOF_MBIM_FUNCDESC; + } if (desc) { @@ -1815,7 +2140,8 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, ifdesc->neps = 0; ifdesc->classid = USB_CLASS_CDC_DATA; ifdesc->subclass = 0; - ifdesc->protocol = CDC_DATA_PROTO_NCMNTB; + ifdesc->protocol = isncm ? CDC_DATA_PROTO_NCMNTB : + CDC_DATA_PROTO_MBIMNTB; ifdesc->iif = 0; desc += USB_SIZEOF_IFDESC; @@ -1835,7 +2161,8 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, ifdesc->neps = 2; ifdesc->classid = USB_CLASS_CDC_DATA; ifdesc->subclass = 0; - ifdesc->protocol = CDC_DATA_PROTO_NCMNTB; + ifdesc->protocol = isncm ? CDC_DATA_PROTO_NCMNTB : + CDC_DATA_PROTO_MBIMNTB; ifdesc->iif = 0; desc += USB_SIZEOF_IFDESC; @@ -1873,11 +2200,51 @@ static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, return len; } +/**************************************************************************** + * Name: cdcncm_mkcfgdesc + * + * Description: + * Construct the config descriptor + * + ****************************************************************************/ + +#ifdef CONFIG_USBDEV_DUALSPEED +static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, + FAR struct usbdev_devinfo_s *devinfo, + uint8_t speed, uint8_t type) +{ + return cdcnm_mkcfgdesc(desc, devinfo, speed, type, true); +} + +# ifdef CONFIG_NET_CDCMBIM +static int16_t cdcmbim_mkcfgdesc(FAR uint8_t *desc, + FAR struct usbdev_devinfo_s *devinfo, + uint8_t speed, uint8_t type) +{ + return cdcnm_mkcfgdesc(desc, devinfo, speed, type, false); +} +# endif +#else +static int16_t cdcncm_mkcfgdesc(FAR uint8_t *desc, + FAR struct usbdev_devinfo_s *devinfo) +{ + return cdcnm_mkcfgdesc(desc, devinfo, true); +} + +# ifdef CONFIG_NET_CDCMBIM +static int16_t cdcmbim_mkcfgdesc(FAR uint8_t *desc, + FAR struct usbdev_devinfo_s *devinfo) +{ + return cdcnm_mkcfgdesc(desc, devinfo, false); +} +# endif +#endif + /**************************************************************************** * Name: cdcncm_getdescriptor * * Description: - * Copy the USB CDC-ECM Device USB Descriptor of a given Type and a given + * Copy the USB CDC-NCM Device USB Descriptor of a given Type and a given * Index into the provided Descriptor Buffer. * * Input Parameter: @@ -1900,10 +2267,18 @@ static int cdcncm_getdescriptor(FAR struct cdcncm_driver_s *self, { #ifndef CONFIG_CDCNCM_COMPOSITE case USB_DESC_TYPE_DEVICE: - { - memcpy(desc, &g_devdesc, sizeof(g_devdesc)); - return (int)sizeof(g_devdesc); - } + if (self->isncm) + { + memcpy(desc, &g_ncmdevdesc, sizeof(g_ncmdevdesc)); + return sizeof(g_ncmdevdesc); + } +# ifdef CONFIG_NET_CDCMBIM + else + { + memcpy(desc, &g_mbimdevdesc, sizeof(g_mbimdevdesc)); + return sizeof(g_mbimdevdesc); + } +# endif break; #endif @@ -1911,21 +2286,15 @@ static int cdcncm_getdescriptor(FAR struct cdcncm_driver_s *self, case USB_DESC_TYPE_OTHERSPEEDCONFIG: #endif /* CONFIG_USBDEV_DUALSPEED */ case USB_DESC_TYPE_CONFIG: - { #ifdef CONFIG_USBDEV_DUALSPEED - return cdcncm_mkcfgdesc((FAR uint8_t *)desc, &self->devinfo, - self->usbdev.speed, type); + return cdcncm_mkcfgdesc((FAR uint8_t *)desc, &self->devinfo, + self->usbdev.speed, type); #else - return cdcncm_mkcfgdesc((FAR uint8_t *)desc, &self->devinfo); + return cdcncm_mkcfgdesc((FAR uint8_t *)desc, &self->devinfo); #endif - } - break; case USB_DESC_TYPE_STRING: - { - return cdcncm_mkstrdesc(index, (FAR struct usb_strdesc_s *)desc); - } - break; + return cdcncm_mkstrdesc(index, (FAR struct usb_strdesc_s *)desc); default: uerr("Unsupported descriptor type: 0x%02hhx\n", type); @@ -2145,8 +2514,7 @@ static void cdcncm_unbind(FAR struct usbdevclass_driver_s *driver, static int cdcncm_setup(FAR struct usbdevclass_driver_s *driver, FAR struct usbdev_s *dev, FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, - size_t outlen) + FAR uint8_t *dataout, size_t outlen) { FAR struct cdcncm_driver_s *self = (FAR struct cdcncm_driver_s *)driver; uint16_t value = GETUINT16(ctrl->value); @@ -2227,7 +2595,6 @@ static int cdcncm_setup(FAR struct usbdevclass_driver_s *driver, default: break; } - break; case NCM_GET_NTB_INPUT_SIZE: @@ -2239,11 +2606,63 @@ static int cdcncm_setup(FAR struct usbdevclass_driver_s *driver, if (len == 4 && value == 0) { uinfo("NCM_SET_NTB_INPUT_SIZE len %d NTB input size %d\n", - len, *(int *)dataout); + len, *(FAR int *)dataout); ret = 0; } break; +#ifdef CONFIG_NET_CDCMBIM + case MBIM_SEND_COMMAND: + { + FAR struct cdcmbim_driver_s *mbim = + (FAR struct cdcmbim_driver_s *)self; + FAR struct iob_s *iob = iob_tryalloc(true); + + if (iob == NULL) + { + return -ENOMEM; + } + + ret = iob_copyin(iob, dataout, len, 0, true); + if (ret < 0) + { + iob_free_chain(iob); + uerr("CDCMBIM copyin failed: %d\n", ret); + return ret; + } + + ret = iob_tryadd_queue(iob, &mbim->rx_queue); + if (ret < 0) + { + iob_free_chain(iob); + uerr("CDCMBIM add rx queue failed: %d\n", ret); + return ret; + } + + nxsem_post(&mbim->read_sem); + poll_notify(mbim->fds, CDC_MBIM_NPOLLWAITERS, POLLIN); + } + break; + + case MBIM_GET_RESPONSE: + { + FAR struct cdcmbim_driver_s *mbim = + (FAR struct cdcmbim_driver_s *)self; + FAR struct iob_s *iob; + ret = -ENOSPC; + + if ((iob = iob_remove_queue(&mbim->tx_queue)) != NULL) + { + ret = iob_copyout(self->ctrlreq->buf, iob, len, 0); + if (ret >= 0) + { + iob_free_chain(iob); + } + } + } + break; +#endif + default: uerr("Unsupported class req: 0x%02hhx\n", ctrl->req); break; @@ -2284,7 +2703,7 @@ static void cdcncm_disconnect(FAR struct usbdevclass_driver_s *driver, * Name: cdcncm_classobject * * Description: - * Register USB CDC/ECM and return the class object. + * Register USB CDC/NCM and return the class object. * * Returned Value: * A pointer to the allocated class object (NULL on failure). @@ -2307,6 +2726,8 @@ static int cdcncm_classobject(int minor, return -ENOMEM; } + self->isncm = true; + /* Network device initialization */ self->dev.ops = &g_netops; @@ -2316,11 +2737,11 @@ static int cdcncm_classobject(int minor, /* USB device initialization */ #ifdef CONFIG_USBDEV_DUALSPEED - self->usbdev.speed = USB_SPEED_HIGH; + self->usbdev.speed = USB_SPEED_HIGH; #else - self->usbdev.speed = USB_SPEED_FULL; + self->usbdev.speed = USB_SPEED_FULL; #endif - self->usbdev.ops = &g_usbdevops; + self->usbdev.ops = &g_usbdevops; memcpy(&self->devinfo, devinfo, sizeof(struct usbdev_devinfo_s)); @@ -2350,18 +2771,106 @@ static int cdcncm_classobject(int minor, return ret; } +/**************************************************************************** + * Name: cdcmbim_classobject + * + * Description: + * Register USB CDC/MBIM and return the class object. + * + * Returned Value: + * A pointer to the allocated class object (NULL on failure). + * + ****************************************************************************/ + +#ifdef CONFIG_NET_CDCMBIM +static int cdcmbim_classobject(int minor, + FAR struct usbdev_devinfo_s *devinfo, + FAR struct usbdevclass_driver_s **classdev) +{ + FAR struct cdcmbim_driver_s *self; + FAR struct cdcncm_driver_s *ncm; + int ret; + + /* Initialize the driver structure */ + + self = kmm_zalloc(sizeof(struct cdcmbim_driver_s)); + if (!self) + { + nerr("Out of memory!\n"); + return -ENOMEM; + } + + ncm = &self->ncmdriver; + ncm->isncm = false; + + /* Network device initialization */ + + ncm->dev.ops = &g_netops; + ncm->dev.quota[NETPKT_TX] = CONFIG_CDCNCM_QUOTA_TX; + ncm->dev.quota[NETPKT_RX] = CONFIG_CDCNCM_QUOTA_RX; + + /* USB device initialization */ + +#ifdef CONFIG_USBDEV_DUALSPEED + ncm->usbdev.speed = USB_SPEED_HIGH; +#else + ncm->usbdev.speed = USB_SPEED_FULL; +#endif + ncm->usbdev.ops = &g_usbdevops; + + memcpy(&ncm->devinfo, devinfo, sizeof(struct usbdev_devinfo_s)); + + nxmutex_init(&self->lock); + nxsem_init(&self->read_sem, 0, 0); + + uinfo("Register character driver\n"); + + /* Put the interface in the down state. This usually amounts to resetting + * the device and/or calling cdcncm_ifdown(). + */ + + g_netops.ifdown(&self->ncmdriver.dev); + + /* Register the device with the OS so that socket IOCTLs can be performed */ + + ret = netdev_lower_register(&self->ncmdriver.dev, NET_LL_MBIM); + if (ret < 0) + { + nerr("netdev_lower_register failed. ret: %d\n", ret); + } + else + { + char devname[CDC_MBIM_DEVNAMELEN]; + uint8_t index = 0; + +#ifdef CONFIG_NETDEV_IFINDEX + index = self->ncmdriver.dev.netdev.d_ifindex; +#endif + snprintf(devname, CDC_MBIM_DEVNAMELEN, CDC_MBIM_DEVFORMAT, index); + ret = register_driver(devname, &g_usbdevfops, 0666, self); + if (ret < 0) + { + nerr("register_driver failed. ret: %d\n", ret); + } + } + + *classdev = (FAR struct usbdevclass_driver_s *)self; + return ret; +} +#endif + /**************************************************************************** * Name: cdcncm_uninitialize * * Description: - * Un-initialize the USB CDC/ECM class driver. This function is used - * internally by the USB composite driver to uninitialize the CDC/ECM + * Un-initialize the USB CDC/NCM class driver. This function is used + * internally by the USB composite driver to uninitialize the CDC/NCM * driver. This same interface is available (with an untyped input - * parameter) when the CDC/ECM driver is used standalone. + * parameter) when the CDC/NCM driver is used standalone. * * Input Parameters: * There is one parameter, it differs in typing depending upon whether the - * CDC/ECM driver is an internal part of a composite device, or a + * CDC/NCM driver is an internal part of a composite device, or a * standalone USB driver: * * classdev - The class object returned by cdcncm_classobject() @@ -2376,7 +2885,7 @@ static void cdcncm_uninitialize(FAR struct usbdevclass_driver_s *classdev) FAR struct cdcncm_driver_s *self = (FAR struct cdcncm_driver_s *)classdev; int ret; - /* Un-register the CDC/ECM netdev device */ + /* Un-register the CDC/NCM netdev device */ ret = netdev_lower_unregister(&self->dev); if (ret < 0) @@ -2394,29 +2903,55 @@ static void cdcncm_uninitialize(FAR struct usbdevclass_driver_s *classdev) } /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: cdcncm_initialize + * Name: cdcmbim_uninitialize * * Description: - * Register CDC/ECM USB device interface. Register the corresponding - * network driver to NuttX and bring up the network. + * Un-initialize the USB CDC/MBIM class driver. This function is used + * internally by the USB composite driver to uninitialize the CDC/MBIM + * driver. This same interface is available (with an untyped input + * parameter) when the CDC/MBIM driver is used standalone. * * Input Parameters: - * minor - Device minor number. - * handle - An optional opaque reference to the CDC/ECM class object that - * may subsequently be used with cdcncm_uninitialize(). + * There is one parameter, it differs in typing depending upon whether the + * CDC/MBIM driver is an internal part of a composite device, or a + * standalone USB driver: + * + * classdev - The class object returned by cdcmbim_classobject() * * Returned Value: - * Zero (OK) means that the driver was successfully registered. On any - * failure, a negated errno value is returned. + * None * ****************************************************************************/ +#ifdef CONFIG_NET_CDCMBIM +static void cdcmbim_uninitialize(FAR struct usbdevclass_driver_s *classdev) +{ + FAR struct cdcmbim_driver_s *self = + (FAR struct cdcmbim_driver_s *)classdev; + int ret; + + /* Un-register the CDC/MBIM netdev device */ + + ret = netdev_lower_unregister(&self->ncmdriver.dev); + if (ret < 0) + { + nerr("ERROR: netdev_lower_unregister failed. ret: %d\n", ret); + } + +# ifndef CONFIG_CDCNCM_COMPOSITE + usbdev_unregister(&self->ncmdriver.usbdev); +# endif + + /* And free the driver structure */ + + nxmutex_destroy(&self->lock); + nxsem_destroy(&self->read_sem); + kmm_free(self); +} +#endif + #ifndef CONFIG_CDCNCM_COMPOSITE -int cdcncm_initialize(int minor, FAR void **handle) +static int cdcnm_initialize(int minor, FAR void **handle, bool isncm) { FAR struct usbdevclass_driver_s *drvr = NULL; struct usbdev_devinfo_s devinfo; @@ -2430,7 +2965,9 @@ int cdcncm_initialize(int minor, FAR void **handle) devinfo.epno[CDCNCM_EP_BULKIN_IDX] = CONFIG_CDCNCM_EPBULKIN; devinfo.epno[CDCNCM_EP_BULKOUT_IDX] = CONFIG_CDCNCM_EPBULKOUT; - ret = cdcncm_classobject(minor, &devinfo, &drvr); + ret = isncm ? cdcncm_classobject(minor, &devinfo, &drvr) : + cdcmbim_classobject(minor, &devinfo, &drvr); + if (ret == OK) { ret = usbdev_register(drvr); @@ -2442,43 +2979,29 @@ int cdcncm_initialize(int minor, FAR void **handle) if (handle) { - *handle = (FAR void *)drvr; + *handle = drvr; } return ret; } #endif -/**************************************************************************** - * Name: cdcncm_get_composite_devdesc - * - * Description: - * Helper function to fill in some constants into the composite - * configuration struct. - * - * Input Parameters: - * dev - Pointer to the configuration struct we should fill - * - * Returned Value: - * None - * - ****************************************************************************/ - #ifdef CONFIG_CDCNCM_COMPOSITE -void cdcncm_get_composite_devdesc(FAR struct composite_devdesc_s *dev) +static void cdcnm_get_composite_devdesc(FAR struct composite_devdesc_s *dev, + bool isncm) { memset(dev, 0, sizeof(struct composite_devdesc_s)); - /* The callback functions for the CDC/ECM class. + /* The callback functions for the CDC/NCM class. * * classobject() and uninitialize() must be provided by board-specific * logic */ - dev->mkconfdesc = cdcncm_mkcfgdesc; - dev->mkstrdesc = cdcncm_mkstrdesc; - dev->classobject = cdcncm_classobject; - dev->uninitialize = cdcncm_uninitialize; + dev->mkconfdesc = isncm ? cdcncm_mkcfgdesc : cdcmbim_mkcfgdesc; + dev->mkstrdesc = isncm ? cdcncm_mkstrdesc : cdcmbim_mkstrdesc; + dev->classobject = isncm ? cdcncm_classobject : cdcmbim_classobject; + dev->uninitialize = isncm ? cdcncm_uninitialize : cdcmbim_uninitialize; dev->nconfigs = CDCECM_NCONFIGS; /* Number of configurations supported */ dev->configid = CDCECM_CONFIGID; /* The only supported configuration ID */ @@ -2486,9 +3009,12 @@ void cdcncm_get_composite_devdesc(FAR struct composite_devdesc_s *dev) /* Let the construction function calculate the size of config descriptor */ #ifdef CONFIG_USBDEV_DUALSPEED - dev->cfgdescsize = cdcncm_mkcfgdesc(NULL, NULL, USB_SPEED_UNKNOWN, 0); + dev->cfgdescsize = isncm ? + cdcncm_mkcfgdesc(NULL, NULL, USB_SPEED_UNKNOWN, 0) : + cdcmbim_mkcfgdesc(NULL, NULL, USB_SPEED_UNKNOWN, 0); #else - dev->cfgdescsize = cdcncm_mkcfgdesc(NULL, NULL); + dev->cfgdescsize = isncm ? cdcncm_mkcfgdesc(NULL, NULL) : + cdcmbim_mkcfgdesc(NULL, NULL); #endif /* Board-specific logic must provide the device minor */ @@ -2516,4 +3042,69 @@ void cdcncm_get_composite_devdesc(FAR struct composite_devdesc_s *dev) } #endif /* CONFIG_CDCNCM_COMPOSITE */ +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cdcncm_initialize / cdcmbim_initialize + * + * Description: + * Register CDC_NCM/MBIM USB device interface. Register the corresponding + * network driver to NuttX and bring up the network. + * + * Input Parameters: + * minor - Device minor number. + * handle - An optional opaque reference to the CDC_NCM/MBIM class object + * that may subsequently be used with cdcncm_uninitialize(). + * + * Returned Value: + * Zero (OK) means that the driver was successfully registered. On any + * failure, a negated errno value is returned. + * + ****************************************************************************/ + +#ifndef CONFIG_CDCNCM_COMPOSITE +int cdcncm_initialize(int minor, FAR void **handle) +{ + return cdcnm_initialize(minor, handle, true); +} + +#ifdef CONFIG_NET_CDCMBIM +int cdcmbim_initialize(int minor, FAR void **handle) +{ + return cdcnm_initialize(minor, handle, false); +} +# endif /* CONFIG_NET_CDCMBIM */ +#endif /* CONFIG_CDCNCM_COMPOSITE */ + +/**************************************************************************** + * Name: cdcncm_get_composite_devdesc / cdcmbim_get_composite_devdesc + * + * Description: + * Helper function to fill in some constants into the composite + * configuration struct. + * + * Input Parameters: + * dev - Pointer to the configuration struct we should fill + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CDCNCM_COMPOSITE +void cdcncm_get_composite_devdesc(FAR struct composite_devdesc_s *dev) +{ + cdcnm_get_composite_devdesc(dev, true); +} + +# ifdef CONFIG_NET_CDCMBIM +void cdcmbim_get_composite_devdesc(FAR struct composite_devdesc_s *dev) +{ + cdcnm_get_composite_devdesc(dev, false); +} +# endif /* CONFIG_NET_CDCMBIM */ +#endif /* CONFIG_CDCNCM_COMPOSITE */ + #endif /* CONFIG_NET_CDCNCM */ diff --git a/include/nuttx/usb/cdc.h b/include/nuttx/usb/cdc.h index ebdecc7fb0..75886f9114 100644 --- a/include/nuttx/usb/cdc.h +++ b/include/nuttx/usb/cdc.h @@ -343,6 +343,16 @@ #define NCM_NETWORK_CONNECTION ECM_NETWORK_CONNECTION #define NCM_SPEED_CHANGE ECM_SPEED_CHANGE +/* Table 16: Requests, Mobile Broadband Interface Model */ + +#define MBIM_SEND_COMMAND ECM_SEND_COMMAND +#define MBIM_GET_RESPONSE ECM_GET_RESPONSE + +/* Table 17: Notifications, Networking Control Model */ + +#define MBIM_NETWORK_CONNECTION NCM_NETWORK_CONNECTION +#define MBIM_SPEED_CHANGE NCM_SPEED_CHANGE + /* Descriptors ***************************************************************/ /* Table 25: bDescriptor SubType in Functional Descriptors */ @@ -913,6 +923,25 @@ struct cdc_ncm_funcdesc_s #define SIZEOF_NCM_FUNCDESC 6 +struct cdc_mbim_funcdesc_s +{ + uint8_t size; /* bLength, Size of this descriptor */ + uint8_t type; /* bDescriptorType, USB_DESC_TYPE_CSINTERFACE */ + uint8_t subtype; /* bDescriptorSubType, CDC_DSUBTYPE_NCM as defined in + * Table 25. + */ + uint8_t version[2]; /* bcdNcmVersion, the NCM version 0x0100 */ + uint8_t maxctrlmsg[2]; + uint8_t numfilter; + uint8_t maxfiltersize; + uint8_t maxsegmentsize[2]; + uint8_t netcaps; /* bmNetworkCapabilities, The NCM net types the device + * supports. + */ +}; + +#define SIZEOF_MBIM_FUNCDESC 12 + /* Table 43: ATM Networking Functional Descriptor */ struct cdc_atm_funcdesc_s diff --git a/include/nuttx/usb/cdcncm.h b/include/nuttx/usb/cdcncm.h index 6b2fd4f735..0c765e3423 100644 --- a/include/nuttx/usb/cdcncm.h +++ b/include/nuttx/usb/cdcncm.h @@ -57,16 +57,16 @@ extern "C" ****************************************************************************/ /**************************************************************************** - * Name: cdcncm_initialize + * Name: cdcncm_initialize / cdcmbim_initialize * * Description: - * Register CDC/NCM USB device interface. Register the corresponding + * Register CDC_NCM/MBIM USB device interface. Register the corresponding * network driver to NuttX and bring up the network. * * Input Parameters: * minor - Device minor number. - * handle - An optional opaque reference to the CDC/NCM class object that - * may subsequently be used with cdcncm_uninitialize(). + * handle - An optional opaque reference to the CDC_NCM/MBIM class object + * that may subsequently be used with cdcncm_uninitialize(). * * Returned Value: * Zero (OK) means that the driver was successfully registered. On any @@ -76,10 +76,13 @@ extern "C" #ifndef CONFIG_CDCNCM_COMPOSITE int cdcncm_initialize(int minor, FAR void **handle); +# ifdef CONFIG_NET_CDCMBIM +int cdcmbim_initialize(int minor, FAR void **handle); +# endif #endif /**************************************************************************** - * Name: cdcncm_get_composite_devdesc + * Name: cdcncm_get_composite_devdesc / cdcmbim_get_composite_devdesc * * Description: * Helper function to fill in some constants into the composite @@ -95,6 +98,9 @@ int cdcncm_initialize(int minor, FAR void **handle); #ifdef CONFIG_CDCNCM_COMPOSITE void cdcncm_get_composite_devdesc(FAR struct composite_devdesc_s *dev); +# ifdef CONFIG_NET_CDCMBIM +void cdcmbim_get_composite_devdesc(FAR struct composite_devdesc_s *dev); +# endif #endif #undef EXTERN diff --git a/net/Kconfig b/net/Kconfig index 5961a091bd..10ce0b2301 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -228,7 +228,6 @@ config NET_LOOPBACK_PKTSIZE menuconfig NET_MBIM bool "MBIM modem support" - depends on USBHOST_CDCMBIM default n menuconfig NET_SLIP