종류
- 문자 디바이스 드라이버: 대부분의 디바이스 드라이버, 구현 간편
- 블록 디바이스 드라이버
- 네트워크 디바이스 드라이버
- 버스 디바이스 드라이버
디바이스 노드
mknod [옵션] <파일이름> <타입> <주번호> <부번호>
- 타입
- c : 문자형
- b : 블록형
- 주번호 : 드라이버마다 고유의 번호, 커널이 할당해주기도
- 부번호 : 드라이버마다 고유의 번호, 드라이버가 할당을 관리
문자 디바이스 드라이버
- 드라이버는 리눅스에서 1바이트 단위로 데이터를 읽고 쓰는 장치를 제어하는 드라이버
- read(), write()와 같이 바이트 단위로 입출력을 처리하는 드라이버
- file_operations를 구현하는 드라이버
- open, read, write, lseek, close 같은 일반적으로 사용하는 파일 함수
- 별도의 시스템콜 없이 새로운 기능 추가 가능 -> 가상 파일 시스템
file_operations를 구현한다?
만약 유저가 write 시스템콜을 호출하면,
커널은 "이 fd에 연결된 파일에 데이터를 쓰라" 라는 요청을 받음.
커널은 이 요청을 처리하기위해서 file_operations.write()를 호출
즉, 정확히 어떤 동작을 할지 정해줘야함
여기서의 write을 구현한다는 말이다
드라이버 등록
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/spinlock.h>
#define BUF_SIZE 16
static DEFINE_RWLOCK(lock);
static char comento_buf[BUF_SIZE] = {0, };
static ssize_t comento_device_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
{
ssize_t ret;
read_lock(&lock);
if(BUF_SIZE <= len + *ppos)
{
len = BUF_SIZE - *ppos;
}
ret = len - copy_to_user(buf, comento_buf + *ppos, len);
*ppos += ret;
read_unlock(&lock);
return ret;
}
static ssize_t comento_device_write(struct file *file, const char __user *buf, size_t len, loff_t *ppos)
{
ssize_t ret;
write_lock(&lock);
if(BUF_SIZE <= len + *ppos)
{
len = BUF_SIZE - *ppos;
}
ret = len - copy_from_user(comento_buf + *ppos, buf, len);
*ppos += ret;
write_unlock(&lock);
return ret;
}
static int comento_device_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
printk(KERN_DEBUG "%s - minor : %d\n", __func__, minor);
return 0;
}
static struct file_operations fops =
{
.open = comento_device_open,
.read = comento_device_read,
.write = comento_device_write,
};
static int __init comento_module_init(void)
{
printk(KERN_DEBUG "%s\n", __func__);
int ret = register_chrdev(177, "comento", &fops);
return ret;
}
static void __exit comento_module_exit(void)
{
unregister_chrdev(177, "comento");
printk(KERN_DEBUG "%s\n", __func__);
}
module_init(comento_module_init);
module_exit(comento_module_exit);
MODULE_AUTHOR("Jin Minu");
MODULE_DESCRIPTION("Example driver");
MODULE_LICENSE("GPL v2");
- 열기 (open)
- 읽기 (read) / 쓰기 구현 (write)
- ----------------테스트과정-----------------
- 커널 재빌드
- rootfs에 마운트
- comento.ko를 rootfs에 이동 (모듈 복사)
- unmount
- qemu실행 후, insmod로 comento.ko 모듈 삽입
- mknod (장치 파일 생성)
- 테스트
이 코드에서는 file_operations에 있는 open, read, write를 구현한다.
또한 spinlock을 사용하여, 특정 파일 사용중에 접근하지 못하도록 함
echo "wow" > /dev/comento 로 쓰기
cat /dev/comento 로 읽기 테스트
파일 특수 제어 (ioctl)
- 사용자 공간에서 커널 공간으로 특정 드라이버에 명령 전달
- 일반적인 read, write로는 부족할 때
udev
- 사용자 공간에서의 장치 파일 자동 생성 및 관리 시스템
- /dev 디렉토리 장치파일을 자동 생성 및 관리
원래 코드는 많이 적지 않으려 했는데..
아무튼, 몇가지 코드는 그냥 생략한다.
종합 정리하면,
드라이버가 하드웨어, 커널사이 연결을 해준다. 드라이버만으로는 유저가 장치를 직접 다루기 어렵다.
그래서 udev라는 시스템이 필요하다.
udev는 드라이버가 인식한 하드웨어를 위한 장치 파일을 /dev에 자동으로 생성하고,
이 파일은 유저 프로그램과 드라이버를 이어주는 역할을 한다.
'Linux' 카테고리의 다른 글
| linux/drivers/char/mem.c 드라이버 분석 (0) | 2025.09.20 |
|---|---|
| objdump활용 vmlinux 분석시 start address의미 (0) | 2025.09.11 |
| 커널 모듈 (insmod, lsmod, rmmod) 커널 API (5) | 2025.07.30 |
| ls 명령어 분석 with strace (1) | 2025.07.29 |
| Kernel 및 System call 디버그 with GDB (0) | 2025.07.28 |