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