XHCI set device configuration
This commit is contained in:
6
kernel/device/usb/mass_storage.c
Normal file
6
kernel/device/usb/mass_storage.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <device/usb/mass_storage.h>
|
||||
#include <device/usb/usb.h>
|
||||
#include <libk/std.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
bool usb_mass_storage_init (void) { return true; }
|
||||
8
kernel/device/usb/mass_storage.h
Normal file
8
kernel/device/usb/mass_storage.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef _KERNEL_DEVICE_USB_MASS_STORAGE_H
|
||||
#define _KERNEL_DEVICE_USB_MASS_STORAGE_H
|
||||
|
||||
#include <libk/std.h>
|
||||
|
||||
bool usb_mass_storage_init (void);
|
||||
|
||||
#endif // _KERNEL_DEVICE_USB_MASS_STORAGE_H
|
||||
@@ -1,3 +1,7 @@
|
||||
c += device/usb/xhci.c
|
||||
c += device/usb/xhci.c \
|
||||
device/usb/usb.c \
|
||||
device/usb/mass_storage.c
|
||||
|
||||
o += device/usb/xhci.o
|
||||
o += device/usb/xhci.o \
|
||||
device/usb/usb.o \
|
||||
device/usb/mass_storage.o
|
||||
|
||||
6
kernel/device/usb/usb.c
Normal file
6
kernel/device/usb/usb.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include <device/usb/mass_storage.h>
|
||||
#include <device/usb/usb.h>
|
||||
|
||||
struct usb_driver_info usb_driver_infos[USB_DRIVER_MAX_MATCHES] = {
|
||||
{.if_class = 0x08, .if_subclass = 0x06, .if_proto = 0x50, .init = &usb_mass_storage_init},
|
||||
};
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <aux/compiler.h>
|
||||
#include <libk/std.h>
|
||||
|
||||
#define USB_DRIVER_MAX_MATCHES 1
|
||||
|
||||
/* descriptor types */
|
||||
|
||||
#define USB_DESC_DEVICE 1
|
||||
@@ -75,4 +77,13 @@ struct usb_endpoint_desc {
|
||||
uint8_t interval;
|
||||
} PACKED;
|
||||
|
||||
struct usb_driver_info {
|
||||
uint8_t if_class;
|
||||
uint8_t if_subclass;
|
||||
uint8_t if_proto;
|
||||
bool (*init) (void);
|
||||
};
|
||||
|
||||
extern struct usb_driver_info usb_driver_infos[USB_DRIVER_MAX_MATCHES];
|
||||
|
||||
#endif // _KERNEL_DEVICE_USB_H
|
||||
|
||||
@@ -330,6 +330,83 @@ static void xhci_portsc_write (struct xhci* xhci, uint8_t port, uint32_t value)
|
||||
xhci_write32 (xhci->xhci_oper_base, 1024 + (16 * port), value);
|
||||
}
|
||||
|
||||
static void xhci_create_pdevice (struct xhci* xhci, struct xhci_port* xhci_port) {
|
||||
struct xhci_pdevice* pdevice;
|
||||
|
||||
list_find (struct xhci_pdevice, xhci->xhci_pdevices, pdevice, xhci_port->port_value,
|
||||
xhci_port->port_value, pdevices_link);
|
||||
|
||||
if (pdevice != NULL)
|
||||
return;
|
||||
|
||||
pdevice = malloc (sizeof (*pdevice));
|
||||
memset (pdevice, 0, sizeof (*pdevice));
|
||||
pdevice->xhci_port = xhci_port;
|
||||
pdevice->slot_id = -1;
|
||||
|
||||
list_append (xhci->xhci_pdevices, &pdevice->pdevices_link);
|
||||
}
|
||||
|
||||
static void xhci_delete_pdevice (struct xhci* xhci, struct xhci_port* xhci_port) {
|
||||
struct xhci_pdevice* pdevice;
|
||||
|
||||
list_find (struct xhci_pdevice, xhci->xhci_pdevices, pdevice, xhci_port->port_value,
|
||||
xhci_port->port_value, pdevices_link);
|
||||
|
||||
list_remove (xhci->xhci_pdevices, &pdevice->pdevices_link);
|
||||
|
||||
if (pdevice->endpoint0_ring.phys != 0)
|
||||
pmm_free (pdevice->endpoint0_ring.phys, 1);
|
||||
|
||||
pmm_free (xhci->xhci_dcbaa[pdevice->slot_id], 1);
|
||||
xhci->xhci_dcbaa[pdevice->slot_id] = 0;
|
||||
|
||||
free (pdevice);
|
||||
}
|
||||
|
||||
static void xhci_bios_handover (struct xhci* xhci) {
|
||||
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
||||
uint32_t ext_offset = (hccparams1 >> XHCI_HCCPARAMS1_XECP) << 2;
|
||||
|
||||
if (ext_offset == 0)
|
||||
return;
|
||||
|
||||
while (ext_offset) {
|
||||
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
|
||||
uint32_t cap = xhci_read32 (cap_ptr, 0);
|
||||
uint8_t cap_id = cap & 0xFF;
|
||||
|
||||
if (cap_id == XHCI_EXTCAP_USB_LEGACY_SUPPORT) {
|
||||
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
|
||||
if (cap & (1 << XHCI_USBLEGSUP_BIOS_SEMA)) {
|
||||
DEBUG ("BIOS owns XHCI, requesting handover!\n");
|
||||
|
||||
xhci_write8 (cap_ptr, 3, 1);
|
||||
|
||||
/* Wait for BIOS Semaphore owned bit to be cleared */
|
||||
int timeout = 1000;
|
||||
while (--timeout > 0) {
|
||||
uint32_t val = xhci_read32 (cap_ptr, 0);
|
||||
if (!(val & (1 << XHCI_USBLEGSUP_BIOS_SEMA)) && (val & (1 << XHCI_USBLEGSUP_OS_SEMA)))
|
||||
break;
|
||||
|
||||
stall_ms (100);
|
||||
}
|
||||
|
||||
DEBUG ("XHCI Handover OK\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t next = (cap >> XHCI_XECP_NEXT_PTR) & 0xFF;
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
ext_offset += (next << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_port_reset (struct xhci* xhci, uint8_t port) {
|
||||
struct xhci_port* xhci_port;
|
||||
|
||||
@@ -372,38 +449,60 @@ static void xhci_port_reset (struct xhci* xhci, uint8_t port) {
|
||||
stall_ms (100);
|
||||
}
|
||||
|
||||
static void xhci_create_pdevice (struct xhci* xhci, struct xhci_port* xhci_port) {
|
||||
struct xhci_pdevice* pdevice;
|
||||
static void xhci_reset_ports (struct xhci* xhci) {
|
||||
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
||||
uint32_t ext_offset = (hccparams1 >> XHCI_HCCPARAMS1_XECP) << 2;
|
||||
|
||||
list_find (struct xhci_pdevice, xhci->xhci_pdevices, pdevice, xhci_port->port_value,
|
||||
xhci_port->port_value, pdevices_link);
|
||||
|
||||
if (pdevice != NULL)
|
||||
if (ext_offset == 0)
|
||||
return;
|
||||
|
||||
pdevice = malloc (sizeof (*pdevice));
|
||||
memset (pdevice, 0, sizeof (*pdevice));
|
||||
pdevice->xhci_port = xhci_port;
|
||||
pdevice->slot_id = -1;
|
||||
while (ext_offset) {
|
||||
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
|
||||
uint32_t cap = xhci_read32 (cap_ptr, 0);
|
||||
uint8_t cap_id = cap & 0xFF;
|
||||
|
||||
list_append (xhci->xhci_pdevices, &pdevice->pdevices_link);
|
||||
}
|
||||
if (cap_id == XHCI_EXTCAP_SUPPORTED_PROTOCOL) {
|
||||
uint8_t minor = (cap >> XHCI_SUPPROTO_DW0_MINOR_REV) & 0xFF;
|
||||
uint8_t major = (cap >> XHCI_SUPPROTO_DW0_MAJOR_REV) & 0xFF;
|
||||
|
||||
static void xhci_delete_pdevice (struct xhci* xhci, struct xhci_port* xhci_port) {
|
||||
struct xhci_pdevice* pdevice;
|
||||
uint32_t dword2 = xhci_read32 (cap_ptr, 8);
|
||||
uint8_t port_off = (dword2 >> XHCI_SUPPROTO_DW2_PORT_OFF) & 0xFF;
|
||||
uint8_t port_count = (dword2 >> XHCI_SUPPROTO_DW2_PORT_COUNT) & 0xFF;
|
||||
|
||||
list_find (struct xhci_pdevice, xhci->xhci_pdevices, pdevice, xhci_port->port_value,
|
||||
xhci_port->port_value, pdevices_link);
|
||||
uint8_t first_port = port_off - 1;
|
||||
uint8_t last_port = first_port + port_count - 1;
|
||||
|
||||
list_remove (xhci->xhci_pdevices, &pdevice->pdevices_link);
|
||||
for (uint8_t port = first_port; port <= last_port; port++) {
|
||||
struct xhci_port* xhci_port = malloc (sizeof (*xhci_port));
|
||||
memset (xhci_port, 0, sizeof (*xhci_port));
|
||||
|
||||
if (pdevice->endpoint0_ring.phys != 0)
|
||||
pmm_free (pdevice->endpoint0_ring.phys, 1);
|
||||
if (major == 3)
|
||||
xhci_port->type = XHCI_PORT_USB3;
|
||||
else
|
||||
xhci_port->type = XHCI_PORT_USB2;
|
||||
|
||||
pmm_free (xhci->xhci_dcbaa[pdevice->slot_id], 1);
|
||||
xhci->xhci_dcbaa[pdevice->slot_id] = 0;
|
||||
xhci_port->port_value = port;
|
||||
|
||||
free (pdevice);
|
||||
list_append (xhci->xhci_ports, &xhci_port->ports_link);
|
||||
|
||||
uint32_t portsc = xhci_portsc_read (xhci, port);
|
||||
|
||||
if ((portsc & (1 << XHCI_PORTSC_CCS))) {
|
||||
DEBUG ("Device connected. resetting\n");
|
||||
xhci_port_reset (xhci, port);
|
||||
xhci_create_pdevice (xhci, xhci_port);
|
||||
}
|
||||
|
||||
DEBUG ("PORT %u: USB %u.%u\n", port, major, minor);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t next = (cap >> XHCI_XECP_NEXT_PTR) & 0xFF;
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
ext_offset += (next << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_event_dispatch (struct xhci* xhci, struct xhci_trb* event, uint8_t type) {
|
||||
@@ -563,20 +662,96 @@ static bool xhci_endpoint0_ctrl_in (struct xhci* xhci, struct xhci_pdevice* pdev
|
||||
memset (&trb, 0, sizeof (trb));
|
||||
trb.param = data_phys;
|
||||
trb.status = length;
|
||||
trb.ctrl = (XHCI_TRB_DATA_STAGE << XHCI_DSTRB_CTRL_TRB_TYPE) | (1 << XHCI_DSTRB_CTRL_DIR);
|
||||
|
||||
write_memory_barrier ();
|
||||
|
||||
trb.ctrl = (XHCI_TRB_DATA_STAGE << XHCI_DSTRB_CTRL_TRB_TYPE) | (1 << XHCI_DSTRB_CTRL_DIR);
|
||||
xhci_endpoint0_put_trb (pdevice, trb);
|
||||
|
||||
/* status stage */
|
||||
memset (&trb, 0, sizeof (trb));
|
||||
trb.param = 0;
|
||||
trb.status = 0;
|
||||
trb.ctrl = (XHCI_TRB_STATUS_STAGE << XHCI_STSTRB_CTRL_TRB_TYPE) | (1 << XHCI_STSTRB_CTRL_IOC);
|
||||
|
||||
write_memory_barrier ();
|
||||
|
||||
trb.ctrl = (XHCI_TRB_STATUS_STAGE << XHCI_STSTRB_CTRL_TRB_TYPE) | (1 << XHCI_STSTRB_CTRL_IOC);
|
||||
xhci_endpoint0_put_trb (pdevice, trb);
|
||||
|
||||
atomic_store (&xhci->pending, true);
|
||||
|
||||
int timeout = 100;
|
||||
|
||||
spin_unlock (&xhci->device->lock, *lockflags);
|
||||
|
||||
xhci_write32 (xhci->xhci_doorbell_base, pdevice->slot_id * 4, 1);
|
||||
|
||||
while (atomic_load (&xhci->pending) && --timeout > 0)
|
||||
stall_ms (10);
|
||||
|
||||
spin_lock (&xhci->device->lock, lockflags);
|
||||
|
||||
if (timeout == 0) {
|
||||
DEBUG ("timed out\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return xhci->last_cmpl_code == 1;
|
||||
}
|
||||
|
||||
static bool xhci_endpoint0_ctrl_out (struct xhci* xhci, struct xhci_pdevice* pdevice,
|
||||
uint8_t request_type, uint8_t request, uint16_t value,
|
||||
uint16_t index, uintptr_t data_phys, uint16_t length,
|
||||
uint64_t* lockflags) {
|
||||
/* clang-format off */
|
||||
uint64_t setup = ((uint64_t)length << XHCI_SSTRB_PARAM_WLENGTH)
|
||||
| ((uint64_t)index << XHCI_SSTRB_PARAM_WINDEX)
|
||||
| ((uint64_t)value << XHCI_SSTRB_PARAM_WVALUE)
|
||||
| ((uint64_t)request << XHCI_SSTRB_PARAM_BREQUEST)
|
||||
| ((uint64_t)request_type << XHCI_SSTRB_PARAM_BMREQUEST_TYPE);
|
||||
/* clang-format on */
|
||||
|
||||
struct xhci_trb trb;
|
||||
|
||||
/* setup stage */
|
||||
memset (&trb, 0, sizeof (trb));
|
||||
trb.param = setup;
|
||||
trb.status = 8;
|
||||
|
||||
write_memory_barrier ();
|
||||
|
||||
if (length == 0) {
|
||||
trb.ctrl = (XHCI_TRB_SETUP_STAGE << XHCI_SSTRB_CTRL_TRB_TYPE) |
|
||||
(1 << XHCI_SSTRB_CTRL_IDT) |
|
||||
(XHCI_SSTRB_TRT_NO_DATA_STAGE << XHCI_SSTRB_CTRL_TRT);
|
||||
xhci_endpoint0_put_trb (pdevice, trb);
|
||||
} else {
|
||||
trb.ctrl = (XHCI_TRB_SETUP_STAGE << XHCI_SSTRB_CTRL_TRB_TYPE) |
|
||||
(1 << XHCI_SSTRB_CTRL_IDT) |
|
||||
(XHCI_SSTRB_TRT_OUT_DATA_STAGE << XHCI_SSTRB_CTRL_TRT);
|
||||
xhci_endpoint0_put_trb (pdevice, trb);
|
||||
|
||||
/* data stage */
|
||||
memset (&trb, 0, sizeof (trb));
|
||||
trb.param = data_phys;
|
||||
trb.status = length;
|
||||
|
||||
write_memory_barrier ();
|
||||
|
||||
trb.ctrl = (XHCI_TRB_DATA_STAGE << XHCI_DSTRB_CTRL_TRB_TYPE);
|
||||
xhci_endpoint0_put_trb (pdevice, trb);
|
||||
}
|
||||
|
||||
/* status stage */
|
||||
memset (&trb, 0, sizeof (trb));
|
||||
trb.param = 0;
|
||||
trb.status = 0;
|
||||
|
||||
write_memory_barrier ();
|
||||
|
||||
trb.ctrl = (XHCI_TRB_STATUS_STAGE << XHCI_STSTRB_CTRL_TRB_TYPE) |
|
||||
(1 << XHCI_STSTRB_CTRL_IOC) |
|
||||
(1 << XHCI_STSTRB_CTRL_DIR);
|
||||
xhci_endpoint0_put_trb (pdevice, trb);
|
||||
|
||||
atomic_store (&xhci->pending, true);
|
||||
@@ -644,103 +819,18 @@ static void xhci_send_cmd (struct xhci* xhci, uint64_t param, uint32_t status, u
|
||||
DEBUG ("timed out\n");
|
||||
}
|
||||
|
||||
static void xhci_bios_handover (struct xhci* xhci) {
|
||||
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
||||
uint32_t ext_offset = (hccparams1 >> XHCI_HCCPARAMS1_XECP) << 2;
|
||||
static void xhci_pdevice_setup_init_endpoints (struct xhci* xhci, struct xhci_pdevice* pdevice) {}
|
||||
|
||||
if (ext_offset == 0)
|
||||
static void xhci_pdevice_setup_set_config (struct xhci* xhci, struct xhci_pdevice* pdevice,
|
||||
uint8_t config_val, uint64_t* lockflags) {
|
||||
bool ok = xhci_endpoint0_ctrl_out (xhci, pdevice, 0x00, 0x09, config_val, 0, 0, 0, lockflags);
|
||||
|
||||
if (!ok) {
|
||||
DEBUG ("Failed to set the config!\n");
|
||||
return;
|
||||
|
||||
while (ext_offset) {
|
||||
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
|
||||
uint32_t cap = xhci_read32 (cap_ptr, 0);
|
||||
uint8_t cap_id = cap & 0xFF;
|
||||
|
||||
if (cap_id == XHCI_EXTCAP_USB_LEGACY_SUPPORT) {
|
||||
/* Make or break on real hardware. We need to take over ownership from the BIOS. */
|
||||
if (cap & (1 << XHCI_USBLEGSUP_BIOS_SEMA)) {
|
||||
DEBUG ("BIOS owns XHCI, requesting handover!\n");
|
||||
|
||||
xhci_write8 (cap_ptr, 3, 1);
|
||||
|
||||
/* Wait for BIOS Semaphore owned bit to be cleared */
|
||||
int timeout = 1000;
|
||||
while (--timeout > 0) {
|
||||
uint32_t val = xhci_read32 (cap_ptr, 0);
|
||||
if (!(val & (1 << XHCI_USBLEGSUP_BIOS_SEMA)) && (val & (1 << XHCI_USBLEGSUP_OS_SEMA)))
|
||||
break;
|
||||
|
||||
stall_ms (100);
|
||||
}
|
||||
|
||||
DEBUG ("XHCI Handover OK\n");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t next = (cap >> XHCI_XECP_NEXT_PTR) & 0xFF;
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
ext_offset += (next << 2);
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_reset_ports (struct xhci* xhci) {
|
||||
uint32_t hccparams1 = xhci_read32 (xhci->xhci_mmio_base, XHCI_HCCPARAMS1);
|
||||
uint32_t ext_offset = (hccparams1 >> XHCI_HCCPARAMS1_XECP) << 2;
|
||||
|
||||
if (ext_offset == 0)
|
||||
return;
|
||||
|
||||
while (ext_offset) {
|
||||
uintptr_t cap_ptr = xhci->xhci_mmio_base + ext_offset;
|
||||
uint32_t cap = xhci_read32 (cap_ptr, 0);
|
||||
uint8_t cap_id = cap & 0xFF;
|
||||
|
||||
if (cap_id == XHCI_EXTCAP_SUPPORTED_PROTOCOL) {
|
||||
uint8_t minor = (cap >> XHCI_SUPPROTO_DW0_MINOR_REV) & 0xFF;
|
||||
uint8_t major = (cap >> XHCI_SUPPROTO_DW0_MAJOR_REV) & 0xFF;
|
||||
|
||||
uint32_t dword2 = xhci_read32 (cap_ptr, 8);
|
||||
uint8_t port_off = (dword2 >> XHCI_SUPPROTO_DW2_PORT_OFF) & 0xFF;
|
||||
uint8_t port_count = (dword2 >> XHCI_SUPPROTO_DW2_PORT_COUNT) & 0xFF;
|
||||
|
||||
uint8_t first_port = port_off - 1;
|
||||
uint8_t last_port = first_port + port_count - 1;
|
||||
|
||||
for (uint8_t port = first_port; port <= last_port; port++) {
|
||||
struct xhci_port* xhci_port = malloc (sizeof (*xhci_port));
|
||||
memset (xhci_port, 0, sizeof (*xhci_port));
|
||||
|
||||
if (major == 3)
|
||||
xhci_port->type = XHCI_PORT_USB3;
|
||||
else
|
||||
xhci_port->type = XHCI_PORT_USB2;
|
||||
|
||||
xhci_port->port_value = port;
|
||||
|
||||
list_append (xhci->xhci_ports, &xhci_port->ports_link);
|
||||
|
||||
uint32_t portsc = xhci_portsc_read (xhci, port);
|
||||
|
||||
if ((portsc & (1 << XHCI_PORTSC_CCS))) {
|
||||
DEBUG ("Device connected. resetting\n");
|
||||
xhci_port_reset (xhci, port);
|
||||
xhci_create_pdevice (xhci, xhci_port);
|
||||
}
|
||||
|
||||
DEBUG ("PORT %u: USB %u.%u\n", port, major, minor);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t next = (cap >> XHCI_XECP_NEXT_PTR) & 0xFF;
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
ext_offset += (next << 2);
|
||||
}
|
||||
DEBUG ("Config set!\n");
|
||||
}
|
||||
|
||||
static void xhci_pdevice_setup_addressing (struct xhci* xhci, struct xhci_pdevice* pdevice,
|
||||
@@ -938,7 +1028,7 @@ static bool xhci_pdevice_setup_get_config_full (struct xhci* xhci, struct xhci_p
|
||||
DEBUG (
|
||||
"Found USB device interface: ifnum=%u altsetting=%u eps=%u ifclass=%u ifsubclass=%u ifproto=%u if=%u\n",
|
||||
dif->desc.if_num, dif->desc.alt_setting, dif->desc.num_endpoints, dif->desc.if_class,
|
||||
dif->desc.if_subclass, dif->desc.if1);
|
||||
dif->desc.if_subclass, dif->desc.if_proto, dif->desc.if1);
|
||||
} break;
|
||||
case USB_DESC_ENDPOINT: {
|
||||
struct xhci_pdevice_dendpoint* dendpoint = malloc (sizeof (*dendpoint));
|
||||
@@ -962,6 +1052,29 @@ static bool xhci_pdevice_setup_get_config_full (struct xhci* xhci, struct xhci_p
|
||||
return true;
|
||||
}
|
||||
|
||||
static void xhci_poll_setup_init_ifs (struct xhci* xhci, struct xhci_pdevice* pdevice,
|
||||
uint64_t* lockflags) {
|
||||
struct list_node_link *ifs_link, *tmp_ifs_link;
|
||||
|
||||
list_foreach (pdevice->difs, ifs_link, tmp_ifs_link) {
|
||||
struct xhci_pdevice_dif* dif = list_entry (ifs_link, struct xhci_pdevice_dif, ifs_link);
|
||||
|
||||
for (size_t i = 0; i < USB_DRIVER_MAX_MATCHES; i++) {
|
||||
struct usb_driver_info* info = &usb_driver_infos[i];
|
||||
|
||||
DEBUG ("%u %u / %u %u / %u %u\n", dif->desc.if_class, info->if_class, dif->desc.if_subclass,
|
||||
info->if_subclass, dif->desc.if_proto, info->if_proto);
|
||||
|
||||
if (dif->desc.if_class == info->if_class &&
|
||||
dif->desc.if_subclass == info->if_subclass &&
|
||||
dif->desc.if_proto == info->if_proto) {
|
||||
if (!info->init ())
|
||||
DEBUG ("USB driver failed to initialize. Skipping device!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) {
|
||||
struct list_node_link *pdevice_link, *tmp_pdevice_link;
|
||||
|
||||
@@ -976,6 +1089,8 @@ static void xhci_poll_setup_devices (struct xhci* xhci, uint64_t* lockflags) {
|
||||
xhci_pdevice_setup_get_info (xhci, pdevice, lockflags);
|
||||
xhci_pdevice_setup_get_config (xhci, pdevice, lockflags);
|
||||
xhci_pdevice_setup_get_config_full (xhci, pdevice, lockflags);
|
||||
xhci_pdevice_setup_set_config (xhci, pdevice, 0, lockflags);
|
||||
xhci_poll_setup_init_ifs (xhci, pdevice, lockflags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user