DM USB: xHCI: support USB hot plug out.

Implements the disconnect callback of libusb which will be called once
USB device plug out.

Change-Id: Ic5f072f08a92270e6e5836b49e5066da783af243
Signed-off-by: Wu, Xiaoguang <xiaoguang.wu@intel.com>
Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
Reviewed-by: Yu Wang <yu1.wang@intel.com>
Reviewed-by: Zhao Yakui <yakui.zhao@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Wu, Xiaoguang 2018-04-10 19:04:52 +08:00 committed by lijinxia
parent 7687a3d0d7
commit 0181d19a61
2 changed files with 62 additions and 1 deletions

View File

@ -325,6 +325,7 @@ static void pci_xhci_set_evtrb(struct xhci_trb *evtrb, uint64_t port,
static int pci_xhci_xfer_complete(struct pci_xhci_vdev *xdev,
struct usb_data_xfer *xfer, uint32_t slot, uint32_t epid,
int *do_intr);
static inline int pci_xhci_is_valid_portnum(int n);
static int
pci_xhci_native_usb_dev_conn_cb(void *hci_data, void *dev_data)
@ -417,6 +418,49 @@ errout:
static int
pci_xhci_native_usb_dev_disconn_cb(void *hci_data, void *dev_data)
{
struct pci_xhci_vdev *xdev;
struct pci_xhci_dev_emu *edev;
struct usb_dev *udev;
uint8_t port, native_port;
assert(hci_data);
assert(dev_data);
xdev = hci_data;
assert(xdev->devices);
native_port = *((uint8_t *)dev_data);
if (!pci_xhci_is_valid_portnum(native_port)) {
UPRINTF(LFTL, "invalid physical port %d\r\n", native_port);
return -1;
}
for (port = 1; port < XHCI_MAX_DEVS; ++port) {
edev = xdev->devices[port];
if (!edev)
continue;
udev = edev->dev_instance;
if (udev->port == native_port)
break;
}
if (port == XHCI_MAX_DEVS) {
UPRINTF(LFTL, "fail to find physical port %d\r\n", native_port);
return -1;
}
UPRINTF(LDBG, "report virtual port %d status\r\n", port);
if (pci_xhci_port_chg(xdev, port, 0)) {
UPRINTF(LFTL, "fail to report event\r\n");
return -1;
}
/*
* At this point, the resources allocated for virtual device
* should not be released, it should be released in the
* pci_xhci_cmd_disable_slot function.
*/
return 0;
}
@ -1110,6 +1154,7 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
{
struct pci_xhci_dev_emu *dev;
uint32_t cmderr;
int i;
UPRINTF(LDBG, "pci_xhci disable slot %u\r\n", slot);
@ -1133,6 +1178,19 @@ pci_xhci_cmd_disable_slot(struct pci_xhci_vdev *xdev, uint32_t slot)
}
}
for (i = 0; i < XHCI_MAX_DEVS; ++i)
if (dev == xdev->devices[i])
break;
if (i < XHCI_MAX_DEVS && XHCI_PORTREG_PTR(xdev, i)) {
XHCI_PORTREG_PTR(xdev, i)->portsc &= ~(XHCI_PS_CSC |
XHCI_PS_CCS | XHCI_PS_PED | XHCI_PS_PP);
xdev->devices[i] = NULL;
xdev->slots[slot] = NULL;
pci_xhci_dev_destroy(dev);
} else
UPRINTF(LWRN, "invalid slot %d\r\n", slot);
done:
return cmderr;
}

View File

@ -864,6 +864,8 @@ static int
usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
*ldev, libusb_hotplug_event event, void *pdata)
{
uint8_t port;
UPRINTF(LDBG, "disconnect event\r\n");
if (!ctx || !ldev) {
@ -871,8 +873,9 @@ usb_dev_native_sys_disconn_cb(struct libusb_context *ctx, struct libusb_device
return -1;
}
port = libusb_get_port_number(ldev);
if (g_ctx.disconn_cb)
g_ctx.disconn_cb(g_ctx.hci_data, NULL);
g_ctx.disconn_cb(g_ctx.hci_data, &port);
return 0;
}