]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
1dee9765041119288536ab6cf77026c02386bdea
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / Uhci.c
1 /** @file
2
3 Copyright (c) 2004 - 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 Uhci.c
15
16 Abstract:
17
18 The UHCI driver model and HC protocol routines.
19
20 Revision History
21
22
23 **/
24
25 #include "Uhci.h"
26
27
28 /**
29 Provides software reset for the USB host controller.
30
31 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
32 Attributes: A bit mask of the reset operation to perform.
33
34 @return EFI_SUCCESS : The reset operation succeeded.
35 @return EFI_INVALID_PARAMETER : Attributes is not valid.
36 @return EFI_DEVICE_ERROR : An error was encountered while attempting
37 @return to perform the reset operation.
38
39 **/
40 STATIC
41 EFI_STATUS
42 EFIAPI
43 UhciReset (
44 IN EFI_USB_HC_PROTOCOL *This,
45 IN UINT16 Attributes
46 )
47 {
48 USB_HC_DEV *Uhc;
49 EFI_TPL OldTpl;
50
51 OldTpl = gBS->RaiseTPL (UHCI_TPL);
52 Uhc = UHC_FROM_USB_HC_PROTO (This);
53
54 switch (Attributes) {
55 case EFI_USB_HC_RESET_GLOBAL:
56 //
57 // Stop schedule and set the Global Reset bit in the command register
58 //
59 UhciStopHc (Uhc, STALL_1_SECOND);
60 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
61
62 //
63 // Wait 50ms for root port to let reset complete
64 // See UHCI spec page122 Reset signaling
65 //
66 gBS->Stall (ROOT_PORT_REST_TIME);
67
68 //
69 // Clear the Global Reset bit to zero.
70 //
71 UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
72
73 //
74 // UHCI spec page120 reset recovery time
75 //
76 gBS->Stall (PORT_RESET_RECOVERY_TIME);
77 break;
78
79 case EFI_USB_HC_RESET_HOST_CONTROLLER:
80 //
81 // Stop schedule and set Host Controller Reset bit to 1
82 //
83 UhciStopHc (Uhc, STALL_1_SECOND);
84 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
85
86 //
87 // this bit will be reset by Host Controller when reset is completed.
88 // wait 10ms to let reset complete
89 //
90 gBS->Stall (PORT_RESET_RECOVERY_TIME);
91 break;
92
93 default:
94 goto ON_INVAILD_PARAMETER;
95 }
96
97 //
98 // Delete all old transactions on the USB bus, then
99 // reinitialize the frame list
100 //
101 UhciFreeAllAsyncReq (Uhc);
102 UhciDestoryFrameList (Uhc);
103 UhciInitFrameList (Uhc);
104
105 gBS->RestoreTPL (OldTpl);
106
107 return EFI_SUCCESS;
108
109 ON_INVAILD_PARAMETER:
110
111 gBS->RestoreTPL (OldTpl);
112
113 return EFI_INVALID_PARAMETER;
114 }
115
116
117 /**
118 Retrieves current state of the USB host controller.
119
120 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
121 State : A pointer to the EFI_USB_HC_STATE data structure that
122 indicates current state of the USB host controller.
123
124 @return EFI_SUCCESS : State was returned
125 @return EFI_INVALID_PARAMETER : State is NULL.
126 @return EFI_DEVICE_ERROR : An error was encountered
127
128 **/
129 STATIC
130 EFI_STATUS
131 EFIAPI
132 UhciGetState (
133 IN EFI_USB_HC_PROTOCOL *This,
134 OUT EFI_USB_HC_STATE *State
135 )
136 {
137 USB_HC_DEV *Uhc;
138 UINT16 UsbSts;
139 UINT16 UsbCmd;
140
141 if (State == NULL) {
142 return EFI_INVALID_PARAMETER;
143 }
144
145 Uhc = UHC_FROM_USB_HC_PROTO (This);
146
147 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
148 UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
149
150 if (UsbCmd & USBCMD_EGSM) {
151 *State = EfiUsbHcStateSuspend;
152
153 } else if ((UsbSts & USBSTS_HCH) != 0) {
154 *State = EfiUsbHcStateHalt;
155
156 } else {
157 *State = EfiUsbHcStateOperational;
158 }
159
160 return EFI_SUCCESS;
161 }
162
163
164 /**
165 Sets the USB host controller to a specific state.
166
167 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
168 State : Indicates the state of the host controller that will be set.
169
170 @return EFI_SUCCESS : The USB host controller was successfully set
171 @return EFI_INVALID_PARAMETER : State is invalid.
172 @return EFI_DEVICE_ERROR : Failed to set the state specified
173
174 **/
175 STATIC
176 EFI_STATUS
177 EFIAPI
178 UhciSetState (
179 IN EFI_USB_HC_PROTOCOL *This,
180 IN EFI_USB_HC_STATE State
181 )
182 {
183 EFI_USB_HC_STATE CurState;
184 USB_HC_DEV *Uhc;
185 EFI_TPL OldTpl;
186 EFI_STATUS Status;
187 UINT16 UsbCmd;
188
189 Uhc = UHC_FROM_USB_HC_PROTO (This);
190 Status = UhciGetState (This, &CurState);
191
192 if (EFI_ERROR (Status)) {
193 return EFI_DEVICE_ERROR;
194 }
195
196 if (CurState == State) {
197 return EFI_SUCCESS;
198 }
199
200 Status = EFI_SUCCESS;
201 OldTpl = gBS->RaiseTPL (UHCI_TPL);
202
203 switch (State) {
204 case EfiUsbHcStateHalt:
205 Status = UhciStopHc (Uhc, STALL_1_SECOND);
206 break;
207
208 case EfiUsbHcStateOperational:
209 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
210
211 if (CurState == EfiUsbHcStateHalt) {
212 //
213 // Set Run/Stop bit to 1, also set the bandwidht reclamation
214 // point to 64 bytes
215 //
216 UsbCmd |= USBCMD_RS | USBCMD_MAXP;
217 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
218
219 } else if (CurState == EfiUsbHcStateSuspend) {
220 //
221 // If FGR(Force Global Resume) bit is 0, set it
222 //
223 if ((UsbCmd & USBCMD_FGR) == 0) {
224 UsbCmd |= USBCMD_FGR;
225 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
226 }
227
228 //
229 // wait 20ms to let resume complete (20ms is specified by UHCI spec)
230 //
231 gBS->Stall (FORCE_GLOBAL_RESUME_TIME);
232
233 //
234 // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
235 //
236 UsbCmd &= ~USBCMD_FGR;
237 UsbCmd &= ~USBCMD_EGSM;
238 UsbCmd |= USBCMD_RS;
239 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
240 }
241
242 break;
243
244 case EfiUsbHcStateSuspend:
245 Status = UhciSetState (This, EfiUsbHcStateHalt);
246
247 if (EFI_ERROR (Status)) {
248 Status = EFI_DEVICE_ERROR;
249 goto ON_EXIT;
250 }
251
252 //
253 // Set Enter Global Suspend Mode bit to 1.
254 //
255 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
256 UsbCmd |= USBCMD_EGSM;
257 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
258 break;
259
260 default:
261 Status = EFI_INVALID_PARAMETER;
262 break;
263 }
264
265 ON_EXIT:
266 gBS->RestoreTPL (OldTpl);
267 return Status;
268 }
269
270
271 /**
272 Retrieves the number of root hub ports.
273
274 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
275 PortNumber : A pointer to the number of the root hub ports.
276
277 @return EFI_SUCCESS : The port number was retrieved successfully.
278 @return EFI_INVALID_PARAMETER : PortNumber is NULL.
279 @return EFI_DEVICE_ERROR : An error was encountered
280
281 **/
282 STATIC
283 EFI_STATUS
284 EFIAPI
285 UhciGetRootHubPortNumber (
286 IN EFI_USB_HC_PROTOCOL *This,
287 OUT UINT8 *PortNumber
288 )
289 {
290 USB_HC_DEV *Uhc;
291 UINT32 Offset;
292 UINT16 PortSC;
293 UINT32 Index;
294
295 Uhc = UHC_FROM_USB_HC_PROTO (This);
296
297 if (PortNumber == NULL) {
298 return EFI_INVALID_PARAMETER;
299 }
300
301 *PortNumber = 0;
302
303 for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {
304 Offset = USBPORTSC_OFFSET + Index * 2;
305 PortSC = UhciReadReg (Uhc->PciIo, Offset);
306
307 //
308 // Port status's bit 7 is reserved and always returns 1 if
309 // the port number is valid. Intel's UHCI (in EHCI controller)
310 // returns 0 in this bit if port number is invalid. Also, if
311 // PciIo IoRead returns error, 0xFFFF is returned to caller.
312 //
313 if (((PortSC & 0x80) != 0) && (PortSC != 0xFFFF)) {
314 (*PortNumber)++;
315 }
316 }
317
318 Uhc->RootPorts = *PortNumber;
319
320 UHCI_DEBUG (("UhciGetRootHubPortNumber: %d ports\n", Uhc->RootPorts));
321 return EFI_SUCCESS;
322 }
323
324
325 /**
326 Retrieves the current status of a USB root hub port.
327
328 This : A pointer to the EFI_USB_HC_PROTOCOL.
329 PortNumber : Specifies the root hub port. This value is zero-based.
330 PortStatus : A pointer to the current port status bits and port status change bits.
331
332 @return EFI_SUCCESS : The port status was returned in PortStatus.
333 @return EFI_INVALID_PARAMETER : PortNumber is invalid.
334 @return EFI_DEVICE_ERROR : Can't read register
335
336 **/
337 EFI_STATUS
338 EFIAPI
339 UhciGetRootHubPortStatus (
340 IN EFI_USB_HC_PROTOCOL *This,
341 IN UINT8 PortNumber,
342 OUT EFI_USB_PORT_STATUS *PortStatus
343 )
344 {
345 USB_HC_DEV *Uhc;
346 UINT32 Offset;
347 UINT16 PortSC;
348
349 Uhc = UHC_FROM_USB_HC_PROTO (This);
350
351 if (PortStatus == NULL) {
352 return EFI_INVALID_PARAMETER;
353 }
354
355 if (PortNumber >= Uhc->RootPorts) {
356 return EFI_INVALID_PARAMETER;
357 }
358
359 Offset = USBPORTSC_OFFSET + PortNumber * 2;
360 PortStatus->PortStatus = 0;
361 PortStatus->PortChangeStatus = 0;
362
363 PortSC = UhciReadReg (Uhc->PciIo, Offset);
364
365 if (PortSC & USBPORTSC_CCS) {
366 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
367 }
368
369 if (PortSC & USBPORTSC_PED) {
370 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
371 }
372
373 if (PortSC & USBPORTSC_SUSP) {
374 UHCI_DEBUG (("UhciGetRootHubPortStatus: port %d is suspended\n", PortNumber));
375 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
376 }
377
378 if (PortSC & USBPORTSC_PR) {
379 PortStatus->PortStatus |= USB_PORT_STAT_RESET;
380 }
381
382 if (PortSC & USBPORTSC_LSDA) {
383 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
384 }
385
386 //
387 // CHC will always return one in port owner bit
388 //
389 PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
390
391 if (PortSC & USBPORTSC_CSC) {
392 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
393 }
394
395 if (PortSC & USBPORTSC_PEDC) {
396 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
397 }
398
399 return EFI_SUCCESS;
400 }
401
402
403 /**
404 Sets a feature for the specified root hub port.
405
406 This : A pointer to the EFI_USB_HC_PROTOCOL.
407 PortNumber : Specifies the root hub port whose feature
408 is requested to be set.
409 PortFeature : Indicates the feature selector associated
410 with the feature set request.
411
412 @return EFI_SUCCESS : The feature was set for the port.
413 @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.
414 @return EFI_DEVICE_ERROR : Can't read register
415
416 **/
417 STATIC
418 EFI_STATUS
419 EFIAPI
420 UhciSetRootHubPortFeature (
421 IN EFI_USB_HC_PROTOCOL *This,
422 IN UINT8 PortNumber,
423 IN EFI_USB_PORT_FEATURE PortFeature
424 )
425 {
426 USB_HC_DEV *Uhc;
427 EFI_TPL OldTpl;
428 UINT32 Offset;
429 UINT16 PortSC;
430 UINT16 Command;
431
432 Uhc = UHC_FROM_USB_HC_PROTO (This);
433
434 if (PortNumber >= Uhc->RootPorts) {
435 return EFI_INVALID_PARAMETER;
436 }
437
438 Offset = USBPORTSC_OFFSET + PortNumber * 2;
439
440 OldTpl = gBS->RaiseTPL (UHCI_TPL);
441 PortSC = UhciReadReg (Uhc->PciIo, Offset);
442
443 switch (PortFeature) {
444 case EfiUsbPortSuspend:
445 Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
446 if (!(Command & USBCMD_EGSM)) {
447 //
448 // if global suspend is not active, can set port suspend
449 //
450 PortSC &= 0xfff5;
451 PortSC |= USBPORTSC_SUSP;
452 }
453 break;
454
455 case EfiUsbPortReset:
456 PortSC &= 0xfff5;
457 PortSC |= USBPORTSC_PR;
458 break;
459
460 case EfiUsbPortPower:
461 //
462 // No action
463 //
464 break;
465
466 case EfiUsbPortEnable:
467 PortSC &= 0xfff5;
468 PortSC |= USBPORTSC_PED;
469 break;
470
471 default:
472 gBS->RestoreTPL (OldTpl);
473 return EFI_INVALID_PARAMETER;
474 }
475
476 UhciWriteReg (Uhc->PciIo, Offset, PortSC);
477 gBS->RestoreTPL (OldTpl);
478
479 return EFI_SUCCESS;
480 }
481
482
483 /**
484 Clears a feature for the specified root hub port.
485
486 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
487 PortNumber : Specifies the root hub port whose feature
488 is requested to be cleared.
489 PortFeature : Indicates the feature selector associated with the
490 feature clear request.
491
492 @return EFI_SUCCESS : The feature was cleared for the port.
493 @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.
494 @return EFI_DEVICE_ERROR : Can't read register
495
496 **/
497 STATIC
498 EFI_STATUS
499 EFIAPI
500 UhciClearRootHubPortFeature (
501 IN EFI_USB_HC_PROTOCOL *This,
502 IN UINT8 PortNumber,
503 IN EFI_USB_PORT_FEATURE PortFeature
504 )
505 {
506 USB_HC_DEV *Uhc;
507 EFI_TPL OldTpl;
508 UINT32 Offset;
509 UINT16 PortSC;
510
511 Uhc = UHC_FROM_USB_HC_PROTO (This);
512
513 if (PortNumber >= Uhc->RootPorts) {
514 return EFI_INVALID_PARAMETER;
515 }
516
517 Offset = USBPORTSC_OFFSET + PortNumber * 2;
518
519 OldTpl = gBS->RaiseTPL (UHCI_TPL);
520 PortSC = UhciReadReg (Uhc->PciIo, Offset);
521
522 switch (PortFeature) {
523 case EfiUsbPortEnable:
524 PortSC &= 0xfff5;
525 PortSC &= ~USBPORTSC_PED;
526 break;
527
528 case EfiUsbPortSuspend:
529 //
530 // Cause a resume on the specified port if in suspend mode.
531 //
532 PortSC &= 0xfff5;
533 PortSC &= ~USBPORTSC_SUSP;
534 break;
535
536 case EfiUsbPortPower:
537 //
538 // No action
539 //
540 break;
541
542 case EfiUsbPortReset:
543 PortSC &= 0xfff5;
544 PortSC &= ~USBPORTSC_PR;
545 break;
546
547 case EfiUsbPortConnectChange:
548 PortSC &= 0xfff5;
549 PortSC |= USBPORTSC_CSC;
550 break;
551
552 case EfiUsbPortEnableChange:
553 PortSC &= 0xfff5;
554 PortSC |= USBPORTSC_PEDC;
555 break;
556
557 case EfiUsbPortSuspendChange:
558 //
559 // Root hub does not support this
560 //
561 break;
562
563 case EfiUsbPortOverCurrentChange:
564 //
565 // Root hub does not support this
566 //
567 break;
568
569 case EfiUsbPortResetChange:
570 //
571 // Root hub does not support this
572 //
573 break;
574
575 default:
576 gBS->RestoreTPL (OldTpl);
577 return EFI_INVALID_PARAMETER;
578 }
579
580 UhciWriteReg (Uhc->PciIo, Offset, PortSC);
581 gBS->RestoreTPL (OldTpl);
582
583 return EFI_SUCCESS;
584 }
585
586
587 /**
588 Submits control transfer to a target USB device.
589
590 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
591 DeviceAddress : Usb device address
592 IsSlowDevice : Whether the device is of slow speed or full speed
593 MaximumPacketLength : maximum packet size of the default control endpoint
594 Request : USB device request to send
595 TransferDirection : Specifies the data direction for the transfer.
596 Data : Data buffer to transmit from or receive into
597 DataLength : Number of bytes of the data
598 TimeOut : Maximum time, in microseconds
599 TransferResult : Return result in this
600
601 @return EFI_SUCCESS : Transfer was completed successfully.
602 @return EFI_OUT_OF_RESOURCES : Failed due to a lack of resources.
603 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
604 @return EFI_TIMEOUT : Failed due to timeout.
605 @return EFI_DEVICE_ERROR : Failed due to host controller or device error.
606
607 **/
608 STATIC
609 EFI_STATUS
610 EFIAPI
611 UhciControlTransfer (
612 IN EFI_USB_HC_PROTOCOL *This,
613 IN UINT8 DeviceAddress,
614 IN BOOLEAN IsSlowDevice,
615 IN UINT8 MaximumPacketLength,
616 IN EFI_USB_DEVICE_REQUEST *Request,
617 IN EFI_USB_DATA_DIRECTION TransferDirection,
618 IN OUT VOID *Data, OPTIONAL
619 IN OUT UINTN *DataLength, OPTIONAL
620 IN UINTN TimeOut,
621 OUT UINT32 *TransferResult
622 )
623 {
624 USB_HC_DEV *Uhc;
625 UHCI_TD_SW *TDs;
626 EFI_TPL OldTpl;
627 EFI_STATUS Status;
628 UHCI_QH_RESULT QhResult;
629 UINT8 PktId;
630 UINT8 *RequestPhy;
631 VOID *RequestMap;
632 UINT8 *DataPhy;
633 VOID *DataMap;
634
635 Uhc = UHC_FROM_USB_HC_PROTO (This);
636 TDs = NULL;
637 DataPhy = NULL;
638 DataMap = NULL;
639 RequestPhy = NULL;
640 RequestMap = NULL;
641
642 //
643 // Parameters Checking
644 //
645 if (Request == NULL || TransferResult == NULL) {
646 return EFI_INVALID_PARAMETER;
647 }
648
649 if (IsSlowDevice && (MaximumPacketLength != 8)) {
650 return EFI_INVALID_PARAMETER;
651 }
652
653 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
654 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
655
656 return EFI_INVALID_PARAMETER;
657 }
658
659 if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {
660 return EFI_INVALID_PARAMETER;
661 }
662
663 *TransferResult = EFI_USB_ERR_SYSTEM;
664 Status = EFI_DEVICE_ERROR;
665
666 //
667 // If errors exist that cause host controller halt,
668 // clear status then return EFI_DEVICE_ERROR.
669 //
670 UhciAckAllInterrupt (Uhc);
671
672 if (!UhciIsHcWorking (Uhc->PciIo)) {
673 return EFI_DEVICE_ERROR;
674 }
675
676 OldTpl = gBS->RaiseTPL (UHCI_TPL);
677
678 //
679 // Map the Request and data for bus master access,
680 // then create a list of TD for this transfer
681 //
682 Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);
683
684 if (EFI_ERROR (Status)) {
685 goto ON_EXIT;
686 }
687
688 Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);
689
690 if (EFI_ERROR (Status)) {
691 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
692 goto ON_EXIT;
693 }
694
695 TDs = UhciCreateCtrlTds (
696 Uhc,
697 DeviceAddress,
698 PktId,
699 RequestPhy,
700 DataPhy,
701 *DataLength,
702 MaximumPacketLength,
703 IsSlowDevice
704 );
705
706 if (TDs == NULL) {
707 Status = EFI_OUT_OF_RESOURCES;
708 goto UNMAP_DATA;
709 }
710
711 //
712 // According to the speed of the end point, link
713 // the TD to corrosponding queue head, then check
714 // the execution result
715 //
716 UhciLinkTdToQh (Uhc->CtrlQh, TDs);
717 Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);
718 UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);
719
720 Uhc->PciIo->Flush (Uhc->PciIo);
721
722 *TransferResult = QhResult.Result;
723
724 if (DataLength != NULL) {
725 *DataLength = QhResult.Complete;
726 }
727
728 UhciDestoryTds (Uhc, TDs);
729
730 UNMAP_DATA:
731 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
732 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
733
734 ON_EXIT:
735 gBS->RestoreTPL (OldTpl);
736 return Status;
737 }
738
739
740 /**
741 Submits bulk transfer to a bulk endpoint of a USB device.
742
743 This :A pointer to the EFI_USB_HC_PROTOCOL instance.
744 DeviceAddress : Usb device address
745 EndPointAddress : Endpoint number and endpoint direction
746 MaximumPacketLength : Maximum packet size of the target endpoint
747 Data : Data buffer to transmit from or receive into
748 DataLength : Length of the data buffer
749 DataToggle : On input, data toggle to use, on output, the next toggle
750 TimeOut : Indicates the maximum time
751 TransferResult : Variable to receive the transfer result
752
753 @return EFI_SUCCESS : The bulk transfer was completed successfully.
754 @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.
755 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
756 @return EFI_TIMEOUT : Failed due to timeout.
757 @return EFI_DEVICE_ERROR : Failed due to host controller or device error.
758
759 **/
760 STATIC
761 EFI_STATUS
762 EFIAPI
763 UhciBulkTransfer (
764 IN EFI_USB_HC_PROTOCOL *This,
765 IN UINT8 DeviceAddress,
766 IN UINT8 EndPointAddress,
767 IN UINT8 MaximumPacketLength,
768 IN OUT VOID *Data,
769 IN OUT UINTN *DataLength,
770 IN OUT UINT8 *DataToggle,
771 IN UINTN TimeOut,
772 OUT UINT32 *TransferResult
773 )
774 {
775 EFI_USB_DATA_DIRECTION Direction;
776 EFI_TPL OldTpl;
777 USB_HC_DEV *Uhc;
778 UHCI_TD_SW *TDs;
779 UHCI_QH_SW *BulkQh;
780 UHCI_QH_RESULT QhResult;
781 EFI_STATUS Status;
782 UINT8 PktId;
783 UINT8 *DataPhy;
784 VOID *DataMap;
785
786 Uhc = UHC_FROM_USB_HC_PROTO (This);
787 DataPhy = NULL;
788 DataMap = NULL;
789
790 if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
791 return EFI_INVALID_PARAMETER;
792 }
793
794 if (*DataLength == 0) {
795 return EFI_INVALID_PARAMETER;
796 }
797
798 if ((*DataToggle != 1) && (*DataToggle != 0)) {
799 return EFI_INVALID_PARAMETER;
800 }
801
802 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
803 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
804 return EFI_INVALID_PARAMETER;
805 }
806
807 *TransferResult = EFI_USB_ERR_SYSTEM;
808 Status = EFI_OUT_OF_RESOURCES;
809
810 //
811 // If has errors that cause host controller halt,
812 // then return EFI_DEVICE_ERROR directly.
813 //
814 UhciAckAllInterrupt (Uhc);
815
816 if (!UhciIsHcWorking (Uhc->PciIo)) {
817 return EFI_DEVICE_ERROR;
818 }
819
820 OldTpl = gBS->RaiseTPL (UHCI_TPL);
821
822 //
823 // Map the source data buffer for bus master access,
824 // then create a list of TDs
825 //
826 if (EndPointAddress & 0x80) {
827 Direction = EfiUsbDataIn;
828 } else {
829 Direction = EfiUsbDataOut;
830 }
831
832 Status = UhciMapUserData (Uhc, Direction, Data, DataLength, &PktId, &DataPhy, &DataMap);
833
834 if (EFI_ERROR (Status)) {
835 goto ON_EXIT;
836 }
837
838 Status = EFI_OUT_OF_RESOURCES;
839 TDs = UhciCreateBulkOrIntTds (
840 Uhc,
841 DeviceAddress,
842 EndPointAddress,
843 PktId,
844 DataPhy,
845 *DataLength,
846 DataToggle,
847 MaximumPacketLength,
848 FALSE
849 );
850
851 if (TDs == NULL) {
852 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
853 goto ON_EXIT;
854 }
855
856
857 //
858 // Link the TDs to bulk queue head. According to the platfore
859 // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured
860 // to do full speed bandwidth reclamation or not.
861 //
862 BulkQh = Uhc->BulkQh;
863
864 UhciLinkTdToQh (BulkQh, TDs);
865 Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);
866 UhciUnlinkTdFromQh (BulkQh, TDs);
867
868 Uhc->PciIo->Flush (Uhc->PciIo);
869
870 *TransferResult = QhResult.Result;
871 *DataToggle = QhResult.NextToggle;
872 *DataLength = QhResult.Complete;
873
874 UhciDestoryTds (Uhc, TDs);
875 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
876
877 ON_EXIT:
878 gBS->RestoreTPL (OldTpl);
879 return Status;
880 }
881
882
883 /**
884 Submits an asynchronous interrupt transfer to an interrupt endpoint of a USB device.
885
886 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
887 DeviceAddress : Target device address
888 EndPointAddress : Endpoint number with direction
889 IsSlowDevice : Whether the target device is slow device or full-speed device.
890 MaximumPacketLength : Maximum packet size of the target endpoint
891 IsNewTransfer : If TRUE, submit a new async interrupt transfer, otherwise
892 cancel an existed one
893 DataToggle : On input, the data toggle to use; On output, next data toggle
894 PollingInterval : Interrupt poll rate in milliseconds
895 DataLength : Length of data to receive
896 CallBackFunction : Function to call periodically
897 Context : User context
898
899 @return EFI_SUCCESS : Request is submitted or cancelled
900 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
901 @return EFI_OUT_OF_RESOURCES : Failed due to a lack of resources.
902 @return EFI_DEVICE_ERROR : Failed to due to device error
903
904 **/
905 STATIC
906 EFI_STATUS
907 EFIAPI
908 UhciAsyncInterruptTransfer (
909 IN EFI_USB_HC_PROTOCOL * This,
910 IN UINT8 DeviceAddress,
911 IN UINT8 EndPointAddress,
912 IN BOOLEAN IsSlowDevice,
913 IN UINT8 MaximumPacketLength,
914 IN BOOLEAN IsNewTransfer,
915 IN OUT UINT8 *DataToggle,
916 IN UINTN PollingInterval, OPTIONAL
917 IN UINTN DataLength, OPTIONAL
918 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL
919 IN VOID *Context OPTIONAL
920 )
921 {
922 USB_HC_DEV *Uhc;
923 UHCI_QH_SW *Qh;
924 UHCI_TD_SW *IntTds;
925 EFI_TPL OldTpl;
926 EFI_STATUS Status;
927 UINT8 *DataPtr;
928 UINT8 *DataPhy;
929 VOID *DataMap;
930 UINT8 PktId;
931
932 Uhc = UHC_FROM_USB_HC_PROTO (This);
933 Qh = NULL;
934 IntTds = NULL;
935 DataPtr = NULL;
936 DataPhy = NULL;
937 DataMap = NULL;
938
939 if ((EndPointAddress & 0x80) == 0) {
940 return EFI_INVALID_PARAMETER;
941 }
942
943 //
944 // Delete Async interrupt transfer request
945 //
946 if (!IsNewTransfer) {
947 OldTpl = gBS->RaiseTPL (UHCI_TPL);
948 Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);
949
950 gBS->RestoreTPL (OldTpl);
951 return Status;
952 }
953
954 if (PollingInterval < 1 || PollingInterval > 255) {
955 return EFI_INVALID_PARAMETER;
956 }
957
958 if (DataLength == 0) {
959 return EFI_INVALID_PARAMETER;
960 }
961
962 if ((*DataToggle != 1) && (*DataToggle != 0)) {
963 return EFI_INVALID_PARAMETER;
964 }
965
966 //
967 // If has errors that cause host controller halt,
968 // then return EFI_DEVICE_ERROR directly.
969 //
970 UhciAckAllInterrupt (Uhc);
971
972 if (!UhciIsHcWorking (Uhc->PciIo)) {
973 return EFI_DEVICE_ERROR;
974 }
975
976 //
977 // Allocate and map source data buffer for bus master access.
978 //
979 DataPtr = AllocatePool (DataLength);
980
981 if (DataPtr == NULL) {
982 return EFI_OUT_OF_RESOURCES;
983 }
984
985 OldTpl = gBS->RaiseTPL (UHCI_TPL);
986
987 //
988 // Map the user data then create a queue head and
989 // list of TD for it.
990 //
991 Status = UhciMapUserData (
992 Uhc,
993 EfiUsbDataIn,
994 DataPtr,
995 &DataLength,
996 &PktId,
997 &DataPhy,
998 &DataMap
999 );
1000
1001 if (EFI_ERROR (Status)) {
1002 goto FREE_DATA;
1003 }
1004
1005 Qh = UhciCreateQh (Uhc, PollingInterval);
1006
1007 if (Qh == NULL) {
1008 Status = EFI_OUT_OF_RESOURCES;
1009 goto UNMAP_DATA;
1010 }
1011
1012 IntTds = UhciCreateBulkOrIntTds (
1013 Uhc,
1014 DeviceAddress,
1015 EndPointAddress,
1016 PktId,
1017 DataPhy,
1018 DataLength,
1019 DataToggle,
1020 MaximumPacketLength,
1021 IsSlowDevice
1022 );
1023
1024 if (IntTds == NULL) {
1025 Status = EFI_OUT_OF_RESOURCES;
1026 goto DESTORY_QH;
1027 }
1028
1029 UhciLinkTdToQh (Qh, IntTds);
1030
1031 //
1032 // Save QH-TD structures to async Interrupt transfer list,
1033 // for monitor interrupt transfer execution routine use.
1034 //
1035 Status = UhciCreateAsyncReq (
1036 Uhc,
1037 Qh,
1038 IntTds,
1039 DeviceAddress,
1040 EndPointAddress,
1041 DataLength,
1042 PollingInterval,
1043 DataMap,
1044 DataPtr,
1045 CallBackFunction,
1046 Context,
1047 IsSlowDevice
1048 );
1049
1050 if (EFI_ERROR (Status)) {
1051 goto DESTORY_QH;
1052 }
1053
1054 UhciLinkQhToFrameList (Uhc->FrameBase, Qh);
1055
1056 gBS->RestoreTPL (OldTpl);
1057 return EFI_SUCCESS;
1058
1059 DESTORY_QH:
1060 UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));
1061
1062 UNMAP_DATA:
1063 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1064
1065 FREE_DATA:
1066 gBS->FreePool (DataPtr);
1067 Uhc->PciIo->Flush (Uhc->PciIo);
1068
1069 gBS->RestoreTPL (OldTpl);
1070 return Status;
1071 }
1072
1073
1074 /**
1075 Submits synchronous interrupt transfer to an interrupt endpoint of a USB device.
1076
1077 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
1078 DeviceAddress : Device address of the target USB device
1079 EndPointAddress : Endpoint number and direction
1080 IsSlowDevice : Whether the target device is of slow speed or full speed
1081 MaximumPacketLength : Maximum packet size of target endpoint
1082 Data : Data to transmit or receive
1083 DataLength : On input, data length to transmit or buffer size.
1084 On output, the number of bytes transferred.
1085 DataToggle : On input, data toggle to use; On output, next data toggle
1086 TimeOut : Maximum time, in microseconds, transfer is allowed to complete.
1087 TransferResult : Variable to receive transfer result
1088
1089 @return EFI_SUCCESS : Transfer was completed successfully.
1090 @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.
1091 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
1092 @return EFI_TIMEOUT : Failed due to timeout.
1093 @return EFI_DEVICE_ERROR : Failed due to host controller or device error
1094
1095 **/
1096 STATIC
1097 EFI_STATUS
1098 EFIAPI
1099 UhciSyncInterruptTransfer (
1100 IN EFI_USB_HC_PROTOCOL *This,
1101 IN UINT8 DeviceAddress,
1102 IN UINT8 EndPointAddress,
1103 IN BOOLEAN IsSlowDevice,
1104 IN UINT8 MaximumPacketLength,
1105 IN OUT VOID *Data,
1106 IN OUT UINTN *DataLength,
1107 IN OUT UINT8 *DataToggle,
1108 IN UINTN TimeOut,
1109 OUT UINT32 *TransferResult
1110 )
1111 {
1112 EFI_STATUS Status;
1113 USB_HC_DEV *Uhc;
1114 UHCI_TD_SW *TDs;
1115 UHCI_QH_RESULT QhResult;
1116 EFI_TPL OldTpl;
1117 UINT8 *DataPhy;
1118 VOID *DataMap;
1119 UINT8 PktId;
1120
1121 Uhc = UHC_FROM_USB_HC_PROTO (This);
1122 DataPhy = NULL;
1123 DataMap = NULL;
1124 TDs = NULL;
1125
1126 if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
1127 return EFI_INVALID_PARAMETER;
1128 }
1129
1130 if ((EndPointAddress & 0x80) == 0) {
1131 return EFI_INVALID_PARAMETER;
1132 }
1133
1134 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1135 return EFI_INVALID_PARAMETER;
1136 }
1137
1138 if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
1139 return EFI_INVALID_PARAMETER;
1140 }
1141
1142 if (IsSlowDevice && (MaximumPacketLength > 8)) {
1143 return EFI_INVALID_PARAMETER;
1144 }
1145
1146 *TransferResult = EFI_USB_ERR_SYSTEM;
1147 Status = EFI_DEVICE_ERROR;
1148
1149
1150 UhciAckAllInterrupt (Uhc);
1151
1152 if (!UhciIsHcWorking (Uhc->PciIo)) {
1153 return Status;
1154 }
1155
1156 OldTpl = gBS->RaiseTPL (UHCI_TPL);
1157
1158 //
1159 // Map the source data buffer for bus master access.
1160 // Create Tds list, then link it to the UHC's interrupt list
1161 //
1162 Status = UhciMapUserData (
1163 Uhc,
1164 EfiUsbDataIn,
1165 Data,
1166 DataLength,
1167 &PktId,
1168 &DataPhy,
1169 &DataMap
1170 );
1171
1172 if (EFI_ERROR (Status)) {
1173 goto ON_EXIT;
1174 }
1175
1176 TDs = UhciCreateBulkOrIntTds (
1177 Uhc,
1178 DeviceAddress,
1179 EndPointAddress,
1180 PktId,
1181 DataPhy,
1182 *DataLength,
1183 DataToggle,
1184 MaximumPacketLength,
1185 IsSlowDevice
1186 );
1187
1188 if (TDs == NULL) {
1189 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1190
1191 Status = EFI_OUT_OF_RESOURCES;
1192 goto ON_EXIT;
1193 }
1194
1195
1196 UhciLinkTdToQh (Uhc->SyncIntQh, TDs);
1197
1198 Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
1199
1200 UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
1201 Uhc->PciIo->Flush (Uhc->PciIo);
1202
1203 *TransferResult = QhResult.Result;
1204 *DataToggle = QhResult.NextToggle;
1205 *DataLength = QhResult.Complete;
1206
1207 UhciDestoryTds (Uhc, TDs);
1208 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1209
1210 ON_EXIT:
1211 gBS->RestoreTPL (OldTpl);
1212 return Status;
1213 }
1214
1215
1216 /**
1217 Submits isochronous transfer to a target USB device.
1218
1219 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
1220 DeviceAddress : Target device address
1221 EndPointAddress : End point address withdirection
1222 MaximumPacketLength : Maximum packet size of the endpoint
1223 Data : Data to transmit or receive
1224 DataLength : Bytes of the data
1225 TransferResult : Variable to receive the result
1226
1227 @return EFI_UNSUPPORTED
1228
1229 **/
1230 STATIC
1231 EFI_STATUS
1232 EFIAPI
1233 UhciIsochronousTransfer (
1234 IN EFI_USB_HC_PROTOCOL *This,
1235 IN UINT8 DeviceAddress,
1236 IN UINT8 EndPointAddress,
1237 IN UINT8 MaximumPacketLength,
1238 IN OUT VOID *Data,
1239 IN UINTN DataLength,
1240 OUT UINT32 *TransferResult
1241 )
1242 {
1243 return EFI_UNSUPPORTED;
1244 }
1245
1246
1247 /**
1248 Submits Async isochronous transfer to a target USB device.
1249
1250 This : A pointer to the EFI_USB_HC_PROTOCOL instance.
1251 DeviceAddress : Target device address
1252 EndPointAddress : End point address withdirection
1253 MaximumPacketLength : Maximum packet size of the endpoint
1254 Data : Data to transmit or receive
1255 IsochronousCallBack : Function to call when the transfer completes
1256 Context : User context
1257
1258 @return EFI_UNSUPPORTED
1259
1260 **/
1261 STATIC
1262 EFI_STATUS
1263 EFIAPI
1264 UhciAsyncIsochronousTransfer (
1265 IN EFI_USB_HC_PROTOCOL * This,
1266 IN UINT8 DeviceAddress,
1267 IN UINT8 EndPointAddress,
1268 IN UINT8 MaximumPacketLength,
1269 IN OUT VOID *Data,
1270 IN UINTN DataLength,
1271 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1272 IN VOID *Context OPTIONAL
1273 )
1274 {
1275 return EFI_UNSUPPORTED;
1276 }
1277
1278
1279
1280 /**
1281 Provides software reset for the USB host controller according to UEFI 2.0 spec.
1282
1283 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1284 @param Attributes A bit mask of the reset operation to perform. See
1285 below for a list of the supported bit mask values.
1286
1287 @return EFI_SUCCESS : The reset operation succeeded.
1288 @return EFI_INVALID_PARAMETER : Attributes is not valid.
1289 @return EFI_UNSUPPORTED : This type of reset is not currently supported
1290 @return EFI_DEVICE_ERROR : Other errors
1291
1292 **/
1293 STATIC
1294 EFI_STATUS
1295 EFIAPI
1296 Uhci2Reset (
1297 IN EFI_USB2_HC_PROTOCOL *This,
1298 IN UINT16 Attributes
1299 )
1300 {
1301 USB_HC_DEV *UhciDev;
1302
1303 UhciDev = UHC_FROM_USB2_HC_PROTO (This);
1304
1305 if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||
1306 (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {
1307 return EFI_UNSUPPORTED;
1308 }
1309
1310 return UhciReset (&UhciDev->UsbHc, Attributes);
1311 }
1312
1313
1314 /**
1315 Retrieves current state of the USB host controller according to UEFI 2.0 spec.
1316
1317 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1318 @param State Variable to receive current device state
1319
1320 @return EFI_SUCCESS : The state is returned
1321 @return EFI_INVALID_PARAMETER : State is not valid.
1322 @return EFI_DEVICE_ERROR : Other errors2006
1323
1324 **/
1325 STATIC
1326 EFI_STATUS
1327 EFIAPI
1328 Uhci2GetState (
1329 IN CONST EFI_USB2_HC_PROTOCOL *This,
1330 OUT EFI_USB_HC_STATE *State
1331 )
1332 {
1333 USB_HC_DEV *Uhc;
1334
1335 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1336 return UhciGetState (&Uhc->UsbHc, State);
1337 }
1338
1339
1340 /**
1341 Sets the USB host controller to a specific state according to UEFI 2.0 spec.
1342
1343 @param This A pointer to the EFI_USB_HC_PROTOCOL instance.
1344 @param State Indicates the state of the host controller that will
1345 be set.
1346
1347 @return EFI_SUCCESS : Host controller was successfully placed in the state
1348 @return EFI_INVALID_PARAMETER : State is invalid.
1349 @return EFI_DEVICE_ERROR : Failed to set the state
1350
1351 **/
1352 STATIC
1353 EFI_STATUS
1354 EFIAPI
1355 Uhci2SetState (
1356 IN EFI_USB2_HC_PROTOCOL *This,
1357 IN EFI_USB_HC_STATE State
1358 )
1359 {
1360 USB_HC_DEV *Uhc;
1361
1362 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1363 return UhciSetState (&Uhc->UsbHc, State);
1364 }
1365
1366
1367 /**
1368 Retrieves capabilities of USB host controller according to UEFI 2.0 spec.
1369
1370 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance
1371 @param MaxSpeed A pointer to the max speed USB host controller
1372 supports.
1373 @param PortNumber A pointer to the number of root hub ports.
1374 @param Is64BitCapable A pointer to an integer to show whether USB host
1375 controller supports 64-bit memory addressing.
1376
1377 @return EFI_SUCCESS : capabilities were retrieved successfully.
1378 @return EFI_INVALID_PARAMETER : MaxSpeed or PortNumber or Is64BitCapable is NULL.
1379 @return EFI_DEVICE_ERROR : An error was encountered
1380
1381 **/
1382 STATIC
1383 EFI_STATUS
1384 EFIAPI
1385 Uhci2GetCapability (
1386 IN EFI_USB2_HC_PROTOCOL *This,
1387 OUT UINT8 *MaxSpeed,
1388 OUT UINT8 *PortNumber,
1389 OUT UINT8 *Is64BitCapable
1390 )
1391 {
1392 USB_HC_DEV *Uhc;
1393
1394 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1395
1396 if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {
1397 return EFI_INVALID_PARAMETER;
1398 }
1399
1400 *MaxSpeed = EFI_USB_SPEED_FULL;
1401 *Is64BitCapable = (UINT8) FALSE;
1402
1403 return UhciGetRootHubPortNumber (&Uhc->UsbHc, PortNumber);
1404 }
1405
1406
1407 /**
1408 Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.
1409
1410 @param This A pointer to the EFI_USB2_HC_PROTOCOL.
1411 @param PortNumber The port to get status
1412 @param PortStatus A pointer to the current port status bits and port
1413 status change bits.
1414
1415 @return EFI_SUCCESS : status of the USB root hub port was returned in PortStatus.
1416 @return EFI_INVALID_PARAMETER : PortNumber is invalid.
1417 @return EFI_DEVICE_ERROR : Can't read register
1418
1419 **/
1420 STATIC
1421 EFI_STATUS
1422 EFIAPI
1423 Uhci2GetRootHubPortStatus (
1424 IN CONST EFI_USB2_HC_PROTOCOL *This,
1425 IN CONST UINT8 PortNumber,
1426 OUT EFI_USB_PORT_STATUS *PortStatus
1427 )
1428 {
1429 USB_HC_DEV *Uhc;
1430
1431 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1432
1433 return UhciGetRootHubPortStatus (&Uhc->UsbHc, PortNumber, PortStatus);
1434 }
1435
1436
1437 /**
1438 Sets a feature for the specified root hub port according to UEFI 2.0 spec.
1439
1440 @param This A pointer to the EFI_USB2_HC_PROTOCOL.
1441 @param PortNumber Specifies the root hub port whose feature is
1442 requested to be set.
1443 @param PortFeature Indicates the feature selector associated with the
1444 feature set request.
1445
1446 @return EFI_SUCCESS : PortFeature was set for the root port
1447 @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.
1448 @return EFI_DEVICE_ERROR : Can't read register
1449
1450 **/
1451 STATIC
1452 EFI_STATUS
1453 EFIAPI
1454 Uhci2SetRootHubPortFeature (
1455 IN EFI_USB2_HC_PROTOCOL *This,
1456 IN UINT8 PortNumber,
1457 IN EFI_USB_PORT_FEATURE PortFeature
1458 )
1459 {
1460 USB_HC_DEV *Uhc;
1461
1462 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1463
1464 return UhciSetRootHubPortFeature (&Uhc->UsbHc, PortNumber, PortFeature);
1465 }
1466
1467
1468 /**
1469 Clears a feature for the specified root hub port according to Uefi 2.0 spec.
1470
1471 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1472 @param PortNumber Specifies the root hub port whose feature is
1473 requested to be cleared.
1474 @param PortFeature Indicates the feature selector associated with the
1475 feature clear request.
1476
1477 @return EFI_SUCCESS : PortFeature was cleared for the USB root hub port
1478 @return EFI_INVALID_PARAMETER : PortNumber is invalid or PortFeature is invalid.
1479 @return EFI_DEVICE_ERROR : Can't read register
1480
1481 **/
1482 STATIC
1483 EFI_STATUS
1484 EFIAPI
1485 Uhci2ClearRootHubPortFeature (
1486 IN EFI_USB2_HC_PROTOCOL *This,
1487 IN UINT8 PortNumber,
1488 IN EFI_USB_PORT_FEATURE PortFeature
1489 )
1490 {
1491 USB_HC_DEV *Uhc;
1492
1493 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1494
1495 return UhciClearRootHubPortFeature (&Uhc->UsbHc, PortNumber, PortFeature);
1496 }
1497
1498
1499 /**
1500 Submits control transfer to a target USB device accroding to UEFI 2.0 spec..
1501
1502 This : A pointer to the EFI_USB2_HC_PROTOCOL instance.
1503 DeviceAddress : Target device address
1504 DeviceSpeed : Device speed
1505 MaximumPacketLength : Maximum packet size of the target endpoint
1506 Request : USB device request to send
1507 TransferDirection : Data direction of the Data stage in control transfer
1508 Data : Data to transmit/receive in data stage
1509 DataLength : Length of the data
1510 TimeOut : Maximum time, in microseconds, for transfer to complete.
1511 TransferResult : Variable to receive the transfer result
1512
1513 @return EFI_SUCCESS : The control transfer was completed successfully.
1514 @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.
1515 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
1516 @return EFI_TIMEOUT : Failed due to timeout.
1517 @return EFI_DEVICE_ERROR : Failed due to host controller or device error.
1518
1519 **/
1520 STATIC
1521 EFI_STATUS
1522 EFIAPI
1523 Uhci2ControlTransfer (
1524 IN EFI_USB2_HC_PROTOCOL *This,
1525 IN UINT8 DeviceAddress,
1526 IN UINT8 DeviceSpeed,
1527 IN UINTN MaximumPacketLength,
1528 IN EFI_USB_DEVICE_REQUEST *Request,
1529 IN EFI_USB_DATA_DIRECTION TransferDirection,
1530 IN OUT VOID *Data,
1531 IN OUT UINTN *DataLength,
1532 IN UINTN TimeOut,
1533 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1534 OUT UINT32 *TransferResult
1535 )
1536 {
1537 USB_HC_DEV *Uhc;
1538 BOOLEAN IsSlow;
1539
1540 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1541 IsSlow = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
1542
1543 return UhciControlTransfer (
1544 &Uhc->UsbHc,
1545 DeviceAddress,
1546 IsSlow,
1547 (UINT8) MaximumPacketLength,
1548 Request,
1549 TransferDirection,
1550 Data,
1551 DataLength,
1552 TimeOut,
1553 TransferResult
1554 );
1555 }
1556
1557
1558 /**
1559 Submits bulk transfer to a bulk endpoint of a USB device
1560
1561 This : A pointer to the EFI_USB2_HC_PROTOCOL instance.
1562 DeviceAddress : Target device address
1563 EndPointAddress : Endpoint number and direction
1564 DeviceSpeed : Device speed
1565 MaximumPacketLength : Maximum packet size of the target endpoint
1566 DataBuffersNumber : Number of data buffers prepared for the transfer.
1567 Data : Array of pointers to the buffers of data
1568 DataLength : On input, size of the data buffer, On output,
1569 actually transferred data size.
1570 DataToggle : On input, data toggle to use; On output, next data toggle
1571 Translator : A pointr to the transaction translator data.
1572 TimeOut : Maximum time out, in microseconds
1573 TransferResult : Variable to receive transfer result
1574
1575 @return EFI_SUCCESS : The bulk transfer was completed successfully.
1576 @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.
1577 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
1578 @return EFI_TIMEOUT : Failed due to timeout.
1579 @return EFI_DEVICE_ERROR : Failed due to host controller or device error.
1580
1581 **/
1582 STATIC
1583 EFI_STATUS
1584 EFIAPI
1585 Uhci2BulkTransfer (
1586 IN EFI_USB2_HC_PROTOCOL *This,
1587 IN UINT8 DeviceAddress,
1588 IN UINT8 EndPointAddress,
1589 IN UINT8 DeviceSpeed,
1590 IN UINTN MaximumPacketLength,
1591 IN UINT8 DataBuffersNumber,
1592 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
1593 IN OUT UINTN *DataLength,
1594 IN OUT UINT8 *DataToggle,
1595 IN UINTN TimeOut,
1596 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1597 OUT UINT32 *TransferResult
1598 )
1599 {
1600 USB_HC_DEV *Uhc;
1601
1602 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1603
1604 if (Data == NULL || DeviceSpeed == EFI_USB_SPEED_LOW) {
1605 return EFI_INVALID_PARAMETER;
1606 }
1607
1608 //
1609 // For full-speed bulk transfers only the data pointed by Data[0] shall be used
1610 //
1611 return UhciBulkTransfer (
1612 &Uhc->UsbHc,
1613 DeviceAddress,
1614 EndPointAddress,
1615 (UINT8) MaximumPacketLength,
1616 *Data,
1617 DataLength,
1618 DataToggle,
1619 TimeOut,
1620 TransferResult
1621 );
1622 }
1623
1624
1625 /**
1626 Submits an asynchronous interrupt transfer to an
1627 interrupt endpoint of a USB device according to UEFI 2.0 spec.
1628
1629 This : A pointer to the EFI_USB2_HC_PROTOCOL instance.
1630 DeviceAddress : Target device address
1631 EndPointAddress : Endpoint number and direction
1632 DeviceSpeed : Device speed
1633 MaximumPacketLength : Maximum packet size of the target endpoint
1634 IsNewTransfer : If TRUE, submit a new transfer, if FALSE cancel old transfer
1635 DataToggle : On input, data toggle to use; On output, next data toggle
1636 PollingInterval : Interrupt poll rate in milliseconds
1637 DataLength : On input, size of the data buffer, On output,
1638 actually transferred data size.
1639 Translator : A pointr to the transaction translator data.
1640 CallBackFunction : Function to call periodically
1641 Context : User context
1642
1643 @return EFI_SUCCESS : Transfer was submitted
1644 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
1645 @return EFI_OUT_OF_RESOURCES : Failed due to a lack of resources.
1646 @return EFI_DEVICE_ERROR : Can't read register
1647
1648 **/
1649 STATIC
1650 EFI_STATUS
1651 EFIAPI
1652 Uhci2AsyncInterruptTransfer (
1653 IN EFI_USB2_HC_PROTOCOL *This,
1654 IN UINT8 DeviceAddress,
1655 IN UINT8 EndPointAddress,
1656 IN UINT8 DeviceSpeed,
1657 IN UINTN MaximumPacketLength,
1658 IN BOOLEAN IsNewTransfer,
1659 IN OUT UINT8 *DataToggle,
1660 IN UINTN PollingInterval,
1661 IN UINTN DataLength,
1662 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1663 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
1664 IN VOID *Context
1665 )
1666 {
1667 USB_HC_DEV *Uhc;
1668 BOOLEAN IsSlow;
1669
1670 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1671 IsSlow = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
1672
1673 return UhciAsyncInterruptTransfer (
1674 &Uhc->UsbHc,
1675 DeviceAddress,
1676 EndPointAddress,
1677 IsSlow,
1678 (UINT8) MaximumPacketLength,
1679 IsNewTransfer,
1680 DataToggle,
1681 PollingInterval,
1682 DataLength,
1683 CallBackFunction,
1684 Context
1685 );
1686 }
1687
1688
1689 /**
1690 Submits synchronous interrupt transfer to an interrupt endpoint
1691 of a USB device according to UEFI 2.0 spec.
1692
1693 This : A pointer to the EFI_USB2_HC_PROTOCOL instance.
1694 DeviceAddress : Target device address
1695 EndPointAddress : Endpoint number and direction
1696 DeviceSpeed : Device speed
1697 MaximumPacketLength : Maximum packet size of the target endpoint
1698 DataBuffersNumber : Number of data buffers prepared for the transfer.
1699 Data : Array of pointers to the buffers of data
1700 DataLength : On input, size of the data buffer, On output,
1701 actually transferred data size.
1702 DataToggle : On input, data toggle to use; On output, next data toggle
1703 TimeOut : Maximum time out, in microseconds
1704 Translator : A pointr to the transaction translator data.
1705 TransferResult : Variable to receive transfer result
1706
1707 @return EFI_SUCCESS : The transfer was completed successfully.
1708 @return EFI_OUT_OF_RESOURCES : Failed due to lack of resource.
1709 @return EFI_INVALID_PARAMETER : Some parameters are invalid.
1710 @return EFI_TIMEOUT : Failed due to timeout.
1711 @return EFI_DEVICE_ERROR : Failed due to host controller or device error.
1712
1713 **/
1714 STATIC
1715 EFI_STATUS
1716 EFIAPI
1717 Uhci2SyncInterruptTransfer (
1718 IN EFI_USB2_HC_PROTOCOL *This,
1719 IN UINT8 DeviceAddress,
1720 IN UINT8 EndPointAddress,
1721 IN UINT8 DeviceSpeed,
1722 IN UINTN MaximumPacketLength,
1723 IN OUT VOID *Data,
1724 IN OUT UINTN *DataLength,
1725 IN OUT UINT8 *DataToggle,
1726 IN UINTN TimeOut,
1727 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1728 OUT UINT32 *TransferResult
1729 )
1730 {
1731 USB_HC_DEV *Uhc;
1732 BOOLEAN IsSlow;
1733
1734 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1735 return EFI_INVALID_PARAMETER;
1736 }
1737
1738 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1739 IsSlow = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
1740
1741 return UhciSyncInterruptTransfer (
1742 &Uhc->UsbHc,
1743 DeviceAddress,
1744 EndPointAddress,
1745 IsSlow,
1746 (UINT8) MaximumPacketLength,
1747 Data,
1748 DataLength,
1749 DataToggle,
1750 TimeOut,
1751 TransferResult
1752 );
1753 }
1754
1755
1756 /**
1757 Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
1758
1759 This : A pointer to the EFI_USB2_HC_PROTOCOL instance.
1760 DeviceAddress : Target device address
1761 EndPointAddress : Endpoint number and direction
1762 DeviceSpeed : Device speed
1763 MaximumPacketLength : Maximum packet size of the target endpoint
1764 DataBuffersNumber : Number of data buffers prepared for the transfer.
1765 Data : Array of pointers to the buffers of data
1766 DataLength : On input, size of the data buffer, On output,
1767 actually transferred data size.
1768 Translator : A pointr to the transaction translator data.
1769 TransferResult : Variable to receive transfer result
1770
1771 @return EFI_UNSUPPORTED
1772
1773 **/
1774 STATIC
1775 EFI_STATUS
1776 EFIAPI
1777 Uhci2IsochronousTransfer (
1778 IN EFI_USB2_HC_PROTOCOL *This,
1779 IN UINT8 DeviceAddress,
1780 IN UINT8 EndPointAddress,
1781 IN UINT8 DeviceSpeed,
1782 IN UINTN MaximumPacketLength,
1783 IN UINT8 DataBuffersNumber,
1784 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1785 IN UINTN DataLength,
1786 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1787 OUT UINT32 *TransferResult
1788 )
1789 {
1790 return EFI_UNSUPPORTED;
1791 }
1792
1793
1794 /**
1795 Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
1796
1797 This : A pointer to the EFI_USB2_HC_PROTOCOL instance.
1798 DeviceAddress : Target device address
1799 EndPointAddress : Endpoint number and direction
1800 DeviceSpeed : Device speed
1801 MaximumPacketLength : Maximum packet size of the target endpoint
1802 DataBuffersNumber : Number of data buffers prepared for the transfer.
1803 Data : Array of pointers to the buffers of data
1804 Translator : A pointr to the transaction translator data.
1805 IsochronousCallBack : Function to call when the transfer complete
1806 Context : Pass to the call back function as parameter
1807
1808 @return EFI_UNSUPPORTED
1809
1810 **/
1811 STATIC
1812 EFI_STATUS
1813 EFIAPI
1814 Uhci2AsyncIsochronousTransfer (
1815 IN EFI_USB2_HC_PROTOCOL *This,
1816 IN UINT8 DeviceAddress,
1817 IN UINT8 EndPointAddress,
1818 IN UINT8 DeviceSpeed,
1819 IN UINTN MaximumPacketLength,
1820 IN UINT8 DataBuffersNumber,
1821 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1822 IN UINTN DataLength,
1823 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1824 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1825 IN VOID *Context
1826 )
1827 {
1828 return EFI_UNSUPPORTED;
1829 }
1830
1831 EFI_STATUS
1832 EFIAPI
1833 UhciDriverEntryPoint (
1834 IN EFI_HANDLE ImageHandle,
1835 IN EFI_SYSTEM_TABLE *SystemTable
1836 )
1837 /*++
1838
1839 Routine Description:
1840
1841 Entry point for EFI drivers.
1842
1843 Arguments:
1844
1845 ImageHandle - EFI_HANDLE
1846 SystemTable - EFI_SYSTEM_TABLE
1847
1848 Returns:
1849
1850 EFI_SUCCESS : Driver is successfully loaded
1851 Others : Failed
1852
1853 --*/
1854 {
1855 return EfiLibInstallDriverBindingComponentName2 (
1856 ImageHandle,
1857 SystemTable,
1858 &gUhciDriverBinding,
1859 ImageHandle,
1860 &gUhciComponentName,
1861 &gUhciComponentName2
1862 );
1863 }
1864
1865
1866 /**
1867 Test to see if this driver supports ControllerHandle. Any
1868 ControllerHandle that has UsbHcProtocol installed will be supported.
1869
1870 @param This Protocol instance pointer.
1871 @param Controller Handle of device to test
1872 @param RemainingDevicePath Not used
1873
1874 @return EFI_SUCCESS : This driver supports this device.
1875 @return EFI_UNSUPPORTED : This driver does not support this device.
1876
1877 **/
1878 EFI_STATUS
1879 EFIAPI
1880 UhciDriverBindingSupported (
1881 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1882 IN EFI_HANDLE Controller,
1883 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1884 )
1885 {
1886 EFI_STATUS OpenStatus;
1887 EFI_STATUS Status;
1888 EFI_PCI_IO_PROTOCOL *PciIo;
1889 USB_CLASSC UsbClassCReg;
1890
1891 //
1892 // Test whether there is PCI IO Protocol attached on the controller handle.
1893 //
1894 OpenStatus = gBS->OpenProtocol (
1895 Controller,
1896 &gEfiPciIoProtocolGuid,
1897 (VOID **) &PciIo,
1898 This->DriverBindingHandle,
1899 Controller,
1900 EFI_OPEN_PROTOCOL_BY_DRIVER
1901 );
1902
1903 if (EFI_ERROR (OpenStatus)) {
1904 return OpenStatus;
1905 }
1906
1907 Status = PciIo->Pci.Read (
1908 PciIo,
1909 EfiPciIoWidthUint8,
1910 CLASSC_OFFSET,
1911 sizeof (USB_CLASSC) / sizeof (UINT8),
1912 &UsbClassCReg
1913 );
1914
1915 if (EFI_ERROR (Status)) {
1916 Status = EFI_UNSUPPORTED;
1917 goto ON_EXIT;
1918 }
1919
1920 //
1921 // Test whether the controller belongs to UHCI type
1922 //
1923 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1924 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1925 (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)
1926 ) {
1927
1928 Status = EFI_UNSUPPORTED;
1929 }
1930
1931 ON_EXIT:
1932 gBS->CloseProtocol (
1933 Controller,
1934 &gEfiPciIoProtocolGuid,
1935 This->DriverBindingHandle,
1936 Controller
1937 );
1938
1939 return Status;
1940
1941 }
1942
1943
1944 /**
1945 Allocate and initialize the empty UHCI device
1946
1947 @param PciIo The PCIIO to use
1948
1949 @return Allocated UHCI device
1950
1951 **/
1952 STATIC
1953 USB_HC_DEV *
1954 UhciAllocateDev (
1955 IN EFI_PCI_IO_PROTOCOL *PciIo
1956 )
1957 {
1958 USB_HC_DEV *Uhc;
1959 EFI_STATUS Status;
1960
1961 Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
1962
1963 if (Uhc == NULL) {
1964 return NULL;
1965 }
1966
1967 //
1968 // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
1969 // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
1970 //
1971 Uhc->Signature = USB_HC_DEV_SIGNATURE;
1972 Uhc->UsbHc.Reset = UhciReset;
1973 Uhc->UsbHc.GetState = UhciGetState;
1974 Uhc->UsbHc.SetState = UhciSetState;
1975 Uhc->UsbHc.ControlTransfer = UhciControlTransfer;
1976 Uhc->UsbHc.BulkTransfer = UhciBulkTransfer;
1977 Uhc->UsbHc.AsyncInterruptTransfer = UhciAsyncInterruptTransfer;
1978 Uhc->UsbHc.SyncInterruptTransfer = UhciSyncInterruptTransfer;
1979 Uhc->UsbHc.IsochronousTransfer = UhciIsochronousTransfer;
1980 Uhc->UsbHc.AsyncIsochronousTransfer = UhciAsyncIsochronousTransfer;
1981 Uhc->UsbHc.GetRootHubPortNumber = UhciGetRootHubPortNumber;
1982 Uhc->UsbHc.GetRootHubPortStatus = UhciGetRootHubPortStatus;
1983 Uhc->UsbHc.SetRootHubPortFeature = UhciSetRootHubPortFeature;
1984 Uhc->UsbHc.ClearRootHubPortFeature = UhciClearRootHubPortFeature;
1985 Uhc->UsbHc.MajorRevision = 0x1;
1986 Uhc->UsbHc.MinorRevision = 0x1;
1987
1988 Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;
1989 Uhc->Usb2Hc.Reset = Uhci2Reset;
1990 Uhc->Usb2Hc.GetState = Uhci2GetState;
1991 Uhc->Usb2Hc.SetState = Uhci2SetState;
1992 Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;
1993 Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;
1994 Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;
1995 Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;
1996 Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;
1997 Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;
1998 Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;
1999 Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;
2000 Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;
2001 Uhc->Usb2Hc.MajorRevision = 0x1;
2002 Uhc->Usb2Hc.MinorRevision = 0x1;
2003
2004 Uhc->PciIo = PciIo;
2005 Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);
2006
2007 if (Uhc->MemPool == NULL) {
2008 Status = EFI_OUT_OF_RESOURCES;
2009 goto ON_ERROR;
2010 }
2011
2012 InitializeListHead (&Uhc->AsyncIntList);
2013
2014 Status = gBS->CreateEvent (
2015 EVT_TIMER | EVT_NOTIFY_SIGNAL,
2016 TPL_CALLBACK,
2017 UhciMonitorAsyncReqList,
2018 Uhc,
2019 &Uhc->AsyncIntMonitor
2020 );
2021
2022 if (EFI_ERROR (Status)) {
2023 UsbHcFreeMemPool (Uhc->MemPool);
2024 goto ON_ERROR;
2025 }
2026
2027 return Uhc;
2028
2029 ON_ERROR:
2030 gBS->FreePool (Uhc);
2031 return NULL;
2032 }
2033
2034
2035 /**
2036 Free the UHCI device and release its associated resources
2037
2038 @param Uhc The UHCI device to release
2039
2040 @return None
2041
2042 **/
2043 STATIC
2044 VOID
2045 UhciFreeDev (
2046 IN USB_HC_DEV *Uhc
2047 )
2048 {
2049 if (Uhc->AsyncIntMonitor != NULL) {
2050 gBS->CloseEvent (Uhc->AsyncIntMonitor);
2051 }
2052
2053 if (Uhc->MemPool != NULL) {
2054 UsbHcFreeMemPool (Uhc->MemPool);
2055 }
2056
2057 if (Uhc->CtrlNameTable) {
2058 FreeUnicodeStringTable (Uhc->CtrlNameTable);
2059 }
2060
2061 gBS->FreePool (Uhc);
2062 }
2063
2064
2065 /**
2066 Uninstall all Uhci Interface
2067
2068 @param Controller Controller handle
2069 @param This Protocol instance pointer.
2070
2071 @return VOID
2072
2073 **/
2074 STATIC
2075 VOID
2076 UhciCleanDevUp (
2077 IN EFI_HANDLE Controller,
2078 IN EFI_USB_HC_PROTOCOL *This
2079 )
2080 {
2081 USB_HC_DEV *Uhc;
2082
2083 //
2084 // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
2085 //
2086 Uhc = UHC_FROM_USB_HC_PROTO (This);
2087 UhciStopHc (Uhc, STALL_1_SECOND);
2088
2089 gBS->UninstallProtocolInterface (
2090 Controller,
2091 &gEfiUsbHcProtocolGuid,
2092 &Uhc->UsbHc
2093 );
2094
2095 gBS->UninstallProtocolInterface (
2096 Controller,
2097 &gEfiUsb2HcProtocolGuid,
2098 &Uhc->Usb2Hc
2099 );
2100
2101 UhciFreeAllAsyncReq (Uhc);
2102 UhciDestoryFrameList (Uhc);
2103
2104 Uhc->PciIo->Attributes (
2105 Uhc->PciIo,
2106 EfiPciIoAttributeOperationDisable,
2107 EFI_PCI_DEVICE_ENABLE,
2108 NULL
2109 );
2110
2111 UhciFreeDev (Uhc);
2112 }
2113
2114
2115 /**
2116 Starting the Usb UHCI Driver
2117
2118 @param This Protocol instance pointer.
2119 @param Controller Handle of device to test
2120 @param RemainingDevicePath Not used
2121
2122 @retval EFI_SUCCESS This driver supports this device.
2123 @retval EFI_UNSUPPORTED This driver does not support this device.
2124 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error
2125 EFI_OUT_OF_RESOURCES- Failed due to resource
2126 shortage
2127
2128 **/
2129 EFI_STATUS
2130 EFIAPI
2131 UhciDriverBindingStart (
2132 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2133 IN EFI_HANDLE Controller,
2134 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
2135 )
2136 {
2137 EFI_STATUS Status;
2138 EFI_PCI_IO_PROTOCOL *PciIo;
2139 USB_HC_DEV *Uhc;
2140
2141 //
2142 // Open PCIIO, then enable the EHC device and turn off emulation
2143 //
2144 Uhc = NULL;
2145 Status = gBS->OpenProtocol (
2146 Controller,
2147 &gEfiPciIoProtocolGuid,
2148 (VOID **) &PciIo,
2149 This->DriverBindingHandle,
2150 Controller,
2151 EFI_OPEN_PROTOCOL_BY_DRIVER
2152 );
2153
2154 if (EFI_ERROR (Status)) {
2155 return Status;
2156 }
2157
2158 UhciTurnOffUsbEmulation (PciIo);
2159
2160 Status = PciIo->Attributes (
2161 PciIo,
2162 EfiPciIoAttributeOperationEnable,
2163 EFI_PCI_DEVICE_ENABLE,
2164 NULL
2165 );
2166
2167 if (EFI_ERROR (Status)) {
2168 goto CLOSE_PCIIO;
2169 }
2170
2171 Uhc = UhciAllocateDev (PciIo);
2172
2173 if (Uhc == NULL) {
2174 Status = EFI_OUT_OF_RESOURCES;
2175 goto CLOSE_PCIIO;
2176 }
2177
2178 //
2179 // Allocate and Init Host Controller's Frame List Entry
2180 //
2181 Status = UhciInitFrameList (Uhc);
2182
2183 if (EFI_ERROR (Status)) {
2184 Status = EFI_OUT_OF_RESOURCES;
2185 goto FREE_UHC;
2186 }
2187
2188 Status = gBS->SetTimer (
2189 Uhc->AsyncIntMonitor,
2190 TimerPeriodic,
2191 INTERRUPT_POLLING_TIME
2192 );
2193
2194 if (EFI_ERROR (Status)) {
2195 goto FREE_UHC;
2196 }
2197
2198 //
2199 // Install both USB_HC_PROTOCOL and USB2_HC_PROTOCOL
2200 //
2201 Status = gBS->InstallMultipleProtocolInterfaces (
2202 &Controller,
2203 &gEfiUsbHcProtocolGuid,
2204 &Uhc->UsbHc,
2205 &gEfiUsb2HcProtocolGuid,
2206 &Uhc->Usb2Hc,
2207 NULL
2208 );
2209
2210 if (EFI_ERROR (Status)) {
2211 goto FREE_UHC;
2212 }
2213
2214 //
2215 // Install the component name protocol
2216 //
2217 Uhc->CtrlNameTable = NULL;
2218
2219 AddUnicodeString2 (
2220 "eng",
2221 gUhciComponentName.SupportedLanguages,
2222 &Uhc->CtrlNameTable,
2223 L"Usb Universal Host Controller",
2224 TRUE
2225 );
2226 AddUnicodeString2 (
2227 "en",
2228 gUhciComponentName2.SupportedLanguages,
2229 &Uhc->CtrlNameTable,
2230 L"Usb Universal Host Controller",
2231 FALSE
2232 );
2233
2234
2235 //
2236 // Start the UHCI hardware, also set its reclamation point to 64 bytes
2237 //
2238 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
2239
2240 return EFI_SUCCESS;
2241
2242 FREE_UHC:
2243 UhciFreeDev (Uhc);
2244
2245 CLOSE_PCIIO:
2246 gBS->CloseProtocol (
2247 Controller,
2248 &gEfiPciIoProtocolGuid,
2249 This->DriverBindingHandle,
2250 Controller
2251 );
2252
2253 return Status;
2254 }
2255
2256
2257 /**
2258 Stop this driver on ControllerHandle. Support stoping any child handles
2259 created by this driver.
2260
2261 @param This Protocol instance pointer.
2262 @param Controller Handle of device to stop driver on
2263 @param NumberOfChildren Number of Children in the ChildHandleBuffer
2264 @param ChildHandleBuffer List of handles for the children we need to stop.
2265
2266 @return EFI_SUCCESS
2267 @return others
2268
2269 **/
2270 EFI_STATUS
2271 EFIAPI
2272 UhciDriverBindingStop (
2273 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2274 IN EFI_HANDLE Controller,
2275 IN UINTN NumberOfChildren,
2276 IN EFI_HANDLE *ChildHandleBuffer
2277 )
2278 {
2279 EFI_USB_HC_PROTOCOL *UsbHc;
2280 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2281 EFI_STATUS Status;
2282
2283 Status = gBS->OpenProtocol (
2284 Controller,
2285 &gEfiUsbHcProtocolGuid,
2286 (VOID **) &UsbHc,
2287 This->DriverBindingHandle,
2288 Controller,
2289 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2290 );
2291 //
2292 // Test whether the Controller handler passed in is a valid
2293 // Usb controller handle that should be supported, if not,
2294 // return the error status directly
2295 //
2296 if (EFI_ERROR (Status)) {
2297 return Status;
2298 }
2299
2300 Status = gBS->OpenProtocol (
2301 Controller,
2302 &gEfiUsb2HcProtocolGuid,
2303 (VOID **) &Usb2Hc,
2304 This->DriverBindingHandle,
2305 Controller,
2306 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2307 );
2308
2309 //
2310 // Test whether the Controller handler passed in is a valid
2311 // Usb controller handle that should be supported, if not,
2312 // return the error status directly
2313 //
2314 if (EFI_ERROR (Status)) {
2315 return Status;
2316 }
2317
2318 UhciCleanDevUp (Controller, UsbHc);
2319
2320 gBS->CloseProtocol (
2321 Controller,
2322 &gEfiPciIoProtocolGuid,
2323 This->DriverBindingHandle,
2324 Controller
2325 );
2326
2327 return EFI_SUCCESS;
2328 }
2329
2330 EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
2331 UhciDriverBindingSupported,
2332 UhciDriverBindingStart,
2333 UhciDriverBindingStop,
2334 0x20,
2335 NULL,
2336 NULL
2337 };