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