[国嵌攻略][132][串口驱动实现]
如何开发Linux驱动程序
一般情况下都会有现成的驱动程序,不需要从零开始开发驱动程序。所以Linux驱动开发主要分为两个步骤:1.读得懂驱动程序;2.写的了核心功能。
发送中断处理程序
发送中断处理函数在/drivers/serial/samsung.c的s3c24xx_serial_tx_chars
循环缓冲
struct circ_buf {
char *buf;
int head;
int tail;
};
存数据的时候移动head,取数据的时候移动tail。
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id){ //判断发送流控 struct s3c24xx_uart_port *ourport = id; struct uart_port *port = &ourport->port; if(port->x_char){ //是否有发送流控字符 //写入流控字符 wr_regb(port, S3C2410_UTXH, port->x_char); //修改发送计数 port->icount.tx++; //清除流控字符 port->x_char = 0; return IRQ_HANDLED; //中断处理完成 } //判断数据发送 struct circ_buf *xmit = &port->state->xmit; if(uart_circ_empty(xmit) || uart_tx_stopped(port)){ //是否循环缓冲为空或者串口停止发送 s3c24xx_serial_stop_tx(port); return IRQ_HANDLED; //中断处理完成 } //循环发送数据 int count = 256; while(!uart_circ_empty(xmit) && (count-- > 0)){ //是否循环缓冲不为空并且发送数据小于256字节 //判断循环缓冲 if(rd_regl(port, S3C2410_UFSTAT) & (1<<14)){ //是否循环缓冲已满 break; } //写入发送数据 wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]); //移动缓冲位置 xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); //循环移动尾部 //修改发送计数 port->icount.tx++; } //唤醒阻塞进程 if(uart_circ_chars_pending(xmit) < 256){ //是否循环缓冲数目小于256 uart_write_wakeup(port); } //关闭发送使能 if(uart_circ_empty(xmit)){ //是否循环缓冲为空 s3c24xx_serial_stop_tx(port); } return IRQ_HANDLED; //中断处理完成 }
接收中断处理程序
接收中断处理函数在/drivers/serial/samsung.c的s3c24xx_serial_rx_chars
static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id){ //循环接收数据 struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; int max_count = 64; while((max_count--) > 0){ //是否接收数据小于64字节 //判断接收缓冲 unsigned int ufstat; ufstat = rd_regl(port, S3C2410_UFSTAT); if((ufstat & 0x3F) == 0){ //是否接收缓冲为空 break; } //读取错误状态 unsigned int uerstat; uerstat = rd_regl(port, S3C2410_UERSTAT); //读取接收数据 unsigned int ch; ch = rd_regb(port, S3C2410_URXH); //写入接收缓冲 uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, TTY_NORMAL); } //写入线路规程 struct tty_struct *tty = port->state->port.tty; tty_flip_buffer_push(tty); return IRQ_HANDLED; //中断处理完成 }