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