강좌 & 팁
타겟보드를 이용하여 디바이스 드라이버를 배워보자!(6)
안녕하세요 이우영 입니다.
저번시간에는 문자 디바이스 드라이버를 만들어 보았습니다.
오늘은 저번 시간에 이어서 read, write 함수를 만들어 보겠습니다.
1. 소스 코드 작성
call_dev.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#define CALL_DEV_NAME "call_dev" //디바이스 이름
#define CALL_DEV_MAJOR 240
static char *buff = NULL;
int call_open( struct inode *inode, struct file *filp)
{
printk( "device open\n" );
return 0;
}
int call_release( struct inode *inode, struct file *filp )
{
printk( "device close\n" );
return 0;
}
ssize_t
call_read( struct file *filp, char *buf, size_t count, loff_t *f_pos )
{
//커널의 data를 응용프로그램으로 복사
copy_to_user( buf, buff, count );
return
count;
}
ssize_t
call_write( struct file *filp, const char *buf,
size_t count, loff_t *f_pos )
{
//응용프로그램의 data를 커널로 복사
copy_from_user( buff, buf, count );
return
count;
}
struct file_operations call_fops = //응용프로그램과 디바이스를 연결해주는 구조체
{
.owner = THIS_MODULE,
.open = call_open,
.release = call_release,
.read = call_read,
.write = call_write,
};
int call_init( void )
{
int result;
printk( "call_init\n");
//커널에서 사용하는 동적 할당
buff = (char *)kmalloc( 1024, GFP_KERNEL );
//문자 디바이스 등록
result = register_chrdev( CALL_DEV_MAJOR, CALL_DEV_NAME, &call_fops );
if( result < 0 )
return result;
return 0;
}
void call_exit( void )
{
printk( "call_exit\n");
//문자 디바이스 해지
unregister_chrdev( CALL_DEV_MAJOR, CALL_DEV_NAME );
//커널에서 사용하는 동적 할당 해제
kfree( buff );
}
module_init( call_init );
module_exit( call_exit );
MODULE_LICENSE("Dual BSD/GPL");
Makefile
저번 시간에 작성한 소스코드에서 진하게 된 부분만 추가 되었습니다.
(make 잊지 말고 해주세요)
이번에는 2개의 응용프로그램을 만들어 보겠습니다.
write 하는 app와 read하는 app 입니다.
call_write.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define DEVICE_FILENAME "/dev/call_dev"
int main()
{
int dev;
char buff;
dev = open( DEVICE_FILENAME, O_RDWR | O_NDELAY );
if( dev >= 0 )
{
printf( "wirte start\n" );
buff = 'a'; write( dev, &buff, sizeof(char) ); close( dev ); } return 0; call_read.c #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define DEVICE_FILENAME "/dev/call_dev" int main() { int dev; char
buff; int ret; dev = open( DEVICE_FILENAME, O_RDWR |
O_NDELAY ); if( dev
>= 0 ) { printf( "read
start\n" ); ret = read( dev, &buff, sizeof(char) ); printf( "read
data = %c\n", buff); close( dev ); } return
0;
} arm-generic-linux-gnueabi-gcc-4.3.2 call_write.c -o call_write arm-generic-linux-gnueabi-gcc-4.3.2 call_read.c -o call_read 위 명령어를 해주시면 다음과 같이 실행 파일들이 생성 됩니다.
2. 동작 테스트 그럼 동작을 확인해 보도록 하겠습니다. 포드를 컴퓨터에 연결하시고 minicom을 실행해 주세요!
프로그램 복사를 까먹었내요 ㅎㅎ 다시 리눅스 터미널 창에서 call_read와 call_write를 /nfs 폴더로 복사해주세요 그럼 위와같이 파일이 생겼습니다. 그럼 디바이스를 올리고 테스트 해보도록 하겠습니다.
오늘도 mknod 명령을 통해 파일부터 생성합니다. 그리고 디바이스를 등록해주세요. 먼저 call_read 를 실행해보면 data를 넘긴적이 없기 때문에 아무것도 나오지 않습니다. call_write를 해준 후에는 그림과 같이 'a'가 출력 됩니다. 3. 소스 설명 이번에 처음 보는 함수들이 있을 수 있습니다. kmalloc , kfree, copy_to_user, copy_from_user 이 4가지 함수 입니다. kmalloc과 kfree는 응용프로그램에서 사용하던 malloc과 free 함수를 생각하시면 좋습니다. 커널에서 동적 할당을 받고 해제하는 함수 입니다. 커널에서 사용하는 것이기 때문에 제약사항이 많지만 저정도 크기라면 문제는 없을 것입니다. copy_to_user, copy_from_user는 커널에서 사용하는 data 카피 명령어 입니다. copy_to_user(*to_user, *from_kernel,data_size) 커널로부터(from_kernel) 유저메모리영역(to_user)으로 data_size만큼 복사한다. copy_from_user(*to_kernel, *from_user,data_size) 유저메모리영역(from_user)으로 부터 커널메모리 영역(to_kernel)으로 data_size만큼 복사한다. 오늘은 응용프로그램에서 write를 하고 다른 응용프로그램에서 read를통해 data를 주고 받아 보았습니다. 오늘은 여기까지 간단하게 알아보았습니다. 커널에서 위의 4가지 함수들을 사용해야하는것을 명심하세요. 그럼 다음시간에 만나요~ 빠른만남을 원하시면 http://ms-osek.org/ 여기로 찾아오세요~