设备驱动中的tty(kernel-4.7)

本文深入解析Linux系统中的TTY概念,包括串口终端、控制台终端和虚拟终端的类型。接着,文章详细分析了TTY架构,描述了tty核心、线路规程和驱动之间的调用关系。此外,还探讨了串口驱动的注册过程和数据读写调用流程,特别是对tty驱动接口的初始化和注册步骤。
摘要由CSDN通过智能技术生成

TTY概念解析

在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备。

• 串口终端(/dev/ttyS*)
串口终端是使用计算机串口连接的终端设备。Linux把每个串行端口都看作是一个字符设备。这些串行端口所对应的设备名称是 /dev/ttySAC0;/dev/ttySAC1……

• 控制台终端(/dev/console)
在Linux系统中,计算机的输出设备通常被称为控制台终端(Console),这里特指printk信息输出到的设备。/dev/console是一个虚拟的设备,它需要映射到真正的tty上,比如通过内核启动参数” console=ttySAC0”就把console映射到了串口0,是一种虚拟的设备,可以和屏幕或者串口关联

• 虚拟终端(/dev/tty*)
当用户登录时,使用的是虚拟终端。使用Ctcl+Alt+[F1—F6]组合键时,我们就可以切换到tty1、tty2、tty3等上面去。tty1–tty6等称为虚拟终端,而tty0则是当前所使用虚拟终端的一个别名.

TTY架构分析

这里写图片描述
Linux tty子系统包含:tty核心,tty线路规程和tty驱动。tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。
下图详细的描述了tty子系统之间的互相调用关系,即用户应用层 –> 线路规划层 –> TTY层 –> 底层驱动层 –> 物理硬件层。
这里写图片描述

串口驱动调用关系分析

串口驱动重要结构和对应的驱动调用层次:
这里写图片描述

整个 uart 框架大概的样子如上图所示,简单来分的话可以说成两层,一层是下层我们的串口驱动层,它直接与硬件相接触,我们需要填充一个 struct uart_ops的结构体,另一层是上层 tty 层,包括 tty 核心以及线路规程,它们各自都有一个 Ops 结构,用户空通过间是 tty 注册的字符设备节点来访问,这么说来如上图所示涉及到了4个 ops 结构了,层层跳转。下面,就来分析分析它们的层次结构。

在 s3c2440 平台,它是这样来注册串口驱动的,分配一个struct uart_driver简单填充,并调用uart_register_driver注册到内核中去。


static struct uart_driver s3c24xx_uart_drv = {
    .owner      = THIS_MODULE,
    .driver_name    = "s3c2410_serial",
    .nr     = CONFIG_SERIAL_SAMSUNG_UARTS,
    .cons       = S3C24XX_SERIAL_CONSOLE,
    .dev_name   = S3C24XX_SERIAL_NAME,
    .major      = S3C24XX_SERIAL_MAJOR,
    .minor      = S3C24XX_SERIAL_MINOR,
};

uart_driver中,只是填充了一些名字、设备号等信息,这些都是不涉及底层硬件访问的,来看一下完整的 uart_driver 结构,在include/linux/serial_core.h中:

struct uart_driver {
    struct module       *owner;/* 拥有该uart_driver的模块,一般为THIS_MODULE */  
    const char      *driver_name;/* 串口驱动名,串口设备文件名以驱动名为基础 */
    const char      *dev_name;  /* 串口设备名 */
    int          major; /* 主设备号 */ 
    int          minor; /* 次设备号 */
    int          nr;  /* 该uart_driver支持的串口个数(最大) */  
    struct console      *cons; /* 其对应的console.若该uart_driver支持serial console,否则为NULL */  

    /*
     * these are private; the low level driver should not
     * touch these; they should be initialised to NULL
     */ 
     /* 下面这俩,它们应该被初始化为NULL */ 
    struct uart_state   *state; /* 下层,串口驱动层 */
    struct tty_driver   *tty_driver;  /* tty相关 */  
};

上边填充的结构体中,有两个成员未被赋值,对于tty_driver代表的是上层,它会在 register_uart_driver 中的过程中赋值,而uart_state则代表下层,uart_state也会在register_uart_driver的过程中分配空间,但是它里面真正设置硬件相关的东西是 uart_state->uart_port,这个uart_port是需要我们从其它地方调用 uart_add_one_port 来添加的。

在串口驱动层首先,需要认识这几个结构体:


/*
 * This is the state information which is persistent across opens.
 */
struct uart_state {
    struct tty_port     port;

    enum uart_pm_state  pm_state;
    struct circ_buf     xmit;

    atomic_t        refcount;
    wait_queue_head_t   remove_wait;
    struct uart_port    *uart_port; //对应于一个串口设备 
};

在注册 driver 时,会根据 uart_driver->nr来申请 nr 个 uart_state空间,用来存放驱动所支持的串口(端口)的物理信息

struct uart_port {
    spinlock_t      lock;           /* port lock */
    unsigned long       iobase; /* in/out[bwl] *//* io端口基地址(物理) */ 
    unsigned char __iomem   *membase;/* read/write[bwl] *//* io内存基地址(虚拟) */ 
    unsigned int        (*serial_in)(struct uart_port *, int);
    void            (*serial_out)(struct uart_port *, int, int);
    void            (*set_termios)(struct uart_port *,
                               struct ktermios *new,
                               struct ktermios *old);
    unsigned int        (*get_mctrl)(struct uart_port *);
    void            (*set_mctrl)(struct uart_port *, unsigned int);
    int         (*startup)(struct uart_port *port);
    void            (*shutdown)(struct uart_port *port);
    void            (*throttle)(struct uart_port *port);
    void            (*unthrottle)(struct uart_port *port);
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值