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