커널 포팅 (4. 드라이버 포팅 / 4.3 새로운 드라이버 추가하기)
2025. 3. 6. 19:44ㆍ프로그래밍/시스템
4.3 새로운 드라이버 추가하기
리눅스에서 새로운 디바이스 드라이버를 추가하는 과정은 크게 다음과 같습니다.
- 간단한 문자 디바이스 드라이버 작성 (register_chrdev(), cdev_add())
- /dev 노드 생성 및 접근 (mknod, udev)
- 새로운 하드웨어 인터페이스 추가 (I2C, SPI, GPIO 등)
🔹 간단한 문자(Character) 디바이스 드라이버 작성
문자 디바이스 드라이버는 데이터를 바이트 단위로 읽고 쓰는 장치를 제어하는 드라이버입니다.
예를 들어 시리얼 포트(UART), 키보드, 마우스 등이 문자 디바이스로 동작합니다.
✅ 1️⃣ 문자 드라이버 기본 코드 (my_char_driver.c)
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define DEVICE_NAME "my_char_device"
static int major;
static struct cdev my_cdev;
static char device_buffer[256];
static int my_open(struct inode *inode, struct file *file) {
printk(KERN_INFO "my_char_device: Opened\n");
return 0;
}
static int my_release(struct inode *inode, struct file *file) {
printk(KERN_INFO "my_char_device: Closed\n");
return 0;
}
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) {
int bytes_read = count < sizeof(device_buffer) ? count : sizeof(device_buffer);
if (copy_to_user(buf, device_buffer, bytes_read))
return -EFAULT;
return bytes_read;
}
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) {
int bytes_written = count < sizeof(device_buffer) ? count : sizeof(device_buffer);
if (copy_from_user(device_buffer, buf, bytes_written))
return -EFAULT;
return bytes_written;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
};
static int __init my_init(void) {
dev_t dev;
if (alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME) < 0)
return -1;
major = MAJOR(dev);
cdev_init(&my_cdev, &fops);
if (cdev_add(&my_cdev, dev, 1) < 0) {
unregister_chrdev_region(dev, 1);
return -1;
}
printk(KERN_INFO "my_char_device: Registered with major number %d\n", major);
return 0;
}
static void __exit my_exit(void) {
cdev_del(&my_cdev);
unregister_chrdev_region(MKDEV(major, 0), 1);
printk(KERN_INFO "my_char_device: Unregistered\n");
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple Character Device Driver");
🔹 /dev 노드 생성 및 접근 (mknod, udev)
디바이스 드라이버를 로드하면, /dev 디렉토리 아래에 장치 파일을 생성해야 사용자 공간에서 접근할 수 있습니다.
✅ 1️⃣ 커널 모듈 빌드
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
✅ 2️⃣ 커널 모듈 로드
sudo insmod my_char_driver.ko
✅ 3️⃣ /dev 노드 수동 생성 (mknod) 커널 모듈을 로드하면 dmesg를 통해 major 번호를 확인하고, /dev에 장치 노드를 생성합니다.
dmesg | grep my_char_device
출력 예시:
my_char_device: Registered with major number 240
mknod 명령어로 /dev 노드를 생성:
sudo mknod /dev/my_char_device c 240 0
sudo chmod 666 /dev/my_char_device
✅ 4️⃣ 자동으로 /dev 노드 생성 (udev 설정) 리눅스에서는 udev를 사용하여 자동으로 /dev 노드를 생성할 수도 있습니다.
/etc/udev/rules.d/99-mydevice.rules 파일을 생성:
echo 'KERNEL=="my_char_device", MODE="0666"' | sudo tee /etc/udev/rules.d/99-mydevice.rules
udev 설정 적용:
sudo udevadm control --reload-rules
sudo udevadm trigger
✅ 5️⃣ 장치 테스트
echo "Hello Device" > /dev/my_char_device
cat /dev/my_char_device
출력 예시:
Hello Device
✅ 6️⃣ 드라이버 언로드
sudo rmmod my_char_driver
🔹 새로운 하드웨어 인터페이스 추가 (I2C, SPI, GPIO 등)
리눅스에서는 문자 디바이스 드라이버를 활용하여 I2C, SPI, GPIO 등과 연결된 하드웨어를 제어할 수 있습니다.
📌 1️⃣ I2C 디바이스 드라이버 예제
✅ I2C 드라이버 코드 추가 (my_i2c_driver.c)
#include <linux/module.h>
#include <linux/i2c.h>
#define DEVICE_NAME "my_i2c_device"
static int my_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) {
printk(KERN_INFO "I2C Device Detected: %s\n", id->name);
return 0;
}
static int my_i2c_remove(struct i2c_client *client) {
printk(KERN_INFO "I2C Device Removed\n");
return 0;
}
static struct i2c_device_id my_i2c_idtable[] = {
{ DEVICE_NAME, 0 },
{ }
};
static struct i2c_driver my_i2c_driver = {
.driver = {
.name = DEVICE_NAME,
},
.probe = my_i2c_probe,
.remove = my_i2c_remove,
.id_table = my_i2c_idtable,
};
module_i2c_driver(my_i2c_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple I2C Device Driver");
✅ I2C 드라이버 빌드 및 로드
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
sudo insmod my_i2c_driver.ko
✅ I2C 디바이스 목록 확인
ls /sys/class/i2c-adapter/
i2cdetect -y 1 # I2C 버스에서 디바이스 검색
✅ 정리
- 문자 디바이스 드라이버 작성
- register_chrdev(), cdev_add()를 사용하여 간단한 문자 디바이스 생성
- /dev/my_char_device를 통해 사용자 공간에서 접근 가능
- /dev 노드 생성 및 접근
- mknod 명령어로 장치 파일 수동 생성
- udev 설정을 통해 /dev 자동 생성 가능
- 새로운 하드웨어 인터페이스 추가
- I2C, SPI, GPIO 등의 하드웨어 인터페이스를 문자 디바이스 드라이버로 확장 가능
- i2c_driver 구조체를 사용하여 새로운 I2C 디바이스 지원 가능
'프로그래밍 > 시스템' 카테고리의 다른 글
커널 포팅 (5. 고급 커널 포팅 및 최적화 / 5.2 루트 파일 시스템 설정) (0) | 2025.03.06 |
---|---|
커널 포팅 (5. 고급 커널 포팅 및 최적화 / 5.1 부트로더 커스터마이징) (0) | 2025.03.06 |
커널 포팅 (4. 드라이버 포팅 / 4.2 기존 드라이버 포팅) (0) | 2025.03.06 |
커널 포팅 (4. 드라이버 포팅 / 4.1 기본적인 디바이스 드라이버 개념) (0) | 2025.03.06 |
커널 포팅 (3. 커널 포팅 기본 실습 / 3.3 부트 로그 분석 및 디버깅) (0) | 2025.03.06 |