码迷,mamicode.com
首页 > 系统相关 > 详细

Linux tty介绍

时间:2018-08-25 14:29:02      阅读:380      评论:0      收藏:0      [点我收藏+]

标签:operation   gic   flags   isp   try   dev   ase   bytes   主设备号   

1. tty介绍

tty(TeleType)指Linux中的一类终端(Terminal)设备, 是一种字符设备

在Linux中, tty可分为如下几类
- 串行端口终端(serial port terminal): 指使用计算机串行端口连接的终端设备 /dev/ttySn
- 伪终端(pseudo terminall)): /dev/pts/*
- 控制终端(controlling terminal)): 代表当前tty设备 /dev/tty
- 控制台终端(console): /dev/ttyn、/dev/console

详细定义如下

/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM         0x0001
#define TTY_DRIVER_TYPE_CONSOLE        0x0002
#define TTY_DRIVER_TYPE_SERIAL         0x0003
#define TTY_DRIVER_TYPE_PTY            0x0004
#define TTY_DRIVER_TYPE_SCC            0x0005    /* scc driver */
#define TTY_DRIVER_TYPE_SYSCONS        0x0006

tty可以分为如下几层
- 核心层(tty core)
- 线路规程(tty line discipline)
- 驱动层(tty driver)

tty代码位于drivers/tty目录下

tty软件框架如图所示:

技术分享图片

2. tty初始化

在系统启动过程中, 注册了/dev/tty和/dev/console设备

chr_dev_init()
  tty_init()
    /* 注册/dev/tty设备 */
    cdev_init(&tty_cdev, &tty_fops);
    cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1)
    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty")
    device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty")
    /* 注册/dev/console设备 */ 
    cdev_init(&console_cdev, &console_fops);
    cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1)
    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console")
    consdev = device_create_with_groups(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, cons_dev_groups, "console");
 
start_kernel()
  console_init()
    n_tty_init()
      tty_register_ldisc(N_TTY, &n_tty_ops);

其中, 值得一说的是tty_fops, 定义了tty设备文件操作集

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,
};

3. tty接口

驱动相关API主要如下:

/* 分配tty驱动数据结构 */
struct tty_driver *alloc_tty_driver(unsigned int lines);
struct tty_driver *tty_alloc_driver(unsigned int lines, unsigned long flags)
/* 注册/释放tty驱动 */
int tty_register_driver(struct tty_driver *driver);
int tty_unregister_driver(struct tty_driver *driver);
/* tty驱动 */
void put_tty_driver(struct tty_driver *d);
/* tty端口销毁 */
void tty_port_destroy(struct tty_port *port);
/* 设置tty文件操作集 */
void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op);

设备相关API主要如下:

/* tty设备注册 */
struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev);
struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device);
struct device *tty_port_register_device_attr(struct tty_port *port, struct tty_driver *driver, unsigned index, struct device *device, void *drvdata, const struct attribute_group **attr_grp);
/* tty设备注销 */
void tty_unregister_device(struct tty_driver *driver, unsigned index);

4. tty数据结构

tty核心层包含如下几个重要数据结构

tty_struct是tty设备的"动态抽象", 和文件句柄的功能类似, 还保存了tty设备生命周期中的临时信息, 其生命周期为从打开tty设备开始, 到关闭tty设备结束; 主要供核心层使用, 必要的时候可以供具体的tty驱动使用

struct tty_struct {
    int    magic;
    struct kref kref;
    struct device *dev;                  /* 指向tty设备 */
    struct tty_driver *driver;           /* 指向tty驱动 */
    const struct tty_operations *ops;    /* 指向tty操作函数集 */
    int index;                           /* 指向tty设备的编号(如tty0、tty1中的0、1) */

    /* Protects ldisc changes: Lock tty not pty */
    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;
    spinlock_t files_lock;        /* protects tty_files list */
    struct list_head tty_files;

    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;               /* 指向tty端口 */
};

tty_driver是tty设备的主要数据结构

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;    /* 该tty驱动的名称, 在tty内部使用 */
    const char       *name;           /* 该tty驱动的设备名称, 体现到sysfs以及/dev/等文件系统下 */
    int              name_base;       /* offset of printed name */
    int              major;           /* 主设备号, 如TTY_MAJOR */
    int              minor_start;     /* 起始次设备号, 通常从64开始, why? */
    unsigned int     num;             /* tty驱动对应设备数 */
    short            type;            /* tty驱动类型, 如SERIAL、PTY等 */
    short            subtype;         /* tty驱动子类型*/
    struct ktermios  init_termios;    /* 初始termios, 如tty_std_termios */
    unsigned long    flags;           /* tty驱动flags */
    struct proc_dir_entry   *proc_entry;      /* /proc文件系统入口 */
    struct tty_driver       *other;           /* 只用于PTY驱动 */

    /*
     * 指向tty相关数据结构
     */
    struct tty_struct **ttys;
    struct tty_port **ports;
    struct ktermios **termios;
    void *driver_state;                    /* tty驱动私有数据 */ 

    const struct tty_operations *ops;      /* tty文件操作集 */ 
    struct list_head tty_drivers;
};

tty_port是tty设备固有属性的"静态抽象", 保存了该tty设备的一些固定的属性, 供具体的tty驱动使用

struct tty_port {
    struct tty_bufhead   buf;                 /* Locked internally */
    struct tty_struct    *tty;                /* Back pointer */
    struct tty_struct    *itty;               /* internal back ptr */
    const struct tty_port_operations *ops;    /* Port operations */
    spinlock_t           lock;                /* Lock protecting tty field */
    int                  blocked_open;        /* Waiting to open */
    int                  count;               /* Usage count */
    wait_queue_head_t    open_wait;           /* Open waiters */
    wait_queue_head_t    delta_msr_wait;      /* Modem status change */
    unsigned long        flags;               /* User TTY flags ASYNC_ */
    unsigned long        iflags;              /* Internal flags TTY_PORT_ */
    unsigned char        console:1,           /* port is a console */
                         low_latency:1;       /* optional: tune for latency */
    struct mutex         mutex;               /* Locking */
    struct mutex         buf_mutex;           /* Buffer alloc lock */
    unsigned char        *xmit_buf;           /* Optional buffer */
    unsigned int         close_delay;         /* Close port delay */
    unsigned int         closing_wait;        /* Delay for output */
    int                  drain_delay;         /* Set to zero if no pure time
                                                 based drain is needed else
                                                 set to size of fifo */
    struct kref          kref;                /* Ref counter */
};

termios, 定义了POSIX终端接口操作对象; 在用户空间为struct termios, 内核空间为struct ktermios

struct ktermios {
    tcflag_t c_iflag;        /* input mode flags */
    tcflag_t c_oflag;        /* output mode flags */
    tcflag_t c_cflag;        /* control mode flags */
    tcflag_t c_lflag;        /* local mode flags */
    cc_t c_line;             /* line discipline */
    cc_t c_cc[NCCS];         /* control characters */
    speed_t c_ispeed;        /* tty设备输入速率 */
    speed_t c_ospeed;        /* tty设备输出速率 */
};

tty_operations定义了硬件有关的操作

struct tty_operations {
    struct tty_struct *(*lookup)(struct tty_driver *driver, struct file *filp, 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;
};

5. tty驱动编写

tty驱动的编写主要步骤如下:

1. 实现tty设备有关的文件操作集(tty_operations)
2. 调用tty_alloc_driver分配一个tty驱动, 并设置driver中相关字段(包括tty_operations变量)
3. 调用tty_register_driver注册tty驱动
4. 如果需要动态注册tty设备, 则需调用tty_register_device或者tty_register_device_attr注册tty设备
5. 接收到数据时, 调用tty_insert_flip_string或者tty_insert_flip_char将数据交给TTY core; TTY core需要发送数据时, 会调用driver提供的回调函数, 在那里面访问硬件送出数据即可

参考:
<Linux字符设备驱动>
<Linux TTY框架子系统>

Linux tty介绍

标签:operation   gic   flags   isp   try   dev   ase   bytes   主设备号   

原文地址:https://www.cnblogs.com/hzl6255/p/9533327.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!