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 -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /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, NULL, 0); // 설정한 write 함수가 불린다. write(fd, NULL, 0); // 설정한 ioctl 함수가 불린다. ioctl(fd, 0, 0); // 설정한 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 |