static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
                           FAR const uint8_t *configdesc, int desclen)
{
  FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_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)
    {
      udbg("usbhost_cfgdesc() failed: %d\n", ret);
    }
  else
    {
      /* Now configure the device and register the NuttX driver */

      ret = usbhost_devinit(priv);
      if (ret < 0)
        {
          udbg("usbhost_devinit() failed: %d\n", ret);
        }
    }

  return ret;
}
Exemple #2
0
int sam_usbhost_initialize(void)
{
  pid_t pid;
  int ret;

  /* First, register all of the class drivers needed to support the drivers
   * that we care about:
   */

  ret = usbhost_storageinit();
  if (ret != OK)
    {
      udbg("ERROR: Failed to register the mass storage class: %d\n", ret);
    }

#ifdef CONFIG_SAMA5_OHCI
  /* Get an instance of the USB OHCI interface */

  g_ohciconn = sam_ohci_initialize(0);
  if (!g_ohciconn)
    {
      udbg("ERROR: sam_ohci_initialize failed\n");
      return -ENODEV;
    }

  /* Start a thread to handle device connection. */

  pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO,  CONFIG_USBHOST_STACKSIZE,
                    (main_t)ohci_waiter, (FAR char * const *)NULL);
  if (pid < 0)
    {
      udbg("ERROR: Failed to create ohci_waiter task: %d\n", ret);
      return -ENODEV;
    }
#endif

#ifdef CONFIG_SAMA5_EHCI
  /* Get an instance of the USB EHCI interface */

  g_ehciconn = sam_ehci_initialize(0);
  if (!g_ehciconn)
    {
      udbg("ERROR: sam_ehci_initialize failed\n");
      return -ENODEV;
    }

  /* Start a thread to handle device connection. */

  pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO,  CONFIG_USBHOST_STACKSIZE,
                    (main_t)ehci_waiter, (FAR char * const *)NULL);
  if (pid < 0)
    {
      udbg("ERROR: Failed to create ehci_waiter task: %d\n", ret);
      return -ENODEV;
    }
#endif

  return OK;
}
static int usbhost_connect(FAR struct usbhost_class_s *hubclass,
                           FAR const uint8_t *configdesc, int desclen)
{
  FAR struct usbhost_hubpriv_s *priv;
  FAR struct usbhost_hubport_s *hport;
  int ret;

  DEBUGASSERT(hubclass != NULL);
  priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;

  DEBUGASSERT(hubclass->hport);
  hport = hubclass->hport;

  DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));

  /* Parse the configuration descriptor to get the endpoints */

  ret = usbhost_cfgdesc(hubclass, configdesc, desclen);
  if (ret < 0)
    {
      udbg("ERROR: Failed to parse config descriptor: %d\n", ret);
      return ret;
    }

  /* Read the hub descriptor */

  ret = usbhost_hubdesc(hubclass);
  if (ret < 0)
    {
      return ret;
    }

  if (priv->nports > USBHUB_MAX_PORTS)
    {
      udbg("ERROR: too many downstream ports: %d\n", priv->nports);
      return -ENOSYS;
    }

  /* Enable power to all downstream ports */

  ret = usbhost_hubpwr(priv, hport, true);
  if (ret < 0)
    {
      udbg("ERROR: usbhost_hubpwr failed: %d\n", ret);
      return ret;
    }

  /* Begin monitoring of port status change events */

  ret = DRVR_ASYNCH(hport->drvr, priv->intin, (FAR uint8_t *)priv->buffer,
                    INTIN_BUFSIZE, usbhost_callback, hubclass);
  if (ret < 0)
    {
      udbg("ERROR: DRVR_ASYNCH failed: %d\n", ret);
      (void)usbhost_hubpwr(priv, hport, false);
    }

  return ret;
}
Exemple #4
0
int stm32_usbhost_initialize(void)
{
  int pid;
  int ret;

  /* First, register all of the class drivers needed to support the drivers
   * that we care about:
   */

  uvdbg("Register class drivers\n");

#ifdef CONFIG_USBHOST_HUB
  /* Initialize USB hub class support */

  ret = usbhost_hub_initialize();
  if (ret < 0)
    {
      udbg("ERROR: usbhost_hub_initialize failed: %d\n", ret);
    }
#endif

#ifdef CONFIG_USBHOST_MSC
  /* Register the USB mass storage class class */

  ret = usbhost_msc_initialize();
  if (ret != OK)
    {
      udbg("ERROR: Failed to register the mass storage class: %d\n", ret);
    }
#endif

#ifdef CONFIG_USBHOST_CDCACM
  /* Register the CDC/ACM serial class */

  ret = usbhost_cdcacm_initialize();
  if (ret != OK)
    {
      udbg("ERROR: Failed to register the CDC/ACM serial class: %d\n", ret);
    }
#endif

  /* Then get an instance of the USB host interface */

  uvdbg("Initialize USB host\n");
  g_usbconn = stm32_otghshost_initialize(0);
  if (g_usbconn)
    {
      /* Start a thread to handle device connection. */

      uvdbg("Start usbhost_waiter\n");

      pid = task_create("usbhost", CONFIG_STM32F429IDISCO_USBHOST_PRIO,
                        CONFIG_STM32F429IDISCO_USBHOST_STACKSIZE,
                        (main_t)usbhost_waiter, (FAR char * const *)NULL);
      return pid < 0 ? -ENOEXEC : OK;
    }

  return -ENODEV;
}
Exemple #5
0
void sam_usbhost_vbusdrive(int rhport, bool enable)
{
  pio_pinset_t pinset = 0;

  uvdbg("RHPort%d: enable=%d\n", rhport+1, enable);

  /* Pick the PIO configuration associated with the selected root hub port */

  switch (rhport)
    {
    case SAM_RHPORT1:
#ifndef CONFIG_SAMA5_UHPHS_RHPORT1
      udbg("ERROR: RHPort1 is not available in this configuration\n");
      return;
#else
      pinset = PIO_USBA_VBUS_ENABLE;
      break;
#endif

    case SAM_RHPORT2:
#ifndef CONFIG_SAMA5_UHPHS_RHPORT2
      udbg("ERROR: RHPort2 is not available in this configuration\n");
      return;
#else
      pinset = PIO_USBB_VBUS_ENABLE;
      break;
#endif

    case SAM_RHPORT3:
#ifndef CONFIG_SAMA5_UHPHS_RHPORT3
      udbg("ERROR: RHPort3 is not available in this configuration\n");
      return;
#else
      pinset = PIO_USBC_VBUS_ENABLE;
      break;
#endif

    default:
      udbg("ERROR: RHPort%d is not supported\n", rhport+1);
      return;
    }

  /* Then enable or disable VBUS power */

  if (enable)
    {
      /* Enable the Power Switch by driving the enable pin low */

      sam_piowrite(pinset, false);
    }
  else
    {
      /* Disable the Power Switch by driving the enable pin high */

      sam_piowrite(pinset, true);
    }
}
int usbhost_devaddr_create(FAR struct usbhost_devaddr_s *hcd,
                           FAR void *associate)
{
  FAR struct usbhost_devhash_s *hentry;
  uint8_t hvalue;
  int devaddr;

  /* Allocate a hash table entry */

  hentry = (FAR struct usbhost_devhash_s *)kmalloc(sizeof(struct usbhost_devhash_s));
  if (!hentry)
    {
      udbg("ERROR: Failed to allocate a hash table entry\n");
      return -ENOMEM;
    }

  /* Get exclusive access to the HCD device address data */

  usbhost_takesem(hcd);

  /* Allocate a device address */

  devaddr = usbhost_devaddr_allocate(hcd);
  if (devaddr < 0)
    {
      udbg("ERROR: Failed to allocate a device address\n");
      free(hentry);
    }
  else
    {
      /* Initialize the hash table entry */

      hentry->devaddr = devaddr;
      hentry->payload = associate;

      /* Add the new device address to the hash table */

      hvalue = usbhost_devaddr_hash(devaddr);
      hentry->flink = hcd->hashtab[hvalue];
      hcd->hashtab[hvalue] = hentry;

      /* Try to re-use the lowest numbered device addresses */

      if (hcd->next > devaddr)
        {
          hcd->next = devaddr;
        }
    }

  usbhost_givesem(hcd);
  return devaddr;
}
Exemple #7
0
void usbip_stop_threads(struct usbip_device *ud)
{
        /* kill threads related to this sdev, if v.c. exists */
	if (ud->tcp_rx.thread != NULL) {
		send_sig(SIGKILL, ud->tcp_rx.thread, 1);
		wait_for_completion(&ud->tcp_rx.thread_done);
		udbg("rx_thread for ud %p has finished\n", ud);
	}

	if (ud->tcp_tx.thread != NULL) {
		send_sig(SIGKILL, ud->tcp_tx.thread, 1);
		wait_for_completion(&ud->tcp_tx.thread_done);
		udbg("tx_thread for ud %p has finished\n", ud);
	}
}
Exemple #8
0
int stm32_usbhost_initialize(void)
{
  int pid;
  int ret;

  /* First, register all of the class drivers needed to support the drivers
   * that we care about:
   */

  uvdbg("Register class drivers\n");
  ret = usbhost_storageinit();
  if (ret != OK)
    {
      udbg("Failed to register the mass storage class\n");
    }

  /* Then get an instance of the USB host interface */

  uvdbg("Initialize USB host\n");
  g_drvr = usbhost_initialize(0);
  if (g_drvr)
    {
      /* Start a thread to handle device connection. */

      uvdbg("Start usbhost_waiter\n");

      pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO,
                        CONFIG_USBHOST_STACKSIZE,
                        (main_t)usbhost_waiter, (FAR char * const *)NULL);
      return pid < 0 ? -ENOEXEC : OK;
    }

  return -ENODEV;
}
Exemple #9
0
static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
		size_t count)
{
	int len;
	char busid[BUS_ID_SIZE];

	if (count < 5)
		return -EINVAL;

	/* strnlen() does not include \0 */
	len = strnlen(buf + 4, BUS_ID_SIZE);

	/* busid needs to include \0 termination */
	if (!(len < BUS_ID_SIZE))
		return -EINVAL;

	strncpy(busid, buf + 4, BUS_ID_SIZE);


	if (!strncmp(buf, "add ", 4)) {
		if (add_match_busid(busid) < 0)
			return -ENOMEM;
		else {
			udbg("add busid %s\n", busid);
			return count;
		}
	} else if (!strncmp(buf, "del ", 4)) {
		if (del_match_busid(busid) < 0)
			return -ENODEV;
		else {
			udbg("del busid %s\n", busid);
			return count;
		}
	} else
		return -EINVAL;
}
static inline int usbhost_classbind(FAR struct usbhost_hubport_s *hport,
                                    const uint8_t *configdesc, int desclen,
                                    struct usbhost_id_s *id,
                                    FAR struct usbhost_class_s **usbclass)
{
  FAR struct usbhost_class_s *devclass;
  FAR const struct usbhost_registry_s *reg;
  int ret = -EINVAL;

  /* Is there is a class implementation registered to support this device. */

  reg = usbhost_findclass(id);
  uvdbg("usbhost_findclass: %p\n", reg);
  if (reg != NULL)
    {
      /* Yes.. there is a class for this device.  Get an instance of
       * its interface.
       */

      ret = -ENOMEM;
      devclass = CLASS_CREATE(reg, hport, id);
      uvdbg("CLASS_CREATE: %p\n", devclass);
      if (devclass != NULL)
        {
          /* Then bind the newly instantiated class instance */

          ret = CLASS_CONNECT(devclass, configdesc, desclen);
          if (ret < 0)
            {
              /* On failures, call the class disconnect method which
               * should then free the allocated devclass instance.
               */

              udbg("CLASS_CONNECT failed: %d\n", ret);
              CLASS_DISCONNECTED(devclass);
            }
          else
            {
              *usbclass = devclass;
            }
        }
    }

  uvdbg("Returning: %d\n", ret);
  return ret;
}
static int usbhost_hubpwr(FAR struct usbhost_hubpriv_s *priv,
                          FAR struct usbhost_hubport_s *hport,
                          bool on)
{
  FAR struct usb_ctrlreq_s *ctrlreq;
  uint16_t req;
  int port;
  int ret;

  /* Are we enabling or disabling power? */

  if (on)
    {
      req = USBHUB_REQ_SETFEATURE;
    }
  else
    {
      req = USBHUB_REQ_CLEARFEATURE;
    }

  /* Enable/disable power to all downstream ports */

  ctrlreq = priv->ctrlreq;
  DEBUGASSERT(ctrlreq);

   for (port = 1; port <= priv->nports; port++)
     {
       ctrlreq->type = USBHUB_REQ_TYPE_PORT;
       ctrlreq->req  = req;
       usbhost_putle16(ctrlreq->value, USBHUB_PORT_FEAT_POWER);
       usbhost_putle16(ctrlreq->index, port);
       usbhost_putle16(ctrlreq->len, 0);

       ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
       if (ret < 0)
         {
           udbg("ERROR: Failed to power %s port %d: %d\n",
                on ? "UP" : "DOWN", port, ret);
           return ret;
        }
    }

  return OK;
}
static int usbhost_hport_activate(FAR struct usbhost_hubport_s *hport)
{
  struct usbhost_epdesc_s epdesc;
  int ret;

  uvdbg("Activating port %d\n", hport->port);

  epdesc.hport        = hport;
  epdesc.addr         = 0;
  epdesc.in           = false;
  epdesc.xfrtype      = USB_EP_ATTR_XFER_CONTROL;
  epdesc.interval     = 0;
  epdesc.mxpacketsize = (hport->speed == USB_SPEED_HIGH) ? 64 : 8;

  ret = DRVR_EPALLOC(hport->drvr, &epdesc, &hport->ep0);
  if (ret < 0)
    {
      udbg("ERROR: Failed to allocate ep0: %d\n", ret);
    }

  return ret;
}
Exemple #13
0
void usbip_dump_header(struct usbip_header *pdu)
{
	udbg("BASE: cmd %u bus %u dev %u seq %u pipe %04x\n",
			pdu->base.command,
			pdu->base.busnum,
			pdu->base.devnum,
			pdu->base.seqnum,
			pdu->base.pipe);

	usbip_dump_pipe(pdu->base.pipe);

	switch(pdu->base.command) {
		case USBIP_CMD_SUBMIT:
			udbg("CMD_SUBMIT: x_flags %u x_len %u bw %u sf %u #p %u iv %u\n",
					pdu->u.cmd_submit.transfer_flags,
					pdu->u.cmd_submit.transfer_buffer_length,
					pdu->u.cmd_submit.bandwidth,
					pdu->u.cmd_submit.start_frame,
					pdu->u.cmd_submit.number_of_packets,
					pdu->u.cmd_submit.interval);
					break;
		case USBIP_CMD_UNLINK:
			udbg("CMD_UNLINK: seq %u\n", pdu->u.cmd_unlink.seqnum);
			break;
		case USBIP_RET_SUBMIT:
			udbg("RET_SUBMIT: st %d al %u bw %u sf %d ec %d\n",
					pdu->u.ret_submit.status,
					pdu->u.ret_submit.actual_length,
					pdu->u.ret_submit.bandwidth,
					pdu->u.ret_submit.start_frame,
					pdu->u.ret_submit.error_count);
		case USBIP_RET_UNLINK:
			udbg("RET_UNLINK: status %d\n", pdu->u.ret_unlink.status);
			break;
		default:
			/* NOT REACHED */
			udbg("UNKNOWN\n");
	}
}
static FAR struct usbhost_class_s *
  usbhost_create(FAR struct usbhost_hubport_s *hport,
                 FAR const struct usbhost_id_s *id)
{
  FAR struct usbhost_hubclass_s *alloc;
  FAR struct usbhost_class_s *hubclass;
  FAR struct usbhost_hubpriv_s *priv;
  size_t maxlen;
  int port;
  int ret;

  /* Allocate a USB host class instance */

  alloc = kmm_zalloc(sizeof(struct usbhost_hubclass_s));
  if (alloc == NULL)
    {
      return NULL;
    }

  /* Initialize the public class structure */

  hubclass               = &alloc->hubclass;
  hubclass->hport        = hport;
  hubclass->connect      = usbhost_connect;
  hubclass->disconnected = usbhost_disconnected;

  /* Initialize the private class structure */

  priv = &alloc->hubpriv;

  /* Allocate memory for control requests */

  ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&priv->ctrlreq, &maxlen);
  if (ret < 0)
    {
      udbg("ERROR: DRVR_ALLOC failed: %d\n", ret);
      goto errout_with_hub;
    }

  /* Allocate buffer for status change (INT) endpoint. */

  ret = DRVR_IOALLOC(hport->drvr, &priv->buffer, INTIN_BUFSIZE);
  if (ret < 0)
    {
      udbg("ERROR: DRVR_IOALLOC failed: %d\n", ret);
      goto errout_with_ctrlreq;
    }

  /* Initialize semaphores (this works okay in the interrupt context) */

  sem_init(&priv->exclsem, 0, 1);

  /* Initialize per-port data */

  for (port = 0; port < USBHUB_MAX_PORTS; port++)
    {
      FAR struct usbhost_hubport_s *child;

      /* Initialize the hub port descriptor */

      child               = &priv->hport[port];
      memset(child, 0, sizeof(struct usbhost_hubport_s));

      child->drvr         = hport->drvr;
      child->parent       = hport;
      child->port         = port;
      child->speed        = USB_SPEED_FULL;
    }

  return hubclass;

errout_with_ctrlreq:
  kmm_free(priv->ctrlreq);

errout_with_hub:
  kmm_free(priv);
  return NULL;
}
Exemple #15
0
int stm32_bringup(void)
{
#ifdef HAVE_RTC_DRIVER
  FAR struct rtc_lowerhalf_s *lower;
#endif
  int ret = OK;

#ifdef CONFIG_ZEROCROSS
  /* Configure the zero-crossing driver */

  stm32_zerocross_initialize();
#endif

#ifdef CONFIG_RGBLED
  /* Configure the RGB LED driver */

  stm32_rgbled_setup();
#endif

#if defined(CONFIG_PCA9635PW)
  /* Initialize the PCA9635 chip */

  ret = stm32_pca9635_initialize();
  if (ret < 0)
    {
      sdbg("ERROR: stm32_pca9635_initialize failed: %d\n", ret);
    }
#endif

#ifdef HAVE_SDIO
  /* Initialize the SDIO block driver */

  ret = stm32_sdio_initialize();
  if (ret != OK)
    {
      fdbg("ERROR: Failed to initialize MMC/SD driver: %d\n", ret);
      return ret;
    }
#endif

#ifdef HAVE_USBHOST
  /* Initialize USB host operation.  stm32_usbhost_initialize() starts a thread
   * will monitor for USB connection and disconnection events.
   */

  ret = stm32_usbhost_initialize();
  if (ret != OK)
    {
      udbg("ERROR: Failed to initialize USB host: %d\n", ret);
      return ret;
    }
#endif

#ifdef HAVE_USBMONITOR
  /* Start the USB Monitor */

  ret = usbmonitor_start(0, NULL);
  if (ret != OK)
    {
      udbg("ERROR: Failed to start USB monitor: %d\n", ret);
      return ret;
    }
#endif

#ifdef HAVE_RTC_DRIVER
  /* Instantiate the STM32 lower-half RTC driver */

  lower = stm32_rtc_lowerhalf();
  if (!lower)
    {
      sdbg("ERROR: Failed to instantiate the RTC lower-half driver\n");
      return -ENOMEM;
    }
  else
    {
      /* Bind the lower half driver and register the combined RTC driver
       * as /dev/rtc0
       */

      ret = rtc_initialize(0, lower);
      if (ret < 0)
        {
          sdbg("ERROR: Failed to bind/register the RTC driver: %d\n", ret);
          return ret;
        }
    }
#endif

#ifdef HAVE_ELF
  /* Initialize the ELF binary loader */

  ret = elf_initialize();
  if (ret < 0)
    {
      sdbg("ERROR: Initialization of the ELF loader failed: %d\n", ret);
    }
#endif

#ifdef CONFIG_MAX31855
  ret = stm32_max31855initialize("/dev/temp0");
#endif

#ifdef CONFIG_MAX6675
  ret = stm32_max6675initialize("/dev/temp0");
#endif

#ifdef CONFIG_FS_PROCFS
  /* Mount the procfs file system */

  ret = mount(NULL, STM32_PROCFS_MOUNTPOINT, "procfs", 0, NULL);
  if (ret < 0)
    {
      sdbg("ERROR: Failed to mount procfs at %s: %d\n",
           STM32_PROCFS_MOUNTPOINT, ret);
    }
#endif

  return ret;
}
int usbhost_enumerate(FAR struct usbhost_hubport_s *hport,
                      FAR struct usbhost_class_s **devclass)
{
  FAR struct usb_ctrlreq_s *ctrlreq = NULL;
  struct usbhost_id_s id;
  size_t maxlen;
  unsigned int cfglen;
  uint8_t maxpacketsize;
  uint8_t descsize;
  uint8_t funcaddr = 0;
  FAR uint8_t *buffer = NULL;
  int ret;

  DEBUGASSERT(hport != NULL && hport->drvr != NULL);

  /* Allocate descriptor buffers for use in this function.  We will need two:
   * One for the request and one for the data buffer.
   */

  ret = DRVR_ALLOC(hport->drvr, (FAR uint8_t **)&ctrlreq, &maxlen);
  if (ret < 0)
    {
      udbg("DRVR_ALLOC failed: %d\n", ret);
      return ret;
    }

  ret = DRVR_ALLOC(hport->drvr, &buffer, &maxlen);
  if (ret < 0)
    {
      udbg("DRVR_ALLOC failed: %d\n", ret);
      goto errout;
    }

  /* Pick an appropriate packet size for this device
   *
   * USB 2.0, Paragraph 5.5.3 "Control Transfer Packet Size Constraints"
   *
   *  "An endpoint for control transfers specifies the maximum data
   *   payload size that the endpoint can accept from or transmit to
   *   the bus. The allowable maximum control transfer data payload
   *   sizes for full-speed devices is 8, 16, 32, or 64 bytes; for
   *   high-speed devices, it is 64 bytes and for low-speed devices,
   *   it is 8 bytes. This maximum applies to the data payloads of the
   *   Data packets following a Setup..."
   */

  if (hport->speed == USB_SPEED_HIGH)
    {
      /* For high-speed, we must use 64 bytes */

      maxpacketsize = 64;
      descsize      = USB_SIZEOF_DEVDESC;
    }
  else
    {
      /* Eight will work for both low- and full-speed */

      maxpacketsize = 8;
      descsize      = 8;
    }

  /* Configure EP0 with the initial maximum packet size */

  DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, 0, hport->speed,
                    maxpacketsize);

  /* Read first bytes of the device descriptor */

  ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE;
  ctrlreq->req  = USB_REQ_GETDESCRIPTOR;
  usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8));
  usbhost_putle16(ctrlreq->index, 0);
  usbhost_putle16(ctrlreq->len, descsize);

  ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
  if (ret < 0)
    {
      udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
           descsize, ret);
      goto errout;
    }

  /* Extract the correct max packetsize from the device descriptor */

  maxpacketsize = ((struct usb_devdesc_s *)buffer)->mxpacketsize;
  uvdbg("maxpacksetsize: %d\n", maxpacketsize);

  /* And reconfigure EP0 with the correct maximum packet size */

  DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, 0, hport->speed,
                    maxpacketsize);

  /* Now read the full device descriptor (if we have not already done so) */

  if (descsize < USB_SIZEOF_DEVDESC)
    {
      ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE;
      ctrlreq->req  = USB_REQ_GETDESCRIPTOR;
      usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8));
      usbhost_putle16(ctrlreq->index, 0);
      usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC);

      ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
      if (ret < 0)
        {
          udbg("ERROR: Failed to get device descriptor, length=%d: %d\n",
               USB_SIZEOF_DEVDESC, ret);
          goto errout;
        }
    }

  /* Get class identification information from the device descriptor.  Most
   * devices set this to USB_CLASS_PER_INTERFACE (zero) and provide the
   * identification information in the interface descriptor(s).  That allows
   * a device to support multiple, different classes.
   */

  (void)usbhost_devdesc((struct usb_devdesc_s *)buffer, &id);

  /* Assign a function address to the device connected to this port */

  funcaddr = usbhost_devaddr_create(hport);
  if (funcaddr < 0)
    {
      udbg("ERROR: usbhost_devaddr_create failed: %d\n", ret);
      goto errout;
    }

  /* Set the USB device address */

  ctrlreq->type = USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_DEVICE;
  ctrlreq->req  = USB_REQ_SETADDRESS;
  usbhost_putle16(ctrlreq->value, (uint16_t)funcaddr);
  usbhost_putle16(ctrlreq->index, 0);
  usbhost_putle16(ctrlreq->len, 0);

  ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
  if (ret < 0)
    {
      udbg("ERROR: Failed to set address: %d\n");
      goto errout;
    }

  usleep(2*1000);

  /* Assign the function address to the port */

  DEBUGASSERT(hport->funcaddr == 0 && funcaddr != 0);
  hport->funcaddr = funcaddr;

  /* And reconfigure EP0 with the correct address */

  DRVR_EP0CONFIGURE(hport->drvr, hport->ep0, hport->funcaddr,
                    hport->speed, maxpacketsize);

  /* Get the configuration descriptor (only), index == 0.  Should not be
   * hard-coded! More logic is needed in order to handle devices with
   * multiple configurations.
   */

  ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE;
  ctrlreq->req  = USB_REQ_GETDESCRIPTOR;
  usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8));
  usbhost_putle16(ctrlreq->index, 0);
  usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC);

  ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
  if (ret < 0)
   {
      udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
           USB_SIZEOF_CFGDESC, ret);
      goto errout;
    }

  /* Extract the full size of the configuration data */

  cfglen = (unsigned int)usbhost_getle16(((struct usb_cfgdesc_s *)buffer)->totallen);
  uvdbg("sizeof config data: %d\n", cfglen);

  /* Get all of the configuration descriptor data, index == 0 (Should not be
   * hard-coded!)
   */

  ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_RECIPIENT_DEVICE;
  ctrlreq->req  = USB_REQ_GETDESCRIPTOR;
  usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8));
  usbhost_putle16(ctrlreq->index, 0);
  usbhost_putle16(ctrlreq->len, cfglen);

  ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, buffer);
  if (ret < 0)
    {
      udbg("ERROR: Failed to get configuration descriptor, length=%d: %d\n",
           cfglen, ret);
      goto errout;
    }

  /* Select device configuration 1 (Should not be hard-coded!) */

  ctrlreq->type = USB_REQ_DIR_OUT | USB_REQ_RECIPIENT_DEVICE;
  ctrlreq->req  = USB_REQ_SETCONFIGURATION;
  usbhost_putle16(ctrlreq->value, 1);
  usbhost_putle16(ctrlreq->index, 0);
  usbhost_putle16(ctrlreq->len, 0);

  ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
  if (ret < 0)
    {
      udbg("ERROR: Failed to set configuration: %d\n", ret);
      goto errout;
    }

  /* Was the class identification information provided in the device
   * descriptor? Or do we need to find it in the interface descriptor(s)?
   */

  if (id.base == USB_CLASS_PER_INTERFACE)
    {
      /* Get the class identification information for this device from the
       * interface descriptor(s).  Hmmm.. More logic is need to handle the
       * case of multiple interface descriptors.
       */

      ret = usbhost_configdesc(buffer, cfglen, &id);
      if (ret < 0)
        {
          udbg("ERROR: usbhost_configdesc failed: %d\n", ret);
          goto errout;
        }
    }

  /* Some devices may require some delay before initialization */

  usleep(100*1000);

  /* Parse the configuration descriptor and bind to the class instance for the
   * device.  This needs to be the last thing done because the class driver
   * will begin configuring the device.
   */

  ret = usbhost_classbind(hport, buffer, cfglen, &id, devclass);
  if (ret < 0)
    {
      udbg("ERROR: usbhost_classbind failed %d\n", ret);
    }

errout:
  if (ret < 0)
    {
      /* Release the device function address on any failure */

      usbhost_devaddr_destroy(hport, funcaddr);
      hport->funcaddr = 0;
    }

  /* Release temporary buffers in any event */

  if (buffer != NULL)
    {
      DRVR_FREE(hport->drvr, buffer);
    }

  if (ctrlreq)
    {
      DRVR_FREE(hport->drvr, (FAR uint8_t *)ctrlreq);
    }

  return ret;
}
static void usbhost_hub_event(FAR void *arg)
{
  FAR struct usbhost_class_s *hubclass;
  FAR struct usbhost_hubport_s *hport;
  FAR struct usbhost_hubport_s *connport;
  FAR struct usbhost_hubpriv_s *priv;
  FAR struct usb_ctrlreq_s *ctrlreq;
  struct usb_portstatus_s portstatus;
  irqstate_t flags;
  uint16_t status;
  uint16_t change;
  uint16_t mask;
  uint16_t feat;
  uint8_t statuschange;
  int port;
  int ret;

  DEBUGASSERT(arg != NULL);
  hubclass = (FAR struct usbhost_class_s *)arg;
  priv     = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;

  /* Has the hub been disconnected? */

  if (priv->disconnected)
    {
      uvdbg("Disconnected\n");
      return;
    }

  /* No.. then set up to process the hub event */

  DEBUGASSERT(priv->ctrlreq);
  ctrlreq = priv->ctrlreq;

  DEBUGASSERT(hubclass->hport);
  hport = hubclass->hport;

  statuschange = priv->buffer[0];
  uvdbg("StatusChange: %02x\n", statuschange);

  /* Check for status change on any port */

  for (port = 1; port <= priv->nports; port++)
    {
      /* Check if port status has changed */

      if ((statuschange & (1 << port)) == 0)
        {
          continue;
        }

      uvdbg("Port %d status change\n", port);

      /* Port status changed, check what happened */

      statuschange &= ~(1 << port);

      /* Read hub port status */

      ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT;
      ctrlreq->req  = USBHUB_REQ_GETSTATUS;
      usbhost_putle16(ctrlreq->value, 0);
      usbhost_putle16(ctrlreq->index, port);
      usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);

      ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq,
                        (FAR uint8_t *)&portstatus);
      if (ret < 0)
        {
          udbg("ERROR: Failed to read port %d status: %d\n", port, ret);
          continue;
        }

      status = usbhost_getle16(portstatus.status);
      change = usbhost_getle16(portstatus.change);

      /* First, clear all change bits */

      mask = 1;
      feat = USBHUB_PORT_FEAT_CCONNECTION;
      while (change)
        {
          if (change & mask)
            {
              ctrlreq->type = USBHUB_REQ_TYPE_PORT;
              ctrlreq->req  = USBHUB_REQ_CLEARFEATURE;
              usbhost_putle16(ctrlreq->value, feat);
              usbhost_putle16(ctrlreq->index, port);
              usbhost_putle16(ctrlreq->len, 0);

              ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
              if (ret < 0)
                {
                  udbg("ERROR: Failed to clear port %d change mask %04x: %d\n",
                       port, mask, ret);
                }

              change &= (~mask);
            }

          mask <<= 1;
          feat++;
        }

      change = usbhost_getle16(portstatus.change);

      /* Handle connect or disconnect, no power management */

      if ((change & USBHUB_PORT_STAT_CCONNECTION) != 0)
        {
          uint16_t debouncetime = 0;
          uint16_t debouncestable = 0;
          uint16_t connection = 0xffff;

          uvdbg("Port %d status %04x change %04x\n", port, status, change);

          /* Debounce */

          while (debouncetime < 1500)
            {
              ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT;
              ctrlreq->req  = USBHUB_REQ_GETSTATUS;
              usbhost_putle16(ctrlreq->value, 0);
              usbhost_putle16(ctrlreq->index, port);
              usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);

              ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq,
                                (FAR uint8_t *)&portstatus);
              if (ret < 0)
                {
                  udbg("ERROR: Failed to get port %d status: %d\n", port, ret);
                  break;
                }

              status = usbhost_getle16(portstatus.status);
              change = usbhost_getle16(portstatus.change);

              if ((change & USBHUB_PORT_STAT_CCONNECTION) == 0 &&
                  (status & USBHUB_PORT_STAT_CONNECTION)  == connection)
                {
                  debouncestable += 25;
                  if (debouncestable >= 100)
                    {
                      uvdbg("Port %d debouncestable=%d\n", port, debouncestable);
                      break;
                    }
                }
              else
                {
                  debouncestable = 0;
                  connection = status & USBHUB_PORT_STAT_CONNECTION;
                }

              if ((change & USBHUB_PORT_STAT_CCONNECTION) != 0)
                {
                  ctrlreq->type = USBHUB_REQ_TYPE_PORT;
                  ctrlreq->req  = USBHUB_REQ_CLEARFEATURE;
                  usbhost_putle16(ctrlreq->value, USBHUB_PORT_FEAT_CCONNECTION);
                  usbhost_putle16(ctrlreq->index, port);
                  usbhost_putle16(ctrlreq->len, 0);

                  (void)DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
                }

              debouncetime += 25;
              usleep(25*1000);
            }

          if (ret < 0 || debouncetime >= 1500)
            {
              udbg("ERROR: Failed to debounce port %d: %d\n", port, ret);
              continue;
            }

          if ((status & USBHUB_PORT_STAT_CONNECTION) != 0)
            {
              /* Device connected to a port on the hub */

              uvdbg("Connection on port %d\n", port);

              ctrlreq->type = USBHUB_REQ_TYPE_PORT;
              ctrlreq->req  = USBHUB_REQ_SETFEATURE;
              usbhost_putle16(ctrlreq->value, USBHUB_PORT_FEAT_RESET);
              usbhost_putle16(ctrlreq->index, port);
              usbhost_putle16(ctrlreq->len, 0);

              ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
              if (ret < 0)
                {
                  udbg("ERROR: Failed to reset port %d: %d\n", port, ret);
                  continue;
                }

              usleep(100*1000);

              ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_PORT;
              ctrlreq->req  = USBHUB_REQ_GETSTATUS;
              usbhost_putle16(ctrlreq->value, 0);
              usbhost_putle16(ctrlreq->index, port);
              usbhost_putle16(ctrlreq->len, USB_SIZEOF_PORTSTS);

              ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq,
                                (FAR uint8_t *)&portstatus);
              if (ret < 0)
                {
                  udbg("ERROR: Failed to get port %d status: %d\n", port, ret);
                  continue;
                }

              status = usbhost_getle16(portstatus.status);
              change = usbhost_getle16(portstatus.change);

              uvdbg("port %d status %04x change %04x after reset\n",
                    port, status, change);

              if ((status & USBHUB_PORT_STAT_RESET)  == 0 &&
                  (status & USBHUB_PORT_STAT_ENABLE) != 0)
                {
                  if ((change & USBHUB_PORT_STAT_CRESET) != 0)
                    {
                      ctrlreq->type = USBHUB_REQ_TYPE_PORT;
                      ctrlreq->req  = USBHUB_REQ_CLEARFEATURE;
                      usbhost_putle16(ctrlreq->value, USBHUB_PORT_FEAT_CRESET);
                      usbhost_putle16(ctrlreq->index, port);
                      usbhost_putle16(ctrlreq->len, 0);

                      (void)DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
                    }

                  connport = &priv->hport[port];
                  if ((status & USBHUB_PORT_STAT_HIGH_SPEED) != 0)
                    {
                      connport->speed = USB_SPEED_HIGH;
                    }
                  else if ((status & USBHUB_PORT_STAT_LOW_SPEED) != 0)
                    {
                      connport->speed = USB_SPEED_LOW;
                    }
                  else
                    {
                      connport->speed = USB_SPEED_FULL;
                    }

                  /* Activate the hub port by assigning it a control endpoint. */

                  ret = usbhost_hport_activate(connport);
                  if (ret < 0)
                    {
                      udbg("ERROR: usbhost_hport_activate failed: %d\n", ret);
                    }
                  else
                    {
                      /* Inform waiters that a new device has been connected */

                      ret = DRVR_CONNECT(connport->drvr, connport, true);
                      if (ret < 0)
                        {
                          udbg("ERROR: DRVR_CONNECT failed: %d\n", ret);
                          usbhost_hport_deactivate(connport);
                        }
                    }
                }
              else
                {
                  udbg("ERROR: Failed to enable port %d\n", port);
                  continue;
                }
            }
          else
            {
              /* Device disconnected from a port on the hub.  Release port
               * resources.
               */

              uvdbg("Disconnection on port %d\n", port);

              /* Free any devices classes connect on this hub port */

              connport = &priv->hport[port];
              if (connport->devclass != NULL)
                {
                  CLASS_DISCONNECTED(connport->devclass);
                  connport->devclass = NULL;
                }

              /* Free any resources used by the hub port */

              usbhost_hport_deactivate(connport);
            }
        }
      else if (change)
        {
          udbg("WARNING: status %04x change %04x not handled\n", status, change);
        }
    }

  /* Check for hub status change */

  if ((statuschange & 1) != 0)
    {
      /* Hub status changed */

      udbg("WARNING: Hub status changed, not handled\n");
    }

  /* The preceding sequence of events may take a significant amount of
   * time and it is possible that the hub may have been removed while this
   * logic operated.  In any event, we will get here after several failures.
   * But we do not want to schedule another hub event if the hub has been
   * removed.
   */

  flags = irqsave();
  if (!priv->disconnected)
    {
      /* Wait for the next hub event */

      ret = DRVR_ASYNCH(hport->drvr, priv->intin, (FAR uint8_t *)priv->buffer,
                        INTIN_BUFSIZE, usbhost_callback, hubclass);
      if (ret < 0)
        {
          udbg("ERROR: Failed to queue interrupt endpoint: %d\n", ret);
        }
    }

  irqrestore(flags);
}
static inline int usbhost_hubdesc(FAR struct usbhost_class_s *hubclass)
{
  FAR struct usbhost_hubpriv_s *priv;
  FAR struct usbhost_hubport_s *hport;
  FAR struct usb_ctrlreq_s *ctrlreq;
  struct usb_hubdesc_s hubdesc;
  uint16_t hubchar;
  int ret;

  uvdbg("Read hub descriptor\n");

  DEBUGASSERT(hubclass != NULL);
  priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;

  DEBUGASSERT(hubclass->hport);
  hport  = hubclass->hport;

  /* Get the hub descriptor */

  ctrlreq = priv->ctrlreq;
  DEBUGASSERT(ctrlreq);

  ctrlreq->type = USB_REQ_DIR_IN | USBHUB_REQ_TYPE_HUB;
  ctrlreq->req  = USBHUB_REQ_GETDESCRIPTOR;
  usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_HUB << 8));
  usbhost_putle16(ctrlreq->index, 0);
  usbhost_putle16(ctrlreq->len, USB_SIZEOF_HUBDESC);

  ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, (FAR uint8_t *)&hubdesc);
  if (ret < 0)
    {
      udbg("ERROR: Failed to read hub descriptor: %d\n", ret);
      return ret;
    }

  priv->nports      = hubdesc.nports;

  hubchar           = usbhost_getle16(hubdesc.characteristics);
  priv->lpsm        = (hubchar & USBHUB_CHAR_LPSM_MASK) >> USBHUB_CHAR_LPSM_SHIFT;
  priv->compounddev = (hubchar & USBHUB_CHAR_COMPOUND) ? true : false;
  priv->ocmode      = (hubchar & USBHUB_CHAR_OCPM_MASK) >> USBHUB_CHAR_OCPM_SHIFT;
  priv->indicator   = (hubchar & USBHUB_CHAR_PORTIND) ? true : false;

  priv->pwrondelay  = (2 * hubdesc.pwrondelay);
  priv->ctrlcurrent = hubdesc.ctrlcurrent;

  uvdbg("Hub Descriptor:\n");
  uvdbg("  bDescLength:         %d\n", hubdesc.len);
  uvdbg("  bDescriptorType:     0x%02x\n", hubdesc.type);
  uvdbg("  bNbrPorts:           %d\n", hubdesc.nports);
  uvdbg("  wHubCharacteristics: 0x%04x\n", usbhost_getle16(hubdesc.characteristics));
  uvdbg("    lpsm:              %d\n", priv->lpsm);
  uvdbg("    compounddev:       %s\n", priv->compounddev ? "TRUE" : "FALSE");
  uvdbg("    ocmode:            %d\n", priv->ocmode);
  uvdbg("    indicator:         %s\n", priv->indicator ? "TRUE" : "FALSE");
  uvdbg("  bPwrOn2PwrGood:      %d\n", hubdesc.pwrondelay);
  uvdbg("    pwrondelay:        %d\n", priv->pwrondelay);
  uvdbg("  bHubContrCurrent:    %d\n", hubdesc.ctrlcurrent);
  uvdbg("  DeviceRemovable:     %d\n", hubdesc.devattached);
  uvdbg("  PortPwrCtrlMask:     %d\n", hubdesc.pwrctrlmask);

  return OK;
}
static inline int usbhost_cfgdesc(FAR struct usbhost_class_s *hubclass,
                                  FAR const uint8_t *configdesc, int desclen)
{
  FAR struct usbhost_hubpriv_s *priv;
  FAR struct usbhost_hubport_s *hport;
  FAR struct usb_cfgdesc_s *cfgdesc;
  FAR struct usb_desc_s *desc;
  FAR struct usbhost_epdesc_s intindesc;
  int remaining;
  uint8_t found = 0;
  int ret;

  DEBUGASSERT(hubclass != NULL);
  priv = &((FAR struct usbhost_hubclass_s *)hubclass)->hubpriv;

  DEBUGASSERT(hubclass->hport);
  hport = hubclass->hport;

  DEBUGASSERT(configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));

  /* Initialize the interrupt IN endpoint information (only to prevent
   * compiler complaints)
   */

  intindesc.hport        = hport;
  intindesc.addr         = 0;
  intindesc.in           = true;
  intindesc.xfrtype      = USB_EP_ATTR_XFER_INT;
  intindesc.interval     = 0;
  intindesc.mxpacketsize = 0;

  /* 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)
        {
        /* 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;

            uvdbg("Interface descriptor\n");
            DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);

            /* Save the interface number and mark ONLY the interface found */

            priv->ifno = ifdesc->ifno;
            found      = USBHOST_IFFOUND;
          }
          break;

        /* Endpoint descriptor.  Here, we expect one interrupt IN endpoints. */

        case USB_DESC_TYPE_ENDPOINT:
          {
            FAR struct usb_epdesc_s *epdesc =
              (FAR struct usb_epdesc_s *)configdesc;

            uvdbg("Endpoint descriptor\n");
            DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);

            /* Check for an interrupt endpoint. */

            if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) ==
                USB_EP_ATTR_XFER_INT)
              {
                /* Yes.. it is a interrupt endpoint.  IN or OUT? */

                if (USB_ISEPOUT(epdesc->addr))
                  {
                    /* It is an OUT interrupt endpoint. Ignore */

                    uvdbg("Interrupt OUT EP addr:%d mxpacketsize:%d\n",
                          (epdesc->addr & USB_EP_ADDR_NUMBER_MASK),
                          usbhost_getle16(epdesc->mxpacketsize));
                  }
                else
                  {
                    /* It is an IN interrupt endpoint. */

                    found |= USBHOST_EPINFOUND;

                    /* Save the interrupt IN endpoint information */

                    intindesc.addr         = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
                    intindesc.interval     = epdesc->interval;
                    intindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);

                    uvdbg("Interrupt IN EP: addr=%d interval=%d mxpacketsize=%d\n",
                          intindesc.addr, intindesc.interval, intindesc.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)
    {
      ulldbg("ERROR: Found IF=%s EPIN=%s\n",
             (found & USBHOST_IFFOUND) != 0  ? "YES" : "NO",
             (found & USBHOST_EPINFOUND) != 0 ? "YES" : "NO");
      return -EINVAL;
    }

  /* We are good... Allocate the interrupt IN endpoint */

  ret = DRVR_EPALLOC(hport->drvr, &intindesc, &priv->intin);
  if (ret < 0)
    {
      udbg("ERROR: Failed to allocate Interrupt IN endpoint: %d\n", ret);
      (void)DRVR_EPFREE(hport->drvr, priv->intin);
      return ret;
    }

  ullvdbg("Endpoint allocated\n");
  return OK;
}
static inline int usbhost_cfgdesc(FAR struct usbhost_state_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;
  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 dscriptors to examine */

  while (remaining >= sizeof(struct usb_desc_s))
    {
      /* What is the next descriptor? */

      desc = (FAR struct usb_desc_s *)configdesc;
      switch (desc->type)
        {
        /* 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;

            uvdbg("Interface descriptor\n");
            DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);

            /* Save the interface number and mark ONLY the interface found */

            priv->ifno = ifdesc->ifno;
            found      = USBHOST_IFFOUND;
          }
          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;

            uvdbg("Endpoint descriptor\n");
            DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);

            /* Check for a bulk endpoint. */

            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);
                    uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n",
                          boutdesc.addr, 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);
                    uvdbg("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)
    {
      ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
             (found & USBHOST_IFFOUND) != 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->epout);
  if (ret < 0)
    {
      udbg("ERROR: Failed to allocate Bulk OUT endpoint\n");
      return ret;
    }

  ret = DRVR_EPALLOC(hport->drvr, &bindesc, &priv->epin);
  if (ret < 0)
    {
      udbg("ERROR: Failed to allocate Bulk IN endpoint\n");
      (void)DRVR_EPFREE(hport->drvr, priv->epout);
      return ret;
    }

  ullvdbg("Endpoints allocated\n");
  return OK;
}
Exemple #21
0
 /*  Send/receive messages over TCP/IP. I refer drivers/block/nbd.c */
int usbip_xmit(int send, struct socket *sock, char *buf, int size, int msg_flags)
{
	int result;
	struct msghdr msg;
	struct kvec iov;
	int total = 0;

	/* for blocks of if (dbg_flag_xmit) */
	char *bp = buf;
	int osize= size;

	dbg_xmit("enter\n");

	if (!sock || !buf || !size) {
		uerr("usbip_xmit: invalid arg, sock %p buff %p size %d\n",
				sock, buf, size);
		return -EINVAL;
	}


	if (dbg_flag_xmit) {
		if (send) {
			if (!in_interrupt())
				printk(KERN_DEBUG "%-10s:", current->comm);
			else
				printk(KERN_DEBUG "interupt  :");

			printk("usbip_xmit: sending... , sock %p, buf %p, size %d, msg_flags %d\n",
					sock, buf, size, msg_flags);
			usbip_dump_buffer(buf, size);
		}
	}


	do {
		sock->sk->sk_allocation = GFP_NOIO;
		iov.iov_base    = buf;
		iov.iov_len     = size;
		msg.msg_name    = NULL;
		msg.msg_namelen = 0;
		msg.msg_control = NULL;
		msg.msg_controllen = 0;
		msg.msg_namelen    = 0;
		msg.msg_flags      = msg_flags | MSG_NOSIGNAL;

		if (send)
			result = kernel_sendmsg(sock, &msg, &iov, 1, size);
		else
			result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL);

		if (result <= 0) {
			udbg("usbip_xmit: %s sock %p buf %p size %u ret %d total %d\n",
					send ? "send" : "receive", sock, buf, size, result, total);
			goto err;
		}

		size -= result;
		buf += result;
		total += result;

	} while (size > 0);


	if (dbg_flag_xmit) {
		if (!send) {
			if (!in_interrupt())
				printk(KERN_DEBUG "%-10s:", current->comm);
			else
				printk(KERN_DEBUG "interupt  :");

			printk("usbip_xmit: receiving....\n");
			usbip_dump_buffer(bp, osize);
			printk("usbip_xmit: received, osize %d ret %d size %d total %d\n",
					osize, result, size, total);
		}

		if (send) {
			printk("usbip_xmit: send, total %d\n", total);
		}
	}

	return total;

err:
	return result;
}
Exemple #22
0
int board_app_initialize(uintptr_t arg)
{
#ifdef HAVE_RTC_DRIVER
  FAR struct rtc_lowerhalf_s *rtclower;
#endif
#if defined(HAVE_N25QXXX)
FAR struct mtd_dev_s *mtd_temp;
#endif
#if defined(HAVE_N25QXXX_CHARDEV)
  char blockdev[18];
  char chardev[12];
#endif
  int ret;

  (void)ret;

#ifdef HAVE_PROC
  /* mount the proc filesystem */

  syslog(LOG_INFO, "Mounting procfs to /proc\n");

  ret = mount(NULL, CONFIG_NSH_PROC_MOUNTPOINT, "procfs", 0, NULL);
  if (ret < 0)
    {
      syslog(LOG_ERR,
             "ERROR: Failed to mount the PROC filesystem: %d (%d)\n",
             ret, errno);
      return ret;
    }
#endif

#ifdef HAVE_RTC_DRIVER
  /* Instantiate the STM32 lower-half RTC driver */

  rtclower = stm32l4_rtc_lowerhalf();
  if (!rtclower)
    {
      serr("ERROR: Failed to instantiate the RTC lower-half driver\n");
      return -ENOMEM;
    }
  else
    {
      /* Bind the lower half driver and register the combined RTC driver
       * as /dev/rtc0
       */

      ret = rtc_initialize(0, rtclower);
      if (ret < 0)
        {
          serr("ERROR: Failed to bind/register the RTC driver: %d\n", ret);
          return ret;
        }
    }
#endif

#ifdef HAVE_N25QXXX
  /* Create an instance of the STM32L4 QSPI device driver */

  g_qspi = stm32l4_qspi_initialize(0);
  if (!g_qspi)
    {
      _err("ERROR: stm32l4_qspi_initialize failed\n");
      return ret;
    }
  else
    {
      /* Use the QSPI device instance to initialize the
       * N25QXXX device.
       */

      mtd_temp = n25qxxx_initialize(g_qspi, true);
      if (!mtd_temp)
        {
          _err("ERROR: n25qxxx_initialize failed\n");
          return ret;
        }
      g_mtd_fs = mtd_temp;

#ifdef CONFIG_MTD_PARTITION
      {
        FAR struct mtd_geometry_s geo;
        off_t nblocks;

        /* Setup a partition of 256KiB for our file system. */

        ret = MTD_IOCTL(g_mtd_fs, MTDIOC_GEOMETRY, (unsigned long)(uintptr_t)&geo);
        if (ret < 0)
          {
            _err("ERROR: MTDIOC_GEOMETRY failed\n");
            return ret;
          }

        nblocks = (256*1024) / geo.blocksize;

        mtd_temp = mtd_partition(g_mtd_fs, 0, nblocks);
        if (!mtd_temp)
          {
            _err("ERROR: mtd_partition failed\n");
            return ret;
          }

        g_mtd_fs = mtd_temp;
      }
#endif

#ifdef HAVE_N25QXXX_SMARTFS
      /* Configure the device with no partition support */

      ret = smart_initialize(N25QXXX_SMART_MINOR, g_mtd_fs, NULL);
      if (ret != OK)
        {
          _err("ERROR: Failed to initialize SmartFS: %d\n", ret);
        }

#elif defined(HAVE_N25QXXX_NXFFS)
      /* Initialize to provide NXFFS on the N25QXXX MTD interface */

      ret = nxffs_initialize(g_mtd_fs);
      if (ret < 0)
        {
         _err("ERROR: NXFFS initialization failed: %d\n", ret);
        }

      /* Mount the file system at /mnt/nxffs */

      ret = mount(NULL, "/mnt/nxffs", "nxffs", 0, NULL);
      if (ret < 0)
        {
          _err("ERROR: Failed to mount the NXFFS volume: %d\n", errno);
          return ret;
        }

#else /* if  defined(HAVE_N25QXXX_CHARDEV) */
      /* Use the FTL layer to wrap the MTD driver as a block driver */

      ret = ftl_initialize(N25QXXX_MTD_MINOR, g_mtd_fs);
      if (ret < 0)
        {
          _err("ERROR: Failed to initialize the FTL layer: %d\n", ret);
          return ret;
        }

      /* Use the minor number to create device paths */

      snprintf(blockdev, 18, "/dev/mtdblock%d", N25QXXX_MTD_MINOR);
      snprintf(chardev, 12, "/dev/mtd%d", N25QXXX_MTD_MINOR);

      /* Now create a character device on the block device */

      /* NOTE:  for this to work, you will need to make sure that
       * CONFIG_FS_WRITABLE is set in the config.  It's not a user-
       * visible setting, but you can make it set by selecting an
       * arbitrary writable file system (you don't have to actually
       * use it, just select it so that the block device created via
       * ftl_initialize() will be writable).
       */

      ret = bchdev_register(blockdev, chardev, false);
      if (ret < 0)
        {
          _err("ERROR: bchdev_register %s failed: %d\n", chardev, ret);
          return ret;
        }
#endif
    }
#endif

#ifdef HAVE_USBHOST
  /* Initialize USB host operation.  stm32l4_usbhost_initialize() starts a thread
   * will monitor for USB connection and disconnection events.
   */

  ret = stm32l4_usbhost_initialize();
  if (ret != OK)
    {
      udbg("ERROR: Failed to initialize USB host: %d\n", ret);
      return ret;
    }
#endif

#ifdef HAVE_USBMONITOR
  /* Start the USB Monitor */

  ret = usbmonitor_start(0, NULL);
  if (ret != OK)
    {
      udbg("ERROR: Failed to start USB monitor: %d\n", ret);
      return ret;
    }
#endif

  return OK;
}