www.pudn.com > sdio-2.6.18-full.rar > htc_utils.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 utility routines used across the entire HTC module.
 */

#include "htc_internal.h"

/* ------ Global Variable Declarations ------- */
extern HTC_TARGET *AtherosTargetList[HIF_MAX_DEVICES];
extern HTC_GLOBAL_EVENT_TABLE AtherosEventTable;
extern A_MUTEX_T instanceCS;

#ifdef DEBUG
extern A_UINT32 debughtc;
#endif

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

/* ------ Functions ------ */
void
dispatchEvent(HTC_TARGET     *target,
              HTC_ENDPOINT_ID endPointId,
              HTC_EVENT_ID    eventId,
              HTC_EVENT_INFO *eventInfo)
{
    EVENT_TABLE_ELEMENT *eventElement;

    if (eventId == HTC_TARGET_AVAILABLE) {
        eventElement = &AtherosEventTable.element[0];
    } else if (eventId == HTC_TARGET_UNAVAILABLE) {
        eventElement = &AtherosEventTable.element[1];
    } else {
        eventElement =
            &target->endPoint[endPointId].eventTable.element[eventId];
    }
    AR_DEBUG_ASSERT(eventElement != NULL);

    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("dispatchEvent(endpoint: %d, eventId: 0x%d, handler: 0x%p)\n", endPointId, eventElement->id, eventElement->handler));
    if (eventElement->handler) {
        eventElement->handler(target, endPointId, eventId, eventInfo,
                              eventElement->param);
    }
}


A_STATUS
addToEventTable(HTC_TARGET       *target,
                HTC_ENDPOINT_ID   endPointId,
                HTC_EVENT_ID      eventId,
                HTC_EVENT_HANDLER handler,
                void             *param)
{
    EVENT_TABLE_ELEMENT *new;

    if (eventId == HTC_TARGET_AVAILABLE) {
        new = &AtherosEventTable.element[0];
    } else if (eventId == HTC_TARGET_UNAVAILABLE) {
        new = &AtherosEventTable.element[1];
    } else {
        new = &target->endPoint[endPointId].eventTable.element[eventId];
    }

    /* Store the event id, the corresponding handler and the param passed */
    new->id = eventId;
    new->handler = handler;
    new->param = param;

    AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                    ("addToEventTable(endpoint: %d, eventId: 0x%d, handler: 0x%p)\n", endPointId, new->id, new->handler));

    return A_OK;
}


A_STATUS
removeFromEventTable(HTC_TARGET *target,
                     HTC_ENDPOINT_ID endPointId,
                     HTC_EVENT_ID  eventId)
{
    EVENT_TABLE_ELEMENT *remove;

    if (eventId == HTC_TARGET_AVAILABLE) {
        remove = &AtherosEventTable.element[0];
    } else if (eventId == HTC_TARGET_UNAVAILABLE) {
        remove = &AtherosEventTable.element[1];
    } else {
        remove = &target->endPoint[endPointId].eventTable.element[eventId];
    }

    /* Remove the event handler */
    A_MEMZERO(remove, sizeof(EVENT_TABLE_ELEMENT));

    return A_OK;
}

A_STATUS
addToMboxQueue(HTC_DATA_REQUEST_QUEUE *queue,
               A_UCHAR        *buffer,
               A_UINT32        bufferLength,
               A_UINT32        actualLength,
               void           *cookie)
{
    A_STATUS status;
    HTC_DATA_REQUEST_ELEMENT *element;

    AR_DEBUG_ASSERT(queue != NULL);
    AR_DEBUG_ASSERT(bufferLength);

    AR_DEBUG_PRINTF(ATH_DEBUG_SYNC,
                    ("Critical Section (queue): LOCK at line %d in file %s\n", __LINE__, __FILE__));
    A_MUTEX_LOCK(&instanceCS);
    element = GET_QUEUE_TAIL(queue);
    if (!(IS_DATA_QUEUE_FULL(queue)) && IS_ELEMENT_FREE(element)) {
        element->buffer.free = FALSE;
        FILL_MBOX_BUFFER(element, buffer, bufferLength, actualLength, cookie);
        queue->size += 1;

        AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                        ("addToMboxQueue (index: %d, size: %d, bufferElement: 0x%p, bufferElement->buffer: 0x%p, bufferElement->cookie: 0x%p)\n", (queue->head + queue->size - 1) % HTC_DATA_REQUEST_RING_BUFFER_SIZE, queue->size, element, (GET_MBOX_BUFFER(element))->buffer, (GET_MBOX_BUFFER(element))->cookie));
        status = A_OK;
    } else {
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Queue size: %d\n", queue->size));
        status = A_ERROR;
    }
    AR_DEBUG_PRINTF(ATH_DEBUG_SYNC,
                    ("Critical Section (queue): UNLOCK at line %d in file %s\n", __LINE__, __FILE__));
    A_MUTEX_UNLOCK(&instanceCS);

    return status;
}

HTC_DATA_REQUEST_ELEMENT *
removeFromMboxQueue(HTC_DATA_REQUEST_QUEUE *queue) {
    HTC_DATA_REQUEST_ELEMENT *element;
    AR_DEBUG_ASSERT(queue != NULL);

    AR_DEBUG_PRINTF(ATH_DEBUG_SYNC,
                    ("Critical Section (queue): LOCK at line %d in file %s\n", __LINE__, __FILE__));
    A_MUTEX_LOCK(&instanceCS);
    if (!(IS_DATA_QUEUE_EMPTY(queue))) {
        element = GET_QUEUE_HEAD(queue);
        queue->head = (queue->head + 1) % HTC_DATA_REQUEST_RING_BUFFER_SIZE;
        queue->size -= 1;

        AR_DEBUG_PRINTF(ATH_DEBUG_INF,
                        ("removeFromMboxQueue (index: %d, size: %d, bufferElement: 0x%p, bufferElement->buffer: 0x%p, bufferElement->cookie: 0x%p)\n", queue->head, queue->size, element, (GET_MBOX_BUFFER(element))->buffer, (GET_MBOX_BUFFER(element))->cookie));
    } else {
        element = NULL;
    }
    AR_DEBUG_PRINTF(ATH_DEBUG_SYNC,
                    ("Critical Section (queue): UNLOCK at line %d in file %s\n", __LINE__, __FILE__));
    A_MUTEX_UNLOCK(&instanceCS);

    return element;
}

void
flushMboxQueue(HTC_ENDPOINT *endPoint,
               HTC_DATA_REQUEST_QUEUE *queue,
               HTC_EVENT_ID eventId)
{
    HTC_DATA_REQUEST_ELEMENT *curr;
    HTC_EVENT_INFO eventInfo;
    HTC_ENDPOINT_EVENT_TABLE *eventTable;
    HTC_ENDPOINT_ID endPointId;
    EVENT_TABLE_ELEMENT *eventElement;
    HTC_MBOX_BUFFER *mboxBuffer;

    eventTable = &endPoint->eventTable;
    endPointId = GET_ENDPOINT_ID(endPoint);

    /*
     * Release the buffer to WMI using the registered event handler. If WMI
     * has not registered any callbacks for a particular endpoint then it
     * means that its queues will not have any buffers so we skip that
     * endpoint.
     */
    if ((eventElement = &eventTable->element[eventId]) != NULL) {
        while ((curr = removeFromMboxQueue(queue)) != NULL) {
            /* Frame the event and dispatch it */
            mboxBuffer = GET_MBOX_BUFFER(curr);
            FRAME_EVENT(eventInfo, mboxBuffer->buffer,
                        mboxBuffer->bufferLength, mboxBuffer->actualLength,
                        A_ECANCELED, mboxBuffer->cookie);
            if (eventElement->handler) {
                eventElement->handler(endPoint->target, endPointId, eventId,
                                      &eventInfo, eventElement->param);
            }
            RECYCLE_DATA_REQUEST_ELEMENT(curr);
        }
    }

    /* Initialize the head and tail pointer */
    queue->head = 0;
    queue->size = 0;
}

HTC_REG_REQUEST_ELEMENT *
allocateRegRequestElement(HTC_TARGET *target) {
    A_UINT32 count;
    HTC_REG_REQUEST_ELEMENT *element;

    A_MUTEX_LOCK(&instanceCS);
    element = NULL;
    for (count = 0; count < HTC_REG_REQUEST_LIST_SIZE; count ++) {
        element = &target->regList.element[count];
        if (IS_ELEMENT_FREE(element)) {
            element->buffer.free = FALSE;
            break;
        }
    }
    A_MUTEX_UNLOCK(&instanceCS);

    return element;
}

void
freeRegRequestElement(HTC_REG_REQUEST_ELEMENT *element) {
    A_MUTEX_LOCK(&instanceCS);
    FILL_REG_BUFFER(element, NULL, 0, 0, 0);
    element->buffer.free = TRUE;
    A_MUTEX_UNLOCK(&instanceCS);
}

HTC_TARGET *
getTargetInstance(void *device)
{
    return AtherosTargetList[0];
}

void
addTargetInstance(HTC_TARGET *target)
{
    AtherosTargetList[0] = target;
}

void
delTargetInstance(HTC_TARGET *target)
{
    AtherosTargetList[0] = NULL;
}

A_UINT32
getRegAddr(TARGET_REGISTERS base,
           HTC_ENDPOINT_ID endPointId)
{
    A_UINT32 address;

    switch(base) {
    case TX_CREDIT_COUNTER_RESET_REG:
        address = COUNT_DEC_ADDRESS + endPointId * 4;
        break;

    case TX_CREDIT_COUNTER_DECREMENT_REG:
        address = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + endPointId) * 4;
        break;

    case TX_CREDIT_COUNTER_REG:
        address = COUNT_ADDRESS + (HTC_MAILBOX_NUM_MAX + endPointId) * 4;
        break;

    case INT_STATUS_ENABLE_REG:
        address = INT_STATUS_ENABLE_ADDRESS;
        break;

    case COUNTER_INT_STATUS_ENABLE_REG:
    case COUNTER_INT_STATUS_DISABLE_REG:
        address = COUNTER_INT_STATUS_ENABLE_ADDRESS;
        break;

    case INT_STATUS_REG:
        address = HOST_INT_STATUS_ADDRESS;
        break;

    case CPU_INT_STATUS_REG:
        address = CPU_INT_STATUS_ADDRESS;
        break;

    case ERROR_INT_STATUS_REG:
        address = ERROR_INT_STATUS_ADDRESS;
        break;

    case INT_WLAN_REG:
        address = INT_WLAN_ADDRESS;
        break;

    case WINDOW_DATA_REG:
        address = WINDOW_DATA_ADDRESS;
        break;

    case WINDOW_WRITE_ADDR_REG:
        address = WINDOW_WRITE_ADDR_ADDRESS;
        break;

    case WINDOW_READ_ADDR_REG:
        address = WINDOW_READ_ADDR_ADDRESS;
        break;

    default:
        AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Invalid register: %d\n", base));
        AR_DEBUG_ASSERT(0);
        address = 0;
        break;
    }

    return address;
}

void
dumpBytes(A_UCHAR *buffer, A_UINT16 length)
{
    A_CHAR stream[60];
    A_UINT32 i;
    A_UINT16 offset, count;

    AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("Dumping %d Bytes : ------>\n", length));

    count = 0;
    offset = 0;
    for(i = 0; i < length; i++) {
        sprintf(stream + offset, "%2x ", buffer[i]);
	count ++;
	offset += 3;

	if(count == 16) {
	    count = 0;
	    offset = 0;
	    AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("[H]: %s\n", stream));
	    A_MEMZERO(stream, 60);
	}
    }

    if(offset != 0) {
	AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("[H]: %s\n", stream));
    }
}

void
dumpRegisters(HTC_TARGET *target)
{
    HTC_REGISTER_TABLE *reg;

    reg = &target->table;
    AR_DEBUG_PRINTF(ATH_DEBUG_DUMP, ("\n<------- Register Table -------->\nInt Status:                0x%x\nCPU Int Status:            0x%x\nError Int Status:          0x%x\nCounter Int Status:        0x%x\nMbox Frame:                0x%x\nRx Lookahead Valid:        0x%x\nRx Lookahead 0:            0x%x\nRx Lookahead 1:            0x%x\nRx Lookahead 2:            0x%x\nRx Lookahead 3:            0x%x\nInt Status Enable:         0x%x\nCounter Int Status Enable: 0x%x\n<------------------------------->\n", reg->host_int_status, reg->cpu_int_status, reg->error_int_status, reg->counter_int_status, reg->mbox_frame, reg->rx_lookahead_valid, reg->rx_lookahead[ENDPOINT1], reg->rx_lookahead[ENDPOINT2], reg->rx_lookahead[ENDPOINT3], reg->rx_lookahead[ENDPOINT4], reg->int_status_enable, reg->counter_int_status_enable));
}

A_UINT8
htcGetBitNumSet(A_UINT32 data)
{
    A_UINT8 count;

    count = 0;
    while(!(data & 0x1)) {
        count += 1;
        data >>= 1;
    }

    return count;
}