Misc 디바이스 드라이버 구현


- 디바이스 드라이버는 커널 모듈의 한 종류

1. file_operations 구조체를 기반으로 가상 파일 시스템과 연계.

* 사용자는 기존 파일 접근 시스템 호출 재사용.

2. 물리적인 저장 장치나 파일시스템 설계가 아니면 캐릭터 디바이스 드라이버 구현

* 일반적인 하드웨어 제어에 적용

* 최근에는 기존 캐릭터 디바이스 드라이버 대신 기타 디바이스 드라이버로 구현

3. 기타 디바이스 드라이버는 캐릭터 디바이스 드라이버의 일종.

* 노드 파일 관리를 커널이 담당.


- 헤더파일

1. #include <linux/fs.h>

2. #include <linux/miscdevice.h>

3. #include <linux/mutex.h>



- 사용자 함수 구현

1. static int x_open(struct inode *inode, struct file *file){ ...  }

* 응용 프로그램에서 open()을 호출할 때 실행.

2. static int x_release(struct inode * inode, struct file * file){ ... }

* 응용 프로그램에서 close()를 호출할 때 실행.

3. static ssize_t x_read(struct file *file, char *buf, size_t length, loff_t *ofs){ ... }

* 응용 프로그램에서 read()를 호출할 때 실행.

4. static ssize_t x_write(struct file *file, const char *buf, size_t length, loff_t *ofs){ ... }

* 응용 프로그램에서 write()를 호출할 때 실행.

5. static long x_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ ... }

* 응용 프로그램에서 ioctl()을 호출할 때 실행.



- file_operations 구조체에 사용자 구현 함수 연결

1
2
3
4
5
6
7
8
static struct file_operations x_fops = {
    .owner = THIS_MODULE,
    .open = x_open,
    .release = x_release,
    .read = x_read,
    .write = x_write,
    .unlocked_ioctl=x_ioctl
};
cs

* 디바이스 드라이버 소유자를 나타내는 owner에는 THIS_MODULE할당.

* 나머지 필드는 응용 프로그램에서 호출하는 API에 대응해 구현 함수 이름(주소) 할당.




- miscdevice 구조체에 노드 이름 및 file_operations 구조체 연결

1
2
3
4
5
static struct miscdevice x_driver = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "x"//장치 파일 이름
    .fops = &x_fops //파일 오퍼레이션 구조체 포인터 할당
};
cs

* 보조 번호를 나타낸 minor에는 커널이 자동 할당하도록 MISC_DYNAMIC_MINOR 할당

* 기타 디바이스 드라이버의 주 번호는 10번임.

* 디바이스 드라이버가 적재될 때 /dev 경로에 name 노드 파일 자동 생성.

* fops에는 앞서 정의한 file_operations 구조체 포인터 할당.



- 디바이스 드라이버 등록

1. 디바이스 드라이버가 적재 될때 misc_register()를 호출해 등록.

1
2
3
4
static int x_init(void){
    return misc_register(&x_driver);
}
module_init(x_init);
cs

2. [참고] 캐릭터 디바이스 드라이버는 register_chrdev() 호출.

* int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);

* 주 번호는 0-233 까지는 미리 할당되어 있고 234-239 까지는 비어있는 상태며 240-254는 내부 테스트 및 실험용.

* 디바이스 드라이버를 사용하기 전에 /dev 경로에 mknode명령으로 노드 파일을 생성해야 함.



- 디바이스 드라이버 제거

1. 디바이스 드라이버가 제거될 때 misc_deregister()를 호출해 제거

1
2
3
4
static void x_exit(void){
    misc_deregister(&x_driver);
}
module_exit(x_exit);
cs

*노드 파일도 자동으로 제거됨.

2. [참고] 캐릭터 디바이스 드라이버는 unregister_chrdev() 호출.

* int unregister_chrdev(unsigned int manjor, const char *name);

* mknode 명령으로 생성한 노드 파일은 제거되지 않음.



- Makefile은 모듈과 동일

1
2
3
4
5
6
7
8
KBUILD_EXTRA_SYMBOLS :=
 
obj-m := 모듈이름.o
 
default:
        make -/lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
        make -/lib/modules/$(shell uname -r)/build M=$(PWD) clean
cs




Misc 디바이스 드라이버 구현 예제


- 모듈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
    
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
 
// 사용자 구현 함수 : 열기, 닫기, 읽기, 쓰기, ioctl
static int drv_hello_open(struct inode * inode, struct file * file)
{
    printk("%s\n", __FUNCTION__);
    
    return 0;
}
 
static int drv_hello_release(struct inode * inode, struct file * file)
{
    printk("%s\n", __FUNCTION__);
    
    return 0;
}
 
static ssize_t drv_hello_read(struct file * file, char * buf, size_t length, loff_t * ofs)
{
    printk("%s\n", __FUNCTION__);
    
    return 0;
}
 
static ssize_t drv_hello_write(struct file * file, const char * buf, size_t length, loff_t * ofs)
{
    printk("%s\n", __FUNCTION__);
    
    return 0;
}
 
static DEFINE_MUTEX(drv_hello_mutex);
static long drv_hello_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{
    printk("%s\n", __FUNCTION__);
    
    mutex_lock(&drv_hello_mutex);
    switch(cmd){
        default:
            mutex_unlock(&drv_hello_mutex);
            return ENOTTY;
    }
    
    mutex_unlock(&drv_hello_mutex);
    return 0;
}
 
static struct file_operations drv_hello_fops = 
{
    .owner = THIS_MODULE,
 
    // 사용자 구현 함수 연결
    .open = drv_hello_open,
    .release = drv_hello_release,
    .read = drv_hello_read,
    .write = drv_hello_write,
    .unlocked_ioctl = drv_hello_ioctl,
};
 
static struct miscdevice drv_hello_driver = 
{
    .minor = MISC_DYNAMIC_MINOR,
    // 드라이버 파일 이름 설정
    .name = "drv_hello",
    // file_operations 구조체 등록
    .fops = &drv_hello_fops,
};
 
static int drv_hello_init(void)
{
    printk("%s\n", __FUNCTION__);
    
    // 디바이스 드라이버가 적재될때 등록
    // miscdevice 구조체 연결
    return misc_register(&drv_hello_driver);
}
 
static void drv_hello_exit(void)
{
    printk("%s\n", __FUNCTION__);
 
    // 모듈이 제거될때 노드 파일 제거
    misc_deregister(&drv_hello_driver);
    
}
 
module_init(drv_hello_init);
module_exit(drv_hello_exit);
 
MODULE_AUTHOR("PlanX Studio");
MODULE_DESCRIPTION("drv_hello");
MODULE_LICENSE("Dual BSD/GPL");
cs



- 응용 프로그램

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
 
// 생성된 장치파일 위치 및 이름
#define NODE_NAME "/dev/drv_hello"
 
int main(int argc, char * argv[])
{
  // 파일 열기
  // 설정한 open 함수가 불린다.
  int fd = open(NODE_NAME, O_RDWR);
  if(fd < 0)
    {
      printf("%s open error... \n", NODE_NAME);
      return -1;
    }
  // 설정한 read 함수가 불린다.
  read(fd, NULL0);
  // 설정한 write 함수가 불린다.
  write(fd, NULL0);
  // 설정한 ioctl 함수가 불린다.
  ioctl(fd, 00);
  // 설정한 release 함수가 불린다.
  close(fd);
}
cs





출처 : 인지소프트웨어 기술포럼 ( 전유진 강사님 수업자료)


'임베디드 > 디바이스 드라이버' 카테고리의 다른 글

디바이스 드라이버 GPIO 조이스틱 예제  (0) 2017.12.28
Misc 디바이스 드라이버2  (0) 2017.12.27
디바이스 드라이버 구조  (0) 2017.12.26
SYSFS  (1) 2017.12.26
GPIO 제어  (0) 2017.12.26

+ Recent posts