1 /** @file
2   The XHCI controller driver.
3 
4 Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Xhci.h"
16 
17 //
18 // Two arrays used to translate the XHCI port state (change)
19 // to the UEFI protocol's port state (change).
20 //
21 USB_PORT_STATE_MAP  mUsbPortStateMap[] = {
22   {XHC_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},
23   {XHC_PORTSC_PED,   USB_PORT_STAT_ENABLE},
24   {XHC_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},
25   {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
26 };
27 
28 USB_PORT_STATE_MAP  mUsbPortChangeMap[] = {
29   {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
30   {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
31   {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
32   {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
33 };
34 
35 USB_CLEAR_PORT_MAP mUsbClearPortChangeMap[] = {
36   {XHC_PORTSC_CSC, EfiUsbPortConnectChange},
37   {XHC_PORTSC_PEC, EfiUsbPortEnableChange},
38   {XHC_PORTSC_OCC, EfiUsbPortOverCurrentChange},
39   {XHC_PORTSC_PRC, EfiUsbPortResetChange}
40 };
41 
42 USB_PORT_STATE_MAP  mUsbHubPortStateMap[] = {
43   {XHC_HUB_PORTSC_CCS,   USB_PORT_STAT_CONNECTION},
44   {XHC_HUB_PORTSC_PED,   USB_PORT_STAT_ENABLE},
45   {XHC_HUB_PORTSC_OCA,   USB_PORT_STAT_OVERCURRENT},
46   {XHC_HUB_PORTSC_RESET, USB_PORT_STAT_RESET}
47 };
48 
49 USB_PORT_STATE_MAP  mUsbHubPortChangeMap[] = {
50   {XHC_HUB_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
51   {XHC_HUB_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
52   {XHC_HUB_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
53   {XHC_HUB_PORTSC_PRC, USB_PORT_STAT_C_RESET}
54 };
55 
56 USB_CLEAR_PORT_MAP mUsbHubClearPortChangeMap[] = {
57   {XHC_HUB_PORTSC_CSC, EfiUsbPortConnectChange},
58   {XHC_HUB_PORTSC_PEC, EfiUsbPortEnableChange},
59   {XHC_HUB_PORTSC_OCC, EfiUsbPortOverCurrentChange},
60   {XHC_HUB_PORTSC_PRC, EfiUsbPortResetChange},
61   {XHC_HUB_PORTSC_BHRC, Usb3PortBHPortResetChange}
62 };
63 
64 EFI_DRIVER_BINDING_PROTOCOL  gXhciDriverBinding = {
65   XhcDriverBindingSupported,
66   XhcDriverBindingStart,
67   XhcDriverBindingStop,
68   0x30,
69   NULL,
70   NULL
71 };
72 
73 //
74 // Template for Xhci's Usb2 Host Controller Protocol Instance.
75 //
76 EFI_USB2_HC_PROTOCOL gXhciUsb2HcTemplate = {
77   XhcGetCapability,
78   XhcReset,
79   XhcGetState,
80   XhcSetState,
81   XhcControlTransfer,
82   XhcBulkTransfer,
83   XhcAsyncInterruptTransfer,
84   XhcSyncInterruptTransfer,
85   XhcIsochronousTransfer,
86   XhcAsyncIsochronousTransfer,
87   XhcGetRootHubPortStatus,
88   XhcSetRootHubPortFeature,
89   XhcClearRootHubPortFeature,
90   0x3,
91   0x0
92 };
93 
94 /**
95   Retrieves the capability of root hub ports.
96 
97   @param  This                  The EFI_USB2_HC_PROTOCOL instance.
98   @param  MaxSpeed              Max speed supported by the controller.
99   @param  PortNumber            Number of the root hub ports.
100   @param  Is64BitCapable        Whether the controller supports 64-bit memory
101                                 addressing.
102 
103   @retval EFI_SUCCESS           Host controller capability were retrieved successfully.
104   @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
105 
106 **/
107 EFI_STATUS
108 EFIAPI
XhcGetCapability(IN EFI_USB2_HC_PROTOCOL * This,OUT UINT8 * MaxSpeed,OUT UINT8 * PortNumber,OUT UINT8 * Is64BitCapable)109 XhcGetCapability (
110   IN  EFI_USB2_HC_PROTOCOL  *This,
111   OUT UINT8                 *MaxSpeed,
112   OUT UINT8                 *PortNumber,
113   OUT UINT8                 *Is64BitCapable
114   )
115 {
116   USB_XHCI_INSTANCE  *Xhc;
117   EFI_TPL            OldTpl;
118 
119   if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
120     return EFI_INVALID_PARAMETER;
121   }
122 
123   OldTpl          = gBS->RaiseTPL (XHC_TPL);
124 
125   Xhc             = XHC_FROM_THIS (This);
126   *MaxSpeed       = EFI_USB_SPEED_SUPER;
127   *PortNumber     = (UINT8) (Xhc->HcSParams1.Data.MaxPorts);
128   *Is64BitCapable = (UINT8) Xhc->Support64BitDma;
129   DEBUG ((EFI_D_INFO, "XhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
130 
131   gBS->RestoreTPL (OldTpl);
132 
133   return EFI_SUCCESS;
134 }
135 
136 
137 /**
138   Provides software reset for the USB host controller.
139 
140   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
141   @param  Attributes            A bit mask of the reset operation to perform.
142 
143   @retval EFI_SUCCESS           The reset operation succeeded.
144   @retval EFI_INVALID_PARAMETER Attributes is not valid.
145   @retval EFI_UNSUPPOURTED      The type of reset specified by Attributes is
146                                 not currently supported by the host controller.
147   @retval EFI_DEVICE_ERROR      Host controller isn't halted to reset.
148 
149 **/
150 EFI_STATUS
151 EFIAPI
XhcReset(IN EFI_USB2_HC_PROTOCOL * This,IN UINT16 Attributes)152 XhcReset (
153   IN EFI_USB2_HC_PROTOCOL  *This,
154   IN UINT16                Attributes
155   )
156 {
157   USB_XHCI_INSTANCE  *Xhc;
158   EFI_STATUS         Status;
159   EFI_TPL            OldTpl;
160 
161   Xhc = XHC_FROM_THIS (This);
162 
163   if (Xhc->DevicePath != NULL) {
164     //
165     // Report Status Code to indicate reset happens
166     //
167     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
168       EFI_PROGRESS_CODE,
169       (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
170       Xhc->DevicePath
171       );
172   }
173 
174   OldTpl = gBS->RaiseTPL (XHC_TPL);
175 
176   switch (Attributes) {
177   case EFI_USB_HC_RESET_GLOBAL:
178   //
179   // Flow through, same behavior as Host Controller Reset
180   //
181   case EFI_USB_HC_RESET_HOST_CONTROLLER:
182     if ((Xhc->DebugCapSupOffset != 0xFFFFFFFF) && ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset) & 0xFF) == XHC_CAP_USB_DEBUG) &&
183         ((XhcReadExtCapReg (Xhc, Xhc->DebugCapSupOffset + XHC_DC_DCCTRL) & BIT0) != 0)) {
184       Status = EFI_SUCCESS;
185       goto ON_EXIT;
186     }
187     //
188     // Host Controller must be Halt when Reset it
189     //
190     if (!XhcIsHalt (Xhc)) {
191       Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
192 
193       if (EFI_ERROR (Status)) {
194         Status = EFI_DEVICE_ERROR;
195         goto ON_EXIT;
196       }
197     }
198 
199     Status = XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
200     ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
201 
202     if (EFI_ERROR (Status)) {
203       goto ON_EXIT;
204     }
205     //
206     // Clean up the asynchronous transfers, currently only
207     // interrupt supports asynchronous operation.
208     //
209     XhciDelAllAsyncIntTransfers (Xhc);
210     XhcFreeSched (Xhc);
211 
212     XhcInitSched (Xhc);
213     break;
214 
215   case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
216   case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
217     Status = EFI_UNSUPPORTED;
218     break;
219 
220   default:
221     Status = EFI_INVALID_PARAMETER;
222   }
223 
224 ON_EXIT:
225   DEBUG ((EFI_D_INFO, "XhcReset: status %r\n", Status));
226   gBS->RestoreTPL (OldTpl);
227 
228   return Status;
229 }
230 
231 
232 /**
233   Retrieve the current state of the USB host controller.
234 
235   @param  This                   This EFI_USB2_HC_PROTOCOL instance.
236   @param  State                  Variable to return the current host controller
237                                  state.
238 
239   @retval EFI_SUCCESS            Host controller state was returned in State.
240   @retval EFI_INVALID_PARAMETER  State is NULL.
241   @retval EFI_DEVICE_ERROR       An error was encountered while attempting to
242                                  retrieve the host controller's current state.
243 
244 **/
245 EFI_STATUS
246 EFIAPI
XhcGetState(IN EFI_USB2_HC_PROTOCOL * This,OUT EFI_USB_HC_STATE * State)247 XhcGetState (
248   IN  EFI_USB2_HC_PROTOCOL  *This,
249   OUT EFI_USB_HC_STATE      *State
250   )
251 {
252   USB_XHCI_INSTANCE  *Xhc;
253   EFI_TPL            OldTpl;
254 
255   if (State == NULL) {
256     return EFI_INVALID_PARAMETER;
257   }
258 
259   OldTpl = gBS->RaiseTPL (XHC_TPL);
260 
261   Xhc    = XHC_FROM_THIS (This);
262 
263   if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
264     *State = EfiUsbHcStateHalt;
265   } else {
266     *State = EfiUsbHcStateOperational;
267   }
268 
269   DEBUG ((EFI_D_INFO, "XhcGetState: current state %d\n", *State));
270   gBS->RestoreTPL (OldTpl);
271 
272   return EFI_SUCCESS;
273 }
274 
275 /**
276   Sets the USB host controller to a specific state.
277 
278   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
279   @param  State                 The state of the host controller that will be set.
280 
281   @retval EFI_SUCCESS           The USB host controller was successfully placed
282                                 in the state specified by State.
283   @retval EFI_INVALID_PARAMETER State is invalid.
284   @retval EFI_DEVICE_ERROR      Failed to set the state due to device error.
285 
286 **/
287 EFI_STATUS
288 EFIAPI
XhcSetState(IN EFI_USB2_HC_PROTOCOL * This,IN EFI_USB_HC_STATE State)289 XhcSetState (
290   IN EFI_USB2_HC_PROTOCOL  *This,
291   IN EFI_USB_HC_STATE      State
292   )
293 {
294   USB_XHCI_INSTANCE   *Xhc;
295   EFI_STATUS          Status;
296   EFI_USB_HC_STATE    CurState;
297   EFI_TPL             OldTpl;
298 
299   Status = XhcGetState (This, &CurState);
300 
301   if (EFI_ERROR (Status)) {
302     return EFI_DEVICE_ERROR;
303   }
304 
305   if (CurState == State) {
306     return EFI_SUCCESS;
307   }
308 
309   OldTpl = gBS->RaiseTPL (XHC_TPL);
310 
311   Xhc    = XHC_FROM_THIS (This);
312 
313   switch (State) {
314   case EfiUsbHcStateHalt:
315     Status = XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
316     break;
317 
318   case EfiUsbHcStateOperational:
319     if (XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HSE)) {
320       Status = EFI_DEVICE_ERROR;
321       break;
322     }
323 
324     //
325     // Software must not write a one to this field unless the host controller
326     // is in the Halted state. Doing so will yield undefined results.
327     // refers to Spec[XHCI1.0-2.3.1]
328     //
329     if (!XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_HALT)) {
330       Status = EFI_DEVICE_ERROR;
331       break;
332     }
333 
334     Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
335     break;
336 
337   case EfiUsbHcStateSuspend:
338     Status = EFI_UNSUPPORTED;
339     break;
340 
341   default:
342     Status = EFI_INVALID_PARAMETER;
343   }
344 
345   DEBUG ((EFI_D_INFO, "XhcSetState: status %r\n", Status));
346   gBS->RestoreTPL (OldTpl);
347 
348   return Status;
349 }
350 
351 /**
352   Retrieves the current status of a USB root hub port.
353 
354   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
355   @param  PortNumber            The root hub port to retrieve the state from.
356                                 This value is zero-based.
357   @param  PortStatus            Variable to receive the port state.
358 
359   @retval EFI_SUCCESS           The status of the USB root hub port specified.
360                                 by PortNumber was returned in PortStatus.
361   @retval EFI_INVALID_PARAMETER PortNumber is invalid.
362   @retval EFI_DEVICE_ERROR      Can't read register.
363 
364 **/
365 EFI_STATUS
366 EFIAPI
XhcGetRootHubPortStatus(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 PortNumber,OUT EFI_USB_PORT_STATUS * PortStatus)367 XhcGetRootHubPortStatus (
368   IN  EFI_USB2_HC_PROTOCOL  *This,
369   IN  UINT8                 PortNumber,
370   OUT EFI_USB_PORT_STATUS   *PortStatus
371   )
372 {
373   USB_XHCI_INSTANCE       *Xhc;
374   UINT32                  Offset;
375   UINT32                  State;
376   UINT32                  TotalPort;
377   UINTN                   Index;
378   UINTN                   MapSize;
379   EFI_STATUS              Status;
380   USB_DEV_ROUTE           ParentRouteChart;
381   EFI_TPL                 OldTpl;
382 
383   if (PortStatus == NULL) {
384     return EFI_INVALID_PARAMETER;
385   }
386 
387   OldTpl = gBS->RaiseTPL (XHC_TPL);
388 
389   Xhc       = XHC_FROM_THIS (This);
390   Status    = EFI_SUCCESS;
391 
392   TotalPort = Xhc->HcSParams1.Data.MaxPorts;
393 
394   if (PortNumber >= TotalPort) {
395     Status = EFI_INVALID_PARAMETER;
396     goto ON_EXIT;
397   }
398 
399   Offset                       = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
400   PortStatus->PortStatus       = 0;
401   PortStatus->PortChangeStatus = 0;
402 
403   State = XhcReadOpReg (Xhc, Offset);
404 
405   //
406   // According to XHCI 1.0 spec, bit 10~13 of the root port status register identifies the speed of the attached device.
407   //
408   switch ((State & XHC_PORTSC_PS) >> 10) {
409   case 2:
410     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
411     break;
412 
413   case 3:
414     PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
415     break;
416 
417   case 4:
418     PortStatus->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
419     break;
420 
421   default:
422     break;
423   }
424 
425   //
426   // Convert the XHCI port/port change state to UEFI status
427   //
428   MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
429 
430   for (Index = 0; Index < MapSize; Index++) {
431     if (XHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
432       PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
433     }
434   }
435   //
436   // Bit5~8 reflects its current link state.
437   //
438   if ((State & XHC_PORTSC_PLS) >> 5 == 3) {
439     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
440   }
441 
442   MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
443 
444   for (Index = 0; Index < MapSize; Index++) {
445     if (XHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
446       PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
447     }
448   }
449 
450   MapSize = sizeof (mUsbClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
451 
452   for (Index = 0; Index < MapSize; Index++) {
453     if (XHC_BIT_IS_SET (State, mUsbClearPortChangeMap[Index].HwState)) {
454       XhcClearRootHubPortFeature (This, PortNumber, (EFI_USB_PORT_FEATURE)mUsbClearPortChangeMap[Index].Selector);
455     }
456   }
457 
458   //
459   // Poll the root port status register to enable/disable corresponding device slot if there is a device attached/detached.
460   // For those devices behind hub, we get its attach/detach event by hooking Get_Port_Status request at control transfer for those hub.
461   //
462   ParentRouteChart.Dword = 0;
463   XhcPollPortStatusChange (Xhc, ParentRouteChart, PortNumber, PortStatus);
464 
465 ON_EXIT:
466   gBS->RestoreTPL (OldTpl);
467   return Status;
468 }
469 
470 
471 /**
472   Sets a feature for the specified root hub port.
473 
474   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
475   @param  PortNumber            Root hub port to set.
476   @param  PortFeature           Feature to set.
477 
478   @retval EFI_SUCCESS           The feature specified by PortFeature was set.
479   @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
480   @retval EFI_DEVICE_ERROR      Can't read register.
481 
482 **/
483 EFI_STATUS
484 EFIAPI
XhcSetRootHubPortFeature(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)485 XhcSetRootHubPortFeature (
486   IN EFI_USB2_HC_PROTOCOL  *This,
487   IN UINT8                 PortNumber,
488   IN EFI_USB_PORT_FEATURE  PortFeature
489   )
490 {
491   USB_XHCI_INSTANCE       *Xhc;
492   UINT32                  Offset;
493   UINT32                  State;
494   UINT32                  TotalPort;
495   EFI_STATUS              Status;
496   EFI_TPL                 OldTpl;
497 
498   OldTpl = gBS->RaiseTPL (XHC_TPL);
499 
500   Xhc    = XHC_FROM_THIS (This);
501   Status = EFI_SUCCESS;
502 
503   TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
504 
505   if (PortNumber >= TotalPort) {
506     Status = EFI_INVALID_PARAMETER;
507     goto ON_EXIT;
508   }
509 
510   Offset = (UINT32) (XHC_PORTSC_OFFSET + (0x10 * PortNumber));
511   State  = XhcReadOpReg (Xhc, Offset);
512 
513   //
514   // Mask off the port status change bits, these bits are
515   // write clean bit
516   //
517   State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
518 
519   switch (PortFeature) {
520   case EfiUsbPortEnable:
521     //
522     // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
523     // A port may be disabled by software writing a '1' to this flag.
524     //
525     Status = EFI_SUCCESS;
526     break;
527 
528   case EfiUsbPortSuspend:
529     State |= XHC_PORTSC_LWS;
530     XhcWriteOpReg (Xhc, Offset, State);
531     State &= ~XHC_PORTSC_PLS;
532     State |= (3 << 5) ;
533     XhcWriteOpReg (Xhc, Offset, State);
534     break;
535 
536   case EfiUsbPortReset:
537     DEBUG ((EFI_D_INFO, "XhcUsbPortReset!\n"));
538     //
539     // Make sure Host Controller not halt before reset it
540     //
541     if (XhcIsHalt (Xhc)) {
542       Status = XhcRunHC (Xhc, XHC_GENERIC_TIMEOUT);
543 
544       if (EFI_ERROR (Status)) {
545         DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
546         break;
547       }
548     }
549 
550     //
551     // 4.3.1 Resetting a Root Hub Port
552     // 1) Write the PORTSC register with the Port Reset (PR) bit set to '1'.
553     //
554     State |= XHC_PORTSC_RESET;
555     XhcWriteOpReg (Xhc, Offset, State);
556     XhcWaitOpRegBit(Xhc, Offset, XHC_PORTSC_PRC, TRUE, XHC_GENERIC_TIMEOUT);
557     break;
558 
559   case EfiUsbPortPower:
560     //
561     // Not supported, ignore the operation
562     //
563     Status = EFI_SUCCESS;
564     break;
565 
566   case EfiUsbPortOwner:
567     //
568     // XHCI root hub port don't has the owner bit, ignore the operation
569     //
570     Status = EFI_SUCCESS;
571     break;
572 
573   default:
574     Status = EFI_INVALID_PARAMETER;
575   }
576 
577 ON_EXIT:
578   DEBUG ((EFI_D_INFO, "XhcSetRootHubPortFeature: status %r\n", Status));
579   gBS->RestoreTPL (OldTpl);
580 
581   return Status;
582 }
583 
584 
585 /**
586   Clears a feature for the specified root hub port.
587 
588   @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.
589   @param  PortNumber            Specifies the root hub port whose feature is
590                                 requested to be cleared.
591   @param  PortFeature           Indicates the feature selector associated with the
592                                 feature clear request.
593 
594   @retval EFI_SUCCESS           The feature specified by PortFeature was cleared
595                                 for the USB root hub port specified by PortNumber.
596   @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
597   @retval EFI_DEVICE_ERROR      Can't read register.
598 
599 **/
600 EFI_STATUS
601 EFIAPI
XhcClearRootHubPortFeature(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 PortNumber,IN EFI_USB_PORT_FEATURE PortFeature)602 XhcClearRootHubPortFeature (
603   IN EFI_USB2_HC_PROTOCOL  *This,
604   IN UINT8                 PortNumber,
605   IN EFI_USB_PORT_FEATURE  PortFeature
606   )
607 {
608   USB_XHCI_INSTANCE       *Xhc;
609   UINT32                  Offset;
610   UINT32                  State;
611   UINT32                  TotalPort;
612   EFI_STATUS              Status;
613   EFI_TPL                 OldTpl;
614 
615   OldTpl = gBS->RaiseTPL (XHC_TPL);
616 
617   Xhc       = XHC_FROM_THIS (This);
618   Status    = EFI_SUCCESS;
619 
620   TotalPort = (Xhc->HcSParams1.Data.MaxPorts);
621 
622   if (PortNumber >= TotalPort) {
623     Status = EFI_INVALID_PARAMETER;
624     goto ON_EXIT;
625   }
626 
627   Offset = XHC_PORTSC_OFFSET + (0x10 * PortNumber);
628 
629   //
630   // Mask off the port status change bits, these bits are
631   // write clean bit
632   //
633   State  = XhcReadOpReg (Xhc, Offset);
634   State &= ~ (BIT1 | BIT17 | BIT18 | BIT19 | BIT20 | BIT21 | BIT22 | BIT23);
635 
636   switch (PortFeature) {
637   case EfiUsbPortEnable:
638     //
639     // Ports may only be enabled by the xHC. Software cannot enable a port by writing a '1' to this flag.
640     // A port may be disabled by software writing a '1' to this flag.
641     //
642     State |= XHC_PORTSC_PED;
643     State &= ~XHC_PORTSC_RESET;
644     XhcWriteOpReg (Xhc, Offset, State);
645     break;
646 
647   case EfiUsbPortSuspend:
648     State |= XHC_PORTSC_LWS;
649     XhcWriteOpReg (Xhc, Offset, State);
650     State &= ~XHC_PORTSC_PLS;
651     XhcWriteOpReg (Xhc, Offset, State);
652     break;
653 
654   case EfiUsbPortReset:
655     //
656     // PORTSC_RESET BIT(4) bit is RW1S attribute, which means Write-1-to-set status:
657     // Register bits indicate status when read, a clear bit may be set by
658     // writing a '1'. Writing a '0' to RW1S bits has no effect.
659     //
660     break;
661 
662   case EfiUsbPortOwner:
663     //
664     // XHCI root hub port don't has the owner bit, ignore the operation
665     //
666     break;
667 
668   case EfiUsbPortConnectChange:
669     //
670     // Clear connect status change
671     //
672     State |= XHC_PORTSC_CSC;
673     XhcWriteOpReg (Xhc, Offset, State);
674     break;
675 
676   case EfiUsbPortEnableChange:
677     //
678     // Clear enable status change
679     //
680     State |= XHC_PORTSC_PEC;
681     XhcWriteOpReg (Xhc, Offset, State);
682     break;
683 
684   case EfiUsbPortOverCurrentChange:
685     //
686     // Clear PortOverCurrent change
687     //
688     State |= XHC_PORTSC_OCC;
689     XhcWriteOpReg (Xhc, Offset, State);
690     break;
691 
692   case EfiUsbPortResetChange:
693     //
694     // Clear Port Reset change
695     //
696     State |= XHC_PORTSC_PRC;
697     XhcWriteOpReg (Xhc, Offset, State);
698     break;
699 
700   case EfiUsbPortPower:
701   case EfiUsbPortSuspendChange:
702     //
703     // Not supported or not related operation
704     //
705     break;
706 
707   default:
708     Status = EFI_INVALID_PARAMETER;
709     break;
710   }
711 
712 ON_EXIT:
713   DEBUG ((EFI_D_INFO, "XhcClearRootHubPortFeature: status %r\n", Status));
714   gBS->RestoreTPL (OldTpl);
715 
716   return Status;
717 }
718 
719 
720 /**
721   Submits control transfer to a target USB device.
722 
723   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
724   @param  DeviceAddress         The target device address.
725   @param  DeviceSpeed           Target device speed.
726   @param  MaximumPacketLength   Maximum packet size the default control transfer
727                                 endpoint is capable of sending or receiving.
728   @param  Request               USB device request to send.
729   @param  TransferDirection     Specifies the data direction for the data stage
730   @param  Data                  Data buffer to be transmitted or received from USB
731                                 device.
732   @param  DataLength            The size (in bytes) of the data buffer.
733   @param  Timeout               Indicates the maximum timeout, in millisecond.
734   @param  Translator            Transaction translator to be used by this device.
735   @param  TransferResult        Return the result of this control transfer.
736 
737   @retval EFI_SUCCESS           Transfer was completed successfully.
738   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resources.
739   @retval EFI_INVALID_PARAMETER Some parameters are invalid.
740   @retval EFI_TIMEOUT           Transfer failed due to timeout.
741   @retval EFI_DEVICE_ERROR      Transfer failed due to host controller or device error.
742 
743 **/
744 EFI_STATUS
745 EFIAPI
XhcControlTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN EFI_USB_DEVICE_REQUEST * Request,IN EFI_USB_DATA_DIRECTION TransferDirection,IN OUT VOID * Data,IN OUT UINTN * DataLength,IN UINTN Timeout,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)746 XhcControlTransfer (
747   IN     EFI_USB2_HC_PROTOCOL                *This,
748   IN     UINT8                               DeviceAddress,
749   IN     UINT8                               DeviceSpeed,
750   IN     UINTN                               MaximumPacketLength,
751   IN     EFI_USB_DEVICE_REQUEST              *Request,
752   IN     EFI_USB_DATA_DIRECTION              TransferDirection,
753   IN OUT VOID                                *Data,
754   IN OUT UINTN                               *DataLength,
755   IN     UINTN                               Timeout,
756   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
757   OUT    UINT32                              *TransferResult
758   )
759 {
760   USB_XHCI_INSTANCE       *Xhc;
761   URB                     *Urb;
762   UINT8                   Endpoint;
763   UINT8                   Index;
764   UINT8                   DescriptorType;
765   UINT8                   SlotId;
766   UINT8                   TTT;
767   UINT8                   MTT;
768   UINT32                  MaxPacket0;
769   EFI_USB_HUB_DESCRIPTOR  *HubDesc;
770   EFI_TPL                 OldTpl;
771   EFI_STATUS              Status;
772   EFI_STATUS              RecoveryStatus;
773   UINTN                   MapSize;
774   EFI_USB_PORT_STATUS     PortStatus;
775   UINT32                  State;
776   EFI_USB_DEVICE_REQUEST  ClearPortRequest;
777   UINTN                   Len;
778 
779   //
780   // Validate parameters
781   //
782   if ((Request == NULL) || (TransferResult == NULL)) {
783     return EFI_INVALID_PARAMETER;
784   }
785 
786   if ((TransferDirection != EfiUsbDataIn) &&
787       (TransferDirection != EfiUsbDataOut) &&
788       (TransferDirection != EfiUsbNoData)) {
789     return EFI_INVALID_PARAMETER;
790   }
791 
792   if ((TransferDirection == EfiUsbNoData) &&
793       ((Data != NULL) || (*DataLength != 0))) {
794     return EFI_INVALID_PARAMETER;
795   }
796 
797   if ((TransferDirection != EfiUsbNoData) &&
798      ((Data == NULL) || (*DataLength == 0))) {
799     return EFI_INVALID_PARAMETER;
800   }
801 
802   if ((MaximumPacketLength != 8)  && (MaximumPacketLength != 16) &&
803       (MaximumPacketLength != 32) && (MaximumPacketLength != 64) &&
804       (MaximumPacketLength != 512)
805       ) {
806     return EFI_INVALID_PARAMETER;
807   }
808 
809   if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
810     return EFI_INVALID_PARAMETER;
811   }
812 
813   if ((DeviceSpeed == EFI_USB_SPEED_SUPER) && (MaximumPacketLength != 512)) {
814     return EFI_INVALID_PARAMETER;
815   }
816 
817   OldTpl = gBS->RaiseTPL (XHC_TPL);
818 
819   Xhc             = XHC_FROM_THIS (This);
820 
821   Status          = EFI_DEVICE_ERROR;
822   *TransferResult = EFI_USB_ERR_SYSTEM;
823   Len             = 0;
824 
825   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
826     DEBUG ((EFI_D_ERROR, "XhcControlTransfer: HC halted at entrance\n"));
827     goto ON_EXIT;
828   }
829 
830   //
831   // Check if the device is still enabled before every transaction.
832   //
833   SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
834   if (SlotId == 0) {
835     goto ON_EXIT;
836   }
837 
838   //
839   // Hook the Set_Address request from UsbBus.
840   // According to XHCI 1.0 spec, the Set_Address request is replaced by XHCI's Address_Device cmd.
841   //
842   if ((Request->Request     == USB_REQ_SET_ADDRESS) &&
843       (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
844     //
845     // Reset the BusDevAddr field of all disabled entries in UsbDevContext array firstly.
846     // This way is used to clean the history to avoid using wrong device address by XhcAsyncInterruptTransfer().
847     //
848     for (Index = 0; Index < 255; Index++) {
849       if (!Xhc->UsbDevContext[Index + 1].Enabled &&
850           (Xhc->UsbDevContext[Index + 1].SlotId == 0) &&
851           (Xhc->UsbDevContext[Index + 1].BusDevAddr == (UINT8)Request->Value)) {
852         Xhc->UsbDevContext[Index + 1].BusDevAddr = 0;
853       }
854     }
855 
856     if (Xhc->UsbDevContext[SlotId].XhciDevAddr == 0) {
857       Status = EFI_DEVICE_ERROR;
858       goto ON_EXIT;
859     }
860     //
861     // The actual device address has been assigned by XHCI during initializing the device slot.
862     // So we just need establish the mapping relationship between the device address requested from UsbBus
863     // and the actual device address assigned by XHCI. The the following invocations through EFI_USB2_HC_PROTOCOL interface
864     // can find out the actual device address by it.
865     //
866     Xhc->UsbDevContext[SlotId].BusDevAddr = (UINT8)Request->Value;
867     Status = EFI_SUCCESS;
868     goto ON_EXIT;
869   }
870 
871   //
872   // Create a new URB, insert it into the asynchronous
873   // schedule list, then poll the execution status.
874   // Note that we encode the direction in address although default control
875   // endpoint is bidirectional. XhcCreateUrb expects this
876   // combination of Ep addr and its direction.
877   //
878   Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
879   Urb = XhcCreateUrb (
880           Xhc,
881           DeviceAddress,
882           Endpoint,
883           DeviceSpeed,
884           MaximumPacketLength,
885           XHC_CTRL_TRANSFER,
886           Request,
887           Data,
888           *DataLength,
889           NULL,
890           NULL
891           );
892 
893   if (Urb == NULL) {
894     DEBUG ((EFI_D_ERROR, "XhcControlTransfer: failed to create URB"));
895     Status = EFI_OUT_OF_RESOURCES;
896     goto ON_EXIT;
897   }
898 
899   Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
900 
901   //
902   // Get the status from URB. The result is updated in XhcCheckUrbResult
903   // which is called by XhcExecTransfer
904   //
905   *TransferResult = Urb->Result;
906   *DataLength     = Urb->Completed;
907 
908   if (Status == EFI_TIMEOUT) {
909     //
910     // The transfer timed out. Abort the transfer by dequeueing of the TD.
911     //
912     RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
913     if (EFI_ERROR(RecoveryStatus)) {
914       DEBUG((EFI_D_ERROR, "XhcControlTransfer: XhcDequeueTrbFromEndpoint failed\n"));
915     }
916     goto FREE_URB;
917   } else {
918     if (*TransferResult == EFI_USB_NOERROR) {
919       Status = EFI_SUCCESS;
920     } else if (*TransferResult == EFI_USB_ERR_STALL) {
921       RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
922       if (EFI_ERROR (RecoveryStatus)) {
923         DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));
924       }
925       Status = EFI_DEVICE_ERROR;
926       goto FREE_URB;
927     } else {
928       goto FREE_URB;
929     }
930   }
931 
932   Xhc->PciIo->Flush (Xhc->PciIo);
933 
934   if (Urb->DataMap != NULL) {
935     Status = Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);
936     ASSERT_EFI_ERROR (Status);
937     if (EFI_ERROR (Status)) {
938       Status = EFI_DEVICE_ERROR;
939       goto FREE_URB;
940     }
941   }
942 
943   //
944   // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
945   // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
946   // Hook Set_Config request from UsbBus as we need configure device endpoint.
947   //
948   if ((Request->Request     == USB_REQ_GET_DESCRIPTOR) &&
949       ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
950       ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
951     DescriptorType = (UINT8)(Request->Value >> 8);
952     if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
953         ASSERT (Data != NULL);
954         //
955         // Store a copy of device scriptor as hub device need this info to configure endpoint.
956         //
957         CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
958         if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB >= 0x0300) {
959           //
960           // If it's a usb3.0 device, then its max packet size is a 2^n.
961           //
962           MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
963         } else {
964           MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
965         }
966         Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
967         if (Xhc->HcCParams.Data.Csz == 0) {
968           Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);
969         } else {
970           Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);
971         }
972     } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
973       ASSERT (Data != NULL);
974       if (*DataLength == ((UINT16 *)Data)[1]) {
975         //
976         // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.
977         //
978         Index = (UINT8)Request->Value;
979         ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
980         Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength);
981         CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
982         //
983         // Default to use AlternateSetting 0 for all interfaces.
984         //
985         Xhc->UsbDevContext[SlotId].ActiveAlternateSetting = AllocateZeroPool (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->NumInterfaces * sizeof (UINT8));
986       }
987     } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
988                (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
989       ASSERT (Data != NULL);
990       HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;
991       ASSERT (HubDesc->NumPorts <= 15);
992       //
993       // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
994       //
995       TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
996       if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
997         //
998         // Don't support multi-TT feature for super speed hub now.
999         //
1000         MTT = 0;
1001         DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
1002       } else {
1003         MTT = 0;
1004       }
1005 
1006       if (Xhc->HcCParams.Data.Csz == 0) {
1007         Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
1008       } else {
1009         Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
1010       }
1011     }
1012   } else if ((Request->Request     == USB_REQ_SET_CONFIG) &&
1013              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
1014     //
1015     // Hook Set_Config request from UsbBus as we need configure device endpoint.
1016     //
1017     for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
1018       if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
1019         if (Xhc->HcCParams.Data.Csz == 0) {
1020           Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1021         } else {
1022           Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
1023         }
1024         break;
1025       }
1026     }
1027   } else if ((Request->Request     == USB_REQ_SET_INTERFACE) &&
1028              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_INTERFACE))) {
1029     //
1030     // Hook Set_Interface request from UsbBus as we need configure interface setting.
1031     // Request->Value indicates AlterlateSetting to set
1032     // Request->Index indicates Interface to set
1033     //
1034     if (Xhc->UsbDevContext[SlotId].ActiveAlternateSetting[(UINT8) Request->Index] != (UINT8) Request->Value) {
1035       if (Xhc->HcCParams.Data.Csz == 0) {
1036         Status = XhcSetInterface (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
1037       } else {
1038         Status = XhcSetInterface64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Xhc->UsbDevContext[SlotId].ActiveConfiguration - 1], Request);
1039       }
1040     }
1041   } else if ((Request->Request     == USB_REQ_GET_STATUS) &&
1042              (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
1043     ASSERT (Data != NULL);
1044     //
1045     // Hook Get_Status request from UsbBus to keep track of the port status change.
1046     //
1047     State                       = *(UINT32 *)Data;
1048     PortStatus.PortStatus       = 0;
1049     PortStatus.PortChangeStatus = 0;
1050 
1051     if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1052       //
1053       // For super speed hub, its bit10~12 presents the attached device speed.
1054       //
1055       if ((State & XHC_PORTSC_PS) >> 10 == 0) {
1056         PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1057       }
1058     } else {
1059       //
1060       // For high or full/low speed hub, its bit9~10 presents the attached device speed.
1061       //
1062       if (XHC_BIT_IS_SET (State, BIT9)) {
1063         PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
1064       } else if (XHC_BIT_IS_SET (State, BIT10)) {
1065         PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1066       }
1067     }
1068 
1069     //
1070     // Convert the XHCI port/port change state to UEFI status
1071     //
1072     MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1073     for (Index = 0; Index < MapSize; Index++) {
1074       if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
1075         PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
1076       }
1077     }
1078 
1079     MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1080     for (Index = 0; Index < MapSize; Index++) {
1081       if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
1082         PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
1083       }
1084     }
1085 
1086     MapSize = sizeof (mUsbHubClearPortChangeMap) / sizeof (USB_CLEAR_PORT_MAP);
1087 
1088     for (Index = 0; Index < MapSize; Index++) {
1089       if (XHC_BIT_IS_SET (State, mUsbHubClearPortChangeMap[Index].HwState)) {
1090         ZeroMem (&ClearPortRequest, sizeof (EFI_USB_DEVICE_REQUEST));
1091         ClearPortRequest.RequestType  = USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER);
1092         ClearPortRequest.Request      = (UINT8) USB_REQ_CLEAR_FEATURE;
1093         ClearPortRequest.Value        = mUsbHubClearPortChangeMap[Index].Selector;
1094         ClearPortRequest.Index        = Request->Index;
1095         ClearPortRequest.Length       = 0;
1096 
1097         XhcControlTransfer (
1098           This,
1099           DeviceAddress,
1100           DeviceSpeed,
1101           MaximumPacketLength,
1102           &ClearPortRequest,
1103           EfiUsbNoData,
1104           NULL,
1105           &Len,
1106           Timeout,
1107           Translator,
1108           TransferResult
1109           );
1110       }
1111     }
1112 
1113     XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
1114 
1115     *(UINT32 *)Data = *(UINT32*)&PortStatus;
1116   }
1117 
1118 FREE_URB:
1119   FreePool (Urb);
1120 
1121 ON_EXIT:
1122 
1123   if (EFI_ERROR (Status)) {
1124     DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1125   }
1126 
1127   gBS->RestoreTPL (OldTpl);
1128 
1129   return Status;
1130 }
1131 
1132 
1133 /**
1134   Submits bulk transfer to a bulk endpoint of a USB device.
1135 
1136   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
1137   @param  DeviceAddress         Target device address.
1138   @param  EndPointAddress       Endpoint number and its direction in bit 7.
1139   @param  DeviceSpeed           Device speed, Low speed device doesn't support bulk
1140                                 transfer.
1141   @param  MaximumPacketLength   Maximum packet size the endpoint is capable of
1142                                 sending or receiving.
1143   @param  DataBuffersNumber     Number of data buffers prepared for the transfer.
1144   @param  Data                  Array of pointers to the buffers of data to transmit
1145                                 from or receive into.
1146   @param  DataLength            The lenght of the data buffer.
1147   @param  DataToggle            On input, the initial data toggle for the transfer;
1148                                 On output, it is updated to to next data toggle to
1149                                 use of the subsequent bulk transfer.
1150   @param  Timeout               Indicates the maximum time, in millisecond, which
1151                                 the transfer is allowed to complete.
1152   @param  Translator            A pointr to the transaction translator data.
1153   @param  TransferResult        A pointer to the detailed result information of the
1154                                 bulk transfer.
1155 
1156   @retval EFI_SUCCESS           The transfer was completed successfully.
1157   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
1158   @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1159   @retval EFI_TIMEOUT           The transfer failed due to timeout.
1160   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
1161 
1162 **/
1163 EFI_STATUS
1164 EFIAPI
XhcBulkTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN UINT8 DataBuffersNumber,IN OUT VOID * Data[EFI_USB_MAX_BULK_BUFFER_NUM],IN OUT UINTN * DataLength,IN OUT UINT8 * DataToggle,IN UINTN Timeout,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)1165 XhcBulkTransfer (
1166   IN     EFI_USB2_HC_PROTOCOL                *This,
1167   IN     UINT8                               DeviceAddress,
1168   IN     UINT8                               EndPointAddress,
1169   IN     UINT8                               DeviceSpeed,
1170   IN     UINTN                               MaximumPacketLength,
1171   IN     UINT8                               DataBuffersNumber,
1172   IN OUT VOID                                *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
1173   IN OUT UINTN                               *DataLength,
1174   IN OUT UINT8                               *DataToggle,
1175   IN     UINTN                               Timeout,
1176   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1177   OUT    UINT32                              *TransferResult
1178   )
1179 {
1180   USB_XHCI_INSTANCE       *Xhc;
1181   URB                     *Urb;
1182   UINT8                   SlotId;
1183   EFI_STATUS              Status;
1184   EFI_STATUS              RecoveryStatus;
1185   EFI_TPL                 OldTpl;
1186 
1187   //
1188   // Validate the parameters
1189   //
1190   if ((DataLength == NULL) || (*DataLength == 0) ||
1191       (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
1192     return EFI_INVALID_PARAMETER;
1193   }
1194 
1195   if ((*DataToggle != 0) && (*DataToggle != 1)) {
1196     return EFI_INVALID_PARAMETER;
1197   }
1198 
1199   if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1200       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1201       ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||
1202       ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024))) {
1203     return EFI_INVALID_PARAMETER;
1204   }
1205 
1206   OldTpl = gBS->RaiseTPL (XHC_TPL);
1207 
1208   Xhc             = XHC_FROM_THIS (This);
1209 
1210   *TransferResult = EFI_USB_ERR_SYSTEM;
1211   Status          = EFI_DEVICE_ERROR;
1212 
1213   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1214     DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: HC is halted\n"));
1215     goto ON_EXIT;
1216   }
1217 
1218   //
1219   // Check if the device is still enabled before every transaction.
1220   //
1221   SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1222   if (SlotId == 0) {
1223     goto ON_EXIT;
1224   }
1225 
1226   //
1227   // Create a new URB, insert it into the asynchronous
1228   // schedule list, then poll the execution status.
1229   //
1230   Urb = XhcCreateUrb (
1231           Xhc,
1232           DeviceAddress,
1233           EndPointAddress,
1234           DeviceSpeed,
1235           MaximumPacketLength,
1236           XHC_BULK_TRANSFER,
1237           NULL,
1238           Data[0],
1239           *DataLength,
1240           NULL,
1241           NULL
1242           );
1243 
1244   if (Urb == NULL) {
1245     DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: failed to create URB\n"));
1246     Status = EFI_OUT_OF_RESOURCES;
1247     goto ON_EXIT;
1248   }
1249 
1250   Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
1251 
1252   *TransferResult = Urb->Result;
1253   *DataLength     = Urb->Completed;
1254 
1255   if (Status == EFI_TIMEOUT) {
1256     //
1257     // The transfer timed out. Abort the transfer by dequeueing of the TD.
1258     //
1259     RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
1260     if (EFI_ERROR(RecoveryStatus)) {
1261       DEBUG((EFI_D_ERROR, "XhcBulkTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1262     }
1263   } else {
1264     if (*TransferResult == EFI_USB_NOERROR) {
1265       Status = EFI_SUCCESS;
1266     } else if (*TransferResult == EFI_USB_ERR_STALL) {
1267       RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
1268       if (EFI_ERROR (RecoveryStatus)) {
1269         DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));
1270       }
1271       Status = EFI_DEVICE_ERROR;
1272     }
1273   }
1274 
1275   Xhc->PciIo->Flush (Xhc->PciIo);
1276   XhcFreeUrb (Xhc, Urb);
1277 
1278 ON_EXIT:
1279 
1280   if (EFI_ERROR (Status)) {
1281     DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1282   }
1283   gBS->RestoreTPL (OldTpl);
1284 
1285   return Status;
1286 }
1287 
1288 /**
1289   Submits an asynchronous interrupt transfer to an
1290   interrupt endpoint of a USB device.
1291 
1292   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
1293   @param  DeviceAddress         Target device address.
1294   @param  EndPointAddress       Endpoint number and its direction encoded in bit 7
1295   @param  DeviceSpeed           Indicates device speed.
1296   @param  MaximumPacketLength   Maximum packet size the target endpoint is capable
1297   @param  IsNewTransfer         If TRUE, to submit an new asynchronous interrupt
1298                                 transfer If FALSE, to remove the specified
1299                                 asynchronous interrupt.
1300   @param  DataToggle            On input, the initial data toggle to use; on output,
1301                                 it is updated to indicate the next data toggle.
1302   @param  PollingInterval       The he interval, in milliseconds, that the transfer
1303                                 is polled.
1304   @param  DataLength            The length of data to receive at the rate specified
1305                                 by  PollingInterval.
1306   @param  Translator            Transaction translator to use.
1307   @param  CallBackFunction      Function to call at the rate specified by
1308                                 PollingInterval.
1309   @param  Context               Context to CallBackFunction.
1310 
1311   @retval EFI_SUCCESS           The request has been successfully submitted or canceled.
1312   @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1313   @retval EFI_OUT_OF_RESOURCES  The request failed due to a lack of resources.
1314   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
1315 
1316 **/
1317 EFI_STATUS
1318 EFIAPI
XhcAsyncInterruptTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN BOOLEAN IsNewTransfer,IN OUT UINT8 * DataToggle,IN UINTN PollingInterval,IN UINTN DataLength,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,IN VOID * Context OPTIONAL)1319 XhcAsyncInterruptTransfer (
1320   IN     EFI_USB2_HC_PROTOCOL                *This,
1321   IN     UINT8                               DeviceAddress,
1322   IN     UINT8                               EndPointAddress,
1323   IN     UINT8                               DeviceSpeed,
1324   IN     UINTN                               MaximumPacketLength,
1325   IN     BOOLEAN                             IsNewTransfer,
1326   IN OUT UINT8                               *DataToggle,
1327   IN     UINTN                               PollingInterval,
1328   IN     UINTN                               DataLength,
1329   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1330   IN     EFI_ASYNC_USB_TRANSFER_CALLBACK     CallBackFunction,
1331   IN     VOID                                *Context OPTIONAL
1332   )
1333 {
1334   USB_XHCI_INSTANCE       *Xhc;
1335   URB                     *Urb;
1336   EFI_STATUS              Status;
1337   UINT8                   SlotId;
1338   UINT8                   Index;
1339   UINT8                   *Data;
1340   EFI_TPL                 OldTpl;
1341 
1342   //
1343   // Validate parameters
1344   //
1345   if (!XHCI_IS_DATAIN (EndPointAddress)) {
1346     return EFI_INVALID_PARAMETER;
1347   }
1348 
1349   if (IsNewTransfer) {
1350     if (DataLength == 0) {
1351       return EFI_INVALID_PARAMETER;
1352     }
1353 
1354     if ((*DataToggle != 1) && (*DataToggle != 0)) {
1355       return EFI_INVALID_PARAMETER;
1356     }
1357 
1358     if ((PollingInterval > 255) || (PollingInterval < 1)) {
1359       return EFI_INVALID_PARAMETER;
1360     }
1361   }
1362 
1363   OldTpl = gBS->RaiseTPL (XHC_TPL);
1364 
1365   Xhc    = XHC_FROM_THIS (This);
1366 
1367   //
1368   // Delete Async interrupt transfer request.
1369   //
1370   if (!IsNewTransfer) {
1371     //
1372     // The delete request may happen after device is detached.
1373     //
1374     for (Index = 0; Index < 255; Index++) {
1375       if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {
1376         break;
1377       }
1378     }
1379 
1380     if (Index == 255) {
1381       Status = EFI_INVALID_PARAMETER;
1382       goto ON_EXIT;
1383     }
1384 
1385     Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);
1386     DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));
1387     goto ON_EXIT;
1388   }
1389 
1390   Status = EFI_SUCCESS;
1391 
1392   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1393     DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));
1394     Status = EFI_DEVICE_ERROR;
1395     goto ON_EXIT;
1396   }
1397 
1398   //
1399   // Check if the device is still enabled before every transaction.
1400   //
1401   SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1402   if (SlotId == 0) {
1403     goto ON_EXIT;
1404   }
1405 
1406   Data = AllocateZeroPool (DataLength);
1407 
1408   if (Data == NULL) {
1409     DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to allocate buffer\n"));
1410     Status = EFI_OUT_OF_RESOURCES;
1411     goto ON_EXIT;
1412   }
1413 
1414   Urb = XhcCreateUrb (
1415           Xhc,
1416           DeviceAddress,
1417           EndPointAddress,
1418           DeviceSpeed,
1419           MaximumPacketLength,
1420           XHC_INT_TRANSFER_ASYNC,
1421           NULL,
1422           Data,
1423           DataLength,
1424           CallBackFunction,
1425           Context
1426           );
1427 
1428   if (Urb == NULL) {
1429     DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to create URB\n"));
1430     FreePool (Data);
1431     Status = EFI_OUT_OF_RESOURCES;
1432     goto ON_EXIT;
1433   }
1434 
1435   InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);
1436   //
1437   // Ring the doorbell
1438   //
1439   Status = RingIntTransferDoorBell (Xhc, Urb);
1440 
1441 ON_EXIT:
1442   Xhc->PciIo->Flush (Xhc->PciIo);
1443   gBS->RestoreTPL (OldTpl);
1444 
1445   return Status;
1446 }
1447 
1448 
1449 /**
1450   Submits synchronous interrupt transfer to an interrupt endpoint
1451   of a USB device.
1452 
1453   @param  This                  This EFI_USB2_HC_PROTOCOL instance.
1454   @param  DeviceAddress         Target device address.
1455   @param  EndPointAddress       Endpoint number and its direction encoded in bit 7
1456   @param  DeviceSpeed           Indicates device speed.
1457   @param  MaximumPacketLength   Maximum packet size the target endpoint is capable
1458                                 of sending or receiving.
1459   @param  Data                  Buffer of data that will be transmitted to  USB
1460                                 device or received from USB device.
1461   @param  DataLength            On input, the size, in bytes, of the data buffer; On
1462                                 output, the number of bytes transferred.
1463   @param  DataToggle            On input, the initial data toggle to use; on output,
1464                                 it is updated to indicate the next data toggle.
1465   @param  Timeout               Maximum time, in second, to complete.
1466   @param  Translator            Transaction translator to use.
1467   @param  TransferResult        Variable to receive the transfer result.
1468 
1469   @return EFI_SUCCESS           The transfer was completed successfully.
1470   @return EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
1471   @return EFI_INVALID_PARAMETER Some parameters are invalid.
1472   @return EFI_TIMEOUT           The transfer failed due to timeout.
1473   @return EFI_DEVICE_ERROR      The failed due to host controller or device error
1474 
1475 **/
1476 EFI_STATUS
1477 EFIAPI
XhcSyncInterruptTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN OUT VOID * Data,IN OUT UINTN * DataLength,IN OUT UINT8 * DataToggle,IN UINTN Timeout,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)1478 XhcSyncInterruptTransfer (
1479   IN     EFI_USB2_HC_PROTOCOL                *This,
1480   IN     UINT8                               DeviceAddress,
1481   IN     UINT8                               EndPointAddress,
1482   IN     UINT8                               DeviceSpeed,
1483   IN     UINTN                               MaximumPacketLength,
1484   IN OUT VOID                                *Data,
1485   IN OUT UINTN                               *DataLength,
1486   IN OUT UINT8                               *DataToggle,
1487   IN     UINTN                               Timeout,
1488   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1489   OUT    UINT32                              *TransferResult
1490   )
1491 {
1492   USB_XHCI_INSTANCE       *Xhc;
1493   URB                     *Urb;
1494   UINT8                   SlotId;
1495   EFI_STATUS              Status;
1496   EFI_STATUS              RecoveryStatus;
1497   EFI_TPL                 OldTpl;
1498 
1499   //
1500   // Validates parameters
1501   //
1502   if ((DataLength == NULL) || (*DataLength == 0) ||
1503       (Data == NULL) || (TransferResult == NULL)) {
1504     return EFI_INVALID_PARAMETER;
1505   }
1506 
1507   if ((*DataToggle != 1) && (*DataToggle != 0)) {
1508     return EFI_INVALID_PARAMETER;
1509   }
1510 
1511   if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8))  ||
1512       ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1513       ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {
1514     return EFI_INVALID_PARAMETER;
1515   }
1516 
1517   OldTpl = gBS->RaiseTPL (XHC_TPL);
1518 
1519   Xhc     = XHC_FROM_THIS (This);
1520 
1521   *TransferResult = EFI_USB_ERR_SYSTEM;
1522   Status          = EFI_DEVICE_ERROR;
1523 
1524   if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1525     DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1526     goto ON_EXIT;
1527   }
1528 
1529   //
1530   // Check if the device is still enabled before every transaction.
1531   //
1532   SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1533   if (SlotId == 0) {
1534     goto ON_EXIT;
1535   }
1536 
1537   Urb = XhcCreateUrb (
1538           Xhc,
1539           DeviceAddress,
1540           EndPointAddress,
1541           DeviceSpeed,
1542           MaximumPacketLength,
1543           XHC_INT_TRANSFER_SYNC,
1544           NULL,
1545           Data,
1546           *DataLength,
1547           NULL,
1548           NULL
1549           );
1550 
1551   if (Urb == NULL) {
1552     DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n"));
1553     Status = EFI_OUT_OF_RESOURCES;
1554     goto ON_EXIT;
1555   }
1556 
1557   Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
1558 
1559   *TransferResult = Urb->Result;
1560   *DataLength     = Urb->Completed;
1561 
1562   if (Status == EFI_TIMEOUT) {
1563     //
1564     // The transfer timed out. Abort the transfer by dequeueing of the TD.
1565     //
1566     RecoveryStatus = XhcDequeueTrbFromEndpoint(Xhc, Urb);
1567     if (EFI_ERROR(RecoveryStatus)) {
1568       DEBUG((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcDequeueTrbFromEndpoint failed\n"));
1569     }
1570   } else {
1571     if (*TransferResult == EFI_USB_NOERROR) {
1572       Status = EFI_SUCCESS;
1573     } else if (*TransferResult == EFI_USB_ERR_STALL) {
1574       RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
1575       if (EFI_ERROR (RecoveryStatus)) {
1576         DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));
1577       }
1578       Status = EFI_DEVICE_ERROR;
1579     }
1580   }
1581 
1582   Xhc->PciIo->Flush (Xhc->PciIo);
1583   XhcFreeUrb (Xhc, Urb);
1584 
1585 ON_EXIT:
1586   if (EFI_ERROR (Status)) {
1587     DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1588   }
1589   gBS->RestoreTPL (OldTpl);
1590 
1591   return Status;
1592 }
1593 
1594 
1595 /**
1596   Submits isochronous transfer to a target USB device.
1597 
1598   @param  This                 This EFI_USB2_HC_PROTOCOL instance.
1599   @param  DeviceAddress        Target device address.
1600   @param  EndPointAddress      End point address with its direction.
1601   @param  DeviceSpeed          Device speed, Low speed device doesn't support this
1602                                type.
1603   @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of
1604                                sending or receiving.
1605   @param  DataBuffersNumber    Number of data buffers prepared for the transfer.
1606   @param  Data                 Array of pointers to the buffers of data that will
1607                                be transmitted to USB device or received from USB
1608                                device.
1609   @param  DataLength           The size, in bytes, of the data buffer.
1610   @param  Translator           Transaction translator to use.
1611   @param  TransferResult       Variable to receive the transfer result.
1612 
1613   @return EFI_UNSUPPORTED      Isochronous transfer is unsupported.
1614 
1615 **/
1616 EFI_STATUS
1617 EFIAPI
XhcIsochronousTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN UINT8 DataBuffersNumber,IN OUT VOID * Data[EFI_USB_MAX_ISO_BUFFER_NUM],IN UINTN DataLength,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,OUT UINT32 * TransferResult)1618 XhcIsochronousTransfer (
1619   IN     EFI_USB2_HC_PROTOCOL                *This,
1620   IN     UINT8                               DeviceAddress,
1621   IN     UINT8                               EndPointAddress,
1622   IN     UINT8                               DeviceSpeed,
1623   IN     UINTN                               MaximumPacketLength,
1624   IN     UINT8                               DataBuffersNumber,
1625   IN OUT VOID                                *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1626   IN     UINTN                               DataLength,
1627   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1628   OUT    UINT32                              *TransferResult
1629   )
1630 {
1631   return EFI_UNSUPPORTED;
1632 }
1633 
1634 
1635 /**
1636   Submits Async isochronous transfer to a target USB device.
1637 
1638   @param  This                 This EFI_USB2_HC_PROTOCOL instance.
1639   @param  DeviceAddress        Target device address.
1640   @param  EndPointAddress      End point address with its direction.
1641   @param  DeviceSpeed          Device speed, Low speed device doesn't support this
1642                                type.
1643   @param  MaximumPacketLength  Maximum packet size that the endpoint is capable of
1644                                sending or receiving.
1645   @param  DataBuffersNumber    Number of data buffers prepared for the transfer.
1646   @param  Data                 Array of pointers to the buffers of data that will
1647                                be transmitted to USB device or received from USB
1648                                device.
1649   @param  DataLength           The size, in bytes, of the data buffer.
1650   @param  Translator           Transaction translator to use.
1651   @param  IsochronousCallBack  Function to be called when the transfer complete.
1652   @param  Context              Context passed to the call back function as
1653                                parameter.
1654 
1655   @return EFI_UNSUPPORTED      Isochronous transfer isn't supported.
1656 
1657 **/
1658 EFI_STATUS
1659 EFIAPI
XhcAsyncIsochronousTransfer(IN EFI_USB2_HC_PROTOCOL * This,IN UINT8 DeviceAddress,IN UINT8 EndPointAddress,IN UINT8 DeviceSpeed,IN UINTN MaximumPacketLength,IN UINT8 DataBuffersNumber,IN OUT VOID * Data[EFI_USB_MAX_ISO_BUFFER_NUM],IN UINTN DataLength,IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,IN VOID * Context)1660 XhcAsyncIsochronousTransfer (
1661   IN     EFI_USB2_HC_PROTOCOL                *This,
1662   IN     UINT8                               DeviceAddress,
1663   IN     UINT8                               EndPointAddress,
1664   IN     UINT8                               DeviceSpeed,
1665   IN     UINTN                               MaximumPacketLength,
1666   IN     UINT8                               DataBuffersNumber,
1667   IN OUT VOID                                *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1668   IN     UINTN                               DataLength,
1669   IN     EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
1670   IN     EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,
1671   IN     VOID                                *Context
1672   )
1673 {
1674   return EFI_UNSUPPORTED;
1675 }
1676 
1677 /**
1678   Entry point for EFI drivers.
1679 
1680   @param  ImageHandle       EFI_HANDLE.
1681   @param  SystemTable       EFI_SYSTEM_TABLE.
1682 
1683   @retval EFI_SUCCESS       Success.
1684   @retval Others            Fail.
1685 
1686 **/
1687 EFI_STATUS
1688 EFIAPI
XhcDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1689 XhcDriverEntryPoint (
1690   IN EFI_HANDLE           ImageHandle,
1691   IN EFI_SYSTEM_TABLE     *SystemTable
1692   )
1693 {
1694   return EfiLibInstallDriverBindingComponentName2 (
1695            ImageHandle,
1696            SystemTable,
1697            &gXhciDriverBinding,
1698            ImageHandle,
1699            &gXhciComponentName,
1700            &gXhciComponentName2
1701            );
1702 }
1703 
1704 
1705 /**
1706   Test to see if this driver supports ControllerHandle. Any
1707   ControllerHandle that has Usb2HcProtocol installed will
1708   be supported.
1709 
1710   @param  This                 Protocol instance pointer.
1711   @param  Controller           Handle of device to test.
1712   @param  RemainingDevicePath  Not used.
1713 
1714   @return EFI_SUCCESS          This driver supports this device.
1715   @return EFI_UNSUPPORTED      This driver does not support this device.
1716 
1717 **/
1718 EFI_STATUS
1719 EFIAPI
XhcDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1720 XhcDriverBindingSupported (
1721   IN EFI_DRIVER_BINDING_PROTOCOL *This,
1722   IN EFI_HANDLE                  Controller,
1723   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
1724   )
1725 {
1726   EFI_STATUS              Status;
1727   EFI_PCI_IO_PROTOCOL     *PciIo;
1728   USB_CLASSC              UsbClassCReg;
1729 
1730   //
1731   // Test whether there is PCI IO Protocol attached on the controller handle.
1732   //
1733   Status = gBS->OpenProtocol (
1734                   Controller,
1735                   &gEfiPciIoProtocolGuid,
1736                   (VOID **) &PciIo,
1737                   This->DriverBindingHandle,
1738                   Controller,
1739                   EFI_OPEN_PROTOCOL_BY_DRIVER
1740                   );
1741 
1742   if (EFI_ERROR (Status)) {
1743     return EFI_UNSUPPORTED;
1744   }
1745 
1746   Status = PciIo->Pci.Read (
1747                         PciIo,
1748                         EfiPciIoWidthUint8,
1749                         PCI_CLASSCODE_OFFSET,
1750                         sizeof (USB_CLASSC) / sizeof (UINT8),
1751                         &UsbClassCReg
1752                         );
1753 
1754   if (EFI_ERROR (Status)) {
1755     Status = EFI_UNSUPPORTED;
1756     goto ON_EXIT;
1757   }
1758 
1759   //
1760   // Test whether the controller belongs to Xhci type
1761   //
1762   if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1763       (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1764       (UsbClassCReg.ProgInterface != PCI_IF_XHCI)) {
1765     Status = EFI_UNSUPPORTED;
1766   }
1767 
1768 ON_EXIT:
1769   gBS->CloseProtocol (
1770          Controller,
1771          &gEfiPciIoProtocolGuid,
1772          This->DriverBindingHandle,
1773          Controller
1774          );
1775 
1776   return Status;
1777 }
1778 
1779 /**
1780   Create and initialize a USB_XHCI_INSTANCE structure.
1781 
1782   @param  PciIo                  The PciIo on this device.
1783   @param  DevicePath             The device path of host controller.
1784   @param  OriginalPciAttributes  Original PCI attributes.
1785 
1786   @return The allocated and initialized USB_XHCI_INSTANCE structure if created,
1787           otherwise NULL.
1788 
1789 **/
1790 USB_XHCI_INSTANCE*
XhcCreateUsbHc(IN EFI_PCI_IO_PROTOCOL * PciIo,IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINT64 OriginalPciAttributes)1791 XhcCreateUsbHc (
1792   IN EFI_PCI_IO_PROTOCOL       *PciIo,
1793   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
1794   IN UINT64                    OriginalPciAttributes
1795   )
1796 {
1797   USB_XHCI_INSTANCE       *Xhc;
1798   EFI_STATUS              Status;
1799   UINT32                  PageSize;
1800   UINT16                  ExtCapReg;
1801 
1802   Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));
1803 
1804   if (Xhc == NULL) {
1805     return NULL;
1806   }
1807 
1808   //
1809   // Initialize private data structure
1810   //
1811   Xhc->Signature             = XHCI_INSTANCE_SIG;
1812   Xhc->PciIo                 = PciIo;
1813   Xhc->DevicePath            = DevicePath;
1814   Xhc->OriginalPciAttributes = OriginalPciAttributes;
1815   CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));
1816 
1817   InitializeListHead (&Xhc->AsyncIntTransfers);
1818 
1819   //
1820   // Be caution that the Offset passed to XhcReadCapReg() should be Dword align
1821   //
1822   Xhc->CapLength        = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);
1823   Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);
1824   Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);
1825   Xhc->HcCParams.Dword  = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);
1826   Xhc->DBOff            = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);
1827   Xhc->RTSOff           = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);
1828 
1829   //
1830   // This PageSize field defines the page size supported by the xHC implementation.
1831   // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1832   // if bit 0 is Set, the xHC supports 4k byte page sizes.
1833   //
1834   PageSize      = XhcReadOpReg(Xhc, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
1835   Xhc->PageSize = 1 << (HighBitSet32(PageSize) + 12);
1836 
1837   ExtCapReg            = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);
1838   Xhc->ExtCapRegBase   = ExtCapReg << 2;
1839   Xhc->UsbLegSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_LEGACY);
1840   Xhc->DebugCapSupOffset = XhcGetCapabilityAddr (Xhc, XHC_CAP_USB_DEBUG);
1841 
1842   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));
1843   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));
1844   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));
1845   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));
1846   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));
1847   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));
1848   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));
1849   DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DebugCapSupOffset 0x%x\n", Xhc->DebugCapSupOffset));
1850 
1851   //
1852   // Create AsyncRequest Polling Timer
1853   //
1854   Status = gBS->CreateEvent (
1855                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
1856                   TPL_NOTIFY,
1857                   XhcMonitorAsyncRequests,
1858                   Xhc,
1859                   &Xhc->PollTimer
1860                   );
1861 
1862   if (EFI_ERROR (Status)) {
1863     goto ON_ERROR;
1864   }
1865 
1866   return Xhc;
1867 
1868 ON_ERROR:
1869   FreePool (Xhc);
1870   return NULL;
1871 }
1872 
1873 /**
1874   One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1875 
1876   @param  Event                   Pointer to this event
1877   @param  Context                 Event handler private data
1878 
1879 **/
1880 VOID
1881 EFIAPI
XhcExitBootService(EFI_EVENT Event,VOID * Context)1882 XhcExitBootService (
1883   EFI_EVENT  Event,
1884   VOID       *Context
1885   )
1886 
1887 {
1888   USB_XHCI_INSTANCE    *Xhc;
1889   EFI_PCI_IO_PROTOCOL  *PciIo;
1890 
1891   Xhc = (USB_XHCI_INSTANCE*) Context;
1892   PciIo = Xhc->PciIo;
1893 
1894   //
1895   // Stop AsyncRequest Polling timer then stop the XHCI driver
1896   // and uninstall the XHCI protocl.
1897   //
1898   gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
1899   XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1900 
1901   if (Xhc->PollTimer != NULL) {
1902     gBS->CloseEvent (Xhc->PollTimer);
1903   }
1904 
1905   XhcClearBiosOwnership (Xhc);
1906 
1907   //
1908   // Restore original PCI attributes
1909   //
1910   PciIo->Attributes (
1911                   PciIo,
1912                   EfiPciIoAttributeOperationSet,
1913                   Xhc->OriginalPciAttributes,
1914                   NULL
1915                   );
1916 }
1917 
1918 /**
1919   Starting the Usb XHCI Driver.
1920 
1921   @param  This                 Protocol instance pointer.
1922   @param  Controller           Handle of device to test.
1923   @param  RemainingDevicePath  Not used.
1924 
1925   @return EFI_SUCCESS          supports this device.
1926   @return EFI_UNSUPPORTED      do not support this device.
1927   @return EFI_DEVICE_ERROR     cannot be started due to device Error.
1928   @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1929 
1930 **/
1931 EFI_STATUS
1932 EFIAPI
XhcDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)1933 XhcDriverBindingStart (
1934   IN EFI_DRIVER_BINDING_PROTOCOL *This,
1935   IN EFI_HANDLE                  Controller,
1936   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
1937   )
1938 {
1939   EFI_STATUS              Status;
1940   EFI_PCI_IO_PROTOCOL     *PciIo;
1941   UINT64                  Supports;
1942   UINT64                  OriginalPciAttributes;
1943   BOOLEAN                 PciAttributesSaved;
1944   USB_XHCI_INSTANCE       *Xhc;
1945   EFI_DEVICE_PATH_PROTOCOL  *HcDevicePath;
1946 
1947   //
1948   // Open the PciIo Protocol, then enable the USB host controller
1949   //
1950   Status = gBS->OpenProtocol (
1951                   Controller,
1952                   &gEfiPciIoProtocolGuid,
1953                   (VOID **) &PciIo,
1954                   This->DriverBindingHandle,
1955                   Controller,
1956                   EFI_OPEN_PROTOCOL_BY_DRIVER
1957                   );
1958 
1959   if (EFI_ERROR (Status)) {
1960     return Status;
1961   }
1962 
1963   //
1964   // Open Device Path Protocol for on USB host controller
1965   //
1966   HcDevicePath = NULL;
1967   Status = gBS->OpenProtocol (
1968                   Controller,
1969                   &gEfiDevicePathProtocolGuid,
1970                   (VOID **) &HcDevicePath,
1971                   This->DriverBindingHandle,
1972                   Controller,
1973                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
1974                   );
1975 
1976   PciAttributesSaved = FALSE;
1977   //
1978   // Save original PCI attributes
1979   //
1980   Status = PciIo->Attributes (
1981                     PciIo,
1982                     EfiPciIoAttributeOperationGet,
1983                     0,
1984                     &OriginalPciAttributes
1985                     );
1986 
1987   if (EFI_ERROR (Status)) {
1988     goto CLOSE_PCIIO;
1989   }
1990   PciAttributesSaved = TRUE;
1991 
1992   Status = PciIo->Attributes (
1993                     PciIo,
1994                     EfiPciIoAttributeOperationSupported,
1995                     0,
1996                     &Supports
1997                     );
1998   if (!EFI_ERROR (Status)) {
1999     Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
2000     Status = PciIo->Attributes (
2001                       PciIo,
2002                       EfiPciIoAttributeOperationEnable,
2003                       Supports,
2004                       NULL
2005                       );
2006   }
2007 
2008   if (EFI_ERROR (Status)) {
2009     DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));
2010     goto CLOSE_PCIIO;
2011   }
2012 
2013   //
2014   // Create then install USB2_HC_PROTOCOL
2015   //
2016   Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);
2017 
2018   if (Xhc == NULL) {
2019     DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));
2020     return EFI_OUT_OF_RESOURCES;
2021   }
2022 
2023   //
2024   // Enable 64-bit DMA support in the PCI layer if this controller
2025   // supports it.
2026   //
2027   if (Xhc->HcCParams.Data.Ac64 != 0) {
2028     Status = PciIo->Attributes (
2029                       PciIo,
2030                       EfiPciIoAttributeOperationEnable,
2031                       EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE,
2032                       NULL
2033                       );
2034     if (!EFI_ERROR (Status)) {
2035       Xhc->Support64BitDma = TRUE;
2036     } else {
2037       DEBUG ((EFI_D_WARN,
2038         "%a: failed to enable 64-bit DMA on 64-bit capable controller @ %p (%r)\n",
2039         __FUNCTION__, Controller, Status));
2040     }
2041   }
2042 
2043   XhcSetBiosOwnership (Xhc);
2044 
2045   XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
2046   ASSERT (XhcIsHalt (Xhc));
2047 
2048   //
2049   // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag
2050   // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.
2051   //
2052   ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
2053 
2054   //
2055   // Initialize the schedule
2056   //
2057   XhcInitSched (Xhc);
2058 
2059   //
2060   // Start the Host Controller
2061   //
2062   XhcRunHC(Xhc, XHC_GENERIC_TIMEOUT);
2063 
2064   //
2065   // Start the asynchronous interrupt monitor
2066   //
2067   Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);
2068   if (EFI_ERROR (Status)) {
2069     DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));
2070     XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2071     goto FREE_POOL;
2072   }
2073 
2074   //
2075   // Create event to stop the HC when exit boot service.
2076   //
2077   Status = gBS->CreateEventEx (
2078                   EVT_NOTIFY_SIGNAL,
2079                   TPL_NOTIFY,
2080                   XhcExitBootService,
2081                   Xhc,
2082                   &gEfiEventExitBootServicesGuid,
2083                   &Xhc->ExitBootServiceEvent
2084                   );
2085   if (EFI_ERROR (Status)) {
2086     goto FREE_POOL;
2087   }
2088 
2089   //
2090   // Install the component name protocol, don't fail the start
2091   // because of something for display.
2092   //
2093   AddUnicodeString2 (
2094     "eng",
2095     gXhciComponentName.SupportedLanguages,
2096     &Xhc->ControllerNameTable,
2097     L"eXtensible Host Controller (USB 3.0)",
2098     TRUE
2099     );
2100   AddUnicodeString2 (
2101     "en",
2102     gXhciComponentName2.SupportedLanguages,
2103     &Xhc->ControllerNameTable,
2104     L"eXtensible Host Controller (USB 3.0)",
2105     FALSE
2106     );
2107 
2108   Status = gBS->InstallProtocolInterface (
2109                   &Controller,
2110                   &gEfiUsb2HcProtocolGuid,
2111                   EFI_NATIVE_INTERFACE,
2112                   &Xhc->Usb2Hc
2113                   );
2114   if (EFI_ERROR (Status)) {
2115     DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
2116     goto FREE_POOL;
2117   }
2118 
2119   DEBUG ((EFI_D_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));
2120   return EFI_SUCCESS;
2121 
2122 FREE_POOL:
2123   gBS->CloseEvent (Xhc->PollTimer);
2124   XhcFreeSched (Xhc);
2125   FreePool (Xhc);
2126 
2127 CLOSE_PCIIO:
2128   if (PciAttributesSaved) {
2129     //
2130     // Restore original PCI attributes
2131     //
2132     PciIo->Attributes (
2133                     PciIo,
2134                     EfiPciIoAttributeOperationSet,
2135                     OriginalPciAttributes,
2136                     NULL
2137                     );
2138   }
2139 
2140   gBS->CloseProtocol (
2141          Controller,
2142          &gEfiPciIoProtocolGuid,
2143          This->DriverBindingHandle,
2144          Controller
2145          );
2146 
2147   return Status;
2148 }
2149 
2150 
2151 /**
2152   Stop this driver on ControllerHandle. Support stopping any child handles
2153   created by this driver.
2154 
2155   @param  This                 Protocol instance pointer.
2156   @param  Controller           Handle of device to stop driver on.
2157   @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
2158   @param  ChildHandleBuffer    List of handles for the children we need to stop.
2159 
2160   @return EFI_SUCCESS          Success.
2161   @return EFI_DEVICE_ERROR     Fail.
2162 
2163 **/
2164 EFI_STATUS
2165 EFIAPI
XhcDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)2166 XhcDriverBindingStop (
2167   IN EFI_DRIVER_BINDING_PROTOCOL *This,
2168   IN EFI_HANDLE                  Controller,
2169   IN UINTN                       NumberOfChildren,
2170   IN EFI_HANDLE                  *ChildHandleBuffer
2171   )
2172 {
2173   EFI_STATUS            Status;
2174   EFI_USB2_HC_PROTOCOL  *Usb2Hc;
2175   EFI_PCI_IO_PROTOCOL   *PciIo;
2176   USB_XHCI_INSTANCE     *Xhc;
2177   UINT8                 Index;
2178 
2179   //
2180   // Test whether the Controller handler passed in is a valid
2181   // Usb controller handle that should be supported, if not,
2182   // return the error status directly
2183   //
2184   Status = gBS->OpenProtocol (
2185                   Controller,
2186                   &gEfiUsb2HcProtocolGuid,
2187                   (VOID **) &Usb2Hc,
2188                   This->DriverBindingHandle,
2189                   Controller,
2190                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
2191                   );
2192 
2193   if (EFI_ERROR (Status)) {
2194     return Status;
2195   }
2196 
2197   Status = gBS->UninstallProtocolInterface (
2198                   Controller,
2199                   &gEfiUsb2HcProtocolGuid,
2200                   Usb2Hc
2201                   );
2202 
2203   if (EFI_ERROR (Status)) {
2204     return Status;
2205   }
2206 
2207   Xhc   = XHC_FROM_THIS (Usb2Hc);
2208   PciIo = Xhc->PciIo;
2209 
2210   //
2211   // Stop AsyncRequest Polling timer then stop the XHCI driver
2212   // and uninstall the XHCI protocl.
2213   //
2214   gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
2215 
2216   //
2217   // Disable the device slots occupied by these devices on its downstream ports.
2218   // Entry 0 is reserved.
2219   //
2220   for (Index = 0; Index < 255; Index++) {
2221     if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2222         (Xhc->UsbDevContext[Index + 1].SlotId == 0)) {
2223       continue;
2224     }
2225     if (Xhc->HcCParams.Data.Csz == 0) {
2226       XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2227     } else {
2228       XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2229     }
2230   }
2231 
2232   if (Xhc->PollTimer != NULL) {
2233     gBS->CloseEvent (Xhc->PollTimer);
2234   }
2235 
2236   if (Xhc->ExitBootServiceEvent != NULL) {
2237     gBS->CloseEvent (Xhc->ExitBootServiceEvent);
2238   }
2239 
2240   XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2241   XhcClearBiosOwnership (Xhc);
2242   XhciDelAllAsyncIntTransfers (Xhc);
2243   XhcFreeSched (Xhc);
2244 
2245   if (Xhc->ControllerNameTable) {
2246     FreeUnicodeStringTable (Xhc->ControllerNameTable);
2247   }
2248 
2249   //
2250   // Restore original PCI attributes
2251   //
2252   PciIo->Attributes (
2253            PciIo,
2254            EfiPciIoAttributeOperationSet,
2255            Xhc->OriginalPciAttributes,
2256            NULL
2257            );
2258 
2259   gBS->CloseProtocol (
2260          Controller,
2261          &gEfiPciIoProtocolGuid,
2262          This->DriverBindingHandle,
2263          Controller
2264          );
2265 
2266   FreePool (Xhc);
2267 
2268   return EFI_SUCCESS;
2269 }
2270 
2271