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:
parent
6ed355110a
commit
b8b86c4c75
5 changed files with 1045 additions and 0 deletions
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
480
drivers/usb/device/usb_dc_native_posix.c
Normal file
480
drivers/usb/device/usb_dc_native_posix.c
Normal 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;
|
||||
}
|
455
drivers/usb/device/usb_dc_native_posix_adapt.c
Normal file
455
drivers/usb/device/usb_dc_native_posix_adapt.c
Normal 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));
|
||||
}
|
100
drivers/usb/device/usb_dc_native_posix_adapt.h
Normal file
100
drivers/usb/device/usb_dc_native_posix_adapt.h
Normal 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);
|
Loading…
Add table
Add a link
Reference in a new issue