- 문자 디바이스 파일 character device file

사용자 공간 애플리케이션이 /dev/ 아래 디바이스 파일을 통해

커널에 구현된 문자 디바이스 드라이버와 소통할 수 있게 하는 인터페이스.

  • 문자 디바이스는 데이터를 byte 스트림단위로 읽고 쓴다.
  • 키보드,프린터,마우스,콘솔,직렬 포트(UART)등.
  • file_operations 구조체의 read,write함수 등을 구현해 데이터 송수신 처리.

- 블록 디바이스 파일 Block device file

/dev/ 아래 존재, 사용자 공간 애플리케이션이 커널 모드의 블록 디바이스 드라이버와 소통하도록 하는 인터페이스.

  • 데이터를 블록 단위(512B~수KB)로 읽고 씀.→랜덤 액세스 가능.
  • HDD,SSD, eMMC,SD,USB저장장치,CD/DVD 등
  • block_device_operations 구조체와 I/O스케줄러를 이용해 읽기/쓰기 요청을 큐에 넣고 처리한다.

문자 디바이스 파일

디바이스의 주 번호와 부 번호


**디바이스 번호의 자료형**
dev_t : 주 번호 12비트/ 부 번호 20 비트 . 32비트의 크기

#define MAJOR(dev) ((unsigned int) ((dev) >> 20))
메이저 번호:  어떤 드라이버가 이 디바이스를 처리하는지 식별
#define MINOR(dev) ((unsigned int) ((dev) & 0xfffff))
마이너 번호: 동일 드라이버 내 어떤 장치인지(tty,tty0b

typedef __u32 __kernel_dev_t;
typedef __kernel_dev_t dev_t;

문자 디바이스 파일 번호 동적 할당과 등록

dev_t sk_dev;
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name);
alloc_chrdev_region(&my_dev, 0, 1, "my_dev");

*dev : 할당된 디바이스 번호를 저장할 포인터.(my_dev에 저장)
baseminor:할당 시작할 부 번호(minor) (0부터 시작) 
count: 필요한 부 번호 개수 (디바이스 수)                
name: /proc/devices에 등록될 이름 (정보용)       

문자 디바이스 번호 등록 (번호 공간 예약)

dev_t devno = MKDEV(GPIO_MAJOR,GPIO_MINOR);
미리 정한 메이저/마이너 번호를 dev_t로 생성
register_chrdev_region(devno,count,GPIO_DEVICE);
이미 정해진 번호를 커널에 예약 등록,이미 사용중->에러.

#include <linux/fs.h>
int register_chrdev_region(dev_t from, unsigned count, const char *name);

from : 등록할 첫번째 디바이스 번호(메이저,마이너가 포함된 dev_t)
count : 등록할 연속된 디바이스 번호 개수
name : 디바이스 이름 (/proc/devices에 표시)
리턴 : 성공 시 0 실패시 음수 에러 (-EBUSY)

void unregister_chrdev_region(dev_t from, unsigned count);
register_chrdev_region으로 예약한 번호 공간 해제하여 다른 드라이버가 쓸 수 있도록 함.
from : 해제할 첫번째 디바이스 번호(예약한 dev_t)
count :해제할 연속 디바이스 번호 개수

번호 충돌 가능성 있음
번호를 명확히 알고 있어야 함
레거시 코드나 특별한 번호 필요할 때 사용

설명
/proc/devices 커널에 등록된 모든 캐릭터 및 블록 디바이스의 리스트. register_chrdev_region()에 의해 등록됨.
./dev/my_dev 유저 공간에서 사용하는 장치 파일 (device node). 커널이 자동으로 만들지 않음. 직접 mknod하거나 udev 설정 필요.

file_operations 구조체에 연산 등록하여 open,read,write 등의 파일 연산 함수 사용

include./linux/fs.h

file_operations 구조체의 역할

  • 리눅스 커널에서 디바이스 드라이버가 파일 시스템 인터페이스를 구현할 수 있도록 해주는 콜백 함수 집합.
    이 구조체에 함수를 등록함으로써
    open(),read(),write(),ioctl(),mmap()등의 시스템 콜이 호출될 때, 해당 드라이버의 동작이 실행되도록 연결.

cdev 구조체 (linux/cdev.h)

struct cdev { struct kobject kobj;//sysfs와 연동하기 위한 커널 오브젝트 
struct module \*owner;//(THIS\_MODULE)이 모듈이 언로드 되지 않도록 참조를 잡아줌 
const struct file\_operations \*ops;//open,read,write 등 파일 연산 함수들 집합 
struct list\_head list;//내부 연결 리스트. cdev가 여러개 일때 리스트로 관리 
dev\_t dev;//major, minor 조합의 디바이스 번호 
unsigned int count;// cdev가 몇개의 마이너 번호 다루는지(대부분 1개) } __randomize_layout; 

cdev_init (fs/char_dev.c)

구조체를 초기화하고 file operations에 open,write 등의 연산을 연결한다.

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
    memset(cdev, 0, sizeof *cdev);
    INIT_LIST_HEAD(&cdev->list);
    kobject_init(&cdev->kobj, &ktype_cdev_default);
    cdev->ops = fops;
}
 /* cdev_init() - initialize a cdev structure
 * @cdev: the structure to initialize
 * @fops: the file_operations for this device
 */

cdev_add

커널 공간의 문자 디바이스 구조체(struct cdev)를 시스템에 연결하여, 유저가 /dev/~ 경로로 접근할 수 있도록 등록한다.

 /*cdev_add() - add a char device to the system
 * @p: the cdev structure for the device
 * @dev: the first device number for which this device is responsible
 * @count: the number of consecutive minor numbers corresponding to this
 *         device
 *
 * cdev_add() adds the device represented by @p to the system, making it
 * live immediately.  A negative error code is returned on failure.
 */
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
    int error;

    p->dev = dev;
    p->count = count;

    if (WARN_ON(dev == WHITEOUT_DEV)) {
        error = -EBUSY;
        goto err;
    }

    error = kobj_map(cdev_map, dev, count, NULL,
             exact_match, exact_lock, p);
             //cdev_map에 전역 맵에 해당 번호 등록. 
    if (error)
        goto err;

    kobject_get(p->kobj.parent);

    return 0;

err:
    kfree_const(p->kobj.name);
    p->kobj.name = NULL;
    return error;
}

mknod

/dev/에 노드 파일을 만들어서 ,등록된 문자 디바이스에 파일로 유저가 접근할 수 있게한다. 디바이스 번호(major,minor)를 가진 파일을 만든다.

실행 흐름 함수/명령어
1. 디바이스 번호 할당 커널에서 Major,Minor번호 할당 alloc_chrdev_region(&devmfirstminor,count,”name”)
2. cdev 구조체 초기화 및 등록 (cdev 구조체에 파일 연산자 연결) cdev_init(&cdev, &fops) cdev_add(&cdev,dev,count)
3. 유저 공간에서 디바이스 파일 생성 mknod /dev/name c (major) (minor)
4. 유저 프로그램에서 /dev/ 파일을 open() 호출하면 커널 드라이버의 open 함수 호출. open(”/dev/name”,flags)

+ Recent posts