Serenity Operating System
at master 150 lines 5.1 kB view raw
1/* 2 * Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com> 3 * Copyright (c) 2022, blackcat <b14ckcat@protonmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#pragma once 9 10#include <AK/OwnPtr.h> 11#include <AK/Types.h> 12#include <Kernel/Bus/USB/USBDescriptors.h> 13#include <Kernel/Locking/Mutex.h> 14#include <Kernel/Memory/Region.h> 15 16namespace Kernel::USB { 17 18class USBController; 19class Transfer; 20 21using USBAsyncCallback = Function<void(Transfer* transfer)>; 22 23// 24// A pipe is the logical connection between a memory buffer on the PC (host) and 25// an endpoint on the device. In this implementation, the data buffer the pipe connects 26// to is the physical buffer created when a Transfer is allocated. 27// 28class Pipe { 29public: 30 enum class Type : u8 { 31 Control = 0, 32 Isochronous = 1, 33 Bulk = 2, 34 Interrupt = 3 35 }; 36 37 enum class Direction : u8 { 38 Out = 0, 39 In = 1, 40 Bidirectional = 2 41 }; 42 43 enum class DeviceSpeed : u8 { 44 LowSpeed, 45 FullSpeed 46 }; 47 48 Type type() const { return m_type; } 49 Direction direction() const { return m_direction; } 50 DeviceSpeed device_speed() const { return m_speed; } 51 52 i8 device_address() const { return m_device_address; } 53 u8 endpoint_address() const { return m_endpoint_address; } 54 u16 max_packet_size() const { return m_max_packet_size; } 55 bool data_toggle() const { return m_data_toggle; } 56 57 void set_max_packet_size(u16 max_size) { m_max_packet_size = max_size; } 58 void set_toggle(bool toggle) { m_data_toggle = toggle; } 59 void set_device_address(i8 addr) { m_device_address = addr; } 60 61protected: 62 friend class Device; 63 64 Pipe(USBController const& controller, Type type, Direction direction, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer); 65 66 NonnullLockRefPtr<USBController> m_controller; 67 68 Type m_type; 69 Direction m_direction; 70 DeviceSpeed m_speed; 71 72 i8 m_device_address { 0 }; // Device address of this pipe 73 u8 m_endpoint_address { 0 }; // Corresponding endpoint address for this pipe 74 u16 m_max_packet_size { 0 }; // Max packet size for this pipe 75 bool m_data_toggle { false }; // Data toggle for stuffing bit 76 77 Mutex m_dma_buffer_lock { "USB pipe mutex"sv }; 78 79 NonnullOwnPtr<Memory::Region> m_dma_buffer; 80}; 81 82class ControlPipe : public Pipe { 83public: 84 static ErrorOr<NonnullOwnPtr<ControlPipe>> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE); 85 86 ErrorOr<size_t> submit_control_transfer(u8 request_type, u8 request, u16 value, u16 index, size_t length, void* data); 87 88private: 89 ControlPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer); 90}; 91 92class BulkInPipe : public Pipe { 93public: 94 static ErrorOr<NonnullOwnPtr<BulkInPipe>> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE); 95 96 ErrorOr<size_t> submit_bulk_in_transfer(size_t length, void* data); 97 98private: 99 BulkInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer); 100}; 101 102class BulkOutPipe : public Pipe { 103public: 104 static ErrorOr<NonnullOwnPtr<BulkOutPipe>> create(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, size_t buffer_size = PAGE_SIZE); 105 106 ErrorOr<size_t> submit_bulk_out_transfer(size_t length, void* data); 107 108private: 109 BulkOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, NonnullOwnPtr<Memory::Region> dma_buffer); 110}; 111 112class InterruptInPipe : public Pipe { 113public: 114 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); 115 116 ErrorOr<NonnullLockRefPtr<Transfer>> submit_interrupt_in_transfer(size_t length, u16 ms_interval, USBAsyncCallback callback); 117 118 u16 poll_interval() const { return m_poll_interval; } 119 120private: 121 InterruptInPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr<Memory::Region> dma_pool); 122 123 u16 m_poll_interval; 124}; 125 126class InterruptOutPipe : public Pipe { 127public: 128 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); 129 130 u16 poll_interval() const { return m_poll_interval; } 131 132private: 133 InterruptOutPipe(USBController const& controller, u8 endpoint_address, u16 max_packet_size, i8 device_address, u16 poll_interval, NonnullOwnPtr<Memory::Region> dma_pool); 134 135 u16 m_poll_interval; 136}; 137 138class IsochronousInPipe : public Pipe { 139 // TODO 140public: 141private: 142}; 143 144class IsochronousOutPipe : public Pipe { 145 // TODO 146public: 147private: 148}; 149 150}