处理过几个串口的问题,这几天才稍微有了些时间来整理一下这一块的东西。

目录暂时大致分为以下几部分吧:

0,背景

1,串口驱动的结构

2,串口驱动的实现

3,关于TTY core

---------------------------------------------------------------------------------------------------

0,背景

往常review这块代码的时候,经常会被linux代码树中东一片西一片的uart,tty,serial device的代码搞的晕头转向。参照linux的驱动设备模型,其实串口驱动被一层层的完美的组装在一起。

对于用于,直接接触的是串口(serial interface),这是在计算机或嵌入式设备上一种应用非常广泛的一个设备接口。我们嘴里经常唠叨的UART其实只是串口通信的一种硬件实现方式而已,只不过最早最广泛使用的是这一种方式,所以大家听到的比较多。现在在串口后面的硬件实现方式越来越多:红外设备,usb设备等等,口那几根线后面接的chip的种类也越来越多,每种片子都对需要不同的驱动来工作。Linux领域的大师们就根据这些情况以及发展趋势,将一些通用的接口抽象出来,形成一个支持多种串行通信的子系统-TTY Core,当然也提供了通用的支持linux 设备模型的接口方便编写符合linux设备模型规范的驱动代码,:).

note:tty并不是完全指代串口的底层抽象,后面会稍加阐述。

1,串口驱动的结构

对于一般的UART串口,它的实现分为三层,最底层是TTY Core,中间是UART Core,最上层是特定的芯片驱动。

最上层的驱动使用UART Core的API简单直观的完成设备和驱动的注册,UART Core利用TTY Core中API最终实现设备驱动的注册。

 

2,串口驱动的实现

系统启动时,tty会作为一个char设备早早的注册到kernel(driver/char/tty_io.c),因为它是抽象的最纯粹的,:)。

UART Core没有作为一个模块注册到kernel,它实现了一些通用的API来供使用到UART的串口设备来调用。

最上层的芯片驱动就根据芯片的具体特性和参考串行通信的基本模式依赖UART Core的一些API实现相应的功能供用户层配置和使用。主要是实现一些tty_operations里面声明的一些回调函数,如果使用UART设备,有一些实现也会在UART Core里面实现。

struct tty_operations {
    struct tty_struct * (*lookup)(struct tty_driver *driver,
            struct inode *inode, int idx);
    int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
    void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
    int  (*open)(struct tty_struct * tty, struct file * filp);
    void (*close)(struct tty_struct * tty, struct file * filp);
    void (*shutdown)(struct tty_struct *tty);
    void (*cleanup)(struct tty_struct *tty);
    int  (*write)(struct tty_struct * tty,
              const unsigned char *buf, int count);
    int  (*put_char)(struct tty_struct *tty, unsigned char ch);
    void (*flush_chars)(struct tty_struct *tty);
    int  (*write_room)(struct tty_struct *tty);
    int  (*chars_in_buffer)(struct tty_struct *tty);
    int  (*ioctl)(struct tty_struct *tty, struct file * file,
            unsigned int cmd, unsigned long arg);
    long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
                 unsigned int cmd, unsigned long arg);
    void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
    void (*throttle)(struct tty_struct * tty);
    void (*unthrottle)(struct tty_struct * tty);
    void (*stop)(struct tty_struct *tty);
    void (*start)(struct tty_struct *tty);
    void (*hangup)(struct tty_struct *tty);
    int (*break_ctl)(struct tty_struct *tty, int state);
    void (*flush_buffer)(struct tty_struct *tty);
    void (*set_ldisc)(struct tty_struct *tty);
    void (*wait_until_sent)(struct tty_struct *tty, int timeout);
    void (*send_xchar)(struct tty_struct *tty, char ch);
    int (*tiocmget)(struct tty_struct *tty, struct file *file);
    int (*tiocmset)(struct tty_struct *tty, struct file *file,
            unsigned int set, unsigned int clear);
    int (*resize)(struct tty_struct *tty, struct winsize *ws);
    int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
#ifdef CONFIG_CONSOLE_POLL
    int (*poll_init)(struct tty_driver *driver, int line, char *options,
            void *rx_callback);
    int (*poll_get_char)(struct tty_driver *driver, int line);
    void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
    const struct file_operations *proc_fops;
};

3,关于TTY core

TTY在linux领域指的是终端,它可以指代任意终端设备,包括串口设备,console设备等等。

在/dev目录下,大家如果看到ttyS*就表示指代的是串口设备(S'serial' tty),而pty就指的是虚拟/伪终端设备(Pseudo tty)

TTY 子系统使用tty_driver来表示一个在它这个层次抽象出来的设备驱动,TTY实现了以下API来完成一个终端设备驱动的注册:

1)alloc_tty_driver()

2)tty_set_operations():建立tty entry point

3)tty_register_driver()

4)tty_register_device()

这样让一个终端驱动的注册变的十分清晰。

Logo

更多推荐