N_TTY

默认(和回退)TTY 行规程。 它尝试按照 POSIX 的规定处理字符。

外部函数

void n_tty_inherit_ops(struct tty_ldisc_ops *ops)

继承 N_TTY 方法

参数

struct tty_ldisc_ops *ops

struct tty_ldisc_ops 在哪里保存 N_TTY 方法

允许“子类”行规程“继承”N_TTY 方法。

内部函数

void n_tty_kick_worker(const struct tty_struct *tty)

启动输入工作进程(如果需要)

参数

const struct tty_struct *tty

终端

描述

如果翻转缓冲区工作可能已停止,则重新安排它。

锁定
  • 调用者持有独占 termios_rwsem,或者

  • n_tty_read()/消费者路径

    持有非独占 termios_rwsem

void n_tty_write_wakeup(struct tty_struct *tty)

异步 I/O 通知器

参数

struct tty_struct *tty

tty 设备

描述

ptys、串行驱动等需要它。因为附加到主设备并依赖 ASYNC IO 的进程必须被唤醒。

void put_tty_queue(u8 c, struct n_tty_data *ldata)

将字符添加到 tty

参数

u8 c

字符

struct n_tty_data *ldata

n_tty 数据

描述

将字符添加到 tty read_buf 队列。

锁定
  • n_tty_receive_buf()/生产者路径

    调用者持有非独占 termios_rwsem

void reset_buffer_flags(struct n_tty_data *ldata)

重置缓冲区状态

参数

struct n_tty_data *ldata

要重置的行规程数据

描述

重置读取缓冲区计数器并清除标志。从 n_tty_open()n_tty_flush_buffer() 调用。

锁定
  • 调用者持有独占 termios_rwsem,或者

  • (不需要锁定)

void n_tty_flush_buffer(struct tty_struct *tty)

清除输入队列

参数

struct tty_struct *tty

终端设备

描述

刷新输入缓冲区。当 tty 层想要刷新缓冲区(例如在挂断时)或者 N_TTY 行规程内部必须清除挂起的队列(例如某些信号)时调用。

持有 termios_rwsem 以排除生产者/消费者,同时重置缓冲区索引。

锁定:ctrl.lock,独占 termios_rwsem

int is_utf8_continuation(u8 c)

utf8 多字节检查

参数

u8 c

要检查的字节

返回值

如果 utf8 字符 c 是多字节延续字符,则为 true。 我们使用它来正确计算打印时字符的屏幕大小。

int is_continuation(u8 c, const struct tty_struct *tty)

多字节检查

参数

u8 c

要检查的字节

const struct tty_struct *tty

终端设备

返回值

如果 utf8 字符 c 是多字节延续字符并且终端处于 unicode 模式,则为 true。

int do_output_char(u8 c, struct tty_struct *tty, int space)

输出一个字符

参数

u8 c

字符(或部分 unicode 符号)

struct tty_struct *tty

终端设备

int space

tty 驱动程序写入缓冲区中的可用空间

描述

这是一个辅助函数,用于处理一个输出字符(包括 TAB、CR、LF 等特殊字符),进行 OPOST 处理并将结果放入 tty 驱动程序的写入缓冲区。

请注意,Linux 目前忽略 TABDLY、CRDLY、VTDLY、FFDLY 和 NLDLY。 它们在今天的世界中根本不相关。 如果您需要它们,请在此处添加它们。

锁定:应在 output_lock 下调用,以保护列状态和缓冲区中的剩余空间。

返回值

使用的缓冲区空间的字节数,如果剩余空间为 0,则为 -1。

int process_output(u8 c, struct tty_struct *tty)

输出后处理器

参数

u8 c

字符(或部分 unicode 符号)

struct tty_struct *tty

终端设备

描述

使用 OPOST 处理输出一个字符。

锁定:output_lock 用于保护列状态和剩余空间(此外,这是从 tty 层的写入锁下的 n_tty_write() 中调用的)。

返回值

当输出设备已满且必须重试字符时为 -1。

ssize_t process_output_block(struct tty_struct *tty, const u8 *buf, unsigned int nr)

块后处理器

参数

struct tty_struct *tty

终端设备

const u8 *buf

字符缓冲区

unsigned int nr

要输出的字节数

描述

使用 OPOST 处理输出一个字符块。

此路径用于加速块控制台写入,以及在处理块输出数据时。 它仅处理通常发现的简单情况,并有助于为控制台驱动程序生成符号块,从而提高性能。

锁定:output_lock 用于保护列状态和剩余空间(此外,这是从 tty 层的写入锁下的 n_tty_write() 中调用的)。

返回值

输出的字符数。

size_t __process_echoes(struct tty_struct *tty)

写入挂起的回显字符

参数

struct tty_struct *tty

终端设备

描述

将先前缓冲的回显(以及其他 ldisc 生成的)字符写入 tty。

由 ldisc 生成的字符(包括回显)需要缓冲,因为驱动程序的写入缓冲区在大量程序输出期间可能会被填满。 在这些条件下,直接回显到驱动程序通常会失败,导致字符丢失并导致 ldisc 状态信息不匹配。

由于 ldisc 状态必须表示写入时实际发送到驱动程序的字符,因此列状态中的某些更改等操作也会保存在缓冲区中并在此处执行。

使用循环 fifo 缓冲区,以便优先处理最近的字符。 此外,当使用带有前缀“^”的回显控制字符时,该对会被原子处理,因此不会分开。

锁定:调用者必须持有 output_lock

void add_echo_byte(u8 c, struct n_tty_data *ldata)

将字节添加到回显缓冲区

参数

u8 c

要回显的 unicode 字节

struct n_tty_data *ldata

n_tty 数据

描述

将字符或操作字节添加到回显缓冲区。

void echo_move_back_col(struct n_tty_data *ldata)

添加向后移动一列的操作

参数

struct n_tty_data *ldata

n_tty 数据

描述

添加一个操作到回显缓冲区,向后移动一列。

void echo_set_canon_col(struct n_tty_data *ldata)

添加一个操作来设置规范列

参数

struct n_tty_data *ldata

n_tty 数据

描述

添加一个操作到回显缓冲区,将规范列设置为当前列。

void echo_erase_tab(unsigned int num_chars, int after_tab, struct n_tty_data *ldata)

添加一个操作来擦除一个 tab

参数

unsigned int num_chars

已使用的字符列数

int after_tab

如果 num_chars 在先前的 tab 之后开始,则为 true

struct n_tty_data *ldata

n_tty 数据

描述

添加一个操作到回显缓冲区,以擦除一个 tab。

由橡皮擦函数调用,该函数知道自先前的 tab 或输入开始以来已使用了多少个字符列。 此信息稍后将与规范列(如果适用)一起使用,以返回正确的列数。

void echo_char_raw(u8 c, struct n_tty_data *ldata)

原始回显字符

参数

u8 c

要回显的 unicode 字节

struct n_tty_data *ldata

行规程数据

描述

将用户输入回显到屏幕上。 只有当 L_ECHO(tty) 为 true 时才能调用此函数。 从 tty_driver.receive_buf() 路径调用。

此变体不会特别处理控制字符。

void echo_char(u8 c, const struct tty_struct *tty)

回显一个字符

参数

u8 c

要回显的 unicode 字节

const struct tty_struct *tty

终端设备

描述

将用户输入回显到屏幕上。 只有当 L_ECHO(tty) 为 true 时才能调用此函数。 从 tty_driver.receive_buf() 路径调用。

此变体标记控制字符以回显为“^X”(其中 X 是表示控制字符的字母)。

void finish_erasing(struct n_tty_data *ldata)

完成擦除

参数

struct n_tty_data *ldata

n_tty 数据

void eraser(u8 c, const struct tty_struct *tty)

处理擦除功能

参数

u8 c

字符输入

const struct tty_struct *tty

终端设备

描述

当来自驱动程序层的流中存在擦除字符时,执行擦除和必要的输出。 处理 UTF-8 多字节符号的复杂性。

锁定:n_tty_receive_buf()/生产者路径

调用者持有非独占 termios_rwsem

void isig(int sig, struct tty_struct *tty)

处理 ISIG 选项

参数

int sig

信号

struct tty_struct *tty

终端

描述

当由于终端输入而发送信号时调用。 从 tty_driver.receive_buf() 路径调用,因此被序列化。

如果 !NOFLSH,则执行输入和输出刷新。 在这种情况下,回显缓冲区是“输出”。 首先处理信号,以提醒任何当前读者或作者停止并退出他们的 i/o 循环。

锁定:ctrl.lock

void n_tty_receive_break(struct tty_struct *tty)

处理中断

参数

struct tty_struct *tty

终端

描述

在传入的比特流中点击了 RS232 中断事件。 根据 termios 设置,这可能会导致各种事件。

锁定:n_tty_receive_buf()/生产者路径

调用者持有非独占 termios_rwsem

注意

如果刷新输入缓冲区,则可能获得独占 termios_rwsem

void n_tty_receive_overrun(const struct tty_struct *tty)

处理溢出报告

参数

const struct tty_struct *tty

终端

描述

数据到达的速度比我们处理的速度快。 虽然 tty 驱动程序已标记此问题,但错过的位将永远消失。

从 receive_buf 路径调用,因此是单线程的。 不需要锁定,因为 num_overrun 和 overrun_time 是函数私有的。

void n_tty_receive_parity_error(const struct tty_struct *tty, u8 c)

错误通知器

参数

const struct tty_struct *tty

终端设备

u8 c

字符

描述

处理奇偶校验错误并排队正确的数据,以在必要时指示错误情况。

锁定:n_tty_receive_buf()/生产者路径

调用者持有非独占 termios_rwsem

bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, u8 c, bool lookahead_done)

接收流控制字符

参数

struct tty_struct *tty

终端设备

u8 c

字符

bool lookahead_done

前瞻已经处理了这个字符

描述

接收和处理流控制字符操作。

如果流控制字符的前瞻已经在正常接收之前提前处理了该字符,则在正常接收期间会跳过这些操作。

如果 c 作为流控制字符被消耗,则返回 true,该字符不能被视为正常字符。

void n_tty_receive_char(struct tty_struct *tty, u8 c)

执行处理

参数

struct tty_struct *tty

终端设备

u8 c

字符

描述

处理从驱动程序收到的输入的单个字符。 通过上述驱动程序的规则,这会相对于自身进行序列化。

锁定:n_tty_receive_buf()/生产者路径

调用者持有非独占 termios_rwsem,如果规范模式处于活动状态,则发布 canon_head

size_t n_tty_receive_buf_common(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count, bool flow)

处理输入

参数

struct tty_struct *tty

设备接收输入

const u8 *cp

输入字符

const u8 *fp

每个字符的标志(如果 NULL,所有字符都是 TTY_NORMAL

size_t count

cp 中的输入字符数

bool flow

启用流量控制

描述

当收到字符块时,由终端驱动程序调用。 必须从软上下文中调用此函数,而不是从中断上下文中调用。 驱动程序负责一次一个地按顺序调用(或使用 flush_to_ldisc())。

在规范模式下,最大行长度为 4096 个字符(包括行终止字符); 长于 4096 个字符的行将被截断。 在 4095 个字符之后,输入数据仍然被处理但不存储。 溢出处理确保 tty 始终可以接收更多输入,直到至少可以读取一行。

在非规范模式下,读取缓冲区只会接受 4095 个字符; 如果输入模式切换到规范模式,这将为换行符提供必要的空间。

请注意,在非规范模式下,读取缓冲区可能会_包含_ 4096 个字符:当模式切换到非规范模式时,读取缓冲区可能已经包含规范行的大值 4096 个字符。

锁定:n_tty_receive_buf()/生产者路径

声明非独占 termios_rwsem 发布 commit_head 或 canon_head

返回值

处理的来自 cp 的输入字符数。

void n_tty_set_termios(struct tty_struct *tty, const struct ktermios *old)

termios 数据已更改

参数

struct tty_struct *tty

终端

const struct ktermios *old

先前的数据

描述

当用户更改 termios 标志时,tty 层会调用此函数,以便行规程可以提前计划。 此函数无法休眠,并且受 tty 层的保护,免于重新进入。 用户可以保证,当 ldisc 关闭时,此函数不会被重新进入或正在进行中。

锁定:调用者持有 tty->termios_rwsem

void n_tty_close(struct tty_struct *tty)

关闭此 tty 的 ldisc

参数

struct tty_struct *tty

设备

描述

当由于关闭或纪律变更而关闭此行规程时,从终端层调用。 当其他 ldisc 方法正在进行时,不会调用该函数。

int n_tty_open(struct tty_struct *tty)

打开 ldisc

参数

struct tty_struct *tty

要打开的终端

描述

当此行规程附加到终端设备时调用。 可以休眠。 串行调用,以便不会并行发生其他事件。 在关闭之前不会发生进一步的打开。

bool copy_from_read_buf(const struct tty_struct *tty, u8 **kbp, size_t *nr)

直接复制读取数据

参数

const struct tty_struct *tty

终端设备

u8 **kbp

数据

size_t *nr

数据大小

描述

辅助函数,用于加速 n_tty_read()。仅当 ICANON 关闭时调用;它直接从 tty 队列复制字符。

锁定
  • ldata->atomic_read_lock sem 下调用

  • n_tty_read()/消费者路径

    调用者持有非独占的 termios_rwsem;read_tail 已发布

返回值

如果成功复制了数据,但仍有更多数据可以获取,则为 true。

bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp, size_t *nr)

以规范模式复制读取数据

参数

const struct tty_struct *tty

终端设备

u8 **kbp

数据

size_t *nr

数据大小

描述

用于 n_tty_read() 的辅助函数。仅当 ICANON 打开时调用;它将一行输入(包括行分隔符)复制到结果缓冲区中。

锁定
  • atomic_read_lock 互斥锁下调用

  • n_tty_read()/消费者路径

    调用者持有非独占的 termios_rwsem;read_tail 已发布

注意

当 termios 从非规范模式更改为规范模式并且读取缓冲区包含数据时,n_tty_set_termios() 模拟 EOF 推送(就像输入 C-d 一样),但缓冲区中 _没有_ DISABLED_CHAR。这会导致已经作为输入处理的数据立即可用作输入,即使尚未收到换行符。

int job_control(struct tty_struct *tty, struct file *file)

检查作业控制

参数

struct tty_struct *tty

tty

struct file *file

文件句柄

描述

对此 file/tty 描述符执行作业控制管理检查,如果适用,则发送任何需要的信号,如果应该采取操作,则返回负错误代码。

锁定
  • 重定向写入测试是安全的

  • current->signal->tty 检查是安全的

  • ctrl.lock 用于安全地引用 tty->ctrl.pgrp

ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf, size_t nr, void **cookie, unsigned long offset)

tty 的读取函数

参数

struct tty_struct *tty

tty 设备

struct file *file

文件对象

u8 *kbuf

内核空间缓冲区指针

size_t nr

I/O 大小

void **cookie

如果非 NULL,则这是一个继续读取

unsigned long offset

从哪里继续读取(在 n_tty 中未使用)

描述

执行线路规程的读取。我们保证线路规程不会在我们之下关闭,但我们可能会获得多个并行读取器,并且必须自己处理此问题。我们可能还会遇到挂断。始终在用户上下文中调用,可能会休眠。

此代码必须确保永远不会在挂断时休眠。

锁定:n_tty_read()/consumer 路径

声明非独占的 termios_rwsem;发布 read_tail

ssize_t n_tty_write(struct tty_struct *tty, struct file *file, const u8 *buf, size_t nr)

tty 的写入函数

参数

struct tty_struct *tty

tty 设备

struct file *file

文件对象

const u8 *buf

用户空间缓冲区指针

size_t nr

I/O 大小

描述

终端设备的写入函数。它与其他写入调用者串行化,但不与 termios 更改、读取和其他此类事件串行化。由于接收代码将回显字符,从而调用驱动程序的写入方法,因此 output_lock 在此处调用的输出处理函数以及回显处理函数中使用,以保护列状态和缓冲区中剩余的空间。

此代码必须确保永远不会在挂断时休眠。

锁定:output_lock 用于保护列状态和剩余空间

(请注意,process_output*() 函数本身会获取此锁)

__poll_t n_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)

N_TTY 的 poll 方法

参数

struct tty_struct *tty

终端设备

struct file *file

访问它的文件

poll_table *wait

轮询表

描述

当要求线路规程对数据或特殊事件进行 poll() 时调用。此代码与其他事件(保存打开/关闭)串行化。

此代码必须确保永远不会在挂断时休眠。

锁定:在没有内核锁的情况下调用 -- 很好。