Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- sscanf
- context
- interrupt handler
- ubuntu
- context switch
- fscanf
- activities
- HDR
- fprintf
- 소캣
- DMA
- layouts
- 멀티프로세싱
- 프레임버퍼
- sprintf
- 디스크 축소
- pagefile.sys
- memcmp
- interrupt context
- 속도저하
- gparted
- 문자형 디바이스 파일
- Shared Folder
- 디스크립터
- makefile
- 젠킨스
- intents
- 환경 변수
- usb2.0
- jenkins
Archives
- Today
- Total
do{학습}while
캐릭터 디바이스 드라이버 생성 본문
간단한 캐릭터 디바이스 드라이버 만들기 (문자열 출력 예제)
이번 글에서는 리눅스 커널에서 캐릭터 디바이스 드라이버를 직접 작성하여, 사용자 공간에서 cat /dev/mychardev 명령어로 커널에서 정의한 문자열을 출력하는 방법을 다룹니다.
1. 디바이스 드라이버 코드 (mychardev.c)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "mychardev"
static int major;
static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off) {
char *msg = "Hello from kernel!\n";
int msg_len = strlen(msg);
if (*off >= msg_len)
return 0;
if (len > msg_len - *off)
len = msg_len - *off;
if (copy_to_user(buf, msg + *off, len))
return -EFAULT;
*off += len;
return len;
}
static int my_open(struct inode *i, struct file *f) {
printk(KERN_INFO "mychardev: device opened\n");
return 0;
}
static int my_release(struct inode *i, struct file *f) {
printk(KERN_INFO "mychardev: device closed\n");
return 0;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = my_read,
.open = my_open,
.release = my_release,
};
static int __init my_init(void) {
major = register_chrdev(0, DEVICE_NAME, &fops);
if (major < 0) {
printk(KERN_ALERT "Failed to register character device\n");
return major;
}
printk(KERN_INFO "mychardev loaded with major number %d\n", major);
return 0;
}
static void __exit my_exit(void) {
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_INFO "mychardev unloaded\n");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
2. Makefile 작성
#Makefile 위치 /drivers/Makefile
obj-y += mychardev.o # built-in 드라이버
3. 빌드 및 테스트
$ make linux-rebuild
$ make linux-install
# rebuild된 커널과 함께 qemu 실행
$ dmesg | grep mychardev #mychardev loaded with major number <major 번호>
로그에 major number가 출력되면 성공적으로 등록된 것입니다.
4. 디바이스 노드 생성
$ sudo mknod /dev/mychardev c <major> 0
$ sudo chmod 666 /dev/mychardev
<major>에는 dmesg에 출력된 숫자를 넣습니다.
mknod를 명령어를 실행하게 된다면 디바이스 노드를 생성하게 되는데
/dev 디렉토리 안에 mychardev 이름을 가진 문자형 디바이스 파일(c)을 만들고 메이저 번호 <major>와 마이너 번호 0을 할당하겠다는 의미입니다.
메이저 번호(Major Number)와 마이너 번호(Minor Number)는 리눅스 커널이 디바이스 드라이버와 실제 디바이스 파일을 연결하는 핵심 정보
- 메이저 번호는 커널이 어떤 디바이스 드라이버에 작업을 전달해야 할지를 식별하기 위한 번호입니다.
→ 하나의 드라이버에 하나의 메이저 번호가 할당됩니다. - 마이너 번호는 같은 드라이버가 관리하는 여러 디바이스 인스턴스를 구분하기 위한 번호입니다.
→ 하나의 드라이버(=같은 메이저 번호) 아래에 여러 개의 디바이스 파일이 있을 수 있고, 이들을 마이너 번호로 식별합니다.
메이저 번호는 드라이버 초기화 단계에서 register_chrdev() 함수를 통해 반환값 형태로 제공 받을 수 있게 됩니다
5. 결과 확인
$ echo hello > /dev/mychardev
mychardev: opened
mychardev: closed
# write 기능 정의 없어 동작 X
$ cat /dev/mychardev
mychardev: opened
mychardev: closed
# read 기능 정의 없어 동작 X
커널에서 mychardev 문자형 디바이스 파일을 열거나(open), 파일에 문자 쓰기(write), 작업을 다 끝나고 파일을 빠져나오는(release) 시점에 드라이버에서 정의한 함수들이 실행되게 됩니다.
참고
- 문자열을 출력할 때 read() 함수는 사용자 공간으로 데이터를 복사하는 역할을 합니다.
- copy_to_user()를 통해 사용자 공간에 안전하게 데이터를 전달해야 합니다.
- offset(*off) 값을 사용하여 한 번 읽은 이후 다시 읽을 때는 0을 반환하도록 구현해야 합니다.