Compare commits
5 Commits
b0b7e2faff
...
e6b232851e
Author | SHA1 | Date |
---|---|---|
|
e6b232851e | |
|
c5f8195255 | |
|
2cc9c89051 | |
|
af69415d4d | |
|
39b6d32d86 |
|
@ -1,6 +1,7 @@
|
|||
add_executable(voyageurs
|
||||
keyboard/keyboard_driver.cpp
|
||||
xhci/device_slot.cpp
|
||||
xhci/endpoint.cpp
|
||||
xhci/trb.cpp
|
||||
xhci/trb_ring.cpp
|
||||
xhci/xhci_driver.cpp
|
||||
|
|
|
@ -21,7 +21,7 @@ class ReadControlCommand {
|
|||
uint64_t value = RequestConstants<Output>::Value() << 16;
|
||||
// TODO: May need to be non-0 for string descriptors.
|
||||
uint64_t index = (uint64_t)0 << 32;
|
||||
uint64_t length = sizeof(Output) << 48;
|
||||
uint64_t length = (uint64_t)0x1000 << 48;
|
||||
return {
|
||||
.parameter = request_type | request | value | index | length,
|
||||
.status = 8,
|
||||
|
@ -34,7 +34,7 @@ class ReadControlCommand {
|
|||
XhciTrb DataTrb() {
|
||||
return {
|
||||
.parameter = output_phys_,
|
||||
.status = sizeof(Output),
|
||||
.status = 0x1000,
|
||||
.type_and_cycle = 1 | (1 << 5) | (3 << 10),
|
||||
.control = 1,
|
||||
};
|
||||
|
|
|
@ -34,3 +34,44 @@ class RequestConstants<DeviceDescriptor> {
|
|||
static uint8_t Request() { return 0x6; };
|
||||
static uint16_t Value() { return 0x100; };
|
||||
};
|
||||
|
||||
struct ConfigurationDescriptor {
|
||||
uint8_t length;
|
||||
uint8_t type;
|
||||
uint16_t total_length;
|
||||
uint8_t num_interfaces;
|
||||
uint8_t configuration_value;
|
||||
uint8_t configuration_string_index;
|
||||
uint8_t attributes;
|
||||
uint8_t max_power;
|
||||
} __attribute__((packed));
|
||||
|
||||
template <>
|
||||
class RequestConstants<ConfigurationDescriptor> {
|
||||
public:
|
||||
static uint8_t RequestType() { return 0x80; }
|
||||
static uint8_t Request() { return 0x6; }
|
||||
// TODO: Consider getting other description indexes.
|
||||
static uint16_t Value() { return 0x200; }
|
||||
};
|
||||
|
||||
struct InterfaceDescriptor {
|
||||
uint8_t length;
|
||||
uint8_t type;
|
||||
uint8_t interface_number;
|
||||
uint8_t alternate_setting;
|
||||
uint8_t num_endpoints;
|
||||
uint8_t interface_class;
|
||||
uint8_t interface_subclass;
|
||||
uint8_t interface_protocol;
|
||||
uint8_t interfact_string_index;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct EndpointDescriptor {
|
||||
uint8_t length;
|
||||
uint8_t type;
|
||||
uint8_t endpoint_address;
|
||||
uint8_t attributes;
|
||||
uint16_t max_packet_size;
|
||||
uint8_t interval;
|
||||
} __attribute__((packed));
|
||||
|
|
|
@ -4,10 +4,13 @@
|
|||
#include <mammoth/util/debug.h>
|
||||
|
||||
#include "xhci/trb.h"
|
||||
#include "xhci/xhci_driver.h"
|
||||
|
||||
void DeviceSlot::EnableAndInitializeDataStructures(
|
||||
uint8_t slot_index, uint64_t* output_context, volatile uint32_t* doorbell) {
|
||||
XhciDriver* driver, uint8_t slot_index, uint64_t* output_context,
|
||||
volatile uint32_t* doorbell) {
|
||||
enabled_ = true;
|
||||
xhci_driver_ = driver;
|
||||
slot_index_ = slot_index;
|
||||
doorbell_ = doorbell;
|
||||
|
||||
|
@ -42,6 +45,8 @@ XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port,
|
|||
input_context_->endpoint_contexts[0].tr_dequeue_ptr =
|
||||
control_endpoint_transfer_trb_->PhysicalAddress() | 0x1;
|
||||
|
||||
endpoints_ = glcr::Array<Endpoint>(32);
|
||||
|
||||
return ::CreateAddressDeviceCommand(context_phys_ + kInputSlotContextOffset,
|
||||
slot_index_);
|
||||
}
|
||||
|
@ -51,8 +56,19 @@ uint8_t DeviceSlot::State() {
|
|||
}
|
||||
|
||||
void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) {
|
||||
if (endpoint_index >= 32) {
|
||||
dbgln("ERROR: Received transfer for invalid endpoint {x}", endpoint_index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (endpoint_index != 1) {
|
||||
crash("Transfer complete on non control endpoint", glcr::UNIMPLEMENTED);
|
||||
if (!endpoints_[endpoint_index].Enabled()) {
|
||||
dbgln("ERROR: XHCI received transfer for disabled endpoint {x}",
|
||||
endpoint_index);
|
||||
return;
|
||||
}
|
||||
endpoints_[endpoint_index].TransferComplete(trb_phys);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!control_completion_sempahores_.Contains(trb_phys)) {
|
||||
|
@ -63,3 +79,27 @@ void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) {
|
|||
control_completion_sempahores_.at(trb_phys)->Signal();
|
||||
check(control_completion_sempahores_.Delete(trb_phys));
|
||||
}
|
||||
|
||||
mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand(uint8_t config_value) {
|
||||
input_context_->input.add_contexts = (0x1 << 3) | 0x1;
|
||||
input_context_->input.configuration_value = config_value;
|
||||
// TODO: Maybe don't hardcode this.
|
||||
input_context_->input.interface_number = 0;
|
||||
|
||||
input_context_->slot_context.route_speed_entries &= 0xFFFFFF;
|
||||
|
||||
// TODO: Don't hardcode this.
|
||||
uint8_t max_endpoint = 0x3;
|
||||
input_context_->slot_context.route_speed_entries |= (max_endpoint << 27);
|
||||
|
||||
// TODO: Dont' hardcode this.
|
||||
endpoints_[3].Initialize(input_context_->endpoint_contexts + 2);
|
||||
|
||||
xhci_driver_->IssueCommand(CreateConfigureEndpointCommand(
|
||||
context_phys_ + kInputSlotContextOffset, slot_index_));
|
||||
return configure_device_semaphore_;
|
||||
}
|
||||
|
||||
void DeviceSlot::SignalConfigureDeviceCompleted() {
|
||||
configure_device_semaphore_.Signal();
|
||||
}
|
||||
|
|
|
@ -8,22 +8,29 @@
|
|||
#include <mammoth/util/memory_region.h>
|
||||
|
||||
#include "xhci/control_command.h"
|
||||
#include "xhci/endpoint.h"
|
||||
#include "xhci/trb_ring.h"
|
||||
#include "xhci/xhci.h"
|
||||
|
||||
class XhciDriver;
|
||||
|
||||
class DeviceSlot {
|
||||
public:
|
||||
DeviceSlot() = default;
|
||||
DeviceSlot(const DeviceSlot&) = delete;
|
||||
DeviceSlot(DeviceSlot&&) = delete;
|
||||
|
||||
void EnableAndInitializeDataStructures(uint8_t slot_index_,
|
||||
void EnableAndInitializeDataStructures(XhciDriver* driver,
|
||||
uint8_t slot_index_,
|
||||
uint64_t* output_context,
|
||||
volatile uint32_t* doorbell);
|
||||
|
||||
XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string,
|
||||
uint16_t max_packet_size);
|
||||
|
||||
mmth::Semaphore IssueConfigureDeviceCommand(uint8_t config_value);
|
||||
void SignalConfigureDeviceCompleted();
|
||||
|
||||
// Caller must keep the command in scope until it completes.
|
||||
template <typename T>
|
||||
void ExecuteReadControlCommand(ReadControlCommand<T>& command);
|
||||
|
@ -35,6 +42,7 @@ class DeviceSlot {
|
|||
private:
|
||||
bool enabled_ = false;
|
||||
|
||||
XhciDriver* xhci_driver_;
|
||||
uint8_t slot_index_ = 0;
|
||||
volatile uint32_t* doorbell_ = nullptr;
|
||||
|
||||
|
@ -49,6 +57,10 @@ class DeviceSlot {
|
|||
glcr::UniquePtr<TrbRingWriter> control_endpoint_transfer_trb_;
|
||||
glcr::HashMap<uint64_t, glcr::SharedPtr<mmth::Semaphore>>
|
||||
control_completion_sempahores_;
|
||||
|
||||
mmth::Semaphore configure_device_semaphore_;
|
||||
|
||||
glcr::Array<Endpoint> endpoints_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#include "xhci/endpoint.h"
|
||||
|
||||
#include <mammoth/util/debug.h>
|
||||
|
||||
void Endpoint::Initialize(XhciEndpointContext* context) {
|
||||
enabled_ = true;
|
||||
context_ = context;
|
||||
|
||||
trb_ring_ = glcr::MakeUnique<TrbRingWriter>();
|
||||
recv_mem_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &recv_phys_);
|
||||
|
||||
context_->tr_dequeue_ptr = trb_ring_->PhysicalAddress() | 1;
|
||||
|
||||
context_->error_and_type = (0x3 << 1) | (0x7 << 3) | (0x8 << 16);
|
||||
for (uint64_t i = 0; i < 10; i++) {
|
||||
trb_ring_->EnqueueTrb({
|
||||
.parameter = recv_phys_ + offset_,
|
||||
.status = 8,
|
||||
.type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10),
|
||||
.control = 0,
|
||||
});
|
||||
offset_ += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void Endpoint::TransferComplete(uint64_t trb_phys) {
|
||||
uint64_t phys_offset =
|
||||
(trb_phys - trb_ring_->PhysicalAddress()) / sizeof(XhciTrb);
|
||||
dbgln("Data: {x}", *((uint64_t*)recv_mem_.vaddr() + phys_offset));
|
||||
trb_ring_->EnqueueTrb({
|
||||
.parameter = recv_phys_ + offset_,
|
||||
.status = 8,
|
||||
.type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10),
|
||||
.control = 0,
|
||||
});
|
||||
offset_ += 8;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <glacier/memory/unique_ptr.h>
|
||||
|
||||
#include "xhci/trb_ring.h"
|
||||
#include "xhci/xhci.h"
|
||||
|
||||
class Endpoint {
|
||||
public:
|
||||
Endpoint() {}
|
||||
|
||||
void Initialize(XhciEndpointContext* context);
|
||||
|
||||
bool Enabled() { return enabled_; }
|
||||
|
||||
void TransferComplete(uint64_t trb_phys);
|
||||
|
||||
private:
|
||||
bool enabled_ = false;
|
||||
|
||||
XhciEndpointContext* context_ = nullptr;
|
||||
glcr::UniquePtr<TrbRingWriter> trb_ring_;
|
||||
|
||||
uint64_t recv_phys_;
|
||||
mmth::OwnedMemoryRegion recv_mem_;
|
||||
uint64_t offset_ = 0;
|
||||
};
|
|
@ -49,6 +49,17 @@ XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id) {
|
|||
};
|
||||
}
|
||||
|
||||
XhciTrb CreateConfigureEndpointCommand(uint64_t input_context,
|
||||
uint8_t slot_id) {
|
||||
return {
|
||||
.parameter = input_context,
|
||||
.status = 0,
|
||||
.type_and_cycle =
|
||||
(uint16_t)(TypeToInt(TrbType::ConfigureEndpoint) | kTrb_Cycle),
|
||||
.control = (uint16_t)(slot_id << 8),
|
||||
};
|
||||
}
|
||||
|
||||
XhciTrb CreateNoOpCommandTrb() {
|
||||
return {
|
||||
.parameter = 0,
|
||||
|
|
|
@ -18,6 +18,7 @@ enum class TrbType : uint8_t {
|
|||
// Commands
|
||||
EnableSlot = 9,
|
||||
AddressDevice = 11,
|
||||
ConfigureEndpoint = 12,
|
||||
NoOpCommand = 23,
|
||||
|
||||
// Events
|
||||
|
@ -32,4 +33,5 @@ XhciTrb CreateLinkTrb(uint64_t physical_address);
|
|||
|
||||
XhciTrb CreateEnableSlotTrb();
|
||||
XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id);
|
||||
XhciTrb CreateConfigureEndpointCommand(uint64_t input_context, uint8_t slot_id);
|
||||
XhciTrb CreateNoOpCommandTrb();
|
||||
|
|
|
@ -36,7 +36,7 @@ uint64_t TrbRingWriter::EnqueueTrb(const XhciTrb& trb) {
|
|||
}
|
||||
|
||||
trb_list_[ptr] = trb;
|
||||
return phys_address_ + (ptr * sizeof(uint64_t));
|
||||
return phys_address_ + (ptr * sizeof(XhciTrb));
|
||||
}
|
||||
|
||||
bool TrbRingReader::HasNext() {
|
||||
|
|
|
@ -31,6 +31,54 @@ void configure_device(void* void_device_slot) {
|
|||
dbgln("Descriptor Type {x}, ({x})", descriptor->type, descriptor->usb_spec);
|
||||
dbgln("Device Class/Sub/Protocol: {x}/{x}/{x}", descriptor->device_class,
|
||||
descriptor->device_subclass, descriptor->device_protocol);
|
||||
dbgln("Num Configurations: {}", descriptor->num_configurations);
|
||||
|
||||
ReadControlCommand<ConfigurationDescriptor> config_command;
|
||||
|
||||
device_slot->ExecuteReadControlCommand(config_command);
|
||||
|
||||
ConfigurationDescriptor* config_descriptor = config_command.AwaitResult();
|
||||
|
||||
dbgln("Configuration Value: {x}", config_descriptor->configuration_value);
|
||||
dbgln("Num Interfaces: {x}", config_descriptor->num_interfaces);
|
||||
dbgln("Size: {x}, Total Length: {x}", config_descriptor->length,
|
||||
config_descriptor->total_length);
|
||||
|
||||
uint64_t next_vaddr =
|
||||
reinterpret_cast<uint64_t>(config_descriptor) + config_descriptor->length;
|
||||
for (auto i = config_descriptor->num_interfaces; i > 0; i--) {
|
||||
InterfaceDescriptor* interface =
|
||||
reinterpret_cast<InterfaceDescriptor*>(next_vaddr);
|
||||
dbgln("Interface: {x}", interface->interface_number);
|
||||
dbgln("Interface Class/Sub/Protocol: {x}/{x}/{x}",
|
||||
interface->interface_class, interface->interface_subclass,
|
||||
interface->interface_protocol);
|
||||
dbgln("Num Endpoints: {x}", interface->num_endpoints);
|
||||
|
||||
next_vaddr += interface->length;
|
||||
for (auto j = interface->num_endpoints; j > 0; j--) {
|
||||
EndpointDescriptor* endpoint =
|
||||
reinterpret_cast<EndpointDescriptor*>(next_vaddr);
|
||||
if (endpoint->type != 5) {
|
||||
dbgln("Descriptor type {x}, skipping", endpoint->type);
|
||||
j++;
|
||||
next_vaddr += endpoint->length;
|
||||
continue;
|
||||
}
|
||||
dbgln("Endpoint Addr: {x}", endpoint->endpoint_address);
|
||||
dbgln("Endpoint Attr: {x}", endpoint->attributes);
|
||||
next_vaddr += endpoint->length;
|
||||
}
|
||||
}
|
||||
|
||||
dbgln("---- Configuring with configuration: {x}",
|
||||
config_descriptor->configuration_value);
|
||||
|
||||
device_slot
|
||||
->IssueConfigureDeviceCommand(config_descriptor->configuration_value)
|
||||
.Wait();
|
||||
|
||||
dbgln("Configured!");
|
||||
}
|
||||
|
||||
glcr::ErrorOr<glcr::UniquePtr<XhciDriver>> XhciDriver::InitiateDriver(
|
||||
|
@ -130,6 +178,11 @@ void XhciDriver::DumpDebugInfo() {
|
|||
runtime_->interrupters[0].event_ring_segment_table_base_address);
|
||||
}
|
||||
|
||||
void XhciDriver::IssueCommand(const XhciTrb& command) {
|
||||
command_ring_.EnqueueTrb(command);
|
||||
doorbells_->doorbell[0] = 0;
|
||||
}
|
||||
|
||||
XhciDriver::XhciDriver(mmth::OwnedMemoryRegion&& pci_space)
|
||||
: pci_region_(glcr::Move(pci_space)) {}
|
||||
|
||||
|
@ -152,6 +205,8 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() {
|
|||
runtime_ = reinterpret_cast<XhciRuntime*>(mmio_regions_.vaddr() +
|
||||
capabilities_->runtime_offset);
|
||||
|
||||
dbgln("INTTTT: {x}", (uint64_t)runtime_->interrupters);
|
||||
|
||||
doorbells_ = reinterpret_cast<XhciDoorbells*>(mmio_regions_.vaddr() +
|
||||
capabilities_->doorbell_offset);
|
||||
dbgln("Doorbells: {x}", (uint64_t)doorbells_);
|
||||
|
@ -290,6 +345,11 @@ void XhciDriver::HandleCommandCompletion(
|
|||
dbgln("State: {x}", devices_[slot - 1].State());
|
||||
Thread(configure_device, &devices_[slot - 1]);
|
||||
break;
|
||||
case TrbType::ConfigureEndpoint:
|
||||
dbgln("Device COnfigured: {x}", slot);
|
||||
dbgln("State: {x}", devices_[slot - 1].State());
|
||||
devices_[slot - 1].SignalConfigureDeviceCompleted();
|
||||
break;
|
||||
case TrbType::NoOpCommand:
|
||||
dbgln("No-op Command Completed");
|
||||
break;
|
||||
|
@ -300,6 +360,11 @@ void XhciDriver::HandleCommandCompletion(
|
|||
}
|
||||
|
||||
void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) {
|
||||
uint8_t status = transfer_event_trb.status >> 24;
|
||||
if (status != 1 && status != 0xD) {
|
||||
dbgln("Unexpected Status {x}", status);
|
||||
return;
|
||||
}
|
||||
uint8_t slot_id = transfer_event_trb.control >> 8;
|
||||
uint8_t endpoint_id = transfer_event_trb.control & 0x1F;
|
||||
uint64_t trb_phys = transfer_event_trb.parameter;
|
||||
|
@ -309,7 +374,7 @@ void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) {
|
|||
void XhciDriver::InitializeSlot(uint8_t slot_index) {
|
||||
// TODO: Consider making this array one longer and ignore the first value.
|
||||
devices_[slot_index - 1].EnableAndInitializeDataStructures(
|
||||
slot_index, &(device_context_base_array_[slot_index]),
|
||||
this, slot_index, &(device_context_base_array_[slot_index]),
|
||||
&doorbells_->doorbell[slot_index]);
|
||||
XhciPort* port =
|
||||
reinterpret_cast<XhciPort*>(reinterpret_cast<uint64_t>(operational_) +
|
||||
|
|
|
@ -23,6 +23,8 @@ class XhciDriver {
|
|||
|
||||
void InterruptLoop();
|
||||
|
||||
void IssueCommand(const XhciTrb& command);
|
||||
|
||||
private:
|
||||
// MMIO Structures.
|
||||
mmth::OwnedMemoryRegion pci_region_;
|
||||
|
|
Loading…
Reference in New Issue