linux tty 串口驱动

linux tty 串口驱动

TTY和serial port

tty:描述各类终端设备,主要包括tty核心、tty线路规划、tty驱动。tty核心是对整个tty设备的抽象,对用户空间提供统一的接口;tty线路规划是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。
serial port也是tty的一种,主要负责对串口硬件的驱动

  • 串口驱动结构如下图所示:

tty&serial port

核心数据结构

  • uart_driver

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct uart_driver{
    struct module *owner;
    const char *driver_name;
    const char *dev_name;
    int major;
    int minor;
    int nr; //uart_driver支持的串口个数
    struct console *cons;

    /*以下两个成员不在初始化uart_driver时赋值*/
    struct uart_state *state;
    struct tty_driver *tty_driver;
    };
    • tty_driver与上层tty联系,会在register_uart_driver的过程中被赋值
    • uart_state中的uart_port成员是uart_driver中真正与硬件打交道的成员,在register_uart_driver的过程中为其分配内存
  • uart_state

    1
    2
    3
    4
    5
    6
    7
    struct uart_state {
    struct tty_port port;
    int pm_state;
    struct circ_buf xmit;
    struct tasklet_struct tlet;
    struct uart_port *uart_port;
    };
    • 此结构体中最重要的成员就是uart_port,在register时会根据uart_driver->nr成员的值去为uart_state分配内存,存放驱动支持的串口物理信息
  • uart_port

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    struct uart_port {
    spinlock_t lock; /* 串口端口锁 */
    unsigned int iobase; /* IO端口基地址 */
    unsigned char __iomem *membase; /* IO内存基地址,经映射(如ioremap)后的IO内存虚拟基地址 */
    unsigned int irq; /* 中断号 */
    unsigned int uartclk; /* 串口时钟 */
    unsigned int fifosize; /* 串口FIFO缓冲大小 */
    unsigned char x_char; /* xon/xoff字符 */
    unsigned char regshift; /* 寄存器位移 */
    unsigned char iotype; /* IO访问方式 */
    unsigned char unused1;

    #define UPIO_PORT (0) /* IO端口 */
    #define UPIO_HUB6 (1)
    #define UPIO_MEM (2) /* IO内存 */
    #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; /* 关心的Rx error status */
    unsigned int ignore_status_mask;/* 忽略的Rx error status */
    struct uart_info *info; /* pointer to parent info */
    struct uart_icount icount; /* 计数器 */

    struct console *cons; /* console结构体 */
    #ifdef CONFIG_SERIAL_CORE_CONSOLE
    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_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))
    #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; /* 当前的moden设置 */
    unsigned int timeout; /* character-based timeout */
    unsigned int type; /* 端口类型 */
    const struct uart_ops *ops; /* 串口端口操作函数集 */
    unsigned int custom_divisor;
    unsigned int line; /* 端口索引 uart_driver.dev_name加上line组成串口的设备节点的名字 */
    resource_size_t mapbase; /* IO内存物理基地址,可用于ioremap */
    struct device *dev; /* 父设备 */
    unsigned char hub6; /* this should be in the 8250 driver */
    unsigned char suspended;
    unsigned char unused[2];
    void *private_data; /* 端口私有数据,一般为platform数据指针 */
    };
    • 每一个uart_port对应一个串口设备,uart_port通过uart_add_port添加到uart_state->port数组中去,此结构体中最重要的成员变量是uart_ops,uart操作函数集
  • struct uart_ops

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /*
    * This structure describes all the operations that can be
    * done on the physical hardware.
    */
    struct uart_ops {
    unsigned int (*tx_empty)(struct uart_port *); /* 串口的Tx FIFO缓存是否为空。如果为空,函数应返回TIOCSER_TEMT,否则返回0。如果端口不支持此操作,返回TIOCSER_TEMT。*/
    void (*set_mctrl)(struct uart_port *, unsigned int mctrl); /* 设置串口modem控制 */
    unsigned int (*get_mctrl)(struct uart_port *); /* 获取串口modem控制 */
    void (*stop_tx)(struct uart_port *); /* 禁止串口发送数据 */
    void (*start_tx)(struct uart_port *); /* 使能串口发送数据 */
    void (*send_xchar)(struct uart_port *, char ch);/* 发送xChar */
    void (*stop_rx)(struct uart_port *); /* 禁止串口接收数据 */
    void (*enable_ms)(struct uart_port *); /* 使能modem的状态信号 */
    void (*break_ctl)(struct uart_port *, int ctl); /* 设置break信号 */
    int (*startup)(struct uart_port *); /* 启动串口,应用程序打开串口设备文件时,该函数会被调用 */
    void (*shutdown)(struct uart_port *); /* 关闭串口,应用程序关闭串口设备文件时,该函数会被调用 */
    void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); /* 设置串口参数 */
    void (*pm)(struct uart_port *, unsigned int state,
    unsigned int oldstate); /* 串口电源管理 */
    int (*set_wake)(struct uart_port *, unsigned int state); /* */
    const char *(*type)(struct uart_port *); /* 返回一描述串口类型的字符串 */
    void (*release_port)(struct uart_port *); /* 释放串口已申请的IO端口/IO内存资源,必要时还需iounmap */
    int (*request_port)(struct uart_port *); /* 申请必要的IO端口/IO内存资源,必要时还可以重新映射串口端口 */
    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); /* IO控制 */
    };
  • tty_driver是在register过程中构建的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    struct tty_driver {
    int magic; /* magic number for this structure */
    struct kref kref; /* Reference management */
    struct cdev **cdevs;
    struct module *owner;
    const char *driver_name;
    const char *name;
    int name_base; /* offset of printed name */
    int major; /* major device number */
    int minor_start; /* start of minor device number */
    unsigned int num; /* number of devices allocated */
    short type; /* type of tty driver */
    short subtype; /* subtype of tty driver */
    struct ktermios init_termios; /* Initial termios */
    unsigned long flags; /* tty driver flags */
    struct proc_dir_entry *proc_entry; /* /proc fs entry */
    struct tty_driver *other; /* only used for the PTY driver */

    //Pointer to the tty data structures
    struct tty_struct **ttys;
    struct tty_port **ports;
    struct ktermios **termios;
    void *driver_state;

    //Driver methods
    const struct tty_operations *ops;
    struct list_head tty_drivers;
    }
    • tty_operations提供操作函数,供用户空间调用
    • 将tty_driver构建完成后 通过tty_regoster_driver注册到tty_core中

linux tty 串口驱动
http://example.com/2022/11/27/linux tty串口驱动/
作者
Hector
发布于
2022年11月27日
许可协议