Modify xhci functions for USB core

This commit is contained in:
xj 2024-06-18 23:10:46 -07:00
parent 9f3edeb6b4
commit 83a4b774b5
1 changed files with 218 additions and 1 deletions

View File

@ -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;
}