Fix EHCI and XHCI drivers to handle USB1 hubs (issue #156)

This commit is contained in:
Martin Whitaker 2022-09-08 18:09:43 +01:00
parent 18f12116c0
commit f265d1f1c5
6 changed files with 48 additions and 19 deletions

View File

@ -405,10 +405,9 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
usb_speed_t device_speed, int device_id, usb_ep_t *ep0)
{
// Store the extra information needed by build_ehci_qhd().
ep0->driver_data = port_num << 8;
if (hub->level > 0) {
ep0->driver_data |= hub->ep0->device_id;
}
usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed);
ep0->driver_data = hs_parent.port_num << 8 | hs_parent.device_id;
if (!assign_usb_address(hcd, hub, port_num, device_speed, device_id, ep0)) {
return false;
}
@ -558,9 +557,8 @@ bool ehci_init(int bus, int dev, int func, uintptr_t base_addr, usb_hcd_t *hcd)
// Construct a hub descriptor for the root hub.
usb_hub_t root_hub;
memset(&root_hub, 0, sizeof(root_hub));
root_hub.ep0 = NULL;
root_hub.level = 0;
root_hub.route = 0;
root_hub.num_ports = num_ehci_ports(hcs_params);
root_hub.power_up_delay = 10; // 20ms

View File

@ -498,9 +498,8 @@ bool ohci_init(uintptr_t base_addr, usb_hcd_t *hcd)
// Construct a hub descriptor for the root hub.
usb_hub_t root_hub;
memset(&root_hub, 0, sizeof(root_hub));
root_hub.ep0 = NULL;
root_hub.level = 0;
root_hub.route = 0;
root_hub.num_ports = rh_descriptor_a & 0xf;
root_hub.power_up_delay = rh_descriptor_a >> 24;

View File

@ -474,11 +474,9 @@ bool uhci_init(int bus, int dev, int func, uint16_t io_base, usb_hcd_t *hcd)
// Construct a hub descriptor for the root hub.
usb_hub_t root_hub;
memset(&root_hub, 0, sizeof(root_hub));
root_hub.ep0 = NULL;
root_hub.level = 0;
root_hub.route = 0;
root_hub.num_ports = MAX_UHCI_PORTS;
root_hub.power_up_delay = 0;
usleep(100*MILLISEC); // USB maximum device attach time

View File

@ -136,6 +136,8 @@ static bool build_hub_info(const usb_hcd_t *hcd, const usb_hub_t *parent, int po
hub->num_ports = hub_desc.num_ports;
hub->tt_think_time = hub_desc.characteristics & 0x0060 >> 5;
hub->power_up_delay = hub_desc.power_up_delay;
hub->hs_parent = usb_hs_parent(parent, port_num, ep0->device_speed);
usb_endpoint_desc_t *ep1_desc = find_hub_endpoint_descriptor(hcd->ws->data_buffer, hcd->ws->data_length);
if (ep1_desc == NULL) {
return false;
@ -456,6 +458,20 @@ uint32_t usb_route(const usb_hub_t *hub, int port_num)
return hub->route | (port_num << (4 * (hub->level - 1)));
}
usb_parent_t usb_hs_parent(const usb_hub_t *hub, int port_num, usb_speed_t device_speed)
{
usb_parent_t hs_parent = { 0, 0 };
if (device_speed < USB_SPEED_HIGH && hub->level > 0) {
if (hub->ep0->device_speed < USB_SPEED_HIGH) {
hs_parent = hub->hs_parent;
} else {
hs_parent.device_id = hub->ep0->device_id;
hs_parent.port_num = port_num;
}
}
return hs_parent;
}
bool wait_until_clr(const volatile uint32_t *reg, uint32_t bit_mask, int max_time)
{
int timer = max_time >> 3;

View File

@ -62,6 +62,14 @@ typedef struct __attribute__ ((packed)) {
uint8_t reserved;
} usb_ep_t;
/**
* A USB parent device descriptor (used internally by the various HCI drivers).
*/
typedef struct __attribute__ ((packed)) {
uint8_t device_id;
uint8_t port_num;
} usb_parent_t;
/**
* A USB hub descriptor (used internally by the various HCI drivers).
*/
@ -72,6 +80,8 @@ typedef struct __attribute__ ((packed)) {
uint8_t num_ports;
uint8_t tt_think_time;
uint8_t power_up_delay;
usb_parent_t hs_parent;
uint16_t reserved;
} usb_hub_t;
/**
@ -210,6 +220,17 @@ static inline bool valid_usb_config_descriptor(const uint8_t *buffer)
*/
uint32_t usb_route(const usb_hub_t *hub, int port_num);
/**
* Returns the high-speed parent device ID and port number (as defined by
* the EHCI and XHCI specifications) for the device attached to the hub
* port specified by hub and port_num. Returns zero values if the device
* is operating at high speed (as specified by device_speed) or is directly
* attached to a root hub port.
*
* Used internally by the various HCI drivers.
*/
usb_parent_t usb_hs_parent(const usb_hub_t *hub, int port_num, usb_speed_t device_speed);
/**
* Waits for all the bits set in bit_mask to be cleared in the register pointed
* to by reg or for max_time microseconds to elapse.

View File

@ -729,10 +729,9 @@ static bool assign_address(const usb_hcd_t *hcd, const usb_hub_t *hub, int port_
uint32_t route = usb_route(hub, port_num);
slot_context->params1 |= route & 0xfffff;
slot_context->root_hub_port_num = route >> 24;
if (device_speed < USB_SPEED_HIGH && hub->ep0->device_speed == USB_SPEED_HIGH) {
slot_context->parent_slot_id = hub->ep0->device_id;
slot_context->parent_port_num = port_num;
}
usb_parent_t hs_parent = usb_hs_parent(hub, port_num, device_speed);
slot_context->parent_slot_id = hs_parent.device_id;
slot_context->parent_port_num = hs_parent.port_num;
} else {
slot_context->root_hub_port_num = port_num;
}
@ -818,7 +817,7 @@ static bool configure_interrupt_endpoint(workspace_t *ws, const usb_ep_t *ep, in
xhci_slot_context_t *slot_context = (xhci_slot_context_t *)(ws->input_context_addr + ws->context_size);
slot_context->params1 = ep_id << 27 | hub_flag << 26 | (slot_context->params1 & 0x00ffffff);
slot_context->num_ports = num_ports;
slot_context->params2 = tt_think_time;
slot_context->params2 = ep->device_speed == USB_SPEED_HIGH ? tt_think_time : 0;
xhci_ep_context_t *ep_context = (xhci_ep_context_t *)(ws->input_context_addr + (1 + ep_id) * ws->context_size);
ep_context->params1 = 0;
@ -1093,11 +1092,9 @@ bool xhci_init(uintptr_t base_addr, usb_hcd_t *hcd)
// Construct a hub descriptor for the root hub.
usb_hub_t root_hub;
memset(&root_hub, 0, sizeof(root_hub));
root_hub.ep0 = NULL;
root_hub.level = 0;
root_hub.route = 0;
root_hub.num_ports = cap_regs->hcs_params1 & 0xff;
root_hub.power_up_delay = 0;
usleep(100*MILLISEC); // USB maximum device attach time.