-
디바이스 드라이버 / 부 번호에 의한 파일 처리Linux/Linux Device Driver 2020. 9. 1. 12:41
부 번호에 의한 파일 처리는 register_chrdev() 함수를 사용해야 합니다.
그럼 register_chrdev() 함수를 사용하는 이유는 뭘까요?
바로 부 번호로 제어를 하기 위해서는 디바이스 파일과 1:N으로 대응해야 하기 때문입니다.
pi@raspberrypi:~/Documents/minor $ nano minor_driver.c
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> // file_operations 포인터 함수 #include <linux/uaccess.h> // copy_to_user() #include <linux/slab.h> // kmalloc() #define MAJOR_DEV_NAME "major_dev" #define MAJOR_DEV_NUM 200 static int minor1_open(struct inode *inode, struct file *file) { printk("minor1_open\n"); return 0; } static ssize_t minor1_read(struct file *file, char *buf, size_t count, loff_t *f_pos) { char *buff; int err; buff = kmalloc(count, GFP_KERNEL); if(buff == NULL) { printk("kmalloc error\n"); return 0; } sprintf(buff, "KERNEL DATA"); err = copy_to_user(buf, buff, count); if(err != 0) { printk("copy_to_user error\n"); kfree(buff); return err; } printk("minor1_read -> count: %d, f_pos: %lld\n", count, *f_pos); kfree(buff); return 0; } static int minor1_close(struct inode *inode, struct file *file) { printk("minor1_close\n"); return 0; } struct file_operations minor1_fops = { .owner = THIS_MODULE, .open = minor1_open, .read = minor1_read, .release = minor1_close, }; static int minor2_open(struct inode *inode, struct file *file) { printk("minor2_open\n"); return 0; } static ssize_t minor2_write(struct file *file, const char *buf, size_t count, loff_t *f_pos) { char *buff; int err; buff = kmalloc(count, GFP_KERNEL); if(buff == NULL) { printk("kmalloc error\n"); return 0; } err = copy_from_user(buff, buf, count); if(err != 0) { printk("copy_from_user error\n"); kfree(buff); return err; } printk("minor2_write -> buff: %s, count: %d, f_pos: %lld\n", buff, count, *f_pos); kfree(buff); return 0; } static int minor2_close(struct inode *inode, struct file *file) { printk("minor2_close\n"); return 0; } struct file_operations minor2_fops = { .owner = THIS_MODULE, .open = minor2_open, .write = minor2_write, .release = minor2_close, }; static int major_open(struct inode *inode, struct file *file) { printk("major_open\n"); switch(MINOR(inode->i_rdev)) { case 1: file->f_op = &minor1_fops; break; case 2: file->f_op = &minor2_fops; break; default: return -ENXIO; } if(file->f_op && file->f_op->open) { return file->f_op->open(inode, file); } return 0; } struct file_operations major_fops = { .owner = THIS_MODULE, .open = major_open, }; int minor_init(void) { int err; printk("minor_init\n"); err = register_chrdev(MAJOR_DEV_NUM, MAJOR_DEV_NAME, &major_fops); if(err < 0) { printk("register_chrdev error\n"); return err; } return 0; } void minor_exit(void) { printk("minor_exit\n"); unregister_chrdev(MAJOR_DEV_NUM, MAJOR_DEV_NAME); } module_init(minor_init); module_exit(minor_exit); MODULE_AUTHOR("icjk1003@gmail.com"); MODULE_LICENSE("GPL");
pi@raspberrypi:~/Documents/minor $ nano minor_app.c
#include <stdio.h> #include <fcntl.h> // open() #include <unistd.h> // write() read() .. #include <stdlib.h> // exit() #include <string.h> // strlen() #define MINOR1_DEV_FILE_NAME "/dev/minor1_dev" #define MINOR2_DEV_FILE_NAME "/dev/minor2_dev" char *msg = "USER DATA"; int main(int argc, char **argv) { int minor1_fd; int minor2_fd; char buf[1024]; minor1_fd = open(MINOR1_DEV_FILE_NAME, O_RDWR); if(minor1_fd < 0) { printf(MINOR1_DEV_FILE_NAME " open error\n"); exit(1); } minor2_fd = open(MINOR2_DEV_FILE_NAME, O_RDWR); if(minor2_fd < 0) { printf(MINOR2_DEV_FILE_NAME " open error\n"); close(minor1_fd); exit(1); } read(minor1_fd, buf, 20); printf("read data: %s\n", buf); write(minor2_fd, msg, strlen(msg)+1); close(minor1_fd); close(minor2_fd); return 0; }
pi@raspberrypi:~/Documents/minor $ nano Makefile
obj-m := minor_driver.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: minor_app minor_driver minor_app: gcc -o $@ minor_app.c minor_driver: make -C $(KDIR) M=$(PWD) modules clean: make -C $(KDIR) M=$(PWD) clean rm minor_app
pi@raspberrypi:~/Documents/minor $ make
pi@raspberrypi:~/Documents/minor $ sudo insmod minor_driver.ko
pi@raspberrypi:~/Documents/minor $ sudo mknod /dev/read_dev c 200 1
pi@raspberrypi:~/Documents/minor $ sudo mknod /dev/write_dev c 200 2
pi@raspberrypi:~/Documents/minor $ sudo ./minor_app
pi@raspberrypi:~/Documents/minor $ dmesg
pi@raspberrypi:~/Documents/major $ sudo rmmod minor_driver.ko
KERNEL DATA는 유저 영역에서 볼 수 있고 USER DATA는 커널 영역에서 볼 수 있다.
성공..
실행 흐름
[minor_app] open() 함수 실행 /dev/minor1_dev 디바이스 파일 [minor_driver] major_open() 함수 실행 [minor_driver] major_open() 함수에서 /dev/minor1_dev 디바이스 파일에 대한 오퍼레이션 함수 등록(부 번호 함수) [minor_driver] minor1_open() 함수 실행 [minor_app] open() 함수 실행 /dev/minor2_dev 디바이스 파일 [minor_driver] major_open() 함수 실행 [minor_driver] major_open() 함수에서 /dev/minor2_dev 디바이스 파일에 대한 오퍼레이션 함수 등록(부 번호 함수) [minor_driver] minor2_open() 함수 실행 [minor_app] read() 함수 실행 [minor_driver] minor1_read() 함수 실행 [minor_app] write() 함수 실행 [minor_driver] minor2_write() 함수 실행 [minor_app] close() 함수 실행 [minor_driver] minor1_close() 함수 실행 [minor_app] close() 함수 실행 [minor_driver] minor2_close() 함수 실행 위 실행 흐름을 보면 /dev/read_dev, /dev/write_dev 둘 중 어느 파일을 읽어도 major_open() 함수가 실행됩니다.
왜냐하면 주 번호를 인자 값으로 사용하는 register_chrdev() 함수로 등록했기 때문에 디바이스 파일과 1:N로 대응되는 것입니다.
주 번호와 부 번호를 인자 값으로 사용하는 register_chrdev_region() 함수로 등록하면 디바이스 파일과는 1:1 대응됩니다.
틀린 점이 있다면 댓글 부탁드리겠습니다. 감사합니다.
'Linux > Linux Device Driver' 카테고리의 다른 글
디바이스 드라이버 / 시간 처리와 커널 타이머 (0) 2020.09.01 디바이스 드라이버 / LED 제어 (0) 2020.09.01 디바이스 드라이버 / 주 번호에 의한 파일 처리 (0) 2020.09.01 디바이스 드라이버 / 메모리 풀 (0) 2020.09.01 디바이스 드라이버 / 동적 메모리 할당 (0) 2020.09.01