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