diff --git a/kernel/include/kernel/USB/Definitions.h b/kernel/include/kernel/USB/Definitions.h index d36f31df..d70487e7 100644 --- a/kernel/include/kernel/USB/Definitions.h +++ b/kernel/include/kernel/USB/Definitions.h @@ -10,13 +10,20 @@ namespace Kernel { enum class SpeedClass { - None, LowSpeed, FullSpeed, HighSpeed, SuperSpeed, }; + enum class EndpointType + { + Control = 0b00, + Isochronous = 0b01, + Bulk = 0b10, + Interrupt = 0b11, + }; + enum class DeviceBaseClass : uint8_t { CommunicationAndCDCControl = 0x02, diff --git a/kernel/include/kernel/USB/Device.h b/kernel/include/kernel/USB/Device.h index 59a17f27..0cb9fedb 100644 --- a/kernel/include/kernel/USB/Device.h +++ b/kernel/include/kernel/USB/Device.h @@ -53,7 +53,9 @@ namespace Kernel }; public: - USBDevice() = default; + USBDevice(USB::SpeedClass speed_class) + : m_speed_class(speed_class) + {} virtual ~USBDevice() = default; BAN::ErrorOr initialize(); @@ -72,6 +74,9 @@ namespace Kernel private: BAN::ErrorOr parse_configuration(size_t index); + protected: + const USB::SpeedClass m_speed_class; + private: DeviceDescriptor m_descriptor; BAN::UniqPtr m_dma_buffer; diff --git a/kernel/include/kernel/USB/XHCI/Device.h b/kernel/include/kernel/USB/XHCI/Device.h index 8e6e51b8..7e09a004 100644 --- a/kernel/include/kernel/USB/XHCI/Device.h +++ b/kernel/include/kernel/USB/XHCI/Device.h @@ -43,11 +43,7 @@ namespace Kernel BAN::ErrorOr initialize_control_endpoint() override; private: - 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(XHCIController& controller, uint32_t port_id, uint32_t slot_id); ~XHCIDevice(); BAN::ErrorOr update_actual_max_packet_size(); @@ -55,6 +51,8 @@ namespace Kernel void advance_endpoint_enqueue(Endpoint&, bool chain); + static uint64_t calculate_port_bits_per_second(XHCIController&, uint32_t port_id); + private: static constexpr uint32_t m_transfer_ring_trb_count = PAGE_SIZE / sizeof(XHCI::TRB); diff --git a/kernel/kernel/USB/XHCI/Device.cpp b/kernel/kernel/USB/XHCI/Device.cpp index 8437bba3..c7d337af 100644 --- a/kernel/kernel/USB/XHCI/Device.cpp +++ b/kernel/kernel/USB/XHCI/Device.cpp @@ -15,6 +15,21 @@ namespace Kernel return TRY(BAN::UniqPtr::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(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( + BAN::Math::ilog2(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(endpoint_descriptor.bInterval - 1, 0, 15); + return 0; + case USB::SpeedClass::FullSpeed: + if (ep_type == USB::EndpointType::Isochronous) + return BAN::Math::clamp(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( + BAN::Math::ilog2(endpoint_descriptor.bInterval * 8), 3, 10 + ); + return 0; + } + + ASSERT_NOT_REACHED(); + } + BAN::ErrorOr 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 = {} };