zoukankan      html  css  js  c++  java
  • linux的串口驱动分析

    1、串口驱动中的数据结构

    • UART驱动程序结构:struct uart_driver  驱动

    • UART端口结构: struct uart_port  串口

    • UART相关操作函数结构: struct uart_ops   串口操作函数集

    • UART状态结构: struct uart_state 串口状态

    • UART信息结构: struct uart_info  串口信息

    2、串口驱动程序-初始化

    3、串口驱动分析-打开设备

    static int s3c24xx_serial_startup(struct uart_port *port)
    {
        struct s3c24xx_uart_port *ourport = to_ourport(port);
        int ret;
    
        dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)
    ",
            port->mapbase, port->membase);
    
        rx_enabled(port) = 1;
    
        ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
                  s3c24xx_serial_portname(port), ourport);
    
        if (ret != 0) {
            printk(KERN_ERR "cannot get irq %d
    ", ourport->rx_irq);
            return ret;
        }
    
        ourport->rx_claimed = 1;
    
        dbg("requesting tx irq...
    ");
    
        tx_enabled(port) = 1;
    
        ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
                  s3c24xx_serial_portname(port), ourport);
    
        if (ret) {
            printk(KERN_ERR "cannot get irq %d
    ", ourport->tx_irq);
            goto err;
        }
    
        ourport->tx_claimed = 1;
    
        dbg("s3c24xx_serial_startup ok
    ");
    
        /* the port reset code should have done the correct
         * register setup for the port controls */
    
        return ret;
    
     err:
        s3c24xx_serial_shutdown(port);
        return ret;
    }

    3、串口驱动程序-数据发送

    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
    ");
    
            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;
        }
    }
    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;
    
        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
        */
    
        if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
            s3c24xx_serial_stop_tx(port);
            goto out;
        }
    
        /* try and drain the buffer... */
    
        while (!uart_circ_empty(xmit) && count-- > 0) {
            if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
                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) < WAKEUP_CHARS)
            uart_write_wakeup(port);
    
        if (uart_circ_empty(xmit))
            s3c24xx_serial_stop_tx(port);
    
     out:
        return IRQ_HANDLED;
    }

    4、串口驱动程序-数据接收

    s3c24xx_serial_rx_chars(int irq, void *dev_id)
    {
        struct s3c24xx_uart_port *ourport = dev_id;
        struct uart_port *port = &ourport->port;
        struct tty_struct *tty = port->state->port.tty;
        unsigned int ufcon, ch, flag, ufstat, uerstat;
        int max_count = 64;
    
        while (max_count-- > 0) {
            ufcon = rd_regl(port, S3C2410_UFCON);
            ufstat = rd_regl(port, S3C2410_UFSTAT);
    
            if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
                break;
    
            uerstat = rd_regl(port, S3C2410_UERSTAT);
            ch = rd_regb(port, S3C2410_URXH);
    
            if (port->flags & UPF_CONS_FLOW) {
                int txe = s3c24xx_serial_txempty_nofifo(port);
    
                if (rx_enabled(port)) {
                    if (!txe) {
                        rx_enabled(port) = 0;
                        continue;
                    }
                } else {
                    if (txe) {
                        ufcon |= S3C2410_UFCON_RESETRX;
                        wr_regl(port, S3C2410_UFCON, ufcon);
                        rx_enabled(port) = 1;
                        goto out;
                    }
                    continue;
                }
            }
    
            /* insert the character into the buffer */
    
            flag = TTY_NORMAL;
            port->icount.rx++;
    
            if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
                dbg("rxerr: port ch=0x%02x, rxs=0x%08x
    ",
                    ch, uerstat);
    
                /* check for break */
                if (uerstat & S3C2410_UERSTAT_BREAK) {
                    dbg("break!
    ");
                    port->icount.brk++;
                    if (uart_handle_break(port))
                        goto ignore_char;
                }
    
                if (uerstat & S3C2410_UERSTAT_FRAME)
                    port->icount.frame++;
                if (uerstat & S3C2410_UERSTAT_OVERRUN)
                    port->icount.overrun++;
    
                uerstat &= port->read_status_mask;
    
                if (uerstat & S3C2410_UERSTAT_BREAK)
                    flag = TTY_BREAK;
                else if (uerstat & S3C2410_UERSTAT_PARITY)
                    flag = TTY_PARITY;
                else if (uerstat & (S3C2410_UERSTAT_FRAME |
                            S3C2410_UERSTAT_OVERRUN))
                    flag = TTY_FRAME;
            }
    
            if (uart_handle_sysrq_char(port, ch))
                goto ignore_char;
    
            uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,
                     ch, flag);
    
     ignore_char:
            continue;
        }
        tty_flip_buffer_push(tty);
    
     out:
        return IRQ_HANDLED;
    }

    附:linux系统中一般的流控技术

  • 相关阅读:
    MyBatis 内连接association 左外连接collection
    mybatis的基本配置:实体类、配置文件、映射文件、工具类 、mapper接口
    SpringMVC 使用Form标签库制作登录表单
    SpringMVC 配置过滤器解决中文乱码问题
    用户登录模块————账户安全问题
    HashSet,TreeSet和LinkedHashSet的区别
    SpringMVC 服务器端验证
    php输出(下载)文件
    26进制(字母)转十进制算法
    PHP之可变变量
  • 原文地址:https://www.cnblogs.com/chd-zhangbo/p/5410336.html
Copyright © 2011-2022 走看看