문자 특수 파일을 이해하려고 노력 중입니다. ~에서위키피디아, 내가 아는 한, 이 파일은 한 번에 한 문자씩 데이터를 전송하는 장치에 "인터페이스를 제공"합니다. 내 이해는 시스템이 장치 드라이버를 직접 호출하는 대신 문자 장치를 호출한다는 것입니다. 하지만 파일은 어떻게 이 인터페이스를 제공합니까? 시스템 호출을 번역하는 실행 파일입니까? 무슨 일인지 설명해 줄 수 있는 사람이 있나요?
답변1
실제로는 인터페이스입니다. 이는 "주요" 및 "부" 숫자로 인코딩되어 커널에 대한 연결을 제공합니다.
여기에는 문자 장치와 블록 장치라는 두 가지 유형이 있습니다(글쎄, 세 가지이지만 명명된 파이프는 현재 이 설명의 범위를 벗어납니다).
블록 장치는 출력을 버퍼링하고 나중에 검색할 수 있도록 데이터를 저장하는 저장 장치인 경향이 있습니다.
문자 장치는 오디오나 그래픽 카드 등의 장치나 키보드, 마우스 등의 입력 장치입니다.
각각의 경우 커널이 올바른 드라이버를 로드할 때(부팅 시 또는 다음과 같은 방법을 통해)우데브) 다양한 버스를 검색하여 이 드라이버가 처리하는 장치가 실제로 시스템에 있는지 확인합니다. 그렇다면 적절한 기본/보조 번호를 "수신"하도록 장치를 설정합니다.
(예를 들어, 시스템이 찾은 첫 번째 사운드 카드의 DSP는 메이저/마이너 번호 쌍 14/3을 얻고 두 번째 사운드 카드는 14,35를 얻는 식입니다.)
udev의 /dev
이름에 dsp
major 14 min 3이라는 레이블이 붙은 문자 장치로 항목이 생성됩니다.
(이전 또는 최소 크기의 Linux 버전에서는 /dev/
가능한 모든 장치 파일이 동적으로 로드되지 않고 단순히 정적으로 포함될 수 있습니다.)
그런 다음 사용자 공간 프로그램이 "문자 특수 파일"이라고 표시된 파일에 액세스하려고 시도하고 적절한 주/부 번호가 있는 경우(예: 오디오 플레이어가 디지털 오디오를 로 보내려고 시도하는 경우 /dev/dsp
) 커널은 데이터를 이동해야 한다는 것을 알고 있습니다. 메이저/마이너 번호를 통해 마이너 번호가 드라이버 전송에 첨부됩니다. 아마도 해당 드라이버는 이를 어떻게 해야 할지 알고 있을 것입니다.
답변2
각 파일, 장치 또는 기타 항목은 VFS 내에서 6가지 기본 작업을 지원합니다.
- 열려 있는
- 폐쇄
- 읽다
- 쓰다
- 찾다
- 말하다
또한 장치 파일은 I/O 제어를 지원하므로 처음 6에서 다루지 않는 기타 기타 작업을 허용합니다.
특수 문자의 경우 검색 및 말하기가 지원되므로 구현되지 않습니다.스트리밍 미디어 인터페이스. 즉, 리디렉션을 통해 쉘에서 직접 읽기 또는 쓰기가 수행됩니다.
echo 'foo' > /dev/some/char
sed ... < /dev/some/char
답변3
최소한의 실행 가능한 file_operations
예
최소한의 예를 보면 모든 것이 분명해집니다.
핵심 아이디어는 다음과 같습니다.
file_operations
각 파일 관련 시스템 호출에 대한 콜백을 포함합니다.mknod <path> c <major> <minor>
이를 활용한 캐릭터 장치 만들기file_operations
- 동적으로 할당된 장치 번호(충돌 방지를 위한 사양)가 있는 문자 장치의 경우 다음 명령을 사용하여 번호를 찾습니다.
cat /proc/devices
character_device.ko
커널 모듈:
#include <asm/uaccess.h> /* copy_from_user, copy_to_user */
#include <linux/errno.h> /* EFAULT */
#include <linux/fs.h> /* register_chrdev, unregister_chrdev */
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/printk.h> /* printk */
#include <uapi/linux/stat.h> /* S_IRUSR */
#define NAME "lkmc_character_device"
MODULE_LICENSE("GPL");
static int major;
static ssize_t read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
size_t ret;
char kbuf[] = {'a', 'b', 'c', 'd'};
ret = 0;
if (*off == 0) {
if (copy_to_user(buf, kbuf, sizeof(kbuf))) {
ret = -EFAULT;
} else {
ret = sizeof(kbuf);
*off = 1;
}
}
return ret;
}
static const struct file_operations fops = {
.owner = THIS_MODULE,
.read = read,
};
static int myinit(void)
{
major = register_chrdev(0, NAME, &fops);
return 0;
}
static void myexit(void)
{
unregister_chrdev(major, NAME);
}
module_init(myinit)
module_exit(myexit)
사용자 모드 테스트 프로그램:
insmod /character_device.ko
dev="lkmc_character_device"
major="$(grep "$dev" /proc/devices | cut -d ' ' -f 1)"
mknod "/dev/$dev" c "$major" 0
cat /dev/lkmc_character_device
# => abcd
rm /dev/lkmc_character_device
rmmod character_device
GitHub QEMU + Buildroot 업스트림(실제로 실행하기 위한 상용구 포함):
- https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/character_device.c
- https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/character_device.sh
더 복잡한 예:
read
,write
,lseek
고정 크기 내부 버퍼 및 문자 장치 대신 debugfs 사용:https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/fops.cpoll
:https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/poll.cioctl
:https://github.com/cirosantilli/linux-kernel-module-cheat/blob/6788a577c394a2fc512d8f3df0806d84dc09f355/kernel_module/poll.canon_inode_getfd
file_operations
파일 시스템 파일 없이 파일 설명자 에 a를 연결합니다 .https://stackoverflow.com/questions/4508998/what-is-anonymous-inode/44388030#44388030
답변4
문자 장치는 커널 모듈(또는 커널 자체)에 의해 생성될 수 있습니다. 장치가 생성되면 생성자는 핸들(예: 열기, 읽기 등)에 대한 표준 호출을 구현하는 함수에 대한 포인터를 제공합니다. 그런 다음 Linux 커널은 이러한 기능을 문자 장치와 연결합니다. 예를 들어 사용자 모드 응용 프로그램이 문자 장치 파일에서 read() 함수를 호출하면 커널은 이 호출을 다음으로 라우팅합니다. 드라이버가 생성될 때 지정된 경로입니다. 캐릭터 장치를 만드는 방법에 대한 단계별 튜토리얼이 있습니다.여기를 사용하면 샘플 프로젝트를 만들고 디버거를 사용하여 단계별로 진행하여 장치 개체가 생성되는 방법과 핸들러가 호출되는 시기를 확인할 수 있습니다.