tty关键结构体清单及其分层简述

本文详细介绍了 Linux TTY 设备模型的四个层面:用户层、TTY Core 层、线程规划层以及 Serial driver 设备层。从字符设备操作集到具体的串口设备驱动,层层递进地展示了 TTY 设备的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一: 用户层:

1
 //字符设备操作集
   /kernel/include/linux/fs.h
   static const struct file_operations tty_fops = {
        .llseek     = no_llseek,
        .read       = tty_read,
        .write      = tty_write,
        .poll       = tty_poll,
        .unlocked_ioctl = tty_ioctl,
        .compat_ioctl   = tty_compat_ioctl,
        .open       = tty_open,
        .release    = tty_release,
        .fasync     = tty_fasync,
    };
    调用位置在  /kernel/driver/tty/Tty_io.c
    static const struct file_operations tty_fops{ ... }

二 : tty_core层:

2.1
 //tty驱动结构体
    /kernel/include/linux/tty_driver.h
    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 */
    struct tty_struct **ttys;
    struct tty_port **ports;
    struct ktermios **termios;
    void *driver_state;
    const struct tty_operations *ops;
    struct list_head tty_drivers;
    };
    调用位置 :/kernel/drivers/tty/serial/XXX.uart.c
    struct tty_driver{ ... } 在设备驱动层 注册设备驱动时 创建初始化
2.2
//tty设备驱动 操作函数
    /kernel/include/linux/tty_driver.h
    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,
            unsigned int cmd, unsigned long arg);
    long (*compat_ioctl)(struct tty_struct *tty,
                 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);
    int (*tiocmset)(struct tty_struct *tty,
            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);
    int (*get_icount)(struct tty_struct *tty,
                struct serial_icounter_struct *icount);
    #ifdef CONFIG_CONSOLE_POLL
    int (*poll_init)(struct tty_driver *driver, int line, char *options);
    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;
    };
    调用位置 :  /kernel/drivers/tty/serial/serial_core.c
    static const struct tty_operations uart_ops { ... }

三 :线程规划层:

3.1
//给tty设备的线路规程
    /kernel/include/linux : Tty_ldisc.h
    struct tty_ldisc {
        struct tty_ldisc_ops *ops;
        struct tty_struct *tty;
    };
3.2
//用来保存当前tty端口的信息
    /kernel/include/linux/tty.h
    struct tty_struct {
    int magic;
    struct kref kref;
    struct device *dev;
    struct tty_driver *driver;
    const struct tty_operations *ops;
    int index;
    struct ld_semaphore ldisc_sem;
    struct tty_ldisc *ldisc;   //具体关联的 线程
    struct mutex atomic_write_lock;
    struct mutex legacy_mutex;
    struct mutex throttle_mutex;
    struct rw_semaphore termios_rwsem;
    struct mutex winsize_mutex;
    spinlock_t ctrl_lock;
    spinlock_t flow_lock;
    /* Termios values are protected by the termios rwsem */
    struct ktermios termios, termios_locked;
    struct termiox *termiox;    /* May be NULL for unsupported */
    char name[64];
    struct pid *pgrp;       /* Protected by ctrl lock */
    struct pid *session;
    unsigned long flags;
    int count;
    struct winsize winsize;     /* winsize_mutex */
    unsigned long stopped:1,    /* flow_lock */
              flow_stopped:1,
              unused:BITS_PER_LONG - 2;
    int hw_stopped;
    unsigned long ctrl_status:8,    /* ctrl_lock */
              packet:1,
              unused_ctrl:BITS_PER_LONG - 9;
    unsigned int receive_room;  /* Bytes free for queue */
    int flow_change;

    struct tty_struct *link;
    struct fasync_struct *fasync;
    int alt_speed;      /* For magic substitution of 38400 bps */
    wait_queue_head_t write_wait;
    wait_queue_head_t read_wait;
    struct work_struct hangup_work;
    void *disc_data;
    void *driver_data;
    struct list_head tty_files;
    #define N_TTY_BUF_SIZE 4096
    int closing;
    unsigned char *write_buf;
    int write_cnt;
    /* If the tty has a pending do_SAK, queue it here - akpm */
    struct work_struct SAK_work;
    struct tty_port *port;
    };
    调用位置 : 在上层用户 open /dev/XXX 的时候创建并初始化 
    tty_struct{ ... }
3.3
 //线程规划ops(操作函数)
    /kernel/include/linux : Tty_ldisc.h
    struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .magic           = TTY_LDISC_MAGIC,
        .name            = "n_tty",
        .open            = n_tty_open,
        .close           = n_tty_close,
        .flush_buffer    = n_tty_flush_buffer,
        .chars_in_buffer = n_tty_chars_in_buffer,
        .read            = n_tty_read,
        .write           = n_tty_write,
        .ioctl           = n_tty_ioctl,
        .set_termios     = n_tty_set_termios,
        .poll            = n_tty_poll,
        .receive_buf     = n_tty_receive_buf,
        .write_wakeup    = n_tty_write_wakeup,
        .fasync      = n_tty_fasync,
        .receive_buf2    = n_tty_receive_buf2,
    };

    调用位置 : /kernel/drivers/tty/n_tty.c
    struct tty_ldisc_ops tty_ldisc_N_TTY{ ... }

四 Serial_driver设备层:

4.1
//tty设备驱动结构体 
    /kernel/include/linux/serial_core.h
    struct uart_driver {
        struct module       *owner;
        const char      *driver_name;
        const char      *dev_name;
        int          major;
        int          minor;
        int          nr;
        struct console      *cons;
        struct uart_state   *state;
        struct tty_driver   *tty_driver;
    };
    调用位置 : /kernel/drivers/tty/serial/uartxxx.c
    static struct uart_driver XXX_uart_driver
4.2
//tty设备空间
    /kernel/include/linux/serial_core.h
    struct uart_state {
        struct tty_port     port;
        enum uart_pm_state  pm_state;
        struct circ_buf     xmit;
        struct uart_port    *uart_port;
    };
4.3
//tty真实的物理串口
/kernel/include/linux/serial_core.h
struct uart_port {  
        spinlock_t      lock;           /* port lock */  
        unsigned long       iobase;         /* io端口基地址(物理) */  
        unsigned char __iomem   *membase;       /* io内存基地址(虚拟) */  
        unsigned int        (*serial_in)(struct uart_port *, int);  
        void            (*serial_out)(struct uart_port *, int, int);  
        unsigned int        irq;            /* 中断号 */  
        unsigned long       irqflags;       /* 中断标志  */  
        unsigned int        uartclk;        /* 串口时钟 */  
        unsigned int        fifosize;       /* 串口缓冲区大小 */  
        unsigned char       x_char;         /* xon/xoff char */  
        unsigned char       regshift;       /* 寄存器位移 */  
        unsigned char       iotype;         /* IO访问方式 */  
        unsigned char       unused1;  

        unsigned int        read_status_mask;   /* 关心 Rx error status */  
        unsigned int        ignore_status_mask; /* 忽略 Rx error status */  
        struct uart_state   *state;         /* pointer to parent state */  
        struct uart_icount  icount;         /* 串口信息计数器 */  

        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;  
        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;           /* 端口索引 */  
        resource_size_t     mapbase;        /* io内存物理基地址 */  
        struct device       *dev;           /* 父设备 */  
        unsigned char       hub6;             
        unsigned char       suspended;  
        unsigned char       unused[2];  
        void            *private_data;      /* generic platform data pointer */  
    };  
调用位置 : /kernel/drivers/tty/serial/uartxxx.c
static struct XXX_port { struct uart_port port ... }    
4.4
//tty真实串口的操作集合
    /kernel/include/linux/serial_core.h
    struct uart_ops {   
            unsigned int (*tx_empty)(struct uart_port *);/* 串口的Tx FIFO缓存是否为空 */  
            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   (*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);  
            const char *(*type)(struct uart_port *);  
            void   (*release_port)(struct uart_port *);   
            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);  
        #ifdef CONFIG_CONSOLE_POLL  
            void    (*poll_put_char)(struct uart_port *, unsigned char);  
            int     (*poll_get_char)(struct uart_port *);  
        #endif  
        };  
    调用位置 : /kernel/drivers/tty/serial/uartxxx.c
    static struct uart_ops wk2xxx_pops  

<think>我们正在讨论Linux内核中的tty_operations结构体。根据引用,tty_operations结构体tty驱动中扮演着核心角色,它定义了一系列函数指针,这些函数指针由具体的tty驱动实现,用于处理tty设备的操作。用户的问题:如何找到或使用tty_operations结构体在Linux内核中的定义和功能?根据引用[3]:tty_driver是tty驱动的主要数据结构,用于注册和注销tty驱动。而tty_operations结构体则通过tty_set_operations函数与tty_driver关联(引用[1]和引用[2])。步骤:1.查找定义:tty_operations结构体的定义位于内核头文件中。根据引用[3],它在<linux/tty_driver.h>中描述。但实际的内核版本中,它可能在<linux/tty.h>或<linux/tty_driver.h>中。我们可以通过内核源代码来确认。2.功能:tty_operations结构体包含了一系列函数指针,如open、close、write、ioctl等,这些函数由具体的tty驱动实现,以完成对tty设备的操作。3.使用:在编写tty驱动时,我们需要定义一个tty_operations结构体变量,并为其各个函数指针赋值(实现具体的操作函数)。然后通过tty_set_operations函数将这个结构体tty_driver关联起来。具体步骤: a.包含必要的头文件,如<linux/tty_driver.h>或<linux/tty.h>。 b.实现tty_operations中需要的函数(至少实现必须的函数,如open、close、write等)。 c.定义tty_operations结构体变量,并将实现的函数赋值给对应的成员。 d.在驱动初始化时,创建tty_driver(例如使用alloc_tty_driver函数),然后调用tty_set_operations将我们实现的tty_operations设置给tty_driver。e.注册tty_driver(使用tty_register_driver)。示例代码片段(基于引用[4]的示例,但注意引用[4]是使用当前tty来写数据,而不是实现一个tty驱动):但是,引用[4]展示了一个如何获取当前tty并调用其write操作的例子。对于编写tty驱动,我们需要自己实现这些操作。下面是一个简单的tty驱动框架,展示如何定义和使用tty_operations: ```c#include <linux/tty.h> #include<linux/tty_driver.h>#include <linux/tty_flip.h>#include <linux/module.h> #include<linux/init.h>staticint my_tty_open(structtty_struct *tty, structfile *file){//打开设备的实现return0;} staticvoid my_tty_close(structtty_struct *tty, structfile *file){//关闭设备的实现} staticintmy_tty_write(struct tty_struct*tty,const unsignedchar *buf,int count) {//写入数据的实现//返回实际写入的字节数return count; }//定义tty_operations结构体static structtty_operationsmy_tty_ops ={.open= my_tty_open,.close =my_tty_close,.write= my_tty_write,//其他需要实现的操作...}; staticstruct tty_driver *my_tty_driver;static int__initmy_tty_init(void){int ret;//分配一个tty_drivermy_tty_driver =alloc_tty_driver(1);//1表示设备数量if(!my_tty_driver)return-ENOMEM;//设置tty_driver的基本信息my_tty_driver->owner= THIS_MODULE;my_tty_driver->driver_name= "my_tty_driver";my_tty_driver->name= "ttyMy";my_tty_driver->type= TTY_DRIVER_TYPE_SYSTEM;my_tty_driver->subtype= SYSTEM_TYPE_TTY;my_tty_driver->init_termios= tty_std_termios;//标准终端设置//将我们实现的tty_operations关联到tty_drivertty_set_operations(my_tty_driver,&my_tty_ops);//注册tty_driverret= tty_register_driver(my_tty_driver);if (ret){printk(KERN_ERR"Failedto registermy tty driver\n");put_tty_driver(my_tty_driver);returnret;}return0; }static void__exitmy_tty_exit(void) {tty_unregister_driver(my_tty_driver);put_tty_driver(my_tty_driver); }module_init(my_tty_init); module_exit(my_tty_exit);MODULE_LICENSE("GPL");```注意:这只是一个框架,实际实现需要根据硬件或虚拟设备的需求来完成各个函数。如何查找tty_operations的定义?在内核源代码中,可以使用grep或IDE的跳转功能查找“struct tty_operations”的定义。通常它定义在include/linux/tty_driver.h中(不同内核版本可能有所不同)。功能:tty_operations结构体中包含的函数指针非常多,常见的包括:-open:打开设备- close:关闭设备-write:向设备写入数据- write_room:查询缓冲区中还有多少空间可以写入-set_termios:设置终端参数(如波特率) -tiocmget:获取调制解调器状态-tiocmset:设置调制解调器状态-等等具体成员可以参考内核头文件中的定义。总结:要使用tty_operations,首先需要了解其定义(查看头文件),然后实现所需函数,最后通过tty_set_operations将其与tty_driver关联。 §§相关问题§§1. tty_operations结构体中必须实现哪些函数? 2.如何在内核源代码中查找tty_operations的具体定义? 3.编写tty驱动时,除了tty_operations还需要哪些步骤? 4. tty_driver和tty_operations之间的关系是什么?</think>### 如何定位和使用 `tty_operations` 结构体 在 Linux 内核中,`tty_operations` 是 TTY 设备驱动的核心接口,定义了驱动与 TTY 子系统交互的操作函数集。以下是定位和使用的关键步骤: #### 1. **定位结构体定义** - **头文件位置**: `tty_operations` 定义在 `include/linux/tty_driver.h`(内核版本 ≥ 3.10)或 `include/linux/tty.h`(旧版本)中[^3]。 - **查看定义**: 使用内核源码工具(如 `cscope`)搜索 `struct tty_operations`,或直接查看头文件: ```c struct tty_operations { int (*open)(struct tty_struct *tty, struct file *filp); void (*close)(struct tty_struct *tty, struct file *filp); ssize_t (*write)(struct tty_struct *tty, const u8 *buf, size_t count); // 其他函数指针(如 ioctl、set_termios 等) }; ``` #### 2. **核心功能** `tty_operations` 包含驱动必须实现的函数指针: - `open()`:设备打开时调用 - `close()`:设备关闭时调用 - `write()`:向设备写入数据 - `ioctl()`:处理设备控制命令 - `set_termios()`:设置终端参数(如波特率) - 其他操作(如 `flush_buffer`, `tiocmget` 等)[^3][^4] #### 3. **使用步骤** ##### (1) **定义驱动专属的 `tty_operations`** ```c static const struct tty_operations my_tty_ops = { .open = my_tty_open, .close = my_tty_close, .write = my_tty_write, .ioctl = my_tty_ioctl, // 其他必要函数 }; ``` ##### (2) **关联到 `tty_driver`** 通过 `tty_set_operations()` 绑定操作集: ```c struct tty_driver *driver = alloc_tty_driver(1); tty_set_operations(driver, &my_tty_ops); // 关键绑定步骤[^1][^2] ``` ##### (3) **实现操作函数** 以 `write` 为例: ```c static ssize_t my_tty_write(struct tty_struct *tty, const u8 *buf, size_t count) { // 将数据 buf[0..count-1] 写入硬件设备 return count; // 返回实际写入字节数 } ``` ##### (4) **注册驱动** ```c tty_register_driver(driver); // 注册到 TTY 子系统 ``` #### 4. **关键注意事项** - **必选函数**:至少实现 `open`、`close`、`write` 等基本操作[^3][^4]。 - **上下文安全**:操作函数可能运行在中断上下文,需避免阻塞。 - **引用管理**:通过 `tty_struct->driver` 可访问关联的驱动: ```c struct tty_operations *ops = tty->driver->ops; ops->write(tty, data, len); // 调用当前 TTY 的 write 方法[^4] ``` --- ### 相关问题 1. `tty_operations` 中的哪些函数是必须实现的?未实现会导致什么后果? 2. 如何在内核模块中动态调试 `tty_operations` 的函数调用? 3. `tty_set_operations()` 和 `tty_register_driver()` 的执行顺序是否可以互换? 4. 在 `tty_operations->write` 中如何正确处理流控和缓冲区管理? [^1]: `tty_set_operations` 函数将自定义的操作集绑定到 `tty_driver`,是驱动初始化的关键步骤。 [^2]: `tty_io.c` 中的 `tty_set_operations` 实现确认了操作集与驱动的关联机制。 [^3]: `tty_operations` 是 TTY 驱动的核心接口,定义了设备操作的标准方法集。 [^4]: 通过 `tty_struct->driver->ops` 可访问当前 TTY 的操作函数,这是调用驱动方法的通用模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux老A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值