printf("ho_tari\n");
8일차 본문
2025.06.20

리눅스 디바이스 드라이버 ⇒ 임베디드에서 관심 영역
- 역할
- 디바이스 드라이버는 하드웨어를 사용 가능하게 만들어 줄 뿐 하드웨어를 어떻게 사용 할지에 대한 결정은 응용 프로그램에게 넘겨야 한다.
- 고려사항
- 최대한 유연하고 많은 기능을 사용자에게 제공하려고 할 수록 디바이스 드라이버 제작자는 많은 부분을 구현 해야한다.
- 동기식, 비동기식 모두 지원할 것인가?
- 장치를 여러 번 열 것 인가?
- 정책 독립성을 제공할 것인가?
- 제공되는 디바이스 드라이버 유틸리티
- 디바이스 제어와 구성을 도울 목적으로 간단한 유틸리티와 디바이스 드라이버를 같이 출시하는 경우가 있다.
- 모놀리식 방식
- 초기 리눅스 커널은 모놀로딕 방식으로 커널에 모든 디바이스 드라이버를 포함 시켜야 했다.
- 이런 방식은 디바이스가 바뀔때마다 커널 컴파일을 다시 해야 한다.
- 모듈구동 방식
- 커널이 동작중인 상태에서 디바이스 드라이버를 동적으로 추가하거나 제거할 수 있는 개념으로 개발 시간을 효과적으로 단축할 수 있다.
- PCI, USB, PCMCIA에 관련된 디바이스의 PNP기능을 지원하려면 모듈 방식이 필요하다.
- 모듈 방식은 MMU가 있는 프로세서에서만 지원되며, 커널 버전이 동일해야 하는 문제가 있다.
hello_module.c
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Simple Hello World module");
static int __init hello_init(void) {
printk(KERN_INFO "Hello World from kernel module!\n");
return 0;
}
static void __exit hello_exit(void) {
printk(KERN_INFO "Goodbye from kernel module!\n");
}
module_init(hello_init);
module_exit(hello_exit);
Makefile
obj-m := hello_module.o
KDIR := $(HOME)/project/linux
PWD := $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
clean:
make -C $(KDIR) M=$(PWD) clean
make -j12 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-







문자 디바이스 드라이버 예제 (하드웨어 불필요)
char_dev.c
#include <linux/module.h>
#include <linux/fs.h>
#define DEV_NAME "mychardev"
static int major_num;
static ssize_t dev_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
{
const char *msg = "Hello from kernel!\n";
return simple_read_from_buffer(buf, len, offset, msg, strlen(msg));
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.read = dev_read,
};
static int __init char_dev_init(void)
{
major_num = register_chrdev(0, DEV_NAME, &fops);
if (major_num < 0) {
pr_err("Device registration failed\n");
return major_num;
}
pr_info("Major number: %d\n", major_num);
return 0;
}
static void __exit char_dev_exit(void)
{
unregister_chrdev(major_num, DEV_NAME);
pr_info("char_dev removed\n");
}
module_init(char_dev_init);
module_exit(char_dev_exit);
MODULE_LICENSE("GPL");





leddrv.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#define DEV_NAME "led-driver"
#define BCM_BASE 0xFE000000
#define GPIO_BASE (BCM_BASE + 0x200000)
#define GPIO_PIN 18
static void __iomem *gpio_base;
#define INP_GPIO(g) (*(volatile unsigned int *)(gpio_base + ((g)/10)*4) &= ~(7 << (((g)%10)*3)))
#define OUT_GPIO(g) (*(volatile unsigned int *)(gpio_base + ((g)/10)*4) |= (1 << (((g)%10)*3)))
#define GPIO_SET(g) (*(volatile unsigned int *)(gpio_base + 0x1C) = (1 << g))
#define GPIO_CLR(g) (*(volatile unsigned int *)(gpio_base + 0x28) = (1 << g))
static int major;
static ssize_t myled_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
char kbuf[2] = {0};
if (copy_from_user(kbuf, buf, 1)) return -EFAULT;
if (kbuf[0] == '1') {
GPIO_SET(GPIO_PIN); // 켜기
pr_info("LED ON\n");
}
else if (kbuf[0] == '0') {
GPIO_CLR(GPIO_PIN); // 끄기
pr_info("LED OFF\n");
}
return count;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.write = myled_write,
};
static int __init myled_init(void)
{
major = register_chrdev(0, DEV_NAME, &fops);
if (major < 0) return major;
gpio_base = ioremap(GPIO_BASE, 0x100);
INP_GPIO(GPIO_PIN);
OUT_GPIO(GPIO_PIN);
pr_info("myled loaded: /dev/%s (major %d)\n", DEV_NAME, major);
return 0;
}
static void __exit myled_exit(void)
{
unregister_chrdev(major, DEV_NAME);
if (gpio_base) iounmap(gpio_base);
pr_info("myled unloaded\n");
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");
myled.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd;
if (argc != 2 || (argv[1][0] != '0' && argv[1][0] != '1')) {
printf("사용법: %s 0|1\n", argv[0]);
return 1;
}
fd = open("/dev/led-driver", O_WRONLY);
if (fd < 0) {
perror("디바이스 열기 실패");
return 1;
}
write(fd, argv[1], 1);
close(fd);
return 0;
}

sudo mknod /dev/led-driver c $(grep led-driver /proc/devices | awk '{print $1}') 0


'(Telechips) AI 시스템 반도체 SW 개발자 교육 > SoC 시스템 반도체를 위한 임베디드 리눅스' 카테고리의 다른 글
10일차 (0) | 2025.06.24 |
---|---|
9일차 (0) | 2025.06.23 |
7일차 (0) | 2025.06.20 |
6일차 (0) | 2025.06.18 |
5일차 (0) | 2025.06.17 |