staging: add ath6kl driver for AR6003 chip

AR6003 is a single stream, SDIO based 802.11 chipset from
Atheros optimized for mobile and embedded devices. ath6kl is a
cfg80211 driver for AR6003 and supports both the station and
AP mode of operation.

Station mode supports 802.11 a/b/g/n with HT20 on 2.4/5GHz and
HT40 only on 5GHz. Some of the other features include WPA/WPA2,
WPS, WMM, WMM-PS, and BT coexistence. AP mode can be operated
only in b/g mode with support for a subset of features mentioned
above.

The driver supports cfg80211 but comes with its own set of
wext ioctls which have historically supported some of our
customers with features like BT 3.0 and AP mode of operation.

For further details, please refer to:

http://wireless.kernel.org/en/users/Drivers/ath6kl

The driver requires firmware that runs on the chip's network
processor. The majority of it is stored in ROM. The binaries
that are downloaded and executed from RAM are as follows:

1) Patch against the code in ROM for bug fixes and feature
   enhancements.
2) Code to copy the data from the OTP region of the memory
   into RAM.
3) Calibration file carrying board specific data.

The above files need to be present in the directory
'/lib/firmware/ath6k/AR6003/hw2.0/' for the driver to initialize
the chip upon enumeration. The files can be downloaded from the
link specified at the following location:

http://wireless.kernel.org/en/users/Drivers/ath6kl#Download

This driver is only provided in the interim while we work on
the mac80211 replacement, ath6k. Once the mac80211 driver
achieves feature parity with the ath6kl driver, the ath6kl will
be deprecated and removed from staging.

Signed-off-by: Vipin Mehta <vmehta@atheros.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/ath6kl/htc2/htc_send.c b/drivers/staging/ath6kl/htc2/htc_send.c
new file mode 100644
index 0000000..bc7ee78
--- /dev/null
+++ b/drivers/staging/ath6kl/htc2/htc_send.c
@@ -0,0 +1,1023 @@
+//------------------------------------------------------------------------------
+// <copyright file="htc_send.c" company="Atheros">
+//    Copyright (c) 2007-2010 Atheros Corporation.  All rights reserved.
+// 
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+//
+//
+//------------------------------------------------------------------------------
+//==============================================================================
+// Author(s): ="Atheros"
+//==============================================================================
+#include "htc_internal.h"
+
+typedef enum _HTC_SEND_QUEUE_RESULT {
+    HTC_SEND_QUEUE_OK = 0,    /* packet was queued */
+    HTC_SEND_QUEUE_DROP = 1,  /* this packet should be dropped */
+} HTC_SEND_QUEUE_RESULT;
+
+#define DO_EP_TX_COMPLETION(ep,q)  DoSendCompletion(ep,q)
+
+/* call the distribute credits callback with the distribution */
+#define DO_DISTRIBUTION(t,reason,description,pList) \
+{                                             \
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,           \
+        ("  calling distribute function (%s) (dfn:0x%lX, ctxt:0x%lX, dist:0x%lX) \n", \
+                (description),                                           \
+                (unsigned long)(t)->DistributeCredits,                   \
+                (unsigned long)(t)->pCredDistContext,                    \
+                (unsigned long)pList));                                  \
+    (t)->DistributeCredits((t)->pCredDistContext,                        \
+                           (pList),                                      \
+                           (reason));                                    \
+}
+
+static void DoSendCompletion(HTC_ENDPOINT       *pEndpoint,
+                             HTC_PACKET_QUEUE   *pQueueToIndicate)
+{           
+    do {
+                
+        if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
+                /* nothing to indicate */
+            break;    
+        }
+ 
+        if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) {    
+            AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d, send complete multiple callback (%d pkts) \n",
+                     pEndpoint->Id, HTC_PACKET_QUEUE_DEPTH(pQueueToIndicate)));
+                /* a multiple send complete handler is being used, pass the queue to the handler */                             
+            pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint->EpCallBacks.pContext,
+                                                        pQueueToIndicate);
+                /* all packets are now owned by the callback, reset queue to be safe */
+            INIT_HTC_PACKET_QUEUE(pQueueToIndicate);                                                      
+        } else {
+            HTC_PACKET *pPacket;  
+            /* using legacy EpTxComplete */         
+            do {
+                pPacket = HTC_PACKET_DEQUEUE(pQueueToIndicate);
+                AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" HTC calling ep %d send complete callback on packet 0x%lX \n", \
+                        pEndpoint->Id, (unsigned long)(pPacket)));
+                pEndpoint->EpCallBacks.EpTxComplete(pEndpoint->EpCallBacks.pContext, pPacket);                                              
+            } while (!HTC_QUEUE_EMPTY(pQueueToIndicate));                                              
+        }
+        
+    } while (FALSE);
+
+}
+
+/* do final completion on sent packet */
+static INLINE void CompleteSentPacket(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_PACKET *pPacket)
+{
+    pPacket->Completion = NULL;  
+    
+    if (A_FAILED(pPacket->Status)) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
+            ("CompleteSentPacket: request failed (status:%d, ep:%d, length:%d creds:%d) \n",
+                pPacket->Status, pPacket->Endpoint, pPacket->ActualLength, pPacket->PktInfo.AsTx.CreditsUsed));                
+            /* on failure to submit, reclaim credits for this packet */        
+        LOCK_HTC_TX(target);        
+        pEndpoint->CreditDist.TxCreditsToDist += pPacket->PktInfo.AsTx.CreditsUsed;
+        pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
+        DO_DISTRIBUTION(target,
+                        HTC_CREDIT_DIST_SEND_COMPLETE,
+                        "Send Complete",
+                        target->EpCreditDistributionListHead->pNext);
+        UNLOCK_HTC_TX(target);            
+    }
+        /* first, fixup the head room we allocated */
+    pPacket->pBuffer += HTC_HDR_LENGTH; 
+}
+
+/* our internal send packet completion handler when packets are submited to the AR6K device
+ * layer */
+static void HTCSendPktCompletionHandler(void *Context, HTC_PACKET *pPacket)
+{
+    HTC_TARGET      *target = (HTC_TARGET *)Context;
+    HTC_ENDPOINT    *pEndpoint = &target->EndPoint[pPacket->Endpoint];
+    HTC_PACKET_QUEUE container;
+    
+    CompleteSentPacket(target,pEndpoint,pPacket);
+    INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
+        /* do completion */
+    DO_EP_TX_COMPLETION(pEndpoint,&container);
+}
+
+A_STATUS HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket)
+{
+    A_STATUS status;
+    A_BOOL   sync = FALSE;
+
+    if (pPacket->Completion == NULL) {
+            /* mark that this request was synchronously issued */
+        sync = TRUE;
+    }
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
+                    ("+-HTCIssueSend: transmit length : %d (%s) \n",
+                    pPacket->ActualLength + (A_UINT32)HTC_HDR_LENGTH,
+                    sync ? "SYNC" : "ASYNC" ));
+
+        /* send message to device */
+    status = DevSendPacket(&target->Device,
+                           pPacket,
+                           pPacket->ActualLength + HTC_HDR_LENGTH);
+
+    if (sync) {
+            /* use local sync variable.  If this was issued asynchronously, pPacket is no longer
+             * safe to access. */
+        pPacket->pBuffer += HTC_HDR_LENGTH;
+    }
+    
+    /* if this request was asynchronous, the packet completion routine will be invoked by
+     * the device layer when the HIF layer completes the request */
+
+    return status;
+}
+
+    /* get HTC send packets from the TX queue on an endpoint */
+static INLINE void GetHTCSendPackets(HTC_TARGET        *target, 
+                                     HTC_ENDPOINT      *pEndpoint, 
+                                     HTC_PACKET_QUEUE  *pQueue)
+{
+    int          creditsRequired;
+    int          remainder;
+    A_UINT8      sendFlags;
+    HTC_PACKET   *pPacket;
+    unsigned int transferLength;
+
+    /****** NOTE : the TX lock is held when this function is called *****************/
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+GetHTCSendPackets \n"));
+     
+        /* loop until we can grab as many packets out of the queue as we can */       
+    while (TRUE) {    
+        
+        sendFlags = 0;   
+            /* get packet at head, but don't remove it */
+        pPacket = HTC_GET_PKT_AT_HEAD(&pEndpoint->TxQueue);       
+        if (pPacket == NULL) {
+            break;    
+        }
+        
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Got head packet:0x%lX , Queue Depth: %d\n",
+                (unsigned long)pPacket, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
+        
+        transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device, pPacket->ActualLength + HTC_HDR_LENGTH);       
+       
+        if (transferLength <= target->TargetCreditSize) {
+            creditsRequired = 1;    
+        } else {
+                /* figure out how many credits this message requires */
+            creditsRequired = transferLength / target->TargetCreditSize;
+            remainder = transferLength % target->TargetCreditSize;
+            
+            if (remainder) {
+                creditsRequired++;
+            }
+        }
+
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Creds Required:%d   Got:%d\n",
+                            creditsRequired, pEndpoint->CreditDist.TxCredits));
+
+        if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
+
+                /* not enough credits */
+            if (pPacket->Endpoint == ENDPOINT_0) {
+                    /* leave it in the queue */
+                break;
+            }
+                /* invoke the registered distribution function only if this is not
+                 * endpoint 0, we let the driver layer provide more credits if it can.
+                 * We pass the credit distribution list starting at the endpoint in question
+                 * */
+
+                /* set how many credits we need  */
+            pEndpoint->CreditDist.TxCreditsSeek =
+                                    creditsRequired - pEndpoint->CreditDist.TxCredits;
+            DO_DISTRIBUTION(target,
+                            HTC_CREDIT_DIST_SEEK_CREDITS,
+                            "Seek Credits",
+                            &pEndpoint->CreditDist);
+            pEndpoint->CreditDist.TxCreditsSeek = 0;
+
+            if (pEndpoint->CreditDist.TxCredits < creditsRequired) {
+                    /* still not enough credits to send, leave packet in the queue */
+                AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
+                    (" Not enough credits for ep %d leaving packet in queue..\n",
+                    pPacket->Endpoint));
+                break;
+            }
+
+        }
+
+        pEndpoint->CreditDist.TxCredits -= creditsRequired;
+        INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, creditsRequired);
+
+            /* check if we need credits back from the target */
+        if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
+                /* we are getting low on credits, see if we can ask for more from the distribution function */
+            pEndpoint->CreditDist.TxCreditsSeek =
+                        pEndpoint->CreditDist.TxCreditsPerMaxMsg - pEndpoint->CreditDist.TxCredits;
+
+            DO_DISTRIBUTION(target,
+                            HTC_CREDIT_DIST_SEEK_CREDITS,
+                            "Seek Credits",
+                            &pEndpoint->CreditDist);
+
+            pEndpoint->CreditDist.TxCreditsSeek = 0;
+                /* see if we were successful in getting more */
+            if (pEndpoint->CreditDist.TxCredits < pEndpoint->CreditDist.TxCreditsPerMaxMsg) {
+                    /* tell the target we need credits ASAP! */
+                sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE;
+                INC_HTC_EP_STAT(pEndpoint, TxCreditLowIndications, 1);
+                AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Host Needs Credits  \n"));
+            }
+        }
+                        
+            /* now we can fully dequeue */
+        pPacket = HTC_PACKET_DEQUEUE(&pEndpoint->TxQueue); 
+            /* save the number of credits this packet consumed */
+        pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired;
+            /* all TX packets are handled asynchronously */
+        pPacket->Completion = HTCSendPktCompletionHandler;
+        pPacket->pContext = target;
+        INC_HTC_EP_STAT(pEndpoint, TxIssued, 1);
+            /* save send flags */
+        pPacket->PktInfo.AsTx.SendFlags = sendFlags;
+        pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo;         
+        pEndpoint->SeqNo++;
+            /* queue this packet into the caller's queue */
+        HTC_PACKET_ENQUEUE(pQueue,pPacket);
+    }
+    
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-GetHTCSendPackets \n"));
+     
+}
+
+static void HTCAsyncSendScatterCompletion(HIF_SCATTER_REQ *pScatterReq)
+{
+    int                 i;    
+    HTC_PACKET          *pPacket;
+    HTC_ENDPOINT        *pEndpoint = (HTC_ENDPOINT *)pScatterReq->Context;
+    HTC_TARGET          *target = (HTC_TARGET *)pEndpoint->target;
+    A_STATUS            status = A_OK;
+    HTC_PACKET_QUEUE    sendCompletes;
+    
+    INIT_HTC_PACKET_QUEUE(&sendCompletes);
+          
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCAsyncSendScatterCompletion  TotLen: %d  Entries: %d\n",
+        pScatterReq->TotalLength, pScatterReq->ValidScatterEntries));
+    
+    DEV_FINISH_SCATTER_OPERATION(pScatterReq);
+           
+    if (A_FAILED(pScatterReq->CompletionStatus)) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("** Send Scatter Request Failed: %d \n",pScatterReq->CompletionStatus));            
+        status = A_ERROR;
+    }
+    
+        /* walk through the scatter list and process */
+    for (i = 0; i < pScatterReq->ValidScatterEntries; i++) {
+        pPacket = (HTC_PACKET *)(pScatterReq->ScatterList[i].pCallerContexts[0]);
+        A_ASSERT(pPacket != NULL);
+        pPacket->Status = status;
+        CompleteSentPacket(target,pEndpoint,pPacket);
+            /* add it to the completion queue */
+        HTC_PACKET_ENQUEUE(&sendCompletes, pPacket);      
+    }
+    
+        /* free scatter request */
+    DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);
+        /* complete all packets */
+    DO_EP_TX_COMPLETION(pEndpoint,&sendCompletes);
+               
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCAsyncSendScatterCompletion \n"));
+}
+
+    /* drain a queue and send as bundles 
+     * this function may return without fully draining the queue under the following conditions :
+     *    - scatter resources are exhausted
+     *    - a message that will consume a partial credit will stop the bundling process early 
+     *    - we drop below the minimum number of messages for a bundle 
+     * */
+static void HTCIssueSendBundle(HTC_ENDPOINT      *pEndpoint, 
+                               HTC_PACKET_QUEUE  *pQueue, 
+                               int               *pBundlesSent, 
+                               int               *pTotalBundlesPkts)
+{
+    int                 pktsToScatter;
+    unsigned int        scatterSpaceRemaining;
+    HIF_SCATTER_REQ     *pScatterReq = NULL;
+    int                 i, packetsInScatterReq;
+    unsigned int        transferLength;
+    HTC_PACKET          *pPacket;
+    A_BOOL              done = FALSE;
+    int                 bundlesSent = 0;
+    int                 totalPktsInBundle = 0;
+    HTC_TARGET          *target = pEndpoint->target;
+    int                 creditRemainder = 0;
+    int                 creditPad;
+    
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCIssueSendBundle \n"));
+    
+    while (!done) {
+          
+        pktsToScatter = HTC_PACKET_QUEUE_DEPTH(pQueue);
+        pktsToScatter = min(pktsToScatter, target->MaxMsgPerBundle);
+        
+        if (pktsToScatter < HTC_MIN_HTC_MSGS_TO_BUNDLE) {
+                /* not enough to bundle */
+            break;    
+        }
+        
+        pScatterReq = DEV_ALLOC_SCATTER_REQ(&target->Device); 
+        
+        if (pScatterReq == NULL) {
+                /* no scatter resources  */
+            AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("   No more scatter resources \n"));
+            break;    
+        }       
+        
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("   pkts to scatter: %d \n", pktsToScatter));
+        
+        pScatterReq->TotalLength = 0;
+        pScatterReq->ValidScatterEntries = 0;  
+        
+        packetsInScatterReq = 0;
+        scatterSpaceRemaining = DEV_GET_MAX_BUNDLE_SEND_LENGTH(&target->Device);
+        
+        for (i = 0; i < pktsToScatter; i++) {
+            
+            pScatterReq->ScatterList[i].pCallerContexts[0] = NULL;
+            
+            pPacket = HTC_GET_PKT_AT_HEAD(pQueue);        
+            if (pPacket == NULL) {
+                A_ASSERT(FALSE);
+                break;    
+            }
+            
+            creditPad = 0;
+            transferLength = DEV_CALC_SEND_PADDED_LEN(&target->Device, 
+                                                      pPacket->ActualLength + HTC_HDR_LENGTH);               
+                /* see if the padded transfer length falls on a credit boundary */         
+            creditRemainder = transferLength % target->TargetCreditSize;
+                                
+            if (creditRemainder != 0) {
+                    /* the transfer consumes a "partial" credit, this packet cannot be bundled unless
+                     * we add additional "dummy" padding (max 255 bytes) to consume the entire credit 
+                     *** NOTE: only allow the send padding if the endpoint is allowed to */
+                if (pEndpoint->LocalConnectionFlags & HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING) {
+                    if (transferLength < target->TargetCreditSize) {
+                            /* special case where the transfer is less than a credit */
+                        creditPad = target->TargetCreditSize - transferLength;                    
+                    } else {
+                        creditPad = creditRemainder;    
+                    }
+                                    
+                        /* now check to see if we can indicate padding in the HTC header */
+                    if ((creditPad > 0) && (creditPad <= 255)) {
+                            /* adjust the transferlength of this packet with the new credit padding */
+                        transferLength += creditPad;            
+                    } else {
+                            /* the amount to pad is too large, bail on this packet, we have to 
+                             * send it using the non-bundled method */
+                        pPacket = NULL;
+                    }
+                } else {
+                        /* bail on this packet, user does not want padding applied */
+                    pPacket = NULL;    
+                }
+            }                       
+                       
+            if (NULL == pPacket) {
+                    /* can't bundle */
+                done = TRUE;
+                break;    
+            }         
+               
+            if (scatterSpaceRemaining < transferLength) {
+                    /* exceeds what we can transfer */
+                break;    
+            }
+            
+            scatterSpaceRemaining -= transferLength;
+                /* now remove it from the queue */ 
+            pPacket = HTC_PACKET_DEQUEUE(pQueue);           
+                /* save it in the scatter list */
+            pScatterReq->ScatterList[i].pCallerContexts[0] = pPacket;            
+                /* prepare packet and flag message as part of a send bundle */               
+            HTC_PREPARE_SEND_PKT(pPacket,
+                                 pPacket->PktInfo.AsTx.SendFlags | HTC_FLAGS_SEND_BUNDLE, 
+                                 creditPad,                                 
+                                 pPacket->PktInfo.AsTx.SeqNo); 
+            pScatterReq->ScatterList[i].pBuffer = pPacket->pBuffer;
+            pScatterReq->ScatterList[i].Length = transferLength;
+            A_ASSERT(transferLength);
+            pScatterReq->TotalLength += transferLength;
+            pScatterReq->ValidScatterEntries++;
+            packetsInScatterReq++;             
+            AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("  %d, Adding packet : 0x%lX, len:%d (remaining space:%d) \n", 
+                    i, (unsigned long)pPacket,transferLength,scatterSpaceRemaining));                                                      
+        }
+                    
+        if (packetsInScatterReq >= HTC_MIN_HTC_MSGS_TO_BUNDLE) {          
+                /* send path is always asynchronous */
+            pScatterReq->CompletionRoutine = HTCAsyncSendScatterCompletion;
+            pScatterReq->Context = pEndpoint;
+            bundlesSent++;
+            totalPktsInBundle += packetsInScatterReq;
+            packetsInScatterReq = 0;
+            AR_DEBUG_PRINTF(ATH_DEBUG_SEND,(" Send Scatter total bytes: %d , entries: %d\n",
+                                pScatterReq->TotalLength,pScatterReq->ValidScatterEntries));
+            DevSubmitScatterRequest(&target->Device, pScatterReq, DEV_SCATTER_WRITE, DEV_SCATTER_ASYNC);
+                /* we don't own this anymore */
+            pScatterReq = NULL;
+                /* try to send some more */
+            continue;               
+        } 
+        
+            /* not enough packets to use the scatter request, cleanup */
+        if (pScatterReq != NULL) {
+            if (packetsInScatterReq > 0) {
+                    /* work backwards to requeue requests */
+                for (i = (packetsInScatterReq - 1); i >= 0; i--) {
+                    pPacket = (HTC_PACKET *)(pScatterReq->ScatterList[i].pCallerContexts[0]);
+                    if (pPacket != NULL) {
+                            /* undo any prep */
+                        HTC_UNPREPARE_SEND_PKT(pPacket);
+                            /* queue back to the head */
+                        HTC_PACKET_ENQUEUE_TO_HEAD(pQueue,pPacket);   
+                    }  
+                }  
+            }               
+            DEV_FREE_SCATTER_REQ(&target->Device,pScatterReq);    
+        }  
+        
+        /* if we get here, we sent all that we could, get out */
+        break;  
+        
+    }
+    
+    *pBundlesSent = bundlesSent;
+    *pTotalBundlesPkts = totalPktsInBundle;
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCIssueSendBundle (sent:%d) \n",bundlesSent));  
+     
+    return; 
+}
+
+/*
+ * if there are no credits, the packet(s) remains in the queue.
+ * this function returns the result of the attempt to send a queue of HTC packets */
+static HTC_SEND_QUEUE_RESULT HTCTrySend(HTC_TARGET       *target,
+                                        HTC_ENDPOINT     *pEndpoint,
+                                        HTC_PACKET_QUEUE *pCallersSendQueue)
+{
+    HTC_PACKET_QUEUE      sendQueue; /* temp queue to hold packets at various stages */
+    HTC_PACKET            *pPacket;
+    int                   bundlesSent;
+    int                   pktsInBundles;
+    int                   overflow;
+    HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK;
+    
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("+HTCTrySend (Queue:0x%lX Depth:%d)\n",
+            (unsigned long)pCallersSendQueue, 
+            (pCallersSendQueue == NULL) ? 0 : HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue)));
+
+        /* init the local send queue */
+    INIT_HTC_PACKET_QUEUE(&sendQueue);
+    
+    do {
+        
+        if (NULL == pCallersSendQueue) {
+                /* caller didn't provide a queue, just wants us to check queues and send */
+            break;    
+        }
+        
+        if (HTC_QUEUE_EMPTY(pCallersSendQueue)) {
+                /* empty queue */
+            result = HTC_SEND_QUEUE_DROP;
+            break;    
+        }
+  
+        if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= pEndpoint->MaxTxQueueDepth) {
+                    /* we've already overflowed */
+            overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue);    
+        } else {
+                /* figure out how much we will overflow by */
+            overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
+            overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); 
+                /* figure out how much we will overflow the TX queue by */
+            overflow -= pEndpoint->MaxTxQueueDepth;     
+        }
+                     
+            /* if overflow is negative or zero, we are okay */    
+        if (overflow > 0) {
+            AR_DEBUG_PRINTF(ATH_DEBUG_SEND, 
+                (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d \n",
+                pEndpoint->Id, overflow, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue), pEndpoint->MaxTxQueueDepth));      
+        }   
+        if ((overflow <= 0) || (pEndpoint->EpCallBacks.EpSendFull == NULL)) {
+                /* all packets will fit or caller did not provide send full indication handler
+                 * --  just move all of them to the local sendQueue object */
+            HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, pCallersSendQueue);           
+        } else {
+            int               i;
+            int               goodPkts = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - overflow;
+                        
+            A_ASSERT(goodPkts >= 0);
+                /* we have overflowed, and a callback is provided */        
+                /* dequeue all non-overflow packets into the sendqueue */
+            for (i = 0; i < goodPkts; i++) {
+                    /* pop off caller's queue*/
+                pPacket = HTC_PACKET_DEQUEUE(pCallersSendQueue);
+                A_ASSERT(pPacket != NULL);
+                    /* insert into local queue */
+                HTC_PACKET_ENQUEUE(&sendQueue,pPacket);
+            }
+            
+                /* the caller's queue has all the packets that won't fit*/                
+                /* walk through the caller's queue and indicate each one to the send full handler */            
+            ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue->QueueHead, pPacket, HTC_PACKET, ListLink) {            
+                
+                AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Indicating overflowed TX packet: 0x%lX \n", 
+                                            (unsigned long)pPacket));    
+                if (pEndpoint->EpCallBacks.EpSendFull(pEndpoint->EpCallBacks.pContext,
+                                                      pPacket) == HTC_SEND_FULL_DROP) {
+                        /* callback wants the packet dropped */
+                    INC_HTC_EP_STAT(pEndpoint, TxDropped, 1);
+                        /* leave this one in the caller's queue for cleanup */
+                } else {
+                        /* callback wants to keep this packet, remove from caller's queue */
+                    HTC_PACKET_REMOVE(pCallersSendQueue, pPacket);
+                        /* put it in the send queue */
+                    HTC_PACKET_ENQUEUE(&sendQueue,pPacket);                                      
+                }
+                
+            } ITERATE_END;
+            
+            if (HTC_QUEUE_EMPTY(&sendQueue)) {
+                    /* no packets made it in, caller will cleanup */
+                result = HTC_SEND_QUEUE_DROP;
+                break;   
+            } 
+        }
+        
+    } while (FALSE);
+    
+    if (result != HTC_SEND_QUEUE_OK) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend:  \n"));
+        return result;
+    }
+
+    LOCK_HTC_TX(target);
+    
+    if (!HTC_QUEUE_EMPTY(&sendQueue)) {
+            /* transfer packets */
+        HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue,&sendQueue);
+        A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue));
+        INIT_HTC_PACKET_QUEUE(&sendQueue); 
+    }
+    
+        /* increment tx processing count on entry */    
+    pEndpoint->TxProcessCount++;
+    if (pEndpoint->TxProcessCount > 1) {
+            /* another thread or task is draining the TX queues on this endpoint
+             * that thread will reset the tx processing count when the queue is drained */
+        pEndpoint->TxProcessCount--;
+        UNLOCK_HTC_TX(target);
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend (busy) \n"));
+        return HTC_SEND_QUEUE_OK; 
+    }
+    
+    /***** beyond this point only 1 thread may enter ******/
+            
+        /* now drain the endpoint TX queue for transmission as long as we have enough
+         * credits */
+    while (TRUE) {
+          
+        if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) {
+            break;
+        }
+                
+            /* get all the packets for this endpoint that we can for this pass */
+        GetHTCSendPackets(target, pEndpoint, &sendQueue);        
+     
+        if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) {
+                /* didn't get any packets due to a lack of credits */
+            break;    
+        }
+        
+        UNLOCK_HTC_TX(target);
+        
+            /* any packets to send are now in our local send queue */    
+         
+        bundlesSent = 0;
+        pktsInBundles = 0;
+     
+        while (TRUE) {
+            
+                /* try to send a bundle on each pass */            
+            if ((target->SendBundlingEnabled) &&
+                    (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= HTC_MIN_HTC_MSGS_TO_BUNDLE)) {
+                 int temp1,temp2;       
+                    /* bundling is enabled and there is at least a minimum number of packets in the send queue
+                     * send what we can in this pass */                       
+                 HTCIssueSendBundle(pEndpoint, &sendQueue, &temp1, &temp2);
+                 bundlesSent += temp1;
+                 pktsInBundles += temp2;
+            }
+        
+                /* if not bundling or there was a packet that could not be placed in a bundle, pull it out
+                 * and send it the normal way */
+            pPacket = HTC_PACKET_DEQUEUE(&sendQueue);
+            if (NULL == pPacket) {
+                    /* local queue is fully drained */
+                break;    
+            }
+            HTC_PREPARE_SEND_PKT(pPacket,
+                                 pPacket->PktInfo.AsTx.SendFlags,
+                                 0,
+                                 pPacket->PktInfo.AsTx.SeqNo);  
+            HTCIssueSend(target, pPacket);
+            
+                /* go back and see if we can bundle some more */
+        }
+        
+        LOCK_HTC_TX(target);
+        
+        INC_HTC_EP_STAT(pEndpoint, TxBundles, bundlesSent);
+        INC_HTC_EP_STAT(pEndpoint, TxPacketsBundled, pktsInBundles);
+        
+    }
+        
+        /* done with this endpoint, we can clear the count */
+    pEndpoint->TxProcessCount = 0;
+    UNLOCK_HTC_TX(target);
+    
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,("-HTCTrySend:  \n"));
+
+    return HTC_SEND_QUEUE_OK;
+}
+
+A_STATUS  HTCSendPktsMultiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue)
+{
+    HTC_TARGET      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
+    HTC_ENDPOINT    *pEndpoint;
+    HTC_PACKET      *pPacket;
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCSendPktsMultiple: Queue: 0x%lX, Pkts %d \n",
+                    (unsigned long)pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue)));
+    
+        /* get packet at head to figure out which endpoint these packets will go into */
+    pPacket = HTC_GET_PKT_AT_HEAD(pPktQueue);
+    if (NULL == pPacket) {
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n"));
+        return A_EINVAL;   
+    }
+    
+    AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX);
+    pEndpoint = &target->EndPoint[pPacket->Endpoint];
+    
+    HTCTrySend(target, pEndpoint, pPktQueue);
+
+        /* do completion on any packets that couldn't get in */
+    if (!HTC_QUEUE_EMPTY(pPktQueue)) {        
+        
+        HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue,pPacket) {
+            if (HTC_STOPPING(target)) {
+                pPacket->Status = A_ECANCELED;
+            } else {
+                pPacket->Status = A_NO_RESOURCE;
+            } 
+        } HTC_PACKET_QUEUE_ITERATE_END;
+                   
+        DO_EP_TX_COMPLETION(pEndpoint,pPktQueue);
+    }
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCSendPktsMultiple \n"));
+
+    return A_OK;   
+}
+
+/* HTC API - HTCSendPkt */
+A_STATUS HTCSendPkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
+{
+    HTC_PACKET_QUEUE queue;
+    
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND,
+                    ("+-HTCSendPkt: Enter endPointId: %d, buffer: 0x%lX, length: %d \n",
+                    pPacket->Endpoint, (unsigned long)pPacket->pBuffer, pPacket->ActualLength));                   
+    INIT_HTC_PACKET_QUEUE_AND_ADD(&queue,pPacket); 
+    return HTCSendPktsMultiple(HTCHandle, &queue);
+}
+
+/* check TX queues to drain because of credit distribution update */
+static INLINE void HTCCheckEndpointTxQueues(HTC_TARGET *target)
+{
+    HTC_ENDPOINT                *pEndpoint;
+    HTC_ENDPOINT_CREDIT_DIST    *pDistItem;
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCCheckEndpointTxQueues \n"));
+    pDistItem = target->EpCreditDistributionListHead;
+
+        /* run through the credit distribution list to see
+         * if there are packets queued
+         * NOTE: no locks need to be taken since the distribution list
+         * is not dynamic (cannot be re-ordered) and we are not modifying any state */
+    while (pDistItem != NULL) {
+        pEndpoint = (HTC_ENDPOINT *)pDistItem->pHTCReserved;
+
+        if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) > 0) {
+            AR_DEBUG_PRINTF(ATH_DEBUG_SEND, (" Ep %d has %d credits and %d Packets in TX Queue \n",
+                    pDistItem->Endpoint, pEndpoint->CreditDist.TxCredits, HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)));
+                /* try to start the stalled queue, this list is ordered by priority.
+                 * Highest priority queue get's processed first, if there are credits available the
+                 * highest priority queue will get a chance to reclaim credits from lower priority
+                 * ones */
+            HTCTrySend(target, pEndpoint, NULL);
+        }
+
+        pDistItem = pDistItem->pNext;
+    }
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCCheckEndpointTxQueues \n"));
+}
+
+/* process credit reports and call distribution function */
+void HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint)
+{
+    int             i;
+    HTC_ENDPOINT    *pEndpoint;
+    int             totalCredits = 0;
+    A_BOOL          doDist = FALSE;
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+HTCProcessCreditRpt, Credit Report Entries:%d \n", NumEntries));
+
+        /* lock out TX while we update credits */
+    LOCK_HTC_TX(target);
+
+    for (i = 0; i < NumEntries; i++, pRpt++) {
+        if (pRpt->EndpointID >= ENDPOINT_MAX) {
+            AR_DEBUG_ASSERT(FALSE);
+            break;
+        }
+
+        pEndpoint = &target->EndPoint[pRpt->EndpointID];
+
+        AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("  Endpoint %d got %d credits \n",
+                pRpt->EndpointID, pRpt->Credits));
+
+
+#ifdef HTC_EP_STAT_PROFILING
+
+        INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1);
+        INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, pRpt->Credits);
+
+        if (FromEndpoint == pRpt->EndpointID) {
+                /* this credit report arrived on the same endpoint indicating it arrived in an RX
+                 * packet */
+            INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, pRpt->Credits);
+            INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1);
+        } else if (FromEndpoint == ENDPOINT_0) {
+                /* this credit arrived on endpoint 0 as a NULL message */
+            INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, pRpt->Credits);
+            INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1);
+        } else {
+                /* arrived on another endpoint */
+            INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, pRpt->Credits);
+            INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1);
+        }
+
+#endif
+
+        if (ENDPOINT_0 == pRpt->EndpointID) {
+                /* always give endpoint 0 credits back */
+            pEndpoint->CreditDist.TxCredits += pRpt->Credits;
+        } else {
+                /* for all other endpoints, update credits to distribute, the distribution function
+                 * will handle giving out credits back to the endpoints */
+            pEndpoint->CreditDist.TxCreditsToDist += pRpt->Credits;
+                /* flag that we have to do the distribution */
+            doDist = TRUE;
+        }
+        
+            /* refresh tx depth for distribution function that will recover these credits
+             * NOTE: this is only valid when there are credits to recover! */
+        pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
+        
+        totalCredits += pRpt->Credits;
+    }
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("  Report indicated %d credits to distribute \n", totalCredits));
+
+    if (doDist) {
+            /* this was a credit return based on a completed send operations
+             * note, this is done with the lock held */
+        DO_DISTRIBUTION(target,
+                        HTC_CREDIT_DIST_SEND_COMPLETE,
+                        "Send Complete",
+                        target->EpCreditDistributionListHead->pNext);
+    }
+
+    UNLOCK_HTC_TX(target);
+
+    if (totalCredits) {
+        HTCCheckEndpointTxQueues(target);
+    }
+
+    AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-HTCProcessCreditRpt \n"));
+}
+
+/* flush endpoint TX queue */
+static void HTCFlushEndpointTX(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, HTC_TX_TAG Tag)
+{
+    HTC_PACKET          *pPacket;
+    HTC_PACKET_QUEUE    discardQueue;
+    HTC_PACKET_QUEUE    container;
+
+        /* initialize the discard queue */
+    INIT_HTC_PACKET_QUEUE(&discardQueue);
+
+    LOCK_HTC_TX(target);
+
+        /* interate from the front of the TX queue and flush out packets */
+    ITERATE_OVER_LIST_ALLOW_REMOVE(&pEndpoint->TxQueue.QueueHead, pPacket, HTC_PACKET, ListLink) {
+
+            /* check for removal */
+        if ((HTC_TX_PACKET_TAG_ALL == Tag) || (Tag == pPacket->PktInfo.AsTx.Tag)) {
+                /* remove from queue */
+            HTC_PACKET_REMOVE(&pEndpoint->TxQueue, pPacket);
+                /* add it to the discard pile */
+            HTC_PACKET_ENQUEUE(&discardQueue, pPacket);
+        }
+
+    } ITERATE_END;
+
+    UNLOCK_HTC_TX(target);
+
+        /* empty the discard queue */
+    while (1) {
+        pPacket = HTC_PACKET_DEQUEUE(&discardQueue);
+        if (NULL == pPacket) {
+            break;
+        }
+        pPacket->Status = A_ECANCELED;
+        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("  Flushing TX packet:0x%lX, length:%d, ep:%d tag:0x%X \n",
+                (unsigned long)pPacket, pPacket->ActualLength, pPacket->Endpoint, pPacket->PktInfo.AsTx.Tag));
+        INIT_HTC_PACKET_QUEUE_AND_ADD(&container,pPacket);
+        DO_EP_TX_COMPLETION(pEndpoint,&container);
+    }
+
+}
+
+void DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist)
+{
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("--- EP : %d  ServiceID: 0x%X    --------------\n",
+                        pEPDist->Endpoint, pEPDist->ServiceID));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" this:0x%lX next:0x%lX prev:0x%lX\n",
+                (unsigned long)pEPDist, (unsigned long)pEPDist->pNext, (unsigned long)pEPDist->pPrev));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" DistFlags          : 0x%X \n", pEPDist->DistFlags));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsNorm      : %d \n", pEPDist->TxCreditsNorm));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsMin       : %d \n", pEPDist->TxCreditsMin));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCredits          : %d \n", pEPDist->TxCredits));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsAssigned  : %d \n", pEPDist->TxCreditsAssigned));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsSeek      : %d \n", pEPDist->TxCreditsSeek));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditSize       : %d \n", pEPDist->TxCreditSize));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsPerMaxMsg : %d \n", pEPDist->TxCreditsPerMaxMsg));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxCreditsToDist    : %d \n", pEPDist->TxCreditsToDist));
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, (" TxQueueDepth       : %d \n", 
+                    HTC_PACKET_QUEUE_DEPTH(&((HTC_ENDPOINT *)pEPDist->pHTCReserved)->TxQueue)));                                      
+    AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("----------------------------------------------------\n"));
+}
+
+void DumpCreditDistStates(HTC_TARGET *target)
+{
+    HTC_ENDPOINT_CREDIT_DIST *pEPList = target->EpCreditDistributionListHead;
+
+    while (pEPList != NULL) {
+        DumpCreditDist(pEPList);
+        pEPList = pEPList->pNext;
+    }
+
+    if (target->DistributeCredits != NULL) {
+        DO_DISTRIBUTION(target,
+                        HTC_DUMP_CREDIT_STATE,
+                        "Dump State",
+                        NULL);
+    }
+}
+
+/* flush all send packets from all endpoint queues */
+void HTCFlushSendPkts(HTC_TARGET *target)
+{
+    HTC_ENDPOINT    *pEndpoint;
+    int             i;
+
+    if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_TRC)) {
+        DumpCreditDistStates(target);
+    }
+
+    for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) {
+        pEndpoint = &target->EndPoint[i];
+        if (pEndpoint->ServiceID == 0) {
+                /* not in use.. */
+            continue;
+        }
+        HTCFlushEndpointTX(target,pEndpoint,HTC_TX_PACKET_TAG_ALL);
+    }
+
+
+}
+
+/* HTC API to flush an endpoint's TX queue*/
+void HTCFlushEndpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, HTC_TX_TAG Tag)
+{
+    HTC_TARGET      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
+    HTC_ENDPOINT    *pEndpoint = &target->EndPoint[Endpoint];
+
+    if (pEndpoint->ServiceID == 0) {
+        AR_DEBUG_ASSERT(FALSE);
+        /* not in use.. */
+        return;
+    }
+
+    HTCFlushEndpointTX(target, pEndpoint, Tag);
+}
+
+/* HTC API to indicate activity to the credit distribution function */
+void HTCIndicateActivityChange(HTC_HANDLE      HTCHandle,
+                               HTC_ENDPOINT_ID Endpoint,
+                               A_BOOL          Active)
+{
+    HTC_TARGET      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
+    HTC_ENDPOINT    *pEndpoint = &target->EndPoint[Endpoint];
+    A_BOOL          doDist = FALSE;
+
+    if (pEndpoint->ServiceID == 0) {
+        AR_DEBUG_ASSERT(FALSE);
+        /* not in use.. */
+        return;
+    }
+
+    LOCK_HTC_TX(target);
+
+    if (Active) {
+        if (!(pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE)) {
+                /* mark active now */
+            pEndpoint->CreditDist.DistFlags |= HTC_EP_ACTIVE;
+            doDist = TRUE;
+        }
+    } else {
+        if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
+                /* mark inactive now */
+            pEndpoint->CreditDist.DistFlags &= ~HTC_EP_ACTIVE;
+            doDist = TRUE;
+        }
+    }
+
+    if (doDist) {
+            /* indicate current Tx Queue depth to the credit distribution function */
+        pEndpoint->CreditDist.TxQueueDepth = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue);
+        /* do distribution again based on activity change
+         * note, this is done with the lock held */
+        DO_DISTRIBUTION(target,
+                        HTC_CREDIT_DIST_ACTIVITY_CHANGE,
+                        "Activity Change",
+                        target->EpCreditDistributionListHead->pNext);
+    }
+
+    UNLOCK_HTC_TX(target);
+
+    if (doDist && !Active) {
+        /* if a stream went inactive and this resulted in a credit distribution change,
+         * some credits may now be available for HTC packets that are stuck in
+         * HTC queues */
+        HTCCheckEndpointTxQueues(target);
+    }
+}
+
+A_BOOL HTCIsEndpointActive(HTC_HANDLE      HTCHandle,
+                           HTC_ENDPOINT_ID Endpoint)
+{
+    HTC_TARGET      *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
+    HTC_ENDPOINT    *pEndpoint = &target->EndPoint[Endpoint];
+
+    if (pEndpoint->ServiceID == 0) {
+        return FALSE;
+    }
+    
+    if (pEndpoint->CreditDist.DistFlags & HTC_EP_ACTIVE) {
+        return TRUE;
+    }
+    
+    return FALSE;
+}