您的位置:首页 > 运维架构 > Linux

Linux串口驱动分析write

2015-04-27 22:49 302 查看
文章来自:http://blog.csdn.net/longwang155069/article/details/42780331

/*和read的分析过程一样, 我们首先分析tty_write*/  

  

/*最重要的就是do_tty_write函数。 前面都是一些合法性判断*/  

static ssize_t tty_write(struct file *file, const char __user *buf,size_t count, loff_t *ppos)  

{  

    struct inode *inode = file->f_path.dentry->d_inode;  

    struct tty_struct *tty = file_tty(file);  

    struct tty_ldisc *ld;  

    ssize_t ret;  

  

    if (tty_paranoia_check(tty, inode, "tty_write"))  

        return -EIO;  

    if (!tty || !tty->ops->write ||  

        (test_bit(TTY_IO_ERROR, &tty->flags)))  

            return -EIO;  

    /* Short term debug to catch buggy drivers */  

    if (tty->ops->write_room == NULL)  

        printk(KERN_ERR "tty driver %s lacks a write_room method.\n",  

            tty->driver->name);  

    ld = tty_ldisc_ref_wait(tty);  

    if (!ld->ops->write)  

        ret = -EIO;  

    else  

        /*调用tty_ldisc_N_TTY中的write函数*/  

        ret = do_tty_write(ld->ops->write, tty, file, buf, count);  

    tty_ldisc_deref(ld);  

    return ret;  

}  

  

/*调用uart_ops中的write函数*/  

static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,const unsigned char *buf, size_t nr)  

{  

    c = tty->ops->write(tty, b, nr);  

}  

  

static int uart_write(struct tty_struct *tty,const unsigned char *buf, int count)  

{  

    struct uart_state *state = tty->driver_data;  

    struct uart_port *port;  

    struct circ_buf *circ;  

    unsigned long flags;  

    int c, ret = 0;  

  

    /* 

     * This means you called this function _after_ the port was 

     * closed.  No cookie for you. 

     */  

    if (!state) {  

        WARN_ON(1);  

        return -EL3HLT;  

    }  

  

  /*取出所对应的port和循环缓冲buf*/  

    port = state->uart_port;  

    circ = &state->xmit;  

  

    if (!circ->buf)  

        return 0;  

  

    spin_lock_irqsave(&port->lock, flags);  

    while (1) {  

        /*计算循环缓冲的剩余空间 */  

        c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);  

        if (count < c)  

            c = count;  

        if (c <= 0)  

            break;  

        /*拷贝数据到循环缓冲区*/  

        memcpy(circ->buf + circ->head, buf, c);  

        /*调正循环缓冲head的位置*/  

        circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);  

        /*挪动buf当前的指针位置*/  

        buf += c;  

        count -= c;  

        ret += c;  

    }  

    spin_unlock_irqrestore(&port->lock, flags);  

  

    uart_start(tty);  

    return ret;  

}  

  

/*判断循环缓冲是否为空等。 然后调用注册驱动时的ops。 也就是s3c24xx_serial_ops*/  

static void __uart_start(struct tty_struct *tty)  

{  

    struct uart_state *state = tty->driver_data;  

    struct uart_port *port = state->uart_port;  

  

    if (!uart_circ_empty(&state->xmit) && state->xmit.buf &&  

        !tty->stopped && !tty->hw_stopped)  

        port->ops->start_tx(port);  

}  

  

/*判断端口是否使能,如果没使能则使能端口。 然后使能tx中断 

* 使能tx中断,则当有数据来时,则会触发tx中断,调用中断函数 

*/  

static void s3c24xx_serial_start_tx(struct uart_port *port)  

{  

    struct s3c24xx_uart_port *ourport = to_ourport(port);  

    static int a =1;//temp  

    if (port->line == 3) {  

//      printk("485_start_tx\n");  

  

        if(a){  

            s3c_gpio_cfgpin(S3C64XX_GPK(5), S3C_GPIO_SFN(1));  

            a=0;  

        }  

        gpio_set_value(S3C64XX_GPK(5), 1);  

    }  

    if (!tx_enabled(port)) {  

        if (port->flags & UPF_CONS_FLOW)  

            s3c24xx_serial_rx_disable(port);  

  

        enable_irq(ourport->tx_irq);  

        tx_enabled(port) = 1;  

    }  

}  

  

/*tx中断触发函数*/  

static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)  

{  

    struct s3c24xx_uart_port *ourport = id;  

    struct uart_port *port = &ourport->port;  

    struct circ_buf *xmit = &port->state->xmit;  

    int count = 256;  

  

    /*判断x_char是否存在,如果存在则写进UTXH寄存器。清空x_char*/  

    if (port->x_char) {  

        wr_regb(port, S3C2410_UTXH, port->x_char);  

        port->icount.tx++;  

        port->x_char = 0;  

        goto out;  

    }  

  

    /* if there isn't anything more to transmit, or the uart is now 

     * stopped, disable the uart and exit 

    */  

  

    /*判断循环缓冲是否为空,或者tx是否为停止状态。 如果是则停止发送*/  

    if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {  

        s3c24xx_serial_stop_tx(port);  

        goto out;  

    }  

  

    /* try and drain the buffer... */  

  

    /*当循环缓冲buff不为空,而且count是大于0的。则进入while循环*/  

    while (!uart_circ_empty(xmit) && count-- > 0) {  

          

        /*首先读取UFSTAT寄存器,然后判断tx_fifo是否为0.是则退出*/  

        if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)  

            break;  

  

        /*然后将循环buff中的数据读出到UTXH寄存器。然后设置tail的指针位置*/  

        wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);  

        xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);  

        port->icount.tx++;  

    }  

  

    /*判断循环缓冲中的数据是否小于WAKEUP_CHARS, 小于则启动接受*/  

    if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)  

        uart_write_wakeup(port);  

          

    /*如果循环buff为空,则停止发送,退出*/  

    if (uart_circ_empty(xmit))  

        s3c24xx_serial_stop_tx(port);  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: