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