Linux 장치 노드는 응용 프로그램과 장치 드라이버 사이의 브리지입니다. 장치 노드는 "/dev"에 생성되며 커널과 사용자 계층을 연결하는 허브입니다. 하드 디스크의 inode와 동일하며 정보를 기록합니다. 하드웨어 장치의 위치 및 정보입니다. 장치 노드를 통해 사용자는 하드웨어를 통해 커널과 통신하고, 장치를 읽고 쓰고, 기타 작업을 수행할 수 있습니다.
이 튜토리얼의 운영 환경: linux5.9.8 시스템, Dell G3 컴퓨터.
디바이스 노드란 무엇입니까
사람 사이의 소통의 다리는 언어입니다. 마찬가지로 애플리케이션과 장치 드라이버도 통신을 위해 브리지가 필요합니다. 이 브리지는 장치 노드입니다.
Linux 시스템의 경우 모든 IO 리소스는 파일, 디렉터리, 하드 디스크, 장치 등을 포함한 파일입니다. 키보드는 컴퓨터 시스템의 입력 장치이며 운영 체제도 이를 파일에서 추상화합니다. 키보드에서 사용자가 입력한 데이터를 얻으려면 키보드가 제공하는 장치 노드만 읽으면 됩니다. .
Linux 시스템에서는 키보드가 입력 장치로 사용되며 해당 장치 노드는 "/dev/input" 아래에 있습니다. 이 폴더에는 event로 시작하는 파일이 많이 있습니다. 이는 모든 입력 장치의 장치 노드입니다. 어떤 장치 노드가 키보드인지 확인하는 방법은 무엇입니까? 키보드를 Raspberry Pi에 연결하고 터미널을 열고 "sudo cat /dev/input/event0"을 실행하고 키보드를 탭한 후 출력이 없으면 출력이 있는 노드를 찾을 때까지 다음 노드로 변경한 다음 이 노드로 이동합니다. 키보드 해당 장치 노드입니다.
디바이스 노드는 /dev 아래에 생성되며 커널과 사용자 레이어를 연결하는 허브입니다. 이는 디바이스가 해당 인터페이스의 어떤 ID에 연결된다는 의미입니다. 하드디스크의 아이노드(inode)에 해당하며 하드웨어 장치의 위치와 정보를 기록한다. 리눅스에서는 모든 장치가 파일 형태로 /dev 디렉터리에 저장되며 파일을 통해 접근한다. 리눅스 커널의 장치 노드이다. 장치의 추상화는 장치 노드입니다. 애플리케이션은 특정 드라이버와는 독립적인 표준화된 호출 집합을 통해 장치에 액세스합니다. 드라이버는 이러한 표준 호출을 실제 하드웨어 관련 작업에 매핑하는 역할을 담당합니다.
디바이스 노드의 역할
디바이스 노드를 통해 사용자는 하드웨어의 커널과 통신하고, 디바이스를 읽고 쓰고, 기타 작업을 수행할 수 있습니다.Linux에서 디바이스는 일반 파일처럼 존재합니다. 파일에 접근하는 것과 같습니다
메이저 디바이스 번호는 디바이스의 종류를 나타내고, 마이너 디바이스 번호는 같은 디바이스의 서로 다른 개체를 나타냅니다. 이 시점에서는 디바이스 노드의 존재 형태를 알 수 없습니다디바이스 노드의 존재 형태
게다가 리눅스에는 또 다른 개념이 있는데, 아이노드(inode)와 블록(block)은 하드디스크 한쪽에 있는 블록이자 노드이다. 파일 또는 폴더 아래에 파일의 위치와 파일의 위치를 기록합니다. 예를 들어 일부 시스템은 크기가 4K이고 inode 크기가 제한되어 있습니다. 단일 파일은 4G를 초과할 수 없다고 합니다. 개인적으로 리눅스 드라이버의 노드는 하드디스크의 아이노드와 유사한 것으로 간주할 수 있는데, 이는 하드웨어 장치의 위치와 기타 정보를 기록할 수 있고, 사용자가 접속해야 할 때 사용할 수 있다. 장치 노드에 기록된 정보를 참조하여 장치에 접근합니다장치 노드에서 데이터를 얻는 방법
운영 체제가 IO를 파일로 추상화하는 이유는 가장 큰 장점은 이 파일을 통해 접근할 수 있다는 것입니다. 통합 인터페이스, 다양한 장치와 통신합니다. 이러한 통합 인터페이스는 파일 작업(열기 기능, 읽기 기능, 쓰기 기능 등)을 위해 운영 체제에서 제공하는 시스템 호출 집합입니다. 예를 들어, 장치에서 데이터를 얻으려면 read 함수를 호출하여 해당 장치에 해당하는 장치 노드를 읽으면 됩니다. 물론 읽기 전에 먼저 open 함수를 호출하여 열어야 합니다. 이제 키보드 입력을 예로 들어보겠습니다.1. 장치 노드 열기
장치 노드의 데이터를 읽기 전에 먼저 open 함수를 호출하여 장치 노드를 열어야 합니다. open 기능의 구체적인 사용법은 링크를 참고하세요. 간략한 설명은 다음과 같습니다.
함수 선언:
int open(const char *pathname, int flags);포함할 헤더 파일:
#include <fcntl.h>매개 변수: * 첫 번째 매개 변수(const char *pathname): 열어야 하는 파일 경로를 나타냅니다.* 두 번째 매개변수(int 플래그): 파일을 여는 방법을 나타냅니다. 예를 들어 "O_RDONLY" - 읽기 전용으로 열림, "O_WRONLY" - 쓰기 전용으로 열림, "O_RDWR" - 읽기 및 쓰기로만 열림 등입니다. 반환값: 열기에 성공하면 읽기, 쓰기 등의 기능에 사용할 수 있도록 파일의 파일 설명자를 반환합니다. 그렇지 않으면 -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 장치 노드의 데이터를 읽습니다. , 읽기 기능을 사용해야 합니다. 구체적인 사용 방법은 링크를 참조하세요. 간략한 소개는 다음과 같습니다: 함수 선언:
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。
这里需要理解的是:设备节点是设备驱动程序提供的,且设备节点的数据是设备驱动写入的,而且写入时,是以上述结构的规则写入的,这是双方通过b8aef83627d8109d104c626ed7bbfbbd约定好的,那么应用程序去设备节点中读取数据之后,也需要按照上述结构去解析数据。那这个结构具体是什么意思呢?
* 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 장치 노드 란 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!