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.
7 * Michael Martin (michael.martin@reactos.org)
16 SetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd
, ULONG PhysicalAddr
)
18 ULONG OpRegisters
= hcd
->OpRegisters
;
19 WRITE_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_ASYNCLISTBASE
), PhysicalAddr
);
24 GetAsyncListQueueRegister(PEHCI_HOST_CONTROLLER hcd
)
26 ULONG OpRegisters
= hcd
->OpRegisters
;
27 return READ_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_ASYNCLISTBASE
));
32 SetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd
, ULONG PhysicalAddr
)
34 ULONG OpRegisters
= hcd
->OpRegisters
;
35 WRITE_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_PERIODICLISTBASE
), PhysicalAddr
);
40 GetPeriodicFrameListRegister(PEHCI_HOST_CONTROLLER hcd
)
42 ULONG OpRegisters
= hcd
->OpRegisters
;
43 return READ_REGISTER_ULONG((PULONG
) (OpRegisters
+ EHCI_PERIODICLISTBASE
));
48 ReadControllerStatus(PEHCI_HOST_CONTROLLER hcd
)
50 ULONG OpRegisters
= hcd
->OpRegisters
;
51 return READ_REGISTER_ULONG ((PULONG
) (OpRegisters
+ EHCI_USBSTS
));
56 ClearControllerStatus(PEHCI_HOST_CONTROLLER hcd
, ULONG Status
)
58 ULONG OpRegisters
= hcd
->OpRegisters
;
59 WRITE_REGISTER_ULONG((PULONG
) (OpRegisters
+ EHCI_USBSTS
), Status
);
63 ResetPort(PEHCI_HOST_CONTROLLER hcd
, UCHAR Port
)
66 ULONG OpRegisters
= hcd
->OpRegisters
;
67 DPRINT("Reset Port %x\n", Port
);
69 tmp
= READ_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * Port
)));
72 DPRINT1("Non HighSpeed device connected. Releasing ownership.\n");
73 WRITE_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * Port
)), 0x2000);
76 /* Get current port state */
77 tmp
= READ_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * Port
)));
79 /* Set reset and clear enable */
82 WRITE_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * Port
)), tmp
);
84 /* USB 2.0 Spec 10.2.8.1, more than 50ms */
85 KeStallExecutionProcessor(100);
89 WRITE_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * Port
)), tmp
);
91 KeStallExecutionProcessor(100);
93 tmp
= READ_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * Port
)));
97 DPRINT1("EHCI ERROR: Port Reset did not complete!\n");
100 DPRINT("Reset complete\n");
104 StopEhci(PEHCI_HOST_CONTROLLER hcd
)
106 ULONG OpRegisters
= hcd
->OpRegisters
;
107 PEHCI_USBCMD_CONTENT UsbCmd
;
108 PEHCI_USBSTS_CONTEXT UsbSts
;
112 DPRINT("Stopping Ehci controller\n");
114 WRITE_REGISTER_ULONG((PULONG
) (OpRegisters
+ EHCI_USBINTR
), 0);
116 tmp
= READ_REGISTER_ULONG((PULONG
) (OpRegisters
+ EHCI_USBCMD
));
117 UsbCmd
= (PEHCI_USBCMD_CONTENT
) & tmp
;
119 WRITE_REGISTER_ULONG((PULONG
) (OpRegisters
+ EHCI_USBCMD
), tmp
);
121 /* Wait for the device to stop */
122 for (FailSafe
= 0; FailSafe
< 1000; FailSafe
++)
124 KeStallExecutionProcessor(10);
125 tmp
= READ_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_USBSTS
));
126 UsbSts
= (PEHCI_USBSTS_CONTEXT
)&tmp
;
128 if (UsbSts
->HCHalted
)
133 if (!UsbSts
->HCHalted
)
135 DPRINT1("EHCI ERROR: Controller is not responding to Stop request!\n");
141 StartEhci(PEHCI_HOST_CONTROLLER hcd
)
143 ULONG OpRegisters
= hcd
->OpRegisters
;
144 PEHCI_USBCMD_CONTENT UsbCmd
;
145 PEHCI_USBSTS_CONTEXT UsbSts
;
150 DPRINT("Starting Ehci controller\n");
152 tmp
= READ_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_USBSTS
));
153 UsbSts
= (PEHCI_USBSTS_CONTEXT
)&tmp
;
155 if (!UsbSts
->HCHalted
)
160 tmp
= READ_REGISTER_ULONG ((PULONG
)(OpRegisters
+ EHCI_USBCMD
));
162 /* Reset the device */
163 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
164 UsbCmd
->HCReset
= TRUE
;
165 WRITE_REGISTER_ULONG ((PULONG
)(OpRegisters
+ EHCI_USBCMD
), tmp
);
167 /* Wait for the device to reset */
168 for (failSafe
= 0; failSafe
< 1000; failSafe
++)
170 KeStallExecutionProcessor(10);
171 tmp
= READ_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_USBCMD
));
172 UsbCmd
= (PEHCI_USBCMD_CONTENT
)&tmp
;
174 if (!UsbCmd
->HCReset
)
178 DPRINT("Waiting for reset, USBCMD: %x\n", READ_REGISTER_ULONG ((PULONG
)(OpRegisters
+ EHCI_USBCMD
)));
183 DPRINT1("EHCI ERROR: Controller failed to reset! Will attempt to continue.\n");
187 UsbCmd
= (PEHCI_USBCMD_CONTENT
) &tmp
;
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);
194 WRITE_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_CTRLDSSEGMENT
), 0);
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
);
202 /* Set the threshold */
203 UsbCmd
->IntThreshold
= 1;
204 WRITE_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_USBCMD
), tmp
);
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
);
215 WRITE_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_USBCMD
), tmp
);
217 /* Wait for the device to start */
218 for (failSafe
= 0; failSafe
< 1000; failSafe
++)
220 KeStallExecutionProcessor(10);
221 tmp2
= READ_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_USBSTS
));
222 UsbSts
= (PEHCI_USBSTS_CONTEXT
)&tmp2
;
224 if (!UsbSts
->HCHalted
)
228 DPRINT("Waiting for start, USBSTS: %x\n", READ_REGISTER_ULONG ((PULONG
)(OpRegisters
+ EHCI_USBSTS
)));
231 if (UsbSts
->HCHalted
)
233 DPRINT1("EHCI ERROR: Controller failed to start!!!\n");
236 /* Set all port routing to ECHI controller */
237 WRITE_REGISTER_ULONG((PULONG
)(OpRegisters
+ EHCI_CONFIGFLAG
), 1);
241 EnumControllerPorts(PEHCI_HOST_CONTROLLER hcd
)
243 ULONG tmp
, i
, OpRegisters
, ChildDeviceCount
= 0;
244 BOOLEAN PortChange
= FALSE
;
246 OpRegisters
= (ULONG
)hcd
->OpRegisters
;
247 /* Loop through the ports */
248 for (i
= 0; i
< hcd
->ECHICaps
.HCSParams
.PortCount
; i
++)
250 tmp
= READ_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
252 /* Check for port change on this port */
255 DPRINT1("Port Change\n");
257 /* Clear status change */
258 tmp
= READ_REGISTER_ULONG((PULONG
)((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
260 WRITE_REGISTER_ULONG((PULONG
) ((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)), tmp
);
263 /* Connect or Disconnect? */
266 DPRINT1("Device connected on port %d\n", i
);
268 /* Check if a companion host controller exists */
269 if (hcd
->ECHICaps
.HCSParams
.CHCCount
)
271 tmp
= READ_REGISTER_ULONG((PULONG
)((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
273 /* Port should be in disabled state, as per USB 2.0 specs */
276 DPRINT1("Warning: The port the device has just connected to is not disabled!\n");
279 /* Is this non high speed device */
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);
289 KeStallExecutionProcessor(30);
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 */
296 //WRITE_REGISTER_ULONG((PULONG) ((Base + EHCI_PORTSC) + (4 * i)), tmp);
298 //KeStallExecutionProcessor(20);
300 tmp
= READ_REGISTER_ULONG((PULONG
)((OpRegisters
+ EHCI_PORTSC
) + (4 * i
)));
303 hcd
->Ports
[i
].PortStatus
&= ~0x8000;
304 DPRINT1("Removed 0x8000\n");
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
;
312 DPRINT1("Device disconnected on port %d\n", i
);
321 GetCapabilities(PEHCI_CAPS PCap
, ULONG CapRegister
)
323 PEHCI_HCS_CONTENT PHCS
;
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));
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
);
341 if (PCap
->HCCParams
& 0x02)
342 DPRINT1("Frame list size is configurable\n");
344 if (PCap
->HCCParams
& 0x01)
345 DPRINT1("64bit address mode not supported!\n");
347 DPRINT1("Number of Ports: %d\n", PCap
->HCSParams
.PortCount
);
349 if (PCap
->HCSParams
.PortPowerControl
)
350 DPRINT1("Port Power Control is enabled\n");
352 if (!PCap
->HCSParams
.CHCCount
)
354 DPRINT1("Number of Companion Host controllers %x\n", PCap
->HCSParams
.CHCCount
);
355 DPRINT1("Number of Ports Per CHC: %d\n", PCap
->HCSParams
.PortPerCHC
);
358 PHCS
= (PEHCI_HCS_CONTENT
)&PCap
->HCSParams
;
359 if (PHCS
->PortRouteRules
)
361 for (i
= 0; i
< PCap
->HCSParams
.PortCount
; i
++)
363 PCap
->PortRoute
[i
] = READ_REGISTER_UCHAR((PUCHAR
) (CapRegister
+ 12 + i
));