DebugLib:
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Uhci / Dxe / uhci.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Uhci.c
15
16 Abstract:
17
18
19 Revision History
20 --*/
21
22 #include "uhci.h"
23
24 //
25 // Prototypes
26 // Driver model protocol interface
27 //
28
29 EFI_STATUS
30 EFIAPI
31 UHCIDriverEntryPoint (
32 IN EFI_HANDLE ImageHandle,
33 IN EFI_SYSTEM_TABLE *SystemTable
34 );
35
36 EFI_STATUS
37 EFIAPI
38 UHCIDriverBindingSupported (
39 IN EFI_DRIVER_BINDING_PROTOCOL *This,
40 IN EFI_HANDLE Controller,
41 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
42 );
43
44 EFI_STATUS
45 EFIAPI
46 UHCIDriverBindingStart (
47 IN EFI_DRIVER_BINDING_PROTOCOL *This,
48 IN EFI_HANDLE Controller,
49 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
50 );
51
52 EFI_STATUS
53 EFIAPI
54 UHCIDriverBindingStop (
55 IN EFI_DRIVER_BINDING_PROTOCOL *This,
56 IN EFI_HANDLE Controller,
57 IN UINTN NumberOfChildren,
58 IN EFI_HANDLE *ChildHandleBuffer
59 );
60
61 //
62 // UHCI interface functions
63 //
64
65 EFI_STATUS
66 EFIAPI
67 UHCIReset (
68 IN EFI_USB_HC_PROTOCOL *This,
69 IN UINT16 Attributes
70 );
71
72 EFI_STATUS
73 EFIAPI
74 UHCIGetState (
75 IN EFI_USB_HC_PROTOCOL *This,
76 OUT EFI_USB_HC_STATE *State
77 );
78
79 EFI_STATUS
80 EFIAPI
81 UHCISetState (
82 IN EFI_USB_HC_PROTOCOL *This,
83 IN EFI_USB_HC_STATE State
84 );
85
86 EFI_STATUS
87 EFIAPI
88 UHCIControlTransfer (
89 IN EFI_USB_HC_PROTOCOL *This,
90 IN UINT8 DeviceAddress,
91 IN BOOLEAN IsSlowDevice,
92 IN UINT8 MaximumPacketLength,
93 IN EFI_USB_DEVICE_REQUEST *Request,
94 IN EFI_USB_DATA_DIRECTION TransferDirection,
95 IN OUT VOID *Data, OPTIONAL
96 IN OUT UINTN *DataLength, OPTIONAL
97 IN UINTN TimeOut,
98 OUT UINT32 *TransferResult
99 );
100
101 EFI_STATUS
102 EFIAPI
103 UHCIBulkTransfer (
104 IN EFI_USB_HC_PROTOCOL *This,
105 IN UINT8 DeviceAddress,
106 IN UINT8 EndPointAddress,
107 IN UINT8 MaximumPacketLength,
108 IN OUT VOID *Data,
109 IN OUT UINTN *DataLength,
110 IN OUT UINT8 *DataToggle,
111 IN UINTN TimeOut,
112 OUT UINT32 *TransferResult
113 );
114
115 EFI_STATUS
116 EFIAPI
117 UHCIAsyncInterruptTransfer (
118 IN EFI_USB_HC_PROTOCOL * This,
119 IN UINT8 DeviceAddress,
120 IN UINT8 EndPointAddress,
121 IN BOOLEAN IsSlowDevice,
122 IN UINT8 MaxiumPacketLength,
123 IN BOOLEAN IsNewTransfer,
124 IN OUT UINT8 *DataToggle,
125 IN UINTN PollingInterval, OPTIONAL
126 IN UINTN DataLength, OPTIONAL
127 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL
128 IN VOID *Context OPTIONAL
129 );
130
131 EFI_STATUS
132 EFIAPI
133 UHCISyncInterruptTransfer (
134 IN EFI_USB_HC_PROTOCOL *This,
135 IN UINT8 DeviceAddress,
136 IN UINT8 EndPointAddress,
137 IN BOOLEAN IsSlowDevice,
138 IN UINT8 MaximumPacketLength,
139 IN OUT VOID *Data,
140 IN OUT UINTN *DataLength,
141 IN OUT UINT8 *DataToggle,
142 IN UINTN TimeOut,
143 OUT UINT32 *TransferResult
144 );
145
146 EFI_STATUS
147 EFIAPI
148 UHCIIsochronousTransfer (
149 IN EFI_USB_HC_PROTOCOL *This,
150 IN UINT8 DeviceAddress,
151 IN UINT8 EndPointAddress,
152 IN UINT8 MaximumPacketLength,
153 IN OUT VOID *Data,
154 IN UINTN DataLength,
155 OUT UINT32 *TransferResult
156 );
157
158 EFI_STATUS
159 EFIAPI
160 UHCIAsyncIsochronousTransfer (
161 IN EFI_USB_HC_PROTOCOL * This,
162 IN UINT8 DeviceAddress,
163 IN UINT8 EndPointAddress,
164 IN UINT8 MaximumPacketLength,
165 IN OUT VOID *Data,
166 IN UINTN DataLength,
167 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
168 IN VOID *Context OPTIONAL
169 );
170
171 EFI_STATUS
172 EFIAPI
173 UHCIGetRootHubPortNumber (
174 IN EFI_USB_HC_PROTOCOL *This,
175 OUT UINT8 *PortNumber
176 );
177
178 EFI_STATUS
179 EFIAPI
180 UHCIGetRootHubPortStatus (
181 IN EFI_USB_HC_PROTOCOL *This,
182 IN UINT8 PortNumber,
183 OUT EFI_USB_PORT_STATUS *PortStatus
184 );
185
186 EFI_STATUS
187 EFIAPI
188 UHCISetRootHubPortFeature (
189 IN EFI_USB_HC_PROTOCOL *This,
190 IN UINT8 PortNumber,
191 IN EFI_USB_PORT_FEATURE PortFeature
192 );
193
194 EFI_STATUS
195 EFIAPI
196 UHCIClearRootHubPortFeature (
197 IN EFI_USB_HC_PROTOCOL *This,
198 IN UINT8 PortNumber,
199 IN EFI_USB_PORT_FEATURE PortFeature
200 );
201
202 //
203 // Asynchronous interrupt transfer monitor function
204 //
205 VOID
206 EFIAPI
207 MonitorInterruptTrans (
208 IN EFI_EVENT Event,
209 IN VOID *Context
210 );
211
212 //
213 // UHCI Driver Global Variables
214 //
215 EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
216 UHCIDriverBindingSupported,
217 UHCIDriverBindingStart,
218 UHCIDriverBindingStop,
219 0x10,
220 NULL,
221 NULL
222 };
223
224 EFI_STATUS
225 EFIAPI
226 UHCIDriverBindingSupported (
227 IN EFI_DRIVER_BINDING_PROTOCOL *This,
228 IN EFI_HANDLE Controller,
229 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
230 )
231 /*++
232
233 Routine Description:
234 Test to see if this driver supports ControllerHandle. Any ControllerHandle
235 that has UsbHcProtocol installed will be supported.
236
237 Arguments:
238 This - Protocol instance pointer.
239 Controller, - Handle of device to test
240 RemainingDevicePath - Not used
241
242 Returns:
243 EFI_SUCCESS - This driver supports this device.
244 EFI_UNSUPPORTED - This driver does not support this device.
245
246 --*/
247 {
248 EFI_STATUS OpenStatus;
249 EFI_STATUS Status;
250 EFI_PCI_IO_PROTOCOL *PciIo;
251 USB_CLASSC UsbClassCReg;
252
253 //
254 // Test whether there is PCI IO Protocol attached on the controller handle.
255 //
256 OpenStatus = gBS->OpenProtocol (
257 Controller,
258 &gEfiPciIoProtocolGuid,
259 (VOID **) &PciIo,
260 This->DriverBindingHandle,
261 Controller,
262 EFI_OPEN_PROTOCOL_BY_DRIVER
263 );
264 if (EFI_ERROR (OpenStatus)) {
265 return OpenStatus;
266 }
267
268 Status = PciIo->Pci.Read (
269 PciIo,
270 EfiPciIoWidthUint8,
271 CLASSC,
272 sizeof (USB_CLASSC) / sizeof (UINT8),
273 &UsbClassCReg
274 );
275 if (EFI_ERROR (Status)) {
276 gBS->CloseProtocol (
277 Controller,
278 &gEfiPciIoProtocolGuid,
279 This->DriverBindingHandle,
280 Controller
281 );
282 return EFI_UNSUPPORTED;
283 }
284 //
285 // Test whether the controller belongs to UHCI type
286 //
287 if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
288 (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
289 (UsbClassCReg.PI != PCI_CLASSC_PI_UHCI)) {
290
291 gBS->CloseProtocol (
292 Controller,
293 &gEfiPciIoProtocolGuid,
294 This->DriverBindingHandle,
295 Controller
296 );
297
298 return EFI_UNSUPPORTED;
299 }
300 gBS->CloseProtocol (
301 Controller,
302 &gEfiPciIoProtocolGuid,
303 This->DriverBindingHandle,
304 Controller
305 );
306 return EFI_SUCCESS;
307
308 }
309
310 EFI_STATUS
311 EFIAPI
312 UHCIDriverBindingStart (
313 IN EFI_DRIVER_BINDING_PROTOCOL *This,
314 IN EFI_HANDLE Controller,
315 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
316 )
317 /*++
318
319 Routine Description:
320 Starting the Usb UHCI Driver
321
322 Arguments:
323 This - Protocol instance pointer.
324 Controller - Handle of device to test
325 RemainingDevicePath - Not used
326
327 Returns:
328 EFI_SUCCESS - This driver supports this device.
329 EFI_UNSUPPORTED - This driver does not support this device.
330 EFI_DEVICE_ERROR - This driver cannot be started due to device
331 Error
332 EFI_OUT_OF_RESOURCES
333
334 --*/
335 {
336 EFI_STATUS Status;
337 UINTN FlBaseAddrReg;
338 EFI_PCI_IO_PROTOCOL *PciIo;
339 USB_HC_DEV *HcDev;
340
341 HcDev = NULL;
342
343 Status = gBS->OpenProtocol (
344 Controller,
345 &gEfiPciIoProtocolGuid,
346 (VOID **) &PciIo,
347 This->DriverBindingHandle,
348 Controller,
349 EFI_OPEN_PROTOCOL_BY_DRIVER
350 );
351 if (EFI_ERROR (Status)) {
352 return Status;
353 }
354 //
355 // Turn off USB emulation
356 //
357 TurnOffUSBEmulation (PciIo);
358
359 //
360 // Enable the USB Host Controller
361 //
362 Status = PciIo->Attributes (
363 PciIo,
364 EfiPciIoAttributeOperationEnable,
365 EFI_PCI_DEVICE_ENABLE,
366 NULL
367 );
368 if (EFI_ERROR (Status)) {
369 gBS->CloseProtocol (
370 Controller,
371 &gEfiPciIoProtocolGuid,
372 This->DriverBindingHandle,
373 Controller
374 );
375 return EFI_UNSUPPORTED;
376 }
377
378 //
379 // allocate memory for UHC private data structure
380 //
381 HcDev = AllocateZeroPool (sizeof (USB_HC_DEV));
382 if (HcDev == NULL) {
383 gBS->CloseProtocol (
384 Controller,
385 &gEfiPciIoProtocolGuid,
386 This->DriverBindingHandle,
387 Controller
388 );
389 return EFI_OUT_OF_RESOURCES;
390 }
391
392 //
393 // init EFI_USB_HC_PROTOCOL protocol interface and install the protocol
394 //
395 HcDev->UsbHc.Reset = UHCIReset;
396 HcDev->UsbHc.GetState = UHCIGetState;
397 HcDev->UsbHc.SetState = UHCISetState;
398 HcDev->UsbHc.ControlTransfer = UHCIControlTransfer;
399 HcDev->UsbHc.BulkTransfer = UHCIBulkTransfer;
400 HcDev->UsbHc.AsyncInterruptTransfer = UHCIAsyncInterruptTransfer;
401 HcDev->UsbHc.SyncInterruptTransfer = UHCISyncInterruptTransfer;
402 HcDev->UsbHc.IsochronousTransfer = UHCIIsochronousTransfer;
403 HcDev->UsbHc.AsyncIsochronousTransfer = UHCIAsyncIsochronousTransfer;
404 HcDev->UsbHc.GetRootHubPortNumber = UHCIGetRootHubPortNumber;
405 HcDev->UsbHc.GetRootHubPortStatus = UHCIGetRootHubPortStatus;
406 HcDev->UsbHc.SetRootHubPortFeature = UHCISetRootHubPortFeature;
407 HcDev->UsbHc.ClearRootHubPortFeature = UHCIClearRootHubPortFeature;
408
409 HcDev->UsbHc.MajorRevision = 0x1;
410 HcDev->UsbHc.MinorRevision = 0x1;
411
412 //
413 // Init UHCI private data structures
414 //
415 HcDev->Signature = USB_HC_DEV_SIGNATURE;
416 HcDev->PciIo = PciIo;
417
418 FlBaseAddrReg = USBFLBASEADD;
419
420 //
421 // Allocate and Init Host Controller's Frame List Entry
422 //
423 Status = CreateFrameList (HcDev, (UINT32) FlBaseAddrReg);
424 if (EFI_ERROR (Status)) {
425
426 if (HcDev != NULL) {
427 gBS->FreePool (HcDev);
428 }
429
430 gBS->CloseProtocol (
431 Controller,
432 &gEfiPciIoProtocolGuid,
433 This->DriverBindingHandle,
434 Controller
435 );
436 return EFI_OUT_OF_RESOURCES;
437 }
438
439 //
440 // Init interrupt list head in the HcDev structure.
441 //
442 InitializeListHead (&(HcDev->InterruptListHead));
443
444 //
445 // Create timer for interrupt transfer result polling
446 //
447 Status = gBS->CreateEvent (
448 EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
449 EFI_TPL_NOTIFY,
450 MonitorInterruptTrans,
451 HcDev,
452 &HcDev->InterruptTransTimer
453 );
454 if (EFI_ERROR (Status)) {
455
456 FreeFrameListEntry (HcDev);
457
458 if (HcDev != NULL) {
459 gBS->FreePool (HcDev);
460 }
461
462 gBS->CloseProtocol (
463 Controller,
464 &gEfiPciIoProtocolGuid,
465 This->DriverBindingHandle,
466 Controller
467 );
468 return EFI_UNSUPPORTED;
469 }
470
471 //
472 // Here set interrupt transfer polling timer in 50ms unit.
473 //
474 Status = gBS->SetTimer (
475 HcDev->InterruptTransTimer,
476 TimerPeriodic,
477 INTERRUPT_POLLING_TIME
478 );
479 if (EFI_ERROR (Status)) {
480 gBS->CloseEvent (HcDev->InterruptTransTimer);
481
482 FreeFrameListEntry (HcDev);
483
484 if (HcDev != NULL) {
485 gBS->FreePool (HcDev);
486 }
487
488 gBS->CloseProtocol (
489 Controller,
490 &gEfiPciIoProtocolGuid,
491 This->DriverBindingHandle,
492 Controller
493 );
494 return EFI_UNSUPPORTED;
495 }
496
497 //
498 // QH,TD structures must in common buffer that will be
499 // accessed by both cpu and usb bus master at the same time.
500 // so, there must has memory management for QH,TD structures.
501 //
502 Status = InitializeMemoryManagement (HcDev);
503 if (EFI_ERROR (Status)) {
504
505 gBS->CloseEvent (HcDev->InterruptTransTimer);
506
507 FreeFrameListEntry (HcDev);
508
509 if (HcDev != NULL) {
510 gBS->FreePool (HcDev);
511 }
512
513 gBS->CloseProtocol (
514 Controller,
515 &gEfiPciIoProtocolGuid,
516 This->DriverBindingHandle,
517 Controller
518 );
519 return Status;
520 }
521
522 //
523 // Install Host Controller Protocol
524 //
525 Status = gBS->InstallProtocolInterface (
526 &Controller,
527 &gEfiUsbHcProtocolGuid,
528 EFI_NATIVE_INTERFACE,
529 &HcDev->UsbHc
530 );
531 if (EFI_ERROR (Status)) {
532 gBS->CloseEvent (HcDev->InterruptTransTimer);
533 FreeFrameListEntry (HcDev);
534 DelMemoryManagement (HcDev);
535
536 if (HcDev != NULL) {
537 gBS->FreePool (HcDev);
538 }
539
540 gBS->CloseProtocol (
541 Controller,
542 &gEfiPciIoProtocolGuid,
543 This->DriverBindingHandle,
544 Controller
545 );
546 return Status;
547 }
548
549 //
550 // component name protocol.
551 //
552 HcDev->ControllerNameTable = NULL;
553 AddUnicodeString (
554 "eng",
555 gUhciComponentName.SupportedLanguages,
556 &HcDev->ControllerNameTable,
557 (CHAR16 *) L"Usb Universal Host Controller"
558 );
559
560 return EFI_SUCCESS;
561 }
562
563
564 EFI_STATUS
565 UnInstallUHCInterface (
566 IN EFI_HANDLE Controller,
567 IN EFI_USB_HC_PROTOCOL *This
568 )
569 /*++
570 Routine Description:
571 UnInstall UHCInterface
572 Arguments:
573 Controller - Controller handle
574 This - Protocol instance pointer.
575 Returns:
576 EFI_SUCCESS
577 others
578 --*/
579 {
580 USB_HC_DEV *HcDev;
581
582 HcDev = USB_HC_DEV_FROM_THIS (This);
583
584 gBS->UninstallProtocolInterface (
585 Controller,
586 &gEfiUsbHcProtocolGuid,
587 &HcDev->UsbHc
588 );
589
590 //
591 // first stop USB Host Controller
592 //
593 This->SetState (This, EfiUsbHcStateHalt);
594
595 //
596 // Delete interrupt transfer polling timer
597 //
598 gBS->CloseEvent (HcDev->InterruptTransTimer);
599
600 //
601 // Delete all the asynchronous interrupt transfers in the interrupt list
602 // and free associated memory
603 //
604 ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead));
605
606 //
607 // free Frame List Entry.
608 //
609 FreeFrameListEntry (HcDev);
610
611 //
612 // Free common buffer allocated for QH,TD structures
613 //
614 DelMemoryManagement (HcDev);
615
616 if (HcDev->ControllerNameTable) {
617 FreeUnicodeStringTable (HcDev->ControllerNameTable);
618 }
619 //
620 // Disable the USB Host Controller
621 //
622 HcDev->PciIo->Attributes (
623 HcDev->PciIo,
624 EfiPciIoAttributeOperationDisable,
625 EFI_PCI_DEVICE_ENABLE,
626 NULL
627 );
628
629 gBS->FreePool (HcDev);
630
631 return EFI_SUCCESS;
632 }
633
634
635 EFI_STATUS
636 EFIAPI
637 UHCIDriverBindingStop (
638 IN EFI_DRIVER_BINDING_PROTOCOL *This,
639 IN EFI_HANDLE Controller,
640 IN UINTN NumberOfChildren,
641 IN EFI_HANDLE *ChildHandleBuffer
642 )
643 /*++
644
645 Routine Description:
646 Stop this driver on ControllerHandle. Support stoping any child handles
647 created by this driver.
648
649 Arguments:
650 This - Protocol instance pointer.
651 Controller - Handle of device to stop driver on
652 NumberOfChildren - Number of Children in the ChildHandleBuffer
653 ChildHandleBuffer - List of handles for the children we need to stop.
654
655 Returns:
656 EFI_SUCCESS
657 others
658
659 --*/
660 {
661 EFI_USB_HC_PROTOCOL *UsbHc;
662 EFI_STATUS OpenStatus;
663
664 OpenStatus = gBS->OpenProtocol (
665 Controller,
666 &gEfiUsbHcProtocolGuid,
667 (VOID **) &UsbHc,
668 This->DriverBindingHandle,
669 Controller,
670 EFI_OPEN_PROTOCOL_GET_PROTOCOL
671 );
672
673 //
674 // Test whether the Controller handler passed in is a valid
675 // Usb controller handle that should be supported, if not,
676 // return the error status directly
677 //
678 if (EFI_ERROR (OpenStatus)) {
679 return OpenStatus;
680 }
681 //
682 // free all the controller related memory and uninstall UHCI Protocol.
683 //
684 UnInstallUHCInterface (Controller, UsbHc);
685
686 gBS->CloseProtocol (
687 Controller,
688 &gEfiPciIoProtocolGuid,
689 This->DriverBindingHandle,
690 Controller
691 );
692
693 return EFI_SUCCESS;
694
695 }
696
697
698 EFI_STATUS
699 EFIAPI
700 UHCIReset (
701 IN EFI_USB_HC_PROTOCOL *This,
702 IN UINT16 Attributes
703 )
704 /*++
705
706 Routine Description:
707 Provides software reset for the USB host controller.
708
709 Arguments:
710
711 This A pointer to the EFI_USB_HC_PROTOCOL instance.
712
713 Attributes A bit mask of the reset operation to perform.
714 See below for a list of the supported bit mask values.
715
716 #define EFI_USB_HC_RESET_GLOBAL 0x0001
717 #define EFI_USB_HC_RESET_HOST_CONTROLLER 0x0002
718
719 EFI_USB_HC_RESET_GLOBAL
720 If this bit is set, a global reset signal will be sent to the USB bus.
721 This resets all of the USB bus logic, including the USB host
722 controller hardware and all the devices attached on the USB bus.
723 EFI_USB_HC_RESET_HOST_CONTROLLER
724 If this bit is set, the USB host controller hardware will be reset.
725 No reset signal will be sent to the USB bus.
726
727 Returns:
728 EFI_SUCCESS
729 The reset operation succeeded.
730 EFI_INVALID_PARAMETER
731 Attributes is not valid.
732 EFI_DEVICE_ERROR
733 An error was encountered while attempting to perform
734 the reset operation.
735 --*/
736 {
737 BOOLEAN Match;
738 USB_HC_DEV *HcDev;
739 UINT32 CommandRegAddr;
740 UINT32 FlBaseAddrReg;
741 UINT16 Command;
742 EFI_STATUS Status;
743
744 Match = FALSE;
745 HcDev = USB_HC_DEV_FROM_THIS (This);
746
747 CommandRegAddr = (UINT32) (USBCMD);
748 FlBaseAddrReg = (UINT32) (USBFLBASEADD);
749
750 if ((Attributes & EFI_USB_HC_RESET_GLOBAL) != 0) {
751 Match = TRUE;
752 //
753 // set the Global Reset bit in the command register
754 //
755 Status = ReadUHCCommandReg (
756 HcDev->PciIo,
757 CommandRegAddr,
758 &Command
759 );
760 if (EFI_ERROR (Status)) {
761 return EFI_DEVICE_ERROR;
762 }
763
764 Command |= USBCMD_GRESET;
765 Status = WriteUHCCommandReg (
766 HcDev->PciIo,
767 CommandRegAddr,
768 Command
769 );
770 if (EFI_ERROR (Status)) {
771 return EFI_DEVICE_ERROR;
772 }
773
774 //
775 // Wait 50ms for root port to let reset complete
776 // See UHCI spec page122 Reset signaling
777 //
778 gBS->Stall (ROOT_PORT_REST_TIME);
779
780 //
781 // Clear the Global Reset bit to zero.
782 //
783 Command &= ~USBCMD_GRESET;
784 Status = WriteUHCCommandReg (
785 HcDev->PciIo,
786 CommandRegAddr,
787 Command
788 );
789 if (EFI_ERROR (Status)) {
790 return EFI_DEVICE_ERROR;
791 }
792 //
793 // UHCI spec page120 reset recovery time
794 //
795 gBS->Stall (PORT_RESET_RECOVERY_TIME);
796 }
797
798 if ((Attributes & EFI_USB_HC_RESET_HOST_CONTROLLER) != 0) {
799 Match = TRUE;
800 //
801 // set Host Controller Reset bit to 1
802 //
803 Status = ReadUHCCommandReg (
804 HcDev->PciIo,
805 CommandRegAddr,
806 &Command
807 );
808 if (EFI_ERROR (Status)) {
809 return EFI_DEVICE_ERROR;
810 }
811
812 Command |= USBCMD_HCRESET;
813 Status = WriteUHCCommandReg (
814 HcDev->PciIo,
815 CommandRegAddr,
816 Command
817 );
818 if (EFI_ERROR (Status)) {
819 return EFI_DEVICE_ERROR;
820 }
821 //
822 // this bit will be reset by Host Controller when reset is completed.
823 // wait 10ms to let reset complete
824 //
825 gBS->Stall (PORT_RESET_RECOVERY_TIME);
826 }
827
828 if (!Match) {
829 return EFI_INVALID_PARAMETER;
830 }
831
832 //
833 // Delete all old transactions on the USB bus
834 //
835 CleanUsbTransactions (HcDev);
836
837 //
838 // Initialize Universal Host Controller's Frame List Data Structure
839 //
840 InitFrameList (HcDev);
841
842 //
843 // Reset may cause Frame List Base Address Register reset to zero,
844 // so set the original value back again.
845 //
846 SetFrameListBaseAddress (
847 HcDev->PciIo,
848 FlBaseAddrReg,
849 (UINT32) ((UINTN) HcDev->FrameListEntry)
850 );
851
852 return EFI_SUCCESS;
853 }
854
855 EFI_STATUS
856 EFIAPI
857 UHCIGetState (
858 IN EFI_USB_HC_PROTOCOL *This,
859 OUT EFI_USB_HC_STATE *State
860 )
861 /*++
862
863 Routine Description:
864 Retrieves current state of the USB host controller.
865
866 Arguments:
867
868 This A pointer to the EFI_USB_HC_PROTOCOL instance.
869
870 State A pointer to the EFI_USB_HC_STATE data structure that
871 indicates current state of the USB host controller.
872 Type EFI_USB_HC_STATE is defined below.
873
874 typedef enum {
875 EfiUsbHcStateHalt,
876 EfiUsbHcStateOperational,
877 EfiUsbHcStateSuspend,
878 EfiUsbHcStateMaximum
879 } EFI_USB_HC_STATE;
880
881 Returns:
882 EFI_SUCCESS
883 The state information of the host controller was returned in State.
884 EFI_INVALID_PARAMETER
885 State is NULL.
886 EFI_DEVICE_ERROR
887 An error was encountered while attempting to retrieve the
888 host controller's current state.
889 --*/
890 {
891 USB_HC_DEV *HcDev;
892 UINT32 CommandRegAddr;
893 UINT32 StatusRegAddr;
894 UINT16 UhcCommand;
895 UINT16 UhcStatus;
896 EFI_STATUS Status;
897
898 if (State == NULL) {
899 return EFI_INVALID_PARAMETER;
900 }
901
902 HcDev = USB_HC_DEV_FROM_THIS (This);
903
904 CommandRegAddr = (UINT32) (USBCMD);
905 StatusRegAddr = (UINT32) (USBSTS);
906
907 Status = ReadUHCCommandReg (
908 HcDev->PciIo,
909 CommandRegAddr,
910 &UhcCommand
911 );
912
913 if (EFI_ERROR (Status)) {
914 return EFI_DEVICE_ERROR;
915 }
916
917 Status = ReadUHCCommandReg (
918 HcDev->PciIo,
919 StatusRegAddr,
920 &UhcStatus
921 );
922 if (EFI_ERROR (Status)) {
923 return EFI_DEVICE_ERROR;
924 }
925
926 if (UhcCommand & USBCMD_EGSM) {
927 *State = EfiUsbHcStateSuspend;
928 return EFI_SUCCESS;
929 }
930
931 if ((UhcStatus & USBSTS_HCH) == 0) {
932 *State = EfiUsbHcStateOperational;
933 } else {
934 *State = EfiUsbHcStateHalt;
935 }
936
937 return EFI_SUCCESS;
938 }
939
940
941 EFI_STATUS
942 EFIAPI
943 UHCISetState (
944 IN EFI_USB_HC_PROTOCOL *This,
945 IN EFI_USB_HC_STATE State
946 )
947 /*++
948
949 Routine Description:
950 Sets the USB host controller to a specific state.
951
952 Arguments:
953
954 This A pointer to the EFI_USB_HC_PROTOCOL instance.
955
956 State Indicates the state of the host controller that will be set.
957
958 Returns:
959 EFI_SUCCESS
960 The USB host controller was successfully placed in the state
961 specified by State.
962 EFI_INVALID_PARAMETER
963 State is invalid.
964 EFI_DEVICE_ERROR
965 Failed to set the state specified by State due to device error.
966 --*/
967 {
968 USB_HC_DEV *HcDev;
969 UINT32 CommandRegAddr;
970 UINT32 StatusRegAddr;
971 UINT16 Command;
972 EFI_USB_HC_STATE CurrentState;
973 EFI_STATUS Status;
974
975 HcDev = USB_HC_DEV_FROM_THIS (This);
976
977 CommandRegAddr = (UINT32) (USBCMD);
978 StatusRegAddr = (UINT32) (USBSTS);
979
980 Status = UHCIGetState (This, &CurrentState);
981 if (EFI_ERROR (Status)) {
982 return EFI_DEVICE_ERROR;
983 }
984
985 switch (State) {
986
987 case EfiUsbHcStateHalt:
988 if (CurrentState == EfiUsbHcStateHalt) {
989 return EFI_SUCCESS;
990 }
991
992 Status = ReadUHCCommandReg (
993 HcDev->PciIo,
994 CommandRegAddr,
995 &Command
996 );
997 if (EFI_ERROR (Status)) {
998 return EFI_DEVICE_ERROR;
999 }
1000
1001 Command &= ~USBCMD_RS;
1002
1003 Status = WriteUHCCommandReg (
1004 HcDev->PciIo,
1005 CommandRegAddr,
1006 Command
1007 );
1008 if (EFI_ERROR (Status)) {
1009 return EFI_DEVICE_ERROR;
1010 }
1011
1012 StatusRegAddr = (UINT32) (USBSTS);
1013 //
1014 // ensure the HC is in halt status after send the stop command
1015 //
1016 if (WaitForUHCHalt (HcDev->PciIo, StatusRegAddr, STALL_1_SECOND) == EFI_TIMEOUT) {
1017 return EFI_DEVICE_ERROR;
1018 }
1019 break;
1020
1021 case EfiUsbHcStateOperational:
1022 if (IsHostSysOrProcessErr (HcDev->PciIo, StatusRegAddr)) {
1023 return EFI_DEVICE_ERROR;
1024 }
1025
1026 switch (CurrentState) {
1027
1028 case EfiUsbHcStateOperational:
1029 return EFI_SUCCESS;
1030
1031 case EfiUsbHcStateHalt:
1032 //
1033 // Set Run/Stop bit to 1.
1034 //
1035 Status = ReadUHCCommandReg (
1036 HcDev->PciIo,
1037 CommandRegAddr,
1038 &Command
1039 );
1040 if (EFI_ERROR (Status)) {
1041 return EFI_DEVICE_ERROR;
1042 }
1043
1044 Command |= USBCMD_RS | USBCMD_MAXP;
1045 Status = WriteUHCCommandReg (
1046 HcDev->PciIo,
1047 CommandRegAddr,
1048 Command
1049 );
1050 if (EFI_ERROR (Status)) {
1051 return EFI_DEVICE_ERROR;
1052 }
1053
1054 break;
1055
1056 case EfiUsbHcStateSuspend:
1057 Status = ReadUHCCommandReg (
1058 HcDev->PciIo,
1059 CommandRegAddr,
1060 &Command
1061 );
1062 if (EFI_ERROR (Status)) {
1063 return EFI_DEVICE_ERROR;
1064 }
1065
1066 //
1067 // FGR(Force Global Resume) bit is 0
1068 //
1069 if ((Command | (~USBCMD_FGR)) != 0xFF) {
1070 //
1071 // Write FGR bit to 1
1072 //
1073 Command |= USBCMD_FGR;
1074 WriteUHCCommandReg (
1075 HcDev->PciIo,
1076 CommandRegAddr,
1077 Command
1078 );
1079 }
1080
1081 //
1082 // wait 20ms to let resume complete
1083 // (20ms is specified by UHCI spec)
1084 //
1085 gBS->Stall (FORCE_GLOBAL_RESUME_TIME);
1086
1087 //
1088 // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
1089 //
1090 Command &= ~USBCMD_FGR;
1091 Command &= ~USBCMD_EGSM;
1092 Command |= USBCMD_RS;
1093 WriteUHCCommandReg (
1094 HcDev->PciIo,
1095 CommandRegAddr,
1096 Command
1097 );
1098 break;
1099
1100 default:
1101 break;
1102 }
1103 break;
1104
1105 case EfiUsbHcStateSuspend:
1106 if (CurrentState == EfiUsbHcStateSuspend) {
1107 return EFI_SUCCESS;
1108 }
1109
1110 Status = UHCISetState (This, EfiUsbHcStateHalt);
1111 if (EFI_ERROR (Status)) {
1112 return EFI_DEVICE_ERROR;
1113 }
1114 //
1115 // Set Enter Global Suspend Mode bit to 1.
1116 //
1117 Status = ReadUHCCommandReg (
1118 HcDev->PciIo,
1119 CommandRegAddr,
1120 &Command
1121 );
1122 if (EFI_ERROR (Status)) {
1123 return EFI_DEVICE_ERROR;
1124 }
1125
1126 Command |= USBCMD_EGSM;
1127 Status = WriteUHCCommandReg (
1128 HcDev->PciIo,
1129 CommandRegAddr,
1130 Command
1131 );
1132 if (EFI_ERROR (Status)) {
1133 return EFI_DEVICE_ERROR;
1134 }
1135 break;
1136
1137 default:
1138 return EFI_INVALID_PARAMETER;
1139 }
1140
1141 return EFI_SUCCESS;
1142 }
1143
1144 EFI_STATUS
1145 EFIAPI
1146 UHCIGetRootHubPortNumber (
1147 IN EFI_USB_HC_PROTOCOL *This,
1148 OUT UINT8 *PortNumber
1149 )
1150 /*++
1151
1152 Routine Description:
1153 Retrieves the number of root hub ports.
1154
1155 Arguments:
1156
1157 This A pointer to the EFI_USB_HC_PROTOCOL instance.
1158
1159 PortNumber A pointer to the number of the root hub ports.
1160
1161 Returns:
1162 EFI_SUCCESS
1163 The port number was retrieved successfully.
1164 EFI_INVALID_PARAMETER
1165 PortNumber is NULL.
1166 EFI_DEVICE_ERROR
1167 An error was encountered while attempting to
1168 retrieve the port number.
1169 --*/
1170 {
1171 USB_HC_DEV *HcDev;
1172 UINT32 PSAddr;
1173 UINT16 RHPortControl;
1174 UINT32 Index;
1175 EFI_STATUS Status;
1176
1177 HcDev = USB_HC_DEV_FROM_THIS (This);
1178
1179 if (PortNumber == NULL) {
1180 return EFI_INVALID_PARAMETER;
1181 }
1182
1183 *PortNumber = 0;
1184
1185 for (Index = 0; Index < 2; Index++) {
1186 PSAddr = (UINT32) (USBPORTSC1 + Index * 2);
1187 Status = ReadRootPortReg (
1188 HcDev->PciIo,
1189 PSAddr,
1190 &RHPortControl
1191 );
1192 if (EFI_ERROR (Status)) {
1193 return EFI_DEVICE_ERROR;
1194 }
1195 //
1196 // Port Register content is valid
1197 //
1198 if (RHPortControl != 0xff) {
1199 (*PortNumber)++;
1200 }
1201 }
1202
1203 return EFI_SUCCESS;
1204 }
1205
1206 EFI_STATUS
1207 EFIAPI
1208 UHCIGetRootHubPortStatus (
1209 IN EFI_USB_HC_PROTOCOL *This,
1210 IN UINT8 PortNumber,
1211 OUT EFI_USB_PORT_STATUS *PortStatus
1212 )
1213 /*++
1214
1215 Routine Description:
1216 Retrieves the current status of a USB root hub port.
1217
1218 Arguments:
1219
1220 This A pointer to the EFI_USB_HC_PROTOCOL.
1221
1222 PortNumber Specifies the root hub port from which the status
1223 is to be retrieved. This value is zero-based. For example,
1224 if a root hub has two ports, then the first port is numbered 0,
1225 and the second port is numbered 1.
1226
1227 PortStatus A pointer to the current port status bits and
1228 port status change bits.
1229
1230 Returns:
1231 EFI_SUCCESS
1232 The status of the USB root hub port specified by PortNumber
1233 was returned in PortStatus.
1234 EFI_INVALID_PARAMETER
1235 PortNumber is invalid.
1236 EFI_DEVICE_ERROR - Can't read register
1237 --*/
1238 {
1239 USB_HC_DEV *HcDev;
1240 UINT32 PSAddr;
1241 UINT16 RHPortStatus;
1242 UINT8 TotalPortNumber;
1243 EFI_STATUS Status;
1244
1245 if (PortStatus == NULL) {
1246 return EFI_INVALID_PARAMETER;
1247 }
1248
1249 UHCIGetRootHubPortNumber (This, &TotalPortNumber);
1250 if (PortNumber >= TotalPortNumber) {
1251 return EFI_INVALID_PARAMETER;
1252 }
1253
1254 HcDev = USB_HC_DEV_FROM_THIS (This);
1255 PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2);
1256
1257 //
1258 // Clear port status
1259 //
1260 PortStatus->PortStatus = 0;
1261 PortStatus->PortChangeStatus = 0;
1262
1263 Status = ReadRootPortReg (
1264 HcDev->PciIo,
1265 PSAddr,
1266 &RHPortStatus
1267 );
1268
1269 if (EFI_ERROR (Status)) {
1270 return EFI_DEVICE_ERROR;
1271 }
1272 //
1273 // Fill Port Status bits
1274 //
1275
1276 //
1277 // Current Connect Status
1278 //
1279 if (RHPortStatus & USBPORTSC_CCS) {
1280 PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
1281 }
1282 //
1283 // Port Enabled/Disabled
1284 //
1285 if (RHPortStatus & USBPORTSC_PED) {
1286 PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
1287 }
1288
1289 //
1290 // Port Suspend
1291 //
1292 if (RHPortStatus & USBPORTSC_SUSP) {
1293 PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
1294 }
1295
1296 //
1297 // Port Reset
1298 //
1299 if (RHPortStatus & USBPORTSC_PR) {
1300 PortStatus->PortStatus |= USB_PORT_STAT_RESET;
1301 }
1302
1303 //
1304 // Low Speed Device Attached
1305 //
1306 if (RHPortStatus & USBPORTSC_LSDA) {
1307 PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
1308 }
1309 //
1310 // Fill Port Status Change bits
1311 //
1312
1313 //
1314 // Connect Status Change
1315 //
1316 if (RHPortStatus & USBPORTSC_CSC) {
1317 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
1318 }
1319
1320 //
1321 // Port Enabled/Disabled Change
1322 //
1323 if (RHPortStatus & USBPORTSC_PEDC) {
1324 PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
1325 }
1326
1327 return EFI_SUCCESS;
1328 }
1329
1330 EFI_STATUS
1331 EFIAPI
1332 UHCISetRootHubPortFeature (
1333 IN EFI_USB_HC_PROTOCOL *This,
1334 IN UINT8 PortNumber,
1335 IN EFI_USB_PORT_FEATURE PortFeature
1336 )
1337 /*++
1338
1339 Routine Description:
1340 Sets a feature for the specified root hub port.
1341
1342 Arguments:
1343
1344 This A pointer to the EFI_USB_HC_PROTOCOL.
1345
1346 PortNumber Specifies the root hub port whose feature
1347 is requested to be set.
1348
1349 PortFeature Indicates the feature selector associated
1350 with the feature set request.
1351
1352 Returns:
1353 EFI_SUCCESS
1354 The feature specified by PortFeature was set for the
1355 USB root hub port specified by PortNumber.
1356 EFI_INVALID_PARAMETER
1357 PortNumber is invalid or PortFeature is invalid.
1358 EFI_DEVICE_ERROR
1359 Can't read register
1360 --*/
1361 {
1362 USB_HC_DEV *HcDev;
1363 UINT32 PSAddr;
1364 UINT32 CommandRegAddr;
1365 //
1366 // root hub port status
1367 //
1368 UINT16 RHPortControl;
1369 UINT16 Command;
1370 UINT8 TotalPortNumber;
1371 EFI_STATUS Status;
1372
1373 UHCIGetRootHubPortNumber (This, &TotalPortNumber);
1374 if (PortNumber >= TotalPortNumber) {
1375 return EFI_INVALID_PARAMETER;
1376 }
1377
1378 HcDev = USB_HC_DEV_FROM_THIS (This);
1379
1380 PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2);
1381 CommandRegAddr = (UINT32) (USBCMD);
1382
1383 Status = ReadRootPortReg (
1384 HcDev->PciIo,
1385 PSAddr,
1386 &RHPortControl
1387 );
1388 if (EFI_ERROR (Status)) {
1389 return EFI_DEVICE_ERROR;
1390 }
1391
1392 switch (PortFeature) {
1393
1394 case EfiUsbPortSuspend:
1395 Status = ReadUHCCommandReg (
1396 HcDev->PciIo,
1397 CommandRegAddr,
1398 &Command
1399 );
1400 if (EFI_ERROR (Status)) {
1401 return EFI_DEVICE_ERROR;
1402 }
1403
1404 if (!(Command & USBCMD_EGSM)) {
1405 //
1406 // if global suspend is not active, can set port suspend
1407 //
1408 RHPortControl &= 0xfff5;
1409 RHPortControl |= USBPORTSC_SUSP;
1410 }
1411 break;
1412
1413 case EfiUsbPortReset:
1414 RHPortControl &= 0xfff5;
1415 //
1416 // Set the reset bit
1417 //
1418 RHPortControl |= USBPORTSC_PR;
1419 break;
1420
1421 case EfiUsbPortPower:
1422 break;
1423
1424 case EfiUsbPortEnable:
1425 RHPortControl &= 0xfff5;
1426 RHPortControl |= USBPORTSC_PED;
1427 break;
1428
1429 default:
1430 return EFI_INVALID_PARAMETER;
1431 }
1432
1433 WriteRootPortReg (
1434 HcDev->PciIo,
1435 PSAddr,
1436 RHPortControl
1437 );
1438
1439 return EFI_SUCCESS;
1440 }
1441
1442 EFI_STATUS
1443 EFIAPI
1444 UHCIClearRootHubPortFeature (
1445 IN EFI_USB_HC_PROTOCOL *This,
1446 IN UINT8 PortNumber,
1447 IN EFI_USB_PORT_FEATURE PortFeature
1448 )
1449 /*++
1450
1451 Routine Description:
1452 Clears a feature for the specified root hub port.
1453
1454 Arguments:
1455
1456 This A pointer to the EFI_USB_HC_PROTOCOL instance.
1457
1458 PortNumber Specifies the root hub port whose feature
1459 is requested to be cleared.
1460
1461 PortFeature Indicates the feature selector associated with the
1462 feature clear request.
1463
1464 Returns:
1465 EFI_SUCCESS
1466 The feature specified by PortFeature was cleared for the
1467 USB root hub port specified by PortNumber.
1468 EFI_INVALID_PARAMETER
1469 PortNumber is invalid or PortFeature is invalid.
1470 EFI_DEVICE_ERROR
1471 Can't read register
1472 --*/
1473 {
1474 USB_HC_DEV *HcDev;
1475 UINT32 PSAddr;
1476 UINT16 RHPortControl;
1477 UINT8 TotalPortNumber;
1478 EFI_STATUS Status;
1479
1480 UHCIGetRootHubPortNumber (This, &TotalPortNumber);
1481
1482 if (PortNumber >= TotalPortNumber) {
1483 return EFI_INVALID_PARAMETER;
1484 }
1485
1486 HcDev = USB_HC_DEV_FROM_THIS (This);
1487 PSAddr = (UINT32) (USBPORTSC1 + PortNumber * 2);
1488
1489 Status = ReadRootPortReg (
1490 HcDev->PciIo,
1491 PSAddr,
1492 &RHPortControl
1493 );
1494 if (EFI_ERROR (Status)) {
1495 return EFI_DEVICE_ERROR;
1496 }
1497
1498 switch (PortFeature) {
1499 //
1500 // clear PORT_ENABLE feature means disable port.
1501 //
1502 case EfiUsbPortEnable:
1503 RHPortControl &= 0xfff5;
1504 RHPortControl &= ~USBPORTSC_PED;
1505 break;
1506
1507 //
1508 // clear PORT_SUSPEND feature means resume the port.
1509 // (cause a resume on the specified port if in suspend mode)
1510 //
1511 case EfiUsbPortSuspend:
1512 RHPortControl &= 0xfff5;
1513 RHPortControl &= ~USBPORTSC_SUSP;
1514 break;
1515
1516 //
1517 // no operation
1518 //
1519 case EfiUsbPortPower:
1520 break;
1521
1522 //
1523 // clear PORT_RESET means clear the reset signal.
1524 //
1525 case EfiUsbPortReset:
1526 RHPortControl &= 0xfff5;
1527 RHPortControl &= ~USBPORTSC_PR;
1528 break;
1529
1530 //
1531 // clear connect status change
1532 //
1533 case EfiUsbPortConnectChange:
1534 RHPortControl &= 0xfff5;
1535 RHPortControl |= USBPORTSC_CSC;
1536 break;
1537
1538 //
1539 // clear enable/disable status change
1540 //
1541 case EfiUsbPortEnableChange:
1542 RHPortControl &= 0xfff5;
1543 RHPortControl |= USBPORTSC_PEDC;
1544 break;
1545
1546 //
1547 // root hub does not support this request
1548 //
1549 case EfiUsbPortSuspendChange:
1550 break;
1551
1552 //
1553 // root hub does not support this request
1554 //
1555 case EfiUsbPortOverCurrentChange:
1556 break;
1557
1558 //
1559 // root hub does not support this request
1560 //
1561 case EfiUsbPortResetChange:
1562 break;
1563
1564 default:
1565 return EFI_INVALID_PARAMETER;
1566 }
1567
1568 WriteRootPortReg (
1569 HcDev->PciIo,
1570 PSAddr,
1571 RHPortControl
1572 );
1573
1574 return EFI_SUCCESS;
1575 }
1576
1577 EFI_STATUS
1578 EFIAPI
1579 UHCIControlTransfer (
1580 IN EFI_USB_HC_PROTOCOL *This,
1581 IN UINT8 DeviceAddress,
1582 IN BOOLEAN IsSlowDevice,
1583 IN UINT8 MaximumPacketLength,
1584 IN EFI_USB_DEVICE_REQUEST *Request,
1585 IN EFI_USB_DATA_DIRECTION TransferDirection,
1586 IN OUT VOID *Data, OPTIONAL
1587 IN OUT UINTN *DataLength, OPTIONAL
1588 IN UINTN TimeOut,
1589 OUT UINT32 *TransferResult
1590 )
1591 /*++
1592
1593 Routine Description:
1594 Submits control transfer to a target USB device.
1595
1596 Arguments:
1597
1598 This A pointer to the EFI_USB_HC_PROTOCOL instance.
1599
1600 DeviceAddress Represents the address of the target device on the USB,
1601 which is assigned during USB enumeration.
1602
1603 IsSlowDevice Indicates whether the target device is slow device
1604 or full-speed device.
1605
1606 MaximumPacketLength Indicates the maximum packet size that the
1607 default control transfer endpoint is capable of
1608 sending or receiving.
1609
1610 Request A pointer to the USB device request that will be sent
1611 to the USB device.
1612
1613 TransferDirection Specifies the data direction for the transfer.
1614 There are three values available, DataIn, DataOut
1615 and NoData.
1616
1617 Data A pointer to the buffer of data that will be transmitted
1618 to USB device or received from USB device.
1619
1620 DataLength Indicates the size, in bytes, of the data buffer
1621 specified by Data.
1622
1623 TimeOut Indicates the maximum time, in microseconds,
1624 which the transfer is allowed to complete.
1625
1626 TransferResult A pointer to the detailed result information generated
1627 by this control transfer.
1628
1629 Returns:
1630 EFI_SUCCESS
1631 The control transfer was completed successfully.
1632 EFI_OUT_OF_RESOURCES
1633 The control transfer could not be completed due to a lack of resources.
1634 EFI_INVALID_PARAMETER
1635 Some parameters are invalid.
1636 EFI_TIMEOUT
1637 The control transfer failed due to timeout.
1638 EFI_DEVICE_ERROR
1639 The control transfer failed due to host controller or device error.
1640 Caller should check TranferResult for detailed error information.
1641
1642 --*/
1643 {
1644 USB_HC_DEV *HcDev;
1645 UINT32 StatusReg;
1646 UINT32 FrameNumReg;
1647 UINT8 PktID;
1648 QH_STRUCT *PtrQH;
1649 TD_STRUCT *PtrTD;
1650 TD_STRUCT *PtrPreTD;
1651 TD_STRUCT *PtrSetupTD;
1652 TD_STRUCT *PtrStatusTD;
1653 EFI_STATUS Status;
1654 UINTN Index;
1655 UINTN DataLen;
1656 UINT8 *PtrDataSource;
1657 UINT8 *Ptr;
1658 UINT8 DataToggle;
1659 UINT16 LoadFrameListIndex;
1660 UINT8 PktSize;
1661
1662 UINT8 *RequestMappedAddress;
1663 VOID *RequestMapping;
1664 UINTN RequestLen;
1665
1666 EFI_PHYSICAL_ADDRESS TempPtr;
1667 VOID *Mapping;
1668
1669 TD_STRUCT *PtrFirstDataTD;
1670 TD_STRUCT *ptrLastDataTD;
1671 BOOLEAN FirstTD;
1672
1673 FirstTD = FALSE;
1674 RequestMappedAddress = NULL;
1675 RequestMapping = NULL;
1676 Mapping = NULL;
1677 PtrFirstDataTD = NULL;
1678 ptrLastDataTD = NULL;
1679 PktID = INPUT_PACKET_ID;
1680 Mapping = NULL;
1681 HcDev = USB_HC_DEV_FROM_THIS (This);
1682 StatusReg = (UINT32) (USBSTS);
1683 FrameNumReg = (UINT32) (USBFRNUM);
1684 PtrPreTD = NULL;
1685 PtrTD = NULL;
1686
1687 //
1688 // Parameters Checking
1689 //
1690 if (Request == NULL || TransferResult == NULL) {
1691 return EFI_INVALID_PARAMETER;
1692 }
1693
1694 //
1695 // if errors exist that cause host controller halt,
1696 // then return EFI_DEVICE_ERROR.
1697 //
1698 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
1699
1700 ClearStatusReg (HcDev->PciIo, StatusReg);
1701 *TransferResult = EFI_USB_ERR_SYSTEM;
1702 return EFI_DEVICE_ERROR;
1703 }
1704
1705 //
1706 // low speed usb devices are limited to only an eight-byte
1707 // maximum data payload size
1708 //
1709 if (IsSlowDevice && (MaximumPacketLength != 8)) {
1710 return EFI_INVALID_PARAMETER;
1711 }
1712
1713 if (MaximumPacketLength != 8 &&
1714 MaximumPacketLength != 16 &&
1715 MaximumPacketLength != 32 &&
1716 MaximumPacketLength != 64) {
1717 return EFI_INVALID_PARAMETER;
1718 }
1719
1720 if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {
1721 return EFI_INVALID_PARAMETER;
1722 }
1723
1724 switch (TransferDirection) {
1725
1726 case EfiUsbDataIn:
1727 PktID = INPUT_PACKET_ID;
1728 PtrDataSource = Data;
1729 DataLen = *DataLength;
1730
1731 //
1732 // map the source data buffer for bus master access.
1733 // BusMasterWrite means cpu read
1734 //
1735 Status = HcDev->PciIo->Map (
1736 HcDev->PciIo,
1737 EfiPciIoOperationBusMasterWrite,
1738 PtrDataSource,
1739 &DataLen,
1740 &TempPtr,
1741 &Mapping
1742 );
1743 if (EFI_ERROR (Status)) {
1744 return Status;
1745 }
1746
1747 Ptr = (UINT8 *) ((UINTN) TempPtr);
1748 break;
1749
1750 case EfiUsbDataOut:
1751 PktID = OUTPUT_PACKET_ID;
1752 PtrDataSource = Data;
1753 DataLen = *DataLength;
1754
1755 //
1756 // map the source data buffer for bus master access.
1757 // BusMasterRead means cpu write
1758 //
1759 Status = HcDev->PciIo->Map (
1760 HcDev->PciIo,
1761 EfiPciIoOperationBusMasterRead,
1762 PtrDataSource,
1763 &DataLen,
1764 &TempPtr,
1765 &Mapping
1766 );
1767 if (EFI_ERROR (Status)) {
1768 return Status;
1769 }
1770
1771 Ptr = (UINT8 *) ((UINTN) TempPtr);
1772 break;
1773
1774 //
1775 // no data stage
1776 //
1777 case EfiUsbNoData:
1778 if ((DataLength != NULL) && (*DataLength != 0)) {
1779 return EFI_INVALID_PARAMETER;
1780 }
1781
1782 PktID = OUTPUT_PACKET_ID;
1783 PtrDataSource = NULL;
1784 DataLen = 0;
1785 Ptr = NULL;
1786 break;
1787
1788 default:
1789 return EFI_INVALID_PARAMETER;
1790 }
1791
1792 Status = ClearStatusReg (HcDev->PciIo, StatusReg);
1793 if (EFI_ERROR (Status)) {
1794 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
1795 return EFI_DEVICE_ERROR;
1796 }
1797 //
1798 // create QH structure and init
1799 //
1800 Status = CreateQH (HcDev, &PtrQH);
1801 if (EFI_ERROR (Status)) {
1802 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
1803 return Status;
1804 }
1805
1806 //
1807 // map the Request for bus master access.
1808 // BusMasterRead means cpu write
1809 //
1810 RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
1811 Status = HcDev->PciIo->Map (
1812 HcDev->PciIo,
1813 EfiPciIoOperationBusMasterRead,
1814 (UINT8 *) Request,
1815 &RequestLen,
1816 &TempPtr,
1817 &RequestMapping
1818 );
1819
1820 if (EFI_ERROR (Status)) {
1821 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
1822 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
1823 return Status;
1824 }
1825
1826 RequestMappedAddress = (UINT8 *) ((UINTN) TempPtr);
1827
1828 //
1829 // generate Setup Stage TD
1830 //
1831 Status = GenSetupStageTD (
1832 HcDev,
1833 DeviceAddress,
1834 0,
1835 IsSlowDevice,
1836 (UINT8 *) RequestMappedAddress,
1837 sizeof (EFI_USB_DEVICE_REQUEST),
1838 &PtrSetupTD
1839 );
1840
1841 if (EFI_ERROR (Status)) {
1842 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
1843 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
1844 HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
1845 return Status;
1846 }
1847
1848 //
1849 // Data Stage of Control Transfer
1850 //
1851 DataToggle = 1;
1852 FirstTD = TRUE;
1853 while (DataLen > 0) {
1854 //
1855 // create TD structures and link together
1856 //
1857
1858 //
1859 // PktSize is the data load size that each TD carries.
1860 //
1861 PktSize = (UINT8) DataLen;
1862 if (DataLen > MaximumPacketLength) {
1863 PktSize = MaximumPacketLength;
1864 }
1865
1866 Status = GenDataTD (
1867 HcDev,
1868 DeviceAddress,
1869 0,
1870 Ptr,
1871 PktSize,
1872 PktID,
1873 DataToggle,
1874 IsSlowDevice,
1875 &PtrTD
1876 );
1877
1878 if (EFI_ERROR (Status)) {
1879 //
1880 // free all resources occupied
1881 //
1882 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
1883 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
1884 HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
1885 DeleteQueuedTDs (HcDev, PtrSetupTD);
1886 DeleteQueuedTDs (HcDev, PtrFirstDataTD);
1887 return Status;
1888 }
1889
1890 //
1891 // Link two TDs in vertical depth
1892 //
1893 if (FirstTD) {
1894 PtrFirstDataTD = PtrTD;
1895 PtrFirstDataTD->ptrNextTD = NULL;
1896 FirstTD = FALSE;
1897 } else {
1898 LinkTDToTD (PtrPreTD, PtrTD);
1899 }
1900
1901 PtrPreTD = PtrTD;
1902
1903 DataToggle ^= 1;
1904 Ptr += PktSize;
1905 DataLen -= PktSize;
1906 }
1907
1908 ptrLastDataTD = PtrTD;
1909
1910 //
1911 // Status Stage of Control Transfer
1912 //
1913 if (PktID == OUTPUT_PACKET_ID) {
1914 PktID = INPUT_PACKET_ID;
1915 } else {
1916 PktID = OUTPUT_PACKET_ID;
1917 }
1918
1919 //
1920 // create Status Stage TD structure
1921 //
1922 Status = CreateStatusTD (
1923 HcDev,
1924 DeviceAddress,
1925 0,
1926 PktID,
1927 IsSlowDevice,
1928 &PtrStatusTD
1929 );
1930
1931 if (EFI_ERROR (Status)) {
1932 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
1933 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
1934 HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
1935 DeleteQueuedTDs (HcDev, PtrSetupTD);
1936 DeleteQueuedTDs (HcDev, PtrFirstDataTD);
1937 return Status;
1938 }
1939
1940 if (IsSlowDevice) {
1941 //
1942 // link setup TD structures to QH structure
1943 //
1944 LinkTDToQH (PtrQH, PtrSetupTD);
1945
1946 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
1947
1948 //
1949 // link QH-TDs to total 100 frame list entry to speed up the execution.
1950 //
1951 for (Index = 0; Index < 100; Index++) {
1952 LinkQHToFrameList (
1953 HcDev->FrameListEntry,
1954 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
1955 PtrQH
1956 );
1957 }
1958 //
1959 // Poll QH-TDs execution and get result.
1960 // detail status is returned
1961 //
1962 Status = ExecuteControlTransfer (
1963 HcDev,
1964 PtrSetupTD,
1965 LoadFrameListIndex,
1966 DataLength,
1967 TimeOut,
1968 TransferResult
1969 );
1970 //
1971 // Remove Control Transfer QH-TDs structure from the frame list
1972 // and update the pointers in the Frame List
1973 // and other pointers in other related QH structures.
1974 //
1975 for (Index = 0; Index < 100; Index++) {
1976 DelLinkSingleQH (
1977 HcDev,
1978 PtrQH,
1979 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
1980 FALSE,
1981 FALSE
1982 );
1983 }
1984 //
1985 // delete setup stage TD; the QH is reserved for the next stages.
1986 //
1987 DeleteQueuedTDs (HcDev, PtrSetupTD);
1988
1989 //
1990 // if setup stage error, return error
1991 //
1992 if (EFI_ERROR (Status)) {
1993 goto Done;
1994 }
1995 //
1996 // some control transfers do not have Data Stage
1997 //
1998 if (PtrFirstDataTD != NULL) {
1999
2000 LinkTDToQH (PtrQH, PtrFirstDataTD);
2001 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
2002
2003 for (Index = 0; Index < 500; Index++) {
2004 LinkQHToFrameList (
2005 HcDev->FrameListEntry,
2006 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
2007 PtrQH
2008 );
2009 }
2010
2011 Status = ExecuteControlTransfer (
2012 HcDev,
2013 PtrFirstDataTD,
2014 LoadFrameListIndex,
2015 DataLength,
2016 TimeOut,
2017 TransferResult
2018 );
2019
2020 for (Index = 0; Index < 500; Index++) {
2021 DelLinkSingleQH (
2022 HcDev,
2023 PtrQH,
2024 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
2025 FALSE,
2026 FALSE
2027 );
2028 }
2029 //
2030 // delete data stage TD; the QH is reserved for the next stage.
2031 //
2032 DeleteQueuedTDs (HcDev, PtrFirstDataTD);
2033 }
2034 //
2035 // if data stage error, goto done and return error
2036 //
2037 if (EFI_ERROR (Status)) {
2038 goto Done;
2039 }
2040
2041 LinkTDToQH (PtrQH, PtrStatusTD);
2042 //
2043 // get the frame list index that the QH-TDs will be linked to.
2044 //
2045 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
2046
2047 for (Index = 0; Index < 100; Index++) {
2048 //
2049 // put the QH-TDs directly or indirectly into the proper place
2050 // in the Frame List
2051 //
2052 LinkQHToFrameList (
2053 HcDev->FrameListEntry,
2054 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
2055 PtrQH
2056 );
2057 }
2058 //
2059 // Poll QH-TDs execution and get result.
2060 // detail status is returned
2061 //
2062 Status = ExecuteControlTransfer (
2063 HcDev,
2064 PtrStatusTD,
2065 LoadFrameListIndex,
2066 DataLength,
2067 TimeOut,
2068 TransferResult
2069 );
2070
2071 //
2072 // Delete Control Transfer QH-TDs structure
2073 // and update the pointers in the Frame List
2074 // and other pointers in other related QH structures.
2075 //
2076 // TRUE means must search other framelistindex
2077 //
2078 for (Index = 0; Index < 100; Index++) {
2079 DelLinkSingleQH (
2080 HcDev,
2081 PtrQH,
2082 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
2083 FALSE,
2084 FALSE
2085 );
2086 }
2087
2088 DeleteQueuedTDs (HcDev, PtrStatusTD);
2089
2090 } else {
2091 //
2092 // link setup stage TD with data stage TD
2093 //
2094 PtrPreTD = PtrSetupTD;
2095 if (PtrFirstDataTD != NULL) {
2096 LinkTDToTD (PtrSetupTD, PtrFirstDataTD);
2097 PtrPreTD = ptrLastDataTD;
2098 }
2099 //
2100 // link status TD with previous TD
2101 //
2102 LinkTDToTD (PtrPreTD, PtrStatusTD);
2103
2104 //
2105 // link QH with TD
2106 //
2107 LinkTDToQH (PtrQH, PtrSetupTD);
2108
2109 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
2110 for (Index = 0; Index < 500; Index++) {
2111 //
2112 // put the QH-TDs directly or indirectly into the proper place
2113 // in the Frame List
2114 //
2115 LinkQHToFrameList (
2116 HcDev->FrameListEntry,
2117 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
2118 PtrQH
2119 );
2120 }
2121 //
2122 // Poll QH-TDs execution and get result.
2123 // detail status is returned
2124 //
2125 Status = ExecuteControlTransfer (
2126 HcDev,
2127 PtrSetupTD,
2128 LoadFrameListIndex,
2129 DataLength,
2130 TimeOut,
2131 TransferResult
2132 );
2133 //
2134 // Remove Control Transfer QH-TDs structure from the frame list
2135 // and update the pointers in the Frame List
2136 // and other pointers in other related QH structures.
2137 //
2138 for (Index = 0; Index < 500; Index++) {
2139 DelLinkSingleQH (
2140 HcDev,
2141 PtrQH,
2142 (UINT16) ((LoadFrameListIndex + Index) & 0x3FF),
2143 FALSE,
2144 FALSE
2145 );
2146 }
2147
2148 DeleteQueuedTDs (HcDev, PtrSetupTD);
2149 }
2150
2151 Done:
2152
2153 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
2154
2155 if (Mapping != NULL) {
2156 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
2157 }
2158
2159 if (RequestMapping != NULL) {
2160 HcDev->PciIo->Unmap (HcDev->PciIo, RequestMapping);
2161 }
2162 //
2163 // if has errors that cause host controller halt,
2164 // then return EFI_DEVICE_ERROR directly.
2165 //
2166 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
2167
2168 ClearStatusReg (HcDev->PciIo, StatusReg);
2169 *TransferResult |= EFI_USB_ERR_SYSTEM;
2170 return EFI_DEVICE_ERROR;
2171 }
2172
2173 ClearStatusReg (HcDev->PciIo, StatusReg);
2174 HcDev->PciIo->Flush (HcDev->PciIo);
2175 return Status;
2176 }
2177
2178 EFI_STATUS
2179 EFIAPI
2180 UHCIBulkTransfer (
2181 IN EFI_USB_HC_PROTOCOL *This,
2182 IN UINT8 DeviceAddress,
2183 IN UINT8 EndPointAddress,
2184 IN UINT8 MaximumPacketLength,
2185 IN OUT VOID *Data,
2186 IN OUT UINTN *DataLength,
2187 IN OUT UINT8 *DataToggle,
2188 IN UINTN TimeOut,
2189 OUT UINT32 *TransferResult
2190 )
2191 /*++
2192
2193 Routine Description:
2194 Submits bulk transfer to a bulk endpoint of a USB device.
2195
2196 Arguments:
2197
2198 This A pointer to the EFI_USB_HC_PROTOCOL instance.
2199
2200 DeviceAddress Represents the address of the target device on the USB,
2201 which is assigned during USB enumeration.
2202 EndPointAddress The combination of an endpoint number and an
2203 endpoint direction of the target USB device.
2204 Each endpoint address supports data transfer in
2205 one direction except the control endpoint
2206 (whose default endpoint address is 0).
2207 It is the caller's responsibility to make sure that
2208 the EndPointAddress represents a bulk endpoint.
2209
2210 MaximumPacketLength Indicates the maximum packet size the target endpoint
2211 is capable of sending or receiving.
2212
2213 Data A pointer to the buffer of data that will be transmitted
2214 to USB device or received from USB device.
2215 DataLength When input, indicates the size, in bytes, of the data buffer
2216 specified by Data. When output, indicates the actually
2217 transferred data size.
2218
2219 DataToggle A pointer to the data toggle value. On input, it indicates
2220 the initial data toggle value the bulk transfer should adopt;
2221 on output, it is updated to indicate the data toggle value
2222 of the subsequent bulk transfer.
2223
2224 TimeOut Indicates the maximum time, in microseconds, which the
2225 transfer is allowed to complete.
2226
2227 TransferResult A pointer to the detailed result information of the
2228 bulk transfer.
2229
2230 Returns:
2231 EFI_SUCCESS
2232 The bulk transfer was completed successfully.
2233 EFI_OUT_OF_RESOURCES
2234 The bulk transfer could not be submitted due to lack of resource.
2235 EFI_INVALID_PARAMETER
2236 Some parameters are invalid.
2237 EFI_TIMEOUT
2238 The bulk transfer failed due to timeout.
2239 EFI_DEVICE_ERROR
2240 The bulk transfer failed due to host controller or device error.
2241 Caller should check TranferResult for detailed error information.
2242
2243 --*/
2244 {
2245 USB_HC_DEV *HcDev;
2246 UINT32 StatusReg;
2247 UINT32 FrameNumReg;
2248 UINTN DataLen;
2249 QH_STRUCT *PtrQH;
2250 TD_STRUCT *PtrFirstTD;
2251 TD_STRUCT *PtrTD;
2252 TD_STRUCT *PtrPreTD;
2253 UINT16 LoadFrameListIndex;
2254 UINT16 SavedFrameListIndex;
2255 UINT8 PktID;
2256 UINT8 *PtrDataSource;
2257 UINT8 *Ptr;
2258 BOOLEAN IsFirstTD;
2259 EFI_STATUS Status;
2260 UINT32 Index;
2261 UINT8 PktSize;
2262
2263 EFI_USB_DATA_DIRECTION TransferDirection;
2264 //
2265 // Used to calculate how many entries are linked to the
2266 // specified bulk transfer QH-TDs
2267 //
2268 UINT32 LinkTimes;
2269
2270 BOOLEAN ShortPacketEnable;
2271 EFI_PHYSICAL_ADDRESS TempPtr;
2272 VOID *Mapping;
2273
2274 HcDev = USB_HC_DEV_FROM_THIS (This);
2275 StatusReg = (UINT32) (USBSTS);
2276 FrameNumReg = (UINT32) (USBFRNUM);
2277 PktID = INPUT_PACKET_ID;
2278 PtrTD = NULL;
2279 PtrFirstTD = NULL;
2280 PtrPreTD = NULL;
2281 LinkTimes = 1;
2282 DataLen = 0;
2283 Ptr = NULL;
2284 ShortPacketEnable = FALSE;
2285 Mapping = NULL;
2286
2287 //
2288 // Parameters Checking
2289 //
2290
2291 if ((DataLength == NULL) ||
2292 (Data == NULL) ||
2293 (TransferResult == NULL)) {
2294 return EFI_INVALID_PARAMETER;
2295 }
2296
2297 //
2298 // if has errors that cause host controller halt,
2299 // then return EFI_DEVICE_ERROR directly.
2300 //
2301 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
2302
2303 ClearStatusReg (HcDev->PciIo, StatusReg);
2304 *TransferResult = EFI_USB_ERR_SYSTEM;
2305 return EFI_DEVICE_ERROR;
2306 }
2307
2308 if (*DataLength == 0) {
2309 return EFI_INVALID_PARAMETER;
2310 }
2311
2312 if ((*DataToggle != 1) && (*DataToggle != 0)) {
2313 return EFI_INVALID_PARAMETER;
2314 }
2315
2316 if (MaximumPacketLength != 8 &&
2317 MaximumPacketLength != 16 &&
2318 MaximumPacketLength != 32 &&
2319 MaximumPacketLength != 64) {
2320 return EFI_INVALID_PARAMETER;
2321 }
2322
2323 //
2324 // Enable the maximum packet size (64bytes)
2325 // that can be used for full speed bandwidth reclamation
2326 // at the end of a frame.
2327 //
2328 EnableMaxPacketSize (HcDev);
2329
2330 Status = ClearStatusReg (HcDev->PciIo, StatusReg);
2331 if (EFI_ERROR (Status)) {
2332 return EFI_DEVICE_ERROR;
2333 }
2334
2335 //
2336 // construct QH and TD data structures,
2337 // and link them together
2338 //
2339 if (EndPointAddress & 0x80) {
2340 TransferDirection = EfiUsbDataIn;
2341 } else {
2342 TransferDirection = EfiUsbDataOut;
2343 }
2344
2345 switch (TransferDirection) {
2346
2347 case EfiUsbDataIn:
2348 ShortPacketEnable = TRUE;
2349 PktID = INPUT_PACKET_ID;
2350 PtrDataSource = Data;
2351 DataLen = *DataLength;
2352
2353 //
2354 // BusMasterWrite means cpu read
2355 //
2356 Status = HcDev->PciIo->Map (
2357 HcDev->PciIo,
2358 EfiPciIoOperationBusMasterWrite,
2359 PtrDataSource,
2360 &DataLen,
2361 &TempPtr,
2362 &Mapping
2363 );
2364 if (EFI_ERROR (Status)) {
2365 return Status;
2366 }
2367
2368 Ptr = (UINT8 *) ((UINTN) TempPtr);
2369 break;
2370
2371 case EfiUsbDataOut:
2372 PktID = OUTPUT_PACKET_ID;
2373 PtrDataSource = Data;
2374 DataLen = *DataLength;
2375
2376 //
2377 // BusMasterRead means cpu write
2378 //
2379 Status = HcDev->PciIo->Map (
2380 HcDev->PciIo,
2381 EfiPciIoOperationBusMasterRead,
2382 PtrDataSource,
2383 &DataLen,
2384 &TempPtr,
2385 &Mapping
2386 );
2387 if (EFI_ERROR (Status)) {
2388 return Status;
2389 }
2390
2391 Ptr = (UINT8 *) ((UINTN) TempPtr);
2392 break;
2393
2394 default:
2395 return EFI_INVALID_PARAMETER;
2396 }
2397
2398 //
2399 // create QH structure and init
2400 //
2401 Status = CreateQH (HcDev, &PtrQH);
2402 if (EFI_ERROR (Status)) {
2403 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
2404 return Status;
2405 }
2406
2407 //
2408 // i is used to calculate the total number of TDs.
2409 //
2410 Index = 0;
2411
2412 IsFirstTD = TRUE;
2413 while (DataLen > 0) {
2414
2415 //
2416 // create TD structures and link together
2417 //
2418
2419 PktSize = (UINT8) DataLen;
2420 if (DataLen > MaximumPacketLength) {
2421 PktSize = MaximumPacketLength;
2422 }
2423
2424 Status = GenDataTD (
2425 HcDev,
2426 DeviceAddress,
2427 EndPointAddress,
2428 Ptr,
2429 PktSize,
2430 PktID,
2431 *DataToggle,
2432 FALSE,
2433 &PtrTD
2434 );
2435
2436 if (EFI_ERROR (Status)) {
2437 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
2438 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
2439 DeleteQueuedTDs (HcDev, PtrFirstTD);
2440 return Status;
2441 }
2442
2443 //
2444 // Enable short packet detection.
2445 // (default action is disabling short packet detection)
2446 //
2447 if (ShortPacketEnable) {
2448 EnableorDisableTDShortPacket (PtrTD, TRUE);
2449 }
2450
2451 if (IsFirstTD) {
2452 PtrFirstTD = PtrTD;
2453 PtrFirstTD->ptrNextTD = NULL;
2454 IsFirstTD = FALSE;
2455 } else {
2456 //
2457 // Link two TDs in vertical depth
2458 //
2459 LinkTDToTD (PtrPreTD, PtrTD);
2460 }
2461
2462 Index++;
2463
2464 PtrPreTD = PtrTD;
2465
2466 *DataToggle ^= 1;
2467 Ptr += PktSize;
2468 DataLen -= PktSize;
2469 }
2470
2471 //
2472 // link TD structures to QH structure
2473 //
2474 LinkTDToQH (PtrQH, PtrFirstTD);
2475
2476 //
2477 // calculate how many entries are linked to the specified bulk transfer QH-TDs
2478 // the below values are referred to the USB spec revision1.1.
2479 //
2480 switch (MaximumPacketLength) {
2481 case 8:
2482 LinkTimes = Index / 71 + 1;
2483 break;
2484
2485 case 16:
2486 LinkTimes = Index / 51 + 1;
2487 break;
2488
2489 case 32:
2490 LinkTimes = Index / 33 + 1;
2491 break;
2492
2493 case 64:
2494 LinkTimes = Index / 19 + 1;
2495 break;
2496 }
2497
2498 LinkTimes += 500;
2499
2500 //
2501 // put QH-TDs into Frame list
2502 //
2503 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
2504 SavedFrameListIndex = LoadFrameListIndex;
2505
2506 for (Index = 0; Index <= LinkTimes; Index++) {
2507
2508 //
2509 // put the QH-TD directly or indirectly into the proper place
2510 // in the Frame List
2511 //
2512 LinkQHToFrameList (HcDev->FrameListEntry, LoadFrameListIndex, PtrQH);
2513
2514 LoadFrameListIndex += 1;
2515 LoadFrameListIndex &= 0x3FF;
2516 }
2517
2518 LoadFrameListIndex = SavedFrameListIndex;
2519
2520 //
2521 // Execute QH-TD and get result
2522 //
2523 //
2524 // detail status is put into the Result field in the pIRP
2525 // the Data Toggle value is also re-updated to the value
2526 // of the last successful TD
2527 //
2528 Status = ExecBulkorSyncInterruptTransfer (
2529 HcDev,
2530 PtrFirstTD,
2531 LoadFrameListIndex,
2532 DataLength,
2533 DataToggle,
2534 TimeOut,
2535 TransferResult
2536 );
2537
2538 //
2539 // Delete Bulk transfer QH-TD structure
2540 // and maitain the pointers in the Frame List
2541 // and other pointers in related QH structure
2542 //
2543 // TRUE means must search other framelistindex
2544 //
2545 for (Index = 0; Index <= LinkTimes; Index++) {
2546 DelLinkSingleQH (
2547 HcDev,
2548 PtrQH,
2549 LoadFrameListIndex,
2550 FALSE,
2551 FALSE
2552 );
2553 LoadFrameListIndex += 1;
2554 LoadFrameListIndex &= 0x3FF;
2555 }
2556
2557 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
2558
2559 DeleteQueuedTDs (HcDev, PtrFirstTD);
2560
2561 if (Mapping != NULL) {
2562 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
2563 }
2564
2565 //
2566 // if has errors that cause host controller halt,
2567 // then return EFI_DEVICE_ERROR directly.
2568 //
2569 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
2570
2571 ClearStatusReg (HcDev->PciIo, StatusReg);
2572 *TransferResult |= EFI_USB_ERR_SYSTEM;
2573 return EFI_DEVICE_ERROR;
2574 }
2575
2576 ClearStatusReg (HcDev->PciIo, StatusReg);
2577
2578 HcDev->PciIo->Flush (HcDev->PciIo);
2579
2580 return Status;
2581 }
2582
2583 EFI_STATUS
2584 EFIAPI
2585 UHCIAsyncInterruptTransfer (
2586 IN EFI_USB_HC_PROTOCOL * This,
2587 IN UINT8 DeviceAddress,
2588 IN UINT8 EndPointAddress,
2589 IN BOOLEAN IsSlowDevice,
2590 IN UINT8 MaxiumPacketLength,
2591 IN BOOLEAN IsNewTransfer,
2592 IN OUT UINT8 *DataToggle,
2593 IN UINTN PollingInterval, OPTIONAL
2594 IN UINTN DataLength, OPTIONAL
2595 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction, OPTIONAL
2596 IN VOID *Context OPTIONAL
2597 )
2598 /*++
2599
2600 Routine Description:
2601 Submits an asynchronous interrupt transfer to an
2602 interrupt endpoint of a USB device.
2603
2604 Arguments:
2605
2606 This A pointer to the EFI_USB_HC_PROTOCOL instance.
2607
2608 DeviceAddress Represents the address of the target device on the USB,
2609 which is assigned during USB enumeration.
2610
2611 EndPointAddress The combination of an endpoint number and an endpoint
2612 direction of the target USB device. Each endpoint address
2613 supports data transfer in one direction except the
2614 control endpoint (whose default endpoint address is 0).
2615 It is the caller's responsibility to make sure that
2616 the EndPointAddress represents an interrupt endpoint.
2617
2618 IsSlowDevice Indicates whether the target device is slow device
2619 or full-speed device.
2620
2621 MaxiumPacketLength Indicates the maximum packet size the target endpoint
2622 is capable of sending or receiving.
2623
2624 IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
2625 the host and the target interrupt endpoint.
2626 If FALSE, the specified asynchronous interrupt pipe
2627 is canceled.
2628
2629 DataToggle A pointer to the data toggle value. On input, it is valid
2630 when IsNewTransfer is TRUE, and it indicates the initial
2631 data toggle value the asynchronous interrupt transfer
2632 should adopt.
2633 On output, it is valid when IsNewTransfer is FALSE,
2634 and it is updated to indicate the data toggle value of
2635 the subsequent asynchronous interrupt transfer.
2636
2637 PollingInterval Indicates the interval, in milliseconds, that the
2638 asynchronous interrupt transfer is polled.
2639 This parameter is required when IsNewTransfer is TRUE.
2640
2641 DataLength Indicates the length of data to be received at the
2642 rate specified by PollingInterval from the target
2643 asynchronous interrupt endpoint. This parameter
2644 is only required when IsNewTransfer is TRUE.
2645
2646 CallBackFunction The Callback function.This function is called at the
2647 rate specified by PollingInterval.This parameter is
2648 only required when IsNewTransfer is TRUE.
2649
2650 Context The context that is passed to the CallBackFunction.
2651 This is an optional parameter and may be NULL.
2652
2653 Returns:
2654 EFI_SUCCESS
2655 The asynchronous interrupt transfer request has been successfully
2656 submitted or canceled.
2657 EFI_INVALID_PARAMETER
2658 Some parameters are invalid.
2659 EFI_OUT_OF_RESOURCES
2660 The request could not be completed due to a lack of resources.
2661 EFI_DEVICE_ERROR
2662 Can't read register
2663 --*/
2664 {
2665 USB_HC_DEV *HcDev;
2666 UINT32 StatusReg;
2667 UINT32 FrameNumReg;
2668 UINTN DataLen;
2669 QH_STRUCT *ptrFirstQH;
2670 QH_STRUCT *PtrQH;
2671 QH_STRUCT *ptrPreQH;
2672 TD_STRUCT *PtrFirstTD;
2673 TD_STRUCT *PtrTD;
2674 TD_STRUCT *PtrPreTD;
2675 UINT16 LoadFrameListIndex;
2676 UINT16 Index;
2677 UINT8 PktID;
2678 UINT8 *Ptr;
2679 UINT8 *MappedPtr;
2680 BOOLEAN IsFirstTD;
2681 BOOLEAN IsFirstQH;
2682 EFI_STATUS Status;
2683 BOOLEAN ShortPacketEnable;
2684 UINT8 CurrentDataToggle;
2685 EFI_PHYSICAL_ADDRESS TempPtr;
2686 VOID *Mapping;
2687 UINT8 PktSize;
2688 QH_STRUCT *TempQH;
2689 EFI_TPL OldTpl;
2690
2691 HcDev = USB_HC_DEV_FROM_THIS (This);
2692 StatusReg = (UINT32) (USBSTS);
2693 FrameNumReg = (UINT32) (USBFRNUM);
2694 Mapping = NULL;
2695 ShortPacketEnable = FALSE;
2696
2697 PktID = INPUT_PACKET_ID;
2698 PtrTD = NULL;
2699 PtrFirstTD = NULL;
2700 PtrPreTD = NULL;
2701 Ptr = NULL;
2702 PtrQH = NULL;
2703 ptrPreQH = NULL;
2704 ptrFirstQH = NULL;
2705
2706 if ((EndPointAddress & 0x80) == 0) {
2707 return EFI_INVALID_PARAMETER;
2708 }
2709
2710 //
2711 // delete Async interrupt transfer request
2712 //
2713 if (!IsNewTransfer) {
2714
2715 OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
2716
2717 Status = DeleteAsyncINTQHTDs (
2718 HcDev,
2719 DeviceAddress,
2720 EndPointAddress,
2721 DataToggle
2722 );
2723
2724 gBS->RestoreTPL (OldTpl);
2725
2726 return Status;
2727 }
2728 //
2729 // if has errors that cause host controller halt,
2730 // then return EFI_DEVICE_ERROR directly.
2731 //
2732 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
2733
2734 ClearStatusReg (HcDev->PciIo, StatusReg);
2735 return EFI_DEVICE_ERROR;
2736 }
2737
2738 ClearStatusReg (HcDev->PciIo, StatusReg);
2739
2740 //
2741 // submit Async interrupt transfer request
2742 //
2743 if (PollingInterval < 1 || PollingInterval > 255) {
2744 return EFI_INVALID_PARAMETER;
2745 }
2746
2747 if (DataLength == 0) {
2748 return EFI_INVALID_PARAMETER;
2749 }
2750
2751 if ((*DataToggle != 1) && (*DataToggle != 0)) {
2752 return EFI_INVALID_PARAMETER;
2753 }
2754
2755 ShortPacketEnable = TRUE;
2756 PktID = INPUT_PACKET_ID;
2757 DataLen = DataLength;
2758 Ptr = AllocatePool (DataLen);
2759 if (Ptr == NULL) {
2760 return EFI_OUT_OF_RESOURCES;
2761 }
2762
2763 //
2764 // BusMasterWrite means cpu read
2765 //
2766 Status = HcDev->PciIo->Map (
2767 HcDev->PciIo,
2768 EfiPciIoOperationBusMasterWrite,
2769 Ptr,
2770 &DataLen,
2771 &TempPtr,
2772 &Mapping
2773 );
2774 if (EFI_ERROR (Status)) {
2775 gBS->FreePool (Ptr);
2776 return Status;
2777 }
2778
2779 MappedPtr = (UINT8 *) ((UINTN) TempPtr);
2780
2781 CurrentDataToggle = *DataToggle;
2782
2783 IsFirstTD = TRUE;
2784
2785 while (DataLen > 0) {
2786 //
2787 // create TD structures and link together
2788 //
2789
2790 PktSize = (UINT8) DataLen;
2791 if (DataLen > MaxiumPacketLength) {
2792 PktSize = MaxiumPacketLength;
2793 }
2794
2795 Status = GenDataTD (
2796 HcDev,
2797 DeviceAddress,
2798 EndPointAddress,
2799 MappedPtr,
2800 PktSize,
2801 PktID,
2802 CurrentDataToggle,
2803 IsSlowDevice,
2804 &PtrTD
2805 );
2806 if (EFI_ERROR (Status)) {
2807 gBS->FreePool (Ptr);
2808 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
2809 DeleteQueuedTDs (HcDev, PtrFirstTD);
2810 return Status;
2811 }
2812 //
2813 // Enable short packet detection.
2814 //
2815 if (ShortPacketEnable) {
2816 EnableorDisableTDShortPacket (PtrTD, TRUE);
2817 }
2818
2819 if (IsFirstTD) {
2820 PtrFirstTD = PtrTD;
2821 PtrFirstTD->ptrNextTD = NULL;
2822 IsFirstTD = FALSE;
2823 } else {
2824 //
2825 // Link two TDs in vertical depth
2826 //
2827 LinkTDToTD (PtrPreTD, PtrTD);
2828 }
2829
2830 PtrPreTD = PtrTD;
2831
2832 CurrentDataToggle ^= 1;
2833 MappedPtr += PktSize;
2834 DataLen -= PktSize;
2835 }
2836
2837 //
2838 // roll one value back
2839 //
2840 CurrentDataToggle ^= 1;
2841
2842 //
2843 // create a list of QH structures and init,
2844 // link TDs to all the QHs, and link all the QHs together using internal
2845 // defined pointer of the QH_STRUCT.
2846 //
2847 IsFirstQH = TRUE;
2848 ptrPreQH = NULL;
2849 for (Index = 0; Index < 1024;) {
2850
2851 Status = CreateQH (HcDev, &PtrQH);
2852 if (EFI_ERROR (Status)) {
2853 gBS->FreePool (Ptr);
2854 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
2855 DeleteQueuedTDs (HcDev, PtrFirstTD);
2856 PtrQH = ptrFirstQH;
2857 while (PtrQH) {
2858 TempQH = PtrQH;
2859 PtrQH = TempQH->ptrNextIntQH;
2860 UhciFreePool (HcDev, (UINT8 *) TempQH, sizeof (QH_STRUCT));
2861 }
2862
2863 return Status;
2864 }
2865
2866 //
2867 // link TD structures to QH structure
2868 //
2869 LinkTDToQH (PtrQH, PtrFirstTD);
2870
2871 if (IsFirstQH) {
2872 ptrFirstQH = PtrQH;
2873 ptrFirstQH->ptrNextIntQH = NULL;
2874 IsFirstQH = FALSE;
2875 } else {
2876 //
2877 // link neighbor QH structures together
2878 //
2879 ptrPreQH->ptrNextIntQH = PtrQH;
2880 }
2881
2882 ptrPreQH = PtrQH;
2883
2884 Index = (UINT16) (PollingInterval + Index);
2885 }
2886 //
2887 // last QH in QH list should set its next QH pointer to NULL.
2888 //
2889 PtrQH->ptrNextIntQH = NULL;
2890
2891 //
2892 // Save QH-TD structures in Interrupt transfer list,
2893 // for monitor interrupt transfer execution routine use.
2894 //
2895 InsertQHTDToINTList (
2896 HcDev,
2897 ptrFirstQH,
2898 PtrFirstTD,
2899 DeviceAddress,
2900 EndPointAddress,
2901 CurrentDataToggle,
2902 DataLength,
2903 PollingInterval,
2904 Mapping,
2905 Ptr,
2906 CallBackFunction,
2907 Context
2908 );
2909
2910 //
2911 // put QHs-TDs into Frame list
2912 //
2913 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
2914
2915 PtrQH = ptrFirstQH;
2916
2917 for (Index = LoadFrameListIndex; Index < (1024 + LoadFrameListIndex);) {
2918
2919 //
2920 // put the QH-TD directly or indirectly into the proper place
2921 // in the Frame List
2922 //
2923 LinkQHToFrameList (HcDev->FrameListEntry, (UINT16) (Index & 0x3FF), PtrQH);
2924
2925 Index = (UINT16) (PollingInterval + Index);
2926
2927 PtrQH = PtrQH->ptrNextIntQH;
2928 }
2929
2930 HcDev->PciIo->Flush (HcDev->PciIo);
2931
2932 return EFI_SUCCESS;
2933 }
2934
2935 EFI_STATUS
2936 EFIAPI
2937 UHCISyncInterruptTransfer (
2938 IN EFI_USB_HC_PROTOCOL *This,
2939 IN UINT8 DeviceAddress,
2940 IN UINT8 EndPointAddress,
2941 IN BOOLEAN IsSlowDevice,
2942 IN UINT8 MaximumPacketLength,
2943 IN OUT VOID *Data,
2944 IN OUT UINTN *DataLength,
2945 IN OUT UINT8 *DataToggle,
2946 IN UINTN TimeOut,
2947 OUT UINT32 *TransferResult
2948 )
2949 /*++
2950
2951 Routine Description:
2952 Submits synchronous interrupt transfer to an interrupt endpoint
2953 of a USB device.
2954
2955 Arguments:
2956
2957 This A pointer to the EFI_USB_HC_PROTOCOL instance.
2958
2959 DeviceAddress Represents the address of the target device on the USB,
2960 which is assigned during USB enumeration.
2961
2962 EndPointAddress The combination of an endpoint number and an endpoint
2963 direction of the target USB device. Each endpoint
2964 address supports data transfer in one direction
2965 except the control endpoint (whose default
2966 endpoint address is 0). It is the caller's responsibility
2967 to make sure that the EndPointAddress represents
2968 an interrupt endpoint.
2969
2970 IsSlowDevice Indicates whether the target device is slow device
2971 or full-speed device.
2972
2973 MaximumPacketLength Indicates the maximum packet size the target endpoint
2974 is capable of sending or receiving.
2975
2976 Data A pointer to the buffer of data that will be transmitted
2977 to USB device or received from USB device.
2978
2979 DataLength On input, the size, in bytes, of the data buffer specified
2980 by Data. On output, the number of bytes transferred.
2981
2982 DataToggle A pointer to the data toggle value. On input, it indicates
2983 the initial data toggle value the synchronous interrupt
2984 transfer should adopt;
2985 on output, it is updated to indicate the data toggle value
2986 of the subsequent synchronous interrupt transfer.
2987
2988 TimeOut Indicates the maximum time, in microseconds, which the
2989 transfer is allowed to complete.
2990
2991 TransferResult A pointer to the detailed result information from
2992 the synchronous interrupt transfer.
2993
2994 Returns:
2995 EFI_SUCCESS
2996 The synchronous interrupt transfer was completed successfully.
2997 EFI_OUT_OF_RESOURCES
2998 The synchronous interrupt transfer could not be submitted due
2999 to lack of resource.
3000 EFI_INVALID_PARAMETER
3001 Some parameters are invalid.
3002 EFI_TIMEOUT
3003 The synchronous interrupt transfer failed due to timeout.
3004 EFI_DEVICE_ERROR
3005 The synchronous interrupt transfer failed due to host controller
3006 or device error. Caller should check TranferResult for detailed
3007 error information.
3008 --*/
3009 {
3010 USB_HC_DEV *HcDev;
3011 UINT32 StatusReg;
3012 UINT32 FrameNumReg;
3013 UINTN DataLen;
3014 QH_STRUCT *PtrQH;
3015 TD_STRUCT *PtrFirstTD;
3016 TD_STRUCT *PtrTD;
3017 TD_STRUCT *PtrPreTD;
3018 UINT16 LoadFrameListIndex;
3019 UINT16 SavedFrameListIndex;
3020 UINT32 Index;
3021 UINT32 LinkTimes;
3022 UINT8 PktID;
3023 UINT8 *PtrDataSource;
3024 UINT8 *Ptr;
3025 BOOLEAN IsFirstTD;
3026 EFI_STATUS Status;
3027 BOOLEAN ShortPacketEnable;
3028 EFI_PHYSICAL_ADDRESS TempPtr;
3029 VOID *Mapping;
3030 UINT8 PktSize;
3031
3032 HcDev = USB_HC_DEV_FROM_THIS (This);
3033 StatusReg = (UINT32) (USBSTS);
3034 FrameNumReg = (UINT32) (USBFRNUM);
3035 ShortPacketEnable = FALSE;
3036 Mapping = NULL;
3037 PktID = INPUT_PACKET_ID;
3038 PtrTD = NULL;
3039 PtrFirstTD = NULL;
3040 PtrPreTD = NULL;
3041 DataLen = 0;
3042 Ptr = NULL;
3043 Index = 0;
3044 LinkTimes = 0;
3045
3046 //
3047 // Parameters Checking
3048 //
3049
3050 if ((DataLength == NULL) ||
3051 (Data == NULL) ||
3052 (TransferResult == NULL)) {
3053 return EFI_INVALID_PARAMETER;
3054 }
3055
3056 //
3057 // if has errors that cause host controller halt,
3058 // then return EFI_DEVICE_ERROR directly.
3059 //
3060 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
3061
3062 ClearStatusReg (HcDev->PciIo, StatusReg);
3063 *TransferResult = EFI_USB_ERR_SYSTEM;
3064 return EFI_DEVICE_ERROR;
3065 }
3066
3067 if ((EndPointAddress & 0x80) == 0) {
3068 return EFI_INVALID_PARAMETER;
3069 }
3070
3071 if (*DataLength == 0) {
3072 return EFI_INVALID_PARAMETER;
3073 }
3074
3075 if ((*DataToggle != 1) && (*DataToggle != 0)) {
3076 return EFI_INVALID_PARAMETER;
3077 }
3078
3079 if (MaximumPacketLength > 64) {
3080 return EFI_INVALID_PARAMETER;
3081 }
3082
3083 if (IsSlowDevice && (MaximumPacketLength > 8)) {
3084 return EFI_INVALID_PARAMETER;
3085 }
3086
3087 ClearStatusReg (HcDev->PciIo, StatusReg);
3088
3089 //
3090 // submit Sync interrupt transfer request
3091 //
3092 ShortPacketEnable = TRUE;
3093 PktID = INPUT_PACKET_ID;
3094 DataLen = *DataLength;
3095 PtrDataSource = Data;
3096
3097 //
3098 // create QH structure and init
3099 //
3100 Status = CreateQH (HcDev, &PtrQH);
3101 if (EFI_ERROR (Status)) {
3102 return Status;
3103 }
3104
3105 //
3106 // BusMasterWrite means cpu read
3107 //
3108 Status = HcDev->PciIo->Map (
3109 HcDev->PciIo,
3110 EfiPciIoOperationBusMasterWrite,
3111 PtrDataSource,
3112 &DataLen,
3113 &TempPtr,
3114 &Mapping
3115 );
3116 if (EFI_ERROR (Status)) {
3117 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
3118 return Status;
3119 }
3120
3121 Ptr = (UINT8 *) ((UINTN) TempPtr);
3122
3123 IsFirstTD = TRUE;
3124 while (DataLen > 0) {
3125 //
3126 // create TD structures and link together
3127 //
3128 PktSize = (UINT8) DataLen;
3129 if (DataLen > MaximumPacketLength) {
3130 PktSize = MaximumPacketLength;
3131 }
3132
3133 Status = GenDataTD (
3134 HcDev,
3135 DeviceAddress,
3136 EndPointAddress,
3137 Ptr,
3138 PktSize,
3139 PktID,
3140 *DataToggle,
3141 IsSlowDevice,
3142 &PtrTD
3143 );
3144 if (EFI_ERROR (Status)) {
3145 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
3146 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
3147 DeleteQueuedTDs (HcDev, PtrFirstTD);
3148 return Status;
3149 }
3150 //
3151 // Enable short packet detection.
3152 //
3153 if (ShortPacketEnable) {
3154 EnableorDisableTDShortPacket (PtrTD, TRUE);
3155 }
3156
3157 if (IsFirstTD) {
3158 PtrFirstTD = PtrTD;
3159 PtrFirstTD->ptrNextTD = NULL;
3160 IsFirstTD = FALSE;
3161 } else {
3162 //
3163 // Link two TDs in vertical depth
3164 //
3165 LinkTDToTD (PtrPreTD, PtrTD);
3166 }
3167
3168 Index++;
3169
3170 PtrPreTD = PtrTD;
3171
3172 *DataToggle ^= 1;
3173 Ptr += PktSize;
3174 DataLen -= PktSize;
3175 }
3176
3177 //
3178 // link TD structures to QH structure
3179 //
3180 LinkTDToQH (PtrQH, PtrFirstTD);
3181
3182 switch (MaximumPacketLength) {
3183 case 8:
3184 LinkTimes = Index / 71 + 1;
3185 break;
3186
3187 case 16:
3188 LinkTimes = Index / 51 + 1;
3189 break;
3190
3191 case 32:
3192 LinkTimes = Index / 33 + 1;
3193 break;
3194
3195 case 64:
3196 LinkTimes = Index / 19 + 1;
3197 break;
3198 }
3199
3200 LinkTimes += 100;
3201
3202 LoadFrameListIndex = (UINT16) ((GetCurrentFrameNumber (HcDev->PciIo, FrameNumReg)) & 0x3FF);
3203 SavedFrameListIndex = LoadFrameListIndex;
3204
3205 for (Index = 0; Index < LinkTimes; Index++) {
3206
3207 //
3208 // put the QH-TD directly or indirectly into the proper place
3209 // in the Frame List
3210 //
3211 LinkQHToFrameList (HcDev->FrameListEntry, LoadFrameListIndex, PtrQH);
3212
3213 LoadFrameListIndex += 1;
3214 LoadFrameListIndex &= 0x3FF;
3215 }
3216
3217 LoadFrameListIndex = SavedFrameListIndex;
3218 //
3219 // detail status is put into the Result field in the pIRP
3220 // the Data Toggle value is also re-updated to the value
3221 // of the last successful TD
3222 //
3223 Status = ExecBulkorSyncInterruptTransfer (
3224 HcDev,
3225 PtrFirstTD,
3226 LoadFrameListIndex,
3227 DataLength,
3228 DataToggle,
3229 TimeOut,
3230 TransferResult
3231 );
3232 //
3233 // Delete Sync Interrupt transfer QH-TD structure
3234 // and maintain the pointers in the Frame List
3235 // and other pointers in related QH structure
3236 //
3237 // TRUE means must search other framelistindex
3238 //
3239 for (Index = 0; Index <= LinkTimes; Index++) {
3240 DelLinkSingleQH (
3241 HcDev,
3242 PtrQH,
3243 LoadFrameListIndex,
3244 FALSE,
3245 FALSE
3246 );
3247 LoadFrameListIndex += 1;
3248 LoadFrameListIndex &= 0x3FF;
3249 }
3250
3251 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
3252
3253 DeleteQueuedTDs (HcDev, PtrFirstTD);
3254
3255 HcDev->PciIo->Unmap (HcDev->PciIo, Mapping);
3256
3257 //
3258 // if has errors that cause host controller halt,
3259 // then return EFI_DEVICE_ERROR directly.
3260 //
3261 if (!IsStatusOK (HcDev->PciIo, StatusReg)) {
3262
3263 ClearStatusReg (HcDev->PciIo, StatusReg);
3264 *TransferResult |= EFI_USB_ERR_SYSTEM;
3265 return EFI_DEVICE_ERROR;
3266 }
3267
3268 ClearStatusReg (HcDev->PciIo, StatusReg);
3269
3270 HcDev->PciIo->Flush (HcDev->PciIo);
3271
3272 return Status;
3273 }
3274
3275 EFI_STATUS
3276 EFIAPI
3277 UHCIIsochronousTransfer (
3278 IN EFI_USB_HC_PROTOCOL *This,
3279 IN UINT8 DeviceAddress,
3280 IN UINT8 EndPointAddress,
3281 IN UINT8 MaximumPacketLength,
3282 IN OUT VOID *Data,
3283 IN UINTN DataLength,
3284 OUT UINT32 *TransferResult
3285 )
3286 /*++
3287
3288 Routine Description:
3289 Submits isochronous transfer to a target USB device.
3290
3291 Arguments:
3292
3293 This - A pointer to the EFI_USB_HC_PROTOCOL instance.
3294 DeviceAddress - Represents the address of the target device on the USB,
3295 which is assigned during USB enumeration.
3296 EndPointAddress - End point address
3297 MaximumPacketLength - Indicates the maximum packet size that the
3298 default control transfer endpoint is capable of
3299 sending or receiving.
3300 Data - A pointer to the buffer of data that will be transmitted
3301 to USB device or received from USB device.
3302 DataLength - Indicates the size, in bytes, of the data buffer
3303 specified by Data.
3304 TransferResult - A pointer to the detailed result information generated
3305 by this control transfer.
3306 Returns:
3307 EFI_UNSUPPORTED
3308
3309 --*/
3310 {
3311 return EFI_UNSUPPORTED;
3312 }
3313
3314
3315 EFI_STATUS
3316 EFIAPI
3317 UHCIAsyncIsochronousTransfer (
3318 IN EFI_USB_HC_PROTOCOL * This,
3319 IN UINT8 DeviceAddress,
3320 IN UINT8 EndPointAddress,
3321 IN UINT8 MaximumPacketLength,
3322 IN OUT VOID *Data,
3323 IN UINTN DataLength,
3324 IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack,
3325 IN VOID *Context OPTIONAL
3326 )
3327 /*++
3328
3329 Routine Description:
3330 Submits Async isochronous transfer to a target USB device.
3331
3332 Arguments:
3333
3334 This - A pointer to the EFI_USB_HC_PROTOCOL instance.
3335
3336 DeviceAddress - Represents the address of the target device on the USB,
3337 which is assigned during USB enumeration.
3338
3339 EndPointAddress - End point address
3340
3341 MaximumPacketLength - Indicates the maximum packet size that the
3342 default control transfer endpoint is capable of
3343 sending or receiving.
3344
3345 Data - A pointer to the buffer of data that will be transmitted
3346 to USB device or received from USB device.
3347
3348 IsochronousCallBack - When the transfer complete, the call back function will be called
3349
3350 Context - Pass to the call back function as parameter
3351
3352 Returns:
3353 EFI_UNSUPPORTED
3354
3355 --*/
3356 {
3357 return EFI_UNSUPPORTED;
3358 }
3359
3360 VOID
3361 EFIAPI
3362 MonitorInterruptTrans (
3363 IN EFI_EVENT Event,
3364 IN VOID *Context
3365 )
3366 /*++
3367 Routine Description:
3368 Interrupt transfer periodic check handler
3369 Arguments:
3370 Event - Interrupt event
3371 Contex - Pointer to USB_HC_DEV
3372 Returns:
3373 None
3374 --*/
3375 {
3376
3377 USB_HC_DEV *HcDev;
3378 INTERRUPT_LIST *PtrList;
3379 LIST_ENTRY *Link;
3380 UINT32 Result;
3381 VOID *DataBuffer;
3382 UINTN DataLen;
3383 UINTN ActualLen;
3384 UINTN ErrTDPos;
3385 UINT32 StatusAddr;
3386 LIST_ENTRY *NextLink;
3387
3388 HcDev = (USB_HC_DEV *) Context;
3389 StatusAddr = (UINT32) (USBSTS);
3390
3391 //
3392 // interrupt transfer list is empty, means that no interrupt transfer
3393 // is submitted by far.
3394 //
3395 if (IsListEmpty (&(HcDev->InterruptListHead))) {
3396 return ;
3397 }
3398
3399 NextLink = HcDev->InterruptListHead.ForwardLink;
3400 do {
3401
3402 Link = NextLink;
3403 NextLink = Link->ForwardLink;
3404
3405 PtrList = INTERRUPT_LIST_FROM_LINK (Link);
3406
3407 //
3408 // get TD execution results.
3409 // ErrTDPos is zero-based value indicating the first error TD's position
3410 // in the TDs' list.
3411 // This value is only valid when Result not equal NOERROR.
3412 //
3413 ExecuteAsyncINTTDs (
3414 HcDev,
3415 PtrList,
3416 &Result,
3417 &ErrTDPos,
3418 &ActualLen
3419 );
3420
3421 //
3422 // interrupt transfer has not been executed yet.
3423 //
3424 if (((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK) ||
3425 ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) {
3426 continue;
3427 }
3428 //
3429 // get actual data length transferred data and its data length.
3430 //
3431 DataLen = ActualLen;
3432 DataBuffer = AllocatePool (DataLen);
3433 if (DataBuffer == NULL) {
3434 return ;
3435 }
3436
3437 CopyMem (
3438 DataBuffer,
3439 PtrList->PtrFirstTD->pTDBuffer,
3440 DataLen
3441 );
3442
3443 //
3444 // only if interrupt endpoint responds
3445 // and the interrupt transfer stops because of completion
3446 // or error, then we will call callback function.
3447 //
3448 if (Result == EFI_USB_NOERROR) {
3449 //
3450 // add for real platform debug
3451 //
3452 if (PtrList->InterruptCallBack != NULL) {
3453 (PtrList->InterruptCallBack) (
3454 DataBuffer,
3455 DataLen,
3456 PtrList->InterruptContext,
3457 Result
3458 );
3459 }
3460
3461 if (DataBuffer) {
3462 gBS->FreePool (DataBuffer);
3463 }
3464
3465 //
3466 // update should done after data buffer got.
3467 //
3468 UpdateAsyncINTQHTDs (PtrList, Result, (UINT32) ErrTDPos);
3469
3470 } else {
3471
3472 DEBUG ((EFI_D_ERROR, "interrupt transfer error code is %x\n", Result));
3473
3474 if (DataBuffer) {
3475 gBS->FreePool (DataBuffer);
3476 }
3477 //
3478 // leave error recovery to its related device driver.
3479 // A common case of the error recovery is to re-submit the interrupt
3480 // transfer.
3481 // When an interrupt transfer is re-submitted, its position in the linked
3482 // list is changed. It is inserted to the head of the linked list, while
3483 // this function scans the whole list from head to tail. Thus, the
3484 // re-submitted interrupt transfer's callback function will not be called
3485 // again in this round.
3486 //
3487 if (PtrList->InterruptCallBack != NULL) {
3488 (PtrList->InterruptCallBack) (
3489 NULL,
3490 0,
3491 PtrList->InterruptContext,
3492 Result
3493 );
3494 }
3495 }
3496 } while (NextLink != &(HcDev->InterruptListHead));
3497
3498 }