www.pudn.com > sdio-2.6.18-full.rar > htc_events.c


/*
 * Copyright (c) 2004-2006 Atheros Communications Inc.
 *
 *  Wireless Network driver for Atheros AR6001
 *
 *  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.
 *
 *
 * This file contains the routines handling the different events and callbacks
 * from the hardware interface layer.
 */

#include "htc_internal.h"

/* ------ Global Variable Declarations ------- */
extern A_MUTEX_T instanceCS, counterCS, creditCS;
extern A_WAITQUEUE_HEAD htcEvent;

#ifdef DEBUG
extern A_UINT32 debughtc;
extern A_UINT32 txcreditsavailable[HTC_MAILBOX_NUM_MAX];
extern A_UINT32 txcreditsconsumed[HTC_MAILBOX_NUM_MAX];
extern A_UINT32 txcreditintrenable[HTC_MAILBOX_NUM_MAX];
extern A_UINT32 txcreditintrenableaggregate[HTC_MAILBOX_NUM_MAX];
#endif

extern A_UINT32 tx_complete[HTC_MAILBOX_NUM_MAX]; /* Num of tx complete */

/* ------ Static Variables ------ */


/* ------ Functions ------ */
#ifdef CF
A_STATUS htcInterruptEnabler(HIF_DEVICE *device) {

    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    HTC_TARGET *target;

    target = getTargetInstance(device);
    AR_DEBUG_ASSERT(target != NULL);
    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
                    ("htcInterruptEnabler Enter target: 0x%p\n", target));

    target->table.int_status_enable = INT_STATUS_ENABLE_ERROR_SET(0x01) |
                                      INT_STATUS_ENABLE_CPU_SET(0x01) |
                                      INT_STATUS_ENABLE_COUNTER_SET(0x01) |
                                      INT_STATUS_ENABLE_MBOX_DATA_SET(0x0F);
    /* Reenable Dragon Interrupts */

    HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
    address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED);
    status = HIFReadWrite(target->device, address,
                          &target->table.int_status_enable, 1,
                          &request, NULL);

	AR_DEBUG_ASSERT(status == A_OK);
    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,("htcInterruptEnabler Exit\n"));

        return A_OK;
}
#endif /* CF */


A_STATUS
htcRWCompletionHandler(void *context,
                       A_STATUS status)
{
    HTC_QUEUE_ELEMENT *element;

    element = (HTC_QUEUE_ELEMENT *)context;
    AR_DEBUG_ASSERT(element != NULL);

    return(element->completionCB(element, status));
}

A_STATUS
htcTxCompletionCB(HTC_DATA_REQUEST_ELEMENT *element,
                  A_STATUS status)
{
    HTC_TARGET *target;
    HTC_ENDPOINT_ID endPointId;
    HTC_ENDPOINT *endPoint;
    HTC_EVENT_INFO eventInfo;
    HTC_MBOX_BUFFER *mboxBuffer;

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND,
                    ("htcTxCompletionCB - Enter\n"));

    /* Get the context */
    mboxBuffer = GET_MBOX_BUFFER(element);
    AR_DEBUG_ASSERT(mboxBuffer != NULL);
    endPoint = mboxBuffer->endPoint;
    AR_DEBUG_ASSERT(endPoint != NULL);
    target = endPoint->target;
    AR_DEBUG_ASSERT(target != NULL);
    endPointId = GET_ENDPOINT_ID(endPoint);

    AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND,
                    ("mboxBuffer: 0x%p, buffer: 0x%p, endPoint(%d): 0x%p, target: 0x%p\n", mboxBuffer, mboxBuffer->buffer, endPointId, endPoint, target));

    /* Return the buffer to the user if the transmission was not successful */
    if (status != A_OK) {
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_SEND,
                        ("Frame transmission failed\n"));
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_SEND,
                        ("EndPoint: %d, Tx credits available: %d\n",
                         endPointId, GET_TX_CREDITS_AVAILABLE(endPoint)));
        /*
         * In the failure case it is possible that while queueing of the
         * request itself it returned an error status in which case we
         * would have dispatched an event and freed the element there
         * itself. Ideally if it failed to queue the request then it
         * should not generate a callback but we are being a little
         * conservative.
         */
        if (!(IS_ELEMENT_FREE(element))) {
            mboxBuffer->buffer += HTC_HEADER_LEN;
            FRAME_EVENT(eventInfo, mboxBuffer->buffer,
                        mboxBuffer->bufferLength, mboxBuffer->actualLength,
                        A_ECANCELED, mboxBuffer->cookie);
            RECYCLE_DATA_REQUEST_ELEMENT(element);
            dispatchEvent(target, endPointId, HTC_BUFFER_SENT, &eventInfo);
            AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND,
                            ("htcTxCompletionCB - Exit\n"));
        }
        return A_OK;
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND,
                    ("Frame transmission complete\n"));

    /*
     * The user should see the actual length and buffer length
     * to be the same. In case of block mode, we use the actual length
     * parameter to reflect the total number of bytes transmitted after
     * padding.
     */
    mboxBuffer->actualLength = mboxBuffer->bufferLength;
    mboxBuffer->buffer += HTC_HEADER_LEN;

    /*
     * Return the transmit buffer to the user through the HTC_BUFFER_SENT
     * event indicating that the frame was transmitted successfully.
     */
    FRAME_EVENT(eventInfo, mboxBuffer->buffer, mboxBuffer->bufferLength,
                mboxBuffer->actualLength, A_OK, mboxBuffer->cookie);
    RECYCLE_DATA_REQUEST_ELEMENT(element);

    tx_complete[endPointId] += 1;

    dispatchEvent(target, endPointId, HTC_BUFFER_SENT, &eventInfo);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND,
                    ("htcTxCompletionCB - Exit\n"));

    return A_OK;
}

A_STATUS
htcBlkSzNegCompletionCB(HTC_DATA_REQUEST_ELEMENT *element,
                        A_STATUS status)
{
    HTC_TARGET *target;
    HTC_ENDPOINT *endPoint;
    HIF_REQUEST request;
    HTC_MBOX_BUFFER *mboxBuffer;
    HTC_REG_REQUEST_ELEMENT *regElement;
    A_UINT32 address;

    /* Get the context */
    mboxBuffer = GET_MBOX_BUFFER(element);
    AR_DEBUG_ASSERT(mboxBuffer != NULL);
    endPoint = mboxBuffer->endPoint;
    AR_DEBUG_ASSERT(endPoint != NULL);
    target = endPoint->target;
    AR_DEBUG_ASSERT(target != NULL);

    /* Recycle the request element */
    RECYCLE_DATA_REQUEST_ELEMENT(element);
    element->completionCB = htcTxCompletionCB;

    if (status == A_OK) {
        /* Mark the state to be ready */
        endPoint->enabled = TRUE;

        /* Set the state of the target as ready */
        if (target->endPoint[ENDPOINT1].enabled &&
            target->endPoint[ENDPOINT2].enabled &&
            target->endPoint[ENDPOINT3].enabled &&
            target->endPoint[ENDPOINT4].enabled )
        {
            /* Send the INT_WLAN interrupt to the target */
            target->table.int_wlan = 1;
            HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO,
                              HIF_ASYNCHRONOUS, HIF_BYTE_BASIS,
                              HIF_FIXED_ADDRESS);
            address = getRegAddr(INT_WLAN_REG, ENDPOINT_UNUSED);
            regElement = allocateRegRequestElement(target);
            AR_DEBUG_ASSERT(regElement != NULL);
            FILL_REG_BUFFER(regElement, &target->table.int_wlan, 1,
                            INT_WLAN_REG, ENDPOINT_UNUSED);
            status = HIFReadWrite(target->device, address,
                                  &target->table.int_wlan,
                                  1, &request, regElement);
#ifndef HTC_SYNC
            AR_DEBUG_ASSERT(status == A_OK);
#else
			AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING);
			if(status == A_OK) {
				regElement->completionCB(regElement, status);
			}
#endif
        }
    }

    return A_OK;
}

A_STATUS
htcRxCompletionCB(HTC_DATA_REQUEST_ELEMENT *element,
                  A_STATUS status)
{
    HTC_TARGET *target;
    HTC_ENDPOINT *endPoint;
    HTC_EVENT_INFO eventInfo;
    HTC_ENDPOINT_ID endPointId;
    HTC_MBOX_BUFFER *mboxBuffer;

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_SEND,
                    ("htcRxCompletionCB - Enter\n"));

    /* Get the context */
    mboxBuffer = GET_MBOX_BUFFER(element);
    AR_DEBUG_ASSERT(mboxBuffer != NULL);
    endPoint = mboxBuffer->endPoint;
    AR_DEBUG_ASSERT(endPoint != NULL);
    target = endPoint->target;
    AR_DEBUG_ASSERT(target != NULL);
    endPointId = GET_ENDPOINT_ID(endPoint);

    AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_RECV,
                    ("mboxBuffer: 0x%p, buffer: 0x%p, endPoint(%d): 0x%p, target: 0x%p\n", mboxBuffer, mboxBuffer->buffer, endPointId, endPoint, target));

    /* Return the buffer to the user if the reception was not successful */
    if (status != A_OK) {
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR | ATH_DEBUG_RECV,
                        ("Frame reception failed\n"));
        /*
         * In the failure case it is possible that while queueing of the
         * request itself it returned an error status in which case we
         * would have dispatched an event and freed the element there
         * itself. Ideally if it failed to queue the request then it
         * should not generate a callback but we are being a little
         * conservative.
         */
        if (!(IS_ELEMENT_FREE(element))) {
            mboxBuffer->actualLength = 0;
            mboxBuffer->buffer += HTC_HEADER_LEN;
            FRAME_EVENT(eventInfo, mboxBuffer->buffer,
                        mboxBuffer->bufferLength, mboxBuffer->actualLength,
                        A_ECANCELED, mboxBuffer->cookie);
            RECYCLE_DATA_REQUEST_ELEMENT(element);
            dispatchEvent(target, endPointId, HTC_BUFFER_RECEIVED, &eventInfo);
            AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
                            ("htcRxCompletionCB - Exit\n"));
        }
        return A_OK;
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_RECV,
                    ("Frame reception complete\n"));

    AR_DEBUG_PRINTBUF(mboxBuffer->buffer, mboxBuffer->actualLength);

    /*
     * Advance the pointer by the size of HTC header and pass the payload
     * pointer to the upper layer.
     */
    mboxBuffer->actualLength = ((mboxBuffer->buffer[0] << 0) |
                                (mboxBuffer->buffer[1] << 8));
    mboxBuffer->buffer += HTC_HEADER_LEN;

    /*
     * Frame the HTC_BUFFER_RECEIVED to the upper layer indicating that the
     * packet has been succesfully received.
     */
    FRAME_EVENT(eventInfo, mboxBuffer->buffer, mboxBuffer->bufferLength,
                mboxBuffer->actualLength, A_OK, mboxBuffer->cookie);

    /* Recycle the bufferElement structure */
    RECYCLE_DATA_REQUEST_ELEMENT(element);

    /* Dispatch the event */
    dispatchEvent(target, endPointId, HTC_BUFFER_RECEIVED, &eventInfo);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV,
                    ("htcRxCompletion - Exit\n"));

    return A_OK;
}

A_STATUS
htcRegCompletionCB(HTC_REG_REQUEST_ELEMENT *element,
                   A_STATUS status)
{
    A_STATUS ret;
    HTC_TARGET *target;
    HTC_ENDPOINT *endPoint;
    HTC_REG_BUFFER *regBuffer;
    A_UINT8 txCreditsConsumed;
    A_UINT8 txCreditsAvailable;
    HTC_ENDPOINT_ID endPointId;

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC | ATH_DEBUG_RECV | ATH_DEBUG_SEND,
                    ("htcRegCompletion - Enter\n"));
    AR_DEBUG_ASSERT(status == A_OK);

    /* Get the context */
    AR_DEBUG_ASSERT(element != NULL);
    regBuffer = GET_REG_BUFFER(element);
    AR_DEBUG_ASSERT(regBuffer != NULL);
    target = regBuffer->target;
    AR_DEBUG_ASSERT(target != NULL);

    /* Identify the register and the operation responsible for the callback */
    ret = A_OK;
    switch(regBuffer->base) {
    case TX_CREDIT_COUNTER_DECREMENT_REG:
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("TX_CREDIT_COUNTER_DECREMENT_REG\n"));
        endPointId = regBuffer->offset;
        endPoint = &target->endPoint[endPointId];

        AR_DEBUG_PRINTF(ATH_DEBUG_SYNC,
                        ("Critical Section (credit): LOCK at line %d in file %s\n", __LINE__, __FILE__));
        A_MUTEX_LOCK(&creditCS);

        /* Calculate the number of credits available */
        AR_DEBUG_ASSERT(GET_TX_CREDITS_CONSUMED(endPoint) == regBuffer->length);
        AR_DEBUG_ASSERT(regBuffer->buffer[0] >=
                        GET_TX_CREDITS_CONSUMED(endPoint));
        SET_TX_CREDITS_AVAILABLE(endPoint, regBuffer->buffer[0] -
                                 GET_TX_CREDITS_CONSUMED(endPoint));
        SET_TX_CREDITS_CONSUMED(endPoint, 0);
        txCreditsAvailable = GET_TX_CREDITS_AVAILABLE(endPoint);
        txCreditsConsumed = GET_TX_CREDITS_CONSUMED(endPoint);
        AR_DEBUG_PRINTF(ATH_DEBUG_SYNC,
                        ("Critical Section (credit): UNLOCK at line %d in file %s\n", __LINE__, __FILE__));
        A_MUTEX_UNLOCK(&creditCS);

        AR_DEBUG_PRINTF(ATH_DEBUG_INF | ATH_DEBUG_SEND,
                        ("Pulling %d tx credits from the target\n",
                        txCreditsAvailable));

#ifdef DEBUG
        txcreditsavailable[endPointId] = txCreditsAvailable;
        txcreditsconsumed[endPointId] = txCreditsConsumed;
#endif /* DEBUG */

        if (txCreditsAvailable) {
            htcSendFrame(endPoint);
        } else {
            /*
             * Enable the Tx credit counter interrupt so that we can get the
             * credits posted by the target.
             */
            htcEnableCreditCounterInterrupt(target, endPointId);

#ifdef DEBUG
            txcreditintrenable[endPointId] += 1;
            txcreditintrenableaggregate[endPointId] += 1;
#endif /* DEBUG */
        }
        break;

    case TX_CREDIT_COUNTER_RESET_REG:
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("TX_CREDIT_COUNTER_RESET_REG\n"));
        endPointId = regBuffer->offset;

        /*
         * Enable the Tx credit counter interrupt so that we can get the
         * credits posted by the target.
         */
        htcEnableCreditCounterInterrupt(target, endPointId);

#ifdef DEBUG
        txcreditintrenable[endPointId] += 1;
        txcreditintrenableaggregate[endPointId] += 1;
#endif /* DEBUG */
        break;

    case COUNTER_INT_STATUS_ENABLE_REG:
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("COUNTER_INT_STATUS_ENABLE: 0x%x\n",
                        target->table.counter_int_status_enable));
        break;

    case COUNTER_INT_STATUS_DISABLE_REG:
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("COUNTER_INT_STATUS_DISABLE:0x%x\n",
                        target->table.counter_int_status_enable));
        HIFAckInterrupt(target->device);
        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcDSRHandler - ACK\n"));
        break;

    case INT_WLAN_REG:
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("INT_WLAN: 0x%x\n",
                        target->table.int_wlan));
        target->table.int_wlan = 0;

        /* Mark the target state as ready and signal the waiting sem */
        target->ready = TRUE;
        A_WAKE_UP(&htcEvent);
        break;

	case INT_STATUS_ENABLE_REG:
		AR_DEBUG_PRINTF(ATH_DEBUG_INF,("INT_STATUS_ENABLE: 0x%x\n",
						target->table.int_status_enable));
		break;

    default:
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
                        ("Invalid register address: %d\n", regBuffer->base));
    }

    /* Free the register request structure */
    freeRegRequestElement(element);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcRegCompletion - Exit\n"));

    return ret;
}


A_STATUS
htcTargetInsertedHandler(HIF_DEVICE *device)
{
    HTC_TARGET *target;
    HTC_ENDPOINT *endPoint;
    A_UINT8 count1, count2;
    HTC_EVENT_INFO eventInfo;
    HTC_REG_BUFFER *regBuffer;
    HTC_QUEUE_ELEMENT *element;
    HTC_MBOX_BUFFER *mboxBuffer;
    HTC_REG_REQUEST_LIST *regList;
    HTC_DATA_REQUEST_QUEUE *sendQueue, *recvQueue;
    A_UINT32 mboxAddress[HTC_MAILBOX_NUM_MAX];
    A_UINT32 blockSize[HTC_MAILBOX_NUM_MAX];
#ifdef CF
	HIF_REQUEST request;
	A_STATUS status;
	A_UINT32 address;
#endif /* CF */

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Enter\n"));

    /* Initialize the locks */
    A_MUTEX_INIT(&instanceCS);
    A_MUTEX_INIT(&creditCS);
    A_MUTEX_INIT(&counterCS);

    /* Allocate target memory */
    if ((target = (HTC_TARGET *)A_MALLOC(sizeof(HTC_TARGET))) == NULL) {
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Unable to allocate memory\n"));
        return A_ERROR;
    }
    A_MEMZERO(target, sizeof(HTC_TARGET));
    target->device = device;
    target->ready = FALSE;

    /* Initialize the endpoints, mbox queues, event table */
    for (count1 = ENDPOINT1; count1 <= ENDPOINT4; count1 ++) {
        endPoint = &target->endPoint[count1];
        AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                        ("endPoint[%d]: %p\n", count1, endPoint));
        A_MEMZERO(endPoint->txCreditsAvailable, HTC_TX_CREDITS_NUM_MAX);
        endPoint->txCreditsConsumed = 0;
        endPoint->txCreditsIntrEnable = FALSE;
        endPoint->rxLengthPending = 0;
        endPoint->target = target;
        endPoint->enabled = FALSE;
        for (count2 = 0; count2sendQueue;
            sendQueue->head = sendQueue->size = 0;
            element = &sendQueue->element[count2];
            A_MEMZERO(element, sizeof(HTC_DATA_REQUEST_ELEMENT));
            element->buffer.free = TRUE;
            element->completionCB = htcTxCompletionCB;
            mboxBuffer = GET_MBOX_BUFFER(element);
            mboxBuffer->endPoint = endPoint;

            /* Receive Queue */
            recvQueue = &endPoint->recvQueue;
            recvQueue->head = recvQueue->size = 0;
            element = &recvQueue->element[count2];
            A_MEMZERO(element, sizeof(HTC_DATA_REQUEST_ELEMENT));
            element->buffer.free = TRUE;
            element->completionCB = htcRxCompletionCB;
            mboxBuffer = GET_MBOX_BUFFER(element);
            mboxBuffer->endPoint = endPoint;
        }
        A_MEMZERO(&target->endPoint[count1].eventTable,
                  sizeof(HTC_ENDPOINT_EVENT_TABLE));
    }

    /* Populate the block size for each of the end points */
    HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_BLOCK_SIZE,
                       &blockSize, sizeof(blockSize));
    HIFConfigureDevice(device, HIF_DEVICE_GET_MBOX_ADDR,
                       &mboxAddress, sizeof(mboxAddress));
    for (count1 = ENDPOINT1; count1 <= ENDPOINT4; count1 ++) {
        endPoint = &target->endPoint[count1];
        endPoint->blockSize = blockSize[count1];
        endPoint->address = mboxAddress[count1];
    }

    /* Initialize the shadow copy of the target register table */
    A_MEMZERO(&target->table, sizeof(HTC_REGISTER_TABLE));

    /* Initialize the register request list */
    regList = &target->regList;
    for (count1 = 0; count1 < HTC_REG_REQUEST_LIST_SIZE; count1 ++) {
        element = ®List->element[count1];
        A_MEMZERO(element, sizeof(HTC_REG_REQUEST_ELEMENT));
        element->buffer.free = TRUE;
        element->completionCB = htcRegCompletionCB;
        regBuffer = GET_REG_BUFFER(element);
        regBuffer->target = target;
    }

    /* Add the target instance to the global list */
    addTargetInstance(target);
#ifdef CF
    /* Disable all the dragon interrupts */
    target->table.int_status_enable = 0;
    target->table.cpu_int_status_enable = 0;
    target->table.error_status_enable = 0;
    target->table.counter_int_status_enable = 0;
    HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS);
    address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED);
    status = HIFReadWrite(target->device, address,
                          &target->table.int_status_enable, 4, &request, NULL);
    AR_DEBUG_ASSERT(status == A_OK);
#endif /* CF */

    /*
     * Frame a TARGET_AVAILABLE event and send it to the host. Return the
     * HIF_DEVICE handle as a parameter with the event.
     */
    FRAME_EVENT(eventInfo, (A_UCHAR *)device, sizeof(HIF_DEVICE *),
                sizeof(HIF_DEVICE *), A_OK, NULL);
    dispatchEvent(target, ENDPOINT_UNUSED, HTC_TARGET_AVAILABLE, &eventInfo);

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcTargetInserted - Exit\n"));

    return A_OK;
}

A_STATUS
htcTargetRemovedHandler(HIF_DEVICE *device)
{
    HTC_TARGET *target;
    HTC_EVENT_INFO eventInfo;

    /* Get the target instance bound to this device */
    target = getTargetInstance(device);

    if (target != NULL) {
        /* Frame a TARGET_UNAVAILABLE event and send it to the host */
        FRAME_EVENT(eventInfo, NULL, 0, 0, A_OK, NULL);
        dispatchEvent(target, ENDPOINT_UNUSED, HTC_TARGET_UNAVAILABLE,
                      &eventInfo);
    }

    return A_OK;
}


#ifdef CF
A_STATUS
htcInterruptDisabler(HIF_DEVICE *device,A_BOOL *callDsr)
{
    A_STATUS status;
    A_UINT32 address;
    HTC_TARGET *target;
    HIF_REQUEST request;

    target = getTargetInstance(device);
    AR_DEBUG_ASSERT(target != NULL);
    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
                    ("htcInterruptDisabler Enter target: 0x%p\n", target));

    HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
    address = getRegAddr(INT_STATUS_REG, ENDPOINT_UNUSED);
    status = HIFReadWrite(target->device, address,
                          &target->table.host_int_status, 1, &request, NULL);
    AR_DEBUG_ASSERT(status == A_OK);

	/* Handle Suprise removal of CF card. Upon removal of the card the
     * host_int_status reads 0xFF
     */
	if (target->table.host_int_status == 0xFF) {
        *callDsr=FALSE;
		return A_OK;
	}

    if ((target->table.int_status_enable & target->table.host_int_status) == 0) {
        AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
                    ("htcInterruptDisabler: MisRouted / Spurious interrupt : 0x%p\n", target));
        *callDsr=FALSE;
    } else {
            /*
         * Disable the interrupts from Dragon.
         *  We do the interrupt servicing in the bottom half and reenable the
         *  Dragon interrupts at the end of the bottom-half
             */

        target->table.int_status_enable = 0;
        HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
        address = getRegAddr(INT_STATUS_ENABLE_REG, ENDPOINT_UNUSED);
        status = HIFReadWrite(target->device, address,
                          &target->table.int_status_enable, 1, &request, NULL);
        AR_DEBUG_ASSERT(status == A_OK);
        *callDsr=TRUE;
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcInterruptDisabler: Exit\n"));
    return A_OK;
}
#endif /* CF */

A_STATUS
htcDSRHandler(HIF_DEVICE *device)
{
    A_STATUS status;
    A_UINT32 address;
    HTC_TARGET *target;
    HIF_REQUEST request;
    A_UCHAR host_int_status;

    target = getTargetInstance(device);
    AR_DEBUG_ASSERT(target != NULL);
    AR_DEBUG_PRINTF(ATH_DEBUG_TRC,
                    ("htcDsrHandler: Enter (target: 0x%p\n", target));

    /*
     * Read the first 28 bytes of the HTC register table. This will yield us
     * the value of different int status registers and the lookahead
     * registers.
     *    length = sizeof(int_status) + sizeof(cpu_int_status) +
     *             sizeof(error_int_status) + sizeof(counter_int_status) +
     *             sizeof(mbox_frame) + sizeof(rx_lookahead_valid) +
     *             sizeof(hole) +  sizeof(rx_lookahead) +
     *             sizeof(int_status_enable) + sizeof(cpu_int_status_enable) +
     *             sizeof(error_status_enable) +
     *             sizeof(counter_int_status_enable);
     */
    HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_INCREMENTAL_ADDRESS);
    address = getRegAddr(INT_STATUS_REG, ENDPOINT_UNUSED);
    status = HIFReadWrite(target->device, address,
                          &target->table.host_int_status, 28,
                          &request, NULL);
    AR_DEBUG_ASSERT(status == A_OK);

#ifdef DEBUG
    dumpRegisters(target);
#endif /* DEBUG */
#ifdef CF
    /* Update only those registers that are enabled */
        /* This is not required as we have already checked for spurious interrupt
         * in htcInterruptDisabler
         */

    host_int_status = target->table.host_int_status;
#else
    /* Update only those registers that are enabled */
    host_int_status = target->table.host_int_status &
                      target->table.int_status_enable;
#endif /* CF */

    AR_DEBUG_ASSERT(host_int_status);
    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("Valid interrupt source(s) in INT_STATUS: 0x%x\n",
                    host_int_status));
    if (HOST_INT_STATUS_CPU_GET(host_int_status)) {
        /* CPU Interrupt */
        htcServiceCPUInterrupt(target);
    }

    if (HOST_INT_STATUS_ERROR_GET(host_int_status)) {
        /* Error Interrupt */
        htcServiceErrorInterrupt(target);
    }

    if (HOST_INT_STATUS_MBOX_DATA_GET(host_int_status)) {
        /* Mailbox Interrupt */
        htcServiceMailboxInterrupt(target);
    }

    if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) {
        /* Counter Interrupt */
        htcServiceCounterInterrupt(target);
    } else {
        /* Ack the interrupt */
        HIFAckInterrupt(target->device);
        AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcDSRHandler - ACK\n"));
    }

    AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htcDSRHandler: Exit\n"));
    return A_OK;
}

void
htcServiceCPUInterrupt(HTC_TARGET *target)
{
    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    A_UINT8 cpu_int_status;

    AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("CPU Interrupt\n"));
    cpu_int_status = target->table.cpu_int_status &
                     target->table.cpu_int_status_enable;
    AR_DEBUG_ASSERT(cpu_int_status);
    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n",
                    cpu_int_status));

    /* Figure out the interrupt number */
    AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Interrupt Number: 0x%x\n",
                    htcGetBitNumSet(cpu_int_status)));

    /* Clear the interrupt */
    target->table.cpu_int_status = cpu_int_status; /* W1C */
    HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
    address = getRegAddr(CPU_INT_STATUS_REG, ENDPOINT_UNUSED);
    status = HIFReadWrite(target->device, address,
                          &target->table.cpu_int_status, 1, &request, NULL);
    AR_DEBUG_ASSERT(status == A_OK);
}


void
htcServiceErrorInterrupt(HTC_TARGET *target)
{
    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    A_UINT8 error_int_status;

    AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Error Interrupt\n"));
    error_int_status = target->table.error_int_status &
                       target->table.error_status_enable;
    AR_DEBUG_ASSERT(error_int_status);
    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("Valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n",
                    error_int_status));

    if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) {
        /* Wakeup */
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Wakeup\n"));
    }

    if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) {
        /* Rx Underflow */
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Rx Underflow\n"));
    }

    if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) {
        /* Tx Overflow */
        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Tx Overflow\n"));
    }

    /* Clear the interrupt */
    target->table.error_int_status = error_int_status; /* W1C */
    HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_SYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
    address = getRegAddr(ERROR_INT_STATUS_REG, ENDPOINT_UNUSED);
    status = HIFReadWrite(target->device, address,
                          &target->table.error_int_status, 1,
                          &request, NULL);
    AR_DEBUG_ASSERT(status == A_OK);
}

void
htcServiceCounterInterrupt(HTC_TARGET *target)
{
    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    HTC_ENDPOINT *endPoint;
    HTC_ENDPOINT_ID endPointId;
    A_UINT8 counter_int_status;
    A_UINT8 reset_credit_int_status;
    A_UINT8 update_credit_int_status;
    HTC_REG_REQUEST_ELEMENT *element;

    AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Counter Interrupt\n"));

    counter_int_status = target->table.counter_int_status &
                         target->table.counter_int_status_enable;
    AR_DEBUG_ASSERT(counter_int_status);
    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("Valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n",
                    counter_int_status));

    /* Service the reset credit counter interrupt */
    reset_credit_int_status = (counter_int_status & 0x0F);
    while(reset_credit_int_status) {
        endPointId = htcGetBitNumSet(reset_credit_int_status);
        endPoint = &target->endPoint[endPointId];
        AR_DEBUG_ASSERT(endPoint != NULL);

        AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                        ("endPoint(%d): %p\n", endPointId, endPoint));

        /* Initialize the number of credits available to zero */
        SET_TX_CREDITS_AVAILABLE(endPoint, 0);

        /* Clear the interrupt */
        HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO,
                          HIF_ASYNCHRONOUS, HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
        address = getRegAddr(TX_CREDIT_COUNTER_RESET_REG, endPointId);
        element = allocateRegRequestElement(target);
        AR_DEBUG_ASSERT(element != NULL);
        FILL_REG_BUFFER(element, &endPoint->txCreditsAvailable[1], 1,
                        TX_CREDIT_COUNTER_RESET_REG, endPointId);
        status = HIFReadWrite(target->device, address,
                              &endPoint->txCreditsAvailable[1],
                              1, &request, element);

#ifndef HTC_SYNC
        AR_DEBUG_ASSERT(status == A_OK);
#else
        AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING);
		if (status == A_OK) {
        	/* Enable the Tx credit counter interrupt so that we can get the
             * credits posted by the target */
        	htcEnableCreditCounterInterrupt(target, endPointId);
		}
#endif
        reset_credit_int_status &=
            ~(1 << htcGetBitNumSet(reset_credit_int_status));
    }

    /* Disable the credit counter interrupt */
    htcDisableCreditCounterInterrupt(target, ENDPOINT_UNUSED);

    /* Service the credit counter interrupt */
    update_credit_int_status = counter_int_status & 0xF0;
    while(update_credit_int_status) {
        endPointId = htcGetBitNumSet(update_credit_int_status) -
                     HTC_MAILBOX_NUM_MAX;
        endPoint = &target->endPoint[endPointId];
        AR_DEBUG_ASSERT(endPoint != NULL);

        /* This is the minimum number of credits that we would have got */
        AR_DEBUG_ASSERT(GET_TX_CREDITS_AVAILABLE(endPoint) == 0);
        SET_TX_CREDITS_AVAILABLE(endPoint, 1);

#ifdef DEBUG
        txcreditsavailable[endPointId] = GET_TX_CREDITS_AVAILABLE(endPoint);
        txcreditintrenable[endPointId] -= 1;
#endif /* DEBUG */

        AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Tx Credits Available: %d\n",
                                        GET_TX_CREDITS_AVAILABLE(endPoint)));

        if (!target->ready) {
            htcSendBlkSize(endPoint);
        } else {
            htcSendFrame(endPoint);
        }

        update_credit_int_status &=
            ~(1 << htcGetBitNumSet(update_credit_int_status));
    }
}

void
htcEnableCreditCounterInterrupt(HTC_TARGET *target,
                                HTC_ENDPOINT_ID endPointId)
{
    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    HTC_ENDPOINT *endPoint;
    HTC_REG_REQUEST_ELEMENT *element;

    endPoint = &target->endPoint[endPointId];
    AR_DEBUG_ASSERT(endPoint != NULL);

    A_MUTEX_LOCK(&counterCS);

    endPoint->txCreditsIntrEnable = TRUE;
    HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO,
                      HIF_ASYNCHRONOUS, HIF_BYTE_BASIS,
                      HIF_FIXED_ADDRESS);

    address = getRegAddr(COUNTER_INT_STATUS_ENABLE_REG,
                         ENDPOINT_UNUSED);
    element = allocateRegRequestElement(target);
    AR_DEBUG_ASSERT(element != NULL);
    FILL_REG_BUFFER(element, NULL, 1, COUNTER_INT_STATUS_ENABLE_REG,
                    (target->endPoint[0].txCreditsIntrEnable << (4)) |
                    (target->endPoint[1].txCreditsIntrEnable << (5)) |
                    (target->endPoint[2].txCreditsIntrEnable << (6)) |
                    (target->endPoint[3].txCreditsIntrEnable << (7)) | 0x0F);
    status = HIFReadWrite(target->device, address,
                     (A_UCHAR *)&((GET_REG_BUFFER(element))->offset),
                     1, &request, element);

#ifndef HTC_SYNC
    AR_DEBUG_ASSERT(status == A_OK);
#else
            AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING);
			if(status == A_OK) {
				element->completionCB(element, status);
			}
#endif

    A_MUTEX_UNLOCK(&counterCS);
}

void
htcDisableCreditCounterInterrupt(HTC_TARGET *target,
                                 HTC_ENDPOINT_ID unused)
{
    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    HTC_ENDPOINT *endPoint;
    HTC_ENDPOINT_ID endPointId;
    A_UINT8 counter_int_status;
    A_UINT8 update_credit_int_status;
    HTC_REG_REQUEST_ELEMENT *element;

    A_MUTEX_LOCK(&counterCS);

    /* The Tx credit counter update bits are reflected in the upper nibble */
    counter_int_status = target->table.counter_int_status &
                         target->table.counter_int_status_enable;
    update_credit_int_status = counter_int_status & 0xF0;
    while(update_credit_int_status) {
        endPointId = htcGetBitNumSet(update_credit_int_status) -
                     HTC_MAILBOX_NUM_MAX;
        endPoint = &target->endPoint[endPointId];
        AR_DEBUG_ASSERT(endPoint != NULL);

        AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                        ("endPoint(%d): %p\n", endPointId, endPoint));

        /* Disable the tx credit interrupt */
        endPoint->txCreditsIntrEnable = FALSE;

        update_credit_int_status &=
            ~(1 << htcGetBitNumSet(update_credit_int_status));
    }

    HIF_FRAME_REQUEST(&request, HIF_WRITE, HIF_EXTENDED_IO, HIF_ASYNCHRONOUS,
                      HIF_BYTE_BASIS, HIF_FIXED_ADDRESS);
    address = getRegAddr(COUNTER_INT_STATUS_DISABLE_REG, ENDPOINT_UNUSED);
    element = allocateRegRequestElement(target);
    AR_DEBUG_ASSERT(element != NULL);
    FILL_REG_BUFFER(element, NULL, 1,
                    COUNTER_INT_STATUS_DISABLE_REG,
                    (target->endPoint[0].txCreditsIntrEnable << (4)) |
                    (target->endPoint[1].txCreditsIntrEnable << (5)) |
                    (target->endPoint[2].txCreditsIntrEnable << (6)) |
                    (target->endPoint[3].txCreditsIntrEnable << (7)) | 0x0F);
    status = HIFReadWrite(target->device, address,
                          (A_UCHAR *)&((GET_REG_BUFFER(element))->offset),
                          1, &request, element);

#ifndef HTC_SYNC
    AR_DEBUG_ASSERT(status == A_OK);
#else
    AR_DEBUG_ASSERT(status == A_OK || status == A_PENDING);
	if ( status == A_OK ) {
		element->completionCB(element, status);
	}
#endif

    A_MUTEX_UNLOCK(&counterCS);
}

void
htcServiceMailboxInterrupt(HTC_TARGET *target)
{
    A_STATUS status;
    A_UINT32 address;
    HIF_REQUEST request;
    HTC_ENDPOINT *endPoint;
    HTC_ENDPOINT_ID endPointId;
    A_UINT8 mailbox_int_status;

    AR_DEBUG_PRINTF(ATH_DEBUG_INF, ("Mailbox Interrupt\n"));

    /* The Rx interrupt bits are reflected in the lower nibble */
    mailbox_int_status = target->table.host_int_status &
                         HOST_INT_STATUS_MBOX_DATA_MASK;
    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("Valid mailbox interrupt source(s) in INT_STATUS: 0x%x\n",
                    mailbox_int_status));

    /* Disable the receive interrupt for all four mailboxes */
    target->table.int_status_enable &= ~(HOST_INT_STATUS_MBOX_DATA_MASK);

    do {
        while(mailbox_int_status) {
            endPointId = htcGetBitNumSet(mailbox_int_status);
            endPoint = &target->endPoint[endPointId];
            AR_DEBUG_ASSERT(endPoint != NULL);

            AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                            ("endPoint(%d): %p\n", endPointId, endPoint));

            /* Service the Rx interrupt */
            htcReceiveFrame(endPoint);
            mailbox_int_status &= ~(1 << htcGetBitNumSet(mailbox_int_status));
        }

        /*
         * Read the register table again. Repeat the process until there are
         * no more valid packets queued up on receive. It is assumed that
         * the following request will be serialized along with the request
         * above and will be completed in the order in which it is received
         * by the bus driver.
         */
        HIF_FRAME_REQUEST(&request, HIF_READ, HIF_EXTENDED_IO,
                          HIF_SYNCHRONOUS, HIF_BYTE_BASIS,
                          HIF_INCREMENTAL_ADDRESS);
        address = getRegAddr(INT_STATUS_REG, ENDPOINT_UNUSED);
        status = HIFReadWrite(target->device, address,
                              &target->table.host_int_status,
                              24, &request, NULL);
        AR_DEBUG_ASSERT(status == A_OK);
        mailbox_int_status = target->table.host_int_status &
                             HOST_INT_STATUS_MBOX_DATA_MASK;
    } while (mailbox_int_status);

    target->table.int_status_enable |= HOST_INT_STATUS_MBOX_DATA_MASK;
}