• ARM-Linux S5PV210 UART驱动(3)----串口核心层、关键结构体、接口关系


          尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现tty_operations其中的成员函数,但是Linux已经在文件serial_core.c中实现了UART设备的通用tty驱动层,称为串口核心层,这样,UART驱动的主要任务变成了实现serial_core.c中定义的一组uart_xxx接口而非tty_xxx接口。    

      uart设备是继tty_driver的又一层封装.实际上uart_driver就是对应tty_driver.在它的操作函数中,将操作转入uart_port.在写操作的时候,先将数据放入一个叫做circ_buf的环形缓存区.然后uart_port从缓存区中取数据,将其写入到串口设备中.当uart_port从serial设备接收到数据时,会将设备放入对应line discipline的缓存区中.这样.用户在编写串口驱动的时候,只先要注册一个uart_driver.它的主要作用是定义设备节点号.然后将对设备的各项操作封装在uart_port.驱动工程师没必要关心上层的流程,只需按硬件规范将uart_port中的接口函数完成就可以了.

    1.下图描述了串行系统间的层次结构关系,可以概括为:用户应用层 --> 线路规划层 --> TTY层 --> 底层驱动层 --> 物理硬件层

     

    2.下图是串口核心层在整个tty源文件关系及数据流向中的位置:

      其中的xxx_uart.c在此处就是drivers/serial/samsung.c和s5pv210.c

    3.接口关系:

    从接口关系图可以看出,用户对uart设备操作的调用关系非常简单,

    file_operations => [tty_ldisc_ops] => tty_operations => uart ops

    其中tty_ldisc_ops线路规程并不是必要的,依赖于应用层设置是否使用ldisc处理数据。

    4.UART驱动的总图:

     

     5.uart驱动常用的数据结构表示如下:

    6.Uart驱动程序主要围绕三个关键的数据结构展开(include/linux/serial_core.h中定义):

       UART特定的驱动程序结构定义:struct uart_driver s3c24xx_uart_drv;

      UART端口结构定义: struct s3c24xx_uart_port s3c24xx_serial_ports

      UART相关操作函数结构定义: struct uart_ops s3c24xx_serial_ops;

     【1】uart_driver 封装了tty_driver,使得底层的UART驱动无需关心tty_driver

    struct uart_driver {
        struct module        *owner;
        const char        *driver_name;
        const char        *dev_name;
        int             major;
        int             minor;
        int             nr;
        struct console        *cons;
    
        /*
         * these are private; the low level driver should not
         * touch these; they should be initialised to NULL
         */
        struct uart_state    *state;
        struct tty_driver    *tty_driver;
    };

     其中的uart_state是设备私有信息结构体,

     在uart_open()中:

     tty->driver_data = state;

     在其他uart_xxx()中:

     struct uart_state *state = tty->driver_data;

     就可以获取设备私有信息结构体。

    static struct uart_driver s3c24xx_uart_drv= {
          .owner           =THIS_MODULE,
          .dev_name      = "s3c2440_serial",  //具体设备名称
          .nr          =CONFIG_SERIAL_SAMSUNG_UARTS,  //定义有几个端口
          .cons             = S3C24XX_SERIAL_CONSOLE,  //console接口
           .driver_name  =S3C24XX_SERIAL_NAME,  //串口名:ttySAC
          .major            =S3C24XX_SERIAL_MAJOR,  //主设备号
          .minor            =S3C24XX_SERIAL_MINOR,   //次设备号
    };

     一个tty驱动必须注册/注销tty_driver,而一个UART驱动则变为注册/注销uart_driver,使用如下接口:

    int uart_register_driver(struct uart_driver *drv);

    void uart_unregister_driver(struct uart_driver *drv);

    【2】uart_port用于描述一个UART端口(直接对应于一个串口)的I/O端口或者IO内存地址等信息。

    struct uart_port {
        spinlock_t        lock;            /* port lock */
        unsigned long        iobase;            /* in/out[bwl] */
        unsigned char __iomem    *membase;        /* read/write[bwl] */
        unsigned int        (*serial_in)(struct uart_port *, int);
        void            (*serial_out)(struct uart_port *, int, int);
        unsigned int        irq;            /* irq number */
        unsigned long        irqflags;        /* irq flags  */
        unsigned int        uartclk;        /* base uart clock */
        unsigned int        fifosize;        /* tx fifo size */
        unsigned char        x_char;            /* xon/xoff char */
        unsigned char        regshift;        /* reg offset shift */
        unsigned char        iotype;            /* io access style */
        unsigned char        unused1;
    
    #define UPIO_PORT        (0)
    #define UPIO_HUB6        (1)
    #define UPIO_MEM        (2)
    #define UPIO_MEM32        (3)
    #define UPIO_AU            (4)            /* Au1x00 type IO */
    #define UPIO_TSI        (5)            /* Tsi108/109 type IO */
    #define UPIO_DWAPB        (6)            /* DesignWare APB UART */
    #define UPIO_RM9000        (7)            /* RM9000 type IO */
    
        unsigned int        read_status_mask;    /* driver specific */
        unsigned int        ignore_status_mask;    /* driver specific */
        struct uart_state    *state;            /* pointer to parent state */
        struct uart_icount    icount;            /* statistics */
    
        struct console        *cons;            /* struct console, if any */
    #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
        unsigned long        sysrq;            /* sysrq timeout */
    #endif
    
        upf_t            flags;
    
    #define UPF_FOURPORT        ((__force upf_t) (1 << 1))
    #define UPF_SAK            ((__force upf_t) (1 << 2))
    #define UPF_SPD_MASK        ((__force upf_t) (0x1030))
    #define UPF_SPD_HI        ((__force upf_t) (0x0010))
    #define UPF_SPD_VHI        ((__force upf_t) (0x0020))
    #define UPF_SPD_CUST        ((__force upf_t) (0x0030))
    #define UPF_SPD_SHI        ((__force upf_t) (0x1000))
    #define UPF_SPD_WARP        ((__force upf_t) (0x1010))
    #define UPF_SKIP_TEST        ((__force upf_t) (1 << 6))
    #define UPF_AUTO_IRQ        ((__force upf_t) (1 << 7))
    #define UPF_HARDPPS_CD        ((__force upf_t) (1 << 11))
    #define UPF_LOW_LATENCY        ((__force upf_t) (1 << 13))
    #define UPF_BUGGY_UART        ((__force upf_t) (1 << 14))
    #define UPF_NO_TXEN_TEST    ((__force upf_t) (1 << 15))
    #define UPF_MAGIC_MULTIPLIER    ((__force upf_t) (1 << 16))
    #define UPF_CONS_FLOW        ((__force upf_t) (1 << 23))
    #define UPF_SHARE_IRQ        ((__force upf_t) (1 << 24))
    /* The exact UART type is known and should not be probed.  */
    #define UPF_FIXED_TYPE        ((__force upf_t) (1 << 27))
    #define UPF_BOOT_AUTOCONF    ((__force upf_t) (1 << 28))
    #define UPF_FIXED_PORT        ((__force upf_t) (1 << 29))
    #define UPF_DEAD        ((__force upf_t) (1 << 30))
    #define UPF_IOREMAP        ((__force upf_t) (1 << 31))
    
    #define UPF_CHANGE_MASK        ((__force upf_t) (0x17fff))
    #define UPF_USR_MASK        ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
    
        unsigned int        mctrl;            /* current modem ctrl settings */
        unsigned int        timeout;        /* character-based timeout */
        unsigned int        type;            /* port type */
        const struct uart_ops    *ops;//UART操作集------->     
        unsigned int        custom_divisor;
        unsigned int        line;            /* port index */
        resource_size_t        mapbase;        /* for ioremap */
        struct device        *dev;            /* parent device */
        unsigned char        hub6;            /* this should be in the 8250 driver */
        unsigned char        suspended;
        unsigned char        unused[2];
        void            *private_data;        /* generic platform data pointer */
    };
    s3c24xx_uart_port 封装了uart_port:
    struct s3c24xx_uart_port {
        unsigned char            rx_claimed;
        unsigned char            tx_claimed;
        unsigned int            pm_level;
        unsigned long            baudclk_rate;
    
        unsigned int            rx_irq;
        unsigned int            tx_irq;
    
        struct s3c24xx_uart_info    *info;
        struct s3c24xx_uart_clksrc    *clksrc;
        struct clk            *clk;
        struct clk            *baudclk;
        struct uart_port        port;
    
    #ifdef CONFIG_CPU_FREQ
        struct notifier_block        freq_transition;
    #endif
        int                channelnum;
    };
    static struct s3c24xx_uart_port
        s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
        [0] = {//串口0;
            .port = {
                .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
                .iotype        = UPIO_MEM,
                .irq        = IRQ_S3CUART_RX0,
                .uartclk    = 0,
                .fifosize    = 16,//定义FIFO缓存区大小 
                .ops        = &s3c24xx_serial_ops,//串口相关操作函数
                .flags        = UPF_BOOT_AUTOCONF,
                .line        = 0,//线路
            }
        },
        [1] = {//串口1;
            .port = {
                .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
                .iotype        = UPIO_MEM,
                .irq        = IRQ_S3CUART_RX1,
                .uartclk    = 0,
                .fifosize    = 16,
                .ops        = &s3c24xx_serial_ops,
                .flags        = UPF_BOOT_AUTOCONF,
                .line        = 1,
            }
        },
    #if CONFIG_SERIAL_SAMSUNG_UARTS > 2
    
        [2] = {
            .port = {
                .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
                .iotype        = UPIO_MEM,
                .irq        = IRQ_S3CUART_RX2,
                .uartclk    = 0,
                .fifosize    = 16,
                .ops        = &s3c24xx_serial_ops,
                .flags        = UPF_BOOT_AUTOCONF,
                .line        = 2,
            }
        },
    #endif
    #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
        [3] = {
            .port = {
                .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
                .iotype        = UPIO_MEM,
                .irq        = IRQ_S3CUART_RX3,
                .uartclk    = 0,
                .fifosize    = 16,
                .ops        = &s3c24xx_serial_ops,
                .flags        = UPF_BOOT_AUTOCONF,
                .line        = 3,
            }
        }
    #endif
    };

    在xxx_probe()中:

    struct s3c24xx_uart_port *ourport;//s3c24xx_uart_port封装了uart_port
    ourport = &s3c24xx_serial_ports[dev->id];//s3c24xx_serial_ports是s3c24xx_uart_port结构体类型的

    【3】uart_ops定义了针对UART的一系列操作,

    /*
     * This structure describes all the operations that can be
     * done on the physical hardware.
     */
    struct uart_ops {
        unsigned int    (*tx_empty)(struct uart_port *);
        void        (*set_mctrl)(struct uart_port *, unsigned int mctrl);
        unsigned int    (*get_mctrl)(struct uart_port *);
        void        (*stop_tx)(struct uart_port *);
        void        (*start_tx)(struct uart_port *);
        void        (*send_xchar)(struct uart_port *, char ch);
        void        (*stop_rx)(struct uart_port *);
        void        (*enable_ms)(struct uart_port *);
        void        (*break_ctl)(struct uart_port *, int ctl);
        int        (*startup)(struct uart_port *);
        void        (*shutdown)(struct uart_port *);
        void        (*flush_buffer)(struct uart_port *);
        void        (*set_termios)(struct uart_port *, struct ktermios *new,
                           struct ktermios *old);
        void        (*set_ldisc)(struct uart_port *);
        void        (*pm)(struct uart_port *, unsigned int state,
                      unsigned int oldstate);
        int        (*set_wake)(struct uart_port *, unsigned int state);
        void        (*wake_peer)(struct uart_port *);
    
        /*
         * Return a string describing the type of the port
         */
        const char *(*type)(struct uart_port *);
    
        /*
         * Release IO and memory resources used by the port.
         * This includes iounmap if necessary.
         */
        void        (*release_port)(struct uart_port *);
    
        /*
         * Request IO and memory resources used by the port.
         * This includes iomapping the port if necessary.
         */
        int        (*request_port)(struct uart_port *);
        void        (*config_port)(struct uart_port *, int);
        int        (*verify_port)(struct uart_port *, struct serial_struct *);
        int        (*ioctl)(struct uart_port *, unsigned int, unsigned long);
    #ifdef CONFIG_CONSOLE_POLL
        void    (*poll_put_char)(struct uart_port *, unsigned char);
        int        (*poll_get_char)(struct uart_port *);
    #endif
    };
    //一般来说,实现下面的成员函数是UART驱动的主体工作
    static
    struct uart_ops s3c24xx_serial_ops ={ .pm =s3c24xx_serial_pm, //电源管理函数 .tx_empty = s3c24xx_serial_tx_empty, //检车发送FIFO缓冲区是否空 .get_mctrl = s3c24xx_serial_get_mctrl, //是否串口流控 .set_mctrl = s3c24xx_serial_set_mctrl, //是否设置串口流控cts .stop_tx =s3c24xx_serial_stop_tx, //停止发送 .start_tx =s3c24xx_serial_start_tx, //启动发送 .stop_rx =s3c24xx_serial_stop_rx, //停止接收 .enable_ms = s3c24xx_serial_enable_ms, //空函数 .break_ctl = s3c24xx_serial_break_ctl, //发送break信号 .startup =s3c24xx_serial_startup, //串口发送/接收,以及中断申请初始配置函数 .shutdown = s3c24xx_serial_shutdown, //关闭串口 .set_termios = s3c24xx_serial_set_termios,//串口clk,波特率,数据位等参数设置 .type = s3c24xx_serial_type, // CPU类型关于串口 .release_port =s3c24xx_serial_release_port, //释放串口 .request_port =s3c24xx_serial_request_port, //申请串口 .config_port = s3c24xx_serial_config_port, //串口的一些配置信息info .verify_port = s3c24xx_serial_verify_port, //串口检测 .wake_peer = s3c24xx_serial_wake_peer, };

     而在serial_core.c中定义了tty_operations的实例,包含uart_open();uart_close();uart_send_xchar()等成员函数,这些函数借助uart_ops结构体中的成员函数来完成具体的操作。

    static const struct tty_operations uart_ops = {
        .open        = uart_open,
        .close        = uart_close,
        .write        = uart_write,
        .put_char    = uart_put_char,
        .flush_chars    = uart_flush_chars,
        .write_room    = uart_write_room,
        .chars_in_buffer= uart_chars_in_buffer,
        .flush_buffer    = uart_flush_buffer,
        .ioctl        = uart_ioctl,
        .throttle    = uart_throttle,
        .unthrottle    = uart_unthrottle,
        .send_xchar    = uart_send_xchar,
        .set_termios    = uart_set_termios,
        .set_ldisc    = uart_set_ldisc,
        .stop        = uart_stop,
        .start        = uart_start,
        .hangup        = uart_hangup,
        .break_ctl    = uart_break_ctl,
        .wait_until_sent= uart_wait_until_sent,
    #ifdef CONFIG_PROC_FS
        .proc_fops    = &uart_proc_fops,
    #endif
        .tiocmget    = uart_tiocmget,
        .tiocmset    = uart_tiocmset,
    #ifdef CONFIG_CONSOLE_POLL
        .poll_init    = uart_poll_init,
        .poll_get_char    = uart_poll_get_char,
        .poll_put_char    = uart_poll_put_char,
    #endif
    };

    从下面的例子中可以看出串口核心层的tty_operations与uart_ops的关系:

    /*
     * This function is used to send a high-priority XON/XOFF character to
     * the device
     */
    static void uart_send_xchar(struct tty_struct *tty, char ch)
    {
        struct uart_state *state = tty->driver_data;
        struct uart_port *port = state->uart_port;
        unsigned long flags;
    
        if (port->ops->send_xchar)/*如果uart_ops中实现了send_xchar成员函数*/
            port->ops->send_xchar(port, ch);
        else {
            port->x_char = ch;
            if (ch) {
                spin_lock_irqsave(&port->lock, flags);
                port->ops->start_tx(port);
                spin_unlock_irqrestore(&port->lock, flags);
            }
        }
    }

    这个例子的调用关系如下:

    send_xchar  ---->  uart_send_xchar ---->  start_tx  --->  s3c24xx_serial_start_tx
  • 相关阅读:
    学生宿舍水电管理系统 产品需求评审(用户故事)
    nyoj 14-会场安排问题 (贪心)
    好看的鼠标hover效果
    JavaScript-三种弹窗方式
    博客园美化夜间模式
    js写个小时钟
    js获取时间,循环执行任务,延迟执行任务
    Bzoj1103 [POI2007]大都市meg
    POJ2155 Matrix
    POJ3625 Building Roads
  • 原文地址:https://www.cnblogs.com/hello2mhb/p/3341291.html
Copyright © 2020-2023  润新知