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