d573532f7e07cf44c08d5eede736eefd82849a91
[people/mcb30/edk2.git] / edk2 / EdkModulePkg / Bus / Pci / Ehci / Dxe / Ehci.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14     Ehci.c\r
15     \r
16 Abstract: \r
17     \r
18 \r
19 Revision History\r
20 --*/\r
21 \r
22 \r
23 #include "Ehci.h"\r
24 \r
25 \r
26 GLOBAL_REMOVE_IF_UNREFERENCED UINTN    gEHCDebugLevel  = EFI_D_INFO;\r
27 GLOBAL_REMOVE_IF_UNREFERENCED UINTN    gEHCErrorLevel  = EFI_D_ERROR;\r
28 \r
29 \r
30 //\r
31 // Prototypes\r
32 // Driver model protocol interface\r
33 //\r
34 \r
35 EFI_STATUS\r
36 EFIAPI\r
37 EhciDriverBindingSupported (\r
38   IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
39   IN EFI_HANDLE                      Controller,\r
40   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
41   );\r
42 \r
43 EFI_STATUS\r
44 EFIAPI\r
45 EhciDriverBindingStart (\r
46   IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
47   IN EFI_HANDLE                      Controller,\r
48   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
49   );\r
50 \r
51 EFI_STATUS\r
52 EFIAPI\r
53 EhciDriverBindingStop (\r
54   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,\r
55   IN  EFI_HANDLE                      Controller,\r
56   IN  UINTN                           NumberOfChildren,\r
57   IN  EFI_HANDLE                      *ChildHandleBuffer\r
58   );\r
59 \r
60 //\r
61 // Ehci protocol interface\r
62 //\r
63 EFI_STATUS\r
64 EFIAPI\r
65 EhciGetCapability (\r
66   IN  EFI_USB2_HC_PROTOCOL   *This,\r
67   OUT UINT8                  *MaxSpeed,\r
68   OUT UINT8                  *PortNumber,\r
69   OUT UINT8                  *Is64BitCapable\r
70   );\r
71 \r
72 EFI_STATUS\r
73 EFIAPI\r
74 EhciReset (\r
75   IN  EFI_USB2_HC_PROTOCOL     *This,\r
76   IN  UINT16                   Attributes\r
77   );\r
78 \r
79 EFI_STATUS\r
80 EFIAPI\r
81 EhciGetState (\r
82   IN  EFI_USB2_HC_PROTOCOL     *This,\r
83   OUT EFI_USB_HC_STATE         *State\r
84   );\r
85 \r
86 EFI_STATUS\r
87 EFIAPI\r
88 EhciSetState (\r
89   IN  EFI_USB2_HC_PROTOCOL     *This,\r
90   IN  EFI_USB_HC_STATE         State\r
91   );\r
92 \r
93 EFI_STATUS\r
94 EFIAPI\r
95 EhciControlTransfer (\r
96   IN  EFI_USB2_HC_PROTOCOL                 *This,\r
97   IN  UINT8                                DeviceAddress,\r
98   IN  UINT8                                DeviceSpeed,\r
99   IN  UINTN                                MaximumPacketLength,\r
100   IN  EFI_USB_DEVICE_REQUEST               *Request,\r
101   IN  EFI_USB_DATA_DIRECTION               TransferDirection,\r
102   IN  OUT VOID                             *Data,\r
103   IN  OUT UINTN                            *DataLength,\r
104   IN  UINTN                                TimeOut,\r
105   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,\r
106   OUT UINT32                               *TransferResult\r
107   );\r
108 \r
109 EFI_STATUS\r
110 EFIAPI\r
111 EhciBulkTransfer (\r
112   IN  EFI_USB2_HC_PROTOCOL                *This,\r
113   IN  UINT8                               DeviceAddress,\r
114   IN  UINT8                               EndPointAddress,\r
115   IN  UINT8                               DeviceSpeed,\r
116   IN  UINTN                               MaximumPacketLength,\r
117   IN  UINT8                               DataBuffersNumber,\r
118   IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
119   IN  OUT UINTN                           *DataLength,\r
120   IN  OUT UINT8                           *DataToggle,\r
121   IN  UINTN                               TimeOut,\r
122   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
123   OUT UINT32                              *TransferResult\r
124   );\r
125 \r
126 EFI_STATUS\r
127 EFIAPI\r
128 EhciAsyncInterruptTransfer (\r
129   IN  EFI_USB2_HC_PROTOCOL                  * This,\r
130   IN  UINT8                                 DeviceAddress,\r
131   IN  UINT8                                 EndPointAddress,\r
132   IN  UINT8                                 DeviceSpeed,\r
133   IN  UINTN                                 MaxiumPacketLength,\r
134   IN  BOOLEAN                               IsNewTransfer,\r
135   IN  OUT UINT8                             *DataToggle,\r
136   IN  UINTN                                 PollingInterval,\r
137   IN  UINTN                                 DataLength,\r
138   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,\r
139   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,\r
140   IN  VOID                                  *Context OPTIONAL\r
141   );\r
142 \r
143 EFI_STATUS\r
144 EFIAPI\r
145 EhciSyncInterruptTransfer (\r
146   IN  EFI_USB2_HC_PROTOCOL                  *This,\r
147   IN  UINT8                                 DeviceAddress,\r
148   IN  UINT8                                 EndPointAddress,\r
149   IN  UINT8                                 DeviceSpeed,\r
150   IN  UINTN                                 MaximumPacketLength,\r
151   IN  OUT VOID                              *Data,\r
152   IN  OUT UINTN                             *DataLength,\r
153   IN  OUT UINT8                             *DataToggle,\r
154   IN  UINTN                                 TimeOut,\r
155   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,\r
156   OUT UINT32                                *TransferResult\r
157   );\r
158 \r
159 EFI_STATUS\r
160 EFIAPI\r
161 EhciIsochronousTransfer (\r
162   IN  EFI_USB2_HC_PROTOCOL                  *This,\r
163   IN  UINT8                                 DeviceAddress,\r
164   IN  UINT8                                 EndPointAddress,\r
165   IN  UINT8                                 DeviceSpeed,\r
166   IN  UINTN                                 MaximumPacketLength,\r
167   IN  UINT8                                 DataBuffersNumber,\r
168   IN  OUT VOID                              *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
169   IN  UINTN                                 DataLength,\r
170   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,\r
171   OUT UINT32                                *TransferResult\r
172   );\r
173 \r
174 EFI_STATUS\r
175 EFIAPI\r
176 EhciAsyncIsochronousTransfer (\r
177   IN  EFI_USB2_HC_PROTOCOL                *This,\r
178   IN  UINT8                               DeviceAddress,\r
179   IN  UINT8                               EndPointAddress,\r
180   IN  UINT8                               DeviceSpeed,\r
181   IN  UINTN                               MaximumPacketLength,\r
182   IN  UINT8                               DataBuffersNumber,\r
183   IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
184   IN  UINTN                               DataLength,\r
185   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
186   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,\r
187   IN  VOID                                *Context\r
188   );\r
189 \r
190 EFI_STATUS\r
191 EFIAPI\r
192 EhciGetRootHubPortStatus (\r
193   IN  EFI_USB2_HC_PROTOCOL     *This,\r
194   IN  UINT8                    PortNumber,\r
195   OUT EFI_USB_PORT_STATUS      *PortStatus\r
196   );\r
197 \r
198 EFI_STATUS\r
199 EFIAPI\r
200 EhciSetRootHubPortFeature (\r
201   IN  EFI_USB2_HC_PROTOCOL     *This,\r
202   IN  UINT8                    PortNumber,\r
203   IN  EFI_USB_PORT_FEATURE     PortFeature\r
204   );\r
205 \r
206 EFI_STATUS\r
207 EFIAPI\r
208 EhciClearRootHubPortFeature (\r
209   IN  EFI_USB2_HC_PROTOCOL     *This,\r
210   IN  UINT8                    PortNumber,\r
211   IN  EFI_USB_PORT_FEATURE     PortFeature\r
212   );\r
213 \r
214 //\r
215 // Ehci Driver Global Variables\r
216 //\r
217 EFI_DRIVER_BINDING_PROTOCOL gEhciDriverBinding = {\r
218   EhciDriverBindingSupported,\r
219   EhciDriverBindingStart,\r
220   EhciDriverBindingStop,\r
221   0x10,\r
222   NULL,\r
223   NULL\r
224 };\r
225 \r
226 UINT32                      mUsbCapabilityLen;\r
227 UINT32                      mDeviceSpeed[16];\r
228 \r
229 EFI_STATUS\r
230 EFIAPI\r
231 EhciDriverBindingSupported (\r
232   IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
233   IN EFI_HANDLE                  Controller,\r
234   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
235   )\r
236 /*++\r
237 \r
238   Routine Description:\r
239   \r
240     Test to see if this driver supports ControllerHandle. Any ControllerHandle\r
241     that has Usb2HcProtocol installed will be supported.\r
242 \r
243   Arguments:\r
244   \r
245     This                - Protocol instance pointer.\r
246     Controlle           - Handle of device to test\r
247     RemainingDevicePath - Not used\r
248 \r
249   Returns:\r
250   \r
251     EFI_SUCCESS       This driver supports this device.\r
252     EFI_UNSUPPORTED   This driver does not support this device.\r
253 \r
254 --*/\r
255 {\r
256   EFI_STATUS          Status;\r
257   EFI_PCI_IO_PROTOCOL *PciIo;\r
258   USB_CLASSC          UsbClassCReg;\r
259 \r
260   \r
261   //\r
262   // Test whether there is PCI IO Protocol attached on the controller handle.\r
263   //\r
264   Status = gBS->OpenProtocol (\r
265                   Controller,\r
266                   &gEfiPciIoProtocolGuid,\r
267                   (VOID **) &PciIo,\r
268                   This->DriverBindingHandle,\r
269                   Controller,\r
270                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
271                   );\r
272   if (EFI_ERROR (Status)) {\r
273     goto exit;\r
274   }\r
275 \r
276   Status = PciIo->Pci.Read (\r
277                         PciIo,\r
278                         EfiPciIoWidthUint8,\r
279                         CLASSC,\r
280                         sizeof (USB_CLASSC) / sizeof (UINT8),\r
281                         &UsbClassCReg\r
282                         );\r
283   if (EFI_ERROR (Status)) {\r
284     gBS->CloseProtocol (\r
285           Controller,\r
286           &gEfiPciIoProtocolGuid,\r
287           This->DriverBindingHandle,\r
288           Controller\r
289           );\r
290     Status = EFI_UNSUPPORTED;\r
291     goto exit;\r
292   }\r
293   \r
294   //\r
295   // Test whether the controller belongs to Ehci type\r
296   //\r
297   if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||\r
298       (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||\r
299       (UsbClassCReg.PI != PCI_CLASSC_PI_EHCI)\r
300       ) {\r
301 \r
302     gBS->CloseProtocol (\r
303            Controller,\r
304            &gEfiPciIoProtocolGuid,\r
305            This->DriverBindingHandle,\r
306            Controller\r
307            );\r
308 \r
309     Status = EFI_UNSUPPORTED;\r
310     goto exit;\r
311   }\r
312 \r
313   gBS->CloseProtocol (\r
314          Controller,\r
315          &gEfiPciIoProtocolGuid,\r
316          This->DriverBindingHandle,\r
317          Controller\r
318          );\r
319 \r
320 exit:\r
321   return Status;\r
322 }\r
323 \r
324 EFI_STATUS\r
325 EFIAPI\r
326 EhciDriverBindingStart (\r
327   IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
328   IN EFI_HANDLE                  Controller,\r
329   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath\r
330   )\r
331 /*++\r
332 \r
333   Routine Description:\r
334   \r
335     Starting the Usb EHCI Driver\r
336 \r
337   Arguments:\r
338   \r
339     This                - Protocol instance pointer.\r
340     Controller          - Handle of device to test\r
341     RemainingDevicePath - Not used\r
342 \r
343   Returns:\r
344   \r
345     EFI_SUCCESS           supports this device.\r
346     EFI_UNSUPPORTED       do not support this device.\r
347     EFI_DEVICE_ERROR      cannot be started due to device Error\r
348     EFI_OUT_OF_RESOURCES  cannot allocate resources\r
349 \r
350 --*/\r
351 {\r
352   EFI_STATUS            Status;\r
353   USB2_HC_DEV           *HcDev;\r
354   EFI_PCI_IO_PROTOCOL   *PciIo;\r
355   UINT8                 MaxSpeed;\r
356   UINT8                 PortNumber;\r
357   UINT8                 Is64BitCapable;\r
358   \r
359   //\r
360   // Open the PciIo Protocol\r
361   //\r
362   Status = gBS->OpenProtocol (\r
363                   Controller,\r
364                   &gEfiPciIoProtocolGuid,\r
365                   (VOID **) &PciIo,\r
366                   This->DriverBindingHandle,\r
367                   Controller,\r
368                   EFI_OPEN_PROTOCOL_BY_DRIVER\r
369                   );\r
370   if (EFI_ERROR (Status)) {\r
371     Status = EFI_OUT_OF_RESOURCES;\r
372     goto exit;\r
373   }\r
374   \r
375   //\r
376   // Enable the USB Host Controller\r
377   //\r
378   Status = PciIo->Attributes (\r
379                     PciIo,\r
380                     EfiPciIoAttributeOperationEnable,\r
381                     EFI_PCI_DEVICE_ENABLE,\r
382                     NULL\r
383                     );\r
384   if (EFI_ERROR (Status)) {\r
385     Status = EFI_OUT_OF_RESOURCES;\r
386     goto close_pciio_protocol;\r
387   }\r
388   \r
389   //\r
390   // Allocate memory for EHC private data structure\r
391   //\r
392   HcDev = AllocateZeroPool (sizeof (USB2_HC_DEV));\r
393   if (NULL == HcDev) {\r
394     Status = EFI_OUT_OF_RESOURCES;\r
395     goto close_pciio_protocol;\r
396   }\r
397   \r
398   //\r
399   // Init EFI_USB2_HC_PROTOCOL interface and private data structure\r
400   //\r
401   HcDev->Usb2Hc.GetCapability             = EhciGetCapability;\r
402   HcDev->Usb2Hc.Reset                     = EhciReset;\r
403   HcDev->Usb2Hc.GetState                  = EhciGetState;\r
404   HcDev->Usb2Hc.SetState                  = EhciSetState;\r
405   HcDev->Usb2Hc.ControlTransfer           = EhciControlTransfer;\r
406   HcDev->Usb2Hc.BulkTransfer              = EhciBulkTransfer;\r
407   HcDev->Usb2Hc.AsyncInterruptTransfer    = EhciAsyncInterruptTransfer;\r
408   HcDev->Usb2Hc.SyncInterruptTransfer     = EhciSyncInterruptTransfer;\r
409   HcDev->Usb2Hc.IsochronousTransfer       = EhciIsochronousTransfer;\r
410   HcDev->Usb2Hc.AsyncIsochronousTransfer  = EhciAsyncIsochronousTransfer;\r
411   HcDev->Usb2Hc.GetRootHubPortStatus      = EhciGetRootHubPortStatus;\r
412   HcDev->Usb2Hc.SetRootHubPortFeature     = EhciSetRootHubPortFeature;\r
413   HcDev->Usb2Hc.ClearRootHubPortFeature   = EhciClearRootHubPortFeature;\r
414   HcDev->Usb2Hc.MajorRevision             = 0x1;\r
415   HcDev->Usb2Hc.MinorRevision             = 0x1;\r
416 \r
417   HcDev->AsyncRequestList                 = NULL;\r
418   HcDev->ControllerNameTable              = NULL;\r
419   HcDev->Signature                        = USB2_HC_DEV_SIGNATURE;\r
420   HcDev->PciIo = PciIo;\r
421 \r
422   //\r
423   // Install USB2_HC_PROTOCOL\r
424   //\r
425   Status = gBS->InstallProtocolInterface (\r
426                   &Controller,\r
427                   &gEfiUsb2HcProtocolGuid,\r
428                   EFI_NATIVE_INTERFACE,\r
429                   &HcDev->Usb2Hc\r
430                   );\r
431   if (EFI_ERROR (Status)) {\r
432     Status = EFI_OUT_OF_RESOURCES;\r
433     goto free_pool;\r
434   }\r
435   \r
436   //\r
437   // Get Capability Register Length\r
438   //\r
439   Status = GetCapabilityLen (HcDev);\r
440   if (EFI_ERROR (Status)) {\r
441     Status = EFI_DEVICE_ERROR;\r
442     goto uninstall_usb2hc_protocol;\r
443   }\r
444 \r
445   ClearLegacySupport (HcDev);\r
446   HostReset (HcDev);\r
447 \r
448   DEBUG_CODE (\r
449    DumpEHCIPortsStatus (HcDev);\r
450   );\r
451   \r
452   //\r
453   // Create and Init Perodic Frame List\r
454   //\r
455   Status = EhciGetCapability (\r
456              &HcDev->Usb2Hc, \r
457              &MaxSpeed, \r
458              &PortNumber, \r
459              &Is64BitCapable\r
460              );\r
461   if (EFI_ERROR (Status)) {\r
462     Status = EFI_OUT_OF_RESOURCES;\r
463     goto uninstall_usb2hc_protocol;\r
464   }\r
465   HcDev->Is64BitCapable = Is64BitCapable;\r
466   \r
467   //\r
468   // Create and Init Perodic Frame List\r
469   //\r
470   Status = InitialPeriodicFrameList (\r
471              HcDev, \r
472              EHCI_MAX_FRAME_LIST_LENGTH\r
473              );\r
474   if (EFI_ERROR (Status)) {\r
475     Status = EFI_OUT_OF_RESOURCES;\r
476     goto uninstall_usb2hc_protocol;\r
477   }\r
478   \r
479   //\r
480   // Init memory pool management\r
481   //\r
482   Status = InitialMemoryManagement (HcDev);\r
483   if (EFI_ERROR (Status)) {\r
484     Status = EFI_OUT_OF_RESOURCES;\r
485     goto deinit_perodic_frame_list;\r
486   }\r
487   \r
488   //\r
489   // Create AsyncRequest Polling Timer\r
490   //\r
491   Status = CreatePollingTimer (HcDev, (EFI_EVENT_NOTIFY) AsyncRequestMoniter);\r
492   if (EFI_ERROR (Status)) {\r
493     Status = EFI_OUT_OF_RESOURCES;\r
494     goto deinit_memory_management;\r
495   }\r
496   \r
497   //\r
498   // Default Maxximum Interrupt Interval is 8, \r
499   // it means that 8 micro frame = 1ms\r
500   //\r
501   \r
502   //\r
503   // Start the Host Controller\r
504   //\r
505   if (IsEhcHalted (HcDev)) {\r
506     Status = StartScheduleExecution (HcDev);\r
507     if (EFI_ERROR (Status)) {\r
508       Status = EFI_DEVICE_ERROR;\r
509       goto deinit_timer;\r
510     }\r
511   }\r
512   \r
513   //\r
514   // Set all ports routing to EHC\r
515   //\r
516   Status = SetPortRoutingEhc (HcDev);\r
517   if (EFI_ERROR (Status)) {\r
518     Status = EFI_DEVICE_ERROR;\r
519     goto deinit_timer;\r
520   }\r
521   \r
522   //\r
523   // Component name protocol\r
524   //\r
525   Status = AddUnicodeString (\r
526              "eng",\r
527              gEhciComponentName.SupportedLanguages,\r
528              &HcDev->ControllerNameTable,\r
529              L"Usb Enhanced Host Controller"\r
530              );\r
531   if (EFI_ERROR (Status)) {\r
532     Status = EFI_OUT_OF_RESOURCES;\r
533     goto deinit_timer;\r
534   }\r
535 \r
536   goto exit;\r
537 \r
538   //\r
539   // Error handle process\r
540   //\r
541 deinit_timer:\r
542   DestoryPollingTimer (HcDev);\r
543 deinit_memory_management:\r
544   DeinitialMemoryManagement (HcDev);\r
545 deinit_perodic_frame_list:\r
546   DeinitialPeriodicFrameList (HcDev);\r
547 uninstall_usb2hc_protocol:\r
548   gBS->UninstallProtocolInterface (\r
549          Controller,\r
550          &gEfiUsb2HcProtocolGuid,\r
551          &HcDev->Usb2Hc\r
552          );\r
553 free_pool:\r
554   gBS->FreePool (HcDev);\r
555 close_pciio_protocol:\r
556   gBS->CloseProtocol (\r
557          Controller,\r
558          &gEfiPciIoProtocolGuid,\r
559          This->DriverBindingHandle,\r
560          Controller\r
561          );\r
562 \r
563 exit:\r
564   return Status;\r
565 }\r
566 \r
567 EFI_STATUS\r
568 EFIAPI\r
569 EhciDriverBindingStop (\r
570   IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
571   IN EFI_HANDLE                  Controller,\r
572   IN UINTN                       NumberOfChildren,\r
573   IN EFI_HANDLE                  *ChildHandleBuffer\r
574   )\r
575 /*++\r
576 \r
577   Routine Description:\r
578   \r
579     Stop this driver on ControllerHandle. Support stoping any child handles\r
580     created by this driver.\r
581 \r
582   Arguments:\r
583   \r
584     This              - Protocol instance pointer.\r
585     Controller        - Handle of device to stop driver on\r
586     NumberOfChildren  - Number of Children in the ChildHandleBuffer\r
587     ChildHandleBuffer - List of handles for the children we need to stop.\r
588 \r
589   Returns:\r
590   \r
591     EFI_SUCCESS         Success\r
592     EFI_DEVICE_ERROR    Fail\r
593 --*/\r
594 {\r
595   EFI_STATUS            Status;\r
596   EFI_USB2_HC_PROTOCOL  *Usb2Hc;\r
597   USB2_HC_DEV           *HcDev;\r
598 \r
599   //\r
600   // Test whether the Controller handler passed in is a valid\r
601   // Usb controller handle that should be supported, if not,\r
602   // return the error status directly\r
603   //\r
604   Status = gBS->OpenProtocol (\r
605                   Controller,\r
606                   &gEfiUsb2HcProtocolGuid,\r
607                   (VOID **) &Usb2Hc,\r
608                   This->DriverBindingHandle,\r
609                   Controller,\r
610                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
611                   );\r
612   if (EFI_ERROR (Status)) {\r
613     Status = EFI_DEVICE_ERROR;\r
614     goto exit;\r
615   }\r
616 \r
617   HcDev = USB2_HC_DEV_FROM_THIS (Usb2Hc);\r
618 \r
619   //\r
620   // free all the controller related memory and uninstall UHCI Protocol.\r
621   //\r
622   Status = gBS->UninstallProtocolInterface (\r
623                   Controller,\r
624                   &gEfiUsb2HcProtocolGuid,\r
625                   Usb2Hc\r
626                   );\r
627   if (EFI_ERROR (Status)) {\r
628     Status = EFI_DEVICE_ERROR;\r
629     goto exit;\r
630   }\r
631   \r
632   //\r
633   // Set Host Controller state as halt\r
634   //\r
635   Status = Usb2Hc->SetState (\r
636                      Usb2Hc, \r
637                      EfiUsbHcStateHalt\r
638                      );\r
639   if (EFI_ERROR (Status)) {\r
640     Status = EFI_DEVICE_ERROR;\r
641     goto exit;\r
642   }\r
643   \r
644   //\r
645   // Stop AsyncRequest Polling Timer\r
646   //\r
647   Status = StopPollingTimer (HcDev);\r
648   if (EFI_ERROR (Status)) {\r
649     Status = EFI_DEVICE_ERROR;\r
650     goto exit;\r
651   }\r
652   \r
653   //\r
654   // Destroy Asynchronous Request Event\r
655   //\r
656   DestoryPollingTimer (HcDev);\r
657 \r
658   //\r
659   // Destroy Perodic Frame List\r
660   //\r
661   DeinitialPeriodicFrameList (HcDev);\r
662 \r
663   //\r
664   // Deinit Ehci pool memory management\r
665   //\r
666   DeinitialMemoryManagement (HcDev);\r
667 \r
668   //\r
669   // Denint Unicode String Table\r
670   //\r
671   FreeUnicodeStringTable (HcDev->ControllerNameTable);\r
672 \r
673   //\r
674   // Disable the USB Host Controller\r
675   //\r
676   Status = HcDev->PciIo->Attributes (\r
677                            HcDev->PciIo,\r
678                            EfiPciIoAttributeOperationDisable,\r
679                            EFI_PCI_DEVICE_ENABLE,\r
680                            NULL\r
681                            );\r
682   if (EFI_ERROR (Status)) {\r
683     Status = EFI_DEVICE_ERROR;\r
684     goto exit;\r
685   }\r
686 \r
687   gBS->FreePool (HcDev);\r
688 \r
689   gBS->CloseProtocol (\r
690         Controller,\r
691         &gEfiPciIoProtocolGuid,\r
692         This->DriverBindingHandle,\r
693         Controller\r
694         );\r
695 \r
696 exit:\r
697   return Status;\r
698 }\r
699 \r
700 EFI_STATUS\r
701 EFIAPI\r
702 EhciGetCapability (\r
703   IN  EFI_USB2_HC_PROTOCOL *This,\r
704   OUT UINT8                *MaxSpeed,\r
705   OUT UINT8                *PortNumber,\r
706   OUT UINT8                *Is64BitCapable\r
707   )\r
708 /*++\r
709   \r
710   Routine Description:\r
711   \r
712     Retrieves the capablility of root hub ports.\r
713     \r
714   Arguments:\r
715   \r
716     This            - A pointer to the EFI_USB_HC_PROTOCOL instance.\r
717     MaxSpeed        - A pointer to the number of the host controller.\r
718     PortNumber      - A pointer to the number of the root hub ports.\r
719     Is64BitCapable  - A pointer to the flag for whether controller supports \r
720                       64-bit memory addressing.\r
721     \r
722   Returns:\r
723   \r
724     EFI_SUCCESS            host controller capability were retrieved successfully.\r
725     EFI_INVALID_PARAMETER  MaxSpeed or PortNumber or Is64BitCapable is NULL.\r
726     EFI_DEVICE_ERROR       An error was encountered while attempting to retrieve the capabilities.  \r
727           \r
728 --*/\r
729 {\r
730   EFI_STATUS  Status;\r
731   USB2_HC_DEV *HcDev;\r
732   UINT32      HcStructParamsAddr;\r
733   UINT32      HcStructParamsReg;\r
734   UINT32      HcCapParamsAddr;\r
735   UINT32      HcCapParamsReg;\r
736 \r
737   if (MaxSpeed == NULL || PortNumber == NULL || Is64BitCapable == NULL) {\r
738     Status = EFI_INVALID_PARAMETER;\r
739     goto exit;\r
740   }\r
741 \r
742   HcStructParamsAddr  = HCSPARAMS;\r
743   HcCapParamsAddr     = HCCPARAMS;\r
744   HcDev               = USB2_HC_DEV_FROM_THIS (This);\r
745 \r
746   Status = ReadEhcCapabiltiyReg (\r
747              HcDev,\r
748              HcStructParamsAddr,\r
749              &HcStructParamsReg\r
750              );\r
751   if (EFI_ERROR (Status)) {\r
752     Status = EFI_DEVICE_ERROR;\r
753     goto exit;\r
754   }\r
755 \r
756   Status = ReadEhcCapabiltiyReg (\r
757              HcDev,\r
758              HcCapParamsAddr,\r
759              &HcCapParamsReg\r
760              );\r
761   if (EFI_ERROR (Status)) {\r
762     Status = EFI_DEVICE_ERROR;\r
763     goto exit;\r
764   }\r
765 \r
766   *MaxSpeed       = EFI_USB_SPEED_HIGH;\r
767   *PortNumber     = (UINT8) (HcStructParamsReg & HCSP_NPORTS);\r
768   *Is64BitCapable = (UINT8) (HcCapParamsReg & HCCP_64BIT);\r
769 \r
770 exit:\r
771   return Status;\r
772 }\r
773 \r
774 EFI_STATUS\r
775 EFIAPI\r
776 EhciReset (\r
777   IN EFI_USB2_HC_PROTOCOL *This,\r
778   IN UINT16               Attributes\r
779   )\r
780 /*++\r
781   \r
782   Routine Description:\r
783   \r
784     Provides software reset for the USB host controller.\r
785   \r
786   Arguments:\r
787   \r
788   This        - A pointer to the EFI_USB2_HC_PROTOCOL instance.  \r
789   Attributes  - A bit mask of the reset operation to perform. \r
790                 See below for a list of the supported bit mask values.\r
791   \r
792   #define EFI_USB_HC_RESET_GLOBAL  0x0001\r
793   #define EFI_USB_HC_RESET_HOST_CONTROLLER  0x0002\r
794   #define EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG  0x0004\r
795   #define EFI_USB_HC_RESET_HOST_WITH_DEBUG  0x0008\r
796 \r
797   EFI_USB_HC_RESET_GLOBAL \r
798         If this bit is set, a global reset signal will be sent to the USB bus.\r
799         This resets all of the USB bus logic, including the USB host \r
800         controller hardware and all the devices attached on the USB bus.\r
801   EFI_USB_HC_RESET_HOST_CONTROLLER  \r
802         If this bit is set, the USB host controller hardware will be reset. \r
803         No reset signal will be sent to the USB bus.\r
804   EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG\r
805         If this bit is set, a global reset signal will be sent to the USB bus.\r
806         This resets all of the USB bus logic, including the USB host \r
807         controller hardware and all the devices attached on the USB bus. \r
808         If this is an EHCI controller and the debug port has configured, then \r
809         this is will still reset the host controller.\r
810   EFI_USB_HC_RESET_HOST_WITH_DEBUG\r
811         If this bit is set, the USB host controller hardware will be reset. \r
812         If this is an EHCI controller and the debug port has been configured,\r
813         then this will still reset the host controller.\r
814         \r
815   Returns:\r
816   \r
817     EFI_SUCCESS \r
818         The reset operation succeeded.\r
819     EFI_INVALID_PARAMETER \r
820         Attributes is not valid.\r
821     EFI_UNSUPPOURTED\r
822         The type of reset specified by Attributes is not currently supported by\r
823         the host controller hardware.\r
824     EFI_ACCESS_DENIED\r
825         Reset operation is rejected due to the debug port being configured and \r
826         active; only EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG or \r
827         EFI_USB_HC_RESET_HOST_WITH_DEBUG reset Atrributes can be used to\r
828         perform reset operation for this host controller.\r
829     EFI_DEVICE_ERROR  \r
830         An error was encountered while attempting to perform \r
831         the reset operation.\r
832         \r
833 --*/\r
834 {\r
835   EFI_STATUS        Status;\r
836   USB2_HC_DEV       *HcDev;\r
837   UINTN             FrameIndex;\r
838   FRAME_LIST_ENTRY  *FrameEntryPtr;\r
839 \r
840   HcDev = USB2_HC_DEV_FROM_THIS (This);\r
841 \r
842   switch (Attributes) {\r
843 \r
844   case EFI_USB_HC_RESET_GLOBAL:\r
845     \r
846     //\r
847     // Same behavior as Host Controller Reset\r
848     //\r
849 \r
850   case EFI_USB_HC_RESET_HOST_CONTROLLER:\r
851         \r
852     //\r
853     // Host Controller must be Halt when Reset it\r
854     //\r
855     if (IsEhcHalted (HcDev)) {\r
856       Status = ResetEhc (HcDev);\r
857       if (EFI_ERROR (Status)) {\r
858         Status = EFI_DEVICE_ERROR;\r
859         goto exit;\r
860       }\r
861       //\r
862       // Set to zero by Host Controller when reset process completes\r
863       //\r
864       Status = WaitForEhcReset (HcDev, EHCI_GENERIC_TIMEOUT);\r
865       if (EFI_ERROR (Status)) {\r
866         Status = EFI_TIMEOUT;\r
867         goto exit;\r
868       }\r
869     } else {\r
870       Status = EFI_DEVICE_ERROR;\r
871       goto exit;\r
872     }\r
873 \r
874     //\r
875     // only asynchronous interrupt transfers are always alive on the bus, need to cleanup\r
876     //\r
877     CleanUpAllAsyncRequestTransfer (HcDev);\r
878     Status = ClearEhcAllStatus (HcDev);\r
879     if (EFI_ERROR (Status)) {\r
880       Status = EFI_DEVICE_ERROR;\r
881       goto exit;\r
882     }\r
883 \r
884     //\r
885     // Set appropriate 4G Segment Selector\r
886     //\r
887     Status = SetCtrlDataStructSeg (HcDev);\r
888     if (EFI_ERROR (Status)) {\r
889       Status = EFI_DEVICE_ERROR;\r
890       goto exit;\r
891     }\r
892 \r
893     //\r
894     // Init Perodic List Base Addr and Frame List\r
895     //\r
896     Status = SetFrameListBaseAddr (\r
897                HcDev, \r
898                (UINT32)GET_0B_TO_31B (HcDev->PeriodicFrameListBuffer)\r
899                );\r
900     if (EFI_ERROR (Status)) {\r
901       Status = EFI_DEVICE_ERROR;\r
902       goto exit;\r
903     }\r
904     FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
905     for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {\r
906       FrameEntryPtr->LinkTerminate = TRUE;\r
907       FrameEntryPtr++;\r
908     }\r
909 \r
910     //\r
911     // Start the Host Controller\r
912     //\r
913     if (IsEhcHalted (HcDev)) {\r
914       Status = StartScheduleExecution (HcDev);\r
915       if (EFI_ERROR (Status)) {\r
916         Status = EFI_DEVICE_ERROR;\r
917         goto exit;\r
918       }\r
919     }\r
920 \r
921     //\r
922     // Set all ports routing to EHC\r
923     //\r
924     Status = SetPortRoutingEhc (HcDev);\r
925     if (EFI_ERROR (Status)) {\r
926       Status = EFI_DEVICE_ERROR;\r
927       goto exit;\r
928     }\r
929     break;\r
930 \r
931   case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:\r
932         \r
933     Status = EFI_UNSUPPORTED;\r
934     break;\r
935 \r
936   case EFI_USB_HC_RESET_HOST_WITH_DEBUG:\r
937         \r
938     Status = EFI_UNSUPPORTED;\r
939     break;\r
940 \r
941   default:\r
942     Status = EFI_INVALID_PARAMETER;\r
943   }\r
944 \r
945 exit:\r
946   return Status;\r
947 }\r
948 \r
949 EFI_STATUS\r
950 EFIAPI\r
951 EhciGetState (\r
952   IN  EFI_USB2_HC_PROTOCOL *This,\r
953   OUT EFI_USB_HC_STATE     *State\r
954   )\r
955 /*++\r
956   \r
957   Routine Description:\r
958   \r
959     Retrieves current state of the USB host controller.\r
960   \r
961   Arguments:\r
962     \r
963     This      A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
964     State     A pointer to the EFI_USB_HC_STATE data structure that \r
965               indicates current state of the USB host controller.  \r
966               Type EFI_USB_HC_STATE is defined below.\r
967               \r
968     typedef enum {\r
969       EfiUsbHcStateHalt,\r
970       EfiUsbHcStateOperational,\r
971       EfiUsbHcStateSuspend,\r
972       EfiUsbHcStateMaximum\r
973     } EFI_USB_HC_STATE;\r
974   \r
975   Returns:\r
976   \r
977     EFI_SUCCESS \r
978             The state information of the host controller was returned in State.\r
979     EFI_INVALID_PARAMETER \r
980             State is NULL.\r
981     EFI_DEVICE_ERROR  \r
982             An error was encountered while attempting to retrieve the \r
983             host controller's current state.  \r
984 --*/\r
985 {\r
986   EFI_STATUS  Status;\r
987   USB2_HC_DEV *HcDev;\r
988   UINT32      UsbStatusAddr;\r
989   UINT32      UsbStatusReg;\r
990 \r
991   if (State == NULL) {\r
992     Status = EFI_INVALID_PARAMETER;\r
993     goto exit;\r
994   }\r
995 \r
996   UsbStatusAddr = USBSTS;\r
997   HcDev         = USB2_HC_DEV_FROM_THIS (This);\r
998 \r
999   Status = ReadEhcOperationalReg (\r
1000              HcDev,\r
1001              UsbStatusAddr,\r
1002              &UsbStatusReg\r
1003              );\r
1004   if (EFI_ERROR (Status)) {\r
1005     Status = EFI_DEVICE_ERROR;\r
1006     goto exit;\r
1007   }\r
1008 \r
1009   if (UsbStatusReg & USBSTS_HCH) {\r
1010     *State = EfiUsbHcStateHalt;\r
1011   } else {\r
1012     *State = EfiUsbHcStateOperational;\r
1013   }\r
1014 \r
1015 exit:\r
1016   return Status;\r
1017 }\r
1018 \r
1019 EFI_STATUS\r
1020 EFIAPI\r
1021 EhciSetState (\r
1022   IN EFI_USB2_HC_PROTOCOL *This,\r
1023   IN EFI_USB_HC_STATE     State\r
1024   )\r
1025 /*++\r
1026   \r
1027   Routine Description:\r
1028   \r
1029     Sets the USB host controller to a specific state.\r
1030   \r
1031   Arguments:\r
1032     \r
1033     This     - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
1034     State    - Indicates the state of the host controller that will be set.\r
1035   \r
1036   Returns:\r
1037   \r
1038     EFI_SUCCESS \r
1039           The USB host controller was successfully placed in the state \r
1040           specified by State.\r
1041     EFI_INVALID_PARAMETER \r
1042           State is invalid.\r
1043     EFI_DEVICE_ERROR  \r
1044           Failed to set the state specified by State due to device error.  \r
1045           \r
1046 --*/\r
1047 {\r
1048   EFI_STATUS        Status;\r
1049   USB2_HC_DEV       *HcDev;\r
1050   UINT32            UsbCommandAddr;\r
1051   UINT32            UsbCommandReg;\r
1052   EFI_USB_HC_STATE  CurrentState;\r
1053 \r
1054   UsbCommandAddr  = USBCMD;\r
1055   HcDev           = USB2_HC_DEV_FROM_THIS (This);\r
1056 \r
1057   Status          = EhciGetState (This, &CurrentState);\r
1058   if (EFI_ERROR (Status)) {\r
1059     Status = EFI_DEVICE_ERROR;\r
1060     goto exit;\r
1061   }\r
1062 \r
1063   switch (State) {\r
1064 \r
1065   case EfiUsbHcStateHalt:\r
1066 \r
1067     if (EfiUsbHcStateHalt == CurrentState) {\r
1068       Status = EFI_SUCCESS;\r
1069       goto exit;\r
1070     } else if (EfiUsbHcStateOperational == CurrentState) {\r
1071       Status = ReadEhcOperationalReg (\r
1072                  HcDev,\r
1073                  UsbCommandAddr,\r
1074                  &UsbCommandReg\r
1075                  );\r
1076       if (EFI_ERROR (Status)) {\r
1077         Status = EFI_DEVICE_ERROR;\r
1078         goto exit;\r
1079       }\r
1080 \r
1081       UsbCommandReg &= ~USBCMD_RS;\r
1082       Status = WriteEhcOperationalReg (\r
1083                  HcDev,\r
1084                  UsbCommandAddr,\r
1085                  UsbCommandReg\r
1086                  );\r
1087       if (EFI_ERROR (Status)) {\r
1088         Status = EFI_DEVICE_ERROR;\r
1089         goto exit;\r
1090       }\r
1091       //\r
1092       // Ensure the HC is in halt status after send the stop command\r
1093       //\r
1094       Status = WaitForEhcHalt (HcDev, EHCI_GENERIC_TIMEOUT);\r
1095       if (EFI_ERROR (Status)) {\r
1096         Status = EFI_TIMEOUT;\r
1097         goto exit;\r
1098       }\r
1099     }\r
1100     break;\r
1101 \r
1102   case EfiUsbHcStateOperational:\r
1103         \r
1104     if (IsEhcSysError (HcDev)) {\r
1105       Status = EFI_DEVICE_ERROR;\r
1106       goto exit;\r
1107     }\r
1108     if (EfiUsbHcStateOperational == CurrentState) {\r
1109       Status = EFI_SUCCESS;\r
1110       goto exit;\r
1111     } else if (EfiUsbHcStateHalt == CurrentState) {\r
1112       //\r
1113       // Set Host Controller Run\r
1114       //\r
1115       Status = ReadEhcOperationalReg (\r
1116                  HcDev,\r
1117                  UsbCommandAddr,\r
1118                  &UsbCommandReg\r
1119                  );\r
1120       if (EFI_ERROR (Status)) {\r
1121         return EFI_DEVICE_ERROR;\r
1122       }\r
1123 \r
1124       UsbCommandReg |= USBCMD_RS;\r
1125       Status = WriteEhcOperationalReg (\r
1126                  HcDev,\r
1127                  UsbCommandAddr,\r
1128                  UsbCommandReg\r
1129                  );\r
1130       if (EFI_ERROR (Status)) {\r
1131         Status = EFI_DEVICE_ERROR;\r
1132         goto exit;\r
1133       }\r
1134     }\r
1135     break;\r
1136 \r
1137   case EfiUsbHcStateSuspend:\r
1138         \r
1139     Status = EFI_UNSUPPORTED;\r
1140     break;\r
1141 \r
1142   default:\r
1143         \r
1144     Status = EFI_INVALID_PARAMETER;\r
1145   }\r
1146 \r
1147 exit:\r
1148   return Status;\r
1149 }\r
1150 \r
1151 EFI_STATUS\r
1152 EFIAPI\r
1153 EhciGetRootHubPortStatus (\r
1154   IN  EFI_USB2_HC_PROTOCOL *This,\r
1155   IN  UINT8                PortNumber,\r
1156   OUT EFI_USB_PORT_STATUS  *PortStatus\r
1157   )\r
1158 /*++\r
1159   \r
1160   Routine Description:\r
1161   \r
1162     Retrieves the current status of a USB root hub port.\r
1163   \r
1164   Arguments:\r
1165   \r
1166     This        - A pointer to the EFI_USB2_HC_PROTOCOL.\r
1167     PortNumber  - Specifies the root hub port from which the status \r
1168                   is to be retrieved.  This value is zero-based. For example, \r
1169                   if a root hub has two ports, then the first port is numbered 0,\r
1170                   and the second port is numbered 1.\r
1171     PortStatus  - A pointer to the current port status bits and \r
1172                   port status change bits.  \r
1173   \r
1174   Returns:\r
1175   \r
1176     EFI_SUCCESS           The status of the USB root hub port specified \r
1177                           by PortNumber was returned in PortStatus.\r
1178     EFI_INVALID_PARAMETER PortNumber is invalid. \r
1179     EFI_DEVICE_ERROR      Can't read register     \r
1180     \r
1181 --*/\r
1182 {\r
1183   EFI_STATUS  Status;\r
1184   USB2_HC_DEV *HcDev;\r
1185   UINT32      PortStatusControlAddr;\r
1186   UINT32      PortStatusControlReg;\r
1187   UINT8       MaxSpeed;\r
1188   UINT8       TotalPortNumber;\r
1189   UINT8       Is64BitCapable;\r
1190 \r
1191   if (PortStatus == NULL) {\r
1192     Status = EFI_INVALID_PARAMETER;\r
1193     goto exit;\r
1194   }\r
1195 \r
1196   EhciGetCapability (\r
1197     This, \r
1198     &MaxSpeed, \r
1199     &TotalPortNumber, \r
1200     &Is64BitCapable\r
1201     );\r
1202   \r
1203   if (PortNumber >= TotalPortNumber) {\r
1204     Status = EFI_INVALID_PARAMETER;\r
1205     goto exit;\r
1206   }\r
1207 \r
1208   HcDev                 = USB2_HC_DEV_FROM_THIS (This);\r
1209   PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));\r
1210 \r
1211   //\r
1212   // Clear port status\r
1213   //\r
1214   PortStatus->PortStatus        = 0;\r
1215   PortStatus->PortChangeStatus  = 0;\r
1216 \r
1217   Status = ReadEhcOperationalReg (\r
1218              HcDev,\r
1219              PortStatusControlAddr,\r
1220              &PortStatusControlReg\r
1221              );\r
1222   if (EFI_ERROR (Status)) {\r
1223     Status = EFI_DEVICE_ERROR;\r
1224     goto exit;\r
1225   }\r
1226   \r
1227   //\r
1228   //    Fill Port Status bits\r
1229   //\r
1230   \r
1231   //\r
1232   // Current Connect Status\r
1233   //\r
1234   if (PORTSC_CCS & PortStatusControlReg) {\r
1235     PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;\r
1236   }\r
1237   //\r
1238   // Port Enabled/Disabled\r
1239   //\r
1240   if (PORTSC_PED & PortStatusControlReg) {\r
1241     PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;\r
1242   }\r
1243   //\r
1244   // Port Suspend\r
1245   //\r
1246   if (PORTSC_SUSP & PortStatusControlReg) {\r
1247     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;\r
1248   }\r
1249   //\r
1250   // Over-current Active\r
1251   //\r
1252   if (PORTSC_OCA & PortStatusControlReg) {\r
1253     PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;\r
1254   }\r
1255   //\r
1256   // Port Reset\r
1257   //\r
1258   if (PORTSC_PR & PortStatusControlReg) {\r
1259     PortStatus->PortStatus |= USB_PORT_STAT_RESET;\r
1260   }\r
1261   //\r
1262   // Port Power\r
1263   //\r
1264   if (PORTSC_PP & PortStatusControlReg) {\r
1265     PortStatus->PortStatus |= USB_PORT_STAT_POWER;\r
1266   }\r
1267   //\r
1268   // Port Owner\r
1269   //\r
1270   if (PORTSC_PO & PortStatusControlReg) {\r
1271     PortStatus->PortStatus |= USB_PORT_STAT_OWNER;\r
1272   }\r
1273   //\r
1274   // Identify device speed\r
1275   //\r
1276   if (PORTSC_LS_KSTATE & PortStatusControlReg) {\r
1277     //\r
1278     // Low Speed Device Attached\r
1279     //\r
1280     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;\r
1281   } else {\r
1282     //\r
1283     // Not Low Speed Device Attached\r
1284     //\r
1285     if ((PORTSC_CCS & PortStatusControlReg) && (PORTSC_CSC & PortStatusControlReg)) {\r
1286       mDeviceSpeed[PortNumber] = IsHighSpeedDevice (This, PortNumber) ? USB_PORT_STAT_HIGH_SPEED : 0;\r
1287     }\r
1288     PortStatus->PortStatus |= mDeviceSpeed[PortNumber];\r
1289   }\r
1290   //\r
1291   // Fill Port Status Change bits\r
1292   //\r
1293   //\r
1294   // Connect Status Change\r
1295   //\r
1296   if (PORTSC_CSC & PortStatusControlReg) {\r
1297     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;\r
1298   }\r
1299   //\r
1300   // Port Enabled/Disabled Change\r
1301   //\r
1302   if (PORTSC_PEDC & PortStatusControlReg) {\r
1303     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;\r
1304   }\r
1305   //\r
1306   // Port Over Current Change\r
1307   //\r
1308   if (PORTSC_OCC & PortStatusControlReg) {\r
1309     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;\r
1310   }\r
1311 \r
1312 exit:\r
1313   return Status;\r
1314 }\r
1315 \r
1316 EFI_STATUS\r
1317 EFIAPI\r
1318 EhciSetRootHubPortFeature (\r
1319   IN  EFI_USB2_HC_PROTOCOL     *This,\r
1320   IN  UINT8                    PortNumber,\r
1321   IN  EFI_USB_PORT_FEATURE     PortFeature\r
1322   )\r
1323 /*++\r
1324   \r
1325   Routine Description:\r
1326   \r
1327     Sets a feature for the specified root hub port.\r
1328   \r
1329   Arguments:\r
1330   \r
1331     This        - A pointer to the EFI_USB2_HC_PROTOCOL.\r
1332     PortNumber  - Specifies the root hub port whose feature \r
1333                   is requested to be set.\r
1334     PortFeature - Indicates the feature selector associated \r
1335                   with the feature set request. \r
1336   \r
1337   Returns:\r
1338   \r
1339     EFI_SUCCESS \r
1340         The feature specified by PortFeature was set for the \r
1341         USB root hub port specified by PortNumber.\r
1342     EFI_INVALID_PARAMETER \r
1343         PortNumber is invalid or PortFeature is invalid.\r
1344     EFI_DEVICE_ERROR\r
1345         Can't read register\r
1346         \r
1347 --*/\r
1348 {\r
1349   EFI_STATUS  Status;\r
1350   USB2_HC_DEV *HcDev;\r
1351   UINT32      PortStatusControlAddr;\r
1352   UINT32      PortStatusControlReg;\r
1353   UINT8       MaxSpeed;\r
1354   UINT8       TotalPortNumber;\r
1355   UINT8       Is64BitCapable;\r
1356 \r
1357   EhciGetCapability (\r
1358     This, \r
1359     &MaxSpeed, \r
1360     &TotalPortNumber, \r
1361     &Is64BitCapable\r
1362     );\r
1363 \r
1364   if (PortNumber >= TotalPortNumber) {\r
1365     Status = EFI_INVALID_PARAMETER;\r
1366     goto exit;\r
1367   }\r
1368 \r
1369   HcDev                 = USB2_HC_DEV_FROM_THIS (This);\r
1370   PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));\r
1371 \r
1372   Status = ReadEhcOperationalReg (\r
1373              HcDev,\r
1374              PortStatusControlAddr,\r
1375              &PortStatusControlReg\r
1376              );\r
1377   if (EFI_ERROR (Status)) {\r
1378     Status = EFI_DEVICE_ERROR;\r
1379     goto exit;\r
1380   }\r
1381 \r
1382   switch (PortFeature) {\r
1383 \r
1384   case EfiUsbPortEnable:\r
1385   \r
1386     //\r
1387     // Sofeware can't set this bit, Port can only be enable by the Host Controller\r
1388     // as a part of the reset and enable\r
1389     //\r
1390     PortStatusControlReg &= 0xffffffd5;\r
1391     PortStatusControlReg |= PORTSC_PED;\r
1392     break;\r
1393 \r
1394   case EfiUsbPortSuspend:\r
1395   \r
1396     PortStatusControlReg &= 0xffffffd5;\r
1397     PortStatusControlReg |= PORTSC_SUSP;\r
1398     break;\r
1399 \r
1400   case EfiUsbPortReset:\r
1401   \r
1402     //\r
1403     // Make sure Host Controller not halt before reset it\r
1404     //\r
1405     if (IsEhcHalted (HcDev)) {\r
1406       Status = StartScheduleExecution (HcDev);\r
1407       if (EFI_ERROR (Status)) {\r
1408         Status = EFI_DEVICE_ERROR;\r
1409         goto exit;\r
1410       }\r
1411       Status = WaitForEhcNotHalt (HcDev, EHCI_GENERIC_TIMEOUT);\r
1412       if (EFI_ERROR (Status)) {\r
1413         DEBUG ((gEHCDebugLevel, "WaitForEhcNotHalt TimeOut\n"));\r
1414         Status = EFI_DEVICE_ERROR;\r
1415         goto exit;\r
1416       }\r
1417     }\r
1418     PortStatusControlReg &= 0xffffffd5;\r
1419     PortStatusControlReg |= PORTSC_PR;\r
1420     //\r
1421     // Set one to PortReset bit must also set zero to PortEnable bit\r
1422     //\r
1423     PortStatusControlReg &= ~PORTSC_PED;\r
1424     break;\r
1425 \r
1426   case EfiUsbPortPower:\r
1427     \r
1428     //\r
1429     // No support, no operation\r
1430     //\r
1431     goto exit;\r
1432 \r
1433   case EfiUsbPortOwner:\r
1434   \r
1435     PortStatusControlReg &= 0xffffffd5;\r
1436     PortStatusControlReg |= PORTSC_PO;\r
1437     break;\r
1438 \r
1439   default:\r
1440         \r
1441     Status = EFI_INVALID_PARAMETER;\r
1442     goto exit;\r
1443   }\r
1444 \r
1445   Status = WriteEhcOperationalReg (\r
1446              HcDev,\r
1447              PortStatusControlAddr,\r
1448              PortStatusControlReg\r
1449              );\r
1450   if (EFI_ERROR (Status)) {\r
1451     Status = EFI_DEVICE_ERROR;\r
1452   }\r
1453 \r
1454 exit:\r
1455   return Status;\r
1456 }\r
1457 \r
1458 EFI_STATUS\r
1459 EFIAPI\r
1460 EhciClearRootHubPortFeature (\r
1461   IN  EFI_USB2_HC_PROTOCOL     *This,\r
1462   IN  UINT8                    PortNumber,\r
1463   IN  EFI_USB_PORT_FEATURE     PortFeature\r
1464   )\r
1465 /*++\r
1466   \r
1467   Routine Description:\r
1468   \r
1469     Clears a feature for the specified root hub port.\r
1470   \r
1471   Arguments:\r
1472   \r
1473     This        - A pointer to the EFI_USB2_HC_PROTOCOL instance. \r
1474     PortNumber  - Specifies the root hub port whose feature \r
1475                   is requested to be cleared.\r
1476     PortFeature - Indicates the feature selector associated with the \r
1477                   feature clear request.\r
1478                   \r
1479   Returns:\r
1480   \r
1481     EFI_SUCCESS \r
1482         The feature specified by PortFeature was cleared for the \r
1483         USB root hub port specified by PortNumber.\r
1484     EFI_INVALID_PARAMETER \r
1485         PortNumber is invalid or PortFeature is invalid.\r
1486     EFI_DEVICE_ERROR\r
1487         Can't read register\r
1488         \r
1489 --*/\r
1490 {\r
1491   EFI_STATUS  Status;\r
1492   USB2_HC_DEV *HcDev;\r
1493   UINT32      PortStatusControlAddr;\r
1494   UINT32      PortStatusControlReg;\r
1495   UINT8       MaxSpeed;\r
1496   UINT8       TotalPortNumber;\r
1497   UINT8       Is64BitCapable;\r
1498 \r
1499   EhciGetCapability (\r
1500     This, \r
1501     &MaxSpeed, \r
1502     &TotalPortNumber, \r
1503     &Is64BitCapable\r
1504     );\r
1505 \r
1506   if (PortNumber >= TotalPortNumber) {\r
1507     Status = EFI_INVALID_PARAMETER;\r
1508     goto exit;\r
1509   }\r
1510 \r
1511   HcDev                 = USB2_HC_DEV_FROM_THIS (This);\r
1512   PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));\r
1513 \r
1514   Status = ReadEhcOperationalReg (\r
1515              HcDev,\r
1516              PortStatusControlAddr,\r
1517              &PortStatusControlReg\r
1518              );\r
1519   if (EFI_ERROR (Status)) {\r
1520     Status = EFI_DEVICE_ERROR;\r
1521     goto exit;\r
1522   }\r
1523 \r
1524   switch (PortFeature) {\r
1525 \r
1526   case EfiUsbPortEnable:\r
1527   \r
1528     //\r
1529     // Clear PORT_ENABLE feature means disable port.\r
1530     //\r
1531     PortStatusControlReg &= 0xffffffd5;\r
1532     PortStatusControlReg &= ~PORTSC_PED;\r
1533     break;\r
1534 \r
1535   case EfiUsbPortSuspend:\r
1536   \r
1537     //\r
1538     // A write of zero to this bit is ignored by the host controller.\r
1539     // The host controller will unconditionally set this bit to a zero when:\r
1540     //   1. software sets the Forct Port Resume bit to a zero from a one.\r
1541     //   2. software sets the Port Reset bit to a one frome a zero.\r
1542     //\r
1543     PortStatusControlReg &= 0xffffffd5;\r
1544     PortStatusControlReg &= ~PORTSC_FPR;\r
1545     break;\r
1546 \r
1547   case EfiUsbPortReset:\r
1548   \r
1549     //\r
1550     // Clear PORT_RESET means clear the reset signal.\r
1551     //\r
1552     PortStatusControlReg &= 0xffffffd5;\r
1553     PortStatusControlReg &= ~PORTSC_PR;\r
1554     break;\r
1555 \r
1556   case EfiUsbPortPower:\r
1557   \r
1558     //\r
1559     // No support, no operation\r
1560     //\r
1561     goto exit;\r
1562 \r
1563   case EfiUsbPortOwner:\r
1564   \r
1565     //\r
1566     // Clear port owner means this port owned by EHC\r
1567     //\r
1568     PortStatusControlReg &= 0xffffffd5;\r
1569     PortStatusControlReg &= ~PORTSC_PO;\r
1570     break;\r
1571 \r
1572   case EfiUsbPortConnectChange:\r
1573   \r
1574     //\r
1575     // Clear connect status change\r
1576     //\r
1577     PortStatusControlReg &= 0xffffffd5;\r
1578     PortStatusControlReg |= PORTSC_CSC;\r
1579     break;\r
1580 \r
1581   case EfiUsbPortEnableChange:\r
1582   \r
1583     //\r
1584     // Clear enable status change\r
1585     //\r
1586     PortStatusControlReg &= 0xffffffd5;\r
1587     PortStatusControlReg |= PORTSC_PEDC;\r
1588     break;\r
1589 \r
1590   case EfiUsbPortSuspendChange:\r
1591   \r
1592     //\r
1593     // No related bit, no operation\r
1594     //\r
1595     goto exit;\r
1596 \r
1597   case EfiUsbPortOverCurrentChange:\r
1598   \r
1599     //\r
1600     // Clear PortOverCurrent change\r
1601     //\r
1602     PortStatusControlReg &= 0xffffffd5;\r
1603     PortStatusControlReg |= PORTSC_OCC;\r
1604     break;\r
1605 \r
1606   case EfiUsbPortResetChange:\r
1607   \r
1608     //\r
1609     // No related bit, no operation\r
1610     //\r
1611     goto exit;\r
1612 \r
1613   default:\r
1614         \r
1615     Status = EFI_INVALID_PARAMETER;\r
1616     goto exit;\r
1617   }\r
1618 \r
1619   Status = WriteEhcOperationalReg (\r
1620              HcDev,\r
1621              PortStatusControlAddr,\r
1622              PortStatusControlReg\r
1623              );\r
1624   if (EFI_ERROR (Status)) {\r
1625     Status = EFI_DEVICE_ERROR;\r
1626     goto exit;\r
1627   }\r
1628 \r
1629 exit:\r
1630   return Status;\r
1631 }\r
1632 \r
1633 EFI_STATUS\r
1634 EFIAPI\r
1635 EhciControlTransfer (\r
1636   IN  EFI_USB2_HC_PROTOCOL                 *This,\r
1637   IN  UINT8                                DeviceAddress,\r
1638   IN  UINT8                                DeviceSpeed,\r
1639   IN  UINTN                                MaximumPacketLength,\r
1640   IN  EFI_USB_DEVICE_REQUEST               *Request,\r
1641   IN  EFI_USB_DATA_DIRECTION               TransferDirection,\r
1642   IN  OUT VOID                             *Data,\r
1643   IN  OUT UINTN                            *DataLength,\r
1644   IN  UINTN                                TimeOut,\r
1645   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,\r
1646   OUT UINT32                               *TransferResult\r
1647   )\r
1648 /*++\r
1649   \r
1650   Routine Description:\r
1651   \r
1652     Submits control transfer to a target USB device.\r
1653   \r
1654   Arguments:\r
1655     \r
1656     This            - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
1657     DeviceAddress   - Represents the address of the target device on the USB,\r
1658                       which is assigned during USB enumeration.\r
1659     DeviceSpeed     - Indicates target device speed.\r
1660     MaximumPacketLength - Indicates the maximum packet size that the \r
1661                          default control transfer endpoint is capable of \r
1662                          sending or receiving.\r
1663     Request         - A pointer to the USB device request that will be sent \r
1664                       to the USB device. \r
1665     TransferDirection - Specifies the data direction for the transfer.\r
1666                         There are three values available, DataIn, DataOut \r
1667                         and NoData.\r
1668     Data            - A pointer to the buffer of data that will be transmitted \r
1669                       to USB device or received from USB device.\r
1670     DataLength      - Indicates the size, in bytes, of the data buffer \r
1671                       specified by Data.\r
1672     TimeOut         - Indicates the maximum time, in microseconds, \r
1673                       which the transfer is allowed to complete.\r
1674     Translator      - A pointr to the transaction translator data.\r
1675     TransferResult  - A pointer to the detailed result information generated \r
1676                       by this control transfer.\r
1677                      \r
1678   Returns:\r
1679   \r
1680     EFI_SUCCESS \r
1681         The control transfer was completed successfully.\r
1682     EFI_OUT_OF_RESOURCES  \r
1683         The control transfer could not be completed due to a lack of resources.\r
1684     EFI_INVALID_PARAMETER \r
1685         Some parameters are invalid.\r
1686     EFI_TIMEOUT \r
1687         The control transfer failed due to timeout.\r
1688     EFI_DEVICE_ERROR  \r
1689         The control transfer failed due to host controller or device error. \r
1690         Caller should check TranferResult for detailed error information.\r
1691 \r
1692 --*/\r
1693 {\r
1694   EFI_STATUS      Status;\r
1695   USB2_HC_DEV     *HcDev;\r
1696   UINT8           PktId;\r
1697   EHCI_QH_ENTITY  *QhPtr;\r
1698   EHCI_QTD_ENTITY *ControlQtdsPtr;\r
1699   UINT8           *DataCursor;\r
1700   VOID            *DataMap;\r
1701   UINT8           *RequestCursor;\r
1702   VOID            *RequestMap;\r
1703 \r
1704   QhPtr           = NULL;\r
1705   ControlQtdsPtr  = NULL;\r
1706   DataCursor      = NULL;\r
1707   DataMap         = NULL;\r
1708   RequestCursor   = NULL;\r
1709   RequestMap      = NULL;\r
1710   HcDev           = USB2_HC_DEV_FROM_THIS (This);\r
1711 \r
1712   //\r
1713   // Parameters Checking\r
1714   //\r
1715   if (TransferDirection != EfiUsbDataIn &&\r
1716         TransferDirection != EfiUsbDataOut &&\r
1717         TransferDirection != EfiUsbNoData\r
1718         ) {\r
1719     Status = EFI_INVALID_PARAMETER;\r
1720     goto exit;\r
1721   }\r
1722 \r
1723   if (EfiUsbNoData == TransferDirection) {\r
1724     if (NULL != Data || 0 != *DataLength) {\r
1725       Status = EFI_INVALID_PARAMETER;\r
1726       goto exit;\r
1727     }\r
1728   } else {\r
1729     if (NULL == Data || 0 == *DataLength) {\r
1730       Status = EFI_INVALID_PARAMETER;\r
1731       goto exit;\r
1732     }\r
1733   }\r
1734 \r
1735   if (Request == NULL || TransferResult == NULL) {\r
1736     Status = EFI_INVALID_PARAMETER;\r
1737     goto exit;\r
1738   }\r
1739 \r
1740   if (EFI_USB_SPEED_LOW == DeviceSpeed) {\r
1741     if (MaximumPacketLength != 8) {\r
1742       Status = EFI_INVALID_PARAMETER;\r
1743       goto exit;\r
1744     }\r
1745   } else if (MaximumPacketLength != 8 &&\r
1746            MaximumPacketLength != 16 &&\r
1747            MaximumPacketLength != 32 &&\r
1748            MaximumPacketLength != 64\r
1749           ) {\r
1750     Status = EFI_INVALID_PARAMETER;\r
1751     goto exit;\r
1752   }\r
1753   \r
1754   //\r
1755   // If errors exist that cause host controller halt,\r
1756   // then return EFI_DEVICE_ERROR.\r
1757   //\r
1758   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
1759     ClearEhcAllStatus (HcDev);\r
1760     *TransferResult = EFI_USB_ERR_SYSTEM;\r
1761     Status          = EFI_DEVICE_ERROR;\r
1762     goto exit;\r
1763   }\r
1764   \r
1765   //\r
1766   // Map the Request for bus master access.\r
1767   // BusMasterRead means cpu write\r
1768   //\r
1769   Status = MapRequestBuffer (\r
1770              HcDev,\r
1771              Request,\r
1772              &RequestCursor,\r
1773              &RequestMap\r
1774              );\r
1775   if (EFI_ERROR (Status)) {\r
1776     *TransferResult = EFI_USB_ERR_SYSTEM;\r
1777     Status          = EFI_DEVICE_ERROR;\r
1778     goto exit;\r
1779   }\r
1780   \r
1781   //\r
1782   // Map the source data buffer for bus master access.\r
1783   //\r
1784   Status = MapDataBuffer (\r
1785              HcDev,\r
1786              TransferDirection,\r
1787              Data,\r
1788              DataLength,\r
1789              &PktId,\r
1790              &DataCursor,\r
1791              &DataMap\r
1792              );\r
1793   if (EFI_ERROR (Status)) {\r
1794     *TransferResult = EFI_USB_ERR_SYSTEM;\r
1795     Status          = EFI_DEVICE_ERROR;\r
1796     goto unmap_request;\r
1797   }\r
1798   \r
1799   //\r
1800   // Create and init control Qh\r
1801   //\r
1802   Status = CreateControlQh (\r
1803              HcDev,\r
1804              DeviceAddress,\r
1805              DeviceSpeed,\r
1806              MaximumPacketLength,\r
1807              Translator,\r
1808              &QhPtr\r
1809              );\r
1810   if (EFI_ERROR (Status)) {\r
1811     *TransferResult = EFI_USB_ERR_SYSTEM;\r
1812     Status          = EFI_OUT_OF_RESOURCES;\r
1813     goto unmap_data;\r
1814   }\r
1815   \r
1816   //\r
1817   // Create and init control Qtds\r
1818   //\r
1819   Status = CreateControlQtds (\r
1820              HcDev,\r
1821              PktId,\r
1822              RequestCursor,\r
1823              DataCursor,\r
1824              *DataLength,\r
1825              Translator,\r
1826              &ControlQtdsPtr\r
1827              );\r
1828   if (EFI_ERROR (Status)) {\r
1829     *TransferResult = EFI_USB_ERR_SYSTEM;\r
1830     Status          = EFI_OUT_OF_RESOURCES;\r
1831     goto destory_qh;\r
1832   }\r
1833   \r
1834   //\r
1835   // Link Qtds to Qh\r
1836   //\r
1837   LinkQtdToQh (QhPtr, ControlQtdsPtr);\r
1838 \r
1839   ClearEhcAllStatus (HcDev);\r
1840 \r
1841   //\r
1842   // Link Qh and Qtds to Async Schedule List\r
1843   //\r
1844   Status = LinkQhToAsyncList (HcDev, QhPtr);\r
1845   if (EFI_ERROR (Status)) {\r
1846     *TransferResult = EFI_USB_ERR_SYSTEM;\r
1847     Status          = EFI_DEVICE_ERROR;\r
1848     goto destory_qtds;\r
1849   }\r
1850   \r
1851   //\r
1852   // Poll Qh-Qtds execution and get result.\r
1853   // detail status is returned\r
1854   //\r
1855   Status = ExecuteTransfer (\r
1856              HcDev,\r
1857              TRUE,\r
1858              QhPtr,\r
1859              DataLength,\r
1860              0,\r
1861              TimeOut,\r
1862              TransferResult\r
1863              );\r
1864   if (EFI_ERROR (Status)) {\r
1865     goto destory_qtds;\r
1866   }\r
1867   \r
1868   //\r
1869   // If has errors that cause host controller halt,\r
1870   // then return EFI_DEVICE_ERROR directly.\r
1871   //\r
1872   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
1873     *TransferResult |= EFI_USB_ERR_SYSTEM;\r
1874   }\r
1875 \r
1876   ClearEhcAllStatus (HcDev);\r
1877 \r
1878 destory_qtds:\r
1879   UnlinkQhFromAsyncList (HcDev, QhPtr);\r
1880   DestoryQtds (HcDev, ControlQtdsPtr);\r
1881 destory_qh:\r
1882   DestoryQh (HcDev, QhPtr);\r
1883 unmap_data:\r
1884   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);\r
1885 unmap_request:\r
1886   HcDev->PciIo->Unmap (HcDev->PciIo, RequestMap);\r
1887 exit:\r
1888   HcDev->PciIo->Flush (HcDev->PciIo);\r
1889   return Status;\r
1890 }\r
1891 \r
1892 EFI_STATUS\r
1893 EFIAPI\r
1894 EhciBulkTransfer (\r
1895   IN  EFI_USB2_HC_PROTOCOL                *This,\r
1896   IN  UINT8                               DeviceAddress,\r
1897   IN  UINT8                               EndPointAddress,\r
1898   IN  UINT8                               DeviceSpeed,\r
1899   IN  UINTN                               MaximumPacketLength,\r
1900   IN  UINT8                               DataBuffersNumber,\r
1901   IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],\r
1902   IN  OUT UINTN                           *DataLength,\r
1903   IN  OUT UINT8                           *DataToggle,\r
1904   IN  UINTN                               TimeOut,\r
1905   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
1906   OUT UINT32                              *TransferResult\r
1907   )\r
1908 /*++\r
1909   \r
1910   Routine Description:\r
1911   \r
1912     Submits bulk transfer to a bulk endpoint of a USB device.\r
1913     \r
1914   Arguments:\r
1915     \r
1916     This              - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
1917     DeviceAddress     - Represents the address of the target device on the USB,\r
1918                         which is assigned during USB enumeration.               \r
1919     EndPointAddress   - The combination of an endpoint number and an \r
1920                         endpoint direction of the target USB device. \r
1921                         Each endpoint address supports data transfer in \r
1922                         one direction except the control endpoint \r
1923                         (whose default endpoint address is 0). \r
1924                         It is the caller's responsibility to make sure that \r
1925                         the EndPointAddress represents a bulk endpoint.                  \r
1926     DeviceSpeed       - Indicates device speed. The supported values are EFI_USB_SPEED_FULL\r
1927                         and EFI_USB_SPEED_HIGH.\r
1928     MaximumPacketLength - Indicates the maximum packet size the target endpoint\r
1929                           is capable of sending or receiving.                 \r
1930     DataBuffersNumber - Number of data buffers prepared for the transfer.\r
1931     Data              - Array of pointers to the buffers of data that will be transmitted \r
1932                         to USB device or received from USB device.              \r
1933     DataLength        - When input, indicates the size, in bytes, of the data buffer\r
1934                         specified by Data. When output, indicates the actually \r
1935                         transferred data size.              \r
1936     DataToggle        - A pointer to the data toggle value. On input, it indicates \r
1937                         the initial data toggle value the bulk transfer should adopt;\r
1938                         on output, it is updated to indicate the data toggle value \r
1939                         of the subsequent bulk transfer. \r
1940     Translator        - A pointr to the transaction translator data. \r
1941     TimeOut           - Indicates the maximum time, in microseconds, which the \r
1942                         transfer is allowed to complete.              \r
1943     TransferResult    - A pointer to the detailed result information of the \r
1944                         bulk transfer.\r
1945 \r
1946   Returns:\r
1947   \r
1948     EFI_SUCCESS \r
1949         The bulk transfer was completed successfully.\r
1950     EFI_OUT_OF_RESOURCES  \r
1951         The bulk transfer could not be submitted due to lack of resource.\r
1952     EFI_INVALID_PARAMETER \r
1953         Some parameters are invalid.\r
1954     EFI_TIMEOUT \r
1955         The bulk transfer failed due to timeout.\r
1956     EFI_DEVICE_ERROR  \r
1957         The bulk transfer failed due to host controller or device error.\r
1958         Caller should check TranferResult for detailed error information.\r
1959 \r
1960 --*/\r
1961 {\r
1962   EFI_STATUS              Status;\r
1963   USB2_HC_DEV             *HcDev;\r
1964   UINT8                   PktId;\r
1965   EHCI_QH_ENTITY          *QhPtr;\r
1966   EHCI_QTD_ENTITY         *BulkQtdsPtr;\r
1967   UINT8                   *DataCursor;\r
1968   VOID                    *DataMap;\r
1969   EFI_USB_DATA_DIRECTION  TransferDirection;\r
1970 \r
1971   QhPtr       = NULL;\r
1972   BulkQtdsPtr = NULL;\r
1973   DataCursor  = NULL;\r
1974   DataMap     = NULL;\r
1975   HcDev       = USB2_HC_DEV_FROM_THIS (This);\r
1976 \r
1977   //\r
1978   // Parameters Checking\r
1979   //\r
1980   if (NULL == DataLength ||\r
1981         NULL == Data || \r
1982         NULL == Data[0] || \r
1983         NULL == TransferResult\r
1984         ) {\r
1985     Status = EFI_INVALID_PARAMETER;\r
1986     goto exit;\r
1987   }\r
1988 \r
1989   if (*DataLength == 0) {\r
1990     Status = EFI_INVALID_PARAMETER;\r
1991     goto exit;\r
1992   }\r
1993 \r
1994   if (1 != *DataToggle && 0 != *DataToggle) {\r
1995     Status = EFI_INVALID_PARAMETER;\r
1996     goto exit;\r
1997   }\r
1998 \r
1999   if (EFI_USB_SPEED_LOW == DeviceSpeed) {\r
2000     Status = EFI_INVALID_PARAMETER;\r
2001     goto exit;\r
2002   }\r
2003 \r
2004   if (EFI_USB_SPEED_FULL == DeviceSpeed) {\r
2005     if (MaximumPacketLength > 64) {\r
2006       Status = EFI_INVALID_PARAMETER;\r
2007       goto exit;\r
2008     }\r
2009   }\r
2010 \r
2011   if (EFI_USB_SPEED_HIGH == DeviceSpeed) {\r
2012     if (MaximumPacketLength > 512) {\r
2013       Status = EFI_INVALID_PARAMETER;\r
2014       goto exit;\r
2015     }\r
2016   }\r
2017   \r
2018   //\r
2019   // if has errors that cause host controller halt,\r
2020   // then return EFI_DEVICE_ERROR directly.\r
2021   //\r
2022   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
2023     ClearEhcAllStatus (HcDev);\r
2024     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2025     Status          = EFI_DEVICE_ERROR;\r
2026     goto exit;\r
2027   }\r
2028 \r
2029   Status = ClearEhcAllStatus (HcDev);\r
2030   if (EFI_ERROR (Status)) {\r
2031     Status = EFI_DEVICE_ERROR;\r
2032     goto exit;\r
2033   }\r
2034   \r
2035   //\r
2036   // construct QH and TD data structures,\r
2037   // and link them together\r
2038   //\r
2039   if (EndPointAddress & 0x80) {\r
2040     TransferDirection = EfiUsbDataIn;\r
2041   } else {\r
2042     TransferDirection = EfiUsbDataOut;\r
2043   }\r
2044 \r
2045   Status = MapDataBuffer (\r
2046              HcDev,\r
2047              TransferDirection,\r
2048              Data[0],\r
2049              DataLength,\r
2050              &PktId,\r
2051              &DataCursor,\r
2052              &DataMap\r
2053              );\r
2054   if (EFI_ERROR (Status)) {\r
2055     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2056     Status          = EFI_DEVICE_ERROR;\r
2057     goto exit;\r
2058   }\r
2059   \r
2060   //\r
2061   // Create and init Bulk Qh\r
2062   //\r
2063   Status = CreateBulkQh (\r
2064              HcDev,\r
2065              DeviceAddress,\r
2066              EndPointAddress,\r
2067              DeviceSpeed,\r
2068              *DataToggle,\r
2069              MaximumPacketLength,\r
2070              Translator,\r
2071              &QhPtr\r
2072              );\r
2073   if (EFI_ERROR (Status)) {\r
2074     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2075     Status          = EFI_OUT_OF_RESOURCES;\r
2076     goto unmap_data;\r
2077   }\r
2078   \r
2079   //\r
2080   // Create and init Bulk Qtds\r
2081   //\r
2082   Status = CreateBulkOrInterruptQtds (\r
2083              HcDev,\r
2084              PktId,\r
2085              DataCursor,\r
2086              *DataLength,\r
2087              Translator,\r
2088              &BulkQtdsPtr\r
2089              );\r
2090   if (EFI_ERROR (Status)) {\r
2091     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2092     Status          = EFI_OUT_OF_RESOURCES;\r
2093     goto destory_qh;\r
2094   }\r
2095   \r
2096   //\r
2097   // Link Qtds to Qh\r
2098   //\r
2099   LinkQtdToQh (QhPtr, BulkQtdsPtr);\r
2100 \r
2101   ClearEhcAllStatus (HcDev);\r
2102 \r
2103   //\r
2104   // Link Qh and qtds to Async Schedule List\r
2105   //\r
2106   Status = LinkQhToAsyncList (HcDev, QhPtr);\r
2107   if (EFI_ERROR (Status)) {\r
2108     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2109     Status          = EFI_DEVICE_ERROR;\r
2110     goto destory_qtds;\r
2111   }\r
2112   \r
2113   //\r
2114   // Poll QH-TDs execution and get result.\r
2115   // detail status is returned\r
2116   //\r
2117   Status = ExecuteTransfer (\r
2118              HcDev,\r
2119              FALSE,\r
2120              QhPtr,\r
2121              DataLength,\r
2122              DataToggle,\r
2123              TimeOut,\r
2124              TransferResult\r
2125              );\r
2126   if (EFI_ERROR (Status)) {\r
2127     goto destory_qtds;\r
2128   }\r
2129   \r
2130   //\r
2131   // if has errors that cause host controller halt,\r
2132   // then return EFI_DEVICE_ERROR directly.\r
2133   //\r
2134   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
2135     *TransferResult |= EFI_USB_ERR_SYSTEM;\r
2136   }\r
2137 \r
2138   ClearEhcAllStatus (HcDev);\r
2139 \r
2140 destory_qtds:\r
2141   UnlinkQhFromAsyncList (HcDev, QhPtr);\r
2142   DestoryQtds (HcDev, BulkQtdsPtr);\r
2143 destory_qh:\r
2144   DestoryQh (HcDev, QhPtr);\r
2145 unmap_data:\r
2146   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);\r
2147 exit:\r
2148   HcDev->PciIo->Flush (HcDev->PciIo);\r
2149   return Status;\r
2150 }\r
2151 \r
2152 EFI_STATUS\r
2153 EFIAPI\r
2154 EhciAsyncInterruptTransfer (\r
2155   IN  EFI_USB2_HC_PROTOCOL                  * This,\r
2156   IN  UINT8                                 DeviceAddress,\r
2157   IN  UINT8                                 EndPointAddress,\r
2158   IN  UINT8                                 DeviceSpeed,\r
2159   IN  UINTN                                 MaximumPacketLength,\r
2160   IN  BOOLEAN                               IsNewTransfer,\r
2161   IN  OUT UINT8                             *DataToggle,\r
2162   IN  UINTN                                 PollingInterval,\r
2163   IN  UINTN                                 DataLength,\r
2164   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    * Translator,\r
2165   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,\r
2166   IN  VOID                                  *Context OPTIONAL\r
2167   )\r
2168 /*++\r
2169   \r
2170   Routine Description:\r
2171   \r
2172     Submits an asynchronous interrupt transfer to an \r
2173     interrupt endpoint of a USB device.\r
2174     Translator parameter doesn't exist in UEFI2.0 spec, but it will be updated \r
2175     in the following specification version.\r
2176     \r
2177   Arguments:\r
2178     \r
2179     This            - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
2180     DeviceAddress   - Represents the address of the target device on the USB,\r
2181                       which is assigned during USB enumeration.                \r
2182     EndPointAddress - The combination of an endpoint number and an endpoint \r
2183                       direction of the target USB device. Each endpoint address \r
2184                       supports data transfer in one direction except the \r
2185                       control endpoint (whose default endpoint address is 0). \r
2186                       It is the caller's responsibility to make sure that \r
2187                       the EndPointAddress represents an interrupt endpoint.              \r
2188     DeviceSpeed     - Indicates device speed.\r
2189     MaximumPacketLength  - Indicates the maximum packet size the target endpoint\r
2190                            is capable of sending or receiving.                   \r
2191     IsNewTransfer   - If TRUE, an asynchronous interrupt pipe is built between\r
2192                       the host and the target interrupt endpoint. \r
2193                       If FALSE, the specified asynchronous interrupt pipe \r
2194                       is canceled.               \r
2195     DataToggle      - A pointer to the data toggle value.  On input, it is valid \r
2196                       when IsNewTransfer is TRUE, and it indicates the initial \r
2197                       data toggle value the asynchronous interrupt transfer \r
2198                       should adopt.  \r
2199                       On output, it is valid when IsNewTransfer is FALSE, \r
2200                       and it is updated to indicate the data toggle value of \r
2201                       the subsequent asynchronous interrupt transfer.              \r
2202     PollingInterval - Indicates the interval, in milliseconds, that the \r
2203                       asynchronous interrupt transfer is polled.  \r
2204                       This parameter is required when IsNewTransfer is TRUE.               \r
2205     DataLength      - Indicates the length of data to be received at the \r
2206                       rate specified by PollingInterval from the target \r
2207                       asynchronous interrupt endpoint.  This parameter \r
2208                       is only required when IsNewTransfer is TRUE.             \r
2209     Translator      - A pointr to the transaction translator data.\r
2210     CallBackFunction  - The Callback function.This function is called at the \r
2211                         rate specified by PollingInterval.This parameter is \r
2212                         only required when IsNewTransfer is TRUE.               \r
2213     Context         - The context that is passed to the CallBackFunction.\r
2214                     - This is an optional parameter and may be NULL.\r
2215   \r
2216   Returns:\r
2217   \r
2218     EFI_SUCCESS \r
2219         The asynchronous interrupt transfer request has been successfully \r
2220         submitted or canceled.\r
2221     EFI_INVALID_PARAMETER \r
2222         Some parameters are invalid.\r
2223     EFI_OUT_OF_RESOURCES  \r
2224         The request could not be completed due to a lack of resources.  \r
2225     EFI_DEVICE_ERROR\r
2226         Can't read register\r
2227         \r
2228 --*/\r
2229 {\r
2230   EFI_STATUS          Status;\r
2231   USB2_HC_DEV         *HcDev;\r
2232   UINT8               PktId;\r
2233   EHCI_QH_ENTITY      *QhPtr;\r
2234   EHCI_QTD_ENTITY     *InterruptQtdsPtr;\r
2235   UINT8               *DataPtr;\r
2236   UINT8               *DataCursor;\r
2237   VOID                *DataMap;\r
2238   UINTN               MappedLength;\r
2239   EHCI_ASYNC_REQUEST  *AsyncRequestPtr;\r
2240   EFI_TPL             OldTpl;\r
2241 \r
2242   QhPtr             = NULL;\r
2243   InterruptQtdsPtr  = NULL;\r
2244   DataPtr           = NULL;\r
2245   DataCursor        = NULL;\r
2246   DataMap           = NULL;\r
2247   AsyncRequestPtr   = NULL;\r
2248   HcDev             = USB2_HC_DEV_FROM_THIS (This);\r
2249 \r
2250   //\r
2251   // Parameters Checking\r
2252   //\r
2253   if (!IsDataInTransfer (EndPointAddress)) {\r
2254     Status = EFI_INVALID_PARAMETER;\r
2255     goto exit;\r
2256   }\r
2257 \r
2258   if (IsNewTransfer) {\r
2259     if (0 == DataLength) {\r
2260       Status = EFI_INVALID_PARAMETER;\r
2261       goto exit;\r
2262     }\r
2263 \r
2264     if (*DataToggle != 1 && *DataToggle != 0) {\r
2265       Status = EFI_INVALID_PARAMETER;\r
2266       goto exit;\r
2267     }\r
2268 \r
2269     if (PollingInterval > 255 || PollingInterval < 1) {\r
2270       Status = EFI_INVALID_PARAMETER;\r
2271       goto exit;\r
2272     }\r
2273   }\r
2274   \r
2275   //\r
2276   // if has errors that cause host controller halt,\r
2277   // then return EFI_DEVICE_ERROR directly.\r
2278   //\r
2279   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
2280     ClearEhcAllStatus (HcDev);\r
2281     Status = EFI_DEVICE_ERROR;\r
2282     goto exit;\r
2283   }\r
2284 \r
2285   Status = ClearEhcAllStatus (HcDev);\r
2286   if (EFI_ERROR (Status)) {\r
2287     Status = EFI_DEVICE_ERROR;\r
2288     goto exit;\r
2289   }\r
2290   \r
2291   //\r
2292   // Delete Async interrupt transfer request\r
2293   //\r
2294   if (!IsNewTransfer) {\r
2295 \r
2296     OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);\r
2297 \r
2298     Status = DeleteAsyncRequestTransfer (\r
2299                HcDev,\r
2300                DeviceAddress,\r
2301                EndPointAddress,\r
2302                DataToggle\r
2303                );\r
2304 \r
2305     gBS->RestoreTPL (OldTpl);\r
2306 \r
2307     goto exit;\r
2308   }\r
2309 \r
2310   Status = EhciAllocatePool (\r
2311                  HcDev, \r
2312                  (UINT8 **) &AsyncRequestPtr, \r
2313                  sizeof (EHCI_ASYNC_REQUEST)\r
2314                  );\r
2315   if (EFI_ERROR (Status)) {\r
2316     Status = EFI_OUT_OF_RESOURCES;\r
2317     goto exit;\r
2318   }\r
2319 \r
2320   Status = EhciAllocatePool (HcDev, &DataPtr, DataLength);\r
2321   if (EFI_ERROR (Status)) {\r
2322     Status = EFI_OUT_OF_RESOURCES;\r
2323     goto free_request;\r
2324   }\r
2325 \r
2326   MappedLength = DataLength;\r
2327   Status = MapDataBuffer (\r
2328              HcDev,\r
2329              EfiUsbDataIn,\r
2330              DataPtr,\r
2331              &MappedLength,\r
2332              &PktId,\r
2333              &DataCursor,\r
2334              &DataMap\r
2335              );\r
2336   if (EFI_ERROR (Status)) {\r
2337     Status = EFI_DEVICE_ERROR;\r
2338     goto free_data;\r
2339   }\r
2340   \r
2341   //\r
2342   // Create and init Interrupt Qh\r
2343   //\r
2344   Status = CreateInterruptQh (\r
2345              HcDev,\r
2346              DeviceAddress,\r
2347              EndPointAddress,\r
2348              DeviceSpeed,\r
2349              *DataToggle,\r
2350              MaximumPacketLength,\r
2351              PollingInterval,\r
2352              Translator,\r
2353              &QhPtr\r
2354              );\r
2355   if (EFI_ERROR (Status)) {\r
2356     Status = EFI_OUT_OF_RESOURCES;\r
2357     goto unmap_data;\r
2358   }\r
2359   \r
2360   //\r
2361   // Create and init Interrupt Qtds\r
2362   //\r
2363   Status = CreateBulkOrInterruptQtds (\r
2364              HcDev,\r
2365              PktId,\r
2366              DataCursor,\r
2367              MappedLength,\r
2368              Translator,\r
2369              &InterruptQtdsPtr\r
2370              );\r
2371   if (EFI_ERROR (Status)) {\r
2372     Status = EFI_OUT_OF_RESOURCES;\r
2373     goto destory_qh;\r
2374   }\r
2375   \r
2376   //\r
2377   // Link Qtds to Qh\r
2378   //\r
2379   LinkQtdToQh (QhPtr, InterruptQtdsPtr);\r
2380 \r
2381   //\r
2382   // Init AsyncRequest Entry\r
2383   //\r
2384   AsyncRequestPtr->Context      = Context;\r
2385   AsyncRequestPtr->CallBackFunc = CallBackFunction;\r
2386   AsyncRequestPtr->TransferType = ASYNC_INTERRUPT_TRANSFER;\r
2387   AsyncRequestPtr->QhPtr        = QhPtr;\r
2388   AsyncRequestPtr->Prev         = NULL;\r
2389   AsyncRequestPtr->Next         = NULL;\r
2390 \r
2391   if (NULL == HcDev->AsyncRequestList) {\r
2392     Status = StartPollingTimer (HcDev);\r
2393     if (EFI_ERROR (Status)) {\r
2394       Status = EFI_DEVICE_ERROR;\r
2395       CleanUpAllAsyncRequestTransfer (HcDev);\r
2396       goto exit;\r
2397     }\r
2398   }\r
2399   \r
2400   //\r
2401   // Link Entry to AsyncRequest List\r
2402   //\r
2403   LinkToAsyncReqeust (HcDev, AsyncRequestPtr);\r
2404 \r
2405   ClearEhcAllStatus (HcDev);\r
2406 \r
2407   Status = DisablePeriodicSchedule (HcDev);\r
2408   if (EFI_ERROR (Status)) {\r
2409     Status = EFI_DEVICE_ERROR;\r
2410     goto exit;\r
2411   }\r
2412 \r
2413   Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2414   if (EFI_ERROR (Status)) {\r
2415     Status = EFI_TIMEOUT;\r
2416     goto exit;\r
2417   }\r
2418   \r
2419   //\r
2420   // Link Qh and Qtds to Periodic Schedule List\r
2421   //\r
2422   LinkQhToPeriodicList (HcDev, QhPtr);\r
2423 \r
2424   Status = EnablePeriodicSchedule (HcDev);\r
2425   if (EFI_ERROR (Status)) {\r
2426     Status = EFI_DEVICE_ERROR;\r
2427     goto exit;\r
2428   }\r
2429 \r
2430   Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2431   if (EFI_ERROR (Status)) {\r
2432     Status = EFI_TIMEOUT;\r
2433     goto exit;\r
2434   }\r
2435 \r
2436   if (IsEhcHalted (HcDev)) {\r
2437     Status = StartScheduleExecution (HcDev);\r
2438     if (EFI_ERROR (Status)) {\r
2439       Status = EFI_DEVICE_ERROR;\r
2440       goto exit;\r
2441     }\r
2442   }\r
2443 \r
2444   HcDev->PciIo->Flush (HcDev->PciIo);\r
2445   goto exit;\r
2446 \r
2447 destory_qh:\r
2448   DestoryQh (HcDev, QhPtr);\r
2449 free_data:\r
2450   EhciFreePool (HcDev, DataPtr, DataLength);\r
2451 free_request:\r
2452   EhciFreePool (\r
2453         HcDev, \r
2454         (UINT8 *) AsyncRequestPtr, \r
2455         sizeof (EHCI_ASYNC_REQUEST)\r
2456         );\r
2457 unmap_data:\r
2458   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);\r
2459 exit:\r
2460   return Status;\r
2461 }\r
2462 \r
2463 EFI_STATUS\r
2464 EFIAPI\r
2465 EhciSyncInterruptTransfer (\r
2466   IN  EFI_USB2_HC_PROTOCOL                  *This,\r
2467   IN  UINT8                                 DeviceAddress,\r
2468   IN  UINT8                                 EndPointAddress,\r
2469   IN  UINT8                                 DeviceSpeed,\r
2470   IN  UINTN                                 MaximumPacketLength,\r
2471   IN  OUT VOID                              *Data,\r
2472   IN  OUT UINTN                             *DataLength,\r
2473   IN  OUT UINT8                             *DataToggle,\r
2474   IN  UINTN                                 TimeOut,\r
2475   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,\r
2476   OUT UINT32                                *TransferResult\r
2477   )\r
2478 /*++\r
2479   \r
2480   Routine Description:\r
2481   \r
2482     Submits synchronous interrupt transfer to an interrupt endpoint \r
2483     of a USB device. \r
2484     Translator parameter doesn't exist in UEFI2.0 spec, but it will be updated \r
2485     in the following specification version.\r
2486   \r
2487   Arguments:\r
2488     \r
2489     This            - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
2490     DeviceAddress   - Represents the address of the target device on the USB, \r
2491                       which is assigned during USB enumeration.\r
2492     EndPointAddress - The combination of an endpoint number and an endpoint \r
2493                       direction of the target USB device. Each endpoint \r
2494                       address supports data transfer in one direction \r
2495                       except the control endpoint (whose default \r
2496                       endpoint address is 0). It is the caller's responsibility\r
2497                       to make sure that the EndPointAddress represents \r
2498                       an interrupt endpoint. \r
2499     DeviceSpeed     - Indicates device speed.\r
2500     MaximumPacketLength - Indicates the maximum packet size the target endpoint \r
2501                           is capable of sending or receiving.\r
2502     Data            - A pointer to the buffer of data that will be transmitted \r
2503                       to USB device or received from USB device.\r
2504     DataLength      - On input, the size, in bytes, of the data buffer specified \r
2505                       by Data. On output, the number of bytes transferred.\r
2506     DataToggle      - A pointer to the data toggle value. On input, it indicates\r
2507                       the initial data toggle value the synchronous interrupt \r
2508                       transfer should adopt; \r
2509                       on output, it is updated to indicate the data toggle value \r
2510                       of the subsequent synchronous interrupt transfer. \r
2511     TimeOut         - Indicates the maximum time, in microseconds, which the \r
2512                       transfer is allowed to complete.\r
2513     Translator      - A pointr to the transaction translator data.\r
2514     TransferResult  - A pointer to the detailed result information from \r
2515                       the synchronous interrupt transfer.  \r
2516 \r
2517   Returns:\r
2518   \r
2519     EFI_SUCCESS \r
2520         The synchronous interrupt transfer was completed successfully.\r
2521     EFI_OUT_OF_RESOURCES  \r
2522         The synchronous interrupt transfer could not be submitted due \r
2523         to lack of resource.\r
2524     EFI_INVALID_PARAMETER \r
2525         Some parameters are invalid.\r
2526     EFI_TIMEOUT \r
2527         The synchronous interrupt transfer failed due to timeout.\r
2528     EFI_DEVICE_ERROR  \r
2529         The synchronous interrupt transfer failed due to host controller \r
2530         or device error. Caller should check TranferResult for detailed \r
2531         error information.  \r
2532         \r
2533 --*/\r
2534 {\r
2535   EFI_STATUS      Status;\r
2536   USB2_HC_DEV     *HcDev;\r
2537   UINT8           PktId;\r
2538   EHCI_QH_ENTITY  *QhPtr;\r
2539   EHCI_QTD_ENTITY *InterruptQtdsPtr;\r
2540   UINT8           *DataCursor;\r
2541   VOID            *DataMap;\r
2542 \r
2543   QhPtr             = NULL;\r
2544   InterruptQtdsPtr  = NULL;\r
2545   DataCursor        = NULL;\r
2546   DataMap           = NULL;\r
2547   HcDev             = USB2_HC_DEV_FROM_THIS (This);\r
2548 \r
2549   //\r
2550   // Parameters Checking\r
2551   //\r
2552   if (DataLength == NULL ||\r
2553         Data == NULL || \r
2554         TransferResult == NULL\r
2555         ) {\r
2556     Status = EFI_INVALID_PARAMETER;\r
2557     goto exit;\r
2558   }\r
2559 \r
2560   if (!IsDataInTransfer (EndPointAddress)) {\r
2561     Status = EFI_INVALID_PARAMETER;\r
2562     goto exit;\r
2563   }\r
2564 \r
2565   if (0 == *DataLength) {\r
2566     Status = EFI_INVALID_PARAMETER;\r
2567     goto exit;\r
2568   }\r
2569 \r
2570   if (*DataToggle != 1 && *DataToggle != 0) {\r
2571     Status = EFI_INVALID_PARAMETER;\r
2572     goto exit;\r
2573   }\r
2574 \r
2575   if (EFI_USB_SPEED_LOW == DeviceSpeed && 8 != MaximumPacketLength) {\r
2576     Status = EFI_INVALID_PARAMETER;\r
2577     goto exit;\r
2578   }\r
2579 \r
2580   if (EFI_USB_SPEED_FULL == DeviceSpeed && MaximumPacketLength > 64) {\r
2581     Status = EFI_INVALID_PARAMETER;\r
2582     goto exit;\r
2583   }\r
2584 \r
2585   if (EFI_USB_SPEED_HIGH == DeviceSpeed && MaximumPacketLength > 3072) {\r
2586     Status = EFI_INVALID_PARAMETER;\r
2587     goto exit;\r
2588   }\r
2589   \r
2590   //\r
2591   // if has errors that cause host controller halt,\r
2592   // then return EFI_DEVICE_ERROR directly.\r
2593   //\r
2594   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
2595     ClearEhcAllStatus (HcDev);\r
2596     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2597     Status          = EFI_DEVICE_ERROR;\r
2598     goto exit;\r
2599   }\r
2600 \r
2601   Status = ClearEhcAllStatus (HcDev);\r
2602   if (EFI_ERROR (Status)) {\r
2603     Status = EFI_DEVICE_ERROR;\r
2604     goto exit;\r
2605   }\r
2606 \r
2607   Status = MapDataBuffer (\r
2608              HcDev,\r
2609              EfiUsbDataIn,\r
2610              Data,\r
2611              DataLength,\r
2612              &PktId,\r
2613              &DataCursor,\r
2614              &DataMap\r
2615              );\r
2616   if (EFI_ERROR (Status)) {\r
2617     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2618     Status          = EFI_DEVICE_ERROR;\r
2619     goto exit;\r
2620   }\r
2621   \r
2622   //\r
2623   // Create and init Interrupt Qh\r
2624   //\r
2625   Status = CreateInterruptQh (\r
2626              HcDev,\r
2627              DeviceAddress,\r
2628              EndPointAddress,\r
2629              DeviceSpeed,\r
2630              *DataToggle,\r
2631              MaximumPacketLength,\r
2632              0,\r
2633              Translator,\r
2634              &QhPtr\r
2635              );\r
2636   if (EFI_ERROR (Status)) {\r
2637     Status = EFI_OUT_OF_RESOURCES;\r
2638     goto unmap_data;\r
2639   }\r
2640   \r
2641   //\r
2642   // Create and init Interrupt Qtds\r
2643   //\r
2644   Status = CreateBulkOrInterruptQtds (\r
2645              HcDev,\r
2646              PktId,\r
2647              DataCursor,\r
2648              *DataLength,\r
2649              Translator,\r
2650              &InterruptQtdsPtr\r
2651              );\r
2652   if (EFI_ERROR (Status)) {\r
2653     *TransferResult = EFI_USB_ERR_SYSTEM;\r
2654     Status          = EFI_OUT_OF_RESOURCES;\r
2655     goto destory_qh;\r
2656   }\r
2657   \r
2658   //\r
2659   // Link Qtds to Qh\r
2660   //\r
2661   LinkQtdToQh (QhPtr, InterruptQtdsPtr);\r
2662 \r
2663   ClearEhcAllStatus (HcDev);\r
2664 \r
2665   Status = DisablePeriodicSchedule (HcDev);\r
2666   if (EFI_ERROR (Status)) {\r
2667     Status = EFI_DEVICE_ERROR;\r
2668     goto exit;\r
2669   }\r
2670 \r
2671   Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2672   if (EFI_ERROR (Status)) {\r
2673     Status = EFI_TIMEOUT;\r
2674     goto exit;\r
2675   }\r
2676   \r
2677   //\r
2678   // Link Qh and Qtds to Periodic Schedule List\r
2679   //\r
2680   LinkQhToPeriodicList (HcDev, QhPtr);\r
2681 \r
2682   Status = EnablePeriodicSchedule (HcDev);\r
2683   if (EFI_ERROR (Status)) {\r
2684     Status = EFI_DEVICE_ERROR;\r
2685     goto exit;\r
2686   }\r
2687 \r
2688   Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2689   if (EFI_ERROR (Status)) {\r
2690     Status = EFI_TIMEOUT;\r
2691     goto exit;\r
2692   }\r
2693 \r
2694   if (IsEhcHalted (HcDev)) {\r
2695     Status = StartScheduleExecution (HcDev);\r
2696     if (EFI_ERROR (Status)) {\r
2697       Status = EFI_DEVICE_ERROR;\r
2698       goto exit;\r
2699     }\r
2700   }\r
2701   \r
2702   //\r
2703   // Poll QH-TDs execution and get result.\r
2704   // detail status is returned\r
2705   //\r
2706   Status = ExecuteTransfer (\r
2707              HcDev,\r
2708              FALSE,\r
2709              QhPtr,\r
2710              DataLength,\r
2711              DataToggle,\r
2712              TimeOut,\r
2713              TransferResult\r
2714              );\r
2715   if (EFI_ERROR (Status)) {\r
2716     goto destory_qtds;\r
2717   }\r
2718   \r
2719   //\r
2720   // if has errors that cause host controller halt,\r
2721   // then return EFI_DEVICE_ERROR directly.\r
2722   //\r
2723   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {\r
2724     *TransferResult |= EFI_USB_ERR_SYSTEM;\r
2725   }\r
2726 \r
2727   ClearEhcAllStatus (HcDev);\r
2728 \r
2729 destory_qtds:\r
2730   UnlinkQhFromPeriodicList (HcDev, QhPtr, 0);\r
2731   DestoryQtds (HcDev, InterruptQtdsPtr);\r
2732 destory_qh:\r
2733   DestoryQh (HcDev, QhPtr);\r
2734 unmap_data:\r
2735   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);\r
2736 exit:\r
2737   HcDev->PciIo->Flush (HcDev->PciIo);\r
2738   return Status;\r
2739 }\r
2740 \r
2741 EFI_STATUS\r
2742 EFIAPI\r
2743 EhciIsochronousTransfer (\r
2744   IN  EFI_USB2_HC_PROTOCOL                  *This,\r
2745   IN  UINT8                                 DeviceAddress,\r
2746   IN  UINT8                                 EndPointAddress,\r
2747   IN  UINT8                                 DeviceSpeed,\r
2748   IN  UINTN                                 MaximumPacketLength,\r
2749   IN  UINT8                                 DataBuffersNumber,\r
2750   IN  OUT VOID                              *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
2751   IN  UINTN                                 DataLength,\r
2752   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,\r
2753   OUT UINT32                                *TransferResult\r
2754   )\r
2755 /*++\r
2756   \r
2757   Routine Description:\r
2758   \r
2759     Submits isochronous transfer to a target USB device.\r
2760   \r
2761   Arguments:\r
2762     \r
2763     This             - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
2764     DeviceAddress    - Represents the address of the target device on the USB,\r
2765                        which is assigned during USB enumeration.\r
2766     EndPointAddress  - End point address\r
2767     DeviceSpeed      - Indicates device speed.\r
2768     MaximumPacketLength    - Indicates the maximum packet size that the \r
2769                              default control transfer endpoint is capable of \r
2770                              sending or receiving.\r
2771     DataBuffersNumber - Number of data buffers prepared for the transfer.\r
2772     Data              - Array of pointers to the buffers of data that will be \r
2773                         transmitted to USB device or received from USB device.\r
2774     DataLength        - Indicates the size, in bytes, of the data buffer \r
2775                         specified by Data.\r
2776     Translator        - A pointr to the transaction translator data.\r
2777     TransferResult    - A pointer to the detailed result information generated \r
2778                         by this control transfer.               \r
2779                       \r
2780   Returns:\r
2781   \r
2782     EFI_UNSUPPORTED \r
2783 \r
2784 --*/\r
2785 {\r
2786   return EFI_UNSUPPORTED;\r
2787 }\r
2788 \r
2789 EFI_STATUS\r
2790 EFIAPI\r
2791 EhciAsyncIsochronousTransfer (\r
2792   IN  EFI_USB2_HC_PROTOCOL                *This,\r
2793   IN  UINT8                               DeviceAddress,\r
2794   IN  UINT8                               EndPointAddress,\r
2795   IN  UINT8                               DeviceSpeed,\r
2796   IN  UINTN                               MaximumPacketLength,\r
2797   IN  UINT8                               DataBuffersNumber,\r
2798   IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],\r
2799   IN  UINTN                               DataLength,\r
2800   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,\r
2801   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,\r
2802   IN  VOID                                *Context\r
2803   )\r
2804 /*++\r
2805   \r
2806   Routine Description:\r
2807   \r
2808     Submits Async isochronous transfer to a target USB device.\r
2809   \r
2810   Arguments:\r
2811     \r
2812     This                - A pointer to the EFI_USB2_HC_PROTOCOL instance.\r
2813     DeviceAddress       - Represents the address of the target device on the USB,\r
2814                           which is assigned during USB enumeration.\r
2815     EndPointAddress     - End point address\r
2816     DeviceSpeed         - Indicates device speed.\r
2817     MaximumPacketLength - Indicates the maximum packet size that the \r
2818                           default control transfer endpoint is capable of \r
2819                           sending or receiving.\r
2820     DataBuffersNumber   - Number of data buffers prepared for the transfer.\r
2821     Data                - Array of pointers to the buffers of data that will be transmitted \r
2822                           to USB device or received from USB device.\r
2823     Translator          - A pointr to the transaction translator data.\r
2824     IsochronousCallBack - When the transfer complete, the call back function will be called\r
2825     Context             - Pass to the call back function as parameter\r
2826                     \r
2827   Returns:\r
2828   \r
2829     EFI_UNSUPPORTED \r
2830 \r
2831 --*/\r
2832 {\r
2833   return EFI_UNSUPPORTED;\r
2834 }\r