From 8a7876d65cf05a93bef71f9287cbd79559e19471 Mon Sep 17 00:00:00 2001 From: b14ckcat Date: Sun, 8 May 2022 01:36:20 -0400 Subject: Kernel/USB: Add support for bulk transfers --- Kernel/Bus/USB/UHCI/UHCIController.cpp | 44 ++++++++++++++++++++++++++++++++++ Kernel/Bus/USB/UHCI/UHCIController.h | 1 + Kernel/Bus/USB/USBController.h | 1 + Kernel/Bus/USB/USBPipe.cpp | 21 ++++++++++++++++ Kernel/Bus/USB/USBPipe.h | 1 + Kernel/Bus/USB/USBTransfer.cpp | 9 +++++++ Kernel/Bus/USB/USBTransfer.h | 3 +++ 7 files changed, 80 insertions(+) (limited to 'Kernel/Bus') diff --git a/Kernel/Bus/USB/UHCI/UHCIController.cpp b/Kernel/Bus/USB/UHCI/UHCIController.cpp index 488e3b59c4..aa35a8e0c4 100644 --- a/Kernel/Bus/USB/UHCI/UHCIController.cpp +++ b/Kernel/Bus/USB/UHCI/UHCIController.cpp @@ -430,6 +430,50 @@ ErrorOr UHCIController::submit_control_transfer(Transfer& transfer) return transfer_size; } +ErrorOr UHCIController::submit_bulk_transfer(Transfer& transfer) +{ + Pipe& pipe = transfer.pipe(); + dbgln_if(UHCI_DEBUG, "UHCI: Received bulk transfer for address {}. Root Hub is at address {}.", pipe.device_address(), m_root_hub->device_address()); + + // Create a new descriptor chain + TransferDescriptor* last_data_descriptor; + TransferDescriptor* data_descriptor_chain; + auto buffer_address = Ptr32(transfer.buffer_physical().as_ptr()); + TRY(create_chain(pipe, transfer.pipe().direction() == Pipe::Direction::In ? PacketID::IN : PacketID::OUT, buffer_address, pipe.max_packet_size(), transfer.transfer_data_size(), &data_descriptor_chain, &last_data_descriptor)); + + last_data_descriptor->terminate(); + + if constexpr (UHCI_VERBOSE_DEBUG) { + if (data_descriptor_chain) { + dbgln("Data TD"); + data_descriptor_chain->print(); + } + } + + QueueHead* transfer_queue = allocate_queue_head(); + if (!transfer_queue) { + free_descriptor_chain(data_descriptor_chain); + return 0; + } + + transfer_queue->attach_transfer_descriptor_chain(data_descriptor_chain); + transfer_queue->set_transfer(&transfer); + + m_bulk_qh->attach_transfer_queue(*transfer_queue); + + size_t transfer_size = 0; + while (!transfer.complete()) { + transfer_size = poll_transfer_queue(*transfer_queue); + dbgln_if(USB_DEBUG, "Transfer size: {}", transfer_size); + } + + free_descriptor_chain(transfer_queue->get_first_td()); + transfer_queue->free(); + m_queue_head_pool->release_to_pool(transfer_queue); + + return transfer_size; +} + size_t UHCIController::poll_transfer_queue(QueueHead& transfer_queue) { Transfer* transfer = transfer_queue.transfer(); diff --git a/Kernel/Bus/USB/UHCI/UHCIController.h b/Kernel/Bus/USB/UHCI/UHCIController.h index 66279b510e..a0d2dec5c6 100644 --- a/Kernel/Bus/USB/UHCI/UHCIController.h +++ b/Kernel/Bus/USB/UHCI/UHCIController.h @@ -45,6 +45,7 @@ public: ErrorOr spawn_port_process(); virtual ErrorOr submit_control_transfer(Transfer& transfer) override; + virtual ErrorOr submit_bulk_transfer(Transfer& transfer) override; void get_port_status(Badge, u8, HubStatus&); ErrorOr set_port_feature(Badge, u8, HubFeatureSelector); diff --git a/Kernel/Bus/USB/USBController.h b/Kernel/Bus/USB/USBController.h index f5f8d561f8..7ff30819e3 100644 --- a/Kernel/Bus/USB/USBController.h +++ b/Kernel/Bus/USB/USBController.h @@ -24,6 +24,7 @@ public: virtual ErrorOr start() = 0; virtual ErrorOr submit_control_transfer(Transfer&) = 0; + virtual ErrorOr submit_bulk_transfer(Transfer& transfer) = 0; u8 allocate_address(); diff --git a/Kernel/Bus/USB/USBPipe.cpp b/Kernel/Bus/USB/USBPipe.cpp index 940b0f5178..982cc14093 100644 --- a/Kernel/Bus/USB/USBPipe.cpp +++ b/Kernel/Bus/USB/USBPipe.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -71,4 +72,24 @@ ErrorOr Pipe::control_transfer(u8 request_type, u8 request, u16 value, u return transfer_length; } +ErrorOr Pipe::bulk_transfer(u16 length, void* data) +{ + size_t transfer_length = 0; + auto transfer = TRY(Transfer::try_create(*this, length)); + + if (m_direction == Direction::In) { + dbgln_if(USB_DEBUG, "Pipe: Bulk in transfer allocated @ {}", transfer->buffer_physical()); + transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer)); + memcpy(data, transfer->buffer().as_ptr(), min(length, transfer_length)); + dbgln_if(USB_DEBUG, "Pipe: Bulk in transfer complete!"); + } else if (m_direction == Direction::Out) { + TRY(transfer->write_buffer(length, data)); + dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer allocated @ {}", transfer->buffer_physical()); + transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer)); + dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer complete!"); + } + + return transfer_length; +} + } diff --git a/Kernel/Bus/USB/USBPipe.h b/Kernel/Bus/USB/USBPipe.h index 3e9db8e272..0371f80517 100644 --- a/Kernel/Bus/USB/USBPipe.h +++ b/Kernel/Bus/USB/USBPipe.h @@ -57,6 +57,7 @@ public: void set_device_address(i8 addr) { m_device_address = addr; } ErrorOr control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data); + ErrorOr bulk_transfer(u16 length, void* data); Pipe(USBController const& controller, Type type, Direction direction, u16 max_packet_size); Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint); diff --git a/Kernel/Bus/USB/USBTransfer.cpp b/Kernel/Bus/USB/USBTransfer.cpp index 62dc28e116..e664e7ced9 100644 --- a/Kernel/Bus/USB/USBTransfer.cpp +++ b/Kernel/Bus/USB/USBTransfer.cpp @@ -43,4 +43,13 @@ void Transfer::set_setup_packet(USBRequestData const& request) m_request = request; } +ErrorOr Transfer::write_buffer(u16 len, void* data) +{ + VERIFY(len <= m_data_buffer->size()); + m_transfer_data_size = len; + memcpy(buffer().as_ptr(), data, len); + + return {}; +} + } diff --git a/Kernel/Bus/USB/USBTransfer.h b/Kernel/Bus/USB/USBTransfer.h index 78487da9fc..914a3c6d72 100644 --- a/Kernel/Bus/USB/USBTransfer.h +++ b/Kernel/Bus/USB/USBTransfer.h @@ -28,6 +28,8 @@ public: void set_complete() { m_complete = true; } void set_error_occurred() { m_error_occurred = true; } + ErrorOr write_buffer(u16 len, void* data); + // `const` here makes sure we don't blow up by writing to a physical address USBRequestData const& request() const { return m_request; } Pipe const& pipe() const { return m_pipe; } @@ -47,4 +49,5 @@ private: bool m_complete { false }; // Has this transfer been completed? bool m_error_occurred { false }; // Did an error occur during this transfer? }; + } -- cgit v1.2.3