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