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