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