]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
1. Sync Tcp4 protocol definitions to match UEFI 2.1
[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 EfiLibInstallAllDriverProtocols (
1856 ImageHandle,
1857 SystemTable,
1858 &gUhciDriverBinding,
1859 ImageHandle,
1860 &gUhciComponentName,
1861 NULL,
1862 NULL
1863 );
1864 }
1865
1866
1867 /**
1868 Test to see if this driver supports ControllerHandle. Any
1869 ControllerHandle that has UsbHcProtocol installed will be supported.
1870
1871 @param This Protocol instance pointer.
1872 @param Controller Handle of device to test
1873 @param RemainingDevicePath Not used
1874
1875 @return EFI_SUCCESS : This driver supports this device.
1876 @return EFI_UNSUPPORTED : This driver does not support this device.
1877
1878 **/
1879 EFI_STATUS
1880 EFIAPI
1881 UhciDriverBindingSupported (
1882 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1883 IN EFI_HANDLE Controller,
1884 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1885 )
1886 {
1887 EFI_STATUS OpenStatus;
1888 EFI_STATUS Status;
1889 EFI_PCI_IO_PROTOCOL *PciIo;
1890 USB_CLASSC UsbClassCReg;
1891
1892 //
1893 // Test whether there is PCI IO Protocol attached on the controller handle.
1894 //
1895 OpenStatus = gBS->OpenProtocol (
1896 Controller,
1897 &gEfiPciIoProtocolGuid,
1898 (VOID **) &PciIo,
1899 This->DriverBindingHandle,
1900 Controller,
1901 EFI_OPEN_PROTOCOL_BY_DRIVER
1902 );
1903
1904 if (EFI_ERROR (OpenStatus)) {
1905 return OpenStatus;
1906 }
1907
1908 Status = PciIo->Pci.Read (
1909 PciIo,
1910 EfiPciIoWidthUint8,
1911 CLASSC_OFFSET,
1912 sizeof (USB_CLASSC) / sizeof (UINT8),
1913 &UsbClassCReg
1914 );
1915
1916 if (EFI_ERROR (Status)) {
1917 Status = EFI_UNSUPPORTED;
1918 goto ON_EXIT;
1919 }
1920
1921 //
1922 // Test whether the controller belongs to UHCI type
1923 //
1924 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1925 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1926 (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)
1927 ) {
1928
1929 Status = EFI_UNSUPPORTED;
1930 }
1931
1932 ON_EXIT:
1933 gBS->CloseProtocol (
1934 Controller,
1935 &gEfiPciIoProtocolGuid,
1936 This->DriverBindingHandle,
1937 Controller
1938 );
1939
1940 return Status;
1941
1942 }
1943
1944
1945 /**
1946 Allocate and initialize the empty UHCI device
1947
1948 @param PciIo The PCIIO to use
1949
1950 @return Allocated UHCI device
1951
1952 **/
1953 STATIC
1954 USB_HC_DEV *
1955 UhciAllocateDev (
1956 IN EFI_PCI_IO_PROTOCOL *PciIo
1957 )
1958 {
1959 USB_HC_DEV *Uhc;
1960 EFI_STATUS Status;
1961
1962 Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
1963
1964 if (Uhc == NULL) {
1965 return NULL;
1966 }
1967
1968 //
1969 // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
1970 // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
1971 //
1972 Uhc->Signature = USB_HC_DEV_SIGNATURE;
1973 Uhc->UsbHc.Reset = UhciReset;
1974 Uhc->UsbHc.GetState = UhciGetState;
1975 Uhc->UsbHc.SetState = UhciSetState;
1976 Uhc->UsbHc.ControlTransfer = UhciControlTransfer;
1977 Uhc->UsbHc.BulkTransfer = UhciBulkTransfer;
1978 Uhc->UsbHc.AsyncInterruptTransfer = UhciAsyncInterruptTransfer;
1979 Uhc->UsbHc.SyncInterruptTransfer = UhciSyncInterruptTransfer;
1980 Uhc->UsbHc.IsochronousTransfer = UhciIsochronousTransfer;
1981 Uhc->UsbHc.AsyncIsochronousTransfer = UhciAsyncIsochronousTransfer;
1982 Uhc->UsbHc.GetRootHubPortNumber = UhciGetRootHubPortNumber;
1983 Uhc->UsbHc.GetRootHubPortStatus = UhciGetRootHubPortStatus;
1984 Uhc->UsbHc.SetRootHubPortFeature = UhciSetRootHubPortFeature;
1985 Uhc->UsbHc.ClearRootHubPortFeature = UhciClearRootHubPortFeature;
1986 Uhc->UsbHc.MajorRevision = 0x1;
1987 Uhc->UsbHc.MinorRevision = 0x1;
1988
1989 Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;
1990 Uhc->Usb2Hc.Reset = Uhci2Reset;
1991 Uhc->Usb2Hc.GetState = Uhci2GetState;
1992 Uhc->Usb2Hc.SetState = Uhci2SetState;
1993 Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;
1994 Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;
1995 Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;
1996 Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;
1997 Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;
1998 Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;
1999 Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;
2000 Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;
2001 Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;
2002 Uhc->Usb2Hc.MajorRevision = 0x1;
2003 Uhc->Usb2Hc.MinorRevision = 0x1;
2004
2005 Uhc->PciIo = PciIo;
2006 Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);
2007
2008 if (Uhc->MemPool == NULL) {
2009 Status = EFI_OUT_OF_RESOURCES;
2010 goto ON_ERROR;
2011 }
2012
2013 InitializeListHead (&Uhc->AsyncIntList);
2014
2015 Status = gBS->CreateEvent (
2016 EVT_TIMER | EVT_NOTIFY_SIGNAL,
2017 TPL_CALLBACK,
2018 UhciMonitorAsyncReqList,
2019 Uhc,
2020 &Uhc->AsyncIntMonitor
2021 );
2022
2023 if (EFI_ERROR (Status)) {
2024 UsbHcFreeMemPool (Uhc->MemPool);
2025 goto ON_ERROR;
2026 }
2027
2028 return Uhc;
2029
2030 ON_ERROR:
2031 gBS->FreePool (Uhc);
2032 return NULL;
2033 }
2034
2035
2036 /**
2037 Free the UHCI device and release its associated resources
2038
2039 @param Uhc The UHCI device to release
2040
2041 @return None
2042
2043 **/
2044 STATIC
2045 VOID
2046 UhciFreeDev (
2047 IN USB_HC_DEV *Uhc
2048 )
2049 {
2050 if (Uhc->AsyncIntMonitor != NULL) {
2051 gBS->CloseEvent (Uhc->AsyncIntMonitor);
2052 }
2053
2054 if (Uhc->MemPool != NULL) {
2055 UsbHcFreeMemPool (Uhc->MemPool);
2056 }
2057
2058 if (Uhc->CtrlNameTable) {
2059 FreeUnicodeStringTable (Uhc->CtrlNameTable);
2060 }
2061
2062 gBS->FreePool (Uhc);
2063 }
2064
2065
2066 /**
2067 Uninstall all Uhci Interface
2068
2069 @param Controller Controller handle
2070 @param This Protocol instance pointer.
2071
2072 @return VOID
2073
2074 **/
2075 STATIC
2076 VOID
2077 UhciCleanDevUp (
2078 IN EFI_HANDLE Controller,
2079 IN EFI_USB_HC_PROTOCOL *This
2080 )
2081 {
2082 USB_HC_DEV *Uhc;
2083
2084 //
2085 // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
2086 //
2087 Uhc = UHC_FROM_USB_HC_PROTO (This);
2088 UhciStopHc (Uhc, STALL_1_SECOND);
2089
2090 gBS->UninstallProtocolInterface (
2091 Controller,
2092 &gEfiUsbHcProtocolGuid,
2093 &Uhc->UsbHc
2094 );
2095
2096 gBS->UninstallProtocolInterface (
2097 Controller,
2098 &gEfiUsb2HcProtocolGuid,
2099 &Uhc->Usb2Hc
2100 );
2101
2102 UhciFreeAllAsyncReq (Uhc);
2103 UhciDestoryFrameList (Uhc);
2104
2105 Uhc->PciIo->Attributes (
2106 Uhc->PciIo,
2107 EfiPciIoAttributeOperationDisable,
2108 EFI_PCI_DEVICE_ENABLE,
2109 NULL
2110 );
2111
2112 UhciFreeDev (Uhc);
2113 }
2114
2115
2116 /**
2117 Starting the Usb UHCI Driver
2118
2119 @param This Protocol instance pointer.
2120 @param Controller Handle of device to test
2121 @param RemainingDevicePath Not used
2122
2123 @retval EFI_SUCCESS This driver supports this device.
2124 @retval EFI_UNSUPPORTED This driver does not support this device.
2125 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error
2126 EFI_OUT_OF_RESOURCES- Failed due to resource
2127 shortage
2128
2129 **/
2130 EFI_STATUS
2131 EFIAPI
2132 UhciDriverBindingStart (
2133 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2134 IN EFI_HANDLE Controller,
2135 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
2136 )
2137 {
2138 EFI_STATUS Status;
2139 EFI_PCI_IO_PROTOCOL *PciIo;
2140 USB_HC_DEV *Uhc;
2141
2142 //
2143 // Open PCIIO, then enable the EHC device and turn off emulation
2144 //
2145 Uhc = NULL;
2146 Status = gBS->OpenProtocol (
2147 Controller,
2148 &gEfiPciIoProtocolGuid,
2149 (VOID **) &PciIo,
2150 This->DriverBindingHandle,
2151 Controller,
2152 EFI_OPEN_PROTOCOL_BY_DRIVER
2153 );
2154
2155 if (EFI_ERROR (Status)) {
2156 return Status;
2157 }
2158
2159 UhciTurnOffUsbEmulation (PciIo);
2160
2161 Status = PciIo->Attributes (
2162 PciIo,
2163 EfiPciIoAttributeOperationEnable,
2164 EFI_PCI_DEVICE_ENABLE,
2165 NULL
2166 );
2167
2168 if (EFI_ERROR (Status)) {
2169 goto CLOSE_PCIIO;
2170 }
2171
2172 Uhc = UhciAllocateDev (PciIo);
2173
2174 if (Uhc == NULL) {
2175 Status = EFI_OUT_OF_RESOURCES;
2176 goto CLOSE_PCIIO;
2177 }
2178
2179 //
2180 // Allocate and Init Host Controller's Frame List Entry
2181 //
2182 Status = UhciInitFrameList (Uhc);
2183
2184 if (EFI_ERROR (Status)) {
2185 Status = EFI_OUT_OF_RESOURCES;
2186 goto FREE_UHC;
2187 }
2188
2189 Status = gBS->SetTimer (
2190 Uhc->AsyncIntMonitor,
2191 TimerPeriodic,
2192 INTERRUPT_POLLING_TIME
2193 );
2194
2195 if (EFI_ERROR (Status)) {
2196 goto FREE_UHC;
2197 }
2198
2199 //
2200 // Install both USB_HC_PROTOCOL and USB2_HC_PROTOCOL
2201 //
2202 Status = gBS->InstallMultipleProtocolInterfaces (
2203 &Controller,
2204 &gEfiUsbHcProtocolGuid,
2205 &Uhc->UsbHc,
2206 &gEfiUsb2HcProtocolGuid,
2207 &Uhc->Usb2Hc,
2208 NULL
2209 );
2210
2211 if (EFI_ERROR (Status)) {
2212 goto FREE_UHC;
2213 }
2214
2215 //
2216 // Install the component name protocol
2217 //
2218 Uhc->CtrlNameTable = NULL;
2219
2220 AddUnicodeString (
2221 "eng",
2222 gUhciComponentName.SupportedLanguages,
2223 &Uhc->CtrlNameTable,
2224 L"Usb Universal Host Controller"
2225 );
2226
2227 //
2228 // Start the UHCI hardware, also set its reclamation point to 64 bytes
2229 //
2230 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
2231
2232 return EFI_SUCCESS;
2233
2234 FREE_UHC:
2235 UhciFreeDev (Uhc);
2236
2237 CLOSE_PCIIO:
2238 gBS->CloseProtocol (
2239 Controller,
2240 &gEfiPciIoProtocolGuid,
2241 This->DriverBindingHandle,
2242 Controller
2243 );
2244
2245 return Status;
2246 }
2247
2248
2249 /**
2250 Stop this driver on ControllerHandle. Support stoping any child handles
2251 created by this driver.
2252
2253 @param This Protocol instance pointer.
2254 @param Controller Handle of device to stop driver on
2255 @param NumberOfChildren Number of Children in the ChildHandleBuffer
2256 @param ChildHandleBuffer List of handles for the children we need to stop.
2257
2258 @return EFI_SUCCESS
2259 @return others
2260
2261 **/
2262 EFI_STATUS
2263 EFIAPI
2264 UhciDriverBindingStop (
2265 IN EFI_DRIVER_BINDING_PROTOCOL *This,
2266 IN EFI_HANDLE Controller,
2267 IN UINTN NumberOfChildren,
2268 IN EFI_HANDLE *ChildHandleBuffer
2269 )
2270 {
2271 EFI_USB_HC_PROTOCOL *UsbHc;
2272 EFI_USB2_HC_PROTOCOL *Usb2Hc;
2273 EFI_STATUS Status;
2274
2275 Status = gBS->OpenProtocol (
2276 Controller,
2277 &gEfiUsbHcProtocolGuid,
2278 (VOID **) &UsbHc,
2279 This->DriverBindingHandle,
2280 Controller,
2281 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2282 );
2283 //
2284 // Test whether the Controller handler passed in is a valid
2285 // Usb controller handle that should be supported, if not,
2286 // return the error status directly
2287 //
2288 if (EFI_ERROR (Status)) {
2289 return Status;
2290 }
2291
2292 Status = gBS->OpenProtocol (
2293 Controller,
2294 &gEfiUsb2HcProtocolGuid,
2295 (VOID **) &Usb2Hc,
2296 This->DriverBindingHandle,
2297 Controller,
2298 EFI_OPEN_PROTOCOL_GET_PROTOCOL
2299 );
2300
2301 //
2302 // Test whether the Controller handler passed in is a valid
2303 // Usb controller handle that should be supported, if not,
2304 // return the error status directly
2305 //
2306 if (EFI_ERROR (Status)) {
2307 return Status;
2308 }
2309
2310 UhciCleanDevUp (Controller, UsbHc);
2311
2312 gBS->CloseProtocol (
2313 Controller,
2314 &gEfiPciIoProtocolGuid,
2315 This->DriverBindingHandle,
2316 Controller
2317 );
2318
2319 return EFI_SUCCESS;
2320 }
2321
2322 EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
2323 UhciDriverBindingSupported,
2324 UhciDriverBindingStart,
2325 UhciDriverBindingStop,
2326 0x20,
2327 NULL,
2328 NULL
2329 };