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


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@file: gps.c

@abstract: OS independent GPS class SDIO function driver

#notes:

@notice: Copyright (c), 2004-2005 Atheros Communications, Inc.
 *
 *  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.
 *
 *  Portions o this code were developed with information supplied from the
 *  SD Card Association Simplified Specifications. The following conditions and disclaimers may apply:
 *
 *   The following conditions apply to the release of the SD simplified specification (“Simplified
 *   Specification”) by the SD Card Association. The Simplified Specification is a subset of the complete
 *   SD Specification which is owned by the SD Card Association. This Simplified Specification is provided
 *   on a non-confidential basis subject to the disclaimers below. Any implementation of the Simplified
 *   Specification may require a license from the SD Card Association or other third parties.
 *   Disclaimers:
 *   The information contained in the Simplified Specification is presented only as a standard
 *   specification for SD Cards and SD Host/Ancillary products and is provided "AS-IS" without any
 *   representations or warranties of any kind. No responsibility is assumed by the SD Card Association for
 *   any damages, any infringements of patents or other right of the SD Card Association or any third
 *   parties, which may result from its use. No license is granted by implication, estoppel or otherwise
 *   under any patent or other rights of the SD Card Association or any third party. Nothing herein shall
 *   be construed as an obligation by the SD Card Association to disclose or distribute any technical
 *   information, know-how or other confidential information to any third party.
 *
 *
 *  The initial developers of the original code are Seung Yi and Paul Lever
 *
 *  sdio@atheros.com
 *
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#define MODULE_NAME  SD_GPS_FD
#include 
#include 
#include "gps.h"
#include 
#include 

void GpsIRQHandler(PVOID pContext);
static void TxCompletion(PSDREQUEST pReq);


/*
 *  GpsInitialize - initialize new device
*/
SDIO_STATUS GpsInitialize(PSDGPS_DEVICE pDevice)
{
    SDIO_STATUS status = SDIO_STATUS_SUCCESS;
    SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;
    struct SDIO_GPS_TPL gpsTpl;
    UINT32              nextTpl;
    UINT8               tplLength;
    UINT8               temp;
    SDCONFIG_FUNC_SLOT_CURRENT_DATA   slotCurrent;

    ZERO_OBJECT(fData);
    ZERO_OBJECT(slotCurrent);

    do {
        status = SemaphoreInitialize(&pDevice->DeviceSem, 0);
        if (!SDIO_SUCCESS(status)) {
            break;
        }

        status = SDLIB_GetDefaultOpCurrent(pDevice->pSDDevice,&slotCurrent.SlotCurrent);
        if (!SDIO_SUCCESS(status)) {
            break;
        }

        DBG_PRINT(SDDBG_TRACE, ("SDIO Gps Function: Allocating Slot current: %d mA\n", slotCurrent.SlotCurrent));
        status = SDLIB_IssueConfig(pDevice->pSDDevice,
                                   SDCONFIG_FUNC_ALLOC_SLOT_CURRENT,
                                   &slotCurrent,
                                   sizeof(slotCurrent));

        if (!SDIO_SUCCESS((status))) {
            DBG_PRINT(SDDBG_ERROR, ("SDIO Gps Function: failed to allocate slot current %d\n",
                                    status));
            if (status == SDIO_STATUS_NO_RESOURCES) {
                DBG_PRINT(SDDBG_ERROR, ("SDIO Gps Function: Remaining Slot Current: %d mA\n",
                                    slotCurrent.SlotCurrent));
            }
            break;
        }

        fData.EnableFlags = SDCONFIG_ENABLE_FUNC;
        fData.TimeOut = 500;
        status = SDLIB_IssueConfig(pDevice->pSDDevice,
                                   SDCONFIG_FUNC_ENABLE_DISABLE,
                                   &fData,
                                   sizeof(fData));
        if (!SDIO_SUCCESS((status))) {
            DBG_PRINT(SDDBG_ERROR, ("SDIO GPS Function: GpsInitialize, failed to enable function %d\n",
                                    status));
            break;
        }
        DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function Ready!\n"));
        pDevice->HwReady = TRUE;
            /* setup starting CIS scan */
        nextTpl = SDDEVICE_GET_SDIO_FUNC_CISPTR(pDevice->pSDDevice);
        DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: Function CIS starts at :0x%X \n",
                                SDDEVICE_GET_SDIO_FUNC_CISPTR(pDevice->pSDDevice)));
            /* look for the GPS TPL */
        while (1) {
                /* reset max buffer length */
            tplLength = sizeof(gpsTpl);
                /* go get the GPS tuple */
            status = SDLIB_FindTuple(pDevice->pSDDevice,
                                     GPS_TUPLE,
                                     &nextTpl,
                                     (PUINT8)&gpsTpl,
                                     &tplLength);

            if (!SDIO_SUCCESS(status)){
                DBG_PRINT(SDDBG_ERROR, ("SDIO GPS Function: Failed to get GPS Tuple: %d \n",status));
                break;
            }

            if (gpsTpl.StdTupleNumber == STD_GPS_TUPLE_SIOREG) {
                DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: Found SDIOREG Tuple \n"));
                DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: RegisterID:%d,RegisterExtID:%d \n",
                          gpsTpl.Tpd.AsSIOReg.RegisterID, gpsTpl.Tpd.AsSIOReg.RegisterExpID));
                DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: MaxBaudCode:%d, DRL:%d , DRM:%d\n",
                          gpsTpl.Tpd.AsSIOReg.MaxBaudRateCode,
                          gpsTpl.Tpd.AsSIOReg.DRL_4800,gpsTpl.Tpd.AsSIOReg.DRM_4800));
                pDevice->UartRegOffset =  gpsTpl.Tpd.AsSIOReg.RegisterOffset[0];
                pDevice->UartRegOffset |=  gpsTpl.Tpd.AsSIOReg.RegisterOffset[1] << 8;
                pDevice->UartRegOffset |=  gpsTpl.Tpd.AsSIOReg.RegisterOffset[2] << 16;
                pDevice->UartMaxBaud = (gpsTpl.Tpd.AsSIOReg.MaxBaudRateCode > 0) ?
                            gpsTpl.Tpd.AsSIOReg.MaxBaudRateCode * 115200 : 115200;
                pDevice->UartDivisor = 4 *(gpsTpl.Tpd.AsSIOReg.DRL_4800 |
                                       (gpsTpl.Tpd.AsSIOReg.DRM_4800 << 8) );
                /* if zero, its not setup, guess */
                if (pDevice->UartDivisor == 0) {
                    pDevice->UartDivisor = 6666;
                    DBG_PRINT(SDDBG_WARN, ("SDIO GPS Function: no UART divisor, using 1\n"));
                }

                DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: RegisterOffset:0x%X \n",
                                        pDevice->UartRegOffset));
                break;
            } else {
                DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: Found Sub-Tuple %d .. continuing search\n",
                                        gpsTpl.StdTupleNumber));
                continue;
            }
        }

        if (!SDIO_SUCCESS(status)) {
            break;
        }

            /* allocate a single request for asynch call usage */
        pDevice->pRequest = SDDeviceAllocRequest(pDevice->pSDDevice);

        if (NULL == pDevice->pRequest) {
            status =  SDIO_STATUS_NO_RESOURCES;
            break;
        }

            /* make sure interrupts are off and this also tests to see if we can see the
             * hardware */
        pDevice->InterruptEnable = 0;
        status = WriteRegister(pDevice, UART_INT_ENABLE_REG, pDevice->InterruptEnable);
        if (!SDIO_SUCCESS((status))) {
            DBG_PRINT(SDDBG_ERROR, ("SDIO GPS Function: GpsInitialize, failed register write, %d\n",
                                    status));
            break;
        }
            /* read registers to clear status */
        ReadRegister(pDevice, UART_LINE_STATUS_REG, &temp);
        ReadRegister(pDevice, UART_RECEIVE_REG, &temp);
        ReadRegister(pDevice, UART_INT_IDENT_REG, &temp);
        ReadRegister(pDevice, UART_MODEM_STATUS_REG, &temp);
        WriteRegister(pDevice, UART_FIFO_CNTRL_REG, UART_DATA_8_BITS | UART_FIFO_ENABLE | UART_FIFO_RCV_RESET);
        WriteRegister(pDevice, UART_FIFO_CNTRL_REG, UART_DATA_8_BITS | UART_FIFO_ENABLE);
        SetBaudRate(pDevice, 4800);
        WriteRegister(pDevice, UART_LINE_CNTRL_REG, (UART_ONE_STOP | UART_NO_PARITY | UART_DATA_8_BITS));

            /* set our IRQ handler */
        DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: Registering GpsIrqHandler \n"));
        SDDEVICE_SET_IRQ_HANDLER(pDevice->pSDDevice,GpsIRQHandler,pDevice);
            /* unmask our interrupt on the card */
        DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: unmasking IRQ \n"));
        status = SDLIB_IssueConfig(pDevice->pSDDevice,SDCONFIG_FUNC_UNMASK_IRQ,NULL,0);
        if (!SDIO_SUCCESS((status))) {
            DBG_PRINT(SDDBG_ERROR, ("SDIO GPS Function: GpsInitialize, failed to unmask IRQ %d\n",
                                    status));
            break;
        }

//??        DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: enabling InterruptEnable \n"));
//??        pDevice->InterruptEnable = UART_ERBFI | UART_ELSI;
//??        WriteRegister(pDevice, UART_INT_ENABLE_REG, pDevice->InterruptEnable);

    } while (FALSE);

    if (!SDIO_SUCCESS(status)) {
        GpsDeinitialize(pDevice);
    }
    SemaphorePost(&pDevice->DeviceSem);
    DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: exiting \n"));

    return status;
}

/*
 *  GpsDeinitialize - initialize new device
*/
void GpsDeinitialize(PSDGPS_DEVICE pDevice)
{
    SDCONFIG_FUNC_ENABLE_DISABLE_DATA fData;

    if (!(SDDEVICE_IS_CARD_REMOVED(pDevice->pSDDevice))) {
        if (pDevice->HwReady) {
                /* try masking our IRQ */
            SDLIB_IssueConfig(pDevice->pSDDevice,SDCONFIG_FUNC_MASK_IRQ,NULL,0);
            DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: Unregistering GpsIrqHandler \n"));
            SDDEVICE_SET_IRQ_HANDLER(pDevice->pSDDevice, NULL, NULL);

                /* power down the hardware */
            ZERO_OBJECT(fData);
            fData.EnableFlags = SDCONFIG_DISABLE_FUNC;
            fData.TimeOut = 500;
            SDLIB_IssueConfig(pDevice->pSDDevice,
                        SDCONFIG_FUNC_ENABLE_DISABLE,
                        &fData,
                        sizeof(fData));
        }
    }
    pDevice->HwReady = FALSE;

    SDLIB_IssueConfig(pDevice->pSDDevice,
                      SDCONFIG_FUNC_FREE_SLOT_CURRENT,
                      NULL,
                      0);

    if (pDevice->pRequest != NULL) {
        SDDeviceFreeRequest(pDevice->pSDDevice, pDevice->pRequest);
        pDevice->pRequest = NULL;
    }
    SemaphoreDelete(&pDevice->DeviceSem);
}
/*
 * SetBaudRate - set the requested baud rate
 */
SDIO_STATUS SetBaudRate(PSDGPS_DEVICE pDevice, UINT32 BaudRate)
{
    UINT8   lineControl;
    UINT8   saveInterrupt;
    UINT32  divisor;

        /* disable device interrupts */
    ReadRegister(pDevice, UART_INT_ENABLE_REG, &saveInterrupt);
    WriteRegister(pDevice, UART_INT_ENABLE_REG, 0);
        /* check for a valid baud rate */
    if ((BaudRate % 1200) || (BaudRate > pDevice->UartMaxBaud)) {
            DBG_PRINT(SDDBG_ERROR, ("SDIO GPS Function: SetBaudRate, invalid rate %d\n", BaudRate));
            WriteRegister(pDevice, UART_INT_ENABLE_REG, saveInterrupt);
        return SDIO_STATUS_INVALID_PARAMETER;
    }

        /* calculate new divisor based on 1200 baud divisor */
    divisor = pDevice->UartDivisor / (BaudRate / 1200);

    ReadRegister(pDevice, UART_LINE_CNTRL_REG, &lineControl);

    WriteRegister(pDevice, UART_LINE_CNTRL_REG, lineControl | UART_CLOCK_ENABLE);
    WriteRegister(pDevice, UART_BAUD_HIGH_REG, (UINT8)((divisor >> 8) & 0xFF));
    WriteRegister(pDevice, UART_BAUD_LOW_REG, (UINT8)(divisor & 0xFF));
    WriteRegister(pDevice, UART_LINE_CNTRL_REG, lineControl);

    WriteRegister(pDevice, UART_INT_ENABLE_REG, saveInterrupt);
    DBG_PRINT(SDDBG_TRACE, ("SDIO GPS Function: SetBaudRate, rate %d, divisor %d\n",
                            BaudRate, divisor));
    return SDIO_STATUS_SUCCESS;
}

/*
 * GpsIRQHandler - hamdle interrupts
*/
void GpsIRQHandler(PVOID pContext)
{
    PSDGPS_DEVICE pDevice;
    SDIO_STATUS   status = SDIO_STATUS_DEVICE_ERROR;
    UINT8         temp;
    int           max = 4;
    pDevice = (PSDGPS_DEVICE)pContext;
    DBG_PRINT(SDIO_GPS_TRACE_INT, ("+I\n"));

    while(1) {
        if (max-- < 0) break;
            /* read the ident register */
        status = ReadRegister(pDevice, UART_INT_IDENT_REG, &temp);
        if (!SDIO_SUCCESS(status)) {
            break;
        }
            /* INTPEND bit is zero indicates a pending interrupt */
        if (!(temp & UART_INTPEND)) {
                /* get the encoded interrupt value */
            switch (temp & UART_IID_MASK) {
                case UART_IID_RLS:
                        /* line status changed */
                    ReadRegister(pDevice, UART_LINE_STATUS_REG, &temp);
                    DBG_PRINT(SDIO_GPS_TRACE_INT, ("+LS 0x%X\n", (UINT)temp));
                    if (temp & UART_LSR_DR) {
                        GpsReceive(pDevice);
                    }
                    break;
                case UART_IID_RDA:
                      /* handle receive */
                    GpsReceive(pDevice);
                    break;
                case UART_IID_CTI:
                        /* receiver timeout? */
                    GpsReceive(pDevice);
                    DBG_PRINT(SDIO_GPS_TRACE_INT, ("+CTI\n"));
                    break;
                case UART_IID_THRE:
                        /* transmitter empty */
                    GpsTransmit(pDevice);
                    break;
                case UART_IID_MS:
                        /* modem status */
                    DBG_PRINT(SDIO_GPS_TRACE_INT, ("SDIO GPS Function: modem status change int \n"));
                    break;
                default:
                    break;
            }
        } else {
                /* no interrupts pending */
            break;
        }
    }

        /* ack the interrupt */
    status = SDLIB_IssueConfig(pDevice->pSDDevice,SDCONFIG_FUNC_ACK_IRQ,NULL,0);

    DBG_PRINT(SDIO_GPS_TRACE_INT, ("-I\n"));

}

/*
 * WriteRegister - write an 8-bit register
*/
SDIO_STATUS WriteRegister(PSDGPS_DEVICE pDevice, UINT reg, UINT8 Data) {
    return SDLIB_IssueCMD52(pDevice->pSDDevice,SDDEVICE_GET_SDIO_FUNCNO(pDevice->pSDDevice),
                    ((pDevice)->UartRegOffset + (reg)),&Data,1,TRUE);
}

/*
 * WriteRegister - write an 8-bit register aysnchronously
*/
SDIO_STATUS WriteRegisterAsynch(PSDGPS_DEVICE pDevice, UINT reg, UINT8 Data, PSDREQUEST pReq)
{
    if (NULL == pReq) {
        return SDIO_STATUS_NO_RESOURCES;
    }

    SDLIB_SetupCMD52Request(SDDEVICE_GET_SDIO_FUNCNO(pDevice->pSDDevice),
                            ((pDevice)->UartRegOffset + (reg)),
                            TRUE,
                            Data,
                            pReq);
    pReq->Flags |= SDREQ_FLAGS_TRANS_ASYNC;
    pReq->pCompletion = TxCompletion;
    pReq->pCompleteContext = (PVOID)pDevice;

    return SDDEVICE_CALL_REQUEST_FUNC(pDevice->pSDDevice, pReq);
}

/*
 * TxCompletion - completion routine for WriteAsynch
*/
static void TxCompletion(PSDREQUEST pReq)
{
     /*  nothing to do
    PSDGPS_DEVICE pDevice;
    pDevice = (PSDGPS_DEVICE)pReq->pCompleteContext;
    */
}