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:
parent
86e9d92ecb
commit
75875d3a8f
|
@ -10,13 +10,20 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
enum class SpeedClass
|
enum class SpeedClass
|
||||||
{
|
{
|
||||||
None,
|
|
||||||
LowSpeed,
|
LowSpeed,
|
||||||
FullSpeed,
|
FullSpeed,
|
||||||
HighSpeed,
|
HighSpeed,
|
||||||
SuperSpeed,
|
SuperSpeed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EndpointType
|
||||||
|
{
|
||||||
|
Control = 0b00,
|
||||||
|
Isochronous = 0b01,
|
||||||
|
Bulk = 0b10,
|
||||||
|
Interrupt = 0b11,
|
||||||
|
};
|
||||||
|
|
||||||
enum class DeviceBaseClass : uint8_t
|
enum class DeviceBaseClass : uint8_t
|
||||||
{
|
{
|
||||||
CommunicationAndCDCControl = 0x02,
|
CommunicationAndCDCControl = 0x02,
|
||||||
|
|
|
@ -53,7 +53,9 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
USBDevice() = default;
|
USBDevice(USB::SpeedClass speed_class)
|
||||||
|
: m_speed_class(speed_class)
|
||||||
|
{}
|
||||||
virtual ~USBDevice() = default;
|
virtual ~USBDevice() = default;
|
||||||
|
|
||||||
BAN::ErrorOr<void> initialize();
|
BAN::ErrorOr<void> initialize();
|
||||||
|
@ -72,6 +74,9 @@ namespace Kernel
|
||||||
private:
|
private:
|
||||||
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
|
BAN::ErrorOr<ConfigurationDescriptor> parse_configuration(size_t index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const USB::SpeedClass m_speed_class;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeviceDescriptor m_descriptor;
|
DeviceDescriptor m_descriptor;
|
||||||
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
BAN::UniqPtr<DMARegion> m_dma_buffer;
|
||||||
|
|
|
@ -43,11 +43,7 @@ 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, uint32_t port_id, uint32_t slot_id);
|
||||||
: m_controller(controller)
|
|
||||||
, m_port_id(port_id)
|
|
||||||
, m_slot_id(slot_id)
|
|
||||||
{}
|
|
||||||
~XHCIDevice();
|
~XHCIDevice();
|
||||||
BAN::ErrorOr<void> update_actual_max_packet_size();
|
BAN::ErrorOr<void> update_actual_max_packet_size();
|
||||||
|
|
||||||
|
@ -55,6 +51,8 @@ namespace Kernel
|
||||||
|
|
||||||
void advance_endpoint_enqueue(Endpoint&, bool chain);
|
void advance_endpoint_enqueue(Endpoint&, bool chain);
|
||||||
|
|
||||||
|
static uint64_t calculate_port_bits_per_second(XHCIController&, uint32_t port_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,21 @@ namespace Kernel
|
||||||
return TRY(BAN::UniqPtr<XHCIDevice>::create(controller, port_id, slot_id));
|
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()
|
XHCIDevice::~XHCIDevice()
|
||||||
{
|
{
|
||||||
XHCI::TRB disable_slot { .disable_slot_command {} };
|
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 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 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;
|
m_endpoints[0].max_packet_size = 0;
|
||||||
switch (speed_class)
|
switch (m_speed_class)
|
||||||
{
|
{
|
||||||
case USB::SpeedClass::LowSpeed:
|
case USB::SpeedClass::LowSpeed:
|
||||||
case USB::SpeedClass::FullSpeed:
|
case USB::SpeedClass::FullSpeed:
|
||||||
|
@ -97,7 +110,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Full speed devices can have other max packet sizes than 8
|
// 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());
|
TRY(update_actual_max_packet_size());
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -155,6 +168,39 @@ namespace Kernel
|
||||||
return {};
|
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)
|
BAN::ErrorOr<void> XHCIDevice::initialize_endpoint(const USBEndpointDescriptor& endpoint_descriptor)
|
||||||
{
|
{
|
||||||
const uint32_t endpoint_id = (endpoint_descriptor.bEndpointAddress & 0x0F) * 2 + !!(endpoint_descriptor.bEndpointAddress & 0x80);
|
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((endpoint_descriptor.bmAttributes & 0x03) == 3);
|
||||||
ASSERT(m_controller.port(m_port_id).revision_major == 2);
|
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);
|
memset(&endpoint_context, 0, context_size);
|
||||||
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
|
endpoint_context.endpoint_type = XHCI::EndpointType::InterruptIn;
|
||||||
endpoint_context.max_packet_size = endpoint.max_packet_size;
|
endpoint_context.max_packet_size = endpoint.max_packet_size;
|
||||||
|
@ -202,9 +251,10 @@ namespace Kernel
|
||||||
endpoint_context.mult = 0;
|
endpoint_context.mult = 0;
|
||||||
endpoint_context.error_count = 3;
|
endpoint_context.error_count = 3;
|
||||||
endpoint_context.tr_dequeue_pointer = endpoint.transfer_ring->paddr() | 1;
|
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_lo = max_esit_payload & 0xFFFF;
|
||||||
endpoint_context.max_esit_payload_hi = max_esit_payload >> 16;
|
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 = {} };
|
XHCI::TRB configure_endpoint { .configure_endpoint_command = {} };
|
||||||
|
|
Loading…
Reference in New Issue