Kernel: Pass xHCI device information in structs
This makes code more readable and extendable
This commit is contained in:
parent
63b15a8855
commit
7de689055c
|
@ -46,7 +46,7 @@ namespace Kernel
|
||||||
|
|
||||||
void port_updater_task();
|
void port_updater_task();
|
||||||
|
|
||||||
BAN::ErrorOr<uint8_t> initialize_slot(int port_index);
|
BAN::ErrorOr<uint8_t> initialize_device(uint32_t route_string, USB::SpeedClass speed_class);
|
||||||
void deinitialize_slot(uint8_t slot_id);
|
void deinitialize_slot(uint8_t slot_id);
|
||||||
|
|
||||||
BAN::ErrorOr<XHCI::TRB> send_command(const XHCI::TRB&);
|
BAN::ErrorOr<XHCI::TRB> send_command(const XHCI::TRB&);
|
||||||
|
|
|
@ -30,8 +30,15 @@ namespace Kernel
|
||||||
void(XHCIDevice::*callback)(XHCI::TRB);
|
void(XHCIDevice::*callback)(XHCI::TRB);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Info
|
||||||
|
{
|
||||||
|
USB::SpeedClass speed_class;
|
||||||
|
uint8_t slot_id;
|
||||||
|
uint32_t route_string;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, uint32_t port_id, uint32_t slot_id);
|
static BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> create(XHCIController&, const Info& info);
|
||||||
|
|
||||||
BAN::ErrorOr<void> configure_endpoint(const USBEndpointDescriptor&) override;
|
BAN::ErrorOr<void> configure_endpoint(const USBEndpointDescriptor&) override;
|
||||||
BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) override;
|
BAN::ErrorOr<size_t> send_request(const USBDeviceRequest&, paddr_t buffer) override;
|
||||||
|
@ -43,8 +50,9 @@ namespace Kernel
|
||||||
BAN::ErrorOr<void> initialize_control_endpoint() override;
|
BAN::ErrorOr<void> initialize_control_endpoint() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id);
|
XHCIDevice(XHCIController& controller, const Info& info);
|
||||||
~XHCIDevice();
|
~XHCIDevice();
|
||||||
|
|
||||||
BAN::ErrorOr<void> update_actual_max_packet_size();
|
BAN::ErrorOr<void> update_actual_max_packet_size();
|
||||||
|
|
||||||
void on_interrupt_or_bulk_endpoint_event(XHCI::TRB);
|
void on_interrupt_or_bulk_endpoint_event(XHCI::TRB);
|
||||||
|
@ -55,8 +63,7 @@ namespace Kernel
|
||||||
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
|
static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB);
|
||||||
|
|
||||||
XHCIController& m_controller;
|
XHCIController& m_controller;
|
||||||
const uint32_t m_port_id;
|
Info m_info;
|
||||||
const uint32_t m_slot_id;
|
|
||||||
|
|
||||||
Mutex m_mutex;
|
Mutex m_mutex;
|
||||||
|
|
||||||
|
|
|
@ -363,7 +363,8 @@ namespace Kernel
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto ret = initialize_slot(i); !ret.is_error())
|
const uint8_t speed_id = (op_port.portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
|
||||||
|
if (auto ret = initialize_device(i + 1, speed_id_to_class(speed_id)); !ret.is_error())
|
||||||
my_port.slot_id = ret.value();
|
my_port.slot_id = ret.value();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -377,10 +378,8 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<uint8_t> XHCIController::initialize_slot(int port_index)
|
BAN::ErrorOr<uint8_t> XHCIController::initialize_device(uint32_t route_string, USB::SpeedClass speed_class)
|
||||||
{
|
{
|
||||||
auto& my_port = m_ports[port_index];
|
|
||||||
|
|
||||||
XHCI::TRB enable_slot { .enable_slot_command {} };
|
XHCI::TRB enable_slot { .enable_slot_command {} };
|
||||||
enable_slot.enable_slot_command.trb_type = XHCI::TRBType::EnableSlotCommand;
|
enable_slot.enable_slot_command.trb_type = XHCI::TRBType::EnableSlotCommand;
|
||||||
// 7.2.2.1.4: The Protocol Slot Type field of a USB3 or USB2 xHCI Supported Protocol Capability shall be set to ‘0’.
|
// 7.2.2.1.4: The Protocol Slot Type field of a USB3 or USB2 xHCI Supported Protocol Capability shall be set to ‘0’.
|
||||||
|
@ -393,9 +392,24 @@ namespace Kernel
|
||||||
dwarnln("EnableSlotCommand returned an invalid slot {}", slot_id);
|
dwarnln("EnableSlotCommand returned an invalid slot {}", slot_id);
|
||||||
return BAN::Error::from_errno(EFAULT);
|
return BAN::Error::from_errno(EFAULT);
|
||||||
}
|
}
|
||||||
dprintln_if(DEBUG_XHCI, "allocated slot {} for port {}", slot_id, port_index + 1);
|
|
||||||
|
|
||||||
m_slots[slot_id - 1] = TRY(XHCIDevice::create(*this, port_index + 1, slot_id));
|
#if DEBUG_XHCI
|
||||||
|
const auto& root_port = m_ports[(route_string & 0x0F) - 1];
|
||||||
|
|
||||||
|
dprintln("Initializing USB {H}.{H} device on slot {}",
|
||||||
|
root_port.revision_major,
|
||||||
|
root_port.revision_minor,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const XHCIDevice::Info info {
|
||||||
|
.speed_class = speed_class,
|
||||||
|
.slot_id = slot_id,
|
||||||
|
.route_string = route_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
m_slots[slot_id - 1] = TRY(XHCIDevice::create(*this, info));
|
||||||
if (auto ret = m_slots[slot_id - 1]->initialize(); ret.is_error())
|
if (auto ret = m_slots[slot_id - 1]->initialize(); ret.is_error())
|
||||||
{
|
{
|
||||||
dwarnln("Could not initialize device on slot {}: {}", slot_id, ret.error());
|
dwarnln("Could not initialize device on slot {}: {}", slot_id, ret.error());
|
||||||
|
@ -403,9 +417,13 @@ namespace Kernel
|
||||||
return ret.release_error();
|
return ret.release_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
my_port.slot_id = slot_id;
|
#if DEBUG_XHCI
|
||||||
|
dprintln("USB {H}.{H} device on slot {} initialized",
|
||||||
dprintln_if(DEBUG_XHCI, "device on slot {} initialized", slot_id);
|
root_port.revision_major,
|
||||||
|
root_port.revision_minor,
|
||||||
|
slot_id
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
return slot_id;
|
return slot_id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,35 +8,32 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> XHCIDevice::create(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
|
BAN::ErrorOr<BAN::UniqPtr<XHCIDevice>> XHCIDevice::create(XHCIController& controller, const Info& info)
|
||||||
{
|
{
|
||||||
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id));
|
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, info));
|
||||||
}
|
}
|
||||||
|
|
||||||
XHCIDevice::XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
|
XHCIDevice::XHCIDevice(XHCIController& controller, const Info& info)
|
||||||
: USBDevice(controller.speed_id_to_class((controller.operational_regs().ports[port_id - 1].portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK))
|
: USBDevice(info.speed_class)
|
||||||
, m_controller(controller)
|
, m_controller(controller)
|
||||||
, m_port_id(port_id)
|
, m_info(info)
|
||||||
, m_slot_id(slot_id)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
XHCIDevice::~XHCIDevice()
|
XHCIDevice::~XHCIDevice()
|
||||||
{
|
{
|
||||||
XHCI::TRB disable_slot { .disable_slot_command {} };
|
XHCI::TRB disable_slot { .disable_slot_command {} };
|
||||||
disable_slot.disable_slot_command.trb_type = XHCI::TRBType::DisableSlotCommand;
|
disable_slot.disable_slot_command.trb_type = XHCI::TRBType::DisableSlotCommand;
|
||||||
disable_slot.disable_slot_command.slot_id = m_slot_id;
|
disable_slot.disable_slot_command.slot_id = m_info.slot_id;
|
||||||
if (auto ret = m_controller.send_command(disable_slot); ret.is_error())
|
if (auto ret = m_controller.send_command(disable_slot); ret.is_error())
|
||||||
dwarnln("Could not disable slot {}: {}", m_slot_id, ret.error());
|
dwarnln("Could not disable slot {}: {}", m_info.slot_id, ret.error());
|
||||||
else
|
else
|
||||||
dprintln_if(DEBUG_XHCI, "Slot {} disabled", m_slot_id);
|
dprintln_if(DEBUG_XHCI, "Slot {} disabled", m_info.slot_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<void> XHCIDevice::initialize_control_endpoint()
|
BAN::ErrorOr<void> XHCIDevice::initialize_control_endpoint()
|
||||||
{
|
{
|
||||||
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
|
const uint32_t context_size = m_controller.context_size_set() ? 64 : 32;
|
||||||
|
|
||||||
const uint32_t portsc = m_controller.operational_regs().ports[m_port_id - 1].portsc;
|
|
||||||
const uint32_t speed_id = (portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
|
|
||||||
|
|
||||||
m_endpoints[0].max_packet_size = 0;
|
m_endpoints[0].max_packet_size = 0;
|
||||||
switch (m_speed_class)
|
switch (m_speed_class)
|
||||||
|
@ -68,25 +65,27 @@ namespace Kernel
|
||||||
auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 1 * context_size);
|
auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 1 * context_size);
|
||||||
auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size);
|
auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size);
|
||||||
|
|
||||||
memset(&input_control_context, 0, context_size);
|
input_control_context.add_context_flags = (1 << 1) | (1 << 0);
|
||||||
input_control_context.add_context_flags = 0b11;
|
|
||||||
|
|
||||||
memset(&slot_context, 0, context_size);
|
slot_context.route_string = m_info.route_string >> 4;
|
||||||
slot_context.route_string = 0;
|
slot_context.root_hub_port_number = m_info.route_string & 0x0F;
|
||||||
slot_context.root_hub_port_number = m_port_id;
|
|
||||||
slot_context.context_entries = 1;
|
slot_context.context_entries = 1;
|
||||||
slot_context.interrupter_target = 0;
|
slot_context.interrupter_target = 0;
|
||||||
slot_context.speed = speed_id;
|
slot_context.speed = m_controller.speed_class_to_id(m_info.speed_class);
|
||||||
// FIXME: 4.5.2 hub
|
// FIXME: 4.5.2 hub
|
||||||
|
|
||||||
memset(&endpoint0_context, 0, context_size);
|
|
||||||
endpoint0_context.endpoint_type = XHCI::EndpointType::Control;
|
endpoint0_context.endpoint_type = XHCI::EndpointType::Control;
|
||||||
endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size;
|
endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size;
|
||||||
endpoint0_context.error_count = 3;
|
endpoint0_context.max_burst_size = 0; // FIXME: SuperSpeed
|
||||||
|
endpoint0_context.interval = 0;
|
||||||
endpoint0_context.tr_dequeue_pointer = m_endpoints[0].transfer_ring->paddr() | 1;
|
endpoint0_context.tr_dequeue_pointer = m_endpoints[0].transfer_ring->paddr() | 1;
|
||||||
|
endpoint0_context.max_primary_streams = 0;
|
||||||
|
endpoint0_context.error_count = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_controller.dcbaa_reg(m_slot_id) = m_output_context->paddr();
|
m_controller.dcbaa_reg(m_info.slot_id) = m_output_context->paddr();
|
||||||
|
|
||||||
|
dprintln_if(DEBUG_XHCI, "Addressing device on slot {}", m_info.slot_id);
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
|
@ -95,7 +94,7 @@ namespace Kernel
|
||||||
address_device.address_device_command.input_context_pointer = m_input_context->paddr();
|
address_device.address_device_command.input_context_pointer = m_input_context->paddr();
|
||||||
// NOTE: some legacy devices require sending request with BSR=1 before actual BSR=0
|
// NOTE: some legacy devices require sending request with BSR=1 before actual BSR=0
|
||||||
address_device.address_device_command.block_set_address_request = (i == 0);
|
address_device.address_device_command.block_set_address_request = (i == 0);
|
||||||
address_device.address_device_command.slot_id = m_slot_id;
|
address_device.address_device_command.slot_id = m_info.slot_id;
|
||||||
TRY(m_controller.send_command(address_device));
|
TRY(m_controller.send_command(address_device));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,12 +115,12 @@ namespace Kernel
|
||||||
USBDeviceRequest request;
|
USBDeviceRequest request;
|
||||||
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
|
request.bmRequestType = USB::RequestType::DeviceToHost | USB::RequestType::Standard | USB::RequestType::Device;
|
||||||
request.bRequest = USB::Request::GET_DESCRIPTOR;
|
request.bRequest = USB::Request::GET_DESCRIPTOR;
|
||||||
request.wValue = 0x0100;
|
request.wValue = USB::DescriptorType::DEVICE << 8;
|
||||||
request.wIndex = 0;
|
request.wIndex = 0;
|
||||||
request.wLength = 8;
|
request.wLength = 8;
|
||||||
TRY(send_request(request, kmalloc_paddr_of((vaddr_t)buffer.data()).value()));
|
TRY(send_request(request, kmalloc_paddr_of((vaddr_t)buffer.data()).value()));
|
||||||
|
|
||||||
const bool is_usb3 = m_controller.port(m_port_id).revision_major == 3;
|
const bool is_usb3 = (m_speed_class == USB::SpeedClass::SuperSpeed);
|
||||||
const uint32_t new_max_packet_size = is_usb3 ? 1u << buffer.back() : buffer.back();
|
const uint32_t new_max_packet_size = is_usb3 ? 1u << buffer.back() : buffer.back();
|
||||||
|
|
||||||
if (m_endpoints[0].max_packet_size == new_max_packet_size)
|
if (m_endpoints[0].max_packet_size == new_max_packet_size)
|
||||||
|
@ -133,31 +132,23 @@ namespace Kernel
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& input_control_context = *reinterpret_cast<XHCI::InputControlContext*>(m_input_context->vaddr() + 0 * context_size);
|
auto& input_control_context = *reinterpret_cast<XHCI::InputControlContext*>(m_input_context->vaddr() + 0 * context_size);
|
||||||
auto& slot_context = *reinterpret_cast<XHCI::SlotContext*> (m_input_context->vaddr() + 1 * context_size);
|
|
||||||
auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size);
|
auto& endpoint0_context = *reinterpret_cast<XHCI::EndpointContext*> (m_input_context->vaddr() + 2 * context_size);
|
||||||
|
|
||||||
memset(&input_control_context, 0, context_size);
|
memset(&input_control_context, 0, context_size);
|
||||||
input_control_context.add_context_flags = 0b11;
|
input_control_context.add_context_flags = (1 << 1);
|
||||||
|
|
||||||
memset(&slot_context, 0, context_size);
|
// Only update max packet size. Other fields should be fine from initial configuration
|
||||||
slot_context.max_exit_latency = 0; // FIXME:
|
endpoint0_context.max_packet_size = new_max_packet_size;
|
||||||
slot_context.interrupter_target = 0;
|
|
||||||
|
|
||||||
memset(&endpoint0_context, 0, context_size);
|
|
||||||
endpoint0_context.endpoint_type = XHCI::EndpointType::Control;
|
|
||||||
endpoint0_context.max_packet_size = m_endpoints[0].max_packet_size;
|
|
||||||
endpoint0_context.error_count = 3;
|
|
||||||
endpoint0_context.tr_dequeue_pointer = m_endpoints[0].transfer_ring->paddr() | 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XHCI::TRB evaluate_context { .address_device_command = {} };
|
XHCI::TRB evaluate_context { .address_device_command = {} };
|
||||||
evaluate_context.address_device_command.trb_type = XHCI::TRBType::EvaluateContextCommand;
|
evaluate_context.address_device_command.trb_type = XHCI::TRBType::EvaluateContextCommand;
|
||||||
evaluate_context.address_device_command.input_context_pointer = m_input_context->paddr();
|
evaluate_context.address_device_command.input_context_pointer = m_input_context->paddr();
|
||||||
evaluate_context.address_device_command.block_set_address_request = 0;
|
evaluate_context.address_device_command.block_set_address_request = 0;
|
||||||
evaluate_context.address_device_command.slot_id = m_slot_id;
|
evaluate_context.address_device_command.slot_id = m_info.slot_id;
|
||||||
TRY(m_controller.send_command(evaluate_context));
|
TRY(m_controller.send_command(evaluate_context));
|
||||||
|
|
||||||
dprintln_if(DEBUG_XHCI, "successfully updated max packet size to {}", m_endpoints[0].max_packet_size);
|
dprintln_if(DEBUG_XHCI, "Updated max packet size to {}", new_max_packet_size);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -282,7 +273,7 @@ namespace Kernel
|
||||||
configure_endpoint.configure_endpoint_command.trb_type = XHCI::TRBType::ConfigureEndpointCommand;
|
configure_endpoint.configure_endpoint_command.trb_type = XHCI::TRBType::ConfigureEndpointCommand;
|
||||||
configure_endpoint.configure_endpoint_command.input_context_pointer = m_input_context->paddr();
|
configure_endpoint.configure_endpoint_command.input_context_pointer = m_input_context->paddr();
|
||||||
configure_endpoint.configure_endpoint_command.deconfigure = 0;
|
configure_endpoint.configure_endpoint_command.deconfigure = 0;
|
||||||
configure_endpoint.configure_endpoint_command.slot_id = m_slot_id;
|
configure_endpoint.configure_endpoint_command.slot_id = m_info.slot_id;
|
||||||
TRY(m_controller.send_command(configure_endpoint));
|
TRY(m_controller.send_command(configure_endpoint));
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -455,7 +446,7 @@ namespace Kernel
|
||||||
|
|
||||||
endpoint.transfer_count = request.wLength;
|
endpoint.transfer_count = request.wLength;
|
||||||
|
|
||||||
m_controller.doorbell_reg(m_slot_id) = 1;
|
m_controller.doorbell_reg(m_info.slot_id) = 1;
|
||||||
|
|
||||||
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000;
|
const uint64_t timeout_ms = SystemTimer::get().ms_since_boot() + 1000;
|
||||||
while ((__atomic_load_n(&completion_trb.raw.dword2, __ATOMIC_SEQ_CST) >> 24) == 0)
|
while ((__atomic_load_n(&completion_trb.raw.dword2, __ATOMIC_SEQ_CST) >> 24) == 0)
|
||||||
|
@ -492,7 +483,7 @@ namespace Kernel
|
||||||
trb.normal.interrupt_on_short_packet = 1;
|
trb.normal.interrupt_on_short_packet = 1;
|
||||||
advance_endpoint_enqueue(endpoint, false);
|
advance_endpoint_enqueue(endpoint, false);
|
||||||
|
|
||||||
m_controller.doorbell_reg(m_slot_id) = endpoint_id;
|
m_controller.doorbell_reg(m_info.slot_id) = endpoint_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHCIDevice::advance_endpoint_enqueue(Endpoint& endpoint, bool chain)
|
void XHCIDevice::advance_endpoint_enqueue(Endpoint& endpoint, bool chain)
|
||||||
|
|
Loading…
Reference in New Issue