캐릭터 장치나 캐릭터 특수 파일은 어떻게 작동하나요?

캐릭터 장치나 캐릭터 특수 파일은 어떻게 작동하나요?

문자 특수 파일을 이해하려고 노력 중입니다. ~에서위키피디아, 내가 아는 한, 이 파일은 한 번에 한 문자씩 데이터를 전송하는 장치에 "인터페이스를 제공"합니다. 내 이해는 시스템이 장치 드라이버를 직접 호출하는 대신 문자 장치를 호출한다는 것입니다. 하지만 파일은 어떻게 이 인터페이스를 제공합니까? 시스템 호출을 번역하는 실행 파일입니까? 무슨 일인지 설명해 줄 수 있는 사람이 있나요?

답변1

실제로는 인터페이스입니다. 이는 "주요" 및 "부" 숫자로 인코딩되어 커널에 대한 연결을 제공합니다.

여기에는 문자 장치와 블록 장치라는 두 가지 유형이 있습니다(글쎄, 세 가지이지만 명명된 파이프는 현재 이 설명의 범위를 벗어납니다).

블록 장치는 출력을 버퍼링하고 나중에 검색할 수 있도록 데이터를 저장하는 저장 장치인 경향이 있습니다.

문자 장치는 오디오나 그래픽 카드 등의 장치나 키보드, 마우스 등의 입력 장치입니다.

각각의 경우 커널이 올바른 드라이버를 로드할 때(부팅 시 또는 다음과 같은 방법을 통해)우데브) 다양한 버스를 검색하여 이 드라이버가 처리하는 장치가 실제로 시스템에 있는지 확인합니다. 그렇다면 적절한 기본/보조 번호를 "수신"하도록 장치를 설정합니다.

(예를 들어, 시스템이 찾은 첫 번째 사운드 카드의 DSP는 메이저/마이너 번호 쌍 14/3을 얻고 두 번째 사운드 카드는 14,35를 얻는 식입니다.)

udev의 /dev이름에 dspmajor 14 min 3이라는 레이블이 붙은 문자 장치로 항목이 생성됩니다.

(이전 또는 최소 크기의 Linux 버전에서는 /dev/가능한 모든 장치 파일이 동적으로 로드되지 않고 단순히 정적으로 포함될 수 있습니다.)

그런 다음 사용자 공간 프로그램이 "문자 특수 파일"이라고 표시된 파일에 액세스하려고 시도하고 적절한 주/부 번호가 있는 경우(예: 오디오 플레이어가 디지털 오디오를 로 보내려고 시도하는 경우 /dev/dsp) 커널은 데이터를 이동해야 한다는 것을 알고 있습니다. 메이저/마이너 번호를 통해 마이너 번호가 드라이버 전송에 첨부됩니다. 아마도 해당 드라이버는 이를 어떻게 해야 할지 알고 있을 것입니다.

답변2

각 파일, 장치 또는 기타 항목은 VFS 내에서 6가지 기본 작업을 지원합니다.

  1. 열려 있는
  2. 폐쇄
  3. 읽다
  4. 쓰다
  5. 찾다
  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 업스트림(실제로 실행하기 위한 상용구 포함):

더 복잡한 예:

답변4

문자 장치는 커널 모듈(또는 커널 자체)에 의해 생성될 수 있습니다. 장치가 생성되면 생성자는 핸들(예: 열기, 읽기 등)에 대한 표준 호출을 구현하는 함수에 대한 포인터를 제공합니다. 그런 다음 Linux 커널은 이러한 기능을 문자 장치와 연결합니다. 예를 들어 사용자 모드 응용 프로그램이 문자 장치 파일에서 read() 함수를 호출하면 커널은 이 호출을 다음으로 라우팅합니다. 드라이버가 생성될 때 지정된 경로입니다. 캐릭터 장치를 만드는 방법에 대한 단계별 튜토리얼이 있습니다.여기를 사용하면 샘플 프로젝트를 만들고 디버거를 사용하여 단계별로 진행하여 장치 개체가 생성되는 방법과 핸들러가 호출되는 시기를 확인할 수 있습니다.

관련 정보