diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 875085660d..b555f14811 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -605,4 +605,34 @@ config SIM_UART3_NAME endmenu +config SIM_USB_DEV + bool "Linux USB Device" + select USBDEV + ---help--- + Build in support for simulated usb device + +if SIM_USB_DEV + +config SIM_USB_RAW_GADGET + bool "Simulated USB Raw Gadget Dev" + default n + depends on HOST_LINUX + ---help--- + Use USB Raw Gadget and Dummy HCD/UDC to set up virtual + USB Device and Host controller that connected to each + other inside the kernel. + + Get Raw Gadget: + Get Raw Gadget code at https://github.com/xairy/raw-gadget. + + Make Raw Gadget: + Run make in the raw_gadget and dummy_hcd directory. If raw_gadget + build fail, you need to check which register interface meets your + kenel version, usb_gadget_probe_driver or usb_gadget_register_driver. + + Install Raw Gadget: + Run ./insmod.sh in the raw_gadget and dummy_hcd directory. + +endif + endif # ARCH_SIM diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index cf69123a8b..07bd914d02 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -198,6 +198,13 @@ ifeq ($(CONFIG_SIM_SPI_LINUX),y) HOSTSRCS += sim_linuxspi.c endif +ifeq ($(CONFIG_SIM_USB_DEV),y) + CSRCS += sim_usbdev.c +ifeq ($(CONFIG_SIM_USB_RAW_GADGET),y) + HOSTSRCS += sim_rawgadget.c +endif +endif + ifeq ($(CONFIG_RPTUN),y) CSRCS += sim_rptun.c endif diff --git a/arch/sim/src/sim/posix/sim_rawgadget.c b/arch/sim/src/sim/posix/sim_rawgadget.c new file mode 100644 index 0000000000..4472f2a35c --- /dev/null +++ b/arch/sim/src/sim/posix/sim_rawgadget.c @@ -0,0 +1,903 @@ +/**************************************************************************** + * arch/sim/src/sim/posix/sim_rawgadget.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 "sim_internal.h" +#include "sim_usbdev.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define ERROR(fmt, ...) \ + syslog(LOG_ERR, "sim_rawgadget: " fmt "\n", ##__VA_ARGS__) +#define INFO(fmt, ...) \ + syslog(LOG_INFO, "sim_rawgadget: " fmt "\n", ##__VA_ARGS__) +#define DEBUG(fmt, ...) + +#define USB_RAW_IOCTL_INIT _IOW('U', 0, struct usb_raw_init_s) +#define USB_RAW_IOCTL_RUN _IO('U', 1) +#define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event_s) +#define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io_s) +#define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io_s) +#define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) +#define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32) +#define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io_s) +#define USB_RAW_IOCTL_EP_READ _IOWR('U', 8, struct usb_raw_ep_io_s) +#define USB_RAW_IOCTL_CONFIGURE _IO('U', 9) +#define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32) +#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info_s) +#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12) +#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32) +#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32) +#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32) + +#define USB_RAW_EP_NUM(addr) ((addr) & USB_ENDPOINT_NUMBER_MASK) +#define USB_RAW_EP_DIR(addr) ((addr) & USB_ENDPOINT_DIR_MASK) + +#define USB_RAW_EPS_NUM_MAX 30 +#define USB_RAW_EP_NAME_MAX 16 +#define USB_RAW_EP_ADDR_ANY 0xff + +#define UDC_NAME_LENGTH_MAX 128 + +#define USB_RAW_EP0_MAX_LEN 256 +#define USB_RAW_EP_MAX_LEN 1024 + +#define USB_RAW_RX_BUF_NUM 8 + +#define USB_RAW_DEVICE "dummy_udc.0" +#define USB_RAW_DRIVER "dummy_udc" + +#define USB_RAW_FIFO_USED(fifo) ((fifo)->write - (fifo)->read) +#define USB_RAW_FIFO_UNUSED(fifo) ((fifo)->elem_num - USB_RAW_FIFO_USED(fifo)) +#define USB_RAW_FIFO_MASK(fifo) ((fifo)->elem_num - 1) +#define USB_RAW_FIFO_PUSH(fifo) ((fifo)->write++) +#define USB_RAW_FIFO_POP(fifo) ((fifo)->read++) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum usb_raw_event_type_e +{ + USB_RAW_EVENT_INVALID, + USB_RAW_EVENT_CONNECT, + USB_RAW_EVENT_CONTROL, +}; + +struct usb_raw_init_s +{ + uint8_t driver_name[UDC_NAME_LENGTH_MAX]; + uint8_t device_name[UDC_NAME_LENGTH_MAX]; + uint8_t speed; +}; + +struct usb_raw_event_s +{ + uint32_t type; + uint32_t length; + uint8_t data[0]; +}; + +struct usb_raw_ep_io_s +{ + uint16_t ep; + uint16_t flags; + uint32_t length; + uint8_t data[0]; +}; + +struct usb_raw_control_io_s +{ + struct usb_raw_ep_io_s inner; + uint8_t data[USB_RAW_EP0_MAX_LEN]; +}; + +struct usb_raw_data_io_s +{ + struct usb_raw_ep_io_s inner; + uint8_t data[USB_RAW_EP_MAX_LEN]; +}; + +struct usb_raw_ep_caps_s +{ + uint32_t type_control : 1; + uint32_t type_iso : 1; + uint32_t type_bulk : 1; + uint32_t type_int : 1; + uint32_t dir_in : 1; + uint32_t dir_out : 1; +}; + +struct usb_raw_ep_limits_s +{ + uint16_t maxpacket_limit; + uint16_t max_streams; + uint32_t reserved; +}; + +struct usb_raw_ep_info_s +{ + uint8_t name[USB_RAW_EP_NAME_MAX]; + uint32_t addr; + struct usb_raw_ep_caps_s caps; + struct usb_raw_ep_limits_s limits; +}; + +struct usb_raw_eps_info_s +{ + struct usb_raw_ep_info_s eps[USB_RAW_EPS_NUM_MAX]; +}; + +struct usb_raw_control_event_s +{ + struct usb_raw_event_s inner; + struct usb_ctrlrequest ctrl; +}; + +struct usb_raw_fifo_s +{ + uint16_t read; + uint16_t write; + uint16_t elem_size; + uint16_t elem_num; + uint8_t *elems; +}; + +struct usb_raw_ep_entry_s +{ + bool halted; + uint16_t addr; + uint16_t raw_epaddr; + uint16_t raw_epid; + struct usb_raw_fifo_s fifo; + pthread_t ep_thread; +}; + +struct usb_raw_gadget_dev_t +{ + int fd; + uint16_t eps_num; + pthread_t ep0_thread; + struct usb_raw_control_io_s ep0_ctrl; + struct usb_raw_ep_entry_s eps_entry[USB_RAW_EPS_NUM_MAX]; + struct usb_raw_eps_info_s eps_info; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct usb_raw_gadget_dev_t g_raw_gadget_dev = +{ + .fd = -1, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void host_raw_fifocreate(struct usb_raw_fifo_s *fifo, + uint16_t elem_size, uint16_t elem_num) +{ + if (elem_num & (elem_num - 1)) + { + ERROR("USB raw fifo num error"); + return; + } + + fifo->write = 0; + fifo->read = 0; + fifo->elem_size = elem_size; + fifo->elem_num = elem_num; + fifo->elems = (uint8_t *)malloc(elem_size * elem_num); +} + +static void host_raw_fifodelete(struct usb_raw_fifo_s *fifo) +{ + fifo->write = 0; + fifo->read = 0; + free(fifo->elems); +} + +static uint8_t *host_raw_fiforead(struct usb_raw_fifo_s *fifo) +{ + uint16_t r_idx; + + if (USB_RAW_FIFO_USED(fifo) == 0) + { + return NULL; + } + + r_idx = fifo->read & USB_RAW_FIFO_MASK(fifo); + return &fifo->elems[fifo->elem_size * r_idx]; +} + +static uint8_t *host_raw_fifoalloc(struct usb_raw_fifo_s *fifo) +{ + uint16_t w_idx; + + if (USB_RAW_FIFO_UNUSED(fifo) == 0) + { + ERROR("USB raw get fifo fail"); + return NULL; + } + + w_idx = fifo->write & USB_RAW_FIFO_MASK(fifo); + return &fifo->elems[fifo->elem_size * w_idx]; +} + +static int host_raw_open(void) +{ + int fd = open("/dev/raw-gadget", O_RDWR); + if (fd < 0) + { + ERROR("open fail"); + } + + return fd; +} + +static void host_raw_close(int fd) +{ + if (fd >= 0) + { + close(fd); + } +} + +static void host_raw_init(int fd, enum usb_device_speed speed, + const char *driver, const char *device) +{ + struct usb_raw_init_s arg; + strcpy((char *)&arg.driver_name[0], driver); + strcpy((char *)&arg.device_name[0], device); + arg.speed = speed; + int rv = ioctl(fd, USB_RAW_IOCTL_INIT, &arg); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_INIT) fail"); + } +} + +static int host_raw_run(int fd) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_RUN, 0); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_RUN) fail"); + } + + return rv; +} + +static int host_raw_eventfetch(int fd, struct usb_raw_event_s *event) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EVENT_FETCH, event); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EVENT_FETCH) fail"); + } + + return rv; +} + +static int host_raw_ep0read(int fd, struct usb_raw_ep_io_s *io) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP0_READ, io); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP0_READ)"); + } + + return rv; +} + +static int host_raw_ep0write(int fd, struct usb_raw_ep_io_s *io) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP0_WRITE, io); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP0_WRITE) fail"); + } + + return rv; +} + +static int host_raw_epenable(int fd, struct usb_endpoint_descriptor *desc) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP_ENABLE, desc); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP_ENABLE) fail"); + } + + return rv; +} + +static int host_raw_epdisable(int fd, uint8_t epno) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP_DISABLE, epno); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP_DISABLE) fail"); + } + + return rv; +} + +static int host_raw_epread(int fd, struct usb_raw_ep_io_s *io) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP_READ, io); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP_READ) fail"); + } + + return rv; +} + +static int host_raw_epwrite(int fd, struct usb_raw_ep_io_s *io) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP_WRITE, io); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP_WRITE) fail"); + } + + return rv; +} + +static void host_raw_configure(int fd) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_CONFIGURE, 0); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_CONFIGURED) fail"); + } +} + +static void host_raw_vbusdraw(int fd, uint32_t power) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_VBUS_DRAW, power); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_VBUS_DRAW) fail"); + } +} + +static int host_raw_epsinfo(int fd, struct usb_raw_eps_info_s *info) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EPS_INFO, info); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EPS_INFO) fail"); + } + + return rv; +} + +static int host_raw_ep0stall(int fd) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP0_STALL, 0); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP0_STALL) fail"); + } + + return rv; +} + +static int host_raw_epsethalt(int fd, int ep) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP_SET_HALT, ep); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP_SET_HALT) fail"); + } + + return rv; +} + +static int host_raw_epclearhalt(int fd, int ep) +{ + int rv = ioctl(fd, USB_RAW_IOCTL_EP_CLEAR_HALT, ep); + if (rv < 0) + { + ERROR("ioctl(USB_RAW_IOCTL_EP_CLEAR_HALT) fail"); + } + + return rv; +} + +static void +host_raw_setctrlreq(struct host_usb_ctrlreq_s *host_req, + const struct usb_ctrlrequest *raw_req) +{ + host_req->type = raw_req->bRequestType; + host_req->req = raw_req->bRequest; + host_req->value = raw_req->wValue; + host_req->index = raw_req->wIndex; + host_req->len = raw_req->wLength; +} + +static void +host_raw_getepdesc(struct usb_endpoint_descriptor *raw_epdesc, + const struct host_usb_epdesc_s *host_epdesc) +{ + raw_epdesc->bLength = host_epdesc->len; + raw_epdesc->bDescriptorType = host_epdesc->type; + raw_epdesc->bEndpointAddress = host_epdesc->addr; + raw_epdesc->bmAttributes = host_epdesc->attr; + raw_epdesc->wMaxPacketSize = host_epdesc->mxpacketsize; + raw_epdesc->bInterval = host_epdesc->interval; +} + +static int host_raw_connecthandle(struct usb_raw_gadget_dev_t *dev) +{ + struct usb_raw_eps_info_s *info = &dev->eps_info; + int i; + + memset(info, 0, sizeof(struct usb_raw_eps_info_s)); + + dev->eps_num = host_raw_epsinfo(dev->fd, info); + for (i = 0; i < dev->eps_num; i++) + { + INFO("ep #%d:", i); + INFO(" name: %s", &info->eps[i].name[0]); + INFO(" addr: %u", info->eps[i].addr); + INFO(" type: %s %s %s", + info->eps[i].caps.type_iso ? "iso" : "___", + info->eps[i].caps.type_bulk ? "blk" : "___", + info->eps[i].caps.type_int ? "int" : "___"); + INFO(" dir : %s %s", + info->eps[i].caps.dir_in ? "in " : "___", + info->eps[i].caps.dir_out ? "out" : "___"); + INFO(" maxpacket_limit: %u", + info->eps[i].limits.maxpacket_limit); + INFO(" max_streams: %u", info->eps[i].limits.max_streams); + } + + return 0; +} + +static bool +host_raw_check_epaddress(struct usb_endpoint_descriptor *epd) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + struct usb_raw_eps_info_s *eps_info = &dev->eps_info; + uint16_t ep_cnt; + + for (ep_cnt = 0; ep_cnt < dev->eps_num; ep_cnt++) + { + struct usb_raw_ep_info_s *ep = &eps_info->eps[ep_cnt]; + + if (ep->addr != USB_RAW_EP_NUM(epd->bEndpointAddress) && + ep->addr != USB_RAW_EP_ADDR_ANY) + { + continue; + } + + if ((usb_endpoint_dir_in(epd) && !ep->caps.dir_in) || + (usb_endpoint_dir_out(epd) && !ep->caps.dir_out)) + { + continue; + } + + if ((usb_endpoint_type(epd) == USB_ENDPOINT_XFER_BULK && + !ep->caps.type_bulk) || + (usb_endpoint_type(epd) == USB_ENDPOINT_XFER_INT && + !ep->caps.type_int) || + (usb_endpoint_type(epd) == USB_ENDPOINT_XFER_ISOC && + !ep->caps.type_iso)) + { + continue; + } + + return true; + } + + return false; +} + +static int host_raw_ctrlhandle(struct usb_raw_gadget_dev_t *dev, + struct usb_raw_control_event_s *event) +{ + struct usb_raw_ep_entry_s *entry = &dev->eps_entry[0]; + struct usb_raw_ep_io_s *io = &dev->ep0_ctrl.inner; + struct host_usb_ctrlreq_s *host_ctrl_req; + int ret = -1; + + host_ctrl_req = (struct host_usb_ctrlreq_s *) + host_raw_fifoalloc(&entry->fifo); + + if (!host_ctrl_req) + { + ERROR("EP0 get raw fifo error"); + return ret; + } + + host_raw_setctrlreq(host_ctrl_req, &event->ctrl); + + if (!(event->ctrl.bRequestType & USB_DIR_IN)) + { + io->ep = 0; + io->flags = 0; + io->length = USB_RAW_EP0_MAX_LEN; + + ret = host_raw_ep0read(dev->fd, io); + if (ret < 0) + { + ERROR("EP0 read out data error"); + return ret; + } + + memcpy(host_ctrl_req->data, io->data, ret); + } + + USB_RAW_FIFO_PUSH(&entry->fifo); + + return ret; +} + +static void *host_raw_ep0handle(void *arg) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + struct usb_raw_ep_entry_s *entry = &dev->eps_entry[0]; + struct usb_raw_control_event_s event; + + while (dev->fd >= 0) + { + event.inner.type = 0; + event.inner.length = sizeof(event.ctrl); + if (host_raw_eventfetch(dev->fd, &event.inner) < 0) + { + ERROR("EP0 event fetch fail."); + continue; + } + + if (event.inner.type == USB_RAW_EVENT_CONNECT) + { + host_raw_connecthandle(dev); + } + else if (event.inner.type == USB_RAW_EVENT_CONTROL) + { + host_raw_ctrlhandle(dev, &event); + } + else + { + ERROR("EP0 receive wrong event."); + } + } + + host_raw_fifodelete(&entry->fifo); + + return NULL; +} + +static void *host_raw_ephandle(void *arg) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + struct usb_raw_ep_entry_s *entry = arg; + struct usb_raw_data_io_s *io; + + while (dev->fd >= 0) + { + io = (struct usb_raw_data_io_s *) + host_raw_fifoalloc(&entry->fifo); + + if (io) + { + if (entry->halted) + { + host_raw_epclearhalt(dev->fd, entry->raw_epid); + entry->halted = false; + } + + io->inner.ep = entry->raw_epid; + io->inner.flags = 0; + io->inner.length = USB_RAW_EP_MAX_LEN; + io->inner.length = host_raw_epread(dev->fd, &io->inner); + USB_RAW_FIFO_PUSH(&entry->fifo); + } + else + { + if (!entry->halted) + { + host_raw_epsethalt(dev->fd, entry->raw_epid); + entry->halted = true; + } + + usleep(10); + } + } + + host_raw_fifodelete(&entry->fifo); + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int host_usbdev_init(uint32_t speed) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + const char *device = USB_RAW_DEVICE; + const char *driver = USB_RAW_DRIVER; + int fd; + + fd = host_raw_open(); + if (fd < 0) + { + ERROR("USB raw open error"); + return -1; + } + + host_raw_init(fd, speed, driver, device); + host_raw_run(fd); + host_raw_vbusdraw(fd, 0x32); + host_raw_configure(fd); + dev->fd = fd; + + host_raw_fifocreate(&dev->eps_entry[0].fifo, + (sizeof(struct host_usb_ctrlreq_s) + + USB_RAW_EP0_MAX_LEN), + USB_RAW_RX_BUF_NUM); + + return pthread_create(&dev->ep0_thread, NULL, + host_raw_ep0handle, NULL); +} + +int host_usbdev_deinit(void) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + host_raw_close(dev->fd); + return 0; +} + +int host_usbdev_epconfig(uint8_t epno, + const struct host_usb_epdesc_s *epdesc) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + struct usb_endpoint_descriptor raw_epdesc; + struct usb_raw_ep_entry_s *entry; + int ret = -1; + + if (dev->fd < 0) + { + ERROR("USB raw not enable"); + return ret; + } + + if (epno > USB_RAW_EPS_NUM_MAX) + { + ERROR("USB raw ep num error"); + return ret; + } + + if (epdesc->mxpacketsize > USB_RAW_EP_MAX_LEN) + { + ERROR("USB raw ep max packet size error"); + return ret; + } + + host_raw_getepdesc(&raw_epdesc, epdesc); + + if (!host_raw_check_epaddress(&raw_epdesc)) + { + ERROR("USB raw check ep address fail"); + return ret; + } + + ret = host_raw_epenable(dev->fd, &raw_epdesc); + if (ret < 0) + { + ERROR("USB raw ep enable fail"); + return ret; + } + + entry = &dev->eps_entry[epno]; + entry->addr = epdesc->addr; + entry->raw_epaddr = raw_epdesc.bEndpointAddress; + entry->raw_epid = ret; + entry->halted = false; + + if (USB_RAW_EP_DIR(epdesc->addr) == USB_DIR_OUT) + { + host_raw_fifocreate(&entry->fifo, + sizeof(struct usb_raw_data_io_s), + USB_RAW_RX_BUF_NUM); + + ret = pthread_create(&entry->ep_thread, NULL, + host_raw_ephandle, + (void *)entry); + } + + return ret; +} + +int host_usbdev_epdisable(uint8_t epno) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + int ret = -1; + + if (dev->fd >= 0) + { + struct usb_raw_ep_entry_s *entry = &dev->eps_entry[epno]; + ret = host_raw_epdisable(dev->fd, entry->raw_epid); + } + + return ret; +} + +int host_usbdev_pullup(bool enable) +{ + /* not support */ + + return -1; +} + +int host_usbdev_epstall(uint8_t epno, bool resume) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + int ret = -1; + + if (dev->fd >= 0) + { + if (!resume && epno == 0) + { + ret = host_raw_ep0stall(dev->fd); + } + } + + return ret; +} + +int host_usbdev_epcancel(uint8_t epno) +{ + /* not support */ + + return -1; +} + +int host_usbdev_epwrite(uint8_t epno, uint8_t flags, + uint8_t *data, uint16_t len) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + struct usb_raw_ep_entry_s *entry; + struct usb_raw_ep_io_s *io; + int ret = -1; + + if (dev->fd < 0) + { + ERROR("USB raw not enable"); + return -1; + } + + if (epno > USB_RAW_EPS_NUM_MAX) + { + ERROR("USB raw ep num error"); + return ret; + } + + entry = &dev->eps_entry[epno]; + + io = malloc(sizeof(struct usb_raw_ep_io_s) + len); + if (!io) + { + ERROR("Host usb malloc ep write io fail"); + return -1; + } + + io->flags = flags; + io->length = len; + io->ep = entry->raw_epid; + memcpy(io->data, data, len); + + if (epno == 0) + { + ret = host_raw_ep0write(dev->fd, io); + } + else + { + ret = host_raw_epwrite(dev->fd, io); + } + + free(io); + + return ret; +} + +uint8_t *host_usbdev_epread(uint8_t epno, uint16_t *len) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + struct usb_raw_ep_entry_s *entry; + struct usb_raw_ep_io_s *io; + + if (dev->fd < 0) + { + ERROR("USB raw not enable"); + return NULL; + } + + if (epno > USB_RAW_EPS_NUM_MAX) + { + ERROR("USB raw ep num error"); + return NULL; + } + + entry = &dev->eps_entry[epno]; + + io = (struct usb_raw_ep_io_s *) + host_raw_fiforead(&entry->fifo); + if (io) + { + *len = io->length; + return io->data; + } + + return NULL; +} + +struct host_usb_ctrlreq_s *host_usbdev_ep0read(void) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + + if (dev->fd < 0) + { + ERROR("USB raw not enable"); + return NULL; + } + + return (struct host_usb_ctrlreq_s *) + host_raw_fiforead(&dev->eps_entry[0].fifo); +} + +void host_usbdev_epread_end(uint8_t epno) +{ + struct usb_raw_gadget_dev_t *dev = &g_raw_gadget_dev; + USB_RAW_FIFO_POP(&dev->eps_entry[epno].fifo); +} diff --git a/arch/sim/src/sim/sim_initialize.c b/arch/sim/src/sim/sim_initialize.c index ab65e77690..45bf36ab6e 100644 --- a/arch/sim/src/sim/sim_initialize.c +++ b/arch/sim/src/sim/sim_initialize.c @@ -203,6 +203,10 @@ static int sim_loop_task(int argc, char **argv) sim_video_loop(); #endif +#ifdef CONFIG_SIM_USB_DEV + sim_usbdev_loop(); +#endif + #ifdef CONFIG_MOTOR_FOC_DUMMY /* Update simulated FOC device */ @@ -289,6 +293,10 @@ void up_initialize(void) audio_register("pcm1c", sim_audio_initialize(false, true)); #endif +#ifdef CONFIG_SIM_USB_DEV + sim_usbdev_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 a2d7c7167b..71010dd297 100644 --- a/arch/sim/src/sim/sim_internal.h +++ b/arch/sim/src/sim/sim_internal.h @@ -383,6 +383,13 @@ int sim_video_initialize(void); void sim_video_loop(void); #endif +/* sim_usbdev.c *************************************************************/ + +#ifdef CONFIG_SIM_USB_DEV +void sim_usbdev_initialize(void); +int sim_usbdev_loop(void); +#endif + /* Debug ********************************************************************/ #ifdef CONFIG_STACK_COLORATION diff --git a/arch/sim/src/sim/sim_usbdev.c b/arch/sim/src/sim/sim_usbdev.c new file mode 100644 index 0000000000..2eee33cae6 --- /dev/null +++ b/arch/sim/src/sim/sim_usbdev.c @@ -0,0 +1,1154 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_usbdev.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 "sim_internal.h" +#include "sim_usbdev.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* USB trace ****************************************************************/ + +/* Trace error codes */ + +#define SIM_TRACEERR_ALLOCFAIL 0x0001 +#define SIM_TRACEERR_BADCLEARFEATURE 0x0002 +#define SIM_TRACEERR_BADDEVGETSTATUS 0x0003 +#define SIM_TRACEERR_BADEPGETSTATUS 0x0004 +#define SIM_TRACEERR_BADEPNO 0x0005 +#define SIM_TRACEERR_BADEPTYPE 0x0006 +#define SIM_TRACEERR_BADGETCONFIG 0x0007 +#define SIM_TRACEERR_BADGETSETDESC 0x0008 +#define SIM_TRACEERR_BADGETSTATUS 0x0009 +#define SIM_TRACEERR_BADSETADDRESS 0x000a +#define SIM_TRACEERR_BADSETCONFIG 0x000b +#define SIM_TRACEERR_BADSETFEATURE 0x000c +#define SIM_TRACEERR_BINDFAILED 0x000d +#define SIM_TRACEERR_DISPATCHSTALL 0x000e +#define SIM_TRACEERR_DRIVER 0x000f +#define SIM_TRACEERR_DRIVERREGISTERED 0x0010 +#define SIM_TRACEERR_EP0BADCTR 0x0011 +#define SIM_TRACEERR_EP0SETUPSTALLED 0x0012 +#define SIM_TRACEERR_EPBUFFER 0x0013 +#define SIM_TRACEERR_EPDISABLED 0x0014 +#define SIM_TRACEERR_EPOUTNULLPACKET 0x0015 +#define SIM_TRACEERR_EPRESERVE 0x0016 +#define SIM_TRACEERR_INVALIDCTRLREQ 0x0017 +#define SIM_TRACEERR_INVALIDPARMS 0x0018 +#define SIM_TRACEERR_IRQREGISTRATION 0x0019 +#define SIM_TRACEERR_NOTCONFIGURED 0x001a +#define SIM_TRACEERR_REQABORTED 0x001b + +#define SIM_USB_EPNUM (15) +#define SIM_USB_EP0MAXSIZE 64 +#define SIM_USB_MAXPACKETSIZE(ep) (((uint16_t)(ep) < 1) ? 64 : 512) +#define SIM_USB_EPMAXSIZE 512 + +#define SIM_EPSET_ALL ((1 << SIM_USB_EPNUM) - 1) /* All endpoints */ +#define SIM_EPSET_NOEP0 (SIM_EPSET_ALL - 1) /* All endpoints except EP0 */ +#define SIM_EP_BIT(ep) (1 << (ep)) + +#define sim_rqempty(q) ((q)->head == NULL) +#define sim_rqpeek(q) ((q)->head) + +#ifdef CONFIG_USBDEV_DUALSPEED +# define SIM_USB_SPEED USB_SPEED_HIGH +#else +# define SIM_USB_SPEED USB_SPEED_FULL +#endif + +#ifndef MIN +# define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* State of an endpoint */ + +enum sim_epstate_e +{ + SIM_EPSTATE_DISABLED = 0, /* Endpoint is disabled */ + SIM_EPSTATE_STALLED, /* Endpoint is stalled */ + SIM_EPSTATE_IDLE, /* Endpoint is idle (i.e. ready for transmission) */ + SIM_EPSTATE_SENDING, /* Endpoint is sending data */ + SIM_EPSTATE_RECEIVING, /* Endpoint is receiving data */ + SIM_EPSTATE_EP0DATAOUT, /* Endpoint 0 is receiving SETUP OUT data */ + SIM_EPSTATE_EP0STATUSIN, /* Endpoint 0 is sending SETUP status */ + SIM_EPSTATE_EP0ADDRESS /* Address change is pending completion of status */ +}; + +/* The overall state of the device */ + +enum sim_devstate_e +{ + SIM_DEVSTATE_SUSPENDED = 0, /* The device is currently suspended */ + SIM_DEVSTATE_POWERED, /* Host is providing +5V through the USB cable */ + SIM_DEVSTATE_DEFAULT, /* Device has been reset */ + SIM_DEVSTATE_ADDRESSED, /* The device has been given an address on the bus */ + SIM_DEVSTATE_CONFIGURED /* A valid configuration has been selected. */ +}; + +/* The head of a queue of requests */ + +struct sim_rqhead_s +{ + struct sim_req_s *head; /* Requests are added to the head of the list */ + struct sim_req_s *tail; /* Requests are removed from the tail of the list */ +}; + +struct sim_usbdev_s; +struct sim_ep_s +{ + struct usbdev_ep_s ep; /* Standard endpoint structure */ + struct sim_usbdev_s *dev; /* Reference to private driver data */ + volatile uint8_t epstate; /* State of the endpoint (see enum sim_epstate_e) */ + struct sim_rqhead_s reqq; /* Read/write request queue */ +}; + +struct sim_usbdev_s +{ + struct usbdev_s usbdev; + struct usbdevclass_driver_s *driver; /* The bound device class driver */ + struct usb_ctrlreq_s ctrl; /* Last EP0 request */ + uint8_t devstate; /* State of the device (see enum sim_devstate_e) */ + uint8_t prevstate; /* Previous state of the device before SUSPEND */ + uint8_t selfpowered:1; /* 1: Device is self powered */ + uint16_t epavail; /* Bitset of available endpoints */ + struct sim_ep_s eps[SIM_USB_EPNUM]; +}; + +struct sim_req_s +{ + struct usbdev_req_s req; /* Standard USB request */ + struct sim_req_s *flink; /* Supports a singly linked list */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Endpoint operations ******************************************************/ + +static int sim_ep_configure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, + bool last); +static int sim_ep_disable(struct usbdev_ep_s *ep); +static struct usbdev_req_s *sim_ep_allocreq(struct usbdev_ep_s *ep); +static void sim_ep_freereq(struct usbdev_ep_s *ep, + struct usbdev_req_s *); +static int sim_ep_submit(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int sim_ep_cancel(struct usbdev_ep_s *ep, + struct usbdev_req_s *req); +static int sim_ep_stall(struct usbdev_ep_s *ep, bool resume); + +/* USB device controller operations *****************************************/ + +static struct usbdev_ep_s *sim_usbdev_allocep(struct usbdev_s *dev, + uint8_t epno, bool in, + uint8_t eptype); +static void sim_usbdev_freeep(struct usbdev_s *dev, struct usbdev_ep_s *ep); +static int sim_usbdev_getframe(struct usbdev_s *dev); +static int sim_usbdev_wakeup(struct usbdev_s *dev); +static int sim_usbdev_selfpowered(struct usbdev_s *dev, bool selfpowered); +static int sim_usbdev_pullup(struct usbdev_s *dev, bool enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct sim_usbdev_s g_sim_usbdev; + +static const struct usbdev_epops_s g_epops = +{ + .configure = sim_ep_configure, + .disable = sim_ep_disable, + .allocreq = sim_ep_allocreq, + .freereq = sim_ep_freereq, + .submit = sim_ep_submit, + .stall = sim_ep_stall, + .cancel = sim_ep_cancel, +}; + +static const struct usbdev_ops_s g_devops = +{ + .allocep = sim_usbdev_allocep, + .freeep = sim_usbdev_freeep, + .selfpowered = sim_usbdev_selfpowered, + .pullup = sim_usbdev_pullup, + .getframe = sim_usbdev_getframe, + .wakeup = sim_usbdev_wakeup, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_rqdequeue + ****************************************************************************/ + +static struct sim_req_s *sim_rqdequeue(struct sim_rqhead_s *queue) +{ + struct sim_req_s *ret = queue->head; + + if (ret) + { + queue->head = ret->flink; + if (!queue->head) + { + queue->tail = NULL; + } + + ret->flink = NULL; + } + + return ret; +} + +/**************************************************************************** + * Name: sim_rqenqueue + ****************************************************************************/ + +static void sim_rqenqueue(struct sim_rqhead_s *queue, + struct sim_req_s *req) +{ + req->flink = NULL; + if (!queue->head) + { + queue->head = req; + queue->tail = req; + } + else + { + queue->tail->flink = req; + queue->tail = req; + } +} + +/**************************************************************************** + * Name: sim_reqabort + ****************************************************************************/ + +static void sim_reqabort(struct sim_ep_s *privep, + struct sim_req_s *privreq, + int16_t result) +{ + usbtrace(TRACE_DEVERROR(SIM_TRACEERR_REQABORTED), + (uint16_t)USB_EPNO(privep->ep.eplog)); + + /* Save the result in the request structure */ + + privreq->req.result = result; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); +} + +/**************************************************************************** + * Name: sim_reqcomplete + ****************************************************************************/ + +static void sim_reqcomplete(struct sim_ep_s *privep, int16_t result) +{ + struct sim_req_s *privreq; + irqstate_t flags; + + /* Remove the completed request at the head of the endpoint request list */ + + flags = enter_critical_section(); + privreq = sim_rqdequeue(&privep->reqq); + leave_critical_section(flags); + + if (privreq) + { + /* Save the result in the request structure */ + + privreq->req.result = result; + + privep->epstate = SIM_EPSTATE_IDLE; + + /* Callback to the request completion handler */ + + privreq->req.callback(&privep->ep, &privreq->req); + } +} + +/**************************************************************************** + * Name: sim_reqwrite + ****************************************************************************/ + +static int sim_reqwrite(struct sim_usbdev_s *priv, struct sim_ep_s *privep) +{ + struct sim_req_s *privreq; + uint8_t *write_data; + int write_len; + uint8_t epno; + + /* Get the unadorned endpoint number */ + + epno = USB_EPNO(privep->ep.eplog); + + /* We get here when an IN endpoint interrupt occurs. So now we know that + * there is no TX transfer in progress. + */ + + while (privep->epstate == SIM_EPSTATE_IDLE) + { + /* Check the request from the head of the endpoint request queue */ + + privreq = sim_rqpeek(&privep->reqq); + if (!privreq) + { + return OK; + } + + while (privreq->req.xfrd < privreq->req.len) + { + /* Handle any bytes in flight. */ + + write_data = privreq->req.buf + privreq->req.xfrd; + write_len = privreq->req.len - privreq->req.xfrd; + + write_len = host_usbdev_epwrite(epno, privreq->req.flags, + write_data, write_len); + + if (write_len < 0) + { + return -EPERM; + } + + privreq->req.xfrd += write_len; + } + + /* If all of the bytes were sent (including any final zero length + * packet) then we are finished with the request buffer and we can + * return the request buffer to the class driver. The state will + * remain IDLE only if nothing else was put in flight. + * + * Note that we will then loop to check to check the next queued + * write request. + */ + + usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)), + privreq->req.xfrd); + sim_reqcomplete(privep, OK); + } + + return OK; +} + +/**************************************************************************** + * Name: sim_ep_configure + ****************************************************************************/ + +static void sim_usbdev_getctrlreq(struct usb_ctrlreq_s *usb_req, + const struct host_usb_ctrlreq_s *host_req) +{ + usb_req->type = host_req->type; + usb_req->req = host_req->req; + usb_req->value[0] = LSBYTE(host_req->value); + usb_req->value[1] = MSBYTE(host_req->value); + usb_req->index[0] = LSBYTE(host_req->index); + usb_req->index[1] = MSBYTE(host_req->index); + usb_req->len[0] = LSBYTE(host_req->len); + usb_req->len[1] = MSBYTE(host_req->len); +} + +/**************************************************************************** + * Name: sim_ep_configure + ****************************************************************************/ + +static void sim_usbdev_setepdesc(struct host_usb_epdesc_s *host_epdesc, + const struct usb_epdesc_s *usb_epdesc) +{ + host_epdesc->len = usb_epdesc->len; + host_epdesc->type = usb_epdesc->type; + host_epdesc->addr = usb_epdesc->addr; + host_epdesc->attr = usb_epdesc->attr; + host_epdesc->mxpacketsize = GETUINT16(usb_epdesc->mxpacketsize); + host_epdesc->interval = usb_epdesc->interval; +} + +/**************************************************************************** + * + * Endpoint operations + * + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_usbdev_ep0read + * + * Description: + * USB Dev receive ep0 control request. + * + ****************************************************************************/ + +static int sim_usbdev_ep0read(struct host_usb_ctrlreq_s *req) +{ + struct sim_usbdev_s *priv = &g_sim_usbdev; + uint8_t *outdata = NULL; + size_t outlen = 0; + int ret = -EINVAL; + + if (priv && priv->driver) + { + /* Save ctrl req */ + + sim_usbdev_getctrlreq(&priv->ctrl, req); + + /* Was this an OUT SETUP command? */ + + if (USB_REQ_ISOUT(priv->ctrl.type)) + { + outlen = GETUINT16(priv->ctrl.len); + outdata = req->data; + } + + /* Forward to the control request to the class driver implementation */ + + ret = CLASS_SETUP(priv->driver, &priv->usbdev, &priv->ctrl, + outdata, outlen); + if (ret < 0) + { + /* Stall on failure */ + + usbtrace(TRACE_DEVERROR(SIM_TRACEERR_DISPATCHSTALL), 0); + sim_ep_stall(&priv->eps[0].ep, false); + } + } + + return ret; +} + +/**************************************************************************** + * Name: sim_usbdev_epread + * + * Description: + * USB Dev receive ep data request. + * + ****************************************************************************/ + +static int sim_usbdev_epread(uint16_t addr, uint8_t *data, uint16_t len) +{ + struct sim_usbdev_s *priv = &g_sim_usbdev; + struct sim_ep_s *privep; + struct sim_req_s *privreq; + uint8_t *dest; + uint8_t epno; + int readlen; + + /* Get the unadorned endpoint number */ + + epno = USB_EPNO(addr); + privep = &priv->eps[epno]; + + usbtrace(TRACE_READ(USB_EPNO(privep->ep.eplog)), len); + + /* We get here when an IN endpoint interrupt occurs. So now we know that + * there is no TX transfer in progress. + */ + + while (privep->epstate == SIM_EPSTATE_IDLE && len > 0) + { + /* Check the request from the head of the endpoint request queue */ + + privreq = sim_rqpeek(&privep->reqq); + if (!privreq) + { + return -ENOENT; + } + + /* Get the source and destination transfer addresses */ + + dest = privreq->req.buf + privreq->req.xfrd; + + /* Get the number of bytes to read from packet memory */ + + readlen = MIN(privreq->req.len - privreq->req.xfrd, len); + + /* Receive the next packet */ + + memcpy(dest, data, readlen); + + /* If the receive buffer is full or this is a partial packet, + * then we are finished with the request buffer). + */ + + privreq->req.xfrd += readlen; + len -= readlen; + data += readlen; + + if (len < privep->ep.maxpacket || + privreq->req.xfrd >= privreq->req.len) + { + /* Return the read request to the class driver. */ + + usbtrace(TRACE_COMPLETE(epno), privreq->req.xfrd); + sim_reqcomplete(privep, OK); + } + } + + return OK; +} + +/**************************************************************************** + * Name: sim_ep_configure + ****************************************************************************/ + +static int sim_ep_configure(struct usbdev_ep_s *ep, + const struct usb_epdesc_s *desc, + bool last) +{ + struct sim_ep_s *privep = (struct sim_ep_s *)ep; + struct host_usb_epdesc_s host_epdesc; + uint8_t epno; + + /* Get the unadorned endpoint address */ + + epno = USB_EPNO(desc->addr); + usbtrace(TRACE_EPCONFIGURE, (uint16_t)epno); + DEBUGASSERT(epno == USB_EPNO(ep->eplog)); + + /* Get the maxpacket size of the endpoint. */ + + ep->maxpacket = GETUINT16(desc->mxpacketsize); + DEBUGASSERT(ep->maxpacket <= SIM_USB_EPMAXSIZE); + + /* Get the subset matching the requested direction */ + + if (USB_ISEPIN(desc->addr)) + { + ep->eplog = USB_EPIN(epno); + } + else + { + ep->eplog = USB_EPOUT(epno); + } + + sim_usbdev_setepdesc(&host_epdesc, desc); + host_usbdev_epconfig(epno, &host_epdesc); + + privep->epstate = SIM_EPSTATE_IDLE; + + return OK; +} + +/**************************************************************************** + * Name: sim_ep_disable + ****************************************************************************/ + +static int sim_ep_disable(struct usbdev_ep_s *ep) +{ + struct sim_ep_s *privep = (struct sim_ep_s *)ep; + irqstate_t flags; + uint8_t epno; + + epno = USB_EPNO(ep->eplog); + usbtrace(TRACE_EPDISABLE, epno); + + /* Cancel any ongoing activity */ + + flags = enter_critical_section(); + + /* Disable TX; disable RX */ + + host_usbdev_epdisable(epno); + + privep->epstate = SIM_EPSTATE_DISABLED; + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: sim_ep_allocreq + ****************************************************************************/ + +static struct usbdev_req_s *sim_ep_allocreq(struct usbdev_ep_s *ep) +{ + struct sim_req_s *privreq; + + usbtrace(TRACE_EPALLOCREQ, USB_EPNO(ep->eplog)); + + privreq = (struct sim_req_s *)kmm_malloc(sizeof(struct sim_req_s)); + if (!privreq) + { + usbtrace(TRACE_DEVERROR(SIM_TRACEERR_ALLOCFAIL), 0); + return NULL; + } + + memset(privreq, 0, sizeof(struct sim_req_s)); + return &privreq->req; +} + +/**************************************************************************** + * Name: sim_ep_freereq + ****************************************************************************/ + +static void sim_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *req) +{ + struct sim_req_s *privreq = (struct sim_req_s *)req; + + usbtrace(TRACE_EPFREEREQ, USB_EPNO(ep->eplog)); + + kmm_free(privreq); +} + +/**************************************************************************** + * Name: sim_ep_stall + ****************************************************************************/ + +static int sim_ep_stall(struct usbdev_ep_s *ep, bool resume) +{ + struct sim_ep_s *privep = (struct sim_ep_s *)ep; + uint8_t epno; + irqstate_t flags; + int ret; + + DEBUGASSERT(ep != NULL); + + epno = USB_EPNO(ep->eplog); + + /* STALL or RESUME the endpoint */ + + flags = enter_critical_section(); + usbtrace(resume ? TRACE_EPRESUME : TRACE_EPSTALL, epno); + + ret = host_usbdev_epstall(epno, resume); + + privep->epstate = SIM_EPSTATE_STALLED; + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: sim_ep_submit + ****************************************************************************/ + +static int sim_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req) +{ + struct sim_req_s *privreq = (struct sim_req_s *)req; + struct sim_ep_s *privep = (struct sim_ep_s *)ep; + struct sim_usbdev_s *priv; + irqstate_t flags; + uint8_t epno; + int ret = OK; + + DEBUGASSERT(ep != NULL && req != NULL && req->callback != + NULL && req->buf != NULL); + usbtrace(TRACE_EPSUBMIT, USB_EPNO(ep->eplog)); + priv = privep->dev; + DEBUGASSERT(priv->driver != NULL); + + /* Handle the request from the class driver */ + + epno = USB_EPNO(ep->eplog); + req->result = -EINPROGRESS; + req->xfrd = 0; + flags = enter_critical_section(); + + if (privep->epstate == SIM_EPSTATE_STALLED) + { + sim_reqabort(privep, privreq, -EBUSY); + return -EPERM; + } + + /* Handle IN (device-to-host) requests. NOTE: If the class device is + * using the bi-directional EP0, then we assume that they intend the EP0 + * IN functionality (EP0 SETUP OUT data receipt does not use requests). + */ + + if (USB_ISEPIN(ep->eplog) || epno == 0) + { + usbtrace(TRACE_INREQQUEUED(epno), req->len); + + /* Add the new request to the request queue for the endpoint */ + + sim_rqenqueue(&privep->reqq, privreq); + + /* If the IN endpoint is IDLE, then transfer the data now */ + + if (privep->epstate == SIM_EPSTATE_IDLE) + { + ret = sim_reqwrite(priv, privep); + } + } + + /* Handle OUT (host-to-device) requests */ + + else + { + /* Add the new request to the request queue for the OUT endpoint */ + + usbtrace(TRACE_OUTREQQUEUED(epno), req->len); + sim_rqenqueue(&privep->reqq, privreq); + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: sim_ep_cancel + ****************************************************************************/ + +static int sim_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req) +{ + irqstate_t flags; + + usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog)); + + flags = enter_critical_section(); + host_usbdev_epcancel(USB_EPNO(ep->eplog)); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Device Controller Operations + ****************************************************************************/ + +/**************************************************************************** + * + * Name: sim_ep_reserve + * + * Description: + * Find an un-reserved endpoint number and reserve it for the caller. + * + ****************************************************************************/ + +static struct sim_ep_s *sim_ep_reserve(struct sim_usbdev_s *priv, + uint16_t epset) +{ + struct sim_ep_s *privep = NULL; + irqstate_t flags; + int epndx = 0; + + flags = enter_critical_section(); + epset &= priv->epavail; + if (epset) + { + /* Select the lowest bit in the set of matching, available endpoints + * (skipping EP0) + */ + + for (epndx = 1; epndx < SIM_USB_EPNUM; epndx++) + { + uint16_t bit = SIM_EP_BIT(epndx); + if ((epset & bit) != 0) + { + /* Mark the endpoint no longer available */ + + priv->epavail &= ~bit; + + /* And return the pointer to the standard endpoint structure */ + + privep = &priv->eps[epndx]; + break; + } + } + } + + leave_critical_section(flags); + return privep; +} + +/**************************************************************************** + * + * Name: sim_ep_unreserve + * + * Description: + * The endpoint is no long in-used. It will be un-reserved and can be + * re-used if needed. + * + ****************************************************************************/ + +static void sim_ep_unreserve(struct sim_usbdev_s *priv, + struct sim_ep_s *privep) +{ + irqstate_t flags = enter_critical_section(); + priv->epavail |= SIM_EP_BIT(USB_EPNO(privep->ep.eplog)); + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: sim_usbdev_allocep + ****************************************************************************/ + +static struct usbdev_ep_s *sim_usbdev_allocep(struct usbdev_s *dev, + uint8_t epno, bool in, + uint8_t eptype) +{ + struct sim_usbdev_s *priv = (struct sim_usbdev_s *)dev; + struct sim_ep_s *privep = NULL; + uint16_t epset = SIM_EPSET_NOEP0; + + usbtrace(TRACE_DEVALLOCEP, (uint16_t)epno); + DEBUGASSERT(dev != NULL); + + /* Ignore any direction bits in the logical address */ + + epno = USB_EPNO(epno); + + /* A logical address of 0 means that any endpoint will do */ + + if (epno > 0) + { + /* Otherwise, we will return the endpoint + * structure only for the requested 'logical' endpoint. + * All of the other checks will still be performed. + * + * First, verify that the logical endpoint is in the + * range supported by the hardware. + */ + + if (epno >= SIM_USB_EPNUM) + { + usbtrace(TRACE_DEVERROR(SIM_TRACEERR_BADEPNO), (uint16_t)epno); + return NULL; + } + + /* Convert the logical address to a physical OUT endpoint address and + * remove all of the candidate endpoints from the bitset except for the + * the IN/OUT pair for this logical address. + */ + + epset = SIM_EP_BIT(epno); + } + + /* Check if the selected endpoint number is available */ + + privep = sim_ep_reserve(priv, epset); + if (!privep) + { + usbtrace(TRACE_DEVERROR(SIM_TRACEERR_EPRESERVE), (uint16_t)epset); + return NULL; + } + + return &privep->ep; +} + +/**************************************************************************** + * Name: sim_usbdev_freeep + ****************************************************************************/ + +static void sim_usbdev_freeep(struct usbdev_s *dev, struct usbdev_ep_s *ep) +{ + struct sim_usbdev_s *priv; + struct sim_ep_s *privep; + + DEBUGASSERT(dev != NULL && ep != NULL); + + priv = (struct sim_usbdev_s *)dev; + privep = (struct sim_ep_s *)ep; + usbtrace(TRACE_DEVFREEEP, (uint16_t)USB_EPNO(ep->eplog)); + + if (priv && privep) + { + /* Mark the endpoint as available */ + + sim_ep_unreserve(priv, privep); + } +} + +/**************************************************************************** + * + * Name: sim_usbdev_getframe + * + * Description: + * This is the getframe() method of the USB device driver interface + * + ****************************************************************************/ + +static int sim_usbdev_getframe(struct usbdev_s *dev) +{ + return 0; +} + +/**************************************************************************** + * + * Name: sim_usbdev_wakeup + * + * Description: + * This is the wakeup() method of the USB device driver interface + * + ****************************************************************************/ + +static int sim_usbdev_wakeup(struct usbdev_s *dev) +{ + return OK; +} + +/**************************************************************************** + * + * Name: sim_usbdev_selfpowered + * + * Description: + * This is the selfpowered() method of the USB device driver interface + * + ****************************************************************************/ + +static int sim_usbdev_selfpowered(struct usbdev_s *dev, bool selfpowered) +{ + struct sim_usbdev_s *priv = (struct sim_usbdev_s *)dev; + + usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered); + DEBUGASSERT(dev != NULL); + + priv->selfpowered = selfpowered; + return OK; +} + +/**************************************************************************** + * + * Name: sim_usbdev_pullup + * + * Description: + * This is the pullup() method of the USB device driver interface + * + ****************************************************************************/ + +static int sim_usbdev_pullup(struct usbdev_s *dev, bool enable) +{ + irqstate_t flags; + + usbtrace(TRACE_DEVPULLUP, (uint16_t)enable); + + flags = enter_critical_section(); + host_usbdev_pullup(enable); + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: sim_usbdevinit + * + * Description: + * Initialize the USB dev + * + ****************************************************************************/ + +static void sim_usbdev_devinit(struct sim_usbdev_s *dev) +{ + uint8_t epno; + + memset(dev, 0, sizeof(struct sim_usbdev_s)); + + dev->usbdev.ep0 = &dev->eps[0].ep; + dev->usbdev.ops = &g_devops; + dev->usbdev.speed = SIM_USB_SPEED; + + for (epno = 0; epno < SIM_USB_EPNUM; epno++) + { + dev->eps[epno].dev = dev; + dev->eps[epno].ep.ops = &g_epops; + dev->eps[epno].ep.eplog = epno; + dev->eps[epno].ep.maxpacket = SIM_USB_MAXPACKETSIZE(epno); + } + + dev->eps[0].epstate = SIM_EPSTATE_IDLE; + + dev->epavail = SIM_EPSET_NOEP0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sim_usbdev_initialize + * + * Description: + * Initialize the USB driver + * + ****************************************************************************/ + +void sim_usbdev_initialize(void) +{ +} + +/**************************************************************************** + * Name: usbdev_register + * + * Description: + * Register a USB device class driver. The class driver's bind() method + * will be called to bind it to a USB device driver. + * + ****************************************************************************/ + +int usbdev_register(struct usbdevclass_driver_s *driver) +{ + struct sim_usbdev_s *priv = &g_sim_usbdev; + int ret; + + usbtrace(TRACE_DEVREGISTER, 0); + + /* First hook up the driver */ + + sim_usbdev_devinit(priv); + priv->driver = driver; + + /* Then bind the class driver */ + + ret = CLASS_BIND(driver, &priv->usbdev); + if (ret) + { + usbtrace(TRACE_DEVERROR(SIM_TRACEERR_BINDFAILED), (uint16_t) - ret); + } + else + { + /* Setup the USB host controller */ + +#ifdef CONFIG_USBDEV_DUALSPEED + host_usbdev_init(SIM_USB_SPEED); +#else + host_usbdev_init(USB_SPEED_FULL); +#endif + } + + return ret; +} + +/**************************************************************************** + * Name: usbdev_unregister + * + * Description: + * Un-register usbdev class driver.If the USB device is connected to a USB + * host, it will first disconnect(). The driver is also requested to + * unbind() and clean up any device state, before this procedure finally + * returns. + * + ****************************************************************************/ + +int usbdev_unregister(struct usbdevclass_driver_s *driver) +{ + /* At present, there is only a single OTG FS device support. Hence it is + * pre-allocated as g_otgfsdev. However, in most code, the private data + * structure will be referenced using the 'priv' pointer (rather than the + * global data) in order to simplify any future support for multiple + * devices. + */ + + struct sim_usbdev_s *priv = &g_sim_usbdev; + irqstate_t flags; + + usbtrace(TRACE_DEVUNREGISTER, 0); + + /* Reset the hardware and cancel all requests. All requests must be + * canceled while the class driver is still bound. + */ + + flags = enter_critical_section(); + host_usbdev_deinit(); + leave_critical_section(flags); + + /* Unbind the class driver */ + + CLASS_UNBIND(driver, &priv->usbdev); + + /* Disable USB controller interrupts */ + + flags = enter_critical_section(); + + /* Disconnect device */ + + host_usbdev_pullup(false); + + /* Unhook the driver */ + + priv->driver = NULL; + leave_critical_section(flags); + + return OK; +} + +/**************************************************************************** + * Name: sim_usbdev_loop + * + * Description: + * USB Dev receive ep0 control request. + * + ****************************************************************************/ + +int sim_usbdev_loop(void) +{ + struct sim_usbdev_s *priv = &g_sim_usbdev; + struct sim_ep_s *privep; + struct host_usb_ctrlreq_s *ctrlreq; + uint8_t *recv_data; + uint16_t data_len; + uint8_t epcnt; + + /* Loop ep0 */ + + ctrlreq = host_usbdev_ep0read(); + if (ctrlreq) + { + sim_usbdev_ep0read(ctrlreq); + host_usbdev_epread_end(0); + } + + /* Loop other eps */ + + for (epcnt = 1; epcnt < SIM_USB_EPNUM; epcnt++) + { + privep = &priv->eps[epcnt]; + if (privep->epstate == SIM_EPSTATE_IDLE && + !USB_ISEPIN(privep->ep.eplog)) + { + recv_data = host_usbdev_epread(epcnt, &data_len); + if (recv_data) + { + sim_usbdev_epread(privep->ep.eplog, recv_data, data_len); + host_usbdev_epread_end(epcnt); + } + } + } + + return OK; +} diff --git a/arch/sim/src/sim/sim_usbdev.h b/arch/sim/src/sim/sim_usbdev.h new file mode 100644 index 0000000000..28aa07a89f --- /dev/null +++ b/arch/sim/src/sim/sim_usbdev.h @@ -0,0 +1,87 @@ +/**************************************************************************** + * arch/sim/src/sim/sim_usbdev.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_DEV_H +#define __ARCH_SIM_SRC_SIM_USB_DEV_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; + uint8_t data[0]; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/* Host USB Interface */ + +int host_usbdev_init(uint32_t speed); +int host_usbdev_deinit(void); +int host_usbdev_pullup(bool enable); +int host_usbdev_epconfig(uint8_t epno, + const struct host_usb_epdesc_s *epdesc); +int host_usbdev_epdisable(uint8_t epno); +int host_usbdev_epstall(uint8_t epno, bool resume); +int host_usbdev_epcancel(uint8_t epno); +int host_usbdev_epwrite(uint8_t epno, uint8_t flags, + uint8_t *data, uint16_t len); +struct host_usb_ctrlreq_s *host_usbdev_ep0read(void); +uint8_t *host_usbdev_epread(uint8_t epno, uint16_t *len); +void host_usbdev_epread_end(uint8_t epno); + +#endif /* __ARCH_SIM_SRC_SIM_USB_DEV_H */ diff --git a/boards/sim/sim/sim/Kconfig b/boards/sim/sim/sim/Kconfig index 44a68af6a5..1267b0bb64 100644 --- a/boards/sim/sim/sim/Kconfig +++ b/boards/sim/sim/sim/Kconfig @@ -59,4 +59,13 @@ config SIM_WTGAHRS2_UARTN We can select the number according to which SIM_UARTX_NAME is used to sensor. This range is 0-4. +config SIM_RNDIS_MACADDR + hex "RNDIS MAC address" + default 0xfadedeadbeef + depends on RNDIS + ---help--- + If the hardware has no built-in MAC address then the fixed, + software-assigned MAC address MAC address must provided + with this selection. + endif diff --git a/boards/sim/sim/sim/README.txt b/boards/sim/sim/sim/README.txt index c6d84bddb6..58e8903cc6 100644 --- a/boards/sim/sim/sim/README.txt +++ b/boards/sim/sim/sim/README.txt @@ -1435,3 +1435,117 @@ wamr [0]crcfinal : 0xa14c Correct operation validated. See README.md for run and reporting rules. CoreMark 1.0 : 5.000000 / Clang 15.0.7 Using NuttX compilation options / Defined by the NuttX configuration + +usbdev + + This is a configuration with sim usbdev support. + + 1. Raw Gadget setup + + Get Raw Gadget: + Get Raw Gadget code at https://github.com/xairy/raw-gadget. + + Make Raw Gadget: + Run make in the raw_gadget and dummy_hcd directory. If raw_gadget build + fail, you need to check which register interface meets your kenel version, + usb_gadget_probe_driver or usb_gadget_register_driver. + + Install Raw Gadget: + Run ./insmod.sh in the raw_gadget and dummy_hcd directory. + + 2. Configuration + + sim:usbdev contains two different sets of composite devices: + conn0: adb & rndis + conn1: cdcacm & cdcecm + + You can use the sim:usbdev configuration: + ./tools/configure.sh sim:usbdev + + 3. How to run + + Run nuttx with root mode, then you can use it as the following: + + 1> Run ADB: + + NuttX enter command: + $ conn 0 + $ adbd & + + Host PC enter the ADB command: + $ adb kill-server + $ adb devices + List of devices attached + * daemon not running; starting now at tcp:5037 + * daemon started successfully + 0101 device + + If ADB connection fails, make sure the udev rule is added correctly. + Edit /etc/udev/rules.d/51-android.rules file and add the following to it: + SUBSYSTEM=="usb", ATTR{idVendor}=="1630", ATTR{idProduct}=="0042", MODE="0666", GROUP="plugdev" + + Then you can use commands such as adb shell, adb push, adb pull as normal. + + 2> Run RNDIS: + + NuttX enter command: + $ conn 0 + $ ifconfig + eth0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 at UP + inet addr:0.0.0.0 DRaddr:0.0.0.0 Mask:0.0.0.0 + $ dhcpd_start eth0 + eth0 Link encap:Ethernet HWaddr 00:00:00:00:00:00 at UP + inet addr:10.0.0.1 DRaddr:10.0.0.1 Mask:255.255.255.0 + + Host PC, you can see the network device named usb0: + $ ifconfig + usb0: flags=4163 mtu 602 + inet 10.0.0.4 netmask 255.255.255.0 broadcast 10.0.0.255 + ether 36:50:3d:62:b5:80 txqueuelen 1000 (以太网) + RX packets 0 bytes 0 (0.0 B) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 43 bytes 8544 (8.5 KB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + + Then you can test the network connection using the ping command or telnet. + + 3> Run CDCACM: + + NuttX enter command: + $ conn 1 + + If the connection is successful, you can see /dev/ttyACM devices on both NuttX + and host PC. + + Then you can use echo and cat command to test: + + NuttX: + nsh> echo hello > /dev/ttyACM0 + + Host PC: + $ cat /dev/ttyACM0 + hello + + 3> Run CDCECM: + + NuttX enter command: + $ conn 1 + $ ifconfig + eth0 Link encap:Ethernet HWaddr 00:e0:de:ad:be:ef at UP + inet addr:0.0.0.0 DRaddr:0.0.0.0 Mask:0.0.0.0 + $ dhcpd_start eth0 + $ ifconfig + eth0 Link encap:Ethernet HWaddr 00:e0:de:ad:be:ef at UP + inet addr:10.0.0.1 DRaddr:10.0.0.1 Mask:255.255.255.0 + + Host PC, you can see the network device named enx020000112233: + $ ifconfig + enx020000112233: flags=4163 mtu 576 + inet 10.0.0.4 netmask 255.255.255.0 broadcast 10.0.0.255 + ether 02:00:00:11:22:33 txqueuelen 1000 (以太网) + RX packets 0 bytes 0 (0.0 B) + RX errors 0 dropped 0 overruns 0 frame 0 + TX packets 58 bytes 9143 (9.1 KB) + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 + + Then you can test the network connection using the ping command or telnet. diff --git a/boards/sim/sim/sim/configs/usbdev/defconfig b/boards/sim/sim/sim/configs/usbdev/defconfig new file mode 100644 index 0000000000..254ebcfd9b --- /dev/null +++ b/boards/sim/sim/sim/configs/usbdev/defconfig @@ -0,0 +1,82 @@ +# +# 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_ADBD_FILE_SERVICE=y +CONFIG_ADBD_FILE_SYMLINK=y +CONFIG_ADBD_SHELL_SERVICE=y +CONFIG_ADBD_USB_SERVER=y +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_BOARD_LATE_INITIALIZE=y +CONFIG_BUILTIN=y +CONFIG_CDCACM=y +CONFIG_CDCACM_COMPOSITE=y +CONFIG_CDCECM_COMPOSITE=y +CONFIG_COMPOSITE_IAD=y +CONFIG_COMPOSITE_PRODUCTID=0x0042 +CONFIG_COMPOSITE_VENDORID=0x1630 +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_EXAMPLES_DHCPD=y +CONFIG_FS_PROCFS=y +CONFIG_FS_TMPFS=y +CONFIG_INIT_ENTRYPOINT="nsh_main" +CONFIG_LIBC_DLFCN=y +CONFIG_LIBUV=y +CONFIG_NETUTILS_DHCPD=y +CONFIG_NETUTILS_TELNETC=y +CONFIG_NETUTILS_TELNETD=y +CONFIG_NET_BROADCAST=y +CONFIG_NET_CDCECM=y +CONFIG_NET_ICMP=y +CONFIG_NET_ICMP_SOCKET=y +CONFIG_NET_LL_GUARDSIZE=50 +CONFIG_NET_SOCKOPTS=y +CONFIG_NET_TCP=y +CONFIG_NET_UDP=y +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_PSEUDOFS_SOFTLINKS=y +CONFIG_READLINE_CMD_HISTORY=y +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_RNDIS=y +CONFIG_RNDIS_COMPOSITE=y +CONFIG_SCHED_CHILD_STATUS=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_LPWORK=y +CONFIG_SCHED_WAITPID=y +CONFIG_SIM_USB_DEV=y +CONFIG_SIM_USB_RAW_GADGET=y +CONFIG_SYSLOG_CHARDEV=y +CONFIG_SYSLOG_MAX_CHANNELS=2 +CONFIG_SYSTEM_ADBD=y +CONFIG_SYSTEM_CLE=y +CONFIG_SYSTEM_COMPOSITE=y +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_PING=y +CONFIG_TESTING_OSTEST=y +CONFIG_TLS_TASK_NELEM=4 +CONFIG_USBADB=y +CONFIG_USBADB_COMPOSITE=y +CONFIG_USBDEV_COMPOSITE=y +CONFIG_USBDEV_DUALSPEED=y diff --git a/boards/sim/sim/sim/src/Makefile b/boards/sim/sim/sim/src/Makefile index a249ae8afa..d8d590dd5f 100644 --- a/boards/sim/sim/sim/src/Makefile +++ b/boards/sim/sim/sim/src/Makefile @@ -67,4 +67,8 @@ ifeq ($(CONFIG_MOTOR_FOC_DUMMY),y) CSRCS += sim_foc.c endif +ifeq ($(CONFIG_USBDEV_COMPOSITE),y) +CSRCS += sim_composite.c +endif + include $(TOPDIR)/boards/Board.mk diff --git a/boards/sim/sim/sim/src/sim_bringup.c b/boards/sim/sim/sim/src/sim_bringup.c index 8d976546cb..7667e2237f 100644 --- a/boards/sim/sim/sim/src/sim_bringup.c +++ b/boards/sim/sim/sim/src/sim_bringup.c @@ -53,6 +53,8 @@ #include #include #include +#include +#include #ifdef CONFIG_LCD_DEV #include @@ -496,5 +498,22 @@ int sim_bringup(void) rc_dummy_initialize(0); #endif +#if defined(CONFIG_USBADB) && !defined(CONFIG_USBADB_COMPOSITE) + usbdev_adb_initialize(); +#endif + +#if defined(CONFIG_RNDIS) && !defined(CONFIG_RNDIS_COMPOSITE) + /* Set up a MAC address for the RNDIS device. */ + + uint8_t mac[6]; + mac[0] = (CONFIG_SIM_RNDIS_MACADDR >> (8 * 5)) & 0xff; + mac[1] = (CONFIG_SIM_RNDIS_MACADDR >> (8 * 4)) & 0xff; + mac[2] = (CONFIG_SIM_RNDIS_MACADDR >> (8 * 3)) & 0xff; + mac[3] = (CONFIG_SIM_RNDIS_MACADDR >> (8 * 2)) & 0xff; + mac[4] = (CONFIG_SIM_RNDIS_MACADDR >> (8 * 1)) & 0xff; + mac[5] = (CONFIG_SIM_RNDIS_MACADDR >> (8 * 0)) & 0xff; + usbdev_rndis_initialize(mac); +#endif + return ret; } diff --git a/boards/sim/sim/sim/src/sim_composite.c b/boards/sim/sim/sim/src/sim_composite.c new file mode 100644 index 0000000000..073a11e95c --- /dev/null +++ b/boards/sim/sim/sim/src/sim_composite.c @@ -0,0 +1,260 @@ +/**************************************************************************** + * boards/sim/sim/sim/src/sim_composite.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 + +#if defined(CONFIG_BOARDCTL_USBDEVCTRL) && defined(CONFIG_USBDEV_COMPOSITE) + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_composite0_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 0. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static void *board_composite0_connect(int port) +{ + struct composite_devdesc_s dev[2]; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS - 1; + int dev_idx = 0; + +#ifdef CONFIG_RNDIS + /* Configure the RNDIS USB device */ + + usbdev_rndis_get_composite_devdesc(&dev[dev_idx]); + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; + dev[dev_idx].minor = 0; + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[RNDIS_EP_BULKIN_IDX] = 1; + dev[dev_idx].devinfo.epno[RNDIS_EP_BULKOUT_IDX] = 2; + dev[dev_idx].devinfo.epno[RNDIS_EP_INTIN_IDX] = 5; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + +#ifdef CONFIG_USBADB + /* Configure the ADB USB device */ + + usbdev_adb_get_composite_devdesc(&dev[dev_idx]); + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; + dev[dev_idx].minor = 0; + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[USBADB_EP_BULKIN_IDX] = 6; + dev[dev_idx].devinfo.epno[USBADB_EP_BULKOUT_IDX] = 7; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + + return composite_initialize(dev_idx, dev); +} + +/**************************************************************************** + * Name: board_composite1_connect + * + * Description: + * Connect the USB composite device on the specified USB device port for + * configuration 1. + * + * Input Parameters: + * port - The USB device port. + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +static void *board_composite1_connect(int port) +{ + struct composite_devdesc_s dev[2]; + int ifnobase = 0; + int strbase = COMPOSITE_NSTRIDS - 1; + int dev_idx = 0; + +#ifdef CONFIG_CDCACM + /* Configure the CDC/ACM device */ + + cdcacm_get_composite_devdesc(&dev[dev_idx]); + + /* The callback functions for the CDC/ACM class */ + + dev[dev_idx].classobject = cdcacm_classobject; + dev[dev_idx].uninitialize = cdcacm_uninitialize; + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; + dev[dev_idx].minor = 0; + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[CDCACM_EP_INTIN_IDX] = 5; + dev[dev_idx].devinfo.epno[CDCACM_EP_BULKIN_IDX] = 6; + dev[dev_idx].devinfo.epno[CDCACM_EP_BULKOUT_IDX] = 7; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + +#ifdef CONFIG_NET_CDCECM + /* Configure the CDC/ECM device */ + + cdcecm_get_composite_devdesc(&dev[dev_idx]); + + /* Interfaces */ + + dev[dev_idx].devinfo.ifnobase = ifnobase; + dev[dev_idx].minor = 0; + + /* Strings */ + + dev[dev_idx].devinfo.strbase = strbase; + + /* Endpoints */ + + dev[dev_idx].devinfo.epno[CDCECM_EP_INTIN_IDX] = 10; + dev[dev_idx].devinfo.epno[CDCECM_EP_BULKIN_IDX] = 11; + dev[dev_idx].devinfo.epno[CDCECM_EP_BULKOUT_IDX] = 12; + + /* Count up the base numbers */ + + ifnobase += dev[dev_idx].devinfo.ninterfaces; + strbase += dev[dev_idx].devinfo.nstrings; + + dev_idx += 1; +#endif + + return composite_initialize(dev_idx, dev); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_composite_initialize + * + * Description: + * Perform architecture specific initialization of a composite USB device. + * + ****************************************************************************/ + +int board_composite_initialize(int port) +{ + return OK; +} + +/**************************************************************************** + * Name: board_composite_connect + * + * Description: + * Connect the USB composite device on the specified USB device port using + * the specified configuration. The interpretation of the configid is + * board specific. + * + * Input Parameters: + * port - The USB device port. + * configid - The USB composite configuration + * + * Returned Value: + * A non-NULL handle value is returned on success. NULL is returned on + * any failure. + * + ****************************************************************************/ + +void *board_composite_connect(int port, int configid) +{ + if (configid == 0) + { + return board_composite0_connect(port); + } + else + { + return board_composite1_connect(port); + } +} + +#endif /* CONFIG_BOARDCTL_USBDEVCTRL && CONFIG_USBDEV_COMPOSITE */ diff --git a/tools/nxstyle.c b/tools/nxstyle.c index c2d71e33c0..45731a6ccf 100644 --- a/tools/nxstyle.c +++ b/tools/nxstyle.c @@ -505,6 +505,22 @@ static const char *g_white_list[] = "NimMain", + /* Ref: + * sim/posix/sim_rawgadget.c + */ + + "bRequestType", + "bRequest", + "wValue", + "wIndex", + "wLength", + "bLength", + "bDescriptorType", + "bEndpointAddress", + "bmAttributes", + "wMaxPacketSize", + "bInterval", + NULL };