📄 uart.c
字号:
#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h> /* printk() */#include <linux/slab.h>#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/poll.h>#include <linux/ioport.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/param.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/irq.h>#include <asm/am5120/am5120.h> /* 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -