diff --git a/devicemodel/Makefile b/devicemodel/Makefile index 3461936f9..9fe3a6b30 100644 --- a/devicemodel/Makefile +++ b/devicemodel/Makefile @@ -57,6 +57,7 @@ SRCS += hw/uart_core.c SRCS += hw/pci/virtio/virtio.c SRCS += hw/pci/virtio/virtio_kernel.c SRCS += hw/platform/usb_mouse.c +SRCS += hw/platform/usb_pmapper.c SRCS += hw/platform/atkbdc.c SRCS += hw/platform/ps2mouse.c SRCS += hw/platform/rtc.c diff --git a/devicemodel/hw/pci/xhci.c b/devicemodel/hw/pci/xhci.c index 8a8badfde..ce2d7a5b0 100644 --- a/devicemodel/hw/pci/xhci.c +++ b/devicemodel/hw/pci/xhci.c @@ -48,6 +48,7 @@ #include "pci_core.h" #include "xhci.h" #include "usb_core.h" +#include "usb_pmapper.h" #undef LOG_TAG #define LOG_TAG "xHCI: " @@ -315,6 +316,18 @@ static void pci_xhci_update_ep_ring(struct pci_xhci_vdev *xdev, uint32_t streamid, uint64_t ringaddr, int ccs); +static int +pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data) +{ + return 0; +} + +static int +pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data) +{ + return 0; +} + static void pci_xhci_set_evtrb(struct xhci_trb *evtrb, uint64_t port, uint32_t errcode, uint32_t evtype) @@ -2842,6 +2855,19 @@ pci_xhci_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) else error = 0; + /* + * TODO: + * Will add command line option in subsequent patches for calling + * usb_dev_sys_init if new parameters are used. + */ + if (xdev->ndevices == 0) + if (usb_dev_sys_init(pci_xhci_native_usb_dev_conn_cb, + pci_xhci_native_usb_dev_disconn_cb, + NULL, NULL, xdev, + usb_get_log_level()) < 0) { + goto done; + } + xdev->caplength = XHCI_SET_CAPLEN(XHCI_CAPLEN) | XHCI_SET_HCIVERSION(0x0100); xdev->hcsparams1 = XHCI_SET_HCSP1_MAXPORTS(XHCI_MAX_DEVS) | diff --git a/devicemodel/hw/platform/usb_pmapper.c b/devicemodel/hw/platform/usb_pmapper.c new file mode 100644 index 000000000..94c5a2ef1 --- /dev/null +++ b/devicemodel/hw/platform/usb_pmapper.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +#include +#include +#include +#include +#include "usb.h" +#include "usbdi.h" +#include "usb_core.h" +#include "usb_pmapper.h" + +#undef LOG_TAG +#define LOG_TAG "USBPM: " + +static struct usb_dev_sys_ctx_info g_ctx; + +static void * +usb_dev_sys_thread(void *arg) +{ + struct timeval t = {1, 0}; + + while (g_ctx.thread_exit == 0 && + libusb_handle_events_timeout(g_ctx.libusb_ctx, &t) >= 0) + ; /* nothing */ + + UPRINTF(LINF, "poll thread exit\n\r"); + return NULL; +} + +static int +usb_dev_native_sys_conn_cb(struct libusb_context *ctx, struct libusb_device + *ldev, libusb_hotplug_event event, void *pdata) +{ + UPRINTF(LDBG, "connect event\r\n"); + + if (!ctx || !ldev) { + UPRINTF(LFTL, "connect callback fails!\n"); + return -1; + } + + if (g_ctx.conn_cb) + g_ctx.conn_cb(g_ctx.hci_data, ldev); + + return 0; +} + +static int +usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device + *ldev, libusb_hotplug_event event, void *pdata) +{ + UPRINTF(LDBG, "disconnect event\r\n"); + + if (!ctx || !ldev) { + UPRINTF(LFTL, "disconnect callback fails!\n"); + return -1; + } + + if (g_ctx.disconn_cb) + g_ctx.disconn_cb(g_ctx.hci_data, NULL); + + return 0; +} + +int +usb_dev_sys_init(usb_dev_sys_cb conn_cb, usb_dev_sys_cb disconn_cb, + usb_dev_sys_cb notify_cb, usb_dev_sys_cb intr_cb, + void *hci_data, int log_level) +{ + libusb_hotplug_event native_conn_evt; + libusb_hotplug_event native_disconn_evt; + libusb_hotplug_flag flags; + libusb_hotplug_callback_handle native_conn_handle; + libusb_hotplug_callback_handle native_disconn_handle; + int native_pid, native_vid, native_cls, rc; + + assert(conn_cb); + assert(disconn_cb); + usb_set_log_level(log_level); + + if (g_ctx.libusb_ctx) { + UPRINTF(LFTL, "port mapper is already initialized.\r\n"); + return -1; + } + + rc = libusb_init(&g_ctx.libusb_ctx); + if (rc < 0) { + UPRINTF(LFTL, "libusb_init fails, rc:%d\r\n", rc); + return -1; + } + + g_ctx.hci_data = hci_data; + g_ctx.conn_cb = conn_cb; + g_ctx.disconn_cb = disconn_cb; + native_conn_evt = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED; + native_disconn_evt = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT; + native_pid = LIBUSB_HOTPLUG_MATCH_ANY; + native_vid = LIBUSB_HOTPLUG_MATCH_ANY; + native_cls = LIBUSB_HOTPLUG_MATCH_ANY; + flags = 0; + + /* register connect callback */ + rc = libusb_hotplug_register_callback(g_ctx.libusb_ctx, native_conn_evt, + flags, native_vid, native_pid, native_cls, + usb_dev_native_sys_conn_cb, NULL, &native_conn_handle); + if (rc != LIBUSB_SUCCESS) + goto errout; + + /* register disconnect callback */ + rc = libusb_hotplug_register_callback(g_ctx.libusb_ctx, + native_disconn_evt, flags, native_vid, native_pid, + native_cls, usb_dev_native_sys_disconn_cb, NULL, + &native_disconn_handle); + if (rc != LIBUSB_SUCCESS) { + libusb_hotplug_deregister_callback(g_ctx.libusb_ctx, + native_conn_handle); + goto errout; + } + + if (pthread_create(&g_ctx.thread, NULL, usb_dev_sys_thread, NULL)) { + libusb_hotplug_deregister_callback(g_ctx.libusb_ctx, + native_conn_handle); + libusb_hotplug_deregister_callback(g_ctx.libusb_ctx, + native_disconn_handle); + goto errout; + } + return 0; + +errout: + if (g_ctx.libusb_ctx) + libusb_exit(g_ctx.libusb_ctx); + + g_ctx.libusb_ctx = NULL; + return -1; +} diff --git a/devicemodel/hw/usb_core.c b/devicemodel/hw/usb_core.c index 8e0eab41a..906ab8cf0 100644 --- a/devicemodel/hw/usb_core.c +++ b/devicemodel/hw/usb_core.c @@ -24,6 +24,57 @@ * SUCH DAMAGE. */ +/* + * USB emulation designed as following diagram. It devided into three layers: + * HCD: USB host controller device layer, like xHCI, eHCI... + * USB core: middle abstraction layer for USB statck. + * USB Port Mapper: This layer supports to share physical USB + * devices(physical ports) to spcified virtual USB port of + * HCD DM. All the commands and data transfers are through + * Libusb to access native USB stack. + * + * +---------------+ + * | | + * +----------+----------+ | + * | ACRN DM | | + * | +-----------------+ | | + * | | HCD (xHCI) | | | + * | +-----------------+ | | + * | | | | + * | +-----------------+ | | + * | | USB Core | | | + * | +-----------------+ | | + * | | | | + * | +-----------------+ | | + * | | USB Port Mapper | | | + * | +-----------------+ | | + * | | | | + * | +-----------------+ | | + * | | Libusb | | | + * | +-----------------+ | | + * +---------------------+ | + * Service OS User Space | User OS User Space + * | + * -------------------------- | --------------------------- + * | + * Service OS Kernel Space | User OS Kernel Space + * | + * | +-----------------+ + * | | USB Core | + * | +-----------------+ + * | | + * | +-----------------+ + * | | HCD | + * | | (xHCI/uHCI/...) | + * | +--------+--------+ + * | | + * +-------------+ + * Current distribution: + * HCD: xhci.{h,c} + * USB core: usb_core.{h,c} + * USB device: usb_mouse.c usb_pmapper.{h,c} + */ + #include #include #include diff --git a/devicemodel/include/usb_core.h b/devicemodel/include/usb_core.h index 3e38153c9..5758c825e 100644 --- a/devicemodel/include/usb_core.h +++ b/devicemodel/include/usb_core.h @@ -62,7 +62,7 @@ struct usb_devemu { #define USB_EMUL_SET(x) DATA_SET(usb_emu_set, x) /* - * USB device events to notify HCI when state changes + * USB device events to notify HCD when state changes */ enum hci_usbev { USBDEV_ATTACH, diff --git a/devicemodel/include/usb_pmapper.h b/devicemodel/include/usb_pmapper.h new file mode 100644 index 000000000..b2853d4f4 --- /dev/null +++ b/devicemodel/include/usb_pmapper.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _USB_DEVICE_H +#define _USB_DEVICE_H +#include + +#define USB_NUM_INTERFACE 16 +#define USB_NUM_ENDPOINT 15 + +struct usb_dev_ep { + uint8_t pid; + uint8_t type; +}; + +struct usb_dev { + /* physical device info */ + int addr; + int version; + int speed; + int configuration; + uint8_t port; + + /* interface info */ + int if_num; + int alts[USB_NUM_INTERFACE]; + + /* endpoints info */ + struct usb_dev_ep epc; + struct usb_dev_ep epi[USB_NUM_ENDPOINT]; + struct usb_dev_ep epo[USB_NUM_ENDPOINT]; + + /* libusb data */ + libusb_device *ldev; + libusb_device_handle *handle; +}; + +/* callback type used by code from HCD layer */ +typedef int (*usb_dev_sys_cb)(void *hci_data, void *dev_data); + +struct usb_dev_sys_ctx_info { + /* + * Libusb related global variables + */ + libusb_context *libusb_ctx; + pthread_t thread; + int thread_exit; + + /* + * The following callback funtions will be registered by + * the code from HCD(eg: XHCI, EHCI...) emulation layer. + */ + usb_dev_sys_cb conn_cb; + usb_dev_sys_cb disconn_cb; + + /* + * private data from HCD layer + */ + void *hci_data; +}; + +/* intialize the usb_dev subsystem and register callbacks for HCD layer */ +int usb_dev_sys_init(usb_dev_sys_cb conn_cb, usb_dev_sys_cb disconn_cb, + usb_dev_sys_cb notify_cb, usb_dev_sys_cb intr_cb, + void *hci_data, int log_level); + +#endif