]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
Adding a segment code to make sure that the EHCI controller get attached to the EHCI...
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / EhciDxe / Ehci.c
1 /** @file
2
3 The Ehci controller driver.
4
5 Copyright (c) 2006 - 2009, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16
17 #include "Ehci.h"
18
19 //
20 // Two arrays used to translate the EHCI port state (change)
21 // to the UEFI protocol's port state (change).
22 //
23 USB_PORT_STATE_MAP mUsbPortStateMap[] = {
24 {PORTSC_CONN, USB_PORT_STAT_CONNECTION},
25 {PORTSC_ENABLED, USB_PORT_STAT_ENABLE},
26 {PORTSC_SUSPEND, USB_PORT_STAT_SUSPEND},
27 {PORTSC_OVERCUR, USB_PORT_STAT_OVERCURRENT},
28 {PORTSC_RESET, USB_PORT_STAT_RESET},
29 {PORTSC_POWER, USB_PORT_STAT_POWER},
30 {PORTSC_OWNER, USB_PORT_STAT_OWNER}
31 };
32
33 USB_PORT_STATE_MAP mUsbPortChangeMap[] = {
34 {PORTSC_CONN_CHANGE, USB_PORT_STAT_C_CONNECTION},
35 {PORTSC_ENABLE_CHANGE, USB_PORT_STAT_C_ENABLE},
36 {PORTSC_OVERCUR_CHANGE, USB_PORT_STAT_C_OVERCURRENT}
37 };
38
39 EFI_DRIVER_BINDING_PROTOCOL
40 gEhciDriverBinding = {
41 EhcDriverBindingSupported,
42 EhcDriverBindingStart,
43 EhcDriverBindingStop,
44 0x30,
45 NULL,
46 NULL
47 };
48
49 ///
50 /// USB host controller Programming Interface.
51 ///
52 #define PCI_CLASSC_PI_UHCI 0x00
53 #define PCI_CLASSC_PI_EHCI 0x20
54
55 /**
56 Retrieves the capability of root hub ports.
57
58 @param This This EFI_USB_HC_PROTOCOL instance.
59 @param MaxSpeed Max speed supported by the controller.
60 @param PortNumber Number of the root hub ports.
61 @param Is64BitCapable Whether the controller supports 64-bit memory
62 addressing.
63
64 @retval EFI_SUCCESS Host controller capability were retrieved successfully.
65 @retval EFI_INVALID_PARAMETER Either of the three capability pointer is NULL.
66
67 **/
68 EFI_STATUS
69 EFIAPI
70 EhcGetCapability (
71 IN EFI_USB2_HC_PROTOCOL *This,
72 OUT UINT8 *MaxSpeed,
73 OUT UINT8 *PortNumber,
74 OUT UINT8 *Is64BitCapable
75 )
76 {
77 USB2_HC_DEV *Ehc;
78 EFI_TPL OldTpl;
79
80 if ((MaxSpeed == NULL) || (PortNumber == NULL) || (Is64BitCapable == NULL)) {
81 return EFI_INVALID_PARAMETER;
82 }
83
84 OldTpl = gBS->RaiseTPL (EHC_TPL);
85 Ehc = EHC_FROM_THIS (This);
86
87 *MaxSpeed = EFI_USB_SPEED_HIGH;
88 *PortNumber = (UINT8) (Ehc->HcStructParams & HCSP_NPORTS);
89 *Is64BitCapable = (UINT8) (Ehc->HcCapParams & HCCP_64BIT);
90
91 DEBUG ((EFI_D_INFO, "EhcGetCapability: %d ports, 64 bit %d\n", *PortNumber, *Is64BitCapable));
92
93 gBS->RestoreTPL (OldTpl);
94 return EFI_SUCCESS;
95 }
96
97
98 /**
99 Provides software reset for the USB host controller.
100
101 @param This This EFI_USB2_HC_PROTOCOL instance.
102 @param Attributes A bit mask of the reset operation to perform.
103
104 @retval EFI_SUCCESS The reset operation succeeded.
105 @retval EFI_INVALID_PARAMETER Attributes is not valid.
106 @retval EFI_UNSUPPOURTED The type of reset specified by Attributes is
107 not currently supported by the host controller.
108 @retval EFI_DEVICE_ERROR Host controller isn't halted to reset.
109
110 **/
111 EFI_STATUS
112 EFIAPI
113 EhcReset (
114 IN EFI_USB2_HC_PROTOCOL *This,
115 IN UINT16 Attributes
116 )
117 {
118 USB2_HC_DEV *Ehc;
119 EFI_TPL OldTpl;
120 EFI_STATUS Status;
121
122 OldTpl = gBS->RaiseTPL (EHC_TPL);
123 Ehc = EHC_FROM_THIS (This);
124
125 switch (Attributes) {
126 case EFI_USB_HC_RESET_GLOBAL:
127 //
128 // Flow through, same behavior as Host Controller Reset
129 //
130 case EFI_USB_HC_RESET_HOST_CONTROLLER:
131 //
132 // Host Controller must be Halt when Reset it
133 //
134 if (!EhcIsHalt (Ehc)) {
135 Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
136
137 if (EFI_ERROR (Status)) {
138 Status = EFI_DEVICE_ERROR;
139 goto ON_EXIT;
140 }
141 }
142
143 //
144 // Clean up the asynchronous transfers, currently only
145 // interrupt supports asynchronous operation.
146 //
147 EhciDelAllAsyncIntTransfers (Ehc);
148 EhcAckAllInterrupt (Ehc);
149 EhcFreeSched (Ehc);
150
151 Status = EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
152
153 if (EFI_ERROR (Status)) {
154 goto ON_EXIT;
155 }
156
157 Status = EhcInitHC (Ehc);
158 break;
159
160 case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
161 case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
162 Status = EFI_UNSUPPORTED;
163 break;
164
165 default:
166 Status = EFI_INVALID_PARAMETER;
167 }
168
169 ON_EXIT:
170 DEBUG ((EFI_D_INFO, "EhcReset: exit status %r\n", Status));
171 gBS->RestoreTPL (OldTpl);
172 return Status;
173 }
174
175
176 /**
177 Retrieve the current state of the USB host controller.
178
179 @param This This EFI_USB2_HC_PROTOCOL instance.
180 @param State Variable to return the current host controller
181 state.
182
183 @retval EFI_SUCCESS Host controller state was returned in State.
184 @retval EFI_INVALID_PARAMETER State is NULL.
185 @retval EFI_DEVICE_ERROR An error was encountered while attempting to
186 retrieve the host controller's current state.
187
188 **/
189 EFI_STATUS
190 EFIAPI
191 EhcGetState (
192 IN CONST EFI_USB2_HC_PROTOCOL *This,
193 OUT EFI_USB_HC_STATE *State
194 )
195 {
196 EFI_TPL OldTpl;
197 USB2_HC_DEV *Ehc;
198
199 if (State == NULL) {
200 return EFI_INVALID_PARAMETER;
201 }
202
203 OldTpl = gBS->RaiseTPL (EHC_TPL);
204 Ehc = EHC_FROM_THIS (This);
205
206 if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
207 *State = EfiUsbHcStateHalt;
208 } else {
209 *State = EfiUsbHcStateOperational;
210 }
211
212 gBS->RestoreTPL (OldTpl);
213
214 DEBUG ((EFI_D_INFO, "EhcGetState: current state %d\n", *State));
215 return EFI_SUCCESS;
216 }
217
218
219 /**
220 Sets the USB host controller to a specific state.
221
222 @param This This EFI_USB2_HC_PROTOCOL instance.
223 @param State The state of the host controller that will be set.
224
225 @retval EFI_SUCCESS The USB host controller was successfully placed
226 in the state specified by State.
227 @retval EFI_INVALID_PARAMETER State is invalid.
228 @retval EFI_DEVICE_ERROR Failed to set the state due to device error.
229
230 **/
231 EFI_STATUS
232 EFIAPI
233 EhcSetState (
234 IN EFI_USB2_HC_PROTOCOL *This,
235 IN EFI_USB_HC_STATE State
236 )
237 {
238 USB2_HC_DEV *Ehc;
239 EFI_TPL OldTpl;
240 EFI_STATUS Status;
241 EFI_USB_HC_STATE CurState;
242
243 Status = EhcGetState (This, &CurState);
244
245 if (EFI_ERROR (Status)) {
246 return EFI_DEVICE_ERROR;
247 }
248
249 if (CurState == State) {
250 return EFI_SUCCESS;
251 }
252
253 OldTpl = gBS->RaiseTPL (EHC_TPL);
254 Ehc = EHC_FROM_THIS (This);
255
256 switch (State) {
257 case EfiUsbHcStateHalt:
258 Status = EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
259 break;
260
261 case EfiUsbHcStateOperational:
262 if (EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_SYS_ERROR)) {
263 Status = EFI_DEVICE_ERROR;
264 break;
265 }
266
267 //
268 // Software must not write a one to this field unless the host controller
269 // is in the Halted state. Doing so will yield undefined results.
270 // refers to Spec[EHCI1.0-2.3.1]
271 //
272 if (!EHC_REG_BIT_IS_SET (Ehc, EHC_USBSTS_OFFSET, USBSTS_HALT)) {
273 Status = EFI_DEVICE_ERROR;
274 break;
275 }
276
277 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
278 break;
279
280 case EfiUsbHcStateSuspend:
281 Status = EFI_UNSUPPORTED;
282 break;
283
284 default:
285 Status = EFI_INVALID_PARAMETER;
286 }
287
288 DEBUG ((EFI_D_INFO, "EhcSetState: exit status %r\n", Status));
289 gBS->RestoreTPL (OldTpl);
290 return Status;
291 }
292
293
294 /**
295 Retrieves the current status of a USB root hub port.
296
297 @param This This EFI_USB2_HC_PROTOCOL instance.
298 @param PortNumber The root hub port to retrieve the state from.
299 This value is zero-based.
300 @param PortStatus Variable to receive the port state.
301
302 @retval EFI_SUCCESS The status of the USB root hub port specified.
303 by PortNumber was returned in PortStatus.
304 @retval EFI_INVALID_PARAMETER PortNumber is invalid.
305 @retval EFI_DEVICE_ERROR Can't read register.
306
307 **/
308 EFI_STATUS
309 EFIAPI
310 EhcGetRootHubPortStatus (
311 IN CONST EFI_USB2_HC_PROTOCOL *This,
312 IN CONST UINT8 PortNumber,
313 OUT EFI_USB_PORT_STATUS *PortStatus
314 )
315 {
316 USB2_HC_DEV *Ehc;
317 EFI_TPL OldTpl;
318 UINT32 Offset;
319 UINT32 State;
320 UINT32 TotalPort;
321 UINTN Index;
322 UINTN MapSize;
323 EFI_STATUS Status;
324
325 if (PortStatus == NULL) {
326 return EFI_INVALID_PARAMETER;
327 }
328
329 OldTpl = gBS->RaiseTPL (EHC_TPL);
330
331 Ehc = EHC_FROM_THIS (This);
332 Status = EFI_SUCCESS;
333
334 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
335
336 if (PortNumber >= TotalPort) {
337 Status = EFI_INVALID_PARAMETER;
338 goto ON_EXIT;
339 }
340
341 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
342 PortStatus->PortStatus = 0;
343 PortStatus->PortChangeStatus = 0;
344
345 State = EhcReadOpReg (Ehc, Offset);
346
347 //
348 // Identify device speed. If in K state, it is low speed.
349 // If the port is enabled after reset, the device is of
350 // high speed. The USB bus driver should retrieve the actual
351 // port speed after reset.
352 //
353 if (EHC_BIT_IS_SET (State, PORTSC_LINESTATE_K)) {
354 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
355
356 } else if (EHC_BIT_IS_SET (State, PORTSC_ENABLED)) {
357 PortStatus->PortStatus |= USB_PORT_STAT_HIGH_SPEED;
358 }
359
360 //
361 // Convert the EHCI port/port change state to UEFI status
362 //
363 MapSize = sizeof (mUsbPortStateMap) / sizeof (USB_PORT_STATE_MAP);
364
365 for (Index = 0; Index < MapSize; Index++) {
366 if (EHC_BIT_IS_SET (State, mUsbPortStateMap[Index].HwState)) {
367 PortStatus->PortStatus = (UINT16) (PortStatus->PortStatus | mUsbPortStateMap[Index].UefiState);
368 }
369 }
370
371 MapSize = sizeof (mUsbPortChangeMap) / sizeof (USB_PORT_STATE_MAP);
372
373 for (Index = 0; Index < MapSize; Index++) {
374 if (EHC_BIT_IS_SET (State, mUsbPortChangeMap[Index].HwState)) {
375 PortStatus->PortChangeStatus = (UINT16) (PortStatus->PortChangeStatus | mUsbPortChangeMap[Index].UefiState);
376 }
377 }
378
379 ON_EXIT:
380 gBS->RestoreTPL (OldTpl);
381 return Status;
382 }
383
384
385 /**
386 Sets a feature for the specified root hub port.
387
388 @param This This EFI_USB2_HC_PROTOCOL instance.
389 @param PortNumber Root hub port to set.
390 @param PortFeature Feature to set.
391
392 @retval EFI_SUCCESS The feature specified by PortFeature was set.
393 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
394 @retval EFI_DEVICE_ERROR Can't read register.
395
396 **/
397 EFI_STATUS
398 EFIAPI
399 EhcSetRootHubPortFeature (
400 IN EFI_USB2_HC_PROTOCOL *This,
401 IN UINT8 PortNumber,
402 IN EFI_USB_PORT_FEATURE PortFeature
403 )
404 {
405 USB2_HC_DEV *Ehc;
406 EFI_TPL OldTpl;
407 UINT32 Offset;
408 UINT32 State;
409 UINT32 TotalPort;
410 EFI_STATUS Status;
411
412 OldTpl = gBS->RaiseTPL (EHC_TPL);
413 Ehc = EHC_FROM_THIS (This);
414 Status = EFI_SUCCESS;
415
416 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
417
418 if (PortNumber >= TotalPort) {
419 Status = EFI_INVALID_PARAMETER;
420 goto ON_EXIT;
421 }
422
423 Offset = (UINT32) (EHC_PORT_STAT_OFFSET + (4 * PortNumber));
424 State = EhcReadOpReg (Ehc, Offset);
425
426 //
427 // Mask off the port status change bits, these bits are
428 // write clean bit
429 //
430 State &= ~PORTSC_CHANGE_MASK;
431
432 switch (PortFeature) {
433 case EfiUsbPortEnable:
434 //
435 // Sofeware can't set this bit, Port can only be enable by
436 // EHCI as a part of the reset and enable
437 //
438 State |= PORTSC_ENABLED;
439 EhcWriteOpReg (Ehc, Offset, State);
440 break;
441
442 case EfiUsbPortSuspend:
443 State |= PORTSC_SUSPEND;
444 EhcWriteOpReg (Ehc, Offset, State);
445 break;
446
447 case EfiUsbPortReset:
448 //
449 // Make sure Host Controller not halt before reset it
450 //
451 if (EhcIsHalt (Ehc)) {
452 Status = EhcRunHC (Ehc, EHC_GENERIC_TIMEOUT);
453
454 if (EFI_ERROR (Status)) {
455 DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature :failed to start HC - %r\n", Status));
456 break;
457 }
458 }
459
460 //
461 // Set one to PortReset bit must also set zero to PortEnable bit
462 //
463 State |= PORTSC_RESET;
464 State &= ~PORTSC_ENABLED;
465 EhcWriteOpReg (Ehc, Offset, State);
466 break;
467
468 case EfiUsbPortPower:
469 //
470 // Not supported, ignore the operation
471 //
472 Status = EFI_SUCCESS;
473 break;
474
475 case EfiUsbPortOwner:
476 State |= PORTSC_OWNER;
477 EhcWriteOpReg (Ehc, Offset, State);
478 break;
479
480 default:
481 Status = EFI_INVALID_PARAMETER;
482 }
483
484 ON_EXIT:
485 DEBUG ((EFI_D_INFO, "EhcSetRootHubPortFeature: exit status %r\n", Status));
486
487 gBS->RestoreTPL (OldTpl);
488 return Status;
489 }
490
491
492 /**
493 Clears a feature for the specified root hub port.
494
495 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
496 @param PortNumber Specifies the root hub port whose feature is
497 requested to be cleared.
498 @param PortFeature Indicates the feature selector associated with the
499 feature clear request.
500
501 @retval EFI_SUCCESS The feature specified by PortFeature was cleared
502 for the USB root hub port specified by PortNumber.
503 @retval EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
504 @retval EFI_DEVICE_ERROR Can't read register.
505
506 **/
507 EFI_STATUS
508 EFIAPI
509 EhcClearRootHubPortFeature (
510 IN EFI_USB2_HC_PROTOCOL *This,
511 IN UINT8 PortNumber,
512 IN EFI_USB_PORT_FEATURE PortFeature
513 )
514 {
515 USB2_HC_DEV *Ehc;
516 EFI_TPL OldTpl;
517 UINT32 Offset;
518 UINT32 State;
519 UINT32 TotalPort;
520 EFI_STATUS Status;
521
522 OldTpl = gBS->RaiseTPL (EHC_TPL);
523 Ehc = EHC_FROM_THIS (This);
524 Status = EFI_SUCCESS;
525
526 TotalPort = (Ehc->HcStructParams & HCSP_NPORTS);
527
528 if (PortNumber >= TotalPort) {
529 Status = EFI_INVALID_PARAMETER;
530 goto ON_EXIT;
531 }
532
533 Offset = EHC_PORT_STAT_OFFSET + (4 * PortNumber);
534 State = EhcReadOpReg (Ehc, Offset);
535 State &= ~PORTSC_CHANGE_MASK;
536
537 switch (PortFeature) {
538 case EfiUsbPortEnable:
539 //
540 // Clear PORT_ENABLE feature means disable port.
541 //
542 State &= ~PORTSC_ENABLED;
543 EhcWriteOpReg (Ehc, Offset, State);
544 break;
545
546 case EfiUsbPortSuspend:
547 //
548 // A write of zero to this bit is ignored by the host
549 // controller. The host controller will unconditionally
550 // set this bit to a zero when:
551 // 1. software sets the Forct Port Resume bit to a zero from a one.
552 // 2. software sets the Port Reset bit to a one frome a zero.
553 //
554 State &= ~PORSTSC_RESUME;
555 EhcWriteOpReg (Ehc, Offset, State);
556 break;
557
558 case EfiUsbPortReset:
559 //
560 // Clear PORT_RESET means clear the reset signal.
561 //
562 State &= ~PORTSC_RESET;
563 EhcWriteOpReg (Ehc, Offset, State);
564 break;
565
566 case EfiUsbPortOwner:
567 //
568 // Clear port owner means this port owned by EHC
569 //
570 State &= ~PORTSC_OWNER;
571 EhcWriteOpReg (Ehc, Offset, State);
572 break;
573
574 case EfiUsbPortConnectChange:
575 //
576 // Clear connect status change
577 //
578 State |= PORTSC_CONN_CHANGE;
579 EhcWriteOpReg (Ehc, Offset, State);
580 break;
581
582 case EfiUsbPortEnableChange:
583 //
584 // Clear enable status change
585 //
586 State |= PORTSC_ENABLE_CHANGE;
587 EhcWriteOpReg (Ehc, Offset, State);
588 break;
589
590 case EfiUsbPortOverCurrentChange:
591 //
592 // Clear PortOverCurrent change
593 //
594 State |= PORTSC_OVERCUR_CHANGE;
595 EhcWriteOpReg (Ehc, Offset, State);
596 break;
597
598 case EfiUsbPortPower:
599 case EfiUsbPortSuspendChange:
600 case EfiUsbPortResetChange:
601 //
602 // Not supported or not related operation
603 //
604 break;
605
606 default:
607 Status = EFI_INVALID_PARAMETER;
608 break;
609 }
610
611 ON_EXIT:
612 DEBUG ((EFI_D_INFO, "EhcClearRootHubPortFeature: exit status %r\n", Status));
613 gBS->RestoreTPL (OldTpl);
614 return Status;
615 }
616
617
618 /**
619 Submits control transfer to a target USB device.
620
621 @param This This EFI_USB2_HC_PROTOCOL instance.
622 @param DeviceAddress The target device address.
623 @param DeviceSpeed Target device speed.
624 @param MaximumPacketLength Maximum packet size the default control transfer
625 endpoint is capable of sending or receiving.
626 @param Request USB device request to send.
627 @param TransferDirection Specifies the data direction for the data stage
628 @param Data Data buffer to be transmitted or received from USB
629 device.
630 @param DataLength The size (in bytes) of the data buffer.
631 @param TimeOut Indicates the maximum timeout, in millisecond.
632 @param Translator Transaction translator to be used by this device.
633 @param TransferResult Return the result of this control transfer.
634
635 @retval EFI_SUCCESS Transfer was completed successfully.
636 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resources.
637 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
638 @retval EFI_TIMEOUT Transfer failed due to timeout.
639 @retval EFI_DEVICE_ERROR Transfer failed due to host controller or device error.
640
641 **/
642 EFI_STATUS
643 EFIAPI
644 EhcControlTransfer (
645 IN EFI_USB2_HC_PROTOCOL *This,
646 IN UINT8 DeviceAddress,
647 IN UINT8 DeviceSpeed,
648 IN UINTN MaximumPacketLength,
649 IN EFI_USB_DEVICE_REQUEST *Request,
650 IN EFI_USB_DATA_DIRECTION TransferDirection,
651 IN OUT VOID *Data,
652 IN OUT UINTN *DataLength,
653 IN UINTN TimeOut,
654 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
655 OUT UINT32 *TransferResult
656 )
657 {
658 USB2_HC_DEV *Ehc;
659 URB *Urb;
660 EFI_TPL OldTpl;
661 UINT8 Endpoint;
662 EFI_STATUS Status;
663
664 //
665 // Validate parameters
666 //
667 if ((Request == NULL) || (TransferResult == NULL)) {
668 return EFI_INVALID_PARAMETER;
669 }
670
671 if ((TransferDirection != EfiUsbDataIn) &&
672 (TransferDirection != EfiUsbDataOut) &&
673 (TransferDirection != EfiUsbNoData)) {
674 return EFI_INVALID_PARAMETER;
675 }
676
677 if ((TransferDirection == EfiUsbNoData) &&
678 ((Data != NULL) || (*DataLength != 0))) {
679 return EFI_INVALID_PARAMETER;
680 }
681
682 if ((TransferDirection != EfiUsbNoData) &&
683 ((Data == NULL) || (*DataLength == 0))) {
684 return EFI_INVALID_PARAMETER;
685 }
686
687 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
688 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
689 return EFI_INVALID_PARAMETER;
690 }
691
692 if ((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) {
693 return EFI_INVALID_PARAMETER;
694 }
695
696 OldTpl = gBS->RaiseTPL (EHC_TPL);
697 Ehc = EHC_FROM_THIS (This);
698
699 Status = EFI_DEVICE_ERROR;
700 *TransferResult = EFI_USB_ERR_SYSTEM;
701
702 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
703 DEBUG ((EFI_D_ERROR, "EhcControlTransfer: HC halted at entrance\n"));
704
705 EhcAckAllInterrupt (Ehc);
706 goto ON_EXIT;
707 }
708
709 EhcAckAllInterrupt (Ehc);
710
711 //
712 // Create a new URB, insert it into the asynchronous
713 // schedule list, then poll the execution status.
714 //
715 //
716 // Encode the direction in address, although default control
717 // endpoint is bidirectional. EhcCreateUrb expects this
718 // combination of Ep addr and its direction.
719 //
720 Endpoint = (UINT8) (0 | ((TransferDirection == EfiUsbDataIn) ? 0x80 : 0));
721 Urb = EhcCreateUrb (
722 Ehc,
723 DeviceAddress,
724 Endpoint,
725 DeviceSpeed,
726 0,
727 MaximumPacketLength,
728 Translator,
729 EHC_CTRL_TRANSFER,
730 Request,
731 Data,
732 *DataLength,
733 NULL,
734 NULL,
735 1
736 );
737
738 if (Urb == NULL) {
739 DEBUG ((EFI_D_ERROR, "EhcControlTransfer: failed to create URB"));
740
741 Status = EFI_OUT_OF_RESOURCES;
742 goto ON_EXIT;
743 }
744
745 EhcLinkQhToAsync (Ehc, Urb->Qh);
746 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
747 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
748
749 //
750 // Get the status from URB. The result is updated in EhcCheckUrbResult
751 // which is called by EhcExecTransfer
752 //
753 *TransferResult = Urb->Result;
754 *DataLength = Urb->Completed;
755
756 if (*TransferResult == EFI_USB_NOERROR) {
757 Status = EFI_SUCCESS;
758 }
759
760 EhcAckAllInterrupt (Ehc);
761 EhcFreeUrb (Ehc, Urb);
762
763 ON_EXIT:
764 Ehc->PciIo->Flush (Ehc->PciIo);
765 gBS->RestoreTPL (OldTpl);
766
767 if (EFI_ERROR (Status)) {
768 DEBUG ((EFI_D_ERROR, "EhcControlTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
769 }
770
771 return Status;
772 }
773
774
775 /**
776 Submits bulk transfer to a bulk endpoint of a USB device.
777
778 @param This This EFI_USB2_HC_PROTOCOL instance.
779 @param DeviceAddress Target device address.
780 @param EndPointAddress Endpoint number and its direction in bit 7.
781 @param DeviceSpeed Device speed, Low speed device doesn't support bulk
782 transfer.
783 @param MaximumPacketLength Maximum packet size the endpoint is capable of
784 sending or receiving.
785 @param DataBuffersNumber Number of data buffers prepared for the transfer.
786 @param Data Array of pointers to the buffers of data to transmit
787 from or receive into.
788 @param DataLength The lenght of the data buffer.
789 @param DataToggle On input, the initial data toggle for the transfer;
790 On output, it is updated to to next data toggle to
791 use of the subsequent bulk transfer.
792 @param TimeOut Indicates the maximum time, in millisecond, which
793 the transfer is allowed to complete.
794 @param Translator A pointr to the transaction translator data.
795 @param TransferResult A pointer to the detailed result information of the
796 bulk transfer.
797
798 @retval EFI_SUCCESS The transfer was completed successfully.
799 @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
800 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
801 @retval EFI_TIMEOUT The transfer failed due to timeout.
802 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
803
804 **/
805 EFI_STATUS
806 EFIAPI
807 EhcBulkTransfer (
808 IN EFI_USB2_HC_PROTOCOL *This,
809 IN UINT8 DeviceAddress,
810 IN UINT8 EndPointAddress,
811 IN UINT8 DeviceSpeed,
812 IN UINTN MaximumPacketLength,
813 IN UINT8 DataBuffersNumber,
814 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
815 IN OUT UINTN *DataLength,
816 IN OUT UINT8 *DataToggle,
817 IN UINTN TimeOut,
818 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
819 OUT UINT32 *TransferResult
820 )
821 {
822 USB2_HC_DEV *Ehc;
823 URB *Urb;
824 EFI_TPL OldTpl;
825 EFI_STATUS Status;
826
827 //
828 // Validate the parameters
829 //
830 if ((DataLength == NULL) || (*DataLength == 0) ||
831 (Data == NULL) || (Data[0] == NULL) || (TransferResult == NULL)) {
832 return EFI_INVALID_PARAMETER;
833 }
834
835 if ((*DataToggle != 0) && (*DataToggle != 1)) {
836 return EFI_INVALID_PARAMETER;
837 }
838
839 if ((DeviceSpeed == EFI_USB_SPEED_LOW) ||
840 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
841 ((EFI_USB_SPEED_HIGH == DeviceSpeed) && (MaximumPacketLength > 512))) {
842 return EFI_INVALID_PARAMETER;
843 }
844
845 OldTpl = gBS->RaiseTPL (EHC_TPL);
846 Ehc = EHC_FROM_THIS (This);
847
848 *TransferResult = EFI_USB_ERR_SYSTEM;
849 Status = EFI_DEVICE_ERROR;
850
851 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
852 DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: HC is halted\n"));
853
854 EhcAckAllInterrupt (Ehc);
855 goto ON_EXIT;
856 }
857
858 EhcAckAllInterrupt (Ehc);
859
860 //
861 // Create a new URB, insert it into the asynchronous
862 // schedule list, then poll the execution status.
863 //
864 Urb = EhcCreateUrb (
865 Ehc,
866 DeviceAddress,
867 EndPointAddress,
868 DeviceSpeed,
869 *DataToggle,
870 MaximumPacketLength,
871 Translator,
872 EHC_BULK_TRANSFER,
873 NULL,
874 Data[0],
875 *DataLength,
876 NULL,
877 NULL,
878 1
879 );
880
881 if (Urb == NULL) {
882 DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: failed to create URB\n"));
883
884 Status = EFI_OUT_OF_RESOURCES;
885 goto ON_EXIT;
886 }
887
888 EhcLinkQhToAsync (Ehc, Urb->Qh);
889 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
890 EhcUnlinkQhFromAsync (Ehc, Urb->Qh);
891
892 *TransferResult = Urb->Result;
893 *DataLength = Urb->Completed;
894 *DataToggle = Urb->DataToggle;
895
896 if (*TransferResult == EFI_USB_NOERROR) {
897 Status = EFI_SUCCESS;
898 }
899
900 EhcAckAllInterrupt (Ehc);
901 EhcFreeUrb (Ehc, Urb);
902
903 ON_EXIT:
904 Ehc->PciIo->Flush (Ehc->PciIo);
905 gBS->RestoreTPL (OldTpl);
906
907 if (EFI_ERROR (Status)) {
908 DEBUG ((EFI_D_ERROR, "EhcBulkTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
909 }
910
911 return Status;
912 }
913
914
915 /**
916 Submits an asynchronous interrupt transfer to an
917 interrupt endpoint of a USB device.
918
919 @param This This EFI_USB2_HC_PROTOCOL instance.
920 @param DeviceAddress Target device address.
921 @param EndPointAddress Endpoint number and its direction encoded in bit 7
922 @param DeviceSpeed Indicates device speed.
923 @param MaximumPacketLength Maximum packet size the target endpoint is capable
924 @param IsNewTransfer If TRUE, to submit an new asynchronous interrupt
925 transfer If FALSE, to remove the specified
926 asynchronous interrupt.
927 @param DataToggle On input, the initial data toggle to use; on output,
928 it is updated to indicate the next data toggle.
929 @param PollingInterval The he interval, in milliseconds, that the transfer
930 is polled.
931 @param DataLength The length of data to receive at the rate specified
932 by PollingInterval.
933 @param Translator Transaction translator to use.
934 @param CallBackFunction Function to call at the rate specified by
935 PollingInterval.
936 @param Context Context to CallBackFunction.
937
938 @retval EFI_SUCCESS The request has been successfully submitted or canceled.
939 @retval EFI_INVALID_PARAMETER Some parameters are invalid.
940 @retval EFI_OUT_OF_RESOURCES The request failed due to a lack of resources.
941 @retval EFI_DEVICE_ERROR The transfer failed due to host controller error.
942
943 **/
944 EFI_STATUS
945 EFIAPI
946 EhcAsyncInterruptTransfer (
947 IN EFI_USB2_HC_PROTOCOL * This,
948 IN UINT8 DeviceAddress,
949 IN UINT8 EndPointAddress,
950 IN UINT8 DeviceSpeed,
951 IN UINTN MaximumPacketLength,
952 IN BOOLEAN IsNewTransfer,
953 IN OUT UINT8 *DataToggle,
954 IN UINTN PollingInterval,
955 IN UINTN DataLength,
956 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR * Translator,
957 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
958 IN VOID *Context OPTIONAL
959 )
960 {
961 USB2_HC_DEV *Ehc;
962 URB *Urb;
963 EFI_TPL OldTpl;
964 EFI_STATUS Status;
965 UINT8 *Data;
966
967 //
968 // Validate parameters
969 //
970 if (!EHCI_IS_DATAIN (EndPointAddress)) {
971 return EFI_INVALID_PARAMETER;
972 }
973
974 if (IsNewTransfer) {
975 if (DataLength == 0) {
976 return EFI_INVALID_PARAMETER;
977 }
978
979 if ((*DataToggle != 1) && (*DataToggle != 0)) {
980 return EFI_INVALID_PARAMETER;
981 }
982
983 if ((PollingInterval > 255) || (PollingInterval < 1)) {
984 return EFI_INVALID_PARAMETER;
985 }
986 }
987
988 OldTpl = gBS->RaiseTPL (EHC_TPL);
989 Ehc = EHC_FROM_THIS (This);
990
991 //
992 // Delete Async interrupt transfer request. DataToggle will return
993 // the next data toggle to use.
994 //
995 if (!IsNewTransfer) {
996 Status = EhciDelAsyncIntTransfer (Ehc, DeviceAddress, EndPointAddress, DataToggle);
997
998 DEBUG ((EFI_D_INFO, "EhcAsyncInterruptTransfer: remove old transfer - %r\n", Status));
999 goto ON_EXIT;
1000 }
1001
1002 Status = EFI_SUCCESS;
1003
1004 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1005 DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: HC is halt\n"));
1006 EhcAckAllInterrupt (Ehc);
1007
1008 Status = EFI_DEVICE_ERROR;
1009 goto ON_EXIT;
1010 }
1011
1012 EhcAckAllInterrupt (Ehc);
1013
1014 Data = AllocatePool (DataLength);
1015
1016 if (Data == NULL) {
1017 DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to allocate buffer\n"));
1018
1019 Status = EFI_OUT_OF_RESOURCES;
1020 goto ON_EXIT;
1021 }
1022
1023 Urb = EhcCreateUrb (
1024 Ehc,
1025 DeviceAddress,
1026 EndPointAddress,
1027 DeviceSpeed,
1028 *DataToggle,
1029 MaximumPacketLength,
1030 Translator,
1031 EHC_INT_TRANSFER_ASYNC,
1032 NULL,
1033 Data,
1034 DataLength,
1035 CallBackFunction,
1036 Context,
1037 PollingInterval
1038 );
1039
1040 if (Urb == NULL) {
1041 DEBUG ((EFI_D_ERROR, "EhcAsyncInterruptTransfer: failed to create URB\n"));
1042
1043 gBS->FreePool (Data);
1044 Status = EFI_OUT_OF_RESOURCES;
1045 goto ON_EXIT;
1046 }
1047
1048 //
1049 // New asynchronous transfer must inserted to the head.
1050 // Check the comments in EhcMoniteAsyncRequests
1051 //
1052 EhcLinkQhToPeriod (Ehc, Urb->Qh);
1053 InsertHeadList (&Ehc->AsyncIntTransfers, &Urb->UrbList);
1054
1055 ON_EXIT:
1056 Ehc->PciIo->Flush (Ehc->PciIo);
1057 gBS->RestoreTPL (OldTpl);
1058
1059 return Status;
1060 }
1061
1062
1063 /**
1064 Submits synchronous interrupt transfer to an interrupt endpoint
1065 of a USB device.
1066
1067 @param This This EFI_USB2_HC_PROTOCOL instance.
1068 @param DeviceAddress Target device address.
1069 @param EndPointAddress Endpoint number and its direction encoded in bit 7
1070 @param DeviceSpeed Indicates device speed.
1071 @param MaximumPacketLength Maximum packet size the target endpoint is capable
1072 of sending or receiving.
1073 @param Data Buffer of data that will be transmitted to USB
1074 device or received from USB device.
1075 @param DataLength On input, the size, in bytes, of the data buffer; On
1076 output, the number of bytes transferred.
1077 @param DataToggle On input, the initial data toggle to use; on output,
1078 it is updated to indicate the next data toggle.
1079 @param TimeOut Maximum time, in second, to complete.
1080 @param Translator Transaction translator to use.
1081 @param TransferResult Variable to receive the transfer result.
1082
1083 @return EFI_SUCCESS The transfer was completed successfully.
1084 @return EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource.
1085 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1086 @return EFI_TIMEOUT The transfer failed due to timeout.
1087 @return EFI_DEVICE_ERROR The failed due to host controller or device error
1088
1089 **/
1090 EFI_STATUS
1091 EFIAPI
1092 EhcSyncInterruptTransfer (
1093 IN EFI_USB2_HC_PROTOCOL *This,
1094 IN UINT8 DeviceAddress,
1095 IN UINT8 EndPointAddress,
1096 IN UINT8 DeviceSpeed,
1097 IN UINTN MaximumPacketLength,
1098 IN OUT VOID *Data,
1099 IN OUT UINTN *DataLength,
1100 IN OUT UINT8 *DataToggle,
1101 IN UINTN TimeOut,
1102 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1103 OUT UINT32 *TransferResult
1104 )
1105 {
1106 USB2_HC_DEV *Ehc;
1107 EFI_TPL OldTpl;
1108 URB *Urb;
1109 EFI_STATUS Status;
1110
1111 //
1112 // Validates parameters
1113 //
1114 if ((DataLength == NULL) || (*DataLength == 0) ||
1115 (Data == NULL) || (TransferResult == NULL)) {
1116 return EFI_INVALID_PARAMETER;
1117 }
1118
1119 if (!EHCI_IS_DATAIN (EndPointAddress)) {
1120 return EFI_INVALID_PARAMETER;
1121 }
1122
1123 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1124 return EFI_INVALID_PARAMETER;
1125 }
1126
1127 if (((DeviceSpeed == EFI_USB_SPEED_LOW) && (MaximumPacketLength != 8)) ||
1128 ((DeviceSpeed == EFI_USB_SPEED_FULL) && (MaximumPacketLength > 64)) ||
1129 ((DeviceSpeed == EFI_USB_SPEED_HIGH) && (MaximumPacketLength > 3072))) {
1130 return EFI_INVALID_PARAMETER;
1131 }
1132
1133 OldTpl = gBS->RaiseTPL (EHC_TPL);
1134 Ehc = EHC_FROM_THIS (This);
1135
1136 *TransferResult = EFI_USB_ERR_SYSTEM;
1137 Status = EFI_DEVICE_ERROR;
1138
1139 if (EhcIsHalt (Ehc) || EhcIsSysError (Ehc)) {
1140 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: HC is halt\n"));
1141
1142 EhcAckAllInterrupt (Ehc);
1143 goto ON_EXIT;
1144 }
1145
1146 EhcAckAllInterrupt (Ehc);
1147
1148 Urb = EhcCreateUrb (
1149 Ehc,
1150 DeviceAddress,
1151 EndPointAddress,
1152 DeviceSpeed,
1153 *DataToggle,
1154 MaximumPacketLength,
1155 Translator,
1156 EHC_INT_TRANSFER_SYNC,
1157 NULL,
1158 Data,
1159 *DataLength,
1160 NULL,
1161 NULL,
1162 1
1163 );
1164
1165 if (Urb == NULL) {
1166 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: failed to create URB\n"));
1167
1168 Status = EFI_OUT_OF_RESOURCES;
1169 goto ON_EXIT;
1170 }
1171
1172 EhcLinkQhToPeriod (Ehc, Urb->Qh);
1173 Status = EhcExecTransfer (Ehc, Urb, TimeOut);
1174 EhcUnlinkQhFromPeriod (Ehc, Urb->Qh);
1175
1176 *TransferResult = Urb->Result;
1177 *DataLength = Urb->Completed;
1178 *DataToggle = Urb->DataToggle;
1179
1180 if (*TransferResult == EFI_USB_NOERROR) {
1181 Status = EFI_SUCCESS;
1182 }
1183
1184 ON_EXIT:
1185 Ehc->PciIo->Flush (Ehc->PciIo);
1186 gBS->RestoreTPL (OldTpl);
1187
1188 if (EFI_ERROR (Status)) {
1189 DEBUG ((EFI_D_ERROR, "EhcSyncInterruptTransfer: error - %r, transfer - %x\n", Status, *TransferResult));
1190 }
1191
1192 return Status;
1193 }
1194
1195
1196 /**
1197 Submits isochronous transfer to a target USB device.
1198
1199 @param This This EFI_USB2_HC_PROTOCOL instance.
1200 @param DeviceAddress Target device address.
1201 @param EndPointAddress End point address with its direction.
1202 @param DeviceSpeed Device speed, Low speed device doesn't support this
1203 type.
1204 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1205 sending or receiving.
1206 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1207 @param Data Array of pointers to the buffers of data that will
1208 be transmitted to USB device or received from USB
1209 device.
1210 @param DataLength The size, in bytes, of the data buffer.
1211 @param Translator Transaction translator to use.
1212 @param TransferResult Variable to receive the transfer result.
1213
1214 @return EFI_UNSUPPORTED Isochronous transfer is unsupported.
1215
1216 **/
1217 EFI_STATUS
1218 EFIAPI
1219 EhcIsochronousTransfer (
1220 IN EFI_USB2_HC_PROTOCOL *This,
1221 IN UINT8 DeviceAddress,
1222 IN UINT8 EndPointAddress,
1223 IN UINT8 DeviceSpeed,
1224 IN UINTN MaximumPacketLength,
1225 IN UINT8 DataBuffersNumber,
1226 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1227 IN UINTN DataLength,
1228 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1229 OUT UINT32 *TransferResult
1230 )
1231 {
1232 return EFI_UNSUPPORTED;
1233 }
1234
1235
1236 /**
1237 Submits Async isochronous transfer to a target USB device.
1238
1239 @param This This EFI_USB2_HC_PROTOCOL instance.
1240 @param DeviceAddress Target device address.
1241 @param EndPointAddress End point address with its direction.
1242 @param DeviceSpeed Device speed, Low speed device doesn't support this
1243 type.
1244 @param MaximumPacketLength Maximum packet size that the endpoint is capable of
1245 sending or receiving.
1246 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1247 @param Data Array of pointers to the buffers of data that will
1248 be transmitted to USB device or received from USB
1249 device.
1250 @param DataLength The size, in bytes, of the data buffer.
1251 @param Translator Transaction translator to use.
1252 @param IsochronousCallBack Function to be called when the transfer complete.
1253 @param Context Context passed to the call back function as
1254 parameter.
1255
1256 @return EFI_UNSUPPORTED Isochronous transfer isn't supported.
1257
1258 **/
1259 EFI_STATUS
1260 EFIAPI
1261 EhcAsyncIsochronousTransfer (
1262 IN EFI_USB2_HC_PROTOCOL *This,
1263 IN UINT8 DeviceAddress,
1264 IN UINT8 EndPointAddress,
1265 IN UINT8 DeviceSpeed,
1266 IN UINTN MaximumPacketLength,
1267 IN UINT8 DataBuffersNumber,
1268 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1269 IN UINTN DataLength,
1270 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1271 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1272 IN VOID *Context
1273 )
1274 {
1275 return EFI_UNSUPPORTED;
1276 }
1277
1278 /**
1279 Entry point for EFI drivers.
1280
1281 @param ImageHandle EFI_HANDLE.
1282 @param SystemTable EFI_SYSTEM_TABLE.
1283
1284 @return EFI_SUCCESS Success.
1285 EFI_DEVICE_ERROR Fail.
1286
1287 **/
1288 EFI_STATUS
1289 EFIAPI
1290 EhcDriverEntryPoint (
1291 IN EFI_HANDLE ImageHandle,
1292 IN EFI_SYSTEM_TABLE *SystemTable
1293 )
1294 {
1295 return EfiLibInstallDriverBindingComponentName2 (
1296 ImageHandle,
1297 SystemTable,
1298 &gEhciDriverBinding,
1299 ImageHandle,
1300 &gEhciComponentName,
1301 &gEhciComponentName2
1302 );
1303 }
1304
1305
1306 /**
1307 Test to see if this driver supports ControllerHandle. Any
1308 ControllerHandle that has Usb2HcProtocol installed will
1309 be supported.
1310
1311 @param This Protocol instance pointer.
1312 @param Controller Handle of device to test.
1313 @param RemainingDevicePath Not used.
1314
1315 @return EFI_SUCCESS This driver supports this device.
1316 @return EFI_UNSUPPORTED This driver does not support this device.
1317
1318 **/
1319 EFI_STATUS
1320 EFIAPI
1321 EhcDriverBindingSupported (
1322 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1323 IN EFI_HANDLE Controller,
1324 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1325 )
1326 {
1327 EFI_STATUS Status;
1328 EFI_PCI_IO_PROTOCOL *PciIo;
1329 USB_CLASSC UsbClassCReg;
1330
1331 //
1332 // Test whether there is PCI IO Protocol attached on the controller handle.
1333 //
1334 Status = gBS->OpenProtocol (
1335 Controller,
1336 &gEfiPciIoProtocolGuid,
1337 (VOID **) &PciIo,
1338 This->DriverBindingHandle,
1339 Controller,
1340 EFI_OPEN_PROTOCOL_BY_DRIVER
1341 );
1342
1343 if (EFI_ERROR (Status)) {
1344 return EFI_UNSUPPORTED;
1345 }
1346
1347 Status = PciIo->Pci.Read (
1348 PciIo,
1349 EfiPciIoWidthUint8,
1350 EHC_PCI_CLASSC,
1351 sizeof (USB_CLASSC) / sizeof (UINT8),
1352 &UsbClassCReg
1353 );
1354
1355 if (EFI_ERROR (Status)) {
1356 Status = EFI_UNSUPPORTED;
1357 goto ON_EXIT;
1358 }
1359
1360 //
1361 // Test whether the controller belongs to Ehci type
1362 //
1363 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) || (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB)
1364 || ((UsbClassCReg.PI != EHC_PCI_CLASSC_PI) && (UsbClassCReg.PI !=PCI_CLASSC_PI_UHCI))) {
1365
1366 Status = EFI_UNSUPPORTED;
1367 }
1368
1369 ON_EXIT:
1370 gBS->CloseProtocol (
1371 Controller,
1372 &gEfiPciIoProtocolGuid,
1373 This->DriverBindingHandle,
1374 Controller
1375 );
1376
1377 return Status;
1378 }
1379
1380
1381 /**
1382 Create and initialize a USB2_HC_DEV.
1383
1384 @param PciIo The PciIo on this device.
1385 @param OriginalPciAttributes Original PCI attributes.
1386
1387 @return The allocated and initialized USB2_HC_DEV structure if created,
1388 otherwise NULL.
1389
1390 **/
1391 USB2_HC_DEV *
1392 EhcCreateUsb2Hc (
1393 IN EFI_PCI_IO_PROTOCOL *PciIo,
1394 IN UINT64 OriginalPciAttributes
1395 )
1396 {
1397 USB2_HC_DEV *Ehc;
1398 EFI_STATUS Status;
1399
1400 Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));
1401
1402 if (Ehc == NULL) {
1403 return NULL;
1404 }
1405
1406 //
1407 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1408 //
1409 Ehc->Signature = USB2_HC_DEV_SIGNATURE;
1410
1411 Ehc->Usb2Hc.GetCapability = EhcGetCapability;
1412 Ehc->Usb2Hc.Reset = EhcReset;
1413 Ehc->Usb2Hc.GetState = EhcGetState;
1414 Ehc->Usb2Hc.SetState = EhcSetState;
1415 Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;
1416 Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;
1417 Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;
1418 Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;
1419 Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;
1420 Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;
1421 Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1422 Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1423 Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1424 Ehc->Usb2Hc.MajorRevision = 0x2;
1425 Ehc->Usb2Hc.MinorRevision = 0x0;
1426
1427 Ehc->PciIo = PciIo;
1428 Ehc->OriginalPciAttributes = OriginalPciAttributes;
1429
1430 InitializeListHead (&Ehc->AsyncIntTransfers);
1431
1432 Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);
1433 Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);
1434 Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1435
1436 DEBUG ((EFI_D_INFO, "EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));
1437
1438 //
1439 // Create AsyncRequest Polling Timer
1440 //
1441 Status = gBS->CreateEvent (
1442 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1443 TPL_CALLBACK,
1444 EhcMonitorAsyncRequests,
1445 Ehc,
1446 &Ehc->PollTimer
1447 );
1448
1449 if (EFI_ERROR (Status)) {
1450 gBS->FreePool (Ehc);
1451 return NULL;
1452 }
1453
1454 return Ehc;
1455 }
1456
1457 /**
1458 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1459
1460 @param Event Pointer to this event
1461 @param Context Event hanlder private data
1462
1463 **/
1464 VOID
1465 EFIAPI
1466 EhcExitBootService (
1467 EFI_EVENT Event,
1468 VOID *Context
1469 )
1470
1471 {
1472 USB2_HC_DEV *Ehc;
1473
1474 Ehc = (USB2_HC_DEV *) Context;
1475
1476 //
1477 // Stop the Host Controller
1478 //
1479 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1480
1481 return;
1482 }
1483
1484
1485 /**
1486 Starting the Usb EHCI Driver.
1487
1488 @param This Protocol instance pointer.
1489 @param Controller Handle of device to test.
1490 @param RemainingDevicePath Not used.
1491
1492 @return EFI_SUCCESS supports this device.
1493 @return EFI_UNSUPPORTED do not support this device.
1494 @return EFI_DEVICE_ERROR cannot be started due to device Error.
1495 @return EFI_OUT_OF_RESOURCES cannot allocate resources.
1496
1497 **/
1498 EFI_STATUS
1499 EFIAPI
1500 EhcDriverBindingStart (
1501 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1502 IN EFI_HANDLE Controller,
1503 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1504 )
1505 {
1506 EFI_STATUS Status;
1507 USB2_HC_DEV *Ehc;
1508 EFI_PCI_IO_PROTOCOL *PciIo;
1509 EFI_PCI_IO_PROTOCOL *Instance;
1510 UINT64 Supports;
1511 UINT64 OriginalPciAttributes;
1512 BOOLEAN PciAttributesSaved;
1513 USB_CLASSC UsbClassCReg;
1514 EFI_HANDLE *HandleBuffer;
1515 UINTN NumberOfHandles;
1516 UINTN Index;
1517 UINTN UhciSegmentNumber;
1518 UINTN UhciBusNumber;
1519 UINTN UhciDeviceNumber;
1520 UINTN UhciFunctionNumber;
1521 UINTN EhciSegmentNumber;
1522 UINTN EhciBusNumber;
1523 UINTN EhciDeviceNumber;
1524 UINTN EhciFunctionNumber;
1525
1526 //
1527 // Open the PciIo Protocol, then enable the USB host controller
1528 //
1529 Status = gBS->OpenProtocol (
1530 Controller,
1531 &gEfiPciIoProtocolGuid,
1532 (VOID **) &PciIo,
1533 This->DriverBindingHandle,
1534 Controller,
1535 EFI_OPEN_PROTOCOL_BY_DRIVER
1536 );
1537
1538 if (EFI_ERROR (Status)) {
1539 return Status;
1540 }
1541
1542 PciAttributesSaved = FALSE;
1543 //
1544 // Save original PCI attributes
1545 //
1546 Status = PciIo->Attributes (
1547 PciIo,
1548 EfiPciIoAttributeOperationGet,
1549 0,
1550 &OriginalPciAttributes
1551 );
1552
1553 if (EFI_ERROR (Status)) {
1554 goto CLOSE_PCIIO;
1555 }
1556 PciAttributesSaved = TRUE;
1557
1558 Status = PciIo->Attributes (
1559 PciIo,
1560 EfiPciIoAttributeOperationSupported,
1561 0,
1562 &Supports
1563 );
1564 if (!EFI_ERROR (Status)) {
1565 Supports &= EFI_PCI_DEVICE_ENABLE;
1566 Status = PciIo->Attributes (
1567 PciIo,
1568 EfiPciIoAttributeOperationEnable,
1569 Supports,
1570 NULL
1571 );
1572 }
1573
1574 if (EFI_ERROR (Status)) {
1575 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to enable controller\n"));
1576 goto CLOSE_PCIIO;
1577 }
1578
1579 Status = PciIo->Pci.Read (
1580 PciIo,
1581 EfiPciIoWidthUint8,
1582 EHC_PCI_CLASSC,
1583 sizeof (USB_CLASSC) / sizeof (UINT8),
1584 &UsbClassCReg
1585 );
1586
1587 if (EFI_ERROR (Status)) {
1588 Status = EFI_UNSUPPORTED;
1589 goto CLOSE_PCIIO;
1590 }
1591
1592 if ((UsbClassCReg.PI == PCI_CLASSC_PI_UHCI) &&
1593 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
1594 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {
1595 Status = PciIo->GetLocation (
1596 PciIo,
1597 &UhciSegmentNumber,
1598 &UhciBusNumber,
1599 &UhciDeviceNumber,
1600 &UhciFunctionNumber
1601 );
1602 if (EFI_ERROR (Status)) {
1603 goto CLOSE_PCIIO;
1604 }
1605
1606 Status = gBS->LocateHandleBuffer (
1607 ByProtocol,
1608 &gEfiPciIoProtocolGuid,
1609 NULL,
1610 &NumberOfHandles,
1611 &HandleBuffer
1612 );
1613 if (EFI_ERROR (Status)) {
1614 goto CLOSE_PCIIO;
1615 }
1616
1617 for (Index = 0; Index < NumberOfHandles; Index++) {
1618 //
1619 // Get the device path on this handle
1620 //
1621 Status = gBS->HandleProtocol (
1622 HandleBuffer[Index],
1623 &gEfiPciIoProtocolGuid,
1624 (VOID **)&Instance
1625 );
1626 ASSERT_EFI_ERROR (Status);
1627
1628 Status = Instance->Pci.Read (
1629 Instance,
1630 EfiPciIoWidthUint8,
1631 EHC_PCI_CLASSC,
1632 sizeof (USB_CLASSC) / sizeof (UINT8),
1633 &UsbClassCReg
1634 );
1635
1636 if (EFI_ERROR (Status)) {
1637 Status = EFI_UNSUPPORTED;
1638 goto CLOSE_PCIIO;
1639 }
1640
1641 if ((UsbClassCReg.PI == PCI_CLASSC_PI_EHCI) &&
1642 (UsbClassCReg.BaseCode == PCI_CLASS_SERIAL) &&
1643 (UsbClassCReg.SubClassCode == PCI_CLASS_SERIAL_USB)) {
1644 Status = Instance->GetLocation (
1645 Instance,
1646 &EhciSegmentNumber,
1647 &EhciBusNumber,
1648 &EhciDeviceNumber,
1649 &EhciFunctionNumber
1650 );
1651 if (EFI_ERROR (Status)) {
1652 goto CLOSE_PCIIO;
1653 }
1654 if (EhciBusNumber == UhciBusNumber) {
1655 gBS->CloseProtocol (
1656 Controller,
1657 &gEfiPciIoProtocolGuid,
1658 This->DriverBindingHandle,
1659 Controller
1660 );
1661 EhcDriverBindingStart(This, HandleBuffer[Index], NULL);
1662 }
1663 }
1664 }
1665 Status = EFI_NOT_FOUND;
1666 goto CLOSE_PCIIO;
1667 }
1668
1669 //
1670 // Create then install USB2_HC_PROTOCOL
1671 //
1672 Ehc = EhcCreateUsb2Hc (PciIo, OriginalPciAttributes);
1673
1674 if (Ehc == NULL) {
1675 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to create USB2_HC\n"));
1676
1677 Status = EFI_OUT_OF_RESOURCES;
1678 goto CLOSE_PCIIO;
1679 }
1680
1681 Status = gBS->InstallProtocolInterface (
1682 &Controller,
1683 &gEfiUsb2HcProtocolGuid,
1684 EFI_NATIVE_INTERFACE,
1685 &Ehc->Usb2Hc
1686 );
1687
1688 if (EFI_ERROR (Status)) {
1689 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1690 goto FREE_POOL;
1691 }
1692
1693 //
1694 // Robustnesss improvement such as for UoL
1695 // Default is not required.
1696 //
1697 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1698 EhcClearLegacySupport (Ehc);
1699 }
1700 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
1701
1702 Status = EhcInitHC (Ehc);
1703
1704 if (EFI_ERROR (Status)) {
1705 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to init host controller\n"));
1706 goto UNINSTALL_USBHC;
1707 }
1708
1709 //
1710 // Start the asynchronous interrupt monitor
1711 //
1712 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);
1713
1714 if (EFI_ERROR (Status)) {
1715 DEBUG ((EFI_D_ERROR, "EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1716
1717 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1718 goto UNINSTALL_USBHC;
1719 }
1720
1721 //
1722 // Create event to stop the HC when exit boot service.
1723 //
1724 Status = gBS->CreateEventEx (
1725 EVT_NOTIFY_SIGNAL,
1726 TPL_NOTIFY,
1727 EhcExitBootService,
1728 Ehc,
1729 &gEfiEventExitBootServicesGuid,
1730 &Ehc->ExitBootServiceEvent
1731 );
1732 if (EFI_ERROR (Status)) {
1733 goto UNINSTALL_USBHC;
1734 }
1735
1736 //
1737 // Install the component name protocol, don't fail the start
1738 // because of something for display.
1739 //
1740 AddUnicodeString2 (
1741 "eng",
1742 gEhciComponentName.SupportedLanguages,
1743 &Ehc->ControllerNameTable,
1744 L"Enhanced Host Controller (USB 2.0)",
1745 TRUE
1746 );
1747 AddUnicodeString2 (
1748 "en",
1749 gEhciComponentName2.SupportedLanguages,
1750 &Ehc->ControllerNameTable,
1751 L"Enhanced Host Controller (USB 2.0)",
1752 FALSE
1753 );
1754
1755
1756 DEBUG ((EFI_D_INFO, "EhcDriverBindingStart: EHCI started for controller @ %p\n", Controller));
1757 return EFI_SUCCESS;
1758
1759 UNINSTALL_USBHC:
1760 gBS->UninstallProtocolInterface (
1761 Controller,
1762 &gEfiUsb2HcProtocolGuid,
1763 &Ehc->Usb2Hc
1764 );
1765
1766 FREE_POOL:
1767 EhcFreeSched (Ehc);
1768 gBS->CloseEvent (Ehc->PollTimer);
1769 gBS->FreePool (Ehc);
1770
1771 CLOSE_PCIIO:
1772 if (PciAttributesSaved) {
1773 //
1774 // Restore original PCI attributes
1775 //
1776 PciIo->Attributes (
1777 PciIo,
1778 EfiPciIoAttributeOperationSet,
1779 OriginalPciAttributes,
1780 NULL
1781 );
1782 }
1783
1784 gBS->CloseProtocol (
1785 Controller,
1786 &gEfiPciIoProtocolGuid,
1787 This->DriverBindingHandle,
1788 Controller
1789 );
1790
1791 return Status;
1792 }
1793
1794
1795 /**
1796 Stop this driver on ControllerHandle. Support stoping any child handles
1797 created by this driver.
1798
1799 @param This Protocol instance pointer.
1800 @param Controller Handle of device to stop driver on.
1801 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1802 @param ChildHandleBuffer List of handles for the children we need to stop.
1803
1804 @return EFI_SUCCESS Success.
1805 @return EFI_DEVICE_ERROR Fail.
1806
1807 **/
1808 EFI_STATUS
1809 EFIAPI
1810 EhcDriverBindingStop (
1811 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1812 IN EFI_HANDLE Controller,
1813 IN UINTN NumberOfChildren,
1814 IN EFI_HANDLE *ChildHandleBuffer
1815 )
1816 {
1817 EFI_STATUS Status;
1818 EFI_USB2_HC_PROTOCOL *Usb2Hc;
1819 EFI_PCI_IO_PROTOCOL *PciIo;
1820 USB2_HC_DEV *Ehc;
1821
1822 //
1823 // Test whether the Controller handler passed in is a valid
1824 // Usb controller handle that should be supported, if not,
1825 // return the error status directly
1826 //
1827 Status = gBS->OpenProtocol (
1828 Controller,
1829 &gEfiUsb2HcProtocolGuid,
1830 (VOID **) &Usb2Hc,
1831 This->DriverBindingHandle,
1832 Controller,
1833 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1834 );
1835
1836 if (EFI_ERROR (Status)) {
1837 return Status;
1838 }
1839
1840 Ehc = EHC_FROM_THIS (Usb2Hc);
1841 PciIo = Ehc->PciIo;
1842
1843 //
1844 // Stop AsyncRequest Polling timer then stop the EHCI driver
1845 // and uninstall the EHCI protocl.
1846 //
1847 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);
1848 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1849
1850 Status = gBS->UninstallProtocolInterface (
1851 Controller,
1852 &gEfiUsb2HcProtocolGuid,
1853 Usb2Hc
1854 );
1855
1856 if (EFI_ERROR (Status)) {
1857 return Status;
1858 }
1859
1860 if (Ehc->PollTimer != NULL) {
1861 gBS->CloseEvent (Ehc->PollTimer);
1862 }
1863
1864 if (Ehc->ExitBootServiceEvent != NULL) {
1865 gBS->CloseEvent (Ehc->ExitBootServiceEvent);
1866 }
1867
1868 EhcFreeSched (Ehc);
1869
1870 if (Ehc->ControllerNameTable != NULL) {
1871 FreeUnicodeStringTable (Ehc->ControllerNameTable);
1872 }
1873
1874 //
1875 // Restore original PCI attributes
1876 //
1877 PciIo->Attributes (
1878 PciIo,
1879 EfiPciIoAttributeOperationSet,
1880 Ehc->OriginalPciAttributes,
1881 NULL
1882 );
1883
1884 gBS->CloseProtocol (
1885 Controller,
1886 &gEfiPciIoProtocolGuid,
1887 This->DriverBindingHandle,
1888 Controller
1889 );
1890
1891 FreePool (Ehc);
1892
1893 return EFI_SUCCESS;
1894 }
1895