300x250
간단한 Char Device 모듈 구현 - 커널 모듈 프로그래밍
** 리눅스 커널 2.6.36 버전에서 간단한 character device와 그 device driver를 만드는 커널 모듈을 제작한다.
1. 루트 권한을 획득한다.
2. 홈 디렉터리 밑에 module 이라는 디렉토리를 생성하고 그 디렉토리로 이동한다.
3. #yum install -y module-init-tools를 수행한다.
4. #vi minibuf.c를 수행하여 아래와 같이 코딩한다.
#include#include #include #include #include #include #include #define DEVICE_NAME "Minibuf" #define BUFFER_LEN 1024 #define DEV_MAJOR 254 #define DEV_MINOR 5 static int s_bDeviceOpen = 0; static char s_strBuf[BUFFER_LEN]; static int s_nBufPos = 0, s_nBufEnd=0; static int device_open(struct inode *inode, struct file *filp); static int device_release(struct inode *inode, struct file *filp); static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset); static ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset); static int is_buffer_empty(void); static int is_buffer_full(void); static int read_buffer_char(char *buffer); static int write_buffer_char(char *buffer); struct file_operations device_fops={ read: device_read, write: device_write, open: device_open, release: device_release }; static struct cdev minibuf_cdev={ .owner = THIS_MODULE, .ops = &device_fops }; dev_t dev_num = -1; struct cdev *dev_ptr = NULL; int __init init_minibuf(void) { printk("Loading Mini Buffer Module\n"); dev_num = MKDEV(DEV_MAJOR, DEV_MINOR); register_chrdev_region(dev_num, 1, DEVICE_NAME); dev_ptr = cdev_alloc(); cdev_init(dev_ptr, &device_fops); cdev_add(dev_ptr, dev_num, 1); strcpy(s_strBuf, "Hello World\n"); s_nBufEnd = strlen(s_strBuf)+1; return 0; } void __exit exit_minibuf(void) { printk("Unloading Mini Buffer Module\n"); unregister_chrdev_region(dev_num, 1); } int device_open(struct inode *inode, struct file *filp) { printk(DEVICE_NAME ": Device open(%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if(s_bDeviceOpen) { printk(DEVICE_NAME ": Device already open\n"); return -EBUSY; } ++s_bDeviceOpen; return 0; } int device_release(struct inode *inode, struct file *filp) { printk(DEVICE_NAME ":Device release(%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev)); if(!s_bDeviceOpen) { printk(DEVICE_NAME ": Device has not opened\n"); return -EINVAL; } --s_bDeviceOpen; return 0; } ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset) { int count = 0; if(is_buffer_empty()) { printk(DEVICE_NAME ": Read return EOF\n"); return 0; } while(!is_buffer_empty()&&length>1) { read_buffer_char(buffer); ++buffer; --length; ++count; } put_user(0, buffer); ++count; printk(DEVICE_NAME ": Read %d bytes\n", count); return count; } ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset) { return -ENOSYS; } int is_buffer_empty(void) { return(s_nBufPos == s_nBufEnd) ? 1 : 0; } int is_buffer_full(void) { int pos = s_nBufEnd + 1; if(pos == BUFFER_LEN) pos = 0; return (pos == s_nBufPos) ? 1 : 0; } int read_buffer_char(char *buffer) { if(is_buffer_empty()) return -1; put_user(s_strBuf[s_nBufPos], buffer); if(++s_nBufPos == BUFFER_LEN) s_nBufPos =0; return 0; } int write_buffer_char(char *buffer) { if(is_buffer_full()) return -1; get_user(s_strBuf[s_nBufEnd], buffer); if(++s_nBufEnd == BUFFER_LEN) s_nBufEnd = 0; return 0; } module_init(init_minibuf); module_exit(exit_minibuf); MODULE_LICENSE("GPL");
5. #vi Makefile 을 수행하여 아래와 같이 코딩한다.
KERNELDIR = /lib/modules/$(shell uname -r)/build obj-m = minibuf.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm -rf *.ko rm -rf *.mod.* rm -rf .*.cmd rm -rf *.o
6. #make를 수행하여 커널 모듈을 생성한다.
7. #/sbin/insmod minibuf.ko를 수행하여 모듈을 로드시킨다.
8. #/sbin/lsmod를 수행하여 로드된 모듈을 확인한다.
9. #mknod /dev/minibuf c 254 5 를 수행하여 가상 디바이스를 생성한다.
10. #cat /dev/minibuf를 수행하여 가상 디바이스에 저장된 문자열을 읽어 화면에 출력한다.
11. #/sbin/rmmod minibuf를 수행하여 로드된 모듈을 언로드한다.
12. #rm/dev/minibuf를 수행하여 가상 디바이스를 삭제한다.
13. #dmesg로 커널 로그를 확인한다.
반응형
'C & Docker & LINUX' 카테고리의 다른 글
칼리리눅스(kali linux) - static 네트워크 설정 (0) | 2017.09.23 |
---|---|
리눅스 커널) 모듈 프로그래밍(읽기 쓰기가 가능한 Character Device 모듈 구현) (2) | 2017.05.10 |
리눅스 커널 컴파일 (0) | 2017.04.25 |
c언어 - stdout, stderr의 차이점 (0) | 2016.10.11 |
리눅스 C언어 (파일 목록 읽어내기) (0) | 2016.10.08 |