Skip to content

Commit 612037e

Browse files
YangLiang3lijinxia
authored andcommitted
DM USB: xHCI: enable Flat Mode Hub emulation support.
Flat Mode for hub emulation means DM emulates USB devices under hub but hide hub itself. Under this design the Guest OS cannot see any emulated hub. So in the perspective of Guest OS, all the emulated devices are under root hub. This patch is used to enable feature as mentioned above. And please NOTE, it is the initial version of hub flat Mode hub emulation, there are one limitation: only one physical hub is supported. If second physical hub is connected, the connect and disconnect behavior in second hub may affect the function of first emulated hub. The USB HUB device model should be the final long term solution, but it is very complex. Use flat mode HUB emulation as the short term solution first to support some USB touch devices which integrated internal HUB. Signed-off-by: Liang Yang <liang3.yang@intel.com> Reviewed-by: Xiaoguang Wu <xiaoguang.wu@intel.com> Acked-by: Yu Wang <yu1.wang@intel.com> Tracked-On: #1243
1 parent d886375 commit 612037e

File tree

3 files changed

+139
-7
lines changed

3 files changed

+139
-7
lines changed

devicemodel/hw/pci/xhci.c

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595

9696
#undef LOG_TAG
9797
#define LOG_TAG "xHCI: "
98-
#define XHCI_MAX_DEVS 8 /* 4 USB3 + 4 USB2 devs */
98+
#define XHCI_MAX_DEVS 20 /* 10 root hub + 10 external hub */
9999
#define XHCI_MAX_SLOTS 64 /* min allowed by Windows drivers */
100100

101101
/*
@@ -394,6 +394,7 @@ struct pci_xhci_vdev {
394394
#define VPORT_ASSIGNED (1)
395395
#define VPORT_CONNECTED (2)
396396
#define VPORT_EMULATED (3)
397+
#define VPORT_HUB_CONNECTED (4)
397398

398399
/* helpers for get port mapping information */
399400
#define VPORT_NUM(state) (state & 0xFF)
@@ -479,6 +480,27 @@ static struct pci_xhci_option_elem xhci_option_table[] = {
479480
{"cap", pci_xhci_parse_extcap}
480481
};
481482

483+
static enum usb_native_dev_type
484+
pci_xhci_get_dev_type(struct pci_xhci_vdev *xdev, void *dev_data)
485+
{
486+
uint16_t port, bus;
487+
struct usb_native_devinfo *di;
488+
489+
assert(dev_data);
490+
491+
di = dev_data;
492+
if (usb_get_parent_dev_type(di->priv_data, &bus, &port) == USB_HUB) {
493+
if (VPORT_STATE(xdev->port_map_tbl[bus][port]) ==
494+
VPORT_HUB_CONNECTED) {
495+
di->port += PORT_HUB_BASE;
496+
return USB_VALID_SUB_DEV;
497+
} else
498+
return USB_INVALID_SUB_DEV;
499+
}
500+
501+
return USB_DEV;
502+
}
503+
482504
static int
483505
pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
484506
{
@@ -487,6 +509,9 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
487509
int vport_start, vport_end;
488510
int port;
489511
int need_intr = 1;
512+
enum usb_native_dev_type type;
513+
int state;
514+
int rc;
490515

491516
xdev = hci_data;
492517

@@ -501,12 +526,37 @@ pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
501526
UPRINTF(LDBG, "%04x:%04x %d-%d connecting.\r\n",
502527
di->vid, di->pid, di->bus, di->port);
503528

504-
if (VPORT_STATE(xdev->port_map_tbl[di->bus][di->port]) ==
505-
VPORT_FREE) {
506-
UPRINTF(LDBG, "%04x:%04x %d-%d doesn't belong to this vm, bye."
507-
"\r\n", di->vid, di->pid, di->bus, di->port);
529+
type = pci_xhci_get_dev_type(xdev, di);
530+
if (type == USB_DEV) {
531+
if (VPORT_STATE(xdev->port_map_tbl[di->bus][di->port]) ==
532+
VPORT_FREE) {
533+
UPRINTF(LDBG, "%04x:%04x %d-%d doesn't belong to this"
534+
" vm, bye.\r\n", di->vid, di->pid,
535+
di->bus, di->port);
536+
goto errout;
537+
}
538+
} else if (type == USB_INVALID_SUB_DEV)
539+
return 0;
540+
541+
state = VPORT_STATE(xdev->port_map_tbl[di->bus][di->port]);
542+
if (state == VPORT_CONNECTED || state == VPORT_EMULATED ||
543+
state == VPORT_HUB_CONNECTED) {
544+
UPRINTF(LFTL, "do not support multiple hubs currently, reject "
545+
"device %d-%d\r\n", di->bus, di->port);
546+
goto errout;
547+
}
548+
549+
rc = usb_dev_is_hub(di->priv_data);
550+
if (rc == USB_HUB) {
551+
xdev->port_map_tbl[di->bus][di->port] =
552+
VPORT_NUM_STATE(VPORT_HUB_CONNECTED, 0);
553+
return 0;
554+
} else if (rc == USB_TYPE_INVALID) {
555+
UPRINTF(LWRN, "usb_dev_is_hub failed\r\n");
508556
goto errout;
509557
}
558+
559+
510560
UPRINTF(LDBG, "%04x:%04x %d-%d belong to this vm.\r\n", di->vid,
511561
di->pid, di->bus, di->port);
512562

@@ -593,8 +643,6 @@ pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
593643
if (xdev->slots[slot] == edev)
594644
break;
595645

596-
assert(slot < XHCI_MAX_SLOTS);
597-
598646
status = VPORT_STATE(xdev->port_map_tbl[di.bus][di.port]);
599647
assert(status == VPORT_EMULATED || status == VPORT_CONNECTED);
600648
xdev->port_map_tbl[di.bus][di.port] = VPORT_NUM_STATE(VPORT_ASSIGNED,

devicemodel/hw/platform/usb_pmapper.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,65 @@ usb_dev_request(void *pdata, struct usb_data_xfer *xfer)
855855
return xfer->status;
856856
}
857857

858+
int
859+
usb_dev_is_hub(void *pdata)
860+
{
861+
struct libusb_device *ldev;
862+
struct libusb_device_descriptor desc;
863+
int rc;
864+
865+
assert(pdata);
866+
867+
ldev = pdata;
868+
rc = libusb_get_device_descriptor(ldev, &desc);
869+
870+
if (rc)
871+
return USB_TYPE_INVALID;
872+
873+
if (desc.bDeviceClass == LIBUSB_CLASS_HUB)
874+
return USB_HUB;
875+
else
876+
return USB_DEV;
877+
878+
}
879+
880+
enum usb_native_dev_type
881+
usb_get_parent_dev_type(void *pdata, uint16_t *bus, uint16_t *port)
882+
{
883+
struct libusb_device *ldev;
884+
struct libusb_device *libdev;
885+
struct libusb_device_descriptor desc;
886+
int rc;
887+
888+
assert(pdata);
889+
assert(bus);
890+
assert(port);
891+
892+
ldev = pdata;
893+
libdev = libusb_get_parent(ldev);
894+
895+
if (libdev == NULL) {
896+
UPRINTF(LWRN, "libusb_get_parent return NULL\r\n");
897+
return USB_TYPE_INVALID;
898+
}
899+
900+
*bus = libusb_get_bus_number(libdev);
901+
*port = libusb_get_port_number(libdev);
902+
903+
rc = libusb_get_device_descriptor(libdev, &desc);
904+
if (rc) {
905+
UPRINTF(LWRN, "libusb_get_device_descriptor error %d\r\n", rc);
906+
return USB_TYPE_INVALID;
907+
}
908+
909+
if (*port == 0)
910+
return ROOT_HUB;
911+
if (desc.bDeviceClass == LIBUSB_CLASS_HUB)
912+
return USB_HUB;
913+
914+
return USB_TYPE_INVALID;
915+
}
916+
858917
void *
859918
usb_dev_init(void *pdata, char *opt)
860919
{
@@ -1039,6 +1098,9 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
10391098
*ldev, libusb_hotplug_event event, void *pdata)
10401099
{
10411100
uint8_t port;
1101+
uint16_t pport;
1102+
uint16_t pbus;
1103+
int rc;
10421104

10431105
UPRINTF(LDBG, "disconnect event\r\n");
10441106

@@ -1048,6 +1110,13 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
10481110
}
10491111

10501112
port = libusb_get_port_number(ldev);
1113+
rc = usb_get_parent_dev_type(ldev, &pbus, &pport);
1114+
if (rc == USB_TYPE_INVALID) {
1115+
UPRINTF(LWRN, "usb_get_parent_dev_type return %d\r\n", rc);
1116+
return 0;
1117+
} else if (rc == USB_HUB)
1118+
port += PORT_HUB_BASE;
1119+
10511120
if (g_ctx.disconn_cb)
10521121
g_ctx.disconn_cb(g_ctx.hci_data, &port);
10531122

devicemodel/include/usb_pmapper.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#define USB_EP_NR(d) (USB_EP_ADDR(d) & 0xF)
2121
#define USB_EP_ERR_TYPE 0xFF
2222

23+
/* hub port start address */
24+
#define PORT_HUB_BASE 0x0A
25+
2326
enum {
2427
USB_INFO_VERSION,
2528
USB_INFO_SPEED,
@@ -29,6 +32,15 @@ enum {
2932
USB_INFO_PID
3033
};
3134

35+
enum usb_native_dev_type {
36+
ROOT_HUB,
37+
USB_HUB,
38+
USB_DEV,
39+
USB_VALID_SUB_DEV,
40+
USB_INVALID_SUB_DEV,
41+
USB_TYPE_INVALID
42+
};
43+
3244
struct usb_dev_ep {
3345
uint8_t pid;
3446
uint8_t type;
@@ -119,4 +131,7 @@ int usb_dev_info(void *pdata, int type, void *value, int size);
119131
int usb_dev_request(void *pdata, struct usb_data_xfer *xfer);
120132
int usb_dev_reset(void *pdata);
121133
int usb_dev_data(void *pdata, struct usb_data_xfer *xfer, int dir, int epctx);
134+
enum usb_native_dev_type usb_get_parent_dev_type(void *pdata, uint16_t *bus,
135+
uint16_t *port);
136+
int usb_dev_is_hub(void *pdata);
122137
#endif

0 commit comments

Comments
 (0)