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