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; }