linux tty驱动实例

为解释 tty 核心如何工作, 我们创建一个小 tty 驱动, 可以被加载, 以及写入读出, 并
且卸载. 任何一个 tty 驱动的主要数据结构是 struct tty_driver. 它用来注册和注销
一个 tty 驱动到 tty 内核, 在内核头文件 <linux/tty_driver.h> 中描述.
为创建一个 struct tty_driver, 函数 alloc_tty_driver 必须用这个驱动作为参数而支
持的 tty 设备号来调用. 这可使用下面的简短代码来完成:
/* allocate the tty driver */
tiny_tty_driver = alloc_tty_driver(TINY_TTY_MINORS);
if (!tiny_tty_driver)
return -ENOMEM;
在 alloc_tty_driver 函数被成功调用后, struct tty_driver 应当用基于 tty 驱动的
需要的正确信息被初始化. 这个结构包含很多不同成员, 但不是为了有一个可工作的 tty
驱动而全部都必须被初始化. 这里有一个例子展示如何初始化这个结构并且建立足够的成
员来创建一个工作的 tty 驱动. 它使用 tty_set_operations 函数来帮助拷贝驱动中定
义的函数操作集合:
static struct tty_operations serial_ops = {
.open = tiny_open,
.close = tiny_close,
.write = tiny_write,
.write_room = tiny_write_room,
.set_termios = tiny_set_termios,
};
...
/* initialize the tty driver */
tiny_tty_driver->owner = THIS_MODULE;
tiny_tty_driver->driver_name = "tiny_tty";
tiny_tty_driver->name = "ttty";
tiny_tty_driver->devfs_name = "tts/ttty%d";
tiny_tty_driver->major = TINY_TTY_MAJOR,
tiny_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
tiny_tty_driver->subtype = SERIAL_TYPE_NORMAL,
tiny_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
tiny_tty_driver->init_termios = tty_std_termios;
tiny_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(tiny_tty_driver, &serial_ops);

上面列出的变量和函数, 以及这个结构如何使用, 在本章的剩下部分讲解.
为注册这个驱动到 tty 核心, struct tty_driver 必须传递到 tty_register_driver 函
数:
/* register the tty driver */
retval = tty_register_driver(tiny_tty_driver);
if (retval)
{
printk(KERN_ERR "failed to register tiny tty driver");
put_tty_driver(tiny_tty_driver);
return retval;
}
当调用 tty_register_driver, 内核创建了所有的不同 sysfs tty 文件为这个 tty 驱动
可能有的整个范围的次设备. 如果你使用 devfs ( 本书不涉及 ) 并且除非指定
TTY_DRIVER_NO_DEVFS 标志, devfs 文件也被创建. 这个标志可被指定如果你只想为这个
实际在系统中存在的设备调用 tty_register_device, 因此用户一直有一个内核中有的最
新的设备视图, 这就是 devfs 用户期望的.
在注册它自己后, 这个驱动通过 tty_register_device 注册它控制的设备. 这个函数有
3 个参数:
•  一个指针指向这个设备所属的 struct tty_driver.
•  设备的次编号
•  一个指针指向这个 tty 设备所绑定的 struct device. 如果这个 tty 设备没绑定
到任何一个 struct device, 这个参数可被设为 NULL.
我们的驱动一次注册所有的 tty 设备, 因为它们是虚拟的并且没有绑定到任何一个物理
设备:
for (i = 0; i < TINY_TTY_MINORS; ++i)
tty_register_device(tiny_tty_driver, i, NULL);
为从 tty 核心注销这个驱动, 所有的通过调用 tty_register_device 而注册的 tty 设
备需要使用对 tty_unregister_device 的调用来清理. 接着 struct tty_driver 必须使
用一个 tty_unregister_driver 调用来注销.
for (i = 0; i < TINY_TTY_MINORS; ++i)
tty_unregister_device(tiny_tty_driver, i);
tty_unregister_driver(tiny_tty_driver);

结构 struct termios

在 struct tty_driver 中的 init_termios 变量是一个 struct termios. 这个变量被用
来提供一个健全的线路设置集合, 如果这个端口在被用户初始化前使用. 驱动初始化这个
变量使用一个标准的数值集, 它拷贝自 tty_std_termios 变量. tty_std_termos 在 tty
核心被定义为:

struct termios tty_std_termios = {
.c_iflag = ICRNL | IXON,
.c_oflag = OPOST | ONLCR,
.c_cflag = B38400 | CS8 | CREAD | HUPCL,
.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
ECHOCTL | ECHOKE | IEXTEN,
.c_cc = INIT_C_CC
};
这个 struct termios 结构用来持有所有的当前线路设置, 给这个 tty 设备的一个特定
端口. 这些线路设置控制当前波特率, 数据大小, 数据流控设置, 以及许多其他值. 这个
结构的不同成员是:
tcflag_t c_iflag;
输入模式标志
tcflag_t c_oflag;
输出模式标志
tcflag_t c_cflag;
控制模式标志
tcflag_t c_lflag;
本地模式标志
cc_t c_line;
线路规程类型
cc_t c_cc[NCCS];
一个控制字符数组
所有的模式标志被定义为一个大的位段. 模式的不同值, 以及它们用在哪里, 可以见在任
何 Linux 发布中都有的 termios 手册页. 内核提供了一套有用的宏定义来获得不同的位.
这些宏定义在头文件 include/linux/tty.h 中定义.
所有的在 tiny_tty_driver 变量中定义的成员有必要有一个工作的 tty 驱动. owner 成
员是为了防止 tty 驱动在 tty 端口打开时被卸载. 在以前的内核版本, 它由 tty 驱动
自己负责处理模块引用计数逻辑. 但是内核程序员认为可能有困难来解决所有的不同的可
能的竞争条件, 因此 tty 核心为 tty 驱动处理所有的这样的控制..
driver_name 和 name 成员看起来非常相似, 然而用于不同用途. driver_name 变量应当
设为某个简单的, 描述性的并且和内核中所有 tty 驱动中是唯一的值. 这是因为它在
/proc/tty/drivers 文件中出现来描述这个驱动给用户, 以及在当前已加载的 tty 驱动
的 sysfs tty 类目录. name 成员用来定义一个名子给单独的分配给这个 tty 驱动的

tty 节点在 /dev 树中. 这个字符串用来创建一个 tty 设备通过在这个字串的后面追加
在使用的 tty 设备号. 它还用来创建一个设备名子在 sysfs /sys/class/tty 目录中.
如果 devfs 在内核中被使能, 这个名子应当包含任何这个 tty 驱动想被放入的子目录.
作为一个例子, 内核中的串口驱动设置这个 name 成员为 tts/ 如果 devfs 被使能,
ttyS 如果它没有被使能. 这个字串也显示在 /proc/tty/drivers 文件中.
如同我们提及的, /proc/tty/drivers 文件展示所有的当前注册的 tty 驱动. 在内核中
注册的 tiny_tty 驱动并且没有 devfs, 这个文件看来如下:
$ cat /proc/tty/drivers
tiny_tty /dev/ttty 240 0-3 serial
usbserial /dev/ttyUSB 188 0-254 serial
serial /dev/ttyS 4 64-107 serial
pty_slave /dev/pts 136 0-255 pty:slave
pty_master /dev/ptm 128 0-255 pty:master
pty_slave /dev/ttyp 3 0-255 pty:slave
pty_master /dev/pty 2 0-255 pty:master
unknown /dev/vc/ 4 1-63 console
/dev/vc/0 /dev/vc/0 4 0 system:vtmaster
/dev/ptmx /dev/ptmx 5 2 system
/dev/console /dev/console 5 1 system:console
/dev/tty /dev/tty 5 0 system:/dev/tty
还有, 当 tny_tty driver 被注册到 tty 核心, sysfs 目录 /sys/class/tty 看来有些
象下面:
$ tree /sys/class/tty/ttty*
/sys/class/tty/ttty0
`-- dev
/sys/class/tty/ttty1
`-- dev
/sys/class/tty/ttty2
`-- dev
/sys/class/tty/ttty3
`-- dev
$ cat /sys/class/tty/ttty0/dev
240:0
major 变量描述这个驱动的主编号是什么. type 和 subtype 变量声明这个驱动是什么
tty 驱动. 对于我们的例子, 我们是一个"正常"类型的串口驱动. 一个 tty 驱动的唯一
的其他子类型可能是一个 "callout" 类型. callout 设备传统上用来控制一个设备的线
路设置. 数据应当通过一个设备节点被发送和接收, 并且任何路线设置改变应当被发送给
一个不同的设备节点, 它是这个 callout 设备. 这要求使用 2 个次编号为每个 tty 设
备. 感激地, 所有的驱动既处理数据也处理线路设置在同一个设备节点, 并且这个
callout 类型很少用在新驱动中.
tty 驱动和 tty 核心都使用 flags 变量来指示驱动的当前状态和它是什么类型 tty 驱
动. 几个在测试或者操作 flags 时你必须使用的位掩码宏被定义了. flags 变量中的 3
个位可被驱动设置:

TTY_DRIVER_RESET_TERMIOS
这个标志说明 tty 核心复位了 termios 设置, 无论何时最后一个进程已关闭这个
设备. 对于控制台和 pty 驱动这是有用的. 例如, 假定用户留置一个终端在一个
奇怪的状态. 在设置了这个标志时, 这个终端被复位为一个正常值当用户注销或者
控制个会话的进程被"杀掉".
TTY_DRIVER_REAL_RAW
这个标志说明 tty 驱动保证发送奇偶或者坏字符通知给线路规程. 这允许线路规
程以一种更快的方式来处理接收到的字符, 因为它不必查看从 tty 驱动收到的每
个字符. 因为速度的得益, 这个值常常为所有 tty 驱动设置.
TTY_DRIVER_NO_DEVFS
这个标志说明当调用 tty_register_driver 时, tty 核心不创建任何 devfs 入口
给这个 tty 设备. 这对任何动态创建和销毁次设备的驱动都是有益的. 设置这个
的驱动的例子是这个 USB-到-串口 驱动, USB 猫驱动, USB 蓝牙 tty 驱动, 以及
好多标准串口设备.
当 tty 驱动后来想注册一个特殊的 tty 设备到 tty 核心, 它必须调用
tty_register_device, 有一个指针到这个 tty 驱动, 并且设备的次编号已被创建. 如果
这个没有完成, tty 核心仍然传递所有的调用到这个 tty 驱动, 但是一些内部的 tty 相
关的功能可能不存在. 这个包括新 tty 设备的 /sbin/hotplug 通知和 tty 设备的
sysfs 表示. 当注册的 tty 设备从机器中被移出, tty 驱动必须调用
tty_unregister_device.
The one remaining bit in this variable is controlled by the tty core and is
called TTY_DRIVER_INSTALLED. This flag is set by the tty core after the driver
has been regis-tered and should never be set by a tty driver.
这个变量中剩下的一位被 tty 核心控制, 被称为 TTY_DRIVER_INSTALLED. 这个标志被
tty 核心在驱动已注册后设置并且应当从不被 tty 驱动设置.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/613665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RLHF与LLM训练的碰撞:寻找最佳实践之路!

了解更多公众号&#xff1a;芝士AI吃鱼 在讨论大型语言模型&#xff08;LLM&#xff09;时&#xff0c;无论是在研究新闻还是教程中&#xff0c;经常提到一个称为“带有人类反馈的强化学习”&#xff08;RLHF&#xff09;的过程。由于RLHF能够将人类偏好纳入优化过程&#xff0…

What does “grep -i“ do?

grep&#xff08; Global Regular Expression Print &#xff09;根据 给定的正则表达式 搜索文本&#xff0c;并将匹配的行打印出来 grep -i 表示查找的过程中忽略大小写 在已安装的rpm包里&#xff0c;查询是否有tree相关的包 rpm -qa | grep -i "tree"在文件中搜…

使用Python打造一个爱奇艺热播好剧提前搜系统

目录 一、系统功能设计 二、数据获取与处理 三、搜索功能实现 四、用户界面设计 五、系统部署与维护 六、总结 随着互联网的普及和人们对于娱乐需求的增加&#xff0c;视频网站成为了人们观看电视剧、电影等视频内容的主要渠道。爱奇艺作为国内知名的视频网站之一&#x…

使用 Asp.net core webapi 集成配置系统,提高程序的灵活和可维护性

前言&#xff1a;什么是集成配置系统&#xff1f; 集成配置系统的主要目的是将应用程序的配置信息与代码分离&#xff0c;使得配置信息可以在不需要修改代码的情况下进行更改。这样可以提高应用程序的灵活性和可维护性。 ASP.NET Core 提供了一种灵活的配置系统&#xff0c;可…

Flink构造宽表实时入库案例介绍

1. 安装包准备 Flink 1.15.4 安装包 Flink cdc的mysql连接器 Flink sql的sdb连接器 MySQL驱动 SDB驱动 Flink jdbc的mysql连接器 2. 入库流程图 3. Flink安装部署 上传Flink压缩包到服务器&#xff0c;并解压 tar -zxvf flink-1.14.5-bin-scala_2.11.tgz -C /opt/ 复…

显示器新赛道Type-C接口

如果把主机比作大脑&#xff0c;那显示器就是眼睛&#xff0c;没有眼睛&#xff0c;大脑再强大也发挥不出效果&#xff0c;所以显示器作为电脑最重要的输出设备&#xff0c;有着举足轻重的地位&#xff0c;可以说在生活中处处都有显示器的影子。其实显示器的历史也是科技发展史…

python第三节:Str字符串类型(3)

str.index(sub[, start[, end]]) 类似于 find()&#xff0c;但在找不到子字符串时会引发 ValueError。 例子&#xff1a; str1 my name is jack!print(str1.index(i))print(str1.index(b)) 结果&#xff1a; Traceback (most recent call last): File "D:/pythonPro…

涛思数据获评北京市“专精特新”中小企业

众所周知&#xff0c;“专精特新”企业是国家引导中小企业增强自主创新能力和核心竞争力&#xff0c;不断提高中小企业发展质量和水平而实施的重大工程&#xff0c;旨在支持企业走专精特新发展之路&#xff0c;更好地促进企业高质量发展&#xff0c;也成为各领域产业链供应的关…

YOLOv8 Ultralytics:使用Ultralytics框架进行定向边界框对象检测

YOLOv8 Ultralytics&#xff1a;使用Ultralytics框架进行定向边界框对象检测 前言相关介绍前提条件实验环境安装环境项目地址LinuxWindows 使用Ultralytics框架进行定向边界框对象检测参考文献 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精…

mysql 索引优化查询

MySQL的索引可以提高数据库查询性能。下面是一些常用的MySQL索引优化技巧&#xff1a; 创建合适的索引&#xff1a;根据查询条件选择合适的列作为索引&#xff0c;并确保这些索引在WHERE子句中被使用到。 示例代码&#xff1a;CREATE INDEX idx_name ON table_name (column_nam…

【设计模式】02-SOLID 设计原则

面向对象编程&#xff08;OOP&#xff09;是一种广泛应用的编程范式&#xff0c;它鼓励开发者通过对象来模拟现实世界。为了提高面向对象设计&#xff08;OOD&#xff09;的质量和可维护性&#xff0c;Robert C. Martin提出了 SOLID 原则&#xff0c;这五个原则构成了编写良好、…

Linux 基于 rsync 实现集群分发脚本 xsync

一、rsync 简介 rsync&#xff08;remote synchronize&#xff09;是 Liunx/Unix 下的一个远程数据同步工具。它可以通过 LAN/WAN 快速同步多台主机间的文件和目录&#xff0c;并适当利用 rsync 算法&#xff08;差分编码&#xff09;以减少数据的传输。 rsync 算法并不是每一次…

Redis 常见数据结构以及使用场景分析

Java面试题目录 Redis 常见数据类型以及使用场景分析 Redis中有string、list、hash、set、sorted set、bitmap这6种数据类型。 string可以用来做缓存&#xff0c;分布式锁&#xff0c;计数器等。 list可以实现消息队列&#xff0c;分页查询等。 hash适合存储对象结构。 set 可…

QT问题 ui提升部件时No such file or directory

问题: qt使用ui对部件提升在编译时找不到对应的头文件 出错原因: 因为将部件提升为自定义部件后&#xff0c;在编译时会去默认的路径下去找头文件&#xff0c;而自定义的头文件并不在默认路径文件下&#xff0c;而是在当前目录下&#xff0c;所以这个时候需要自己指定出自…

回归预测 | Matlab实现RIME-HKELM霜冰算法优化混合核极限学习机多变量回归预测

回归预测 | Matlab实现RIME-HKELM霜冰算法优化混合核极限学习机多变量回归预测 目录 回归预测 | Matlab实现RIME-HKELM霜冰算法优化混合核极限学习机多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现RIME-HKELM霜冰算法优化混合核极限学习机多变…

Redis群集-主从、哨兵、集群

redis群集有三种模式&#xff0c;分别是主从同步/复制、哨兵模式、Cluster ●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均衡和简单的故障恢…

priority_queue比较规则

priority_queue比较规则 std::priority_queue实际上就是一个堆&#xff0c;可用于堆排序。 std::priority_queue是C STL中的一个容器适配器&#xff0c;它提供常数时间查找最大元素的功能。默认情况下&#xff0c;它使用元素的<运算符进行排序&#xff08;升序&#xff09…

关于java的面向对象

关于java的面向对象 我们在前面的文章中&#xff0c;学习到了java的基础知识。类&#xff0c;变量&#xff0c;方法&#xff0c;数组等&#xff0c;我们本篇文章来了解一下&#xff0c;java的面向对象&#xff0c;也是java比较核心的存在&#x1f60a; 1、面向过程的思想&…

Redis 发布订阅

目录 1.Redis Unsubscribe 命令 - 指退订给定的频道。简介语法可用版本: > 2.0.0返回值: 这个命令在不同的客户端中有不同的表现。 示例 2.Redis Subscribe 命令 - 订阅给定的一个或多个频道的信息。简介语法可用版本: > 2.0.0返回值: 接收到的信息 示例 3.Redis Pubsub …

【技能---labelme软件的安装及其使用--ubuntu】

文章目录 概要Labelme 是什么&#xff1f;Labelme 能干啥&#xff1f; Ubuntu20.04安装Labelme1.Anaconda的安装2.Labelme的安装3.Labelme的使用 概要 图像检测需要自己的数据集&#xff0c;为此需要对一些数据进行数据标注&#xff0c;这里提供了一种图像的常用标注工具——la…