zhhyu7 commented on code in PR #12914:
URL: https://github.com/apache/nuttx/pull/12914#discussion_r1719282079


##########
drivers/usbdev/cdcncm.c:
##########
@@ -0,0 +1,2541 @@
+/****************************************************************************
+ * drivers/usbdev/cdcncm.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/* References:
+ *   [CDCNCM1.2] Universal Serial Bus - Communications Class - Subclass
+ *               Specification for Ethernet Control Model Devices - Rev 1.2
+ */
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/net/netdev_lowerhalf.h>
+#include <nuttx/usb/cdc.h>
+#include <nuttx/usb/cdcncm.h>
+#include <nuttx/usb/usbdev.h>
+#include <nuttx/usb/usbdev_trace.h>
+#include <nuttx/wqueue.h>
+
+#ifdef CONFIG_BOARD_USBDEV_SERIALSTR
+#  include <nuttx/board.h>
+#endif
+
+#include "cdcecm.h"
+
+#ifdef CONFIG_NET_CDCNCM
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Work queue support is required. */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+#  error Work queue support is required in this configuration 
(CONFIG_SCHED_WORKQUEUE)
+#endif
+
+/* The low priority work queue is preferred.  If it is not enabled, LPWORK
+ * will be the same as HPWORK. NOTE: Use of the high priority work queue will
+ * have a negative impact on interrupt handling latency and overall system
+ * performance.  This should be avoided.
+ */
+
+#define ETHWORK LPWORK
+
+/* CONFIG_CDCECM_NINTERFACES determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#ifndef CONFIG_CDCECM_NINTERFACES
+#  define CONFIG_CDCECM_NINTERFACES 1
+#endif
+
+/* TX timeout = 1 minute */
+
+#define CDCNCM_TXTIMEOUT             (60*CLK_TCK)
+#define CDCNCM_DGRAM_COMBINE_PERIOD   1
+
+#define NTB_DEFAULT_IN_SIZE           16384
+#define NTB_OUT_SIZE                  16384
+#define TX_MAX_NUM_DPE                32
+
+/* NCM Transfer Block Parameter Structure */
+
+#define CDC_NCM_NTB16_SUPPORTED      (1 << 0)
+#define CDC_NCM_NTB32_SUPPORTED      (1 << 1)
+
+#define FORMATS_SUPPORTED            (CDC_NCM_NTB16_SUPPORTED | \
+                                      CDC_NCM_NTB32_SUPPORTED)
+
+#define CDC_NCM_NTH16_SIGN            0x484D434E /* NCMH */
+#define CDC_NCM_NTH32_SIGN            0x686D636E /* ncmh */
+#define CDC_NCM_NDP16_NOCRC_SIGN      0x304D434E /* NCM0 */
+#define CDC_NCM_NDP32_NOCRC_SIGN      0x306D636E /* ncm0 */
+
+#define INIT_NDP16_OPTS {                               \
+    .nthsign      = CDC_NCM_NTH16_SIGN,                 \
+    .ndpsign      = CDC_NCM_NDP16_NOCRC_SIGN,           \
+    .nthsize      = sizeof(struct cdc_ncm_nth16_s),     \
+    .ndpsize      = sizeof(struct usb_cdc_ncm_ndp16_s), \
+    .dpesize      = sizeof(struct usb_cdc_ncm_dpe16_s), \
+    .ndpalign     = 4,                                  \
+    .dgramitemlen = 2,                                  \
+    .blocklen     = 2,                                  \
+    .ndpindex     = 2,                                  \
+    .reserved1    = 0,                                  \
+    .reserved2    = 0,                                  \
+    .nextndpindex = 2,                                  \
+  }
+
+#define INIT_NDP32_OPTS {                               \
+    .nthsign      = CDC_NCM_NTH32_SIGN,                 \
+    .ndpsign      = CDC_NCM_NDP32_NOCRC_SIGN,           \
+    .nthsize      = sizeof(struct cdc_ncm_nth32_s),     \
+    .ndpsize      = sizeof(struct usb_cdc_ncm_ndp32_s), \
+    .dpesize      = sizeof(struct usb_cdc_ncm_dpe32_s), \
+    .ndpalign     = 8,                                  \
+    .dgramitemlen = 4,                                  \
+    .blocklen     = 4,                                  \
+    .ndpindex     = 4,                                  \
+    .reserved1    = 2,                                  \
+    .reserved2    = 4,                                  \
+    .nextndpindex = 4,                                  \
+  }
+
+#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))
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum ncm_notify_state_e
+{
+  NCM_NOTIFY_NONE,    /* Don't notify */
+  NCM_NOTIFY_CONNECT, /* Issue CONNECT next */
+  NCM_NOTIFY_SPEED,   /* Issue SPEED_CHANGE next */
+};
+
+struct ndp_parser_opts_s
+{
+  uint32_t nthsign;          /* NCM Transfer Header signature */
+  uint32_t ndpsign;          /* NCM Datagram Pointer signature */
+  uint_fast8_t nthsize;      /* The length of NTH */
+  uint_fast8_t ndpsize;      /* The length of NDP */
+  uint_fast8_t dpesize;      /* The length of NDP Entry */
+  uint_fast8_t ndpalign;     /* NDP alignment length */
+  uint_fast8_t dgramitemlen; /* The length of index or length */
+  uint_fast8_t blocklen;     /* The length of current NTB */
+  uint_fast8_t ndpindex;     /* The offset of first NDP in current NTB */
+  uint_fast8_t reserved1;    /* Reserved1 */
+  uint_fast8_t reserved2;    /* Reserved2 */
+  uint_fast8_t nextndpindex; /* The offset of next NDP in current NTB */
+};
+
+/* NTH: NCM Transfer Header
+ * NDP: NCM Datagram Pointer
+ * DPE: NCM Datagram Pointer Entry
+ * +------------+  or   +------------+
+ * |     NTH    |       |     NTH    |
+ * +------------+       +------------+
+ * |     NDP    |       |  Datagrams |
+ * +------------+       +------------+
+ * |  Datagrams |       |     NDP    |
+ * +------------+       +------------+
+ *
+ * The layout of the NTB(NCM Transfer Block) structure in the NuttX system
+ * is as follows:
+ * +--------------------------+
+ * |NTH :       nth sign      |
+ * |            nth len       |
+ * |            sequence      |
+ * |            total len     |
+ * |            ndp index     |----+
+ * +--------------------------+    |
+ * |NDP:        ndp sign      |<---+
+ * |            ndp len       |
+ * |            next ndp index|
+ * |            Datagram index|----+
+ * |            Datagram len  |    |
+ * |            Datagram index|----|--+
+ * |            Datagram len  |    |  |
+ * |            Datagram index|----|--|--+
+ * |            Datagram len  |    |  |  |
+ * |            0             | Need to end with two zeros
+ * |            0             | Need to end with two zeros
+ * |            ... [32]      |    |  |  |
+ * +--------------------------+    |  |  |
+ * |Datagrams:  Datagram1     |<---+  |  |
+ * |            pad           |       |  |
+ * |            Datagram2     |<------+  |
+ * |            pad           |          |
+ * |            Datagram3     |<---------+
+ * +--------------------------+
+ */
+
+begin_packed_struct struct cdc_ncm_nth16_s
+{
+  uint32_t sign;
+  uint16_t headerlen;
+  uint16_t seq;
+  uint16_t blocklen;
+  uint16_t ndpindex;
+} end_packed_struct;
+
+begin_packed_struct struct cdc_ncm_nth32_s
+{
+  uint32_t sign;
+  uint16_t headerlen;
+  uint16_t seq;
+  uint32_t blocklen;
+  uint32_t ndpindex;
+} end_packed_struct;
+
+/* 16-bit NCM Datagram Pointer Entry */
+
+begin_packed_struct struct usb_cdc_ncm_dpe16_s
+{
+  uint16_t index;
+  uint16_t len;
+} end_packed_struct;
+
+/* 16-bit NCM Datagram Pointer Table */
+
+begin_packed_struct struct usb_cdc_ncm_ndp16_s
+{
+  uint32_t sign;
+  uint16_t len;
+  uint16_t nextndpindex;
+
+  /* struct usb_cdc_ncm_dpe16_s dpe16[]; */
+} end_packed_struct;
+
+/* 32-bit NCM Datagram Pointer Entry */
+
+begin_packed_struct struct usb_cdc_ncm_dpe32_s
+{
+  uint32_t index;
+  uint32_t len;
+} end_packed_struct;
+
+/* 32-bit NCM Datagram Pointer Table */
+
+begin_packed_struct struct usb_cdc_ncm_ndp32_s
+{
+  uint32_t sign;
+  uint16_t len;
+  uint16_t reserved1;
+  uint32_t nextndpindex;
+  uint32_t reserved2;
+
+  /* struct usb_cdc_ncm_dpe32_s dpe32[]; */
+} end_packed_struct;
+
+begin_packed_struct struct usb_cdc_ncm_ntb_parameters_s
+{
+  uint16_t len;
+  uint16_t ntbsupported;
+  uint32_t ntbinmaxsize;
+  uint16_t ndpindivisor;
+  uint16_t ndpinpayloadremainder;
+  uint16_t ndpinalignment;
+  uint16_t padding;
+  uint32_t ntboutmaxsize;
+  uint16_t ndpoutdivisor;
+  uint16_t ndpoutpayloadremainder;
+  uint16_t ndpoutalignment;
+  uint16_t ntboutmaxdatagrams;
+} end_packed_struct;
+
+/* The cdcncm_driver_s encapsulates all state information for a single
+ * hardware interface
+ */
+
+struct cdcncm_driver_s
+{
+  /* USB CDC-ECM 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 
*/
+
+  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 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 */
+
+  /* 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 */
+
+  /* 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 */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Network Device ***********************************************************/
+
+/* Interrupt handling */
+
+static void cdcncm_receive(FAR struct cdcncm_driver_s *priv);
+static void cdcncm_txdone(FAR struct cdcncm_driver_s *priv);
+
+static void cdcncm_interrupt_work(FAR void *arg);
+
+/* NuttX callback functions */
+
+static int  cdcncm_ifup(FAR struct netdev_lowerhalf_s *dev);
+static int  cdcncm_ifdown(FAR struct netdev_lowerhalf_s *dev);
+static int  cdcncm_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt);
+static FAR netpkt_t *cdcncm_recv(FAR struct netdev_lowerhalf_s *dev);
+
+#if defined(CONFIG_NET_MCASTGROUP) || defined(CONFIG_NET_ICMPv6)
+static int  cdcncm_addmac(FAR struct netdev_lowerhalf_s *dev,
+                          FAR const uint8_t *mac);
+#ifdef CONFIG_NET_MCASTGROUP
+static int  cdcncm_rmmac(FAR struct netdev_lowerhalf_s *dev,
+                         FAR const uint8_t *mac);
+#endif
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+static int  cdcncm_ioctl(FAR struct netdev_lowerhalf_s *dev, int cmd,
+                         unsigned long arg);
+#endif
+
+/* USB Device Class Driver **************************************************/
+
+/* USB Device Class methods */
+
+static int  cdcncm_bind(FAR struct usbdevclass_driver_s *driver,
+                        FAR struct usbdev_s *dev);
+
+static void cdcncm_unbind(FAR struct usbdevclass_driver_s *driver,
+                          FAR struct usbdev_s *dev);
+
+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);
+
+static void cdcncm_disconnect(FAR struct usbdevclass_driver_s *driver,
+                              FAR struct usbdev_s *dev);
+
+/* USB Device Class helpers */
+
+static void cdcncm_ep0incomplete(FAR struct usbdev_ep_s *ep,
+                                 FAR struct usbdev_req_s *req);
+static void cdcncm_rdcomplete(FAR struct usbdev_ep_s *ep,
+                              FAR struct usbdev_req_s *req);
+static void cdcncm_wrcomplete(FAR struct usbdev_ep_s *ep,
+                              FAR struct usbdev_req_s *req);
+
+static void cdcncm_mkepdesc(int epidx, FAR struct usb_epdesc_s *epdesc,
+                            FAR struct usbdev_devinfo_s *devinfo,
+                            bool hispeed);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* USB Device Class Methods */
+
+static const struct usbdevclass_driverops_s g_usbdevops =
+{
+  cdcncm_bind,
+  cdcncm_unbind,
+  cdcncm_setup,
+  cdcncm_disconnect,
+  NULL,
+  NULL
+};
+
+#ifndef CONFIG_CDCNCM_COMPOSITE
+static const struct usb_devdesc_s g_devdesc =
+{
+  USB_SIZEOF_DEVDESC,
+  USB_DESC_TYPE_DEVICE,
+  {
+    LSBYTE(0x0200),
+    MSBYTE(0x0200)
+  },
+  USB_CLASS_CDC,
+  CDC_SUBCLASS_NCM,
+  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)
+  },
+  CDCNCM_MANUFACTURERSTRID,
+  CDCNCM_PRODUCTSTRID,
+  CDCNCM_SERIALSTRID,
+  CDCECM_NCONFIGS
+};
+#endif
+
+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;
+
+static const struct usb_cdc_ncm_ntb_parameters_s g_ntbparameters =
+{
+  .len                    = sizeof(g_ntbparameters),
+  .ntbsupported           = FORMATS_SUPPORTED,
+  .ntbinmaxsize           = NTB_DEFAULT_IN_SIZE,
+  .ndpindivisor           = 4,
+  .ndpinpayloadremainder  = 0,
+  .ndpinalignment         = 4,
+
+  .ntboutmaxsize          = NTB_OUT_SIZE,
+  .ndpoutdivisor          = 4,
+  .ndpoutpayloadremainder = 0,
+  .ndpoutalignment        = 4,
+};
+
+static const struct netdev_ops_s g_netops =
+{
+  cdcncm_ifup,   /* ifup */
+  cdcncm_ifdown, /* ifdown */
+  cdcncm_send,   /* transmit */
+  cdcncm_recv,   /* receive */
+#ifdef CONFIG_NET_MCASTGROUP
+  cdcncm_addmac, /* addmac */
+  cdcncm_rmmac,  /* rmmac */
+#endif
+#ifdef CONFIG_NETDEV_IOCTL
+  cdcncm_ioctl,  /* ioctl */
+#endif
+};
+
+/****************************************************************************
+ * Inline Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cdcncm_get
+ *
+ * Description:
+ *   Read size length data from address and increases the address by the
+ *   corresponding size
+ *
+ * Input Parameters:
+ *   address - Pointer to address
+ *   size    - Size of data
+ *
+ * Returned Value:
+ *   The read value
+ *
+ ****************************************************************************/
+
+static inline uint32_t cdcncm_get(FAR uint8_t **address, size_t size)
+{
+  uint32_t value;
+
+  switch (size)
+  {
+    case 2:
+      value = GETUINT16(*address);
+      break;
+    case 4:
+      value = GETUINT32(*address);
+      break;
+    default:
+      nerr("Wrong size cdcncm_get %zu\n", size);
+  }
+
+  *address += size;
+  return value;
+}
+
+/****************************************************************************
+ * Name: cdcncm_put
+ *
+ * Description:
+ *   Write size length data to address and increases the address by the
+ *   corresponding size
+ *
+ * Input Parameters:
+ *   address - Pointer to address
+ *   size    - Size of data
+ *   value   - Value of data
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static inline
+void cdcncm_put(FAR uint8_t **address, size_t size, uint32_t value)
+{
+  switch (size)
+  {
+    case 2:
+      PUTUINT16(*address, value);
+      break;
+    case 4:
+      PUTUINT32(*address, value);
+      break;
+    default:
+      uerr("Wrong cdcncm_put\n");
+  }
+
+  *address += size;
+}
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: cdcncm_transmit_format
+ *
+ * Description:
+ *   Format the data to be transmitted to the host in the format specified by
+ *   the NCM protocol (Network Control Model) and the NCM NTB (Network
+ *   Transfer Block) format.
+ *
+ * Input Parameters:
+ *   self - Reference to the driver state structure
+ *   pkt  - Reference to the packet to be transmitted
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void cdcncm_transmit_format(FAR struct cdcncm_driver_s *self,
+                                   FAR netpkt_t *pkt)
+{
+  FAR const struct ndp_parser_opts_s *opts = self->parseropts;
+  unsigned int dglen = netpkt_getdatalen(&self->dev, pkt);
+  const int div = g_ntbparameters.ndpindivisor;
+  const int rem = g_ntbparameters.ndpinpayloadremainder;
+  const int dgramidxlen = 2 * opts->dgramitemlen;
+  const int ndpalign = g_ntbparameters.ndpinalignment;
+  FAR uint8_t *tmp;
+  int ncblen;
+  int ndpindex;
+
+  ncblen   = opts->nthsize;
+  ndpindex = NCM_ALIGN(ncblen, ndpalign);
+
+  if (self->dgramcount == 0)
+    {
+      /* Fill NCB */
+
+      tmp = self->wrreq->buf;
+      memset(tmp, 0, ncblen);
+      cdcncm_put(&tmp, 4, opts->nthsign);
+      cdcncm_put(&tmp, 2, opts->nthsize);
+      tmp += 2;              /* Skip seq */
+      tmp += opts->blocklen; /* Skip block len */
+      cdcncm_put(&tmp, opts->ndpindex, ndpindex);
+      self->dgramaddr = self->wrreq->buf + ndpindex +
+                        opts->ndpsize + (TX_MAX_NUM_DPE + 1) * dgramidxlen;
+      self->dgramaddr = (FAR uint8_t *)NCM_ALIGN((uintptr_t)self->dgramaddr,
+                                                 div) + rem;
+
+      /* Fill NDP */
+
+      tmp = self->wrreq->buf + ndpindex;
+      cdcncm_put(&tmp, 4, self->ndpsign);
+      tmp += 2 + opts->reserved1;
+      cdcncm_put(&tmp, opts->nextndpindex, 0);
+    }
+
+  tmp = self->wrreq->buf + ndpindex + opts->ndpsize +
+        self->dgramcount * dgramidxlen;
+  cdcncm_put(&tmp, opts->dgramitemlen, self->dgramaddr - self->wrreq->buf);
+  cdcncm_put(&tmp, opts->dgramitemlen, dglen);
+
+  /* Fill IP packet */
+
+  netpkt_copyout(&self->dev, self->dgramaddr, pkt, dglen, 0);
+
+  self->dgramaddr += dglen;
+  self->dgramaddr  = (FAR uint8_t *)NCM_ALIGN((uintptr_t)self->dgramaddr,
+                                              div) + rem;
+
+  self->dgramcount++;
+}
+
+/****************************************************************************
+ * Name: cdcncm_transmit_work
+ *
+ * Description:
+ *   Send NTB to the USB device for ethernet frame transmission
+ *
+ * Input Parameters:
+ *   arg - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void cdcncm_transmit_work(FAR void *arg)
+{
+  FAR struct cdcncm_driver_s *self = arg;
+  FAR const struct ndp_parser_opts_s *opts = self->parseropts;
+  FAR uint8_t *tmp;
+  const int dgramidxlen = 2 * opts->dgramitemlen;
+  const int ndpalign = g_ntbparameters.ndpinalignment;
+  int ncblen;
+  int ndpindex;
+  int totallen;
+
+  /* Wait until the USB device request for Ethernet frame transmissions
+   * becomes available.
+   */
+
+  while (nxsem_wait(&self->wrreq_idle) != OK)
+    {
+    }
+
+  ncblen   = opts->nthsize;
+  ndpindex = NCM_ALIGN(ncblen, ndpalign);
+
+  /* Fill NCB */
+
+  tmp      = self->wrreq->buf + 8; /* Offset to block length */
+  totallen = self->dgramaddr - self->wrreq->buf;
+  cdcncm_put(&tmp, opts->blocklen, totallen);
+
+  /* Fill NDP */
+
+  tmp = self->wrreq->buf + ndpindex + 4; /* Offset to ndp length */
+  cdcncm_put(&tmp, 2, opts->ndpsize + (self->dgramcount + 1) * dgramidxlen);
+
+  tmp += opts->reserved1 + opts->nextndpindex + opts->reserved2 +
+         self->dgramcount * dgramidxlen;
+  self->dgramcount = 0;
+
+  cdcncm_put(&tmp, opts->dgramitemlen, 0);
+  cdcncm_put(&tmp, opts->dgramitemlen, 0);
+
+  self->wrreq->len = totallen;
+
+  EP_SUBMIT(self->epbulkin, self->wrreq);
+}
+
+/****************************************************************************
+ * Name: cdcncm_packet_handler
+ *
+ * Description:
+ *   Sends a single complete packet to the protocol stack
+ *
+ * Input Parameters:
+ *   self - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int cdcncm_packet_handler(FAR struct cdcncm_driver_s *self,
+                                 FAR uint8_t *dgram, uint32_t dglen)
+{
+  FAR netpkt_t *pkt = netpkt_alloc(&self->dev, NETPKT_RX);
+  int ret = -ENOMEM;
+
+  if (pkt == NULL)
+    {
+      return ret;
+    }
+
+  ret = netpkt_copyin(&self->dev, pkt, dgram, dglen, 0);
+  if (ret < 0)
+    {
+      netpkt_free(&self->dev, pkt, NETPKT_RX);
+      return ret;
+    }
+
+  ret = netpkt_tryadd_queue(pkt, &self->rx_queue);
+  if (ret != 0)
+    {
+      netpkt_free(&self->dev, pkt, NETPKT_RX);
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: cdcncm_receive
+ *
+ * Description:
+ *   An interrupt was received indicating the availability of a new RX packet
+ *
+ * Input Parameters:
+ *   self - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void cdcncm_receive(FAR struct cdcncm_driver_s *self)
+{
+  FAR const struct ndp_parser_opts_s *opts = self->parseropts;
+  FAR uint8_t *tmp = self->rdreq->buf;
+  uint32_t ntbmax = g_ntbparameters.ntboutmaxsize;
+  uint32_t blocklen;
+  uint32_t ndplen;
+  int ndpindex;
+  int dgramcounter;
+
+  /* Get signature */
+
+  if (GETUINT32(tmp) != opts->nthsign)
+    {
+      uerr("Wrong NTH SIGN, skblen %d\n", self->rdreq->xfrd);
+      return;
+    }
+
+  tmp += 4;
+
+  /* Get header len */
+
+  if (GETUINT16(tmp) != opts->nthsize)
+    {
+      uerr("Wrong NTB headersize\n");
+      return;
+    }
+
+  tmp += 4; /* Skip header len and seq */
+
+  blocklen = cdcncm_get(&tmp, opts->blocklen);
+
+  /* Get block len */
+
+  if (blocklen > ntbmax)
+    {
+      uerr("OUT size exceeded\n");
+      return;
+    }
+
+  ndpindex = cdcncm_get(&tmp, opts->ndpindex);
+
+  do
+    {
+      uint32_t index;
+      uint32_t dglen;
+
+      if (((ndpindex % 4) != 0) || (ndpindex < opts->nthsize) ||
+          (ndpindex > (blocklen - opts->ndpsize)))
+        {
+          uerr("Bad index: %#X\n", ndpindex);
+          return;
+        }
+
+      tmp = self->rdreq->buf + ndpindex;
+
+      if (GETUINT32(tmp) != self->ndpsign)
+        {
+          uerr("Wrong NDP SIGN\n");
+          return;
+        }
+
+      tmp   += 4;
+      ndplen = cdcncm_get(&tmp, 2);
+
+      if ((ndplen < opts->ndpsize + 2 * (opts->dgramitemlen * 2)) ||
+          (ndplen % opts->ndpalign != 0))
+        {
+          uerr("Bad NDP length: %x\n", ndplen);
+          return;
+        }
+
+      tmp         += opts->reserved1;
+      ndpindex     = cdcncm_get(&tmp, opts->nextndpindex);
+      tmp         += opts->reserved2;
+
+      ndplen      -= opts->ndpsize;
+      dgramcounter = 0;
+      do
+        {
+          index = cdcncm_get(&tmp, opts->dgramitemlen);
+          dglen = cdcncm_get(&tmp, opts->dgramitemlen);
+
+          /* TODO: support CRC */
+
+          /* Check if the packet is a valid size for the network buffer
+           * configuration.
+           */
+
+          if (index == 0 || dglen == 0)
+            {
+              break;
+            }
+
+          dgramcounter++;
+
+          /* Copy the data from the hardware to self->rx_queue. */
+
+          cdcncm_packet_handler(self, self->rdreq->buf + index, dglen);
+
+          ndplen -= 2 * (opts->dgramitemlen);
+        }
+      while (ndplen > 2 * (opts->dgramitemlen));
+    }
+  while (ndpindex);
+}
+
+/****************************************************************************
+ * Name: cdcncm_txdone
+ *
+ * Description:
+ *   An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Input Parameters:
+ *   priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void cdcncm_txdone(FAR struct cdcncm_driver_s *priv)
+{
+  /* In any event, poll the network for new TX data */
+
+  netdev_lower_txdone(&priv->dev);
+}
+
+/****************************************************************************
+ * Name: cdcncm_interrupt_work
+ *
+ * Description:
+ *   Perform interrupt related work from the worker thread
+ *
+ * Input Parameters:
+ *   arg - The argument passed when work_queue() was called.
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ * Assumptions:
+ *   Runs on a worker thread.
+ *
+ ****************************************************************************/
+
+static void cdcncm_interrupt_work(FAR void *arg)
+{
+  FAR struct cdcncm_driver_s *self = (FAR struct cdcncm_driver_s *)arg;
+  irqstate_t flags;
+
+  /* Check if we received an incoming packet, if so, call cdcncm_receive() */
+
+  if (self->rxpending)
+    {
+      cdcncm_receive(self);
+      netdev_lower_rxready(&self->dev);
+
+      flags = enter_critical_section();
+      self->rxpending = false;
+      EP_SUBMIT(self->epbulkout, self->rdreq);
+      leave_critical_section(flags);
+    }
+
+  /* Check if a packet transmission just completed.  If so, call
+   * cdcncm_txdone. This may disable further Tx interrupts if there
+   * are no pending transmissions.
+   */
+
+  if (self->txdone)
+    {
+      flags = enter_critical_section();
+      self->txdone = false;
+      leave_critical_section(flags);
+
+      cdcncm_txdone(self);
+    }
+}
+
+/****************************************************************************
+ * Name: cdcncm_ifup
+ *
+ * Description:
+ *   NuttX Callback: Bring up the Ethernet interface when an IP address is
+ *   provided
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static int cdcncm_ifup(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct cdcncm_driver_s *priv =
+    container_of(dev, struct cdcncm_driver_s, dev);
+
+#ifdef CONFIG_NET_IPv4
+  ninfo("Bringing up: %u.%u.%u.%u\n",
+        ip4_addr1(dev->netdev.d_ipaddr), ip4_addr2(dev->netdev.d_ipaddr),
+        ip4_addr3(dev->netdev.d_ipaddr), ip4_addr4(dev->netdev.d_ipaddr));
+#endif
+#ifdef CONFIG_NET_IPv6
+  ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+        dev->netdev.d_ipv6addr[0], dev->netdev.d_ipv6addr[1],
+        dev->netdev.d_ipv6addr[2], dev->netdev.d_ipv6addr[3],
+        dev->netdev.d_ipv6addr[4], dev->netdev.d_ipv6addr[5],
+        dev->netdev.d_ipv6addr[6], dev->netdev.d_ipv6addr[7]);
+#endif
+
+  priv->bifup = true;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcncm_ifdown
+ *
+ * Description:
+ *   NuttX Callback: Stop the interface.
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ *   None
+ *
+ * Assumptions:
+ *   The network is locked.
+ *
+ ****************************************************************************/
+
+static int cdcncm_ifdown(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct cdcncm_driver_s *priv =
+    container_of(dev, struct cdcncm_driver_s, dev);
+  irqstate_t flags;
+
+  /* Disable the Ethernet interrupt */
+
+  flags = enter_critical_section();
+
+  /* Put the EMAC in its reset, non-operational state.  This should be
+   * a known configuration that will guarantee the cdcncm_ifup() always
+   * successfully brings the interface back up.
+   */
+
+  /* Mark the device "down" */
+
+  priv->bifup = false;
+  leave_critical_section(flags);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcncm_send
+ *
+ * Description:
+ *   Transmit a packet through the USB interface
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX netdev lowerhalf driver structure
+ *   pkt - The packet to be sent
+ *
+ * Returned Value:
+ *   OK on success
+ *
+ ****************************************************************************/
+
+static int cdcncm_send(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt)
+{
+  FAR struct cdcncm_driver_s *self;
+
+  self = container_of(dev, struct cdcncm_driver_s, dev);
+  cdcncm_transmit_format(self, pkt);
+  netpkt_free(dev, pkt, NETPKT_TX);
+
+  if ((self->wrreq->buf + NTB_OUT_SIZE - self->dgramaddr <
+       self->dev.netdev.d_pktsize) || self->dgramcount >= TX_MAX_NUM_DPE)
+    {
+      work_cancel(ETHWORK, &self->delaywork);
+      cdcncm_transmit_work(self);
+    }
+  else
+    {
+      work_queue(ETHWORK, &self->delaywork, cdcncm_transmit_work, self,
+                 MSEC2TICK(CDCNCM_DGRAM_COMBINE_PERIOD));
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: cdcncm_recv
+ *
+ * Description:
+ *   Receive a packet from the USB interface
+ *
+ * Input Parameters:
+ *   dev - Reference to the NuttX netdev lowerhalf driver structure
+ *
+ * Returned Value:
+ *   The received packet, or NULL if no packet is available
+ *
+ ****************************************************************************/
+
+static FAR netpkt_t *cdcncm_recv(FAR struct netdev_lowerhalf_s *dev)
+{
+  FAR struct cdcncm_driver_s *self;
+  FAR netpkt_t *pkt;
+
+  self = container_of(dev, struct cdcncm_driver_s, dev);
+  pkt  = netpkt_remove_queue(&self->rx_queue);

Review Comment:
   Done.



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

To unsubscribe, e-mail: [email protected]

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

Reply via email to