[커널] Read/Write/ioctl

정재훈·2022년 5월 10일
0

Kernel

목록 보기
4/8

Read / Write 추가하기

read : 커널 모듈로부터 장문의 데이터 받기
write : 커널 모듈로에 장문의 데이터 보내기

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    printf("OPEN FILE!!\n");
    int fd = open("/dev/nobrand", O_RDWR);  // 읽기 쓰기 둘가 가능 모드로 설정
    if (fd == -1) {
        printf("FILE OPEN ERROR!!!\n");
        return 0;
    }

    //write
    write(fd, "Let's go\n", 7);

    //read
    char buf[100];
    read(fd, buf, 100);
    printf("%s\n", buf);
    printf("%s\n", buf);

    printf("CLOSE FILE!!\n");
    close(fd);

    return 0;
}

nobrand.c

#include <linux/module.h>
#include <linux/fs.h>

#define NOD_NAME "nobrand"
#define NOD_MAJOR 100

MODULE_LICENSE("GPL");

static int nobrand_open(struct inode *inode, struct file *filp) {
    printk( KERN_INFO "OPEN!!!\n");
    return 0;
}

static int nobrand_release(struct inode *inode, struct file *filp) {
    printk( KERN_INFO "CLOSE!!!\n");
    return 0;
}

static ssize_t nobrand_read(struct file *filp, char *buf, size_t count, loff_t *ppos) {

    buf[0] = 'H';
    buf[1] = 'I';
    buf[2] = '\0';

    return count;
}

static ssize_t nobrand_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
{
    printk( KERN_INFO "HIHI\n\n");
    printk( KERN_INFO "app message : %s\n", buf);
    return count;
}

static struct file_operations fops = {
    .open = nobrand_open,
    .release = nobrand_release,
    .read = nobrand_read,
    .write = nobrand_write
};

static int nobrand_init(void) {
    printk( KERN_INFO "OK HELLO NOBRAND!!\n");
    if (register_chrdev(NOD_MAJOR, NOD_NAME, &fops) < 0) {
        printk( KERN_INFO "ERROR!!! register error\n");
    }

    return 0;
}

static void nobrand_exit(void) {
    unregister_chrdev(NOD_MAJOR, NOD_NAME);
    printk( KERN_INFO "BYE BYE\n\n");
}



module_init(nobrand_init);
module_exit(nobrand_exit);

ioctl 추가

ioctl : 만능, read/write 둘다 가능, 대신 가독성 떨어짐
또한 ioctl은 값 하나의 데이터를 보내고 받을 수 있다.
장문의 데이터를 송수신하려면 copy_from_user()와 같은 커널함수를 추가 작성해줘야 한다.

app.c에 추가

#include <sys/ioctl.h>

ioctl(fd, 3, 0);  // 3 전송
ioctl(fd, 4, 0);  // 4 전송

nobrand.c에 추가

static long nobrand_ioctl(struct file *flip, unsigned int cmd, unsigned long arg)
{
    printk( KERN_ALERT "%d\n", cmd);  // 3과 4 커널 로그에 찍음
    return 0;
}

static struct file_operations fops = {
    .open = nobrand_open,
    .release = nobrand_release,
    .read = nobrand_read,
    .write = nobrand_write,
    .unlocked_ioctl = nobrand_ioctl
};

Build 환경

  1. Native 환경 개발 : 개발할 장치 OS에서 코딩하는 것으로, Device Driver와 App을 개발할 때는 유용하다.
  2. Cross Compile : 개발 PC 개발 후 Target 보드로 옮겨 테스트하며 개발하는 것으로, Kernel 혹은 규모가 큰 Device Driver와 App을 개발할 때 유용하다.

참고 : intel CPU 컴파일러를 통해 나온 실행파일은 ARM Core에서 작동되지 않는다. 따라서, ARM 컴파일러를 통해 실행파일을 만들면 된다.

profile
여러 방향으로 접근하는 개발자

0개의 댓글