]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/EhciDxe/Ehci.c
07a690edce0788237587137a6e9853cdbd29c3b6
[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 EHC_DEBUG (("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 EHC_DEBUG (("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 EHC_DEBUG (("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 EHC_DEBUG (("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 EHC_DEBUG (("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 EHC_DEBUG (("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 EHC_DEBUG (("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 EHC_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 EHC_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 EHC_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 EHC_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 EHC_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 EHC_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 EHC_DEBUG (("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 EHC_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 EHC_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 EHC_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 EHC_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 EHC_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 EHC_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
1400 @return The allocated and initialized USB2_HC_DEV structure
1401 @return if created, otherwise NULL.
1402
1403 **/
1404 STATIC
1405 USB2_HC_DEV *
1406 EhcCreateUsb2Hc (
1407 IN EFI_PCI_IO_PROTOCOL *PciIo
1408 )
1409 {
1410 USB2_HC_DEV *Ehc;
1411 EFI_STATUS Status;
1412
1413 Ehc = AllocateZeroPool (sizeof (USB2_HC_DEV));
1414
1415 if (Ehc == NULL) {
1416 return NULL;
1417 }
1418
1419 //
1420 // Init EFI_USB2_HC_PROTOCOL interface and private data structure
1421 //
1422 Ehc->Signature = USB2_HC_DEV_SIGNATURE;
1423
1424 Ehc->Usb2Hc.GetCapability = EhcGetCapability;
1425 Ehc->Usb2Hc.Reset = EhcReset;
1426 Ehc->Usb2Hc.GetState = EhcGetState;
1427 Ehc->Usb2Hc.SetState = EhcSetState;
1428 Ehc->Usb2Hc.ControlTransfer = EhcControlTransfer;
1429 Ehc->Usb2Hc.BulkTransfer = EhcBulkTransfer;
1430 Ehc->Usb2Hc.AsyncInterruptTransfer = EhcAsyncInterruptTransfer;
1431 Ehc->Usb2Hc.SyncInterruptTransfer = EhcSyncInterruptTransfer;
1432 Ehc->Usb2Hc.IsochronousTransfer = EhcIsochronousTransfer;
1433 Ehc->Usb2Hc.AsyncIsochronousTransfer = EhcAsyncIsochronousTransfer;
1434 Ehc->Usb2Hc.GetRootHubPortStatus = EhcGetRootHubPortStatus;
1435 Ehc->Usb2Hc.SetRootHubPortFeature = EhcSetRootHubPortFeature;
1436 Ehc->Usb2Hc.ClearRootHubPortFeature = EhcClearRootHubPortFeature;
1437 Ehc->Usb2Hc.MajorRevision = 0x1;
1438 Ehc->Usb2Hc.MinorRevision = 0x1;
1439
1440 Ehc->PciIo = PciIo;
1441
1442 InitializeListHead (&Ehc->AsyncIntTransfers);
1443
1444 Ehc->HcStructParams = EhcReadCapRegister (Ehc, EHC_HCSPARAMS_OFFSET);
1445 Ehc->HcCapParams = EhcReadCapRegister (Ehc, EHC_HCCPARAMS_OFFSET);
1446 Ehc->CapLen = EhcReadCapRegister (Ehc, EHC_CAPLENGTH_OFFSET) & 0x0FF;
1447
1448 EHC_DEBUG (("EhcCreateUsb2Hc: capability length %d\n", Ehc->CapLen));
1449
1450 //
1451 // Create AsyncRequest Polling Timer
1452 //
1453 Status = gBS->CreateEvent (
1454 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1455 TPL_CALLBACK,
1456 EhcMoniteAsyncRequests,
1457 Ehc,
1458 &Ehc->PollTimer
1459 );
1460
1461 if (EFI_ERROR (Status)) {
1462 gBS->FreePool (Ehc);
1463 return NULL;
1464 }
1465
1466 return Ehc;
1467 }
1468
1469
1470 /**
1471 Starting the Usb EHCI Driver
1472
1473 @param This Protocol instance pointer.
1474 @param Controller Handle of device to test
1475 @param RemainingDevicePath Not used
1476
1477 @return EFI_SUCCESS : supports this device.
1478 @return EFI_UNSUPPORTED : do not support this device.
1479 @return EFI_DEVICE_ERROR : cannot be started due to device Error
1480 @return EFI_OUT_OF_RESOURCES : cannot allocate resources
1481
1482 **/
1483 EFI_STATUS
1484 EFIAPI
1485 EhcDriverBindingStart (
1486 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1487 IN EFI_HANDLE Controller,
1488 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1489 )
1490 {
1491 EFI_STATUS Status;
1492 USB2_HC_DEV *Ehc;
1493 EFI_PCI_IO_PROTOCOL *PciIo;
1494
1495 //
1496 // Open the PciIo Protocol, then enable the USB host controller
1497 //
1498 Status = gBS->OpenProtocol (
1499 Controller,
1500 &gEfiPciIoProtocolGuid,
1501 (VOID **) &PciIo,
1502 This->DriverBindingHandle,
1503 Controller,
1504 EFI_OPEN_PROTOCOL_BY_DRIVER
1505 );
1506
1507 if (EFI_ERROR (Status)) {
1508 EHC_ERROR (("EhcDriverBindingStart: failed to open PCI_IO\n"));
1509 return EFI_DEVICE_ERROR;
1510 }
1511
1512 Status = PciIo->Attributes (
1513 PciIo,
1514 EfiPciIoAttributeOperationEnable,
1515 EFI_PCI_DEVICE_ENABLE,
1516 NULL
1517 );
1518
1519 if (EFI_ERROR (Status)) {
1520 EHC_ERROR (("EhcDriverBindingStart: failed to enable controller\n"));
1521 goto CLOSE_PCIIO;
1522 }
1523
1524 //
1525 // Create then install USB2_HC_PROTOCOL
1526 //
1527 Ehc = EhcCreateUsb2Hc (PciIo);
1528
1529 if (Ehc == NULL) {
1530 EHC_ERROR (("EhcDriverBindingStart: failed to create USB2_HC\n"));
1531
1532 Status = EFI_OUT_OF_RESOURCES;
1533 goto CLOSE_PCIIO;
1534 }
1535
1536 Status = gBS->InstallProtocolInterface (
1537 &Controller,
1538 &gEfiUsb2HcProtocolGuid,
1539 EFI_NATIVE_INTERFACE,
1540 &Ehc->Usb2Hc
1541 );
1542
1543 if (EFI_ERROR (Status)) {
1544 EHC_ERROR (("EhcDriverBindingStart: failed to install USB2_HC Protocol\n"));
1545 goto FREE_POOL;
1546 }
1547
1548 //
1549 // Robustnesss improvement such as for UoL
1550 //
1551 EhcClearLegacySupport (Ehc);
1552 EhcResetHC (Ehc, EHC_RESET_TIMEOUT);
1553
1554 Status = EhcInitHC (Ehc);
1555
1556 if (EFI_ERROR (Status)) {
1557 EHC_ERROR (("EhcDriverBindingStart: failed to init host controller\n"));
1558 goto UNINSTALL_USBHC;
1559 }
1560
1561 //
1562 // Start the asynchronous interrupt monitor
1563 //
1564 Status = gBS->SetTimer (Ehc->PollTimer, TimerPeriodic, EHC_ASYNC_POLL_INTERVAL);
1565
1566 if (EFI_ERROR (Status)) {
1567 EHC_ERROR (("EhcDriverBindingStart: failed to start async interrupt monitor\n"));
1568
1569 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1570 goto UNINSTALL_USBHC;
1571 }
1572
1573 //
1574 // Install the component name protocol, don't fail the start
1575 // because of something for display.
1576 //
1577 AddUnicodeString2 (
1578 "eng",
1579 gEhciComponentName.SupportedLanguages,
1580 &Ehc->ControllerNameTable,
1581 L"Enhanced Host Controller (USB 2.0)",
1582 TRUE
1583 );
1584 AddUnicodeString2 (
1585 "en",
1586 gEhciComponentName2.SupportedLanguages,
1587 &Ehc->ControllerNameTable,
1588 L"Enhanced Host Controller (USB 2.0)",
1589 FALSE
1590 );
1591
1592
1593 EHC_DEBUG (("EhcDriverBindingStart: EHCI started for controller @ %x\n", Controller));
1594 return EFI_SUCCESS;
1595
1596 UNINSTALL_USBHC:
1597 gBS->UninstallProtocolInterface (
1598 Controller,
1599 &gEfiUsb2HcProtocolGuid,
1600 &Ehc->Usb2Hc
1601 );
1602
1603 FREE_POOL:
1604 EhcFreeSched (Ehc);
1605 gBS->CloseEvent (Ehc->PollTimer);
1606 gBS->FreePool (Ehc);
1607
1608 CLOSE_PCIIO:
1609 gBS->CloseProtocol (
1610 Controller,
1611 &gEfiPciIoProtocolGuid,
1612 This->DriverBindingHandle,
1613 Controller
1614 );
1615
1616 return Status;
1617 }
1618
1619
1620 /**
1621 Stop this driver on ControllerHandle. Support stoping any child handles
1622 created by this driver.
1623
1624 @param This Protocol instance pointer.
1625 @param Controller Handle of device to stop driver on
1626 @param NumberOfChildren Number of Children in the ChildHandleBuffer
1627 @param ChildHandleBuffer List of handles for the children we need to stop.
1628
1629 @return EFI_SUCCESS Success
1630 @return EFI_DEVICE_ERROR Fail
1631
1632 **/
1633 EFI_STATUS
1634 EFIAPI
1635 EhcDriverBindingStop (
1636 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1637 IN EFI_HANDLE Controller,
1638 IN UINTN NumberOfChildren,
1639 IN EFI_HANDLE *ChildHandleBuffer
1640 )
1641 {
1642 EFI_STATUS Status;
1643 EFI_USB2_HC_PROTOCOL *Usb2Hc;
1644 EFI_PCI_IO_PROTOCOL *PciIo;
1645 USB2_HC_DEV *Ehc;
1646
1647 //
1648 // Test whether the Controller handler passed in is a valid
1649 // Usb controller handle that should be supported, if not,
1650 // return the error status directly
1651 //
1652 Status = gBS->OpenProtocol (
1653 Controller,
1654 &gEfiUsb2HcProtocolGuid,
1655 (VOID **) &Usb2Hc,
1656 This->DriverBindingHandle,
1657 Controller,
1658 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1659 );
1660
1661 if (EFI_ERROR (Status)) {
1662 return Status;
1663 }
1664
1665 Ehc = EHC_FROM_THIS (Usb2Hc);
1666 PciIo = Ehc->PciIo;
1667
1668 //
1669 // Stop AsyncRequest Polling timer then stop the EHCI driver
1670 // and uninstall the EHCI protocl.
1671 //
1672 gBS->SetTimer (Ehc->PollTimer, TimerCancel, EHC_ASYNC_POLL_INTERVAL);
1673 EhcHaltHC (Ehc, EHC_GENERIC_TIMEOUT);
1674
1675 Status = gBS->UninstallProtocolInterface (
1676 Controller,
1677 &gEfiUsb2HcProtocolGuid,
1678 Usb2Hc
1679 );
1680
1681 if (EFI_ERROR (Status)) {
1682 return Status;
1683 }
1684
1685 if (Ehc->PollTimer != NULL) {
1686 gBS->CloseEvent (Ehc->PollTimer);
1687 }
1688
1689 EhcFreeSched (Ehc);
1690
1691 if (Ehc->ControllerNameTable) {
1692 FreeUnicodeStringTable (Ehc->ControllerNameTable);
1693 }
1694
1695 //
1696 // Disable the USB Host Controller
1697 //
1698 PciIo->Attributes (
1699 PciIo,
1700 EfiPciIoAttributeOperationDisable,
1701 EFI_PCI_DEVICE_ENABLE,
1702 NULL
1703 );
1704
1705 gBS->CloseProtocol (
1706 Controller,
1707 &gEfiPciIoProtocolGuid,
1708 This->DriverBindingHandle,
1709 Controller
1710 );
1711
1712 gBS->FreePool (Ehc);
1713 return Status;
1714 }
1715
1716 EFI_DRIVER_BINDING_PROTOCOL
1717 gEhciDriverBinding = {
1718 EhcDriverBindingSupported,
1719 EhcDriverBindingStart,
1720 EhcDriverBindingStop,
1721 0x10,
1722 NULL,
1723 NULL
1724 };