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