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