1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-06-29 07:42:07 +00:00

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.
This commit is contained in:
b14ckcat 2022-10-15 20:34:49 -04:00 committed by Andreas Kling
parent 1304575190
commit bf3c99ef23
6 changed files with 179 additions and 69 deletions

View file

@ -18,7 +18,7 @@ namespace Kernel::USB {
ErrorOr<NonnullLockRefPtr<Device>> Device::try_create(USBController const& controller, u8 port, DeviceSpeed speed) ErrorOr<NonnullLockRefPtr<Device>> 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 device = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Device(controller, port, speed, move(pipe))));
auto sysfs_node = TRY(SysFSUSBDeviceInformation::create(*device)); auto sysfs_node = TRY(SysFSUSBDeviceInformation::create(*device));
device->m_sysfs_device_info_node = move(sysfs_node); device->m_sysfs_device_info_node = move(sysfs_node);
@ -26,7 +26,7 @@ ErrorOr<NonnullLockRefPtr<Device>> Device::try_create(USBController const& contr
return device; return device;
} }
Device::Device(USBController const& controller, u8 port, DeviceSpeed speed, NonnullOwnPtr<Pipe> default_pipe) Device::Device(USBController const& controller, u8 port, DeviceSpeed speed, NonnullOwnPtr<ControlPipe> default_pipe)
: m_device_port(port) : m_device_port(port)
, m_device_speed(speed) , m_device_speed(speed)
, m_address(0) , m_address(0)
@ -35,7 +35,7 @@ Device::Device(USBController const& controller, u8 port, DeviceSpeed speed, Nonn
{ {
} }
Device::Device(NonnullLockRefPtr<USBController> controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr<Pipe> default_pipe) Device::Device(NonnullLockRefPtr<USBController> controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr<ControlPipe> default_pipe)
: m_device_port(port) : m_device_port(port)
, m_device_speed(speed) , m_device_speed(speed)
, m_address(address) , m_address(address)
@ -44,7 +44,7 @@ Device::Device(NonnullLockRefPtr<USBController> controller, u8 address, u8 port,
{ {
} }
Device::Device(Device const& device, NonnullOwnPtr<Pipe> default_pipe) Device::Device(Device const& device, NonnullOwnPtr<ControlPipe> default_pipe)
: m_device_port(device.port()) : m_device_port(device.port())
, m_device_speed(device.speed()) , m_device_speed(device.speed())
, m_address(device.address()) , m_address(device.address())

View file

@ -36,8 +36,8 @@ public:
static ErrorOr<NonnullLockRefPtr<Device>> try_create(USBController const&, u8, DeviceSpeed); static ErrorOr<NonnullLockRefPtr<Device>> try_create(USBController const&, u8, DeviceSpeed);
Device(USBController const&, u8, DeviceSpeed, NonnullOwnPtr<Pipe> default_pipe); Device(USBController const&, u8, DeviceSpeed, NonnullOwnPtr<ControlPipe> default_pipe);
Device(Device const& device, NonnullOwnPtr<Pipe> default_pipe); Device(Device const& device, NonnullOwnPtr<ControlPipe> default_pipe);
virtual ~Device(); virtual ~Device();
ErrorOr<void> enumerate_device(); ErrorOr<void> enumerate_device();
@ -59,7 +59,7 @@ public:
SysFSUSBDeviceInformation& sysfs_device_info_node(Badge<USB::Hub>) { return *m_sysfs_device_info_node; } SysFSUSBDeviceInformation& sysfs_device_info_node(Badge<USB::Hub>) { return *m_sysfs_device_info_node; }
protected: protected:
Device(NonnullLockRefPtr<USBController> controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr<Pipe> default_pipe); Device(NonnullLockRefPtr<USBController> controller, u8 address, u8 port, DeviceSpeed speed, NonnullOwnPtr<ControlPipe> default_pipe);
u8 m_device_port { 0 }; // What port is this device attached to. NOTE: This is 1-based. 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 DeviceSpeed m_device_speed; // What speed is this device running at
@ -72,7 +72,7 @@ protected:
Vector<USBConfiguration> m_configurations; // Configurations for this device Vector<USBConfiguration> m_configurations; // Configurations for this device
NonnullLockRefPtr<USBController> m_controller; NonnullLockRefPtr<USBController> m_controller;
NonnullOwnPtr<Pipe> m_default_pipe; // Default communication pipe (endpoint0) used during enumeration NonnullOwnPtr<ControlPipe> m_default_pipe; // Default communication pipe (endpoint0) used during enumeration
private: private:
IntrusiveListNode<Device, NonnullLockRefPtr<Device>> m_hub_child_node; IntrusiveListNode<Device, NonnullLockRefPtr<Device>> m_hub_child_node;

View file

@ -18,25 +18,25 @@ namespace Kernel::USB {
ErrorOr<NonnullLockRefPtr<Hub>> Hub::try_create_root_hub(NonnullLockRefPtr<USBController> controller, DeviceSpeed device_speed) ErrorOr<NonnullLockRefPtr<Hub>> Hub::try_create_root_hub(NonnullLockRefPtr<USBController> 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. // 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)))); auto hub = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Hub(controller, device_speed, move(pipe))));
return hub; return hub;
} }
ErrorOr<NonnullLockRefPtr<Hub>> Hub::try_create_from_device(Device const& device) ErrorOr<NonnullLockRefPtr<Hub>> 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)))); auto hub = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Hub(device, move(pipe))));
TRY(hub->enumerate_and_power_on_hub()); TRY(hub->enumerate_and_power_on_hub());
return hub; return hub;
} }
Hub::Hub(NonnullLockRefPtr<USBController> controller, DeviceSpeed device_speed, NonnullOwnPtr<Pipe> default_pipe) Hub::Hub(NonnullLockRefPtr<USBController> controller, DeviceSpeed device_speed, NonnullOwnPtr<ControlPipe> default_pipe)
: Device(move(controller), 1 /* Port 1 */, device_speed, move(default_pipe)) : Device(move(controller), 1 /* Port 1 */, device_speed, move(default_pipe))
{ {
} }
Hub::Hub(Device const& device, NonnullOwnPtr<Pipe> default_pipe) Hub::Hub(Device const& device, NonnullOwnPtr<ControlPipe> default_pipe)
: Device(device, move(default_pipe)) : Device(device, move(default_pipe))
{ {
} }

View file

@ -96,9 +96,9 @@ public:
private: private:
// Root Hub constructor // Root Hub constructor
Hub(NonnullLockRefPtr<USBController>, DeviceSpeed, NonnullOwnPtr<Pipe> default_pipe); Hub(NonnullLockRefPtr<USBController>, DeviceSpeed, NonnullOwnPtr<ControlPipe> default_pipe);
Hub(Device const&, NonnullOwnPtr<Pipe> default_pipe); Hub(Device const&, NonnullOwnPtr<ControlPipe> default_pipe);
USBHubDescriptor m_hub_descriptor {}; USBHubDescriptor m_hub_descriptor {};

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
* Copyright (c) 2022, blackcat <b14ckcat@protonmail.com>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -12,48 +13,33 @@
namespace Kernel::USB { 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) Pipe::Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer)
{
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)
: 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<Memory::Region> 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<Memory::Region> dma_buffer)
: m_controller(controller) : m_controller(controller)
, m_type(type) , m_type(type)
, m_direction(direction) , m_direction(direction)
, m_device_address(device_address) , m_device_address(device_address)
, m_endpoint_address(endpoint_address) , m_endpoint_address(endpoint_address)
, m_max_packet_size(max_packet_size) , m_max_packet_size(max_packet_size)
, m_poll_interval(poll_interval)
, m_data_toggle(false) , m_data_toggle(false)
, m_dma_buffer(move(dma_buffer)) , m_dma_buffer(move(dma_buffer))
{ {
} }
ErrorOr<size_t> Pipe::control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data) ErrorOr<NonnullOwnPtr<ControlPipe>> 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<Memory::Region> dma_buffer)
: Pipe(controller, Type::Control, Direction::Bidirectional, endpoint_address, max_packet_size, device_address, move(dma_buffer))
{
}
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); MutexLocker lock(m_dma_buffer_lock);
USBRequestData usb_request; 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)); auto transfer = TRY(Transfer::try_create(*this, length, *m_dma_buffer));
transfer->set_setup_packet(usb_request); 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)); auto transfer_length = TRY(m_controller->submit_control_transfer(*transfer));
// TODO: Check transfer for completion and copy data from transfer buffer into data // 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; 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));
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); MutexLocker lock(m_dma_buffer_lock);
size_t transfer_length = 0; size_t transfer_length = 0;
auto transfer = TRY(Transfer::try_create(*this, length, *m_dma_buffer)); 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)); TRY(transfer->write_buffer(length, data));
dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer allocated @ {}", transfer->buffer_physical()); dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer allocated @ {}", transfer->buffer_physical());
transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer)); transfer_length = TRY(m_controller->submit_bulk_transfer(*transfer));
dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer complete!"); dbgln_if(USB_DEBUG, "Pipe: Bulk out transfer complete!");
}
return transfer_length; 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)
{
}
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
* Copyright (c) 2022, blackcat <b14ckcat@protonmail.com>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -15,6 +16,7 @@
namespace Kernel::USB { namespace Kernel::USB {
class USBController; class USBController;
class Transfer;
// //
// A pipe is the logical connection between a memory buffer on the PC (host) and // A pipe is the logical connection between a memory buffer on the PC (host) and
@ -41,8 +43,6 @@ public:
FullSpeed FullSpeed
}; };
static ErrorOr<NonnullOwnPtr<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 = PAGE_SIZE, u8 poll_interval = 0);
Type type() const { return m_type; } Type type() const { return m_type; }
Direction direction() const { return m_direction; } Direction direction() const { return m_direction; }
DeviceSpeed device_speed() const { return m_speed; } DeviceSpeed device_speed() const { return m_speed; }
@ -50,23 +50,17 @@ public:
i8 device_address() const { return m_device_address; } i8 device_address() const { return m_device_address; }
u8 endpoint_address() const { return m_endpoint_address; } u8 endpoint_address() const { return m_endpoint_address; }
u16 max_packet_size() const { return m_max_packet_size; } 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; } bool data_toggle() const { return m_data_toggle; }
void set_max_packet_size(u16 max_size) { m_max_packet_size = max_size; } 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_toggle(bool toggle) { m_data_toggle = toggle; }
void set_device_address(i8 addr) { m_device_address = addr; } void set_device_address(i8 addr) { m_device_address = addr; }
ErrorOr<size_t> control_transfer(u8 request_type, u8 request, u16 value, u16 index, u16 length, void* data); protected:
ErrorOr<size_t> bulk_transfer(u16 length, void* data);
Pipe(USBController const& controller, Type type, Direction direction, u16 max_packet_size, NonnullOwnPtr<Memory::Region> dma_buffer);
Pipe(USBController const& controller, Type type, Direction direction, USBEndpointDescriptor& endpoint, NonnullOwnPtr<Memory::Region> dma_buffer);
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);
private:
friend class Device; friend class Device;
Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer);
NonnullLockRefPtr<USBController> m_controller; NonnullLockRefPtr<USBController> m_controller;
Type m_type; Type m_type;
@ -76,11 +70,77 @@ private:
i8 m_device_address { 0 }; // Device address of this pipe i8 m_device_address { 0 }; // Device address of this pipe
u8 m_endpoint_address { 0 }; // Corresponding endpoint address for 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 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 bool m_data_toggle { false }; // Data toggle for stuffing bit
Mutex m_dma_buffer_lock { "USB pipe mutex"sv }; Mutex m_dma_buffer_lock { "USB pipe mutex"sv };
NonnullOwnPtr<Memory::Region> m_dma_buffer; NonnullOwnPtr<Memory::Region> m_dma_buffer;
}; };
class ControlPipe : public Pipe {
public:
static ErrorOr<NonnullOwnPtr<ControlPipe>> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE);
ErrorOr<size_t> 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<Memory::Region> dma_buffer);
};
class BulkInPipe : public Pipe {
public:
static ErrorOr<NonnullOwnPtr<BulkInPipe>> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE);
ErrorOr<size_t> bulk_in_transfer(size_t length, void* data);
private:
BulkInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer);
};
class BulkOutPipe : public Pipe {
public:
static ErrorOr<NonnullOwnPtr<BulkOutPipe>> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE);
ErrorOr<size_t> bulk_out_transfer(size_t length, void* data);
private:
BulkOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer);
};
class InterruptInPipe : public Pipe {
public:
static ErrorOr<NonnullOwnPtr<InterruptInPipe>> 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<Memory::Region> dma_pool);
u16 m_poll_interval;
};
class InterruptOutPipe : public Pipe {
public:
static ErrorOr<NonnullOwnPtr<InterruptOutPipe>> 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<Memory::Region> dma_pool);
u16 m_poll_interval;
};
class IsochronousInPipe : public Pipe {
// TODO
public:
private:
};
class IsochronousOutPipe : public Pipe {
// TODO
public:
private:
};
} }