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