Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions drivers/usb/host/ehci/ehci.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ typedef struct ehci_controller {
usb_device_t *devices[EHCI_MAX_PORTS];
ehci_periodic_transfer_t *periodic[EHCI_MAX_PERIODIC];
uint64_t pending_ports;
uint64_t failed_ports;
spinlock_t lock;
raw_spinlock_t io_lock;
wait_queue_t worker_wait;
Expand Down Expand Up @@ -546,6 +547,7 @@ static int ehci_enumerate_port(ehci_controller_t *ctrl, uint8_t port)
device->speed = speed;
device->bus_number = ctrl->bus_number;
device->port_number = port + 1;
device->depth = 1; // Root-port device: depth 1 (root hub depth 0)
device->hcd_ops = &ehci_hcd_ops;
device->hc_private = ctrl;
device->dev.release = ehci_usb_device_release;
Expand Down Expand Up @@ -660,13 +662,22 @@ static int ehci_worker(void *argument)
uint32_t portsc = ehci_read32(ctrl->operational, offset);
uint32_t change = portsc & EHCI_PORT_CHANGE_BITS;
if (change) ehci_write32(ctrl->operational, offset, portsc);
uint64_t port_mask = 1ULL << port;
if (!(portsc & EHCI_PORT_CCS)) {
ctrl->failed_ports &= ~port_mask;
if (ctrl->devices[port]) ehci_disconnect_port(ctrl, port);
} else if (!ctrl->devices[port] || (portsc & EHCI_PORT_CSC)) {
} else {
if (portsc & EHCI_PORT_CSC) ctrl->failed_ports &= ~port_mask;
if (ctrl->failed_ports & port_mask) continue;
if (!(portsc & EHCI_PORT_CSC) && ctrl->devices[port]) continue;
if (ctrl->devices[port]) ehci_disconnect_port(ctrl, port);
msleep(100);
int ret = ehci_enumerate_port(ctrl, port);
if (ret != EOK) plogk("usb-ehci: Port %u enumeration failed: %d\n", port, ret);
if (ret != EOK) {
/* The port reset of this attempt raises PCD again; retry only after a new connection. */
ctrl->failed_ports |= port_mask;
plogk("usb-ehci: Port %u enumeration failed: %d; waiting for reconnect\n", port, ret);
}
}
}
ehci_service_periodic(ctrl);
Expand Down Expand Up @@ -810,8 +821,10 @@ static int ehci_probe(pci_device_cache_t *pci, uint8_t bus_number)

pci_irq_state_t irq_state;
pci_irq_request_t request = {
.modes = PCI_IRQ_MSI | PCI_IRQ_LEGACY,
.idt_handler = (void *)ehci_interrupt_handler,
.modes = PCI_IRQ_MSI | PCI_IRQ_LEGACY,
.idt_handler = (void *)ehci_interrupt_handler,
.legacy_base = IRQ_0,
.legacy_ioapic = 1,
};
if (pci_request_irq(pci, &request, &irq_state) < 0) return -ENODEV;

Expand Down
7 changes: 5 additions & 2 deletions drivers/usb/host/ohci/ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ static int ohci_enumerate_port(ohci_controller_t *ctrl, uint8_t port)
device->speed = speed;
device->bus_number = ctrl->bus_number;
device->port_number = port + 1;
device->depth = 1; // Root-port device: depth 1 (root hub depth 0)
device->hcd_ops = &ohci_hcd_ops;
device->hc_private = ctrl;
device->dev.release = ohci_usb_device_release;
Expand Down Expand Up @@ -826,8 +827,10 @@ static int ohci_probe(pci_device_cache_t *pci, uint8_t bus_number)

pci_irq_state_t irq_state;
pci_irq_request_t request = {
.modes = PCI_IRQ_MSI | PCI_IRQ_LEGACY,
.idt_handler = (void *)ohci_interrupt_handler,
.modes = PCI_IRQ_MSI | PCI_IRQ_LEGACY,
.idt_handler = (void *)ohci_interrupt_handler,
.legacy_base = IRQ_0,
.legacy_ioapic = 1,
};
if (pci_request_irq(pci, &request, &irq_state) < 0) return -ENODEV;

Expand Down
14 changes: 11 additions & 3 deletions drivers/usb/host/uhci/uhci.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ static int uhci_enumerate_port(uhci_controller_t *ctrl, uint8_t port)
device->speed = speed;
device->bus_number = ctrl->bus_number;
device->port_number = port + 1;
device->depth = 1; // Root-port device: depth 1 (root hub depth 0)
device->hcd_ops = &uhci_hcd_ops;
device->hc_private = ctrl;
device->dev.release = uhci_usb_device_release;
Expand Down Expand Up @@ -725,8 +726,13 @@ static int uhci_worker(void *argument)
{
uhci_controller_t *ctrl = argument;
while (ctrl->running && !kthread_should_stop()) {
/* UHCI has no port-change interrupt (RD only fires in global suspend), so poll the root ports like Linux's POLL_RH. */
uint64_t polled = 0;
for (uint8_t p = 0; p < UHCI_MAX_PORTS; p++)
if (uhci_readw(ctrl, UHCI_PORTSC1 + p * 2) & (UHCI_PORTSC_CSC | UHCI_PORTSC_PEC)) polled |= 1ULL << p;

uint64_t flags = spin_lock_irqsave(&ctrl->lock);
uint64_t ports = ctrl->pending_ports;
uint64_t ports = ctrl->pending_ports | polled;
ctrl->pending_ports = 0;
if (!ports && ctrl->running && !kthread_should_stop()) wait_queue_prepare(&ctrl->worker_wait);
spin_unlock_irqrestore(&ctrl->lock, flags);
Expand Down Expand Up @@ -875,8 +881,10 @@ static int uhci_probe(pci_device_cache_t *pci, uint8_t bus_number)

pci_irq_state_t irq_state;
pci_irq_request_t request = {
.modes = PCI_IRQ_MSI | PCI_IRQ_LEGACY,
.idt_handler = (void *)uhci_interrupt_handler,
.modes = PCI_IRQ_MSI | PCI_IRQ_LEGACY,
.idt_handler = (void *)uhci_interrupt_handler,
.legacy_base = IRQ_0,
.legacy_ioapic = 1,
};
if (pci_request_irq(pci, &request, &irq_state) < 0) return -ENODEV;

Expand Down
Loading