www.pudn.com > S3c2410bsp.zip > s3c2410xSio.c


/* s3c2410xSio.c - Samsung S3C2410X serial driver */

#include "copyright_wrs.h"



#include "vxWorks.h"
#include "sioLib.h"
#include "intLib.h"
#include "errno.h"
#include "s3c2410xSio.h"
#include "ioLib.h"

#define S3C2410X_BAUD_MIN         1200
#define S3C2410X_BAUD_MAX         460860
#define S3C2410X_SIO_DEFAULT_BAUD 9600

#ifndef s3c2410x_UART_REG
#define s3c2410x_UART_REG(pChan, reg) \
	(*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg)))
#endif

#ifndef S3C2410X_SIO_REG_READ
#define S3C2410X_SIO_REG_READ(pChan, reg, result) \
    ((result) = (*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg))))
#endif   

#ifndef S3C2410X_SIO_REG_WRITE
#define S3C2410X_SIO_REG_WRITE(pChan, reg, data) \
    ((*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg))) = (data))
#endif   

#ifndef s3c2410x_UART_REG_READ
#define s3c2410x_UART_REG_READ(pChan, reg, result) \
	(result) = (s3c2410x_UART_REG(pChan, reg))
#endif

#ifndef s3c2410x_UART_REG_WRITE
#define s3c2410x_UART_REG_WRITE(pChan, reg, data) \
	(s3c2410x_UART_REG(pChan, reg)) = (data)
#endif

#ifndef s3c2410x_UART_REG_BIT_SET
#define s3c2410x_UART_REG_BIT_SET(pChan, reg, data) \
	(s3c2410x_UART_REG(pChan, reg)) |= (data)
#endif

#ifndef s3c2410x_UART_REG_BIT_CLR
#define s3c2410x_UART_REG_BIT_CLR(pChan, reg, data) \
	(s3c2410x_UART_REG(pChan, reg)) &= ~(data)
#endif

#ifndef s3c2410x_INT_REG_READ
#define s3c2410x_INT_REG_READ(reg,result) \
	((result) = *(volatile UINT32 *)(reg))
#endif

#ifndef s3c2410x_INT_REG_WRITE
#define s3c2410x_INT_REG_WRITE(reg,data) \
	(*((volatile UINT32 *)(reg)) = (data))
#endif

#define _IS_USER_FIFO_


/* for backward compatibility */

#ifndef    SIO_HUP
#   define SIO_OPEN    0x100A    
#   define SIO_HUP     0x100B   
#endif



LOCAL int    s3c2410xTxStartup (SIO_CHAN * pSioChan);
LOCAL int    s3c2410xCallbackInstall (SIO_CHAN *pSioChan, int callbackType,
                                      STATUS (*callback)(), void *callbackArg);
LOCAL int    s3c2410xPollOutput (SIO_CHAN *pSioChan, char    outChar);
LOCAL int    s3c2410xPollInput (SIO_CHAN *pSioChan, char *thisChar);
LOCAL int    s3c2410xIoctl (SIO_CHAN *pSioChan, int request, void *arg);
LOCAL STATUS dummyCallback (void);

/* local variables */

LOCAL    SIO_DRV_FUNCS s3c2410xSioDrvFuncs =
    {
    s3c2410xIoctl,
    s3c2410xTxStartup,
    s3c2410xCallbackInstall,
    s3c2410xPollInput,
    s3c2410xPollOutput
    };

LOCAL BOOL s3c2410xIntrMode = FALSE;   

/******************************************************************************
*
* s3c2410xDevInit - initialize a S3C2410X_DUSART
*
*
* RETURNS: N/A
*/

void s3c2410xDevInit(S3C2410X_CHAN * pChan)
    {

    pChan->sio.pDrvFuncs    = &s3c2410xSioDrvFuncs;


    pChan->getTxChar     = dummyCallback;
    pChan->putRcvChar    = dummyCallback;
    

	S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_ULCON,(INFRA_RED_NONE | PARITY_NONE | ONE_STOP | WORD_LEN));
	S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UCON,0x005);
	#ifdef _IS_USER_FIFO_
	S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UFCON,0xd7);	
	#else
	S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UFCON,0x00);	
	#endif
	S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UMCON,0);


    s3c2410xIoctl ((SIO_CHAN *)pChan, SIO_MODE_SET, (void *)SIO_MODE_POLL);
    s3c2410xIoctl ((SIO_CHAN *)pChan, SIO_BAUD_SET, (void *)S3C2410X_SIO_DEFAULT_BAUD);


	

    }

/******************************************************************************
*
* s3c2410xDevInit2 - initialize a S3C2410X_DUSART, part 2
*
*
* RETURNS: N/A
* ARGSUSED
*/

void s3c2410xDevInit2
    (
    S3C2410X_CHAN * pChan        /* device to initialize */
    )
    {
    char      outchar = '\0';

	UINT32	tempUINT32;

    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_ULCON,(INFRA_RED_NONE | PARITY_NONE | ONE_STOP | WORD_LEN));

    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UTXBUF,outchar);

    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UCON,UCON_RX|UCON_TX|0x80);
	
	s3c2410x_INT_REG_READ(S3C2410X_INTSUBMSK,tempUINT32);
	switch((int)(pChan->regs))
	{
	case SERIAL_B_BASE_ADR:
		tempUINT32 &= ~((1<regs))
	{		
		case SERIAL_B_BASE_ADR:
			s3c2410x_INT_REG_WRITE(S3C2410X_SUBSRCPND, (1<putRcvChar) (pChan->putRcvArg, inChar);
    }    
    #else
    S3C2410X_SIO_REG_READ(pChan,S3C2410X_USTAT, status);
    if((status & USTAT_RX_READY) == USTAT_RX_READY)
    {
        S3C2410X_SIO_REG_READ(pChan,S3C2410X_URXBUF, inChar);
        (*pChan->putRcvChar) (pChan->putRcvArg, inChar);
    }
	#endif
	
}


static int sending = 0;		


/******************************************************************************
*
* s3c2410xIntTx - handle a channels transmitter-ready interrupt
*
* RETURNS: N/A
*/ 

void s3c2410xIntTx
    (
    S3C2410X_CHAN *    pChan        /* channel generating the interrupt */
    )
    {
    char      outChar;
    UINT32    status;
    FAST int     oldlevel; 	

	
    switch((int)(pChan->regs))
	{		
		case SERIAL_B_BASE_ADR:
			s3c2410x_INT_REG_WRITE(S3C2410X_SUBSRCPND, (1<getTxChar) (pChan->getTxArg, &outChar) != ERROR)
	{
		#ifdef _IS_USER_FIFO_
        S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
		while(1)
		{			

			S3C2410X_SIO_REG_READ(pChan,S3C2410X_UFSTAT, status);    
    		if((status & UFSTAT_TX_FULL) == UFSTAT_TX_FULL) 
				break;			

			if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) == ERROR) 
				break;			

			S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
		}
		#else
		S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
		#endif
    }	    
    intUnlock (oldlevel);
}

/********************

************************/
void    s3c2410xInt    (S3C2410X_CHAN *pChan)
{
	UINT32 intId;
	
	s3c2410x_INT_REG_READ(S3C2410X_SUBSRCPND , intId);

	if(intId & ((1<mode == SIO_MODE_INT)
	{
		intEnable(pChan->intLevelTx);

		s3c2410xIntTx(pChan);

		return OK;
	}
	else
	{
		return ERROR;
	}
    }

/******************************************************************************
*
* s3c2410xCallbackInstall - install ISR callbacks to get/put chars
*
*
* RETURNS: OK on success, or ENOSYS for an unsupported callback type.
*/ 

LOCAL int s3c2410xCallbackInstall
    (
    SIO_CHAN *    pSioChan,               
    int           callbackType,          
    STATUS        (*callback)(),          
    void *        callbackArg           
    )
    {
    S3C2410X_CHAN * pChan = (S3C2410X_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);
    }
    }

/*******************************************************************************
*
* s3c2410xPollOutput - 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 s3c2410xPollOutput
    (
    SIO_CHAN *pSioChan,
    char      outChar
    )
    {
    S3C2410X_CHAN * pChan = (S3C2410X_CHAN *)pSioChan;
    UINT32    status;


    S3C2410X_SIO_REG_READ (pChan, S3C2410X_USTAT, status);
    if ((status & USTAT_TX_READY) == 0x00)
        return (EAGAIN);

    S3C2410X_SIO_REG_WRITE(pChan, S3C2410X_UTXBUF, outChar);
	
    return (OK);
    }

/******************************************************************************
*
* s3c2410xPollInput - 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 s3c2410xPollInput
    (
    SIO_CHAN *    pSioChan,
    char *        thisChar
    )
    {
    S3C2410X_CHAN * pChan = (S3C2410X_CHAN *)pSioChan;
    UINT32    status;


    S3C2410X_SIO_REG_READ (pChan,S3C2410X_USTAT, status);

    if ((status & USTAT_RX_AVAIL) == 0x00)
        return (EAGAIN);    


    S3C2410X_SIO_REG_READ(pChan, S3C2410X_URXBUF, *thisChar);
	
    return (OK);
    }

/******************************************************************************
*
* s3c2410xModeSet - toggle between interrupt and polled mode
*
* RETURNS: OK on success, EIO on unsupported mode.
*/

LOCAL int s3c2410xModeSet
    (
    S3C2410X_CHAN * pChan,        /* channel */
    uint_t          newMode       /* new mode */
    )
    {
    UINT32    temp;
	UINT32	tempUINT32;

    if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))    
    	return (EIO);


    if ((newMode == SIO_MODE_INT) && (!s3c2410xIntrMode))
    	return (EIO);


    pChan->mode = newMode;

    if (pChan->mode == SIO_MODE_INT)
    {
    	switch((int)(pChan->regs))
		{	
		case SERIAL_B_BASE_ADR:
			s3c2410x_INT_REG_WRITE(S3C2410X_SUBSRCPND, ((1<intLevelRx);
		
        S3C2410X_SIO_REG_READ(pChan, S3C2410X_UCON, temp);
        temp &=UCON_RX_TX_RESET;    
        temp |= (UCON_RX|UCON_TX);
        S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UCON, temp);
		
		
		
		s3c2410x_INT_REG_READ(S3C2410X_INTSUBMSK,tempUINT32);		
		switch((int)(pChan->regs))
		{		
		case SERIAL_B_BASE_ADR:
			tempUINT32 &= ~((1<intLevelRx);

		s3c2410x_INT_REG_READ(S3C2410X_INTSUBMSK,tempUINT32);		
		switch((int)(pChan->regs))
		{		
		case SERIAL_B_BASE_ADR:
			tempUINT32 |= ((1<options == newOpts)
    return OK;


    switch (newOpts & CSIZE)
    {
    case CS5:
        dataBits = 0x00; break;
    case CS6:
        dataBits = 0x01; break;
    case CS7:
        dataBits = 0x02; break;
	case CS8:
    default:    
        dataBits = 0x03; break;
    }

    if (newOpts & STOPB)
        stopBits = 0x04;
    else
        stopBits = 0x00;

    switch (newOpts & (PARENB|PARODD))
    {
    case PARENB|PARODD:
            temp=PARITY_ODD;
        break;

    case PARENB:
        temp=PARITY_EVEN; 
        break;

    case PARODD:
        break;

    default:
    case 0:
        temp=PARITY_NONE ;/* no parity */
        break;
    }

    if (newOpts & CLOCAL)
    {
        hdweFlowCtrl = FALSE;
    }

    if ((newOpts & CREAD) == 0)
        rcvrEnable = FALSE;


    lvl = intLock ();

    
    S3C2410X_SIO_REG_READ(pChan, S3C2410X_ULCON, result);    
    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_ULCON,(result|dataBits|temp|stopBits));
    
    intUnlock (lvl);

    pChan->options = newOpts;

    return (OK);
    }

/*******************************************************************************
*
* s3c2410xIoctl - special device control
*
*
* RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
* request.
*/

LOCAL int s3c2410xIoctl
    (
    SIO_CHAN *    pSioChan,        /* device to control */
    int        request,        /* request code */
    void *    someArg            /* some argument */
    )
    {
    S3C2410X_CHAN *pChan = (S3C2410X_CHAN *) pSioChan;
    int     oldlevel;        /* current interrupt level mask */
    int     arg = (int)someArg;

 
    switch (request)
    {
    case SIO_BAUD_SET:
      

        if (arg == 0)
        return s3c2410xHup (pChan);

        

        if (arg < S3C2410X_BAUD_MIN || arg > S3C2410X_BAUD_MAX)
        {
        	return (EIO);
        }

            switch(arg)
                {
                case 1200:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_1200|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 2400:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_2400|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 4800:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_4800|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 9600:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_9600|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 19200:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_19200|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 38400:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_38400|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 57600:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_57600|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 115200:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_115200|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 230400:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_230400|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);

                case 460800:
                    oldlevel = intLock ();
                    S3C2410X_SIO_REG_WRITE(pChan,S3C2410X_UBRDIV,S3C2410X_CNT0_460800|S3C2410X_CNT1_VAL);
                    intUnlock (oldlevel);
                    pChan->baudRate=arg;
                    return (OK);
          
                default:
                    return(EIO);

                }
            break;

    case SIO_BAUD_GET:

            *(int *)arg = pChan->baudRate;
            break;

    case SIO_MODE_SET:


        return (s3c2410xModeSet (pChan, arg));

    case SIO_MODE_GET:
            

        *(int *)arg = pChan->mode;
        return (OK);

    case SIO_AVAIL_MODES_GET:


        *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL; 
        return (OK);

    case SIO_HW_OPTS_SET:


        return (s3c2410xOptSet (pChan, arg));

    case SIO_HW_OPTS_GET:


        *(int *)arg = pChan->options;
        return (OK);

    case SIO_HUP:


            if (pChan->options & HUPCL) 
                return (s3c2410xHup (pChan));
            return (OK);

    case SIO_OPEN:
            return (s3c2410xOpen (pChan)); 

    default:
        return (ENOSYS);
    }
    return (ENOSYS);
    }

/*******************************************************************************
*
* dummyCallback - dummy callback routine
*
* RETURNS: ERROR.
*/

LOCAL STATUS dummyCallback (void)
    {
    return (ERROR);
    }