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