]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/UhciDxe/Uhci.c
1) Add type cast for better coding style.
[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 - 2014, 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 accroding 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 ((EndPointAddress & 0x80) == 0) {
1161 return EFI_INVALID_PARAMETER;
1162 }
1163
1164 if ((*DataToggle != 1) && (*DataToggle != 0)) {
1165 return EFI_INVALID_PARAMETER;
1166 }
1167
1168 if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
1169 return EFI_INVALID_PARAMETER;
1170 }
1171
1172 if (IsSlowDevice && (MaximumPacketLength > 8)) {
1173 return EFI_INVALID_PARAMETER;
1174 }
1175
1176 *TransferResult = EFI_USB_ERR_SYSTEM;
1177 Status = EFI_DEVICE_ERROR;
1178
1179
1180 UhciAckAllInterrupt (Uhc);
1181
1182 if (!UhciIsHcWorking (Uhc->PciIo)) {
1183 return Status;
1184 }
1185
1186 OldTpl = gBS->RaiseTPL (UHCI_TPL);
1187
1188 //
1189 // Map the source data buffer for bus master access.
1190 // Create Tds list, then link it to the UHC's interrupt list
1191 //
1192 Status = UhciMapUserData (
1193 Uhc,
1194 EfiUsbDataIn,
1195 Data,
1196 DataLength,
1197 &PktId,
1198 &DataPhy,
1199 &DataMap
1200 );
1201
1202 if (EFI_ERROR (Status)) {
1203 goto ON_EXIT;
1204 }
1205
1206 TDs = UhciCreateBulkOrIntTds (
1207 Uhc,
1208 DeviceAddress,
1209 EndPointAddress,
1210 PktId,
1211 (UINT8 *)Data,
1212 DataPhy,
1213 *DataLength,
1214 DataToggle,
1215 (UINT8) MaximumPacketLength,
1216 IsSlowDevice
1217 );
1218
1219 if (TDs == NULL) {
1220 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1221
1222 Status = EFI_OUT_OF_RESOURCES;
1223 goto ON_EXIT;
1224 }
1225
1226
1227 UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);
1228
1229 Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
1230
1231 UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
1232 Uhc->PciIo->Flush (Uhc->PciIo);
1233
1234 *TransferResult = QhResult.Result;
1235 *DataToggle = QhResult.NextToggle;
1236 *DataLength = QhResult.Complete;
1237
1238 UhciDestoryTds (Uhc, TDs);
1239 Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
1240
1241 ON_EXIT:
1242 gBS->RestoreTPL (OldTpl);
1243 return Status;
1244 }
1245
1246
1247 /**
1248 Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
1249
1250 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1251 @param DeviceAddress Target device address.
1252 @param EndPointAddress Endpoint number and direction.
1253 @param DeviceSpeed Device speed.
1254 @param MaximumPacketLength Maximum packet size of the target endpoint.
1255 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1256 @param Data Array of pointers to the buffers of data.
1257 @param DataLength On input, size of the data buffer, On output,
1258 actually transferred data size.
1259 @param Translator A pointr to the transaction translator data.
1260 @param TransferResult Variable to receive transfer result.
1261
1262 @return EFI_UNSUPPORTED
1263
1264 **/
1265 EFI_STATUS
1266 EFIAPI
1267 Uhci2IsochronousTransfer (
1268 IN EFI_USB2_HC_PROTOCOL *This,
1269 IN UINT8 DeviceAddress,
1270 IN UINT8 EndPointAddress,
1271 IN UINT8 DeviceSpeed,
1272 IN UINTN MaximumPacketLength,
1273 IN UINT8 DataBuffersNumber,
1274 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1275 IN UINTN DataLength,
1276 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1277 OUT UINT32 *TransferResult
1278 )
1279 {
1280 return EFI_UNSUPPORTED;
1281 }
1282
1283
1284 /**
1285 Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
1286
1287 @param This A pointer to the EFI_USB2_HC_PROTOCOL instance.
1288 @param DeviceAddress Target device address.
1289 @param EndPointAddress Endpoint number and direction.
1290 @param DeviceSpeed Device speed.
1291 @param MaximumPacketLength Maximum packet size of the target endpoint.
1292 @param DataBuffersNumber Number of data buffers prepared for the transfer.
1293 @param Data Array of pointers to the buffers of data.
1294 @param DataLength On input, size of the data buffer, On output,
1295 actually transferred data size.
1296 @param Translator A pointr to the transaction translator data.
1297 @param IsochronousCallBack Function to call when the transfer complete.
1298 @param Context Pass to the call back function as parameter.
1299
1300 @return EFI_UNSUPPORTED
1301
1302 **/
1303 EFI_STATUS
1304 EFIAPI
1305 Uhci2AsyncIsochronousTransfer (
1306 IN EFI_USB2_HC_PROTOCOL *This,
1307 IN UINT8 DeviceAddress,
1308 IN UINT8 EndPointAddress,
1309 IN UINT8 DeviceSpeed,
1310 IN UINTN MaximumPacketLength,
1311 IN UINT8 DataBuffersNumber,
1312 IN OUT VOID *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
1313 IN UINTN DataLength,
1314 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
1315 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
1316 IN VOID *Context
1317 )
1318 {
1319 return EFI_UNSUPPORTED;
1320 }
1321
1322 /**
1323 Entry point for EFI drivers.
1324
1325 @param ImageHandle EFI_HANDLE.
1326 @param SystemTable EFI_SYSTEM_TABLE.
1327
1328 @retval EFI_SUCCESS Driver is successfully loaded.
1329 @return Others Failed.
1330
1331 **/
1332 EFI_STATUS
1333 EFIAPI
1334 UhciDriverEntryPoint (
1335 IN EFI_HANDLE ImageHandle,
1336 IN EFI_SYSTEM_TABLE *SystemTable
1337 )
1338 {
1339 return EfiLibInstallDriverBindingComponentName2 (
1340 ImageHandle,
1341 SystemTable,
1342 &gUhciDriverBinding,
1343 ImageHandle,
1344 &gUhciComponentName,
1345 &gUhciComponentName2
1346 );
1347 }
1348
1349
1350 /**
1351 Test to see if this driver supports ControllerHandle. Any
1352 ControllerHandle that has UsbHcProtocol installed will be supported.
1353
1354 @param This Protocol instance pointer.
1355 @param Controller Handle of device to test.
1356 @param RemainingDevicePath Not used.
1357
1358 @return EFI_SUCCESS This driver supports this device.
1359 @return EFI_UNSUPPORTED This driver does not support this device.
1360
1361 **/
1362 EFI_STATUS
1363 EFIAPI
1364 UhciDriverBindingSupported (
1365 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1366 IN EFI_HANDLE Controller,
1367 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1368 )
1369 {
1370 EFI_STATUS OpenStatus;
1371 EFI_STATUS Status;
1372 EFI_PCI_IO_PROTOCOL *PciIo;
1373 USB_CLASSC UsbClassCReg;
1374
1375 //
1376 // Test whether there is PCI IO Protocol attached on the controller handle.
1377 //
1378 OpenStatus = gBS->OpenProtocol (
1379 Controller,
1380 &gEfiPciIoProtocolGuid,
1381 (VOID **) &PciIo,
1382 This->DriverBindingHandle,
1383 Controller,
1384 EFI_OPEN_PROTOCOL_BY_DRIVER
1385 );
1386
1387 if (EFI_ERROR (OpenStatus)) {
1388 return OpenStatus;
1389 }
1390
1391 Status = PciIo->Pci.Read (
1392 PciIo,
1393 EfiPciIoWidthUint8,
1394 PCI_CLASSCODE_OFFSET,
1395 sizeof (USB_CLASSC) / sizeof (UINT8),
1396 &UsbClassCReg
1397 );
1398
1399 if (EFI_ERROR (Status)) {
1400 Status = EFI_UNSUPPORTED;
1401 goto ON_EXIT;
1402 }
1403
1404 //
1405 // Test whether the controller belongs to UHCI type
1406 //
1407 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
1408 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
1409 (UsbClassCReg.ProgInterface != PCI_IF_UHCI)
1410 ) {
1411
1412 Status = EFI_UNSUPPORTED;
1413 }
1414
1415 ON_EXIT:
1416 gBS->CloseProtocol (
1417 Controller,
1418 &gEfiPciIoProtocolGuid,
1419 This->DriverBindingHandle,
1420 Controller
1421 );
1422
1423 return Status;
1424
1425 }
1426
1427
1428 /**
1429 Allocate and initialize the empty UHCI device.
1430
1431 @param PciIo The PCIIO to use.
1432 @param DevicePath The device path of host controller.
1433 @param OriginalPciAttributes The original PCI attributes.
1434
1435 @return Allocated UHCI device. If err, return NULL.
1436
1437 **/
1438 USB_HC_DEV *
1439 UhciAllocateDev (
1440 IN EFI_PCI_IO_PROTOCOL *PciIo,
1441 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1442 IN UINT64 OriginalPciAttributes
1443 )
1444 {
1445 USB_HC_DEV *Uhc;
1446 EFI_STATUS Status;
1447
1448 Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
1449
1450 if (Uhc == NULL) {
1451 return NULL;
1452 }
1453
1454 //
1455 // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
1456 // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
1457 //
1458 Uhc->Signature = USB_HC_DEV_SIGNATURE;
1459 Uhc->Usb2Hc.GetCapability = Uhci2GetCapability;
1460 Uhc->Usb2Hc.Reset = Uhci2Reset;
1461 Uhc->Usb2Hc.GetState = Uhci2GetState;
1462 Uhc->Usb2Hc.SetState = Uhci2SetState;
1463 Uhc->Usb2Hc.ControlTransfer = Uhci2ControlTransfer;
1464 Uhc->Usb2Hc.BulkTransfer = Uhci2BulkTransfer;
1465 Uhc->Usb2Hc.AsyncInterruptTransfer = Uhci2AsyncInterruptTransfer;
1466 Uhc->Usb2Hc.SyncInterruptTransfer = Uhci2SyncInterruptTransfer;
1467 Uhc->Usb2Hc.IsochronousTransfer = Uhci2IsochronousTransfer;
1468 Uhc->Usb2Hc.AsyncIsochronousTransfer = Uhci2AsyncIsochronousTransfer;
1469 Uhc->Usb2Hc.GetRootHubPortStatus = Uhci2GetRootHubPortStatus;
1470 Uhc->Usb2Hc.SetRootHubPortFeature = Uhci2SetRootHubPortFeature;
1471 Uhc->Usb2Hc.ClearRootHubPortFeature = Uhci2ClearRootHubPortFeature;
1472 Uhc->Usb2Hc.MajorRevision = 0x1;
1473 Uhc->Usb2Hc.MinorRevision = 0x1;
1474
1475 Uhc->PciIo = PciIo;
1476 Uhc->DevicePath = DevicePath;
1477 Uhc->OriginalPciAttributes = OriginalPciAttributes;
1478 Uhc->MemPool = UsbHcInitMemPool (PciIo, TRUE, 0);
1479
1480 if (Uhc->MemPool == NULL) {
1481 Status = EFI_OUT_OF_RESOURCES;
1482 goto ON_ERROR;
1483 }
1484
1485 InitializeListHead (&Uhc->AsyncIntList);
1486
1487 Status = gBS->CreateEvent (
1488 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1489 TPL_CALLBACK,
1490 UhciMonitorAsyncReqList,
1491 Uhc,
1492 &Uhc->AsyncIntMonitor
1493 );
1494
1495 if (EFI_ERROR (Status)) {
1496 UsbHcFreeMemPool (Uhc->MemPool);
1497 goto ON_ERROR;
1498 }
1499
1500 return Uhc;
1501
1502 ON_ERROR:
1503 FreePool (Uhc);
1504 return NULL;
1505 }
1506
1507
1508 /**
1509 Free the UHCI device and release its associated resources.
1510
1511 @param Uhc The UHCI device to release.
1512
1513 **/
1514 VOID
1515 UhciFreeDev (
1516 IN USB_HC_DEV *Uhc
1517 )
1518 {
1519 if (Uhc->AsyncIntMonitor != NULL) {
1520 gBS->CloseEvent (Uhc->AsyncIntMonitor);
1521 }
1522
1523 if (Uhc->ExitBootServiceEvent != NULL) {
1524 gBS->CloseEvent (Uhc->ExitBootServiceEvent);
1525 }
1526
1527 if (Uhc->MemPool != NULL) {
1528 UsbHcFreeMemPool (Uhc->MemPool);
1529 }
1530
1531 if (Uhc->CtrlNameTable != NULL) {
1532 FreeUnicodeStringTable (Uhc->CtrlNameTable);
1533 }
1534
1535 FreePool (Uhc);
1536 }
1537
1538
1539 /**
1540 Uninstall all Uhci Interface.
1541
1542 @param Controller Controller handle.
1543 @param This Protocol instance pointer.
1544
1545 **/
1546 VOID
1547 UhciCleanDevUp (
1548 IN EFI_HANDLE Controller,
1549 IN EFI_USB2_HC_PROTOCOL *This
1550 )
1551 {
1552 USB_HC_DEV *Uhc;
1553 EFI_STATUS Status;
1554
1555 //
1556 // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
1557 //
1558 Uhc = UHC_FROM_USB2_HC_PROTO (This);
1559
1560
1561 Status = gBS->UninstallProtocolInterface (
1562 Controller,
1563 &gEfiUsb2HcProtocolGuid,
1564 &Uhc->Usb2Hc
1565 );
1566 if (EFI_ERROR (Status)) {
1567 return ;
1568 }
1569
1570 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1571 UhciFreeAllAsyncReq (Uhc);
1572 UhciDestoryFrameList (Uhc);
1573
1574 //
1575 // Restore original PCI attributes
1576 //
1577 Uhc->PciIo->Attributes (
1578 Uhc->PciIo,
1579 EfiPciIoAttributeOperationSet,
1580 Uhc->OriginalPciAttributes,
1581 NULL
1582 );
1583
1584 UhciFreeDev (Uhc);
1585 }
1586
1587 /**
1588 One notified function to stop the Host Controller when gBS->ExitBootServices() called.
1589
1590 @param Event Pointer to this event
1591 @param Context Event handler private data
1592
1593 **/
1594 VOID
1595 EFIAPI
1596 UhcExitBootService (
1597 EFI_EVENT Event,
1598 VOID *Context
1599 )
1600 {
1601 USB_HC_DEV *Uhc;
1602
1603 Uhc = (USB_HC_DEV *) Context;
1604
1605 //
1606 // Stop the Host Controller
1607 //
1608 UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
1609
1610 //
1611 // Reset the Host Controller
1612 //
1613 UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
1614 gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
1615 }
1616
1617 /**
1618 Starting the Usb UHCI Driver.
1619
1620 @param This Protocol instance pointer.
1621 @param Controller Handle of device to test.
1622 @param RemainingDevicePath Not used.
1623
1624 @retval EFI_SUCCESS This driver supports this device.
1625 @retval EFI_UNSUPPORTED This driver does not support this device.
1626 @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error.
1627 EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
1628
1629 **/
1630 EFI_STATUS
1631 EFIAPI
1632 UhciDriverBindingStart (
1633 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1634 IN EFI_HANDLE Controller,
1635 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1636 )
1637 {
1638 EFI_STATUS Status;
1639 EFI_PCI_IO_PROTOCOL *PciIo;
1640 USB_HC_DEV *Uhc;
1641 UINT64 Supports;
1642 UINT64 OriginalPciAttributes;
1643 BOOLEAN PciAttributesSaved;
1644 EFI_DEVICE_PATH_PROTOCOL *HcDevicePath;
1645
1646 //
1647 // Open PCIIO, then enable the EHC device and turn off emulation
1648 //
1649 Uhc = NULL;
1650 Status = gBS->OpenProtocol (
1651 Controller,
1652 &gEfiPciIoProtocolGuid,
1653 (VOID **) &PciIo,
1654 This->DriverBindingHandle,
1655 Controller,
1656 EFI_OPEN_PROTOCOL_BY_DRIVER
1657 );
1658
1659 if (EFI_ERROR (Status)) {
1660 return Status;
1661 }
1662
1663 //
1664 // Open Device Path Protocol for on USB host controller
1665 //
1666 HcDevicePath = NULL;
1667 Status = gBS->OpenProtocol (
1668 Controller,
1669 &gEfiDevicePathProtocolGuid,
1670 (VOID **) &HcDevicePath,
1671 This->DriverBindingHandle,
1672 Controller,
1673 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1674 );
1675
1676 PciAttributesSaved = FALSE;
1677 //
1678 // Save original PCI attributes
1679 //
1680 Status = PciIo->Attributes (
1681 PciIo,
1682 EfiPciIoAttributeOperationGet,
1683 0,
1684 &OriginalPciAttributes
1685 );
1686
1687 if (EFI_ERROR (Status)) {
1688 goto CLOSE_PCIIO;
1689 }
1690 PciAttributesSaved = TRUE;
1691
1692 //
1693 // Robustnesss improvement such as for UoL
1694 // Default is not required.
1695 //
1696 if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
1697 UhciTurnOffUsbEmulation (PciIo);
1698 }
1699
1700 Status = PciIo->Attributes (
1701 PciIo,
1702 EfiPciIoAttributeOperationSupported,
1703 0,
1704 &Supports
1705 );
1706 if (!EFI_ERROR (Status)) {
1707 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
1708 Status = PciIo->Attributes (
1709 PciIo,
1710 EfiPciIoAttributeOperationEnable,
1711 Supports,
1712 NULL
1713 );
1714 }
1715
1716 if (EFI_ERROR (Status)) {
1717 goto CLOSE_PCIIO;
1718 }
1719
1720 Uhc = UhciAllocateDev (PciIo, HcDevicePath, OriginalPciAttributes);
1721
1722 if (Uhc == NULL) {
1723 Status = EFI_OUT_OF_RESOURCES;
1724 goto CLOSE_PCIIO;
1725 }
1726
1727 //
1728 // Allocate and Init Host Controller's Frame List Entry
1729 //
1730 Status = UhciInitFrameList (Uhc);
1731
1732 if (EFI_ERROR (Status)) {
1733 Status = EFI_OUT_OF_RESOURCES;
1734 goto FREE_UHC;
1735 }
1736
1737 Status = gBS->SetTimer (
1738 Uhc->AsyncIntMonitor,
1739 TimerPeriodic,
1740 UHC_ASYNC_POLL_INTERVAL
1741 );
1742
1743 if (EFI_ERROR (Status)) {
1744 goto FREE_UHC;
1745 }
1746
1747 //
1748 // Install USB2_HC_PROTOCOL
1749 //
1750 Status = gBS->InstallMultipleProtocolInterfaces (
1751 &Controller,
1752 &gEfiUsb2HcProtocolGuid,
1753 &Uhc->Usb2Hc,
1754 NULL
1755 );
1756
1757 if (EFI_ERROR (Status)) {
1758 goto FREE_UHC;
1759 }
1760
1761 //
1762 // Create event to stop the HC when exit boot service.
1763 //
1764 Status = gBS->CreateEventEx (
1765 EVT_NOTIFY_SIGNAL,
1766 TPL_NOTIFY,
1767 UhcExitBootService,
1768 Uhc,
1769 &gEfiEventExitBootServicesGuid,
1770 &Uhc->ExitBootServiceEvent
1771 );
1772 if (EFI_ERROR (Status)) {
1773 goto UNINSTALL_USBHC;
1774 }
1775
1776 //
1777 // Install the component name protocol
1778 //
1779 Uhc->CtrlNameTable = NULL;
1780
1781 AddUnicodeString2 (
1782 "eng",
1783 gUhciComponentName.SupportedLanguages,
1784 &Uhc->CtrlNameTable,
1785 L"Usb Universal Host Controller",
1786 TRUE
1787 );
1788 AddUnicodeString2 (
1789 "en",
1790 gUhciComponentName2.SupportedLanguages,
1791 &Uhc->CtrlNameTable,
1792 L"Usb Universal Host Controller",
1793 FALSE
1794 );
1795
1796
1797 //
1798 // Start the UHCI hardware, also set its reclamation point to 64 bytes
1799 //
1800 UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
1801
1802 return EFI_SUCCESS;
1803
1804 UNINSTALL_USBHC:
1805 gBS->UninstallMultipleProtocolInterfaces (
1806 Controller,
1807 &gEfiUsb2HcProtocolGuid,
1808 &Uhc->Usb2Hc,
1809 NULL
1810 );
1811
1812 FREE_UHC:
1813 UhciFreeDev (Uhc);
1814
1815 CLOSE_PCIIO:
1816 if (PciAttributesSaved) {
1817 //
1818 // Restore original PCI attributes
1819 //
1820 PciIo->Attributes (
1821 PciIo,
1822 EfiPciIoAttributeOperationSet,
1823 OriginalPciAttributes,
1824 NULL
1825 );
1826 }
1827
1828 gBS->CloseProtocol (
1829 Controller,
1830 &gEfiPciIoProtocolGuid,
1831 This->DriverBindingHandle,
1832 Controller
1833 );
1834
1835 return Status;
1836 }
1837
1838
1839 /**
1840 Stop this driver on ControllerHandle. Support stoping any child handles
1841 created by this driver.
1842
1843 @param This Protocol instance pointer.
1844 @param Controller Handle of device to stop driver on.
1845 @param NumberOfChildren Number of Children in the ChildHandleBuffer.
1846 @param ChildHandleBuffer List of handles for the children we need to stop.
1847
1848 @return EFI_SUCCESS
1849 @return others
1850
1851 **/
1852 EFI_STATUS
1853 EFIAPI
1854 UhciDriverBindingStop (
1855 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1856 IN EFI_HANDLE Controller,
1857 IN UINTN NumberOfChildren,
1858 IN EFI_HANDLE *ChildHandleBuffer
1859 )
1860 {
1861 EFI_USB2_HC_PROTOCOL *Usb2Hc;
1862 EFI_STATUS Status;
1863
1864 Status = gBS->OpenProtocol (
1865 Controller,
1866 &gEfiUsb2HcProtocolGuid,
1867 (VOID **) &Usb2Hc,
1868 This->DriverBindingHandle,
1869 Controller,
1870 EFI_OPEN_PROTOCOL_GET_PROTOCOL
1871 );
1872
1873 //
1874 // Test whether the Controller handler passed in is a valid
1875 // Usb controller handle that should be supported, if not,
1876 // return the error status directly
1877 //
1878 if (EFI_ERROR (Status)) {
1879 return Status;
1880 }
1881
1882 UhciCleanDevUp (Controller, Usb2Hc);
1883
1884 gBS->CloseProtocol (
1885 Controller,
1886 &gEfiPciIoProtocolGuid,
1887 This->DriverBindingHandle,
1888 Controller
1889 );
1890
1891 return EFI_SUCCESS;
1892 }
1893