diff options
author | b14ckcat <b14ckcat@protonmail.com> | 2022-10-15 20:34:49 -0400 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-10-18 12:58:12 +0200 |
commit | bf3c99ef23118d148a9dbde109bbf45b284e70cb (patch) | |
tree | b1c0f7540a1fda987d0ea35030dda0853efe18da /Kernel/Bus/USB/USBPipe.cpp | |
parent | 13045751903eda77421fbd71fddc89a1ddb1bb10 (diff) | |
download | serenity-bf3c99ef23118d148a9dbde109bbf45b284e70cb.zip |
Kernel/USB: Refactor USB Pipe
Decompose the current monolithic USBD Pipe interface into several
subclasses, one for each pair of endpoint type & direction. This is to
make it more clear what data and functionality belongs to which Pipe
type, and prevent nonsensical things like trying to execute a control
transfer on a non-control pipe. This is important, because the Pipe
class is the interface by which USB device drivers will interact with
the HCD, so the clearer and more explicit this interface is the better.
Diffstat (limited to 'Kernel/Bus/USB/USBPipe.cpp')
-rw-r--r-- | Kernel/Bus/USB/USBPipe.cpp | 128 |
1 files changed, 89 insertions, 39 deletions
diff --git a/Kernel/Bus/USB/USBPipe.cpp b/Kernel/Bus/USB/USBPipe.cpp index ab1cd8bb3b..ac4c79bc57 100644 --- a/Kernel/Bus/USB/USBPipe.cpp +++ b/Kernel/Bus/USB/USBPipe.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> + * Copyright (c) 2022, blackcat <b14ckcat@protonmail.com> * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,48 +13,33 @@ namespace Kernel::USB { -ErrorOr<NonnullOwnPtr<Pipe>> Pipe::try_create_pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size, u8 poll_interval) -{ - auto dma_region = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB device DMA buffer"sv, Memory::Region::Access::ReadWrite)); - return adopt_nonnull_own_or_enomem(new (nothrow) Pipe(controller, type, direction, endpoint_address, max_packet_size, poll_interval, device_address, move(dma_region))); -} - -Pipe::Pipe(USBController const& controller, Type type, Pipe::Direction direction, u16 max_packet_size, NonnullOwnPtr<Memory::Region> dma_buffer) +Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) : m_controller(controller) , m_type(type) , m_direction(direction) - , m_endpoint_address(0) + , m_device_address(device_address) + , m_endpoint_address(endpoint_address) , m_max_packet_size(max_packet_size) - , m_poll_interval(0) , m_data_toggle(false) , m_dma_buffer(move(dma_buffer)) { } -Pipe::Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint [[maybe_unused]], NonnullOwnPtr<Memory::Region> dma_buffer) - : m_controller(controller) - , m_type(type) - , m_direction(direction) - , m_dma_buffer(move(dma_buffer)) +ErrorOr<NonnullOwnPtr<ControlPipe>> ControlPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) { - // TODO: decode endpoint structure + auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB device DMA buffer"sv, Memory::Region::Access::ReadWrite)); + return adopt_nonnull_own_or_enomem(new (nothrow) ControlPipe(controller, endpoint_address, max_packet_size, device_address, move(dma_buffer))); } -Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, u8 poll_interval, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) - : m_controller(controller) - , m_type(type) - , m_direction(direction) - , m_device_address(device_address) - , m_endpoint_address(endpoint_address) - , m_max_packet_size(max_packet_size) - , m_poll_interval(poll_interval) - , m_data_toggle(false) - , m_dma_buffer(move(dma_buffer)) +ControlPipe::ControlPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) + : Pipe(controller, Type::Control, Direction::Bidirectional, endpoint_address, max_packet_size, device_address, move(dma_buffer)) { } -ErrorOr<size_t> Pipe::control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data) +ErrorOr<size_t> ControlPipe::control_transfer(u8 request_type, u8 request, u16 value, u16 index, size_t length, void* data) { + VERIFY(length <= m_dma_buffer->size()); + MutexLocker lock(m_dma_buffer_lock); USBRequestData usb_request; @@ -67,7 +53,7 @@ ErrorOr<size_t> Pipe::control_transfer(u8 request_type, u8 request, u16 value, u auto transfer = TRY(Transfer::try_create(*this, length, *m_dma_buffer)); transfer->set_setup_packet(usb_request); - dbgln_if(USB_DEBUG, "Pipe: Transfer allocated @ {}", transfer->buffer_physical()); + dbgln_if(USB_DEBUG, "ControlPipe: Transfer allocated @ {}", transfer->buffer_physical()); auto transfer_length = TRY(m_controller->submit_control_transfer(*transfer)); // TODO: Check transfer for completion and copy data from transfer buffer into data @@ -78,26 +64,90 @@ ErrorOr<size_t> Pipe::control_transfer(u8 request_type, u8 request, u16 value, u return transfer_length; } -ErrorOr<size_t> Pipe::bulk_transfer(u16 length, void* data) +ErrorOr<NonnullOwnPtr<BulkInPipe>> BulkInPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) { + VERIFY(buffer_size >= max_packet_size); + auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); + return adopt_nonnull_own_or_enomem(new (nothrow) BulkInPipe(controller, endpoint_address, max_packet_size, device_address, move(dma_buffer))); +} + +BulkInPipe::BulkInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) + : Pipe(controller, Pipe::Type::Bulk, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) +{ +} + +ErrorOr<size_t> BulkInPipe::bulk_in_transfer(size_t length, void* data) +{ + VERIFY(length <= m_dma_buffer->size()); + MutexLocker lock(m_dma_buffer_lock); size_t transfer_length = 0; + auto transfer = TRY(Transfer::try_create(*this, length, *m_dma_buffer)); - 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!"); - } + 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!"); return transfer_length; } +ErrorOr<NonnullOwnPtr<BulkOutPipe>> BulkOutPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) +{ + VERIFY(buffer_size >= max_packet_size); + auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); + return adopt_nonnull_own_or_enomem(new (nothrow) BulkOutPipe(controller, endpoint_address, max_packet_size, device_address, move(dma_buffer))); +} + +BulkOutPipe::BulkOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer) + : Pipe(controller, Type::Bulk, Direction::Out, endpoint_address, max_packet_size, device_address, move(dma_buffer)) + +{ +} + +ErrorOr<size_t> BulkOutPipe::bulk_out_transfer(size_t length, void* data) +{ + VERIFY(length <= m_dma_buffer->size()); + + MutexLocker lock(m_dma_buffer_lock); + + size_t transfer_length = 0; + auto transfer = TRY(Transfer::try_create(*this, length, *m_dma_buffer)); + + 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; +} + +ErrorOr<NonnullOwnPtr<InterruptInPipe>> InterruptInPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, size_t buffer_size) +{ + VERIFY(buffer_size >= max_packet_size); + auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); + return adopt_nonnull_own_or_enomem(new (nothrow) InterruptInPipe(controller, endpoint_address, max_packet_size, device_address, poll_interval, move(dma_buffer))); +} + +InterruptInPipe::InterruptInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr<Memory::Region> dma_buffer) + : Pipe(controller, Type::Interrupt, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) + , m_poll_interval(poll_interval) +{ +} + +ErrorOr<NonnullOwnPtr<InterruptOutPipe>> InterruptOutPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, size_t buffer_size) +{ + VERIFY(buffer_size >= max_packet_size); + auto dma_buffer = TRY(MM.allocate_dma_buffer_pages(TRY(Memory::page_round_up(buffer_size)), "USB pipe DMA buffer"sv, Memory::Region::Access::ReadWrite)); + return adopt_nonnull_own_or_enomem(new (nothrow) InterruptOutPipe(controller, endpoint_address, max_packet_size, device_address, poll_interval, move(dma_buffer))); +} + +InterruptOutPipe::InterruptOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr<Memory::Region> dma_buffer) + : Pipe(controller, Type::Interrupt, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) + , m_poll_interval(poll_interval) +{ +} + } |