sim/usb: add sim usb host

signed-off-by: zhangyuan21 <zhangyuan21@xiaomi.com>
This commit is contained in:
zhangyuan21 2022-11-30 19:08:14 +08:00 committed by Alan Carvalho de Assis
parent c61c694a77
commit 0af63cfc48
10 changed files with 1746 additions and 0 deletions

View File

@ -635,4 +635,39 @@ config SIM_USB_RAW_GADGET
endif
config SIM_USB_HOST
bool "Linux USB Host"
select USBHOST
select USBHOST_HAVE_ASYNCH
select USBHOST_ASYNCH
---help---
Build in support for simulated usb host
if SIM_USB_HOST
config SIM_LIBUSB
bool "Simulated USB Host use libusb"
default n
depends on HOST_LINUX
---help---
Use libusb to set up virtual USB Host controller.
config SIM_USB_VID
hex "Simulated USB Dev VID"
default 0x18d1
config SIM_USB_PID
hex "Simulated USB Dev PID"
default 0x4e11
config SIM_USB_STACKSIZE
int "Simulated USB waiter stack size"
default 1024
config SIM_USB_PRIO
int "Simulated USB waiter task priority"
default 100
endif
endif # ARCH_SIM

View File

@ -205,6 +205,14 @@ ifeq ($(CONFIG_SIM_USB_RAW_GADGET),y)
endif
endif
ifeq ($(CONFIG_SIM_USB_HOST),y)
CSRCS += sim_usbhost.c
ifeq ($(CONFIG_SIM_LIBUSB),y)
HOSTSRCS += sim_libusb.c
STDLIBS += -lusb-1.0
endif
endif
ifeq ($(CONFIG_RPTUN),y)
CSRCS += sim_rptun.c
endif

View File

@ -0,0 +1,700 @@
/****************************************************************************
* arch/sim/src/sim/posix/sim_libusb.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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <pthread.h>
#include <linux/usb/ch9.h>
#include <libusb-1.0/libusb.h>
#include "sim_usbhost.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ERROR(fmt, ...) \
syslog(LOG_ERR, "sim_libusb: " fmt "\n", ##__VA_ARGS__)
#define INFO(fmt, ...) \
syslog(LOG_INFO, "sim_libusb: " fmt "\n", ##__VA_ARGS__)
#define DEBUG(fmt, ...)
#define HOST_LIBUSB_EP_NUM(addr) ((addr) & USB_ENDPOINT_NUMBER_MASK)
#define HOST_LIBUSB_EP_DIR(addr) ((addr) & USB_ENDPOINT_DIR_MASK)
#ifdef CONFIG_SIM_USB_VID
# define USB_VID CONFIG_SIM_USB_VID
#else
# define USB_VID 0x18d1
#endif
#ifdef CONFIG_SIM_USB_PID
# define USB_PID CONFIG_SIM_USB_PID
#else
# define USB_PID 0x4e11
#endif
#define HOST_LIBUSB_FIFO_NUM 8
#define HOST_LIBUSB_FIFO_USED(fifo) \
((fifo)->write - (fifo)->read)
#define HOST_LIBUSB_FIFO_PUSH(fifo) \
((fifo)->write++)
#define HOST_LIBUSB_FIFO_POP(fifo) \
((fifo)->read++)
/****************************************************************************
* Private Types
****************************************************************************/
struct host_libusb_fifo_s
{
uint16_t read;
uint16_t write;
struct host_usb_datareq_s *datareq[HOST_LIBUSB_FIFO_NUM];
};
struct host_libusb_hostdev_s
{
libusb_device *priv;
libusb_device_handle *handle;
struct libusb_device_descriptor dev_desc;
struct libusb_config_descriptor **config_desc;
libusb_hotplug_callback_handle callback_handle;
struct host_libusb_fifo_s completed;
pthread_t handle_thread;
bool connected;
};
/****************************************************************************
* Private Data
****************************************************************************/
static libusb_context *g_libusb_context;
static struct host_libusb_hostdev_s g_libusb_dev;
static libusb_device **g_libusb_dev_list;
/****************************************************************************
* Private Functions
****************************************************************************/
static void host_libusb_fifoinit(struct host_libusb_fifo_s *fifo)
{
fifo->write = 0;
fifo->read = 0;
}
static struct host_usb_datareq_s *
host_libusb_fifopop(struct host_libusb_fifo_s *fifo)
{
struct host_usb_datareq_s *datareq;
uint16_t r_idx;
if (HOST_LIBUSB_FIFO_USED(fifo) == 0)
{
return NULL;
}
r_idx = fifo->read & (HOST_LIBUSB_FIFO_NUM - 1);
datareq = fifo->datareq[r_idx];
fifo->read++;
return datareq;
}
static bool host_libusb_fifopush(struct host_libusb_fifo_s *fifo,
struct host_usb_datareq_s *datareq)
{
uint16_t w_idx;
if (HOST_LIBUSB_FIFO_USED(fifo) == HOST_LIBUSB_FIFO_NUM)
{
ERROR("USB get fifo fail");
return false;
}
w_idx = fifo->write & (HOST_LIBUSB_FIFO_NUM - 1);
fifo->datareq[w_idx] = datareq;
fifo->write++;
return true;
}
static void
host_libusb_getctrlreq(struct usb_ctrlrequest *libusb_req,
const struct host_usb_ctrlreq_s *host_req)
{
libusb_req->bRequestType = host_req->type;
libusb_req->bRequest = host_req->req;
libusb_req->wValue = host_req->value;
libusb_req->wIndex = host_req->index;
libusb_req->wLength = host_req->len;
}
static void host_libusb_ep0transfer_cb(struct libusb_transfer *transfer)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
struct host_usb_datareq_s *datareq;
uint8_t *buffer;
if (!transfer)
{
ERROR("host_libusb_ep0transfer_cb() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_INVALID_PARAM));
return;
}
datareq = (struct host_usb_datareq_s *)transfer->user_data;
buffer = libusb_control_transfer_get_data(transfer);
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
datareq->success = true;
datareq->xfer += transfer->actual_length;
memcpy(datareq->data, buffer, transfer->actual_length);
}
else
{
datareq->success = false;
}
free(buffer - LIBUSB_CONTROL_SETUP_SIZE);
host_libusb_fifopush(&dev->completed, datareq);
libusb_free_transfer(transfer);
}
static void host_libusb_bulktransfer_cb(struct libusb_transfer *transfer)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
struct host_usb_datareq_s *datareq;
if (!transfer)
{
ERROR("host_libusb_bulktransfer_cb() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_INVALID_PARAM));
return;
}
datareq = (struct host_usb_datareq_s *)transfer->user_data;
if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
{
datareq->success = false;
goto transfer_end;
}
datareq->xfer += transfer->actual_length;
if ((datareq->xfer >= datareq->len) ||
(datareq->addr & USB_DIR_IN) != 0)
{
datareq->success = true;
goto transfer_end;
}
libusb_fill_bulk_transfer(transfer, dev->handle, datareq->addr,
datareq->data + datareq->xfer,
datareq->len - datareq->xfer,
host_libusb_bulktransfer_cb,
datareq, 0);
if (libusb_submit_transfer(transfer) != LIBUSB_SUCCESS)
{
datareq->success = false;
goto transfer_end;
}
return;
transfer_end:
host_libusb_fifopush(&dev->completed, datareq);
libusb_free_transfer(transfer);
}
static void host_libusb_inttransfer_cb(struct libusb_transfer *transfer)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
struct host_usb_datareq_s *datareq;
if (!transfer)
{
ERROR("host_libusb_inttransfer_cb() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_INVALID_PARAM));
return;
}
datareq = (struct host_usb_datareq_s *)transfer->user_data;
if (transfer->status == LIBUSB_TRANSFER_COMPLETED)
{
datareq->success = true;
datareq->xfer += transfer->actual_length;
}
else
{
datareq->success = false;
}
host_libusb_fifopush(&dev->completed, datareq);
libusb_free_transfer(transfer);
}
static int host_libusb_ep0inhandle(struct host_libusb_hostdev_s *dev,
struct usb_ctrlrequest *ctrlreq,
struct host_usb_datareq_s *datareq,
int timeout)
{
struct libusb_transfer *transfer;
uint8_t *buffer;
int ret = LIBUSB_SUCCESS;
if (!dev->handle)
{
ERROR("host_libusb_ep0inhandle() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_DEVICE));
return LIBUSB_ERROR_NO_DEVICE;
}
buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + ctrlreq->wLength);
if (!buffer)
{
ERROR("control data buffer malloc() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_MEM));
return LIBUSB_ERROR_NO_MEM;
}
transfer = libusb_alloc_transfer(0);
if (!transfer)
{
ERROR("libusb_alloc_transfer() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_MEM));
ret = LIBUSB_ERROR_NO_MEM;
goto err_with_buffer;
}
libusb_fill_control_setup(buffer, ctrlreq->bRequestType,
ctrlreq->bRequest, ctrlreq->wValue,
ctrlreq->wIndex, ctrlreq->wLength);
libusb_fill_control_transfer(transfer, dev->handle, buffer,
host_libusb_ep0transfer_cb,
datareq, timeout);
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
goto err_with_transfer;
}
return LIBUSB_SUCCESS;
err_with_transfer:
libusb_free_transfer(transfer);
err_with_buffer:
free(buffer);
return ret;
}
static int host_libusb_ep0outhandle(struct host_libusb_hostdev_s *dev,
struct usb_ctrlrequest *ctrlreq)
{
int ret = LIBUSB_SUCCESS;
if (!dev->handle)
{
ERROR("host_libusb_control_request() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_DEVICE));
return LIBUSB_ERROR_NO_DEVICE;
}
if ((ctrlreq->bRequestType & USB_TYPE_MASK) !=
USB_TYPE_STANDARD)
{
return ret;
}
switch (ctrlreq->bRequest)
{
case USB_REQ_SET_CONFIGURATION:
ret = libusb_detach_kernel_driver(dev->handle, 0);
if (ret == LIBUSB_SUCCESS)
{
ret = libusb_set_configuration(dev->handle,
ctrlreq->wValue);
ret |= libusb_claim_interface(dev->handle, 0);
}
break;
case USB_REQ_SET_INTERFACE: /* TODO */
break;
default:
break;
}
return ret;
}
static int
host_libusb_bulktransfer(struct host_libusb_hostdev_s *dev, uint8_t addr,
struct host_usb_datareq_s *datareq)
{
struct libusb_transfer *transfer;
int ret = LIBUSB_SUCCESS;
transfer = libusb_alloc_transfer(0);
if (!transfer)
{
ERROR("libusb_alloc_transfer() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_MEM));
return LIBUSB_ERROR_NO_MEM;
}
libusb_fill_bulk_transfer(transfer, dev->handle, addr,
datareq->data, datareq->len,
host_libusb_bulktransfer_cb,
datareq, 0);
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
libusb_free_transfer(transfer);
}
return ret;
}
static int
host_libusb_inttransfer(struct host_libusb_hostdev_s *dev, uint8_t addr,
struct host_usb_datareq_s *datareq)
{
struct libusb_transfer *transfer;
int ret = LIBUSB_SUCCESS;
transfer = libusb_alloc_transfer(0);
if (!transfer)
{
ERROR("libusb_alloc_transfer() fail: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_MEM));
return LIBUSB_ERROR_NO_MEM;
}
libusb_fill_interrupt_transfer(transfer, dev->handle, addr,
datareq->data, datareq->len,
host_libusb_inttransfer_cb,
datareq, 0);
ret = libusb_submit_transfer(transfer);
if (ret != LIBUSB_SUCCESS)
{
libusb_free_transfer(transfer);
}
return ret;
}
static void *host_libusb_event_handle(void *arg)
{
while (1)
{
libusb_handle_events(g_libusb_context);
}
return NULL;
}
static bool host_libusb_connectdevice(void)
{
int dev_cnt;
int i;
dev_cnt = libusb_get_device_list(g_libusb_context,
&g_libusb_dev_list);
if (dev_cnt < 0)
{
ERROR("libusb_get_device_list() failed: %s\n",
libusb_strerror(dev_cnt));
return false;
}
for (i = 0; i < dev_cnt; i++)
{
libusb_device *dev = g_libusb_dev_list[i];
struct libusb_device_descriptor dev_desc;
int ret = libusb_get_device_descriptor(dev, &dev_desc);
if (ret != LIBUSB_SUCCESS)
{
ERROR("libusb_get_device_descriptor() failed: %s\n",
libusb_strerror(ret));
continue;
}
if (dev_desc.bDeviceClass == LIBUSB_CLASS_HUB)
{
continue;
}
if (dev_desc.idVendor == USB_VID ||
dev_desc.idProduct == USB_PID)
{
g_libusb_dev.priv = dev;
memcpy(&g_libusb_dev.dev_desc, &dev_desc,
sizeof(struct libusb_device_descriptor));
return true;
}
}
libusb_free_device_list(g_libusb_dev_list, 1);
g_libusb_dev_list = NULL;
return false;
}
static int host_libusb_hotplug_callback(libusb_context *ctx,
libusb_device *device,
libusb_hotplug_event event,
void *user_data)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
INFO("Hotplug event: %d\n", event);
if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)
{
dev->connected = true;
}
else
{
dev->connected = false;
}
return LIBUSB_SUCCESS;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int host_usbhost_ep0trans(struct host_usb_ctrlreq_s *ctrlreq,
struct host_usb_datareq_s *datareq)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
struct usb_ctrlrequest libusb_ctrlreq;
int ret;
host_libusb_getctrlreq(&libusb_ctrlreq, ctrlreq);
if (!(libusb_ctrlreq.bRequestType & USB_DIR_IN))
{
ret = host_libusb_ep0outhandle(dev, &libusb_ctrlreq);
datareq->success = (ret != LIBUSB_SUCCESS) ? false : true;
host_libusb_fifopush(&dev->completed, datareq);
}
else
{
ret = host_libusb_ep0inhandle(dev, &libusb_ctrlreq,
datareq, 0);
if (ret != LIBUSB_SUCCESS)
{
datareq->success = false;
host_libusb_fifopush(&dev->completed, datareq);
}
}
return ret;
}
int host_usbhost_eptrans(struct host_usb_datareq_s *datareq)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
int ret = LIBUSB_SUCCESS;
switch (datareq->xfrtype & USB_ENDPOINT_XFERTYPE_MASK)
{
case USB_ENDPOINT_XFER_BULK:
ret = host_libusb_bulktransfer(dev, datareq->addr, datareq);
break;
case USB_ENDPOINT_XFER_INT:
ret = host_libusb_inttransfer(dev, datareq->addr, datareq);
break;
default:
ERROR("Unsupported transfer type");
ret = LIBUSB_ERROR_NOT_SUPPORTED;
break;
}
if (ret != LIBUSB_SUCCESS)
{
datareq->success = false;
host_libusb_fifopush(&dev->completed, datareq);
}
return ret;
}
int host_usbhost_open(void)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
uint8_t cnt;
int ret;
if (!dev->priv)
{
if (!host_libusb_connectdevice())
{
ERROR("host_libusb_connectdevice() failed\n");
goto err_out;
}
}
ret = libusb_open(dev->priv, &dev->handle);
if (ret != LIBUSB_SUCCESS)
{
ERROR("libusb_open() failed: %s\n", libusb_strerror(ret));
goto err_out;
}
ret = libusb_set_auto_detach_kernel_driver(dev->handle, 1);
if (ret != LIBUSB_SUCCESS)
{
ERROR("libusb_set_auto_detach_kernel_driver() failed: %s\n",
libusb_strerror(ret));
goto err_out;
}
dev->config_desc = (struct libusb_config_descriptor **)
malloc(dev->dev_desc.bNumConfigurations
*(sizeof(struct libusb_config_descriptor *)));
if (!dev->config_desc)
{
ERROR("host_libusb_devinit() malloc failed: %s\n",
libusb_strerror(LIBUSB_ERROR_NO_MEM));
ret = LIBUSB_ERROR_NO_MEM;
goto err_out;
}
for (cnt = 0; cnt < dev->dev_desc.bNumConfigurations; cnt++)
{
ret = libusb_get_config_descriptor(dev->priv, cnt,
&dev->config_desc[cnt]);
if (ret != LIBUSB_SUCCESS)
{
ERROR("libusb_get_config_descriptor() failed: %s\n",
libusb_strerror(ret));
goto err_out;
}
}
host_libusb_fifoinit(&dev->completed);
return LIBUSB_SUCCESS;
err_out:
host_usbhost_close();
return ret;
}
void host_usbhost_close(void)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
dev->priv = NULL;
if (dev->config_desc)
{
free(dev->config_desc);
dev->config_desc = NULL;
}
if (dev->handle)
{
libusb_close(dev->handle);
dev->handle = NULL;
}
if (g_libusb_dev_list)
{
libusb_free_device_list(g_libusb_dev_list, 1);
g_libusb_dev_list = NULL;
}
}
struct host_usb_datareq_s *host_usbhost_getcomplete(void)
{
struct host_libusb_hostdev_s *dev = &g_libusb_dev;
return host_libusb_fifopop(&dev->completed);
}
bool host_usbhost_getconnstate(void)
{
return g_libusb_dev.connected;
}
int host_usbhost_init(void)
{
int ret;
ret = libusb_init(&g_libusb_context);
if (ret < 0)
{
ERROR("libusb_init() failed: %s\n", libusb_strerror(ret));
return ret;
}
ret = libusb_hotplug_register_callback(g_libusb_context,
(libusb_hotplug_event) (LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT |
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED),
(libusb_hotplug_flag) 0, USB_VID, USB_PID,
LIBUSB_HOTPLUG_MATCH_ANY, host_libusb_hotplug_callback,
NULL, NULL);
if (ret != LIBUSB_SUCCESS)
{
ERROR("libusb_hotplug_register_callback() failed: %s\n",
libusb_strerror(ret));
return ret;
}
g_libusb_dev.connected = host_libusb_connectdevice();
ret = pthread_create(&g_libusb_dev.handle_thread, NULL,
host_libusb_event_handle, NULL);
if (ret < 0)
{
ERROR("pthread_create() failed\n");
return LIBUSB_ERROR_INVALID_PARAM;
}
return LIBUSB_SUCCESS;
}

View File

@ -216,6 +216,10 @@ static int sim_loop_task(int argc, char **argv)
sched_unlock();
up_irq_restore(flags);
#ifdef CONFIG_SIM_USB_HOST
sim_usbhost_loop();
#endif
/* Sleep minimal time, let the idle run */
usleep(CONFIG_SIM_LOOPTASK_INTERVAL);
@ -297,6 +301,10 @@ void up_initialize(void)
sim_usbdev_initialize();
#endif
#ifdef CONFIG_SIM_USB_HOST
sim_usbhost_initialize();
#endif
kthread_create("loop_task", SCHED_PRIORITY_MAX,
CONFIG_DEFAULT_TASK_STACKSIZE,
sim_loop_task, NULL);

View File

@ -390,6 +390,13 @@ void sim_usbdev_initialize(void);
int sim_usbdev_loop(void);
#endif
/* sim_usbhost.c ************************************************************/
#ifdef CONFIG_SIM_USB_HOST
int sim_usbhost_initialize(void);
int sim_usbhost_loop(void);
#endif
/* Debug ********************************************************************/
#ifdef CONFIG_STACK_COLORATION

View File

@ -0,0 +1,803 @@
/****************************************************************************
* arch/sim/src/sim/sim_usbhost.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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/kthread.h>
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbhost.h>
#include <nuttx/usb/usbhost_trace.h>
#include "sim_usbhost.h"
#include "sim_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define SIM_USBHOST_BUFSIZE 256
#define RHPNDX(rh) ((rh)->hport.hport.port)
#define RHPORT(rh) (RHPNDX(rh)+1)
#ifndef MIN
# define MIN(a,b) ((a) > (b) ? (b) : (a))
#endif
/****************************************************************************
* Private Types
****************************************************************************/
enum sim_hoststate_e
{
USB_HOST_DETACHED = 0, /* Not attached to a device */
USB_HOST_ATTACHED, /* Attached to a device */
USB_HOST_ENUM, /* Attached, enumerating */
USB_HOST_CLASS_BOUND, /* Enumeration complete, class bound */
};
struct sim_epinfo_s
{
uint8_t epno:7; /* Endpoint number */
uint8_t dirin:1; /* 1:IN endpoint 0:OUT endpoint */
uint8_t devaddr:7; /* Device address */
uint8_t toggle:1; /* Next data toggle */
uint8_t interval; /* Polling interval */
uint8_t status; /* Retained token status bits (for debug purposes) */
uint16_t maxpacket:11; /* Maximum packet size */
uint16_t xfrtype:2; /* See USB_EP_ATTR_XFER_* definitions in usb.h */
uint16_t speed:2; /* See USB_*_SPEED definitions */
int result; /* The result of the transfer */
uint32_t xfrd; /* On completion, will hold the number of bytes transferred */
sem_t iocsem; /* Semaphore used to wait for transfer completion */
};
struct sim_usbhost_s
{
/* Common device fields. This must be the first thing defined in the
* structure so that it is possible to simply cast from struct usbhost_s
* to struct sim_usbhost_s.
*/
struct usbhost_driver_s drvr;
/* This is the hub port description understood by class drivers */
struct usbhost_roothubport_s hport;
/* Root hub port status */
volatile bool connected; /* Connected to device */
struct sim_epinfo_s ep0; /* EP0 endpoint info */
uint8_t state;
volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */
mutex_t lock; /* Support mutually exclusive access */
sem_t pscsem; /* Semaphore to wait for port status change events */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* USB host connection operations *******************************************/
static int sim_usbhost_wait(struct usbhost_connection_s *conn,
struct usbhost_hubport_s **hport);
static int sim_usbhost_enumerate(struct usbhost_connection_s *conn,
struct usbhost_hubport_s *hport);
/* USB host driver operations ***********************************************/
static int sim_usbhost_ep0configure(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep0, uint8_t funcaddr,
uint8_t speed, uint16_t maxpacketsize);
static int sim_usbhost_epalloc(FAR struct usbhost_driver_s *drvr,
FAR const struct usbhost_epdesc_s *epdesc,
FAR usbhost_ep_t *ep);
static int sim_usbhost_epfree(FAR struct usbhost_driver_s *drvr,
FAR usbhost_ep_t ep);
static int sim_usbhost_alloc(FAR struct usbhost_driver_s *drvr,
FAR uint8_t **buffer, FAR size_t *maxlen);
static int sim_usbhost_free(FAR struct usbhost_driver_s *drvr,
FAR uint8_t *buffer);
static int sim_usbhost_ioalloc(FAR struct usbhost_driver_s *drvr,
FAR uint8_t **buffer, size_t buflen);
static int sim_usbhost_iofree(FAR struct usbhost_driver_s *drvr,
FAR uint8_t *buffer);
static int sim_usbhost_ctrlin(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep0,
FAR const struct usb_ctrlreq_s *req,
FAR uint8_t *buffer);
static int sim_usbhost_ctrlout(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep0,
FAR const struct usb_ctrlreq_s *req,
FAR const uint8_t *buffer);
static ssize_t sim_usbhost_transfer(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep, FAR uint8_t *buffer,
size_t buflen);
static int sim_usbhost_cancel(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep);
static void sim_usbhost_disconnect(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_hubport_s *hport);
/****************************************************************************
* Private Data
****************************************************************************/
static struct sim_usbhost_s g_sim_usbhost =
{
.lock = NXMUTEX_INITIALIZER,
.pscsem = SEM_INITIALIZER(0),
.ep0.iocsem = SEM_INITIALIZER(1),
};
static struct usbhost_connection_s g_sim_usbconn =
{
.wait = sim_usbhost_wait,
.enumerate = sim_usbhost_enumerate,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sim_usbhost_allocrq
****************************************************************************/
static struct host_usb_datareq_s *sim_usbhost_allocrq(void)
{
struct host_usb_datareq_s *req;
req = zalloc(sizeof(struct host_usb_datareq_s));
if (req)
{
req->success = false;
}
return req;
}
/****************************************************************************
* Name: sim_usbhost_freerq
****************************************************************************/
static void sim_usbhost_freerq(struct host_usb_datareq_s *req)
{
DEBUGASSERT(req);
free(req);
}
/****************************************************************************
* Name: sim_usbhost_getctrlreq
****************************************************************************/
static void
sim_usbhost_getctrlreq(struct host_usb_ctrlreq_s *host_req,
const struct usb_ctrlreq_s *ctr_req)
{
host_req->type = ctr_req->type;
host_req->req = ctr_req->req;
host_req->value = GETUINT16(ctr_req->value);
host_req->index = GETUINT16(ctr_req->index);
host_req->len = GETUINT16(ctr_req->len);
}
/****************************************************************************
* Name: sim_usbhost_waittask
****************************************************************************/
static int sim_usbhost_waittask(int argc, char *argv[])
{
struct usbhost_connection_s *conn = &g_sim_usbconn;
struct usbhost_hubport_s *hport;
for (; ; )
{
/* Wait for the device to change state */
CONN_WAIT(conn, &hport);
uinfo("%s\n", hport->connected ? "connected" : "disconnected");
/* Did we just become connected? */
if (hport->connected)
{
/* Yes.. enumerate the newly connected device */
CONN_ENUMERATE(conn, hport);
}
}
return 0;
}
/****************************************************************************
* Name: sim_usbhost_wait
****************************************************************************/
static int sim_usbhost_wait(struct usbhost_connection_s *conn,
struct usbhost_hubport_s **hport)
{
struct sim_usbhost_s *priv = &g_sim_usbhost;
irqstate_t flags;
int ret;
/* Loop until the connection state changes on one of the root hub ports or
* until an error occurs.
*/
flags = enter_critical_section();
for (; ; )
{
/* Check for a change in the connection state on any root hub port */
struct usbhost_hubport_s *connport;
/* Has the connection state changed on the RH port? */
connport = &priv->hport.hport;
if (priv->connected != connport->connected)
{
/* Yes.. Return the RH port to inform the caller which
* port has the connection change.
*/
connport->connected = priv->connected;
*hport = connport;
leave_critical_section(flags);
return OK;
}
/* No changes on any port. Wait for a connection/disconnection event
* and check again
*/
priv->pscwait = true;
ret = nxsem_wait_uninterruptible(&priv->pscsem);
if (ret < 0)
{
return ret;
}
}
}
/****************************************************************************
* Name: sim_usbhost_enumerate
****************************************************************************/
static int sim_usbhost_enumerate(struct usbhost_connection_s *conn,
struct usbhost_hubport_s *hport)
{
struct sim_usbhost_s *priv = &g_sim_usbhost;
int ret;
DEBUGASSERT(hport);
/* Then let the common usbhost_enumerate do the real enumeration. */
uinfo("Enumerate the device\n");
priv->state = USB_HOST_ENUM;
ret = usbhost_enumerate(hport, &hport->devclass);
/* The enumeration may fail either because of some HCD interfaces failure
* or because the device class is not supported. In either case, we just
* need to perform the disconnection operation and make ready for a new
* enumeration.
*/
if (ret < 0)
{
/* Return to the disconnected state */
uerr("ERROR: Enumeration failed: %d\n", ret);
hport->connected = false;
}
return ret;
}
/****************************************************************************
* Name: sim_usbhost_ep0configure
****************************************************************************/
static int sim_usbhost_ep0configure(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep0, uint8_t funcaddr,
uint8_t speed, uint16_t maxpacketsize)
{
struct sim_usbhost_s *priv = &g_sim_usbhost;
struct sim_epinfo_s *epinfo = (struct sim_epinfo_s *)ep0;
int ret;
DEBUGASSERT(drvr != NULL && epinfo != NULL);
ret = nxmutex_lock(&priv->lock);
if (ret >= 0)
{
/* Remember the new device address and max packet size */
epinfo->devaddr = funcaddr;
epinfo->speed = speed;
epinfo->maxpacket = maxpacketsize;
nxmutex_unlock(&priv->lock);
}
return ret;
}
/****************************************************************************
* Name: sim_usbhost_epalloc
****************************************************************************/
static int sim_usbhost_epalloc(FAR struct usbhost_driver_s *drvr,
FAR const struct usbhost_epdesc_s *epdesc,
FAR usbhost_ep_t *ep)
{
struct sim_epinfo_s *epinfo;
struct usbhost_hubport_s *hport;
/* Sanity check. NOTE that this method should only be called if a device
* is connected (because we need a valid low speed indication).
*/
DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL &&
ep != NULL);
hport = epdesc->hport;
uinfo("EP%d DIR=%s FA=%08x TYPE=%d Interval=%d MaxPacket=%d\n",
epdesc->addr, epdesc->in ? "IN" : "OUT", hport->funcaddr,
epdesc->xfrtype, epdesc->interval, epdesc->mxpacketsize);
/* Allocate a endpoint information structure */
epinfo = (struct sim_epinfo_s *)kmm_zalloc(sizeof(struct sim_epinfo_s));
if (!epinfo)
{
return -ENOMEM;
}
/* Initialize the endpoint container (which is really just another form of
* 'struct usbhost_epdesc_s', packed differently and with additional
* information. A cleaner design might just embed struct usbhost_epdesc_s
* inside of struct sim_epinfo_s and just memcpy here.
*/
epinfo->epno = epdesc->addr;
epinfo->dirin = epdesc->in;
epinfo->devaddr = hport->funcaddr;
epinfo->interval = epdesc->interval;
epinfo->maxpacket = epdesc->mxpacketsize;
epinfo->xfrtype = epdesc->xfrtype;
epinfo->speed = hport->speed;
nxsem_init(&epinfo->iocsem, 0, 0);
/* Success.. return an opaque reference to the endpoint information
* structure instance
*/
*ep = (usbhost_ep_t)epinfo;
return OK;
}
/****************************************************************************
* Name: sim_usbhost_epfree
****************************************************************************/
static int sim_usbhost_epfree(FAR struct usbhost_driver_s *drvr,
FAR usbhost_ep_t ep)
{
struct sim_epinfo_s *epinfo = (struct sim_epinfo_s *)ep;
/* There should not be any pending, transfers */
DEBUGASSERT(drvr && epinfo);
/* Free the container */
kmm_free(epinfo);
return OK;
}
/****************************************************************************
* Name: sim_usbhost_alloc
****************************************************************************/
static int sim_usbhost_alloc(FAR struct usbhost_driver_s *drvr,
FAR uint8_t **buffer, FAR size_t *maxlen)
{
DEBUGASSERT(drvr && buffer && maxlen);
*buffer = (uint8_t *)kmm_malloc(SIM_USBHOST_BUFSIZE);
if (*buffer)
{
*maxlen = SIM_USBHOST_BUFSIZE;
return OK;
}
return -ENOMEM;
}
/****************************************************************************
* Name: sim_usbhost_free
****************************************************************************/
static int sim_usbhost_free(FAR struct usbhost_driver_s *drvr,
FAR uint8_t *buffer)
{
DEBUGASSERT(drvr && buffer);
kmm_free(buffer);
return OK;
}
/****************************************************************************
* Name: sim_usbhost_ioalloc
****************************************************************************/
static int sim_usbhost_ioalloc(FAR struct usbhost_driver_s *drvr,
FAR uint8_t **buffer, size_t buflen)
{
DEBUGASSERT(drvr && buffer && buflen > 0);
*buffer = (uint8_t *)kumm_malloc(buflen);
return *buffer ? OK : -ENOMEM;
}
/****************************************************************************
* Name: sim_usbhost_iofree
****************************************************************************/
static int sim_usbhost_iofree(FAR struct usbhost_driver_s *drvr,
FAR uint8_t *buffer)
{
DEBUGASSERT(drvr && buffer);
kumm_free(buffer);
return OK;
}
/****************************************************************************
* Name: sim_usbhost_ctrlin
****************************************************************************/
static int sim_usbhost_ctrlin(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep0,
FAR const struct usb_ctrlreq_s *req,
FAR uint8_t *buffer)
{
struct sim_usbhost_s *priv = (struct sim_usbhost_s *)drvr;
struct sim_epinfo_s *ep0info = (struct sim_epinfo_s *)ep0;
struct host_usb_ctrlreq_s hostreq;
struct host_usb_datareq_s *datareq;
uint16_t len;
ssize_t nbytes;
sem_t iocsem;
DEBUGASSERT(ep0info != NULL && req != NULL);
datareq = sim_usbhost_allocrq();
if (!datareq)
{
uerr("sim_usbhost_allocrq fail\n");
return -ENOMEM;
}
len = GETUINT16(req->len);
/* Terse output only if we are tracing */
uinfo("type: %02x req: %02x value: %02x%02x index: %02x%02x "
"len: %04x\n",
req->type, req->req, req->value[1], req->value[0],
req->index[1], req->index[0], len);
sim_usbhost_getctrlreq(&hostreq, req);
nxsem_init(&iocsem, 0, 0);
datareq->addr = 0;
datareq->data = buffer;
datareq->len = len;
datareq->priv = &iocsem;
/* We must have exclusive access to the data structures. */
nxmutex_lock(&priv->lock);
nbytes = host_usbhost_ep0trans(&hostreq, datareq);
nxmutex_unlock(&priv->lock);
/* Wait for transfer completion */
nxsem_wait(&iocsem);
nbytes = datareq->xfer;
sim_usbhost_freerq(datareq);
return (int)nbytes;
}
/****************************************************************************
* Name: sim_usbhost_ctrlout
****************************************************************************/
static int sim_usbhost_ctrlout(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep0,
FAR const struct usb_ctrlreq_s *req,
FAR const uint8_t *buffer)
{
return sim_usbhost_ctrlin(drvr, ep0, req, (uint8_t *)buffer);
}
/****************************************************************************
* Name: sim_usbhost_transfer
****************************************************************************/
static ssize_t sim_usbhost_transfer(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep, FAR uint8_t *buffer,
size_t buflen)
{
struct sim_usbhost_s *priv = (struct sim_usbhost_s *)drvr;
struct sim_epinfo_s *epinfo = (struct sim_epinfo_s *)ep;
struct host_usb_datareq_s *datareq;
sem_t iocsem;
int nbytes;
DEBUGASSERT(epinfo && buffer && buflen > 0);
datareq = sim_usbhost_allocrq();
if (!datareq)
{
uerr("sim_usbhost_allocrq fail\n");
return -ENOMEM;
}
nbytes = MIN(buflen, epinfo->maxpacket);
nxsem_init(&iocsem, 0, 0);
datareq->addr = (epinfo->dirin << 7) + epinfo->epno;
datareq->xfrtype = epinfo->xfrtype;
datareq->data = buffer;
datareq->len = nbytes;
datareq->priv = &iocsem;
/* We must have exclusive access to and data structures. */
nxmutex_lock(&priv->lock);
nbytes = host_usbhost_eptrans(datareq);
nxmutex_unlock(&priv->lock);
/* Wait for transfer completion */
nxsem_wait(&iocsem);
nbytes = datareq->xfer;
sim_usbhost_freerq(datareq);
return (ssize_t)nbytes;
}
/****************************************************************************
* Name: sim_usbhost_cancel
****************************************************************************/
static int sim_usbhost_cancel(FAR struct usbhost_driver_s *drvr,
usbhost_ep_t ep)
{
return 0;
}
/****************************************************************************
* Name: sim_usbhost_disconnect
****************************************************************************/
static void sim_usbhost_disconnect(FAR struct usbhost_driver_s *drvr,
FAR struct usbhost_hubport_s *hport)
{
DEBUGASSERT(hport != NULL);
hport->devclass = NULL;
}
/****************************************************************************
* Name: sim_usbhost_rqcomplete
****************************************************************************/
static void sim_usbhost_rqcomplete(FAR struct sim_usbhost_s *drvr)
{
struct host_usb_datareq_s *datareq;
while ((datareq = host_usbhost_getcomplete()) != NULL)
{
sem_t *iocsem = datareq->priv;
nxsem_post(iocsem);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sim_usbhost_initialize
*
* Description:
* Initialize USB host device controller hardware.
*
****************************************************************************/
int sim_usbhost_initialize(void)
{
struct sim_usbhost_s *priv = &g_sim_usbhost;
struct usbhost_hubport_s *hport;
int ret;
#ifdef CONFIG_USBHOST_CDCACM
ret = usbhost_cdcacm_initialize();
#endif
/* Initialize the device operations */
priv->drvr.ep0configure = sim_usbhost_ep0configure;
priv->drvr.epalloc = sim_usbhost_epalloc;
priv->drvr.epfree = sim_usbhost_epfree;
priv->drvr.alloc = sim_usbhost_alloc;
priv->drvr.free = sim_usbhost_free;
priv->drvr.ioalloc = sim_usbhost_ioalloc;
priv->drvr.iofree = sim_usbhost_iofree;
priv->drvr.ctrlin = sim_usbhost_ctrlin;
priv->drvr.ctrlout = sim_usbhost_ctrlout;
priv->drvr.transfer = sim_usbhost_transfer;
priv->drvr.cancel = sim_usbhost_cancel;
priv->drvr.disconnect = sim_usbhost_disconnect;
/* Initialize the public port representation */
hport = &priv->hport.hport;
hport->drvr = &priv->drvr;
hport->ep0 = &priv->ep0;
hport->port = 0;
hport->speed = USB_SPEED_HIGH;
/* Initialize function address generation logic */
usbhost_devaddr_initialize(&priv->hport);
/* Initialize host usb controller */
host_usbhost_init();
/* Initialize the driver state data */
priv->state = USB_HOST_DETACHED;
ret = kthread_create("usbhost monitor", CONFIG_SIM_USB_PRIO,
CONFIG_SIM_USB_STACKSIZE,
sim_usbhost_waittask, NULL);
if (ret < 0)
{
uerr("ERROR: Failed to create sim_usbhost_waittask: %d\n", ret);
return -ENODEV;
}
return OK;
}
/****************************************************************************
* Name: sim_usbhost_loop
*
* Description:
* USB host loop process.
*
****************************************************************************/
int sim_usbhost_loop(void)
{
struct sim_usbhost_s *priv = &g_sim_usbhost;
struct usbhost_hubport_s *hport;
bool connect;
/* Handle root hub status change on each root port */
connect = host_usbhost_getconnstate();
/* Check current connect status */
if (connect)
{
/* Connected ... Did we just become connected? */
if (!priv->connected)
{
host_usbhost_open();
/* Yes.. connected. */
priv->connected = true;
/* Notify any waiters */
nxsem_post(&priv->pscsem);
priv->pscwait = false;
}
sim_usbhost_rqcomplete(priv);
}
else
{
/* Disconnected... Did we just become disconnected? */
if (priv->connected)
{
sim_usbhost_rqcomplete(priv);
host_usbhost_close();
/* Yes.. disconnect the device */
priv->connected = false;
/* Are we bound to a class instance? */
hport = &priv->hport.hport;
if (hport->devclass)
{
/* Yes.. Disconnect the class */
CLASS_DISCONNECTED(hport->devclass);
hport->devclass = NULL;
}
/* Notify any waiters for the Root Hub Status change
* event.
*/
nxsem_post(&priv->pscsem);
priv->pscwait = false;
}
}
return OK;
}

View File

@ -0,0 +1,93 @@
/****************************************************************************
* arch/sim/src/sim/sim_usbhost.h
*
* 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.
*
****************************************************************************/
#ifndef __ARCH_SIM_SRC_SIM_USB_HOST_H
#define __ARCH_SIM_SRC_SIM_USB_HOST_H
/****************************************************************************
* Included Files
****************************************************************************/
#ifdef __SIM__
#include "config.h"
#endif
#include <stdint.h>
#include <stdbool.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/* NuttX Endpoint descriptor */
struct host_usb_epdesc_s
{
uint8_t len; /* Descriptor length */
uint8_t type; /* Descriptor type */
uint8_t addr; /* Endpoint address */
uint8_t attr; /* Endpoint attributes */
uint16_t mxpacketsize; /* Maximum packet size */
uint8_t interval; /* Interval */
};
/* This structure is used to send control requests to a USB device. */
struct host_usb_ctrlreq_s
{
uint8_t type; /* Matches request type */
uint8_t req; /* Matches request field */
uint16_t value;
uint16_t index;
uint16_t len;
};
struct host_usb_datareq_s
{
struct host_usb_datareq_s *flink;
uint8_t addr;
uint8_t xfrtype;
uint8_t *data;
uint16_t len;
uint16_t xfer;
bool success;
void *priv;
};
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Host USB host Interface */
int host_usbhost_init(void);
bool host_usbhost_getconnstate(void);
int host_usbhost_open(void);
void host_usbhost_close(void);
int host_usbhost_ep0trans(struct host_usb_ctrlreq_s *ctrlreq,
struct host_usb_datareq_s *datareq);
int host_usbhost_eptrans(struct host_usb_datareq_s *datareq);
struct host_usb_datareq_s *host_usbhost_getcomplete(void);
#endif /* __ARCH_SIM_SRC_SIM_USB_HOST_H */

View File

@ -1549,3 +1549,29 @@ usbdev
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Then you can test the network connection using the ping command or telnet.
usbhost
This is a configuration with sim usbhost support.
1. Libusb1.0 setup
$ sudo apt-get -y install libusb-1.0-0-dev
$ sudo apt-get -y install libusb-1.0-0-dev:i386
2. Configuration
sim:usbhost support cdcacm.
You can use the sim:usbdev configuration:
$ ./tools/configure.sh sim:usbhost
Configure the device you want to connet:
CONFIG_SIM_USB_PID=0x0042
CONFIG_SIM_USB_VID=0x1630
3. How to run
Run sim usbhost with root mode, run sim usbdev or plug-in cdcacm usb device.
Then you can use /dev/ttyACM to transfer data.

View File

@ -0,0 +1,57 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_SIM_UART_DMA is not set
CONFIG_ARCH="sim"
CONFIG_ARCH_BOARD="sim"
CONFIG_ARCH_BOARD_SIM=y
CONFIG_ARCH_CHIP="sim"
CONFIG_ARCH_SIM=y
CONFIG_BOARDCTL_POWEROFF=y
CONFIG_BUILTIN=y
CONFIG_DEBUG_ERROR=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_SCHED=y
CONFIG_DEBUG_SCHED_ERROR=y
CONFIG_DEBUG_SCHED_WARN=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEBUG_USB=y
CONFIG_DEBUG_USB_ERROR=y
CONFIG_DEBUG_USB_INFO=y
CONFIG_DEBUG_USB_WARN=y
CONFIG_DEBUG_WARN=y
CONFIG_FS_PROCFS=y
CONFIG_FS_TMPFS=y
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_LIBC_DLFCN=y
CONFIG_LIBC_EXECFUNCS=y
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_READLINE=y
CONFIG_PSEUDOFS_SOFTLINKS=y
CONFIG_PSEUDOTERM=y
CONFIG_READLINE_CMD_HISTORY=y
CONFIG_READLINE_TABCOMPLETION=y
CONFIG_SCHED_CHILD_STATUS=y
CONFIG_SCHED_HAVE_PARENT=y
CONFIG_SCHED_LPNTHREADS=2
CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_WAITPID=y
CONFIG_SIM_LIBUSB=y
CONFIG_SIM_USB_HOST=y
CONFIG_SIM_USB_PID=0x0042
CONFIG_SIM_USB_STACKSIZE=2048
CONFIG_SIM_USB_VID=0x1630
CONFIG_SYSLOG_CHARDEV=y
CONFIG_SYSLOG_MAX_CHANNELS=2
CONFIG_SYSTEM_CLE=y
CONFIG_SYSTEM_NSH=y
CONFIG_TESTING_OSTEST=y
CONFIG_TLS_TASK_NELEM=4
CONFIG_USBHOST_CDCACM=y
CONFIG_USBHOST_COMPOSITE=y

View File

@ -521,6 +521,15 @@ static const char *g_white_list[] =
"wMaxPacketSize",
"bInterval",
/* Ref:
* sim/posix/sim_libusb.c
*/
"bNumConfigurations",
"bDeviceClass",
"idVendor",
"idProduct",
NULL
};