Compare commits
11 Commits
8e624ca85a
...
076001462e
Author | SHA1 | Date |
---|---|---|
Bananymous | 076001462e | |
Bananymous | d2e1d8ec13 | |
Bananymous | 30ceaa6bef | |
Bananymous | 0247d47a3d | |
Bananymous | 480368c878 | |
Bananymous | c1d8790623 | |
Bananymous | fb1ffec5bb | |
Bananymous | 1bdabe693f | |
Bananymous | ce09f35275 | |
Bananymous | 40c13043b3 | |
Bananymous | e620068416 |
|
@ -0,0 +1,124 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/ParseContext.h>
|
||||
#include <kernel/ACPI/AML/String.h>
|
||||
|
||||
namespace Kernel::ACPI::AML
|
||||
{
|
||||
|
||||
struct Concat
|
||||
{
|
||||
static ParseResult parse(ParseContext& context)
|
||||
{
|
||||
ASSERT(context.aml_data.size() >= 1);
|
||||
ASSERT(static_cast<Byte>(context.aml_data[0]) == Byte::ConcatOp);
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
||||
auto source1_result = AML::parse_object(context);
|
||||
if (!source1_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source1 = source1_result.node() ? source1_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
|
||||
|
||||
auto source2_result = AML::parse_object(context);
|
||||
if (!source2_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source2 = source1_result.node() ? source1_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
|
||||
|
||||
if (!source1 || !source2)
|
||||
{
|
||||
AML_ERROR("ConcatOp sources could not be parsed");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
switch (source1->type)
|
||||
{
|
||||
case AML::Node::Type::Integer:
|
||||
source1 = source1->convert(AML::Node::ConvBuffer);
|
||||
source2 = source2->convert(AML::Node::ConvBuffer);
|
||||
break;
|
||||
case AML::Node::Type::String:
|
||||
source2 = source2->convert(AML::Node::ConvString);
|
||||
break;
|
||||
case AML::Node::Type::Buffer:
|
||||
source2 = source2->convert(AML::Node::ConvBuffer);
|
||||
break;
|
||||
default:
|
||||
source1 = source1->convert(AML::Node::ConvString);
|
||||
source2 = source2->convert(AML::Node::ConvString);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!source1 || !source2)
|
||||
{
|
||||
AML_ERROR("ConcatOp sources could not be converted");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
ASSERT(source1->type == source2->type);
|
||||
|
||||
BAN::RefPtr<AML::Node> result;
|
||||
BAN::Vector<uint8_t>* result_data = nullptr;
|
||||
BAN::Vector<uint8_t>* source1_data = nullptr;
|
||||
BAN::Vector<uint8_t>* source2_data = nullptr;
|
||||
|
||||
switch (source1->type)
|
||||
{
|
||||
case AML::Node::Type::String:
|
||||
result = MUST(BAN::RefPtr<AML::String>::create());
|
||||
result_data = &static_cast<AML::String*>(result.ptr())->string;
|
||||
source1_data = &static_cast<AML::String*>(source1.ptr())->string;
|
||||
source2_data = &static_cast<AML::String*>(source2.ptr())->string;
|
||||
break;
|
||||
case AML::Node::Type::Buffer:
|
||||
result = MUST(BAN::RefPtr<AML::Buffer>::create());
|
||||
result_data = &static_cast<AML::Buffer*>(result.ptr())->buffer;
|
||||
source1_data = &static_cast<AML::Buffer*>(source1.ptr())->buffer;
|
||||
source2_data = &static_cast<AML::Buffer*>(source2.ptr())->buffer;
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ASSERT(result_data && source1_data && source2_data);
|
||||
|
||||
MUST(result_data->resize(source1_data->size() + source2_data->size()));
|
||||
for (size_t i = 0; i < source1_data->size(); i++)
|
||||
(*result_data)[i] = (*source1_data)[i];
|
||||
for (size_t i = 0; i < source2_data->size(); i++)
|
||||
(*result_data)[source1_data->size() + i] = (*source2_data)[i];
|
||||
|
||||
#if AML_DEBUG_LEVEL >= 2
|
||||
AML_DEBUG_PRINT("Concat ");
|
||||
source1->debug_print(0);
|
||||
AML_DEBUG_PRINT(", ");
|
||||
source2->debug_print(0);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
#endif
|
||||
|
||||
if (context.aml_data.size() < 1)
|
||||
return ParseResult::Failure;
|
||||
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto destination_result = AML::parse_object(context);
|
||||
if (!destination_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto destination = destination_result.node();
|
||||
if (!destination)
|
||||
{
|
||||
AML_ERROR("IndexOp failed to resolve destination");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
if (!destination->store(result))
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return ParseResult(result);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -17,8 +17,9 @@ namespace Kernel::ACPI::AML
|
|||
|
||||
switch (opcode)
|
||||
{
|
||||
case AML::Byte::ToIntegerOp:
|
||||
case AML::Byte::ToBufferOp:
|
||||
case AML::Byte::ToHexStringOp:
|
||||
case AML::Byte::ToIntegerOp:
|
||||
case AML::Byte::ToStringOp:
|
||||
break;
|
||||
default:
|
||||
|
@ -28,7 +29,7 @@ namespace Kernel::ACPI::AML
|
|||
auto data_result = AML::parse_object(context);
|
||||
if (!data_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto data_node = data_result.node();
|
||||
auto data_node = data_result.node() ? data_result.node()->to_underlying() : BAN::RefPtr<AML::Node>();
|
||||
if (!data_node)
|
||||
{
|
||||
AML_ERROR("Conversion {2H} data could not be evaluated", static_cast<uint8_t>(opcode));
|
||||
|
@ -69,6 +70,37 @@ namespace Kernel::ACPI::AML
|
|||
case AML::Byte::ToStringOp:
|
||||
converted = data_node->convert(AML::Node::ConvString);
|
||||
break;
|
||||
case AML::Byte::ToHexStringOp:
|
||||
{
|
||||
switch (data_node->type)
|
||||
{
|
||||
case AML::Node::Type::Integer:
|
||||
converted = MUST(BAN::RefPtr<AML::String>::create(
|
||||
MUST(BAN::String::formatted("0x{H}", static_cast<AML::Integer*>(data_node.ptr())->value))
|
||||
));
|
||||
break;
|
||||
case AML::Node::Type::String:
|
||||
converted = data_node->copy();
|
||||
break;
|
||||
case AML::Node::Type::Buffer:
|
||||
{
|
||||
const auto& buffer = static_cast<AML::Buffer*>(data_node.ptr())->buffer;
|
||||
|
||||
BAN::String temp;
|
||||
for (size_t i = 0; i < buffer.size(); i++)
|
||||
{
|
||||
const char* format = (i == 0) ? "0x{H}" : ", 0x{H}";
|
||||
MUST(temp.append(MUST(BAN::String::formatted(format, buffer[i]))));
|
||||
}
|
||||
|
||||
converted = MUST(BAN::RefPtr<AML::String>::create(temp));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -44,8 +44,48 @@ namespace Kernel::ACPI::AML
|
|||
return ParseResult(source_node);
|
||||
}
|
||||
case AML::Byte::NotOp:
|
||||
AML_TODO("NotOp", context.aml_data[0]);
|
||||
return ParseResult::Failure;
|
||||
{
|
||||
auto source_result = AML::parse_object(context);
|
||||
if (!source_result.success())
|
||||
return ParseResult::Failure;
|
||||
auto source_conv = source_result.node() ? source_result.node()->convert(AML::Node::ConvInteger) : BAN::RefPtr<AML::Node>();
|
||||
if (!source_conv)
|
||||
{
|
||||
AML_ERROR("NotOp source not an integer, type {}",
|
||||
static_cast<uint8_t>(source_result.node()->type)
|
||||
);
|
||||
if (source_result.node())
|
||||
source_result.node()->debug_print(1);
|
||||
AML_DEBUG_PRINTLN("");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
const auto source_value = static_cast<AML::Integer*>(source_conv.ptr())->value;
|
||||
|
||||
BAN::RefPtr<AML::Node> target_node;
|
||||
if (context.aml_data[0] == 0x00)
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
else
|
||||
{
|
||||
auto target_result = AML::parse_object(context);
|
||||
if (!target_result.success())
|
||||
return ParseResult::Failure;
|
||||
target_node = target_result.node();
|
||||
if (!target_node)
|
||||
{
|
||||
AML_ERROR("NotOp target invalid");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
}
|
||||
|
||||
auto result_node = MUST(BAN::RefPtr<AML::Integer>::create(~source_value));
|
||||
if (target_node && !target_node->store(result_node))
|
||||
{
|
||||
AML_ERROR("NotOp failed to store result");
|
||||
return ParseResult::Failure;
|
||||
}
|
||||
|
||||
return ParseResult(result_node);
|
||||
}
|
||||
case AML::Byte::LNotOp:
|
||||
{
|
||||
context.aml_data = context.aml_data.slice(1);
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Kernel
|
|||
|
||||
virtual BAN::ErrorOr<void> initialize() { return {}; };
|
||||
|
||||
virtual void handle_stall(uint8_t endpoint_id) = 0;
|
||||
virtual void handle_input_data(size_t byte_count, uint8_t endpoint_id) = 0;
|
||||
};
|
||||
|
||||
|
@ -71,6 +72,7 @@ namespace Kernel
|
|||
static USB::SpeedClass determine_speed_class(uint64_t bits_per_second);
|
||||
|
||||
protected:
|
||||
void handle_stall(uint8_t endpoint_id);
|
||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id);
|
||||
virtual BAN::ErrorOr<void> initialize_control_endpoint() = 0;
|
||||
|
||||
|
|
|
@ -75,6 +75,7 @@ namespace Kernel
|
|||
};
|
||||
|
||||
public:
|
||||
void handle_stall(uint8_t endpoint_id) override;
|
||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Kernel
|
|||
BAN_NON_MOVABLE(USBMassStorageDriver);
|
||||
|
||||
public:
|
||||
void handle_stall(uint8_t endpoint_id) override;
|
||||
void handle_input_data(size_t byte_count, uint8_t endpoint_id) override;
|
||||
|
||||
BAN::ErrorOr<size_t> send_bytes(paddr_t, size_t count);
|
||||
|
|
|
@ -22,8 +22,11 @@ namespace Kernel
|
|||
USBSCSIDevice(USBMassStorageDriver& driver, uint8_t lun, BAN::UniqPtr<DMARegion>&&, uint64_t block_count, uint32_t block_size);
|
||||
~USBSCSIDevice();
|
||||
|
||||
static BAN::ErrorOr<size_t> send_scsi_command_impl(USBMassStorageDriver&, DMARegion& dma_region, uint8_t lun, BAN::ConstByteSpan command, BAN::ByteSpan data, bool in);
|
||||
BAN::ErrorOr<size_t> send_scsi_command(BAN::ConstByteSpan command, BAN::ByteSpan data, bool in);
|
||||
template<bool IN, typename SPAN = BAN::either_or_t<IN, BAN::ByteSpan, BAN::ConstByteSpan>>
|
||||
BAN::ErrorOr<size_t> send_scsi_command(BAN::ConstByteSpan command, SPAN data);
|
||||
|
||||
template<bool IN, typename SPAN = BAN::either_or_t<IN, BAN::ByteSpan, BAN::ConstByteSpan>>
|
||||
static BAN::ErrorOr<size_t> send_scsi_command_impl(USBMassStorageDriver&, DMARegion& dma_region, uint8_t lun, BAN::ConstByteSpan command, SPAN data);
|
||||
|
||||
BAN::ErrorOr<void> read_sectors_impl(uint64_t first_lba, uint64_t sector_count, BAN::ByteSpan buffer) override;
|
||||
BAN::ErrorOr<void> write_sectors_impl(uint64_t lba, uint64_t sector_count, BAN::ConstByteSpan buffer) override;
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> initialize_impl();
|
||||
BAN::ErrorOr<void> initialize_ports();
|
||||
BAN::ErrorOr<void> initialize_primary_interrupter();
|
||||
BAN::ErrorOr<void> initialize_scratchpad();
|
||||
|
||||
BAN::ErrorOr<void> reset_controller();
|
||||
|
||||
|
@ -91,6 +92,9 @@ namespace Kernel
|
|||
uint32_t m_command_enqueue { 0 };
|
||||
bool m_command_cycle { 1 };
|
||||
|
||||
BAN::UniqPtr<DMARegion> m_scratchpad_buffer_array;
|
||||
BAN::Vector<paddr_t> m_scratchpad_buffers;
|
||||
|
||||
BAN::UniqPtr<DMARegion> m_event_ring_region;
|
||||
uint32_t m_event_dequeue { 0 };
|
||||
bool m_event_cycle { 1 };
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <kernel/ACPI/AML/Alias.h>
|
||||
#include <kernel/ACPI/AML/Buffer.h>
|
||||
#include <kernel/ACPI/AML/Bytes.h>
|
||||
#include <kernel/ACPI/AML/Concat.h>
|
||||
#include <kernel/ACPI/AML/Conversion.h>
|
||||
#include <kernel/ACPI/AML/CopyObject.h>
|
||||
#include <kernel/ACPI/AML/Device.h>
|
||||
|
@ -152,6 +153,7 @@ namespace Kernel::ACPI
|
|||
case AML::Byte::XorOp:
|
||||
return AML::Expression::parse(context);
|
||||
case AML::Byte::ToBufferOp:
|
||||
case AML::Byte::ToHexStringOp:
|
||||
case AML::Byte::ToIntegerOp:
|
||||
case AML::Byte::ToStringOp:
|
||||
return AML::Conversion::parse(context);
|
||||
|
@ -161,6 +163,8 @@ namespace Kernel::ACPI
|
|||
case AML::Byte::CreateDWordFieldOp:
|
||||
case AML::Byte::CreateQWordFieldOp:
|
||||
return AML::BufferField::parse(context);
|
||||
case AML::Byte::ConcatOp:
|
||||
return AML::Concat::parse(context);
|
||||
case AML::Byte::AliasOp:
|
||||
return AML::Alias::parse(context);
|
||||
case AML::Byte::NameOp:
|
||||
|
|
|
@ -437,7 +437,7 @@ namespace Kernel::PCI
|
|||
{
|
||||
write_dword(*m_offset_msi + 0x04, msg_addr & 0xFFFFFFFF);
|
||||
write_dword(*m_offset_msi + 0x08, msg_addr >> 32);
|
||||
write_word(*m_offset_msi + 0x12, msg_data);
|
||||
write_word(*m_offset_msi + 0x0C, msg_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -328,6 +328,12 @@ namespace Kernel
|
|||
return BAN::move(configuration);
|
||||
}
|
||||
|
||||
void USBDevice::handle_stall(uint8_t endpoint_id)
|
||||
{
|
||||
for (auto& driver : m_class_drivers)
|
||||
driver->handle_stall(endpoint_id);
|
||||
}
|
||||
|
||||
void USBDevice::handle_input_data(size_t byte_count, uint8_t endpoint_id)
|
||||
{
|
||||
for (auto& driver : m_class_drivers)
|
||||
|
|
|
@ -272,6 +272,12 @@ namespace Kernel
|
|||
return BAN::move(result);
|
||||
}
|
||||
|
||||
void USBHIDDriver::handle_stall(uint8_t endpoint_id)
|
||||
{
|
||||
(void)endpoint_id;
|
||||
// FIXME: do something :)
|
||||
}
|
||||
|
||||
void USBHIDDriver::handle_input_data(size_t byte_count, uint8_t endpoint_id)
|
||||
{
|
||||
if (m_data_endpoint_id != endpoint_id)
|
||||
|
|
|
@ -169,6 +169,12 @@ namespace Kernel
|
|||
return static_cast<size_t>(bytes_recv);
|
||||
}
|
||||
|
||||
void USBMassStorageDriver::handle_stall(uint8_t endpoint_id)
|
||||
{
|
||||
(void)endpoint_id;
|
||||
// FIXME: do something :)
|
||||
}
|
||||
|
||||
void USBMassStorageDriver::handle_input_data(size_t byte_count, uint8_t endpoint_id)
|
||||
{
|
||||
if (endpoint_id != m_in_endpoint_id && endpoint_id != m_out_endpoint_id)
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace Kernel
|
|||
0x00
|
||||
};
|
||||
SCSI::InquiryRes inquiry_res;
|
||||
TRY(send_scsi_command_impl(driver, *dma_region, lun, BAN::ConstByteSpan::from(scsi_inquiry_req), BAN::ByteSpan::from(inquiry_res), true));
|
||||
TRY(send_scsi_command_impl<true>(driver, *dma_region, lun, BAN::ConstByteSpan::from(scsi_inquiry_req), BAN::ByteSpan::from(inquiry_res)));
|
||||
|
||||
dprintln(" vendor: {}", BAN::StringView(reinterpret_cast<const char*>(inquiry_res.t10_vendor_identification), 8));
|
||||
dprintln(" product: {}", BAN::StringView(reinterpret_cast<const char*>(inquiry_res.product_identification), 16));
|
||||
|
@ -105,7 +105,7 @@ namespace Kernel
|
|||
0x00
|
||||
};
|
||||
SCSI::ReadCapacity10 read_capacity_res;
|
||||
TRY(send_scsi_command_impl(driver, *dma_region, lun, BAN::ConstByteSpan::from(scsi_read_capacity_req), BAN::ByteSpan::from(read_capacity_res), true));
|
||||
TRY(send_scsi_command_impl<true>(driver, *dma_region, lun, BAN::ConstByteSpan::from(scsi_read_capacity_req), BAN::ByteSpan::from(read_capacity_res)));
|
||||
|
||||
block_count = read_capacity_res.logical_block_address + 1;
|
||||
block_size = read_capacity_res.block_length;
|
||||
|
@ -144,12 +144,14 @@ namespace Kernel
|
|||
scsi_free_rdev(m_rdev);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> USBSCSIDevice::send_scsi_command(BAN::ConstByteSpan scsi_command, BAN::ByteSpan data, bool in)
|
||||
template<bool IN, typename SPAN>
|
||||
BAN::ErrorOr<size_t> USBSCSIDevice::send_scsi_command(BAN::ConstByteSpan scsi_command, SPAN data)
|
||||
{
|
||||
return TRY(send_scsi_command_impl(m_driver, *m_dma_region, m_lun, scsi_command, data, in));
|
||||
return TRY(send_scsi_command_impl<IN>(m_driver, *m_dma_region, m_lun, scsi_command, data));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> USBSCSIDevice::send_scsi_command_impl(USBMassStorageDriver& driver, DMARegion& dma_region, uint8_t lun, BAN::ConstByteSpan scsi_command, BAN::ByteSpan data, bool in)
|
||||
template<bool IN, typename SPAN>
|
||||
BAN::ErrorOr<size_t> USBSCSIDevice::send_scsi_command_impl(USBMassStorageDriver& driver, DMARegion& dma_region, uint8_t lun, BAN::ConstByteSpan scsi_command, SPAN data)
|
||||
{
|
||||
ASSERT(scsi_command.size() <= 16);
|
||||
|
||||
|
@ -160,7 +162,7 @@ namespace Kernel
|
|||
.dCBWSignature = 0x43425355,
|
||||
.dCBWTag = 0x00000000,
|
||||
.dCBWDataTransferLength = static_cast<uint32_t>(data.size()),
|
||||
.bmCBWFlags = static_cast<uint8_t>(in ? 0x80 : 0x00),
|
||||
.bmCBWFlags = IN ? 0x80 : 0x00,
|
||||
.bCBWLUN = lun,
|
||||
.bCBWCBLength = static_cast<uint8_t>(scsi_command.size()),
|
||||
.CBWCB = {},
|
||||
|
@ -178,19 +180,19 @@ namespace Kernel
|
|||
{
|
||||
if (data.empty())
|
||||
return 0;
|
||||
if (in)
|
||||
if constexpr(IN)
|
||||
return TRY(driver.recv_bytes(dma_region.paddr(), data.size()));
|
||||
memcpy(reinterpret_cast<void*>(dma_region.vaddr()), data.data(), data.size());
|
||||
return TRY(driver.send_bytes(dma_region.paddr(), data.size()));
|
||||
}());
|
||||
|
||||
if (ntransfer > data.size())
|
||||
if (ntransfer != data.size())
|
||||
{
|
||||
dwarnln("device responded with more bytes than requested");
|
||||
dwarnln("device responded with {}/{} bytes", ntransfer, data.size());
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
if (in && !data.empty())
|
||||
if constexpr (IN)
|
||||
memcpy(data.data(), reinterpret_cast<void*>(dma_region.vaddr()), ntransfer);
|
||||
|
||||
if (TRY(driver.recv_bytes(dma_region.paddr(), sizeof(USBMassStorage::CSW))) != sizeof(USBMassStorage::CSW))
|
||||
|
@ -226,7 +228,7 @@ namespace Kernel
|
|||
(uint8_t)(count >> 8), (uint8_t)(count >> 0),
|
||||
0x00
|
||||
};
|
||||
TRY(send_scsi_command(BAN::ConstByteSpan::from(scsi_read_req), buffer.slice(i * m_block_size, count * m_block_size), true));
|
||||
TRY(send_scsi_command<true>(BAN::ConstByteSpan::from(scsi_read_req), buffer.slice(i * m_block_size, count * m_block_size)));
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
@ -234,13 +236,13 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> USBSCSIDevice::write_sectors_impl(uint64_t first_lba, uint64_t sector_count, BAN::ConstByteSpan _buffer)
|
||||
BAN::ErrorOr<void> USBSCSIDevice::write_sectors_impl(uint64_t first_lba, uint64_t sector_count, BAN::ConstByteSpan buffer)
|
||||
{
|
||||
dprintln("write_sectors_impl({}, {})", first_lba, sector_count);
|
||||
|
||||
const size_t max_blocks_per_write = m_dma_region->size() / m_block_size;
|
||||
ASSERT(max_blocks_per_write <= 0xFFFF);
|
||||
|
||||
auto buffer = BAN::ByteSpan(const_cast<uint8_t*>(_buffer.data()), _buffer.size());
|
||||
|
||||
for (uint64_t i = 0; i < sector_count;)
|
||||
{
|
||||
const uint32_t lba = first_lba + i;
|
||||
|
@ -254,7 +256,7 @@ namespace Kernel
|
|||
(uint8_t)(count >> 8), (uint8_t)(count >> 0),
|
||||
0x00
|
||||
};
|
||||
TRY(send_scsi_command(BAN::ConstByteSpan::from(scsi_write_req), buffer.slice(i * m_block_size, count * m_block_size), false));
|
||||
TRY(send_scsi_command<false>(BAN::ConstByteSpan::from(scsi_write_req), buffer.slice(i * m_block_size, count * m_block_size)));
|
||||
|
||||
i += count;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@ namespace Kernel
|
|||
{
|
||||
if (m_port_updater)
|
||||
m_port_updater->exit(0, SIGKILL);
|
||||
|
||||
for (auto paddr : m_scratchpad_buffers)
|
||||
if (paddr)
|
||||
Heap::get().release_page(paddr);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> XHCIController::take_ownership(PCI::Device& pci_device)
|
||||
|
@ -123,6 +127,8 @@ namespace Kernel
|
|||
|
||||
TRY(initialize_primary_interrupter());
|
||||
|
||||
TRY(initialize_scratchpad());
|
||||
|
||||
// enable the controller
|
||||
operational.usbcmd.run_stop = 1;
|
||||
while (operational.usbsts & XHCI::USBSTS::HCHalted)
|
||||
|
@ -224,8 +230,8 @@ namespace Kernel
|
|||
event_ring_table_entry.rsz = m_event_ring_trb_count;
|
||||
|
||||
auto& primary_interrupter = runtime.irs[0];
|
||||
primary_interrupter.erstsz = 1;
|
||||
primary_interrupter.erdp = m_event_ring_region->paddr();
|
||||
primary_interrupter.erstsz = (primary_interrupter.erstsz & 0xFFFF0000) | 1;
|
||||
primary_interrupter.erdp = m_event_ring_region->paddr() | XHCI::ERDP::EventHandlerBusy;
|
||||
primary_interrupter.erstba = m_event_ring_region->paddr() + event_ring_table_offset;
|
||||
|
||||
auto& operational = operational_regs();
|
||||
|
@ -238,7 +244,32 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
static Mutex s_port_mutex;
|
||||
BAN::ErrorOr<void> XHCIController::initialize_scratchpad()
|
||||
{
|
||||
auto& capabilities = capability_regs();
|
||||
|
||||
const uint32_t max_scratchpads = (capabilities.hcsparams2.max_scratchpad_buffers_hi << 5) | capabilities.hcsparams2.max_scratchpad_buffers_lo;
|
||||
if (max_scratchpads == 0)
|
||||
return {};
|
||||
|
||||
m_scratchpad_buffer_array = TRY(DMARegion::create(max_scratchpads * sizeof(uint64_t)));
|
||||
TRY(m_scratchpad_buffers.resize(max_scratchpads));
|
||||
|
||||
auto* scratchpad_buffer_array = reinterpret_cast<uint64_t*>(m_scratchpad_buffer_array->vaddr());
|
||||
for (size_t i = 0; i < max_scratchpads; i++)
|
||||
{
|
||||
const paddr_t paddr = Heap::get().take_free_page();
|
||||
if (paddr == 0)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
m_scratchpad_buffers[i] = paddr;
|
||||
scratchpad_buffer_array[i] = paddr;
|
||||
}
|
||||
|
||||
ASSERT(m_dcbaa_region);
|
||||
*reinterpret_cast<uint64_t*>(m_dcbaa_region->vaddr()) = m_scratchpad_buffer_array->paddr();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void XHCIController::port_updater_task()
|
||||
{
|
||||
|
@ -260,8 +291,6 @@ namespace Kernel
|
|||
|
||||
for (size_t i = 0; i < m_ports.size(); i++)
|
||||
{
|
||||
LockGuard _(s_port_mutex);
|
||||
|
||||
auto& my_port = m_ports[i];
|
||||
if (my_port.revision_major == 0)
|
||||
continue;
|
||||
|
@ -375,6 +404,13 @@ namespace Kernel
|
|||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
auto& operational = operational_regs();
|
||||
if (operational.usbsts & XHCI::USBSTS::HCHalted)
|
||||
{
|
||||
dwarnln("Trying to send a command on a halted controller");
|
||||
return BAN::Error::from_errno(EFAULT);
|
||||
}
|
||||
|
||||
auto& command_trb = reinterpret_cast<volatile XHCI::TRB*>(m_command_ring_region->vaddr())[m_command_enqueue];
|
||||
command_trb.raw.dword0 = trb.raw.dword0;
|
||||
command_trb.raw.dword1 = trb.raw.dword1;
|
||||
|
@ -427,98 +463,95 @@ namespace Kernel
|
|||
|
||||
void XHCIController::handle_irq()
|
||||
{
|
||||
auto& primary_interrupter = runtime_regs().irs[0];
|
||||
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
|
||||
|
||||
auto& operational = operational_regs();
|
||||
if (!(operational.usbsts & XHCI::USBSTS::EventInterrupt))
|
||||
return;
|
||||
operational.usbsts = XHCI::USBSTS::EventInterrupt;
|
||||
|
||||
auto& primary_interrupter = runtime_regs().irs[0];
|
||||
primary_interrupter.iman = primary_interrupter.iman | XHCI::IMAN::InterruptPending | XHCI::IMAN::InterruptEnable;
|
||||
|
||||
if (current_event_trb().cycle == m_event_cycle)
|
||||
for (;;)
|
||||
{
|
||||
for (;;)
|
||||
auto& trb = current_event_trb();
|
||||
if (trb.cycle != m_event_cycle)
|
||||
break;
|
||||
|
||||
switch (trb.trb_type)
|
||||
{
|
||||
auto& trb = current_event_trb();
|
||||
if (trb.cycle != m_event_cycle)
|
||||
case XHCI::TRBType::TransferEvent:
|
||||
{
|
||||
dprintln_if(DEBUG_XHCI, "TransferEvent");
|
||||
|
||||
const uint32_t slot_id = trb.transfer_event.slot_id;
|
||||
if (slot_id == 0 || slot_id > m_slots.size() || !m_slots[slot_id - 1])
|
||||
{
|
||||
dwarnln("TransferEvent for invalid slot {}", slot_id);
|
||||
dwarnln("Completion error: {}", +trb.transfer_event.completion_code);
|
||||
break;
|
||||
}
|
||||
|
||||
m_slots[slot_id - 1]->on_transfer_event(trb);
|
||||
|
||||
break;
|
||||
|
||||
switch (trb.trb_type)
|
||||
{
|
||||
case XHCI::TRBType::TransferEvent:
|
||||
{
|
||||
dprintln_if(DEBUG_XHCI, "TransferEvent");
|
||||
|
||||
const uint32_t slot_id = trb.transfer_event.slot_id;
|
||||
if (slot_id == 0 || slot_id > m_slots.size() || !m_slots[slot_id - 1])
|
||||
{
|
||||
dwarnln("TransferEvent for invalid slot {}", slot_id);
|
||||
dwarnln("Completion error: {}", +trb.transfer_event.completion_code);
|
||||
break;
|
||||
}
|
||||
|
||||
m_slots[slot_id - 1]->on_transfer_event(trb);
|
||||
|
||||
break;
|
||||
}
|
||||
case XHCI::TRBType::CommandCompletionEvent:
|
||||
{
|
||||
dprintln_if(DEBUG_XHCI, "CommandCompletionEvent");
|
||||
|
||||
const uint32_t trb_index = (trb.command_completion_event.command_trb_pointer - m_command_ring_region->paddr()) / sizeof(XHCI::TRB);
|
||||
|
||||
// NOTE: dword2 is last (and atomic) as that is what send_command is waiting for
|
||||
auto& completion_trb = const_cast<volatile XHCI::TRB&>(m_command_completions[trb_index]);
|
||||
completion_trb.raw.dword0 = trb.raw.dword0;
|
||||
completion_trb.raw.dword1 = trb.raw.dword1;
|
||||
completion_trb.raw.dword3 = trb.raw.dword3;
|
||||
__atomic_store_n(&completion_trb.raw.dword2, trb.raw.dword2, __ATOMIC_SEQ_CST);
|
||||
|
||||
break;
|
||||
}
|
||||
case XHCI::TRBType::PortStatusChangeEvent:
|
||||
{
|
||||
dprintln_if(DEBUG_XHCI, "PortStatusChangeEvent");
|
||||
uint8_t port_id = trb.port_status_chage_event.port_id;
|
||||
if (port_id > capability_regs().hcsparams1.max_ports)
|
||||
{
|
||||
dwarnln("PortStatusChangeEvent on non-existent port {}", port_id);
|
||||
break;
|
||||
}
|
||||
m_port_changed = true;
|
||||
m_port_thread_blocker.unblock();
|
||||
break;
|
||||
}
|
||||
case XHCI::TRBType::BandwidthRequestEvent:
|
||||
dwarnln("Unhandled BandwidthRequestEvent");
|
||||
break;
|
||||
case XHCI::TRBType::DoorbellEvent:
|
||||
dwarnln("Unhandled DoorbellEvent");
|
||||
break;
|
||||
case XHCI::TRBType::HostControllerEvent:
|
||||
dwarnln("Unhandled HostControllerEvent");
|
||||
break;
|
||||
case XHCI::TRBType::DeviceNotificationEvent:
|
||||
dwarnln("Unhandled DeviceNotificationEvent");
|
||||
break;
|
||||
case XHCI::TRBType::MFINDEXWrapEvent:
|
||||
dwarnln("Unhandled MFINDEXWrapEvent");
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unrecognized event TRB type {}", +trb.trb_type);
|
||||
break;
|
||||
}
|
||||
|
||||
m_event_dequeue++;
|
||||
if (m_event_dequeue >= m_event_ring_trb_count)
|
||||
case XHCI::TRBType::CommandCompletionEvent:
|
||||
{
|
||||
m_event_dequeue = 0;
|
||||
m_event_cycle = !m_event_cycle;
|
||||
dprintln_if(DEBUG_XHCI, "CommandCompletionEvent");
|
||||
|
||||
const uint32_t trb_index = (trb.command_completion_event.command_trb_pointer - m_command_ring_region->paddr()) / sizeof(XHCI::TRB);
|
||||
|
||||
// NOTE: dword2 is last (and atomic) as that is what send_command is waiting for
|
||||
auto& completion_trb = const_cast<volatile XHCI::TRB&>(m_command_completions[trb_index]);
|
||||
completion_trb.raw.dword0 = trb.raw.dword0;
|
||||
completion_trb.raw.dword1 = trb.raw.dword1;
|
||||
completion_trb.raw.dword3 = trb.raw.dword3;
|
||||
__atomic_store_n(&completion_trb.raw.dword2, trb.raw.dword2, __ATOMIC_SEQ_CST);
|
||||
|
||||
break;
|
||||
}
|
||||
case XHCI::TRBType::PortStatusChangeEvent:
|
||||
{
|
||||
dprintln_if(DEBUG_XHCI, "PortStatusChangeEvent");
|
||||
uint8_t port_id = trb.port_status_chage_event.port_id;
|
||||
if (port_id > capability_regs().hcsparams1.max_ports)
|
||||
{
|
||||
dwarnln("PortStatusChangeEvent on non-existent port {}", port_id);
|
||||
break;
|
||||
}
|
||||
m_port_changed = true;
|
||||
m_port_thread_blocker.unblock();
|
||||
break;
|
||||
}
|
||||
case XHCI::TRBType::BandwidthRequestEvent:
|
||||
dwarnln("Unhandled BandwidthRequestEvent");
|
||||
break;
|
||||
case XHCI::TRBType::DoorbellEvent:
|
||||
dwarnln("Unhandled DoorbellEvent");
|
||||
break;
|
||||
case XHCI::TRBType::HostControllerEvent:
|
||||
dwarnln("Unhandled HostControllerEvent");
|
||||
break;
|
||||
case XHCI::TRBType::DeviceNotificationEvent:
|
||||
dwarnln("Unhandled DeviceNotificationEvent");
|
||||
break;
|
||||
case XHCI::TRBType::MFINDEXWrapEvent:
|
||||
dwarnln("Unhandled MFINDEXWrapEvent");
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unrecognized event TRB type {}", +trb.trb_type);
|
||||
break;
|
||||
}
|
||||
|
||||
primary_interrupter.erdp = (m_event_ring_region->paddr() + (m_event_dequeue * sizeof(XHCI::TRB))) | XHCI::ERDP::EventHandlerBusy;
|
||||
m_event_dequeue++;
|
||||
if (m_event_dequeue >= m_event_ring_trb_count)
|
||||
{
|
||||
m_event_dequeue = 0;
|
||||
m_event_cycle = !m_event_cycle;
|
||||
}
|
||||
}
|
||||
|
||||
primary_interrupter.erdp = (m_event_ring_region->paddr() + (m_event_dequeue * sizeof(XHCI::TRB))) | XHCI::ERDP::EventHandlerBusy;
|
||||
}
|
||||
|
||||
volatile XHCI::CapabilityRegs& XHCIController::capability_regs()
|
||||
|
|
|
@ -295,15 +295,19 @@ namespace Kernel
|
|||
void XHCIDevice::on_interrupt_or_bulk_endpoint_event(XHCI::TRB trb)
|
||||
{
|
||||
ASSERT(trb.trb_type == XHCI::TRBType::TransferEvent);
|
||||
|
||||
const uint32_t endpoint_id = trb.transfer_event.endpoint_id;
|
||||
auto& endpoint = m_endpoints[endpoint_id - 1];
|
||||
|
||||
if (trb.transfer_event.completion_code == 6)
|
||||
return handle_stall(endpoint_id);
|
||||
|
||||
if (trb.transfer_event.completion_code != 1 && trb.transfer_event.completion_code != 13)
|
||||
{
|
||||
dwarnln("Interrupt or bulk endpoint got transfer event with completion code {}", +trb.transfer_event.completion_code);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t endpoint_id = trb.transfer_event.endpoint_id;
|
||||
auto& endpoint = m_endpoints[endpoint_id - 1];
|
||||
|
||||
const auto* transfer_trb_arr = reinterpret_cast<volatile XHCI::TRB*>(endpoint.transfer_ring->vaddr());
|
||||
const uint32_t transfer_trb_index = (trb.transfer_event.trb_pointer - endpoint.transfer_ring->paddr()) / sizeof(XHCI::TRB);
|
||||
const uint32_t original_len = transfer_trb_arr[transfer_trb_index].normal.trb_transfer_length;
|
||||
|
|
Loading…
Reference in New Issue