summaryrefslogtreecommitdiff
path: root/Kernel/Bus/USB/USBPipe.cpp
diff options
context:
space:
mode:
authorb14ckcat <b14ckcat@protonmail.com>2022-10-15 20:34:49 -0400
committerAndreas Kling <kling@serenityos.org>2022-10-18 12:58:12 +0200
commitbf3c99ef23118d148a9dbde109bbf45b284e70cb (patch)
treeb1c0f7540a1fda987d0ea35030dda0853efe18da /Kernel/Bus/USB/USBPipe.cpp
parent13045751903eda77421fbd71fddc89a1ddb1bb10 (diff)
downloadserenity-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.cpp128
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)
+{
+}
+
}