]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/Uhci/Dxe/uhchlp.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Uhci / Dxe / uhchlp.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 UhcHlp.c\r
15 \r
16Abstract: \r
17 \r
18\r
19Revision History\r
20--*/\r
21\r
22#include "uhci.h"\r
23\r
1cc8ee78 24STATIC\r
878ddf1f 25EFI_STATUS\r
26USBReadPortW (\r
27 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
28 IN UINT32 PortOffset,\r
29 IN OUT UINT16 *Data\r
30 )\r
31/*++\r
32\r
33Routine Description:\r
34\r
35 USBReadPort Word\r
36\r
37Arguments:\r
38\r
39 PciIo - EFI_PCI_IO_PROTOCOL\r
40 PortOffset - Port offset\r
41 Data - Data to reutrn\r
42\r
43Returns:\r
44\r
45 EFI_SUCCESS\r
46\r
47--*/\r
48{\r
49 //\r
50 // Perform 16bit Read in PCI IO Space\r
51 //\r
52 return PciIo->Io.Read (\r
562d2849 53 PciIo,\r
54 EfiPciIoWidthUint16,\r
55 USB_BAR_INDEX,\r
56 (UINT64) PortOffset,\r
57 1,\r
58 Data\r
59 );\r
878ddf1f 60}\r
61\r
1cc8ee78 62STATIC\r
878ddf1f 63EFI_STATUS\r
64USBReadPortDW (\r
65 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
66 IN UINT32 PortOffset,\r
67 IN OUT UINT32 *Data\r
68 )\r
69/*++\r
70\r
71Routine Description:\r
72\r
73 USBReadPort DWord\r
74\r
75Arguments:\r
76\r
77 PciIo - EFI_PCI_IO_PROTOCOL\r
78 PortOffset - Port offset\r
79 Data - Data to reutrn\r
80\r
81Returns:\r
82\r
83 EFI_SUCCESS\r
84\r
85--*/\r
86{\r
87 //\r
88 // Perform 32bit Read in PCI IO Space\r
89 //\r
90 return PciIo->Io.Read (\r
562d2849 91 PciIo,\r
92 EfiPciIoWidthUint32,\r
93 USB_BAR_INDEX,\r
94 (UINT64) PortOffset,\r
95 1,\r
96 Data\r
97 );\r
878ddf1f 98}\r
99\r
1cc8ee78 100STATIC\r
878ddf1f 101EFI_STATUS\r
102USBWritePortW (\r
103 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
104 IN UINT32 PortOffset,\r
105 IN UINT16 Data\r
106 )\r
107/*++\r
108\r
109Routine Description:\r
110\r
111 USB Write Port Word\r
112\r
113Arguments:\r
114\r
115 PciIo - EFI_PCI_IO_PROTOCOL\r
116 PortOffset - Port offset\r
117 Data - Data to write\r
118\r
119Returns:\r
120\r
121 EFI_SUCCESS\r
122\r
123--*/\r
124{\r
125 //\r
126 // Perform 16bit Write in PCI IO Space\r
127 //\r
128 return PciIo->Io.Write (\r
562d2849 129 PciIo,\r
130 EfiPciIoWidthUint16,\r
131 USB_BAR_INDEX,\r
132 (UINT64) PortOffset,\r
133 1,\r
134 &Data\r
135 );\r
878ddf1f 136}\r
137\r
1cc8ee78 138STATIC\r
878ddf1f 139EFI_STATUS\r
140USBWritePortDW (\r
141 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
142 IN UINT32 PortOffset,\r
143 IN UINT32 Data\r
144 )\r
145/*++\r
146\r
147Routine Description:\r
148\r
149 USB Write Port DWord\r
150\r
151Arguments:\r
152\r
153 PciIo - EFI_PCI_IO_PROTOCOL\r
154 PortOffset - Port offset\r
155 Data - Data to write\r
156\r
157Returns:\r
158\r
159 EFI_SUCCESS\r
160\r
161--*/\r
162{\r
163 //\r
164 // Perform 32bit Write in PCI IO Space\r
165 //\r
166 return PciIo->Io.Write (\r
562d2849 167 PciIo,\r
168 EfiPciIoWidthUint32,\r
169 USB_BAR_INDEX,\r
170 (UINT64) PortOffset,\r
171 1,\r
172 &Data\r
173 );\r
878ddf1f 174}\r
175//\r
176// USB register-base helper functions\r
177//\r
178EFI_STATUS\r
179WriteUHCCommandReg (\r
180 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
181 IN UINT32 CmdAddrOffset,\r
182 IN UINT16 UsbCmd\r
183 )\r
184/*++\r
185\r
186Routine Description:\r
187\r
188 Write UHCI Command Register\r
189\r
190Arguments:\r
191\r
192 PciIo - EFI_PCI_IO_PROTOCOL\r
193 CmdAddrOffset - Command address offset\r
194 UsbCmd - Data to write\r
195\r
196Returns:\r
197\r
198 EFI_SUCCESS\r
199\r
200--*/\r
201{\r
202 //\r
203 // Write to UHC's Command Register\r
204 //\r
205 return USBWritePortW (PciIo, CmdAddrOffset, UsbCmd);\r
206}\r
207\r
208EFI_STATUS\r
209ReadUHCCommandReg (\r
210 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
211 IN UINT32 CmdAddrOffset,\r
212 IN OUT UINT16 *Data\r
213 )\r
214/*++\r
215\r
216Routine Description:\r
217\r
218 Read UHCI Command Register\r
219\r
220Arguments:\r
221\r
222 PciIo - EFI_PCI_IO_PROTOCOL\r
223 CmdAddrOffset - Command address offset\r
224 Data - Data to return\r
225\r
226Returns:\r
227\r
228 EFI_SUCCESS\r
229\r
230--*/\r
231{\r
232 //\r
233 // Read from UHC's Command Register\r
234 //\r
235 return USBReadPortW (PciIo, CmdAddrOffset, Data);\r
236}\r
237\r
238EFI_STATUS\r
239WriteUHCStatusReg (\r
240 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
241 IN UINT32 StatusAddrOffset,\r
242 IN UINT16 UsbSts\r
243 )\r
244/*++\r
245\r
246Routine Description:\r
247\r
248 Write UHCI Staus Register\r
249\r
250Arguments:\r
251\r
252 PciIo - EFI_PCI_IO_PROTOCOL\r
253 StatusAddrOffset - Status address offset\r
254 UsbSts - Data to write\r
255\r
256Returns:\r
257\r
258 EFI_SUCCESS\r
259\r
260--*/\r
261{\r
262 //\r
263 // Write to UHC's Status Register\r
264 //\r
265 return USBWritePortW (PciIo, StatusAddrOffset, UsbSts);\r
266}\r
267\r
268EFI_STATUS\r
269ReadUHCStatusReg (\r
270 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
271 IN UINT32 StatusAddrOffset,\r
272 IN OUT UINT16 *Data\r
273 )\r
274/*++\r
275\r
276Routine Description:\r
277\r
278 Read UHCI Staus Register\r
279\r
280Arguments:\r
281\r
282 PciIo - EFI_PCI_IO_PROTOCOL\r
283 StatusAddrOffset - Status address offset\r
284 UsbSts - Data to return\r
285\r
286Returns:\r
287\r
288 EFI_SUCCESS\r
289\r
290--*/\r
291{\r
292 //\r
293 // Read from UHC's Status Register\r
294 //\r
295 return USBReadPortW (PciIo, StatusAddrOffset, Data);\r
296}\r
297\r
298\r
299EFI_STATUS\r
300ClearStatusReg (\r
301 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
302 IN UINT32 StatusAddrOffset\r
303 )\r
304/*++\r
305\r
306Routine Description:\r
307\r
308 Clear the content of UHC's Status Register\r
309\r
310Arguments:\r
311\r
312 PciIo - EFI_PCI_IO_PROTOCOL\r
313 StatusAddrOffset - Status address offset\r
314 \r
315Returns:\r
316\r
317 EFI_SUCCESS\r
318\r
319--*/\r
320{\r
321 \r
322 return WriteUHCStatusReg (PciIo, StatusAddrOffset, 0x003F);\r
323}\r
324\r
325EFI_STATUS\r
326ReadUHCFrameNumberReg (\r
327 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
328 IN UINT32 FrameNumAddrOffset,\r
329 IN OUT UINT16 *Data\r
330 )\r
331/*++\r
332\r
333Routine Description:\r
334\r
335 Read from UHC's Frame Number Register\r
336\r
337Arguments:\r
338\r
339 PciIo - EFI_PCI_IO_PROTOCOL\r
340 FrameNumAddrOffset - Frame number register offset\r
341 Data - Data to return \r
342Returns:\r
343\r
344 EFI_SUCCESS\r
345\r
346--*/\r
347{\r
348 \r
349 return USBReadPortW (PciIo, FrameNumAddrOffset, Data);\r
350}\r
351\r
352EFI_STATUS\r
353WriteUHCFrameListBaseReg (\r
354 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
355 IN UINT32 FlBaseAddrOffset,\r
356 IN UINT32 UsbFrameListBaseAddr\r
357 )\r
358/*++\r
359\r
360Routine Description:\r
361\r
362 Write to UHC's Frame List Base Register\r
363\r
364Arguments:\r
365\r
366 PciIo - EFI_PCI_IO_PROTOCOL\r
367 FlBaseAddrOffset - Frame Base address register\r
368 UsbFrameListBaseAddr - Address to write\r
369\r
370Returns:\r
371\r
372 EFI_SUCCESS\r
373\r
374--*/\r
375{\r
376 \r
377 return USBWritePortDW (PciIo, FlBaseAddrOffset, UsbFrameListBaseAddr);\r
378}\r
379\r
380EFI_STATUS\r
381ReadRootPortReg (\r
382 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
383 IN UINT32 PortAddrOffset,\r
384 IN OUT UINT16 *Data\r
385 )\r
386/*++\r
387\r
388Routine Description:\r
389\r
390 Read from UHC's Root Port Register\r
391\r
392Arguments:\r
393\r
394 PciIo - EFI_PCI_IO_PROTOCOL\r
395 PortAddrOffset - Port Addrress Offset,\r
396 Data - Data to return\r
397Returns:\r
398\r
399 EFI_SUCCESS\r
400\r
401--*/\r
402{\r
403 \r
404 return USBReadPortW (PciIo, PortAddrOffset, Data);\r
405}\r
406\r
407EFI_STATUS\r
408WriteRootPortReg (\r
409 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
410 IN UINT32 PortAddrOffset,\r
411 IN UINT16 ControlBits\r
412 )\r
413/*++\r
414\r
415Routine Description:\r
416\r
417 Write to UHC's Root Port Register\r
418\r
419Arguments:\r
420\r
421 PciIo - EFI_PCI_IO_PROTOCOL\r
422 PortAddrOffset - Port Addrress Offset,\r
423 ControlBits - Data to write\r
424Returns:\r
425\r
426 EFI_SUCCESS\r
427\r
428--*/\r
429{\r
430 \r
431 return USBWritePortW (PciIo, PortAddrOffset, ControlBits);\r
432}\r
433\r
434\r
435\r
436EFI_STATUS\r
437WaitForUHCHalt (\r
438 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
439 IN UINT32 StatusRegAddr,\r
440 IN UINTN Timeout\r
441 )\r
442/*++\r
443\r
444Routine Description:\r
445\r
446 Wait until UHCI halt or timeout\r
447\r
448Arguments:\r
449\r
450 PciIo - EFI_PCI_IO_PROTOCOL\r
451 StatusRegAddr - Status Register Address\r
452 Timeout - Time out value in us\r
453\r
454Returns:\r
455\r
456 EFI_DEVICE_ERROR - Unable to read the status register\r
457 EFI_TIMEOUT - Time out\r
458 EFI_SUCCESS - Success\r
459\r
460--*/\r
461{\r
462 UINTN Delay;\r
463 EFI_STATUS Status;\r
464 UINT16 HcStatus;\r
465\r
466 //\r
467 // Timeout is in us unit\r
468 //\r
469 Delay = (Timeout / 50) + 1;\r
470 do {\r
471 Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);\r
472 if (EFI_ERROR (Status)) {\r
473 return EFI_DEVICE_ERROR;\r
474 }\r
475\r
476 if ((HcStatus & USBSTS_HCH) == USBSTS_HCH) {\r
477 break;\r
478 }\r
479 //\r
480 // Stall for 50 us\r
481 //\r
482 gBS->Stall (50);\r
483\r
484 } while (Delay--);\r
485\r
486 if (Delay == 0) {\r
487 return EFI_TIMEOUT;\r
488 }\r
489\r
490 return EFI_SUCCESS;\r
491}\r
492\r
493BOOLEAN\r
494IsStatusOK (\r
495 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
496 IN UINT32 StatusRegAddr\r
497 )\r
498/*++\r
499\r
500Routine Description:\r
501\r
502 Judge whether the host controller operates well\r
503\r
504Arguments:\r
505\r
506 PciIo - EFI_PCI_IO_PROTOCOL\r
507 StatusRegAddr - Status register address\r
508\r
509Returns:\r
510\r
511 TRUE - Status is good\r
512 FALSE - Status is bad\r
513\r
514--*/\r
515{\r
516 EFI_STATUS Status;\r
517 UINT16 HcStatus;\r
518 //\r
519 // Detect whether the interrupt is caused by fatal error.\r
520 // see "UHCI Design Guid".\r
521 //\r
522 Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);\r
523 if (EFI_ERROR (Status)) {\r
524 return FALSE;\r
525 }\r
526\r
527 if (HcStatus & (USBSTS_HCPE | USBSTS_HSE | USBSTS_HCH)) {\r
528 return FALSE;\r
529 } else {\r
530 return TRUE;\r
531 }\r
532\r
533}\r
534\r
535\r
536BOOLEAN \r
537IsHostSysOrProcessErr (\r
538 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
539 IN UINT32 StatusRegAddr\r
540 )\r
541/*++\r
542\r
543Routine Description:\r
544\r
545 Judge the status is HostSys,ProcessErr error or good\r
546\r
547Arguments:\r
548\r
549 PciIo - EFI_PCI_IO_PROTOCOL\r
550 StatusRegAddr - Status register address\r
551\r
552Returns:\r
553\r
554 TRUE - Status is good\r
555 FALSE - Status is bad\r
556\r
557--*/\r
558{\r
559 EFI_STATUS Status;\r
560 UINT16 HcStatus;\r
561 //\r
562 // Detect whether the interrupt is caused by serious error.\r
563 // see "UHCI Design Guid".\r
564 //\r
565 Status = ReadUHCStatusReg (PciIo, StatusRegAddr, &HcStatus);\r
566 if (EFI_ERROR (Status)) {\r
567 return FALSE;\r
568 }\r
569\r
570 if (HcStatus & (USBSTS_HSE | USBSTS_HCPE)) {\r
571 return TRUE;\r
572 } else {\r
573 return FALSE;\r
574 }\r
575}\r
576\r
577\r
578UINT16\r
579GetCurrentFrameNumber (\r
580 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
581 IN UINT32 FrameNumAddrOffset\r
582 )\r
583/*++\r
584\r
585Routine Description:\r
586\r
587 Get Current Frame Number\r
588\r
589Arguments:\r
590\r
591 PciIo - EFI_PCI_IO_PROTOCOL\r
592 FrameNumAddrOffset - FrameNum register AddrOffset\r
593\r
594Returns:\r
595\r
596 Frame number \r
597\r
598--*/\r
599{\r
600 //\r
601 // Gets value in the USB frame number register.\r
602 //\r
603 UINT16 FrameNumber;\r
604\r
605 ReadUHCFrameNumberReg (PciIo, FrameNumAddrOffset, &FrameNumber);\r
606\r
607 return (UINT16) (FrameNumber & 0x03FF);\r
608}\r
609\r
610EFI_STATUS\r
611SetFrameListBaseAddress (\r
612 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
613 IN UINT32 FlBaseAddrReg,\r
614 IN UINT32 Addr\r
615 )\r
616/*++\r
617\r
618Routine Description:\r
619\r
620 Set FrameListBase Address\r
621\r
622Arguments:\r
623\r
624 PciIo - EFI_PCI_IO_PROTOCOL\r
625 FlBaseAddrReg - FrameListBase register\r
626 Addr - Address to set\r
627\r
628Returns:\r
629\r
630 EFI_SUCCESS\r
631\r
632--*/\r
633{\r
634 //\r
635 // Sets value in the USB Frame List Base Address register.\r
636 //\r
637 return WriteUHCFrameListBaseReg (PciIo, FlBaseAddrReg, (UINT32) (Addr & 0xFFFFF000));\r
638}\r
639\r
640VOID\r
641EnableMaxPacketSize (\r
642 IN USB_HC_DEV *HcDev\r
643 )\r
644/*++\r
645\r
646Routine Description:\r
647\r
648 Enable Max Packet Size\r
649\r
650Arguments:\r
651\r
652 HcDev - USB_HC_DEV\r
653\r
654Returns:\r
655\r
656 VOID\r
657\r
658--*/\r
659{\r
660 UINT16 CommandContent;\r
878ddf1f 661\r
1cc8ee78 662 ReadUHCCommandReg (\r
663 HcDev->PciIo,\r
664 (UINT32) (USBCMD),\r
665 &CommandContent\r
666 );\r
878ddf1f 667\r
668 if ((CommandContent & USBCMD_MAXP) != USBCMD_MAXP) {\r
669 CommandContent |= USBCMD_MAXP;\r
670 WriteUHCCommandReg (\r
671 HcDev->PciIo,\r
672 (UINT32) (USBCMD),\r
673 CommandContent\r
674 );\r
675 }\r
676\r
677 return ;\r
678}\r
679\r
680EFI_STATUS\r
681CreateFrameList (\r
682 IN USB_HC_DEV *HcDev,\r
683 IN UINT32 FlBaseAddrReg\r
684 )\r
685/*++\r
686\r
687Routine Description:\r
688\r
689 CreateFrameList\r
690\r
691Arguments:\r
692\r
693 HcDev - USB_HC_DEV\r
694 FlBaseAddrReg - Frame List register\r
695\r
696Returns:\r
697\r
698 EFI_OUT_OF_RESOURCES - Can't allocate memory resources\r
699 EFI_UNSUPPORTED - Map memory fail\r
700 EFI_SUCCESS - Success\r
701\r
702--*/\r
703{\r
704 EFI_STATUS Status;\r
705 VOID *CommonBuffer;\r
706 EFI_PHYSICAL_ADDRESS MappedAddress;\r
707 VOID *Mapping;\r
708 UINTN BufferSizeInPages;\r
709 UINTN BufferSizeInBytes;\r
710\r
711 //\r
712 // The Frame List is a common buffer that will be\r
713 // accessed by both the cpu and the usb bus master\r
714 // at the same time.\r
715 // The Frame List ocupies 4K bytes,\r
716 // and must be aligned on 4-Kbyte boundaries.\r
717 //\r
718 BufferSizeInBytes = 4096;\r
719 BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);\r
720 Status = HcDev->PciIo->AllocateBuffer (\r
562d2849 721 HcDev->PciIo,\r
722 AllocateAnyPages,\r
723 EfiBootServicesData,\r
724 BufferSizeInPages,\r
725 &CommonBuffer,\r
726 0\r
727 );\r
878ddf1f 728 if (EFI_ERROR (Status)) {\r
729 return EFI_OUT_OF_RESOURCES;\r
730 }\r
731\r
732 Status = HcDev->PciIo->Map (\r
562d2849 733 HcDev->PciIo,\r
734 EfiPciIoOperationBusMasterCommonBuffer,\r
735 CommonBuffer,\r
736 &BufferSizeInBytes,\r
737 &MappedAddress,\r
738 &Mapping\r
739 );\r
878ddf1f 740 if (EFI_ERROR (Status) || (BufferSizeInBytes != 4096)) {\r
741 HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);\r
742 return EFI_UNSUPPORTED;\r
743 }\r
744\r
745 HcDev->FrameListEntry = (FRAMELIST_ENTRY *) ((UINTN) MappedAddress);\r
746\r
747 HcDev->FrameListMapping = Mapping;\r
748\r
749 InitFrameList (HcDev);\r
750\r
751 //\r
752 // Tell the Host Controller where the Frame List lies,\r
753 // by set the Frame List Base Address Register.\r
754 //\r
755 SetFrameListBaseAddress (\r
756 HcDev->PciIo,\r
757 FlBaseAddrReg,\r
758 (UINT32) ((UINTN) HcDev->FrameListEntry)\r
759 );\r
760\r
761 return EFI_SUCCESS;\r
762}\r
763\r
764EFI_STATUS\r
765FreeFrameListEntry (\r
766 IN USB_HC_DEV *HcDev\r
767 )\r
768/*++\r
769\r
770Routine Description:\r
771\r
772 Free FrameList buffer\r
773\r
774Arguments:\r
775\r
776 HcDev - USB_HC_DEV\r
777\r
778Returns:\r
779\r
780 EFI_SUCCESS - success\r
781\r
782--*/\r
783{\r
784 //\r
785 // Unmap the common buffer for framelist entry,\r
786 // and free the common buffer.\r
787 // Uhci's frame list occupy 4k memory.\r
788 //\r
789 HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->FrameListMapping);\r
790 HcDev->PciIo->FreeBuffer (\r
791 HcDev->PciIo,\r
792 EFI_SIZE_TO_PAGES (4096),\r
793 (VOID *) (HcDev->FrameListEntry)\r
794 );\r
795 return EFI_SUCCESS;\r
796}\r
797\r
798VOID\r
799InitFrameList (\r
800 IN USB_HC_DEV *HcDev\r
801 )\r
802/*++\r
803\r
804Routine Description:\r
805\r
806 Initialize FrameList\r
807\r
808Arguments:\r
809\r
810 HcDev - USB_HC_DEV\r
811\r
812Returns:\r
813 VOID\r
814\r
815--*/ \r
816{\r
817 FRAMELIST_ENTRY *FrameListPtr;\r
818 UINTN Index;\r
819\r
820 //\r
821 // Validate each Frame List Entry\r
822 //\r
823 FrameListPtr = HcDev->FrameListEntry;\r
824 for (Index = 0; Index < 1024; Index++) {\r
825 FrameListPtr->FrameListPtrTerminate = 1;\r
826 FrameListPtr->FrameListPtr = 0;\r
827 FrameListPtr->FrameListPtrQSelect = 0;\r
828 FrameListPtr->FrameListRsvd = 0;\r
829 FrameListPtr++;\r
830 }\r
831}\r
832//\r
833// //////////////////////////////////////////////////////////////\r
834//\r
835// QH TD related Helper Functions\r
836//\r
837////////////////////////////////////////////////////////////////\r
838//\r
839// functions for QH\r
840//\r
1cc8ee78 841STATIC\r
878ddf1f 842EFI_STATUS\r
843AllocateQHStruct (\r
844 IN USB_HC_DEV *HcDev,\r
845 OUT QH_STRUCT **ppQHStruct\r
846 )\r
847/*++\r
848\r
849Routine Description:\r
850\r
851 Allocate QH Struct\r
852\r
853Arguments:\r
854\r
855 HcDev - USB_HC_DEV\r
856 ppQHStruct - QH_STRUCT content to return\r
857Returns:\r
858\r
859 EFI_SUCCESS\r
860\r
861--*/\r
862{\r
863 *ppQHStruct = NULL;\r
864\r
865 //\r
866 // QH must align on 16 bytes alignment,\r
867 // since the memory allocated by UhciAllocatePool ()\r
868 // is aligned on 32 bytes, it is no need to adjust\r
869 // the allocated memory returned.\r
870 //\r
871 return UhciAllocatePool (HcDev, (UINT8 **) ppQHStruct, sizeof (QH_STRUCT));\r
872}\r
873\r
874\r
875EFI_STATUS\r
876CreateQH (\r
877 IN USB_HC_DEV *HcDev,\r
878 OUT QH_STRUCT **pptrQH\r
879 )\r
880/*++\r
881\r
882Routine Description:\r
883\r
884 CreateQH\r
885\r
886Arguments:\r
887\r
888 HcDev - USB_HC_DEV\r
889 ppQHStruct - QH_STRUCT content to return\r
890Returns:\r
891\r
892 EFI_SUCCESS - Success\r
893 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
894--*/\r
895{\r
896 EFI_STATUS Status;\r
897\r
898 //\r
899 // allocate align memory for QH_STRUCT\r
900 //\r
901 Status = AllocateQHStruct (HcDev, pptrQH);\r
902 if (EFI_ERROR (Status)) {\r
903 return EFI_OUT_OF_RESOURCES;\r
904 }\r
905 //\r
906 // init each field of the QH_STRUCT\r
907 //\r
908 //\r
909 // Make QH ready\r
910 //\r
911 SetQHHorizontalValidorInvalid (*pptrQH, FALSE);\r
912 SetQHVerticalValidorInvalid (*pptrQH, FALSE);\r
913\r
914 return EFI_SUCCESS;\r
915}\r
916\r
917VOID\r
918SetQHHorizontalLinkPtr (\r
919 IN QH_STRUCT *PtrQH,\r
920 IN VOID *ptrNext\r
921 )\r
922/*++\r
923\r
924Routine Description:\r
925\r
926 Set QH Horizontal Link Pointer\r
927\r
928Arguments:\r
929\r
930 PtrQH - QH_STRUCT\r
931 ptrNext - Data to write \r
932\r
933Returns:\r
934\r
935 VOID\r
936\r
937--*/\r
938{\r
939 //\r
940 // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
941 // Only the highest 28bit of the address is valid\r
942 // (take 32bit address as an example).\r
943 //\r
944 PtrQH->QH.QHHorizontalPtr = (UINT32) ((UINTN) ptrNext >> 4);\r
945}\r
946\r
947VOID *\r
948GetQHHorizontalLinkPtr (\r
949 IN QH_STRUCT *PtrQH\r
950 )\r
951/*++\r
952\r
953Routine Description:\r
954\r
955 Get QH Horizontal Link Pointer\r
956\r
957Arguments:\r
958\r
959 PtrQH - QH_STRUCT\r
960 \r
961\r
962Returns:\r
963\r
964 Data to return \r
965\r
966--*/\r
967{\r
968 //\r
969 // Restore the 28bit address to 32bit address\r
970 // (take 32bit address as an example)\r
971 //\r
972 return (VOID *) ((UINTN) (PtrQH->QH.QHHorizontalPtr << 4));\r
973}\r
974\r
975VOID\r
976SetQHHorizontalQHorTDSelect (\r
977 IN QH_STRUCT *PtrQH,\r
978 IN BOOLEAN bQH\r
979 )\r
980/*++\r
981\r
982Routine Description:\r
983\r
984 Set QH Horizontal QH or TD \r
985\r
986Arguments:\r
987\r
988 PtrQH - QH_STRUCT\r
989 bQH - TRUE is QH FALSE is TD\r
990\r
991Returns:\r
992 VOID\r
993\r
994--*/\r
995{\r
996 //\r
997 // if QH is connected, the specified bit is set,\r
998 // if TD is connected, the specified bit is cleared.\r
999 //\r
1000 PtrQH->QH.QHHorizontalQSelect = bQH ? 1 : 0;\r
1001}\r
1002\r
1003\r
1004VOID\r
1005SetQHHorizontalValidorInvalid (\r
1006 IN QH_STRUCT *PtrQH,\r
1007 IN BOOLEAN bValid\r
1008 )\r
1009/*++\r
1010\r
1011Routine Description:\r
1012\r
1013 Set QH Horizontal Valid or Invalid\r
1014\r
1015Arguments:\r
1016\r
1017 PtrQH - QH_STRUCT\r
1018 bValid - TRUE is Valid FALSE is Invalid\r
1019\r
1020Returns:\r
1021 VOID\r
1022\r
1023--*/\r
1024{\r
1025 //\r
1026 // Valid means the horizontal link pointer is valid,\r
1027 // else, it's invalid.\r
1028 //\r
1029 PtrQH->QH.QHHorizontalTerminate = bValid ? 0 : 1;\r
1030}\r
1031\r
1032VOID\r
1033SetQHVerticalLinkPtr (\r
1034 IN QH_STRUCT *PtrQH,\r
1035 IN VOID *ptrNext\r
1036 )\r
1037/*++\r
1038\r
1039Routine Description:\r
1040\r
1041 Set QH Vertical Link Pointer\r
1042 \r
1043Arguments:\r
1044\r
1045 PtrQH - QH_STRUCT\r
1046 ptrNext - Data to write\r
1047Returns:\r
1048\r
1049 VOID\r
1050\r
1051--*/\r
1052{\r
1053 //\r
1054 // Since the QH_STRUCT is aligned on 16-byte boundaries,\r
1055 // Only the highest 28bit of the address is valid\r
1056 // (take 32bit address as an example).\r
1057 //\r
1058 PtrQH->QH.QHVerticalPtr = (UINT32) ((UINTN) ptrNext >> 4);\r
1059}\r
1060\r
1061VOID *\r
1062GetQHVerticalLinkPtr (\r
1063 IN QH_STRUCT *PtrQH\r
1064 )\r
1065/*++\r
1066\r
1067Routine Description:\r
1068\r
1069 Get QH Vertical Link Pointer\r
1070 \r
1071Arguments:\r
1072\r
1073 PtrQH - QH_STRUCT\r
1074 \r
1075Returns:\r
1076\r
1077 Data to return\r
1078\r
1079--*/\r
1080{\r
1081 //\r
1082 // Restore the 28bit address to 32bit address\r
1083 // (take 32bit address as an example)\r
1084 //\r
1085 return (VOID *) ((UINTN) (PtrQH->QH.QHVerticalPtr << 4));\r
1086}\r
1087\r
1088VOID\r
1089SetQHVerticalQHorTDSelect (\r
1090 IN QH_STRUCT *PtrQH,\r
1091 IN BOOLEAN bQH\r
1092 )\r
1093/*++\r
1094\r
1095Routine Description:\r
1096\r
1097 Set QH Vertical QH or TD\r
1098\r
1099Arguments:\r
1100\r
1101 PtrQH - QH_STRUCT\r
1102 bQH - TRUE is QH FALSE is TD\r
1103\r
1104Returns:\r
1105\r
1106 VOID\r
1107\r
1108--*/\r
1109{\r
1110 //\r
1111 // Set the specified bit if the Vertical Link Pointer pointing to a QH,\r
1112 // Clear the specified bit if the Vertical Link Pointer pointing to a TD.\r
1113 //\r
1114 PtrQH->QH.QHVerticalQSelect = bQH ? 1 : 0;\r
1115}\r
1116\r
1117BOOLEAN\r
1118IsQHHorizontalQHSelect (\r
1119 IN QH_STRUCT *PtrQH\r
1120 )\r
1121/*++\r
1122\r
1123Routine Description:\r
1124\r
1125 Is QH Horizontal QH Select\r
1126\r
1127Arguments:\r
1128\r
1129 PtrQH - QH_STRUCT\r
1130 \r
1131Returns:\r
1132\r
1133 TRUE - QH\r
1134 FALSE - TD\r
1135\r
1136--*/\r
1137{\r
1138 //\r
1139 // Retrieve the information about whether the Horizontal Link Pointer\r
1140 // pointing to a QH or TD.\r
1141 //\r
1142 return (BOOLEAN) (PtrQH->QH.QHHorizontalQSelect ? TRUE : FALSE);\r
1143}\r
1144\r
1145VOID\r
1146SetQHVerticalValidorInvalid (\r
1147 IN QH_STRUCT *PtrQH,\r
1148 IN BOOLEAN IsValid\r
1149 )\r
1150/*++\r
1151\r
1152Routine Description:\r
1153\r
1154 Set QH Vertical Valid or Invalid\r
1155\r
1156Arguments:\r
1157\r
1158 PtrQH - QH_STRUCT\r
1159 IsValid - TRUE is valid FALSE is invalid\r
1160\r
1161Returns:\r
1162\r
1163 VOID\r
1164\r
1165--*/\r
1166{\r
1167 //\r
1168 // If TRUE, indicates the Vertical Link Pointer field is valid,\r
1169 // else, the field is invalid.\r
1170 //\r
1171 PtrQH->QH.QHVerticalTerminate = IsValid ? 0 : 1;\r
1172}\r
1173\r
1174\r
1175BOOLEAN\r
1176GetQHVerticalValidorInvalid (\r
1177 IN QH_STRUCT *PtrQH\r
1178 )\r
1179/*++\r
1180\r
1181Routine Description:\r
1182\r
1183 Get QH Vertical Valid or Invalid\r
1184\r
1185Arguments:\r
1186\r
1187 PtrQH - QH_STRUCT\r
1188\r
1189Returns:\r
1190\r
1191 TRUE - Valid\r
1192 FALSE - Invalid\r
1193\r
1194--*/\r
1195{\r
1196 //\r
1197 // If TRUE, indicates the Vertical Link Pointer field is valid,\r
1198 // else, the field is invalid.\r
1199 //\r
1200 return (BOOLEAN) (!(PtrQH->QH.QHVerticalTerminate));\r
1201}\r
1202\r
1cc8ee78 1203STATIC\r
878ddf1f 1204BOOLEAN\r
1205GetQHHorizontalValidorInvalid (\r
1206 IN QH_STRUCT *PtrQH\r
1207 )\r
1208/*++\r
1209\r
1210Routine Description:\r
1211\r
1212 Get QH Horizontal Valid or Invalid\r
1213\r
1214Arguments:\r
1215\r
1216 PtrQH - QH_STRUCT\r
1217\r
1218Returns:\r
1219\r
1220 TRUE - Valid\r
1221 FALSE - Invalid\r
1222\r
1223--*/\r
1224{\r
1225 //\r
1226 // If TRUE, meaning the Horizontal Link Pointer field is valid,\r
1227 // else, the field is invalid.\r
1228 //\r
1229 return (BOOLEAN) (!(PtrQH->QH.QHHorizontalTerminate));\r
1230}\r
1231//\r
1232// functions for TD\r
1233//\r
1234EFI_STATUS\r
1235AllocateTDStruct (\r
1236 IN USB_HC_DEV *HcDev,\r
1237 OUT TD_STRUCT **ppTDStruct\r
1238 )\r
1239/*++\r
1240\r
1241Routine Description:\r
1242\r
1243 Allocate TD Struct\r
1244\r
1245Arguments:\r
1246\r
1247 HcDev - USB_HC_DEV\r
1248 ppTDStruct - place to store TD_STRUCT pointer\r
1249Returns:\r
1250\r
1251 EFI_SUCCESS\r
1252\r
1253--*/\r
1254{\r
1255 *ppTDStruct = NULL;\r
1256\r
1257 //\r
1258 // TD must align on 16 bytes alignment,\r
1259 // since the memory allocated by UhciAllocatePool ()\r
1260 // is aligned on 32 bytes, it is no need to adjust\r
1261 // the allocated memory returned.\r
1262 //\r
1263 return UhciAllocatePool (\r
1264 HcDev,\r
1265 (UINT8 **) ppTDStruct,\r
1266 sizeof (TD_STRUCT)\r
1267 );\r
1268}\r
1269\r
1270EFI_STATUS\r
1271CreateTD (\r
1272 IN USB_HC_DEV *HcDev,\r
1273 OUT TD_STRUCT **pptrTD\r
1274 )\r
1275/*++\r
1276\r
1277Routine Description:\r
1278\r
1279 Create TD\r
1280\r
1281Arguments:\r
1282\r
1283 HcDev - USB_HC_DEV\r
1284 pptrTD - TD_STRUCT pointer to store\r
1285\r
1286Returns:\r
1287\r
1288 EFI_OUT_OF_RESOURCES - Can't allocate resources\r
1289 EFI_SUCCESS - Success\r
1290\r
1291--*/\r
1292{\r
1293 EFI_STATUS Status;\r
1294 //\r
1295 // create memory for TD_STRUCT, and align the memory.\r
1296 //\r
1297 Status = AllocateTDStruct (HcDev, pptrTD);\r
1298 if (EFI_ERROR (Status)) {\r
1299 return EFI_OUT_OF_RESOURCES;\r
1300 }\r
1301\r
1302 //\r
1303 // Make TD ready.\r
1304 //\r
1305 SetTDLinkPtrValidorInvalid (*pptrTD, FALSE);\r
1306\r
1307\r
1308 return EFI_SUCCESS;\r
1309}\r
1310\r
1311EFI_STATUS\r
1312GenSetupStageTD (\r
1313 IN USB_HC_DEV *HcDev,\r
1314 IN UINT8 DevAddr,\r
1315 IN UINT8 Endpoint,\r
1316 IN BOOLEAN bSlow,\r
1317 IN UINT8 *pDevReq,\r
1318 IN UINT8 RequestLen,\r
1319 OUT TD_STRUCT **ppTD\r
1320 )\r
1321/*++\r
1322\r
1323Routine Description:\r
1324\r
1325 Generate Setup Stage TD\r
1326\r
1327Arguments:\r
1328\r
1329 HcDev - USB_HC_DEV\r
1330 DevAddr - Device address\r
1331 Endpoint - Endpoint number \r
1332 bSlow - Full speed or low speed\r
1333 pDevReq - Device request\r
1334 RequestLen - Request length\r
1335 ppTD - TD_STRUCT to return\r
1336Returns:\r
1337\r
1338 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
1339 EFI_SUCCESS - Success\r
1340\r
1341--*/\r
1342{\r
1343 EFI_STATUS Status;\r
1344 TD_STRUCT *pTDStruct;\r
1345\r
1346 Status = CreateTD (HcDev, &pTDStruct);\r
1347 if (EFI_ERROR (Status)) {\r
1348 return EFI_OUT_OF_RESOURCES;\r
1349 }\r
1350\r
1351 SetTDLinkPtr (pTDStruct, NULL);\r
1352\r
1353 //\r
1354 // Depth first fashion\r
1355 //\r
1356 SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE);\r
1357\r
1358 //\r
1359 // initialize as the last TD in the QH context,\r
1360 // this field will be updated in the TD linkage process.\r
1361 //\r
1362 SetTDLinkPtrValidorInvalid (pTDStruct, FALSE);\r
1363\r
1364 //\r
1365 // Disable Short Packet Detection by default\r
1366 //\r
1367 EnableorDisableTDShortPacket (pTDStruct, FALSE);\r
1368\r
1369 //\r
1370 // Max error counter is 3, retry 3 times when error encountered.\r
1371 //\r
1372 SetTDControlErrorCounter (pTDStruct, 3);\r
1373\r
1374 //\r
1375 // set device speed attribute\r
1376 // (TRUE - Slow Device; FALSE - Full Speed Device)\r
1377 //\r
1378 SetTDLoworFullSpeedDevice (pTDStruct, bSlow);\r
1379\r
1380 //\r
1381 // Non isochronous transfer TD\r
1382 //\r
1383 SetTDControlIsochronousorNot (pTDStruct, FALSE);\r
1384\r
1385 //\r
1386 // Interrupt On Complete bit be set to zero,\r
1387 // Disable IOC interrupt.\r
1388 //\r
1389 SetorClearTDControlIOC (pTDStruct, FALSE);\r
1390\r
1391 //\r
1392 // Set TD Active bit\r
1393 //\r
1394 SetTDStatusActiveorInactive (pTDStruct, TRUE);\r
1395\r
1396 SetTDTokenMaxLength (pTDStruct, RequestLen);\r
1397\r
1398 SetTDTokenDataToggle0 (pTDStruct);\r
1399\r
1400 SetTDTokenEndPoint (pTDStruct, Endpoint);\r
1401\r
1402 SetTDTokenDeviceAddress (pTDStruct, DevAddr);\r
1403\r
1404 SetTDTokenPacketID (pTDStruct, SETUP_PACKET_ID);\r
1405\r
1406 pTDStruct->pTDBuffer = (UINT8 *) pDevReq;\r
1407 pTDStruct->TDBufferLength = RequestLen;\r
1408 SetTDDataBuffer (pTDStruct);\r
1409\r
1410 *ppTD = pTDStruct;\r
1411\r
1412 return EFI_SUCCESS;\r
1413}\r
1414\r
1415EFI_STATUS\r
1416GenDataTD (\r
1417 IN USB_HC_DEV *HcDev,\r
1418 IN UINT8 DevAddr,\r
1419 IN UINT8 Endpoint,\r
1420 IN UINT8 *pData,\r
1421 IN UINT8 Len,\r
1422 IN UINT8 PktID,\r
1423 IN UINT8 Toggle,\r
1424 IN BOOLEAN bSlow,\r
1425 OUT TD_STRUCT **ppTD\r
1426 )\r
1427/*++\r
1428\r
1429Routine Description:\r
1430\r
1431 Generate Data Stage TD\r
1432\r
1433Arguments:\r
1434\r
1435 HcDev - USB_HC_DEV\r
1436 DevAddr - Device address\r
1437 Endpoint - Endpoint number \r
1438 pData - Data buffer \r
1439 Len - Data length\r
1440 PktID - Packet ID\r
1441 Toggle - Data toggle value\r
1442 bSlow - Full speed or low speed\r
1443 ppTD - TD_STRUCT to return\r
1444Returns:\r
1445\r
1446 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
1447 EFI_SUCCESS - Success\r
1448\r
1449--*/\r
1450{\r
1451 TD_STRUCT *pTDStruct;\r
1452 EFI_STATUS Status;\r
1453\r
1454 Status = CreateTD (HcDev, &pTDStruct);\r
1455 if (EFI_ERROR (Status)) {\r
1456 return EFI_OUT_OF_RESOURCES;\r
1457 }\r
1458\r
1459 SetTDLinkPtr (pTDStruct, NULL);\r
1460\r
1461 //\r
1462 // Depth first fashion\r
1463 //\r
1464 SetTDLinkPtrDepthorBreadth (pTDStruct, TRUE);\r
1465\r
1466 //\r
1467 // Link pointer pointing to TD struct\r
1468 //\r
1469 SetTDLinkPtrQHorTDSelect (pTDStruct, FALSE);\r
1470\r
1471 //\r
1472 // initialize as the last TD in the QH context,\r
1473 // this field will be updated in the TD linkage process.\r
1474 //\r
1475 SetTDLinkPtrValidorInvalid (pTDStruct, FALSE);\r
1476\r
1477 //\r
1478 // Disable short packet detect\r
1479 //\r
1480 EnableorDisableTDShortPacket (pTDStruct, FALSE);\r
1481 //\r
1482 // Max error counter is 3\r
1483 //\r
1484 SetTDControlErrorCounter (pTDStruct, 3);\r
1485\r
1486 //\r
1487 // set device speed attribute\r
1488 // (TRUE - Slow Device; FALSE - Full Speed Device)\r
1489 //\r
1490 SetTDLoworFullSpeedDevice (pTDStruct, bSlow);\r
1491\r
1492 //\r
1493 // Non isochronous transfer TD\r
1494 //\r
1495 SetTDControlIsochronousorNot (pTDStruct, FALSE);\r
1496\r
1497 //\r
1498 // Disable Interrupt On Complete\r
1499 // Disable IOC interrupt.\r
1500 //\r
1501 SetorClearTDControlIOC (pTDStruct, FALSE);\r
1502\r
1503 //\r
1504 // Set Active bit\r
1505 //\r
1506 SetTDStatusActiveorInactive (pTDStruct, TRUE);\r
1507\r
1508 SetTDTokenMaxLength (pTDStruct, Len);\r
1509\r
1510 if (Toggle) {\r
1511 SetTDTokenDataToggle1 (pTDStruct);\r
1512 } else {\r
1513 SetTDTokenDataToggle0 (pTDStruct);\r
1514 }\r
1515\r
1516 SetTDTokenEndPoint (pTDStruct, Endpoint);\r
1517\r
1518 SetTDTokenDeviceAddress (pTDStruct, DevAddr);\r
1519\r
1520 SetTDTokenPacketID (pTDStruct, PktID);\r
1521\r
1522 pTDStruct->pTDBuffer = (UINT8 *) pData;\r
1523 pTDStruct->TDBufferLength = Len;\r
1524 SetTDDataBuffer (pTDStruct);\r
1525 *ppTD = pTDStruct;\r
1526\r
1527 return EFI_SUCCESS;\r
1528}\r
1529\r
1530\r
1531EFI_STATUS\r
1532CreateStatusTD (\r
1533 IN USB_HC_DEV *HcDev,\r
1534 IN UINT8 DevAddr,\r
1535 IN UINT8 Endpoint,\r
1536 IN UINT8 PktID,\r
1537 IN BOOLEAN bSlow,\r
1538 OUT TD_STRUCT **ppTD\r
1539 )\r
1540/*++\r
1541\r
1542Routine Description:\r
1543\r
1544 Generate Status Stage TD\r
1545\r
1546Arguments:\r
1547\r
1548 HcDev - USB_HC_DEV\r
1549 DevAddr - Device address\r
1550 Endpoint - Endpoint number \r
1551 PktID - Packet ID\r
1552 bSlow - Full speed or low speed\r
1553 ppTD - TD_STRUCT to return\r
1554Returns:\r
1555\r
1556 EFI_OUT_OF_RESOURCES - Can't allocate memory\r
1557 EFI_SUCCESS - Success\r
1558\r
1559--*/\r
1560{\r
1561 TD_STRUCT *ptrTDStruct;\r
1562 EFI_STATUS Status;\r
1563\r
1564 Status = CreateTD (HcDev, &ptrTDStruct);\r
1565 if (EFI_ERROR (Status)) {\r
1566 return EFI_OUT_OF_RESOURCES;\r
1567 }\r
1568\r
1569 SetTDLinkPtr (ptrTDStruct, NULL);\r
1570\r
1571 //\r
1572 // Depth first fashion\r
1573 //\r
1574 SetTDLinkPtrDepthorBreadth (ptrTDStruct, TRUE);\r
1575\r
1576 //\r
1577 // initialize as the last TD in the QH context,\r
1578 // this field will be updated in the TD linkage process.\r
1579 //\r
1580 SetTDLinkPtrValidorInvalid (ptrTDStruct, FALSE);\r
1581\r
1582 //\r
1583 // Disable short packet detect\r
1584 //\r
1585 EnableorDisableTDShortPacket (ptrTDStruct, FALSE);\r
1586\r
1587 //\r
1588 // Max error counter is 3\r
1589 //\r
1590 SetTDControlErrorCounter (ptrTDStruct, 3);\r
1591\r
1592 //\r
1593 // set device speed attribute\r
1594 // (TRUE - Slow Device; FALSE - Full Speed Device)\r
1595 //\r
1596 SetTDLoworFullSpeedDevice (ptrTDStruct, bSlow);\r
1597\r
1598 //\r
1599 // Non isochronous transfer TD\r
1600 //\r
1601 SetTDControlIsochronousorNot (ptrTDStruct, FALSE);\r
1602\r
1603 //\r
1604 // Disable Interrupt On Complete\r
1605 // Disable IOC interrupt.\r
1606 //\r
1607 SetorClearTDControlIOC (ptrTDStruct, FALSE);\r
1608\r
1609 //\r
1610 // Set TD Active bit\r
1611 //\r
1612 SetTDStatusActiveorInactive (ptrTDStruct, TRUE);\r
1613\r
1614 SetTDTokenMaxLength (ptrTDStruct, 0);\r
1615\r
1616 SetTDTokenDataToggle1 (ptrTDStruct);\r
1617\r
1618 SetTDTokenEndPoint (ptrTDStruct, Endpoint);\r
1619\r
1620 SetTDTokenDeviceAddress (ptrTDStruct, DevAddr);\r
1621\r
1622 SetTDTokenPacketID (ptrTDStruct, PktID);\r
1623\r
1624 ptrTDStruct->pTDBuffer = NULL;\r
1625 ptrTDStruct->TDBufferLength = 0;\r
1626 SetTDDataBuffer (ptrTDStruct);\r
1627\r
1628 *ppTD = ptrTDStruct;\r
1629\r
1630 return EFI_SUCCESS;\r
1631}\r
1632\r
1633\r
1634VOID\r
1635SetTDLinkPtrValidorInvalid (\r
1636 IN TD_STRUCT *ptrTDStruct,\r
1637 IN BOOLEAN bValid\r
1638 )\r
1639/*++\r
1640\r
1641Routine Description:\r
1642\r
1643 Set TD Link Pointer Valid or Invalid\r
1644\r
1645Arguments:\r
1646\r
1647 ptrTDStruct - TD_STRUCT\r
1648 bValid - TRUE is valid FALSE is invalid\r
1649\r
1650Returns:\r
1651\r
1652 VOID\r
1653\r
1654--*/\r
1655{\r
1656 //\r
1657 // Valid means the link pointer is valid,\r
1658 // else, it's invalid.\r
1659 //\r
1660 ptrTDStruct->TDData.TDLinkPtrTerminate = (bValid ? 0 : 1);\r
1661}\r
1662\r
1663VOID\r
1664SetTDLinkPtrQHorTDSelect (\r
1665 IN TD_STRUCT *ptrTDStruct,\r
1666 IN BOOLEAN bQH\r
1667 )\r
1668/*++\r
1669\r
1670Routine Description:\r
1671\r
1672 Set TD Link Pointer QH or TD Select\r
1673\r
1674Arguments:\r
1675\r
1676 ptrTDStruct - TD_STRUCT\r
1677 bQH - TRUE is QH FALSE is TD\r
1678 \r
1679Returns:\r
1680\r
1681 VOID\r
1682\r
1683--*/\r
1684{\r
1685 //\r
1686 // Indicate whether the Link Pointer pointing to a QH or TD\r
1687 //\r
1688 ptrTDStruct->TDData.TDLinkPtrQSelect = (bQH ? 1 : 0);\r
1689}\r
1690\r
1691VOID\r
1692SetTDLinkPtrDepthorBreadth (\r
1693 IN TD_STRUCT *ptrTDStruct,\r
1694 IN BOOLEAN bDepth\r
1695 )\r
1696/*++\r
1697\r
1698Routine Description:\r
1699\r
1700 Set TD Link Pointer depth or bread priority\r
1701\r
1702Arguments:\r
1703\r
1704 ptrTDStruct - TD_STRUCT\r
1705 bDepth - TRUE is Depth FALSE is Breadth\r
1706 \r
1707Returns:\r
1708\r
1709 VOID\r
1710\r
1711--*/\r
1712{\r
1713 //\r
1714 // If TRUE, indicating the host controller should process in depth first\r
1715 // fashion,\r
1716 // else, the host controller should process in breadth first fashion\r
1717 //\r
1718 ptrTDStruct->TDData.TDLinkPtrDepthSelect = (bDepth ? 1 : 0);\r
1719}\r
1720\r
1721VOID\r
1722SetTDLinkPtr (\r
1723 IN TD_STRUCT *ptrTDStruct,\r
1724 IN VOID *ptrNext\r
1725 )\r
1726/*++\r
1727\r
1728Routine Description:\r
1729\r
1730 Set TD Link Pointer\r
1731\r
1732Arguments:\r
1733\r
1734 ptrTDStruct - TD_STRUCT\r
1735 ptrNext - Pointer to set\r
1736 \r
1737Returns:\r
1738\r
1739 VOID\r
1740\r
1741--*/\r
1742{\r
1743 //\r
1744 // Set TD Link Pointer. Since QH,TD align on 16-byte boundaries,\r
1745 // only the highest 28 bits are valid. (if take 32bit address as an example)\r
1746 //\r
1747 ptrTDStruct->TDData.TDLinkPtr = (UINT32) ((UINTN) ptrNext >> 4);\r
1748}\r
1749\r
1750VOID *\r
1751GetTDLinkPtr (\r
1752 IN TD_STRUCT *ptrTDStruct\r
1753 )\r
1754/*++\r
1755\r
1756Routine Description:\r
1757\r
1758 Get TD Link Pointer\r
1759\r
1760Arguments:\r
1761\r
1762 ptrTDStruct - TD_STRUCT\r
1763 \r
1764Returns:\r
1765\r
1766 Pointer to get\r
1767\r
1768--*/\r
1769{\r
1770 //\r
1771 // Get TD Link Pointer. Restore it back to 32bit\r
1772 // (if take 32bit address as an example)\r
1773 //\r
1774 return (VOID *) ((UINTN) (ptrTDStruct->TDData.TDLinkPtr << 4));\r
1775}\r
1776\r
1cc8ee78 1777STATIC\r
878ddf1f 1778BOOLEAN\r
1779IsTDLinkPtrQHOrTD (\r
1780 IN TD_STRUCT *ptrTDStruct\r
1781 )\r
1782/*++\r
1783\r
1784Routine Description:\r
1785\r
1786 Is TD Link Pointer is QH Or TD\r
1787\r
1788Arguments:\r
1789\r
1790 ptrTDStruct - TODO: add argument description\r
1791\r
1792Returns:\r
1793\r
1794 TRUE - QH\r
1795 FALSE - TD \r
1796\r
1797--*/\r
1798{\r
1799 //\r
1800 // Get the information about whether the Link Pointer field pointing to\r
1801 // a QH or a TD.\r
1802 //\r
1803 return (BOOLEAN) (ptrTDStruct->TDData.TDLinkPtrQSelect);\r
1804}\r
1805\r
1806VOID\r
1807EnableorDisableTDShortPacket (\r
1808 IN TD_STRUCT *ptrTDStruct,\r
1809 IN BOOLEAN bEnable\r
1810 )\r
1811/*++\r
1812\r
1813Routine Description:\r
1814\r
1815 Enable or Disable TD ShortPacket\r
1816\r
1817Arguments:\r
1818\r
1819 ptrTDStruct - TD_STRUCT\r
1820 bEnable - TRUE is Enanble FALSE is Disable\r
1821\r
1822Returns:\r
1823\r
1824 VOID\r
1825\r
1826--*/\r
1827{\r
1828 //\r
1829 // TRUE means enable short packet detection mechanism.\r
1830 //\r
1831 ptrTDStruct->TDData.TDStatusSPD = (bEnable ? 1 : 0);\r
1832}\r
1833\r
1834VOID\r
1835SetTDControlErrorCounter (\r
1836 IN TD_STRUCT *ptrTDStruct,\r
1837 IN UINT8 nMaxErrors\r
1838 )\r
1839/*++\r
1840\r
1841Routine Description:\r
1842\r
1843 Set TD Control ErrorCounter\r
1844\r
1845Arguments:\r
1846\r
1847 ptrTDStruct - TD_STRUCT\r
1848 nMaxErrors - Error counter number\r
1849 \r
1850Returns:\r
1851\r
1852 VOID\r
1853\r
1854--*/\r
1855{\r
1856 //\r
1857 // valid value of nMaxErrors is 0,1,2,3\r
1858 //\r
1859 if (nMaxErrors > 3) {\r
1860 nMaxErrors = 3;\r
1861 }\r
1862\r
1863 ptrTDStruct->TDData.TDStatusErr = nMaxErrors;\r
1864}\r
1865\r
1866\r
1867VOID\r
1868SetTDLoworFullSpeedDevice (\r
1869 IN TD_STRUCT *ptrTDStruct,\r
1870 IN BOOLEAN bLowSpeedDevice\r
1871 )\r
1872{\r
1873 //\r
1874 // TRUE means the TD is targeting at a Low-speed device\r
1875 //\r
1876 ptrTDStruct->TDData.TDStatusLS = (bLowSpeedDevice ? 1 : 0);\r
1877}\r
1878\r
1879VOID\r
1880SetTDControlIsochronousorNot (\r
1881 IN TD_STRUCT *ptrTDStruct,\r
1882 IN BOOLEAN IsIsochronous\r
1883 )\r
1884{\r
1885 //\r
1886 // TRUE means the TD belongs to Isochronous transfer type.\r
1887 //\r
1888 ptrTDStruct->TDData.TDStatusIOS = (IsIsochronous ? 1 : 0);\r
1889}\r
1890\r
1891VOID\r
1892SetorClearTDControlIOC (\r
1893 IN TD_STRUCT *ptrTDStruct,\r
1894 IN BOOLEAN IsSet\r
1895 )\r
1896{\r
1897 //\r
1898 // If this bit is set, it indicates that the host controller should issue\r
1899 // an interrupt on completion of the frame in which this TD is executed.\r
1900 //\r
1901 ptrTDStruct->TDData.TDStatusIOC = IsSet ? 1 : 0;\r
1902}\r
1903\r
1904VOID\r
1905SetTDStatusActiveorInactive (\r
1906 IN TD_STRUCT *ptrTDStruct,\r
1907 IN BOOLEAN IsActive\r
1908 )\r
1909{\r
1910 //\r
1911 // If this bit is set, it indicates that the TD is active and can be\r
1912 // executed.\r
1913 //\r
1914 if (IsActive) {\r
1915 ptrTDStruct->TDData.TDStatus |= 0x80;\r
1916 } else {\r
1917 ptrTDStruct->TDData.TDStatus &= 0x7F;\r
1918 }\r
1919}\r
1920\r
1921UINT16\r
1922SetTDTokenMaxLength (\r
1923 IN TD_STRUCT *ptrTDStruct,\r
1924 IN UINT16 MaximumLength\r
1925 )\r
1926{\r
1927 //\r
1928 // Specifies the maximum number of data bytes allowed for the transfer.\r
1929 // the legal value extent is 0 ~ 0x500.\r
1930 //\r
1931 if (MaximumLength > 0x500) {\r
1932 MaximumLength = 0x500;\r
1933 }\r
1934 ptrTDStruct->TDData.TDTokenMaxLen = MaximumLength - 1;\r
1935\r
1936 return MaximumLength;\r
1937}\r
1938\r
1939VOID\r
1940SetTDTokenDataToggle1 (\r
1941 IN TD_STRUCT *ptrTDStruct\r
1942 )\r
1943{\r
1944 //\r
1945 // Set the data toggle bit to DATA1\r
1946 //\r
1947 ptrTDStruct->TDData.TDTokenDataToggle = 1;\r
1948}\r
1949\r
1950VOID\r
1951SetTDTokenDataToggle0 (\r
1952 IN TD_STRUCT *ptrTDStruct\r
1953 )\r
1954{\r
1955 //\r
1956 // Set the data toggle bit to DATA0\r
1957 //\r
1958 ptrTDStruct->TDData.TDTokenDataToggle = 0;\r
1959}\r
1960\r
1961UINT8\r
1962GetTDTokenDataToggle (\r
1963 IN TD_STRUCT *ptrTDStruct\r
1964 )\r
1965{\r
1966 //\r
1967 // Get the data toggle value.\r
1968 //\r
1969 return (UINT8) (ptrTDStruct->TDData.TDTokenDataToggle);\r
1970}\r
1971\r
1972VOID\r
1973SetTDTokenEndPoint (\r
1974 IN TD_STRUCT *ptrTDStruct,\r
1975 IN UINTN EndPoint\r
1976 )\r
1977{\r
1978 //\r
1979 // Set EndPoint Number the TD is targeting at.\r
1980 //\r
1981 ptrTDStruct->TDData.TDTokenEndPt = (UINT8) EndPoint;\r
1982}\r
1983\r
1984VOID\r
1985SetTDTokenDeviceAddress (\r
1986 IN TD_STRUCT *ptrTDStruct,\r
1987 IN UINTN DeviceAddress\r
1988 )\r
1989{\r
1990 //\r
1991 // Set Device Address the TD is targeting at.\r
1992 //\r
1993 ptrTDStruct->TDData.TDTokenDevAddr = (UINT8) DeviceAddress;\r
1994}\r
1995\r
1996VOID\r
1997SetTDTokenPacketID (\r
1998 IN TD_STRUCT *ptrTDStruct,\r
1999 IN UINT8 PID\r
2000 )\r
2001{\r
2002 //\r
2003 // Set the Packet Identification to be used for this transaction.\r
2004 //\r
2005 ptrTDStruct->TDData.TDTokenPID = PID;\r
2006}\r
2007\r
2008VOID\r
2009SetTDDataBuffer (\r
2010 IN TD_STRUCT *ptrTDStruct\r
2011 )\r
2012{\r
2013 //\r
2014 // Set the beginning address of the data buffer that will be used\r
2015 // during the transaction.\r
2016 //\r
2017 ptrTDStruct->TDData.TDBufferPtr = (UINT32) ((UINTN) (ptrTDStruct->pTDBuffer));\r
2018}\r
2019\r
2020BOOLEAN\r
2021IsTDStatusActive (\r
2022 IN TD_STRUCT *ptrTDStruct\r
2023 )\r
2024{\r
2025 UINT8 TDStatus;\r
2026\r
2027 //\r
2028 // Detect whether the TD is active.\r
2029 //\r
2030 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2031 return (BOOLEAN) (TDStatus & 0x80);\r
2032}\r
2033\r
2034BOOLEAN\r
2035IsTDStatusStalled (\r
2036 IN TD_STRUCT *ptrTDStruct\r
2037 )\r
2038{\r
2039 UINT8 TDStatus;\r
2040\r
2041 //\r
2042 // Detect whether the device/endpoint addressed by this TD is stalled.\r
2043 //\r
2044 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2045 return (BOOLEAN) (TDStatus & 0x40);\r
2046}\r
2047\r
2048BOOLEAN\r
2049IsTDStatusBufferError (\r
2050 IN TD_STRUCT *ptrTDStruct\r
2051 )\r
2052{\r
2053 UINT8 TDStatus;\r
2054 //\r
2055 // Detect whether Data Buffer Error is happened.\r
2056 //\r
2057 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2058 return (BOOLEAN) (TDStatus & 0x20);\r
2059}\r
2060\r
2061BOOLEAN\r
2062IsTDStatusBabbleError (\r
2063 IN TD_STRUCT *ptrTDStruct\r
2064 )\r
2065{\r
2066 UINT8 TDStatus;\r
2067\r
2068 //\r
2069 // Detect whether Babble Error is happened.\r
2070 //\r
2071 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2072 return (BOOLEAN) (TDStatus & 0x10);\r
2073}\r
2074\r
2075BOOLEAN\r
2076IsTDStatusNAKReceived (\r
2077 IN TD_STRUCT *ptrTDStruct\r
2078 )\r
2079{\r
2080 UINT8 TDStatus;\r
2081\r
2082 //\r
2083 // Detect whether NAK is received.\r
2084 //\r
2085 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2086 return (BOOLEAN) (TDStatus & 0x08);\r
2087}\r
2088\r
2089BOOLEAN\r
2090IsTDStatusCRCTimeOutError (\r
2091 IN TD_STRUCT *ptrTDStruct\r
2092 )\r
2093{\r
2094 UINT8 TDStatus;\r
2095\r
2096 //\r
2097 // Detect whether CRC/Time Out Error is encountered.\r
2098 //\r
2099 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2100 return (BOOLEAN) (TDStatus & 0x04);\r
2101}\r
2102\r
2103BOOLEAN\r
2104IsTDStatusBitStuffError (\r
2105 IN TD_STRUCT *ptrTDStruct\r
2106 )\r
2107{\r
2108 UINT8 TDStatus;\r
2109\r
2110 //\r
2111 // Detect whether Bitstuff Error is received.\r
2112 //\r
2113 TDStatus = (UINT8) (ptrTDStruct->TDData.TDStatus);\r
2114 return (BOOLEAN) (TDStatus & 0x02);\r
2115}\r
2116\r
2117UINT16\r
2118GetTDStatusActualLength (\r
2119 IN TD_STRUCT *ptrTDStruct\r
2120 )\r
2121{\r
2122 //\r
2123 // Retrieve the actual number of bytes that were tansferred.\r
2124 // the value is encoded as n-1. so return the decoded value.\r
2125 //\r
2126 return (UINT16) ((ptrTDStruct->TDData.TDStatusActualLength) + 1);\r
2127}\r
2128\r
2129UINT16\r
2130GetTDTokenMaxLength (\r
2131 IN TD_STRUCT *ptrTDStruct\r
2132 )\r
2133{\r
2134 //\r
2135 // Retrieve the maximum number of data bytes allowed for the trnasfer.\r
2136 //\r
2137 return (UINT16) ((ptrTDStruct->TDData.TDTokenMaxLen) + 1);\r
2138}\r
2139\r
2140UINT8\r
2141GetTDTokenEndPoint (\r
2142 IN TD_STRUCT *ptrTDStruct\r
2143 )\r
2144{\r
2145 //\r
2146 // Retrieve the endpoint number the transaction is targeting at.\r
2147 //\r
2148 return (UINT8) (ptrTDStruct->TDData.TDTokenEndPt);\r
2149}\r
2150\r
2151UINT8\r
2152GetTDTokenDeviceAddress (\r
2153 IN TD_STRUCT *ptrTDStruct\r
2154 )\r
2155{\r
2156 //\r
2157 // Retrieve the device address the transaction is targeting at.\r
2158 //\r
2159 return (UINT8) (ptrTDStruct->TDData.TDTokenDevAddr);\r
2160}\r
2161\r
2162UINT8\r
2163GetTDTokenPacketID (\r
2164 IN TD_STRUCT *ptrTDStruct\r
2165 )\r
2166{\r
2167 //\r
2168 // Retrieve the Packet Identification information.\r
2169 //\r
2170 return (UINT8) (ptrTDStruct->TDData.TDTokenPID);\r
2171}\r
2172\r
2173UINT8 *\r
2174GetTDDataBuffer (\r
2175 IN TD_STRUCT *ptrTDStruct\r
2176 )\r
2177{\r
2178 //\r
2179 // Retrieve the beginning address of the data buffer\r
2180 // that involved in this transaction.\r
2181 //\r
2182 return ptrTDStruct->pTDBuffer;\r
2183}\r
2184\r
2185BOOLEAN\r
2186GetTDLinkPtrValidorInvalid (\r
2187 IN TD_STRUCT *ptrTDStruct\r
2188 )\r
2189{\r
2190 //\r
2191 // Retrieve the information of whether the Link Pointer field\r
2192 // is valid or not.\r
2193 //\r
2194 if (ptrTDStruct->TDData.TDLinkPtrTerminate) {\r
2195 return FALSE;\r
2196 } else {\r
2197 return TRUE;\r
2198 }\r
2199\r
2200}\r
2201\r
2202UINTN\r
2203CountTDsNumber (\r
2204 IN TD_STRUCT *PtrFirstTD\r
2205 )\r
2206{\r
2207 UINTN Number;\r
2208 TD_STRUCT *ptr;\r
2209 //\r
2210 // Count the queued TDs number.\r
2211 //\r
2212 Number = 0;\r
2213 ptr = PtrFirstTD;\r
2214 while (ptr) {\r
2215 ptr = (TD_STRUCT *) ptr->ptrNextTD;\r
2216 Number++;\r
2217 }\r
2218\r
2219 return Number;\r
2220}\r
2221\r
2222\r
2223\r
2224VOID\r
2225LinkTDToQH (\r
2226 IN QH_STRUCT *PtrQH,\r
2227 IN TD_STRUCT *PtrTD\r
2228 )\r
2229/*++\r
2230\r
2231Routine Description:\r
2232\r
2233 Link TD To QH\r
2234\r
2235Arguments:\r
2236\r
2237 PtrQH - QH_STRUCT\r
2238 PtrTD - TD_STRUCT\r
2239Returns:\r
2240\r
2241 VOID\r
2242\r
2243--*/\r
2244{\r
2245 if (PtrQH == NULL || PtrTD == NULL) {\r
2246 return ;\r
2247 }\r
2248 //\r
2249 // Validate QH Vertical Ptr field\r
2250 //\r
2251 SetQHVerticalValidorInvalid (PtrQH, TRUE);\r
2252\r
2253 //\r
2254 // Vertical Ptr pointing to TD structure\r
2255 //\r
2256 SetQHVerticalQHorTDSelect (PtrQH, FALSE);\r
2257\r
2258 SetQHVerticalLinkPtr (PtrQH, (VOID *) PtrTD);\r
2259\r
2260 PtrQH->ptrDown = (VOID *) PtrTD;\r
2261}\r
2262\r
2263VOID\r
2264LinkTDToTD (\r
2265 IN TD_STRUCT *ptrPreTD,\r
2266 IN TD_STRUCT *PtrTD\r
2267 )\r
2268/*++\r
2269\r
2270Routine Description:\r
2271\r
2272 Link TD To TD\r
2273\r
2274Arguments:\r
2275\r
2276 ptrPreTD - Previous TD_STRUCT to be linked\r
2277 PtrTD - TD_STRUCT to link\r
2278Returns:\r
2279\r
2280 VOID\r
2281\r
2282--*/\r
2283{\r
2284 if (ptrPreTD == NULL || PtrTD == NULL) {\r
2285 return ;\r
2286 }\r
2287 //\r
2288 // Depth first fashion\r
2289 //\r
2290 SetTDLinkPtrDepthorBreadth (ptrPreTD, TRUE);\r
2291\r
2292 //\r
2293 // Link pointer pointing to TD struct\r
2294 //\r
2295 SetTDLinkPtrQHorTDSelect (ptrPreTD, FALSE);\r
2296\r
2297 //\r
2298 // Validate the link pointer valid bit\r
2299 //\r
2300 SetTDLinkPtrValidorInvalid (ptrPreTD, TRUE);\r
2301\r
2302 SetTDLinkPtr (ptrPreTD, PtrTD);\r
2303\r
2304 ptrPreTD->ptrNextTD = (VOID *) PtrTD;\r
2305}\r
2306//\r
2307// Transfer Schedule related Helper Functions\r
2308//\r
2309VOID\r
2310SetorClearCurFrameListTerminate (\r
2311 IN FRAMELIST_ENTRY *pCurEntry,\r
2312 IN BOOLEAN IsSet\r
2313 )\r
2314{\r
2315 //\r
2316 // If TRUE, empty the frame. If FALSE, indicate the Pointer field is valid.\r
2317 //\r
2318 pCurEntry->FrameListPtrTerminate = (IsSet ? 1 : 0);\r
2319}\r
2320\r
2321VOID\r
2322SetCurFrameListQHorTD (\r
2323 IN FRAMELIST_ENTRY *pCurEntry,\r
2324 IN BOOLEAN IsQH\r
2325 )\r
2326{\r
2327 //\r
2328 // This bit indicates to the hardware whether the item referenced by the\r
2329 // link pointer is a TD or a QH.\r
2330 //\r
2331 pCurEntry->FrameListPtrQSelect = (IsQH ? 1 : 0);\r
2332}\r
2333\r
1cc8ee78 2334STATIC\r
878ddf1f 2335BOOLEAN\r
2336IsCurFrameListQHorTD (\r
2337 IN FRAMELIST_ENTRY *pCurEntry\r
2338 )\r
2339{\r
2340 //\r
2341 // TRUE is QH\r
2342 // FALSE is TD\r
2343 //\r
2344 return (BOOLEAN) (pCurEntry->FrameListPtrQSelect);\r
2345}\r
2346\r
2347BOOLEAN\r
2348GetCurFrameListTerminate (\r
2349 IN FRAMELIST_ENTRY *pCurEntry\r
2350 )\r
2351{\r
2352 //\r
2353 // TRUE means the frame is empty,\r
2354 // FALSE means the link pointer field is valid.\r
2355 //\r
2356 return (BOOLEAN) (pCurEntry->FrameListPtrTerminate);\r
2357}\r
2358\r
2359VOID\r
2360SetCurFrameListPointer (\r
2361 IN FRAMELIST_ENTRY *pCurEntry,\r
2362 IN UINT8 *ptr\r
2363 )\r
2364{\r
2365 //\r
2366 // Set the pointer field of the frame.\r
2367 //\r
2368 pCurEntry->FrameListPtr = (UINT32) ((UINTN) ptr >> 4);\r
2369}\r
2370\r
2371VOID *\r
2372GetCurFrameListPointer (\r
2373 IN FRAMELIST_ENTRY *pCurEntry\r
2374 )\r
2375{\r
2376 //\r
2377 // Get the link pointer of the frame.\r
2378 //\r
2379 return (VOID *) ((UINTN) (pCurEntry->FrameListPtr << 4));\r
2380\r
2381}\r
2382\r
2383VOID\r
2384LinkQHToFrameList (\r
2385 IN FRAMELIST_ENTRY *pEntry,\r
2386 IN UINT16 FrameListIndex,\r
2387 IN QH_STRUCT *PtrQH\r
2388 )\r
2389/*++\r
2390\r
2391Routine Description:\r
2392\r
2393 Link QH To Frame List\r
2394\r
2395Arguments:\r
2396\r
2397 pEntry - FRAMELIST_ENTRY\r
2398 FrameListIndex - Frame List Index\r
2399 PtrQH - QH to link \r
2400Returns:\r
2401\r
2402 VOID\r
2403\r
2404--*/\r
2405{\r
2406 FRAMELIST_ENTRY *pCurFrame;\r
2407 QH_STRUCT *TempQH;\r
2408 QH_STRUCT *NextTempQH;\r
2409 TD_STRUCT *TempTD;\r
2410 BOOLEAN LINK;\r
2411\r
2412 //\r
2413 // Get frame list entry that the link process will begin from.\r
2414 //\r
2415 pCurFrame = pEntry + FrameListIndex;\r
2416\r
2417 //\r
2418 // if current frame is empty\r
2419 // then link the specified QH directly to the Frame List.\r
2420 //\r
2421 if (GetCurFrameListTerminate (pCurFrame)) {\r
2422 \r
2423 //\r
2424 // Link new QH to the frame list entry.\r
2425 //\r
2426 SetCurFrameListQHorTD (pCurFrame, TRUE);\r
2427\r
2428 SetCurFrameListPointer (pCurFrame, (UINT8 *) PtrQH);\r
2429\r
2430 //\r
2431 // clear T bit in the Frame List, indicating that the frame list entry\r
2432 // is no longer empty.\r
2433 //\r
2434 SetorClearCurFrameListTerminate (pCurFrame, FALSE);\r
2435\r
2436 return ;\r
2437\r
2438 } else {\r
2439 //\r
2440 // current frame list has link pointer\r
2441 //\r
2442 if (!IsCurFrameListQHorTD (pCurFrame)) {\r
2443 //\r
2444 // a TD is linked to the framelist entry\r
2445 //\r
2446 TempTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2447\r
2448 while (GetTDLinkPtrValidorInvalid (TempTD)) {\r
2449\r
2450 if (IsTDLinkPtrQHOrTD (TempTD)) {\r
2451 //\r
2452 // QH linked next to the TD\r
2453 //\r
2454 break;\r
2455 }\r
2456\r
2457 TempTD = (TD_STRUCT *) GetTDLinkPtr (TempTD);\r
2458 }\r
2459 \r
2460 //\r
2461 // either no ptr linked next to the TD or QH is linked next to the TD\r
2462 //\r
2463 if (!GetTDLinkPtrValidorInvalid (TempTD)) {\r
2464 \r
2465 //\r
2466 // no ptr linked next to the TD\r
2467 //\r
2468 TempTD->ptrNextQH = PtrQH;\r
2469 SetTDLinkPtrQHorTDSelect (TempTD, TRUE);\r
2470 SetTDLinkPtr (TempTD, PtrQH);\r
2471 SetTDLinkPtrValidorInvalid (TempTD, TRUE);\r
2472 return ;\r
2473\r
2474 } else {\r
2475 //\r
2476 // QH is linked next to the TD\r
2477 //\r
2478 TempQH = (QH_STRUCT *) GetTDLinkPtr (TempTD);\r
2479 }\r
2480 } else {\r
2481 //\r
2482 // a QH is linked to the framelist entry\r
2483 //\r
2484 TempQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2485 }\r
2486 \r
2487 //\r
2488 // Set up Flag\r
2489 //\r
2490 LINK = TRUE;\r
2491\r
2492 //\r
2493 // Avoid the same qh repeated linking in one frame entry\r
2494 //\r
2495 if (TempQH == PtrQH) {\r
2496 LINK = FALSE;\r
2497 return ;\r
2498 }\r
2499 //\r
2500 // if current QH has next QH connected\r
2501 //\r
2502 while (GetQHHorizontalValidorInvalid (TempQH)) {\r
2503 //\r
2504 // Get next QH pointer\r
2505 //\r
2506 NextTempQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (TempQH);\r
2507\r
2508 //\r
2509 // Bulk transfer qh may be self-linked,\r
2510 // so, the code below is to aVOID dead-loop when meeting self-linked qh\r
2511 //\r
2512 if (NextTempQH == TempQH) {\r
2513 LINK = FALSE;\r
2514 break;\r
2515 }\r
2516\r
2517 TempQH = NextTempQH;\r
2518\r
2519 //\r
2520 // Avoid the same qh repeated linking in one frame entry\r
2521 //\r
2522 if (TempQH == PtrQH) {\r
2523 LINK = FALSE;\r
2524 }\r
2525 }\r
2526\r
2527 if (LINK) {\r
2528 TempQH->ptrNext = PtrQH;\r
2529 SetQHHorizontalQHorTDSelect (TempQH, TRUE);\r
2530 SetQHHorizontalLinkPtr (TempQH, PtrQH);\r
2531 SetQHHorizontalValidorInvalid (TempQH, TRUE);\r
2532 }\r
2533\r
2534 return ;\r
2535 }\r
2536}\r
2537\r
2538EFI_STATUS\r
2539ExecuteControlTransfer (\r
2540 IN USB_HC_DEV *HcDev,\r
2541 IN TD_STRUCT *PtrTD,\r
2542 IN UINT32 wIndex,\r
2543 OUT UINTN *ActualLen,\r
2544 IN UINTN TimeOut,\r
2545 OUT UINT32 *TransferResult\r
2546 )\r
2547/*++\r
2548\r
2549Routine Description:\r
2550\r
2551 Execute Control Transfer\r
2552\r
2553Arguments:\r
2554\r
2555 HcDev - USB_HC_DEV\r
2556 PtrTD - TD_STRUCT\r
2557 wIndex - No use\r
2558 ActualLen - Actual transfered Len \r
2559 TimeOut - TimeOut value in milliseconds\r
2560 TransferResult - Transfer result\r
2561Returns:\r
2562\r
2563 EFI_SUCCESS - Sucess\r
2564 EFI_DEVICE_ERROR - Error\r
2565 \r
2566\r
2567--*/\r
2568{\r
2569 UINTN ErrTDPos;\r
2570 UINTN Delay;\r
2571 UINTN RequiredLen;\r
2572 BOOLEAN TransferFinished;\r
2573\r
2574 ErrTDPos = 0;\r
2575 *TransferResult = EFI_USB_NOERROR;\r
2576 RequiredLen = *ActualLen;\r
2577 *ActualLen = 0;\r
2578\r
2579 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
2580\r
2581 do {\r
2582 TransferFinished = CheckTDsResults (\r
2583 PtrTD,\r
2584 RequiredLen,\r
2585 TransferResult,\r
2586 &ErrTDPos,\r
2587 ActualLen\r
2588 );\r
2589\r
2590 if (TransferFinished) {\r
2591 break;\r
2592 }\r
2593 \r
2594 //\r
2595 // TD is inactive, which means the control transfer is end.\r
2596 //\r
2597 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
2598 break;\r
2599 } \r
2600\r
2601 gBS->Stall (50);\r
2602\r
2603 } while (Delay--);\r
2604\r
2605 if (*TransferResult != EFI_USB_NOERROR) {\r
2606 return EFI_DEVICE_ERROR;\r
2607 }\r
2608\r
2609 return EFI_SUCCESS;\r
2610}\r
2611\r
2612EFI_STATUS\r
2613ExecBulkorSyncInterruptTransfer (\r
2614 IN USB_HC_DEV *HcDev,\r
2615 IN TD_STRUCT *PtrTD,\r
2616 IN UINT32 wIndex,\r
2617 OUT UINTN *ActualLen,\r
2618 OUT UINT8 *DataToggle,\r
2619 IN UINTN TimeOut,\r
2620 OUT UINT32 *TransferResult\r
2621 )\r
2622/*++\r
2623\r
2624Routine Description:\r
2625\r
2626 Execute Bulk or SyncInterrupt Transfer\r
2627\r
2628Arguments:\r
2629\r
2630 HcDev - USB_HC_DEV\r
2631 PtrTD - TD_STRUCT\r
2632 wIndex - No use\r
2633 ActualLen - Actual transfered Len \r
2634 DataToggle - Data Toggle\r
2635 TimeOut - TimeOut value in milliseconds\r
2636 TransferResult - Transfer result\r
2637Returns:\r
2638\r
2639 EFI_SUCCESS - Sucess\r
2640 EFI_DEVICE_ERROR - Error\r
2641--*/\r
2642{\r
2643 UINTN ErrTDPos;\r
2644 UINTN ScrollNum;\r
2645 UINTN Delay;\r
2646 UINTN RequiredLen;\r
2647 BOOLEAN TransferFinished;\r
2648\r
2649 ErrTDPos = 0;\r
2650 *TransferResult = EFI_USB_NOERROR;\r
2651 RequiredLen = *ActualLen;\r
2652 *ActualLen = 0;\r
2653\r
2654 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
2655\r
2656 do {\r
2657\r
2658 TransferFinished = CheckTDsResults (\r
2659 PtrTD,\r
2660 RequiredLen,\r
2661 TransferResult,\r
2662 &ErrTDPos,\r
2663 ActualLen\r
2664 );\r
2665 \r
2666 if (TransferFinished) {\r
2667 break;\r
2668 }\r
2669 \r
2670 //\r
2671 // TD is inactive, which means bulk or interrupt transfer's end.\r
2672 // \r
2673 if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {\r
2674 break;\r
2675 }\r
2676\r
2677 gBS->Stall (50);\r
2678\r
2679 } while (Delay--);\r
2680\r
2681 //\r
2682 // has error\r
2683 //\r
2684 if (*TransferResult != EFI_USB_NOERROR) {\r
2685 \r
2686 //\r
2687 // scroll the Data Toggle back to the last success TD\r
2688 //\r
2689 ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;\r
2690 if (ScrollNum & 0x1) {\r
2691 *DataToggle ^= 1;\r
2692 }\r
2693\r
2694 return EFI_DEVICE_ERROR;\r
2695 }\r
2696\r
2697 return EFI_SUCCESS;\r
2698}\r
2699\r
2700VOID\r
2701DelLinkSingleQH (\r
2702 IN USB_HC_DEV *HcDev,\r
2703 IN QH_STRUCT *PtrQH,\r
2704 IN UINT16 FrameListIndex,\r
2705 IN BOOLEAN SearchOther,\r
2706 IN BOOLEAN Delete\r
2707 )\r
2708/*++\r
2709\r
2710Routine Description:\r
2711\r
2712 Unlink from frame list and delete single QH\r
2713Arguments:\r
2714\r
2715 HcDev - USB_HC_DEV\r
2716 PtrQH - QH_STRUCT\r
2717 FrameListIndex - Frame List Index\r
2718 SearchOther - Search Other QH\r
2719 Delete - TRUE is to delete the QH\r
2720Returns:\r
2721 VOID\r
2722--*/\r
2723{\r
2724 FRAMELIST_ENTRY *pCurFrame;\r
2725 UINTN Index;\r
2726 UINTN BeginFrame;\r
2727 UINTN EndFrame;\r
2728 QH_STRUCT *CurrentQH;\r
2729 QH_STRUCT *NextQH;\r
2730 TD_STRUCT *CurrentTD;\r
2731 VOID *PtrPreQH;\r
2732 BOOLEAN Found;\r
2733\r
2734 NextQH = NULL;\r
2735 PtrPreQH = NULL;\r
2736 Found = FALSE;\r
2737\r
2738 if (PtrQH == NULL) {\r
2739 return ;\r
2740 }\r
2741\r
2742 if (SearchOther) {\r
2743 BeginFrame = 0;\r
2744 EndFrame = 1024;\r
2745 } else {\r
2746 BeginFrame = FrameListIndex;\r
2747 EndFrame = FrameListIndex + 1;\r
2748 }\r
2749\r
2750 for (Index = BeginFrame; Index < EndFrame; Index++) {\r
2751\r
2752 pCurFrame = HcDev->FrameListEntry + (Index & 0x3FF);\r
2753\r
2754 if (GetCurFrameListTerminate (pCurFrame)) {\r
2755 //\r
2756 // current frame list is empty,search next frame list entry\r
2757 //\r
2758 continue;\r
2759 }\r
2760\r
2761 if (!IsCurFrameListQHorTD (pCurFrame)) {\r
2762 //\r
2763 // TD linked to current framelist\r
2764 //\r
2765 CurrentTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2766\r
2767 while (GetTDLinkPtrValidorInvalid (CurrentTD)) {\r
2768\r
2769 if (IsTDLinkPtrQHOrTD (CurrentTD)) {\r
2770 //\r
2771 // QH linked next to the TD,break while ()\r
2772 //\r
2773 break;\r
2774 }\r
2775\r
2776 CurrentTD = (TD_STRUCT *) GetTDLinkPtr (CurrentTD);\r
2777 }\r
2778\r
2779 if (!GetTDLinkPtrValidorInvalid (CurrentTD)) {\r
2780 //\r
2781 // no QH linked next to the last TD,\r
2782 // search next frame list\r
2783 //\r
2784 continue;\r
2785 }\r
2786 \r
2787 //\r
2788 // a QH linked next to the last TD\r
2789 //\r
2790 CurrentQH = (QH_STRUCT *) GetTDLinkPtr (CurrentTD);\r
2791\r
2792 PtrPreQH = CurrentTD;\r
2793\r
2794 } else {\r
2795 //\r
2796 // a QH linked to current framelist\r
2797 //\r
2798 CurrentQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);\r
2799\r
2800 PtrPreQH = NULL;\r
2801 }\r
2802\r
2803 if (CurrentQH == PtrQH) {\r
2804\r
2805 if (GetQHHorizontalValidorInvalid (PtrQH)) {\r
2806 //\r
2807 // there is QH connected after the QH found\r
2808 //\r
2809 //\r
2810 // retrieve nex qh pointer of the qh found.\r
2811 //\r
2812 NextQH = GetQHHorizontalLinkPtr (PtrQH);\r
2813 } else {\r
2814 NextQH = NULL;\r
2815 }\r
2816\r
2817 if (PtrPreQH) {\r
2818 //\r
2819 // QH linked to a TD struct\r
2820 //\r
2821 CurrentTD = (TD_STRUCT *) PtrPreQH;\r
2822\r
2823 SetTDLinkPtrValidorInvalid (CurrentTD, (BOOLEAN) ((NextQH == NULL) ? FALSE : TRUE));\r
2824 SetTDLinkPtr (CurrentTD, NextQH);\r
2825 CurrentTD->ptrNextQH = NextQH;\r
2826\r
2827 } else {\r
2828 //\r
2829 // QH linked directly to current framelist entry\r
2830 //\r
2831 SetorClearCurFrameListTerminate (pCurFrame, (BOOLEAN) ((NextQH == NULL) ? TRUE : FALSE));\r
2832 SetCurFrameListPointer (pCurFrame, (UINT8 *) NextQH);\r
2833 }\r
2834\r
2835 Found = TRUE;\r
2836 //\r
2837 // search next framelist entry\r
2838 //\r
2839 continue;\r
2840 }\r
2841\r
2842 while (GetQHHorizontalValidorInvalid (CurrentQH)) {\r
2843\r
2844 PtrPreQH = CurrentQH;\r
2845 //\r
2846 // Get next horizontal linked QH\r
2847 //\r
2848 CurrentQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (CurrentQH);\r
2849 //\r
2850 // the qh is found\r
2851 //\r
2852 if (CurrentQH == PtrQH) {\r
2853 break;\r
2854 }\r
2855 }\r
2856 \r
2857 //\r
2858 // search next frame list entry\r
2859 //\r
2860 if (CurrentQH != PtrQH) {\r
2861 //\r
2862 // Not find the QH\r
2863 //\r
2864 continue;\r
2865 }\r
2866 //\r
2867 // find the specified qh, then delink it from\r
2868 // the horizontal QH list in the frame entry.\r
2869 //\r
2870 \r
2871 if (GetQHHorizontalValidorInvalid (PtrQH)) {\r
2872 //\r
2873 // there is QH connected after the QH found\r
2874 //\r
2875 //\r
2876 // retrieve nex qh pointer of the qh found.\r
2877 //\r
2878 NextQH = GetQHHorizontalLinkPtr (PtrQH);\r
2879\r
2880 } else {\r
2881 //\r
2882 // NO QH connected after the QH found\r
2883 //\r
2884 NextQH = NULL;\r
2885 //\r
2886 // NULL the previous QH's link ptr and set Terminate field.\r
2887 //\r
2888 SetQHHorizontalValidorInvalid ((QH_STRUCT *) PtrPreQH, FALSE);\r
2889 }\r
2890\r
2891 SetQHHorizontalLinkPtr ((QH_STRUCT *) PtrPreQH, NextQH);\r
2892 ((QH_STRUCT *) PtrPreQH)->ptrNext = NextQH;\r
2893\r
2894 Found = TRUE;\r
2895 }\r
2896\r
2897 if (Found && Delete) {\r
2898 //\r
2899 // free memory once used by the specific QH\r
2900 //\r
2901 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));\r
2902 }\r
2903\r
2904 return ;\r
2905}\r
2906\r
2907\r
2908VOID\r
2909DeleteQueuedTDs (\r
2910 IN USB_HC_DEV *HcDev,\r
2911 IN TD_STRUCT *PtrFirstTD\r
2912 )\r
2913/*++\r
2914Routine Description:\r
2915\r
2916 Delete Queued TDs\r
2917Arguments:\r
2918\r
2919 HcDev - USB_HC_DEV\r
2920 PtrFirstTD - TD link list head\r
2921\r
2922Returns:\r
2923 VOID\r
2924\r
2925--*/\r
2926{\r
2927 TD_STRUCT *Tptr1;\r
2928 TD_STRUCT *Tptr2;\r
2929\r
2930 Tptr1 = PtrFirstTD;\r
2931 //\r
2932 // Delete all the TDs in a queue.\r
2933 //\r
2934 while (Tptr1) {\r
2935\r
2936 Tptr2 = Tptr1;\r
2937\r
2938 if (!GetTDLinkPtrValidorInvalid (Tptr2)) {\r
2939 Tptr1 = NULL;\r
2940 } else {\r
2941\r
2942 Tptr1 = GetTDLinkPtr (Tptr2);\r
2943\r
2944 //\r
2945 // TD link to itself\r
2946 //\r
2947 if (Tptr1 == Tptr2) {\r
2948 Tptr1 = NULL;\r
2949 }\r
2950 }\r
2951\r
2952 UhciFreePool (HcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));\r
2953 }\r
2954\r
2955 return ;\r
2956}\r
2957\r
2958VOID\r
2959InsertQHTDToINTList (\r
2960 IN USB_HC_DEV *HcDev,\r
2961 IN QH_STRUCT *PtrQH,\r
2962 IN TD_STRUCT *PtrFirstTD,\r
2963 IN UINT8 DeviceAddress,\r
2964 IN UINT8 EndPointAddress,\r
2965 IN UINT8 DataToggle,\r
2966 IN UINTN DataLength,\r
2967 IN UINTN PollingInterval,\r
2968 IN VOID *Mapping,\r
2969 IN UINT8 *DataBuffer,\r
2970 IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,\r
2971 IN VOID *Context\r
2972 )\r
2973/*++\r
2974Routine Description:\r
2975 Insert QH and TD To Interrupt List\r
2976Arguments:\r
2977\r
2978 HcDev - USB_HC_DEV\r
2979 PtrQH - QH_STRUCT\r
2980 PtrFirstTD - First TD_STRUCT\r
2981 DeviceAddress - Device Address\r
2982 EndPointAddress - EndPoint Address\r
2983 DataToggle - Data Toggle\r
2984 DataLength - Data length \r
2985 PollingInterval - Polling Interval when inserted to frame list\r
2986 Mapping - Mapping alue \r
2987 DataBuffer - Data buffer\r
2988 CallBackFunction- CallBackFunction after interrupt transfeer\r
2989 Context - CallBackFunction Context passed as function parameter\r
2990Returns:\r
2991 EFI_SUCCESS - Sucess\r
2992 EFI_INVALID_PARAMETER - Paremeter is error \r
2993\r
2994--*/\r
2995{\r
2996 INTERRUPT_LIST *Node;\r
2997\r
2998 Node = AllocatePool (sizeof (INTERRUPT_LIST));\r
2999 if (Node == NULL) {\r
3000 return ;\r
3001 }\r
3002 \r
3003 //\r
3004 // Fill Node field\r
3005 //\r
3006 Node->Signature = INTERRUPT_LIST_SIGNATURE;\r
3007 Node->DevAddr = DeviceAddress;\r
3008 Node->EndPoint = EndPointAddress;\r
3009 Node->PtrQH = PtrQH;\r
3010 Node->PtrFirstTD = PtrFirstTD;\r
3011 Node->DataToggle = DataToggle;\r
3012 Node->DataLen = DataLength;\r
3013 Node->PollInterval = PollingInterval;\r
3014 Node->Mapping = Mapping;\r
3015 //\r
3016 // DataBuffer is allocated host memory, not mapped memory\r
3017 //\r
3018 Node->DataBuffer = DataBuffer;\r
3019 Node->InterruptCallBack = CallBackFunction;\r
3020 Node->InterruptContext = Context;\r
3021\r
3022 //\r
3023 // insert the new interrupt transfer to the head of the list.\r
3024 // The interrupt transfer's monitor function scans the whole list from head\r
3025 // to tail. The new interrupt transfer MUST be added to the head of the list\r
3026 // for the sake of error recovery.\r
3027 //\r
3028 InsertHeadList (&(HcDev->InterruptListHead), &(Node->Link));\r
3029\r
3030 return ;\r
3031}\r
3032\r
3033\r
3034EFI_STATUS\r
3035DeleteAsyncINTQHTDs (\r
3036 IN USB_HC_DEV *HcDev,\r
3037 IN UINT8 DeviceAddress,\r
3038 IN UINT8 EndPointAddress,\r
3039 OUT UINT8 *DataToggle\r
3040 )\r
3041/*++\r
3042Routine Description:\r
3043\r
3044 Delete Async INT QH and TDs\r
3045Arguments:\r
3046\r
3047 HcDev - USB_HC_DEV\r
3048 DeviceAddress - Device Address\r
3049 EndPointAddress - EndPoint Address\r
3050 DataToggle - Data Toggle\r
3051\r
3052Returns:\r
3053 EFI_SUCCESS - Sucess\r
3054 EFI_INVALID_PARAMETER - Paremeter is error \r
3055\r
3056--*/\r
3057{\r
3058 QH_STRUCT *MatchQH;\r
3059 QH_STRUCT *ptrNextQH;\r
3060 TD_STRUCT *MatchTD;\r
3061 LIST_ENTRY *Link;\r
3062 INTERRUPT_LIST *MatchList;\r
3063 INTERRUPT_LIST *PtrList;\r
3064 BOOLEAN Found;\r
3065\r
3066 UINT32 Result;\r
3067 UINTN ErrTDPos;\r
3068 UINTN ActualLen;\r
3069\r
3070 MatchQH = NULL;\r
3071 MatchTD = NULL;\r
3072 MatchList = NULL;\r
3073\r
3074 //\r
3075 // no interrupt transaction exists\r
3076 //\r
3077 if (IsListEmpty (&(HcDev->InterruptListHead))) {\r
3078 return EFI_INVALID_PARAMETER;\r
3079 }\r
3080 //\r
3081 // find the correct QH-TD that need to delete\r
3082 // (by matching Device address and EndPoint number to match QH-TD )\r
3083 //\r
3084 Found = FALSE;\r
3085 Link = &(HcDev->InterruptListHead);\r
3086 do {\r
3087\r
3088 Link = Link->ForwardLink;\r
3089 PtrList = INTERRUPT_LIST_FROM_LINK (Link);\r
3090\r
3091 if ((PtrList->DevAddr == DeviceAddress) && ((PtrList->EndPoint & 0x0f) == (EndPointAddress & 0x0f))) {\r
3092 MatchList = PtrList;\r
3093\r
3094 Found = TRUE;\r
3095 break;\r
3096 }\r
3097\r
3098 } while (Link->ForwardLink != &(HcDev->InterruptListHead));\r
3099\r
3100 if (!Found) {\r
3101 return EFI_INVALID_PARAMETER;\r
3102 }\r
3103 //\r
3104 // get current endpoint's data toggle bit and save.\r
3105 //\r
3106 ExecuteAsyncINTTDs (HcDev, MatchList, &Result, &ErrTDPos, &ActualLen);\r
3107 UpdateAsyncINTQHTDs (MatchList, Result, (UINT32) ErrTDPos);\r
3108 *DataToggle = MatchList->DataToggle;\r
3109\r
3110 MatchTD = MatchList->PtrFirstTD;\r
3111 MatchQH = MatchList->PtrQH;\r
3112 //\r
3113 // find the first matching QH position in the FrameList\r
3114 //\r
3115 while (MatchQH) {\r
3116\r
3117 ptrNextQH = MatchQH->ptrNextIntQH;\r
3118\r
3119 //\r
3120 // Search all the entries\r
3121 //\r
3122 DelLinkSingleQH (HcDev, MatchQH, 0, TRUE, TRUE);\r
3123\r
3124 MatchQH = ptrNextQH;\r
3125 }\r
3126 \r
3127 //\r
3128 // Call PciIo->Unmap() to unmap the busmaster read/write\r
3129 //\r
3130 HcDev->PciIo->Unmap (HcDev->PciIo, MatchList->Mapping);\r
3131\r
3132 //\r
3133 // free host data buffer allocated,\r
3134 // mapped data buffer is freed by Unmap\r
3135 //\r
3136 if (MatchList->DataBuffer != NULL) {\r
3137 gBS->FreePool (MatchList->DataBuffer);\r
3138 }\r
3139 \r
3140 //\r
3141 // at last delete the TDs, to aVOID problems\r
3142 //\r
3143 DeleteQueuedTDs (HcDev, MatchTD);\r
3144\r
3145 //\r
3146 // remove Match node from interrupt list\r
3147 //\r
3148 RemoveEntryList (&(MatchList->Link));\r
3149 gBS->FreePool (MatchList);\r
3150 return EFI_SUCCESS;\r
3151}\r
3152\r
3153BOOLEAN\r
3154CheckTDsResults (\r
3155 IN TD_STRUCT *PtrTD,\r
3156 IN UINTN RequiredLen,\r
3157 OUT UINT32 *Result,\r
3158 OUT UINTN *ErrTDPos,\r
3159 OUT UINTN *ActualTransferSize\r
3160 )\r
3161/*++\r
3162\r
3163Routine Description:\r
3164\r
3165 Check TDs Results\r
3166\r
3167Arguments:\r
3168\r
3169 PtrTD - TD_STRUCT to check\r
3170 RequiredLen - Required Len\r
3171 Result - Transfer result\r
3172 ErrTDPos - Error TD Position\r
3173 ActualTransferSize - Actual Transfer Size\r
3174\r
3175Returns:\r
3176\r
3177 TRUE - Sucess\r
3178 FALSE - Fail\r
3179\r
3180--*/\r
3181{\r
3182 UINTN Len;\r
3183\r
3184 *Result = EFI_USB_NOERROR;\r
3185 *ErrTDPos = 0;\r
3186\r
3187 //\r
3188 // Init to zero.\r
3189 //\r
3190 *ActualTransferSize = 0;\r
3191\r
3192 while (PtrTD) {\r
3193\r
3194 if (IsTDStatusActive (PtrTD)) {\r
3195 *Result |= EFI_USB_ERR_NOTEXECUTE;\r
3196 }\r
3197\r
3198 if (IsTDStatusStalled (PtrTD)) {\r
3199 *Result |= EFI_USB_ERR_STALL;\r
3200 }\r
3201\r
3202 if (IsTDStatusBufferError (PtrTD)) {\r
3203 *Result |= EFI_USB_ERR_BUFFER;\r
3204 }\r
3205\r
3206 if (IsTDStatusBabbleError (PtrTD)) {\r
3207 *Result |= EFI_USB_ERR_BABBLE;\r
3208 }\r
3209\r
3210 if (IsTDStatusNAKReceived (PtrTD)) {\r
3211 *Result |= EFI_USB_ERR_NAK;\r
3212 }\r
3213\r
3214 if (IsTDStatusCRCTimeOutError (PtrTD)) {\r
3215 *Result |= EFI_USB_ERR_TIMEOUT;\r
3216 }\r
3217\r
3218 if (IsTDStatusBitStuffError (PtrTD)) {\r
3219 *Result |= EFI_USB_ERR_BITSTUFF;\r
3220 }\r
3221 \r
3222 //\r
3223 // if any error encountered, stop processing the left TDs.\r
3224 //\r
3225 if (*Result) {\r
3226 return FALSE;\r
3227 }\r
3228\r
3229 Len = GetTDStatusActualLength (PtrTD) & 0x7FF;\r
3230 *ActualTransferSize += Len;\r
3231\r
3232 if (*ActualTransferSize <= RequiredLen && Len < PtrTD->TDData.TDTokenMaxLen) {\r
3233 //\r
3234 // transter finished and actural length less than required length\r
3235 //\r
3236 goto Done;\r
3237 }\r
3238 //\r
3239 // Accumulate actual transferred data length in each TD.\r
3240 //\r
3241 PtrTD = (TD_STRUCT *) (PtrTD->ptrNextTD);\r
3242 //\r
3243 // Record the first Error TD's position in the queue,\r
3244 // this value is zero-based.\r
3245 //\r
3246 (*ErrTDPos)++;\r
3247 }\r
3248\r
3249Done:\r
3250 return TRUE;\r
3251}\r
3252\r
3253\r
3254VOID\r
3255ExecuteAsyncINTTDs (\r
3256 IN USB_HC_DEV *HcDev,\r
3257 IN INTERRUPT_LIST *PtrList,\r
3258 OUT UINT32 *Result,\r
3259 OUT UINTN *ErrTDPos,\r
3260 OUT UINTN *ActualLen\r
3261 )\r
3262/*++\r
3263\r
3264Routine Description:\r
3265\r
3266 Execute Async Interrupt TDs\r
3267\r
3268Arguments:\r
3269\r
3270 HcDev - USB_HC_DEV\r
3271 PtrList - INTERRUPT_LIST\r
3272 Result - Transfer result\r
3273 ErrTDPos - Error TD Position\r
3274 ActualTransferSize - Actual Transfer Size\r
3275 \r
3276Returns:\r
3277\r
3278 VOID\r
3279\r
3280--*/\r
3281{\r
3282 //\r
3283 // *ErrTDPos is zero-based value, indicating the first error TD's position\r
3284 // in the TDs' sequence.\r
3285 // *ErrTDPos value is only valid when *Result is not equal NOERROR.\r
3286 //\r
3287 UINTN RequiredLen;\r
3288\r
3289 RequiredLen = *ActualLen;\r
3290 CheckTDsResults (PtrList->PtrFirstTD, RequiredLen, Result, ErrTDPos, ActualLen);\r
3291\r
3292 return ;\r
3293}\r
3294\r
3295\r
3296VOID\r
3297UpdateAsyncINTQHTDs (\r
3298 IN INTERRUPT_LIST *PtrList,\r
3299 IN UINT32 Result,\r
3300 IN UINT32 ErrTDPos\r
3301 )\r
3302/*++\r
3303\r
3304Routine Description:\r
3305\r
3306 Update Async Interrupt QH and TDs\r
3307\r
3308Arguments:\r
3309\r
3310 PtrList - INTERRUPT_LIST\r
3311 Result - Transfer reslut\r
3312 ErrTDPos - Error TD Position\r
3313\r
3314Returns:\r
3315\r
3316 VOID\r
3317\r
3318--*/\r
3319{\r
3320 QH_STRUCT *PtrFirstQH;\r
3321 QH_STRUCT *PtrQH;\r
3322 TD_STRUCT *PtrFirstTD;\r
3323 TD_STRUCT *PtrTD;\r
3324 UINT8 DataToggle;\r
3325 UINT32 Index;\r
3326\r
3327 PtrFirstQH = PtrList->PtrQH;\r
3328 PtrFirstTD = PtrList->PtrFirstTD;\r
3329\r
3330 DataToggle = 0;\r
3331\r
3332 if (Result == EFI_USB_NOERROR) {\r
3333\r
3334 PtrTD = PtrFirstTD;\r
3335 while (PtrTD) {\r
3336 DataToggle = GetTDTokenDataToggle (PtrTD);\r
3337 PtrTD = PtrTD->ptrNextTD;\r
3338 }\r
3339 \r
3340 //\r
3341 // save current DataToggle value to interrupt list.\r
3342 // this value is used for tracing the interrupt endpoint DataToggle.\r
3343 // when this interrupt transfer is deleted, the last DataToggle is saved\r
3344 //\r
3345 PtrList->DataToggle = DataToggle;\r
3346\r
3347 PtrTD = PtrFirstTD;\r
3348\r
3349 //\r
3350 // Since DataToggle bit should toggle after each success transaction,\r
3351 // the First TD's DataToggle bit will be updated to XOR of Last TD's\r
3352 // DataToggle bit. If the First TD's DataToggle bit is not equal Last\r
3353 // TD's DataToggle bit, that means it already be the XOR of Last TD's,\r
3354 // so no update is needed.\r
3355 //\r
3356 if (DataToggle == GetTDTokenDataToggle (PtrFirstTD)) {\r
3357 PtrTD = PtrFirstTD;\r
3358 while (PtrTD) {\r
3359\r
3360 DataToggle ^= 1;\r
3361 if (DataToggle) {\r
3362 SetTDTokenDataToggle1 (PtrTD);\r
3363 } else {\r
3364 SetTDTokenDataToggle0 (PtrTD);\r
3365 }\r
3366\r
3367 PtrTD = PtrTD->ptrNextTD;\r
3368 }\r
3369 }\r
3370 //\r
3371 // restore Link Pointer of QH to First TD\r
3372 // (because QH's Link Pointer will change during TD execution)\r
3373 //\r
3374 PtrQH = PtrFirstQH;\r
3375 while (PtrQH) {\r
3376\r
3377 LinkTDToQH (PtrQH, PtrFirstTD);\r
3378 PtrQH = PtrQH->ptrNextIntQH;\r
3379 }\r
3380 \r
3381 //\r
3382 // set all the TDs active\r
3383 //\r
3384 PtrTD = PtrFirstTD;\r
3385 while (PtrTD) {\r
3386 SetTDStatusActiveorInactive (PtrTD, TRUE);\r
3387 PtrTD = PtrTD->ptrNextTD;\r
3388 }\r
3389\r
3390 } else if (((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE) ||\r
3391 ((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK)\r
3392 ) {\r
3393 //\r
3394 // no update\r
3395 //\r
3396 } else {\r
3397 //\r
3398 // Have Errors\r
3399 //\r
3400 PtrTD = PtrFirstTD;\r
3401 //\r
3402 // not first TD error\r
3403 //\r
3404 if (ErrTDPos != 0) {\r
3405 //\r
3406 // get the last success TD\r
3407 //\r
3408 for (Index = 1; Index < ErrTDPos; Index++) {\r
3409 PtrTD = PtrTD->ptrNextTD;\r
3410 }\r
3411 //\r
3412 // update Data Toggle in the interrupt list node\r
3413 //\r
3414 PtrList->DataToggle = GetTDTokenDataToggle (PtrTD);\r
3415\r
3416 //\r
3417 // get the error TD\r
3418 //\r
3419 PtrTD = PtrTD->ptrNextTD;\r
3420\r
3421 } else {\r
3422 PtrList->DataToggle = GetTDTokenDataToggle (PtrTD);\r
3423 }\r
3424 //\r
3425 // do not restore the QH's vertical link pointer,\r
3426 // let the callback function do the rest of error handling.\r
3427 //\r
3428 }\r
3429\r
3430 return ;\r
3431}\r
3432\r
3433VOID\r
3434ReleaseInterruptList (\r
3435 IN USB_HC_DEV *HcDev,\r
3436 IN LIST_ENTRY *ListHead\r
3437 )\r
3438/*++\r
3439\r
3440Routine Description:\r
3441\r
3442 Release Interrupt List\r
3443Arguments:\r
3444\r
3445 HcDev - USB_HC_DEV\r
3446 ListHead - List head\r
3447\r
3448Returns:\r
3449\r
3450 VOID\r
3451\r
3452--*/\r
3453{\r
3454 LIST_ENTRY *Link;\r
3455 LIST_ENTRY *SavedLink;\r
3456 INTERRUPT_LIST *pNode;\r
3457 TD_STRUCT *PtrTD;\r
3458 TD_STRUCT *ptrNextTD;\r
3459 QH_STRUCT *PtrQH;\r
3460 QH_STRUCT *SavedQH;\r
3461\r
3462 if (ListHead == NULL) {\r
3463 return ;\r
3464 }\r
3465\r
3466 Link = ListHead;\r
3467\r
3468 //\r
3469 // Free all the resources in the interrupt list\r
3470 //\r
3471 SavedLink = Link->ForwardLink;\r
3472 while (!IsListEmpty (ListHead)) {\r
3473\r
3474 Link = SavedLink;\r
3475\r
3476 SavedLink = Link->ForwardLink;\r
3477\r
3478 pNode = INTERRUPT_LIST_FROM_LINK (Link);\r
3479\r
3480 RemoveEntryList (&pNode->Link);\r
3481\r
3482 SavedQH = pNode->PtrQH;\r
3483 for (PtrQH = SavedQH; PtrQH != NULL; PtrQH = SavedQH) {\r
3484 SavedQH = PtrQH->ptrNextIntQH;\r
3485 UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));\r
3486 }\r
3487\r
3488 PtrTD = pNode->PtrFirstTD;\r
3489 while (PtrTD != NULL) {\r
3490\r
3491 ptrNextTD = PtrTD->ptrNextTD;\r
3492 UhciFreePool (HcDev, (UINT8 *) PtrTD, sizeof (TD_STRUCT));\r
3493 PtrTD = ptrNextTD;\r
3494 }\r
3495\r
3496 gBS->FreePool (pNode);\r
3497 }\r
3498}\r
3499\r
3500\r
3501EFI_STATUS\r
3502InitializeMemoryManagement (\r
3503 IN USB_HC_DEV *HcDev\r
3504 )\r
3505/*++\r
3506\r
3507Routine Description:\r
3508\r
3509 Initialize Memory Management\r
3510\r
3511Arguments:\r
3512\r
3513 HcDev - USB_HC_DEV\r
3514\r
3515Returns:\r
3516\r
3517 EFI_SUCCESS - Success\r
3518--*/\r
3519{\r
3520 MEMORY_MANAGE_HEADER *MemoryHeader;\r
3521 EFI_STATUS Status;\r
3522 UINTN MemPages;\r
3523\r
3524 MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
3525 Status = CreateMemoryBlock (HcDev, &MemoryHeader, MemPages);\r
3526 if (EFI_ERROR (Status)) {\r
3527 return Status;\r
3528 }\r
3529\r
3530 HcDev->MemoryHeader = MemoryHeader;\r
3531\r
3532 return EFI_SUCCESS;\r
3533}\r
3534\r
3535EFI_STATUS\r
3536CreateMemoryBlock (\r
3537 IN USB_HC_DEV *HcDev,\r
3538 OUT MEMORY_MANAGE_HEADER **MemoryHeader,\r
3539 IN UINTN MemoryBlockSizeInPages\r
3540 )\r
3541/*++\r
3542\r
3543Routine Description:\r
3544\r
3545 Use PciIo->AllocateBuffer to allocate common buffer for the memory block,\r
3546 and use PciIo->Map to map the common buffer for Bus Master Read/Write.\r
3547\r
3548\r
3549Arguments:\r
3550\r
3551 HcDev - USB_HC_DEV\r
3552 MemoryHeader - MEMORY_MANAGE_HEADER to output\r
3553 MemoryBlockSizeInPages - MemoryBlockSizeInPages\r
3554Returns:\r
3555\r
3556 EFI_SUCCESS - Success\r
3557--*/\r
3558{\r
3559 EFI_STATUS Status;\r
3560 VOID *CommonBuffer;\r
3561 EFI_PHYSICAL_ADDRESS MappedAddress;\r
3562 UINTN MemoryBlockSizeInBytes;\r
3563 VOID *Mapping;\r
3564\r
3565 //\r
3566 // Allocate memory for MemoryHeader\r
3567 //\r
3568 *MemoryHeader = AllocateZeroPool (sizeof (MEMORY_MANAGE_HEADER));\r
3569 if (*MemoryHeader == NULL) {\r
3570 return EFI_OUT_OF_RESOURCES;\r
3571 }\r
3572\r
3573 (*MemoryHeader)->Next = NULL;\r
3574\r
3575 //\r
3576 // set Memory block size\r
3577 //\r
3578 (*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);\r
3579\r
3580 //\r
3581 // each bit in Bit Array will manage 32 bytes memory in memory block\r
3582 //\r
3583 (*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;\r
3584\r
3585 //\r
3586 // Allocate memory for BitArray\r
3587 //\r
3588 (*MemoryHeader)->BitArrayPtr = AllocateZeroPool ((*MemoryHeader)->BitArraySizeInBytes);\r
3589 if ((*MemoryHeader)->BitArrayPtr == NULL) {\r
3590 gBS->FreePool (*MemoryHeader);\r
3591 return EFI_OUT_OF_RESOURCES;\r
3592 }\r
3593 \r
3594 //\r
3595 // Memory Block uses MemoryBlockSizeInPages pages,\r
3596 // and it is allocated as common buffer use.\r
3597 //\r
3598 Status = HcDev->PciIo->AllocateBuffer (\r
562d2849 3599 HcDev->PciIo,\r
3600 AllocateAnyPages,\r
3601 EfiBootServicesData,\r
3602 MemoryBlockSizeInPages,\r
3603 &CommonBuffer,\r
3604 0\r
3605 );\r
878ddf1f 3606 if (EFI_ERROR (Status)) {\r
3607 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
3608 gBS->FreePool (*MemoryHeader);\r
3609 return Status;\r
3610 }\r
3611\r
3612 MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);\r
3613 Status = HcDev->PciIo->Map (\r
562d2849 3614 HcDev->PciIo,\r
3615 EfiPciIoOperationBusMasterCommonBuffer,\r
3616 CommonBuffer,\r
3617 &MemoryBlockSizeInBytes,\r
3618 &MappedAddress,\r
3619 &Mapping\r
3620 );\r
878ddf1f 3621 //\r
3622 // if returned Mapped size is less than the size we request,do not support.\r
3623 //\r
3624 if (EFI_ERROR (Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages))) {\r
3625 HcDev->PciIo->FreeBuffer (HcDev->PciIo, MemoryBlockSizeInPages, CommonBuffer);\r
3626 gBS->FreePool ((*MemoryHeader)->BitArrayPtr);\r
3627 gBS->FreePool (*MemoryHeader);\r
3628 return EFI_UNSUPPORTED;\r
3629 }\r
3630 //\r
3631 // Set Memory block initial address\r
3632 //\r
3633 (*MemoryHeader)->MemoryBlockPtr = (UINT8 *) ((UINTN) MappedAddress);\r
3634 (*MemoryHeader)->Mapping = Mapping;\r
3635\r
3636 ZeroMem (\r
3637 (*MemoryHeader)->MemoryBlockPtr,\r
3638 EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages)\r
3639 );\r
3640\r
3641 return EFI_SUCCESS;\r
3642}\r
3643\r
3644EFI_STATUS\r
3645FreeMemoryHeader (\r
3646 IN USB_HC_DEV *HcDev,\r
3647 IN MEMORY_MANAGE_HEADER *MemoryHeader\r
3648 )\r
3649/*++\r
3650\r
3651Routine Description:\r
3652\r
3653 Free Memory Header\r
3654\r
3655Arguments:\r
3656\r
3657 HcDev - USB_HC_DEV\r
3658 MemoryHeader - MemoryHeader to be freed\r
3659\r
3660Returns:\r
3661\r
3662 EFI_INVALID_PARAMETER - Parameter is error\r
3663 EFI_SUCCESS - Success\r
3664\r
3665--*/\r
3666{\r
3667 if ((MemoryHeader == NULL) || (HcDev == NULL)) {\r
3668 return EFI_INVALID_PARAMETER;\r
3669 }\r
3670 //\r
3671 // unmap the common buffer used by the memory block\r
3672 //\r
3673 HcDev->PciIo->Unmap (HcDev->PciIo, MemoryHeader->Mapping);\r
3674\r
3675 //\r
3676 // free common buffer\r
3677 //\r
3678 HcDev->PciIo->FreeBuffer (\r
3679 HcDev->PciIo,\r
3680 EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),\r
3681 MemoryHeader->MemoryBlockPtr\r
3682 );\r
3683 //\r
3684 // free bit array\r
3685 //\r
3686 gBS->FreePool (MemoryHeader->BitArrayPtr);\r
3687 //\r
3688 // free memory header\r
3689 //\r
3690 gBS->FreePool (MemoryHeader);\r
3691\r
3692 return EFI_SUCCESS;\r
3693}\r
3694\r
3695EFI_STATUS\r
3696UhciAllocatePool (\r
3697 IN USB_HC_DEV *HcDev,\r
3698 OUT UINT8 **Pool,\r
3699 IN UINTN AllocSize\r
3700 )\r
3701/*++\r
3702\r
3703Routine Description:\r
3704\r
3705 Uhci Allocate Pool\r
3706\r
3707Arguments:\r
3708\r
3709 HcDev - USB_HC_DEV\r
3710 Pool - Place to store pointer to the memory buffer\r
3711 AllocSize - Alloc Size\r
3712\r
3713Returns:\r
3714\r
3715 EFI_SUCCESS - Success\r
3716\r
3717--*/\r
3718{\r
3719 MEMORY_MANAGE_HEADER *MemoryHeader;\r
3720 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
3721 MEMORY_MANAGE_HEADER *NewMemoryHeader;\r
3722 UINTN RealAllocSize;\r
3723 UINTN MemoryBlockSizeInPages;\r
3724 EFI_STATUS Status;\r
3725\r
3726 *Pool = NULL;\r
3727\r
3728 MemoryHeader = HcDev->MemoryHeader;\r
3729 ASSERT (MemoryHeader != NULL);\r
3730\r
3731 //\r
3732 // allocate unit is 32 bytes (align on 32 byte)\r
3733 //\r
3734 if (AllocSize & 0x1F) {\r
3735 RealAllocSize = (AllocSize / 32 + 1) * 32;\r
3736 } else {\r
3737 RealAllocSize = AllocSize;\r
3738 }\r
3739 \r
3740 //\r
3741 // There may be linked MemoryHeaders.\r
3742 // To allocate a free pool in Memory blocks,\r
3743 // must search in the MemoryHeader link list\r
3744 // until enough free pool is found.\r
3745 //\r
3746 Status = EFI_NOT_FOUND;\r
3747 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;\r
3748 TempHeaderPtr = TempHeaderPtr->Next) {\r
3749\r
3750 Status = AllocMemInMemoryBlock (\r
562d2849 3751 TempHeaderPtr,\r
3752 (VOID **) Pool,\r
3753 RealAllocSize / 32\r
3754 );\r
878ddf1f 3755 if (!EFI_ERROR (Status)) {\r
3756 ZeroMem (*Pool, AllocSize);\r
3757 return EFI_SUCCESS;\r
3758 }\r
3759 }\r
3760 \r
3761 //\r
3762 // There is no enough memory,\r
3763 // Create a new Memory Block\r
3764 //\r
3765 \r
3766 //\r
3767 // if pool size is larger than NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES,\r
3768 // just allocate a large enough memory block.\r
3769 //\r
3770 if (RealAllocSize > EFI_PAGES_TO_SIZE (NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES)) {\r
3771 MemoryBlockSizeInPages = EFI_SIZE_TO_PAGES (RealAllocSize) + 1;\r
3772 } else {\r
3773 MemoryBlockSizeInPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;\r
3774 }\r
3775\r
3776 Status = CreateMemoryBlock (HcDev, &NewMemoryHeader, MemoryBlockSizeInPages);\r
3777 if (EFI_ERROR (Status)) {\r
3778 return Status;\r
3779 }\r
3780 \r
3781 //\r
3782 // Link the new Memory Block to the Memory Header list\r
3783 //\r
3784 InsertMemoryHeaderToList (MemoryHeader, NewMemoryHeader);\r
3785\r
3786 Status = AllocMemInMemoryBlock (\r
562d2849 3787 NewMemoryHeader,\r
3788 (VOID **) Pool,\r
3789 RealAllocSize / 32\r
3790 );\r
878ddf1f 3791\r
3792 if (!EFI_ERROR (Status)) {\r
3793 ZeroMem (*Pool, AllocSize);\r
3794 }\r
3795\r
3796 return Status;\r
3797}\r
3798\r
3799VOID\r
3800UhciFreePool (\r
3801 IN USB_HC_DEV *HcDev,\r
3802 IN UINT8 *Pool,\r
3803 IN UINTN AllocSize\r
3804 )\r
3805/*++\r
3806\r
3807Routine Description:\r
3808\r
3809 Uhci Free Pool\r
3810\r
3811Arguments:\r
3812\r
3813 HcDev - USB_HC_DEV\r
3814 Pool - Pool to free\r
3815 AllocSize - Pool size\r
3816\r
3817Returns:\r
3818\r
3819 VOID\r
3820\r
3821--*/\r
3822{\r
3823 MEMORY_MANAGE_HEADER *MemoryHeader;\r
3824 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
3825 UINTN StartBytePos;\r
3826 UINTN Index;\r
3827 UINT8 StartBitPos;\r
3828 UINT8 Index2;\r
3829 UINTN Count;\r
3830 UINTN RealAllocSize;\r
3831\r
3832 MemoryHeader = HcDev->MemoryHeader;\r
3833\r
3834 //\r
3835 // allocate unit is 32 byte (align on 32 byte)\r
3836 //\r
3837 if (AllocSize & 0x1F) {\r
3838 RealAllocSize = (AllocSize / 32 + 1) * 32;\r
3839 } else {\r
3840 RealAllocSize = AllocSize;\r
3841 }\r
3842 //\r
3843 // scan the memory header linked list for\r
3844 // the asigned memory to free.\r
3845 //\r
3846 for (TempHeaderPtr = MemoryHeader;TempHeaderPtr != NULL;\r
3847 TempHeaderPtr = TempHeaderPtr->Next) {\r
3848\r
3849 if ((Pool >= TempHeaderPtr->MemoryBlockPtr) &&\r
3850 ((Pool + RealAllocSize) <= (TempHeaderPtr->MemoryBlockPtr + TempHeaderPtr->MemoryBlockSizeInBytes))\r
3851 ) {\r
3852 //\r
3853 // Pool is in the Memory Block area,\r
3854 // find the start byte and bit in the bit array\r
3855 //\r
3856 StartBytePos = ((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) / 8;\r
3857 StartBitPos = (UINT8) (((Pool - TempHeaderPtr->MemoryBlockPtr) / 32) & 0x7);\r
3858\r
3859 //\r
3860 // reset associated bits in bit arry\r
3861 //\r
3862 for (Index = StartBytePos, Index2 = StartBitPos, Count = 0; Count < (RealAllocSize / 32); Count++) {\r
3863\r
1cc8ee78 3864 TempHeaderPtr->BitArrayPtr[Index] = (UINT8) (TempHeaderPtr->BitArrayPtr[Index] ^ bit (Index2));\r
878ddf1f 3865 Index2++;\r
3866 if (Index2 == 8) {\r
3867 Index += 1;\r
3868 Index2 = 0;\r
3869 }\r
3870 }\r
3871 //\r
3872 // break the loop\r
3873 //\r
3874 break;\r
3875 }\r
3876 }\r
3877 \r
3878 //\r
3879 // Release emptied memory blocks (only if the memory block is not\r
3880 // the first one in the memory header list\r
3881 //\r
3882 for (TempHeaderPtr = MemoryHeader->Next; TempHeaderPtr != NULL;) {\r
3883 //\r
3884 // Debug\r
3885 //\r
3886 ASSERT (MemoryHeader->Next != NULL);\r
3887\r
3888 if (IsMemoryBlockEmptied (TempHeaderPtr)) {\r
3889\r
3890 DelinkMemoryBlock (MemoryHeader, TempHeaderPtr);\r
3891 //\r
3892 // when the TempHeaderPtr is freed in FreeMemoryHeader(),\r
3893 // the TempHeaderPtr is pointing to nonsense content.\r
3894 //\r
3895 FreeMemoryHeader (HcDev, TempHeaderPtr);\r
3896 //\r
3897 // reset the TempHeaderPtr, continue search for\r
3898 // another empty memory block.\r
3899 //\r
3900 TempHeaderPtr = MemoryHeader->Next;\r
3901 continue;\r
3902 }\r
3903\r
3904 TempHeaderPtr = TempHeaderPtr->Next;\r
3905 }\r
3906}\r
3907\r
3908VOID\r
3909InsertMemoryHeaderToList (\r
3910 IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
3911 IN MEMORY_MANAGE_HEADER *NewMemoryHeader\r
3912 )\r
3913/*++\r
3914\r
3915Routine Description:\r
3916\r
3917 Insert Memory Header To List\r
3918\r
3919Arguments:\r
3920\r
3921 MemoryHeader - MEMORY_MANAGE_HEADER\r
3922 NewMemoryHeader - MEMORY_MANAGE_HEADER\r
3923\r
3924Returns:\r
3925\r
3926 VOID\r
3927\r
3928--*/\r
3929{\r
3930 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
3931\r
3932 for (TempHeaderPtr = MemoryHeader; TempHeaderPtr != NULL;\r
3933 TempHeaderPtr = TempHeaderPtr->Next) {\r
3934 if (TempHeaderPtr->Next == NULL) {\r
3935 TempHeaderPtr->Next = NewMemoryHeader;\r
3936 break;\r
3937 }\r
3938 }\r
3939}\r
3940\r
3941EFI_STATUS\r
3942AllocMemInMemoryBlock (\r
3943 IN MEMORY_MANAGE_HEADER *MemoryHeader,\r
3944 OUT VOID **Pool,\r
3945 IN UINTN NumberOfMemoryUnit\r
3946 )\r
3947/*++\r
3948\r
3949Routine Description:\r
3950\r
3951 Alloc Memory In MemoryBlock\r
3952\r
3953Arguments:\r
3954\r
3955 MemoryHeader - MEMORY_MANAGE_HEADER\r
3956 Pool - Place to store pointer to memory\r
3957 NumberOfMemoryUnit - Number Of Memory Unit\r
3958\r
3959Returns:\r
3960\r
3961 EFI_NOT_FOUND - Can't find the free memory \r
3962 EFI_SUCCESS - Success\r
3963\r
3964--*/\r
3965{\r
3966 UINTN TempBytePos;\r
3967 UINTN FoundBytePos;\r
3968 UINT8 Index;\r
3969 UINT8 FoundBitPos;\r
3970 UINT8 ByteValue;\r
3971 UINT8 BitValue;\r
3972 UINTN NumberOfZeros;\r
3973 UINTN Count;\r
3974\r
3975 FoundBytePos = 0;\r
3976 FoundBitPos = 0;\r
3977 ByteValue = MemoryHeader->BitArrayPtr[0];\r
3978 NumberOfZeros = 0;\r
3979 Index = 0;\r
3980\r
3981 for (TempBytePos = 0; TempBytePos < MemoryHeader->BitArraySizeInBytes;) {\r
3982 \r
3983 //\r
3984 // Pop out BitValue from a byte in TempBytePos.\r
3985 //\r
3986 BitValue = (UINT8) (ByteValue & 0x1);\r
3987 //\r
3988 // right shift the byte\r
3989 //\r
3990 ByteValue /= 2;\r
3991\r
3992 if (BitValue == 0) {\r
3993 //\r
3994 // Found a free bit, the NumberOfZeros only record the number\r
3995 // of those consecutive zeros\r
3996 //\r
3997 NumberOfZeros++;\r
3998 //\r
3999 // Found enough consecutive free space, break the loop\r
4000 //\r
4001 if (NumberOfZeros >= NumberOfMemoryUnit) {\r
4002 break;\r
4003 }\r
4004 } else {\r
4005 //\r
4006 // Encountering a '1', meant the bit is ocupied.\r
4007 //\r
4008 if (NumberOfZeros >= NumberOfMemoryUnit) {\r
4009 //\r
4010 // Found enough consecutive free space,break the loop\r
4011 //\r
4012 break;\r
4013 } else {\r
4014 //\r
4015 // the NumberOfZeros only record the number of those consecutive zeros,\r
4016 // so reset the NumberOfZeros to 0 when encountering '1' before finding\r
4017 // enough consecutive '0's\r
4018 //\r
4019 NumberOfZeros = 0;\r
4020 //\r
4021 // reset the (FoundBytePos,FoundBitPos) to the position of '1'\r
4022 //\r
4023 FoundBytePos = TempBytePos;\r
4024 FoundBitPos = Index;\r
4025 }\r
4026 }\r
4027 //\r
4028 // step forward a bit\r
4029 //\r
4030 Index++;\r
4031 if (Index == 8) {\r
4032 //\r
4033 // step forward a byte, getting the byte value,\r
4034 // and reset the bit pos.\r
4035 //\r
4036 TempBytePos += 1;\r
4037 ByteValue = MemoryHeader->BitArrayPtr[TempBytePos];\r
4038 Index = 0;\r
4039 }\r
4040 }\r
4041\r
4042 if (NumberOfZeros < NumberOfMemoryUnit) {\r
4043 return EFI_NOT_FOUND;\r
4044 }\r
4045 \r
4046 //\r
4047 // Found enough free space.\r
4048 //\r
4049 \r
4050 //\r
4051 // The values recorded in (FoundBytePos,FoundBitPos) have two conditions:\r
4052 // 1)(FoundBytePos,FoundBitPos) record the position\r
4053 // of the last '1' before the consecutive '0's, it must\r
4054 // be adjusted to the start position of the consecutive '0's.\r
4055 // 2)the start address of the consecutive '0's is just the start of\r
4056 // the bitarray. so no need to adjust the values of\r
4057 // (FoundBytePos,FoundBitPos).\r
4058 //\r
4059 if ((MemoryHeader->BitArrayPtr[0] & bit (0)) != 0) {\r
4060 FoundBitPos += 1;\r
4061 }\r
4062 \r
4063 //\r
4064 // Have the (FoundBytePos,FoundBitPos) make sense.\r
4065 //\r
4066 if (FoundBitPos > 7) {\r
4067 FoundBytePos += 1;\r
4068 FoundBitPos -= 8;\r
4069 }\r
4070 \r
4071 //\r
4072 // Set the memory as allocated\r
4073 //\r
4074 for (TempBytePos = FoundBytePos, Index = FoundBitPos,Count = 0;\r
4075 Count < NumberOfMemoryUnit; Count ++) {\r
4076\r
1cc8ee78 4077 MemoryHeader->BitArrayPtr[TempBytePos] = (UINT8) (MemoryHeader->BitArrayPtr[TempBytePos] | bit (Index));\r
878ddf1f 4078 Index++;\r
4079 if (Index == 8) {\r
4080 TempBytePos += 1;\r
4081 Index = 0;\r
4082 }\r
4083 }\r
4084\r
4085 *Pool = MemoryHeader->MemoryBlockPtr + (FoundBytePos * 8 + FoundBitPos) * 32;\r
4086\r
4087 return EFI_SUCCESS;\r
4088}\r
4089\r
4090BOOLEAN\r
4091IsMemoryBlockEmptied (\r
4092 IN MEMORY_MANAGE_HEADER *MemoryHeaderPtr\r
4093 )\r
4094/*++\r
4095\r
4096Routine Description:\r
4097\r
4098 Is Memory Block Emptied\r
4099\r
4100Arguments:\r
4101\r
4102 MemoryHeaderPtr - MEMORY_MANAGE_HEADER\r
4103\r
4104Returns:\r
4105\r
4106 TRUE - Empty\r
4107 FALSE - Not Empty \r
4108\r
4109--*/\r
4110{\r
4111 UINTN Index;\r
4112\r
4113 for (Index = 0; Index < MemoryHeaderPtr->BitArraySizeInBytes; Index++) {\r
4114 if (MemoryHeaderPtr->BitArrayPtr[Index] != 0) {\r
4115 return FALSE;\r
4116 }\r
4117 }\r
4118\r
4119 return TRUE;\r
4120}\r
4121\r
4122VOID\r
4123DelinkMemoryBlock (\r
4124 IN MEMORY_MANAGE_HEADER *FirstMemoryHeader,\r
4125 IN MEMORY_MANAGE_HEADER *NeedFreeMemoryHeader\r
4126 )\r
4127/*++\r
4128\r
4129Routine Description:\r
4130\r
4131 Delink Memory Block\r
4132\r
4133Arguments:\r
4134\r
4135 FirstMemoryHeader - MEMORY_MANAGE_HEADER\r
4136 NeedFreeMemoryHeader - MEMORY_MANAGE_HEADER\r
4137\r
4138Returns:\r
4139\r
4140 VOID\r
4141\r
4142--*/\r
4143{\r
4144 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
4145\r
4146 if ((FirstMemoryHeader == NULL) || (NeedFreeMemoryHeader == NULL)) {\r
4147 return ;\r
4148 }\r
4149 for (TempHeaderPtr = FirstMemoryHeader; TempHeaderPtr != NULL;\r
4150 TempHeaderPtr = TempHeaderPtr->Next) {\r
4151\r
4152 if (TempHeaderPtr->Next == NeedFreeMemoryHeader) {\r
4153 //\r
4154 // Link the before and after\r
4155 //\r
4156 TempHeaderPtr->Next = NeedFreeMemoryHeader->Next;\r
4157 break;\r
4158 }\r
4159 }\r
4160}\r
4161\r
4162EFI_STATUS\r
4163DelMemoryManagement (\r
4164 IN USB_HC_DEV *HcDev\r
4165 )\r
4166/*++\r
4167\r
4168Routine Description:\r
4169\r
4170 Delete Memory Management\r
4171\r
4172Arguments:\r
4173\r
4174 HcDev - USB_HC_DEV\r
4175\r
4176Returns:\r
4177\r
4178 EFI_SUCCESS - Success\r
4179\r
4180--*/\r
4181{\r
4182 MEMORY_MANAGE_HEADER *TempHeaderPtr;\r
4183\r
4184 for (TempHeaderPtr = HcDev->MemoryHeader->Next; TempHeaderPtr != NULL;) {\r
4185\r
4186 DelinkMemoryBlock (HcDev->MemoryHeader, TempHeaderPtr);\r
4187 //\r
4188 // when the TempHeaderPtr is freed in FreeMemoryHeader(),\r
4189 // the TempHeaderPtr is pointing to nonsense content.\r
4190 //\r
4191 FreeMemoryHeader (HcDev, TempHeaderPtr);\r
4192 //\r
4193 // reset the TempHeaderPtr,continue free another memory block.\r
4194 //\r
4195 TempHeaderPtr = HcDev->MemoryHeader->Next;\r
4196 }\r
4197\r
4198 FreeMemoryHeader (HcDev, HcDev->MemoryHeader);\r
4199\r
4200 return EFI_SUCCESS;\r
4201}\r
4202\r
4203\r
4204VOID\r
4205CleanUsbTransactions (\r
4206 IN USB_HC_DEV *HcDev\r
4207 )\r
4208{\r
4209 //\r
4210 // only asynchronous interrupt transfers are always alive on the bus\r
4211 //\r
4212 ReleaseInterruptList (HcDev, &(HcDev->InterruptListHead));\r
4213}\r
4214\r
4215VOID\r
4216TurnOffUSBEmulation (\r
4217 IN EFI_PCI_IO_PROTOCOL *PciIo\r
4218 )\r
4219/*++\r
4220 \r
4221 Routine Description:\r
4222 Disable USB Emulation\r
4223 Arguments:\r
4224 PciIo - EFI_PCI_IO_PROTOCOL\r
4225 Returns:\r
4226 VOID\r
4227--*/\r
4228{\r
4229 UINT16 Command;\r
4230\r
4231 //\r
4232 // Disable USB Emulation\r
4233 //\r
4234 Command = 0;\r
4235 PciIo->Pci.Write (\r
562d2849 4236 PciIo,\r
4237 EfiPciIoWidthUint16,\r
4238 USB_EMULATION,\r
4239 1,\r
4240 &Command\r
4241 );\r
878ddf1f 4242\r
4243 return ;\r
4244}\r