git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1459 6f19259b...
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / Ehci / Dxe / EhciSched.c
CommitLineData
562d2849 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 EhciSched.c\r
15 \r
16Abstract: \r
17 \r
18\r
19Revision History\r
20--*/\r
21\r
22#include "Ehci.h"\r
23\r
24EFI_STATUS\r
25InitialPeriodicFrameList (\r
26 IN USB2_HC_DEV *HcDev,\r
27 IN UINTN Length\r
28 )\r
29/*++\r
30\r
31Routine Description:\r
32\r
33 Initialize Periodic Schedule Frame List\r
34\r
35Arguments:\r
36\r
37 HcDev - USB2_HC_DEV\r
38 Length - Frame List Length\r
39 \r
40Returns:\r
41\r
42 EFI_SUCCESS Success\r
43 EFI_DEVICE_ERROR Fail\r
44\r
45--*/\r
46{\r
47 EFI_STATUS Status;\r
48 VOID *CommonBuffer;\r
49 EFI_PHYSICAL_ADDRESS FrameBuffer;\r
50 VOID *Map;\r
51 UINTN BufferSizeInPages;\r
52 UINTN BufferSizeInBytes;\r
53 UINTN FrameIndex;\r
54 FRAME_LIST_ENTRY *FrameEntryPtr;\r
55 \r
56 //\r
57 // The Frame List is a common buffer that will be\r
58 // accessed by both the cpu and the usb bus master\r
59 // at the same time.\r
60 // The Frame List ocupies 4K bytes,\r
61 // and must be aligned on 4-Kbyte boundaries.\r
62 //\r
63 if (EHCI_MAX_FRAME_LIST_LENGTH != Length && IsFrameListProgrammable (HcDev)) {\r
64 Status = SetFrameListLen (HcDev, Length);\r
65 if (EFI_ERROR (Status)) {\r
66 Status = EFI_INVALID_PARAMETER;\r
67 goto exit;\r
68 }\r
69 }\r
70\r
71 BufferSizeInBytes = EFI_PAGE_SIZE;\r
72 BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);\r
73 Status = HcDev->PciIo->AllocateBuffer (\r
74 HcDev->PciIo,\r
75 AllocateAnyPages,\r
76 EfiBootServicesData,\r
77 BufferSizeInPages,\r
78 &CommonBuffer,\r
79 0\r
80 );\r
81 if (EFI_ERROR (Status)) {\r
82 DEBUG ((gEHCErrorLevel, "PciIo->AllocateBuffer Failed\n"));\r
83 Status = EFI_OUT_OF_RESOURCES;\r
84 goto exit;\r
85 }\r
86\r
87 Status = HcDev->PciIo->Map (\r
88 HcDev->PciIo,\r
89 EfiPciIoOperationBusMasterCommonBuffer,\r
90 CommonBuffer,\r
91 &BufferSizeInBytes,\r
92 &FrameBuffer,\r
93 &Map\r
94 );\r
95 if (EFI_ERROR (Status) || (BufferSizeInBytes != EFI_PAGE_SIZE)) {\r
96 DEBUG ((gEHCErrorLevel, "PciIo->MapBuffer Failed\n"));\r
97 Status = EFI_OUT_OF_RESOURCES;\r
98 goto free_buffer;\r
99 }\r
100\r
101 //\r
102 // Put high 32bit into CtrlDataStructSeg reg \r
103 // when 64bit addressing range capability\r
104 //\r
105 if (HcDev->Is64BitCapable != 0) {\r
106 HcDev->High32BitAddr = (UINT32) GET_32B_TO_63B (FrameBuffer);\r
107 \r
108 Status = SetCtrlDataStructSeg (HcDev);\r
109 if (EFI_ERROR (Status)) {\r
110 DEBUG ((gEHCErrorLevel, "SetCtrlDataStructSeg Failed\n"));\r
111 Status = EFI_DEVICE_ERROR;\r
112 goto unmap_buffer;\r
113 }\r
114 }\r
115 \r
116 //\r
117 // Tell the Host Controller where the Frame List lies,\r
118 // by set the Frame List Base Address Register.\r
119 //\r
120 Status = SetFrameListBaseAddr (HcDev, (UINT32) FrameBuffer);\r
121 if (EFI_ERROR (Status)) {\r
122 Status = EFI_DEVICE_ERROR;\r
123 goto unmap_buffer;\r
124 }\r
125\r
126 HcDev->PeriodicFrameListLength = Length;\r
127 HcDev->PeriodicFrameListBuffer = (VOID *) ((UINTN) FrameBuffer);\r
128 HcDev->PeriodicFrameListMap = Map;\r
129\r
130 //\r
131 // Init Frame List Array fields\r
132 //\r
133 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
134 for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {\r
135 FrameEntryPtr->LinkPointer = 0;\r
136 FrameEntryPtr->Rsvd = 0;\r
137 FrameEntryPtr->SelectType = 0;\r
138 FrameEntryPtr->LinkTerminate = TRUE;\r
139 FrameEntryPtr++;\r
140 }\r
141\r
142 goto exit;\r
143\r
144unmap_buffer:\r
145 HcDev->PciIo->Unmap (HcDev->PciIo, Map);\r
146free_buffer:\r
147 HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);\r
148exit:\r
149 return Status;\r
150}\r
151\r
152VOID\r
153DeinitialPeriodicFrameList (\r
154 IN USB2_HC_DEV *HcDev\r
155 )\r
156/*++\r
157\r
158Routine Description:\r
159\r
160 Deinitialize Periodic Schedule Frame List\r
161\r
162Arguments:\r
163\r
164 HcDev - USB2_HC_DEV\r
165\r
166Returns:\r
167\r
168 VOID\r
169 \r
170--*/\r
171{\r
172 HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->PeriodicFrameListMap);\r
173 HcDev->PciIo->FreeBuffer (HcDev->PciIo, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), HcDev->PeriodicFrameListBuffer);\r
174 return ;\r
175}\r
176\r
177EFI_STATUS\r
178CreatePollingTimer (\r
179 IN USB2_HC_DEV *HcDev,\r
180 IN EFI_EVENT_NOTIFY NotifyFunction\r
181 )\r
182/*++\r
183\r
184Routine Description:\r
185\r
186 Create Async Request Polling Timer\r
187\r
188Arguments:\r
189\r
190 HcDev - USB2_HC_DEV\r
191 NotifyFunction - Timer Notify Function\r
192 \r
193Returns:\r
194 \r
195 EFI_SUCCESS Success\r
196 EFI_DEVICE_ERROR Fail\r
197 \r
198--*/\r
199{\r
200 return gBS->CreateEvent (\r
201 EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,\r
202 EFI_TPL_NOTIFY,\r
203 NotifyFunction,\r
204 HcDev,\r
205 &HcDev->AsyncRequestEvent\r
206 );\r
207}\r
208\r
209EFI_STATUS\r
210DestoryPollingTimer (\r
211 IN USB2_HC_DEV *HcDev\r
212 )\r
213/*++\r
214\r
215Routine Description:\r
216\r
217 Destory Async Request Polling Timer\r
218\r
219Arguments:\r
220\r
221 HcDev - USB2_HC_DEV\r
222 \r
223Returns:\r
224\r
225 EFI_SUCCESS Success\r
226 EFI_DEVICE_ERROR Fail\r
227 \r
228--*/\r
229{\r
230 return gBS->CloseEvent (HcDev->AsyncRequestEvent);\r
231}\r
232\r
233EFI_STATUS\r
234StartPollingTimer (\r
235 IN USB2_HC_DEV *HcDev\r
236 )\r
237/*++\r
238\r
239Routine Description:\r
240\r
241 Start Async Request Polling Timer\r
242\r
243Arguments:\r
244\r
245 HcDev - USB2_HC_DEV\r
246 \r
247Returns:\r
248\r
249 EFI_SUCCESS Success\r
250 EFI_DEVICE_ERROR Fail\r
251 \r
252--*/\r
253{\r
254 return gBS->SetTimer (\r
255 HcDev->AsyncRequestEvent,\r
256 TimerPeriodic,\r
257 EHCI_ASYNC_REQUEST_POLLING_TIME\r
258 );\r
259}\r
260\r
261EFI_STATUS\r
262StopPollingTimer (\r
263 IN USB2_HC_DEV *HcDev\r
264 )\r
265/*++\r
266\r
267Routine Description:\r
268\r
269 Stop Async Request Polling Timer\r
270\r
271Arguments:\r
272\r
273 HcDev - USB2_HC_DEV\r
274 \r
275Returns:\r
276\r
277 EFI_SUCCESS Success\r
278 EFI_DEVICE_ERROR Fail\r
279 \r
280--*/\r
281{\r
282 return gBS->SetTimer (\r
283 HcDev->AsyncRequestEvent,\r
284 TimerCancel,\r
285 EHCI_ASYNC_REQUEST_POLLING_TIME\r
286 );\r
287}\r
288\r
289EFI_STATUS\r
290CreateQh (\r
291 IN USB2_HC_DEV *HcDev,\r
292 IN UINT8 DeviceAddr,\r
293 IN UINT8 Endpoint,\r
294 IN UINT8 DeviceSpeed,\r
295 IN UINTN MaxPacketLen,\r
296 OUT EHCI_QH_ENTITY **QhPtrPtr\r
297 )\r
298/*++\r
299\r
300Routine Description:\r
301\r
302 Create Qh Structure and Pre-Initialize\r
303\r
304Arguments:\r
305\r
306 HcDev - USB2_HC_DEV \r
307 DeviceAddr - Address of Device\r
308 Endpoint - Endpoint Number\r
309 DeviceSpeed - Device Speed\r
310 MaxPacketLen - Max Length of one Packet\r
311 QhPtrPtr - A pointer of pointer to Qh for return\r
312 \r
313Returns:\r
314\r
315 EFI_SUCCESS Success\r
316 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
317 \r
318--*/\r
319{\r
320 EFI_STATUS Status;\r
321 EHCI_QH_HW *QhHwPtr;\r
322\r
323 ASSERT (HcDev);\r
324 ASSERT (QhPtrPtr);\r
325\r
326 *QhPtrPtr = NULL;\r
327\r
328 //\r
329 // Allocate memory for Qh structure\r
330 //\r
331 Status = EhciAllocatePool (\r
332 HcDev,\r
333 (UINT8 **) QhPtrPtr,\r
334 sizeof (EHCI_QH_ENTITY)\r
335 );\r
336 if (EFI_ERROR (Status)) {\r
337 Status = EFI_OUT_OF_RESOURCES;\r
338 goto exit;\r
339 }\r
340 //\r
341 // Init fields in Qh\r
342 //\r
343 gBS->SetMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY), 0);\r
344\r
345 //\r
346 // Software field\r
347 //\r
348 (*QhPtrPtr)->Next = NULL;\r
349 (*QhPtrPtr)->Prev = NULL;\r
350 (*QhPtrPtr)->FirstQtdPtr = NULL;\r
351 (*QhPtrPtr)->AltQtdPtr = NULL;\r
352 (*QhPtrPtr)->LastQtdPtr = NULL;\r
353\r
354 //\r
355 // Hardware field\r
356 //\r
357 QhHwPtr = &((*QhPtrPtr)->Qh);\r
358 QhHwPtr->QhHorizontalPointer = 0;\r
359 QhHwPtr->SelectType = 0;\r
360 QhHwPtr->MaxPacketLen = (UINT32) MaxPacketLen;\r
361 QhHwPtr->EndpointSpeed = (DeviceSpeed & 0x3);\r
362 QhHwPtr->EndpointNum = (Endpoint & 0x0f);\r
363 QhHwPtr->DeviceAddr = (DeviceAddr & 0x7f);\r
364 QhHwPtr->Multiplier = HIGH_BANDWIDTH_PIPE_MULTIPLIER;\r
365 QhHwPtr->Rsvd1 = 0;\r
366 QhHwPtr->Rsvd2 = 0;\r
367 QhHwPtr->Rsvd3 = 0;\r
368 QhHwPtr->Rsvd4 = 0;\r
369 QhHwPtr->Rsvd5 = 0;\r
370 QhHwPtr->Rsvd6 = 0;\r
371\r
372exit:\r
373 return Status;\r
374}\r
375\r
376VOID\r
377DestoryQh (\r
378 IN USB2_HC_DEV *HcDev,\r
379 IN EHCI_QH_ENTITY *QhPtr\r
380 )\r
381/*++\r
382\r
383Routine Description:\r
384\r
385 Destory Qh Structure \r
386 \r
387Arguments:\r
388\r
389 HcDev - USB2_HC_DEV \r
390 QhPtr - A pointer to Qh\r
391 \r
392Returns:\r
393\r
394 EFI_SUCCESS Success\r
395 EFI_DEVICE_ERROR Fail\r
396 \r
397--*/\r
398{\r
399 ASSERT (HcDev);\r
400 ASSERT (QhPtr);\r
401\r
402 EhciFreePool (HcDev, (UINT8 *) QhPtr, sizeof (EHCI_QH_ENTITY));\r
403 return ;\r
404}\r
405\r
406EFI_STATUS\r
407CreateControlQh (\r
408 IN USB2_HC_DEV *HcDev,\r
409 IN UINT8 DeviceAddr,\r
410 IN UINT8 DeviceSpeed,\r
411 IN UINTN MaxPacketLen,\r
412 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
413 OUT EHCI_QH_ENTITY **QhPtrPtr\r
414 )\r
415/*++\r
416\r
417Routine Description:\r
418\r
419 Create Qh for Control Transfer\r
420\r
421Arguments:\r
422\r
423 HcDev - USB2_HC_DEV \r
424 DeviceAddr - Address of Device\r
425 DeviceSpeed - Device Speed\r
426 MaxPacketLen - Max Length of one Packet\r
427 Translator - Translator Transaction for SplitX\r
428 QhPtrPtr - A pointer of pointer to Qh for return\r
429 \r
430Returns:\r
431\r
432 EFI_SUCCESS Success\r
433 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
434 \r
435--*/\r
436{\r
437 EFI_STATUS Status;\r
438\r
439 //\r
440 // Create and init Control Qh\r
441 //\r
442 Status = CreateQh (\r
443 HcDev,\r
444 DeviceAddr,\r
445 0,\r
446 DeviceSpeed,\r
447 MaxPacketLen,\r
448 QhPtrPtr\r
449 );\r
450 if (EFI_ERROR (Status)) {\r
451 Status = EFI_OUT_OF_RESOURCES;\r
452 goto exit;\r
453 }\r
454 //\r
455 // Software field\r
456 //\r
457 (*QhPtrPtr)->Next = (*QhPtrPtr);\r
458 (*QhPtrPtr)->Prev = (*QhPtrPtr);\r
459 (*QhPtrPtr)->TransferType = CONTROL_TRANSFER;\r
460\r
461 //\r
462 // Hardware field\r
463 //\r
464 // Control Transfer use DataToggleControl\r
465 //\r
466 (*QhPtrPtr)->Qh.DataToggleControl = TRUE;\r
467 (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);\r
468 (*QhPtrPtr)->Qh.SelectType = QH_SELECT_TYPE;\r
469 (*QhPtrPtr)->Qh.QhTerminate = FALSE;\r
470 (*QhPtrPtr)->Qh.ControlEndpointFlag = TRUE;\r
471 (*QhPtrPtr)->Qh.NakCountReload = NAK_COUNT_RELOAD;\r
472 if (NULL != Translator) {\r
473 (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;\r
474 (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;\r
475 (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;\r
476 }\r
477\r
478exit:\r
479 return Status;\r
480}\r
481\r
482EFI_STATUS\r
483CreateBulkQh (\r
484 IN USB2_HC_DEV *HcDev,\r
485 IN UINT8 DeviceAddr,\r
486 IN UINT8 EndPointAddr,\r
487 IN UINT8 DeviceSpeed,\r
488 IN UINT8 DataToggle,\r
489 IN UINTN MaxPacketLen,\r
490 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
491 OUT EHCI_QH_ENTITY **QhPtrPtr\r
492 )\r
493/*++\r
494\r
495Routine Description:\r
496\r
497 Create Qh for Bulk Transfer\r
498\r
499Arguments:\r
500\r
501 HcDev - USB2_HC_DEV \r
502 DeviceAddr - Address of Device\r
503 EndPointAddr - Address of Endpoint\r
504 DeviceSpeed - Device Speed\r
505 MaxPacketLen - Max Length of one Packet\r
506 Translator - Translator Transaction for SplitX\r
507 QhPtrPtr - A pointer of pointer to Qh for return\r
508 \r
509Returns:\r
510\r
511 EFI_SUCCESS Success\r
512 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
513 \r
514--*/\r
515{\r
516 EFI_STATUS Status;\r
517\r
518 //\r
519 // Create and init Bulk Qh\r
520 //\r
521 Status = CreateQh (\r
522 HcDev,\r
523 DeviceAddr,\r
524 EndPointAddr,\r
525 DeviceSpeed,\r
526 MaxPacketLen,\r
527 QhPtrPtr\r
528 );\r
529 if (EFI_ERROR (Status)) {\r
530 Status = EFI_OUT_OF_RESOURCES;\r
531 goto exit;\r
532 }\r
533 \r
534 //\r
535 // Software fields\r
536 //\r
537 (*QhPtrPtr)->Next = (*QhPtrPtr);\r
538 (*QhPtrPtr)->Prev = (*QhPtrPtr);\r
539 (*QhPtrPtr)->TransferType = BULK_TRANSFER;\r
540\r
541 //\r
542 // Hardware fields\r
543 //\r
544 // BulkTransfer don't use DataToggleControl\r
545 //\r
546 (*QhPtrPtr)->Qh.DataToggleControl = FALSE; \r
547 (*QhPtrPtr)->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&((*QhPtrPtr)->Qh)) >> 5);\r
548 (*QhPtrPtr)->Qh.SelectType = QH_SELECT_TYPE;\r
549 (*QhPtrPtr)->Qh.QhTerminate = FALSE;\r
550 (*QhPtrPtr)->Qh.NakCountReload = NAK_COUNT_RELOAD;\r
551 (*QhPtrPtr)->Qh.DataToggle = DataToggle;\r
552 if (NULL != Translator) {\r
553 (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;\r
554 (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;\r
555 (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;\r
556 }\r
557\r
558exit:\r
559 return Status;\r
560}\r
561\r
562EFI_STATUS\r
563CreateInterruptQh (\r
564 IN USB2_HC_DEV *HcDev,\r
565 IN UINT8 DeviceAddr,\r
566 IN UINT8 EndPointAddr,\r
567 IN UINT8 DeviceSpeed,\r
568 IN UINT8 DataToggle,\r
569 IN UINTN MaxPacketLen,\r
570 IN UINTN Interval,\r
571 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
572 OUT EHCI_QH_ENTITY **QhPtrPtr\r
573 )\r
574/*++\r
575\r
576Routine Description:\r
577\r
578 Create Qh for Control Transfer\r
579\r
580Arguments:\r
581\r
582 HcDev - USB2_HC_DEV \r
583 DeviceAddr - Address of Device\r
584 EndPointAddr - Address of Endpoint\r
585 DeviceSpeed - Device Speed\r
586 MaxPacketLen - Max Length of one Packet\r
587 Interval - value of interval\r
588 Translator - Translator Transaction for SplitX\r
589 QhPtrPtr - A pointer of pointer to Qh for return\r
590 \r
591Returns:\r
592\r
593 EFI_SUCCESS Success\r
594 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
595 \r
596--*/\r
597{\r
598 EFI_STATUS Status;\r
599\r
600 //\r
601 // Create and init InterruptQh\r
602 //\r
603 Status = CreateQh (\r
604 HcDev,\r
605 DeviceAddr,\r
606 EndPointAddr,\r
607 DeviceSpeed,\r
608 MaxPacketLen,\r
609 QhPtrPtr\r
610 );\r
611 if (EFI_ERROR (Status)) {\r
612 Status = EFI_OUT_OF_RESOURCES;\r
613 goto exit;\r
614 }\r
615 \r
616 //\r
617 // Software fields\r
618 //\r
619 if (Interval == 0) {\r
620 (*QhPtrPtr)->TransferType = SYNC_INTERRUPT_TRANSFER;\r
621 } else {\r
622 (*QhPtrPtr)->TransferType = ASYNC_INTERRUPT_TRANSFER;\r
623 }\r
624 (*QhPtrPtr)->Interval = GetApproxiOfInterval (Interval);\r
625\r
626 //\r
627 // Hardware fields\r
628 //\r
629 // InterruptTranfer don't use DataToggleControl\r
630 //\r
631 (*QhPtrPtr)->Qh.DataToggleControl = FALSE;\r
632 (*QhPtrPtr)->Qh.QhHorizontalPointer = 0;\r
633 (*QhPtrPtr)->Qh.QhTerminate = TRUE;\r
634 (*QhPtrPtr)->Qh.NakCountReload = 0;\r
635 (*QhPtrPtr)->Qh.InerruptScheduleMask = MICRO_FRAME_0_CHANNEL;\r
636 (*QhPtrPtr)->Qh.SplitComletionMask = (MICRO_FRAME_2_CHANNEL | MICRO_FRAME_3_CHANNEL | MICRO_FRAME_4_CHANNEL);\r
637 (*QhPtrPtr)->Qh.DataToggle = DataToggle;\r
638 if (NULL != Translator) {\r
639 (*QhPtrPtr)->Qh.PortNum = Translator->TranslatorPortNumber;\r
640 (*QhPtrPtr)->Qh.HubAddr = Translator->TranslatorHubAddress;\r
641 (*QhPtrPtr)->Qh.Status |= QTD_STATUS_DO_START_SPLIT;\r
642 }\r
643\r
644exit:\r
645 return Status;\r
646}\r
647\r
648EFI_STATUS\r
649CreateQtd (\r
650 IN USB2_HC_DEV *HcDev,\r
651 IN UINT8 *DataPtr,\r
652 IN UINTN DataLen,\r
653 IN UINT8 PktId,\r
654 IN UINT8 Toggle,\r
655 IN UINT8 QtdStatus,\r
656 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
657 )\r
658/*++\r
659\r
660Routine Description:\r
661\r
662 Create Qtd Structure and Pre-Initialize it\r
663\r
664Arguments:\r
665\r
666 HcDev - USB2_HC_DEV \r
667 DataPtr - A pointer to user data buffer to transfer\r
668 DataLen - Length of user data to transfer\r
669 PktId - Packet Identification of this Qtd\r
670 Toggle - Data Toggle of this Qtd\r
671 QtdStatus - Default value of status of this Qtd\r
672 QtdPtrPtr - A pointer of pointer to Qtd for return\r
673 \r
674Returns:\r
675\r
676 EFI_SUCCESS Success\r
677 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
678 \r
679--*/\r
680{\r
681 EFI_STATUS Status;\r
682 EHCI_QTD_HW *QtdHwPtr;\r
683\r
684 ASSERT (HcDev);\r
685 ASSERT (QtdPtrPtr);\r
686\r
687 //\r
688 // Create memory for Qtd structure\r
689 //\r
690 Status = EhciAllocatePool (\r
691 HcDev,\r
692 (UINT8 **) QtdPtrPtr,\r
693 sizeof (EHCI_QTD_ENTITY)\r
694 );\r
695 if (EFI_ERROR (Status)) {\r
696 Status = EFI_OUT_OF_RESOURCES;\r
697 goto exit;\r
698 }\r
699 //\r
700 // Init fields in Qtd\r
701 //\r
702 gBS->SetMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY), 0);\r
703\r
704 //\r
705 // Software field\r
706 //\r
707 (*QtdPtrPtr)->TotalBytes = (UINT32) DataLen;\r
708 (*QtdPtrPtr)->StaticTotalBytes = (UINT32) DataLen;\r
709 (*QtdPtrPtr)->Prev = NULL;\r
710 (*QtdPtrPtr)->Next = NULL;\r
711\r
712 //\r
713 // Hardware field\r
714 //\r
715 QtdHwPtr = &((*QtdPtrPtr)->Qtd);\r
716 QtdHwPtr->NextQtdPointer = 0;\r
717 QtdHwPtr->NextQtdTerminate = TRUE;\r
718 QtdHwPtr->AltNextQtdPointer = 0;\r
719 QtdHwPtr->AltNextQtdTerminate = TRUE;\r
720 QtdHwPtr->DataToggle = Toggle;\r
721 QtdHwPtr->TotalBytes = (UINT32) DataLen;\r
722 QtdHwPtr->CurrentPage = 0;\r
723 QtdHwPtr->ErrorCount = QTD_ERROR_COUNTER;\r
724 QtdHwPtr->Status = QtdStatus;\r
725 QtdHwPtr->Rsvd1 = 0;\r
726 QtdHwPtr->Rsvd2 = 0;\r
727 QtdHwPtr->Rsvd3 = 0;\r
728 QtdHwPtr->Rsvd4 = 0;\r
729 QtdHwPtr->Rsvd5 = 0;\r
730 QtdHwPtr->Rsvd6 = 0;\r
731\r
732 //\r
733 // Set PacketID [Setup/Data/Status]\r
734 //\r
735 switch (PktId) {\r
736 case SETUP_PACKET_ID:\r
737 QtdHwPtr->PidCode = SETUP_PACKET_PID_CODE;\r
738 break;\r
739\r
740 case INPUT_PACKET_ID:\r
741 QtdHwPtr->PidCode = INPUT_PACKET_PID_CODE;\r
742 break;\r
743\r
744 case OUTPUT_PACKET_ID:\r
745 QtdHwPtr->PidCode = OUTPUT_PACKET_PID_CODE;\r
746 break;\r
747\r
748 default:\r
749 Status = EFI_INVALID_PARAMETER;\r
750 goto exit;\r
751 }\r
752 \r
753 //\r
754 // Set Data Buffer Pointers\r
755 //\r
756 if (NULL != DataPtr) {\r
757 SetQtdBufferPointer (\r
758 QtdHwPtr,\r
759 DataPtr,\r
760 DataLen\r
761 );\r
762 (*QtdPtrPtr)->StaticCurrentOffset = QtdHwPtr->CurrentOffset;\r
763 }\r
764\r
765exit:\r
766 return Status;\r
767}\r
768\r
769EFI_STATUS\r
770CreateSetupQtd (\r
771 IN USB2_HC_DEV *HcDev,\r
772 IN UINT8 *DevReqPtr,\r
773 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
774 )\r
775/*++\r
776\r
777Routine Description:\r
778\r
779 Create Qtd Structure for Setup \r
780\r
781Arguments:\r
782\r
783 HcDev - USB2_HC_DEV \r
784 DevReqPtr - A pointer to Device Request Data\r
785 QtdPtrPtr - A pointer of pointer to Qtd for return\r
786 \r
787Returns:\r
788\r
789 EFI_SUCCESS Success\r
790 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
791 \r
792--*/\r
793{\r
794 return CreateQtd (\r
795 HcDev,\r
796 DevReqPtr,\r
797 sizeof (EFI_USB_DEVICE_REQUEST),\r
798 SETUP_PACKET_ID,\r
799 DATA0,\r
800 QTD_STATUS_ACTIVE,\r
801 QtdPtrPtr\r
802 );\r
803}\r
804\r
805EFI_STATUS\r
806CreateDataQtd (\r
807 IN USB2_HC_DEV *HcDev,\r
808 IN UINT8 *DataPtr,\r
809 IN UINTN DataLen,\r
810 IN UINT8 PktId,\r
811 IN UINT8 Toggle,\r
812 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
813 )\r
814/*++\r
815\r
816Routine Description:\r
817\r
818 Create Qtd Structure for data \r
819\r
820Arguments:\r
821\r
822 HcDev - USB2_HC_DEV \r
823 DataPtr - A pointer to user data buffer to transfer\r
824 DataLen - Length of user data to transfer\r
825 PktId - Packet Identification of this Qtd\r
826 Toggle - Data Toggle of this Qtd\r
827 QtdPtrPtr - A pointer of pointer to Qtd for return\r
828 \r
829Returns:\r
830\r
831 EFI_SUCCESS Success\r
832 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
833 \r
834--*/\r
835{\r
836 return CreateQtd (\r
837 HcDev,\r
838 DataPtr,\r
839 DataLen,\r
840 PktId,\r
841 Toggle,\r
842 QTD_STATUS_ACTIVE,\r
843 QtdPtrPtr\r
844 );\r
845}\r
846\r
847EFI_STATUS\r
848CreateAltQtd (\r
849 IN USB2_HC_DEV *HcDev,\r
850 IN UINT8 PktId,\r
851 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
852 )\r
853/*++\r
854\r
855Routine Description:\r
856\r
857 Create Qtd Structure for Alternative \r
858\r
859Arguments:\r
860\r
861 HcDev - USB2_HC_DEV \r
862 PktId - Packet Identification of this Qtd\r
863 QtdPtrPtr - A pointer of pointer to Qtd for return\r
864 \r
865Returns:\r
866\r
867 EFI_SUCCESS Success\r
868 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
869 \r
870--*/\r
871{\r
872 return CreateQtd (\r
873 HcDev,\r
874 NULL,\r
875 0,\r
876 PktId,\r
877 0,\r
878 QTD_STATUS_ACTIVE,\r
879 QtdPtrPtr\r
880 );\r
881}\r
882\r
883EFI_STATUS\r
884CreateStatusQtd (\r
885 IN USB2_HC_DEV *HcDev,\r
886 IN UINT8 PktId,\r
887 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
888 )\r
889/*++\r
890\r
891Routine Description:\r
892\r
893 Create Qtd Structure for status \r
894\r
895Arguments:\r
896\r
897 HcDev - USB2_HC_DEV \r
898 PktId - Packet Identification of this Qtd\r
899 QtdPtrPtr - A pointer of pointer to Qtd for return\r
900 \r
901Returns:\r
902\r
903 EFI_SUCCESS Success\r
904 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
905 \r
906--*/\r
907{\r
908 return CreateQtd (\r
909 HcDev,\r
910 NULL,\r
911 0,\r
912 PktId,\r
913 DATA1,\r
914 QTD_STATUS_ACTIVE,\r
915 QtdPtrPtr\r
916 );\r
917}\r
918\r
919EFI_STATUS\r
920CreateControlQtds (\r
921 IN USB2_HC_DEV *HcDev,\r
922 IN UINT8 DataPktId,\r
923 IN UINT8 *RequestCursor,\r
924 IN UINT8 *DataCursor,\r
925 IN UINTN DataLen,\r
926 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
927 OUT EHCI_QTD_ENTITY **ControlQtdsHead\r
928 )\r
929/*++\r
930\r
931Routine Description:\r
932\r
933 Create Qtds list for Control Transfer \r
934\r
935Arguments:\r
936\r
937 HcDev - USB2_HC_DEV \r
938 DataPktId - Packet Identification of Data Qtds\r
939 RequestCursor - A pointer to request structure buffer to transfer\r
940 DataCursor - A pointer to user data buffer to transfer\r
941 DataLen - Length of user data to transfer\r
942 ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return\r
943 \r
944Returns:\r
945\r
946 EFI_SUCCESS Success\r
947 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
948 \r
949--*/\r
950{\r
951 EFI_STATUS Status;\r
952 EHCI_QTD_ENTITY *QtdPtr;\r
953 EHCI_QTD_ENTITY *PreQtdPtr;\r
954 EHCI_QTD_ENTITY *SetupQtdPtr;\r
955 EHCI_QTD_ENTITY *FirstDataQtdPtr;\r
956 EHCI_QTD_ENTITY *LastDataQtdPtr;\r
957 EHCI_QTD_ENTITY *StatusQtdPtr;\r
958 UINT8 DataToggle;\r
959 UINT8 StatusPktId;\r
960 UINTN CapacityOfQtd;\r
961 UINTN SizePerQtd;\r
962 UINTN DataCount;\r
963 UINTN Xnum;\r
964 \r
965 QtdPtr = NULL;\r
966 PreQtdPtr = NULL;\r
967 SetupQtdPtr = NULL;\r
968 FirstDataQtdPtr = NULL;\r
969 LastDataQtdPtr = NULL;\r
970 StatusQtdPtr = NULL;\r
971 CapacityOfQtd = 0;\r
972\r
973 //\r
974 // Setup Stage of Control Transfer\r
975 //\r
976 Status = CreateSetupQtd (\r
977 HcDev,\r
978 RequestCursor,\r
979 &SetupQtdPtr\r
980 );\r
981 if (EFI_ERROR (Status)) {\r
982 Status = EFI_OUT_OF_RESOURCES;\r
983 goto exit;\r
984 }\r
985 \r
986 //\r
987 // Data Stage of Control Transfer\r
988 //\r
989 DataToggle = 1;\r
990 DataCount = DataLen;\r
991\r
992 //\r
993 // Create Qtd structure and link together\r
994 //\r
995 while (DataCount > 0) {\r
996 //\r
997 // PktSize is the data load size that each Qtd.\r
998 //\r
999 CapacityOfQtd = GetCapacityOfQtd (DataCursor);\r
1000 SizePerQtd = DataCount;\r
1001 if (DataCount > CapacityOfQtd) {\r
1002 SizePerQtd = CapacityOfQtd;\r
1003 }\r
1004\r
1005 Status = CreateDataQtd (\r
1006 HcDev,\r
1007 DataCursor,\r
1008 SizePerQtd,\r
1009 DataPktId,\r
1010 DataToggle,\r
1011 &QtdPtr\r
1012 );\r
1013 if (EFI_ERROR (Status)) {\r
1014 Status = EFI_OUT_OF_RESOURCES;\r
1015 if (NULL == FirstDataQtdPtr) {\r
1016 goto destory_setup_qtd;\r
1017 } else {\r
1018 goto destory_qtds;\r
1019 }\r
1020 }\r
1021\r
1022 if (NULL == FirstDataQtdPtr) {\r
1023 FirstDataQtdPtr = QtdPtr;\r
1024 } else {\r
1025 LinkQtdToQtd (PreQtdPtr, QtdPtr);\r
1026 }\r
1027\r
1028 //\r
1029 // Reverse Data Toggle or not determined by parity of transactions of one qtd\r
1030 //\r
1031 Xnum = Translator ? GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE_WITH_TT) : GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE);\r
1032 if (Xnum % 2 != 0) {\r
1033 DataToggle ^= 1;\r
1034 }\r
1035 \r
1036 PreQtdPtr = QtdPtr;\r
1037 DataCursor += SizePerQtd;\r
1038 DataCount -= SizePerQtd;\r
1039 }\r
1040\r
1041 LastDataQtdPtr = QtdPtr;\r
1042\r
1043 //\r
1044 // Status Stage of Control Transfer\r
1045 //\r
1046 if (OUTPUT_PACKET_ID == DataPktId) {\r
1047 StatusPktId = INPUT_PACKET_ID;\r
1048 } else {\r
1049 StatusPktId = OUTPUT_PACKET_ID;\r
1050 }\r
1051\r
1052 Status = CreateStatusQtd (\r
1053 HcDev,\r
1054 StatusPktId,\r
1055 &StatusQtdPtr\r
1056 );\r
1057 if (EFI_ERROR (Status)) {\r
1058 Status = EFI_OUT_OF_RESOURCES;\r
1059 goto destory_qtds;\r
1060 }\r
1061 \r
1062 //\r
1063 // Link setup Qtd -> data Qtds -> status Qtd\r
1064 //\r
1065 if (FirstDataQtdPtr != NULL) {\r
1066 LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);\r
1067 LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);\r
1068 } else {\r
1069 LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);\r
1070 }\r
1071\r
1072 *ControlQtdsHead = SetupQtdPtr;\r
1073\r
1074 goto exit;\r
1075\r
1076destory_qtds:\r
1077 DestoryQtds (HcDev, FirstDataQtdPtr);\r
1078destory_setup_qtd:\r
1079 DestoryQtds (HcDev, SetupQtdPtr);\r
1080exit:\r
1081 return Status;\r
1082}\r
1083\r
1084EFI_STATUS\r
1085CreateBulkOrInterruptQtds (\r
1086 IN USB2_HC_DEV *HcDev,\r
1087 IN UINT8 PktId,\r
1088 IN UINT8 *DataCursor,\r
1089 IN UINTN DataLen,\r
1090 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1091 OUT EHCI_QTD_ENTITY **QtdsHead\r
1092 )\r
1093/*++\r
1094\r
1095Routine Description:\r
1096\r
1097 Create Qtds list for Bulk or Interrupt Transfer \r
1098\r
1099Arguments:\r
1100\r
1101 HcDev - USB2_HC_DEV \r
1102 PktId - Packet Identification of Qtds\r
1103 DataCursor - A pointer to user data buffer to transfer\r
1104 DataLen - Length of user data to transfer\r
1105 DataToggle - Data Toggle to start\r
1106 Translator - Translator Transaction for SplitX\r
1107 QtdsHead - A pointer of pointer to first Qtd for control tranfer for return\r
1108 \r
1109Returns:\r
1110\r
1111 EFI_SUCCESS Success\r
1112 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
1113 \r
1114--*/\r
1115{\r
1116 EFI_STATUS Status;\r
1117 EHCI_QTD_ENTITY *QtdPtr;\r
1118 EHCI_QTD_ENTITY *PreQtdPtr;\r
1119 EHCI_QTD_ENTITY *FirstQtdPtr;\r
1120 EHCI_QTD_ENTITY *AltQtdPtr;\r
1121 UINTN DataCount;\r
1122 UINTN CapacityOfQtd;\r
1123 UINTN SizePerQtd;\r
1124\r
1125 Status = EFI_SUCCESS;\r
1126 QtdPtr = NULL;\r
1127 PreQtdPtr = NULL;\r
1128 FirstQtdPtr = NULL;\r
1129 AltQtdPtr = NULL;\r
1130 CapacityOfQtd = 0;\r
1131\r
1132 DataCount = DataLen;\r
1133 while (DataCount > 0) {\r
1134\r
1135 CapacityOfQtd = GetCapacityOfQtd (DataCursor);\r
1136 SizePerQtd = DataCount;\r
1137 if (DataCount > CapacityOfQtd) {\r
1138 SizePerQtd = CapacityOfQtd;\r
1139 }\r
1140\r
1141 Status = CreateDataQtd (\r
1142 HcDev,\r
1143 DataCursor,\r
1144 SizePerQtd,\r
1145 PktId,\r
1146 0,\r
1147 &QtdPtr\r
1148 );\r
1149 if (EFI_ERROR (Status)) {\r
1150 Status = EFI_OUT_OF_RESOURCES;\r
1151 if (NULL == FirstQtdPtr) {\r
1152 goto exit;\r
1153 } else {\r
1154 goto destory_qtds;\r
1155 }\r
1156 }\r
1157\r
1158 if (NULL == FirstQtdPtr) {\r
1159 FirstQtdPtr = QtdPtr;\r
1160 } else {\r
1161 LinkQtdToQtd (PreQtdPtr, QtdPtr);\r
1162 }\r
1163\r
1164 PreQtdPtr = QtdPtr;\r
1165 DataCursor += SizePerQtd;\r
1166 DataCount -= SizePerQtd;\r
1167 }\r
1168 \r
1169 //\r
1170 // Set Alternate Qtd\r
1171 //\r
1172 if (INPUT_PACKET_ID == PktId && 1 < GetNumberOfQtd (FirstQtdPtr)) {\r
1173 Status = CreateAltQtd (\r
1174 HcDev,\r
1175 PktId,\r
1176 &AltQtdPtr\r
1177 );\r
1178 if (EFI_ERROR (Status)) {\r
1179 Status = EFI_OUT_OF_RESOURCES;\r
1180 goto destory_qtds;\r
1181 }\r
1182\r
1183 LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);\r
1184 }\r
1185\r
1186 *QtdsHead = FirstQtdPtr;\r
1187 goto exit;\r
1188\r
1189destory_qtds:\r
1190 DestoryQtds (HcDev, FirstQtdPtr);\r
1191exit:\r
1192 return Status;\r
1193}\r
1194\r
1195VOID\r
1196DestoryQtds (\r
1197 IN USB2_HC_DEV *HcDev,\r
1198 IN EHCI_QTD_ENTITY *FirstQtdPtr\r
1199 )\r
1200/*++\r
1201\r
1202Routine Description:\r
1203\r
1204 Destory all Qtds in the list\r
1205\r
1206Arguments:\r
1207\r
1208 HcDev - USB2_HC_DEV \r
1209 FirstQtdPtr - A pointer to first Qtd in the list \r
1210 \r
1211Returns:\r
1212\r
1213 VOID\r
1214\r
1215--*/\r
1216{\r
1217 EHCI_QTD_ENTITY *PrevQtd;\r
1218 EHCI_QTD_ENTITY *NextQtd;\r
1219\r
1220 if (!FirstQtdPtr) {\r
1221 goto exit;\r
1222 }\r
1223\r
1224 PrevQtd = FirstQtdPtr;\r
1225\r
1226 //\r
1227 // Delete all the Qtds.\r
1228 //\r
1229 do {\r
1230 NextQtd = PrevQtd->Next;\r
1231 EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));\r
1232 PrevQtd = NextQtd;\r
1233 } while (NULL != PrevQtd);\r
1234\r
1235exit:\r
1236 return ;\r
1237}\r
1238\r
1239UINTN\r
1240GetNumberOfQtd (\r
1241 IN EHCI_QTD_ENTITY *FirstQtdPtr\r
1242 )\r
1243/*++\r
1244\r
1245Routine Description:\r
1246\r
1247 Number of Qtds in the list\r
1248 \r
1249Arguments:\r
1250\r
1251 FirstQtdPtr - A pointer to first Qtd in the list\r
1252 \r
1253Returns:\r
1254\r
1255 Number of Qtds in the list\r
1256\r
1257--*/\r
1258{\r
1259 UINTN Count;\r
1260 EHCI_QTD_ENTITY *QtdPtr;\r
1261 Count = 0;\r
1262 QtdPtr = FirstQtdPtr;\r
1263\r
1264 ;\r
1265\r
1266 while (NULL != QtdPtr) {\r
1267 Count++;\r
1268 QtdPtr = QtdPtr->Next;\r
1269 }\r
1270\r
1271 return Count;\r
1272}\r
1273\r
1274UINTN\r
1275GetNumberOfTransaction (\r
1276 IN UINTN SizeOfData,\r
1277 IN UINTN SizeOfTransaction\r
1278 )\r
1279/*++\r
1280\r
1281Routine Description:\r
1282\r
1283 Number of Transactions in one Qtd\r
1284 \r
1285Arguments:\r
1286\r
1287 SizeOfData - Size of one Qtd\r
1288 SizeOfTransaction - Size of one Transaction\r
1289 \r
1290Returns:\r
1291\r
1292 Number of Transactions in this Qtd\r
1293\r
1294--*/\r
1295{\r
1296\r
1297 return ((SizeOfData & (SizeOfTransaction - 1)) ? SizeOfData / SizeOfTransaction + 1 : SizeOfData / SizeOfTransaction);\r
1298\r
1299}\r
1300\r
1301UINTN\r
1302GetCapacityOfQtd (\r
1303 IN UINT8 *BufferCursor\r
1304 )\r
1305/*++\r
1306\r
1307Routine Description:\r
1308\r
1309 Get Size of First Qtd\r
1310 \r
1311Arguments:\r
1312\r
1313 BufferCursor - BufferCursor of the Qtd\r
1314 \r
1315Returns:\r
1316\r
1317 Size of First Qtd\r
1318\r
1319--*/\r
1320{\r
1321\r
1322 return (EHCI_MAX_QTD_CAPACITY - (EHCI_BLOCK_SIZE * GetNumberOfTransaction (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor), EHCI_BLOCK_SIZE)));\r
1323\r
1324}\r
1325\r
1326UINTN\r
1327GetApproxiOfInterval (\r
1328 IN UINTN Interval\r
1329 )\r
1330/*++\r
1331\r
1332Routine Description:\r
1333\r
1334 Get the approximate value in the 2 index sequence\r
1335 \r
1336Arguments:\r
1337\r
1338 Interval - the value of interval\r
1339 \r
1340Returns:\r
1341\r
1342 approximate value of interval in the 2 index sequence\r
1343 \r
1344--*/\r
1345{\r
1346 UINTN Orignate;\r
1347 UINTN Approxi;\r
1348\r
1349 Orignate = Interval;\r
1350 Approxi = 1;\r
1351\r
1352 while (Orignate != 1 && Orignate != 0) {\r
1353 Orignate = Orignate >> 1;\r
1354 Approxi = Approxi << 1;\r
1355 }\r
1356\r
1357 if (Interval & (Approxi >> 1)) {\r
1358 Approxi = Approxi << 1;\r
1359 }\r
1360\r
1361 return Approxi;\r
1362}\r
1363\r
1364EHCI_QTD_HW *\r
1365GetQtdAlternateNextPointer (\r
1366 IN EHCI_QTD_HW *HwQtdPtr\r
1367 )\r
1368/*++\r
1369\r
1370Routine Description:\r
1371\r
1372 Get Qtd alternate next pointer field\r
1373 \r
1374Arguments:\r
1375\r
1376 HwQtdPtr - A pointer to hardware Qtd structure\r
1377 \r
1378Returns:\r
1379\r
1380 A pointer to hardware alternate Qtd\r
1381 \r
1382--*/\r
1383{\r
1384 EHCI_QTD_HW *Value;\r
1385\r
1386 Value = NULL;\r
1387\r
1388 if (!HwQtdPtr->AltNextQtdTerminate) {\r
ffac4bcb 1389 Value = (EHCI_QTD_HW *) (UINTN) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);\r
562d2849 1390 }\r
1391\r
1392 return Value;\r
1393}\r
1394\r
1395EHCI_QTD_HW *\r
1396GetQtdNextPointer (\r
1397 IN EHCI_QTD_HW *HwQtdPtr\r
1398 )\r
1399/*++\r
1400\r
1401Routine Description:\r
1402\r
1403 Get Qtd next pointer field\r
1404 \r
1405Arguments:\r
1406\r
1407 HwQtdPtr - A pointer to hardware Qtd structure\r
1408 \r
1409Returns:\r
1410\r
1411 A pointer to next hardware Qtd structure\r
1412 \r
1413--*/\r
1414{\r
1415 EHCI_QTD_HW *Value;\r
1416\r
1417 Value = NULL;\r
1418\r
1419 if (!HwQtdPtr->NextQtdTerminate) {\r
ffac4bcb 1420 Value = (EHCI_QTD_HW *) (UINTN) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);\r
562d2849 1421 }\r
1422\r
1423 return Value;\r
1424}\r
1425\r
1426VOID LinkQtdToQtd (\r
1427 IN EHCI_QTD_ENTITY * PreQtdPtr, \r
1428 IN EHCI_QTD_ENTITY * QtdPtr\r
1429 )\r
1430/*++\r
1431\r
1432Routine Description:\r
1433\r
1434 Link Qtds together\r
1435 \r
1436Arguments:\r
1437\r
1438 PreQtdPtr - A pointer to pre Qtd\r
1439 QtdPtr - A pointer to next Qtd\r
1440 \r
1441Returns:\r
1442\r
1443 VOID\r
1444\r
1445--*/\r
1446{\r
1447 EHCI_QTD_HW *QtdHwPtr;\r
1448\r
1449 ASSERT(PreQtdPtr);\r
1450 ASSERT(QtdPtr);\r
1451\r
1452 //\r
1453 // Software link\r
1454 //\r
1455 PreQtdPtr->Next = QtdPtr;\r
1456 QtdPtr->Prev = PreQtdPtr;\r
1457\r
1458 //\r
1459 // Hardware link\r
1460 //\r
1461 QtdHwPtr = &(QtdPtr->Qtd);\r
1462 PreQtdPtr->Qtd.NextQtdPointer = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);\r
1463 PreQtdPtr->Qtd.NextQtdTerminate = FALSE;\r
1464\r
1465 return ;\r
1466}\r
1467\r\r
1468\r
1469VOID LinkQtdsToAltQtd (\r
1470 IN EHCI_QTD_ENTITY * FirstQtdPtr, \r
1471 IN EHCI_QTD_ENTITY * AltQtdPtr\r
1472 )\r
1473/*++\r
1474\r
1475Routine Description:\r
1476\r
1477 Link AlterQtds together\r
1478 \r
1479Arguments:\r
1480\r
1481 FirstQtdPtr - A pointer to first Qtd in the list\r
1482 AltQtdPtr - A pointer to alternative Qtd\r
1483 \r
1484Returns:\r
1485\r
1486 VOID\r
1487\r
1488--*/\r
1489{\r
1490 EHCI_QTD_ENTITY *QtdPtr;\r
1491 EHCI_QTD_HW *AltQtdHwPtr;\r
1492\r
1493 ASSERT(FirstQtdPtr);\r
1494 ASSERT(AltQtdPtr);\r
1495\r
1496 AltQtdHwPtr = &(AltQtdPtr->Qtd);\r
1497 QtdPtr = FirstQtdPtr;\r
1498 \r
1499 while (NULL != QtdPtr) {\r
1500 //\r
1501 // Software link\r
1502 //\r
1503 QtdPtr->AltNext = AltQtdPtr;\r
1504 //\r
1505 // Hardware link\r
1506 //\r
1507 QtdPtr->Qtd.AltNextQtdPointer = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);\r
1508 QtdPtr->Qtd.AltNextQtdTerminate = FALSE;\r
1509 QtdPtr = QtdPtr->Next;\r
1510 }\r
1511\r
1512 return ;\r
1513}\r
1514\r
1515VOID\r
1516LinkQtdToQh (\r
1517 IN EHCI_QH_ENTITY *QhPtr,\r
1518 IN EHCI_QTD_ENTITY *QtdPtr\r
1519 )\r
1520/*++\r
1521\r
1522Routine Description:\r
1523\r
1524 Link Qtds list to Qh\r
1525 \r
1526Arguments:\r
1527\r
1528 QhPtr - A pointer to Qh\r
1529 QtdPtr - A pointer to first Qtd in the list\r
1530 \r
1531Returns:\r
1532\r
1533 VOID\r
1534\r
1535--*/\r
1536{\r
1537 EHCI_QTD_ENTITY *Cursor;\r
1538 EHCI_QTD_HW *QtdHwPtr;\r
1539\r
1540 ASSERT (QhPtr);\r
1541 ASSERT (QtdPtr);\r
1542\r
1543 QhPtr->FirstQtdPtr = QtdPtr;\r
1544 if (NULL != QtdPtr->AltNext) {\r
1545 QhPtr->AltQtdPtr = QtdPtr->AltNext;\r
1546 }\r
1547\r
1548 Cursor = QtdPtr;\r
1549 while (NULL != Cursor) {\r
1550 Cursor->SelfQh = QhPtr;\r
1551 if (NULL == Cursor->Next) {\r
1552 QhPtr->LastQtdPtr = Cursor;\r
1553 }\r
1554\r
1555 Cursor = Cursor->Next;\r
1556 }\r
1557\r
1558 QtdHwPtr = &(QtdPtr->Qtd);\r
1559 QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);\r
1560 QhPtr->Qh.NextQtdTerminate = FALSE;\r
1561\r
1562 return ;\r
1563}\r
1564\r
1565EFI_STATUS\r
1566LinkQhToAsyncList (\r
1567 IN USB2_HC_DEV *HcDev,\r
1568 IN EHCI_QH_ENTITY *QhPtr\r
1569 )\r
1570/*++\r
1571\r
1572Routine Description:\r
1573\r
1574 Link Qh to Async Schedule List\r
1575 \r
1576Arguments:\r
1577\r
1578 HcDev - USB2_HC_DEV \r
1579 QhPtr - A pointer to Qh\r
1580 \r
1581Returns:\r
1582\r
1583 EFI_SUCCESS Success\r
1584 EFI_DEVICE_ERROR Fail\r
1585 \r
1586--*/\r
1587{\r
1588 EFI_STATUS Status;\r
1589\r
1590 ASSERT (HcDev);\r
1591 ASSERT (QhPtr);\r
1592\r
1593 QhPtr->Qh.HeadReclamationFlag = TRUE;\r
1594\r
1595 Status = SetAsyncListAddr (HcDev, QhPtr);\r
1596 if (EFI_ERROR (Status)) {\r
1597 Status = EFI_DEVICE_ERROR;\r
1598 goto exit;\r
1599 }\r
1600\r
1601 if (!IsAsyncScheduleEnabled (HcDev)) {\r
1602\r
1603 Status = EnableAsynchronousSchedule (HcDev);\r
1604 if (EFI_ERROR (Status)) {\r
1605 Status = EFI_DEVICE_ERROR;\r
1606 goto exit;\r
1607 }\r
1608\r
1609 Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
1610 if (EFI_ERROR (Status)) {\r
1611 DEBUG ((gEHCDebugLevel, "WaitForAsyncScheduleEnable TimeOut"));\r
1612 Status = EFI_TIMEOUT;\r
1613 goto exit;\r
1614 }\r
1615\r
1616 if (IsEhcHalted (HcDev)) {\r
1617 Status = StartScheduleExecution (HcDev);\r
1618 if (EFI_ERROR (Status)) {\r
1619 Status = EFI_DEVICE_ERROR;\r
1620 }\r
1621 }\r
1622\r
1623 }\r
1624\r
1625exit:\r
1626 return Status;\r
1627}\r
1628\r
1629EFI_STATUS\r
1630UnlinkQhFromAsyncList (\r
1631 IN USB2_HC_DEV *HcDev,\r
1632 IN EHCI_QH_ENTITY *QhPtr\r
1633 )\r
1634/*++\r
1635\r
1636Routine Description:\r
1637\r
1638 Unlink Qh from Async Schedule List\r
1639 \r
1640Arguments:\r
1641\r
1642 HcDev - USB2_HC_DEV \r
1643 QhPtr - A pointer to Qh\r
1644 \r
1645Returns:\r
1646\r
1647 EFI_SUCCESS Success\r
1648 EFI_DEVICE_ERROR Fail\r
1649 \r
1650--*/\r
1651{\r
1652 EFI_STATUS Status;\r
1653\r
1654 Status = EFI_SUCCESS;\r
1655\r
1656 ASSERT (HcDev);\r
1657 ASSERT (QhPtr);\r
1658\r
1659 if (QhPtr == QhPtr->Next) {\r
1660\r
1661 Status = DisableAsynchronousSchedule (HcDev);\r
1662 if (EFI_ERROR (Status)) {\r
1663 Status = EFI_DEVICE_ERROR;\r
1664 goto exit;\r
1665 }\r
1666\r
1667 Status = WaitForAsyncScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
1668 if (EFI_ERROR (Status)) {\r
1669 DEBUG ((gEHCErrorLevel, "WaitForAsyncScheduleDisable TimeOut\n"));\r
1670 Status = EFI_TIMEOUT;\r
1671 goto exit;\r
1672 }\r
1673\r
1674 }\r
1675\r
1676exit:\r
1677 return Status;\r
1678}\r
1679\r
1680VOID\r
1681LinkQhToPeriodicList (\r
1682 IN USB2_HC_DEV *HcDev,\r
1683 IN EHCI_QH_ENTITY *QhPtr\r
1684 )\r
1685/*++\r
1686\r
1687Routine Description:\r
1688\r
1689 Link Qh to Periodic Schedule List\r
1690 \r
1691Arguments:\r
1692\r
1693 HcDev - USB2_HC_DEV \r
1694 QhPtr - A pointer to Qh\r
1695 \r
1696Returns:\r
1697\r
1698 VOID\r
1699 \r
1700--*/\r
1701{\r
1702 FRAME_LIST_ENTRY *FrameEntryPtr;\r
1703 EHCI_QH_ENTITY *FindQhPtr;\r
1704 EHCI_QH_HW *FindQhHwPtr;\r
1705 UINTN FrameIndex;\r
1706\r
1707 ASSERT (HcDev);\r
1708 ASSERT (QhPtr);\r
1709\r
1710 FindQhPtr = NULL;\r
1711 FindQhHwPtr = NULL;\r
1712 FrameIndex = 0;\r
1713 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
1714\r
1715 QhPtr->Qh.HeadReclamationFlag = FALSE;\r
1716\r
1717 if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {\r
1718 \r
1719 //\r
1720 // AsyncInterruptTransfer Qh\r
1721 //\r
1722 \r
1723 //\r
1724 // Link to Frame[0] List\r
1725 //\r
1726 if (!FrameEntryPtr->LinkTerminate) {\r
1727 //\r
1728 // Not Null FrameList\r
1729 //\r
ffac4bcb 1730 FindQhHwPtr = (EHCI_QH_HW *) (UINTN) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
562d2849 1731 FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);\r
1732 //\r
1733 // FindQh is Left/Right to Qh\r
1734 //\r
1735 while ((NULL != FindQhPtr->Next) && (FindQhPtr->Interval > QhPtr->Interval)) {\r
1736 FindQhPtr = FindQhPtr->Next;\r
1737 }\r
1738\r
1739 if (FindQhPtr->Interval == QhPtr->Interval) {\r
1740 //\r
1741 // Link Qh after FindQh\r
1742 //\r
1743 if (NULL != FindQhPtr->Next) {\r
1744 FindQhPtr->Next->Prev = QhPtr;\r
ffac4bcb 1745 QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(FindQhPtr->Next->Qh)) >> 5);\r
562d2849 1746 QhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1747 QhPtr->Qh.QhTerminate = FALSE;\r
1748 }\r
1749\r
ffac4bcb 1750 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN)&(QhPtr->Qh)) >> 5);\r
562d2849 1751 FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1752 FindQhPtr->Qh.QhTerminate = FALSE;\r
1753\r
1754 QhPtr->Prev = FindQhPtr;\r
1755 QhPtr->Next = FindQhPtr->Next;\r
1756 FindQhPtr->Next = QhPtr;\r
1757 } else if (FindQhPtr->Interval < QhPtr->Interval) {\r
1758 //\r
1759 // Link Qh before FindQh\r
1760 //\r
1761 if (NULL == FindQhPtr->Prev) {\r
1762 //\r
1763 // Qh is the First one in Frame[0] List\r
1764 //\r
ffac4bcb 1765 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1766 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1767 FrameEntryPtr->LinkTerminate = FALSE;\r
1768 } else {\r
1769 //\r
1770 // Qh is not the First one in Frame[0] List\r
1771 //\r
1772 FindQhPtr->Prev->Next = QhPtr;\r
ffac4bcb 1773 FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1774 FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;\r
1775 FindQhPtr->Prev->Qh.QhTerminate = FALSE;\r
1776 }\r
1777\r
ffac4bcb 1778 QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(FindQhPtr->Qh)) >> 5);\r
562d2849 1779 QhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1780 QhPtr->Qh.QhTerminate = FALSE;\r
1781\r
1782 QhPtr->Next = FindQhPtr;\r
1783 QhPtr->Prev = FindQhPtr->Prev;\r
1784 FindQhPtr->Prev = QhPtr;\r
1785 } else {\r
1786 //\r
1787 // Link Qh after FindQh, Qh is the Last one\r
1788 //\r
ffac4bcb 1789 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1790 FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;\r
1791 FindQhPtr->Qh.QhTerminate = FALSE;\r
1792\r
1793 QhPtr->Prev = FindQhPtr;\r
1794 QhPtr->Next = NULL;\r
1795 FindQhPtr->Next = QhPtr;\r
1796 }\r
1797 } else {\r
1798 //\r
1799 // Null FrameList\r
1800 //\r
ffac4bcb 1801 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1802 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1803 FrameEntryPtr->LinkTerminate = FALSE;\r
1804 }\r
1805 //\r
1806 // Other Frame[X]\r
1807 //\r
1808 if (NULL == QhPtr->Prev) {\r
1809 //\r
1810 // Qh is the First one in Frame[0] List\r
1811 //\r
1812 FrameIndex += QhPtr->Interval;\r
1813 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1814 FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);\r
ffac4bcb 1815 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1816 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1817 FrameEntryPtr->LinkTerminate = FALSE;\r
1818 FrameIndex += QhPtr->Interval;\r
1819 }\r
1820 } else if (QhPtr->Interval < QhPtr->Prev->Interval) {\r
1821 //\r
1822 // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval\r
1823 //\r
1824 FrameIndex += QhPtr->Interval;\r
1825 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1826 FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);\r
1827 if ((FrameIndex % QhPtr->Prev->Interval) != 0) {\r
ffac4bcb 1828 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1829 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1830 FrameEntryPtr->LinkTerminate = FALSE;\r
1831 }\r
1832\r
1833 FrameIndex += QhPtr->Interval;\r
1834 }\r
1835 }\r
1836 } else {\r
1837 \r
1838 //\r
1839 // SyncInterruptTransfer Qh\r
1840 //\r
1841 \r
1842 if (!FrameEntryPtr->LinkTerminate) {\r
1843 //\r
1844 // Not Null FrameList\r
1845 //\r
ffac4bcb 1846 FindQhHwPtr = (EHCI_QH_HW *) (UINTN) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
562d2849 1847 FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);\r
1848 //\r
1849 // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh\r
1850 //\r
1851 while (NULL != FindQhPtr->Next) {\r
1852 FindQhPtr = FindQhPtr->Next;\r
1853 }\r
1854\r
ffac4bcb 1855 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1856 FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1857 FindQhPtr->Qh.QhTerminate = FALSE;\r
1858\r
1859 FindQhPtr->Next = QhPtr;\r
1860 QhPtr->Prev = FindQhPtr;\r
1861 } else {\r
1862 //\r
1863 // Null FrameList\r
1864 //\r
ffac4bcb 1865 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Qh)) >> 5);\r
562d2849 1866 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1867 FrameEntryPtr->LinkTerminate = FALSE;\r
1868 }\r
1869 }\r
1870\r
1871 return ;\r
1872}\r
1873\r
1874VOID\r
1875UnlinkQhFromPeriodicList (\r
1876 IN USB2_HC_DEV *HcDev,\r
1877 IN EHCI_QH_ENTITY *QhPtr,\r
1878 IN UINTN Interval\r
1879 )\r
1880/*++\r
1881\r
1882Routine Description:\r
1883\r
1884 Unlink Qh from Periodic Schedule List\r
1885 \r
1886Arguments:\r
1887\r
1888 HcDev - USB2_HC_DEV \r
1889 QhPtr - A pointer to Qh\r
1890 Interval - Interval of this periodic transfer\r
1891 \r
1892Returns:\r
1893\r
1894 VOID\r
1895 \r
1896--*/\r
1897{\r
1898 FRAME_LIST_ENTRY *FrameEntryPtr;\r
1899 UINTN FrameIndex;\r
1900\r
1901 FrameIndex = 0;\r
1902\r
1903 ASSERT (HcDev);\r
1904 ASSERT (QhPtr);\r
1905\r
1906 FrameIndex = 0;\r
1907 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
1908\r
1909 if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {\r
1910 \r
1911 //\r
1912 // AsyncInterruptTransfer Qh\r
1913 //\r
1914 \r
1915 if (NULL == QhPtr->Prev) {\r
1916 //\r
1917 // Qh is the First one on Frame[0] List\r
1918 //\r
1919 if (NULL == QhPtr->Next) {\r
1920 //\r
1921 // Only one on Frame[0] List\r
1922 //\r
1923 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1924 FrameEntryPtr->LinkPointer = 0;\r
1925 FrameEntryPtr->SelectType = 0;\r
1926 FrameEntryPtr->LinkTerminate = TRUE;\r
1927 FrameEntryPtr += Interval;\r
1928 FrameIndex += Interval;\r
1929 }\r
1930 } else {\r
1931 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
ffac4bcb 1932 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Next->Qh)) >> 5);\r
562d2849 1933 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1934 FrameEntryPtr->LinkTerminate = FALSE;\r
1935 FrameEntryPtr += Interval;\r
1936 FrameIndex += Interval;\r
1937 }\r
1938 }\r
1939 } else {\r
1940 \r
1941 //\r
1942 // Not First one on Frame[0] List\r
1943 //\r
1944 if (NULL == QhPtr->Next) {\r
1945 //\r
1946 // Qh is the Last one on Frame[0] List\r
1947 //\r
1948 QhPtr->Prev->Qh.QhHorizontalPointer = 0;\r
1949 QhPtr->Prev->Qh.SelectType = 0;\r
1950 QhPtr->Prev->Qh.QhTerminate = TRUE;\r
1951 } else {\r
ffac4bcb 1952 QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (((UINTN) &(QhPtr->Next->Qh)) >> 5);\r
562d2849 1953 QhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;\r
1954 QhPtr->Prev->Qh.QhTerminate = FALSE;\r
1955 }\r
1956\r
1957 if (Interval == QhPtr->Prev->Interval) {\r
1958 //\r
1959 // Interval is the same as Prev\r
1960 // Not involed Frame[X]\r
1961 //\r
1962 } else {\r
1963 //\r
1964 // Other Frame[X]\r
1965 //\r
1966 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1967 if ((FrameIndex % QhPtr->Prev->Interval) != 0) {\r
1968 FrameEntryPtr->LinkPointer = QhPtr->Prev->Qh.QhHorizontalPointer;\r
1969 FrameEntryPtr->SelectType = QhPtr->Prev->Qh.SelectType;\r
1970 FrameEntryPtr->LinkTerminate = QhPtr->Prev->Qh.QhTerminate;\r
1971 }\r
1972 FrameEntryPtr += Interval;\r
1973 FrameIndex += Interval;\r
1974 }\r
1975 }\r
1976 }\r
1977\r
1978 if (NULL != QhPtr->Next) {\r
1979 QhPtr->Next->Prev = QhPtr->Prev;\r
1980 }\r
1981\r
1982 if (NULL != QhPtr->Prev) {\r
1983 QhPtr->Prev->Next = QhPtr->Next;\r
1984 }\r
1985 } else {\r
1986 //\r
1987 // SyncInterruptTransfer Qh\r
1988 //\r
1989 if (NULL == QhPtr->Prev) {\r
1990 //\r
1991 // Qh is the only one Qh on Frame[0] List\r
1992 //\r
1993 FrameEntryPtr->LinkPointer = 0;\r
1994 FrameEntryPtr->SelectType = 0;\r
1995 FrameEntryPtr->LinkTerminate = TRUE;\r
1996 } else {\r
1997 QhPtr->Prev->Qh.QhHorizontalPointer = 0;\r
1998 QhPtr->Prev->Qh.SelectType = 0;\r
1999 QhPtr->Prev->Qh.QhTerminate = TRUE;\r
2000 }\r
2001\r
2002 if (NULL != QhPtr->Prev) {\r
2003 QhPtr->Prev->Next = NULL;\r
2004 }\r
2005 }\r
2006\r
2007 return ;\r
2008}\r
2009\r
2010VOID\r
2011LinkToAsyncReqeust (\r
2012 IN USB2_HC_DEV *HcDev,\r
2013 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
2014 )\r
2015/*++\r
2016\r
2017Routine Description:\r
2018\r
2019 Llink AsyncRequest Entry to Async Request List\r
2020 \r
2021Arguments:\r
2022\r
2023 HcDev - USB2_HC_DEV \r
2024 AsyncRequestPtr - A pointer to Async Request Entry\r
2025 \r
2026Returns:\r
2027\r
2028 VOID\r
2029 \r
2030--*/\r
2031{\r
2032 EHCI_ASYNC_REQUEST *CurrentPtr;\r
2033\r
2034 CurrentPtr = HcDev->AsyncRequestList;\r
2035 HcDev->AsyncRequestList = AsyncRequestPtr;\r
2036 AsyncRequestPtr->Prev = NULL;\r
2037 AsyncRequestPtr->Next = CurrentPtr;\r
2038\r
2039 if (NULL != CurrentPtr) {\r
2040 CurrentPtr->Prev = AsyncRequestPtr;\r
2041 }\r
2042\r
2043 return ;\r
2044}\r
2045\r
2046VOID\r
2047UnlinkFromAsyncReqeust (\r
2048 IN USB2_HC_DEV *HcDev,\r
2049 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
2050 )\r
2051/*++\r
2052\r
2053Routine Description:\r
2054\r
2055 Unlink AsyncRequest Entry from Async Request List\r
2056 \r
2057Arguments:\r
2058\r
2059 HcDev - USB2_HC_DEV \r
2060 AsyncRequestPtr - A pointer to Async Request Entry\r
2061 \r
2062Returns:\r
2063\r
2064 VOID\r
2065 \r
2066--*/\r
2067{\r
2068 if (NULL == AsyncRequestPtr->Prev) {\r
2069 HcDev->AsyncRequestList = AsyncRequestPtr->Next;\r
2070 if (NULL != AsyncRequestPtr->Next) {\r
2071 AsyncRequestPtr->Next->Prev = NULL;\r
2072 }\r
2073 } else {\r
2074 AsyncRequestPtr->Prev->Next = AsyncRequestPtr->Next;\r
2075 if (NULL != AsyncRequestPtr->Next) {\r
2076 AsyncRequestPtr->Next->Prev = AsyncRequestPtr->Prev;\r
2077 }\r
2078 }\r
2079\r
2080 return ;\r
2081}\r
2082\r
2083VOID\r
2084SetQtdBufferPointer (\r
2085 IN EHCI_QTD_HW *QtdHwPtr,\r
2086 IN VOID *DataPtr,\r
2087 IN UINTN DataLen\r
2088 )\r
2089/*++\r
2090\r
2091Routine Description:\r
2092\r
2093 Set data buffer pointers in Qtd\r
2094\r
2095Arguments:\r
2096\r
2097 QtdHwPtr - A pointer to Qtd hardware structure \r
2098 DataPtr - A pointer to user data buffer\r
2099 DataLen - Length of the user data buffer\r
2100 \r
2101Returns:\r
2102\r
2103 VOID\r
2104\r
2105--*/\r
2106{\r
2107 UINTN RemainLen;\r
2108\r
2109 RemainLen = DataLen;\r
2110 ASSERT (QtdHwPtr);\r
2111\r
2112 //\r
2113 // Set BufferPointer0, ExtBufferPointer0 and Offset\r
2114 //\r
2115 QtdHwPtr->BufferPointer0 = (UINT32) (GET_0B_TO_31B (DataPtr) >> 12);\r
2116 QtdHwPtr->CurrentOffset = (UINT32) (GET_0B_TO_31B (DataPtr) & EFI_PAGE_MASK);\r
2117 QtdHwPtr->ExtBufferPointer0 = (UINT32) GET_32B_TO_63B (DataPtr);\r
2118\r
2119 //\r
2120 // Set BufferPointer1 and ExtBufferPointer1\r
2121 //\r
2122 RemainLen = RemainLen > (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset) ? (RemainLen - (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset)) : 0;\r
2123 if (RemainLen == 0) {\r
2124 goto exit;\r
2125 }\r
2126\r
2127 QtdHwPtr->BufferPointer1 = QtdHwPtr->BufferPointer0 + 1;\r
2128 QtdHwPtr->ExtBufferPointer1 = QtdHwPtr->ExtBufferPointer0;\r
2129\r
2130 //\r
2131 // Set BufferPointer2 and ExtBufferPointer2\r
2132 //\r
2133 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
2134 if (RemainLen == 0) {\r
2135 goto exit;\r
2136 }\r
2137\r
2138 QtdHwPtr->BufferPointer2 = QtdHwPtr->BufferPointer1 + 1;\r
2139 QtdHwPtr->ExtBufferPointer2 = QtdHwPtr->ExtBufferPointer0;\r
2140\r
2141 //\r
2142 // Set BufferPointer3 and ExtBufferPointer3\r
2143 //\r
2144 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
2145 if (RemainLen == 0) {\r
2146 goto exit;\r
2147 }\r
2148\r
2149 QtdHwPtr->BufferPointer3 = QtdHwPtr->BufferPointer2 + 1;\r
2150 QtdHwPtr->ExtBufferPointer3 = QtdHwPtr->ExtBufferPointer0;\r
2151\r
2152 //\r
2153 // Set BufferPointer4 and ExtBufferPointer4\r
2154 //\r
2155 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
2156 if (RemainLen == 0) {\r
2157 goto exit;\r
2158 }\r
2159\r
2160 QtdHwPtr->BufferPointer4 = QtdHwPtr->BufferPointer3 + 1;\r
2161 QtdHwPtr->ExtBufferPointer4 = QtdHwPtr->ExtBufferPointer0;\r
2162\r
2163exit:\r
2164 return ;\r
2165}\r
2166\r
2167BOOLEAN\r
2168IsQtdStatusActive (\r
2169 IN EHCI_QTD_HW *HwQtdPtr\r
2170 )\r
2171/*++\r
2172\r
2173Routine Description:\r
2174\r
2175 Whether Qtd status is active or not\r
2176 \r
2177Arguments:\r
2178\r
2179 HwQtdPtr - A pointer to hardware Qtd structure\r
2180 \r
2181Returns:\r
2182\r
2183 TRUE Active\r
2184 FALSE Inactive\r
2185 \r
2186--*/\r
2187{\r
2188 UINT8 QtdStatus;\r
2189 BOOLEAN Value;\r
2190\r
2191 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2192 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_ACTIVE);\r
2193\r
2194 return Value;\r
2195}\r
2196\r
2197BOOLEAN\r
2198IsQtdStatusHalted (\r
2199 IN EHCI_QTD_HW *HwQtdPtr\r
2200 )\r
2201/*++\r
2202\r
2203Routine Description:\r
2204\r
2205 Whether Qtd status is halted or not\r
2206 \r
2207Arguments:\r
2208\r
2209 HwQtdPtr - A pointer to hardware Qtd structure\r
2210 \r
2211Returns:\r
2212\r
2213 TRUE Halted\r
2214 FALSE Not halted\r
2215 \r
2216--*/\r
2217{\r
2218 UINT8 QtdStatus;\r
2219 BOOLEAN Value;\r
2220\r
2221 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2222 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_HALTED);\r
2223\r
2224 return Value;\r
2225}\r
2226\r
2227BOOLEAN\r
2228IsQtdStatusBufferError (\r
2229 IN EHCI_QTD_HW *HwQtdPtr\r
2230 )\r
2231/*++\r
2232\r
2233Routine Description:\r
2234\r
2235 Whether Qtd status is buffer error or not\r
2236 \r
2237Arguments:\r
2238\r
2239 HwQtdPtr - A pointer to hardware Qtd structure\r
2240 \r
2241Returns:\r
2242\r
2243 TRUE Buffer error\r
2244 FALSE No buffer error\r
2245 \r
2246--*/\r
2247{\r
2248 UINT8 QtdStatus;\r
2249 BOOLEAN Value;\r
2250\r
2251 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2252 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BUFFER_ERR);\r
2253\r
2254 return Value;\r
2255}\r
2256\r
2257BOOLEAN\r
2258IsQtdStatusBabbleError (\r
2259 IN EHCI_QTD_HW *HwQtdPtr\r
2260 )\r
2261/*++\r
2262\r
2263Routine Description:\r
2264\r
2265 Whether Qtd status is babble error or not\r
2266 \r
2267Arguments:\r
2268\r
2269 HwQtdPtr - A pointer to hardware Qtd structure\r
2270 \r
2271Returns:\r
2272\r
2273 TRUE Babble error\r
2274 FALSE No babble error\r
2275 \r
2276--*/\r
2277{\r
2278 UINT8 QtdStatus;\r
2279 BOOLEAN Value;\r
2280\r
2281 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2282 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BABBLE_ERR);\r
2283\r
2284 return Value;\r
2285}\r
2286\r
2287BOOLEAN\r
2288IsQtdStatusTransactionError (\r
2289 IN EHCI_QTD_HW *HwQtdPtr\r
2290 )\r
2291/*++\r
2292\r
2293Routine Description:\r
2294\r
2295 Whether Qtd status is transaction error or not\r
2296 \r
2297Arguments:\r
2298\r
2299 HwQtdPtr - A pointer to hardware Qtd structure\r
2300 \r
2301Returns:\r
2302\r
2303 TRUE Transaction error\r
2304 FALSE No transaction error\r
2305 \r
2306--*/\r
2307{\r
2308 UINT8 QtdStatus;\r
2309 BOOLEAN Value;\r
2310\r
2311 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2312 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_TRANSACTION_ERR);\r
2313\r
2314 return Value;\r
2315}\r
2316\r
2317BOOLEAN\r
2318IsDataInTransfer (\r
2319 IN UINT8 EndPointAddress\r
2320 )\r
2321/*++\r
2322\r
2323Routine Description:\r
2324\r
2325 Whether is a DataIn direction transfer\r
2326 \r
2327Arguments:\r
2328\r
2329 EndPointAddress - address of the endpoint \r
2330 \r
2331Returns:\r
2332\r
2333 TRUE DataIn\r
2334 FALSE DataOut\r
2335 \r
2336--*/\r
2337{\r
2338 BOOLEAN Value;\r
2339\r
2340 if (EndPointAddress & 0x80) {\r
2341 Value = TRUE;\r
2342 } else {\r
2343 Value = FALSE;\r
2344 }\r
2345\r
2346 return Value;\r
2347}\r
2348\r
2349EFI_STATUS\r
2350MapDataBuffer (\r
2351 IN USB2_HC_DEV *HcDev,\r
2352 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
2353 IN VOID *Data,\r
2354 IN OUT UINTN *DataLength,\r
2355 OUT UINT8 *PktId,\r
2356 OUT UINT8 **DataCursor,\r
2357 OUT VOID **DataMap\r
2358 )\r
2359/*++\r
2360\r
2361Routine Description:\r
2362\r
2363 Map address of user data buffer\r
2364 \r
2365Arguments:\r
2366\r
2367 HcDev - USB2_HC_DEV \r
2368 TransferDirection - direction of transfer\r
2369 Data - A pointer to user data buffer \r
2370 DataLength - length of user data\r
2371 PktId - Packte Identificaion\r
2372 DataCursor - mapped address to return\r
2373 DataMap - identificaion of this mapping to return\r
2374 \r
2375Returns:\r
2376\r
2377 EFI_SUCCESS Success\r
2378 EFI_DEVICE_ERROR Fail\r
2379 \r
2380--*/\r
2381{\r
2382 EFI_STATUS Status;\r
2383 EFI_PHYSICAL_ADDRESS TempPhysicalAddr;\r
2384\r
2385 Status = EFI_SUCCESS;\r
2386\r
2387 switch (TransferDirection) {\r
2388\r
2389 case EfiUsbDataIn:\r
2390\r
2391 *PktId = INPUT_PACKET_ID;\r
2392 //\r
2393 // BusMasterWrite means cpu read\r
2394 //\r
2395 Status = HcDev->PciIo->Map (\r
2396 HcDev->PciIo,\r
2397 EfiPciIoOperationBusMasterWrite,\r
2398 Data,\r
2399 DataLength,\r
2400 &TempPhysicalAddr,\r
2401 DataMap\r
2402 );\r
2403 if (EFI_ERROR (Status)) {\r
2404 DEBUG ((gEHCDebugLevel, "MapDataBuffer Failed\n"));\r
2405 Status = EFI_DEVICE_ERROR;\r
2406 goto exit;\r
2407 }\r
2408\r
2409 *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
2410 break;\r
2411\r
2412 case EfiUsbDataOut:\r
2413\r
2414 *PktId = OUTPUT_PACKET_ID;\r
2415 //\r
2416 // BusMasterRead means cpu write\r
2417 //\r
2418 Status = HcDev->PciIo->Map (\r
2419 HcDev->PciIo,\r
2420 EfiPciIoOperationBusMasterRead,\r
2421 Data,\r
2422 DataLength,\r
2423 &TempPhysicalAddr,\r
2424 DataMap\r
2425 );\r
2426 if (EFI_ERROR (Status)) {\r
2427 Status = EFI_DEVICE_ERROR;\r
2428 goto exit;\r
2429 }\r
2430\r
2431 *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
2432 break;\r
2433\r
2434 case EfiUsbNoData:\r
2435\r
2436 *PktId = OUTPUT_PACKET_ID;\r
2437 Data = NULL;\r
2438 *DataLength = 0;\r
2439 *DataCursor = NULL;\r
2440 *DataMap = NULL;\r
2441 break;\r
2442\r
2443 default:\r
2444 \r
2445 Status = EFI_INVALID_PARAMETER;\r
2446 }\r
2447\r
2448exit:\r
2449 return Status;\r
2450}\r
2451\r
2452EFI_STATUS\r
2453MapRequestBuffer (\r
2454 IN USB2_HC_DEV *HcDev,\r
2455 IN OUT VOID *Request,\r
2456 OUT UINT8 **RequestCursor,\r
2457 OUT VOID **RequestMap\r
2458 )\r
2459/*++\r
2460\r
2461Routine Description:\r
2462\r
2463 Map address of request structure buffer\r
2464 \r
2465Arguments:\r
2466\r
2467 HcDev - USB2_HC_DEV \r
2468 Request - A pointer to request structure\r
2469 RequestCursor - Mapped address of request structure to return\r
2470 RequestMap - Identificaion of this mapping to return\r
2471 \r
2472Returns:\r
2473\r
2474 EFI_SUCCESS Success\r
2475 EFI_DEVICE_ERROR Fail\r
2476 \r
2477--*/\r
2478{\r
2479 EFI_STATUS Status;\r
2480 UINTN RequestLen;\r
2481 EFI_PHYSICAL_ADDRESS TempPhysicalAddr;\r
2482\r
2483 RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);\r
2484 Status = HcDev->PciIo->Map (\r
2485 HcDev->PciIo,\r
2486 EfiPciIoOperationBusMasterRead,\r
2487 (UINT8 *) Request,\r
2488 (UINTN *) &RequestLen,\r
2489 &TempPhysicalAddr,\r
2490 RequestMap\r
2491 );\r
2492 if (EFI_ERROR (Status)) {\r
2493 Status = EFI_DEVICE_ERROR;\r
2494 goto exit;\r
2495 }\r
2496\r
2497 *RequestCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
2498\r
2499exit:\r
2500 return Status;\r
2501}\r
2502\r
2503EFI_STATUS\r
2504DeleteAsyncRequestTransfer (\r
2505 IN USB2_HC_DEV *HcDev,\r
2506 IN UINT8 DeviceAddress,\r
2507 IN UINT8 EndPointAddress,\r
2508 OUT UINT8 *DataToggle\r
2509 )\r
2510/*++\r
2511\r
2512Routine Description:\r
2513\r
2514 Delete all asynchronous request transfer\r
2515 \r
2516Arguments:\r
2517\r
2518 HcDev - USB2_HC_DEV \r
2519 DeviceAddress - address of usb device\r
2520 EndPointAddress - address of endpoint\r
2521 DataToggle - stored data toggle\r
2522 \r
2523Returns:\r
2524\r
2525 EFI_SUCCESS Success\r
2526 EFI_DEVICE_ERROR Fail\r
2527 \r
2528--*/\r
2529{\r
2530 EFI_STATUS Status;\r
2531 EHCI_ASYNC_REQUEST *AsyncRequestPtr;\r
2532 EHCI_ASYNC_REQUEST *MatchPtr;\r
2533 EHCI_QH_HW *QhHwPtr;\r
2534 UINT8 EndPointNum;\r
2535\r
2536 if (NULL == HcDev->AsyncRequestList) {\r
2537 Status = EFI_INVALID_PARAMETER;\r
2538 goto exit;\r
2539 }\r
2540\r
2541 MatchPtr = NULL;\r
2542 QhHwPtr = NULL;\r
2543 EndPointNum = EndPointAddress & 0x0f;\r
2544 AsyncRequestPtr = HcDev->AsyncRequestList;\r
2545\r
2546 //\r
2547 // Find QH of AsyncRequest by DeviceAddress and EndPointNum\r
2548 //\r
2549 do {\r
2550\r
2551 QhHwPtr = &(AsyncRequestPtr->QhPtr->Qh);\r
2552 if (QhHwPtr->DeviceAddr == DeviceAddress && QhHwPtr->EndpointNum == EndPointNum) {\r
2553 MatchPtr = AsyncRequestPtr;\r
2554 break;\r
2555 }\r
2556\r
2557 AsyncRequestPtr = AsyncRequestPtr->Next;\r
2558\r
2559 } while (NULL != AsyncRequestPtr);\r
2560\r
2561 if (NULL == MatchPtr) {\r
2562 Status = EFI_INVALID_PARAMETER;\r
2563 goto exit;\r
2564 }\r
2565\r
2566 Status = DisablePeriodicSchedule (HcDev);\r
2567 if (EFI_ERROR (Status)) {\r
2568 Status = EFI_DEVICE_ERROR;\r
2569 goto exit;\r
2570 }\r
2571\r
2572 Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2573 if (EFI_ERROR (Status)) {\r
2574 DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleDisable TimeOut\n"));\r
2575 Status = EFI_TIMEOUT;\r
2576 goto exit;\r
2577 }\r
2578\r
2579 *DataToggle = (UINT8) MatchPtr->QhPtr->Qh.DataToggle;\r
2580 UnlinkQhFromPeriodicList (HcDev, MatchPtr->QhPtr, MatchPtr->QhPtr->Interval);\r
2581 UnlinkFromAsyncReqeust (HcDev, MatchPtr);\r
2582\r
2583 if (NULL == HcDev->AsyncRequestList) {\r
2584\r
2585 Status = StopPollingTimer (HcDev);\r
2586 if (EFI_ERROR (Status)) {\r
2587 Status = EFI_DEVICE_ERROR;\r
2588 goto exit;\r
2589 }\r
2590\r
2591 } else {\r
2592\r
2593 Status = EnablePeriodicSchedule (HcDev);\r
2594 if (EFI_ERROR (Status)) {\r
2595 Status = EFI_DEVICE_ERROR;\r
2596 goto exit;\r
2597 }\r
2598\r
2599 Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2600 if (EFI_ERROR (Status)) {\r
2601 DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleEnable TimeOut\n"));\r
2602 Status = EFI_TIMEOUT;\r
2603 goto exit;\r
2604 }\r
2605\r
2606 if (IsEhcHalted (HcDev)) {\r
2607 Status = StartScheduleExecution (HcDev);\r
2608 if (EFI_ERROR (Status)) {\r
2609 Status = EFI_DEVICE_ERROR;\r
2610 goto exit;\r
2611 }\r
2612 }\r
2613\r
2614 }\r
2615\r
2616 DestoryQtds (HcDev, MatchPtr->QhPtr->FirstQtdPtr);\r
2617 DestoryQh (HcDev, MatchPtr->QhPtr);\r
2618 EhciFreePool (HcDev, (UINT8 *) MatchPtr, sizeof (EHCI_ASYNC_REQUEST));\r
2619\r
2620exit:\r
2621 return Status;\r
2622}\r
2623\r
2624VOID\r
2625CleanUpAllAsyncRequestTransfer (\r
2626 IN USB2_HC_DEV *HcDev\r
2627 )\r
2628/*++\r
2629\r
2630Routine Description:\r
2631\r
2632 Clean up all asynchronous request transfer\r
2633 \r
2634Arguments:\r
2635\r
2636 HcDev - USB2_HC_DEV \r
2637 \r
2638Returns:\r
2639\r
2640 VOID\r
2641 \r
2642--*/\r
2643{\r
2644 EHCI_ASYNC_REQUEST *AsyncRequestPtr;\r
2645 EHCI_ASYNC_REQUEST *FreePtr;\r
2646\r
2647 AsyncRequestPtr = NULL;\r
2648 FreePtr = NULL;\r
2649\r
2650 StopPollingTimer (HcDev);\r
2651\r
2652 AsyncRequestPtr = HcDev->AsyncRequestList;\r
2653 while (NULL != AsyncRequestPtr) {\r
2654\r
2655 FreePtr = AsyncRequestPtr;\r
2656 AsyncRequestPtr = AsyncRequestPtr->Next;\r
2657 UnlinkFromAsyncReqeust (HcDev, FreePtr);\r
2658 UnlinkQhFromPeriodicList (HcDev, FreePtr->QhPtr, FreePtr->QhPtr->Interval);\r
2659 DestoryQtds (HcDev, FreePtr->QhPtr->FirstQtdPtr);\r
2660 DestoryQh (HcDev, FreePtr->QhPtr);\r
2661 EhciFreePool (HcDev, (UINT8 *) FreePtr, sizeof (EHCI_ASYNC_REQUEST));\r
2662\r
2663 }\r
2664\r
2665 return ;\r
2666}\r
2667\r
2668VOID\r
2669ZeroOutQhOverlay (\r
2670 IN EHCI_QH_ENTITY *QhPtr\r
2671 )\r
2672/*++\r
2673\r
2674Routine Description:\r
2675\r
2676 Zero out the fields in Qh structure\r
2677 \r
2678Arguments:\r
2679\r
2680 QhPtr - A pointer to Qh structure\r
2681 \r
2682Returns:\r
2683\r
2684 VOID\r
2685 \r
2686--*/\r
2687{\r
2688 QhPtr->Qh.CurrentQtdPointer = 0;\r
2689 QhPtr->Qh.AltNextQtdPointer = 0;\r
2690 QhPtr->Qh.NakCount = 0;\r
2691 QhPtr->Qh.AltNextQtdTerminate = 0;\r
2692 QhPtr->Qh.TotalBytes = 0;\r
2693 QhPtr->Qh.InterruptOnComplete = 0;\r
2694 QhPtr->Qh.CurrentPage = 0;\r
2695 QhPtr->Qh.ErrorCount = 0;\r
2696 QhPtr->Qh.PidCode = 0;\r
2697 QhPtr->Qh.Status = 0;\r
2698 QhPtr->Qh.BufferPointer0 = 0;\r
2699 QhPtr->Qh.CurrentOffset = 0;\r
2700 QhPtr->Qh.BufferPointer1 = 0;\r
2701 QhPtr->Qh.CompleteSplitMask = 0;\r
2702 QhPtr->Qh.BufferPointer2 = 0;\r
2703 QhPtr->Qh.SplitBytes = 0;\r
2704 QhPtr->Qh.FrameTag = 0;\r
2705 QhPtr->Qh.BufferPointer3 = 0;\r
2706 QhPtr->Qh.BufferPointer4 = 0;\r
2707 QhPtr->Qh.ExtBufferPointer0 = 0;\r
2708 QhPtr->Qh.ExtBufferPointer1 = 0;\r
2709 QhPtr->Qh.ExtBufferPointer2 = 0;\r
2710 QhPtr->Qh.ExtBufferPointer3 = 0;\r
2711 QhPtr->Qh.ExtBufferPointer4 = 0;\r
2712}\r
2713\r
2714VOID\r
2715UpdateAsyncRequestTransfer (\r
2716 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,\r
2717 IN UINT32 TransferResult,\r
2718 IN UINTN ErrQtdPos\r
2719 )\r
2720/*++\r
2721\r
2722Routine Description:\r
2723\r
2724 Update asynchronous request transfer\r
2725 \r
2726Arguments:\r
2727\r
2728 AsyncRequestPtr - A pointer to async request \r
2729 TransferResult - transfer result \r
2730 ErrQtdPos - postion of error Qtd\r
2731 \r
2732Returns:\r
2733\r
2734 VOID\r
2735 \r
2736--*/\r
2737{\r
2738 EHCI_QTD_ENTITY *QtdPtr;\r
2739\r
2740 QtdPtr = NULL;\r
2741\r
2742 if (EFI_USB_NOERROR == TransferResult) {\r
2743 \r
2744 //\r
2745 // Update Qh for next trigger\r
2746 //\r
2747\r
2748 QtdPtr = AsyncRequestPtr->QhPtr->FirstQtdPtr;\r
2749\r
2750 //\r
2751 // Update fields in Qh\r
2752 //\r
2753\r
2754 //\r
2755 // Get DataToggle from Overlay in Qh\r
2756 //\r
2757 // ZeroOut Overlay in Qh except DataToggle, HostController will update this field\r
2758 //\r
2759 ZeroOutQhOverlay (AsyncRequestPtr->QhPtr);\r
2760 AsyncRequestPtr->QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (&(QtdPtr->Qtd)) >> 5);\r
2761 AsyncRequestPtr->QhPtr->Qh.NextQtdTerminate = FALSE;\r
2762\r
2763 //\r
2764 // Update fields in Qtd\r
2765 //\r
2766 while (NULL != QtdPtr) {\r
2767 QtdPtr->Qtd.TotalBytes = QtdPtr->StaticTotalBytes;\r
2768 QtdPtr->Qtd.CurrentOffset = QtdPtr->StaticCurrentOffset;\r
2769 QtdPtr->Qtd.CurrentPage = 0;\r
2770 QtdPtr->Qtd.ErrorCount = QTD_ERROR_COUNTER;\r
2771 QtdPtr->Qtd.Status = QTD_STATUS_ACTIVE;\r
2772\r
2773 QtdPtr->TotalBytes = QtdPtr->StaticTotalBytes;\r
2774 QtdPtr = QtdPtr->Next;\r
2775 }\r
2776 }\r
2777\r
2778 return ;\r
2779}\r
2780\r
2781BOOLEAN\r
2782CheckQtdsTransferResult (\r
2783 IN BOOLEAN IsControl,\r
2784 IN EHCI_QH_ENTITY *QhPtr,\r
2785 OUT UINT32 *Result,\r
2786 OUT UINTN *ErrQtdPos,\r
2787 OUT UINTN *ActualLen\r
2788 )\r
2789/*++\r
2790\r
2791Routine Description:\r
2792\r
2793 Check transfer result of Qtds\r
2794\r
2795Arguments:\r
2796\r
2797 IsControl - Is control transfer or not\r
2798 QhPtr - A pointer to Qh\r
2799 Result - Transfer result\r
2800 ErrQtdPos - Error TD Position\r
2801 ActualLen - Actual Transfer Size\r
2802\r
2803Returns:\r
2804\r
2805 TRUE Qtds finished\r
2806 FALSE Not finish\r
2807 \r
2808--*/\r
2809{\r
2810 UINTN ActualLenPerQtd;\r
2811 EHCI_QTD_ENTITY *QtdPtr;\r
2812 EHCI_QTD_HW *QtdHwPtr;\r
2813 BOOLEAN Value;\r
2814\r
2815 ASSERT (QhPtr);\r
2816 ASSERT (Result);\r
2817 ASSERT (ErrQtdPos);\r
2818 ASSERT (ActualLen);\r
2819\r
2820 Value = TRUE;\r
2821 QtdPtr = QhPtr->FirstQtdPtr;\r
2822 QtdHwPtr = &(QtdPtr->Qtd);\r
2823\r
2824 while (NULL != QtdHwPtr) {\r
2825\r
2826 if (IsQtdStatusActive (QtdHwPtr)) {\r
2827 *Result |= EFI_USB_ERR_NOTEXECUTE;\r
2828 }\r
2829\r
2830 if (IsQtdStatusHalted (QtdHwPtr)) {\r
2831 *Result |= EFI_USB_ERR_STALL;\r
2832 }\r
2833\r
2834 if (IsQtdStatusBufferError (QtdHwPtr)) {\r
2835 *Result |= EFI_USB_ERR_BUFFER;\r
2836 }\r
2837\r
2838 if (IsQtdStatusBabbleError (QtdHwPtr)) {\r
2839 *Result |= EFI_USB_ERR_BABBLE;\r
2840 }\r
2841\r
2842 if (IsQtdStatusTransactionError (QtdHwPtr)) {\r
2843 *Result |= EFI_USB_ERR_TIMEOUT;\r
2844 }\r
2845\r
2846 ActualLenPerQtd = QtdPtr->TotalBytes - QtdHwPtr->TotalBytes;\r
2847 QtdPtr->TotalBytes = QtdHwPtr->TotalBytes;\r
2848 //\r
2849 // Accumulate actual transferred data length in each DataQtd.\r\r
2850 //\r
2851 if (SETUP_PACKET_PID_CODE != QtdHwPtr->PidCode) {\r
2852 *ActualLen += ActualLenPerQtd;\r
2853 }\r
2854\r
2855 if (*Result) {\r
2856 Value = FALSE;\r
2857 break;\r
2858 }\r
2859\r
2860 if ((!IsControl) && (QtdPtr->TotalBytes > 0)) {\r
2861 //\r
2862 // Did something, but isn't full workload\r
2863 //\r
2864 break;\r
2865 }\r
2866\r
2867 (*ErrQtdPos)++;\r
2868 QtdHwPtr = GetQtdNextPointer (QtdHwPtr);\r
2869 QtdPtr = (EHCI_QTD_ENTITY *) GET_QTD_ENTITY_ADDR (QtdHwPtr);\r
2870\r
2871 }\r
2872\r
2873 return Value;\r
2874}\r
2875\r
2876EFI_STATUS\r
2877ExecuteTransfer (\r
2878 IN USB2_HC_DEV *HcDev,\r
2879 IN BOOLEAN IsControl,\r
2880 IN EHCI_QH_ENTITY *QhPtr,\r
2881 IN OUT UINTN *ActualLen,\r
2882 OUT UINT8 *DataToggle,\r
2883 IN UINTN TimeOut,\r
2884 OUT UINT32 *TransferResult\r
2885 )\r
2886/*++\r
2887\r
2888Routine Description:\r
2889\r
2890 Execute Bulk or SyncInterrupt Transfer\r
2891\r
2892Arguments:\r
2893\r
2894 HcDev - USB2_HC_DEV\r
2895 IsControl - Is control transfer or not\r
2896 QhPtr - A pointer to Qh\r
2897 ActualLen - Actual transfered Len \r
2898 DataToggle - Data Toggle\r
2899 TimeOut - TimeOut threshold\r
2900 TransferResult - Transfer result\r
2901 \r
2902Returns:\r
2903\r
2904 EFI_SUCCESS Sucess\r
2905 EFI_DEVICE_ERROR Fail\r
2906 \r
2907--*/\r
2908{\r
2909 EFI_STATUS Status;\r
2910 UINTN ErrQtdPos;\r
2911 UINTN Delay;\r
2912 UINTN RequireLen;\r
2913 BOOLEAN Finished;\r
2914\r
2915 Status = EFI_SUCCESS;\r
2916 ErrQtdPos = 0;\r
2917 *TransferResult = EFI_USB_NOERROR;\r
2918 RequireLen = *ActualLen;\r
2919 *ActualLen = 0;\r
2920 Finished = FALSE;\r
2921\r
2922 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
2923\r
2924 do {\r
2925 *TransferResult = 0;\r
2926 Finished = CheckQtdsTransferResult (\r
2927 IsControl,\r
2928 QhPtr,\r
2929 TransferResult,\r
2930 &ErrQtdPos,\r
2931 ActualLen\r
2932 );\r
2933 if (Finished) {\r
2934 break;\r
2935 }\r
2936 //\r
2937 // Qtd is inactive, which means bulk or interrupt transfer's end.\r
2938 //\r
2939 if (!(*TransferResult & EFI_USB_ERR_NOTEXECUTE)) {\r
2940 break;\r
2941 }\r
2942\r
2943 gBS->Stall (EHCI_SYNC_REQUEST_POLLING_TIME);\r
2944\r
2945 } while (--Delay);\r
2946\r
2947 if (EFI_USB_NOERROR != *TransferResult) {\r
2948 if (0 == Delay) {\r
2949 Status = EFI_TIMEOUT;\r
2950 } else {\r
2951 Status = EFI_DEVICE_ERROR;\r
2952 }\r
2953 }\r
2954\r
2955 //\r
2956 // Special for Bulk and Interrupt Transfer\r
2957 //\r
2958 *DataToggle = (UINT8) QhPtr->Qh.DataToggle;\r
2959 \r
2960 return Status;\r
2961}\r
2962\r
2963EFI_STATUS\r
2964AsyncRequestMoniter (\r
2965 IN EFI_EVENT Event,\r
2966 IN VOID *Context\r
2967 )\r
2968/*++\r
2969Routine Description:\r
2970 \r
2971 Interrupt transfer periodic check handler\r
2972 \r
2973Arguments:\r
2974 Event - Interrupt event\r
2975 Context - Pointer to USB2_HC_DEV\r
2976 \r
2977Returns:\r
2978\r
2979 EFI_SUCCESS Success\r
2980 EFI_DEVICE_ERROR Fail\r
2981 \r
2982--*/\r
2983{\r
2984 EFI_STATUS Status;\r
2985 USB2_HC_DEV *HcDev;\r
2986 EHCI_ASYNC_REQUEST *AsyncRequestPtr;\r
2987 EHCI_QTD_HW *QtdHwPtr;\r
2988 UINTN ErrQtdPos;\r
2989 UINTN ActualLen;\r
2990 UINT32 TransferResult;\r
2991 UINT8 *ReceiveBuffer;\r
2992 UINT8 *ProcessBuffer;\r
2993\r
2994 Status = EFI_SUCCESS;\r
2995 QtdHwPtr = NULL;\r
2996 ReceiveBuffer = NULL;\r
2997 ProcessBuffer = NULL;\r
2998 HcDev = (USB2_HC_DEV *) Context;\r
2999 AsyncRequestPtr = HcDev->AsyncRequestList;\r
3000\r
3001 while (NULL != AsyncRequestPtr) {\r
3002\r
3003 TransferResult = 0;\r
3004 ErrQtdPos = 0;\r
3005 ActualLen = 0;\r
3006\r
3007 CheckQtdsTransferResult (\r
3008 FALSE, \r
3009 AsyncRequestPtr->QhPtr, \r
3010 &TransferResult, \r
3011 &ErrQtdPos, \r
3012 &ActualLen\r
3013 );\r
3014\r
3015 if ((TransferResult & EFI_USB_ERR_NAK) || (TransferResult & EFI_USB_ERR_NOTEXECUTE)) {\r
3016 AsyncRequestPtr = AsyncRequestPtr->Next;\r
3017 continue;\r
3018 }\r
3019 //\r
3020 // Allocate memory for EHC private data structure\r
3021 //\r
3022 ProcessBuffer = AllocateZeroPool (ActualLen);\r
3023 if (NULL == ProcessBuffer) {\r
3024 Status = EFI_OUT_OF_RESOURCES;\r
3025 goto exit;\r
3026 }\r
3027\r
3028 QtdHwPtr = &(AsyncRequestPtr->QhPtr->FirstQtdPtr->Qtd);\r
ffac4bcb 3029 ReceiveBuffer = (UINT8 *) (UINTN) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);\r
562d2849 3030 CopyMem (\r
3031 ProcessBuffer,\r
3032 ReceiveBuffer,\r
3033 ActualLen\r
3034 );\r
3035\r
3036 UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);\r
3037\r
3038 if (EFI_USB_NOERROR == TransferResult) {\r
3039\r
3040 if (AsyncRequestPtr->CallBackFunc != NULL) {\r
3041 (AsyncRequestPtr->CallBackFunc) (ProcessBuffer, ActualLen, AsyncRequestPtr->Context, TransferResult);\r
3042 }\r
3043\r
3044 } else {\r
3045\r
3046 //\r
3047 // leave error recovery to its related device driver. A common case of \r
3048 // the error recovery is to re-submit the interrupt transfer.\r
3049 // When an interrupt transfer is re-submitted, its position in the linked\r
3050 // list is changed. It is inserted to the head of the linked list, while\r
3051 // this function scans the whole list from head to tail. Thus, the\r
3052 // re-submitted interrupt transfer's callback function will not be called\r
3053 // again in this round.\r
3054 //\r
3055 if (AsyncRequestPtr->CallBackFunc != NULL) {\r
3056 (AsyncRequestPtr->CallBackFunc) (NULL, 0, AsyncRequestPtr->Context, TransferResult);\r
3057 }\r
3058\r
3059 }\r
3060\r
3061 if (NULL != ProcessBuffer) {\r
3062 gBS->FreePool (ProcessBuffer);\r
3063 }\r
3064\r
3065 AsyncRequestPtr = AsyncRequestPtr->Next;\r
3066\r
3067 }\r
3068\r
3069exit:\r
3070 return Status;\r
3071}\r
3072\r