-
2021-05-14 15:36:18
Linux TTY framework(4)_TTY driver
作者:wowo 发布于:2016-10-25 22:40
分类:TTY子系统
1. 前言
本文将从驱动工程师的角度去看TTY framework:它怎么抽象、管理各个TTY设备?它提供了哪些编程接口以方便TTY driver的开发?怎么利用这些接口编写一个TTY driver?等等。
注1:话说介绍各个framework的时候,我一直比较喜欢用provider、consumer等概念,因为非常生动、易懂。不过在TTY framework的官方俗语中,压根没有provider、consumer等概念,为了不混淆试听,就算了吧。
注2:TTY framework在Linux kernel中算得上一个比较繁琐、庞杂的framework了,再加上现在很少有人会直接去写一个TTY driver,因此本文只是介绍一些概念性的东西,以加深对TTY及其driver的理解,为后续学习serial framework打基础。一些细节的东西,大家可参考callme_friend同学写的"TTY驱动分析[2]”,特别是其中的一些图示,很清晰!
注3:本文所使用的kernel版本为“X Project”初始的“Linux 4.6-rc5”版本。
2. 关键数据结构
注4:阅读本章内容时可对照callme_friend画的的TTY个数据结构的关系图[3]以加深理解。
2.1 TTY device
Linux TTY framework的核心功能,就是管理TTY设备,以方便应用程序使用。于是,问题来了,Linux kernel是怎么抽象TTY设备的呢?答案很尴尬,kernel并不认为TTY device是一个设备,这很好理解:
比如,我们熟悉的串口终端,串口控制器(serial controller)是一个实实在在的硬件设备,一个控制器可以支持多个串口(serial port),软件在串口上收发数据,就相当于在驱动“串口终端”。此处的TTY device,就是从串口控制器中抽象出来的一个数据通道;
再比如,我们常用的网络终端,只有以太网控制器(或者WLAN控制器)是实实在在的设备,sshd等服务进程,会基于网络socket,虚拟出来一个数据通道,软件在这个通道上收发数据,就相当于在驱动“网络终端”。
因此,从kernel的角度看,TTY device就是指那些“虚拟的数据通道”。
另外,由于TTY driver在linux kernel中出现的远比设备模型早,所以在TTY framework中,没有特殊的数据结构用于表示TTY设备。当然,为了方便,kernel从设备模型和字符设备两个角度对它进行了抽象:
1)设备模型的角度
为每个“数据通道”注册了一个stuct device,以便可以在sysfs中体现出来,例如:
/sys/class/tty/tty
/sys/class/tty/console
/sys/class/tty/ttyS0
2)字符设备的角度
为每个“数据通道”注册一个struct cdev,以便在用户空间可以访问,例如:
/dev/tty
/dev/console
/dev/ttyS0
2.2 TTY driver
从当前设备模型的角度看,TTY framework有点奇怪,它淡化了device的概念(参考2.1的介绍),却着重突出driver。由struct tty_driver所代表的TTY driver,几乎大包大揽了TTY device有关的所有内容,如下:
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 driver的时候,我们只需要定义一个struct tty_driver变量,并根据实际情况正确填充其中的字段后,注册到TTY core中,即可完成驱动的设计。当然,我们不需要关心struct tty_driver中的所有字段,下面我们捡一些重点的字段一一说明。
1)需要TTY driver关心的字段
driver_name,该TTY driver的名称,在软件内部使用;
name,该TTY driver所驱动的TTY devices的名称,会体现到sysfs以及/dev/等文件系统下;
major、minor_start,该TTY driver所驱动的TTY devices的在字符设备中的主次设备号。因为一个tty driver可以支持多个tty device,因此次设备号只指定了一个start number;
num,该driver所驱动的tty device的个数,可以在tty driver注册的时候指定,也可以让TTY core自行维护,具体由TTY_DRIVER_DYNAMIC_DEV flag决定(可参考“”中的介绍);
type、subtype,TTY driver的类型,具体可参考“include/linux/tty_driver.h”中的定义;
init_termios,初始的termios,可参考2.5小节的介绍;
flags,可参考2.6小节的介绍;
ops,tty driver的操作函数集,可参考2.7小节的介绍;
driver_state,可存放tty driver的私有数据。
2)内部使用的字段
ttys,一个struct tty_struct类型的指针数组,可参考2.3小节的介绍;
ports,一个struct tty_port类型的指针数组,可参考2.4小节的介绍;
termios,一个struct ktermios类型的指针数组,可参考2.5小节的介绍。
2.3 TTY struct(struct tty_struct)
TTY struct是TTY设备在TTY core中的内部表示。
从TTY driver的角度看,它和文件句柄的功能类似,用于指代某个TTY设备。
从TTY core的角度看,它是一个比较复杂的数据结构,保存了TTY设备生命周期中的很多中间变量,如:
dev,该设备的struct device指针;
driver,该设备的struct tty_driver指针;
ops,该设备的tty操作函数集指针;
index,该设备的编号(如tty0、tty1中的0、1);
一些用于同步操作的mutex锁、spinlock锁、读写信号量等;
一些等待队列;
write buffer有关的信息;
port,该设备对应的struct tty_port(可参考2.4小节的介绍)
等等。
由于编写TTY driver的时候不需要特别关心struct tty_struct的内部细节,这里不再详细介绍。
2.4 TTY port(struct tty_port)
在TTY framework中TTY port是一个比较难理解的概念,因为它和TTY struct类似,也是TTY device的一种抽象。那么,既然有了TTY struct,为什么还需要TTY port呢?先看一下kernel代码注释的解释:
/* include/linux/tty.h */
/*
* Port level information. Each device keeps its own port level information
* so provide a common structure for those ports wanting to use common support
* routines.
*
* The tty port has a different lifetime to the tty so must be kept apart.
* In addition be careful as tty -> port mappings are valid for the life
* of the tty object but in many cases port -> tty mappings are valid only
* until a hangup so don't use the wrong path.
*/
我的理解是:
TTY struct是TTY设备的“动态抽象”,保存了TTY设备访问过程中的一些临时信息,这些信息是有生命周期的:从打开TTY设备开始,到关闭TTY设备结束;
TTY port是TTY设备固有属性的“静态抽象”,保存了该设备的一些固定不变的属性值,例如是否是一个控制台设备(console)、打开关闭时是否需要一些delay操作、等等;
另外(这一点很重要),TTY core负责的是逻辑上的抽象,并不关心这些固有属性。因此从层次上看,这些属性完全可以由具体的TTY driver自行维护;
不过,由于不同TTY设备的属性有很多共性,如果每个TTY driver都维护一个私有的数据结构,将带来代码的冗余。所以TTY framework就将这些共同的属性抽象出来,保存在struct tty_port数据结构中,同时提供一些通用的操作接口,供具体的TTY driver使用;
因此,总结来说:TTY struct是TTY core的一个数据结构,由TTY core提供并使用,必要的时候可以借给具体的TTY driver使用;TTY port是TTY driver的一个数据结构,由TTY core提供,由具体的TTY driver使用,TTY core完全不关心。
2.5 termios(struct ktermios)
说实话,在Unix/Linux的世界中,终端(terminal)编程是一个非常繁琐的事情,为了改善这种状态,特意制订了符合POSIX规范的应用程序编程接口,称作POSIX terminal interface[3]。POSIX terminal interface操作的对象,就是名称为termios的数据结构(在用户空间为struct termios,内核空间为struct ktermios)。以kernel中的struct ktermios为例,其定义如下:
/* include/uapi/asm-generic/termbits.h */
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; /* input speed */
speed_t c_ospeed; /* output speed */
};
说实话,要理解上面的数据结构,真的不是一件容易的事情,这里只能简单介绍一些我们常用的内容,更为具体的,如有需要,后面会用单独的文章去分析:
c_cflag,可以控制TTY设备的一些特性,例如data bits、parity type、stop bit、flow control等(例如串口设备中经常提到的8N1);
c_ispeed、c_ospeed,可以分别控制TTY设备输入和输出的速度(例如串口设备中的波特率);
其它,暂不介绍。
2.6 tty driver flags
TTY driver在注册struct tty_driver变量的时候,可以提供一些flags,以告知TTY core一些额外的信息,例如(具体可参考include/linux/tty_driver.h中的定义和注释,写的很清楚):
TTY_DRIVER_DYNAMIC_DEV:如果设置了该flag,则表示TTY driver会在需要的时候,自行调用tty_register_device接口注册TTY设备(相应地回体现在字符设备以及sysfs中);如果没有设置,TTY core会在tty_register_driver时根据driver->num信息,自行创建对应的TTY设备。
2.7 TTY操作函数集
TTY core将和硬件有关的操作,抽象、封装出来,形成名称为struct tty_operations的数据结构,具体的TTY driver不需要关心具体的业务逻辑,只需要根据实际的硬件情况,实现这些操作接口即可。
听着还挺不错啊(framework的中心思想一贯如此,大家牢记即可),不过不能高兴的太早,看过这个数据结构之后,估计心会凉半截:
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;
};
这也太复杂了吧?确实如此,好在终端设备正在慢慢的退出历史舞台,看这篇文章的同学们,可能这一辈子都不会直接去写一个TTY driver。所以,这里我也不打算详细介绍,仅仅出于理解TTY framework的目的,做如下说明:
这些操作函数的操作对象,基本上都是struct tty_struct类型的指针,这也印证了我们在2.3中所说的----TTY struct是TTY设备的操作句柄;
当然,具体的TTY driver,可以从struct tty_struct指针中获取足够多的有关该TTY设备的信息,例如TTY port等;
TTY core会通过“.write“接口,将输出信息送给终端设备并显示。因此具体的TTY driver需要实现该接口,并通过硬件操作将数据送出;
你一定会好奇:既然有“.write“接口,为什么没有相应的read接口?TTY设备上的输入信息,怎么经由TTY core送给Application呢?具体可以参考"TTY驱动分析[2]”,本文不再详细介绍了。
3. 提供的用于编写TTY driver的API
在提供了一系列的数据结构的同时,TTY framework向下封装了一些API,以方便TTY driver的开发,具体如下。
3.1 TTY driver有关的API
用于struct tty_driver数据结构的分配、初始化、注册等:
/* include/linux/tty_driver.h */
extern struct tty_driver *__tty_alloc_driver(unsigned int lines,
struct module *owner, unsigned long flags);
extern void put_tty_driver(struct tty_driver *driver);
extern void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op);
extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
extern void tty_driver_kref_put(struct tty_driver *driver);
/* Use TTY_DRIVER_* flags below */
#define tty_alloc_driver(lines, flags) \
__tty_alloc_driver(lines, THIS_MODULE, flags)
/* include/linux/tty.h */
extern int tty_register_driver(struct tty_driver *driver);
extern int tty_unregister_driver(struct tty_driver *driver);
tty_alloc_driver,分配一个struct tty_driver指针,并初始化那些不需要driver关心的字段:
lines,指明该driver最多能支持多少个设备,TTY core会根据该参数,分配相应个数的ttys、ports、termios数组;
flags,请参考2.6小节的说明。
tty_set_operations,设置TTY操作函数集。
tty_register_driver,将TTY driver注册给TTY core。
3.2 TTY device有关的API
如果TTY driver设置了TTY_DRIVER_DYNAMIC_DEV flag,就需要自行注册TTY device,相应的API包括:
/* include/linux/tty.h */
extern struct device *tty_register_device(struct tty_driver *driver,
unsigned index, struct device *dev);
extern struct device *tty_register_device_attr(struct tty_driver *driver,
unsigned index, struct device *device,
void *drvdata,
const struct attribute_group **attr_grp);
extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
tty_register_device,分配并注册一个TTY device,最后将新分配的设备指针返回给调用者:
driver,对应的TTY driver;
index,该TTY设备的编号,它会决定该设备在字符设备中的设备号,以及相应的设备名称,例如/dev/ttyS0中的‘0’;
dev,可选的父设备指针。
tty_register_device_attr,和tty_register_device类似,只不过可以额外指定设备的attribute。
3.3 数据传输有关的API
当TTY core有数据需要发送给TTY设备时,会调用TTY driver提供的.write或者.put_char回调函数,TTY driver在这些回调函数中操作硬件即可。
当TTY driver从TTY设备收到数据并需要转交给TTY core的时候,需要调用TTY buffer有关的接口,将数据保存在缓冲区中,并等待Application读取,相关的API有:
/* include/linux/tty_flip.h*/
static inline int tty_insert_flip_char(struct tty_port *port,
unsigned char ch, char flag)
{
….
}
static inline int tty_insert_flip_string(struct tty_port *port,
const unsigned char *chars, size_t size)
{
return tty_insert_flip_string_fixed_flag(port, chars, TTY_NORMAL, size);
}
注5:本文没有涉及TTY buffer、TTY flip有关的知识,大家知道有这么回事就行了。
4. TTY driver的编写步骤
说实话,TTY driver的编写步骤,就和“把大象放进冰箱”一样“简单”:
步骤1:实现TTY设备有关的操作函数集,并保存在一个struct tty_operations变量中。
步骤2:调用tty_alloc_driver分配一个TTY driver,并根据实际情况,设置driver中的字段(包括步骤1中的struct tty_operations变量)。
步骤3:调用tty_register_driver将driver注册到kernel。
步骤4:如果需要动态注册TTY设备,在合适的时机,调用tty_register_device或者tty_register_device_attr,向kernel注册TTY设备。
步骤5:接收到数据时,调用tty_insert_flip_string或者tty_insert_flip_char将数据交给TTY core;TTY core需要发送数据时,会调用driver提供的回调函数,在那里面访问硬件送出数据即可。
好吧,相信任何人看到上面的步骤之后,都没办法去写一个完整的TTY driver(我也是)。好在这是一个幸福的时代,我们很少需要直接去写这样的一个driver。那么本文的目的又是什么呢?权当是一个科普吧,如果你真的打算去写一个TTY driver,不至于无从下手。
5. 参考文档
[2] TTY驱动分析(链接失效,TODO)
[3] TTY各数据结构关系图,http://www.wowotech.net/content/uploadfile/201505/eb451430746679.gif((链接失效,TODO))
原创文章,转发请注明出处。蜗窝科技,www.wowotech.net。
评论:
magicse7en
2017-06-19 13:50
参考文档 [2][3] 的链接都已经失效
2017-06-19 17:11
@magicse7en:多谢提醒,我处理一下。
hit20j
2017-09-22 23:30
@wowo:请问 TTY驱动分析 链接在哪里?
2017-09-23 10:24
@hit20j:没有链接了,被原作者删除了:-)
numbqq
2017-06-15 16:07
Hi wowo,
看了你的系列文章,受益匪浅,非常感谢!我最近调试终端碰到点问题想请教一下。忘不吝赐教。我现在使用HDMI输出,配置framebuffer console使信息输出到显示器,但是输出显示碰到一个问题就是显示器字符刷新慢,我通过键盘输入字符,字符不会马上在屏幕上显示完整,而是慢慢才会显示完整,感觉刷新很慢。通过
echo kkkkkkk > /dev/tty1,kkkkkkk也是慢慢才显示完整,请问你知道这会是哪方面的问题吗?非常感谢!
2017-06-15 18:27
@numbqq:fb console每画一个字符,都是把这个字符,和屏幕上已有的内容一起,转成一副完整的图片,然后写入到buffer中。
因此,基于当前的分辨率、刷新率、fb的位数,你可以算算显示一个字符的时间(估计快不到哪里去)。
numbqq
2017-06-15 18:56
@wowo:谢谢这么快回复!
正常来说从键盘输入字符到显示器显示出这个字符,时间应该是一致的,至少肉眼看不出时间差,但是现在我碰到的问题是键盘输入一个字符后,屏幕不会马上显示出这个完整的字符,而是会显示字符其中一部分像素点,在慢慢显示出完整的字符,肉眼明显能感受到显示字符不对。以前没有调过这方面的,不知道问题到底出在哪,能不能给一些建议呢?谢谢!
2017-06-19 08:43
@numbqq:出现这种情况,是因为fbcon在一个像素点一个像素点地画这个字符的时候,你的现实硬件还在不停的从ram中刷新到显示屏上,二者没有同步,你可以从这个方面思考一下。
randy
2017-04-10 11:50
问一个问题:如何屏蔽掉tty对tty ldisc线性规程的处理?我现在板子上只有一个uart设备,但是这个设备默认使用line ldisc进行字符串预处理了,比如换行什么的,我现在不希望它做预处理,而是直接把数据从uart->line ldisc->tty->fs透传上来到用户态应用程序。我想到一个方案是自己写一个ldisc的驱动,然后在应用层告诉这个tty文件节点使用我写的ldisc驱动进行透传数据,但是这个比较麻烦,在应用层有可以更简单的方式使用uart接收到的数据么?
2017-04-10 16:05
@randy:如果仅仅是去掉线路规程的预处理,在用户空间设置tty设备的termios,将input设置为non-canonical模式,并disable output的OPOST flag,应该可以实现。
具体你可以查查termios的flag,例如:
http://man7.org/linux/man-pages/man3/tcsetattr.3.html
randy
2017-04-10 17:11
@wowo:谢谢回复。再请教一个问题:我看你前面的文章有说tty不是一个device,也就是说一个uart设备可以虚拟出多个tty设备吗?如果是这样,假如我单板上一个uart口已经用作了控制台,那再抽象出一个ttyA的话,对于读操作而言,uart怎么知道数据是扔给控制台还是ttyA呢?还是说谁先读就扔给谁?
2017-04-11 13:25
@randy:这样的用法有点奇怪。通常情况下,一个串口,对应一个tty设备,不会有两个。
adrian
2017-06-11 19:26
@wowo:我的看法是:
1, 你可以试试cfmakeraw
2, 如果真有这重需求的话(serial multiplexing), 需要自己实现,可以考虑自己在driver里实现一个复用协议,但是需要serial两端都遵守,没有通用意义
发表评论:
昵称
邮件地址 (选填)
个人主页 (选填)
更多相关内容 -
概述Linux TTY/PTS的区别
2020-09-14 21:42:45主要介绍了概述Linux TTY/PTS的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
一文搞懂 Linux TTY
2022-04-19 15:34:30由于历史原因, Linux保留了TTY,上述的输入和输出两个电缆,可以简单的认为是键盘输入和显卡输出 tty和stty命令 tty命令返回当前的终端名字,1表示可以通过Ctrl+Alt+F3得到 $ tty /dev/pts/1 stty是对tty进行设置...TTY的历史
TTY全称
TeleTYpewriter
,也即是电传打字机,它通过两根电缆连接计算机,一根用于向计算机发送指令,一根用于接收计算机的输出,输出结果是打印在纸上的由于历史原因, Linux保留了TTY,上述的输入和输出两个电缆,可以简单的认为是键盘输入和显卡输出
tty和stty命令
tty命令返回当前的终端名字,1表示可以通过Ctrl+Alt+F3得到
$ tty /dev/pts/1
stty是对tty进行设置的命令,s表示set
- Display all settings for the current terminal: stty -a - Set the number of rows: stty rows rows - Set the number of columns: stty cols cols - Get the actual transfer speed of a device: stty -F path/to/device_file speed - Reset all modes to reasonable values for the current terminal: stty sane
列出当前tty的所有配置信息:
$ stty -a speed 9600 baud; rows 35; columns 129; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0; -parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
切换tty
Ctrl+Alt+F1可以切换到第一个tty,以此类推
这里把字符串输入到tty2,由于现在处于pts1,因此终端没有显示,当切换到tty2就会显示字符串
这里切换到了tty4
伪终端:pseudo terminal
- 终端模拟器(terminal emulator) ,是运行在内核的模块
- 用户态的终端模拟程序,被称为伪终端(pseudo terminal, PTY)
可以通过打开文件 /dev/ptmx 创建伪终端,伪终端 pty 具有以下两种用途:
- 使用 telnet、 ssh 命令支持远程登录
- 提供窗口系统用以创建命令解释程序窗口的界面
pty最大配额
/proc/sys/kernel/pty/max This file defines the maximum number of pseudoterminals. /proc/sys/kernel/pty/nr This read-only file indicates how many pseudoterminals are currently in use.
-
linux tty驱动源码分析
2016-09-05 09:13:07对linux tty驱动源码进行简要分析,明确tty工作流程,及tty线路规程作用。 -
如何修改Linux TTY的屏幕分辨率?
2021-05-15 08:27:12如果没有替Linux操作系统安装桌面环境的话,在Linux操作系统开机之后,缺省会进入TTY主控台画面。有时缺省的TTY画面所套用的屏幕分辨率并不是我们想要的,若要修改屏幕分辨率的话可以参考本篇文章。要修改TTY的屏幕...如果没有替Linux操作系统安装桌面环境的话,在Linux操作系统开机之后,缺省会进入TTY主控台画面。有时缺省的TTY画面所套用的屏幕分辨率并不是我们想要的,若要修改屏幕分辨率的话可以参考本篇文章。
要修改TTY的屏幕分辨率,可以去设置GRUB开机引导程序,本篇文章将会以GRUB2来说明。
修改Linux TTY的屏幕分辨率
首先要在电脑开机时进入GRUB菜单。如果您的电脑并没有安装两个以上的操作系统,那么在电脑开机时可能不会显示出GRUB菜单,若要调用出GRUB菜单,可以在按下电脑开机键之后,掌握时机按下键盘上的ESC键。
在GRUB菜单中按下c键,可以进入GRUB的命令行模式。
先运行以下指令:
set pager=1
这个指令可以将环境变量pager设置为1,目的在于使之后运行的指令,如果屏幕输出内容太多的话,可以拥有如more或是less等工具的「继续阅读」功能。避免因屏幕塞不下过多的内容,而导致我们无法查看指令完整的输出信息。
接着运行以下指令:
vbeinfo
以上指令可以查看这台电脑的VBE(VESA BIOS Extensions)支持哪些显示模式。
将我们所需要的分辨率的长和宽,以及色彩的比特深度记下之后,即可在GRUB命令行模式中按下键盘上的ESC键来回到GRUB菜单。
正常开机之后,使用文本编辑器来编辑GRUB的设置档/etc/default/grub。例如要用Vim来编辑的话,可以直接在终端机运行以下指令:
sudo vim /etc/default/grub
找到GRUB_GFXMODE这个设置项目,缺省应该会被加上井字号#而变成注解,将其解除注解之后,依照以下的方式进行修改:
GRUB_GFXMODE=长x宽x比特深度
最后的比特深度可以省略掉。
理论上这样设置就可以了,但实际上GRUB_GFXMODE这个设置项目常常不能正常工作,建议再加上GRUB_GFXPAYLOAD_LINUX这个项目,并设置为与GRUB_GFXMODE相同的值。网络上有些数据可能会讲说要把GRUB_GFXPAYLOAD_LINUX设置为keep,但这通常无法解决问题。
所以,假设我们想将TTY的屏幕分辨率和色彩比特深度设为1152x864和32比特,则GRUB设置档可以这样写:
GRUB_GFXMODE=1152x864x32
GRUB_GFXPAYLOAD_LINUX=1152x864x32
保存GRUB设置档的变更之后,在终端机运行以下指令来检查并套用新设置:
sudo update-grub
重新开机后,即可看见修改成果。
-
Linux TTY子系统(1) - 了解TTY
2020-10-28 13:05:39了解linux tty 1.TTY概述 TTY 是 Teletype 或 Teletypewriter 的缩写,原来是指电传打字机,后来这种设备逐渐键盘和显示器取代。不管是电传打字机还是键盘显示器,都是作为计算机的终端设备存在的,所以 TTY 也...- 了解linux tty
1.TTY概述
TTY 是 Teletype 或 Teletypewriter 的缩写,原来是指电传打字机,后来这种设备逐渐键盘和显示器取代。不管是电传打字机还是键盘显示器,都是作为计算机的终端设备存在的,所以 TTY 也泛指计算机的终端(terminal)设备。为了支持这些 TTY 设备,Linux 实现了一个叫做 TTY 的子系统。所以 TTY 既指终端,也指 Linux 的 TTY 子系统,当然 TTY 还有更丰富(混乱)的含义。
硬件终端 terminal(TTY):
早期的终端(terminal) 是一台独立于计算机的机器(teletype 即, TTY),样子:
它终端通过线缆与计算机连接,并完成计算机的输入输出功能:
现在物理终端实际上已经灭绝了,看到的所有 TTY 都是模拟视频终端,即软件仿真出来的终端。可以通过 toe -a 命令查看系统支持的终端类型。2.控制台 console
提到终端就不能不提控制台 console。控制台的概念与终端含义非常相近,其实现在经常用它们表示相同的东西,但是在计算机的早期时代,它们确实是不同的东西。
一些数控设备(比如数控机床)的控制箱,通常会被称为控制台,顾名思义,控制台就是一个直接控制设备的面板,上面有很多控制按钮。 在计算机里,把那套直接连接在电脑上的键盘和显示器就叫做控制台。而终端是通过串口连接上的,不是计算机自身的设备,而控制台是计算机本身就有的设备,一个计算机只有一个控制台。计算机启动的时候,所有的信息都会显示到控制台上,而不会显示到终端上。这同样说明,控制台是计算机的基本设备,而终端是附加设备。计算机操作系统中,与终端不相关的信息,比如内核消息,后台服务消息,都可以显示到控制台上,但不会显示到终端上。
现在终端和控制台都由硬件概念,逐渐演化成了软件的概念。简单的说,能直接显示系统消息的那个终端称为控制台,其他的则称为终端(控制台也是一个终端)。或者我们在平时的使用中压根就不区分 Linux 中的终端与控制台。
3.TTY 设备
从历史上看,终端刚开始就是终端机,配有打印机,键盘,带有一个串口,通过串口传送数据到主机端,然后主机处理完交给终端打印出来。电传打字机(teletype)可以被看作是这类设备的统称,因此终端也被简称为 TTY(teletype 的缩写)。
如下图所示:
-
UART 驱动
如上图所示,物理终端通过电缆连接到计算机上的 UART(通用异步接收器和发射器)。操作系统中有一个 UART 驱动程序用于管理字节的物理传输。 -
行规范
上图中内核中的 Line discipline(行规范)用来提供一个编辑缓冲区和一些基本的编辑命令(退格,清除单个单词,清除行,重新打印),主要用来支持用户在输入时的行为(比如输错了,需要退格)。 -
TTY 驱动
TTY 驱动用来进行会话管理,并且处理各种终端设备。 -
UART 驱动、行规范和 TTY 驱动都位于内核中,它们的一端是终端设备,另一端是用户进程。因为在 Linux 下所有的设备都是文件,所以它们三个加在一起被称为 “TTY 设备”,即常说的 TTY。
4.从软件仿真终端到伪终端
后来的终端慢慢演变成了键盘 + 显示器。如果我们要把内容输出到显示器,只要把这些内容写入到显示器对应的 TTY 设备就可以了,然后由 TTY 层负责匹配合适的驱动完成输出,这也是 Linux 控制台的工作原理:
上图中,TTY 驱动和行规范的行为与前面的示例类似,但不再有 UART 或物理终端。相反,软件仿真出视频终端,并最终被渲染到 VGA 显示器。注意,这里出现了软件仿真终端,它们是运行在内核态的。refer to
- https://www.cnblogs.com/sparkdev/p/11460821.html
- http://www.mysixue.com/?p=127
-
linux TTY子系统(3) - tty driver
2020-10-28 14:53:52了解linux tty driver 1.TTY device kernel从设备模型和字符设备两个角度对它进行了抽象: 设备模型的角度 为每个“数据通道”注册了一个stuct device,以便可以在sysfs中体现出来,例如: /sys/class/... -
linux tty驱动架构分析
2021-05-14 04:56:44前一阵子移植一个串口驱动,发现linux的驱动构架中,面向对象的思想已经根深蒂固。就比如这串口驱动,代码中经常有一些貌似和串口无关的代码,比如,tty_register_driver等。但我们却删它不得。因为正是这些代码实现... -
linux tty1-7理解
2021-05-18 14:18:47tty1-6是文本型控制台,7是x-window(图形)控制台.在本地机器上可以通过alt+f1(f1-f7键)切换到对应的登录控制台.比如可以在tty1用root登录,再在tty2登录root,tty1查询的结果跟tty2查询的结果进行对比.因为它不像在xp... -
linux tty个数修改
2020-12-21 10:28:09自动启用的tty@.service数量,默认为6指tty2-tty7 ReserveVT 不包含在NAutoVTs个数中,启用的tty@.service eg: NAutoVTs=3,ReserveVT=6表示启用tty2,3,7 + tty6 关于默认具体是哪个tty,系统不同可能有差异。 2... -
Linux设备模型之tty驱动架构分析
2021-01-31 04:41:59Tty这个名称源于电传打字节的简称。在linux表示各种终端。终端通常都跟硬件相对应。比如对应于输入设备键盘鼠标。输出设备显示器的控制 终端和串口终端.也有对应于不存在设备的pty驱动。在如此众多的终端模型之中,... -
Linux tty字符界面显示方块乱码?一条命令可以解决
2021-05-10 04:52:37tty文本字符界面显示中文乱码是个比较头疼的事情。偶尔一两次也没多大影响,但每执行一条命令之后都会输出方块文字,搞不懂电脑在说啥,的确影响心情。如果碰上mc和nano这样的cli应用,界面菜单上会有大量的方块乱码... -
linux TTY子系统(2) -- 软件框架
2020-10-28 13:47:54为了简化终端的使用,以及终端驱动程序的编写,Linux kernel抽象出了TTY framework:对上,向应用程序提供使用终端的统一接口;对下,提供编写终端驱动程序(如serial driver)的统一框架。TTY framework通过TTY ... -
Linux tty子系统分析之二相关数据结构及设备抽象说明
2020-04-29 23:01:50在上一章我们主要介绍了tty子系统的软件架构,并简要说明了数据结构间的关系,本...struct tty_file_private struct file struct tty_struct struct tty_driver struct tty_operations struct tty_ldisc struct tty... -
Linux tty登录提示Login incorrect的解决方法
2021-07-28 14:27:48Linux切换到tty登录时,明明输入了正确的用户名和密码,可仍然一直提示Login incorrect, 摸索了几次发现,这是由于我的密码中包含数字,而此时num lock数字键盘的锁定状态不正确引起的,只要重新按几下num lock... -
linux虚拟tty驱动(kernel4.9版本以上)
2020-03-21 13:57:45linux虚拟tty驱动(kernel4.9版本以上),可产生多个tty串口设备于/dev/下,本人在Hi3516上交叉编译并应用,实现多个虚拟串口同时控制一个实际串口的操作 -
linux tty driver
2016-12-12 22:05:23Linux TTY 驱动 1.前言 上世纪,六七十年代,虽然已经有电脑了,但还没有普及,电脑还是极其昂贵的,普通老百姓都买不起这么贵的一台电脑。那时候,UNIX的发明人——汤普森,为了实现多用户能够同时登陆UNIX系统... -
Linux tty 命令 command not found tty 命令详解 tty 命令未找到 tty 命令安装 - CommandNotFound ⚡️ 坑...
2021-05-09 01:01:03显示行号|选择喜欢的代码风格默认...tty 命令安装:-bash: tty: command not found#Debianapt-get install coreutils#Ubuntuapt-get install coreutils#Alpine... -
linux tty
2018-01-07 13:20:54who查看系统连接多少个登录终端,tty查看当前的终端号: [root@system1 ~]# tty /dev/pts/3 tty1-6是文本型控制台,7是x-window(图形)控制台.在本地机器上可以通过alt+f1(f1-f7键)切换到对应的登录控制台.比如... -
Linux TTY Driver
2020-03-10 22:58:09引用 蜗蜗科技 ... Linux终端和Line discipline图解 https://blog.csdn.net/dog250/article/details/78818612 一. TTY drive框图 二. TTY framework 2.1 框图 2.2 数据结构图 三. ... -
2.9 Linux tty终端
2017-10-13 11:28:35Linux在内核启动完成以后,需要启动用户态的各种应用服务,让linux可以提供给用户使用。通常用户程序的执行过程如图所示。 其执行顺序是/sbin/init ——–>/sbin/mingetty ——–>/bin/login ——–>/bin/sh。Init... -
Linux中TTY
2021-12-16 16:07:37Linux中TTY1.串行端口终端(/dev/ttySn)2.虚拟终端(/dev/pty/)3.控制终端(/dev/tty)4.控制台终端(/dev/ttyn, /dev/console)5.其它类型 终端是一种字符型设备,它有多种类型,通常使用tty来简称各种类型的终端... -
Linux系统TTY串口驱动实例详解
2022-03-18 16:15:48Linux tty子系统包含:tty核心,tty线路规程和tty驱动。tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。它们的关系如下图: 简单来分的... -
linux-TTY子系统.pdf
2020-07-24 17:32:47在Linux系统中, 与终端相关的概念很容易让人迷糊. 首先有终端这个概念, 然后还有各种类型的终端(串口终端, 伪终端, 控制台终端, 控制终端), 还有一个概念叫console. 那么什么是终端? 什么是控制台终端? 什么是... -
Linux tty子系统分析之三 tty驱动、设备、线路规程的注册以及注销接口说明
2020-04-29 23:02:57在上一章中我们介绍了tty子系统相关的数据结构,本章我们主要介绍tty driver的注册与注销、线路... 主要实现tty controller 驱动的注册与注销操作,相应的函数包括tty_register_driver、tty_unregister_driver,下面... -
linux tty、伪tty是什么?
2022-07-05 10:36:02Linux 黑话解释:TTY 是什么? | Linux 中国看不太懂。。参考文章:linux中tty是什么意思 -
Linux tty串口测试程序
2015-04-10 14:07:53关于termios的详细介绍,可以另行查资料,或者参考:详解linux下的串口通讯开发:http://blog.itpub.net/24790158/viewspace-1041147/ #include #include #include #include #include #include #in