From 0af63cfc481ba9c0db62cc1ebb7711a4bd1f81d2 Mon Sep 17 00:00:00 2001 From: zhangyuan21 Date: Wed, 30 Nov 2022 19:08:14 +0800 Subject: [PATCH] sim/usb: add sim usb host signed-off-by: zhangyuan21 --- arch/sim/Kconfig | 35 + arch/sim/src/Makefile | 8 + arch/sim/src/sim/posix/sim_libusb.c | 700 ++++++++++++++++ arch/sim/src/sim/sim_initialize.c | 8 + arch/sim/src/sim/sim_internal.h | 7 + arch/sim/src/sim/sim_usbhost.c | 803 +++++++++++++++++++ arch/sim/src/sim/sim_usbhost.h | 93 +++ boards/sim/sim/sim/README.txt | 26 + boards/sim/sim/sim/configs/usbhost/defconfig | 57 ++ tools/nxstyle.c | 9 + 10 files changed, 1746 insertions(+) create mode 100644 arch/sim/src/sim/posix/sim_libusb.c create mode 100644 arch/sim/src/sim/sim_usbhost.c create mode 100644 arch/sim/src/sim/sim_usbhost.h create mode 100644 boards/sim/sim/sim/configs/usbhost/defconfig diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index b555f14811..3499d77b61 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -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 diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index 07bd914d02..4a5758ff28 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -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 diff --git a/arch/sim/src/sim/posix/sim_libusb.c b/arch/sim/src/sim/posix/sim_libusb.c new file mode 100644 index 0000000000..af8c1ab684 --- /dev/null +++ b/arch/sim/src/sim/posix/sim_libusb.c @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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; +} diff --git a/arch/sim/src/sim/sim_initialize.c b/arch/sim/src/sim/sim_initialize.c index 45bf36ab6e..8e778a5c3f 100644 --- a/arch/sim/src/sim/sim_initialize.c +++ b/arch/sim/src/sim/sim_initialize.c @@ -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); diff --git a/arch/sim/src/sim/sim_internal.h b/arch/sim/src/sim/sim_internal.h index 71010dd297..346fc8fe7a 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -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 diff --git a/arch/sim/src/sim/sim_usbhost.c b/arch/sim/src/sim/sim_usbhost.c new file mode 100644 index 0000000000..ee5d21ecba --- /dev/null +++ b/arch/sim/src/sim/sim_usbhost.c @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/arch/sim/src/sim/sim_usbhost.h b/arch/sim/src/sim/sim_usbhost.h new file mode 100644 index 0000000000..e198bf224e --- /dev/null +++ b/arch/sim/src/sim/sim_usbhost.h @@ -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 +#include + +/**************************************************************************** + * 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 */ diff --git a/boards/sim/sim/sim/README.txt b/boards/sim/sim/sim/README.txt index 58e8903cc6..2f75aecb80 100644 --- a/boards/sim/sim/sim/README.txt +++ b/boards/sim/sim/sim/README.txt @@ -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. \ No newline at end of file diff --git a/boards/sim/sim/sim/configs/usbhost/defconfig b/boards/sim/sim/sim/configs/usbhost/defconfig new file mode 100644 index 0000000000..0c5bb12193 --- /dev/null +++ b/boards/sim/sim/sim/configs/usbhost/defconfig @@ -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 diff --git a/tools/nxstyle.c b/tools/nxstyle.c index 45731a6ccf..46df53d555 100644 --- a/tools/nxstyle.c +++ b/tools/nxstyle.c @@ -521,6 +521,15 @@ static const char *g_white_list[] = "wMaxPacketSize", "bInterval", + /* Ref: + * sim/posix/sim_libusb.c + */ + + "bNumConfigurations", + "bDeviceClass", + "idVendor", + "idProduct", + NULL };