1/** @file
2This file contains the implementation of Usb Hc Protocol.
3
4Copyright (c) 2013-2015 Intel Corporation.
5
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
42EFI_STATUS
43EFIAPI
44OhciControlTransfer (
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
302FREE_TD_BUFF:
303  while (HeadTd) {
304    DataTd = HeadTd;
305    HeadTd = HeadTd->NextTDPointer;
306    UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR));
307  }
308
309FREE_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**/
342EFI_STATUS
343EFIAPI
344OhciBulkTransfer (
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
540FREE_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
563EFI_STATUS
564EFIAPI
565OhciGetRootHubNumOfPorts (
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
594EFI_STATUS
595EFIAPI
596OhciGetRootHubPortStatus (
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
668EFI_STATUS
669EFIAPI
670OhciSetRootHubPortFeature (
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
792EFI_STATUS
793EFIAPI
794OhciClearRootHubPortFeature (
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**/
984EFI_STATUS
985InitializeUsbHC (
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**/
1108EFI_STATUS
1109EFIAPI
1110RedirectOhciControlTransfer (
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**/
1221EFI_STATUS
1222EFIAPI
1223RedirectOhciBulkTransfer (
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**/
1292EFI_STATUS
1293OhcPeimEntry (
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