www.pudn.com > uart.zip > uart.c




#include 
#include 

#include    /* printk() */
#include 
#include        /* everything... */
#include     /* error codes */
#include     /* size_t */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include  


/* The maximum write buffer */
#define _MAX_BUF_                       256
/* The maximun size of the DECT Base frame */
#define _MAX_DECT_                      30
/* Byte data mask */
#define _BYT_MASK_                      0xff
/* Default UART baudrate */
#define DEFAULT_BAUDRATE		        19200
/* Read UART register */
#define _UART_REG_READ_(base, _reg)		\
	*((volatile unsigned long *)(base + (_reg)))
/* Write UART register */	
#define _UART_REG_WRITE_(base, _reg, _val)      \
	*((volatile unsigned long *)(base + (_reg))) = (_val)

/* Data structure for UART baudrate */
typedef struct _UART_RATE_ENTRY_
{
	int	rate;
	unsigned long div;
} UART_RATE_ENTRY, *PUART_RATE_ENTRY;

/* Function point */
typedef void (*_FUNCPTR) (char *recvBuf, int cnt);

/* Data structure for UART object */
typedef struct _UART_OBJ_
{
	unsigned long status;
	unsigned long io_base;
	unsigned long ctrl;
	int	baudrate;
	int irq;
    _FUNCPTR func;
} UART_OBJ, *PUART_OBJ;

/* Receiving buffer for UART I/O */
typedef struct 
{
    int 	cnt;
    char 	buf[32];
} UART_RECV;

/* UART baudrate value */
const UART_RATE_ENTRY rate_tab[] =
{
	{1200,		UART_1200bps_DIVISOR},
	{2400,		UART_2400bps_DIVISOR},
	{9600,		UART_9600bps_DIVISOR},
	{14400,		UART_14400bps_DIVISOR},
	{19200,		UART_19200bps_DIVISOR},
	{38400,		UART_38400bps_DIVISOR},
	{57600,		UART_57600bps_DIVISOR},
	{115200,	UART_115200bps_DIVISOR}
};

/* Global variable declaration */
const int rate_option = sizeof(rate_tab) / sizeof(UART_RATE_ENTRY);
UART_OBJ uartObj[2] = {0};
UART_RECV recv = {0};


/*******************************************************************************
Description:
   Set baudrate for the UART device.
Arguments:
Note:
*******************************************************************************/
void uart_set_baudrate (PUART_OBJ uart)
{
	unsigned long lcr_h, i;

    for (i = 0; i < rate_option; i++)
        if (rate_tab[i].rate == uart->baudrate) 
            break;
		
	if (i == rate_option)
	    printk("DECTBase Driver: UART1 Baudrate out of range!\n");
	else
	{
    	/* Save lcr_h */
    	lcr_h = _UART_REG_READ_(uart->io_base, UART_LCR_H_REG);
    
    	_UART_REG_WRITE_(uart->io_base, UART_LCR_M_REG, rate_tab[i].div >> 8);
    	_UART_REG_WRITE_(uart->io_base, UART_LCR_L_REG, rate_tab[i].div);
    
    	/* Write lcr_h to update the lcr register */
    	_UART_REG_WRITE_(uart->io_base, UART_LCR_H_REG, lcr_h);
    }
    
    return;
}


/*******************************************************************************
Description:
   Init UART device using the default value.
Arguments:
Note:
*******************************************************************************/
void uart_init(PUART_OBJ uart)
{
	/* Set baudrate */
	uart_set_baudrate(uart);

	/* Set default line mode */
	_UART_REG_WRITE_(uart->io_base, UART_LCR_H_REG, UART_WLEN_8BITS);
		
	/* Enable uart port */
	_UART_REG_WRITE_(uart->io_base, UART_CR_REG, UART_PORT_EN | UART_RX_INT_EN);
	
	/* Enable interrupt controller */
	ADM5120_INTC_REG(IRQ_ENABLE_REG) = ADM5120_INTC_REG(IRQ_ENABLE_REG) | (1 << uart->irq);
}


/*******************************************************************************
Description:
   Init UART device using the default value.
Arguments:
Note:
*******************************************************************************/
void uart_irq_hd(int irq, void *dev_id, struct pt_regs *regs)
{
    PUART_OBJ uart = (PUART_OBJ)dev_id;
    unsigned long status;
          
    status = _UART_REG_READ_(uart->io_base, UART_IIR_REG);
    
    if (status & UART_RX_INT)
    {
        recv.buf[recv.cnt++] = _UART_REG_READ_(uart->io_base, UART_DR_REG) & _BYT_MASK_;
        
#ifdef _DRV_DEBUG_
        {
            int db = recv.cnt - 1;
            printk("[R:0x%.2x]\n", recv.buf[db]);
        }
#endif
        
        /* If this is garbage, clean buffer, and do not thing. */
        if (recv.cnt == 2 && (recv.buf[1] < 0 || recv.buf[1] > _MAX_DECT_))
        {
            memset(&recv, 0, sizeof(recv));
            return;
        }
        
        /***************************************************************/
        /* workaround for some error packets */
        if (recv.cnt == 2)
        {
            switch (recv.buf[0])
            {
            case 0x02:
            case 0x04:
            case 0x05:
            case 0x06:
            case 0x13:
            case 0x14:
            case 0x15:
            case 0x40:
            case 0x42:
            case 0x4f:
            case 0x0d:
                recv.buf[1] = 0;
                break;
            default:
                break;
            }
        }
        /***************************************************************/

        /* After receive the last byte we will return dect buffer to upper layer. */
        if ((recv.cnt - 2) == recv.buf[1])
        {
            /* Handle this DECT frame. */
            uart->func(recv.buf, recv.cnt);
            /* Reset the data buffer. */ 
            memset(&recv, 0, sizeof(recv));
        }
    }
}


/*******************************************************************************
Description:
   Write the data to UART.
Arguments:
Note:
*******************************************************************************/
int uart_write(int uart_n, const char *buf, size_t count)
{
    PUART_OBJ uart = &uartObj[uart_n];
    unsigned long uartfr;
    char tmp_buf[_MAX_BUF_] = {0};
    int num, i = 0;
    
    if (count > _MAX_BUF_)
        num = _MAX_BUF_;
    else
        num = count;
        
    memcpy(tmp_buf, buf, num);

    while(1)
    {
	    uartfr = _UART_REG_READ_(uart->io_base, UART_FR_REG);

	    if (!(uartfr & UART_TX_FIFO_EMPTY)) continue;
            
#ifdef _DRV_DEBUG_
        printk("[W:0x%.2x]\n", tmp_buf[i]);
#endif
	    _UART_REG_WRITE_(uart->io_base, UART_DR_REG, (int)tmp_buf[i++]);
	    
	    if (i >= num) break;
	}

    return i;
}


/*******************************************************************************
Description:
   Open the UART device.
Arguments:
Note:
*******************************************************************************/
int uart_open(int num, _FUNCPTR callback)
{
    PUART_OBJ uart;
       
    if (num < 0 || num > 1)
    {
        printk("DECTBase Driver: UART1 major number error!\n");
        return -1;
    }
    
    /* Already init */
    if (uartObj[num].status)
        return 0;
        
    uart = &uartObj[num];  
	uart->baudrate = DEFAULT_BAUDRATE;
	uart->status = 1;
	uart->ctrl = 0;
	uart->func = callback;
	
	if (num == 0)
	{
	    uart->irq = INT_LVL_UART0;
	    uart->io_base = PA2VA(UART0_BASE);
	}
	else
	{
	    uart->irq = INT_LVL_UART1;
	    uart->io_base = PA2VA(UART1_BASE);
	}
	
	/* Register irq routine */
	request_irq(uart->irq, uart_irq_hd, SA_SHIRQ, NULL, uart);

	uart_init(uart);
	
    return 0;
}


/*******************************************************************************
Description:
   Close the UART device.
Arguments:
Note:
*******************************************************************************/
int uart_close(int num)
{
    PUART_OBJ uart = &uartObj[num];
    
    /* Disable hardware interrupt */
	ADM5120_INTC_REG(IRQ_DISABLE_REG) = ADM5120_INTC_REG(IRQ_DISABLE_REG) | (1 << uart->irq);
	
    /* Disable irq request */
    free_irq(uart->irq, uart);

    /* Reset data structure */
    memset(uart, 0, sizeof(UART_OBJ));
    
    return 0;
}