[임베디드]Device Driver

공부기록·2023년 12월 4일
0
post-thumbnail

🖥️ Device driver

  • device driver란 하드웨어를 관리하기 위하여 필요한 인터페이스이다.
  • 어떻게 쓰이는지 고려하는 것과 policy에 관한 것보단 기능이 잘 구현되는 것이 중요하다. 응용프로그램이 알아서 가져다 쓰는 것

과정

  1. 모듈 프로그램 작성 후 컴파일하여 드라이버 파일(디바이스 파일) 작성 (hello.ko)
  2. mknod를 이용하여 /dev 안에 노드 생성
  3. insmod를 이용하여 디바이스 드라이버를 커널에 등록
  4. register_chrdev를 호출하여 필요한 함수를 지정하고 file_operation 정보들을 문자 디바이스 드라이버로 등록

🏷️ 3개의 클래스

  • Character devices
    • 일련의 바이트들
    • Terminal, Keyboard, Sound Card, Scanner, Printer
  • Block devices
    • disk 같은 host file system
    • floppy disk, hard disk, CD-ROM drivers
    • mount command
  • Network interfaces
    • data 교환

🏷️ number

  • Major number
    • 디바이스를 구분하는 id로register_chrdev를 이용하여 major number가 할당가능하다.
  • Minor number
    • major number가 같은 device를 구분하기 위한 id이다.

🔈 character device file 만들기

mknod /dev/hello c major# minor#

명령어를 실행하면 inode가 생성되어 i_rdev에 number가 i_fop에 device_fops가 할당된다.

🔈 dynamic module linking

  • insmod - 모듈을 커널에 등록하는 명령어
    	insmod hello.ko
  • rmmod - 모듈을 커널에서 제거하는 명령어
    	rmmod hello

🔈 함수들

  • init_module()
    • insmod시 자동 호출되어 major#를 할당한다.
    int register_chdev(unsigned int major, const * name, struct file_operation * fops);
    • major에 0 넣으면 자동 할당된다.
      fops : device(file)에 file operation pointer를 mapping한다.
    • 메모리 할당 및 초기화 진행
  • cleanup_module()
    • rmmod시 자동 호출
    // major# 회수
    void unregister_chrdev(unsigned int major, const * name);
    • 메모리 해제

insmode \rarr init_module( ) \rarr register_chrdev
rmmode \rarr cleanup_module( ) \rarr unregister_chrdev
후엔 file operation에 해당하는 함수 정의

  • open(), release()
    • device count 및 usage count 숫자 설정
  • read(), write(), ioctl()
    • 유저와 커널 사이에 메모리가 전송하도록 하는 명령어
dev = open("/dev/device", O_WRONLY);
write(dev, &buf, 1);
close(dev);

예시

kdriver.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/uaccess.h>

static char device_name[20];
static int result; // holds the return value from register_chrdev
static int major_number=0; // holds major number

int test_open(struct inode *inode, struct file *file){
    printk("Open call for test device \n");
    return 0;
}

int test_release(struct inode *inode, struct file *file) {
    printk("Release call for Char Device \n");
    return 0;
}
ssize_t test_read(struct file *file, char *buffer, size_t length, loff_t *offset) {
    printk("Read Call for test device \n");
    return 0;
}

ssize_t test_write(struct file *file, const char *buffer, size_t length, loff_t *offset) {
    char val;
    printk("Write Call for test device \n ");
    return 0;
}

struct file_operations test_fops = { //mapping
    open : test_open,// open
    read : test_read, // read
    write : test_write, // write
    release : test_release,// release
};
int init_module(void) {
	printk("TEST DEVICE DRIVER\n");

    strcpy(device_name, "TEST_Device");
    result= register_chrdev(major_number, device_name, &test_fops);
    if(result<0) {
        printk("device: can get major number");
        return result;
    }
    if(major_number==0) major_number=result;
        printk("major_number:%d\n",major_number);
        return 0;
 }
    
void cleanup_module(void) {
    printk("Clean Up Module\n");
    unregister_chrdev(major_number,device_name);
}

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("dummy module");
MODULE_AUTHOR("EMBEDDED");

kdriver_test.c

#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
static int fd;

int main(int argc, char **argv){
    char buf[1];
    if((fd=open("/dev/test",O_RDWR))<=0){
    fprintf(stderr,"Open error: %s\n",strerror(errno));
    return 0;
}
read(fd,buf,1);
write(fd,buf,1);
close(fd);



🖥️ Misc device drivers

  • 간단한 device driver는 굳이 복잡하게 major#를 할당할 필요가 없으므로 10정도를 할당한 후 List 형태로 관리한다. List에서 장치는 minor#로 구분한다.

kdriver.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>

static int kdriver_open(struct inode * inode, struct file * file){
    printk("kdriver_open, \n");
    return 0;
}
static int kdriver_release(struct inode * inode, struct file * file){
    printk("kdriver_release, \n");
    return 0;
}
static ssize_t kdriver_read(struct file * file, char * buf, size_t length, loff_t * ofs){
    printk("kdriver_read, \n");
    return 0;
}
static ssize_t kdriver_write(struct file * file, const char * buf, size_t length, loff_t * ofs){
    printk("kdriver_write, \n");
    return 0;
}
static long kdriver_ioctl(struct file * file, unsigned int cmd, unsigned long arg){
    printk("kdriver_ioctl, \n");
    switch(cmd){
        default:
        return ENOTTY;
    }
    return 0;
}
static struct file_operations kdriver_fops = {
    .owner = THIS_MODULE,
    .open = kdriver_open,
    .release = kdriver_release,
    .read = kdriver_read,
    .write = kdriver_write,
    .unlocked_ioctl = kdriver_ioctl, 
}
    
static struct miscdevice kdriver_driver = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "kdriver",
    .fops =&kdriver_fops,
};

static int kdriver_init(void){
    printk("kdriver_init, \n");
    return misc_register(&kdriver_driver);
}
static void kdriver_exit(void){
    printk("kdriver_exit, \n");
    misc_deregister(&kdriver_driver);
}
module_init(kdriver_init);
module_exit(kdriver_exit);

MODULE_AUTHOR("Author of the kdriver to put it here.");
MODULE_DESCRIPTION("Description of the kdriver to put it here.");
MODULE_LICENSE("Dual BSD/GPL");

kdriver_test.c

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#define NODE_NAME "/dev/kdriver"

int main(int argc, char * argv[]) {
int fd;

fd = open(NODE_NAME, O_WRONLY);
if(fd < 0) {
    printf("%s open error...\n", NODE_NAME);
    return -1;
}
write(fd, NULL, 0);
ioctl(fd, 0, 0);
close(fd);
exit(0);
}

0개의 댓글

관련 채용 정보