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