[Voyageurs] Send GetDescriptor command to the device.
This commit is contained in:
parent
3d7e911045
commit
b0b7e2faff
|
@ -0,0 +1,69 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glacier/memory/shared_ptr.h>
|
||||||
|
#include <mammoth/sync/semaphore.h>
|
||||||
|
#include <mammoth/util/memory_region.h>
|
||||||
|
|
||||||
|
#include "xhci/descriptors.h"
|
||||||
|
#include "xhci/xhci.h"
|
||||||
|
|
||||||
|
template <typename Output>
|
||||||
|
class ReadControlCommand {
|
||||||
|
public:
|
||||||
|
ReadControlCommand() {
|
||||||
|
output_mem_ =
|
||||||
|
mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &output_phys_);
|
||||||
|
}
|
||||||
|
|
||||||
|
XhciTrb SetupTrb() {
|
||||||
|
uint64_t request_type = RequestConstants<Output>::RequestType();
|
||||||
|
uint64_t request = RequestConstants<Output>::Request() << 8;
|
||||||
|
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;
|
||||||
|
return {
|
||||||
|
.parameter = request_type | request | value | index | length,
|
||||||
|
.status = 8,
|
||||||
|
.type_and_cycle = 1 | (1 << 5) | (1 << 6) | (2 << 10),
|
||||||
|
// IN Data Stage
|
||||||
|
.control = 3,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
XhciTrb DataTrb() {
|
||||||
|
return {
|
||||||
|
.parameter = output_phys_,
|
||||||
|
.status = sizeof(Output),
|
||||||
|
.type_and_cycle = 1 | (1 << 5) | (3 << 10),
|
||||||
|
.control = 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
XhciTrb StatusTrb() {
|
||||||
|
return {
|
||||||
|
.parameter = 0,
|
||||||
|
.status = 0,
|
||||||
|
.type_and_cycle = 1 | (1 << 5) | (4 << 10),
|
||||||
|
.control = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Output* AwaitResult() {
|
||||||
|
if (!is_complete_) {
|
||||||
|
semaphore_->Wait();
|
||||||
|
}
|
||||||
|
is_complete_ = true;
|
||||||
|
return reinterpret_cast<Output*>(output_mem_.vaddr());
|
||||||
|
}
|
||||||
|
|
||||||
|
glcr::SharedPtr<mmth::Semaphore> CompletionSemaphore() { return semaphore_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t output_phys_;
|
||||||
|
mmth::OwnedMemoryRegion output_mem_;
|
||||||
|
|
||||||
|
bool is_complete_ = false;
|
||||||
|
glcr::SharedPtr<mmth::Semaphore> semaphore_ =
|
||||||
|
glcr::MakeShared<mmth::Semaphore>();
|
||||||
|
};
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class RequestConstants {
|
||||||
|
public:
|
||||||
|
static uint8_t RequestType();
|
||||||
|
static uint8_t Request();
|
||||||
|
static uint16_t Value();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeviceDescriptor {
|
||||||
|
uint8_t length;
|
||||||
|
uint8_t type;
|
||||||
|
uint16_t usb_spec;
|
||||||
|
uint8_t device_class;
|
||||||
|
uint8_t device_subclass;
|
||||||
|
uint8_t device_protocol;
|
||||||
|
uint8_t max_packet_size_exp;
|
||||||
|
uint16_t vendor_id;
|
||||||
|
uint16_t product_id;
|
||||||
|
uint16_t device_release;
|
||||||
|
uint8_t manufacturer_string_index;
|
||||||
|
uint8_t product_string_index;
|
||||||
|
uint8_t serial_string_index;
|
||||||
|
uint8_t num_configurations;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class RequestConstants<DeviceDescriptor> {
|
||||||
|
public:
|
||||||
|
static uint8_t RequestType() { return 0x80; }
|
||||||
|
static uint8_t Request() { return 0x6; };
|
||||||
|
static uint16_t Value() { return 0x100; };
|
||||||
|
};
|
|
@ -1,11 +1,15 @@
|
||||||
#include "xhci/device_slot.h"
|
#include "xhci/device_slot.h"
|
||||||
|
|
||||||
|
#include <glacier/status/error.h>
|
||||||
|
#include <mammoth/util/debug.h>
|
||||||
|
|
||||||
#include "xhci/trb.h"
|
#include "xhci/trb.h"
|
||||||
|
|
||||||
void DeviceSlot::EnableAndInitializeDataStructures(uint8_t slot_index,
|
void DeviceSlot::EnableAndInitializeDataStructures(
|
||||||
uint64_t* output_context) {
|
uint8_t slot_index, uint64_t* output_context, volatile uint32_t* doorbell) {
|
||||||
enabled_ = true;
|
enabled_ = true;
|
||||||
slot_index_ = slot_index;
|
slot_index_ = slot_index;
|
||||||
|
doorbell_ = doorbell;
|
||||||
|
|
||||||
context_memory_ =
|
context_memory_ =
|
||||||
mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &context_phys_);
|
mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &context_phys_);
|
||||||
|
@ -45,3 +49,17 @@ XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port,
|
||||||
uint8_t DeviceSlot::State() {
|
uint8_t DeviceSlot::State() {
|
||||||
return device_context_->slot_context.address_and_state >> 27;
|
return device_context_->slot_context.address_and_state >> 27;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) {
|
||||||
|
if (endpoint_index != 1) {
|
||||||
|
crash("Transfer complete on non control endpoint", glcr::UNIMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!control_completion_sempahores_.Contains(trb_phys)) {
|
||||||
|
// Skip this if we don't have a semaphore for it (Setup and Transfer Trbs).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
control_completion_sempahores_.at(trb_phys)->Signal();
|
||||||
|
check(control_completion_sempahores_.Delete(trb_phys));
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <glacier/container/hash_map.h>
|
||||||
|
#include <glacier/memory/shared_ptr.h>
|
||||||
#include <glacier/memory/unique_ptr.h>
|
#include <glacier/memory/unique_ptr.h>
|
||||||
|
#include <mammoth/sync/semaphore.h>
|
||||||
|
#include <mammoth/util/debug.h>
|
||||||
#include <mammoth/util/memory_region.h>
|
#include <mammoth/util/memory_region.h>
|
||||||
|
|
||||||
|
#include "xhci/control_command.h"
|
||||||
#include "xhci/trb_ring.h"
|
#include "xhci/trb_ring.h"
|
||||||
#include "xhci/xhci.h"
|
#include "xhci/xhci.h"
|
||||||
|
|
||||||
|
@ -13,17 +18,25 @@ class DeviceSlot {
|
||||||
DeviceSlot(DeviceSlot&&) = delete;
|
DeviceSlot(DeviceSlot&&) = delete;
|
||||||
|
|
||||||
void EnableAndInitializeDataStructures(uint8_t slot_index_,
|
void EnableAndInitializeDataStructures(uint8_t slot_index_,
|
||||||
uint64_t* output_context);
|
uint64_t* output_context,
|
||||||
|
volatile uint32_t* doorbell);
|
||||||
|
|
||||||
XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string,
|
XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string,
|
||||||
uint16_t max_packet_size);
|
uint16_t max_packet_size);
|
||||||
|
|
||||||
|
// Caller must keep the command in scope until it completes.
|
||||||
|
template <typename T>
|
||||||
|
void ExecuteReadControlCommand(ReadControlCommand<T>& command);
|
||||||
|
|
||||||
|
void TransferComplete(uint8_t endpoint_index, uint64_t trb_phys);
|
||||||
|
|
||||||
uint8_t State();
|
uint8_t State();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool enabled_ = false;
|
bool enabled_ = false;
|
||||||
|
|
||||||
uint8_t slot_index_ = 0;
|
uint8_t slot_index_ = 0;
|
||||||
|
volatile uint32_t* doorbell_ = nullptr;
|
||||||
|
|
||||||
uint64_t context_phys_ = 0;
|
uint64_t context_phys_ = 0;
|
||||||
mmth::OwnedMemoryRegion context_memory_;
|
mmth::OwnedMemoryRegion context_memory_;
|
||||||
|
@ -34,4 +47,19 @@ class DeviceSlot {
|
||||||
XhciInputContext* input_context_;
|
XhciInputContext* input_context_;
|
||||||
|
|
||||||
glcr::UniquePtr<TrbRingWriter> control_endpoint_transfer_trb_;
|
glcr::UniquePtr<TrbRingWriter> control_endpoint_transfer_trb_;
|
||||||
|
glcr::HashMap<uint64_t, glcr::SharedPtr<mmth::Semaphore>>
|
||||||
|
control_completion_sempahores_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void DeviceSlot::ExecuteReadControlCommand(ReadControlCommand<T>& command) {
|
||||||
|
control_endpoint_transfer_trb_->EnqueueTrb(command.SetupTrb());
|
||||||
|
control_endpoint_transfer_trb_->EnqueueTrb(command.DataTrb());
|
||||||
|
uint64_t last_phys =
|
||||||
|
control_endpoint_transfer_trb_->EnqueueTrb(command.StatusTrb());
|
||||||
|
// Ring the control endpoint doorbell.
|
||||||
|
*doorbell_ = 1;
|
||||||
|
|
||||||
|
check(control_completion_sempahores_.Insert(last_phys,
|
||||||
|
command.CompletionSemaphore()));
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ enum class TrbType : uint8_t {
|
||||||
NoOpCommand = 23,
|
NoOpCommand = 23,
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
|
Transfer = 32,
|
||||||
CommandCompletion = 33,
|
CommandCompletion = 33,
|
||||||
PortStatusChange = 34,
|
PortStatusChange = 34,
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,13 +29,14 @@ XhciTrb TrbRing::GetTrbFromPhysical(uint64_t address) {
|
||||||
return trb_list_[offset];
|
return trb_list_[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrbRingWriter::EnqueueTrb(const XhciTrb& trb) {
|
uint64_t TrbRingWriter::EnqueueTrb(const XhciTrb& trb) {
|
||||||
uint64_t ptr = enqueue_ptr_++;
|
uint64_t ptr = enqueue_ptr_++;
|
||||||
if (enqueue_ptr_ == trb_list_.size()) {
|
if (enqueue_ptr_ == trb_list_.size()) {
|
||||||
crash("Not implemented: queue wrapping", glcr::UNIMPLEMENTED);
|
crash("Not implemented: queue wrapping", glcr::UNIMPLEMENTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
trb_list_[ptr] = trb;
|
trb_list_[ptr] = trb;
|
||||||
|
return phys_address_ + (ptr * sizeof(uint64_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TrbRingReader::HasNext() {
|
bool TrbRingReader::HasNext() {
|
||||||
|
|
|
@ -20,7 +20,7 @@ class TrbRing {
|
||||||
|
|
||||||
class TrbRingWriter : public TrbRing {
|
class TrbRingWriter : public TrbRing {
|
||||||
public:
|
public:
|
||||||
void EnqueueTrb(const XhciTrb& trb);
|
uint64_t EnqueueTrb(const XhciTrb& trb);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t enqueue_ptr_ = 0;
|
uint64_t enqueue_ptr_ = 0;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#include "xhci/xhci_driver.h"
|
#include "xhci/xhci_driver.h"
|
||||||
|
|
||||||
|
#include <mammoth/proc/thread.h>
|
||||||
#include <mammoth/util/debug.h>
|
#include <mammoth/util/debug.h>
|
||||||
#include <mammoth/util/memory_region.h>
|
#include <mammoth/util/memory_region.h>
|
||||||
#include <zcall.h>
|
#include <zcall.h>
|
||||||
|
|
||||||
|
#include "xhci/descriptors.h"
|
||||||
#include "xhci/trb.h"
|
#include "xhci/trb.h"
|
||||||
#include "xhci/xhci.h"
|
#include "xhci/xhci.h"
|
||||||
|
|
||||||
|
@ -15,6 +17,22 @@ void interrupt_thread(void* void_driver) {
|
||||||
crash("Driver returned from interrupt loop", glcr::INTERNAL);
|
crash("Driver returned from interrupt loop", glcr::INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void configure_device(void* void_device_slot) {
|
||||||
|
DeviceSlot* device_slot = static_cast<DeviceSlot*>(void_device_slot);
|
||||||
|
|
||||||
|
dbgln("Configuring device");
|
||||||
|
|
||||||
|
ReadControlCommand<DeviceDescriptor> command;
|
||||||
|
|
||||||
|
device_slot->ExecuteReadControlCommand(command);
|
||||||
|
|
||||||
|
DeviceDescriptor* descriptor = command.AwaitResult();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
glcr::ErrorOr<glcr::UniquePtr<XhciDriver>> XhciDriver::InitiateDriver(
|
glcr::ErrorOr<glcr::UniquePtr<XhciDriver>> XhciDriver::InitiateDriver(
|
||||||
yellowstone::YellowstoneClient& yellowstone) {
|
yellowstone::YellowstoneClient& yellowstone) {
|
||||||
yellowstone::XhciInfo info;
|
yellowstone::XhciInfo info;
|
||||||
|
@ -43,6 +61,9 @@ void XhciDriver::InterruptLoop() {
|
||||||
while (event_ring_.HasNext()) {
|
while (event_ring_.HasNext()) {
|
||||||
XhciTrb trb = event_ring_.Read();
|
XhciTrb trb = event_ring_.Read();
|
||||||
switch (GetType(trb)) {
|
switch (GetType(trb)) {
|
||||||
|
case TrbType::Transfer:
|
||||||
|
HandleTransferCompletion(trb);
|
||||||
|
break;
|
||||||
case TrbType::CommandCompletion:
|
case TrbType::CommandCompletion:
|
||||||
HandleCommandCompletion(trb);
|
HandleCommandCompletion(trb);
|
||||||
break;
|
break;
|
||||||
|
@ -52,6 +73,7 @@ void XhciDriver::InterruptLoop() {
|
||||||
command_ring_.EnqueueTrb(CreateEnableSlotTrb());
|
command_ring_.EnqueueTrb(CreateEnableSlotTrb());
|
||||||
doorbells_->doorbell[0] = 0;
|
doorbells_->doorbell[0] = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dbgln("Unknown TRB Type {x} received.", (uint8_t)GetType(trb));
|
dbgln("Unknown TRB Type {x} received.", (uint8_t)GetType(trb));
|
||||||
break;
|
break;
|
||||||
|
@ -132,6 +154,7 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() {
|
||||||
|
|
||||||
doorbells_ = reinterpret_cast<XhciDoorbells*>(mmio_regions_.vaddr() +
|
doorbells_ = reinterpret_cast<XhciDoorbells*>(mmio_regions_.vaddr() +
|
||||||
capabilities_->doorbell_offset);
|
capabilities_->doorbell_offset);
|
||||||
|
dbgln("Doorbells: {x}", (uint64_t)doorbells_);
|
||||||
|
|
||||||
return glcr::OK;
|
return glcr::OK;
|
||||||
}
|
}
|
||||||
|
@ -265,6 +288,7 @@ void XhciDriver::HandleCommandCompletion(
|
||||||
case TrbType::AddressDevice:
|
case TrbType::AddressDevice:
|
||||||
dbgln("Device Addressed: {x}", slot);
|
dbgln("Device Addressed: {x}", slot);
|
||||||
dbgln("State: {x}", devices_[slot - 1].State());
|
dbgln("State: {x}", devices_[slot - 1].State());
|
||||||
|
Thread(configure_device, &devices_[slot - 1]);
|
||||||
break;
|
break;
|
||||||
case TrbType::NoOpCommand:
|
case TrbType::NoOpCommand:
|
||||||
dbgln("No-op Command Completed");
|
dbgln("No-op Command Completed");
|
||||||
|
@ -275,10 +299,18 @@ void XhciDriver::HandleCommandCompletion(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) {
|
||||||
|
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;
|
||||||
|
devices_[slot_id - 1].TransferComplete(endpoint_id, trb_phys);
|
||||||
|
}
|
||||||
|
|
||||||
void XhciDriver::InitializeSlot(uint8_t slot_index) {
|
void XhciDriver::InitializeSlot(uint8_t slot_index) {
|
||||||
// TODO: Consider making this array one longer and ignore the first value.
|
// TODO: Consider making this array one longer and ignore the first value.
|
||||||
devices_[slot_index - 1].EnableAndInitializeDataStructures(
|
devices_[slot_index - 1].EnableAndInitializeDataStructures(
|
||||||
slot_index, &(device_context_base_array_[slot_index]));
|
slot_index, &(device_context_base_array_[slot_index]),
|
||||||
|
&doorbells_->doorbell[slot_index]);
|
||||||
XhciPort* port =
|
XhciPort* port =
|
||||||
reinterpret_cast<XhciPort*>(reinterpret_cast<uint64_t>(operational_) +
|
reinterpret_cast<XhciPort*>(reinterpret_cast<uint64_t>(operational_) +
|
||||||
0x400 + (0x10 * (slot_index - 1)));
|
0x400 + (0x10 * (slot_index - 1)));
|
||||||
|
|
|
@ -66,6 +66,7 @@ class XhciDriver {
|
||||||
glcr::ErrorCode NoOpCommand();
|
glcr::ErrorCode NoOpCommand();
|
||||||
|
|
||||||
void HandleCommandCompletion(const XhciTrb& command_completion_trb);
|
void HandleCommandCompletion(const XhciTrb& command_completion_trb);
|
||||||
|
void HandleTransferCompletion(const XhciTrb& transfer_event_trb);
|
||||||
|
|
||||||
void InitializeSlot(uint8_t slot_index);
|
void InitializeSlot(uint8_t slot_index);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue