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