테스트 해본 코드
Struct File Operations
/usr/src/linux-headers-2.6.27-17-generic/include/linux/fs.h
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
int (*fsetattr)(struct file *, struct iattr *);
};
장치 사용 예시
- Device 사용 함수 작성
1. Open()함수 작성
{
printk( "[VB] opened\n" );
return 0;
}
2. struct file_operations 요소 중 .open에 함수를 지정
…
.release = my_release
};
3. 같은 방법으로 read(), write(), release() 등 필요한 함수를 작성
4. struct file_operations에 위와 같은 방법으로 지정
- Device Driver 등록
{
register_chrdev( MAJOR_NUMBER, "virtual_buffer", &vd_fops );
......... 기타 필요한 초기화 작업 .............
buffer = (char*) kmalloc( BUFF_SIZE, GFP_KERNEL );
memset( buffer, 0, BUFF_SIZE);
printk( "[VB] initialized\n");
return 0;
};
- Device Driver 삭제
모듈을 커널에서 제거하게 되면, unregister_chrdev()를 이용하여, 커널에서 Device Driver의 정보를 삭제함.
{
unregister_chrdev( MAJOR_NUMBER, "virtual_buffer" );
kfree( buffer );
printk( "[VB] exited\n");
}
- 예제 소스
[virtual_buffer.c]
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#define BUFF_SIZE 1024
#define MAJOR_NUMBER 250
static char *buffer = NULL;
static int sz_data = 0;
static int my_open( struct inode *inode, struct file *filp )
{
printk( "[VB] opened\n" );
return 0;
}
static int my_release( struct inode *inode, struct file *filp )
{
printk( "[VB] released\n" );
return 0;
}
static ssize_t my_write( struct file *filp, const char *buf, size_t count, loff_t *f_pos )
{
printk( "[VB] write to buffer\n");
if (BUFF_SIZE < count) sz_data = BUFF_SIZE;
sz_data = count;
strncpy( buffer, buf, sz_data);
return count;
}
static ssize_t my_read( struct file *filp, char *buf, size_t count, loff_t *f_pos )
{
printk( "[VB] read from buffer\n" );
copy_to_user( buf, buffer, sz_data);
return sz_data;
}
static struct file_operations vd_fops = {
.read = my_read,
.write = my_write,
.open = my_open,
.release = my_release
};
int __init my_init( void )
{
register_chrdev( MAJOR_NUMBER, "virtual_buffer", &vd_fops );
buffer = (char*) kmalloc( BUFF_SIZE, GFP_KERNEL );
memset( buffer, 0, BUFF_SIZE);
printk( "[VB] initialized\n");
return 0;
}
void __exit my_exit( void )
{
unregister_chrdev( MAJOR_NUMBER, "virtual_buffer" );
kfree( buffer );
printk( "[VB] exited\n");
}
module_init( my_init );
module_exit( my_exit );
MODULE_LICENSE( "GPL" );
- Makefile
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
rm -rf .tmp_versions
- Module Compile
$> make
- virtual_buffer.ko 생성됨.
- Module 실행
= mknod를 이용하여 /dev 안에 node를 생성
- Device Driver 파일을 만들었다면, 일반 프로그램에서는 그 장치를 파일처럼 다루기 위해, 즉 가상파일 시스템으로 접근할 수 있도록 /dev 안에 node로 등록해야 함.
$> mknod /dev/virtual_buffer c 250 0
- insmod를 이용하여 디바이스 드라이버를 커널에 등록
$> insmod virtual_buffer.ko
[ Application을 이용한 module Test ]
#include <string.h> // strlen()
#include <unistd.h> // read, write
#include <fcntl.h> // open, close, O_RDWR, O_NONBLOCK
#define BUFF_SIZE 1024
char *getword()
{
char inputword[256];
memset(inputword, 0x0, 256);
printf("input word : ");
scanf("%s", inputword);
return inputword;
}
int main(void)
{
int fd;
char *str_hello = "Hello, Virtual Buffer!!";
char buff[BUFF_SIZE];
char *str;
if ( 0 < ( fd = open( "/dev/virtual_buffer", O_RDWR)))
{
// init buffer
memset(buff , 0x0, BUFF_SIZE);
write( fd, buff, BUFF_SIZE);
str = getword();
if (str[0] == '1')
{
write( fd, str_hello, strlen( str_hello)+1); // +1: Include NULL
}
else
{
write( fd, str, strlen(str)+1); // +1: Include NULL
}
read( fd, buff, BUFF_SIZE);
printf( "\n%s\n", buff);
close( fd);
}
return 0;
}
- Application Compile 및 실행
$> gcc -o sam sample.c
-o (실행파일을 만듬)
sam (실행파일 이름 지정)
sample.c (compile 할 소스 이름)
$> ./sam (실행, run)