Kernel: Set interval and average trb length on configure endpoint
Real controllers seem to require this while spec 4.8.2.4 says that they should be left as zero.
This commit is contained in:
@@ -15,6 +15,21 @@ namespace Kernel
|
||||
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id));
|
||||
}
|
||||
|
||||
|
||||
uint64_t XHCIDevice::calculate_port_bits_per_second(XHCIController& controller, uint32_t port_id)
|
||||
{
|
||||
const uint32_t portsc = controller.operational_regs().ports[port_id - 1].portsc;
|
||||
const uint32_t speed_id = (portsc >> XHCI::PORTSC::PORT_SPEED_SHIFT) & XHCI::PORTSC::PORT_SPEED_MASK;
|
||||
return controller.port(port_id).speed_id_to_speed[speed_id];
|
||||
}
|
||||
|
||||
XHCIDevice::XHCIDevice(XHCIController& controller, uint32_t port_id, uint32_t slot_id)
|
||||
: USBDevice(determine_speed_class(calculate_port_bits_per_second(controller, port_id)))
|
||||
, m_controller(controller)
|
||||
, m_port_id(port_id)
|
||||
, m_slot_id(slot_id)
|
||||
{}
|
||||
|
||||
XHCIDevice::~XHCIDevice()
|
||||
{
|
||||
XHCI::TRB disable_slot { .disable_slot_command {} };
|
||||
@@ -32,11 +47,9 @@ namespace Kernel
|
||||
|
||||
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;
|
||||
const uint32_t bits_per_second = m_controller.port(m_port_id).speed_id_to_speed[speed_id];
|
||||
const auto speed_class = determine_speed_class(bits_per_second);
|
||||
|
||||
m_endpoints[0].max_packet_size = 0;
|
||||
switch (speed_class)
|
||||
switch (m_speed_class)
|
||||
{
|
||||
case USB::SpeedClass::LowSpeed:
|
||||
case USB::SpeedClass::FullSpeed:
|
||||
@@ -97,7 +110,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
// NOTE: Full speed devices can have other max packet sizes than 8
|
||||
if (speed_class == USB::SpeedClass::FullSpeed)
|
||||
if (m_speed_class == USB::SpeedClass::FullSpeed)
|
||||
TRY(update_actual_max_packet_size());
|
||||
|
||||
return {};
|
||||
@@ -155,6 +168,39 @@ namespace Kernel
|
||||
return {};
|
||||
}
|
||||
|
||||
// 6.2.3.6 Interval
|
||||
static uint32_t determine_interval(const USBEndpointDescriptor& endpoint_descriptor, USB::SpeedClass speed_class)
|
||||
{
|
||||
auto ep_type = static_cast<USB::EndpointType>(endpoint_descriptor.bDescriptorType & 0x03);
|
||||
|
||||
switch (speed_class)
|
||||
{
|
||||
case USB::SpeedClass::HighSpeed:
|
||||
// maximum NAK rate
|
||||
if (ep_type == USB::EndpointType::Control || ep_type == USB::EndpointType::Bulk)
|
||||
return (endpoint_descriptor.bInterval == 0) ? 0 : BAN::Math::clamp<uint32_t>(
|
||||
BAN::Math::ilog2<uint32_t>(endpoint_descriptor.bInterval), 0, 15
|
||||
);
|
||||
// fall through
|
||||
case USB::SpeedClass::SuperSpeed:
|
||||
if (ep_type == USB::EndpointType::Isochronous || ep_type == USB::EndpointType::Interrupt)
|
||||
return BAN::Math::clamp<uint32_t>(endpoint_descriptor.bInterval - 1, 0, 15);
|
||||
return 0;
|
||||
case USB::SpeedClass::FullSpeed:
|
||||
if (ep_type == USB::EndpointType::Isochronous)
|
||||
return BAN::Math::clamp<uint32_t>(endpoint_descriptor.bInterval + 2, 3, 18);
|
||||
// fall through
|
||||
case USB::SpeedClass::LowSpeed:
|
||||
if (ep_type == USB::EndpointType::Isochronous || ep_type == USB::EndpointType::Interrupt)
|
||||
return (endpoint_descriptor.bInterval == 0) ? 0 : BAN::Math::clamp<uint32_t>(
|
||||
BAN::Math::ilog2<uint32_t>(endpoint_descriptor.bInterval * 8), 3, 10
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor)
|
||||
{
|
||||
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
|
||||
@@ -195,6 +241,9 @@ namespace Kernel
|
||||
ASSERT((endpoint_descriptor.bmAttributes & 0x03) == 3);
|
||||
ASSERT(m_controller.port(m_port_id).revision_major == 2);
|
||||
|
||||
const uint32_t max_esit_payload = endpoint_context.max_packet_size * (endpoint_context.max_burst_size + 1);
|
||||
const uint32_t interval = determine_interval(endpoint_descriptor, m_speed_class);
|
||||
|
||||
memset(&endpoint_context, 0, context_size);
|
||||
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
|
||||
endpoint_context.max_packet_size = endpoint.max_packet_size;
|
||||
@@ -202,9 +251,10 @@ namespace Kernel
|
||||
endpoint_context.mult = 0;
|
||||
endpoint_context.error_count = 3;
|
||||
endpoint_context.tr_dequeue_pointer = endpoint.transfer_ring->paddr() | 1;
|
||||
const uint32_t max_esit_payload = endpoint_context.max_packet_size * (endpoint_context.max_burst_size + 1);
|
||||
endpoint_context.max_esit_payload_lo = max_esit_payload & 0xFFFF;
|
||||
endpoint_context.max_esit_payload_hi = max_esit_payload >> 16;
|
||||
endpoint_context.average_trb_length = max_esit_payload;
|
||||
endpoint_context.interval = interval;
|
||||
}
|
||||
|
||||
XHCI::TRB configure_endpoint { .configure_endpoint_command = {} };
|
||||
|
||||
Reference in New Issue
Block a user