[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbehci / hardware.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/hardware.c
5 * PURPOSE: Hardware related routines.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 */
9
10 #include "hardware.h"
11 #define NDEBUG
12 #include <debug.h>
13
14 //FORCEINLINE
15 VOID
16 SetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr)
17 {
18 ULONG OpRegisters = hcd->OpRegisters;
19 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_ASYNCLISTBASE), PhysicalAddr);
20 }
21
22 //FORCEINLINE
23 ULONG
24 GetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd)
25 {
26 ULONG OpRegisters = hcd->OpRegisters;
27 return READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_ASYNCLISTBASE));
28 }
29
30 //FORCEINLINE
31 VOID
32 SetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd, ULONG PhysicalAddr)
33 {
34 ULONG OpRegisters = hcd->OpRegisters;
35 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_PERIODICLISTBASE), PhysicalAddr);
36 }
37
38 //FORCEINLINE
39 ULONG
40 GetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd)
41 {
42 ULONG OpRegisters = hcd->OpRegisters;
43 return READ_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_PERIODICLISTBASE));
44 }
45
46 //FORCEINLINE
47 ULONG
48 ReadControllerStatus(PEHCI_HOST_CONTROLLER hcd)
49 {
50 ULONG OpRegisters = hcd->OpRegisters;
51 return READ_REGISTER_ULONG ((PULONG) (OpRegisters + EHCI_USBSTS));
52 }
53
54 //FORCEINLINE
55 VOID
56 ClearControllerStatus(PEHCI_HOST_CONTROLLER hcd, ULONG Status)
57 {
58 ULONG OpRegisters = hcd->OpRegisters;
59 WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBSTS), Status);
60 }
61
62 VOID
63 ResetPort(PEHCI_HOST_CONTROLLER hcd, UCHAR Port)
64 {
65 ULONG tmp;
66 ULONG OpRegisters = hcd->OpRegisters;
67 DPRINT("Reset Port %x\n", Port);
68
69 tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)));
70 if (tmp & 0x400)
71 {
72 DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
73 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)), 0x2000);
74 }
75
76 /* Get current port state */
77 tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)));
78
79 /* Set reset and clear enable */
80 tmp |= 0x100;
81 tmp &= ~0x04;
82 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)), tmp);
83
84 /* USB 2.0 Spec 10.2.8.1, more than 50ms */
85 KeStallExecutionProcessor(100);
86
87 /* Clear reset */
88 tmp &= ~0x100;
89 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)), tmp);
90
91 KeStallExecutionProcessor(100);
92
93 tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * Port)));
94
95 if (tmp & 0x100)
96 {
97 DPRINT1("EHCI ERROR: Port Reset did not complete!\n");
98 ASSERT(FALSE);
99 }
100 DPRINT("Reset complete\n");
101 }
102
103 VOID
104 StopEhci(PEHCI_HOST_CONTROLLER hcd)
105 {
106 ULONG OpRegisters = hcd->OpRegisters;
107 PEHCI_USBCMD_CONTENT UsbCmd;
108 PEHCI_USBSTS_CONTEXT UsbSts;
109 LONG FailSafe;
110 LONG tmp;
111
112 DPRINT("Stopping Ehci controller\n");
113
114 WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBINTR), 0);
115
116 tmp = READ_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD));
117 UsbCmd = (PEHCI_USBCMD_CONTENT) & tmp;
118 UsbCmd->Run = FALSE;
119 WRITE_REGISTER_ULONG((PULONG) (OpRegisters + EHCI_USBCMD), tmp);
120
121 /* Wait for the device to stop */
122 for (FailSafe = 0; FailSafe < 1000; FailSafe++)
123 {
124 KeStallExecutionProcessor(10);
125 tmp = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS));
126 UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp;
127
128 if (UsbSts->HCHalted)
129 {
130 break;
131 }
132 }
133 if (!UsbSts->HCHalted)
134 {
135 DPRINT1("EHCI ERROR: Controller is not responding to Stop request!\n");
136 ASSERT(FALSE);
137 }
138 }
139
140 VOID
141 StartEhci(PEHCI_HOST_CONTROLLER hcd)
142 {
143 ULONG OpRegisters = hcd->OpRegisters;
144 PEHCI_USBCMD_CONTENT UsbCmd;
145 PEHCI_USBSTS_CONTEXT UsbSts;
146 LONG failSafe;
147 LONG tmp;
148 LONG tmp2;
149
150 DPRINT("Starting Ehci controller\n");
151
152 tmp = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS));
153 UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp;
154
155 if (!UsbSts->HCHalted)
156 {
157 StopEhci(hcd);
158 }
159
160 tmp = READ_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBCMD));
161
162 /* Reset the device */
163 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
164 UsbCmd->HCReset = TRUE;
165 WRITE_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
166
167 /* Wait for the device to reset */
168 for (failSafe = 0; failSafe < 1000; failSafe++)
169 {
170 KeStallExecutionProcessor(10);
171 tmp = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD));
172 UsbCmd = (PEHCI_USBCMD_CONTENT)&tmp;
173
174 if (!UsbCmd->HCReset)
175 {
176 break;
177 }
178 DPRINT("Waiting for reset, USBCMD: %x\n", READ_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBCMD)));
179 }
180
181 if (UsbCmd->HCReset)
182 {
183 DPRINT1("EHCI ERROR: Controller failed to reset! Will attempt to continue.\n");
184 ASSERT(FALSE);
185 }
186
187 UsbCmd = (PEHCI_USBCMD_CONTENT) &tmp;
188
189 /* Disable Interrupts on the device */
190 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBINTR), 0);
191 /* Clear the Status */
192 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS), 0x0000001f);
193
194 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_CTRLDSSEGMENT), 0);
195
196 SetAsyncListQueueRegister(hcd, hcd->AsyncListQueue->PhysicalAddr | QH_TYPE_QH);
197 /* Set the ansync and periodic to disable */
198 UsbCmd->PeriodicEnable = FALSE;
199 UsbCmd->AsyncEnable = TRUE;
200 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
201
202 /* Set the threshold */
203 UsbCmd->IntThreshold = 1;
204 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
205
206 /* Turn back on interrupts */
207 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBINTR),
208 EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
209 /*| EHCI_USBINTR_FLROVR*/ | EHCI_USBINTR_PC);
210 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBINTR),
211 EHCI_USBINTR_INTE | EHCI_USBINTR_ERR | EHCI_USBINTR_ASYNC | EHCI_USBINTR_HSERR
212 /*| EHCI_USBINTR_FLROVR*/ | EHCI_USBINTR_PC);
213
214 UsbCmd->Run = TRUE;
215 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBCMD), tmp);
216
217 /* Wait for the device to start */
218 for (failSafe = 0; failSafe < 1000; failSafe++)
219 {
220 KeStallExecutionProcessor(10);
221 tmp2 = READ_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_USBSTS));
222 UsbSts = (PEHCI_USBSTS_CONTEXT)&tmp2;
223
224 if (!UsbSts->HCHalted)
225 {
226 break;
227 }
228 DPRINT("Waiting for start, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG)(OpRegisters + EHCI_USBSTS)));
229 }
230
231 if (UsbSts->HCHalted)
232 {
233 DPRINT1("EHCI ERROR: Controller failed to start!!!\n");
234 ASSERT(FALSE);
235 }
236 /* Set all port routing to ECHI controller */
237 WRITE_REGISTER_ULONG((PULONG)(OpRegisters + EHCI_CONFIGFLAG), 1);
238 }
239
240 BOOLEAN
241 EnumControllerPorts(PEHCI_HOST_CONTROLLER hcd)
242 {
243 ULONG tmp, i, OpRegisters, ChildDeviceCount = 0;
244 BOOLEAN PortChange = FALSE;
245
246 OpRegisters = (ULONG)hcd->OpRegisters;
247 /* Loop through the ports */
248 for (i = 0; i < hcd->ECHICaps.HCSParams.PortCount; i++)
249 {
250 tmp = READ_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)));
251
252 /* Check for port change on this port */
253 if (tmp & 0x02)
254 {
255 DPRINT1("Port Change\n");
256
257 /* Clear status change */
258 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
259 tmp |= 0x02;
260 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), tmp);
261
262 PortChange = TRUE;
263 /* Connect or Disconnect? */
264 if (tmp & 0x01)
265 {
266 DPRINT1("Device connected on port %d\n", i);
267
268 /* Check if a companion host controller exists */
269 if (hcd->ECHICaps.HCSParams.CHCCount)
270 {
271 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
272
273 /* Port should be in disabled state, as per USB 2.0 specs */
274 if (tmp & 0x04)
275 {
276 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
277 }
278
279 /* Is this non high speed device */
280 if (tmp & 0x400)
281 {
282 DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
283 /* Release ownership to companion host controller */
284 WRITE_REGISTER_ULONG((PULONG) ((OpRegisters + EHCI_PORTSC) + (4 * i)), 0x2000);
285 continue;
286 }
287 }
288
289 KeStallExecutionProcessor(30);
290
291 /* As per USB 2.0 Specs, 9.1.2. Reset the port and clear the status change */
292 //tmp |= 0x100 | 0x02;
293 /* Sanity, Disable port */
294 //tmp &= ~0x04;
295
296 //WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
297
298 //KeStallExecutionProcessor(20);
299
300 tmp = READ_REGISTER_ULONG((PULONG)((OpRegisters + EHCI_PORTSC) + (4 * i)));
301
302 ChildDeviceCount++;
303 hcd->Ports[i].PortStatus &= ~0x8000;
304 DPRINT1("Removed 0x8000\n");
305 ASSERT(FALSE);
306 hcd->Ports[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED;
307 hcd->Ports[i].PortStatus |= USB_PORT_STATUS_CONNECT;
308 hcd->Ports[i].PortChange |= USB_PORT_STATUS_CONNECT;
309 }
310 else
311 {
312 DPRINT1("Device disconnected on port %d\n", i);
313 ChildDeviceCount--;
314 }
315 }
316 }
317 return PortChange;
318 }
319
320 VOID
321 GetCapabilities(PEHCI_CAPS PCap, ULONG CapRegister)
322 {
323 PEHCI_HCS_CONTENT PHCS;
324 LONG i;
325
326 if (!PCap)
327 return;
328
329 PCap->Length = READ_REGISTER_UCHAR((PUCHAR)CapRegister);
330 PCap->Reserved = READ_REGISTER_UCHAR((PUCHAR)(CapRegister + 1));
331 PCap->HCIVersion = READ_REGISTER_USHORT((PUSHORT)(CapRegister + 2));
332 PCap->HCSParamsLong = READ_REGISTER_ULONG((PULONG)(CapRegister + 4));
333 PCap->HCCParams = READ_REGISTER_ULONG((PULONG)(CapRegister + 8));
334
335 DPRINT("Length %d\n", PCap->Length);
336 DPRINT("Reserved %d\n", PCap->Reserved);
337 DPRINT("HCIVersion %x\n", PCap->HCIVersion);
338 DPRINT("HCSParams %x\n", PCap->HCSParamsLong);
339 DPRINT("HCCParams %x\n", PCap->HCCParams);
340
341 if (PCap->HCCParams & 0x02)
342 DPRINT1("Frame list size is configurable\n");
343
344 if (PCap->HCCParams & 0x01)
345 DPRINT1("64bit address mode not supported!\n");
346
347 DPRINT1("Number of Ports: %d\n", PCap->HCSParams.PortCount);
348
349 if (PCap->HCSParams.PortPowerControl)
350 DPRINT1("Port Power Control is enabled\n");
351
352 if (!PCap->HCSParams.CHCCount)
353 {
354 DPRINT1("Number of Companion Host controllers %x\n", PCap->HCSParams.CHCCount);
355 DPRINT1("Number of Ports Per CHC: %d\n", PCap->HCSParams.PortPerCHC);
356 }
357
358 PHCS = (PEHCI_HCS_CONTENT)&PCap->HCSParams;
359 if (PHCS->PortRouteRules)
360 {
361 for (i = 0; i < PCap->HCSParams.PortCount; i++)
362 {
363 PCap->PortRoute[i] = READ_REGISTER_UCHAR((PUCHAR) (CapRegister + 12 + i));
364 }
365 }
366 }