1a947058be0a378edcc86987aeac920c7b549bed
[people/mcb30/edk2.git] / edk2 / EdkModulePkg / Bus / Pci / Ehci / Dxe / EhciSched.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                     \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14     EhciSched.c\r
15     \r
16 Abstract: \r
17     \r
18 \r
19 Revision History\r
20 --*/\r
21 \r
22 #include "Ehci.h"\r
23 \r
24 EFI_STATUS\r
25 InitialPeriodicFrameList (\r
26   IN  USB2_HC_DEV     *HcDev,\r
27   IN  UINTN           Length\r
28   )\r
29 /*++\r
30 \r
31 Routine Description:\r
32 \r
33   Initialize Periodic Schedule Frame List\r
34 \r
35 Arguments:\r
36 \r
37   HcDev   - USB2_HC_DEV\r
38   Length  - Frame List Length\r
39   \r
40 Returns:\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
144 unmap_buffer:\r
145   HcDev->PciIo->Unmap (HcDev->PciIo, Map);\r
146 free_buffer:\r
147   HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);\r
148 exit:\r
149   return Status;\r
150 }\r
151 \r
152 VOID\r
153 DeinitialPeriodicFrameList (\r
154   IN  USB2_HC_DEV     *HcDev\r
155   )\r
156 /*++\r
157 \r
158 Routine Description:\r
159 \r
160   Deinitialize Periodic Schedule Frame List\r
161 \r
162 Arguments:\r
163 \r
164   HcDev - USB2_HC_DEV\r
165 \r
166 Returns:\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
177 EFI_STATUS\r
178 CreatePollingTimer (\r
179   IN  USB2_HC_DEV      *HcDev,\r
180   IN  EFI_EVENT_NOTIFY NotifyFunction\r
181   )\r
182 /*++\r
183 \r
184 Routine Description:\r
185 \r
186   Create Async Request Polling Timer\r
187 \r
188 Arguments:\r
189 \r
190   HcDev          - USB2_HC_DEV\r
191   NotifyFunction - Timer Notify Function\r
192   \r
193 Returns:\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
209 EFI_STATUS\r
210 DestoryPollingTimer (\r
211   IN  USB2_HC_DEV *HcDev\r
212   )\r
213 /*++\r
214 \r
215 Routine Description:\r
216 \r
217   Destory Async Request Polling Timer\r
218 \r
219 Arguments:\r
220 \r
221   HcDev - USB2_HC_DEV\r
222   \r
223 Returns:\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
233 EFI_STATUS\r
234 StartPollingTimer (\r
235   IN  USB2_HC_DEV *HcDev\r
236   )\r
237 /*++\r
238 \r
239 Routine Description:\r
240 \r
241   Start Async Request Polling Timer\r
242 \r
243 Arguments:\r
244 \r
245   HcDev - USB2_HC_DEV\r
246   \r
247 Returns:\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
261 EFI_STATUS\r
262 StopPollingTimer (\r
263   IN  USB2_HC_DEV *HcDev\r
264   )\r
265 /*++\r
266 \r
267 Routine Description:\r
268 \r
269   Stop Async Request Polling Timer\r
270 \r
271 Arguments:\r
272 \r
273   HcDev - USB2_HC_DEV\r
274   \r
275 Returns:\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
289 EFI_STATUS\r
290 CreateQh (\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
300 Routine Description:\r
301 \r
302   Create Qh Structure and Pre-Initialize\r
303 \r
304 Arguments:\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
313 Returns:\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   ZeroMem (*QhPtrPtr, sizeof (EHCI_QH_ENTITY));\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
372 exit:\r
373   return Status;\r
374 }\r
375 \r
376 VOID\r
377 DestoryQh (\r
378   IN USB2_HC_DEV         *HcDev,\r
379   IN EHCI_QH_ENTITY      *QhPtr\r
380   )\r
381 /*++\r
382 \r
383 Routine Description:\r
384 \r
385   Destory Qh Structure \r
386   \r
387 Arguments:\r
388 \r
389   HcDev - USB2_HC_DEV \r
390   QhPtr - A pointer to Qh\r
391   \r
392 Returns:\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
406 EFI_STATUS\r
407 CreateControlQh (\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
417 Routine Description:\r
418 \r
419   Create Qh for Control Transfer\r
420 \r
421 Arguments:\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
430 Returns:\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
478 exit:\r
479   return Status;\r
480 }\r
481 \r
482 EFI_STATUS\r
483 CreateBulkQh (\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
495 Routine Description:\r
496 \r
497   Create Qh for Bulk Transfer\r
498 \r
499 Arguments:\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
509 Returns:\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
558 exit:\r
559   return Status;\r
560 }\r
561 \r
562 EFI_STATUS\r
563 CreateInterruptQh (\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
576 Routine Description:\r
577 \r
578   Create Qh for Control Transfer\r
579 \r
580 Arguments:\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
591 Returns:\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
644 exit:\r
645   return Status;\r
646 }\r
647 \r
648 EFI_STATUS\r
649 CreateQtd (\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
660 Routine Description:\r
661 \r
662   Create Qtd Structure and Pre-Initialize it\r
663 \r
664 Arguments:\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
674 Returns:\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 \r
703   ZeroMem (*QtdPtrPtr, sizeof (EHCI_QTD_ENTITY));\r
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
766 exit:\r
767   return Status;\r
768 }\r
769 \r
770 EFI_STATUS\r
771 CreateSetupQtd (\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
778 Routine Description:\r
779 \r
780   Create Qtd Structure for Setup \r
781 \r
782 Arguments:\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
788 Returns:\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
806 EFI_STATUS\r
807 CreateDataQtd (\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
817 Routine Description:\r
818 \r
819   Create Qtd Structure for data \r
820 \r
821 Arguments:\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
830 Returns:\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
848 EFI_STATUS\r
849 CreateAltQtd (\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
856 Routine Description:\r
857 \r
858   Create Qtd Structure for Alternative \r
859 \r
860 Arguments:\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
866 Returns:\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
884 EFI_STATUS\r
885 CreateStatusQtd (\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
892 Routine Description:\r
893 \r
894   Create Qtd Structure for status \r
895 \r
896 Arguments:\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
902 Returns:\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
920 EFI_STATUS\r
921 CreateControlQtds (\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
932 Routine Description:\r
933 \r
934   Create Qtds list for Control Transfer \r
935 \r
936 Arguments:\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
945 Returns:\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
1077 destory_qtds:\r
1078   DestoryQtds (HcDev, FirstDataQtdPtr);\r
1079 destory_setup_qtd:\r
1080   DestoryQtds (HcDev, SetupQtdPtr);\r
1081 exit:\r
1082   return Status;\r
1083 }\r
1084 \r
1085 EFI_STATUS\r
1086 CreateBulkOrInterruptQtds (\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
1096 Routine Description:\r
1097 \r
1098   Create Qtds list for Bulk or Interrupt Transfer \r
1099 \r
1100 Arguments:\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
1110 Returns:\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
1190 destory_qtds:\r
1191   DestoryQtds (HcDev, FirstQtdPtr);\r
1192 exit:\r
1193   return Status;\r
1194 }\r
1195 \r
1196 VOID\r
1197 DestoryQtds (\r
1198   IN USB2_HC_DEV          *HcDev,\r
1199   IN EHCI_QTD_ENTITY      *FirstQtdPtr\r
1200   )\r
1201 /*++\r
1202 \r
1203 Routine Description:\r
1204 \r
1205   Destory all Qtds in the list\r
1206 \r
1207 Arguments:\r
1208 \r
1209   HcDev         - USB2_HC_DEV \r
1210   FirstQtdPtr   - A pointer to first Qtd in the list \r
1211     \r
1212 Returns:\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
1236 exit:\r
1237   return ;\r
1238 }\r
1239 \r
1240 UINTN\r
1241 GetNumberOfQtd (\r
1242   IN EHCI_QTD_ENTITY    *FirstQtdPtr\r
1243   )\r
1244 /*++\r
1245 \r
1246 Routine Description:\r
1247 \r
1248   Number of Qtds in the list\r
1249   \r
1250 Arguments:\r
1251 \r
1252   FirstQtdPtr - A pointer to first Qtd in the list\r
1253     \r
1254 Returns:\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
1275 UINTN\r
1276 GetNumberOfTransaction (\r
1277   IN UINTN    SizeOfData,\r
1278   IN UINTN    SizeOfTransaction\r
1279   )\r
1280 /*++\r
1281 \r
1282 Routine Description:\r
1283 \r
1284   Number of Transactions in one Qtd\r
1285   \r
1286 Arguments:\r
1287 \r
1288   SizeOfData           - Size of one Qtd\r
1289   SizeOfTransaction    - Size of one Transaction\r
1290    \r
1291 Returns:\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
1302 UINTN\r
1303 GetCapacityOfQtd (\r
1304   IN UINT8    *BufferCursor\r
1305   )\r
1306 /*++\r
1307 \r
1308 Routine Description:\r
1309 \r
1310   Get Size of First Qtd\r
1311   \r
1312 Arguments:\r
1313 \r
1314   BufferCursor       - BufferCursor of the Qtd\r
1315    \r
1316 Returns:\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
1327 UINTN\r
1328 GetApproxiOfInterval (\r
1329   IN UINTN  Interval\r
1330   )\r
1331 /*++\r
1332 \r
1333 Routine Description:\r
1334 \r
1335   Get the approximate value in the 2 index sequence\r
1336   \r
1337 Arguments:\r
1338 \r
1339   Interval  - the value of interval\r
1340   \r
1341 Returns:\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
1365 EHCI_QTD_HW *\r
1366 GetQtdAlternateNextPointer (\r
1367   IN EHCI_QTD_HW  *HwQtdPtr\r
1368   )\r
1369 /*++\r
1370 \r
1371 Routine Description:\r
1372 \r
1373   Get Qtd alternate next pointer field\r
1374   \r
1375 Arguments:\r
1376 \r
1377   HwQtdPtr - A pointer to hardware Qtd structure\r
1378   \r
1379 Returns:\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
1390     Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->AltNextQtdPointer << 5);\r
1391   }\r
1392 \r
1393   return Value;\r
1394 }\r
1395 \r
1396 EHCI_QTD_HW *\r
1397 GetQtdNextPointer (\r
1398   IN EHCI_QTD_HW  *HwQtdPtr\r
1399   )\r
1400 /*++\r
1401 \r
1402 Routine Description:\r
1403 \r
1404   Get Qtd next pointer field\r
1405   \r
1406 Arguments:\r
1407 \r
1408   HwQtdPtr - A pointer to hardware Qtd structure\r
1409   \r
1410 Returns:\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
1421     Value = (EHCI_QTD_HW *) GET_0B_TO_31B (HwQtdPtr->NextQtdPointer << 5);\r
1422   }\r
1423 \r
1424   return Value;\r
1425 }\r
1426 \r
1427 VOID LinkQtdToQtd (\r
1428   IN EHCI_QTD_ENTITY * PreQtdPtr, \r
1429   IN EHCI_QTD_ENTITY * QtdPtr\r
1430   )\r
1431 /*++\r
1432 \r
1433 Routine Description:\r
1434 \r
1435   Link Qtds together\r
1436   \r
1437 Arguments:\r
1438 \r
1439   PreQtdPtr   - A pointer to pre Qtd\r
1440   QtdPtr      - A pointer to next Qtd\r
1441     \r
1442 Returns:\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
1470 VOID LinkQtdsToAltQtd (\r
1471   IN EHCI_QTD_ENTITY  * FirstQtdPtr, \r
1472   IN EHCI_QTD_ENTITY  * AltQtdPtr\r
1473   )\r
1474 /*++\r
1475 \r
1476 Routine Description:\r
1477 \r
1478   Link AlterQtds together\r
1479   \r
1480 Arguments:\r
1481 \r
1482   FirstQtdPtr  - A pointer to first Qtd in the list\r
1483   AltQtdPtr    - A pointer to alternative Qtd\r
1484     \r
1485 Returns:\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
1516 VOID\r
1517 LinkQtdToQh (\r
1518   IN EHCI_QH_ENTITY      *QhPtr,\r
1519   IN EHCI_QTD_ENTITY     *QtdPtr\r
1520   )\r
1521 /*++\r
1522 \r
1523 Routine Description:\r
1524 \r
1525   Link Qtds list to Qh\r
1526   \r
1527 Arguments:\r
1528 \r
1529   QhPtr    - A pointer to Qh\r
1530   QtdPtr   - A pointer to first Qtd in the list\r
1531   \r
1532 Returns:\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
1566 EFI_STATUS\r
1567 LinkQhToAsyncList (\r
1568   IN  USB2_HC_DEV       *HcDev,\r
1569   IN EHCI_QH_ENTITY     *QhPtr\r
1570   )\r
1571 /*++\r
1572 \r
1573 Routine Description:\r
1574 \r
1575   Link Qh to Async Schedule List\r
1576   \r
1577 Arguments:\r
1578 \r
1579   HcDev  - USB2_HC_DEV \r
1580   QhPtr  - A pointer to Qh\r
1581   \r
1582 Returns:\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
1626 exit:\r
1627   return Status;\r
1628 }\r
1629 \r
1630 EFI_STATUS\r
1631 UnlinkQhFromAsyncList (\r
1632   IN USB2_HC_DEV        *HcDev,\r
1633   IN EHCI_QH_ENTITY     *QhPtr\r
1634   )\r
1635 /*++\r
1636 \r
1637 Routine Description:\r
1638 \r
1639   Unlink Qh from Async Schedule List\r
1640   \r
1641 Arguments:\r
1642 \r
1643   HcDev  - USB2_HC_DEV \r
1644   QhPtr  - A pointer to Qh\r
1645   \r
1646 Returns:\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
1677 exit:\r
1678   return Status;\r
1679 }\r
1680 \r
1681 VOID\r
1682 LinkQhToPeriodicList (\r
1683   IN USB2_HC_DEV        *HcDev,\r
1684   IN EHCI_QH_ENTITY     *QhPtr\r
1685   )\r
1686 /*++\r
1687 \r
1688 Routine Description:\r
1689 \r
1690   Link Qh to Periodic Schedule List\r
1691   \r
1692 Arguments:\r
1693 \r
1694   HcDev  - USB2_HC_DEV \r
1695   QhPtr  - A pointer to Qh\r
1696   \r
1697 Returns:\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
1731       FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
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
1746           QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Next->Qh) >> 5);\r
1747           QhPtr->Qh.SelectType          = QH_SELECT_TYPE;\r
1748           QhPtr->Qh.QhTerminate         = FALSE;\r
1749         }\r
1750 \r
1751         FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1766           FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1774           FindQhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
1775           FindQhPtr->Prev->Qh.SelectType          = QH_SELECT_TYPE;\r
1776           FindQhPtr->Prev->Qh.QhTerminate         = FALSE;\r
1777         }\r
1778 \r
1779         QhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(FindQhPtr->Qh) >> 5);\r
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
1790         FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1802       FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1816         FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1829           FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1847       FindQhHwPtr = (EHCI_QH_HW *) GET_0B_TO_31B (FrameEntryPtr->LinkPointer << 5);\r
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
1856       FindQhPtr->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1866       FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Qh) >> 5);\r
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
1875 VOID\r
1876 UnlinkQhFromPeriodicList (\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
1883 Routine Description:\r
1884 \r
1885   Unlink Qh from Periodic Schedule List\r
1886   \r
1887 Arguments:\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
1893 Returns:\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
1933           FrameEntryPtr->LinkPointer    = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);\r
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
1953         QhPtr->Prev->Qh.QhHorizontalPointer = (UINT32) GET_0B_TO_31B (&(QhPtr->Next->Qh) >> 5);\r
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
2011 VOID\r
2012 LinkToAsyncReqeust (\r
2013   IN  USB2_HC_DEV        *HcDev,\r
2014   IN  EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
2015   )\r
2016 /*++\r
2017 \r
2018 Routine Description:\r
2019 \r
2020   Llink AsyncRequest Entry to Async Request List\r
2021   \r
2022 Arguments:\r
2023 \r
2024   HcDev             - USB2_HC_DEV \r
2025   AsyncRequestPtr   - A pointer to Async Request Entry\r
2026   \r
2027 Returns:\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
2047 VOID\r
2048 UnlinkFromAsyncReqeust (\r
2049   IN  USB2_HC_DEV        *HcDev,\r
2050   IN  EHCI_ASYNC_REQUEST *AsyncRequestPtr\r
2051   )\r
2052 /*++\r
2053 \r
2054 Routine Description:\r
2055 \r
2056   Unlink AsyncRequest Entry from Async Request List\r
2057   \r
2058 Arguments:\r
2059 \r
2060   HcDev            - USB2_HC_DEV \r
2061   AsyncRequestPtr  - A pointer to Async Request Entry\r
2062   \r
2063 Returns:\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
2084 VOID\r
2085 SetQtdBufferPointer (\r
2086   IN EHCI_QTD_HW  *QtdHwPtr,\r
2087   IN VOID         *DataPtr,\r
2088   IN UINTN        DataLen\r
2089   )\r
2090 /*++\r
2091 \r
2092 Routine Description:\r
2093 \r
2094   Set data buffer pointers in Qtd\r
2095 \r
2096 Arguments:\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
2102 Returns:\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
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
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
2135   QtdHwPtr->ExtBufferPointer1 = (QtdHwPtr->BufferPointer1 == 0) ? (QtdHwPtr->ExtBufferPointer0 + 1) : QtdHwPtr->ExtBufferPointer0;\r
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
2146   QtdHwPtr->ExtBufferPointer2 = (QtdHwPtr->BufferPointer2 == 0) ? (QtdHwPtr->ExtBufferPointer1 + 1) : QtdHwPtr->ExtBufferPointer1;\r
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
2157   QtdHwPtr->ExtBufferPointer3 = (QtdHwPtr->BufferPointer2 == 0) ? (QtdHwPtr->ExtBufferPointer2 + 1) : QtdHwPtr->ExtBufferPointer2;\r
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
2168   QtdHwPtr->ExtBufferPointer4 = (QtdHwPtr->BufferPointer3 == 0) ? (QtdHwPtr->ExtBufferPointer3 + 1) : QtdHwPtr->ExtBufferPointer3;\r
2169 \r
2170 exit:\r
2171   return ;\r
2172 }\r
2173 \r
2174 BOOLEAN\r
2175 IsQtdStatusActive (\r
2176   IN EHCI_QTD_HW  *HwQtdPtr\r
2177   )\r
2178 /*++\r
2179 \r
2180 Routine Description:\r
2181 \r
2182   Whether Qtd status is active or not\r
2183   \r
2184 Arguments:\r
2185 \r
2186   HwQtdPtr - A pointer to hardware Qtd structure\r
2187   \r
2188 Returns:\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
2204 BOOLEAN\r
2205 IsQtdStatusHalted (\r
2206   IN EHCI_QTD_HW  *HwQtdPtr\r
2207   )\r
2208 /*++\r
2209 \r
2210 Routine Description:\r
2211 \r
2212   Whether Qtd status is halted or not\r
2213   \r
2214 Arguments:\r
2215 \r
2216   HwQtdPtr - A pointer to hardware Qtd structure\r
2217   \r
2218 Returns:\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
2234 BOOLEAN\r
2235 IsQtdStatusBufferError (\r
2236   IN EHCI_QTD_HW  *HwQtdPtr\r
2237   )\r
2238 /*++\r
2239 \r
2240 Routine Description:\r
2241 \r
2242   Whether Qtd status is buffer error or not\r
2243   \r
2244 Arguments:\r
2245 \r
2246   HwQtdPtr - A pointer to hardware Qtd structure\r
2247   \r
2248 Returns:\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
2264 BOOLEAN\r
2265 IsQtdStatusBabbleError (\r
2266   IN EHCI_QTD_HW  *HwQtdPtr\r
2267   )\r
2268 /*++\r
2269 \r
2270 Routine Description:\r
2271 \r
2272   Whether Qtd status is babble error or not\r
2273   \r
2274 Arguments:\r
2275 \r
2276   HwQtdPtr - A pointer to hardware Qtd structure\r
2277   \r
2278 Returns:\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
2294 BOOLEAN\r
2295 IsQtdStatusTransactionError (\r
2296   IN EHCI_QTD_HW  *HwQtdPtr\r
2297   )\r
2298 /*++\r
2299 \r
2300 Routine Description:\r
2301 \r
2302   Whether Qtd status is transaction error or not\r
2303   \r
2304 Arguments:\r
2305 \r
2306   HwQtdPtr - A pointer to hardware Qtd structure\r
2307   \r
2308 Returns:\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
2324 BOOLEAN\r
2325 IsDataInTransfer (\r
2326   IN UINT8     EndPointAddress\r
2327   )\r
2328 /*++\r
2329 \r
2330 Routine Description:\r
2331 \r
2332   Whether is a DataIn direction transfer\r
2333   \r
2334 Arguments:\r
2335 \r
2336   EndPointAddress - address of the endpoint \r
2337   \r
2338 Returns:\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
2356 EFI_STATUS\r
2357 MapDataBuffer (\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
2368 Routine Description:\r
2369 \r
2370   Map address of user data buffer\r
2371   \r
2372 Arguments:\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
2382 Returns:\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
2455 exit:\r
2456   return Status;\r
2457 }\r
2458 \r
2459 EFI_STATUS\r
2460 MapRequestBuffer (\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
2468 Routine Description:\r
2469 \r
2470   Map address of request structure buffer\r
2471   \r
2472 Arguments:\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
2479 Returns:\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
2506 exit:\r
2507   return Status;\r
2508 }\r
2509 \r
2510 EFI_STATUS\r
2511 DeleteAsyncRequestTransfer (\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
2519 Routine Description:\r
2520 \r
2521   Delete all asynchronous request transfer\r
2522   \r
2523 Arguments:\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
2530 Returns:\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
2627 exit:\r
2628   return Status;\r
2629 }\r
2630 \r
2631 VOID\r
2632 CleanUpAllAsyncRequestTransfer (\r
2633   IN USB2_HC_DEV  *HcDev\r
2634   )\r
2635 /*++\r
2636 \r
2637 Routine Description:\r
2638 \r
2639   Clean up all asynchronous request transfer\r
2640   \r
2641 Arguments:\r
2642 \r
2643   HcDev - USB2_HC_DEV \r
2644   \r
2645 Returns:\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
2675 VOID\r
2676 ZeroOutQhOverlay (\r
2677   IN EHCI_QH_ENTITY  *QhPtr\r
2678   )\r
2679 /*++\r
2680 \r
2681 Routine Description:\r
2682 \r
2683   Zero out the fields in Qh structure\r
2684   \r
2685 Arguments:\r
2686 \r
2687   QhPtr - A pointer to Qh structure\r
2688   \r
2689 Returns:\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
2721 VOID\r
2722 UpdateAsyncRequestTransfer (\r
2723   IN EHCI_ASYNC_REQUEST *AsyncRequestPtr,\r
2724   IN UINT32             TransferResult,\r
2725   IN UINTN              ErrQtdPos\r
2726   )\r
2727 /*++\r
2728 \r
2729 Routine Description:\r
2730 \r
2731   Update asynchronous request transfer\r
2732   \r
2733 Arguments:\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
2739 Returns:\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
2788 BOOLEAN\r
2789 CheckQtdsTransferResult (\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
2798 Routine Description:\r
2799 \r
2800   Check transfer result of Qtds\r
2801 \r
2802 Arguments:\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
2810 Returns:\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
2875     QtdPtr   = QtdPtr->Next;\r
2876     QtdHwPtr = &(QtdPtr->Qtd);\r
2877 \r
2878   }\r
2879 \r
2880   return Value;\r
2881 }\r
2882 \r
2883 EFI_STATUS\r
2884 ExecuteTransfer (\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
2895 Routine Description:\r
2896 \r
2897   Execute Bulk or SyncInterrupt Transfer\r
2898 \r
2899 Arguments:\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
2909 Returns:\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
2970 EFI_STATUS\r
2971 AsyncRequestMoniter (\r
2972   IN EFI_EVENT     Event,\r
2973   IN VOID          *Context\r
2974   )\r
2975 /*++\r
2976 Routine Description:\r
2977   \r
2978   Interrupt transfer periodic check handler\r
2979     \r
2980 Arguments:\r
2981   Event    - Interrupt event\r
2982   Context  - Pointer to USB2_HC_DEV\r
2983     \r
2984 Returns:\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
3000   EHCI_ASYNC_REQUEST  *NextPtr;\r
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
3037     ReceiveBuffer = (UINT8 *) GET_0B_TO_31B ((QtdHwPtr->BufferPointer0 << 12) | AsyncRequestPtr->QhPtr->FirstQtdPtr->StaticCurrentOffset);\r
3038     CopyMem (\r
3039       ProcessBuffer,\r
3040       ReceiveBuffer,\r
3041       ActualLen\r
3042       );\r
3043 \r
3044     UpdateAsyncRequestTransfer (AsyncRequestPtr, TransferResult, ErrQtdPos);\r
3045 \r
3046     NextPtr = AsyncRequestPtr->Next;\r
3047 \r
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
3075     AsyncRequestPtr = NextPtr;\r
3076   }\r
3077 \r
3078 exit:\r
3079   return Status;\r
3080 }\r
3081 \r