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