标签:operation gic flags isp try dev ase bytes 主设备号
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软件框架如图所示:
在系统启动过程中, 注册了/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, };
驱动相关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);
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; };
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框架子系统>
标签:operation gic flags isp try dev ase bytes 主设备号
原文地址:https://www.cnblogs.com/hzl6255/p/9533327.html