]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
MdeModulePkg/XhciDxe: Event Ring traverse algorithm enhancement to avoid that those...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / Xhci.c
1 /** @file
2 The XHCI controller driver.
3
4 Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Xhci.h"
16
17 //
18 // Two arrays used to translate the XHCI port state (change)
19 // to the UEFI protocol's port state (change).
20 //
21 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
22 {XHC_PORTSC_CCS, USB_PORT_STAT_CONNECTION},
23 {XHC_PORTSC_PED, USB_PORT_STAT_ENABLE},
24 {XHC_PORTSC_OCA, USB_PORT_STAT_OVERCURRENT},
25 {XHC_PORTSC_RESET, USB_PORT_STAT_RESET}
26 };
27
28 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
29 {XHC_PORTSC_CSC, USB_PORT_STAT_C_CONNECTION},
30 {XHC_PORTSC_PEC, USB_PORT_STAT_C_ENABLE},
31 {XHC_PORTSC_OCC, USB_PORT_STAT_C_OVERCURRENT},
32 {XHC_PORTSC_PRC, USB_PORT_STAT_C_RESET}
33 };
34
35 USB_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
42 USB_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
49 EFI_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 //
61 EFI_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 **/
92 EFI_STATUS
93 EFIAPI
94 XhcGetCapability (
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 **/
135 EFI_STATUS
136 EFIAPI
137 XhcReset (
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
193 ON_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 **/
214 EFI_STATUS
215 EFIAPI
216 XhcGetState (
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 **/
256 EFI_STATUS
257 EFIAPI
258 XhcSetState (
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 **/
334 EFI_STATUS
335 EFIAPI
336 XhcGetRootHubPortStatus (
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
426 ON_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 **/
444 EFI_STATUS
445 EFIAPI
446 XhcSetRootHubPortFeature (
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
551 ON_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 **/
574 EFI_STATUS
575 EFIAPI
576 XhcClearRootHubPortFeature (
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
686 ON_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 **/
718 EFI_STATUS
719 EFIAPI
720 XhcControlTransfer (
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
1034 FREE_URB:
1035 FreePool (Urb);
1036
1037 ON_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 **/
1079 EFI_STATUS
1080 EFIAPI
1081 XhcBulkTransfer (
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
1181 ON_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 **/
1220 EFI_STATUS
1221 EFIAPI
1222 XhcAsyncInterruptTransfer (
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
1344 ON_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 **/
1378 EFI_STATUS
1379 EFIAPI
1380 XhcSyncInterruptTransfer (
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
1478 ON_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 **/
1509 EFI_STATUS
1510 EFIAPI
1511 XhcIsochronousTransfer (
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 **/
1551 EFI_STATUS
1552 EFIAPI
1553 XhcAsyncIsochronousTransfer (
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 **/
1580 EFI_STATUS
1581 EFIAPI
1582 XhcDriverEntryPoint (
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 **/
1611 EFI_STATUS
1612 EFIAPI
1613 XhcDriverBindingSupported (
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
1661 ON_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 **/
1682 USB_XHCI_INSTANCE*
1683 XhcCreateUsbHc (
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
1756 ON_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 **/
1768 VOID
1769 EFIAPI
1770 XhcExitBootService (
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 **/
1819 EFI_STATUS
1820 EFIAPI
1821 XhcDriverBindingStart (
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
1976 FREE_POOL:
1977 gBS->CloseEvent (Xhc->PollTimer);
1978 XhcFreeSched (Xhc);
1979 FreePool (Xhc);
1980
1981 CLOSE_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 **/
2018 EFI_STATUS
2019 EFIAPI
2020 XhcDriverBindingStop (
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