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