linux设备节点的概念是什么

56次阅读
没有评论

共计 3606 个字符,预计需要花费 10 分钟才能阅读完成。

这篇文章主要介绍了 linux 设备节点的概念是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇 linux 设备节点的概念是什么文章都会有所收获,下面我们一起来看看吧。

linux 设备节点是应用程序和设备驱动程序沟通的一个桥梁;设备节点被创建在“/dev”,是连接内核与用户层的枢纽,相当于硬盘的 inode 一样的东西,记录了硬件设备的位置和信息。设备节点使用户可以与内核进行硬件的沟通,读写设备以及其他的操作。

本教程操作环境:linux5.9.8 系统、Dell G3 电脑。

什么是设备节点

人和人之间沟通桥梁是语言。同样,应用程序和设备驱动程序沟通也需要一个桥梁。这个桥梁就是设备节点。

对于 Linux 系统,所有的 IO 资源都是文件,包括文件、目录、硬盘、设备等。那么,键盘作为计算机系统中的一款输入设备,操作系统同样也把它抽象了文件,要想获取用户从键盘上输入的数据时,只需要读取键盘提供的设备节点即可。

在 Linux 系统中,键盘作为输入设备,其对应的设备节点位于”/dev/input“下。在这个文件夹下有很多以 event 打头的文件,这些就是所有 input 设备的设备节点。如何确定哪个是键盘的设备节点呢?将键盘连接到树莓派上,打开终端,执行“sudo cat /dev/input/event0”,敲击键盘,如果没有输出,就换下一个节点,直到找到有输出的节点,那这个节点就是键盘对应的设备节点。

设备节点被创建在 /dev 下,是连接内核与用户层的枢纽,就是设备是接到对应哪种接口的哪个 ID 上。相当于硬盘的 inode 一样的东西,记录了硬件设备的位置和信息

在 Linux 中,所有设备都以文件的形式存放在 /dev 目录下,都是通过文件的方式进行访问,设备节点是 Linux 内核对设备的抽象,一个设备节点就是一个文件。应用程序通过一组标准化的调用执行访问设备,这些调用独立于任何特定的驱动程序。而驱动程序负责将这些标准调用映射到实际硬件的特有操作。

设备节点的作用

设备节点使得用户可以与内核进行硬件的沟通,读写设备以及其他的操作

在 linux 里面设备就像是普通文件一样的存在,访问一个设备就好像是访问一个文件一样

主设备号代表着一类设备,次设备号代表着同一类设备的不同个体,说到这里也许并不知道设备节点的存在形式

设备节点的存在形式

另外在 linux 里面还有一个概念,就是 inode 与 block,也就是硬盘一面的块与节点,硬盘里面的 inode 就相当于一个文件或者文件夹,它记录下此文件下面的文件位置所在,文件的位置是以 block 大小对齐的,例如有些系统就是 4K 的大小,而 inode 的大小是有限的,所以就有了单个文件不能超过 4G 的说法。而在 linux 的驱动程序里面的节点在我个人的理解也可以看做是一个类似于硬盘的 inode 一样的东西,里面可以记录硬件设备的位置以及别的一些信息,在用户需要进行访问的时候就参照到设备节点所记录的信息进行设备的访问

如何从设备节点中获取数据

操作系统之所以把 IO 都抽象成了文件,最大的好处就是可以通过统一的接口来访问这个文件,从而和不同的设备沟通。这些统一的接口就是操作系统针对文件操作对外提供的一组系统调用:open 函数、read 函数、write 函数等。比如,如果需要从一个设备中获取数据,只需要调用 read 函数去读取该设备对应的设备节点就可以了,当然在 read 之前,要先调用 open 函数打开。现在以获取键盘输入为例来介绍。

1、打开设备节点

在读取设备节点的数据之前,要先调用 open 函数打开设备节点。open 函数的具体用法可以参考链接。简单描述如下:

函数声明:

int open(const char *pathname, int flags);

需要包含的头文件:

#include  fcntl.h

参数:

* 第一个参数(const char *pathname):表示需要打开的文件路径

* 第二个参数(int flags):表示打开文件的方式,比如,”O_RDONLY”——只读打开;”O_WRONLY”——只写打开;”O_RDWR”——读、写打开,等。

返回值:

如果打开成功,则返回该文件的文件描述符,以供 read,write 等函数使用。否则,返回 -1。

那么,要打开键盘的设备文件(假设是”/dev/input/even10“), 则需要以下代码:

 int keys_fd;
 keys_fd = open(/dev/input/even10 , O_RDONLY);
 if(keys_fd  = 0)
 {
 printf( open /dev/input/event10 device error!\n 
 return -1;
 }

2、读取设备节点的数据

读取设备节点需要使用 read 函数,具体使用方法可以参考链接。简单介绍如下:

函数声明:

ssize_t read(int fd, void *buf, size_t count);

需要包含的头文件:

#include  unistd.h

参数:

* 第一个参数(int fd):要打开文件的文件描述符,来源一般是上述 open 函数的返回值。

* 第二个参数(void *buf):读取到的数据存放的起始位置指针

* 第三个参数(size_t count):要读取的数据字节数

返回值:

* 如果读取成功,则返回实际读取到的字节数

* 如果读取失败,则返回 -1

* 如果返回值小于第三个参数 count,则表示已经读取到文件结尾,返回值表示实际读取的字节数。

在读取键盘的例子中,我们循环读取键盘设备的文件节点,并将设备保存到一个 char buf[24] 的数组中去。具体代码如下:

char buf[24];
while(1)
 if(read(keys_fd, buf, 24) == 24)
 {
 //  成功的从设备节点中获取到了 24 个字节
 ...
 }
}

根据 read 函数用法,当要读取 24 个字节,且 read 函数的返回值是 24 时,表示成功的从设备节点中获取到了 24 个字节。

3、分析从设备节点获取的数据

为什么这里要从键盘的设备驱动获取 24 个字节呢?这是因为正常情况下,从键盘设备节点获取的数据实际上是一个 struct input_event 结构。其定义为:

struct input_event {
 struct timeval time;
 __u16 type;
 __u16 code;
 __s32 value;
};

显然,上述结构体的大小为 24。

这里需要理解的是:设备节点是设备驱动程序提供的,且设备节点的数据是设备驱动写入的,而且写入时,是以上述结构的规则写入的,这是双方通过 linux/input.h 约定好的,那么应用程序去设备节点中读取数据之后,也需要按照上述结构去解析数据。那这个结构具体是什么意思呢?

* struct timeval time:其大小为 16 个字节,具体意义暂时不考虑。

* __u16 type:其大小为 2 个字节,表示 input 设备的类型,比如:EV_KEY 表示上报的是键盘类型的数据,EV_REL 表示相对路径,鼠标就属于这种类型,还是其他等等。

* __u16 code:其大小为 2 个字节,表示事件的代码。比如,如果 type 为 EV_KEY,那么该代码 code 为设备键盘代码。code 值实际上是应用程序和驱动程序约定好的一些固定的值,它可取的值位于 include/uapi/linux/input-event-codes.h 中。举例来讲,根据 Linux 源码下的 include/uapi/linux/input-event-codes.h 文件的第 91 行 #define KEY_Q 16,如果键盘上按下或松开了 Q 键,那么键盘的驱动程序上报的 code 值应该是 16;反之,如果应用程序获取到的值是 19,那么,表示用户按下或松开了键盘上的 Q 键。

* __s32 value:其大小为 4 个字节,事件的值。如果事件的类型代码是 EV_KEY,当按键按下时值为 1,松开时值为 0;

根据上述解释,我们可以添加以下代码来解析从设备节点中获取的数据。

if(t.type == EV_KEY) //  我们只关心 input event 类型为 EV_KEY(按键)的消息
 if(t.value == 0 || t.value == 1)
 {
 printf( key %d %s\n , 
 t.code, // t.code 表示按下或松开了哪个按键
 (t.value) ?  Pressed  :  Released  // t.value 表示按下还是松开了相应的按键
 }

4、关闭设备节点

在从设备节点获取数据完成后,务必调用 close 函数,来关闭设备节点。即

close(keys_fd);

关于“linux 设备节点的概念是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“linux 设备节点的概念是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-03发表,共计3606字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)