본문으로 바로가기

Character Device Driver 실습

category LinuxEmbedded 3년 전

Character Device Driver 실습

Source Code & Makefile 작성

  • 작업 디렉터리 생성(위치는 아무곳이나 상관 없음)
$ mkdir driver
$ cd driver
$ mkdir chardev
  • Source Code 작성
    • 생성한 chardev 디렉터리 밑에 생성(chardev.c)
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>

#define CHR_DEV_NAME "chardev"
#define CHR_DEV_MAJOR 255

int chr_open(struct inode * inode, struct file * file)
{
    // process open operation
    int number = MINOR(inode->i_rdev);
    printk("Virtual Character Device Open : Minor Number is %d\n", number);
    return 0;
}

ssize_t chr_write(struct file * file, const char * buf, size_t count, loff_t * f_pos)
{
    printk("write data : %s\n", buf);
    return count;
}

ssize_t chr_read(struct file * filep, char * buf, size_t count, loff_t * f_pos)
{
    printk("read data : %s\n", buf);
    return count;
}

long chr_ioctl(struct file * filep, unsigned int cmd, unsigned long arg)
{
    switch(cmd) {
        case 0: printk("cmd value is %d\n", cmd); break;
        case 1: printk("cmd value is %d\n", cmd); break;
        case 2: printk("cmd value is %d\n", cmd); break;
        case 3: printk("cmd value is %d\n", cmd); break;
        case 4: printk("cmd value is %d\n", cmd); break;
    }
    return 0;
}

int chr_release(struct inode * inode, struct file * filep)
{
    // process close operation
    printk("Virtual Character Device Release\n");
    return 0;
}

struct file_operations chr_fops =
{
    .owner          = THIS_MODULE,
    .write          = chr_write,
    .read           = chr_read,
    .open           = chr_open,
    .release        = chr_release,
    .unlocked_ioctl = chr_ioctl,
};

int chr_init(void)
{
    int registration;
    printk("Registration Character Device to Kernel\n");
    registration = register_chrdev(CHR_DEV_MAJOR, CHR_DEV_NAME, &chr_fops);
    if (registration < 0)
        return registration;
    printk("Major Number : %d\n", registration);
    return 0;
}

void chr_exit(void)
{
    printk("Unregistration Character Device to Kernel\n");
    unregister_chrdev(CHR_DEV_MAJOR, CHR_DEV_NAME);
}

module_init(chr_init);
module_exit(chr_exit);

MODULE_LICENSE("GPL");

  • Makefile 작성
    • 생성한 chardev 디렉터리 밑에 생성(Makefile)
obj-m += chardev.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all :
        make -C $(KDIR) M=$(PWD) modules
clean :
        rm -rf chardev.o chardev.mod.* chardev.ko

빌드 및 결과 확인

  • 빌드
$ cd driver/chardev
$ make
$ ls

  • module 설치 및 결과 확인
$ mkmod /dev/chardev c 255 0        // 코드에 명시한 내용과 똑같이 주번호 255, 부번호 0
$ insmod chardev.ko
$ lsmod | head -n 5
$ dmsg | tail -n 5
$ rmmod chardev
$ dmesg | tail -n 5

디바이스 드라이버 테스트

  • 테스트 코드 작성
    • 아무 위치에 상관없음
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

#define DEVICE_FILE_NAME "/dev/chardev"

int main(int argc, char *argv[])
{
    int device;
    char wbuf[128] = "Write buffer data";
    char rbuf[128] = "Read buffer data";
    int n = atoi(argv[1]);

    device = open(DEVICE_FILE_NAME, O_RDWR|O_NDELAY);
    if (device >= 0)
    {
        printf("Device file Open\n");
        ioctl(device, n);
        write(device, wbuf, 10);
        printf("Write value is %s\n", wbuf);
        read(device, rbuf, 10);
        printf("Read value is %s\n", rbuf);
    } else {
        perror("Device file open fail");
    }
    close(device);
    return 0;
}

  • 테스트 코드 실행
$ gcc -o chardev_test chardev_test.c
$ ./chardev_test 1
$ dmesg | tail -n 5

LinuxEmbedded카테고리의 다른글

Arg(인자처리) Module Programming  (0) 2022.09.15
Basic Module Programming  (0) 2022.09.13
Basic System Call 구현  (0) 2022.09.07