diff --git a/drivers/usb/device/CMakeLists.txt b/drivers/usb/device/CMakeLists.txt index 27e68f60b09..65a5d4e529b 100644 --- a/drivers/usb/device/CMakeLists.txt +++ b/drivers/usb/device/CMakeLists.txt @@ -4,3 +4,7 @@ zephyr_sources_ifdef(CONFIG_USB_DC_SAM0 usb_dc_sam0.c) zephyr_sources_ifdef(CONFIG_USB_DC_SAM usb_dc_sam.c) zephyr_sources_ifdef(CONFIG_USB_NRF52840 usb_dc_nrfx.c) zephyr_sources_ifdef(CONFIG_USB_KINETIS usb_dc_kinetis.c) +zephyr_sources_ifdef(CONFIG_USB_NATIVE_POSIX + usb_dc_native_posix.c + usb_dc_native_posix_adapt.c + ) diff --git a/drivers/usb/device/Kconfig b/drivers/usb/device/Kconfig index d7f44ebcfe5..2d750965af5 100644 --- a/drivers/usb/device/Kconfig +++ b/drivers/usb/device/Kconfig @@ -91,4 +91,10 @@ config USB_DC_STM32_DISCONN_ENABLE Say Y if your board uses USB DISCONNECT pin to enable the pull-up resistor on USB DP. +config USB_NATIVE_POSIX + bool "Native Posix USB Device Controller Driver" + select USB_DEVICE_DRIVER + help + Native Posix USB Device Controller Driver. + endif # USB diff --git a/drivers/usb/device/usb_dc_native_posix.c b/drivers/usb/device/usb_dc_native_posix.c new file mode 100644 index 00000000000..e474f432d5e --- /dev/null +++ b/drivers/usb/device/usb_dc_native_posix.c @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * @brief USB native_posix device driver + */ + +#include +#include +#include +#include +#include +#include + +#include "usb_dc_native_posix_adapt.h" + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_USB_DRIVER_LEVEL +#define SYS_LOG_DOMAIN "usb/native_posix" +#include + +/* convert from endpoint address to hardware endpoint index */ +#define USBIP_EP_ADDR2IDX(ep) ((ep) & ~USB_EP_DIR_MASK) +/* get direction from endpoint address */ +#define USBIP_EP_ADDR2DIR(ep) ((ep) & USB_EP_DIR_MASK) +/* convert from hardware endpoint index and direction to endpoint address */ +#define USBIP_EP_IDX2ADDR(idx, dir) ((idx) | ((dir) & USB_EP_DIR_MASK)) + +#define USBIP_IN_EP_NUM 4 +#define USBIP_OUT_EP_NUM 4 + +#define USBIP_MAX_PACKET_SIZE 64 + +K_THREAD_STACK_MEMBER(thread_stack, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); +static struct k_thread thread; + +static void thread_main(void *a, void *b, void *c) +{ + SYS_LOG_DBG(""); + + usbip_start(); +} + +/* + * USBIP private structures and logic initially copied from + * Designware USB driver + */ + +/* + * USB endpoint private structure. + */ +struct usb_ep_ctrl_prv { + u8_t ep_ena; + u16_t mps; + usb_dc_ep_callback cb; + u32_t data_len; +}; + +/* + * USB controller private structure. + */ +static struct usbip_ctrl_prv { + usb_dc_status_callback status_cb; + struct usb_ep_ctrl_prv in_ep_ctrl[USBIP_IN_EP_NUM]; + struct usb_ep_ctrl_prv out_ep_ctrl[USBIP_OUT_EP_NUM]; + u8_t attached; +} usbip_ctrl; + +static u8_t usbip_ep_is_valid(u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + /* Check if ep is valid */ + if ((USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT) && + ep_idx < USBIP_OUT_EP_NUM) { + return 1; + } else if ((USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_IN) && + ep_idx < USBIP_IN_EP_NUM) { + return 1; + } + + return 0; +} + +static u8_t usbip_ep_is_enabled(u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + SYS_LOG_DBG("ep %x", ep); + + /* Check if ep enabled */ + if ((USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT) && + usbip_ctrl.out_ep_ctrl[ep_idx].ep_ena) { + return 1; + } else if ((USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_IN) && + usbip_ctrl.in_ep_ctrl[ep_idx].ep_ena) { + return 1; + } + + return 0; +} + +int usb_dc_attach(void) +{ + SYS_LOG_DBG(""); + + if (usbip_ctrl.attached) { + SYS_LOG_WRN("Already attached"); + return 0; + } + + k_thread_create(&thread, thread_stack, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE, + thread_main, NULL, NULL, NULL, + K_PRIO_COOP(2), 0, K_NO_WAIT); + + usbip_ctrl.attached = 1; + + return 0; +} + +int usb_dc_detach(void) +{ + SYS_LOG_DBG(""); + + if (!usbip_ctrl.attached) { + return 0; + } + + usbip_ctrl.attached = 0; + + return 0; +} + +int usb_dc_reset(void) +{ + SYS_LOG_DBG(""); + + /* Clear private data */ + memset(&usbip_ctrl, 0, sizeof(usbip_ctrl)); + + return 0; +} + +int usb_dc_set_address(const u8_t addr) +{ + SYS_LOG_DBG(""); + + return 0; +} + +int usb_dc_ep_check_cap(const struct usb_dc_ep_cfg_data * const cfg) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(cfg->ep_addr); + + SYS_LOG_DBG("ep %x, mps %d, type %d", cfg->ep_addr, cfg->ep_mps, + cfg->ep_type); + + if ((cfg->ep_type == USB_DC_EP_CONTROL) && ep_idx) { + SYS_LOG_ERR("invalid endpoint configuration"); + return -1; + } + + if (cfg->ep_mps > USBIP_MAX_PACKET_SIZE) { + SYS_LOG_WRN("unsupported packet size"); + return -1; + } + + if ((USBIP_EP_ADDR2DIR(cfg->ep_addr) == USB_EP_DIR_OUT) && + (ep_idx >= USBIP_OUT_EP_NUM)) { + SYS_LOG_WRN("OUT endpoint address out of range"); + return -1; + } + + if ((USBIP_EP_ADDR2DIR(cfg->ep_addr) == USB_EP_DIR_IN) && + (ep_idx >= USBIP_IN_EP_NUM)) { + SYS_LOG_WRN("IN endpoint address out of range"); + return -1; + } + + return 0; +} + +int usb_dc_ep_configure(const struct usb_dc_ep_cfg_data * const cfg) +{ + SYS_LOG_DBG("ep %x, mps %d, type %d", cfg->ep_addr, cfg->ep_mps, + cfg->ep_type); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(cfg->ep_addr)) { + return -EINVAL; + } + + return 0; +} + +int usb_dc_ep_set_stall(const u8_t ep) +{ + SYS_LOG_DBG("ep %x", ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + /* Use standard reply for now */ + usb_dc_ep_write(0x80, NULL, 0, NULL); + + return 0; +} + +int usb_dc_ep_clear_stall(const u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + SYS_LOG_DBG("ep %x", ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + if (!ep_idx) { + /* Not possible to clear stall for EP0 */ + return -EINVAL; + } + + return 0; +} + +int usb_dc_ep_halt(const u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + SYS_LOG_DBG("ep %x", ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + if (!ep_idx) { + /* Cannot disable EP0, just set stall */ + usb_dc_ep_set_stall(ep); + } + + return 0; +} + +int usb_dc_ep_is_stalled(const u8_t ep, u8_t *const stalled) +{ + SYS_LOG_DBG("ep %x", ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + if (!stalled) { + return -EINVAL; + } + + return 0; +} + +int usb_dc_ep_enable(const u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + SYS_LOG_DBG("ep %x", ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + /* Enable Ep */ + if (USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT) { + usbip_ctrl.out_ep_ctrl[ep_idx].ep_ena = 1; + } else { + usbip_ctrl.in_ep_ctrl[ep_idx].ep_ena = 1; + } + + return 0; +} + +int usb_dc_ep_disable(const u8_t ep) +{ + SYS_LOG_DBG("ep %x", ep); + + return 0; +} + +int usb_dc_ep_flush(const u8_t ep) +{ + SYS_LOG_DBG("ep %x", ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + if (USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT) { + /* RX FIFO is global and cannot be flushed per EP */ + return -EINVAL; + } + + return 0; +} + +int usb_dc_ep_write(const u8_t ep, const u8_t *const data, + const u32_t data_len, u32_t * const ret_bytes) +{ + SYS_LOG_DBG("ep %x len %u", ep, data_len); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + /* Check if IN ep */ + if (USBIP_EP_ADDR2DIR(ep) != USB_EP_DIR_IN) { + return -EINVAL; + } + + /* Check if ep enabled */ + if (!usbip_ep_is_enabled(ep)) { + return -EINVAL; + } + + /* Control */ + if (USBIP_EP_ADDR2IDX(ep) == 0) { + usbip_send_common(ep, data_len); + usbip_send(ep, (u8_t *)&setup, sizeof(setup)); + usbip_send(ep, data, data_len); + } + + if (ret_bytes) { + *ret_bytes = data_len; + } + + return 0; +} + +int usb_dc_ep_read_wait(u8_t ep, u8_t *data, u32_t max_data_len, + u32_t *read_bytes) +{ + u32_t bytes; + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + SYS_LOG_ERR("No valid endpoint"); + return -EINVAL; + } + + /* Check if OUT ep */ + if (USBIP_EP_ADDR2DIR(ep) != USB_EP_DIR_OUT) { + SYS_LOG_ERR("Wrong endpoint direction"); + return -EINVAL; + } + + /* Allow to read 0 bytes */ + if (!data && max_data_len) { + SYS_LOG_ERR("Wrong arguments"); + return -EINVAL; + } + + /* Check if ep enabled */ + if (!usbip_ep_is_enabled(ep)) { + SYS_LOG_ERR("Not enabled endpoint"); + return -EINVAL; + } + + SYS_LOG_DBG("ep %x max_data_len %u", ep, max_data_len); + + bytes = usbip_recv(data, max_data_len); + + if (read_bytes) { + *read_bytes = bytes; + } + + return 0; +} + +int usb_dc_ep_read_continue(u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + SYS_LOG_ERR("No valid endpoint"); + return -EINVAL; + } + + /* Check if OUT ep */ + if (USBIP_EP_ADDR2DIR(ep) != USB_EP_DIR_OUT) { + SYS_LOG_ERR("Wrong endpoint direction"); + return -EINVAL; + } + + if (!usbip_ctrl.out_ep_ctrl[ep_idx].data_len) { + /* TODO: continue read */ + /* usbip_prep_rx(ep_idx, 0); */ + } + + return 0; +} + +int usb_dc_ep_read(const u8_t ep, u8_t *const data, + const u32_t max_data_len, u32_t * const read_bytes) +{ + SYS_LOG_DBG("ep %x max_data_len %u", ep, max_data_len); + + if (usb_dc_ep_read_wait(ep, data, max_data_len, read_bytes) != 0) { + return -EINVAL; + } + + if (!data && !max_data_len) { + /* When both buffer and max data to read are zero the above + * call would fetch the data len and we simply return. + */ + return 0; + } + + if (usb_dc_ep_read_continue(ep) != 0) { + return -EINVAL; + } + + return 0; +} + +int usb_dc_ep_set_callback(const u8_t ep, const usb_dc_ep_callback cb) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + SYS_LOG_DBG("ep %x callback %p", ep, cb); + + if (!usbip_ctrl.attached && !usbip_ep_is_valid(ep)) { + return -EINVAL; + } + + if (USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_IN) { + usbip_ctrl.in_ep_ctrl[ep_idx].cb = cb; + } else { + usbip_ctrl.out_ep_ctrl[ep_idx].cb = cb; + } + + return 0; +} + +int usb_dc_set_status_callback(const usb_dc_status_callback cb) +{ + usbip_ctrl.status_cb = cb; + + return 0; +} + +int usb_dc_ep_mps(const u8_t ep) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ep); + + if (USBIP_EP_ADDR2DIR(ep) == USB_EP_DIR_OUT) { + return usbip_ctrl.out_ep_ctrl[ep_idx].mps; + } else { + return usbip_ctrl.in_ep_ctrl[ep_idx].mps; + } +} + +int handle_usb_control(struct usbip_header *hdr) +{ + u8_t ep_idx = USBIP_EP_ADDR2IDX(ntohl(hdr->common.ep)); + usb_dc_ep_callback ep_cb = usbip_ctrl.out_ep_ctrl[ep_idx].cb; + + SYS_LOG_DBG("ep %x idx %u", ntohl(hdr->common.ep), ep_idx); + + if (ep_cb) { + SYS_LOG_DBG("Call ep_cb"); + ep_cb(hdr->common.ep, USB_DC_EP_SETUP); + } + + return 0; +} + +int handle_usb_data(struct usbip_header *hdr) +{ + return 0; +} diff --git a/drivers/usb/device/usb_dc_native_posix_adapt.c b/drivers/usb/device/usb_dc_native_posix_adapt.c new file mode 100644 index 00000000000..655f73840a9 --- /dev/null +++ b/drivers/usb/device/usb_dc_native_posix_adapt.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define __packed __attribute__((__packed__)) + +/* System headers */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Zephyr headers */ +#include +#include +#include + +#define SYS_LOG_LEVEL CONFIG_SYS_LOG_USB_DRIVER_LEVEL +#define SYS_LOG_DOMAIN "usb/native_posix_adapt" +#include + +#include +#include "usb_dc_native_posix_adapt.h" + +#define USBIP_PORT 3240 +#define USBIP_VERSION 273 + +#define VERBOSE_DEBUG + +int connfd_global; +int seqnum_global; +int devid_global; + +/* Helpers */ + +#ifdef VERBOSE_DEBUG +static void hexdump(const u8_t *data, size_t len) +{ + int n = 0; + + while (len--) { + if (n % 16 == 0) { + printf("%08X ", n); + } + + printf("%02X ", *data++); + + n++; + if (n % 8 == 0) { + if (n % 16 == 0) { + printf("\n"); + } else { + printf(" "); + } + } + } + + if (n % 16) { + printf("\n"); + } +} + +static void usbip_header_dump(struct usbip_header *hdr) +{ + printf("USBIP header dump:\n"); + printf("\tcommand %u\n", ntohl(hdr->common.command)); + printf("\tseqnum %u\n", ntohl(hdr->common.seqnum)); + printf("\tdevid %x\n", ntohl(hdr->common.devid)); + printf("\tdirection %u\n", ntohl(hdr->common.direction)); + printf("\tep %x\n", ntohl(hdr->common.ep)); + + switch (ntohl(hdr->common.command)) { + case USBIP_CMD_SUBMIT: + printf("\tflags %x\n", ntohl(hdr->u.submit.transfer_flags)); + printf("\tnumber of packets %u\n", + ntohl(hdr->u.submit.number_of_packets)); + printf("\tinterval %u\n", ntohl(hdr->u.submit.interval)); + printf("\tbuffer length %u\n", + ntohl(hdr->u.submit.transfer_buffer_length)); + break; + case USBIP_CMD_UNLINK: + printf("\tseqnum %d\n", ntohl(hdr->u.unlink.seqnum)); + break; + default: + break; + } +} +#else +#define hexdump(x, y) +#define usbip_header_dump(x) +#endif + +void get_interface(u8_t *descriptors) +{ + while (descriptors[0]) { + if (descriptors[1] == DESC_INTERFACE) { + SYS_LOG_DBG("interface found"); + } + + /* skip to next descriptor */ + descriptors += descriptors[0]; + } +} + +static int send_interfaces(const u8_t *descriptors, int connfd) +{ + struct devlist_interface { + u8_t bInterfaceClass; + u8_t bInterfaceSubClass; + u8_t bInterfaceProtocol; + u8_t padding; /* alignment */ + } __packed iface; + + while (descriptors[0]) { + if (descriptors[1] == DESC_INTERFACE) { + struct usb_if_descriptor *desc = (void *)descriptors; + + iface.bInterfaceClass = desc->bInterfaceClass; + iface.bInterfaceSubClass = desc->bInterfaceSubClass; + iface.bInterfaceProtocol = desc->bInterfaceProtocol; + iface.padding = 0; + + if (send(connfd, &iface, sizeof(iface), 0) != + sizeof(iface)) { + SYS_LOG_ERR("send() failed: %s", + strerror(errno)); + return errno; + } + } + + /* skip to next descriptor */ + descriptors += descriptors[0]; + } + + return 0; +} + +static void fill_device(struct devlist_device *dev, const u8_t *desc) +{ + struct usb_device_descriptor *dev_dsc = (void *)desc; + struct usb_cfg_descriptor *cfg = + (void *)(desc + sizeof(struct usb_device_descriptor)); + + memset(dev->path, 0, 256); + strcpy(dev->path, "/sys/devices/pci0000:00/0000:00:01.2/usb1/1-1"); + memset(dev->busid, 0, 32); + strcpy(dev->busid, "1-1"); + + dev->busnum = htonl(1); + dev->devnum = htonl(2); + dev->speed = htonl(2); + + dev->idVendor = htons(dev_dsc->idVendor); + dev->idProduct = htons(dev_dsc->idProduct); + dev->bcdDevice = htons(dev_dsc->bcdDevice); + dev->bDeviceClass = dev_dsc->bDeviceClass; + dev->bDeviceSubClass = dev_dsc->bDeviceSubClass; + dev->bDeviceProtocol = dev_dsc->bDeviceProtocol; + + dev->bConfigurationValue = cfg->bConfigurationValue; + dev->bNumConfigurations = dev_dsc->bNumConfigurations; + dev->bNumInterfaces = cfg->bNumInterfaces; +} + +static int send_device(const u8_t *desc, int connfd) +{ + struct devlist_device dev; + + fill_device(&dev, desc); + + if (send(connfd, &dev, sizeof(dev), 0) != sizeof(dev)) { + SYS_LOG_ERR("send() device failed: %s", strerror(errno)); + return errno; + } + + return 0; +} + +static int handle_device_list(const u8_t *desc, int connfd) +{ + struct op_common header = { + .version = htons(USBIP_VERSION), + .code = htons(OP_REP_DEVLIST), + .status = 0, + }; + + SYS_LOG_DBG("desc %p", desc); + + if (send(connfd, &header, sizeof(header), 0) != sizeof(header)) { + SYS_LOG_ERR("send() header failed: %s", strerror(errno)); + return errno; + } + + /* Send number of devices */ + u32_t ndev = htonl(1); + + if (send(connfd, &ndev, sizeof(ndev), 0) != sizeof(ndev)) { + SYS_LOG_ERR("send() ndev failed: %s", strerror(errno)); + return errno; + } + + send_device(desc, connfd); + + send_interfaces(desc, connfd); + + return 0; +} + +static void handle_usbip_submit(int connfd, struct usbip_header *hdr) +{ + struct usbip_submit *req = &hdr->u.submit; + int read; + + SYS_LOG_DBG(""); + + read = recv(connfd, req, sizeof(*req), 0); + if (read != sizeof(*req)) { + SYS_LOG_ERR("recv() failed: %s", strerror(errno)); + return; + } + + usbip_header_dump((void *)hdr); + + if (ntohl(hdr->common.ep) == 0) { + handle_usb_control(hdr); + } else { + handle_usb_data(hdr); + } +} + +static void handle_usbip_unlink(int connfd, struct usbip_header *hdr) +{ + struct usbip_unlink *req = &hdr->u.unlink; + u64_t setup_padding; + int read; + + SYS_LOG_DBG(""); + + read = recv(connfd, req, sizeof(hdr->u), 0); + if (read != sizeof(hdr->u)) { + SYS_LOG_ERR("recv() failed: %s", strerror(errno)); + return; + } + + /* Read also padding */ + read = recv(connfd, &setup_padding, sizeof(setup_padding), 0); + if (read != sizeof(setup_padding)) { + SYS_LOG_ERR("recv() failed: %s", strerror(errno)); + return; + } + + usbip_header_dump((void *)hdr); + + /* TODO: unlink */ +} + +static int handle_import(const u8_t *desc, int connfd) +{ + struct op_common header = { + .version = htons(USBIP_VERSION), + .code = htons(OP_REP_IMPORT), + .status = 0, + }; + char busid[32]; + + SYS_LOG_DBG("attach device"); + + if (recv(connfd, busid, 32, 0) != sizeof(busid)) { + SYS_LOG_ERR("recv() failed: %s", strerror(errno)); + return errno; + } + + if (send(connfd, &header, sizeof(header), 0) != sizeof(header)) { + SYS_LOG_ERR("send() header failed: %s", strerror(errno)); + return errno; + } + + send_device(desc, connfd); + + return 0; +} + +extern struct usb_desc_header __usb_descriptor_start[]; + +void usbip_start(void) +{ + struct sockaddr_in srv; + unsigned char attached; + int listenfd, connfd; + const u8_t *desc; + int reuse = 1; + + SYS_LOG_DBG("Starting"); + + /* + * Do not use usb_get_device_descriptor(); + * to prevent double string fixing + */ + desc = (const u8_t *)__usb_descriptor_start; + if (!desc) { + SYS_LOG_ERR("Descriptors are not set"); + posix_exit(EXIT_FAILURE); + } + + listenfd = socket(PF_INET, SOCK_STREAM, 0); + if (listenfd < 0) { + SYS_LOG_ERR("socket() failed: %s", strerror(errno)); + posix_exit(EXIT_FAILURE); + } + + if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, + (const char *)&reuse, sizeof(reuse)) < 0) { + SYS_LOG_WRN("setsockopt() failed: %s", strerror(errno)); + } + + memset(&srv, 0, sizeof(srv)); + srv.sin_family = AF_INET; + srv.sin_addr.s_addr = htonl(INADDR_ANY); + srv.sin_port = htons(USBIP_PORT); + + if (bind(listenfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) { + SYS_LOG_ERR("bind() failed: %s", strerror(errno)); + posix_exit(EXIT_FAILURE); + } + + if (listen(listenfd, SOMAXCONN) < 0) { + SYS_LOG_ERR("listen() failed: %s", strerror(errno)); + posix_exit(EXIT_FAILURE); + } + + while (true) { + struct sockaddr_in client_addr; + socklen_t client_addr_len = sizeof(client_addr); + + connfd = accept(listenfd, (struct sockaddr *)&client_addr, + &client_addr_len); + if (connfd < 0) { + SYS_LOG_ERR("accept() failed: %s", strerror(errno)); + posix_exit(EXIT_FAILURE); + } + + connfd_global = connfd; + + SYS_LOG_DBG("Connection: %s", inet_ntoa(client_addr.sin_addr)); + + /* Set attached 0 */ + attached = 0; + + while (true) { + struct usbip_header cmd; + struct usbip_header_common *hdr = &cmd.common; + int read; + + if (!attached) { + struct op_common req; + + read = recv(connfd, &req, sizeof(req), 0); + if (read != sizeof(req)) { + SYS_LOG_WRN("small packet, %u", read); + break; + } + + hexdump((u8_t *)&req, sizeof(req)); + + SYS_LOG_DBG("Code: 0x%x", ntohs(req.code)); + + switch (ntohs(req.code)) { + case OP_REQ_DEVLIST: + handle_device_list(desc, connfd); + break; + case OP_REQ_IMPORT: + if (!handle_import(desc, connfd)) { + attached = 1; + } + break; + default: + SYS_LOG_ERR("Unhandled code: 0x%x", + ntohs(req.code)); + break; + } + + continue; + } + + /* Handle attached case */ + + read = recv(connfd, hdr, sizeof(*hdr), 0); + if (read != sizeof(*hdr)) { + SYS_LOG_ERR("recv failed: %d", read); + break; + } + + hexdump((u8_t *)hdr, sizeof(*hdr)); + + devid_global = ntohl(hdr->devid); + seqnum_global = ntohl(hdr->seqnum); + + switch (ntohl(hdr->command)) { + case USBIP_CMD_SUBMIT: + handle_usbip_submit(connfd, &cmd); + break; + case USBIP_CMD_UNLINK: + handle_usbip_unlink(connfd, &cmd); + break; + default: + SYS_LOG_ERR("Unknown command: 0x%x", + ntohl(hdr->command)); + close(connfd); + return; + } + } + + close(connfd); + } +} + +int usbip_recv(u8_t *buf, size_t len) +{ + return recv(connfd_global, buf, len, 0); +} + +int usbip_send(u8_t ep, const u8_t *data, size_t len) +{ + return send(connfd_global, data, len, 0); +} + +int usbip_send_common(u8_t ep, u32_t data_len) +{ + struct usbip_submit_rsp rsp; + + rsp.common.command = htonl(USBIP_RET_SUBMIT); + rsp.common.seqnum = htonl(seqnum_global); + rsp.common.devid = htonl(0); + rsp.common.direction = htonl(0); /* TODO get from ep */ + rsp.common.ep = htonl(ep); + + rsp.status = htonl(0); + rsp.actual_length = htonl(data_len); + rsp.start_frame = htonl(0); + rsp.number_of_packets = htonl(0); + rsp.error_count = htonl(0); + + return usbip_send(ep, (u8_t *)&rsp, sizeof(rsp)); +} diff --git a/drivers/usb/device/usb_dc_native_posix_adapt.h b/drivers/usb/device/usb_dc_native_posix_adapt.h new file mode 100644 index 00000000000..2b71f99af72 --- /dev/null +++ b/drivers/usb/device/usb_dc_native_posix_adapt.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +struct op_common { + u16_t version; + u16_t code; + u32_t status; +} __packed; + +struct devlist_device { + char path[256]; + char busid[32]; + + u32_t busnum; + u32_t devnum; + u32_t speed; + + u16_t idVendor; + u16_t idProduct; + u16_t bcdDevice; + + u8_t bDeviceClass; + u8_t bDeviceSubClass; + u8_t bDeviceProtocol; + u8_t bConfigurationValue; + u8_t bNumConfigurations; + u8_t bNumInterfaces; +} __packed; + +#define OP_REQUEST (0x80 << 8) +#define OP_REPLY (0x00 << 8) + +/* Devlist */ +#define OP_DEVLIST 0x05 +#define OP_REQ_DEVLIST (OP_REQUEST | OP_DEVLIST) +#define OP_REP_DEVLIST (OP_REPLY | OP_DEVLIST) + +/* Import USB device */ +#define OP_IMPORT 0x03 +#define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT) +#define OP_REP_IMPORT (OP_REPLY | OP_IMPORT) + +/* USBIP requests */ +#define USBIP_CMD_SUBMIT 0x0001 +#define USBIP_CMD_UNLINK 0x0002 +#define USBIP_RET_SUBMIT 0x0003 +#define USBIP_RET_UNLINK 0x0004 + +struct usbip_header_common { + u32_t command; + u32_t seqnum; + u32_t devid; + u32_t direction; + u32_t ep; +} __packed; + +struct usbip_submit { + u32_t transfer_flags; + s32_t transfer_buffer_length; + s32_t start_frame; + s32_t number_of_packets; + s32_t interval; +} __packed; + +struct usbip_unlink { + u32_t seqnum; +} __packed; + +struct usbip_submit_rsp { + struct usbip_header_common common; + + s32_t status; + s32_t actual_length; + s32_t start_frame; + s32_t number_of_packets; + s32_t error_count; +} __packed; + +struct usbip_header { + struct usbip_header_common common; + + union { + struct usbip_submit submit; + struct usbip_unlink unlink; + } u; +} __packed; + +/* Function definitions */ + +int usbip_recv(u8_t *buf, size_t len); +int usbip_send_common(u8_t ep, u32_t data_len); +int usbip_send(u8_t ep, const u8_t *data, size_t len); + +void usbip_start(void); + +int handle_usb_control(struct usbip_header *hdr); +int handle_usb_data(struct usbip_header *hdr);