diff --git a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/port/xhci/usb_hc_xhci.c b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/port/xhci/usb_hc_xhci.c index 4e5d109c7..85813ae0f 100644 --- a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/port/xhci/usb_hc_xhci.c +++ b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/port/xhci/usb_hc_xhci.c @@ -544,7 +544,30 @@ void USBH_IRQHandler(void *param) * Functions for xHCI drivers. These functions are called by USB core. */ int xhci_usb_hc_init(uint32_t id){ - return 0; + USB_ASSERT(id < CONFIG_USBHOST_XHCI_NUM); + int rc = 0; + struct usbh_bus *bus = usbh_get_bus_of_index(id); + USB_ASSERT(bus); + struct xhci_host *xhci = &(xhci_host[id]); + + size_t flag = usb_osal_enter_critical_section(); /* no interrupt when init hc */ + + usb_hc_low_level_init(id); /* set gic and memp */ + + memset(xhci, 0, sizeof(*xhci)); + xhci->bus = bus; + bus->priv = xhci; + if (rc = xhci_probe(xhci, usb_hc_get_register_base(id)) != 0) { + goto err_open; + } + + if (rc = xhci_open(xhci) != 0 ) { + goto err_open; + } + + err_open: + usb_osal_leave_critical_section(flag); + return rc; } @@ -555,6 +578,200 @@ uint16_t xhci_usbh_get_frame_number(void){ int xhci_usbh_roothub_control(struct usbh_bus *usb, struct usb_setup_packet *setup, uint8_t *buf){ + uint8_t nports; + uint8_t port; + uint32_t portsc; + uint32_t status; + int ret = 0; + struct xhci_host *xhci = usb->priv; + nports = CONFIG_USBHOST_MAX_RHPORTS; + + port = setup->wIndex; + + /* + bmRequestType bit[4:0], define whether the request is directed to the device (0000b), + specific interface (00001b), endpoint (00010b), or other element (00011b) + bRequest, identifies the request + wValue, pass the request-specific info to the device + */ + if (setup->bmRequestType & USB_REQUEST_RECIPIENT_DEVICE) /* request is directed to device */ + { + switch (setup->bRequest) + { + case HUB_REQUEST_CLEAR_FEATURE: /* disable the feature */ + switch (setup->wValue) + { + case HUB_FEATURE_HUB_C_LOCALPOWER: + USB_LOG_ERR("HUB_FEATURE_HUB_C_LOCALPOWER not implmented.\n"); + break; + case HUB_FEATURE_HUB_C_OVERCURRENT: + USB_LOG_ERR("HUB_FEATURE_HUB_C_OVERCURRENT not implmented.\n"); + break; + default: + return -EPIPE; + } + break; + case HUB_REQUEST_SET_FEATURE: /* set a value reported in the hub status */ + switch (setup->wValue) + { + case HUB_FEATURE_HUB_C_LOCALPOWER: + USB_LOG_ERR("HUB_FEATURE_HUB_C_LOCALPOWER not implmented.\n"); + break; + case HUB_FEATURE_HUB_C_OVERCURRENT: + USB_LOG_ERR("HUB_FEATURE_HUB_C_OVERCURRENT not implmented.\n"); + break; + default: + return -EPIPE; + } + break; + case HUB_REQUEST_GET_DESCRIPTOR: + USB_LOG_ERR("HUB_REQUEST_GET_DESCRIPTOR not implmented.\n"); + break; + case HUB_REQUEST_GET_STATUS: + USB_ASSERT(buf); + memset(buf, 0, 4); + break; + default: + break; + } + } + else if (setup->bmRequestType & USB_REQUEST_RECIPIENT_OTHER) + { + switch (setup->bRequest) + { + case HUB_REQUEST_CLEAR_FEATURE: + if (!port || port > nports) + { + return -EPIPE; + } + + portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); + switch (setup->wValue) + { + case HUB_PORT_FEATURE_ENABLE: + break; + case HUB_PORT_FEATURE_SUSPEND: + case HUB_PORT_FEATURE_C_SUSPEND: + break; + case HUB_PORT_FEATURE_POWER: + break; + case HUB_PORT_FEATURE_C_CONNECTION: + portsc |= XHCI_PORTSC_CSC; + break; + case HUB_PORT_FEATURE_C_ENABLE: + portsc |= XHCI_PORTSC_PEC; + break; + case HUB_PORT_FEATURE_C_OVER_CURREN: + break; + case HUB_PORT_FEATURE_C_RESET: + break; + default: + return -EPIPE; + } + + uint32_t pclear = portsc & XHCI_PORTSC_RW_MASK; + /* clear port status */ + writel(pclear, xhci->op + XHCI_OP_PORTSC ( port )); + + break; + case HUB_REQUEST_SET_FEATURE: + if (!port || port > nports) + { + return -EPIPE; + } + + switch (setup->wValue) + { + case HUB_PORT_FEATURE_SUSPEND: + break; + case HUB_PORT_FEATURE_POWER: + break; + case HUB_PORT_FEATURE_RESET: + ret = xhci_port_enable(xhci, port); + break; + default: + return -EPIPE; + } + break; + case HUB_REQUEST_GET_STATUS: + if (!port || port > nports) + { + return -EPIPE; + } + + portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) ); + status = 0; + + if (portsc & XHCI_PORTSC_CSC) + { + /* Port connection status changed */ + status |= (1 << HUB_PORT_FEATURE_C_CONNECTION); + + /* always clear all the status change bits */ + uint32_t temp = portsc & ( XHCI_PORTSC_PRESERVE | XHCI_PORTSC_CHANGE ); + writel ( temp, xhci->op + XHCI_OP_PORTSC ( port ) ); + } + + if (portsc & XHCI_PORTSC_PEC) + { + /* Port enabled status changed */ + status |= (1 << HUB_PORT_FEATURE_C_ENABLE); + } + + if (portsc & XHCI_PORTSC_OCC) + { + /* Port status changed due to over-current */ + status |= (1 << HUB_PORT_FEATURE_C_OVER_CURREN); + } + + if (portsc & XHCI_PORTSC_CCS) + { + /* Port connected */ + status |= (1 << HUB_PORT_FEATURE_CONNECTION); + } + + if (portsc & XHCI_PORTSC_PED) + { + /* Port enabled */ + status |= (1 << HUB_PORT_FEATURE_ENABLE); + + const unsigned int speed = xhci_root_speed(xhci, port); + USB_LOG_DBG("Port-%d speed = %d \r\n", port, speed); + if (speed == USB_SPEED_LOW) + { + status |= (1 << HUB_PORT_FEATURE_LOWSPEED); + } + else if (speed == USB_SPEED_HIGH) + { + status |= (1 << HUB_PORT_FEATURE_HIGHSPEED); + } + /* else is full-speed */ + } + + if (portsc & XHCI_PORTSC_OCA) + { + /* Over-current condition */ + status |= (1 << HUB_PORT_FEATURE_OVERCURRENT); + } + + if (portsc & XHCI_PORTSC_PR) + { + /* Reset is in progress */ + status |= (1 << HUB_PORT_FEATURE_RESET); + } + + if (portsc & XHCI_PORTSC_PP) + { + /* Port is not power off */ + status |= (1 << HUB_PORT_FEATURE_POWER); + } + memcpy(buf, &status, 4); + break; + default: + break; + } + } + return 0; }