ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디바이스 드라이버 / 주 번호에 의한 파일 처리
    Linux/Linux Device Driver 2020. 9. 1. 12:41

    주 번호에 의한 파일 처리는 register_chrdev()와 register_chrdev_region() 두 가지 함수를 사용할 수 있습니다.

     

     

    pi@raspberrypi:~/Documents/major $ nano major_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 major_open(struct inode *inode, struct file *file)
    {
    	printk("major_open\n");
    
    	return 0;
    }
    
    static ssize_t major_close(struct inode *inode, struct file *file)
    {
    	printk("major_close\n");
    
    	return 0;
    }
    
    static ssize_t major_read(struct file *file, char *buf, size_t count, loff_t *f_pos)
    {
    	int err;
    	char *buff;
    
    	buff = kmalloc(count, GFP_KERNEL);
    
    	if(buff == NULL)
    	{
    		printk("malloc 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("major_read -> count: %d, f_pos: %lld\n", count, *f_pos);
    
    	kfree(buff);
    
    	return 0;
    }
    
    static ssize_t major_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("major_write -> buff: %s, count: %d, f_pos: %lld\n", buff, count, *f_pos);
    
    	kfree(buff);
    
    	return 0;
    }
    
    struct file_operations major_fops = {
    .owner = THIS_MODULE,
    .open = major_open,
    .release = major_close,
    .read = major_read,
    .write = major_write,
    };
    
    int major_init(void)
    {
    	int err;
    
    	printk("major_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 major_exit(void)
    {
    	printk("major_exit\n");
    
    	unregister_chrdev(MAJOR_DEV_NUM, MAJOR_DEV_NAME);
    }
    
    module_init(major_init);
    module_exit(major_exit);
    
    MODULE_AUTHOR("icjk1003@gmail.com");
    MODULE_LICENSE("GPL");

     

     

    pi@raspberrypi:~/Documents/major $ nano major_app.c

    #include <stdio.h>
    #include <fcntl.h>	// open()
    #include <unistd.h>	// write() read()..
    #include <stdlib.h>	// exit()
    #include <string.h>	// strlen()
    
    #define MAJOR_DEV_FILE_NAME "/dev/major_dev"
    
    char *msg = "USER DATA";
    
    int main(int argc, char** argv)
    {
    	int fd;
    	char buf[1024];
    
    	fd = open(MAJOR_DEV_FILE_NAME, O_RDWR);
    
    	if(fd < 0)
    	{
    		printf(MAJOR_DEV_FILE_NAME " open error\n");
    
    		exit(1);
    	}
    
    	read(fd, buf, 20);
    	printf("read data: %s\n", buf);
    
    	write(fd, msg, strlen(msg)+1);
    
    	close(fd);
    
    	return 0;
    }

     

     

    pi@raspberrypi:~/Documents/major $ nano Makefile

    obj-m := major_driver.o
    KDIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
    
    default: major_app major_driver
    
    major_app:
            gcc -o $@ major_app.c		
    major_driver:
            make -C $(KDIR) M=$(PWD) modules
    clean:
            make -C $(KDIR) M=$(PWD) clean
            rm major_app

     

    pi@raspberrypi:~/Documents/major $ sudo make

    pi@raspberrypi:~/Documents/major $ sudo insmod major_driver.ko

     

    pi@raspberrypi:~/Documents/major $ sudo mknod /dev/major_dev 200 0

     

    pi@raspberrypi:~/Documents/major $ sudo ./major_app

    pi@raspberrypi:~/Documents/major $ dmesg

     

    pi@raspberrypi:~/Documents/major $ sudo rmmod major_driver.ko

    pi@raspberrypi:~/Documents/major $ sudo make clean

     

     

     

    KERNEL DATA는 유저 영역에서 볼 수 있고 USER DATA는 커널 영역에서 볼 수 있다.

     

    성공...

     

     

     

    xxx_write() 함수에서는 const char * 매개변수가 가리키는 값을 그대로 읽을 수는 있지만 가리키는 값을 커널 영역으로 복사하지는 못한다. 그래서 copy_from_user() 함수를 사용하여 커널 영역으로 복사해야 한다.

     

    xxx_write() 함수에서는 문자열 포인터를 사용할 경우 kmalloc() 함수로 동적 메모리 할당을 해야 한다. 

     

     

     

     

     

    틀린 점이 있다면 댓글 부탁드리겠습니다. 감사합니다.

     

     

    댓글

Designed by Tistory.