]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/XhciDxe/Xhci.c
Remove several ASSERT in XhciDxe to allow error status happen then do error handling.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / XhciDxe / Xhci.c
CommitLineData
a50f7c4c 1/** @file
2 The XHCI controller driver.
3
20bcb757 4Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>
a50f7c4c 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);
260fbf53
EL
903 if (EFI_ERROR (RecoveryStatus)) {
904 DEBUG ((EFI_D_ERROR, "XhcControlTransfer: XhcRecoverHaltedEndpoint failed\n"));
905 }
a50f7c4c 906 Status = EFI_DEVICE_ERROR;
907 goto FREE_URB;
908 } else {
909 goto FREE_URB;
910 }
911
1847ed0b
EL
912 Xhc->PciIo->Flush (Xhc->PciIo);
913
914 if (Urb->DataMap != NULL) {
915 Status = Xhc->PciIo->Unmap (Xhc->PciIo, Urb->DataMap);
916 ASSERT_EFI_ERROR (Status);
917 if (EFI_ERROR (Status)) {
918 Status = EFI_DEVICE_ERROR;
919 goto FREE_URB;
920 }
921 }
922
a50f7c4c 923 //
924 // Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
925 // Hook Get_Status request form UsbBus as we need trace device attach/detach event happened at hub.
926 // Hook Set_Config request from UsbBus as we need configure device endpoint.
927 //
928 if ((Request->Request == USB_REQ_GET_DESCRIPTOR) &&
929 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE)) ||
930 ((Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_DEVICE))))) {
931 DescriptorType = (UINT8)(Request->Value >> 8);
20bcb757 932 if ((DescriptorType == USB_DESC_TYPE_DEVICE) && ((*DataLength == sizeof (EFI_USB_DEVICE_DESCRIPTOR)) || ((DeviceSpeed == EFI_USB_SPEED_FULL) && (*DataLength == 8)))) {
a50f7c4c 933 ASSERT (Data != NULL);
934 //
935 // Store a copy of device scriptor as hub device need this info to configure endpoint.
936 //
937 CopyMem (&Xhc->UsbDevContext[SlotId].DevDesc, Data, *DataLength);
938 if (Xhc->UsbDevContext[SlotId].DevDesc.BcdUSB == 0x0300) {
939 //
940 // If it's a usb3.0 device, then its max packet size is a 2^n.
941 //
942 MaxPacket0 = 1 << Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
943 } else {
944 MaxPacket0 = Xhc->UsbDevContext[SlotId].DevDesc.MaxPacketSize0;
945 }
946 Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
947 if (Xhc->HcCParams.Data.Csz == 0) {
11249a73 948 Status = XhcEvaluateContext (Xhc, SlotId, MaxPacket0);
a50f7c4c 949 } else {
11249a73 950 Status = XhcEvaluateContext64 (Xhc, SlotId, MaxPacket0);
a50f7c4c 951 }
a50f7c4c 952 } else if (DescriptorType == USB_DESC_TYPE_CONFIG) {
953 ASSERT (Data != NULL);
954 if (*DataLength == ((UINT16 *)Data)[1]) {
955 //
956 // Get configuration value from request, Store the configuration descriptor for Configure_Endpoint cmd.
957 //
958 Index = (UINT8)Request->Value;
959 ASSERT (Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations);
960 Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool(*DataLength);
961 CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
962 }
963 } else if (((DescriptorType == USB_DESC_TYPE_HUB) ||
964 (DescriptorType == USB_DESC_TYPE_HUB_SUPER_SPEED)) && (*DataLength > 2)) {
965 ASSERT (Data != NULL);
966 HubDesc = (EFI_USB_HUB_DESCRIPTOR *)Data;
967 ASSERT (HubDesc->NumPorts <= 15);
968 //
969 // The bit 5,6 of HubCharacter field of Hub Descriptor is TTT.
970 //
971 TTT = (UINT8)((HubDesc->HubCharacter & (BIT5 | BIT6)) >> 5);
972 if (Xhc->UsbDevContext[SlotId].DevDesc.DeviceProtocol == 2) {
973 //
974 // Don't support multi-TT feature for super speed hub now.
975 //
976 MTT = 0;
977 DEBUG ((EFI_D_ERROR, "XHCI: Don't support multi-TT feature for Hub now. (force to disable MTT)\n"));
978 } else {
979 MTT = 0;
980 }
981
982 if (Xhc->HcCParams.Data.Csz == 0) {
983 Status = XhcConfigHubContext (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
984 } else {
985 Status = XhcConfigHubContext64 (Xhc, SlotId, HubDesc->NumPorts, TTT, MTT);
986 }
a50f7c4c 987 }
988 } else if ((Request->Request == USB_REQ_SET_CONFIG) &&
989 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbNoData, USB_REQ_TYPE_STANDARD, USB_TARGET_DEVICE))) {
990 //
991 // Hook Set_Config request from UsbBus as we need configure device endpoint.
992 //
993 for (Index = 0; Index < Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations; Index++) {
994 if (Xhc->UsbDevContext[SlotId].ConfDesc[Index]->ConfigurationValue == (UINT8)Request->Value) {
995 if (Xhc->HcCParams.Data.Csz == 0) {
996 Status = XhcSetConfigCmd (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
997 } else {
998 Status = XhcSetConfigCmd64 (Xhc, SlotId, DeviceSpeed, Xhc->UsbDevContext[SlotId].ConfDesc[Index]);
999 }
a50f7c4c 1000 break;
1001 }
1002 }
1003 } else if ((Request->Request == USB_REQ_GET_STATUS) &&
1004 (Request->RequestType == USB_REQUEST_TYPE (EfiUsbDataIn, USB_REQ_TYPE_CLASS, USB_TARGET_OTHER))) {
1005 ASSERT (Data != NULL);
1006 //
1007 // Hook Get_Status request from UsbBus to keep track of the port status change.
1008 //
1009 State = *(UINT32 *)Data;
1010 PortStatus.PortStatus = 0;
1011 PortStatus.PortChangeStatus = 0;
1012
1013 if (DeviceSpeed == EFI_USB_SPEED_SUPER) {
1014 //
1015 // For super speed hub, its bit10~12 presents the attached device speed.
1016 //
1017 if ((State & XHC_PORTSC_PS) >> 10 == 0) {
1018 PortStatus.PortStatus |= USB_PORT_STAT_SUPER_SPEED;
1019 }
b3b1e97b 1020 } else {
a50f7c4c 1021 //
b3b1e97b 1022 // For high or full/low speed hub, its bit9~10 presents the attached device speed.
a50f7c4c 1023 //
1024 if (XHC_BIT_IS_SET (State, BIT9)) {
1025 PortStatus.PortStatus |= USB_PORT_STAT_LOW_SPEED;
1026 } else if (XHC_BIT_IS_SET (State, BIT10)) {
1027 PortStatus.PortStatus |= USB_PORT_STAT_HIGH_SPEED;
1028 }
a50f7c4c 1029 }
1030
1031 //
1032 // Convert the XHCI port/port change state to UEFI status
1033 //
1034 MapSize = sizeof (mUsbHubPortStateMap) / sizeof (USB_PORT_STATE_MAP);
1035 for (Index = 0; Index < MapSize; Index++) {
1036 if (XHC_BIT_IS_SET (State, mUsbHubPortStateMap[Index].HwState)) {
1037 PortStatus.PortStatus = (UINT16) (PortStatus.PortStatus | mUsbHubPortStateMap[Index].UefiState);
1038 }
1039 }
1040
1041 MapSize = sizeof (mUsbHubPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
1042 for (Index = 0; Index < MapSize; Index++) {
1043 if (XHC_BIT_IS_SET (State, mUsbHubPortChangeMap[Index].HwState)) {
1044 PortStatus.PortChangeStatus = (UINT16) (PortStatus.PortChangeStatus | mUsbHubPortChangeMap[Index].UefiState);
1045 }
1046 }
1047
1048 XhcPollPortStatusChange (Xhc, Xhc->UsbDevContext[SlotId].RouteString, (UINT8)Request->Index, &PortStatus);
1049
1050 *(UINT32 *)Data = *(UINT32*)&PortStatus;
1051 }
1052
1053FREE_URB:
1054 FreePool (Urb);
1055
1056ON_EXIT:
1057
1058 if (EFI_ERROR (Status)) {
1059 DEBUG ((EFI_D_ERROR, "XhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1060 }
1061
1062 gBS->RestoreTPL (OldTpl);
1063
1064 return Status;
1065}
1066
1067
1068/**
1069 Submits bulk transfer to a bulk endpoint of a USB device.
1070
1071 @param This This EFI_USB2_HC_PROTOCOL instance.
1072 @param DeviceAddress Target device address.
1073 @param EndPointAddress Endpoint number and its direction in bit 7.
1074 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
1075 transfer.
1076 @param MaximumPacketLength Maximum packet size the endpoint is capable of
1077 sending or receiving.
1078 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1079 @param Data Array of pointers to the buffers of data to transmit
1080 from or receive into.
1081 @param DataLength The lenght of the data buffer.
1082 @param DataToggle On input, the initial data toggle for the transfer;
1083 On output, it is updated to to next data toggle to
1084 use of the subsequent bulk transfer.
1085 @param Timeout Indicates the maximum time, in millisecond, which
1086 the transfer is allowed to complete.
1087 @param Translator A pointr to the transaction translator data.
1088 @param TransferResult A pointer to the detailed result information of the
1089 bulk transfer.
1090
1091 @retval EFI_SUCCESS The transfer was completed successfully.
1092 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1093 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1094 @retval EFI_TIMEOUT The transfer failed due to timeout.
1095 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
1096
1097**/
1098EFI_STATUS
1099EFIAPI
1100XhcBulkTransfer (
1101 IN EFI_USB2_HC_PROTOCOL *This,
1102 IN UINT8 DeviceAddress,
1103 IN UINT8 EndPointAddress,
1104 IN UINT8 DeviceSpeed,
1105 IN UINTN MaximumPacketLength,
1106 IN UINT8 DataBuffersNumber,
1107 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
1108 IN OUT UINTN *DataLength,
1109 IN OUT UINT8 *DataToggle,
1110 IN UINTN Timeout,
1111 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1112 OUT UINT32 *TransferResult
1113 )
1114{
1115 USB_XHCI_INSTANCE *Xhc;
1116 URB *Urb;
1117 UINT8 SlotId;
1118 EFI_STATUS Status;
1119 EFI_STATUS RecoveryStatus;
1120 EFI_TPL OldTpl;
1121
1122 //
1123 // Validate the parameters
1124 //
1125 if ((DataLength == NULL) || (*DataLength == 0) ||
1126 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
1127 return EFI_INVALID_PARAMETER;
1128 }
1129
1130 if ((*DataToggle != 0) && (*DataToggle != 1)) {
1131 return EFI_INVALID_PARAMETER;
1132 }
1133
1134 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
1135 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1136 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512)) ||
1137 ((EFI_USB_SPEED_SUPER == DeviceSpeed) && (MaximumPacketLength > 1024))) {
1138 return EFI_INVALID_PARAMETER;
1139 }
1140
1141 OldTpl = gBS->RaiseTPL (XHC_TPL);
1142
1143 Xhc = XHC_FROM_THIS (This);
1144
1145 *TransferResult = EFI_USB_ERR_SYSTEM;
1146 Status = EFI_DEVICE_ERROR;
1147
1148 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1149 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: HC is halted\n"));
1150 goto ON_EXIT;
1151 }
1152
1153 //
1154 // Check if the device is still enabled before every transaction.
1155 //
1156 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1157 if (SlotId == 0) {
1158 goto ON_EXIT;
1159 }
1160
1161 //
1162 // Create a new URB, insert it into the asynchronous
1163 // schedule list, then poll the execution status.
1164 //
1165 Urb = XhcCreateUrb (
1166 Xhc,
1167 DeviceAddress,
1168 EndPointAddress,
1169 DeviceSpeed,
1170 MaximumPacketLength,
1171 XHC_BULK_TRANSFER,
1172 NULL,
1173 Data[0],
1174 *DataLength,
1175 NULL,
1176 NULL
1177 );
1178
1179 if (Urb == NULL) {
1180 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: failed to create URB\n"));
1181 Status = EFI_OUT_OF_RESOURCES;
1182 goto ON_EXIT;
1183 }
1184
1185 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
1186
1187 *TransferResult = Urb->Result;
1188 *DataLength = Urb->Completed;
1189
1190 if (*TransferResult == EFI_USB_NOERROR) {
1191 Status = EFI_SUCCESS;
1192 } else if (*TransferResult == EFI_USB_ERR_STALL) {
1193 RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
260fbf53
EL
1194 if (EFI_ERROR (RecoveryStatus)) {
1195 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: XhcRecoverHaltedEndpoint failed\n"));
1196 }
a50f7c4c 1197 Status = EFI_DEVICE_ERROR;
1198 }
1199
1847ed0b
EL
1200 Xhc->PciIo->Flush (Xhc->PciIo);
1201 XhcFreeUrb (Xhc, Urb);
a50f7c4c 1202
1203ON_EXIT:
1204
1205 if (EFI_ERROR (Status)) {
1206 DEBUG ((EFI_D_ERROR, "XhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1207 }
1208 gBS->RestoreTPL (OldTpl);
1209
1210 return Status;
1211}
1212
1213/**
1214 Submits an asynchronous interrupt transfer to an
1215 interrupt endpoint of a USB device.
1216
1217 @param This This EFI_USB2_HC_PROTOCOL instance.
1218 @param DeviceAddress Target device address.
1219 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1220 @param DeviceSpeed Indicates device speed.
1221 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1222 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
1223 transfer If FALSE, to remove the specified
1224 asynchronous interrupt.
1225 @param DataToggle On input, the initial data toggle to use; on output,
1226 it is updated to indicate the next data toggle.
1227 @param PollingInterval The he interval, in milliseconds, that the transfer
1228 is polled.
1229 @param DataLength The length of data to receive at the rate specified
1230 by PollingInterval.
1231 @param Translator Transaction translator to use.
1232 @param CallBackFunction Function to call at the rate specified by
1233 PollingInterval.
1234 @param Context Context to CallBackFunction.
1235
1236 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
1237 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
1238 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
1239 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
1240
1241**/
1242EFI_STATUS
1243EFIAPI
1244XhcAsyncInterruptTransfer (
1245 IN EFI_USB2_HC_PROTOCOL *This,
1246 IN UINT8 DeviceAddress,
1247 IN UINT8 EndPointAddress,
1248 IN UINT8 DeviceSpeed,
1249 IN UINTN MaximumPacketLength,
1250 IN BOOLEAN IsNewTransfer,
1251 IN OUT UINT8 *DataToggle,
1252 IN UINTN PollingInterval,
1253 IN UINTN DataLength,
1254 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1255 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
1256 IN VOID *Context OPTIONAL
1257 )
1258{
1259 USB_XHCI_INSTANCE *Xhc;
1260 URB *Urb;
1261 EFI_STATUS Status;
1262 UINT8 SlotId;
1263 UINT8 Index;
1264 UINT8 *Data;
1265 EFI_TPL OldTpl;
1266
1267 //
1268 // Validate parameters
1269 //
1270 if (!XHCI_IS_DATAIN (EndPointAddress)) {
1271 return EFI_INVALID_PARAMETER;
1272 }
1273
1274 if (IsNewTransfer) {
1275 if (DataLength == 0) {
1276 return EFI_INVALID_PARAMETER;
1277 }
1278
1279 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1280 return EFI_INVALID_PARAMETER;
1281 }
1282
1283 if ((PollingInterval > 255) || (PollingInterval < 1)) {
1284 return EFI_INVALID_PARAMETER;
1285 }
1286 }
1287
1288 OldTpl = gBS->RaiseTPL (XHC_TPL);
1289
1290 Xhc = XHC_FROM_THIS (This);
1291
1292 //
1293 // Delete Async interrupt transfer request.
1294 //
1295 if (!IsNewTransfer) {
1296 //
1297 // The delete request may happen after device is detached.
1298 //
1299 for (Index = 0; Index < 255; Index++) {
1300 if (Xhc->UsbDevContext[Index + 1].BusDevAddr == DeviceAddress) {
1301 break;
1302 }
1303 }
1304
1305 if (Index == 255) {
1306 Status = EFI_INVALID_PARAMETER;
1307 goto ON_EXIT;
1308 }
1309
1310 Status = XhciDelAsyncIntTransfer (Xhc, DeviceAddress, EndPointAddress);
1311 DEBUG ((EFI_D_INFO, "XhcAsyncInterruptTransfer: remove old transfer for addr %d, Status = %r\n", DeviceAddress, Status));
1312 goto ON_EXIT;
1313 }
1314
1315 Status = EFI_SUCCESS;
1316
1317 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1318 DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: HC is halt\n"));
1319 Status = EFI_DEVICE_ERROR;
1320 goto ON_EXIT;
1321 }
1322
1323 //
1324 // Check if the device is still enabled before every transaction.
1325 //
1326 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1327 if (SlotId == 0) {
1328 goto ON_EXIT;
1329 }
1330
1331 Data = AllocateZeroPool (DataLength);
1332
1333 if (Data == NULL) {
1334 DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to allocate buffer\n"));
1335 Status = EFI_OUT_OF_RESOURCES;
1336 goto ON_EXIT;
1337 }
1338
1339 Urb = XhcCreateUrb (
1340 Xhc,
1341 DeviceAddress,
1342 EndPointAddress,
1343 DeviceSpeed,
1344 MaximumPacketLength,
1345 XHC_INT_TRANSFER_ASYNC,
1346 NULL,
1347 Data,
1348 DataLength,
1349 CallBackFunction,
1350 Context
1351 );
1352
1353 if (Urb == NULL) {
1354 DEBUG ((EFI_D_ERROR, "XhcAsyncInterruptTransfer: failed to create URB\n"));
1355 FreePool (Data);
1356 Status = EFI_OUT_OF_RESOURCES;
1357 goto ON_EXIT;
1358 }
1359
1360 InsertHeadList (&Xhc->AsyncIntTransfers, &Urb->UrbList);
1361 //
1362 // Ring the doorbell
1363 //
1364 Status = RingIntTransferDoorBell (Xhc, Urb);
1365
1366ON_EXIT:
1847ed0b 1367 Xhc->PciIo->Flush (Xhc->PciIo);
a50f7c4c 1368 gBS->RestoreTPL (OldTpl);
1369
1370 return Status;
1371}
1372
1373
1374/**
1375 Submits synchronous interrupt transfer to an interrupt endpoint
1376 of a USB device.
1377
1378 @param This This EFI_USB2_HC_PROTOCOL instance.
1379 @param DeviceAddress Target device address.
1380 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1381 @param DeviceSpeed Indicates device speed.
1382 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1383 of sending or receiving.
1384 @param Data Buffer of data that will be transmitted to USB
1385 device or received from USB device.
1386 @param DataLength On input, the size, in bytes, of the data buffer; On
1387 output, the number of bytes transferred.
1388 @param DataToggle On input, the initial data toggle to use; on output,
1389 it is updated to indicate the next data toggle.
1390 @param Timeout Maximum time, in second, to complete.
1391 @param Translator Transaction translator to use.
1392 @param TransferResult Variable to receive the transfer result.
1393
1394 @return EFI_SUCCESS The transfer was completed successfully.
1395 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1396 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1397 @return EFI_TIMEOUT The transfer failed due to timeout.
1398 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1399
1400**/
1401EFI_STATUS
1402EFIAPI
1403XhcSyncInterruptTransfer (
1404 IN EFI_USB2_HC_PROTOCOL *This,
1405 IN UINT8 DeviceAddress,
1406 IN UINT8 EndPointAddress,
1407 IN UINT8 DeviceSpeed,
1408 IN UINTN MaximumPacketLength,
1409 IN OUT VOID *Data,
1410 IN OUT UINTN *DataLength,
1411 IN OUT UINT8 *DataToggle,
1412 IN UINTN Timeout,
1413 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1414 OUT UINT32 *TransferResult
1415 )
1416{
1417 USB_XHCI_INSTANCE *Xhc;
1418 URB *Urb;
1419 UINT8 SlotId;
1420 EFI_STATUS Status;
1421 EFI_STATUS RecoveryStatus;
1422 EFI_TPL OldTpl;
1423
1424 //
1425 // Validates parameters
1426 //
1427 if ((DataLength == NULL) || (*DataLength == 0) ||
1428 (Data == NULL) || (TransferResult == NULL)) {
1429 return EFI_INVALID_PARAMETER;
1430 }
1431
1432 if (!XHCI_IS_DATAIN (EndPointAddress)) {
1433 return EFI_INVALID_PARAMETER;
1434 }
1435
1436 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1437 return EFI_INVALID_PARAMETER;
1438 }
1439
1440 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
1441 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1442 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {
1443 return EFI_INVALID_PARAMETER;
1444 }
1445
1446 OldTpl = gBS->RaiseTPL (XHC_TPL);
1447
1448 Xhc = XHC_FROM_THIS (This);
1449
1450 *TransferResult = EFI_USB_ERR_SYSTEM;
1451 Status = EFI_DEVICE_ERROR;
1452
1453 if (XhcIsHalt (Xhc) || XhcIsSysError (Xhc)) {
1454 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1455 goto ON_EXIT;
1456 }
1457
1458 //
1459 // Check if the device is still enabled before every transaction.
1460 //
1461 SlotId = XhcBusDevAddrToSlotId (Xhc, DeviceAddress);
1462 if (SlotId == 0) {
1463 goto ON_EXIT;
1464 }
1465
1466 Urb = XhcCreateUrb (
1467 Xhc,
1468 DeviceAddress,
1469 EndPointAddress,
1470 DeviceSpeed,
1471 MaximumPacketLength,
1472 XHC_INT_TRANSFER_SYNC,
1473 NULL,
1474 Data,
1475 *DataLength,
1476 NULL,
1477 NULL
1478 );
1479
1480 if (Urb == NULL) {
1481 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: failed to create URB\n"));
1482 Status = EFI_OUT_OF_RESOURCES;
1483 goto ON_EXIT;
1484 }
1485
1486 Status = XhcExecTransfer (Xhc, FALSE, Urb, Timeout);
1487
1488 *TransferResult = Urb->Result;
1489 *DataLength = Urb->Completed;
1490
1491 if (*TransferResult == EFI_USB_NOERROR) {
1492 Status = EFI_SUCCESS;
1493 } else if (*TransferResult == EFI_USB_ERR_STALL) {
1494 RecoveryStatus = XhcRecoverHaltedEndpoint(Xhc, Urb);
260fbf53
EL
1495 if (EFI_ERROR (RecoveryStatus)) {
1496 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: XhcRecoverHaltedEndpoint failed\n"));
1497 }
a50f7c4c 1498 Status = EFI_DEVICE_ERROR;
1499 }
1500
1847ed0b
EL
1501 Xhc->PciIo->Flush (Xhc->PciIo);
1502 XhcFreeUrb (Xhc, Urb);
a50f7c4c 1503
1504ON_EXIT:
1505 if (EFI_ERROR (Status)) {
1506 DEBUG ((EFI_D_ERROR, "XhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1507 }
1508 gBS->RestoreTPL (OldTpl);
1509
1510 return Status;
1511}
1512
1513
1514/**
1515 Submits isochronous transfer to a target USB device.
1516
1517 @param This This EFI_USB2_HC_PROTOCOL instance.
1518 @param DeviceAddress Target device address.
1519 @param EndPointAddress End point address with its direction.
1520 @param DeviceSpeed Device speed, Low speed device doesn't support this
1521 type.
1522 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1523 sending or receiving.
1524 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1525 @param Data Array of pointers to the buffers of data that will
1526 be transmitted to USB device or received from USB
1527 device.
1528 @param DataLength The size, in bytes, of the data buffer.
1529 @param Translator Transaction translator to use.
1530 @param TransferResult Variable to receive the transfer result.
1531
1532 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1533
1534**/
1535EFI_STATUS
1536EFIAPI
1537XhcIsochronousTransfer (
1538 IN EFI_USB2_HC_PROTOCOL *This,
1539 IN UINT8 DeviceAddress,
1540 IN UINT8 EndPointAddress,
1541 IN UINT8 DeviceSpeed,
1542 IN UINTN MaximumPacketLength,
1543 IN UINT8 DataBuffersNumber,
1544 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1545 IN UINTN DataLength,
1546 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1547 OUT UINT32 *TransferResult
1548 )
1549{
1550 return EFI_UNSUPPORTED;
1551}
1552
1553
1554/**
1555 Submits Async isochronous transfer to a target USB device.
1556
1557 @param This This EFI_USB2_HC_PROTOCOL instance.
1558 @param DeviceAddress Target device address.
1559 @param EndPointAddress End point address with its direction.
1560 @param DeviceSpeed Device speed, Low speed device doesn't support this
1561 type.
1562 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1563 sending or receiving.
1564 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1565 @param Data Array of pointers to the buffers of data that will
1566 be transmitted to USB device or received from USB
1567 device.
1568 @param DataLength The size, in bytes, of the data buffer.
1569 @param Translator Transaction translator to use.
1570 @param IsochronousCallBack Function to be called when the transfer complete.
1571 @param Context Context passed to the call back function as
1572 parameter.
1573
1574 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1575
1576**/
1577EFI_STATUS
1578EFIAPI
1579XhcAsyncIsochronousTransfer (
1580 IN EFI_USB2_HC_PROTOCOL *This,
1581 IN UINT8 DeviceAddress,
1582 IN UINT8 EndPointAddress,
1583 IN UINT8 DeviceSpeed,
1584 IN UINTN MaximumPacketLength,
1585 IN UINT8 DataBuffersNumber,
1586 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1587 IN UINTN DataLength,
1588 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1589 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1590 IN VOID *Context
1591 )
1592{
1593 return EFI_UNSUPPORTED;
1594}
1595
1596/**
1597 Entry point for EFI drivers.
1598
1599 @param ImageHandle EFI_HANDLE.
1600 @param SystemTable EFI_SYSTEM_TABLE.
1601
1602 @retval EFI_SUCCESS Success.
1603 @retval Others Fail.
1604
1605**/
1606EFI_STATUS
1607EFIAPI
1608XhcDriverEntryPoint (
1609 IN EFI_HANDLE ImageHandle,
1610 IN EFI_SYSTEM_TABLE *SystemTable
1611 )
1612{
1613 return EfiLibInstallDriverBindingComponentName2 (
1614 ImageHandle,
1615 SystemTable,
1616 &gXhciDriverBinding,
1617 ImageHandle,
1618 &gXhciComponentName,
1619 &gXhciComponentName2
1620 );
1621}
1622
1623
1624/**
1625 Test to see if this driver supports ControllerHandle. Any
1626 ControllerHandle that has Usb2HcProtocol installed will
1627 be supported.
1628
1629 @param This Protocol instance pointer.
1630 @param Controller Handle of device to test.
1631 @param RemainingDevicePath Not used.
1632
1633 @return EFI_SUCCESS This driver supports this device.
1634 @return EFI_UNSUPPORTED This driver does not support this device.
1635
1636**/
1637EFI_STATUS
1638EFIAPI
1639XhcDriverBindingSupported (
1640 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1641 IN EFI_HANDLE Controller,
1642 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1643 )
1644{
1645 EFI_STATUS Status;
1646 EFI_PCI_IO_PROTOCOL *PciIo;
1647 USB_CLASSC UsbClassCReg;
1648
1649 //
1650 // Test whether there is PCI IO Protocol attached on the controller handle.
1651 //
1652 Status = gBS->OpenProtocol (
1653 Controller,
1654 &gEfiPciIoProtocolGuid,
1655 (VOID **) &PciIo,
1656 This->DriverBindingHandle,
1657 Controller,
1658 EFI_OPEN_PROTOCOL_BY_DRIVER
1659 );
1660
1661 if (EFI_ERROR (Status)) {
1662 return EFI_UNSUPPORTED;
1663 }
1664
1665 Status = PciIo->Pci.Read (
1666 PciIo,
1667 EfiPciIoWidthUint8,
1668 PCI_CLASSCODE_OFFSET,
1669 sizeof (USB_CLASSC) / sizeof (UINT8),
1670 &UsbClassCReg
1671 );
1672
1673 if (EFI_ERROR (Status)) {
1674 Status = EFI_UNSUPPORTED;
1675 goto ON_EXIT;
1676 }
1677
1678 //
1679 // Test whether the controller belongs to Xhci type
1680 //
1681 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1682 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1683 (UsbClassCReg.ProgInterface != PCI_IF_XHCI)) {
1684 Status = EFI_UNSUPPORTED;
1685 }
1686
1687ON_EXIT:
1688 gBS->CloseProtocol (
1689 Controller,
1690 &gEfiPciIoProtocolGuid,
1691 This->DriverBindingHandle,
1692 Controller
1693 );
1694
1695 return Status;
1696}
1697
1698/**
1699 Create and initialize a USB_XHCI_INSTANCE structure.
1700
1701 @param PciIo The PciIo on this device.
44c56530 1702 @param DevicePath The device path of host controller.
a50f7c4c 1703 @param OriginalPciAttributes Original PCI attributes.
1704
1705 @return The allocated and initialized USB_XHCI_INSTANCE structure if created,
1706 otherwise NULL.
1707
b3b1e97b 1708**/
1709USB_XHCI_INSTANCE*
1710XhcCreateUsbHc (
1711 IN EFI_PCI_IO_PROTOCOL *PciIo,
1712 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1713 IN UINT64 OriginalPciAttributes
1714 )
1715{
1716 USB_XHCI_INSTANCE *Xhc;
a50f7c4c 1717 EFI_STATUS Status;
1718 UINT32 PageSize;
1719 UINT16 ExtCapReg;
1720
1721 Xhc = AllocateZeroPool (sizeof (USB_XHCI_INSTANCE));
1722
1723 if (Xhc == NULL) {
1724 return NULL;
1725 }
1726
1727 //
1728 // Initialize private data structure
b3b1e97b 1729 //
1730 Xhc->Signature = XHCI_INSTANCE_SIG;
1731 Xhc->PciIo = PciIo;
1732 Xhc->DevicePath = DevicePath;
1733 Xhc->OriginalPciAttributes = OriginalPciAttributes;
1734 CopyMem (&Xhc->Usb2Hc, &gXhciUsb2HcTemplate, sizeof (EFI_USB2_HC_PROTOCOL));
1735
a50f7c4c 1736 InitializeListHead (&Xhc->AsyncIntTransfers);
1737
1738 //
1739 // Be caution that the Offset passed to XhcReadCapReg() should be Dword align
1740 //
1741 Xhc->CapLength = XhcReadCapReg8 (Xhc, XHC_CAPLENGTH_OFFSET);
1742 Xhc->HcSParams1.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS1_OFFSET);
1743 Xhc->HcSParams2.Dword = XhcReadCapReg (Xhc, XHC_HCSPARAMS2_OFFSET);
1744 Xhc->HcCParams.Dword = XhcReadCapReg (Xhc, XHC_HCCPARAMS_OFFSET);
1745 Xhc->DBOff = XhcReadCapReg (Xhc, XHC_DBOFF_OFFSET);
1746 Xhc->RTSOff = XhcReadCapReg (Xhc, XHC_RTSOFF_OFFSET);
1747
1748 //
1749 // This PageSize field defines the page size supported by the xHC implementation.
1750 // This xHC supports a page size of 2^(n+12) if bit n is Set. For example,
1751 // if bit 0 is Set, the xHC supports 4k byte page sizes.
1752 //
1753 PageSize = XhcReadOpReg(Xhc, XHC_PAGESIZE_OFFSET) & XHC_PAGESIZE_MASK;
1754 Xhc->PageSize = 1 << (HighBitSet32(PageSize) + 12);
1755
1756 ExtCapReg = (UINT16) (Xhc->HcCParams.Data.ExtCapReg);
1757 Xhc->ExtCapRegBase = ExtCapReg << 2;
1758 Xhc->UsbLegSupOffset = XhcGetLegSupCapAddr (Xhc);
1759
1760 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: Capability length 0x%x\n", Xhc->CapLength));
1761 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams1 0x%x\n", Xhc->HcSParams1));
1762 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcSParams2 0x%x\n", Xhc->HcSParams2));
1763 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: HcCParams 0x%x\n", Xhc->HcCParams));
1764 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: DBOff 0x%x\n", Xhc->DBOff));
1765 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: RTSOff 0x%x\n", Xhc->RTSOff));
1766 DEBUG ((EFI_D_INFO, "XhcCreateUsb3Hc: UsbLegSupOffset 0x%x\n", Xhc->UsbLegSupOffset));
1767
1768 //
1769 // Create AsyncRequest Polling Timer
1770 //
1771 Status = gBS->CreateEvent (
1772 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1773 TPL_CALLBACK,
1774 XhcMonitorAsyncRequests,
1775 Xhc,
1776 &Xhc->PollTimer
1777 );
1778
1779 if (EFI_ERROR (Status)) {
1780 goto ON_ERROR;
1781 }
1782
1783 return Xhc;
1784
1785ON_ERROR:
1786 FreePool (Xhc);
1787 return NULL;
1788}
1789
1790/**
1791 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1792
1793 @param Event Pointer to this event
1794 @param Context Event hanlder private data
1795
1796**/
1797VOID
1798EFIAPI
1799XhcExitBootService (
1800 EFI_EVENT Event,
1801 VOID *Context
1802 )
1803
1804{
1805 USB_XHCI_INSTANCE *Xhc;
1806 EFI_PCI_IO_PROTOCOL *PciIo;
1807
1808 Xhc = (USB_XHCI_INSTANCE*) Context;
1809 PciIo = Xhc->PciIo;
1810
1811 //
1812 // Stop AsyncRequest Polling timer then stop the XHCI driver
1813 // and uninstall the XHCI protocl.
1814 //
1815 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
1816 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1817
1818 if (Xhc->PollTimer != NULL) {
1819 gBS->CloseEvent (Xhc->PollTimer);
1820 }
1821
11249a73 1822 XhcClearBiosOwnership (Xhc);
1823
a50f7c4c 1824 //
1825 // Restore original PCI attributes
1826 //
1827 PciIo->Attributes (
1828 PciIo,
1829 EfiPciIoAttributeOperationSet,
1830 Xhc->OriginalPciAttributes,
1831 NULL
1832 );
a50f7c4c 1833}
1834
1835/**
1836 Starting the Usb XHCI Driver.
1837
1838 @param This Protocol instance pointer.
1839 @param Controller Handle of device to test.
1840 @param RemainingDevicePath Not used.
1841
1842 @return EFI_SUCCESS supports this device.
1843 @return EFI_UNSUPPORTED do not support this device.
1844 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1845 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1846
1847**/
1848EFI_STATUS
1849EFIAPI
1850XhcDriverBindingStart (
1851 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1852 IN EFI_HANDLE Controller,
1853 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1854 )
1855{
1856 EFI_STATUS Status;
1857 EFI_PCI_IO_PROTOCOL *PciIo;
1858 UINT64 Supports;
b3b1e97b 1859 UINT64 OriginalPciAttributes;
1860 BOOLEAN PciAttributesSaved;
1861 USB_XHCI_INSTANCE *Xhc;
1862 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1863
1864 //
1865 // Open the PciIo Protocol, then enable the USB host controller
a50f7c4c 1866 //
1867 Status = gBS->OpenProtocol (
1868 Controller,
1869 &gEfiPciIoProtocolGuid,
1870 (VOID **) &PciIo,
1871 This->DriverBindingHandle,
1872 Controller,
1873 EFI_OPEN_PROTOCOL_BY_DRIVER
1874 );
1875
1876 if (EFI_ERROR (Status)) {
b3b1e97b 1877 return Status;
1878 }
1879
1880 //
1881 // Open Device Path Protocol for on USB host controller
1882 //
1883 HcDevicePath = NULL;
1884 Status = gBS->OpenProtocol (
1885 Controller,
1886 &gEfiDevicePathProtocolGuid,
1887 (VOID **) &HcDevicePath,
1888 This->DriverBindingHandle,
1889 Controller,
1890 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1891 );
1892
1893 PciAttributesSaved = FALSE;
1894 //
1895 // Save original PCI attributes
a50f7c4c 1896 //
1897 Status = PciIo->Attributes (
1898 PciIo,
1899 EfiPciIoAttributeOperationGet,
1900 0,
1901 &OriginalPciAttributes
1902 );
1903
1904 if (EFI_ERROR (Status)) {
1905 goto CLOSE_PCIIO;
1906 }
1907 PciAttributesSaved = TRUE;
1908
1909 Status = PciIo->Attributes (
1910 PciIo,
1911 EfiPciIoAttributeOperationSupported,
1912 0,
1913 &Supports
1914 );
1915 if (!EFI_ERROR (Status)) {
1916 Supports &= EFI_PCI_DEVICE_ENABLE;
1917 Status = PciIo->Attributes (
1918 PciIo,
1919 EfiPciIoAttributeOperationEnable,
1920 Supports,
1921 NULL
1922 );
1923 }
1924
1925 if (EFI_ERROR (Status)) {
1926 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to enable controller\n"));
1927 goto CLOSE_PCIIO;
1928 }
1929
b3b1e97b 1930 //
1931 // Create then install USB2_HC_PROTOCOL
1932 //
1933 Xhc = XhcCreateUsbHc (PciIo, HcDevicePath, OriginalPciAttributes);
1934
1935 if (Xhc == NULL) {
1936 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to create USB2_HC\n"));
a50f7c4c 1937 return EFI_OUT_OF_RESOURCES;
1938 }
1939
1940 XhcSetBiosOwnership (Xhc);
1941
1942 XhcResetHC (Xhc, XHC_RESET_TIMEOUT);
1943 ASSERT (XhcIsHalt (Xhc));
1944
1945 //
1946 // After Chip Hardware Reset wait until the Controller Not Ready (CNR) flag
1947 // in the USBSTS is '0' before writing any xHC Operational or Runtime registers.
1948 //
1949 ASSERT (!(XHC_REG_BIT_IS_SET (Xhc, XHC_USBSTS_OFFSET, XHC_USBSTS_CNR)));
1950
1951 //
1952 // Initialize the schedule
1953 //
1954 XhcInitSched (Xhc);
1955
1956 //
1957 // Start the Host Controller
1958 //
1959 XhcRunHC(Xhc, XHC_GENERIC_TIMEOUT);
1960
1961 //
1962 // Start the asynchronous interrupt monitor
1963 //
1964 Status = gBS->SetTimer (Xhc->PollTimer, TimerPeriodic, XHC_ASYNC_TIMER_INTERVAL);
1965 if (EFI_ERROR (Status)) {
1966 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to start async interrupt monitor\n"));
1967 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
1968 goto FREE_POOL;
1969 }
1970
1971 //
1972 // Create event to stop the HC when exit boot service.
1973 //
1974 Status = gBS->CreateEventEx (
1975 EVT_NOTIFY_SIGNAL,
1976 TPL_NOTIFY,
1977 XhcExitBootService,
1978 Xhc,
1979 &gEfiEventExitBootServicesGuid,
1980 &Xhc->ExitBootServiceEvent
1981 );
1982 if (EFI_ERROR (Status)) {
1983 goto FREE_POOL;
1984 }
1985
1986 //
1987 // Install the component name protocol, don't fail the start
1988 // because of something for display.
1989 //
1990 AddUnicodeString2 (
1991 "eng",
1992 gXhciComponentName.SupportedLanguages,
1993 &Xhc->ControllerNameTable,
1994 L"eXtensible Host Controller (USB 3.0)",
1995 TRUE
1996 );
1997 AddUnicodeString2 (
1998 "en",
1999 gXhciComponentName2.SupportedLanguages,
2000 &Xhc->ControllerNameTable,
2001 L"eXtensible Host Controller (USB 3.0)",
2002 FALSE
2003 );
2004
2005 Status = gBS->InstallProtocolInterface (
2006 &Controller,
2007 &gEfiUsb2HcProtocolGuid,
2008 EFI_NATIVE_INTERFACE,
2009 &Xhc->Usb2Hc
2010 );
2011 if (EFI_ERROR (Status)) {
2012 DEBUG ((EFI_D_ERROR, "XhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
2013 goto FREE_POOL;
2014 }
2015
2016 DEBUG ((EFI_D_INFO, "XhcDriverBindingStart: XHCI started for controller @ %x\n", Controller));
2017 return EFI_SUCCESS;
2018
2019FREE_POOL:
2020 gBS->CloseEvent (Xhc->PollTimer);
2021 XhcFreeSched (Xhc);
2022 FreePool (Xhc);
2023
2024CLOSE_PCIIO:
2025 if (PciAttributesSaved) {
2026 //
2027 // Restore original PCI attributes
2028 //
2029 PciIo->Attributes (
2030 PciIo,
2031 EfiPciIoAttributeOperationSet,
2032 OriginalPciAttributes,
2033 NULL
2034 );
2035 }
2036
2037 gBS->CloseProtocol (
2038 Controller,
2039 &gEfiPciIoProtocolGuid,
2040 This->DriverBindingHandle,
2041 Controller
2042 );
2043
2044 return Status;
2045}
2046
2047
2048/**
2049 Stop this driver on ControllerHandle. Support stoping any child handles
2050 created by this driver.
2051
2052 @param This Protocol instance pointer.
2053 @param Controller Handle of device to stop driver on.
2054 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
2055 @param ChildHandleBuffer List of handles for the children we need to stop.
2056
2057 @return EFI_SUCCESS Success.
2058 @return EFI_DEVICE_ERROR Fail.
2059
2060**/
2061EFI_STATUS
2062EFIAPI
2063XhcDriverBindingStop (
2064 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2065 IN EFI_HANDLE Controller,
2066 IN UINTN NumberOfChildren,
2067 IN EFI_HANDLE *ChildHandleBuffer
2068 )
2069{
2070 EFI_STATUS Status;
2071 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2072 EFI_PCI_IO_PROTOCOL *PciIo;
2073 USB_XHCI_INSTANCE *Xhc;
2074 UINT8 Index;
2075
2076 //
2077 // Test whether the Controller handler passed in is a valid
2078 // Usb controller handle that should be supported, if not,
2079 // return the error status directly
2080 //
2081 Status = gBS->OpenProtocol (
2082 Controller,
2083 &gEfiUsb2HcProtocolGuid,
2084 (VOID **) &Usb2Hc,
2085 This->DriverBindingHandle,
2086 Controller,
2087 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2088 );
2089
2090 if (EFI_ERROR (Status)) {
2091 return Status;
2092 }
2093
2094 Xhc = XHC_FROM_THIS (Usb2Hc);
2095 PciIo = Xhc->PciIo;
2096
2097 //
2098 // Stop AsyncRequest Polling timer then stop the XHCI driver
2099 // and uninstall the XHCI protocl.
2100 //
2101 gBS->SetTimer (Xhc->PollTimer, TimerCancel, 0);
2102
2103 //
2104 // Disable the device slots occupied by these devices on its downstream ports.
2105 // Entry 0 is reserved.
2106 //
2107 for (Index = 0; Index < 255; Index++) {
2108 if (!Xhc->UsbDevContext[Index + 1].Enabled ||
2109 (Xhc->UsbDevContext[Index + 1].SlotId == 0)) {
2110 continue;
2111 }
2112 if (Xhc->HcCParams.Data.Csz == 0) {
2113 XhcDisableSlotCmd (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2114 } else {
2115 XhcDisableSlotCmd64 (Xhc, Xhc->UsbDevContext[Index + 1].SlotId);
2116 }
2117 }
2118
2119 XhcHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
2120 XhcClearBiosOwnership (Xhc);
2121
2122 Status = gBS->UninstallProtocolInterface (
2123 Controller,
2124 &gEfiUsb2HcProtocolGuid,
2125 Usb2Hc
2126 );
2127
2128 if (EFI_ERROR (Status)) {
2129 return Status;
2130 }
2131
2132 if (Xhc->PollTimer != NULL) {
2133 gBS->CloseEvent (Xhc->PollTimer);
2134 }
2135
2136 if (Xhc->ExitBootServiceEvent != NULL) {
2137 gBS->CloseEvent (Xhc->ExitBootServiceEvent);
2138 }
2139
2140 XhciDelAllAsyncIntTransfers (Xhc);
2141 XhcFreeSched (Xhc);
2142
2143 if (Xhc->ControllerNameTable) {
2144 FreeUnicodeStringTable (Xhc->ControllerNameTable);
2145 }
2146
2147 //
2148 // Restore original PCI attributes
2149 //
2150 PciIo->Attributes (
2151 PciIo,
2152 EfiPciIoAttributeOperationSet,
2153 Xhc->OriginalPciAttributes,
2154 NULL
2155 );
2156
2157 gBS->CloseProtocol (
2158 Controller,
2159 &gEfiPciIoProtocolGuid,
2160 This->DriverBindingHandle,
2161 Controller
2162 );
2163
2164 FreePool (Xhc);
2165
2166 return EFI_SUCCESS;
2167}
2168