]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
a4cb27af90b4421129e634df98ec931cce3489b5
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UhciDxe / Uhci.c
1 /** @file
2
3 The UHCI driver model and HC protocol routines.
4
5 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "Uhci.h"
17
18
19 EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
20 UhciDriverBindingSupported,
21 UhciDriverBindingStart,
22 UhciDriverBindingStop,
23 0x20,
24 NULL,
25 NULL
26 };
27
28 /**
29 Provides software reset for the USB host controller according to UEFI 2.0 spec.
30
31 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
32 @param Attributes A bit mask of the reset operation to perform. See
33 below for a list of the supported bit mask values.
34
35 @return EFI_SUCCESS The reset operation succeeded.
36 @return EFI_INVALID_PARAMETER Attributes is not valid.
37 @return EFI_UNSUPPORTED This type of reset is not currently supported.
38 @return EFI_DEVICE_ERROR Other errors.
39
40 **/
41 EFI_STATUS
42 EFIAPI
43 Uhci2Reset (
44 IN EFI_USB2_HC_PROTOCOL *This,
45 IN UINT16 Attributes
46 )
47 {
48 USB_HC_DEV *Uhc;
49 EFI_TPL OldTpl;
50
51 if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||
52 (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {
53 return EFI_UNSUPPORTED;
54 }
55
56 Uhc = UHC_FROM_USB2_HC_PROTO (This);
57
58 if (Uhc->DevicePath != NULL) {
59 //
60 // Report Status Code to indicate reset happens
61 //
62 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
63 EFI_PROGRESS_CODE,
64 (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
65 Uhc->DevicePath
66 );
67 }
68
69 OldTpl = gBS->RaiseTPL (UHCI_TPL);
70
71 switch (Attributes) {
72 case EFI_USB_HC_RESET_GLOBAL:
73 //
74 // Stop schedule and set the Global Reset bit in the command register
75 //
76 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
77 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
78
79 gBS->Stall (UHC_ROOT_PORT_RESET_STALL);
80
81 //
82 // Clear the Global Reset bit to zero.
83 //
84 UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
85
86 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
87 break;
88
89 case EFI_USB_HC_RESET_HOST_CONTROLLER:
90 //
91 // Stop schedule and set Host Controller Reset bit to 1
92 //
93 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
94 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
95
96 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
97 break;
98
99 default:
100 goto ON_INVAILD_PARAMETER;
101 }
102
103 //
104 // Delete all old transactions on the USB bus, then
105 // reinitialize the frame list
106 //
107 UhciFreeAllAsyncReq (Uhc);
108 UhciDestoryFrameList (Uhc);
109 UhciInitFrameList (Uhc);
110
111 gBS->RestoreTPL (OldTpl);
112
113 return EFI_SUCCESS;
114
115 ON_INVAILD_PARAMETER:
116
117 gBS->RestoreTPL (OldTpl);
118
119 return EFI_INVALID_PARAMETER;
120 }
121
122
123 /**
124 Retrieves current state of the USB host controller according to UEFI 2.0 spec.
125
126 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
127 @param State Variable to receive current device state.
128
129 @return EFI_SUCCESS The state is returned.
130 @return EFI_INVALID_PARAMETER State is not valid.
131 @return EFI_DEVICE_ERROR Other errors.
132
133 **/
134 EFI_STATUS
135 EFIAPI
136 Uhci2GetState (
137 IN EFI_USB2_HC_PROTOCOL *This,
138 OUT EFI_USB_HC_STATE *State
139 )
140 {
141 USB_HC_DEV *Uhc;
142 UINT16 UsbSts;
143 UINT16 UsbCmd;
144
145 if (State == NULL) {
146 return EFI_INVALID_PARAMETER;
147 }
148
149 Uhc = UHC_FROM_USB2_HC_PROTO (This);
150
151 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
152 UsbSts = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
153
154 if ((UsbCmd & USBCMD_EGSM) !=0 ) {
155 *State = EfiUsbHcStateSuspend;
156
157 } else if ((UsbSts & USBSTS_HCH) != 0) {
158 *State = EfiUsbHcStateHalt;
159
160 } else {
161 *State = EfiUsbHcStateOperational;
162 }
163
164 return EFI_SUCCESS;
165 }
166
167
168 /**
169 Sets the USB host controller to a specific state according to UEFI 2.0 spec.
170
171 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
172 @param State Indicates the state of the host controller that will
173 be set.
174
175 @return EFI_SUCCESS Host controller was successfully placed in the state.
176 @return EFI_INVALID_PARAMETER State is invalid.
177 @return EFI_DEVICE_ERROR Failed to set the state.
178
179 **/
180 EFI_STATUS
181 EFIAPI
182 Uhci2SetState (
183 IN EFI_USB2_HC_PROTOCOL *This,
184 IN EFI_USB_HC_STATE State
185 )
186 {
187 EFI_USB_HC_STATE CurState;
188 USB_HC_DEV *Uhc;
189 EFI_TPL OldTpl;
190 EFI_STATUS Status;
191 UINT16 UsbCmd;
192
193 Uhc = UHC_FROM_USB2_HC_PROTO (This);
194 Status = Uhci2GetState (This, &CurState);
195
196 if (EFI_ERROR (Status)) {
197 return EFI_DEVICE_ERROR;
198 }
199
200 if (CurState == State) {
201 return EFI_SUCCESS;
202 }
203
204 Status = EFI_SUCCESS;
205 OldTpl = gBS->RaiseTPL (UHCI_TPL);
206
207 switch (State) {
208 case EfiUsbHcStateHalt:
209 Status = UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
210 break;
211
212 case EfiUsbHcStateOperational:
213 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
214
215 if (CurState == EfiUsbHcStateHalt) {
216 //
217 // Set Run/Stop bit to 1, also set the bandwidht reclamation
218 // point to 64 bytes
219 //
220 UsbCmd |= USBCMD_RS | USBCMD_MAXP;
221 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
222
223 } else if (CurState == EfiUsbHcStateSuspend) {
224 //
225 // If FGR(Force Global Resume) bit is 0, set it
226 //
227 if ((UsbCmd & USBCMD_FGR) == 0) {
228 UsbCmd |= USBCMD_FGR;
229 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
230 }
231
232 //
233 // wait 20ms to let resume complete (20ms is specified by UHCI spec)
234 //
235 gBS->Stall (UHC_FORCE_GLOBAL_RESUME_STALL);
236
237 //
238 // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
239 //
240 UsbCmd &= ~USBCMD_FGR;
241 UsbCmd &= ~USBCMD_EGSM;
242 UsbCmd |= USBCMD_RS;
243 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
244 }
245
246 break;
247
248 case EfiUsbHcStateSuspend:
249 Status = Uhci2SetState (This, EfiUsbHcStateHalt);
250
251 if (EFI_ERROR (Status)) {
252 Status = EFI_DEVICE_ERROR;
253 goto ON_EXIT;
254 }
255
256 //
257 // Set Enter Global Suspend Mode bit to 1.
258 //
259 UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
260 UsbCmd |= USBCMD_EGSM;
261 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
262 break;
263
264 default:
265 Status = EFI_INVALID_PARAMETER;
266 break;
267 }
268
269 ON_EXIT:
270 gBS->RestoreTPL (OldTpl);
271 return Status;
272 }
273
274 /**
275 Retrieves capabilities of USB host controller according to UEFI 2.0 spec.
276
277 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
278 @param MaxSpeed A pointer to the max speed USB host controller
279 supports.
280 @param PortNumber A pointer to the number of root hub ports.
281 @param Is64BitCapable A pointer to an integer to show whether USB host
282 controller supports 64-bit memory addressing.
283
284 @return EFI_SUCCESS capabilities were retrieved successfully.
285 @return EFI_INVALID_PARAMETER MaxSpeed or PortNumber or Is64BitCapable is NULL.
286 @return EFI_DEVICE_ERROR An error was encountered.
287
288 **/
289 EFI_STATUS
290 EFIAPI
291 Uhci2GetCapability (
292 IN EFI_USB2_HC_PROTOCOL *This,
293 OUT UINT8 *MaxSpeed,
294 OUT UINT8 *PortNumber,
295 OUT UINT8 *Is64BitCapable
296 )
297 {
298 USB_HC_DEV *Uhc;
299 UINT32 Offset;
300 UINT16 PortSC;
301 UINT32 Index;
302
303 Uhc = UHC_FROM_USB2_HC_PROTO (This);
304
305 if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {
306 return EFI_INVALID_PARAMETER;
307 }
308
309 *MaxSpeed = EFI_USB_SPEED_FULL;
310 *Is64BitCapable = (UINT8) FALSE;
311
312 *PortNumber = 0;
313
314 for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {
315 Offset = USBPORTSC_OFFSET + Index * 2;
316 PortSC = UhciReadReg (Uhc->PciIo, Offset);
317
318 //
319 // Port status's bit 7 is reserved and always returns 1 if
320 // the port number is valid. Intel's UHCI (in EHCI controller)
321 // returns 0 in this bit if port number is invalid. Also, if
322 // PciIo IoRead returns error, 0xFFFF is returned to caller.
323 //
324 if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) {
325 break;
326 }
327 (*PortNumber)++;
328 }
329
330 Uhc->RootPorts = *PortNumber;
331
332 DEBUG ((EFI_D_INFO, "Uhci2GetCapability: %d ports\n", (UINT32)Uhc->RootPorts));
333 return EFI_SUCCESS;
334 }
335
336
337 /**
338 Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.
339
340 @param This A pointer to the EFI_USB2_HC_PROTOCOL.
341 @param PortNumber The port to get status.
342 @param PortStatus A pointer to the current port status bits and port
343 status change bits.
344
345 @return EFI_SUCCESS status of the USB root hub port was returned in PortStatus.
346 @return EFI_INVALID_PARAMETER PortNumber is invalid.
347 @return EFI_DEVICE_ERROR Can't read register.
348
349 **/
350 EFI_STATUS
351 EFIAPI
352 Uhci2GetRootHubPortStatus (
353 IN EFI_USB2_HC_PROTOCOL *This,
354 IN UINT8 PortNumber,
355 OUT EFI_USB_PORT_STATUS *PortStatus
356 )
357 {
358 USB_HC_DEV *Uhc;
359 UINT32 Offset;
360 UINT16 PortSC;
361
362 Uhc = UHC_FROM_USB2_HC_PROTO (This);
363
364 if (PortStatus == NULL) {
365 return EFI_INVALID_PARAMETER;
366 }
367
368 if (PortNumber >= Uhc->RootPorts) {
369 return EFI_INVALID_PARAMETER;
370 }
371
372 Offset = USBPORTSC_OFFSET + PortNumber * 2;
373 PortStatus->PortStatus = 0;
374 PortStatus->PortChangeStatus = 0;
375
376 PortSC = UhciReadReg (Uhc->PciIo, Offset);
377
378 if ((PortSC & USBPORTSC_CCS) != 0) {
379 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
380 }
381
382 if ((PortSC & USBPORTSC_PED) != 0) {
383 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
384 }
385
386 if ((PortSC & USBPORTSC_SUSP) != 0) {
387 DEBUG ((EFI_D_INFO, "Uhci2GetRootHubPortStatus: port %d is suspended\n", PortNumber));
388 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
389 }
390
391 if ((PortSC & USBPORTSC_PR) != 0) {
392 PortStatus->PortStatus |= USB_PORT_STAT_RESET;
393 }
394
395 if ((PortSC & USBPORTSC_LSDA) != 0) {
396 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
397 }
398
399 //
400 // CHC will always return one in port owner bit
401 //
402 PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
403
404 if ((PortSC & USBPORTSC_CSC) != 0) {
405 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
406 }
407
408 if ((PortSC & USBPORTSC_PEDC) != 0) {
409 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
410 }
411
412 return EFI_SUCCESS;
413 }
414
415
416 /**
417 Sets a feature for the specified root hub port according to UEFI 2.0 spec.
418
419 @param This A pointer to the EFI_USB2_HC_PROTOCOL.
420 @param PortNumber Specifies the root hub port whose feature is
421 requested to be set.
422 @param PortFeature Indicates the feature selector associated with the
423 feature set request.
424
425 @return EFI_SUCCESS PortFeature was set for the root port.
426 @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
427 @return EFI_DEVICE_ERROR Can't read register.
428
429 **/
430 EFI_STATUS
431 EFIAPI
432 Uhci2SetRootHubPortFeature (
433 IN EFI_USB2_HC_PROTOCOL *This,
434 IN UINT8 PortNumber,
435 IN EFI_USB_PORT_FEATURE PortFeature
436 )
437 {
438 USB_HC_DEV *Uhc;
439 EFI_TPL OldTpl;
440 UINT32 Offset;
441 UINT16 PortSC;
442 UINT16 Command;
443
444 Uhc = UHC_FROM_USB2_HC_PROTO (This);
445
446 if (PortNumber >= Uhc->RootPorts) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 Offset = USBPORTSC_OFFSET + PortNumber * 2;
451
452 OldTpl = gBS->RaiseTPL (UHCI_TPL);
453 PortSC = UhciReadReg (Uhc->PciIo, Offset);
454
455 switch (PortFeature) {
456 case EfiUsbPortSuspend:
457 Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
458 if ((Command & USBCMD_EGSM) == 0) {
459 //
460 // if global suspend is not active, can set port suspend
461 //
462 PortSC &= 0xfff5;
463 PortSC |= USBPORTSC_SUSP;
464 }
465 break;
466
467 case EfiUsbPortReset:
468 PortSC &= 0xfff5;
469 PortSC |= USBPORTSC_PR;
470 break;
471
472 case EfiUsbPortPower:
473 //
474 // No action
475 //
476 break;
477
478 case EfiUsbPortEnable:
479 PortSC &= 0xfff5;
480 PortSC |= USBPORTSC_PED;
481 break;
482
483 default:
484 gBS->RestoreTPL (OldTpl);
485 return EFI_INVALID_PARAMETER;
486 }
487
488 UhciWriteReg (Uhc->PciIo, Offset, PortSC);
489 gBS->RestoreTPL (OldTpl);
490
491 return EFI_SUCCESS;
492 }
493
494
495 /**
496 Clears a feature for the specified root hub port according to Uefi 2.0 spec.
497
498 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
499 @param PortNumber Specifies the root hub port whose feature is
500 requested to be cleared.
501 @param PortFeature Indicates the feature selector associated with the
502 feature clear request.
503
504 @return EFI_SUCCESS PortFeature was cleared for the USB root hub port.
505 @return EFI_INVALID_PARAMETER PortNumber is invalid or PortFeature is invalid.
506 @return EFI_DEVICE_ERROR Can't read register.
507
508 **/
509 EFI_STATUS
510 EFIAPI
511 Uhci2ClearRootHubPortFeature (
512 IN EFI_USB2_HC_PROTOCOL *This,
513 IN UINT8 PortNumber,
514 IN EFI_USB_PORT_FEATURE PortFeature
515 )
516 {
517 USB_HC_DEV *Uhc;
518 EFI_TPL OldTpl;
519 UINT32 Offset;
520 UINT16 PortSC;
521
522 Uhc = UHC_FROM_USB2_HC_PROTO (This);
523
524 if (PortNumber >= Uhc->RootPorts) {
525 return EFI_INVALID_PARAMETER;
526 }
527
528 Offset = USBPORTSC_OFFSET + PortNumber * 2;
529
530 OldTpl = gBS->RaiseTPL (UHCI_TPL);
531 PortSC = UhciReadReg (Uhc->PciIo, Offset);
532
533 switch (PortFeature) {
534 case EfiUsbPortEnable:
535 PortSC &= 0xfff5;
536 PortSC &= ~USBPORTSC_PED;
537 break;
538
539 case EfiUsbPortSuspend:
540 //
541 // Cause a resume on the specified port if in suspend mode.
542 //
543 PortSC &= 0xfff5;
544 PortSC &= ~USBPORTSC_SUSP;
545 break;
546
547 case EfiUsbPortPower:
548 //
549 // No action
550 //
551 break;
552
553 case EfiUsbPortReset:
554 PortSC &= 0xfff5;
555 PortSC &= ~USBPORTSC_PR;
556 break;
557
558 case EfiUsbPortConnectChange:
559 PortSC &= 0xfff5;
560 PortSC |= USBPORTSC_CSC;
561 break;
562
563 case EfiUsbPortEnableChange:
564 PortSC &= 0xfff5;
565 PortSC |= USBPORTSC_PEDC;
566 break;
567
568 case EfiUsbPortSuspendChange:
569 //
570 // Root hub does not support this
571 //
572 break;
573
574 case EfiUsbPortOverCurrentChange:
575 //
576 // Root hub does not support this
577 //
578 break;
579
580 case EfiUsbPortResetChange:
581 //
582 // Root hub does not support this
583 //
584 break;
585
586 default:
587 gBS->RestoreTPL (OldTpl);
588 return EFI_INVALID_PARAMETER;
589 }
590
591 UhciWriteReg (Uhc->PciIo, Offset, PortSC);
592 gBS->RestoreTPL (OldTpl);
593
594 return EFI_SUCCESS;
595 }
596
597
598 /**
599 Submits control transfer to a target USB device according to UEFI 2.0 spec.
600
601 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
602 @param DeviceAddress Target device address.
603 @param DeviceSpeed Device speed.
604 @param MaximumPacketLength Maximum packet size of the target endpoint.
605 @param Request USB device request to send.
606 @param TransferDirection Data direction of the Data stage in control transfer.
607 @param Data Data to transmit/receive in data stage.
608 @param DataLength Length of the data.
609 @param TimeOut Maximum time, in microseconds, for transfer to complete.
610 @param Translator Transaction translator to be used by this device.
611 @param TransferResult Variable to receive the transfer result.
612
613 @return EFI_SUCCESS The control transfer was completed successfully.
614 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
615 @return EFI_INVALID_PARAMETER Some parameters are invalid.
616 @return EFI_TIMEOUT Failed due to timeout.
617 @return EFI_DEVICE_ERROR Failed due to host controller or device error.
618
619 **/
620 EFI_STATUS
621 EFIAPI
622 Uhci2ControlTransfer (
623 IN EFI_USB2_HC_PROTOCOL *This,
624 IN UINT8 DeviceAddress,
625 IN UINT8 DeviceSpeed,
626 IN UINTN MaximumPacketLength,
627 IN EFI_USB_DEVICE_REQUEST *Request,
628 IN EFI_USB_DATA_DIRECTION TransferDirection,
629 IN OUT VOID *Data,
630 IN OUT UINTN *DataLength,
631 IN UINTN TimeOut,
632 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
633 OUT UINT32 *TransferResult
634 )
635 {
636 USB_HC_DEV *Uhc;
637 UHCI_TD_SW *TDs;
638 EFI_TPL OldTpl;
639 EFI_STATUS Status;
640 UHCI_QH_RESULT QhResult;
641 UINT8 PktId;
642 UINT8 *RequestPhy;
643 VOID *RequestMap;
644 UINT8 *DataPhy;
645 VOID *DataMap;
646 BOOLEAN IsSlowDevice;
647 UINTN TransferDataLength;
648
649 Uhc = UHC_FROM_USB2_HC_PROTO (This);
650 TDs = NULL;
651 DataPhy = NULL;
652 DataMap = NULL;
653 RequestPhy = NULL;
654 RequestMap = NULL;
655
656 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
657
658 //
659 // Parameters Checking
660 //
661 if (Request == NULL || TransferResult == NULL) {
662 return EFI_INVALID_PARAMETER;
663 }
664
665 if (IsSlowDevice && (MaximumPacketLength != 8)) {
666 return EFI_INVALID_PARAMETER;
667 }
668
669 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
670 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
671
672 return EFI_INVALID_PARAMETER;
673 }
674
675 if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) {
676 return EFI_INVALID_PARAMETER;
677 }
678
679 if (TransferDirection == EfiUsbNoData) {
680 TransferDataLength = 0;
681 } else {
682 TransferDataLength = *DataLength;
683 }
684
685 *TransferResult = EFI_USB_ERR_SYSTEM;
686 Status = EFI_DEVICE_ERROR;
687
688 //
689 // If errors exist that cause host controller halt,
690 // clear status then return EFI_DEVICE_ERROR.
691 //
692 UhciAckAllInterrupt (Uhc);
693
694 if (!UhciIsHcWorking (Uhc->PciIo)) {
695 return EFI_DEVICE_ERROR;
696 }
697
698 OldTpl = gBS->RaiseTPL (UHCI_TPL);
699
700 //
701 // Map the Request and data for bus master access,
702 // then create a list of TD for this transfer
703 //
704 Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);
705
706 if (EFI_ERROR (Status)) {
707 goto ON_EXIT;
708 }
709
710 Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);
711
712 if (EFI_ERROR (Status)) {
713 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
714 goto ON_EXIT;
715 }
716
717 TDs = UhciCreateCtrlTds (
718 Uhc,
719 DeviceAddress,
720 PktId,
721 (UINT8*)Request,
722 RequestPhy,
723 (UINT8*)Data,
724 DataPhy,
725 TransferDataLength,
726 (UINT8) MaximumPacketLength,
727 IsSlowDevice
728 );
729
730 if (TDs == NULL) {
731 Status = EFI_OUT_OF_RESOURCES;
732 goto UNMAP_DATA;
733 }
734
735 //
736 // According to the speed of the end point, link
737 // the TD to corrosponding queue head, then check
738 // the execution result
739 //
740 UhciLinkTdToQh (Uhc, Uhc->CtrlQh, TDs);
741 Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);
742 UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);
743
744 Uhc->PciIo->Flush (Uhc->PciIo);
745
746 *TransferResult = QhResult.Result;
747
748 if (DataLength != NULL) {
749 *DataLength = QhResult.Complete;
750 }
751
752 UhciDestoryTds (Uhc, TDs);
753
754 UNMAP_DATA:
755 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
756 Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
757
758 ON_EXIT:
759 gBS->RestoreTPL (OldTpl);
760 return Status;
761 }
762
763
764 /**
765 Submits bulk transfer to a bulk endpoint of a USB device.
766
767 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
768 @param DeviceAddress Target device address.
769 @param EndPointAddress Endpoint number and direction.
770 @param DeviceSpeed Device speed.
771 @param MaximumPacketLength Maximum packet size of the target endpoint.
772 @param DataBuffersNumber Number of data buffers prepared for the transfer.
773 @param Data Array of pointers to the buffers of data.
774 @param DataLength On input, size of the data buffer, On output,
775 actually transferred data size.
776 @param DataToggle On input, data toggle to use; On output, next data toggle.
777 @param TimeOut Maximum time out, in microseconds.
778 @param Translator A pointr to the transaction translator data.
779 @param TransferResult Variable to receive transfer result.
780
781 @return EFI_SUCCESS The bulk transfer was completed successfully.
782 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
783 @return EFI_INVALID_PARAMETER Some parameters are invalid.
784 @return EFI_TIMEOUT Failed due to timeout.
785 @return EFI_DEVICE_ERROR Failed due to host controller or device error.
786
787 **/
788 EFI_STATUS
789 EFIAPI
790 Uhci2BulkTransfer (
791 IN EFI_USB2_HC_PROTOCOL *This,
792 IN UINT8 DeviceAddress,
793 IN UINT8 EndPointAddress,
794 IN UINT8 DeviceSpeed,
795 IN UINTN MaximumPacketLength,
796 IN UINT8 DataBuffersNumber,
797 IN OUT VOID *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
798 IN OUT UINTN *DataLength,
799 IN OUT UINT8 *DataToggle,
800 IN UINTN TimeOut,
801 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
802 OUT UINT32 *TransferResult
803 )
804 {
805 EFI_USB_DATA_DIRECTION Direction;
806 EFI_TPL OldTpl;
807 USB_HC_DEV *Uhc;
808 UHCI_TD_SW *TDs;
809 UHCI_QH_SW *BulkQh;
810 UHCI_QH_RESULT QhResult;
811 EFI_STATUS Status;
812 UINT8 PktId;
813 UINT8 *DataPhy;
814 VOID *DataMap;
815
816 Uhc = UHC_FROM_USB2_HC_PROTO (This);
817 DataPhy = NULL;
818 DataMap = NULL;
819
820 if (DeviceSpeed == EFI_USB_SPEED_LOW) {
821 return EFI_INVALID_PARAMETER;
822 }
823
824 if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
825 return EFI_INVALID_PARAMETER;
826 }
827
828 if ((*DataToggle != 1) && (*DataToggle != 0)) {
829 return EFI_INVALID_PARAMETER;
830 }
831
832 if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
833 (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
834 return EFI_INVALID_PARAMETER;
835 }
836
837 *TransferResult = EFI_USB_ERR_SYSTEM;
838 Status = EFI_OUT_OF_RESOURCES;
839
840 //
841 // If has errors that cause host controller halt,
842 // then return EFI_DEVICE_ERROR directly.
843 //
844 UhciAckAllInterrupt (Uhc);
845
846 if (!UhciIsHcWorking (Uhc->PciIo)) {
847 return EFI_DEVICE_ERROR;
848 }
849
850 OldTpl = gBS->RaiseTPL (UHCI_TPL);
851
852 //
853 // Map the source data buffer for bus master access,
854 // then create a list of TDs
855 //
856 if ((EndPointAddress & 0x80) != 0) {
857 Direction = EfiUsbDataIn;
858 } else {
859 Direction = EfiUsbDataOut;
860 }
861
862 Status = UhciMapUserData (Uhc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap);
863
864 if (EFI_ERROR (Status)) {
865 goto ON_EXIT;
866 }
867
868 Status = EFI_OUT_OF_RESOURCES;
869 TDs = UhciCreateBulkOrIntTds (
870 Uhc,
871 DeviceAddress,
872 EndPointAddress,
873 PktId,
874 (UINT8 *)*Data,
875 DataPhy,
876 *DataLength,
877 DataToggle,
878 (UINT8) MaximumPacketLength,
879 FALSE
880 );
881
882 if (TDs == NULL) {
883 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
884 goto ON_EXIT;
885 }
886
887
888 //
889 // Link the TDs to bulk queue head. According to the platfore
890 // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured
891 // to do full speed bandwidth reclamation or not.
892 //
893 BulkQh = Uhc->BulkQh;
894
895 UhciLinkTdToQh (Uhc, BulkQh, TDs);
896 Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);
897 UhciUnlinkTdFromQh (BulkQh, TDs);
898
899 Uhc->PciIo->Flush (Uhc->PciIo);
900
901 *TransferResult = QhResult.Result;
902 *DataToggle = QhResult.NextToggle;
903 *DataLength = QhResult.Complete;
904
905 UhciDestoryTds (Uhc, TDs);
906 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
907
908 ON_EXIT:
909 gBS->RestoreTPL (OldTpl);
910 return Status;
911 }
912
913
914 /**
915 Submits an asynchronous interrupt transfer to an
916 interrupt endpoint of a USB device according to UEFI 2.0 spec.
917
918 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
919 @param DeviceAddress Target device address.
920 @param EndPointAddress Endpoint number and direction.
921 @param DeviceSpeed Device speed.
922 @param MaximumPacketLength Maximum packet size of the target endpoint.
923 @param IsNewTransfer If TRUE, submit a new transfer, if FALSE cancel old transfer.
924 @param DataToggle On input, data toggle to use; On output, next data toggle.
925 @param PollingInterval Interrupt poll rate in milliseconds.
926 @param DataLength On input, size of the data buffer, On output,
927 actually transferred data size.
928 @param Translator A pointr to the transaction translator data.
929 @param CallBackFunction Function to call periodically.
930 @param Context User context.
931
932 @return EFI_SUCCESS Transfer was submitted.
933 @return EFI_INVALID_PARAMETER Some parameters are invalid.
934 @return EFI_OUT_OF_RESOURCES Failed due to a lack of resources.
935 @return EFI_DEVICE_ERROR Can't read register.
936
937 **/
938 EFI_STATUS
939 EFIAPI
940 Uhci2AsyncInterruptTransfer (
941 IN EFI_USB2_HC_PROTOCOL *This,
942 IN UINT8 DeviceAddress,
943 IN UINT8 EndPointAddress,
944 IN UINT8 DeviceSpeed,
945 IN UINTN MaximumPacketLength,
946 IN BOOLEAN IsNewTransfer,
947 IN OUT UINT8 *DataToggle,
948 IN UINTN PollingInterval,
949 IN UINTN DataLength,
950 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
951 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
952 IN VOID *Context
953 )
954 {
955 USB_HC_DEV *Uhc;
956 BOOLEAN IsSlowDevice;
957 UHCI_QH_SW *Qh;
958 UHCI_TD_SW *IntTds;
959 EFI_TPL OldTpl;
960 EFI_STATUS Status;
961 UINT8 *DataPtr;
962 UINT8 *DataPhy;
963 UINT8 PktId;
964
965 Uhc = UHC_FROM_USB2_HC_PROTO (This);
966 Qh = NULL;
967 IntTds = NULL;
968 DataPtr = NULL;
969 DataPhy = NULL;
970
971 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
972
973 if ((EndPointAddress & 0x80) == 0) {
974 return EFI_INVALID_PARAMETER;
975 }
976
977 //
978 // Delete Async interrupt transfer request
979 //
980 if (!IsNewTransfer) {
981 OldTpl = gBS->RaiseTPL (UHCI_TPL);
982 Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);
983
984 gBS->RestoreTPL (OldTpl);
985 return Status;
986 }
987
988 if (PollingInterval < 1 || PollingInterval > 255) {
989 return EFI_INVALID_PARAMETER;
990 }
991
992 if (DataLength == 0) {
993 return EFI_INVALID_PARAMETER;
994 }
995
996 if ((*DataToggle != 1) && (*DataToggle != 0)) {
997 return EFI_INVALID_PARAMETER;
998 }
999
1000 //
1001 // If has errors that cause host controller halt,
1002 // then return EFI_DEVICE_ERROR directly.
1003 //
1004 UhciAckAllInterrupt (Uhc);
1005
1006 if (!UhciIsHcWorking (Uhc->PciIo)) {
1007 return EFI_DEVICE_ERROR;
1008 }
1009
1010 if ((EndPointAddress & 0x80) == 0) {
1011 PktId = OUTPUT_PACKET_ID;
1012 } else {
1013 PktId = INPUT_PACKET_ID;
1014 }
1015
1016 //
1017 // Allocate and map source data buffer for bus master access.
1018 //
1019 DataPtr = UsbHcAllocateMem (Uhc->MemPool, DataLength);
1020
1021 if (DataPtr == NULL) {
1022 return EFI_OUT_OF_RESOURCES;
1023 }
1024
1025 DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Uhc->MemPool, DataPtr, DataLength);
1026
1027 OldTpl = gBS->RaiseTPL (UHCI_TPL);
1028
1029 Qh = UhciCreateQh (Uhc, PollingInterval);
1030
1031 if (Qh == NULL) {
1032 Status = EFI_OUT_OF_RESOURCES;
1033 goto FREE_DATA;
1034 }
1035
1036 IntTds = UhciCreateBulkOrIntTds (
1037 Uhc,
1038 DeviceAddress,
1039 EndPointAddress,
1040 PktId,
1041 DataPtr,
1042 DataPhy,
1043 DataLength,
1044 DataToggle,
1045 (UINT8) MaximumPacketLength,
1046 IsSlowDevice
1047 );
1048
1049 if (IntTds == NULL) {
1050 Status = EFI_OUT_OF_RESOURCES;
1051 goto DESTORY_QH;
1052 }
1053
1054 UhciLinkTdToQh (Uhc, Qh, IntTds);
1055
1056 //
1057 // Save QH-TD structures to async Interrupt transfer list,
1058 // for monitor interrupt transfer execution routine use.
1059 //
1060 Status = UhciCreateAsyncReq (
1061 Uhc,
1062 Qh,
1063 IntTds,
1064 DeviceAddress,
1065 EndPointAddress,
1066 DataLength,
1067 PollingInterval,
1068 DataPtr,
1069 CallBackFunction,
1070 Context,
1071 IsSlowDevice
1072 );
1073
1074 if (EFI_ERROR (Status)) {
1075 goto DESTORY_QH;
1076 }
1077
1078 UhciLinkQhToFrameList (Uhc, Qh);
1079
1080 gBS->RestoreTPL (OldTpl);
1081 return EFI_SUCCESS;
1082
1083 DESTORY_QH:
1084 UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));
1085
1086 FREE_DATA:
1087 UsbHcFreeMem (Uhc->MemPool, DataPtr, DataLength);
1088 Uhc->PciIo->Flush (Uhc->PciIo);
1089
1090 gBS->RestoreTPL (OldTpl);
1091 return Status;
1092 }
1093
1094 /**
1095 Submits synchronous interrupt transfer to an interrupt endpoint
1096 of a USB device according to UEFI 2.0 spec.
1097
1098
1099 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1100 @param DeviceAddress Target device address.
1101 @param EndPointAddress Endpoint number and direction.
1102 @param DeviceSpeed Device speed.
1103 @param MaximumPacketLength Maximum packet size of the target endpoint.
1104 @param Data Array of pointers to the buffers of data.
1105 @param DataLength On input, size of the data buffer, On output,
1106 actually transferred data size.
1107 @param DataToggle On input, data toggle to use; On output, next data toggle.
1108 @param TimeOut Maximum time out, in microseconds.
1109 @param Translator A pointr to the transaction translator data.
1110 @param TransferResult Variable to receive transfer result.
1111
1112 @return EFI_SUCCESS The transfer was completed successfully.
1113 @return EFI_OUT_OF_RESOURCES Failed due to lack of resource.
1114 @return EFI_INVALID_PARAMETER Some parameters are invalid.
1115 @return EFI_TIMEOUT Failed due to timeout.
1116 @return EFI_DEVICE_ERROR Failed due to host controller or device error.
1117
1118 **/
1119 EFI_STATUS
1120 EFIAPI
1121 Uhci2SyncInterruptTransfer (
1122 IN EFI_USB2_HC_PROTOCOL *This,
1123 IN UINT8 DeviceAddress,
1124 IN UINT8 EndPointAddress,
1125 IN UINT8 DeviceSpeed,
1126 IN UINTN MaximumPacketLength,
1127 IN OUT VOID *Data,
1128 IN OUT UINTN *DataLength,
1129 IN OUT UINT8 *DataToggle,
1130 IN UINTN TimeOut,
1131 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1132 OUT UINT32 *TransferResult
1133 )
1134 {
1135 EFI_STATUS Status;
1136 USB_HC_DEV *Uhc;
1137 UHCI_TD_SW *TDs;
1138 UHCI_QH_RESULT QhResult;
1139 EFI_TPL OldTpl;
1140 UINT8 *DataPhy;
1141 VOID *DataMap;
1142 UINT8 PktId;
1143 BOOLEAN IsSlowDevice;
1144
1145 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1146 DataPhy = NULL;
1147 DataMap = NULL;
1148 TDs = NULL;
1149
1150 if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
1151 return EFI_INVALID_PARAMETER;
1152 }
1153
1154 IsSlowDevice = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
1155
1156 if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
1157 return EFI_INVALID_PARAMETER;
1158 }
1159
1160 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1161 return EFI_INVALID_PARAMETER;
1162 }
1163
1164 if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
1165 return EFI_INVALID_PARAMETER;
1166 }
1167
1168 if (IsSlowDevice && (MaximumPacketLength > 8)) {
1169 return EFI_INVALID_PARAMETER;
1170 }
1171
1172 *TransferResult = EFI_USB_ERR_SYSTEM;
1173 Status = EFI_DEVICE_ERROR;
1174
1175
1176 UhciAckAllInterrupt (Uhc);
1177
1178 if (!UhciIsHcWorking (Uhc->PciIo)) {
1179 return Status;
1180 }
1181
1182 OldTpl = gBS->RaiseTPL (UHCI_TPL);
1183
1184 //
1185 // Map the source data buffer for bus master access.
1186 // Create Tds list, then link it to the UHC's interrupt list
1187 //
1188 Status = UhciMapUserData (
1189 Uhc,
1190 EfiUsbDataIn,
1191 Data,
1192 DataLength,
1193 &PktId,
1194 &DataPhy,
1195 &DataMap
1196 );
1197
1198 if (EFI_ERROR (Status)) {
1199 goto ON_EXIT;
1200 }
1201
1202 TDs = UhciCreateBulkOrIntTds (
1203 Uhc,
1204 DeviceAddress,
1205 EndPointAddress,
1206 PktId,
1207 (UINT8 *)Data,
1208 DataPhy,
1209 *DataLength,
1210 DataToggle,
1211 (UINT8) MaximumPacketLength,
1212 IsSlowDevice
1213 );
1214
1215 if (TDs == NULL) {
1216 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1217
1218 Status = EFI_OUT_OF_RESOURCES;
1219 goto ON_EXIT;
1220 }
1221
1222
1223 UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);
1224
1225 Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
1226
1227 UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
1228 Uhc->PciIo->Flush (Uhc->PciIo);
1229
1230 *TransferResult = QhResult.Result;
1231 *DataToggle = QhResult.NextToggle;
1232 *DataLength = QhResult.Complete;
1233
1234 UhciDestoryTds (Uhc, TDs);
1235 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1236
1237 ON_EXIT:
1238 gBS->RestoreTPL (OldTpl);
1239 return Status;
1240 }
1241
1242
1243 /**
1244 Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
1245
1246 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1247 @param DeviceAddress Target device address.
1248 @param EndPointAddress Endpoint number and direction.
1249 @param DeviceSpeed Device speed.
1250 @param MaximumPacketLength Maximum packet size of the target endpoint.
1251 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1252 @param Data Array of pointers to the buffers of data.
1253 @param DataLength On input, size of the data buffer, On output,
1254 actually transferred data size.
1255 @param Translator A pointr to the transaction translator data.
1256 @param TransferResult Variable to receive transfer result.
1257
1258 @return EFI_UNSUPPORTED
1259
1260 **/
1261 EFI_STATUS
1262 EFIAPI
1263 Uhci2IsochronousTransfer (
1264 IN EFI_USB2_HC_PROTOCOL *This,
1265 IN UINT8 DeviceAddress,
1266 IN UINT8 EndPointAddress,
1267 IN UINT8 DeviceSpeed,
1268 IN UINTN MaximumPacketLength,
1269 IN UINT8 DataBuffersNumber,
1270 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1271 IN UINTN DataLength,
1272 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1273 OUT UINT32 *TransferResult
1274 )
1275 {
1276 return EFI_UNSUPPORTED;
1277 }
1278
1279
1280 /**
1281 Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
1282
1283 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1284 @param DeviceAddress Target device address.
1285 @param EndPointAddress Endpoint number and direction.
1286 @param DeviceSpeed Device speed.
1287 @param MaximumPacketLength Maximum packet size of the target endpoint.
1288 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1289 @param Data Array of pointers to the buffers of data.
1290 @param DataLength On input, size of the data buffer, On output,
1291 actually transferred data size.
1292 @param Translator A pointr to the transaction translator data.
1293 @param IsochronousCallBack Function to call when the transfer complete.
1294 @param Context Pass to the call back function as parameter.
1295
1296 @return EFI_UNSUPPORTED
1297
1298 **/
1299 EFI_STATUS
1300 EFIAPI
1301 Uhci2AsyncIsochronousTransfer (
1302 IN EFI_USB2_HC_PROTOCOL *This,
1303 IN UINT8 DeviceAddress,
1304 IN UINT8 EndPointAddress,
1305 IN UINT8 DeviceSpeed,
1306 IN UINTN MaximumPacketLength,
1307 IN UINT8 DataBuffersNumber,
1308 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1309 IN UINTN DataLength,
1310 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1311 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1312 IN VOID *Context
1313 )
1314 {
1315 return EFI_UNSUPPORTED;
1316 }
1317
1318 /**
1319 Entry point for EFI drivers.
1320
1321 @param ImageHandle EFI_HANDLE.
1322 @param SystemTable EFI_SYSTEM_TABLE.
1323
1324 @retval EFI_SUCCESS Driver is successfully loaded.
1325 @return Others Failed.
1326
1327 **/
1328 EFI_STATUS
1329 EFIAPI
1330 UhciDriverEntryPoint (
1331 IN EFI_HANDLE ImageHandle,
1332 IN EFI_SYSTEM_TABLE *SystemTable
1333 )
1334 {
1335 return EfiLibInstallDriverBindingComponentName2 (
1336 ImageHandle,
1337 SystemTable,
1338 &gUhciDriverBinding,
1339 ImageHandle,
1340 &gUhciComponentName,
1341 &gUhciComponentName2
1342 );
1343 }
1344
1345
1346 /**
1347 Test to see if this driver supports ControllerHandle. Any
1348 ControllerHandle that has UsbHcProtocol installed will be supported.
1349
1350 @param This Protocol instance pointer.
1351 @param Controller Handle of device to test.
1352 @param RemainingDevicePath Not used.
1353
1354 @return EFI_SUCCESS This driver supports this device.
1355 @return EFI_UNSUPPORTED This driver does not support this device.
1356
1357 **/
1358 EFI_STATUS
1359 EFIAPI
1360 UhciDriverBindingSupported (
1361 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1362 IN EFI_HANDLE Controller,
1363 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1364 )
1365 {
1366 EFI_STATUS OpenStatus;
1367 EFI_STATUS Status;
1368 EFI_PCI_IO_PROTOCOL *PciIo;
1369 USB_CLASSC UsbClassCReg;
1370
1371 //
1372 // Test whether there is PCI IO Protocol attached on the controller handle.
1373 //
1374 OpenStatus = gBS->OpenProtocol (
1375 Controller,
1376 &gEfiPciIoProtocolGuid,
1377 (VOID **) &PciIo,
1378 This->DriverBindingHandle,
1379 Controller,
1380 EFI_OPEN_PROTOCOL_BY_DRIVER
1381 );
1382
1383 if (EFI_ERROR (OpenStatus)) {
1384 return OpenStatus;
1385 }
1386
1387 Status = PciIo->Pci.Read (
1388 PciIo,
1389 EfiPciIoWidthUint8,
1390 PCI_CLASSCODE_OFFSET,
1391 sizeof (USB_CLASSC) / sizeof (UINT8),
1392 &UsbClassCReg
1393 );
1394
1395 if (EFI_ERROR (Status)) {
1396 Status = EFI_UNSUPPORTED;
1397 goto ON_EXIT;
1398 }
1399
1400 //
1401 // Test whether the controller belongs to UHCI type
1402 //
1403 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1404 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1405 (UsbClassCReg.ProgInterface != PCI_IF_UHCI)
1406 ) {
1407
1408 Status = EFI_UNSUPPORTED;
1409 }
1410
1411 ON_EXIT:
1412 gBS->CloseProtocol (
1413 Controller,
1414 &gEfiPciIoProtocolGuid,
1415 This->DriverBindingHandle,
1416 Controller
1417 );
1418
1419 return Status;
1420
1421 }
1422
1423
1424 /**
1425 Allocate and initialize the empty UHCI device.
1426
1427 @param PciIo The PCIIO to use.
1428 @param DevicePath The device path of host controller.
1429 @param OriginalPciAttributes The original PCI attributes.
1430
1431 @return Allocated UHCI device. If err, return NULL.
1432
1433 **/
1434 USB_HC_DEV *
1435 UhciAllocateDev (
1436 IN EFI_PCI_IO_PROTOCOL *PciIo,
1437 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1438 IN UINT64 OriginalPciAttributes
1439 )
1440 {
1441 USB_HC_DEV *Uhc;
1442 EFI_STATUS Status;
1443
1444 Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
1445
1446 if (Uhc == NULL) {
1447 return NULL;
1448 }
1449
1450 //
1451 // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
1452 // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
1453 //
1454 Uhc->Signature = USB_HC_DEV_SIGNATURE;
1455 Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;
1456 Uhc->Usb2Hc.Reset = Uhci2Reset;
1457 Uhc->Usb2Hc.GetState = Uhci2GetState;
1458 Uhc->Usb2Hc.SetState = Uhci2SetState;
1459 Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;
1460 Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;
1461 Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;
1462 Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;
1463 Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;
1464 Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;
1465 Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;
1466 Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;
1467 Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;
1468 Uhc->Usb2Hc.MajorRevision = 0x1;
1469 Uhc->Usb2Hc.MinorRevision = 0x1;
1470
1471 Uhc->PciIo = PciIo;
1472 Uhc->DevicePath = DevicePath;
1473 Uhc->OriginalPciAttributes = OriginalPciAttributes;
1474 Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);
1475
1476 if (Uhc->MemPool == NULL) {
1477 Status = EFI_OUT_OF_RESOURCES;
1478 goto ON_ERROR;
1479 }
1480
1481 InitializeListHead (&Uhc->AsyncIntList);
1482
1483 Status = gBS->CreateEvent (
1484 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1485 TPL_NOTIFY,
1486 UhciMonitorAsyncReqList,
1487 Uhc,
1488 &Uhc->AsyncIntMonitor
1489 );
1490
1491 if (EFI_ERROR (Status)) {
1492 UsbHcFreeMemPool (Uhc->MemPool);
1493 goto ON_ERROR;
1494 }
1495
1496 return Uhc;
1497
1498 ON_ERROR:
1499 FreePool (Uhc);
1500 return NULL;
1501 }
1502
1503
1504 /**
1505 Free the UHCI device and release its associated resources.
1506
1507 @param Uhc The UHCI device to release.
1508
1509 **/
1510 VOID
1511 UhciFreeDev (
1512 IN USB_HC_DEV *Uhc
1513 )
1514 {
1515 if (Uhc->AsyncIntMonitor != NULL) {
1516 gBS->CloseEvent (Uhc->AsyncIntMonitor);
1517 }
1518
1519 if (Uhc->ExitBootServiceEvent != NULL) {
1520 gBS->CloseEvent (Uhc->ExitBootServiceEvent);
1521 }
1522
1523 if (Uhc->MemPool != NULL) {
1524 UsbHcFreeMemPool (Uhc->MemPool);
1525 }
1526
1527 if (Uhc->CtrlNameTable != NULL) {
1528 FreeUnicodeStringTable (Uhc->CtrlNameTable);
1529 }
1530
1531 FreePool (Uhc);
1532 }
1533
1534
1535 /**
1536 Uninstall all Uhci Interface.
1537
1538 @param Controller Controller handle.
1539 @param This Protocol instance pointer.
1540
1541 **/
1542 VOID
1543 UhciCleanDevUp (
1544 IN EFI_HANDLE Controller,
1545 IN EFI_USB2_HC_PROTOCOL *This
1546 )
1547 {
1548 USB_HC_DEV *Uhc;
1549 EFI_STATUS Status;
1550
1551 //
1552 // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
1553 //
1554 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1555
1556
1557 Status = gBS->UninstallProtocolInterface (
1558 Controller,
1559 &gEfiUsb2HcProtocolGuid,
1560 &Uhc->Usb2Hc
1561 );
1562 if (EFI_ERROR (Status)) {
1563 return ;
1564 }
1565
1566 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1567 UhciFreeAllAsyncReq (Uhc);
1568 UhciDestoryFrameList (Uhc);
1569
1570 //
1571 // Restore original PCI attributes
1572 //
1573 Uhc->PciIo->Attributes (
1574 Uhc->PciIo,
1575 EfiPciIoAttributeOperationSet,
1576 Uhc->OriginalPciAttributes,
1577 NULL
1578 );
1579
1580 UhciFreeDev (Uhc);
1581 }
1582
1583 /**
1584 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1585
1586 @param Event Pointer to this event
1587 @param Context Event handler private data
1588
1589 **/
1590 VOID
1591 EFIAPI
1592 UhcExitBootService (
1593 EFI_EVENT Event,
1594 VOID *Context
1595 )
1596 {
1597 USB_HC_DEV *Uhc;
1598
1599 Uhc = (USB_HC_DEV *) Context;
1600
1601 //
1602 // Stop the Host Controller
1603 //
1604 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1605
1606 //
1607 // Reset the Host Controller
1608 //
1609 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
1610 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
1611 }
1612
1613 /**
1614 Starting the Usb UHCI Driver.
1615
1616 @param This Protocol instance pointer.
1617 @param Controller Handle of device to test.
1618 @param RemainingDevicePath Not used.
1619
1620 @retval EFI_SUCCESS This driver supports this device.
1621 @retval EFI_UNSUPPORTED This driver does not support this device.
1622 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
1623 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
1624
1625 **/
1626 EFI_STATUS
1627 EFIAPI
1628 UhciDriverBindingStart (
1629 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1630 IN EFI_HANDLE Controller,
1631 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1632 )
1633 {
1634 EFI_STATUS Status;
1635 EFI_PCI_IO_PROTOCOL *PciIo;
1636 USB_HC_DEV *Uhc;
1637 UINT64 Supports;
1638 UINT64 OriginalPciAttributes;
1639 BOOLEAN PciAttributesSaved;
1640 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1641
1642 //
1643 // Open PCIIO, then enable the EHC device and turn off emulation
1644 //
1645 Uhc = NULL;
1646 Status = gBS->OpenProtocol (
1647 Controller,
1648 &gEfiPciIoProtocolGuid,
1649 (VOID **) &PciIo,
1650 This->DriverBindingHandle,
1651 Controller,
1652 EFI_OPEN_PROTOCOL_BY_DRIVER
1653 );
1654
1655 if (EFI_ERROR (Status)) {
1656 return Status;
1657 }
1658
1659 //
1660 // Open Device Path Protocol for on USB host controller
1661 //
1662 HcDevicePath = NULL;
1663 Status = gBS->OpenProtocol (
1664 Controller,
1665 &gEfiDevicePathProtocolGuid,
1666 (VOID **) &HcDevicePath,
1667 This->DriverBindingHandle,
1668 Controller,
1669 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1670 );
1671
1672 PciAttributesSaved = FALSE;
1673 //
1674 // Save original PCI attributes
1675 //
1676 Status = PciIo->Attributes (
1677 PciIo,
1678 EfiPciIoAttributeOperationGet,
1679 0,
1680 &OriginalPciAttributes
1681 );
1682
1683 if (EFI_ERROR (Status)) {
1684 goto CLOSE_PCIIO;
1685 }
1686 PciAttributesSaved = TRUE;
1687
1688 //
1689 // Robustnesss improvement such as for UoL
1690 // Default is not required.
1691 //
1692 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1693 UhciTurnOffUsbEmulation (PciIo);
1694 }
1695
1696 Status = PciIo->Attributes (
1697 PciIo,
1698 EfiPciIoAttributeOperationSupported,
1699 0,
1700 &Supports
1701 );
1702 if (!EFI_ERROR (Status)) {
1703 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1704 Status = PciIo->Attributes (
1705 PciIo,
1706 EfiPciIoAttributeOperationEnable,
1707 Supports,
1708 NULL
1709 );
1710 }
1711
1712 if (EFI_ERROR (Status)) {
1713 goto CLOSE_PCIIO;
1714 }
1715
1716 Uhc = UhciAllocateDev (PciIo, HcDevicePath, OriginalPciAttributes);
1717
1718 if (Uhc == NULL) {
1719 Status = EFI_OUT_OF_RESOURCES;
1720 goto CLOSE_PCIIO;
1721 }
1722
1723 //
1724 // Allocate and Init Host Controller's Frame List Entry
1725 //
1726 Status = UhciInitFrameList (Uhc);
1727
1728 if (EFI_ERROR (Status)) {
1729 Status = EFI_OUT_OF_RESOURCES;
1730 goto FREE_UHC;
1731 }
1732
1733 Status = gBS->SetTimer (
1734 Uhc->AsyncIntMonitor,
1735 TimerPeriodic,
1736 UHC_ASYNC_POLL_INTERVAL
1737 );
1738
1739 if (EFI_ERROR (Status)) {
1740 goto FREE_UHC;
1741 }
1742
1743 //
1744 // Install USB2_HC_PROTOCOL
1745 //
1746 Status = gBS->InstallMultipleProtocolInterfaces (
1747 &Controller,
1748 &gEfiUsb2HcProtocolGuid,
1749 &Uhc->Usb2Hc,
1750 NULL
1751 );
1752
1753 if (EFI_ERROR (Status)) {
1754 goto FREE_UHC;
1755 }
1756
1757 //
1758 // Create event to stop the HC when exit boot service.
1759 //
1760 Status = gBS->CreateEventEx (
1761 EVT_NOTIFY_SIGNAL,
1762 TPL_NOTIFY,
1763 UhcExitBootService,
1764 Uhc,
1765 &gEfiEventExitBootServicesGuid,
1766 &Uhc->ExitBootServiceEvent
1767 );
1768 if (EFI_ERROR (Status)) {
1769 goto UNINSTALL_USBHC;
1770 }
1771
1772 //
1773 // Install the component name protocol
1774 //
1775 Uhc->CtrlNameTable = NULL;
1776
1777 AddUnicodeString2 (
1778 "eng",
1779 gUhciComponentName.SupportedLanguages,
1780 &Uhc->CtrlNameTable,
1781 L"Usb Universal Host Controller",
1782 TRUE
1783 );
1784 AddUnicodeString2 (
1785 "en",
1786 gUhciComponentName2.SupportedLanguages,
1787 &Uhc->CtrlNameTable,
1788 L"Usb Universal Host Controller",
1789 FALSE
1790 );
1791
1792
1793 //
1794 // Start the UHCI hardware, also set its reclamation point to 64 bytes
1795 //
1796 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
1797
1798 return EFI_SUCCESS;
1799
1800 UNINSTALL_USBHC:
1801 gBS->UninstallMultipleProtocolInterfaces (
1802 Controller,
1803 &gEfiUsb2HcProtocolGuid,
1804 &Uhc->Usb2Hc,
1805 NULL
1806 );
1807
1808 FREE_UHC:
1809 UhciFreeDev (Uhc);
1810
1811 CLOSE_PCIIO:
1812 if (PciAttributesSaved) {
1813 //
1814 // Restore original PCI attributes
1815 //
1816 PciIo->Attributes (
1817 PciIo,
1818 EfiPciIoAttributeOperationSet,
1819 OriginalPciAttributes,
1820 NULL
1821 );
1822 }
1823
1824 gBS->CloseProtocol (
1825 Controller,
1826 &gEfiPciIoProtocolGuid,
1827 This->DriverBindingHandle,
1828 Controller
1829 );
1830
1831 return Status;
1832 }
1833
1834
1835 /**
1836 Stop this driver on ControllerHandle. Support stoping any child handles
1837 created by this driver.
1838
1839 @param This Protocol instance pointer.
1840 @param Controller Handle of device to stop driver on.
1841 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1842 @param ChildHandleBuffer List of handles for the children we need to stop.
1843
1844 @return EFI_SUCCESS
1845 @return others
1846
1847 **/
1848 EFI_STATUS
1849 EFIAPI
1850 UhciDriverBindingStop (
1851 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1852 IN EFI_HANDLE Controller,
1853 IN UINTN NumberOfChildren,
1854 IN EFI_HANDLE *ChildHandleBuffer
1855 )
1856 {
1857 EFI_USB2_HC_PROTOCOL *Usb2Hc;
1858 EFI_STATUS Status;
1859
1860 Status = gBS->OpenProtocol (
1861 Controller,
1862 &gEfiUsb2HcProtocolGuid,
1863 (VOID **) &Usb2Hc,
1864 This->DriverBindingHandle,
1865 Controller,
1866 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1867 );
1868
1869 //
1870 // Test whether the Controller handler passed in is a valid
1871 // Usb controller handle that should be supported, if not,
1872 // return the error status directly
1873 //
1874 if (EFI_ERROR (Status)) {
1875 return Status;
1876 }
1877
1878 UhciCleanDevUp (Controller, Usb2Hc);
1879
1880 gBS->CloseProtocol (
1881 Controller,
1882 &gEfiPciIoProtocolGuid,
1883 This->DriverBindingHandle,
1884 Controller
1885 );
1886
1887 return EFI_SUCCESS;
1888 }
1889