www.pudn.com > nxplpc2204bsp.rar > lpc2204Sio.c


/* Copyright 1984-2001 Wind River Systems, Inc. */ 
#include "copyright_wrs.h" 
 
/* 
modification history 
-------------------- 
01o,27jul04,a_m  BSP定制 for 精英arm7开发板 
01c,30nov01,m_h  Save pChan->baudRate when setting baud 
01b,26apr01,m_h  convert tabs to spaces for readability 
01a,12apr01,m_h  created from snds100 template. 
*/ 
 
#include "vxWorks.h" 
#include "sioLib.h" 
#include "intLib.h" 
#include "errno.h" 
#include "lpc2210Sio.h" 
#include "ioLib.h" 
 
#define OFFSETRBR   0 
#define OFFSETTHR   0 
#define OFFSETIER   4 
#define OFFSETIIR   8 
#define OFFSETFCR   8 
#define OFFSETLCR   0x0C 
#define OFFSETLSR   0x14 
#define OFFSETSCR   0x1C 
#define OFFSETDLL   0 
#define OFFSETDLM   4 
 
#define UARTRBR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETRBR))) 
#define UARTTHR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETTHR))) 
#define UARTIER(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETIER))) 
#define UARTIIR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETIIR))) 
#define UARTFCR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETFCR))) 
#define UARTLCR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETLCR))) 
#define UARTLSR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETLSR))) 
#define UARTSCR(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETSCR))) 
#define UARTDLL(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETDLL))) 
#define UARTDLM(BaseAddress)    (*((volatile unsigned char *)((DWORD)BaseAddress+OFFSETDLM))) 
 
 
#define LPC2210_BAUD_MIN         1200 
#define LPC2210_BAUD_MAX         460860 
#define LPC2210_SIO_DEFAULT_BAUD 9600 
 
/* Hardware abstraction macros */ 
 
/* local defines  */ 
 
/* for backward compatibility */ 
 
/* forward static declarations */ 
 
LOCAL int    lpc2210TxStartup (SIO_CHAN * pSioChan); 
LOCAL int    lpc2210CallbackInstall (SIO_CHAN *pSioChan, int callbackType, 
                                      STATUS (*callback)(), void *callbackArg); 
LOCAL int    lpc2210PollOutput (SIO_CHAN *pSioChan, char    outChar); 
LOCAL int    lpc2210PollInput (SIO_CHAN *pSioChan, char *thisChar); 
LOCAL int    lpc2210Ioctl (SIO_CHAN *pSioChan, int request, void *arg); 
LOCAL STATUS dummyCallback (void); 
 
/* local variables */ 
 
LOCAL    SIO_DRV_FUNCS lpc2210DrvFuncs = 
{ 
    lpc2210Ioctl, 
    lpc2210TxStartup, 
    lpc2210CallbackInstall, 
    lpc2210PollInput, 
    lpc2210PollOutput 
}; 
 
LOCAL BOOL lpc2210IntrMode = FALSE;    /* interrupt mode allowed flag */ 
 
static int g_sending = 0;		/*  : added */	 
 
void lpc2210DevInit 
( 
    LPC2210_CHAN * pChan 
) 
{ 
    /* initialize each channel's driver function pointers */ 
    pChan->sio.pDrvFuncs    = &lpc2210DrvFuncs; 
 
    /* install dummy driver callbacks */ 
    pChan->getTxChar     = dummyCallback; 
    pChan->putRcvChar    = dummyCallback; 
     
    /* reset the chip */ 
    UARTLCR(pChan->regs) = 0x03;    /* 禁止访问分频因子寄存器且设置为8,1,n */ 
    UARTFCR(pChan->regs) = 0x87;    /* 初始化FIFO */ 
    /*UARTFCR(pChan->regs) = 0x06;  */   /* 禁止FIFO */ 
    UARTIER(pChan->regs) = 0x05;     /* 禁止发送中断,允许接收和状态中断 */ 
 
    /* setting polled mode is one way to make the device quiet */ 
    lpc2210Ioctl ((SIO_CHAN *)pChan, SIO_MODE_SET, (void *)SIO_MODE_POLL); 
    lpc2210Ioctl ((SIO_CHAN *)pChan, SIO_BAUD_SET, (void *)LPC2210_SIO_DEFAULT_BAUD); 
} 
 
void lpc2210DevInit2 
    ( 
    LPC2210_CHAN * pChan        /* device to initialize */ 
    ) 
{ 
    /* Interrupt mode is allowed */ 
    lpc2210IntrMode = TRUE; 
} 
 
/****************************************************************************** 
* 
* lpc2210UARTInt - handle a channel's interrupt 
* 
* RETURNS: N/A 
*/  
void lpc2210UARTInt 
    ( 
    LPC2210_CHAN *    pChan        /* channel generating the interrupt */ 
    ) 
{ 
    BYTE byteData; 
    DWORD dwIIR; 
    DWORD dwIntState; 
    FAST int oldlevel;    		/*  : added */ 
    BYTE temp; 
  
    oldlevel = intLock ();			/*  : added */ 
 
    dwIIR = UARTIIR(pChan->regs); 
    if (dwIIR & 0x1)            /* 没有挂起的中断*/ 
        return; 
 
    dwIntState = (dwIIR & 0x0E) >> 1; 
 
    switch(dwIntState) 
    { 
        case 3:             /* 线状态中断*/ 
            temp = UARTLSR(pChan->regs); 
            break; 
        case 2:         /* 接收到数据中断*/ 
        case 6: 
            while(UARTLSR(pChan->regs) & 0x01) 
            { 
                byteData = UARTRBR(pChan->regs); 
                (pChan->putRcvChar) (pChan->putRcvArg, byteData); 
            } 
            break; 
        case 1:         /* 发送数据中断*/ 
            if ((pChan->getTxChar) (pChan->getTxArg, &byteData) != ERROR) 
            { 
                UARTTHR(pChan->regs) = byteData; 
            }	 
            else 
            { 
                temp = UARTIER(pChan->regs); 
                temp &= ~0x02; 
                UARTIER(pChan->regs) = temp; 
                g_sending = 0; 
            } 
            break; 
        default: 
            break; 
    }	 
	 
    intUnlock (oldlevel);			/*  : added */ 
} 
 
	 
 
/****************************************************************************** 
* 
* lpc2210TxStartup - start the interrupt transmitter 
* 
* RETURNS: OK on success, ENOSYS if the device is polled-only, or 
* EIO on hardware error. 
*/ 
 
LOCAL int lpc2210TxStartup 
    ( 
    SIO_CHAN * pSioChan                 /* channel to start */ 
    ) 
{ 
    char      outChar;			/*  : added */ 
    FAST int     oldlevel;    	/*  : added */ 
 
    LPC2210_CHAN * pChan = (LPC2210_CHAN *)pSioChan; 
 
    if(g_sending == 1) 
        return OK; 
 
    oldlevel = intLock (); 
 
    UARTIER(pChan->regs) = UARTIER(pChan->regs) | 0x02; 
 
    g_sending = 1; 
    if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR) 
        UARTTHR(pChan->regs) = outChar; 
 
    intUnlock (oldlevel); 
 
    return (OK); 
} 
 
/****************************************************************************** 
* 
* lpc2210CallbackInstall - install ISR callbacks to get/put chars 
* 
* This driver allows interrupt callbacks for transmitting characters 
* and receiving characters. In general, drivers may support other 
* types of callbacks too. 
* 
* RETURNS: OK on success, or ENOSYS for an unsupported callback type. 
*/  
 
LOCAL int lpc2210CallbackInstall 
    ( 
    SIO_CHAN *    pSioChan,               /* channel */ 
    int           callbackType,           /* type of callback */ 
    STATUS        (*callback)(),          /* callback */ 
    void *        callbackArg             /* parameter to callback */ 
    ) 
    { 
    LPC2210_CHAN * pChan = (LPC2210_CHAN *)pSioChan; 
 
    switch (callbackType) 
    { 
    case SIO_CALLBACK_GET_TX_CHAR: 
        pChan->getTxChar    = callback; 
        pChan->getTxArg     = callbackArg; 
        return (OK); 
 
    case SIO_CALLBACK_PUT_RCV_CHAR: 
        pChan->putRcvChar    = callback; 
        pChan->putRcvArg     = callbackArg; 
        return (OK); 
 
    default: 
        return (ENOSYS); 
    } 
    } 
 
/******************************************************************************* 
* 
* lpc2210PollOutput - output a character in polled mode 
* 
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN 
* if the output buffer if full. ENOSYS if the device is 
* interrupt-only. 
*/ 
LOCAL int lpc2210PollOutput 
    ( 
    SIO_CHAN *pSioChan, 
    char      outChar 
    ) 
{ 
    LPC2210_CHAN * pChan = (LPC2210_CHAN *)pSioChan; 
    UINT32    status; 
 
    /* is the transmitter ready to accept a character? */ 
 
    status = UARTLSR(pChan->regs); 
    if ((status & (1<<5)) == 0) 
        return (EAGAIN); 
 
    /* write out the character */ 
    UARTTHR(pChan->regs) = outChar; 
    return (OK); 
} 
 
/****************************************************************************** 
* 
* lpc2210PollInput - poll the device for input 
* 
* RETURNS: OK if a character arrived, EIO on device error, EAGAIN 
* if the input buffer if empty, ENOSYS if the device is 
* interrupt-only. 
*/ 
LOCAL int lpc2210PollInput 
    ( 
    SIO_CHAN *    pSioChan, 
    char *        thisChar 
    ) 
{ 
    LPC2210_CHAN * pChan = (LPC2210_CHAN *)pSioChan; 
    UINT32    status; 
 
    status = UARTLSR(pChan->regs); 
    if ((status & 1) == 0x00) 
        return (EAGAIN);    /* no input available at this time */ 
 
    /* got a character */ 
    *thisChar = (char)UARTRBR(pChan->regs); 
 
    return (OK); 
} 
 
LOCAL int lpc2210ModeSet 
    ( 
    LPC2210_CHAN * pChan,        /* channel */ 
    uint_t          newMode       /* new mode */ 
    ) 
{ 
    UINT32    temp; 
 
    if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))     
        return (EIO); 
 
    /* Don't enter interrupt mode unless it is allowed. */ 
    if ((newMode == SIO_MODE_INT) && (!lpc2210IntrMode)) 
        return (EIO); 
 
    /* set the new mode */ 
    pChan->mode = newMode; 
 
    if (pChan->mode == SIO_MODE_INT) 
    { 
        temp = UARTFCR(pChan->regs); 
        temp |= 6;                                      /*Reset RX and TX mode bits*/ 
        UARTFCR(pChan->regs) = temp; 
        intEnable(pChan->intLevel); 
    } 
    else 
    { 
        temp = UARTFCR(pChan->regs); 
        temp |= 6;                                      /*Reset RX and TX mode bits*/ 
        UARTFCR(pChan->regs) = temp; 
        intDisable (pChan->intLevel); 
    } 
     
    return (OK); 
} 
 
LOCAL STATUS lpc2210Hup 
    ( 
    LPC2210_CHAN * pChan     /* pointer to channel */ 
    ) 
{ 
    FAST int     oldlevel;    /* current interrupt level mask */ 
 
    oldlevel = intLock (); 
    intUnlock (oldlevel); 
 
    return (OK); 
}     
 
/******************************************************************************* 
* 
* lpc2210Open - Set the modem control lines  
* 
* Set the modem control lines(RTS, DTR) TRUE if not already set.   
* 
* RETURNS: OK 
*/ 
LOCAL STATUS lpc2210Open 
    ( 
    LPC2210_CHAN * pChan     /* pointer to channel */ 
    ) 
{ 
    FAST int     oldlevel;    /* current interrupt level mask */ 
 
    oldlevel = intLock (); 
 
    /* set RTS and DTR active */ 
 
/*    SNGKS32C_SIO_REG_WRITE(pChan, SNGKS32C_USTAT, USTAT_DTR_HIGH);    */ 
    intUnlock (oldlevel); 
 
    return (OK); 
} 
 
LOCAL int lpc2210OptSet 
    ( 
    LPC2210_CHAN * pChan,        /* channel */ 
    uint_t    newOpts              /* new options */ 
    ) 
{ 
    UINT8 dataBits = 0x03; 
    UINT8 stopBits = 0x00; 
    int  lvl; 
    UINT8 temp=PARITY_NONE; 
    UINT32 result;     
 
    if (pChan == NULL || newOpts & 0xffffff00) 
        return EIO; 
 
    /* do nothing if options already set */ 
    if (pChan->options == newOpts) 
        return OK; 
 
    /* ignore requests for unsupported options */ 
 
    /* decode individual request elements */ 
 
    switch (newOpts & CSIZE) 
    { 
        case CS5: 
            dataBits = 0x00; break; 
        case CS6: 
            dataBits = 0x01; break; 
        case CS7: 
            dataBits = 0x02; break; 
        default: 
        case CS8: 
            dataBits = 0x03; break; 
    } 
 
    if (newOpts & STOPB) 
        stopBits = 0x01; 
    else 
        stopBits = 0x00; 
 
    switch (newOpts & (PARENB|PARODD)) 
    { 
        case PARENB|PARODD: 
            /* enable odd parity */ 
            temp=PARITY_ODD; 
            break; 
 
        case PARENB: 
            /* enable even parity */ 
            temp=PARITY_EVEN;  
            break; 
 
        case PARODD: 
            /* invalid mode, not normally used. */ 
            break; 
 
        default: 
        case 0: 
            temp=PARITY_NONE ;/* no parity */ 
            break; 
    } 
 
    lvl = intLock (); 
    /* 
     * Reset the device according to dataBits, stopBits, hdweFlowCtrl, 
     * rcvrEnable, and parity selections. 
     */ 
    result = UARTLCR(pChan->regs);    
    result &= 0xC0; 
    UARTLCR(pChan->regs) = result | dataBits | (stopBits<<2) | (temp<<3); 
 
    intUnlock (lvl); 
 
    pChan->options = newOpts; 
 
    return (OK); 
} 
 
/******************************************************************************* 
* 
* lpc2210Ioctl - special device control 
* 
* This routine handles the IOCTL messages from the user. It supports commands  
* to get/set baud rate, mode(INT,POLL), hardware options(parity, number of  
* data bits) and modem control(RTS/CTS and DTR/DSR handshakes). 
* The ioctl commands SIO_HUP and SIO_OPEN are used to implement the HUPCL(hang 
* up on last close) function. 
* 
* As on a UNIX system, requesting a baud rate of zero is translated into 
* a hangup request.  The DTR and RTS lines are dropped.  This should cause 
* a connected modem to drop the connection.  The SIO_HUP command will only 
* hangup if the HUPCL option is active.  The SIO_OPEN function will raise 
* DTR and RTS lines whenever it is called. Use the BAUD_RATE=0 function 
* to hangup when HUPCL is not active. 
* 
* The CLOCAL option will disable hardware flow control.  When selected, 
* hardware flow control is not used.  When not selected hardware flow control 
* is based on the RTS/CTS signals.  CTS is the clear to send input 
* from the other end.  It must be true for this end to begin sending new 
* characters.  In most drivers, the RTS signal will be assumed to be connected 
* to the opposite end's CTS signal and can be used to control output from 
* the other end.  Raising RTS asserts CTS at the other end and the other end 
* can send data.  Lowering RTS de-asserts CTS and the other end will stop 
* sending data. (This is non-EIA defined use of RTS). 
* 
* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed 
* request. 
*/ 
 
LOCAL int lpc2210Ioctl 
    ( 
    SIO_CHAN *    pSioChan,        /* device to control */ 
    int        request,        /* request code */ 
    void *    someArg            /* some argument */ 
    ) 
{ 
    LPC2210_CHAN *pChan = (LPC2210_CHAN *) pSioChan; 
    int     oldlevel;        /* current interrupt level mask */ 
    DWORD arg = (DWORD)someArg; 
     
    switch (request) 
    { 
        case SIO_BAUD_SET: 
        { 
            DWORD Fdiv = (Fpclk / 16) / arg; 
            DWORD temp = 0; 
             
            if (arg == 0) 
                return lpc2210Hup (pChan); 
 
            if (arg < LPC2210_BAUD_MIN || arg > LPC2210_BAUD_MAX) 
            { 
                return (EIO); 
            } 
 
            oldlevel = intLock (); 
            temp = UARTLCR(pChan->regs); 
            UARTLCR(pChan->regs) = temp | 0x80; 
            U0DLM = Fdiv / 256;							 
            U0DLL = Fdiv % 256; 
            UARTLCR(pChan->regs) = temp; 
            intUnlock(oldlevel); 
            pChan->baudRate = arg; 
            return (OK); 
        } 
            break; 
 
        case SIO_BAUD_GET: 
            /* Get the baud rate and return OK */ 
            *(DWORD *)arg = pChan->baudRate; 
            break; 
 
        case SIO_MODE_SET: 
            return (lpc2210ModeSet (pChan, arg)); 
 
        case SIO_MODE_GET: 
            *(int *)arg = pChan->mode; 
            return (OK); 
 
        case SIO_AVAIL_MODES_GET: 
            /* Get the available modes and return OK.  */ 
            *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;  
            return (OK); 
 
        case SIO_HW_OPTS_SET: 
            return (lpc2210OptSet (pChan, arg)); 
 
        case SIO_HW_OPTS_GET: 
            /* 
             * Optional command to get the hardware options (as defined 
             * in sioLib.h). Return OK or ENOSYS if this command is not 
             * implemented.  Note: if this command is unimplemented, it 
             * will be assumed that the driver options are CREAD | CS8 
             * (e.g., eight data bits, one stop bit, no parity, ints enabled). 
             */ 
            *(int *)arg = pChan->options; 
            return (OK); 
 
        case SIO_HUP: 
            /* check if hupcl option is enabled */ 
            if (pChan->options & HUPCL)  
                return (lpc2210Hup (pChan)); 
            return (OK); 
 
        case SIO_OPEN: 
            return (lpc2210Open (pChan)); /* always open */ 
 
        default: 
            return (ENOSYS); 
    } 
    return (ENOSYS); 
} 
 
/******************************************************************************* 
* 
* dummyCallback - dummy callback routine 
* 
* RETURNS: ERROR. 
*/ 
 
LOCAL STATUS dummyCallback (void) 
    { 
    return (ERROR); 
    }