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