diff --git a/Kernel/Bus/USB/USBDevice.cpp b/Kernel/Bus/USB/USBDevice.cpp index 955da88ae79..53a7f2a78eb 100644 --- a/Kernel/Bus/USB/USBDevice.cpp +++ b/Kernel/Bus/USB/USBDevice.cpp @@ -18,7 +18,7 @@ namespace Kernel::USB { ErrorOr> Device::try_create(USBController const& controller, u8 port, DeviceSpeed speed) { - auto pipe = TRY(Pipe::try_create_pipe(controller, Pipe::Type::Control, Pipe::Direction::Bidirectional, 0, 8, 0)); + auto pipe = TRY(ControlPipe::create(controller, 0, 8, 0)); auto device = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Device(controller, port, speed, move(pipe)))); auto sysfs_node = TRY(SysFSUSBDeviceInformation::create(*device)); device->m_sysfs_device_info_node = move(sysfs_node); @@ -26,7 +26,7 @@ ErrorOr> Device::try_create(USBController const& contr return device; } -Device::Device(USBController const& controller, u8 port, DeviceSpeed speed, NonnullOwnPtr default_pipe) +Device::Device(USBController const& controller, u8 port, DeviceSpeed speed, NonnullOwnPtr default_pipe) : m_device_port(port) , m_device_speed(speed) , m_address(0) @@ -35,7 +35,7 @@ Device::Device(USBController const& controller, u8 port, DeviceSpeed speed, Nonn { } -Device::Device(NonnullLockRefPtr controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr default_pipe) +Device::Device(NonnullLockRefPtr controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr default_pipe) : m_device_port(port) , m_device_speed(speed) , m_address(address) @@ -44,7 +44,7 @@ Device::Device(NonnullLockRefPtr controller, u8 address, u8 port, { } -Device::Device(Device const& device, NonnullOwnPtr default_pipe) +Device::Device(Device const& device, NonnullOwnPtr default_pipe) : m_device_port(device.port()) , m_device_speed(device.speed()) , m_address(device.address()) diff --git a/Kernel/Bus/USB/USBDevice.h b/Kernel/Bus/USB/USBDevice.h index 0eb5b207187..c1069b9939d 100644 --- a/Kernel/Bus/USB/USBDevice.h +++ b/Kernel/Bus/USB/USBDevice.h @@ -36,8 +36,8 @@ public: static ErrorOr> try_create(USBController const&, u8, DeviceSpeed); - Device(USBController const&, u8, DeviceSpeed, NonnullOwnPtr default_pipe); - Device(Device const& device, NonnullOwnPtr default_pipe); + Device(USBController const&, u8, DeviceSpeed, NonnullOwnPtr default_pipe); + Device(Device const& device, NonnullOwnPtr default_pipe); virtual ~Device(); ErrorOr enumerate_device(); @@ -59,7 +59,7 @@ public: SysFSUSBDeviceInformation& sysfs_device_info_node(Badge) { return *m_sysfs_device_info_node; } protected: - Device(NonnullLockRefPtr controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr default_pipe); + Device(NonnullLockRefPtr controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr default_pipe); u8 m_device_port { 0 }; // What port is this device attached to. NOTE: This is 1-based. DeviceSpeed m_device_speed; // What speed is this device running at @@ -72,7 +72,7 @@ protected: Vector m_configurations; // Configurations for this device NonnullLockRefPtr m_controller; - NonnullOwnPtr m_default_pipe; // Default communication pipe (endpoint0) used during enumeration + NonnullOwnPtr m_default_pipe; // Default communication pipe (endpoint0) used during enumeration private: IntrusiveListNode> m_hub_child_node; diff --git a/Kernel/Bus/USB/USBHub.cpp b/Kernel/Bus/USB/USBHub.cpp index bb80647ed26..629c00f2993 100644 --- a/Kernel/Bus/USB/USBHub.cpp +++ b/Kernel/Bus/USB/USBHub.cpp @@ -18,25 +18,25 @@ namespace Kernel::USB { ErrorOr> Hub::try_create_root_hub(NonnullLockRefPtr controller, DeviceSpeed device_speed) { // NOTE: Enumeration does not happen here, as the controller must know what the device address is at all times during enumeration to intercept requests. - auto pipe = TRY(Pipe::try_create_pipe(controller, Pipe::Type::Control, Pipe::Direction::Bidirectional, 0, 8, 0)); + auto pipe = TRY(ControlPipe::create(controller, 0, 8, 0)); auto hub = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Hub(controller, device_speed, move(pipe)))); return hub; } ErrorOr> Hub::try_create_from_device(Device const& device) { - auto pipe = TRY(Pipe::try_create_pipe(device.controller(), Pipe::Type::Control, Pipe::Direction::Bidirectional, 0, device.device_descriptor().max_packet_size, device.address())); + auto pipe = TRY(ControlPipe::create(device.controller(), 0, device.device_descriptor().max_packet_size, device.address())); auto hub = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Hub(device, move(pipe)))); TRY(hub->enumerate_and_power_on_hub()); return hub; } -Hub::Hub(NonnullLockRefPtr controller, DeviceSpeed device_speed, NonnullOwnPtr default_pipe) +Hub::Hub(NonnullLockRefPtr controller, DeviceSpeed device_speed, NonnullOwnPtr default_pipe) : Device(move(controller), 1 /* Port 1 */, device_speed, move(default_pipe)) { } -Hub::Hub(Device const& device, NonnullOwnPtr default_pipe) +Hub::Hub(Device const& device, NonnullOwnPtr default_pipe) : Device(device, move(default_pipe)) { } diff --git a/Kernel/Bus/USB/USBHub.h b/Kernel/Bus/USB/USBHub.h index aaefe513d4a..6108bf8828f 100644 --- a/Kernel/Bus/USB/USBHub.h +++ b/Kernel/Bus/USB/USBHub.h @@ -96,9 +96,9 @@ public: private: // Root Hub constructor - Hub(NonnullLockRefPtr, DeviceSpeed, NonnullOwnPtr default_pipe); + Hub(NonnullLockRefPtr, DeviceSpeed, NonnullOwnPtr default_pipe); - Hub(Device const&, NonnullOwnPtr default_pipe); + Hub(Device const&, NonnullOwnPtr default_pipe); USBHubDescriptor m_hub_descriptor {}; diff --git a/Kernel/Bus/USB/USBPipe.cpp b/Kernel/Bus/USB/USBPipe.cpp index ab1cd8bb3b0..ac4c79bc575 100644 --- a/Kernel/Bus/USB/USBPipe.cpp +++ b/Kernel/Bus/USB/USBPipe.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jesse Buhagiar + * Copyright (c) 2022, blackcat * * SPDX-License-Identifier: BSD-2-Clause */ @@ -12,48 +13,33 @@ namespace Kernel::USB { -ErrorOr> 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 dma_buffer) - : m_controller(controller) - , m_type(type) - , m_direction(direction) - , m_endpoint_address(0) - , 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 dma_buffer) - : m_controller(controller) - , m_type(type) - , m_direction(direction) - , m_dma_buffer(move(dma_buffer)) -{ - // TODO: decode endpoint structure -} - -Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, u8 poll_interval, i8 device_address, NonnullOwnPtr dma_buffer) +Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr 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)) { } -ErrorOr Pipe::control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data) +ErrorOr> ControlPipe::create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size) { + 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))); +} + +ControlPipe::ControlPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr dma_buffer) + : Pipe(controller, Type::Control, Direction::Bidirectional, endpoint_address, max_packet_size, device_address, move(dma_buffer)) +{ +} + +ErrorOr 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 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 Pipe::control_transfer(u8 request_type, u8 request, u16 value, u return transfer_length; } -ErrorOr Pipe::bulk_transfer(u16 length, void* data) +ErrorOr> 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 dma_buffer) + : Pipe(controller, Pipe::Type::Bulk, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) +{ +} + +ErrorOr 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)); + + 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> 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 dma_buffer) + : Pipe(controller, Type::Bulk, Direction::Out, endpoint_address, max_packet_size, device_address, move(dma_buffer)) + +{ +} + +ErrorOr 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)); - 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!"); - } + 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> 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 dma_buffer) + : Pipe(controller, Type::Interrupt, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) + , m_poll_interval(poll_interval) +{ +} + +ErrorOr> 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 dma_buffer) + : Pipe(controller, Type::Interrupt, Direction::In, endpoint_address, max_packet_size, device_address, move(dma_buffer)) + , m_poll_interval(poll_interval) +{ +} + } diff --git a/Kernel/Bus/USB/USBPipe.h b/Kernel/Bus/USB/USBPipe.h index 73c423b2d28..578852dc0f2 100644 --- a/Kernel/Bus/USB/USBPipe.h +++ b/Kernel/Bus/USB/USBPipe.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Jesse Buhagiar + * Copyright (c) 2022, blackcat * * SPDX-License-Identifier: BSD-2-Clause */ @@ -15,6 +16,7 @@ namespace Kernel::USB { class USBController; +class Transfer; // // A pipe is the logical connection between a memory buffer on the PC (host) and @@ -41,8 +43,6 @@ public: FullSpeed }; - static ErrorOr> try_create_pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE, u8 poll_interval = 0); - Type type() const { return m_type; } Direction direction() const { return m_direction; } DeviceSpeed device_speed() const { return m_speed; } @@ -50,23 +50,17 @@ public: i8 device_address() const { return m_device_address; } u8 endpoint_address() const { return m_endpoint_address; } u16 max_packet_size() const { return m_max_packet_size; } - u8 poll_interval() const { return m_poll_interval; } bool data_toggle() const { return m_data_toggle; } void set_max_packet_size(u16 max_size) { m_max_packet_size = max_size; } void set_toggle(bool toggle) { m_data_toggle = toggle; } 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, NonnullOwnPtr dma_buffer); - Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint, NonnullOwnPtr dma_buffer); - Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, u8 poll_interval, i8 device_address, NonnullOwnPtr dma_buffer); - -private: +protected: friend class Device; + Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr dma_buffer); + NonnullLockRefPtr m_controller; Type m_type; @@ -76,11 +70,77 @@ private: i8 m_device_address { 0 }; // Device address of this pipe u8 m_endpoint_address { 0 }; // Corresponding endpoint address for this pipe u16 m_max_packet_size { 0 }; // Max packet size for this pipe - u8 m_poll_interval { 0 }; // Polling interval (in frames) bool m_data_toggle { false }; // Data toggle for stuffing bit Mutex m_dma_buffer_lock { "USB pipe mutex"sv }; NonnullOwnPtr m_dma_buffer; }; + +class ControlPipe : public Pipe { +public: + static ErrorOr> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE); + + ErrorOr control_transfer(u8 request_type, u8 request, u16 value, u16 index, size_t length, void* data); + +private: + ControlPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr dma_buffer); +}; + +class BulkInPipe : public Pipe { +public: + static ErrorOr> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE); + + ErrorOr bulk_in_transfer(size_t length, void* data); + +private: + BulkInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr dma_buffer); +}; + +class BulkOutPipe : public Pipe { +public: + static ErrorOr> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE); + + ErrorOr bulk_out_transfer(size_t length, void* data); + +private: + BulkOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr dma_buffer); +}; + +class InterruptInPipe : public Pipe { +public: + static ErrorOr> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, size_t buffer_size = PAGE_SIZE); + + u16 poll_interval() const { return m_poll_interval; } + +private: + InterruptInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr dma_pool); + + u16 m_poll_interval; +}; + +class InterruptOutPipe : public Pipe { +public: + static ErrorOr> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, size_t buffer_size = PAGE_SIZE); + + u16 poll_interval() const { return m_poll_interval; } + +private: + InterruptOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr dma_pool); + + u16 m_poll_interval; +}; + +class IsochronousInPipe : public Pipe { + // TODO +public: +private: +}; + +class IsochronousOutPipe : public Pipe { + // TODO +public: +private: +}; + }