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