usb: driver: Add native_posix USB driver

Add native_posix USB virtual driver connected over USBIP to the Host
Linux.

Fixes: #9846

Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This commit is contained in:
Andrei Emeltchenko 2018-09-10 16:07:31 +03:00 committed by Anas Nashif
commit b8b86c4c75
5 changed files with 1045 additions and 0 deletions

View file

@ -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_DC_SAM usb_dc_sam.c)
zephyr_sources_ifdef(CONFIG_USB_NRF52840 usb_dc_nrfx.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_KINETIS usb_dc_kinetis.c)
zephyr_sources_ifdef(CONFIG_USB_NATIVE_POSIX
usb_dc_native_posix.c
usb_dc_native_posix_adapt.c
)

View file

@ -91,4 +91,10 @@ config USB_DC_STM32_DISCONN_ENABLE
Say Y if your board uses USB DISCONNECT pin to enable the Say Y if your board uses USB DISCONNECT pin to enable the
pull-up resistor on USB DP. 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 endif # USB

View file

@ -0,0 +1,480 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief USB native_posix device driver
*/
#include <string.h>
#include <stdio.h>
#include <misc/byteorder.h>
#include <usb/usb_dc.h>
#include <usb/usb_device.h>
#include <net/net_ip.h>
#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 <logging/sys_log.h>
/* 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;
}

View file

@ -0,0 +1,455 @@
/*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#define __packed __attribute__((__packed__))
/* System headers */
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* Zephyr headers */
#include <kernel.h>
#include <usb/usb_common.h>
#include <usb/usbstruct.h>
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_USB_DRIVER_LEVEL
#define SYS_LOG_DOMAIN "usb/native_posix_adapt"
#include <logging/sys_log.h>
#include <posix_board_if.h>
#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));
}

View file

@ -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);