Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
xhci.cpp
Go to the documentation of this file.
1#include "xhci/xhci.hpp"
2#include "ioforge/ioforge.h"
3#include "ioforge/ioforge.hpp"
4#include "memory/kalloc.h"
5
7 op_regs->usbcmd &= ~XHCI_CMD_RS;
8 while (!(op_regs->usbsts & XHCI_STS_HCH)) {
9 IOUtils::sleep(1);
10 }
11
12 op_regs->usbcmd |= XHCI_CMD_HCRST;
13 while (op_regs->usbcmd & XHCI_CMD_HCRST) {
14 IOUtils::sleep(1);
15 }
16
17 while (op_regs->usbsts & XHCI_STS_CNR) {
18 IOUtils::sleep(1);
19 }
20
21 log(mod, "Controller reset complete");
22}
23
25 num_slots = cap_regs->hcsparams1 & 0xFF;
26 num_ports = (cap_regs->hcsparams1 >> 24) & 0xFF;
27 max_intrs = (cap_regs->hcsparams1 >> 8) & 0x7FF;
28
29 log(mod, "Slots: %d, Ports: %d, Interrupters: %d", num_slots, num_ports,
30 max_intrs);
31
32 op_regs->config = num_slots;
33
34 uintptr_t dcbaa_paddr = 0;
35 dcbaa = (uint64_t*) IOUtils::DMAAlloc(
36 sizeof(uint64_t) * (num_slots + 1), &dcbaa_paddr);
37 IOUtils::memset(dcbaa, 0, sizeof(uint64_t) * (num_slots + 1));
38 op_regs->dcbaap = (uint64_t) dcbaa_paddr;
39 dcbaa_phys = dcbaa_paddr;
40
41 uintptr_t cmd_ring_paddr = 0;
42 cmd_ring = (struct xhci_trb*) IOUtils::DMAAlloc(
43 sizeof(struct xhci_trb) * 64, &cmd_ring_paddr);
44 IOUtils::memset(cmd_ring, 0, sizeof(struct xhci_trb) * 64);
45 op_regs->crcr = (uint64_t) cmd_ring_paddr | 1;
46 cmd_ring_phys = cmd_ring_paddr;
48 cmd_ring_pcs = 1;
49
50 uintptr_t erst_paddr = 0;
51 erst = (struct xhci_erst_entry*) IOUtils::DMAAlloc(
52 sizeof(struct xhci_erst_entry), &erst_paddr);
53
54 uintptr_t event_ring_paddr = 0;
55 event_ring = (struct xhci_trb*) IOUtils::DMAAlloc(
56 sizeof(struct xhci_trb) * 64, &event_ring_paddr);
57 IOUtils::memset(event_ring, 0, sizeof(struct xhci_trb) * 64);
58
59 erst[0].ba = (uint64_t) event_ring_paddr;
60 erst[0].size = 64;
61 erst[0].reserved = 0;
62
63 runtime_regs->ir[0].erstsz = 1;
64 runtime_regs->ir[0].erdp =
65 (uint64_t) event_ring_paddr | (1 << 3); // EHB
66 runtime_regs->ir[0].erstba = (uint64_t) erst_paddr;
67 runtime_regs->ir[0].iman |= 3;
68
69 event_ring_phys = event_ring_paddr;
70 erst_phys = erst_paddr;
73
74 op_regs->usbcmd |= XHCI_CMD_RS;
75 while (op_regs->usbsts & XHCI_STS_HCH) {
76 IOUtils::sleep(1);
77 }
78
79 log(mod, "Controller started");
80}
81
83 volatile uint32_t* portsc =
84 (volatile uint32_t*) ((uintptr_t) op_regs + 0x400);
85
86 for (uint32_t i = 0; i < num_ports; i++) {
87 volatile uint32_t* reg = &portsc[i * 4];
89
90 if (status & XHCI_PORT_CCS) {
91 uint32_t speed = (status >> 10) & 0xF;
92 log(mod, "Port %d: Connected (Speed %d)", i + 1, speed);
93
94 if (!(status & XHCI_PORT_PED)) {
95 log(mod, "Port %d: Resetting...", i + 1);
96 *reg |= XHCI_PORT_PR;
97 while (*reg & XHCI_PORT_PR) {
98 IOUtils::sleep(1);
99 }
100 }
101
102 // After reset, enable slot and address device
103 uint8_t slot_id = enable_slot();
104 if (slot_id) {
105 log(mod, "Port %d: Slot %d enabled", i + 1,
106 slot_id);
107 address_device(slot_id, i + 1);
108 }
109 }
110 }
111}
112
114 uint32_t index = cmd_ring_index;
115 cmd_ring[index].ptr = trb->ptr;
116 cmd_ring[index].status = trb->status;
117
118 uint32_t ctrl = trb->control & ~1;
119 if (cmd_ring_pcs)
120 ctrl |= 1;
121 cmd_ring[index].control = ctrl;
122
124 if (cmd_ring_index >= 63) {
125 // Handle link TRB if needed, simplified for now
126 cmd_ring_index = 0;
127 }
128
129 doorbell_regs[0] = 0; // Host controller command ring doorbell
130}
131
132struct xhci_trb XHCIModule::wait_for_event(uint8_t type) {
133 for (int timeout = 0; timeout < 1000; timeout++) {
134 struct xhci_trb event = event_ring[event_ring_index];
135 uint8_t pcs = event.control & 1;
136
137 if (pcs == event_ring_pcs) {
138 uint8_t ev_type = (event.control >> 10) & 0x3F;
139
140 // Update cycle bit logic
142 if (event_ring_index >= 64) {
144 event_ring_pcs ^= 1;
145 }
146
147 runtime_regs->ir[0].erdp =
149 + (event_ring_index * sizeof(struct xhci_trb)))
150 | (1 << 3);
151
152 if (ev_type == type)
153 return event;
154 }
155 IOUtils::sleep(1);
156 }
157 struct xhci_trb empty = {0, 0, 0};
158 return empty;
159}
160
162 struct xhci_trb cmd = {0, 0, (XHCI_TRB_ENABLE_SLOT_CMD << 10)};
165 return (ev.control >> 24) & 0xFF;
166}
167
169 uintptr_t ctx_paddr = 0;
170 struct xhci_device_ctx* dev_ctx =
171 (struct xhci_device_ctx*) IOUtils::DMAAlloc(
172 sizeof(struct xhci_device_ctx), &ctx_paddr);
173 IOUtils::memset(dev_ctx, 0, sizeof(struct xhci_device_ctx));
174
175 slots[slot_id].ctx = dev_ctx;
176 slots[slot_id].ctx_phys = ctx_paddr;
177 slots[slot_id].port_id = port_id;
178 slots[slot_id].active = true;
179 dcbaa[slot_id] = (uint64_t) ctx_paddr;
180
181 // Set Slot Context
182 dev_ctx->slot.info = (1 << 27); // Context entries = 1 (only EP0)
183 dev_ctx->slot.info2 = port_id; // Root hub port number
184
185 // Set EP0 Context
186 uintptr_t ring_paddr = 0;
187 struct xhci_trb* ring = create_transfer_ring(&ring_paddr);
188 dev_ctx->ep[0].info2 = (4 << 3) | (3 << 1); // Control, Error Count 3
189 dev_ctx->ep[0].info2 |=
190 (64 << 16); // Max Packet Size 64 (default for FS/HS/SS)
191 dev_ctx->ep[0].trdp = (uint64_t) ring_paddr | 1; // DCS = 1
192
193 slots[slot_id].rings[0] = ring;
194 slots[slot_id].rings_phys[0] = ring_paddr;
195 slots[slot_id].ring_indices[0] = 0;
196 slots[slot_id].ring_pcs[0] = 1;
197
198 uintptr_t input_paddr = 0;
199 struct xhci_input_ctx* input_ctx =
200 (struct xhci_input_ctx*) IOUtils::DMAAlloc(
201 sizeof(struct xhci_input_ctx), &input_paddr);
202 IOUtils::memset(input_ctx, 0, sizeof(struct xhci_input_ctx));
203
204 input_ctx->input_control.add_flags = 3; // Slot and EP0
205 IOUtils::memcpy(&input_ctx->device, dev_ctx,
206 sizeof(struct xhci_device_ctx));
207
208 struct xhci_trb cmd = {(uint64_t) input_paddr, 0,
210 | (slot_id << 24))};
213}
214
216 struct xhci_trb* ring = (struct xhci_trb*) IOUtils::DMAAlloc(
217 sizeof(struct xhci_trb) * 64, phys);
218 IOUtils::memset(ring, 0, sizeof(struct xhci_trb) * 64);
219 return ring;
220}
221
223 uint32_t data_phys, size_t /*size*/,
224 uint32_t response_phys,
225 size_t response_size) {
226 uint8_t slot_id =
227 addr; // In XHCI, addr corresponds to slot_id in this simplified driver
228 if (!slots[slot_id].active)
229 return;
230
231 uint32_t ep_idx = 0; // EP0 for control transfers
232 struct xhci_trb* ring = slots[slot_id].rings[ep_idx];
233 uint32_t idx = slots[slot_id].ring_indices[ep_idx];
234 uint8_t pcs = slots[slot_id].ring_pcs[ep_idx];
235
236 // 1. Setup Stage
237 ring[idx].ptr = data_phys; // Packet data (8 bytes setup)
238 ring[idx].status = 8; // Length
239 uint32_t ctrl =
241 | (1
242 << 6); // IDT (Immediate Data) - Wait, no, setup is 8 bytes in buffer
243 if (response_phys && response_size > 0)
244 ctrl |= (3 << 16); // TRT = 3 (IN)
245 else
246 ctrl |= (2 << 16); // TRT = 2 (OUT/NoData)
247 if (pcs)
248 ctrl |= 1;
249 ring[idx].control = ctrl;
250
251 idx++;
252 if (idx >= 63)
253 idx = 0; // Simplified ring wrap
254
255 // 2. Data Stage (Optional)
256 if (response_phys && response_size > 0) {
257 ring[idx].ptr = response_phys;
258 ring[idx].status = response_size;
259 ctrl = (XHCI_TRB_DATA_STAGE << 10);
260 ctrl |= (1 << 16); // DIR = 1 (IN)
261 if (pcs)
262 ctrl |= 1;
263 ring[idx].control = ctrl;
264 idx++;
265 if (idx >= 63)
266 idx = 0;
267 }
268
269 // 3. Status Stage
270 ring[idx].ptr = 0;
271 ring[idx].status = 0;
272 ctrl = (XHCI_TRB_STATUS_STAGE << 10) | (1 << 5); // IOC
273 if (pcs)
274 ctrl |= 1;
275 ring[idx].control = ctrl;
276 idx++;
277 if (idx >= 63)
278 idx = 0;
279
280 slots[slot_id].ring_indices[ep_idx] = idx;
281 doorbell_regs[slot_id] = ep_idx + 1; // Doorbell for EP
282
284}
const char * mod
Definition ioforge.hpp:65
uint8_t enable_slot()
Definition xhci.cpp:161
uint32_t max_intrs
Definition xhci.hpp:161
uintptr_t cmd_ring_phys
Definition xhci.hpp:167
void address_device(uint8_t slot_id, uint8_t port_id)
Definition xhci.cpp:168
XHCIModule()
Definition init.cpp:10
struct xhci_trb * create_transfer_ring(uintptr_t *phys)
Definition xhci.cpp:215
struct xhci_trb * cmd_ring
Definition xhci.hpp:166
volatile uint32_t * doorbell_regs
Definition xhci.hpp:157
struct xhci_trb * event_ring
Definition xhci.hpp:171
uintptr_t dcbaa_phys
Definition xhci.hpp:164
void send_async_with_response(uint8_t addr, uint8_t endpoint, uint32_t data_phys, size_t size, uint32_t response_phys, size_t response_size)
Definition xhci.cpp:222
void probe_ports()
Definition xhci.cpp:82
struct XHCIModule::xhci_slot slots[256]
uint32_t num_ports
Definition xhci.hpp:160
uint64_t * dcbaa
Definition xhci.hpp:163
void send_command(struct xhci_trb *trb)
Definition xhci.cpp:113
uint8_t event_ring_pcs
Definition xhci.hpp:174
void reset_controller()
Definition xhci.cpp:6
struct xhci_op_regs * op_regs
Definition xhci.hpp:155
struct xhci_trb wait_for_event(uint8_t type)
Definition xhci.cpp:132
uint32_t event_ring_index
Definition xhci.hpp:173
struct xhci_cap_regs * cap_regs
Definition xhci.hpp:154
uintptr_t event_ring_phys
Definition xhci.hpp:172
uint32_t num_slots
Definition xhci.hpp:159
struct xhci_runtime_regs * runtime_regs
Definition xhci.hpp:156
void init_controller()
Definition xhci.cpp:24
uintptr_t erst_phys
Definition xhci.hpp:193
uint32_t cmd_ring_index
Definition xhci.hpp:168
uint8_t cmd_ring_pcs
Definition xhci.hpp:169
volatile uint64_t addr
Definition e1000.hpp:0
volatile uint8_t cmd
Definition e1000.hpp:3
cpu_register_t reg
Definition thread.h:14
#define log(mod, fmt,...)
Definition ioforge.hpp:12
Definition xhci.hpp:188
struct xhci_slot_ctx slot
Definition xhci.hpp:108
struct xhci_endpoint_ctx ep[31]
Definition xhci.hpp:109
uint64_t trdp
Definition xhci.hpp:102
uint32_t info2
Definition xhci.hpp:101
struct xhci_device_ctx device
Definition xhci.hpp:120
struct xhci_input_control_ctx input_control
Definition xhci.hpp:119
uint32_t info
Definition xhci.hpp:93
uint32_t info2
Definition xhci.hpp:94
uint64_t ptr
Definition xhci.hpp:87
uint32_t status
Definition xhci.hpp:88
uint32_t control
Definition xhci.hpp:89
unsigned int uint32_t
Definition type.h:19
unsigned long uintptr_t
Definition type.h:73
unsigned long uint64_t
Definition type.h:25
unsigned char uint8_t
Definition type.h:7
uint16_t ring[64]
Definition virtio-gpu.hpp:2
uint16_t idx
Definition virtio-gpu.hpp:1
uint8_t type
Definition vnode.h:2
#define XHCI_PORT_PED
Definition xhci.hpp:56
#define XHCI_STS_HCH
Definition xhci.hpp:70
#define XHCI_CMD_RS
Definition xhci.hpp:65
#define XHCI_TRB_STATUS_STAGE
Definition xhci.hpp:77
#define XHCI_TRB_ADDRESS_DEVICE_CMD
Definition xhci.hpp:80
#define XHCI_TRB_ENABLE_SLOT_CMD
Definition xhci.hpp:79
#define XHCI_PORT_PR
Definition xhci.hpp:57
#define XHCI_TRB_TRANSFER_EVENT
Definition xhci.hpp:82
#define XHCI_PORT_CCS
Definition xhci.hpp:55
#define XHCI_TRB_DATA_STAGE
Definition xhci.hpp:76
#define XHCI_CMD_HCRST
Definition xhci.hpp:66
uint32_t status
Definition xhci.hpp:1
#define XHCI_TRB_COMMAND_COMPLETION_EVENT
Definition xhci.hpp:83
#define XHCI_TRB_SETUP_STAGE
Definition xhci.hpp:75
#define XHCI_STS_CNR
Definition xhci.hpp:71