/*
 *
 * Copyright (c) 2007 Atheros Communications Inc.
 * All rights reserved.
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation;
 *
 *  Software distributed under the License is distributed on an "AS
 *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 *  implied. See the License for the specific language governing
 *  rights and limitations under the License.
 *
 *
 *
 */

#ifndef _HTC_INTERNAL_H_
#define _HTC_INTERNAL_H_

/* for debugging, uncomment this to capture the last frame header, on frame header
 * processing errors, the last frame header is dump for comparison */
//#define HTC_CAPTURE_LAST_FRAME

//#define HTC_EP_STAT_PROFILING

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* Header files */
#include "a_config.h"
#include "athdefs.h"
#include "a_types.h"
#include "a_osapi.h"
#include "a_debug.h"
#include "htc.h"
#include "htc_api.h"
#include "bmi_msg.h"
#include "hif.h"
#include "ar6k.h"

/* HTC operational parameters */
#define HTC_TARGET_RESPONSE_TIMEOUT        2000 /* in ms */
#define HTC_TARGET_DEBUG_INTR_MASK         0x01
#define HTC_TARGET_CREDIT_INTR_MASK        0xF0

typedef struct _HTC_ENDPOINT {
    HTC_SERVICE_ID              ServiceID;      /* service ID this endpoint is bound to
                                                   non-zero value means this endpoint is in use */
    HTC_PACKET_QUEUE            TxQueue;        /* HTC frame buffer TX queue */
    HTC_PACKET_QUEUE            RxBuffers;      /* HTC frame buffer RX list */
    HTC_ENDPOINT_CREDIT_DIST    CreditDist;     /* credit distribution structure (exposed to driver layer) */
    HTC_EP_CALLBACKS            EpCallBacks;    /* callbacks associated with this endpoint */
    int                         MaxTxQueueDepth;   /* max depth of the TX queue before we need to
                                                      call driver's full handler */
    int                         CurrentTxQueueDepth; /* current TX queue depth */
    int                         MaxMsgLength;        /* max length of endpoint message */
#ifdef HTC_EP_STAT_PROFILING
    HTC_ENDPOINT_STATS          EndPointStats;  /* endpoint statistics */
#endif
} HTC_ENDPOINT;

#ifdef HTC_EP_STAT_PROFILING
#define INC_HTC_EP_STAT(p,stat,count) (p)->EndPointStats.stat += (count);
#else
#define INC_HTC_EP_STAT(p,stat,count)
#endif

#define HTC_SERVICE_TX_PACKET_TAG  HTC_TX_PACKET_TAG_INTERNAL

#define NUM_CONTROL_BUFFERS     8
#define NUM_CONTROL_TX_BUFFERS  2
#define NUM_CONTROL_RX_BUFFERS  (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS)

#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH)

typedef struct HTC_CONTROL_BUFFER {
    HTC_PACKET    HtcPacket;
    A_UINT8       Buffer[HTC_CONTROL_BUFFER_SIZE];
} HTC_CONTROL_BUFFER;

/* our HTC target state */
typedef struct _HTC_TARGET {
    HTC_ENDPOINT                EndPoint[ENDPOINT_MAX];
    HTC_CONTROL_BUFFER          HTCControlBuffers[NUM_CONTROL_BUFFERS];
    HTC_ENDPOINT_CREDIT_DIST   *EpCreditDistributionListHead;
    HTC_PACKET_QUEUE            ControlBufferTXFreeList;
    HTC_PACKET_QUEUE            ControlBufferRXFreeList;
    HTC_CREDIT_DIST_CALLBACK    DistributeCredits;
    HTC_CREDIT_INIT_CALLBACK    InitCredits;
    void                       *pCredDistContext;
    int                         TargetCredits;
    int                         TargetCreditSize;
    A_MUTEX_T                   HTCLock;
    A_MUTEX_T                   HTCRxLock;
    A_MUTEX_T                   HTCTxLock;
    AR6K_DEVICE                 Device;         /* AR6K - specific state */
    A_UINT32                    HTCStateFlags;
    HTC_ENDPOINT_ID             EpWaitingForBuffers;
    A_BOOL                      TargetFailure;
    void                       *pInstanceContext;
#define HTC_STATE_WAIT_BUFFERS  (1 << 0)
#define HTC_STATE_STOPPING      (1 << 1)
#ifdef HTC_CAPTURE_LAST_FRAME
    HTC_FRAME_HDR               LastFrameHdr;  /* useful for debugging */
    A_UINT8                     LastTrailer[256];
    A_UINT8                     LastTrailerLength;
#endif
} HTC_TARGET;

#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING)
#define LOCK_HTC(t)      A_MUTEX_LOCK(&(t)->HTCLock);
#define UNLOCK_HTC(t)    A_MUTEX_UNLOCK(&(t)->HTCLock);
#define LOCK_HTC_RX(t)   A_MUTEX_LOCK(&(t)->HTCRxLock);
#define UNLOCK_HTC_RX(t) A_MUTEX_UNLOCK(&(t)->HTCRxLock);
#define LOCK_HTC_TX(t)   A_MUTEX_LOCK(&(t)->HTCTxLock);
#define UNLOCK_HTC_TX(t) A_MUTEX_UNLOCK(&(t)->HTCTxLock);

#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd))
#define HTC_RECYCLE_RX_PKT(target,p)                \
{                                                   \
    HTC_PACKET_RESET_RX(pPacket);                   \
    HTCAddReceivePkt((HTC_HANDLE)(target),(p));     \
}

/* internal HTC functions */
void        HTCControlTxComplete(void *Context, HTC_PACKET *pPacket);
void        HTCControlRecv(void *Context, HTC_PACKET *pPacket);
A_STATUS    HTCWaitforControlMessage(HTC_TARGET *target, HTC_PACKET **ppControlPacket);
HTC_PACKET *HTCAllocControlBuffer(HTC_TARGET *target, HTC_PACKET_QUEUE *pList);
void        HTCFreeControlBuffer(HTC_TARGET *target, HTC_PACKET *pPacket, HTC_PACKET_QUEUE *pList);
A_STATUS    HTCIssueSend(HTC_TARGET *target, HTC_PACKET *pPacket, A_UINT8 Flags);
A_STATUS    HTCIssueRecv(HTC_TARGET *target, HTC_PACKET *pPacket);
void        HTCRecvCompleteHandler(void *Context, HTC_PACKET *pPacket);
A_STATUS    HTCRecvMessagePendingHandler(void *Context, A_UINT32 LookAhead, A_BOOL *pAsyncProc);
void        HTCProcessCreditRpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, int NumEntries, HTC_ENDPOINT_ID FromEndpoint);
A_STATUS    HTCSendSetupComplete(HTC_TARGET *target);
void        HTCFlushRecvBuffers(HTC_TARGET *target);
void        HTCFlushSendPkts(HTC_TARGET *target);
void        DumpCreditDist(HTC_ENDPOINT_CREDIT_DIST *pEPDist);
void        DumpCreditDistStates(HTC_TARGET *target);
void 		DebugDumpBytes(A_UCHAR *buffer, A_UINT16 length, char *pDescription);

static INLINE HTC_PACKET *HTC_ALLOC_CONTROL_TX(HTC_TARGET *target) {
    HTC_PACKET *pPacket = HTCAllocControlBuffer(target,&target->ControlBufferTXFreeList);
    if (pPacket != NULL) {
            /* set payload pointer area with some headroom */
        pPacket->pBuffer = pPacket->pBufferStart + HTC_HDR_LENGTH;
    }
    return pPacket;
}

#define HTC_FREE_CONTROL_TX(t,p) HTCFreeControlBuffer((t),(p),&(t)->ControlBufferTXFreeList)
#define HTC_ALLOC_CONTROL_RX(t)  HTCAllocControlBuffer((t),&(t)->ControlBufferRXFreeList)
#define HTC_FREE_CONTROL_RX(t,p) \
{                                                                \
    HTC_PACKET_RESET_RX(p);                                      \
    HTCFreeControlBuffer((t),(p),&(t)->ControlBufferRXFreeList); \
}

#ifdef __cplusplus
}
#endif

#endif /* _HTC_INTERNAL_H_ */