1913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/** @file
2913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
3ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  The EHCI register operation routines.
4ab6495eacf44edbccd0a187cf4295727f0318691eric_tian
5ca243131657ba03f58206a417b938aa14cff585cFeng TianCopyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
6cd5ebaa06dca3e6ef3c464081e6defe00d358c69hhtianThis program and the accompanying materials
7913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffare licensed and made available under the terms and conditions of the BSD License
8913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffwhich accompanies this distribution.  The full text of the license may be found at
9913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffhttp://opensource.org/licenses/bsd-license.php
10913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
11913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
14913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
15913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
16913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff#include "Uhci.h"
17913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
18913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
19913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
20ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Create Frame List Structure.
21913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
22ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    UHCI device.
23913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
24ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
25ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_UNSUPPORTED        Map memory fail.
26ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_SUCCESS            Success.
27913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
28913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
29913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffEFI_STATUS
30913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciInitFrameList (
31913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV         *Uhc
32913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
33913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
34913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  EFI_PHYSICAL_ADDRESS  MappedAddr;
35913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  EFI_STATUS            Status;
36913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  VOID                  *Buffer;
37913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  VOID                  *Mapping;
38913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                 Pages;
39913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                 Bytes;
40913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                 Index;
413af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  EFI_PHYSICAL_ADDRESS  PhyAddr;
42913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
43913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
44913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // The Frame List is a common buffer that will be
45913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // accessed by both the cpu and the usb bus master
46913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // at the same time. The Frame List ocupies 4K bytes,
47913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // and must be aligned on 4-Kbyte boundaries.
48913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
49913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Bytes = 4096;
50913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Pages = EFI_SIZE_TO_PAGES (Bytes);
51913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
52913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Status = Uhc->PciIo->AllocateBuffer (
53913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         Uhc->PciIo,
54913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         AllocateAnyPages,
55913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         EfiBootServicesData,
56913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         Pages,
57913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         &Buffer,
58913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         0
59913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         );
60913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
61913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (EFI_ERROR (Status)) {
62913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return EFI_OUT_OF_RESOURCES;
63913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
64913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
65913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Status = Uhc->PciIo->Map (
66913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         Uhc->PciIo,
67913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         EfiPciIoOperationBusMasterCommonBuffer,
68913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         Buffer,
69913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         &Bytes,
70913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         &MappedAddr,
71913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         &Mapping
72913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                         );
73913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
74913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (EFI_ERROR (Status) || (Bytes != 4096)) {
75913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Status = EFI_UNSUPPORTED;
76913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    goto ON_ERROR;
77913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
78913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
79aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  Uhc->FrameBase           = (UINT32 *) (UINTN) Buffer;
803af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->FrameMapping        = Mapping;
81913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
82913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
83aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  // Tell the Host Controller where the Frame List lies,
84aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  // by set the Frame List Base Address Register.
85aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  //
866691cae97ef6d23617a32f4c9fec60f6312ec959lgao  UhciSetFrameListBaseAddr (Uhc->PciIo, (VOID *) (UINTN) MappedAddr);
87aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian
88aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  //
89913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Allocate the QH used by sync interrupt/control/bulk transfer.
90913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // FS ctrl/bulk queue head is set to loopback so additional BW
91913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // can be reclaimed. Notice, LS don't support bulk transfer and
92913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // also doesn't support BW reclamation.
93913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
94913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->SyncIntQh  = UhciCreateQh (Uhc, 1);
95913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->CtrlQh     = UhciCreateQh (Uhc, 1);
96913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->BulkQh     = UhciCreateQh (Uhc, 1);
97913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
98913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if ((Uhc->SyncIntQh == NULL) || (Uhc->CtrlQh == NULL) || (Uhc->BulkQh == NULL)) {
99913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Uhc->PciIo->Unmap (Uhc->PciIo, Mapping);
100913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Status = EFI_OUT_OF_RESOURCES;
101913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    goto ON_ERROR;
102913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
103913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
104913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
105913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //                                                +-------------+
106913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //                                                |             |
107913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Link the three together: SyncIntQh->CtrlQh->BulkQh <---------+
108913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Each frame entry is linked to this sequence of QH. These QH
109913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // will remain on the schedul, never got removed
110913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
111aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_HW));
1123af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->SyncIntQh->QhHw.HorizonLink  = QH_HLINK (PhyAddr, FALSE);
113913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->SyncIntQh->NextQh            = Uhc->CtrlQh;
114913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
115aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_HW));
1163af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->CtrlQh->QhHw.HorizonLink     = QH_HLINK (PhyAddr, FALSE);
117913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->CtrlQh->NextQh               = Uhc->BulkQh;
118913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
119913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
120913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Some old platform such as Intel's Tiger 4 has a difficult time
121913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // in supporting the full speed bandwidth reclamation in the previous
122913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // mentioned form. Most new platforms don't suffer it.
123913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
1243af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->BulkQh->QhHw.HorizonLink     = QH_HLINK (PhyAddr, FALSE);
125913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
126913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->BulkQh->NextQh               = NULL;
127913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
128aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  Uhc->FrameBaseHostAddr = AllocateZeroPool (4096);
129aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  if (Uhc->FrameBaseHostAddr == NULL) {
130aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    Status = EFI_OUT_OF_RESOURCES;
131aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    goto ON_ERROR;
132aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  }
1333af875e2209cc43c8d14a75061eebde7bd91b198eric_tian
134aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_HW));
135913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  for (Index = 0; Index < UHCI_FRAME_NUM; Index++) {
136aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    Uhc->FrameBase[Index] = QH_HLINK (PhyAddr, FALSE);
137aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    Uhc->FrameBaseHostAddr[Index] = (UINT32)(UINTN)Uhc->SyncIntQh;
138913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
139913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
140913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return EFI_SUCCESS;
141913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
142913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffON_ERROR:
143913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Uhc->SyncIntQh != NULL) {
144913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW));
145913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
146913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
147913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Uhc->CtrlQh != NULL) {
148913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW));
149913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
150913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
151913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Uhc->BulkQh != NULL) {
152913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW));
153913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
154913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
155913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->PciIo->FreeBuffer (Uhc->PciIo, Pages, Buffer);
156913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return Status;
157913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
158913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
159913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
160913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
161ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Destory FrameList buffer.
162913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
163ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
164913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
165913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
166913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
167913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciDestoryFrameList (
168913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV           *Uhc
169913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
170913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
171913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
172913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Unmap the common buffer for framelist entry,
173913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // and free the common buffer.
174913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Uhci's frame list occupy 4k memory.
175913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
176913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->PciIo->Unmap (Uhc->PciIo, Uhc->FrameMapping);
177913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
178913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->PciIo->FreeBuffer (
179913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                Uhc->PciIo,
180913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                EFI_SIZE_TO_PAGES (4096),
181913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                (VOID *) Uhc->FrameBase
182913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                );
183913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
184aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  if (Uhc->FrameBaseHostAddr != NULL) {
185aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    FreePool (Uhc->FrameBaseHostAddr);
186aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  }
187aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian
188913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Uhc->SyncIntQh != NULL) {
189913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UsbHcFreeMem (Uhc->MemPool, Uhc->SyncIntQh, sizeof (UHCI_QH_SW));
190913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
191913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
192913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Uhc->CtrlQh != NULL) {
193913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UsbHcFreeMem (Uhc->MemPool, Uhc->CtrlQh, sizeof (UHCI_QH_SW));
194913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
195913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
196913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Uhc->BulkQh != NULL) {
197913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UsbHcFreeMem (Uhc->MemPool, Uhc->BulkQh, sizeof (UHCI_QH_SW));
198913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
199913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
2003af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->FrameBase           = NULL;
201aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  Uhc->FrameBaseHostAddr   = NULL;
2023af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->SyncIntQh           = NULL;
2033af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->CtrlQh              = NULL;
2043af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  Uhc->BulkQh              = NULL;
205913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
206913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
207913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
208913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
209913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Convert the poll rate to the maxium 2^n that is smaller
210ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  than Interval.
211913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
212ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Interval               The poll rate to convert.
213913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
214ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @return The converted poll rate.
215913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
216913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
217913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUINTN
218913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciConvertPollRate (
219913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UINTN               Interval
220913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
221913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
222913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                   BitCount;
223913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
224913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  ASSERT (Interval != 0);
225913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
226913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
227913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Find the index (1 based) of the highest non-zero bit
228913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
229913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  BitCount = 0;
230913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
231913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  while (Interval != 0) {
232913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Interval >>= 1;
233913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    BitCount++;
234913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
235913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
236913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return (UINTN)1 << (BitCount - 1);
237913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
238913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
239913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
240913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
241913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Link a queue head (for asynchronous interrupt transfer) to
242913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  the frame list.
243913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
2443af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  @param  Uhc                    The UHCI device.
245ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Qh                     The queue head to link into.
246913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
247913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
248913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
249913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciLinkQhToFrameList (
2503af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  USB_HC_DEV              *Uhc,
251913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_SW              *Qh
252913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
253913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
254913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                   Index;
255913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_SW              *Prev;
256913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_SW              *Next;
2573af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  EFI_PHYSICAL_ADDRESS    PhyAddr;
2583af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  EFI_PHYSICAL_ADDRESS    QhPciAddr;
2593af875e2209cc43c8d14a75061eebde7bd91b198eric_tian
2603af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  ASSERT ((Uhc->FrameBase != NULL) && (Qh != NULL));
261913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
262aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian  QhPciAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_HW));
263913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
264913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) {
265913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
266913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // First QH can't be NULL because we always keep static queue
267913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // heads on the frame list
268913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
2693af875e2209cc43c8d14a75061eebde7bd91b198eric_tian    ASSERT (!LINK_TERMINATED (Uhc->FrameBase[Index]));
270aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    Next  = (UHCI_QH_SW*)(UINTN)Uhc->FrameBaseHostAddr[Index];
271913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Prev  = NULL;
272913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
273913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
274913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Now, insert the queue head (Qh) into this frame:
275913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // 1. Find a queue head with the same poll interval, just insert
276913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //    Qh after this queue head, then we are done.
277913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
278913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // 2. Find the position to insert the queue head into:
279913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //      Previous head's interval is bigger than Qh's
280913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //      Next head's interval is less than Qh's
281913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //    Then, insert the Qh between then
282913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
283913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // This method is very much the same as that used by EHCI.
284913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Because each QH's interval is round down to 2^n, poll
285913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // rate is correct.
286913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
287913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    while (Next->Interval > Qh->Interval) {
288913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev  = Next;
289913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Next  = Next->NextQh;
2903af875e2209cc43c8d14a75061eebde7bd91b198eric_tian      ASSERT (Next != NULL);
291913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
292913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
293913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
294913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // The entry may have been linked into the frame by early insertation.
295913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // For example: if insert a Qh with Qh.Interval == 4, and there is a Qh
296913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // with Qh.Interval == 8 on the frame. If so, we are done with this frame.
297913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // It isn't necessary to compare all the QH with the same interval to
298913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Qh. This is because if there is other QH with the same interval, Qh
299913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // should has been inserted after that at FrameBase[0] and at FrameBase[0] it is
300913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // impossible (Next == Qh)
301913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
302913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Next == Qh) {
303913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      continue;
304913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
305913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
306913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Next->Interval == Qh->Interval) {
307913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
308913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // If there is a QH with the same interval, it locates at
309913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // FrameBase[0], and we can simply insert it after this QH. We
310913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // are all done.
311913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
312913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      ASSERT ((Index == 0) && (Qh->NextQh == NULL));
313913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
314913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev                    = Next;
315913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Next                    = Next->NextQh;
316913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
317913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Qh->NextQh              = Next;
318913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev->NextQh            = Qh;
319913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
320913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Qh->QhHw.HorizonLink    = Prev->QhHw.HorizonLink;
3213af875e2209cc43c8d14a75061eebde7bd91b198eric_tian
3223af875e2209cc43c8d14a75061eebde7bd91b198eric_tian      Prev->QhHw.HorizonLink  = QH_HLINK (QhPciAddr, FALSE);
323913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      break;
324913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
325913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
326913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
327913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // OK, find the right position, insert it in. If Qh's next
328913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // link has already been set, it is in position. This is
329913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // guarranted by 2^n polling interval.
330913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
331913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Qh->NextQh == NULL) {
332913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Qh->NextQh            = Next;
333aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian      PhyAddr = UsbHcGetPciAddressForHostMem (Uhc->MemPool, Next, sizeof (UHCI_QH_HW));
3343af875e2209cc43c8d14a75061eebde7bd91b198eric_tian      Qh->QhHw.HorizonLink  = QH_HLINK (PhyAddr, FALSE);
335913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
336913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
337913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Prev == NULL) {
338aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian      Uhc->FrameBase[Index]           = QH_HLINK (QhPciAddr, FALSE);
339aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian      Uhc->FrameBaseHostAddr[Index]   = (UINT32)(UINTN)Qh;
340913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    } else {
341913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev->NextQh            = Qh;
3423af875e2209cc43c8d14a75061eebde7bd91b198eric_tian      Prev->QhHw.HorizonLink  = QH_HLINK (QhPciAddr, FALSE);
343913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
344913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
345913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
346913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
347913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
348913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
349913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Unlink QH from the frame list is easier: find all
350913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  the precedence node, and pointer there next to QhSw's
351913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  next.
352913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
3533af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  @param  Uhc                    The UHCI device.
354ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Qh                     The queue head to unlink.
355913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
356913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
357913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
358913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciUnlinkQhFromFrameList (
3593af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  USB_HC_DEV              *Uhc,
3603af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  UHCI_QH_SW              *Qh
361913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
362913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
363913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                   Index;
364913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_SW              *Prev;
365913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_SW              *This;
366913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
3673af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  ASSERT ((Uhc->FrameBase != NULL) && (Qh != NULL));
368913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
369913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  for (Index = 0; Index < UHCI_FRAME_NUM; Index += Qh->Interval) {
370913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
371913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Frame link can't be NULL because we always keep static
372913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // queue heads on the frame list
373913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
3743af875e2209cc43c8d14a75061eebde7bd91b198eric_tian    ASSERT (!LINK_TERMINATED (Uhc->FrameBase[Index]));
375aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian    This  = (UHCI_QH_SW*)(UINTN)Uhc->FrameBaseHostAddr[Index];
376913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Prev  = NULL;
377913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
378913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
379913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Walk through the frame's QH list to find the
380913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // queue head to remove
381913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
382913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    while ((This != NULL) && (This != Qh)) {
383913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev  = This;
384913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      This  = This->NextQh;
385913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
386913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
387913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
388913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Qh may have already been unlinked from this frame
389913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // by early action.
390913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
391913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (This == NULL) {
392913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      continue;
393913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
394913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
395913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Prev == NULL) {
396913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
397913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // Qh is the first entry in the frame
398913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
399aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian      Uhc->FrameBase[Index]           = Qh->QhHw.HorizonLink;
400aa91de055c5e15a716f3a0ce6bf5a1c28fda9e56erictian      Uhc->FrameBaseHostAddr[Index]   = (UINT32)(UINTN)Qh->NextQh;
401913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    } else {
402913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev->NextQh            = Qh->NextQh;
403913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Prev->QhHw.HorizonLink  = Qh->QhHw.HorizonLink;
404913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
405913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
406913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
407913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
408913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
409913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
410ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Check TDs Results.
411913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
412ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    This UHCI device.
413ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Td                     UHCI_TD_SW to check.
414ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  IsLow                  Is Low Speed Device.
415ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  QhResult               Return the result of this TD list.
416913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
417913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  @return Whether the TD's result is finialized.
418913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
419913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
420913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffBOOLEAN
421913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciCheckTdStatus (
422913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  USB_HC_DEV          *Uhc,
423913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UHCI_TD_SW          *Td,
424913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  BOOLEAN             IsLow,
425913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  OUT UHCI_QH_RESULT      *QhResult
426913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
427913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
428913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                   Len;
429913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINT8                   State;
430913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_TD_HW              *TdHw;
431913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  BOOLEAN                 Finished;
432913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
433913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Finished             = TRUE;
434913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
435913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
436913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Initialize the data toggle to that of the first
437913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // TD. The next toggle to use is either:
438913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // 1. first TD's toggle if no TD is executed OK
439913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // 2. the next toggle of last executed-OK TD
440913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
441913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  QhResult->Result     = EFI_USB_NOERROR;
442913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  QhResult->NextToggle = (UINT8)Td->TdHw.DataToggle;
443913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  QhResult->Complete   = 0;
444913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
445913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  while (Td != NULL) {
446913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    TdHw  = &Td->TdHw;
447913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    State = (UINT8)TdHw->Status;
448913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
449913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
450913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // UHCI will set STALLED bit when it abort the execution
451913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // of TD list. There are several reasons:
452913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //   1. BABBLE error happened
453913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //   2. Received a STALL response
454913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //   3. Error count decreased to zero.
455913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
456913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error
457913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // bits when corresponding conditions happen. But these
458913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // conditions are not deadly, that is a TD can successfully
459913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // completes even these bits are set. But it is likely that
460913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // upper layer won't distinguish these condtions. So, only
461913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // set these bits when TD is actually halted.
462913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
463ab6495eacf44edbccd0a187cf4295727f0318691eric_tian    if ((State & USBTD_STALLED) != 0) {
464ab6495eacf44edbccd0a187cf4295727f0318691eric_tian      if ((State & USBTD_BABBLE) != 0) {
465913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Result |= EFI_USB_ERR_BABBLE;
466913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
467913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      } else if (TdHw->ErrorCount != 0) {
468913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Result |= EFI_USB_ERR_STALL;
469913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
470913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
471ab6495eacf44edbccd0a187cf4295727f0318691eric_tian      if ((State & USBTD_CRC) != 0) {
472913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Result |= EFI_USB_ERR_CRC;
473913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
474913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
475ab6495eacf44edbccd0a187cf4295727f0318691eric_tian      if ((State & USBTD_BUFFERR) != 0) {
476913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Result |= EFI_USB_ERR_BUFFER;
477913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
478913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
479ab6495eacf44edbccd0a187cf4295727f0318691eric_tian      if ((Td->TdHw.Status & USBTD_BITSTUFF) != 0) {
480913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Result |= EFI_USB_ERR_BITSTUFF;
481913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
482913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
483913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      if (TdHw->ErrorCount == 0) {
484913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Result |= EFI_USB_ERR_TIMEOUT;
485913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
486913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
487913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Finished = TRUE;
488913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      goto ON_EXIT;
489913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
490ab6495eacf44edbccd0a187cf4295727f0318691eric_tian    } else if ((State & USBTD_ACTIVE) != 0) {
491913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
492913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // The TD is still active, no need to check further.
493913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
494913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      QhResult->Result |= EFI_USB_ERR_NOTEXECUTE;
495913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
496913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Finished = FALSE;
497913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      goto ON_EXIT;
498913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
499913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    } else {
500913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
501913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // Update the next data toggle, it is always the
502913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // next to the last known-good TD's data toggle if
503913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // any TD is executed OK
504913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
505c52fa98ca98ceaab75e8ddf9ebcfbcbd323bab13vanjeff      QhResult->NextToggle = (UINT8) (1 - (UINT8)TdHw->DataToggle);
506913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
507913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
508913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // This TD is finished OK or met short packet read. Update the
509913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // transfer length if it isn't a SETUP.
510913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
511913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Len = (TdHw->ActualLen + 1) & 0x7FF;
512913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
513913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      if (TdHw->PidCode != SETUP_PACKET_ID) {
514913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        QhResult->Complete += Len;
515913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
516913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
517913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
518913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // Short packet condition for full speed input TD, also
519913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // terminate the transfer
520913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
521913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) {
52201331951708f980fca1fb3a791ab544adcd3a5d0Samer El-Haj-Mahmoud        DEBUG ((EFI_D_VERBOSE, "UhciCheckTdStatus: short packet read occured\n"));
523913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
524913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        Finished = TRUE;
525913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        goto ON_EXIT;
526913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
527913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
528913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
529913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Td = Td->NextTd;
530913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
531913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
532913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffON_EXIT:
533913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
534913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Check whether HC is halted. Don't move this up. It must be
535913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // called after data toggle is successfully updated.
536913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
537913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (!UhciIsHcWorking (Uhc->PciIo)) {
538913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    QhResult->Result |= EFI_USB_ERR_SYSTEM;
539913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Finished  = TRUE;
540913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
541913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
542913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Finished) {
543913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Uhc->PciIo->Flush (Uhc->PciIo);
544913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
545913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
546913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciAckAllInterrupt (Uhc);
547913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return Finished;
548913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
549913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
550913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
551913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
552ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Check the result of the transfer.
553913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
554ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
555ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Qh                     The queue head of the transfer.
556ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Td                     The first TDs of the transfer.
557ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  TimeOut                TimeOut value in milliseconds.
558ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  IsLow                  Is Low Speed Device.
559ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  QhResult               The variable to return result.
560913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
561ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_SUCCESS            The transfer finished with success.
562ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_DEVICE_ERROR       Transfer failed.
563913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
564913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
565913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffEFI_STATUS
566913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciExecuteTransfer (
567913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  USB_HC_DEV          *Uhc,
568913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UHCI_QH_SW          *Qh,
569913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UHCI_TD_SW          *Td,
570913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UINTN               TimeOut,
571913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  BOOLEAN             IsLow,
572913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  OUT UHCI_QH_RESULT      *QhResult
573913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
574913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
575913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                   Index;
576913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UINTN                   Delay;
577913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  BOOLEAN                 Finished;
578913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  EFI_STATUS              Status;
57917a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  BOOLEAN                 InfiniteLoop;
580913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
58117a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  Finished     = FALSE;
58217a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  Status       = EFI_SUCCESS;
583ca243131657ba03f58206a417b938aa14cff585cFeng Tian  Delay        = TimeOut * UHC_1_MILLISECOND;
58417a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  InfiniteLoop = FALSE;
5851c61953576f35507eb24032fe2804eaf9a0e976cvanjeff
58617a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  //
58717a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  // According to UEFI spec section 16.2.4, If Timeout is 0, then the caller
58817a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  // must wait for the function to be completed until EFI_SUCCESS or EFI_DEVICE_ERROR
58917a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  // is returned.
59017a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  //
59117a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  if (TimeOut == 0) {
59217a6c337d2a5fefd42feb83049e7dfa1b852822cerictian    InfiniteLoop = TRUE;
59317a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  }
59417a6c337d2a5fefd42feb83049e7dfa1b852822cerictian
59517a6c337d2a5fefd42feb83049e7dfa1b852822cerictian  for (Index = 0; InfiniteLoop || (Index < Delay); Index++) {
596913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Finished = UhciCheckTdStatus (Uhc, Td, IsLow, QhResult);
597913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
598913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
599913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Transfer is OK or some error occured (TD inactive)
600913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
601913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Finished) {
602913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      break;
603913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
604913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
605ca243131657ba03f58206a417b938aa14cff585cFeng Tian    gBS->Stall (UHC_1_MICROSECOND);
606913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
607913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
608913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (!Finished) {
6097df7393feb90e87c32f5473af14eec7562b09ce3jji    DEBUG ((EFI_D_ERROR, "UhciExecuteTransfer: execution not finished for %dms\n", (UINT32)TimeOut));
6101c61953576f35507eb24032fe2804eaf9a0e976cvanjeff    UhciDumpQh (Qh);
6111c61953576f35507eb24032fe2804eaf9a0e976cvanjeff    UhciDumpTds (Td);
612913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
613913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Status = EFI_TIMEOUT;
614913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
615913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  } else if (QhResult->Result != EFI_USB_NOERROR) {
6161c61953576f35507eb24032fe2804eaf9a0e976cvanjeff    DEBUG ((EFI_D_ERROR, "UhciExecuteTransfer: execution failed with result %x\n", QhResult->Result));
6171c61953576f35507eb24032fe2804eaf9a0e976cvanjeff    UhciDumpQh (Qh);
6181c61953576f35507eb24032fe2804eaf9a0e976cvanjeff    UhciDumpTds (Td);
619913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
620913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Status = EFI_DEVICE_ERROR;
621913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
622913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
623913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return Status;
624913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
625913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
626913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
627913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
628ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Update Async Request, QH and TDs.
629913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
6303af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  @param  Uhc                    The UHCI device.
631ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  AsyncReq               The UHCI asynchronous transfer to update.
632ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Result                 Transfer reslut.
633ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  NextToggle             The toggle of next data.
634913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
635913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
636913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
637913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciUpdateAsyncReq (
6383af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  IN USB_HC_DEV          *Uhc,
639913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UHCI_ASYNC_REQUEST  *AsyncReq,
640913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINT32              Result,
641913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINT32              NextToggle
642913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
643913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
644913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_SW              *Qh;
645913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_TD_SW              *FirstTd;
646913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_TD_SW              *Td;
647913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
648913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Qh          = AsyncReq->QhSw;
649913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  FirstTd     = AsyncReq->FirstTd;
650913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
651913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (Result == EFI_USB_NOERROR) {
652913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
653913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // The last transfer succeeds. Then we need to update
654913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // the Qh and Td for next round of transfer.
655913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // 1. Update the TD's data toggle
656913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // 2. Activate all the TDs
657913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // 3. Link the TD to the queue head again since during
658913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //    execution, queue head's TD pointer is changed by
659913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //    hardware.
660913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
661913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    for (Td = FirstTd; Td != NULL; Td = Td->NextTd) {
662913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Td->TdHw.DataToggle = NextToggle;
663913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      NextToggle         ^= 1;
664913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Td->TdHw.Status    |= USBTD_ACTIVE;
665913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
666913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
6673af875e2209cc43c8d14a75061eebde7bd91b198eric_tian    UhciLinkTdToQh (Uhc, Qh, FirstTd);
668913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return ;
669913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
670913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
671913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
672913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
673913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
674ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Create Async Request node, and Link to List.
675ab6495eacf44edbccd0a187cf4295727f0318691eric_tian
676ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
677ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Qh                     The queue head of the transfer.
678ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  FirstTd                First TD of the transfer.
679ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  DevAddr                Device Address.
680ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  EndPoint               EndPoint Address.
681ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  DataLen                Data length.
682ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Interval               Polling Interval when inserted to frame list.
683ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Data                   Data buffer, unmapped.
684ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Callback               Callback after interrupt transfeer.
685ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Context                Callback Context passed as function parameter.
686ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  IsLow                  Is Low Speed.
687ab6495eacf44edbccd0a187cf4295727f0318691eric_tian
688ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_SUCCESS            An asynchronous transfer is created.
689ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_INVALID_PARAMETER  Paremeter is error.
690913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  @retval EFI_OUT_OF_RESOURCES   Failed because of resource shortage.
691913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
692913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
693913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffEFI_STATUS
694913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciCreateAsyncReq (
695913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV                       *Uhc,
696913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UHCI_QH_SW                       *Qh,
697913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UHCI_TD_SW                       *FirstTd,
698913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINT8                            DevAddr,
699913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINT8                            EndPoint,
700913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINTN                            DataLen,
701913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINTN                            Interval,
702913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UINT8                            *Data,
703913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN EFI_ASYNC_USB_TRANSFER_CALLBACK  Callback,
704913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN VOID                             *Context,
705913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN BOOLEAN                          IsLow
706913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
707913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
708913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_ASYNC_REQUEST      *AsyncReq;
709913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
710913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq = AllocatePool (sizeof (UHCI_ASYNC_REQUEST));
711913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
712913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (AsyncReq == NULL) {
713913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return EFI_OUT_OF_RESOURCES;
714913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
715913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
716913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
717913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Fill Request field. Data is allocated host memory, not mapped
718913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
719913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->Signature   = UHCI_ASYNC_INT_SIGNATURE;
720913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->DevAddr     = DevAddr;
721913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->EndPoint    = EndPoint;
722913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->DataLen     = DataLen;
723b4c24e2d42b6d91a6abdca2c3341469350e57483vanjeff  AsyncReq->Interval    = UhciConvertPollRate(Interval);
724913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->Data        = Data;
725913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->Callback    = Callback;
726913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->Context     = Context;
727913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->QhSw        = Qh;
728913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->FirstTd     = FirstTd;
729913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  AsyncReq->IsLow       = IsLow;
730913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
731913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
732913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Insert the new interrupt transfer to the head of the list.
733913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // The interrupt transfer's monitor function scans the whole
734913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // list from head to tail. The new interrupt transfer MUST be
735913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // added to the head of the list.
736913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
737913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  InsertHeadList (&(Uhc->AsyncIntList), &(AsyncReq->Link));
738913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
739913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return EFI_SUCCESS;
740913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
741913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
742913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
743913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
744ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Free an asynchronous request's resource such as memory.
745913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
746ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
747ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  AsyncReq               The asynchronous request to free.
748913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
749913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
750913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
751913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciFreeAsyncReq (
752913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV           *Uhc,
753913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UHCI_ASYNC_REQUEST   *AsyncReq
754913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
755913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
756913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  ASSERT ((Uhc != NULL) && (AsyncReq != NULL));
757913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
758913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciDestoryTds (Uhc, AsyncReq->FirstTd);
759913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UsbHcFreeMem (Uhc->MemPool, AsyncReq->QhSw, sizeof (UHCI_QH_SW));
760913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
761913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (AsyncReq->Data != NULL) {
762db731882fa90d1311a0828b2fbf13f766d8c21b6eric_tian    UsbHcFreeMem (Uhc->MemPool, AsyncReq->Data, AsyncReq->DataLen);
763913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
764913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
765913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  gBS->FreePool (AsyncReq);
766913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
767913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
768913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
769913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
770913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Unlink an asynchronous request's from UHC's asynchronus list.
771913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  also remove the queue head from the frame list. If FreeNow,
772913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  release its resource also. Otherwise, add the request to the
773913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHC's recycle list to wait for a while before release the memory.
774913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Until then, hardware won't hold point to the request.
775913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
776ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
777ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  AsyncReq               The asynchronous request to free.
778913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  @param  FreeNow                If TRUE, free the resource immediately, otherwise
779913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff                                 add the request to recycle wait list.
780913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
781913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
782913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
783913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciUnlinkAsyncReq (
784913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV           *Uhc,
785913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN UHCI_ASYNC_REQUEST   *AsyncReq,
786913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN BOOLEAN              FreeNow
787913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
788913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
789913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  ASSERT ((Uhc != NULL) && (AsyncReq != NULL));
790913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
791913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  RemoveEntryList (&(AsyncReq->Link));
7923af875e2209cc43c8d14a75061eebde7bd91b198eric_tian  UhciUnlinkQhFromFrameList (Uhc, AsyncReq->QhSw);
793913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
794913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (FreeNow) {
795913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UhciFreeAsyncReq (Uhc, AsyncReq);
796913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  } else {
797913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
798913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // To sychronize with hardware, mark the queue head as inactive
799913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // then add AsyncReq to UHC's recycle list
800913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
801913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    AsyncReq->QhSw->QhHw.VerticalLink = QH_VLINK (NULL, TRUE);
802913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    AsyncReq->Recycle = Uhc->RecycleWait;
803913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Uhc->RecycleWait  = AsyncReq;
804913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
805913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
806913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
807913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
808913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
809ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Delete Async Interrupt QH and TDs.
810913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
811ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
812ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  DevAddr                Device Address.
813ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  EndPoint               EndPoint Address.
814ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Toggle                 The next data toggle to use.
815913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
816ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_SUCCESS            The request is deleted.
817ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_INVALID_PARAMETER  Paremeter is error.
818ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @retval EFI_NOT_FOUND          The asynchronous isn't found.
819913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
820913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
821913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffEFI_STATUS
822913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciRemoveAsyncReq (
823913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  USB_HC_DEV          *Uhc,
824913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UINT8               DevAddr,
825913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN  UINT8               EndPoint,
826913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  OUT UINT8               *Toggle
827913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
828913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
829913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  EFI_STATUS          Status;
830913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_ASYNC_REQUEST  *AsyncReq;
831913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_RESULT      QhResult;
832913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  LIST_ENTRY          *Link;
833913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  BOOLEAN             Found;
834913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
835913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Status = EFI_SUCCESS;
836913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
837913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
838913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // If no asynchronous interrupt transaction exists
839913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
840913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (IsListEmpty (&(Uhc->AsyncIntList))) {
841913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return EFI_SUCCESS;
842913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
843913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
844913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
845913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Find the asynchronous transfer to this device/endpoint pair
846913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
847913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Found = FALSE;
848913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Link  = Uhc->AsyncIntList.ForwardLink;
849913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
850913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  do {
851913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    AsyncReq  = UHCI_ASYNC_INT_FROM_LINK (Link);
852913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Link      = Link->ForwardLink;
853913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
854913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if ((AsyncReq->DevAddr == DevAddr) && (AsyncReq->EndPoint == EndPoint)) {
855913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Found = TRUE;
856913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      break;
857913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
858913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
859913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  } while (Link != &(Uhc->AsyncIntList));
860913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
861913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (!Found) {
862913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return EFI_NOT_FOUND;
863913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
864913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
865913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
866913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Check the result of the async transfer then update it
867913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // to get the next data toggle to use.
868913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
869913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciCheckTdStatus (Uhc, AsyncReq->FirstTd, AsyncReq->IsLow, &QhResult);
870913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  *Toggle = QhResult.NextToggle;
871913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
872913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
873913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Don't release the request now, keep it to synchronize with hardware.
874913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
875913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciUnlinkAsyncReq (Uhc, AsyncReq, FALSE);
876913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  return Status;
877913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
878913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
879913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
880913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
881913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Recycle the asynchronouse request. When a queue head
882913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  is unlinked from frame list, host controller hardware
883913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  may still hold a cached pointer to it. To synchronize
884913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  with hardware, the request is released in two steps:
885913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  first it is linked to the UHC's RecycleWait list. At
886913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  the next time UhciMonitorAsyncReqList is fired, it is
887913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  moved to UHC's Recylelist. Then, at another timer
888913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  activation, all the requests on Recycle list is freed.
889913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  This guarrantes that each unlink queue head keeps
890913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  existing for at least 50ms, far enough for the hardware
891913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  to clear its cache.
892913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
893ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
894913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
895913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
896913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
897913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciRecycleAsyncReq (
898913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV           *Uhc
899913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
900913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
901913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_ASYNC_REQUEST      *Req;
902913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_ASYNC_REQUEST      *Next;
903913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
904913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Req = Uhc->Recycle;
905913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
906913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  while (Req != NULL) {
907913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Next = Req->Recycle;
908913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UhciFreeAsyncReq (Uhc, Req);
909913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Req  = Next;
910913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
911913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
912913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->Recycle     = Uhc->RecycleWait;
913913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc->RecycleWait = NULL;
914913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
915913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
916913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
917913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
918913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
919913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Release all the asynchronous transfers on the lsit.
920913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
921ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Uhc                    The UHCI device.
922913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
923913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
924913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
925913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciFreeAllAsyncReq (
926913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN USB_HC_DEV           *Uhc
927913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
928913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
929913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  LIST_ENTRY              *Head;
930913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_ASYNC_REQUEST      *AsyncReq;
931913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
932913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
933913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Call UhciRecycleAsyncReq twice. The requests on Recycle
934913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // will be released at the first call; The requests on
935913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // RecycleWait will be released at the second call.
936913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
937913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciRecycleAsyncReq (Uhc);
938913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciRecycleAsyncReq (Uhc);
939913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
940913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Head = &(Uhc->AsyncIntList);
941913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
942913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (IsListEmpty (Head)) {
943913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return;
944913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
945913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
946913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  while (!IsListEmpty (Head)) {
947913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    AsyncReq  = UHCI_ASYNC_INT_FROM_LINK (Head->ForwardLink);
948913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    UhciUnlinkAsyncReq (Uhc, AsyncReq, TRUE);
949913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
950913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
951913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
952913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
953913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff/**
954ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  Interrupt transfer periodic check handler.
955913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
956ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Event                  The event of the time.
957ab6495eacf44edbccd0a187cf4295727f0318691eric_tian  @param  Context                Context of the event, pointer to USB_HC_DEV.
958913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
959913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff**/
960913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffVOID
9616d3ea23f1183f3378a53e44d34c0a27aebec7d9ajljustenEFIAPI
962913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeffUhciMonitorAsyncReqList (
963913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN EFI_EVENT            Event,
964913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  IN VOID                 *Context
965913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  )
966913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff{
967913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_ASYNC_REQUEST      *AsyncReq;
968913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  LIST_ENTRY              *Link;
969913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  USB_HC_DEV              *Uhc;
970913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  VOID                    *Data;
971913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  BOOLEAN                 Finished;
972913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UHCI_QH_RESULT          QhResult;
973913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
974913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Uhc = (USB_HC_DEV *) Context;
975913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
976913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
977913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // Recycle the asynchronous requests expired, and promote
978913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // requests waiting to be recycled the next time when this
979913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // timer expires
980913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
981913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  UhciRecycleAsyncReq (Uhc);
982913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
983913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  if (IsListEmpty (&(Uhc->AsyncIntList))) {
984913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    return ;
985913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  }
986913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
987913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
988913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  // This loop must be delete safe
989913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  //
990913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  Link = Uhc->AsyncIntList.ForwardLink;
991913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
992913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  do {
993913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    AsyncReq  = UHCI_ASYNC_INT_FROM_LINK (Link);
994913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Link      = Link->ForwardLink;
995913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
996913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Finished = UhciCheckTdStatus (Uhc, AsyncReq->FirstTd, AsyncReq->IsLow, &QhResult);
997913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
998913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (!Finished) {
999913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      continue;
1000913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
1001913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
1002913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
1003913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Copy the data to temporary buffer if there are some
1004913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // data transferred. We may have zero-length packet
1005913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
1006913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    Data = NULL;
1007913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
1008913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (QhResult.Complete != 0) {
1009913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      Data = AllocatePool (QhResult.Complete);
1010913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
1011913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      if (Data == NULL) {
1012913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff        return ;
1013913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      }
1014913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
1015913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      CopyMem (Data, AsyncReq->FirstTd->Data, QhResult.Complete);
1016913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
1017913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
10183af875e2209cc43c8d14a75061eebde7bd91b198eric_tian    UhciUpdateAsyncReq (Uhc, AsyncReq, QhResult.Result, QhResult.NextToggle);
1019913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
1020913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
1021913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // Now, either transfer is SUCCESS or met errors since
1022913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // we have skipped to next transfer earlier if current
1023913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    // transfer is still active.
1024913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    //
1025913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (QhResult.Result == EFI_USB_NOERROR) {
1026913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      AsyncReq->Callback (Data, QhResult.Complete, AsyncReq->Context, QhResult.Result);
1027913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    } else {
1028913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
1029913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // Leave error recovery to its related device driver.
1030913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // A common case of the error recovery is to re-submit
1031913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // the interrupt transfer. When an interrupt transfer
1032913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // is re-submitted, its position in the linked list is
1033913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // changed. It is inserted to the head of the linked
1034913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // list, while this function scans the whole list from
1035913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // head to tail. Thus, the re-submitted interrupt transfer's
1036913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      // callback function will not be called again in this round.
1037913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      //
1038913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      AsyncReq->Callback (NULL, 0, AsyncReq->Context, QhResult.Result);
1039913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
1040913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff
1041913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    if (Data != NULL) {
1042913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff      gBS->FreePool (Data);
1043913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff    }
1044913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff  } while (Link != &(Uhc->AsyncIntList));
1045913cb9dc645d6db47d8c2a0be0369083b8bed25dvanjeff}
1046