]> git.proxmox.com Git - mirror_edk2.git/blame - QuarkSocPkg/QuarkSouthCluster/Usb/Ohci/Pei/OhcPeim.c
ArmPkg/CompilerIntrinsicsLib: Add uread, uwrite GCC assembly sources
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Usb / Ohci / Pei / OhcPeim.c
CommitLineData
9b6bbcdb
MK
1/** @file\r
2This file contains the implementation of Usb Hc Protocol.\r
3\r
4Copyright (c) 2013-2015 Intel Corporation.\r
5\r
c9f231d0 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
9b6bbcdb
MK
7\r
8**/\r
9\r
10\r
11#include "OhcPeim.h"\r
12\r
13/**\r
14 Submits control transfer to a target USB device.\r
15\r
16 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
17 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
18 @param DeviceAddress The target device address.\r
19 @param DeviceSpeed Target device speed.\r
20 @param MaximumPacketLength Maximum packet size the default control transfer\r
21 endpoint is capable of sending or receiving.\r
22 @param Request USB device request to send.\r
23 @param TransferDirection Specifies the data direction for the data stage.\r
24 @param Data Data buffer to be transmitted or received from USB device.\r
25 @param DataLength The size (in bytes) of the data buffer.\r
26 @param TimeOut Indicates the maximum timeout, in millisecond.\r
27 @param TransferResult Return the result of this control transfer.\r
28\r
29 @retval EFI_SUCCESS Transfer was completed successfully.\r
30 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
31 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
32 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
33 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
34\r
35**/\r
36EFI_STATUS\r
37EFIAPI\r
38OhciControlTransfer (\r
39 IN EFI_PEI_SERVICES **PeiServices,\r
40 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
41 IN UINT8 DeviceAddress,\r
42 IN UINT8 DeviceSpeed,\r
43 IN UINT8 MaxPacketLength,\r
44 IN EFI_USB_DEVICE_REQUEST *Request,\r
45 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
46 IN OUT VOID *Data,\r
47 IN OUT UINTN *DataLength,\r
48 IN UINTN TimeOut,\r
49 OUT UINT32 *TransferResult\r
50 )\r
51{\r
52 USB_OHCI_HC_DEV *Ohc;\r
53 ED_DESCRIPTOR *Ed;\r
54 TD_DESCRIPTOR *HeadTd;\r
55 TD_DESCRIPTOR *SetupTd;\r
56 TD_DESCRIPTOR *DataTd;\r
57 TD_DESCRIPTOR *StatusTd;\r
58 TD_DESCRIPTOR *EmptyTd;\r
59 EFI_STATUS Status;\r
60 UINT32 DataPidDir;\r
61 UINT32 StatusPidDir;\r
62 UINTN TimeCount;\r
63 UINT32 ErrorCode;\r
64\r
65 UINTN ActualSendLength;\r
66 UINTN LeftLength;\r
67 UINT8 DataToggle;\r
68\r
9b6bbcdb
MK
69 EFI_PHYSICAL_ADDRESS ReqMapPhyAddr = 0;\r
70\r
71 UINTN DataMapLength = 0;\r
72 EFI_PHYSICAL_ADDRESS DataMapPhyAddr = 0;\r
73\r
74 HeadTd = NULL;\r
75 DataTd = NULL;\r
76\r
77 if ((TransferDirection != EfiUsbDataOut && TransferDirection != EfiUsbDataIn &&\r
78 TransferDirection != EfiUsbNoData) ||\r
79 Request == NULL || DataLength == NULL || TransferResult == NULL ||\r
80 (TransferDirection == EfiUsbNoData && (*DataLength != 0 || Data != NULL)) ||\r
81 (TransferDirection != EfiUsbNoData && (*DataLength == 0 || Data == NULL)) ||\r
82 (DeviceSpeed != EFI_USB_SPEED_LOW && DeviceSpeed != EFI_USB_SPEED_FULL) ||\r
83 (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
84 MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
85 DEBUG ((EFI_D_INFO, "OhciControlTransfer: EFI_INVALID_PARAMETER\n"));\r
86 return EFI_INVALID_PARAMETER;\r
87 }\r
88\r
89 if (*DataLength > MAX_BYTES_PER_TD) {\r
90 DEBUG ((EFI_D_ERROR, "OhciControlTransfer: Request data size is too large\n"));\r
91 return EFI_INVALID_PARAMETER;\r
92 }\r
93\r
94 Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS(This);\r
95\r
96 if (TransferDirection == EfiUsbDataIn) {\r
97 DataPidDir = TD_IN_PID;\r
98 StatusPidDir = TD_OUT_PID;\r
99 } else {\r
100 DataPidDir = TD_OUT_PID;\r
101 StatusPidDir = TD_IN_PID;\r
102 }\r
103\r
104 OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
105 if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
106 MicroSecondDelay (HC_1_MILLISECOND);\r
107 if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
108 *TransferResult = EFI_USB_ERR_SYSTEM;\r
109 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to disable CONTROL transfer\n"));\r
110 return EFI_DEVICE_ERROR;\r
111 }\r
112 }\r
113 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
114 Ed = OhciCreateED (Ohc);\r
115 if (Ed == NULL) {\r
116 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate ED buffer\n"));\r
117 return EFI_OUT_OF_RESOURCES;\r
118 }\r
119 OhciSetEDField (Ed, ED_SKIP, 1);\r
120 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
121 OhciSetEDField (Ed, ED_ENDPT_NUM, 0);\r
122 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
123 OhciSetEDField (Ed, ED_SPEED, DeviceSpeed);\r
124 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
125 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
126 OhciSetEDField (Ed, ED_PDATA, 0);\r
127 OhciSetEDField (Ed, ED_ZERO, 0);\r
128 OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);\r
129 OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);\r
130 OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);\r
131 OhciAttachEDToList (Ohc, CONTROL_LIST, Ed, NULL);\r
132 //\r
133 // Setup Stage\r
134 //\r
135 if(Request != NULL) {\r
9b6bbcdb
MK
136 ReqMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Request;\r
137 }\r
138 SetupTd = OhciCreateTD (Ohc);\r
139 if (SetupTd == NULL) {\r
140 Status = EFI_OUT_OF_RESOURCES;\r
141 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Setup TD buffer\n"));\r
142 goto FREE_ED_BUFF;\r
143 }\r
144 HeadTd = SetupTd;\r
145 OhciSetTDField (SetupTd, TD_PDATA, 0);\r
146 OhciSetTDField (SetupTd, TD_BUFFER_ROUND, 1);\r
147 OhciSetTDField (SetupTd, TD_DIR_PID, TD_SETUP_PID);\r
148 OhciSetTDField (SetupTd, TD_DELAY_INT, TD_NO_DELAY);\r
149 OhciSetTDField (SetupTd, TD_DT_TOGGLE, 2);\r
150 OhciSetTDField (SetupTd, TD_ERROR_CNT, 0);\r
151 OhciSetTDField (SetupTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
152 OhciSetTDField (SetupTd, TD_CURR_BUFFER_PTR, (UINTN)ReqMapPhyAddr);\r
153 OhciSetTDField (SetupTd, TD_NEXT_PTR, (UINT32) NULL);\r
154 OhciSetTDField (SetupTd, TD_BUFFER_END_PTR, (UINTN)ReqMapPhyAddr + sizeof (EFI_USB_DEVICE_REQUEST) - 1);\r
155 SetupTd->ActualSendLength = 0;\r
156 SetupTd->DataBuffer = NULL;\r
157 SetupTd->NextTDPointer = NULL;\r
158\r
159 DataMapLength = *DataLength;\r
160 if ((Data != NULL) && (DataMapLength != 0)) {\r
161 DataMapPhyAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;\r
162 }\r
163 //\r
164 //Data Stage\r
165 //\r
166 LeftLength = DataMapLength;\r
167 ActualSendLength = DataMapLength;\r
168 DataToggle = 1;\r
169 while (LeftLength > 0) {\r
170 ActualSendLength = LeftLength;\r
171 if (LeftLength > MaxPacketLength) {\r
172 ActualSendLength = MaxPacketLength;\r
173 }\r
174 DataTd = OhciCreateTD (Ohc);\r
175 if (DataTd == NULL) {\r
176 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Data TD buffer\n"));\r
177 Status = EFI_OUT_OF_RESOURCES;\r
178 goto FREE_TD_BUFF;\r
179 }\r
180 OhciSetTDField (DataTd, TD_PDATA, 0);\r
181 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
182 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
183 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
184 OhciSetTDField (DataTd, TD_DT_TOGGLE, DataToggle);\r
185 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
186 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
187 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) DataMapPhyAddr);\r
188 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) DataMapPhyAddr + ActualSendLength - 1);\r
189 OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);\r
190 DataTd->ActualSendLength = ActualSendLength;\r
191 DataTd->DataBuffer = (UINT8 *)(UINTN)DataMapPhyAddr;\r
192 DataTd->NextTDPointer = 0;\r
193 OhciLinkTD (HeadTd, DataTd);\r
194 DataToggle ^= 1;\r
195 DataMapPhyAddr += ActualSendLength;\r
196 LeftLength -= ActualSendLength;\r
197 }\r
198 //\r
199 // Status Stage\r
200 //\r
201 StatusTd = OhciCreateTD (Ohc);\r
202 if (StatusTd == NULL) {\r
203 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Status TD buffer\n"));\r
204 Status = EFI_OUT_OF_RESOURCES;\r
205 goto FREE_TD_BUFF;\r
206 }\r
207 OhciSetTDField (StatusTd, TD_PDATA, 0);\r
208 OhciSetTDField (StatusTd, TD_BUFFER_ROUND, 1);\r
209 OhciSetTDField (StatusTd, TD_DIR_PID, StatusPidDir);\r
210 OhciSetTDField (StatusTd, TD_DELAY_INT, 7);\r
211 OhciSetTDField (StatusTd, TD_DT_TOGGLE, 3);\r
212 OhciSetTDField (StatusTd, TD_ERROR_CNT, 0);\r
213 OhciSetTDField (StatusTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
214 OhciSetTDField (StatusTd, TD_CURR_BUFFER_PTR, (UINT32) NULL);\r
215 OhciSetTDField (StatusTd, TD_NEXT_PTR, (UINT32) NULL);\r
216 OhciSetTDField (StatusTd, TD_BUFFER_END_PTR, (UINT32) NULL);\r
217 StatusTd->ActualSendLength = 0;\r
218 StatusTd->DataBuffer = NULL;\r
219 StatusTd->NextTDPointer = NULL;\r
220 OhciLinkTD (HeadTd, StatusTd);\r
221 //\r
222 // Empty Stage\r
223 //\r
224 EmptyTd = OhciCreateTD (Ohc);\r
225 if (EmptyTd == NULL) {\r
226 Status = EFI_OUT_OF_RESOURCES;\r
227 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to allocate Empty TD buffer\n"));\r
228 goto FREE_TD_BUFF;\r
229 }\r
230 OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
231 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
232 OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
233 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
234 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
235 EmptyTd->Word0.DataToggle = 0;\r
236 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
237 OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
238 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
239 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
240 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
241 EmptyTd->ActualSendLength = 0;\r
242 EmptyTd->DataBuffer = NULL;\r
243 EmptyTd->NextTDPointer = NULL;\r
244 OhciLinkTD (HeadTd, EmptyTd);\r
245 Ed->TdTailPointer = EmptyTd;\r
246 OhciAttachTDListToED (Ed, HeadTd);\r
247 //\r
248 OhciSetEDField (Ed, ED_SKIP, 0);\r
249 MicroSecondDelay (20 * HC_1_MILLISECOND);\r
250 OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED, 1);\r
251 OhciSetHcControl (Ohc, CONTROL_ENABLE, 1);\r
252 MicroSecondDelay (20 * HC_1_MILLISECOND);\r
253 if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {\r
254 MicroSecondDelay (HC_1_MILLISECOND);\r
255 if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 1) {\r
256 *TransferResult = EFI_USB_ERR_SYSTEM;\r
257 Status = EFI_DEVICE_ERROR;\r
258 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Fail to enable CONTROL transfer\n"));\r
259 goto FREE_TD_BUFF;\r
260 }\r
261 }\r
262\r
263 TimeCount = 0;\r
264 Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);\r
265\r
266 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
267 MicroSecondDelay (HC_1_MILLISECOND);\r
268 TimeCount++;\r
269 Status = CheckIfDone (Ohc, CONTROL_LIST, Ed, HeadTd, &ErrorCode);\r
270 }\r
271 //\r
272 *TransferResult = ConvertErrorCode (ErrorCode);\r
273\r
274 if (ErrorCode != TD_NO_ERROR) {\r
275 if (ErrorCode == TD_TOBE_PROCESSED) {\r
276 DEBUG ((EFI_D_INFO, "Control pipe timeout, > %d mS\r\n", TimeOut));\r
277 } else {\r
278 DEBUG ((EFI_D_INFO, "Control pipe broken\r\n"));\r
279 }\r
280\r
281 *DataLength = 0;\r
282 }\r
283\r
284 OhciSetHcControl (Ohc, CONTROL_ENABLE, 0);\r
285 if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
286 MicroSecondDelay (HC_1_MILLISECOND);\r
287 if (OhciGetHcControl (Ohc, CONTROL_ENABLE) != 0) {\r
288 *TransferResult = EFI_USB_ERR_SYSTEM;\r
289 DEBUG ((EFI_D_INFO, "OhciControlTransfer: Cannot disable CONTROL_ENABLE transfer\n"));\r
290 goto FREE_TD_BUFF;\r
291 }\r
292 }\r
293\r
294FREE_TD_BUFF:\r
295 while (HeadTd) {\r
296 DataTd = HeadTd;\r
297 HeadTd = HeadTd->NextTDPointer;\r
298 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
299 }\r
300\r
301FREE_ED_BUFF:\r
302 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
303\r
304 return Status;\r
305}\r
306\r
307/**\r
308 Submits bulk transfer to a bulk endpoint of a USB device.\r
309\r
310 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
311 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
312 @param DeviceAddress Target device address.\r
313 @param EndPointAddress Endpoint number and its direction in bit 7.\r
314 @param MaxiPacketLength Maximum packet size the endpoint is capable of\r
315 sending or receiving.\r
316 @param Data A pointers to the buffers of data to transmit\r
317 from or receive into.\r
318 @param DataLength The lenght of the data buffer.\r
319 @param DataToggle On input, the initial data toggle for the transfer;\r
320 On output, it is updated to to next data toggle to use of\r
321 the subsequent bulk transfer.\r
322 @param TimeOut Indicates the maximum time, in millisecond, which the\r
323 transfer is allowed to complete.\r
324 @param TransferResult A pointer to the detailed result information of the\r
325 bulk transfer.\r
326\r
327 @retval EFI_SUCCESS The transfer was completed successfully.\r
328 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
329 @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
330 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
331 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
332\r
333**/\r
334EFI_STATUS\r
335EFIAPI\r
336OhciBulkTransfer (\r
337 IN EFI_PEI_SERVICES **PeiServices,\r
338 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
339 IN UINT8 DeviceAddress,\r
340 IN UINT8 EndPointAddress,\r
341 IN UINT8 MaxPacketLength,\r
342 IN OUT VOID *Data,\r
343 IN OUT UINTN *DataLength,\r
344 IN OUT UINT8 *DataToggle,\r
345 IN UINTN TimeOut,\r
346 OUT UINT32 *TransferResult\r
347 )\r
348{\r
349 USB_OHCI_HC_DEV *Ohc;\r
350 ED_DESCRIPTOR *Ed;\r
9b6bbcdb
MK
351 UINT32 DataPidDir;\r
352 TD_DESCRIPTOR *HeadTd;\r
353 TD_DESCRIPTOR *DataTd;\r
354 TD_DESCRIPTOR *EmptyTd;\r
355 EFI_STATUS Status;\r
9b6bbcdb
MK
356 UINT8 EndPointNum;\r
357 UINTN TimeCount;\r
358 UINT32 ErrorCode;\r
359\r
360 UINT8 CurrentToggle;\r
9b6bbcdb
MK
361 UINTN MapLength;\r
362 EFI_PHYSICAL_ADDRESS MapPyhAddr;\r
363 UINTN LeftLength;\r
364 UINTN ActualSendLength;\r
365 BOOLEAN FirstTD;\r
366\r
9b6bbcdb
MK
367 MapLength = 0;\r
368 MapPyhAddr = 0;\r
369 LeftLength = 0;\r
370 Status = EFI_SUCCESS;\r
371\r
372 if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL ||\r
373 *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) ||\r
374 (MaxPacketLength != 8 && MaxPacketLength != 16 &&\r
375 MaxPacketLength != 32 && MaxPacketLength != 64)) {\r
376 return EFI_INVALID_PARAMETER;\r
377 }\r
378\r
379 Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
380\r
381 if ((EndPointAddress & 0x80) != 0) {\r
9b6bbcdb
MK
382 DataPidDir = TD_IN_PID;\r
383 } else {\r
9b6bbcdb
MK
384 DataPidDir = TD_OUT_PID;\r
385 }\r
386\r
387 EndPointNum = (EndPointAddress & 0xF);\r
388\r
389 OhciSetHcControl (Ohc, BULK_ENABLE, 0);\r
390 if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {\r
391 MicroSecondDelay (HC_1_MILLISECOND);\r
392 if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) {\r
393 *TransferResult = EFI_USB_ERR_SYSTEM;\r
394 return EFI_DEVICE_ERROR;\r
395 }\r
396 }\r
397\r
398 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
399\r
400 Ed = OhciCreateED (Ohc);\r
401 if (Ed == NULL) {\r
402 DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n"));\r
403 return EFI_OUT_OF_RESOURCES;\r
404 }\r
405 OhciSetEDField (Ed, ED_SKIP, 1);\r
406 OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress);\r
407 OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum);\r
408 OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR);\r
409 OhciSetEDField (Ed, ED_SPEED, HI_SPEED);\r
410 OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0);\r
411 OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength);\r
412 OhciSetEDField (Ed, ED_PDATA, 0);\r
413 OhciSetEDField (Ed, ED_ZERO, 0);\r
414 OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL);\r
415 OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL);\r
416 OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL);\r
417 OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL);\r
418\r
419 if(Data != NULL) {\r
420 MapLength = *DataLength;\r
421 MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data;\r
422 }\r
423 //\r
424 //Data Stage\r
425 //\r
426 LeftLength = MapLength;\r
427 ActualSendLength = MapLength;\r
428 CurrentToggle = *DataToggle;\r
429 HeadTd = NULL;\r
430 FirstTD = TRUE;\r
431 while (LeftLength > 0) {\r
432 ActualSendLength = LeftLength;\r
433 if (LeftLength > MaxPacketLength) {\r
434 ActualSendLength = MaxPacketLength;\r
435 }\r
436 DataTd = OhciCreateTD (Ohc);\r
437 if (DataTd == NULL) {\r
438 DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n"));\r
439 Status = EFI_OUT_OF_RESOURCES;\r
440 goto FREE_TD_BUFF;\r
441 }\r
442 OhciSetTDField (DataTd, TD_PDATA, 0);\r
443 OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1);\r
444 OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir);\r
445 OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY);\r
446 OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle);\r
447 OhciSetTDField (DataTd, TD_ERROR_CNT, 0);\r
448 OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED);\r
449 OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr);\r
450 OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1);\r
451 OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL);\r
452 DataTd->ActualSendLength = ActualSendLength;\r
453 DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr;\r
454 DataTd->NextTDPointer = 0;\r
455 if (FirstTD) {\r
456 HeadTd = DataTd;\r
457 FirstTD = FALSE;\r
458 } else {\r
459 OhciLinkTD (HeadTd, DataTd);\r
460 }\r
461 CurrentToggle ^= 1;\r
462 MapPyhAddr += ActualSendLength;\r
463 LeftLength -= ActualSendLength;\r
464 }\r
465 //\r
466 // Empty Stage\r
467 //\r
468 EmptyTd = OhciCreateTD (Ohc);\r
469 if (EmptyTd == NULL) {\r
470 Status = EFI_OUT_OF_RESOURCES;\r
471 DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n"));\r
472 goto FREE_TD_BUFF;\r
473 }\r
474 OhciSetTDField (EmptyTd, TD_PDATA, 0);\r
475 OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0);\r
476 OhciSetTDField (EmptyTd, TD_DIR_PID, 0);\r
477 OhciSetTDField (EmptyTd, TD_DELAY_INT, 0);\r
478 //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle);\r
479 EmptyTd->Word0.DataToggle = 0;\r
480 OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0);\r
481 OhciSetTDField (EmptyTd, TD_COND_CODE, 0);\r
482 OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0);\r
483 OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0);\r
484 OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0);\r
485 EmptyTd->ActualSendLength = 0;\r
486 EmptyTd->DataBuffer = NULL;\r
487 EmptyTd->NextTDPointer = NULL;\r
488 OhciLinkTD (HeadTd, EmptyTd);\r
489 Ed->TdTailPointer = EmptyTd;\r
490 OhciAttachTDListToED (Ed, HeadTd);\r
491\r
492 OhciSetEDField (Ed, ED_SKIP, 0);\r
493 OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1);\r
494 OhciSetHcControl (Ohc, BULK_ENABLE, 1);\r
495 if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {\r
496 MicroSecondDelay (HC_1_MILLISECOND);\r
497 if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) {\r
498 *TransferResult = EFI_USB_ERR_SYSTEM;\r
499 goto FREE_TD_BUFF;\r
500 }\r
501 }\r
502\r
503 TimeCount = 0;\r
504 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);\r
505\r
506 while (Status == EFI_NOT_READY && TimeCount <= TimeOut) {\r
507 MicroSecondDelay (HC_1_MILLISECOND);\r
508 TimeCount++;\r
509 Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode);\r
510 }\r
511\r
512 *TransferResult = ConvertErrorCode (ErrorCode);\r
513\r
514 if (ErrorCode != TD_NO_ERROR) {\r
515 if (ErrorCode == TD_TOBE_PROCESSED) {\r
516 DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut));\r
517 } else {\r
518 DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n"));\r
519 }\r
520 *DataLength = 0;\r
521 }\r
522 *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE);\r
523\r
524FREE_TD_BUFF:\r
525 while (HeadTd) {\r
526 DataTd = HeadTd;\r
527 HeadTd = HeadTd->NextTDPointer;\r
528 UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));\r
529 }\r
530 UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));\r
531\r
532 return Status;\r
533}\r
534/**\r
535 Retrieves the number of root hub ports.\r
536\r
537 @param[in] PeiServices The pointer to the PEI Services Table.\r
538 @param[in] This The pointer to this instance of the\r
539 PEI_USB_HOST_CONTROLLER_PPI.\r
540 @param[out] NumOfPorts The pointer to the number of the root hub ports.\r
541\r
542 @retval EFI_SUCCESS The port number was retrieved successfully.\r
543 @retval EFI_INVALID_PARAMETER PortNumber is NULL.\r
544\r
545**/\r
546\r
547EFI_STATUS\r
548EFIAPI\r
549OhciGetRootHubNumOfPorts (\r
550 IN EFI_PEI_SERVICES **PeiServices,\r
551 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
552 OUT UINT8 *NumOfPorts\r
553 )\r
554{\r
555 USB_OHCI_HC_DEV *Ohc;\r
556 if (NumOfPorts == NULL) {\r
557 return EFI_INVALID_PARAMETER;\r
558 }\r
559 Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
560 *NumOfPorts = (UINT8)OhciGetRootHubDescriptor(Ohc, RH_NUM_DS_PORTS);\r
561\r
562 return EFI_SUCCESS;\r
563}\r
564/**\r
565 Retrieves the current status of a USB root hub port.\r
566\r
567 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
568 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
569 @param PortNumber The root hub port to retrieve the state from.\r
570 @param PortStatus Variable to receive the port state.\r
571\r
572 @retval EFI_SUCCESS The status of the USB root hub port specified.\r
573 by PortNumber was returned in PortStatus.\r
574 @retval EFI_INVALID_PARAMETER PortNumber is invalid.\r
575\r
576**/\r
577\r
578EFI_STATUS\r
579EFIAPI\r
580OhciGetRootHubPortStatus (\r
581 IN EFI_PEI_SERVICES **PeiServices,\r
582 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
583 IN UINT8 PortNumber,\r
584 OUT EFI_USB_PORT_STATUS *PortStatus\r
585 )\r
586{\r
587 USB_OHCI_HC_DEV *Ohc;\r
588 UINT8 NumOfPorts;\r
589\r
590 Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
591\r
592 OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);\r
593 if (PortNumber >= NumOfPorts) {\r
594 return EFI_INVALID_PARAMETER;\r
595 }\r
596 PortStatus->PortStatus = 0;\r
597 PortStatus->PortChangeStatus = 0;\r
598\r
599 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_CURR_CONNECT_STAT)) {\r
600 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
601 }\r
602 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_ENABLE_STAT)) {\r
603 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
604 }\r
605 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_SUSPEND_STAT)) {\r
606 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
607 }\r
608 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_OC_INDICATOR)) {\r
609 PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
610 }\r
611 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_RESET_STAT)) {\r
612 PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
613 }\r
614 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_PORT_POWER_STAT)) {\r
615 PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
616 }\r
617 if (OhciReadRootHubPortStatus (Ohc,PortNumber, RH_LSDEVICE_ATTACHED)) {\r
618 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
619 }\r
620 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE)) {\r
621 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
622 }\r
623 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE)) {\r
624 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
625 }\r
626 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE)) {\r
627 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_SUSPEND;\r
628 }\r
629 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE)) {\r
630 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
631 }\r
632 if (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE)) {\r
633 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_RESET;\r
634 }\r
635\r
636 return EFI_SUCCESS;\r
637}\r
638/**\r
639 Sets a feature for the specified root hub port.\r
640\r
641 @param PeiServices The pointer of EFI_PEI_SERVICES\r
642 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI\r
643 @param PortNumber Root hub port to set.\r
644 @param PortFeature Feature to set.\r
645\r
646 @retval EFI_SUCCESS The feature specified by PortFeature was set.\r
647 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
648 @retval EFI_TIMEOUT The time out occurred.\r
649\r
650**/\r
651\r
652EFI_STATUS\r
653EFIAPI\r
654OhciSetRootHubPortFeature (\r
655 IN EFI_PEI_SERVICES **PeiServices,\r
656 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
657 IN UINT8 PortNumber,\r
658 IN EFI_USB_PORT_FEATURE PortFeature\r
659 )\r
660{\r
661 USB_OHCI_HC_DEV *Ohc;\r
662 EFI_STATUS Status;\r
663 UINT8 NumOfPorts;\r
664 UINTN RetryTimes;\r
665\r
666 OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);\r
667 if (PortNumber >= NumOfPorts) {\r
668 return EFI_INVALID_PARAMETER;\r
669 }\r
670\r
671 Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
672\r
673 Status = EFI_SUCCESS;\r
674\r
675\r
676 switch (PortFeature) {\r
677 case EfiUsbPortPower:\r
678 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_POWER);\r
679\r
680 //\r
681 // Verify the state\r
682 //\r
683 RetryTimes = 0;\r
684 do {\r
685 MicroSecondDelay (HC_1_MILLISECOND);\r
686 RetryTimes++;\r
687 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 0 &&\r
688 RetryTimes < MAX_RETRY_TIMES);\r
689\r
690 if (RetryTimes >= MAX_RETRY_TIMES) {\r
691 return EFI_DEVICE_ERROR;\r
692 }\r
693 break;\r
694\r
695 case EfiUsbPortReset:\r
696 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_RESET);\r
697\r
698 //\r
699 // Verify the state\r
700 //\r
701 RetryTimes = 0;\r
702 do {\r
703 MicroSecondDelay (HC_1_MILLISECOND);\r
704 RetryTimes++;\r
705 } while ((OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 0 ||\r
706 OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT) == 1) &&\r
707 RetryTimes < MAX_RETRY_TIMES);\r
708\r
709 if (RetryTimes >= MAX_RETRY_TIMES) {\r
710 return EFI_DEVICE_ERROR;\r
711 }\r
712\r
713 OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
714 break;\r
715\r
716 case EfiUsbPortEnable:\r
717 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_ENABLE);\r
718\r
719 //\r
720 // Verify the state\r
721 //\r
722 RetryTimes = 0;\r
723 do {\r
724 MicroSecondDelay (HC_1_MILLISECOND);;\r
725 RetryTimes++;\r
726 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 0 &&\r
727 RetryTimes < MAX_RETRY_TIMES);\r
728\r
729 if (RetryTimes >= MAX_RETRY_TIMES) {\r
730 return EFI_DEVICE_ERROR;\r
731 }\r
732 break;\r
733\r
734\r
735 case EfiUsbPortSuspend:\r
736 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_SET_PORT_SUSPEND);\r
737\r
738 //\r
739 // Verify the state\r
740 //\r
741 RetryTimes = 0;\r
742 do {\r
743 MicroSecondDelay (HC_1_MILLISECOND);;\r
744 RetryTimes++;\r
745 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 0 &&\r
746 RetryTimes < MAX_RETRY_TIMES);\r
747\r
748 if (RetryTimes >= MAX_RETRY_TIMES) {\r
749 return EFI_DEVICE_ERROR;\r
750 }\r
751 break;\r
752\r
753 default:\r
754 return EFI_INVALID_PARAMETER;\r
755 }\r
756\r
757 return Status;\r
758}\r
759\r
760/**\r
761 Clears a feature for the specified root hub port.\r
762\r
763 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
764 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
765 @param PortNumber Specifies the root hub port whose feature\r
766 is requested to be cleared.\r
767 @param PortFeature Indicates the feature selector associated with the\r
768 feature clear request.\r
769\r
770 @retval EFI_SUCCESS The feature specified by PortFeature was cleared\r
771 for the USB root hub port specified by PortNumber.\r
772 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.\r
773\r
774**/\r
775\r
776EFI_STATUS\r
777EFIAPI\r
778OhciClearRootHubPortFeature (\r
779 IN EFI_PEI_SERVICES **PeiServices,\r
780 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
781 IN UINT8 PortNumber,\r
782 IN EFI_USB_PORT_FEATURE PortFeature\r
783 )\r
784{\r
785 USB_OHCI_HC_DEV *Ohc;\r
786 EFI_STATUS Status;\r
787 UINT8 NumOfPorts;\r
788 UINTN RetryTimes;\r
789\r
790\r
791 OhciGetRootHubNumOfPorts (PeiServices, This, &NumOfPorts);\r
792 if (PortNumber >= NumOfPorts) {\r
793 return EFI_INVALID_PARAMETER;\r
794 }\r
795\r
796 Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This);\r
797\r
798 Status = EFI_SUCCESS;\r
799\r
800 switch (PortFeature) {\r
801 case EfiUsbPortEnable:\r
802 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_ENABLE);\r
803\r
804 //\r
805 // Verify the state\r
806 //\r
807 RetryTimes = 0;\r
808 do {\r
809 MicroSecondDelay (HC_1_MILLISECOND);\r
810 RetryTimes++;\r
811 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT) == 1 &&\r
812 RetryTimes < MAX_RETRY_TIMES);\r
813\r
814 if (RetryTimes >= MAX_RETRY_TIMES) {\r
815 return EFI_DEVICE_ERROR;\r
816 }\r
817 break;\r
818\r
819 case EfiUsbPortSuspend:\r
820 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_SUSPEND_STATUS);\r
821\r
822 //\r
823 // Verify the state\r
824 //\r
825 RetryTimes = 0;\r
826 do {\r
827 MicroSecondDelay (HC_1_MILLISECOND);\r
828 RetryTimes++;\r
829 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT) == 1 &&\r
830 RetryTimes < MAX_RETRY_TIMES);\r
831\r
832 if (RetryTimes >= MAX_RETRY_TIMES) {\r
833 return EFI_DEVICE_ERROR;\r
834 }\r
835 break;\r
836\r
837 case EfiUsbPortReset:\r
838 break;\r
839\r
840 case EfiUsbPortPower:\r
841 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CLEAR_PORT_POWER);\r
842\r
843 //\r
844 // Verify the state\r
845 //\r
846 RetryTimes = 0;\r
847 do {\r
848 MicroSecondDelay (HC_1_MILLISECOND);\r
849 RetryTimes++;\r
850 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_POWER_STAT) == 1 &&\r
851 RetryTimes < MAX_RETRY_TIMES);\r
852\r
853 if (RetryTimes >= MAX_RETRY_TIMES) {\r
854 return EFI_DEVICE_ERROR;\r
855 }\r
856 break;\r
857\r
858 case EfiUsbPortConnectChange:\r
859 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE);\r
860\r
861 //\r
862 // Verify the state\r
863 //\r
864 RetryTimes = 0;\r
865 do {\r
866 MicroSecondDelay (HC_1_MILLISECOND);\r
867 RetryTimes++;\r
868 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_CONNECT_STATUS_CHANGE) == 1 &&\r
869 RetryTimes < MAX_RETRY_TIMES);\r
870\r
871 if (RetryTimes >= MAX_RETRY_TIMES) {\r
872 return EFI_DEVICE_ERROR;\r
873 }\r
874 break;\r
875\r
876 case EfiUsbPortResetChange:\r
877 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE);\r
878\r
879 //\r
880 // Verify the state\r
881 //\r
882 RetryTimes = 0;\r
883 do {\r
884 MicroSecondDelay (HC_1_MILLISECOND);\r
885 RetryTimes++;\r
886 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_RESET_STAT_CHANGE) == 1 &&\r
887 RetryTimes < MAX_RETRY_TIMES);\r
888\r
889 if (RetryTimes >= MAX_RETRY_TIMES) {\r
890 return EFI_DEVICE_ERROR;\r
891 }\r
892 break;\r
893\r
894\r
895 case EfiUsbPortEnableChange:\r
896 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE);\r
897\r
898 //\r
899 // Verify the state\r
900 //\r
901 RetryTimes = 0;\r
902 do {\r
903 MicroSecondDelay (HC_1_MILLISECOND);\r
904 RetryTimes++;\r
905 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_ENABLE_STAT_CHANGE) == 1 &&\r
906 RetryTimes < MAX_RETRY_TIMES);\r
907\r
908 if (RetryTimes >= MAX_RETRY_TIMES) {\r
909 return EFI_DEVICE_ERROR;\r
910 }\r
911 break;\r
912\r
913 case EfiUsbPortSuspendChange:\r
914 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE);\r
915\r
916 //\r
917 // Verify the state\r
918 //\r
919 RetryTimes = 0;\r
920 do {\r
921 MicroSecondDelay (HC_1_MILLISECOND);\r
922 RetryTimes++;\r
923 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_PORT_SUSPEND_STAT_CHANGE) == 1 &&\r
924 RetryTimes < MAX_RETRY_TIMES);\r
925\r
926 if (RetryTimes >= MAX_RETRY_TIMES) {\r
927 return EFI_DEVICE_ERROR;\r
928 }\r
929 break;\r
930\r
931 case EfiUsbPortOverCurrentChange:\r
932 Status = OhciSetRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE);\r
933\r
934 //\r
935 // Verify the state\r
936 //\r
937 RetryTimes = 0;\r
938 do {\r
939 MicroSecondDelay (HC_1_MILLISECOND);\r
940 RetryTimes++;\r
941 } while (OhciReadRootHubPortStatus (Ohc, PortNumber, RH_OC_INDICATOR_CHANGE) == 1 &&\r
942 RetryTimes < MAX_RETRY_TIMES);\r
943\r
944 if (RetryTimes >= MAX_RETRY_TIMES) {\r
945 return EFI_DEVICE_ERROR;\r
946 }\r
947 break;\r
948\r
949 default:\r
950 return EFI_INVALID_PARAMETER;\r
951 }\r
952\r
953 return Status;\r
954}\r
955/**\r
956 Provides software reset for the USB host controller.\r
957\r
958 @param This This EFI_USB_HC_PROTOCOL instance.\r
959 @param Attributes A bit mask of the reset operation to perform.\r
960\r
961 @retval EFI_SUCCESS The reset operation succeeded.\r
962 @retval EFI_INVALID_PARAMETER Attributes is not valid.\r
963 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is\r
964 not currently supported by the host controller.\r
965 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.\r
966\r
967**/\r
968EFI_STATUS\r
969InitializeUsbHC (\r
970 IN EFI_PEI_SERVICES **PeiServices,\r
971 IN USB_OHCI_HC_DEV *Ohc,\r
972 IN UINT16 Attributes\r
973 )\r
974{\r
975 EFI_STATUS Status;\r
976 UINT8 Index;\r
977 UINT8 NumOfPorts;\r
978 UINT32 PowerOnGoodTime;\r
979 UINT32 Data32;\r
980 BOOLEAN Flag = FALSE;\r
981\r
982 if ((Attributes & ~(EFI_USB_HC_RESET_GLOBAL | EFI_USB_HC_RESET_HOST_CONTROLLER)) != 0) {\r
983 return EFI_INVALID_PARAMETER;\r
984 }\r
985 Status = EFI_SUCCESS;\r
986\r
987 if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {\r
988 MicroSecondDelay (50 * HC_1_MILLISECOND);\r
989 Status = OhciSetHcCommandStatus (Ohc, HC_RESET, HC_RESET);\r
990 if (EFI_ERROR (Status)) {\r
991 return EFI_DEVICE_ERROR;\r
992 }\r
993 MicroSecondDelay (50 * HC_1_MILLISECOND);\r
994 //\r
995 // Wait for host controller reset.\r
996 //\r
997 PowerOnGoodTime = 50;\r
998 do {\r
999 MicroSecondDelay (HC_1_MILLISECOND);\r
1000 Data32 = OhciGetOperationalReg (Ohc, HC_COMMAND_STATUS );\r
1001 if ((Data32 & HC_RESET) == 0) {\r
1002 Flag = TRUE;\r
1003 break;\r
1004 }\r
1005 }while(PowerOnGoodTime--);\r
1006 if (!Flag){\r
1007 return EFI_DEVICE_ERROR;\r
1008 }\r
1009 }\r
1010\r
1011 OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
1012 if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {\r
1013 Status = OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_RESET);\r
1014 if (EFI_ERROR (Status)) {\r
1015 return EFI_DEVICE_ERROR;\r
1016 }\r
1017 MicroSecondDelay (50 * HC_1_MILLISECOND);\r
1018 }\r
1019 //\r
1020 // Initialize host controller operational registers\r
1021 //\r
1022 OhciSetFrameInterval (Ohc, FS_LARGEST_DATA_PACKET, 0x2778);\r
1023 OhciSetFrameInterval (Ohc, FRAME_INTERVAL, 0x2edf);\r
1024 OhciSetPeriodicStart (Ohc, 0x2a2f);\r
1025 OhciSetHcControl (Ohc, CONTROL_BULK_RATIO, 0x0);\r
1026 OhciSetHcCommandStatus (Ohc, CONTROL_LIST_FILLED | BULK_LIST_FILLED, 0);\r
1027 OhciSetRootHubDescriptor (Ohc, RH_PSWITCH_MODE, 0);\r
1028 OhciSetRootHubDescriptor (Ohc, RH_NO_PSWITCH | RH_NOC_PROT, 1);\r
1029 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NO_PSWITCH, 0);\r
1030 //OhciSetRootHubDescriptor (Hc, RH_PSWITCH_MODE | RH_NOC_PROT, 1);\r
1031\r
1032 OhciSetRootHubDescriptor (Ohc, RH_DEV_REMOVABLE, 0);\r
1033 OhciSetRootHubDescriptor (Ohc, RH_PORT_PWR_CTRL_MASK, 0xffff);\r
1034 OhciSetRootHubStatus (Ohc, RH_LOCAL_PSTAT_CHANGE);\r
1035 OhciSetRootHubPortStatus (Ohc, 0, RH_SET_PORT_POWER);\r
1036 OhciGetRootHubNumOfPorts (PeiServices, &Ohc->UsbHostControllerPpi, &NumOfPorts);\r
1037 for (Index = 0; Index < NumOfPorts; Index++) {\r
1038 if (!EFI_ERROR (OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset))) {\r
1039 MicroSecondDelay (200 * HC_1_MILLISECOND);\r
1040 OhciClearRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortReset);\r
1041 MicroSecondDelay (HC_1_MILLISECOND);\r
1042 OhciSetRootHubPortFeature (PeiServices, &Ohc->UsbHostControllerPpi, Index, EfiUsbPortEnable);\r
1043 MicroSecondDelay (HC_1_MILLISECOND);\r
1044 }\r
1045 }\r
1046\r
1047 Ohc->MemPool = UsbHcInitMemPool(TRUE, 0);\r
1048 if(Ohc->MemPool == NULL) {\r
1049 return EFI_OUT_OF_RESOURCES;\r
1050 }\r
1051 OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, NULL);\r
1052 OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL);\r
1053 OhciSetHcControl (Ohc, CONTROL_ENABLE | BULK_ENABLE, 1);\r
1054 OhciSetHcControl (Ohc, HC_FUNCTIONAL_STATE, HC_STATE_OPERATIONAL);\r
1055 MicroSecondDelay (50 * HC_1_MILLISECOND);\r
1056 //\r
1057 // Wait till first SOF occurs, and then clear it\r
1058 //\r
1059 while (OhciGetHcInterruptStatus (Ohc, START_OF_FRAME) == 0);\r
1060 OhciClearInterruptStatus (Ohc, START_OF_FRAME);\r
1061 MicroSecondDelay (HC_1_MILLISECOND);\r
1062\r
1063 return EFI_SUCCESS;\r
1064}\r
1065\r
1066/**\r
1067 Submits control transfer to a target USB device.\r
1068\r
1069 Calls underlying OhciControlTransfer to do work. This wrapper routine required\r
1070 on Quark so that USB DMA transfers do not cause an IMR violation.\r
1071\r
1072 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
1073 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
1074 @param DeviceAddress The target device address.\r
1075 @param DeviceSpeed Target device speed.\r
1076 @param MaximumPacketLength Maximum packet size the default control transfer\r
1077 endpoint is capable of sending or receiving.\r
1078 @param Request USB device request to send.\r
1079 @param TransferDirection Specifies the data direction for the data stage.\r
1080 @param Data Data buffer to be transmitted or received from USB device.\r
1081 @param DataLength The size (in bytes) of the data buffer.\r
1082 @param TimeOut Indicates the maximum timeout, in millisecond.\r
1083 @param TransferResult Return the result of this control transfer.\r
1084\r
1085 @retval EFI_SUCCESS Transfer was completed successfully.\r
1086 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.\r
1087 @retval EFI_INVALID_PARAMETER Some parameters are invalid.\r
1088 @retval EFI_TIMEOUT Transfer failed due to timeout.\r
1089 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.\r
1090\r
1091**/\r
1092EFI_STATUS\r
1093EFIAPI\r
1094RedirectOhciControlTransfer (\r
1095 IN EFI_PEI_SERVICES **PeiServices,\r
1096 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
1097 IN UINT8 DeviceAddress,\r
1098 IN UINT8 DeviceSpeed,\r
1099 IN UINT8 MaxPacketLength,\r
1100 IN EFI_USB_DEVICE_REQUEST *Request,\r
1101 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
1102 IN OUT VOID *Data,\r
1103 IN OUT UINTN *DataLength,\r
1104 IN UINTN TimeOut,\r
1105 OUT UINT32 *TransferResult\r
1106 )\r
1107{\r
1108 EFI_STATUS Status;\r
1109 EFI_USB_DEVICE_REQUEST *NewRequest;\r
1110 VOID *NewData;\r
1111 UINT8 *Alloc;\r
1112\r
1113 //\r
1114 // Allocate memory external to IMR protected region for transfer data.\r
1115 //\r
1116 Status = PeiServicesAllocatePool (\r
1117 sizeof(EFI_USB_DEVICE_REQUEST) + *DataLength,\r
1118 (VOID **) &Alloc\r
1119 );\r
1120 ASSERT_EFI_ERROR (Status);\r
1121\r
1122 //\r
1123 // Setup pointers to transfer buffers.\r
1124 //\r
1125 NewRequest = (EFI_USB_DEVICE_REQUEST *) Alloc;\r
1126 Alloc += sizeof(EFI_USB_DEVICE_REQUEST);\r
1127 NewData = (VOID *) Alloc;\r
1128\r
1129 //\r
1130 // Copy callers request packet into transfer request packet.\r
1131 //\r
1132 if (Request != NULL) {\r
1133 CopyMem (NewRequest,Request,sizeof(EFI_USB_DEVICE_REQUEST));\r
1134 } else {\r
1135 NewRequest = NULL;\r
1136 }\r
1137 //\r
1138 // Copy callers data into transfer data buffer.\r
1139 //\r
1140 if (Data != NULL) {\r
1141 if (DataLength > 0) {\r
1142 CopyMem (NewData,Data,*DataLength);\r
1143 }\r
1144 } else {\r
1145 NewData = NULL;\r
1146 }\r
1147\r
1148 //\r
1149 // Call underlying OhciControlTransfer to do work.\r
1150 //\r
1151 Status = OhciControlTransfer (\r
1152 PeiServices,\r
1153 This,\r
1154 DeviceAddress,\r
1155 DeviceSpeed,\r
1156 MaxPacketLength,\r
1157 NewRequest,\r
1158 TransferDirection,\r
1159 NewData,\r
1160 DataLength,\r
1161 TimeOut,\r
1162 TransferResult\r
1163 );\r
1164\r
1165 //\r
1166 // Copy transfer buffer back into callers buffer.\r
1167 //\r
1168 if (Data != NULL && *DataLength > 0) {\r
1169 CopyMem (Data, NewData, *DataLength);\r
1170 }\r
1171\r
1172 return Status;\r
1173}\r
1174\r
1175/**\r
1176 Submits bulk transfer to a bulk endpoint of a USB device.\r
1177\r
1178 Calls underlying OhciBulkTransfer to do work. This wrapper routine required\r
1179 on Quark so that USB DMA transfers do not cause an IMR violation.\r
1180\r
1181 @param PeiServices The pointer of EFI_PEI_SERVICES.\r
1182 @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI.\r
1183 @param DeviceAddress Target device address.\r
1184 @param EndPointAddress Endpoint number and its direction in bit 7.\r
1185 @param MaxiPacketLength Maximum packet size the endpoint is capable of\r
1186 sending or receiving.\r
1187 @param Data A pointers to the buffers of data to transmit\r
1188 from or receive into.\r
1189 @param DataLength The lenght of the data buffer.\r
1190 @param DataToggle On input, the initial data toggle for the transfer;\r
1191 On output, it is updated to to next data toggle to use of\r
1192 the subsequent bulk transfer.\r
1193 @param TimeOut Indicates the maximum time, in millisecond, which the\r
1194 transfer is allowed to complete.\r
1195 @param TransferResult A pointer to the detailed result information of the\r
1196 bulk transfer.\r
1197\r
1198 @retval EFI_SUCCESS The transfer was completed successfully.\r
1199 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.\r
1200 @retval EFI_INVALID_PARAMETER Parameters are invalid.\r
1201 @retval EFI_TIMEOUT The transfer failed due to timeout.\r
1202 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.\r
1203\r
1204**/\r
1205EFI_STATUS\r
1206EFIAPI\r
1207RedirectOhciBulkTransfer (\r
1208 IN EFI_PEI_SERVICES **PeiServices,\r
1209 IN PEI_USB_HOST_CONTROLLER_PPI *This,\r
1210 IN UINT8 DeviceAddress,\r
1211 IN UINT8 EndPointAddress,\r
1212 IN UINT8 MaxPacketLength,\r
1213 IN OUT VOID *Data,\r
1214 IN OUT UINTN *DataLength,\r
1215 IN OUT UINT8 *DataToggle,\r
1216 IN UINTN TimeOut,\r
1217 OUT UINT32 *TransferResult\r
1218 )\r
1219{\r
1220 EFI_STATUS Status;\r
1221 UINT8 *NewData;\r
1222\r
1223 //\r
1224 // Allocate memory external to IMR protected region for transfer data.\r
1225 //\r
1226 Status = PeiServicesAllocatePool (\r
1227 *DataLength,\r
1228 (VOID **) &NewData\r
1229 );\r
1230 ASSERT_EFI_ERROR (Status);\r
1231\r
1232 //\r
1233 // Copy callers data into transfer buffer.\r
1234 //\r
1235 if (Data != NULL) {\r
1236 if (DataLength > 0) {\r
1237 CopyMem (NewData,Data,*DataLength);\r
1238 }\r
1239 } else {\r
1240 NewData = NULL;\r
1241 }\r
1242\r
1243 //\r
1244 // Call underlying OhciBulkTransfer to do work.\r
1245 //\r
1246 Status = OhciBulkTransfer (\r
1247 PeiServices,\r
1248 This,\r
1249 DeviceAddress,\r
1250 EndPointAddress,\r
1251 MaxPacketLength,\r
1252 NewData,\r
1253 DataLength,\r
1254 DataToggle,\r
1255 TimeOut,\r
1256 TransferResult\r
1257 );\r
1258\r
1259 //\r
1260 // Copy transfer buffer back into callers buffer.\r
1261 //\r
1262 if (Data != NULL && *DataLength > 0) {\r
1263 CopyMem (Data, NewData, *DataLength);\r
1264 }\r
1265\r
1266 return Status;\r
1267}\r
1268\r
1269/**\r
1270 @param FileHandle Handle of the file being invoked.\r
1271 @param PeiServices Describes the list of possible PEI Services.\r
1272\r
1273 @retval EFI_SUCCESS PPI successfully installed.\r
1274\r
1275**/\r
1276EFI_STATUS\r
1277OhcPeimEntry (\r
1278 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1279 IN CONST EFI_PEI_SERVICES **PeiServices\r
1280 )\r
1281{\r
1282\r
1283 PEI_USB_CONTROLLER_PPI *ChipSetUsbControllerPpi;\r
1284 EFI_STATUS Status;\r
1285 UINT8 Index;\r
1286 UINTN ControllerType;\r
1287 UINTN BaseAddress;\r
1288 UINTN MemPages;\r
1289 USB_OHCI_HC_DEV *Ohc;\r
1290 EFI_PHYSICAL_ADDRESS TempPtr;\r
1291\r
1292\r
1293 //\r
1294 // Shadow this PEIM to run from memory\r
1295 //\r
1296 if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {\r
1297 return EFI_SUCCESS;\r
1298 }\r
1299 Status = PeiServicesLocatePpi (\r
1300 &gPeiUsbControllerPpiGuid,\r
1301 0,\r
1302 NULL,\r
1303 (VOID **) &ChipSetUsbControllerPpi\r
1304 );\r
1305 if (EFI_ERROR (Status)) {\r
1306 return EFI_UNSUPPORTED;\r
1307 }\r
1308\r
1309 Index = 0;\r
1310 while (TRUE) {\r
1311 Status = ChipSetUsbControllerPpi->GetUsbController (\r
1312 (EFI_PEI_SERVICES **) PeiServices,\r
1313 ChipSetUsbControllerPpi,\r
1314 Index,\r
1315 &ControllerType,\r
1316 &BaseAddress\r
1317 );\r
1318 //\r
1319 // When status is error, meant no controller is found\r
1320 //\r
1321 if (EFI_ERROR (Status)) {\r
1322 break;\r
1323 }\r
1324 //\r
1325 // This PEIM is for OHC type controller.\r
1326 //\r
1327 if (ControllerType != PEI_OHCI_CONTROLLER) {\r
1328 Index++;\r
1329 continue;\r
1330 }\r
1331\r
1332 MemPages = sizeof (USB_OHCI_HC_DEV) / PAGESIZE + 1;\r
1333 Status = PeiServicesAllocatePages (\r
1334 EfiBootServicesCode,\r
1335 MemPages,\r
1336 &TempPtr\r
1337 );\r
1338 if (EFI_ERROR (Status)) {\r
1339 DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to allocate buffer for the %dth OHCI ControllerPpi\n", Index));\r
1340 return EFI_OUT_OF_RESOURCES;\r
1341 }\r
1342 ZeroMem((VOID *)(UINTN)TempPtr, MemPages*PAGESIZE);\r
1343 Ohc = (USB_OHCI_HC_DEV *) ((UINTN) TempPtr);\r
1344\r
1345 Ohc->Signature = USB_OHCI_HC_DEV_SIGNATURE;\r
1346\r
1347 Ohc->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
1348\r
1349 //\r
1350 // Initialize Uhc's hardware\r
1351 //\r
1352 Status = InitializeUsbHC (\r
1353 (EFI_PEI_SERVICES **)PeiServices,\r
1354 Ohc,\r
1355 EFI_USB_HC_RESET_GLOBAL\r
1356 );\r
1357 if (EFI_ERROR (Status)) {\r
1358 DEBUG ((EFI_D_INFO, "OhcPeimEntry: Fail to init %dth OHCI ControllerPpi\n", Index));\r
1359 return Status;\r
1360 }\r
1361 //\r
1362 // Control & Bulk transfer services are accessed via their Redirect\r
1363 // routine versions on Quark so that USB DMA transfers do not cause an\r
1364 // IMR violation.\r
1365 //\r
1366 Ohc->UsbHostControllerPpi.ControlTransfer = RedirectOhciControlTransfer;\r
1367 Ohc->UsbHostControllerPpi.BulkTransfer = RedirectOhciBulkTransfer;\r
1368 Ohc->UsbHostControllerPpi.GetRootHubPortNumber = OhciGetRootHubNumOfPorts;\r
1369 Ohc->UsbHostControllerPpi.GetRootHubPortStatus = OhciGetRootHubPortStatus;\r
1370 Ohc->UsbHostControllerPpi.SetRootHubPortFeature = OhciSetRootHubPortFeature;\r
1371 Ohc->UsbHostControllerPpi.ClearRootHubPortFeature = OhciClearRootHubPortFeature;\r
1372\r
1373 Ohc->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
1374 Ohc->PpiDescriptor.Guid = &gPeiUsbHostControllerPpiGuid;\r
1375 Ohc->PpiDescriptor.Ppi = &Ohc->UsbHostControllerPpi;\r
1376\r
1377 Status = PeiServicesInstallPpi (&Ohc->PpiDescriptor);\r
1378 if (EFI_ERROR (Status)) {\r
1379 Index++;\r
1380 continue;\r
1381 }\r
1382 Index++;\r
1383 }\r
1384 return EFI_SUCCESS;\r
1385}\r
1386\r