- 문자 디바이스 파일 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) |
'Linux' 카테고리의 다른 글
| 메모리 맵 I/O - mmap()으로 매핑하여 GPIO 직접 제어해보기 (2) | 2025.08.17 |
|---|---|
| [리눅스 커널과 디바이스 드라이버]애플리케이션->syscall->vfs->디바이스파일open 까지 (2) | 2025.08.17 |
| 리눅스 디바이스 드라이버 - module_init() 모듈 등록부터 사용자 호출까지 (1) | 2025.08.17 |
| syscall번호를 테이블에 넣어 커널에 빌트인하여 사용 (2) | 2025.08.17 |
| U-Boot 부팅 흐름 과정 요약 2 -Linux kernel 로드 (3) | 2025.08.16 |