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