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