]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/Ehci/Dxe/EhciSched.c
AsyncRequestPtr maybe NULL after its callback function is invoke. So Caching it tempo...
[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
71a62114 343 ZeroMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY));\r
562d2849 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
71a62114 702\r
703 ZeroMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY));\r
562d2849 704\r
705 //\r
706 // Software field\r
707 //\r
708 (*QtdPtrPtr)->TotalBytes = (UINT32) DataLen;\r
709 (*QtdPtrPtr)->StaticTotalBytes = (UINT32) DataLen;\r
710 (*QtdPtrPtr)->Prev = NULL;\r
711 (*QtdPtrPtr)->Next = NULL;\r
712\r
713 //\r
714 // Hardware field\r
715 //\r
716 QtdHwPtr = &((*QtdPtrPtr)->Qtd);\r
717 QtdHwPtr->NextQtdPointer = 0;\r
718 QtdHwPtr->NextQtdTerminate = TRUE;\r
719 QtdHwPtr->AltNextQtdPointer = 0;\r
720 QtdHwPtr->AltNextQtdTerminate = TRUE;\r
721 QtdHwPtr->DataToggle = Toggle;\r
722 QtdHwPtr->TotalBytes = (UINT32) DataLen;\r
723 QtdHwPtr->CurrentPage = 0;\r
724 QtdHwPtr->ErrorCount = QTD_ERROR_COUNTER;\r
725 QtdHwPtr->Status = QtdStatus;\r
726 QtdHwPtr->Rsvd1 = 0;\r
727 QtdHwPtr->Rsvd2 = 0;\r
728 QtdHwPtr->Rsvd3 = 0;\r
729 QtdHwPtr->Rsvd4 = 0;\r
730 QtdHwPtr->Rsvd5 = 0;\r
731 QtdHwPtr->Rsvd6 = 0;\r
732\r
733 //\r
734 // Set PacketID [Setup/Data/Status]\r
735 //\r
736 switch (PktId) {\r
737 case SETUP_PACKET_ID:\r
738 QtdHwPtr->PidCode = SETUP_PACKET_PID_CODE;\r
739 break;\r
740\r
741 case INPUT_PACKET_ID:\r
742 QtdHwPtr->PidCode = INPUT_PACKET_PID_CODE;\r
743 break;\r
744\r
745 case OUTPUT_PACKET_ID:\r
746 QtdHwPtr->PidCode = OUTPUT_PACKET_PID_CODE;\r
747 break;\r
748\r
749 default:\r
750 Status = EFI_INVALID_PARAMETER;\r
751 goto exit;\r
752 }\r
753 \r
754 //\r
755 // Set Data Buffer Pointers\r
756 //\r
757 if (NULL != DataPtr) {\r
758 SetQtdBufferPointer (\r
759 QtdHwPtr,\r
760 DataPtr,\r
761 DataLen\r
762 );\r
763 (*QtdPtrPtr)->StaticCurrentOffset = QtdHwPtr->CurrentOffset;\r
764 }\r
765\r
766exit:\r
767 return Status;\r
768}\r
769\r
770EFI_STATUS\r
771CreateSetupQtd (\r
772 IN USB2_HC_DEV *HcDev,\r
773 IN UINT8 *DevReqPtr,\r
774 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
775 )\r
776/*++\r
777\r
778Routine Description:\r
779\r
780 Create Qtd Structure for Setup \r
781\r
782Arguments:\r
783\r
784 HcDev - USB2_HC_DEV \r
785 DevReqPtr - A pointer to Device Request Data\r
786 QtdPtrPtr - A pointer of pointer to Qtd for return\r
787 \r
788Returns:\r
789\r
790 EFI_SUCCESS Success\r
791 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
792 \r
793--*/\r
794{\r
795 return CreateQtd (\r
796 HcDev,\r
797 DevReqPtr,\r
798 sizeof (EFI_USB_DEVICE_REQUEST),\r
799 SETUP_PACKET_ID,\r
800 DATA0,\r
801 QTD_STATUS_ACTIVE,\r
802 QtdPtrPtr\r
803 );\r
804}\r
805\r
806EFI_STATUS\r
807CreateDataQtd (\r
808 IN USB2_HC_DEV *HcDev,\r
809 IN UINT8 *DataPtr,\r
810 IN UINTN DataLen,\r
811 IN UINT8 PktId,\r
812 IN UINT8 Toggle,\r
813 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
814 )\r
815/*++\r
816\r
817Routine Description:\r
818\r
819 Create Qtd Structure for data \r
820\r
821Arguments:\r
822\r
823 HcDev - USB2_HC_DEV \r
824 DataPtr - A pointer to user data buffer to transfer\r
825 DataLen - Length of user data to transfer\r
826 PktId - Packet Identification of this Qtd\r
827 Toggle - Data Toggle of this Qtd\r
828 QtdPtrPtr - A pointer of pointer to Qtd for return\r
829 \r
830Returns:\r
831\r
832 EFI_SUCCESS Success\r
833 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
834 \r
835--*/\r
836{\r
837 return CreateQtd (\r
838 HcDev,\r
839 DataPtr,\r
840 DataLen,\r
841 PktId,\r
842 Toggle,\r
843 QTD_STATUS_ACTIVE,\r
844 QtdPtrPtr\r
845 );\r
846}\r
847\r
848EFI_STATUS\r
849CreateAltQtd (\r
850 IN USB2_HC_DEV *HcDev,\r
851 IN UINT8 PktId,\r
852 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
853 )\r
854/*++\r
855\r
856Routine Description:\r
857\r
858 Create Qtd Structure for Alternative \r
859\r
860Arguments:\r
861\r
862 HcDev - USB2_HC_DEV \r
863 PktId - Packet Identification of this Qtd\r
864 QtdPtrPtr - A pointer of pointer to Qtd for return\r
865 \r
866Returns:\r
867\r
868 EFI_SUCCESS Success\r
869 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
870 \r
871--*/\r
872{\r
873 return CreateQtd (\r
874 HcDev,\r
875 NULL,\r
876 0,\r
877 PktId,\r
878 0,\r
879 QTD_STATUS_ACTIVE,\r
880 QtdPtrPtr\r
881 );\r
882}\r
883\r
884EFI_STATUS\r
885CreateStatusQtd (\r
886 IN USB2_HC_DEV *HcDev,\r
887 IN UINT8 PktId,\r
888 OUT EHCI_QTD_ENTITY **QtdPtrPtr\r
889 )\r
890/*++\r
891\r
892Routine Description:\r
893\r
894 Create Qtd Structure for status \r
895\r
896Arguments:\r
897\r
898 HcDev - USB2_HC_DEV \r
899 PktId - Packet Identification of this Qtd\r
900 QtdPtrPtr - A pointer of pointer to Qtd for return\r
901 \r
902Returns:\r
903\r
904 EFI_SUCCESS Success\r
905 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
906 \r
907--*/\r
908{\r
909 return CreateQtd (\r
910 HcDev,\r
911 NULL,\r
912 0,\r
913 PktId,\r
914 DATA1,\r
915 QTD_STATUS_ACTIVE,\r
916 QtdPtrPtr\r
917 );\r
918}\r
919\r
920EFI_STATUS\r
921CreateControlQtds (\r
922 IN USB2_HC_DEV *HcDev,\r
923 IN UINT8 DataPktId,\r
924 IN UINT8 *RequestCursor,\r
925 IN UINT8 *DataCursor,\r
926 IN UINTN DataLen,\r
927 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
928 OUT EHCI_QTD_ENTITY **ControlQtdsHead\r
929 )\r
930/*++\r
931\r
932Routine Description:\r
933\r
934 Create Qtds list for Control Transfer \r
935\r
936Arguments:\r
937\r
938 HcDev - USB2_HC_DEV \r
939 DataPktId - Packet Identification of Data Qtds\r
940 RequestCursor - A pointer to request structure buffer to transfer\r
941 DataCursor - A pointer to user data buffer to transfer\r
942 DataLen - Length of user data to transfer\r
943 ControlQtdsHead - A pointer of pointer to first Qtd for control tranfer for return\r
944 \r
945Returns:\r
946\r
947 EFI_SUCCESS Success\r
948 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
949 \r
950--*/\r
951{\r
952 EFI_STATUS Status;\r
953 EHCI_QTD_ENTITY *QtdPtr;\r
954 EHCI_QTD_ENTITY *PreQtdPtr;\r
955 EHCI_QTD_ENTITY *SetupQtdPtr;\r
956 EHCI_QTD_ENTITY *FirstDataQtdPtr;\r
957 EHCI_QTD_ENTITY *LastDataQtdPtr;\r
958 EHCI_QTD_ENTITY *StatusQtdPtr;\r
959 UINT8 DataToggle;\r
960 UINT8 StatusPktId;\r
961 UINTN CapacityOfQtd;\r
962 UINTN SizePerQtd;\r
963 UINTN DataCount;\r
964 UINTN Xnum;\r
965 \r
966 QtdPtr = NULL;\r
967 PreQtdPtr = NULL;\r
968 SetupQtdPtr = NULL;\r
969 FirstDataQtdPtr = NULL;\r
970 LastDataQtdPtr = NULL;\r
971 StatusQtdPtr = NULL;\r
972 CapacityOfQtd = 0;\r
973\r
974 //\r
975 // Setup Stage of Control Transfer\r
976 //\r
977 Status = CreateSetupQtd (\r
978 HcDev,\r
979 RequestCursor,\r
980 &SetupQtdPtr\r
981 );\r
982 if (EFI_ERROR (Status)) {\r
983 Status = EFI_OUT_OF_RESOURCES;\r
984 goto exit;\r
985 }\r
986 \r
987 //\r
988 // Data Stage of Control Transfer\r
989 //\r
990 DataToggle = 1;\r
991 DataCount = DataLen;\r
992\r
993 //\r
994 // Create Qtd structure and link together\r
995 //\r
996 while (DataCount > 0) {\r
997 //\r
998 // PktSize is the data load size that each Qtd.\r
999 //\r
1000 CapacityOfQtd = GetCapacityOfQtd (DataCursor);\r
1001 SizePerQtd = DataCount;\r
1002 if (DataCount > CapacityOfQtd) {\r
1003 SizePerQtd = CapacityOfQtd;\r
1004 }\r
1005\r
1006 Status = CreateDataQtd (\r
1007 HcDev,\r
1008 DataCursor,\r
1009 SizePerQtd,\r
1010 DataPktId,\r
1011 DataToggle,\r
1012 &QtdPtr\r
1013 );\r
1014 if (EFI_ERROR (Status)) {\r
1015 Status = EFI_OUT_OF_RESOURCES;\r
1016 if (NULL == FirstDataQtdPtr) {\r
1017 goto destory_setup_qtd;\r
1018 } else {\r
1019 goto destory_qtds;\r
1020 }\r
1021 }\r
1022\r
1023 if (NULL == FirstDataQtdPtr) {\r
1024 FirstDataQtdPtr = QtdPtr;\r
1025 } else {\r
1026 LinkQtdToQtd (PreQtdPtr, QtdPtr);\r
1027 }\r
1028\r
1029 //\r
1030 // Reverse Data Toggle or not determined by parity of transactions of one qtd\r
1031 //\r
1032 Xnum = Translator ? GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE_WITH_TT) : GetNumberOfTransaction (SizePerQtd, EHCI_BLOCK_SIZE);\r
1033 if (Xnum % 2 != 0) {\r
1034 DataToggle ^= 1;\r
1035 }\r
1036 \r
1037 PreQtdPtr = QtdPtr;\r
1038 DataCursor += SizePerQtd;\r
1039 DataCount -= SizePerQtd;\r
1040 }\r
1041\r
1042 LastDataQtdPtr = QtdPtr;\r
1043\r
1044 //\r
1045 // Status Stage of Control Transfer\r
1046 //\r
1047 if (OUTPUT_PACKET_ID == DataPktId) {\r
1048 StatusPktId = INPUT_PACKET_ID;\r
1049 } else {\r
1050 StatusPktId = OUTPUT_PACKET_ID;\r
1051 }\r
1052\r
1053 Status = CreateStatusQtd (\r
1054 HcDev,\r
1055 StatusPktId,\r
1056 &StatusQtdPtr\r
1057 );\r
1058 if (EFI_ERROR (Status)) {\r
1059 Status = EFI_OUT_OF_RESOURCES;\r
1060 goto destory_qtds;\r
1061 }\r
1062 \r
1063 //\r
1064 // Link setup Qtd -> data Qtds -> status Qtd\r
1065 //\r
1066 if (FirstDataQtdPtr != NULL) {\r
1067 LinkQtdToQtd (SetupQtdPtr, FirstDataQtdPtr);\r
1068 LinkQtdToQtd (LastDataQtdPtr, StatusQtdPtr);\r
1069 } else {\r
1070 LinkQtdToQtd (SetupQtdPtr, StatusQtdPtr);\r
1071 }\r
1072\r
1073 *ControlQtdsHead = SetupQtdPtr;\r
1074\r
1075 goto exit;\r
1076\r
1077destory_qtds:\r
1078 DestoryQtds (HcDev, FirstDataQtdPtr);\r
1079destory_setup_qtd:\r
1080 DestoryQtds (HcDev, SetupQtdPtr);\r
1081exit:\r
1082 return Status;\r
1083}\r
1084\r
1085EFI_STATUS\r
1086CreateBulkOrInterruptQtds (\r
1087 IN USB2_HC_DEV *HcDev,\r
1088 IN UINT8 PktId,\r
1089 IN UINT8 *DataCursor,\r
1090 IN UINTN DataLen,\r
1091 IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,\r
1092 OUT EHCI_QTD_ENTITY **QtdsHead\r
1093 )\r
1094/*++\r
1095\r
1096Routine Description:\r
1097\r
1098 Create Qtds list for Bulk or Interrupt Transfer \r
1099\r
1100Arguments:\r
1101\r
1102 HcDev - USB2_HC_DEV \r
1103 PktId - Packet Identification of Qtds\r
1104 DataCursor - A pointer to user data buffer to transfer\r
1105 DataLen - Length of user data to transfer\r
1106 DataToggle - Data Toggle to start\r
1107 Translator - Translator Transaction for SplitX\r
1108 QtdsHead - A pointer of pointer to first Qtd for control tranfer for return\r
1109 \r
1110Returns:\r
1111\r
1112 EFI_SUCCESS Success\r
1113 EFI_OUT_OF_RESOURCES Cannot allocate resources\r
1114 \r
1115--*/\r
1116{\r
1117 EFI_STATUS Status;\r
1118 EHCI_QTD_ENTITY *QtdPtr;\r
1119 EHCI_QTD_ENTITY *PreQtdPtr;\r
1120 EHCI_QTD_ENTITY *FirstQtdPtr;\r
1121 EHCI_QTD_ENTITY *AltQtdPtr;\r
1122 UINTN DataCount;\r
1123 UINTN CapacityOfQtd;\r
1124 UINTN SizePerQtd;\r
1125\r
1126 Status = EFI_SUCCESS;\r
1127 QtdPtr = NULL;\r
1128 PreQtdPtr = NULL;\r
1129 FirstQtdPtr = NULL;\r
1130 AltQtdPtr = NULL;\r
1131 CapacityOfQtd = 0;\r
1132\r
1133 DataCount = DataLen;\r
1134 while (DataCount > 0) {\r
1135\r
1136 CapacityOfQtd = GetCapacityOfQtd (DataCursor);\r
1137 SizePerQtd = DataCount;\r
1138 if (DataCount > CapacityOfQtd) {\r
1139 SizePerQtd = CapacityOfQtd;\r
1140 }\r
1141\r
1142 Status = CreateDataQtd (\r
1143 HcDev,\r
1144 DataCursor,\r
1145 SizePerQtd,\r
1146 PktId,\r
1147 0,\r
1148 &QtdPtr\r
1149 );\r
1150 if (EFI_ERROR (Status)) {\r
1151 Status = EFI_OUT_OF_RESOURCES;\r
1152 if (NULL == FirstQtdPtr) {\r
1153 goto exit;\r
1154 } else {\r
1155 goto destory_qtds;\r
1156 }\r
1157 }\r
1158\r
1159 if (NULL == FirstQtdPtr) {\r
1160 FirstQtdPtr = QtdPtr;\r
1161 } else {\r
1162 LinkQtdToQtd (PreQtdPtr, QtdPtr);\r
1163 }\r
1164\r
1165 PreQtdPtr = QtdPtr;\r
1166 DataCursor += SizePerQtd;\r
1167 DataCount -= SizePerQtd;\r
1168 }\r
1169 \r
1170 //\r
1171 // Set Alternate Qtd\r
1172 //\r
1173 if (INPUT_PACKET_ID == PktId && 1 < GetNumberOfQtd (FirstQtdPtr)) {\r
1174 Status = CreateAltQtd (\r
1175 HcDev,\r
1176 PktId,\r
1177 &AltQtdPtr\r
1178 );\r
1179 if (EFI_ERROR (Status)) {\r
1180 Status = EFI_OUT_OF_RESOURCES;\r
1181 goto destory_qtds;\r
1182 }\r
1183\r
1184 LinkQtdsToAltQtd (FirstQtdPtr, AltQtdPtr);\r
1185 }\r
1186\r
1187 *QtdsHead = FirstQtdPtr;\r
1188 goto exit;\r
1189\r
1190destory_qtds:\r
1191 DestoryQtds (HcDev, FirstQtdPtr);\r
1192exit:\r
1193 return Status;\r
1194}\r
1195\r
1196VOID\r
1197DestoryQtds (\r
1198 IN USB2_HC_DEV *HcDev,\r
1199 IN EHCI_QTD_ENTITY *FirstQtdPtr\r
1200 )\r
1201/*++\r
1202\r
1203Routine Description:\r
1204\r
1205 Destory all Qtds in the list\r
1206\r
1207Arguments:\r
1208\r
1209 HcDev - USB2_HC_DEV \r
1210 FirstQtdPtr - A pointer to first Qtd in the list \r
1211 \r
1212Returns:\r
1213\r
1214 VOID\r
1215\r
1216--*/\r
1217{\r
1218 EHCI_QTD_ENTITY *PrevQtd;\r
1219 EHCI_QTD_ENTITY *NextQtd;\r
1220\r
1221 if (!FirstQtdPtr) {\r
1222 goto exit;\r
1223 }\r
1224\r
1225 PrevQtd = FirstQtdPtr;\r
1226\r
1227 //\r
1228 // Delete all the Qtds.\r
1229 //\r
1230 do {\r
1231 NextQtd = PrevQtd->Next;\r
1232 EhciFreePool (HcDev, (UINT8 *) PrevQtd, sizeof (EHCI_QTD_ENTITY));\r
1233 PrevQtd = NextQtd;\r
1234 } while (NULL != PrevQtd);\r
1235\r
1236exit:\r
1237 return ;\r
1238}\r
1239\r
1240UINTN\r
1241GetNumberOfQtd (\r
1242 IN EHCI_QTD_ENTITY *FirstQtdPtr\r
1243 )\r
1244/*++\r
1245\r
1246Routine Description:\r
1247\r
1248 Number of Qtds in the list\r
1249 \r
1250Arguments:\r
1251\r
1252 FirstQtdPtr - A pointer to first Qtd in the list\r
1253 \r
1254Returns:\r
1255\r
1256 Number of Qtds in the list\r
1257\r
1258--*/\r
1259{\r
1260 UINTN Count;\r
1261 EHCI_QTD_ENTITY *QtdPtr;\r
1262 Count = 0;\r
1263 QtdPtr = FirstQtdPtr;\r
1264\r
1265 ;\r
1266\r
1267 while (NULL != QtdPtr) {\r
1268 Count++;\r
1269 QtdPtr = QtdPtr->Next;\r
1270 }\r
1271\r
1272 return Count;\r
1273}\r
1274\r
1275UINTN\r
1276GetNumberOfTransaction (\r
1277 IN UINTN SizeOfData,\r
1278 IN UINTN SizeOfTransaction\r
1279 )\r
1280/*++\r
1281\r
1282Routine Description:\r
1283\r
1284 Number of Transactions in one Qtd\r
1285 \r
1286Arguments:\r
1287\r
1288 SizeOfData - Size of one Qtd\r
1289 SizeOfTransaction - Size of one Transaction\r
1290 \r
1291Returns:\r
1292\r
1293 Number of Transactions in this Qtd\r
1294\r
1295--*/\r
1296{\r
1297\r
1298 return ((SizeOfData & (SizeOfTransaction - 1)) ? SizeOfData / SizeOfTransaction + 1 : SizeOfData / SizeOfTransaction);\r
1299\r
1300}\r
1301\r
1302UINTN\r
1303GetCapacityOfQtd (\r
1304 IN UINT8 *BufferCursor\r
1305 )\r
1306/*++\r
1307\r
1308Routine Description:\r
1309\r
1310 Get Size of First Qtd\r
1311 \r
1312Arguments:\r
1313\r
1314 BufferCursor - BufferCursor of the Qtd\r
1315 \r
1316Returns:\r
1317\r
1318 Size of First Qtd\r
1319\r
1320--*/\r
1321{\r
1322\r
1323 return (EHCI_MAX_QTD_CAPACITY - (EHCI_BLOCK_SIZE * GetNumberOfTransaction (EFI_PAGE_MASK & GET_0B_TO_31B (BufferCursor), EHCI_BLOCK_SIZE)));\r
1324\r
1325}\r
1326\r
1327UINTN\r
1328GetApproxiOfInterval (\r
1329 IN UINTN Interval\r
1330 )\r
1331/*++\r
1332\r
1333Routine Description:\r
1334\r
1335 Get the approximate value in the 2 index sequence\r
1336 \r
1337Arguments:\r
1338\r
1339 Interval - the value of interval\r
1340 \r
1341Returns:\r
1342\r
1343 approximate value of interval in the 2 index sequence\r
1344 \r
1345--*/\r
1346{\r
1347 UINTN Orignate;\r
1348 UINTN Approxi;\r
1349\r
1350 Orignate = Interval;\r
1351 Approxi = 1;\r
1352\r
1353 while (Orignate != 1 && Orignate != 0) {\r
1354 Orignate = Orignate >> 1;\r
1355 Approxi = Approxi << 1;\r
1356 }\r
1357\r
1358 if (Interval & (Approxi >> 1)) {\r
1359 Approxi = Approxi << 1;\r
1360 }\r
1361\r
1362 return Approxi;\r
1363}\r
1364\r
1365EHCI_QTD_HW *\r
1366GetQtdAlternateNextPointer (\r
1367 IN EHCI_QTD_HW *HwQtdPtr\r
1368 )\r
1369/*++\r
1370\r
1371Routine Description:\r
1372\r
1373 Get Qtd alternate next pointer field\r
1374 \r
1375Arguments:\r
1376\r
1377 HwQtdPtr - A pointer to hardware Qtd structure\r
1378 \r
1379Returns:\r
1380\r
1381 A pointer to hardware alternate Qtd\r
1382 \r
1383--*/\r
1384{\r
1385 EHCI_QTD_HW *Value;\r
1386\r
1387 Value = NULL;\r
1388\r
1389 if (!HwQtdPtr->AltNextQtdTerminate) {\r
71a62114 1390 Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);\r
562d2849 1391 }\r
1392\r
1393 return Value;\r
1394}\r
1395\r
1396EHCI_QTD_HW *\r
1397GetQtdNextPointer (\r
1398 IN EHCI_QTD_HW *HwQtdPtr\r
1399 )\r
1400/*++\r
1401\r
1402Routine Description:\r
1403\r
1404 Get Qtd next pointer field\r
1405 \r
1406Arguments:\r
1407\r
1408 HwQtdPtr - A pointer to hardware Qtd structure\r
1409 \r
1410Returns:\r
1411\r
1412 A pointer to next hardware Qtd structure\r
1413 \r
1414--*/\r
1415{\r
1416 EHCI_QTD_HW *Value;\r
1417\r
1418 Value = NULL;\r
1419\r
1420 if (!HwQtdPtr->NextQtdTerminate) {\r
71a62114 1421 Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);\r
562d2849 1422 }\r
1423\r
1424 return Value;\r
1425}\r
1426\r
1427VOID LinkQtdToQtd (\r
1428 IN EHCI_QTD_ENTITY * PreQtdPtr, \r
1429 IN EHCI_QTD_ENTITY * QtdPtr\r
1430 )\r
1431/*++\r
1432\r
1433Routine Description:\r
1434\r
1435 Link Qtds together\r
1436 \r
1437Arguments:\r
1438\r
1439 PreQtdPtr - A pointer to pre Qtd\r
1440 QtdPtr - A pointer to next Qtd\r
1441 \r
1442Returns:\r
1443\r
1444 VOID\r
1445\r
1446--*/\r
1447{\r
1448 EHCI_QTD_HW *QtdHwPtr;\r
1449\r
1450 ASSERT(PreQtdPtr);\r
1451 ASSERT(QtdPtr);\r
1452\r
1453 //\r
1454 // Software link\r
1455 //\r
1456 PreQtdPtr->Next = QtdPtr;\r
1457 QtdPtr->Prev = PreQtdPtr;\r
1458\r
1459 //\r
1460 // Hardware link\r
1461 //\r
1462 QtdHwPtr = &(QtdPtr->Qtd);\r
1463 PreQtdPtr->Qtd.NextQtdPointer = (UINT32) (GET_0B_TO_31B(QtdHwPtr) >> 5);\r
1464 PreQtdPtr->Qtd.NextQtdTerminate = FALSE;\r
1465\r
1466 return ;\r
1467}\r
1468\r\r
1469\r
1470VOID LinkQtdsToAltQtd (\r
1471 IN EHCI_QTD_ENTITY * FirstQtdPtr, \r
1472 IN EHCI_QTD_ENTITY * AltQtdPtr\r
1473 )\r
1474/*++\r
1475\r
1476Routine Description:\r
1477\r
1478 Link AlterQtds together\r
1479 \r
1480Arguments:\r
1481\r
1482 FirstQtdPtr - A pointer to first Qtd in the list\r
1483 AltQtdPtr - A pointer to alternative Qtd\r
1484 \r
1485Returns:\r
1486\r
1487 VOID\r
1488\r
1489--*/\r
1490{\r
1491 EHCI_QTD_ENTITY *QtdPtr;\r
1492 EHCI_QTD_HW *AltQtdHwPtr;\r
1493\r
1494 ASSERT(FirstQtdPtr);\r
1495 ASSERT(AltQtdPtr);\r
1496\r
1497 AltQtdHwPtr = &(AltQtdPtr->Qtd);\r
1498 QtdPtr = FirstQtdPtr;\r
1499 \r
1500 while (NULL != QtdPtr) {\r
1501 //\r
1502 // Software link\r
1503 //\r
1504 QtdPtr->AltNext = AltQtdPtr;\r
1505 //\r
1506 // Hardware link\r
1507 //\r
1508 QtdPtr->Qtd.AltNextQtdPointer = (UINT32) (GET_0B_TO_31B(AltQtdHwPtr) >> 5);\r
1509 QtdPtr->Qtd.AltNextQtdTerminate = FALSE;\r
1510 QtdPtr = QtdPtr->Next;\r
1511 }\r
1512\r
1513 return ;\r
1514}\r
1515\r
1516VOID\r
1517LinkQtdToQh (\r
1518 IN EHCI_QH_ENTITY *QhPtr,\r
1519 IN EHCI_QTD_ENTITY *QtdPtr\r
1520 )\r
1521/*++\r
1522\r
1523Routine Description:\r
1524\r
1525 Link Qtds list to Qh\r
1526 \r
1527Arguments:\r
1528\r
1529 QhPtr - A pointer to Qh\r
1530 QtdPtr - A pointer to first Qtd in the list\r
1531 \r
1532Returns:\r
1533\r
1534 VOID\r
1535\r
1536--*/\r
1537{\r
1538 EHCI_QTD_ENTITY *Cursor;\r
1539 EHCI_QTD_HW *QtdHwPtr;\r
1540\r
1541 ASSERT (QhPtr);\r
1542 ASSERT (QtdPtr);\r
1543\r
1544 QhPtr->FirstQtdPtr = QtdPtr;\r
1545 if (NULL != QtdPtr->AltNext) {\r
1546 QhPtr->AltQtdPtr = QtdPtr->AltNext;\r
1547 }\r
1548\r
1549 Cursor = QtdPtr;\r
1550 while (NULL != Cursor) {\r
1551 Cursor->SelfQh = QhPtr;\r
1552 if (NULL == Cursor->Next) {\r
1553 QhPtr->LastQtdPtr = Cursor;\r
1554 }\r
1555\r
1556 Cursor = Cursor->Next;\r
1557 }\r
1558\r
1559 QtdHwPtr = &(QtdPtr->Qtd);\r
1560 QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (QtdHwPtr) >> 5);\r
1561 QhPtr->Qh.NextQtdTerminate = FALSE;\r
1562\r
1563 return ;\r
1564}\r
1565\r
1566EFI_STATUS\r
1567LinkQhToAsyncList (\r
1568 IN USB2_HC_DEV *HcDev,\r
1569 IN EHCI_QH_ENTITY *QhPtr\r
1570 )\r
1571/*++\r
1572\r
1573Routine Description:\r
1574\r
1575 Link Qh to Async Schedule List\r
1576 \r
1577Arguments:\r
1578\r
1579 HcDev - USB2_HC_DEV \r
1580 QhPtr - A pointer to Qh\r
1581 \r
1582Returns:\r
1583\r
1584 EFI_SUCCESS Success\r
1585 EFI_DEVICE_ERROR Fail\r
1586 \r
1587--*/\r
1588{\r
1589 EFI_STATUS Status;\r
1590\r
1591 ASSERT (HcDev);\r
1592 ASSERT (QhPtr);\r
1593\r
1594 QhPtr->Qh.HeadReclamationFlag = TRUE;\r
1595\r
1596 Status = SetAsyncListAddr (HcDev, QhPtr);\r
1597 if (EFI_ERROR (Status)) {\r
1598 Status = EFI_DEVICE_ERROR;\r
1599 goto exit;\r
1600 }\r
1601\r
1602 if (!IsAsyncScheduleEnabled (HcDev)) {\r
1603\r
1604 Status = EnableAsynchronousSchedule (HcDev);\r
1605 if (EFI_ERROR (Status)) {\r
1606 Status = EFI_DEVICE_ERROR;\r
1607 goto exit;\r
1608 }\r
1609\r
1610 Status = WaitForAsyncScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
1611 if (EFI_ERROR (Status)) {\r
1612 DEBUG ((gEHCDebugLevel, "WaitForAsyncScheduleEnable TimeOut"));\r
1613 Status = EFI_TIMEOUT;\r
1614 goto exit;\r
1615 }\r
1616\r
1617 if (IsEhcHalted (HcDev)) {\r
1618 Status = StartScheduleExecution (HcDev);\r
1619 if (EFI_ERROR (Status)) {\r
1620 Status = EFI_DEVICE_ERROR;\r
1621 }\r
1622 }\r
1623\r
1624 }\r
1625\r
1626exit:\r
1627 return Status;\r
1628}\r
1629\r
1630EFI_STATUS\r
1631UnlinkQhFromAsyncList (\r
1632 IN USB2_HC_DEV *HcDev,\r
1633 IN EHCI_QH_ENTITY *QhPtr\r
1634 )\r
1635/*++\r
1636\r
1637Routine Description:\r
1638\r
1639 Unlink Qh from Async Schedule List\r
1640 \r
1641Arguments:\r
1642\r
1643 HcDev - USB2_HC_DEV \r
1644 QhPtr - A pointer to Qh\r
1645 \r
1646Returns:\r
1647\r
1648 EFI_SUCCESS Success\r
1649 EFI_DEVICE_ERROR Fail\r
1650 \r
1651--*/\r
1652{\r
1653 EFI_STATUS Status;\r
1654\r
1655 Status = EFI_SUCCESS;\r
1656\r
1657 ASSERT (HcDev);\r
1658 ASSERT (QhPtr);\r
1659\r
1660 if (QhPtr == QhPtr->Next) {\r
1661\r
1662 Status = DisableAsynchronousSchedule (HcDev);\r
1663 if (EFI_ERROR (Status)) {\r
1664 Status = EFI_DEVICE_ERROR;\r
1665 goto exit;\r
1666 }\r
1667\r
1668 Status = WaitForAsyncScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
1669 if (EFI_ERROR (Status)) {\r
1670 DEBUG ((gEHCErrorLevel, "WaitForAsyncScheduleDisable TimeOut\n"));\r
1671 Status = EFI_TIMEOUT;\r
1672 goto exit;\r
1673 }\r
1674\r
1675 }\r
1676\r
1677exit:\r
1678 return Status;\r
1679}\r
1680\r
1681VOID\r
1682LinkQhToPeriodicList (\r
1683 IN USB2_HC_DEV *HcDev,\r
1684 IN EHCI_QH_ENTITY *QhPtr\r
1685 )\r
1686/*++\r
1687\r
1688Routine Description:\r
1689\r
1690 Link Qh to Periodic Schedule List\r
1691 \r
1692Arguments:\r
1693\r
1694 HcDev - USB2_HC_DEV \r
1695 QhPtr - A pointer to Qh\r
1696 \r
1697Returns:\r
1698\r
1699 VOID\r
1700 \r
1701--*/\r
1702{\r
1703 FRAME_LIST_ENTRY *FrameEntryPtr;\r
1704 EHCI_QH_ENTITY *FindQhPtr;\r
1705 EHCI_QH_HW *FindQhHwPtr;\r
1706 UINTN FrameIndex;\r
1707\r
1708 ASSERT (HcDev);\r
1709 ASSERT (QhPtr);\r
1710\r
1711 FindQhPtr = NULL;\r
1712 FindQhHwPtr = NULL;\r
1713 FrameIndex = 0;\r
1714 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
1715\r
1716 QhPtr->Qh.HeadReclamationFlag = FALSE;\r
1717\r
1718 if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {\r
1719 \r
1720 //\r
1721 // AsyncInterruptTransfer Qh\r
1722 //\r
1723 \r
1724 //\r
1725 // Link to Frame[0] List\r
1726 //\r
1727 if (!FrameEntryPtr->LinkTerminate) {\r
1728 //\r
1729 // Not Null FrameList\r
1730 //\r
71a62114 1731 FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
562d2849 1732 FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);\r
1733 //\r
1734 // FindQh is Left/Right to Qh\r
1735 //\r
1736 while ((NULL != FindQhPtr->Next) && (FindQhPtr->Interval > QhPtr->Interval)) {\r
1737 FindQhPtr = FindQhPtr->Next;\r
1738 }\r
1739\r
1740 if (FindQhPtr->Interval == QhPtr->Interval) {\r
1741 //\r
1742 // Link Qh after FindQh\r
1743 //\r
1744 if (NULL != FindQhPtr->Next) {\r
1745 FindQhPtr->Next->Prev = QhPtr;\r
71a62114 1746 QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Next->Qh) >> 5);\r
562d2849 1747 QhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1748 QhPtr->Qh.QhTerminate = FALSE;\r
1749 }\r
1750\r
71a62114 1751 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1752 FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1753 FindQhPtr->Qh.QhTerminate = FALSE;\r
1754\r
1755 QhPtr->Prev = FindQhPtr;\r
1756 QhPtr->Next = FindQhPtr->Next;\r
1757 FindQhPtr->Next = QhPtr;\r
1758 } else if (FindQhPtr->Interval < QhPtr->Interval) {\r
1759 //\r
1760 // Link Qh before FindQh\r
1761 //\r
1762 if (NULL == FindQhPtr->Prev) {\r
1763 //\r
1764 // Qh is the First one in Frame[0] List\r
1765 //\r
71a62114 1766 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1767 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1768 FrameEntryPtr->LinkTerminate = FALSE;\r
1769 } else {\r
1770 //\r
1771 // Qh is not the First one in Frame[0] List\r
1772 //\r
1773 FindQhPtr->Prev->Next = QhPtr;\r
71a62114 1774 FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1775 FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;\r
1776 FindQhPtr->Prev->Qh.QhTerminate = FALSE;\r
1777 }\r
1778\r
71a62114 1779 QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Qh) >> 5);\r
562d2849 1780 QhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1781 QhPtr->Qh.QhTerminate = FALSE;\r
1782\r
1783 QhPtr->Next = FindQhPtr;\r
1784 QhPtr->Prev = FindQhPtr->Prev;\r
1785 FindQhPtr->Prev = QhPtr;\r
1786 } else {\r
1787 //\r
1788 // Link Qh after FindQh, Qh is the Last one\r
1789 //\r
71a62114 1790 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1791 FindQhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;\r
1792 FindQhPtr->Qh.QhTerminate = FALSE;\r
1793\r
1794 QhPtr->Prev = FindQhPtr;\r
1795 QhPtr->Next = NULL;\r
1796 FindQhPtr->Next = QhPtr;\r
1797 }\r
1798 } else {\r
1799 //\r
1800 // Null FrameList\r
1801 //\r
71a62114 1802 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1803 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1804 FrameEntryPtr->LinkTerminate = FALSE;\r
1805 }\r
1806 //\r
1807 // Other Frame[X]\r
1808 //\r
1809 if (NULL == QhPtr->Prev) {\r
1810 //\r
1811 // Qh is the First one in Frame[0] List\r
1812 //\r
1813 FrameIndex += QhPtr->Interval;\r
1814 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1815 FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);\r
71a62114 1816 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1817 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1818 FrameEntryPtr->LinkTerminate = FALSE;\r
1819 FrameIndex += QhPtr->Interval;\r
1820 }\r
1821 } else if (QhPtr->Interval < QhPtr->Prev->Interval) {\r
1822 //\r
1823 // Qh is not the First one in Frame[0] List, and Prev.interval > Qh.interval\r
1824 //\r
1825 FrameIndex += QhPtr->Interval;\r
1826 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1827 FrameEntryPtr = (FRAME_LIST_ENTRY *) (FrameEntryPtr + QhPtr->Interval);\r
1828 if ((FrameIndex % QhPtr->Prev->Interval) != 0) {\r
71a62114 1829 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1830 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1831 FrameEntryPtr->LinkTerminate = FALSE;\r
1832 }\r
1833\r
1834 FrameIndex += QhPtr->Interval;\r
1835 }\r
1836 }\r
1837 } else {\r
1838 \r
1839 //\r
1840 // SyncInterruptTransfer Qh\r
1841 //\r
1842 \r
1843 if (!FrameEntryPtr->LinkTerminate) {\r
1844 //\r
1845 // Not Null FrameList\r
1846 //\r
71a62114 1847 FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
562d2849 1848 FindQhPtr = (EHCI_QH_ENTITY *) GET_QH_ENTITY_ADDR (FindQhHwPtr);\r
1849 //\r
1850 // FindQh is Last Qh in the Asynchronous List, Link Qh after FindQh\r
1851 //\r
1852 while (NULL != FindQhPtr->Next) {\r
1853 FindQhPtr = FindQhPtr->Next;\r
1854 }\r
1855\r
71a62114 1856 FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1857 FindQhPtr->Qh.SelectType = QH_SELECT_TYPE;\r
1858 FindQhPtr->Qh.QhTerminate = FALSE;\r
1859\r
1860 FindQhPtr->Next = QhPtr;\r
1861 QhPtr->Prev = FindQhPtr;\r
1862 } else {\r
1863 //\r
1864 // Null FrameList\r
1865 //\r
71a62114 1866 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
562d2849 1867 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1868 FrameEntryPtr->LinkTerminate = FALSE;\r
1869 }\r
1870 }\r
1871\r
1872 return ;\r
1873}\r
1874\r
1875VOID\r
1876UnlinkQhFromPeriodicList (\r
1877 IN USB2_HC_DEV *HcDev,\r
1878 IN EHCI_QH_ENTITY *QhPtr,\r
1879 IN UINTN Interval\r
1880 )\r
1881/*++\r
1882\r
1883Routine Description:\r
1884\r
1885 Unlink Qh from Periodic Schedule List\r
1886 \r
1887Arguments:\r
1888\r
1889 HcDev - USB2_HC_DEV \r
1890 QhPtr - A pointer to Qh\r
1891 Interval - Interval of this periodic transfer\r
1892 \r
1893Returns:\r
1894\r
1895 VOID\r
1896 \r
1897--*/\r
1898{\r
1899 FRAME_LIST_ENTRY *FrameEntryPtr;\r
1900 UINTN FrameIndex;\r
1901\r
1902 FrameIndex = 0;\r
1903\r
1904 ASSERT (HcDev);\r
1905 ASSERT (QhPtr);\r
1906\r
1907 FrameIndex = 0;\r
1908 FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;\r
1909\r
1910 if (QhPtr->TransferType == ASYNC_INTERRUPT_TRANSFER) {\r
1911 \r
1912 //\r
1913 // AsyncInterruptTransfer Qh\r
1914 //\r
1915 \r
1916 if (NULL == QhPtr->Prev) {\r
1917 //\r
1918 // Qh is the First one on Frame[0] List\r
1919 //\r
1920 if (NULL == QhPtr->Next) {\r
1921 //\r
1922 // Only one on Frame[0] List\r
1923 //\r
1924 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1925 FrameEntryPtr->LinkPointer = 0;\r
1926 FrameEntryPtr->SelectType = 0;\r
1927 FrameEntryPtr->LinkTerminate = TRUE;\r
1928 FrameEntryPtr += Interval;\r
1929 FrameIndex += Interval;\r
1930 }\r
1931 } else {\r
1932 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
71a62114 1933 FrameEntryPtr->LinkPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);\r
562d2849 1934 FrameEntryPtr->SelectType = QH_SELECT_TYPE;\r
1935 FrameEntryPtr->LinkTerminate = FALSE;\r
1936 FrameEntryPtr += Interval;\r
1937 FrameIndex += Interval;\r
1938 }\r
1939 }\r
1940 } else {\r
1941 \r
1942 //\r
1943 // Not First one on Frame[0] List\r
1944 //\r
1945 if (NULL == QhPtr->Next) {\r
1946 //\r
1947 // Qh is the Last one on Frame[0] List\r
1948 //\r
1949 QhPtr->Prev->Qh.QhHorizontalPointer = 0;\r
1950 QhPtr->Prev->Qh.SelectType = 0;\r
1951 QhPtr->Prev->Qh.QhTerminate = TRUE;\r
1952 } else {\r
71a62114 1953 QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);\r
562d2849 1954 QhPtr->Prev->Qh.SelectType = QH_SELECT_TYPE;\r
1955 QhPtr->Prev->Qh.QhTerminate = FALSE;\r
1956 }\r
1957\r
1958 if (Interval == QhPtr->Prev->Interval) {\r
1959 //\r
1960 // Interval is the same as Prev\r
1961 // Not involed Frame[X]\r
1962 //\r
1963 } else {\r
1964 //\r
1965 // Other Frame[X]\r
1966 //\r
1967 while (FrameIndex < HcDev->PeriodicFrameListLength) {\r
1968 if ((FrameIndex % QhPtr->Prev->Interval) != 0) {\r
1969 FrameEntryPtr->LinkPointer = QhPtr->Prev->Qh.QhHorizontalPointer;\r
1970 FrameEntryPtr->SelectType = QhPtr->Prev->Qh.SelectType;\r
1971 FrameEntryPtr->LinkTerminate = QhPtr->Prev->Qh.QhTerminate;\r
1972 }\r
1973 FrameEntryPtr += Interval;\r
1974 FrameIndex += Interval;\r
1975 }\r
1976 }\r
1977 }\r
1978\r
1979 if (NULL != QhPtr->Next) {\r
1980 QhPtr->Next->Prev = QhPtr->Prev;\r
1981 }\r
1982\r
1983 if (NULL != QhPtr->Prev) {\r
1984 QhPtr->Prev->Next = QhPtr->Next;\r
1985 }\r
1986 } else {\r
1987 //\r
1988 // SyncInterruptTransfer Qh\r
1989 //\r
1990 if (NULL == QhPtr->Prev) {\r
1991 //\r
1992 // Qh is the only one Qh on Frame[0] List\r
1993 //\r
1994 FrameEntryPtr->LinkPointer = 0;\r
1995 FrameEntryPtr->SelectType = 0;\r
1996 FrameEntryPtr->LinkTerminate = TRUE;\r
1997 } else {\r
1998 QhPtr->Prev->Qh.QhHorizontalPointer = 0;\r
1999 QhPtr->Prev->Qh.SelectType = 0;\r
2000 QhPtr->Prev->Qh.QhTerminate = TRUE;\r
2001 }\r
2002\r
2003 if (NULL != QhPtr->Prev) {\r
2004 QhPtr->Prev->Next = NULL;\r
2005 }\r
2006 }\r
2007\r
2008 return ;\r
2009}\r
2010\r
2011VOID\r
2012LinkToAsyncReqeust (\r
2013 IN USB2_HC_DEV *HcDev,\r
2014 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
2015 )\r
2016/*++\r
2017\r
2018Routine Description:\r
2019\r
2020 Llink AsyncRequest Entry to Async Request List\r
2021 \r
2022Arguments:\r
2023\r
2024 HcDev - USB2_HC_DEV \r
2025 AsyncRequestPtr - A pointer to Async Request Entry\r
2026 \r
2027Returns:\r
2028\r
2029 VOID\r
2030 \r
2031--*/\r
2032{\r
2033 EHCI_ASYNC_REQUEST *CurrentPtr;\r
2034\r
2035 CurrentPtr = HcDev->AsyncRequestList;\r
2036 HcDev->AsyncRequestList = AsyncRequestPtr;\r
2037 AsyncRequestPtr->Prev = NULL;\r
2038 AsyncRequestPtr->Next = CurrentPtr;\r
2039\r
2040 if (NULL != CurrentPtr) {\r
2041 CurrentPtr->Prev = AsyncRequestPtr;\r
2042 }\r
2043\r
2044 return ;\r
2045}\r
2046\r
2047VOID\r
2048UnlinkFromAsyncReqeust (\r
2049 IN USB2_HC_DEV *HcDev,\r
2050 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
2051 )\r
2052/*++\r
2053\r
2054Routine Description:\r
2055\r
2056 Unlink AsyncRequest Entry from Async Request List\r
2057 \r
2058Arguments:\r
2059\r
2060 HcDev - USB2_HC_DEV \r
2061 AsyncRequestPtr - A pointer to Async Request Entry\r
2062 \r
2063Returns:\r
2064\r
2065 VOID\r
2066 \r
2067--*/\r
2068{\r
2069 if (NULL == AsyncRequestPtr->Prev) {\r
2070 HcDev->AsyncRequestList = AsyncRequestPtr->Next;\r
2071 if (NULL != AsyncRequestPtr->Next) {\r
2072 AsyncRequestPtr->Next->Prev = NULL;\r
2073 }\r
2074 } else {\r
2075 AsyncRequestPtr->Prev->Next = AsyncRequestPtr->Next;\r
2076 if (NULL != AsyncRequestPtr->Next) {\r
2077 AsyncRequestPtr->Next->Prev = AsyncRequestPtr->Prev;\r
2078 }\r
2079 }\r
2080\r
2081 return ;\r
2082}\r
2083\r
2084VOID\r
2085SetQtdBufferPointer (\r
2086 IN EHCI_QTD_HW *QtdHwPtr,\r
2087 IN VOID *DataPtr,\r
2088 IN UINTN DataLen\r
2089 )\r
2090/*++\r
2091\r
2092Routine Description:\r
2093\r
2094 Set data buffer pointers in Qtd\r
2095\r
2096Arguments:\r
2097\r
2098 QtdHwPtr - A pointer to Qtd hardware structure \r
2099 DataPtr - A pointer to user data buffer\r
2100 DataLen - Length of the user data buffer\r
2101 \r
2102Returns:\r
2103\r
2104 VOID\r
2105\r
2106--*/\r
2107{\r
2108 UINTN RemainLen;\r
2109\r
2110 RemainLen = DataLen;\r
2111 ASSERT (QtdHwPtr);\r
2112\r
71a62114 2113 //\r
2114 // Allow buffer address range across 4G.\r
2115 // But EFI_USB_MAX_BULK_BUFFER_NUM = 1, so don't allow\r
2116 // seperate buffer array.\r
2117 //\r
2118\r
562d2849 2119 //\r
2120 // Set BufferPointer0, ExtBufferPointer0 and Offset\r
2121 //\r
2122 QtdHwPtr->BufferPointer0 = (UINT32) (GET_0B_TO_31B (DataPtr) >> 12);\r
2123 QtdHwPtr->CurrentOffset = (UINT32) (GET_0B_TO_31B (DataPtr) & EFI_PAGE_MASK);\r
2124 QtdHwPtr->ExtBufferPointer0 = (UINT32) GET_32B_TO_63B (DataPtr);\r
2125\r
2126 //\r
2127 // Set BufferPointer1 and ExtBufferPointer1\r
2128 //\r
2129 RemainLen = RemainLen > (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset) ? (RemainLen - (EFI_PAGE_SIZE - QtdHwPtr->CurrentOffset)) : 0;\r
2130 if (RemainLen == 0) {\r
2131 goto exit;\r
2132 }\r
2133\r
2134 QtdHwPtr->BufferPointer1 = QtdHwPtr->BufferPointer0 + 1;\r
71a62114 2135 QtdHwPtr->ExtBufferPointer1 = (QtdHwPtr->BufferPointer1 == 0) ? (QtdHwPtr->ExtBufferPointer0 + 1) : QtdHwPtr->ExtBufferPointer0;\r
562d2849 2136\r
2137 //\r
2138 // Set BufferPointer2 and ExtBufferPointer2\r
2139 //\r
2140 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
2141 if (RemainLen == 0) {\r
2142 goto exit;\r
2143 }\r
2144\r
2145 QtdHwPtr->BufferPointer2 = QtdHwPtr->BufferPointer1 + 1;\r
71a62114 2146 QtdHwPtr->ExtBufferPointer2 = (QtdHwPtr->BufferPointer2 == 0) ? (QtdHwPtr->ExtBufferPointer1 + 1) : QtdHwPtr->ExtBufferPointer1;\r
562d2849 2147\r
2148 //\r
2149 // Set BufferPointer3 and ExtBufferPointer3\r
2150 //\r
2151 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
2152 if (RemainLen == 0) {\r
2153 goto exit;\r
2154 }\r
2155\r
2156 QtdHwPtr->BufferPointer3 = QtdHwPtr->BufferPointer2 + 1;\r
71a62114 2157 QtdHwPtr->ExtBufferPointer3 = (QtdHwPtr->BufferPointer2 == 0) ? (QtdHwPtr->ExtBufferPointer2 + 1) : QtdHwPtr->ExtBufferPointer2;\r
562d2849 2158\r
2159 //\r
2160 // Set BufferPointer4 and ExtBufferPointer4\r
2161 //\r
2162 RemainLen = RemainLen > EFI_PAGE_SIZE ? (RemainLen - EFI_PAGE_SIZE) : 0;\r
2163 if (RemainLen == 0) {\r
2164 goto exit;\r
2165 }\r
2166\r
2167 QtdHwPtr->BufferPointer4 = QtdHwPtr->BufferPointer3 + 1;\r
71a62114 2168 QtdHwPtr->ExtBufferPointer4 = (QtdHwPtr->BufferPointer3 == 0) ? (QtdHwPtr->ExtBufferPointer3 + 1) : QtdHwPtr->ExtBufferPointer3;\r
562d2849 2169\r
2170exit:\r
2171 return ;\r
2172}\r
2173\r
2174BOOLEAN\r
2175IsQtdStatusActive (\r
2176 IN EHCI_QTD_HW *HwQtdPtr\r
2177 )\r
2178/*++\r
2179\r
2180Routine Description:\r
2181\r
2182 Whether Qtd status is active or not\r
2183 \r
2184Arguments:\r
2185\r
2186 HwQtdPtr - A pointer to hardware Qtd structure\r
2187 \r
2188Returns:\r
2189\r
2190 TRUE Active\r
2191 FALSE Inactive\r
2192 \r
2193--*/\r
2194{\r
2195 UINT8 QtdStatus;\r
2196 BOOLEAN Value;\r
2197\r
2198 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2199 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_ACTIVE);\r
2200\r
2201 return Value;\r
2202}\r
2203\r
2204BOOLEAN\r
2205IsQtdStatusHalted (\r
2206 IN EHCI_QTD_HW *HwQtdPtr\r
2207 )\r
2208/*++\r
2209\r
2210Routine Description:\r
2211\r
2212 Whether Qtd status is halted or not\r
2213 \r
2214Arguments:\r
2215\r
2216 HwQtdPtr - A pointer to hardware Qtd structure\r
2217 \r
2218Returns:\r
2219\r
2220 TRUE Halted\r
2221 FALSE Not halted\r
2222 \r
2223--*/\r
2224{\r
2225 UINT8 QtdStatus;\r
2226 BOOLEAN Value;\r
2227\r
2228 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2229 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_HALTED);\r
2230\r
2231 return Value;\r
2232}\r
2233\r
2234BOOLEAN\r
2235IsQtdStatusBufferError (\r
2236 IN EHCI_QTD_HW *HwQtdPtr\r
2237 )\r
2238/*++\r
2239\r
2240Routine Description:\r
2241\r
2242 Whether Qtd status is buffer error or not\r
2243 \r
2244Arguments:\r
2245\r
2246 HwQtdPtr - A pointer to hardware Qtd structure\r
2247 \r
2248Returns:\r
2249\r
2250 TRUE Buffer error\r
2251 FALSE No buffer error\r
2252 \r
2253--*/\r
2254{\r
2255 UINT8 QtdStatus;\r
2256 BOOLEAN Value;\r
2257\r
2258 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2259 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BUFFER_ERR);\r
2260\r
2261 return Value;\r
2262}\r
2263\r
2264BOOLEAN\r
2265IsQtdStatusBabbleError (\r
2266 IN EHCI_QTD_HW *HwQtdPtr\r
2267 )\r
2268/*++\r
2269\r
2270Routine Description:\r
2271\r
2272 Whether Qtd status is babble error or not\r
2273 \r
2274Arguments:\r
2275\r
2276 HwQtdPtr - A pointer to hardware Qtd structure\r
2277 \r
2278Returns:\r
2279\r
2280 TRUE Babble error\r
2281 FALSE No babble error\r
2282 \r
2283--*/\r
2284{\r
2285 UINT8 QtdStatus;\r
2286 BOOLEAN Value;\r
2287\r
2288 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2289 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_BABBLE_ERR);\r
2290\r
2291 return Value;\r
2292}\r
2293\r
2294BOOLEAN\r
2295IsQtdStatusTransactionError (\r
2296 IN EHCI_QTD_HW *HwQtdPtr\r
2297 )\r
2298/*++\r
2299\r
2300Routine Description:\r
2301\r
2302 Whether Qtd status is transaction error or not\r
2303 \r
2304Arguments:\r
2305\r
2306 HwQtdPtr - A pointer to hardware Qtd structure\r
2307 \r
2308Returns:\r
2309\r
2310 TRUE Transaction error\r
2311 FALSE No transaction error\r
2312 \r
2313--*/\r
2314{\r
2315 UINT8 QtdStatus;\r
2316 BOOLEAN Value;\r
2317\r
2318 QtdStatus = (UINT8) (HwQtdPtr->Status);\r
2319 Value = (BOOLEAN) (QtdStatus & QTD_STATUS_TRANSACTION_ERR);\r
2320\r
2321 return Value;\r
2322}\r
2323\r
2324BOOLEAN\r
2325IsDataInTransfer (\r
2326 IN UINT8 EndPointAddress\r
2327 )\r
2328/*++\r
2329\r
2330Routine Description:\r
2331\r
2332 Whether is a DataIn direction transfer\r
2333 \r
2334Arguments:\r
2335\r
2336 EndPointAddress - address of the endpoint \r
2337 \r
2338Returns:\r
2339\r
2340 TRUE DataIn\r
2341 FALSE DataOut\r
2342 \r
2343--*/\r
2344{\r
2345 BOOLEAN Value;\r
2346\r
2347 if (EndPointAddress & 0x80) {\r
2348 Value = TRUE;\r
2349 } else {\r
2350 Value = FALSE;\r
2351 }\r
2352\r
2353 return Value;\r
2354}\r
2355\r
2356EFI_STATUS\r
2357MapDataBuffer (\r
2358 IN USB2_HC_DEV *HcDev,\r
2359 IN EFI_USB_DATA_DIRECTION TransferDirection,\r
2360 IN VOID *Data,\r
2361 IN OUT UINTN *DataLength,\r
2362 OUT UINT8 *PktId,\r
2363 OUT UINT8 **DataCursor,\r
2364 OUT VOID **DataMap\r
2365 )\r
2366/*++\r
2367\r
2368Routine Description:\r
2369\r
2370 Map address of user data buffer\r
2371 \r
2372Arguments:\r
2373\r
2374 HcDev - USB2_HC_DEV \r
2375 TransferDirection - direction of transfer\r
2376 Data - A pointer to user data buffer \r
2377 DataLength - length of user data\r
2378 PktId - Packte Identificaion\r
2379 DataCursor - mapped address to return\r
2380 DataMap - identificaion of this mapping to return\r
2381 \r
2382Returns:\r
2383\r
2384 EFI_SUCCESS Success\r
2385 EFI_DEVICE_ERROR Fail\r
2386 \r
2387--*/\r
2388{\r
2389 EFI_STATUS Status;\r
2390 EFI_PHYSICAL_ADDRESS TempPhysicalAddr;\r
2391\r
2392 Status = EFI_SUCCESS;\r
2393\r
2394 switch (TransferDirection) {\r
2395\r
2396 case EfiUsbDataIn:\r
2397\r
2398 *PktId = INPUT_PACKET_ID;\r
2399 //\r
2400 // BusMasterWrite means cpu read\r
2401 //\r
2402 Status = HcDev->PciIo->Map (\r
2403 HcDev->PciIo,\r
2404 EfiPciIoOperationBusMasterWrite,\r
2405 Data,\r
2406 DataLength,\r
2407 &TempPhysicalAddr,\r
2408 DataMap\r
2409 );\r
2410 if (EFI_ERROR (Status)) {\r
2411 DEBUG ((gEHCDebugLevel, "MapDataBuffer Failed\n"));\r
2412 Status = EFI_DEVICE_ERROR;\r
2413 goto exit;\r
2414 }\r
2415\r
2416 *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
2417 break;\r
2418\r
2419 case EfiUsbDataOut:\r
2420\r
2421 *PktId = OUTPUT_PACKET_ID;\r
2422 //\r
2423 // BusMasterRead means cpu write\r
2424 //\r
2425 Status = HcDev->PciIo->Map (\r
2426 HcDev->PciIo,\r
2427 EfiPciIoOperationBusMasterRead,\r
2428 Data,\r
2429 DataLength,\r
2430 &TempPhysicalAddr,\r
2431 DataMap\r
2432 );\r
2433 if (EFI_ERROR (Status)) {\r
2434 Status = EFI_DEVICE_ERROR;\r
2435 goto exit;\r
2436 }\r
2437\r
2438 *DataCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
2439 break;\r
2440\r
2441 case EfiUsbNoData:\r
2442\r
2443 *PktId = OUTPUT_PACKET_ID;\r
2444 Data = NULL;\r
2445 *DataLength = 0;\r
2446 *DataCursor = NULL;\r
2447 *DataMap = NULL;\r
2448 break;\r
2449\r
2450 default:\r
2451 \r
2452 Status = EFI_INVALID_PARAMETER;\r
2453 }\r
2454\r
2455exit:\r
2456 return Status;\r
2457}\r
2458\r
2459EFI_STATUS\r
2460MapRequestBuffer (\r
2461 IN USB2_HC_DEV *HcDev,\r
2462 IN OUT VOID *Request,\r
2463 OUT UINT8 **RequestCursor,\r
2464 OUT VOID **RequestMap\r
2465 )\r
2466/*++\r
2467\r
2468Routine Description:\r
2469\r
2470 Map address of request structure buffer\r
2471 \r
2472Arguments:\r
2473\r
2474 HcDev - USB2_HC_DEV \r
2475 Request - A pointer to request structure\r
2476 RequestCursor - Mapped address of request structure to return\r
2477 RequestMap - Identificaion of this mapping to return\r
2478 \r
2479Returns:\r
2480\r
2481 EFI_SUCCESS Success\r
2482 EFI_DEVICE_ERROR Fail\r
2483 \r
2484--*/\r
2485{\r
2486 EFI_STATUS Status;\r
2487 UINTN RequestLen;\r
2488 EFI_PHYSICAL_ADDRESS TempPhysicalAddr;\r
2489\r
2490 RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);\r
2491 Status = HcDev->PciIo->Map (\r
2492 HcDev->PciIo,\r
2493 EfiPciIoOperationBusMasterRead,\r
2494 (UINT8 *) Request,\r
2495 (UINTN *) &RequestLen,\r
2496 &TempPhysicalAddr,\r
2497 RequestMap\r
2498 );\r
2499 if (EFI_ERROR (Status)) {\r
2500 Status = EFI_DEVICE_ERROR;\r
2501 goto exit;\r
2502 }\r
2503\r
2504 *RequestCursor = (UINT8 *) ((UINTN) TempPhysicalAddr);\r
2505\r
2506exit:\r
2507 return Status;\r
2508}\r
2509\r
2510EFI_STATUS\r
2511DeleteAsyncRequestTransfer (\r
2512 IN USB2_HC_DEV *HcDev,\r
2513 IN UINT8 DeviceAddress,\r
2514 IN UINT8 EndPointAddress,\r
2515 OUT UINT8 *DataToggle\r
2516 )\r
2517/*++\r
2518\r
2519Routine Description:\r
2520\r
2521 Delete all asynchronous request transfer\r
2522 \r
2523Arguments:\r
2524\r
2525 HcDev - USB2_HC_DEV \r
2526 DeviceAddress - address of usb device\r
2527 EndPointAddress - address of endpoint\r
2528 DataToggle - stored data toggle\r
2529 \r
2530Returns:\r
2531\r
2532 EFI_SUCCESS Success\r
2533 EFI_DEVICE_ERROR Fail\r
2534 \r
2535--*/\r
2536{\r
2537 EFI_STATUS Status;\r
2538 EHCI_ASYNC_REQUEST *AsyncRequestPtr;\r
2539 EHCI_ASYNC_REQUEST *MatchPtr;\r
2540 EHCI_QH_HW *QhHwPtr;\r
2541 UINT8 EndPointNum;\r
2542\r
2543 if (NULL == HcDev->AsyncRequestList) {\r
2544 Status = EFI_INVALID_PARAMETER;\r
2545 goto exit;\r
2546 }\r
2547\r
2548 MatchPtr = NULL;\r
2549 QhHwPtr = NULL;\r
2550 EndPointNum = EndPointAddress & 0x0f;\r
2551 AsyncRequestPtr = HcDev->AsyncRequestList;\r
2552\r
2553 //\r
2554 // Find QH of AsyncRequest by DeviceAddress and EndPointNum\r
2555 //\r
2556 do {\r
2557\r
2558 QhHwPtr = &(AsyncRequestPtr->QhPtr->Qh);\r
2559 if (QhHwPtr->DeviceAddr == DeviceAddress && QhHwPtr->EndpointNum == EndPointNum) {\r
2560 MatchPtr = AsyncRequestPtr;\r
2561 break;\r
2562 }\r
2563\r
2564 AsyncRequestPtr = AsyncRequestPtr->Next;\r
2565\r
2566 } while (NULL != AsyncRequestPtr);\r
2567\r
2568 if (NULL == MatchPtr) {\r
2569 Status = EFI_INVALID_PARAMETER;\r
2570 goto exit;\r
2571 }\r
2572\r
2573 Status = DisablePeriodicSchedule (HcDev);\r
2574 if (EFI_ERROR (Status)) {\r
2575 Status = EFI_DEVICE_ERROR;\r
2576 goto exit;\r
2577 }\r
2578\r
2579 Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2580 if (EFI_ERROR (Status)) {\r
2581 DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleDisable TimeOut\n"));\r
2582 Status = EFI_TIMEOUT;\r
2583 goto exit;\r
2584 }\r
2585\r
2586 *DataToggle = (UINT8) MatchPtr->QhPtr->Qh.DataToggle;\r
2587 UnlinkQhFromPeriodicList (HcDev, MatchPtr->QhPtr, MatchPtr->QhPtr->Interval);\r
2588 UnlinkFromAsyncReqeust (HcDev, MatchPtr);\r
2589\r
2590 if (NULL == HcDev->AsyncRequestList) {\r
2591\r
2592 Status = StopPollingTimer (HcDev);\r
2593 if (EFI_ERROR (Status)) {\r
2594 Status = EFI_DEVICE_ERROR;\r
2595 goto exit;\r
2596 }\r
2597\r
2598 } else {\r
2599\r
2600 Status = EnablePeriodicSchedule (HcDev);\r
2601 if (EFI_ERROR (Status)) {\r
2602 Status = EFI_DEVICE_ERROR;\r
2603 goto exit;\r
2604 }\r
2605\r
2606 Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);\r
2607 if (EFI_ERROR (Status)) {\r
2608 DEBUG ((gEHCErrorLevel, "WaitForPeriodicScheduleEnable TimeOut\n"));\r
2609 Status = EFI_TIMEOUT;\r
2610 goto exit;\r
2611 }\r
2612\r
2613 if (IsEhcHalted (HcDev)) {\r
2614 Status = StartScheduleExecution (HcDev);\r
2615 if (EFI_ERROR (Status)) {\r
2616 Status = EFI_DEVICE_ERROR;\r
2617 goto exit;\r
2618 }\r
2619 }\r
2620\r
2621 }\r
2622\r
2623 DestoryQtds (HcDev, MatchPtr->QhPtr->FirstQtdPtr);\r
2624 DestoryQh (HcDev, MatchPtr->QhPtr);\r
2625 EhciFreePool (HcDev, (UINT8 *) MatchPtr, sizeof (EHCI_ASYNC_REQUEST));\r
2626\r
2627exit:\r
2628 return Status;\r
2629}\r
2630\r
2631VOID\r
2632CleanUpAllAsyncRequestTransfer (\r
2633 IN USB2_HC_DEV *HcDev\r
2634 )\r
2635/*++\r
2636\r
2637Routine Description:\r
2638\r
2639 Clean up all asynchronous request transfer\r
2640 \r
2641Arguments:\r
2642\r
2643 HcDev - USB2_HC_DEV \r
2644 \r
2645Returns:\r
2646\r
2647 VOID\r
2648 \r
2649--*/\r
2650{\r
2651 EHCI_ASYNC_REQUEST *AsyncRequestPtr;\r
2652 EHCI_ASYNC_REQUEST *FreePtr;\r
2653\r
2654 AsyncRequestPtr = NULL;\r
2655 FreePtr = NULL;\r
2656\r
2657 StopPollingTimer (HcDev);\r
2658\r
2659 AsyncRequestPtr = HcDev->AsyncRequestList;\r
2660 while (NULL != AsyncRequestPtr) {\r
2661\r
2662 FreePtr = AsyncRequestPtr;\r
2663 AsyncRequestPtr = AsyncRequestPtr->Next;\r
2664 UnlinkFromAsyncReqeust (HcDev, FreePtr);\r
2665 UnlinkQhFromPeriodicList (HcDev, FreePtr->QhPtr, FreePtr->QhPtr->Interval);\r
2666 DestoryQtds (HcDev, FreePtr->QhPtr->FirstQtdPtr);\r
2667 DestoryQh (HcDev, FreePtr->QhPtr);\r
2668 EhciFreePool (HcDev, (UINT8 *) FreePtr, sizeof (EHCI_ASYNC_REQUEST));\r
2669\r
2670 }\r
2671\r
2672 return ;\r
2673}\r
2674\r
2675VOID\r
2676ZeroOutQhOverlay (\r
2677 IN EHCI_QH_ENTITY *QhPtr\r
2678 )\r
2679/*++\r
2680\r
2681Routine Description:\r
2682\r
2683 Zero out the fields in Qh structure\r
2684 \r
2685Arguments:\r
2686\r
2687 QhPtr - A pointer to Qh structure\r
2688 \r
2689Returns:\r
2690\r
2691 VOID\r
2692 \r
2693--*/\r
2694{\r
2695 QhPtr->Qh.CurrentQtdPointer = 0;\r
2696 QhPtr->Qh.AltNextQtdPointer = 0;\r
2697 QhPtr->Qh.NakCount = 0;\r
2698 QhPtr->Qh.AltNextQtdTerminate = 0;\r
2699 QhPtr->Qh.TotalBytes = 0;\r
2700 QhPtr->Qh.InterruptOnComplete = 0;\r
2701 QhPtr->Qh.CurrentPage = 0;\r
2702 QhPtr->Qh.ErrorCount = 0;\r
2703 QhPtr->Qh.PidCode = 0;\r
2704 QhPtr->Qh.Status = 0;\r
2705 QhPtr->Qh.BufferPointer0 = 0;\r
2706 QhPtr->Qh.CurrentOffset = 0;\r
2707 QhPtr->Qh.BufferPointer1 = 0;\r
2708 QhPtr->Qh.CompleteSplitMask = 0;\r
2709 QhPtr->Qh.BufferPointer2 = 0;\r
2710 QhPtr->Qh.SplitBytes = 0;\r
2711 QhPtr->Qh.FrameTag = 0;\r
2712 QhPtr->Qh.BufferPointer3 = 0;\r
2713 QhPtr->Qh.BufferPointer4 = 0;\r
2714 QhPtr->Qh.ExtBufferPointer0 = 0;\r
2715 QhPtr->Qh.ExtBufferPointer1 = 0;\r
2716 QhPtr->Qh.ExtBufferPointer2 = 0;\r
2717 QhPtr->Qh.ExtBufferPointer3 = 0;\r
2718 QhPtr->Qh.ExtBufferPointer4 = 0;\r
2719}\r
2720\r
2721VOID\r
2722UpdateAsyncRequestTransfer (\r
2723 IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,\r
2724 IN UINT32 TransferResult,\r
2725 IN UINTN ErrQtdPos\r
2726 )\r
2727/*++\r
2728\r
2729Routine Description:\r
2730\r
2731 Update asynchronous request transfer\r
2732 \r
2733Arguments:\r
2734\r
2735 AsyncRequestPtr - A pointer to async request \r
2736 TransferResult - transfer result \r
2737 ErrQtdPos - postion of error Qtd\r
2738 \r
2739Returns:\r
2740\r
2741 VOID\r
2742 \r
2743--*/\r
2744{\r
2745 EHCI_QTD_ENTITY *QtdPtr;\r
2746\r
2747 QtdPtr = NULL;\r
2748\r
2749 if (EFI_USB_NOERROR == TransferResult) {\r
2750 \r
2751 //\r
2752 // Update Qh for next trigger\r
2753 //\r
2754\r
2755 QtdPtr = AsyncRequestPtr->QhPtr->FirstQtdPtr;\r
2756\r
2757 //\r
2758 // Update fields in Qh\r
2759 //\r
2760\r
2761 //\r
2762 // Get DataToggle from Overlay in Qh\r
2763 //\r
2764 // ZeroOut Overlay in Qh except DataToggle, HostController will update this field\r
2765 //\r
2766 ZeroOutQhOverlay (AsyncRequestPtr->QhPtr);\r
2767 AsyncRequestPtr->QhPtr->Qh.NextQtdPointer = (UINT32) (GET_0B_TO_31B (&(QtdPtr->Qtd)) >> 5);\r
2768 AsyncRequestPtr->QhPtr->Qh.NextQtdTerminate = FALSE;\r
2769\r
2770 //\r
2771 // Update fields in Qtd\r
2772 //\r
2773 while (NULL != QtdPtr) {\r
2774 QtdPtr->Qtd.TotalBytes = QtdPtr->StaticTotalBytes;\r
2775 QtdPtr->Qtd.CurrentOffset = QtdPtr->StaticCurrentOffset;\r
2776 QtdPtr->Qtd.CurrentPage = 0;\r
2777 QtdPtr->Qtd.ErrorCount = QTD_ERROR_COUNTER;\r
2778 QtdPtr->Qtd.Status = QTD_STATUS_ACTIVE;\r
2779\r
2780 QtdPtr->TotalBytes = QtdPtr->StaticTotalBytes;\r
2781 QtdPtr = QtdPtr->Next;\r
2782 }\r
2783 }\r
2784\r
2785 return ;\r
2786}\r
2787\r
2788BOOLEAN\r
2789CheckQtdsTransferResult (\r
2790 IN BOOLEAN IsControl,\r
2791 IN EHCI_QH_ENTITY *QhPtr,\r
2792 OUT UINT32 *Result,\r
2793 OUT UINTN *ErrQtdPos,\r
2794 OUT UINTN *ActualLen\r
2795 )\r
2796/*++\r
2797\r
2798Routine Description:\r
2799\r
2800 Check transfer result of Qtds\r
2801\r
2802Arguments:\r
2803\r
2804 IsControl - Is control transfer or not\r
2805 QhPtr - A pointer to Qh\r
2806 Result - Transfer result\r
2807 ErrQtdPos - Error TD Position\r
2808 ActualLen - Actual Transfer Size\r
2809\r
2810Returns:\r
2811\r
2812 TRUE Qtds finished\r
2813 FALSE Not finish\r
2814 \r
2815--*/\r
2816{\r
2817 UINTN ActualLenPerQtd;\r
2818 EHCI_QTD_ENTITY *QtdPtr;\r
2819 EHCI_QTD_HW *QtdHwPtr;\r
2820 BOOLEAN Value;\r
2821\r
2822 ASSERT (QhPtr);\r
2823 ASSERT (Result);\r
2824 ASSERT (ErrQtdPos);\r
2825 ASSERT (ActualLen);\r
2826\r
2827 Value = TRUE;\r
2828 QtdPtr = QhPtr->FirstQtdPtr;\r
2829 QtdHwPtr = &(QtdPtr->Qtd);\r
2830\r
2831 while (NULL != QtdHwPtr) {\r
2832\r
2833 if (IsQtdStatusActive (QtdHwPtr)) {\r
2834 *Result |= EFI_USB_ERR_NOTEXECUTE;\r
2835 }\r
2836\r
2837 if (IsQtdStatusHalted (QtdHwPtr)) {\r
2838 *Result |= EFI_USB_ERR_STALL;\r
2839 }\r
2840\r
2841 if (IsQtdStatusBufferError (QtdHwPtr)) {\r
2842 *Result |= EFI_USB_ERR_BUFFER;\r
2843 }\r
2844\r
2845 if (IsQtdStatusBabbleError (QtdHwPtr)) {\r
2846 *Result |= EFI_USB_ERR_BABBLE;\r
2847 }\r
2848\r
2849 if (IsQtdStatusTransactionError (QtdHwPtr)) {\r
2850 *Result |= EFI_USB_ERR_TIMEOUT;\r
2851 }\r
2852\r
2853 ActualLenPerQtd = QtdPtr->TotalBytes - QtdHwPtr->TotalBytes;\r
2854 QtdPtr->TotalBytes = QtdHwPtr->TotalBytes;\r
2855 //\r
2856 // Accumulate actual transferred data length in each DataQtd.\r\r
2857 //\r
2858 if (SETUP_PACKET_PID_CODE != QtdHwPtr->PidCode) {\r
2859 *ActualLen += ActualLenPerQtd;\r
2860 }\r
2861\r
2862 if (*Result) {\r
2863 Value = FALSE;\r
2864 break;\r
2865 }\r
2866\r
2867 if ((!IsControl) && (QtdPtr->TotalBytes > 0)) {\r
2868 //\r
2869 // Did something, but isn't full workload\r
2870 //\r
2871 break;\r
2872 }\r
2873\r
2874 (*ErrQtdPos)++;\r
71a62114 2875 QtdPtr = QtdPtr->Next;\r
2876 QtdHwPtr = &(QtdPtr->Qtd);\r
562d2849 2877\r
2878 }\r
2879\r
2880 return Value;\r
2881}\r
2882\r
2883EFI_STATUS\r
2884ExecuteTransfer (\r
2885 IN USB2_HC_DEV *HcDev,\r
2886 IN BOOLEAN IsControl,\r
2887 IN EHCI_QH_ENTITY *QhPtr,\r
2888 IN OUT UINTN *ActualLen,\r
2889 OUT UINT8 *DataToggle,\r
2890 IN UINTN TimeOut,\r
2891 OUT UINT32 *TransferResult\r
2892 )\r
2893/*++\r
2894\r
2895Routine Description:\r
2896\r
2897 Execute Bulk or SyncInterrupt Transfer\r
2898\r
2899Arguments:\r
2900\r
2901 HcDev - USB2_HC_DEV\r
2902 IsControl - Is control transfer or not\r
2903 QhPtr - A pointer to Qh\r
2904 ActualLen - Actual transfered Len \r
2905 DataToggle - Data Toggle\r
2906 TimeOut - TimeOut threshold\r
2907 TransferResult - Transfer result\r
2908 \r
2909Returns:\r
2910\r
2911 EFI_SUCCESS Sucess\r
2912 EFI_DEVICE_ERROR Fail\r
2913 \r
2914--*/\r
2915{\r
2916 EFI_STATUS Status;\r
2917 UINTN ErrQtdPos;\r
2918 UINTN Delay;\r
2919 UINTN RequireLen;\r
2920 BOOLEAN Finished;\r
2921\r
2922 Status = EFI_SUCCESS;\r
2923 ErrQtdPos = 0;\r
2924 *TransferResult = EFI_USB_NOERROR;\r
2925 RequireLen = *ActualLen;\r
2926 *ActualLen = 0;\r
2927 Finished = FALSE;\r
2928\r
2929 Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;\r
2930\r
2931 do {\r
2932 *TransferResult = 0;\r
2933 Finished = CheckQtdsTransferResult (\r
2934 IsControl,\r
2935 QhPtr,\r
2936 TransferResult,\r
2937 &ErrQtdPos,\r
2938 ActualLen\r
2939 );\r
2940 if (Finished) {\r
2941 break;\r
2942 }\r
2943 //\r
2944 // Qtd is inactive, which means bulk or interrupt transfer's end.\r
2945 //\r
2946 if (!(*TransferResult & EFI_USB_ERR_NOTEXECUTE)) {\r
2947 break;\r
2948 }\r
2949\r
2950 gBS->Stall (EHCI_SYNC_REQUEST_POLLING_TIME);\r
2951\r
2952 } while (--Delay);\r
2953\r
2954 if (EFI_USB_NOERROR != *TransferResult) {\r
2955 if (0 == Delay) {\r
2956 Status = EFI_TIMEOUT;\r
2957 } else {\r
2958 Status = EFI_DEVICE_ERROR;\r
2959 }\r
2960 }\r
2961\r
2962 //\r
2963 // Special for Bulk and Interrupt Transfer\r
2964 //\r
2965 *DataToggle = (UINT8) QhPtr->Qh.DataToggle;\r
2966 \r
2967 return Status;\r
2968}\r
2969\r
2970EFI_STATUS\r
2971AsyncRequestMoniter (\r
2972 IN EFI_EVENT Event,\r
2973 IN VOID *Context\r
2974 )\r
2975/*++\r
2976Routine Description:\r
2977 \r
2978 Interrupt transfer periodic check handler\r
2979 \r
2980Arguments:\r
2981 Event - Interrupt event\r
2982 Context - Pointer to USB2_HC_DEV\r
2983 \r
2984Returns:\r
2985\r
2986 EFI_SUCCESS Success\r
2987 EFI_DEVICE_ERROR Fail\r
2988 \r
2989--*/\r
2990{\r
2991 EFI_STATUS Status;\r
2992 USB2_HC_DEV *HcDev;\r
2993 EHCI_ASYNC_REQUEST *AsyncRequestPtr;\r
2994 EHCI_QTD_HW *QtdHwPtr;\r
2995 UINTN ErrQtdPos;\r
2996 UINTN ActualLen;\r
2997 UINT32 TransferResult;\r
2998 UINT8 *ReceiveBuffer;\r
2999 UINT8 *ProcessBuffer;\r
38a70270 3000 EHCI_ASYNC_REQUEST *NextPtr;\r
562d2849 3001\r
3002 Status = EFI_SUCCESS;\r
3003 QtdHwPtr = NULL;\r
3004 ReceiveBuffer = NULL;\r
3005 ProcessBuffer = NULL;\r
3006 HcDev = (USB2_HC_DEV *) Context;\r
3007 AsyncRequestPtr = HcDev->AsyncRequestList;\r
3008\r
3009 while (NULL != AsyncRequestPtr) {\r
3010\r
3011 TransferResult = 0;\r
3012 ErrQtdPos = 0;\r
3013 ActualLen = 0;\r
3014\r
3015 CheckQtdsTransferResult (\r
3016 FALSE, \r
3017 AsyncRequestPtr->QhPtr, \r
3018 &TransferResult, \r
3019 &ErrQtdPos, \r
3020 &ActualLen\r
3021 );\r
3022\r
3023 if ((TransferResult & EFI_USB_ERR_NAK) || (TransferResult & EFI_USB_ERR_NOTEXECUTE)) {\r
3024 AsyncRequestPtr = AsyncRequestPtr->Next;\r
3025 continue;\r
3026 }\r
3027 //\r
3028 // Allocate memory for EHC private data structure\r
3029 //\r
3030 ProcessBuffer = AllocateZeroPool (ActualLen);\r
3031 if (NULL == ProcessBuffer) {\r
3032 Status = EFI_OUT_OF_RESOURCES;\r
3033 goto exit;\r
3034 }\r
3035\r
3036 QtdHwPtr = &(AsyncRequestPtr->QhPtr->FirstQtdPtr->Qtd);\r
71a62114 3037 ReceiveBuffer = (UINT8 *) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);\r
562d2849 3038 CopyMem (\r
3039 ProcessBuffer,\r
3040 ReceiveBuffer,\r
3041 ActualLen\r
3042 );\r
3043\r
3044 UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);\r
3045\r
38a70270 3046 NextPtr = AsyncRequestPtr->Next;\r
3047\r
562d2849 3048 if (EFI_USB_NOERROR == TransferResult) {\r
3049\r
3050 if (AsyncRequestPtr->CallBackFunc != NULL) {\r
3051 (AsyncRequestPtr->CallBackFunc) (ProcessBuffer, ActualLen, AsyncRequestPtr->Context, TransferResult);\r
3052 }\r
3053\r
3054 } else {\r
3055\r
3056 //\r
3057 // leave error recovery to its related device driver. A common case of \r
3058 // the error recovery is to re-submit the interrupt transfer.\r
3059 // When an interrupt transfer is re-submitted, its position in the linked\r
3060 // list is changed. It is inserted to the head of the linked list, while\r
3061 // this function scans the whole list from head to tail. Thus, the\r
3062 // re-submitted interrupt transfer's callback function will not be called\r
3063 // again in this round.\r
3064 //\r
3065 if (AsyncRequestPtr->CallBackFunc != NULL) {\r
3066 (AsyncRequestPtr->CallBackFunc) (NULL, 0, AsyncRequestPtr->Context, TransferResult);\r
3067 }\r
3068\r
3069 }\r
3070\r
3071 if (NULL != ProcessBuffer) {\r
3072 gBS->FreePool (ProcessBuffer);\r
3073 }\r
3074\r
38a70270 3075 AsyncRequestPtr = NextPtr;\r
562d2849 3076 }\r
3077\r
3078exit:\r
3079 return Status;\r
3080}\r
3081\r