Serenity Operating System
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}