강좌 & 팁
타겟보드를 이용하여 디바이스 드라이버를 배워보자!(5)
안녕하세요 이우영 입니다.
저번시간에는 여러 파일을 이용해서 하나의 모듈을 만들어 보았습니다.
오늘 부터 본격적인 디바이스 드라이버를 만들어 보겠습니다.
오늘은 문자 디바이스 드라이버를 만들어 보겠습니다.
1. 문자 디바이스?
문자 디바이스란 무엇일까요?
이건 파일처럼 읽고 쓸수 있는 디바이스를 의미 합니다. ???
리눅스는 모든 접근을 파일로 접근을 하게 됩니다. 디바이스 또한 파일을 읽는것처럼 디바이스의 정보를 읽어 옵니다.
하지만 이런 동작을 그냥 해주지 않겠죠? 바로 디바이스 드라이버가 이런 동작을 하도록 작성을 해야합니다.
음 몬가 어려운걸 건드렸구나!! 하실지 모르지만 문자 디바이스 드라이버가 요구하는건 많지 않습니다. ㅎㅎ
파일 접근을 하기위해 사용되는 기본적인 것들(open, close, read, write)등을 만들어 주시면 됩니다.
이부분은 소스코드를 보시면 조금더 쉽게 이해하실 수 있습니다. (무챔임 ㅎㅎ)
오늘은 간단하게 open, close를 해보겠습니다.
2. 소스 코드 작성
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
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;
}
struct file_operations call_fops = //응용프로그램과 디바이스를 연결해주는 구조체
{
.owner = THIS_MODULE,
.open =
call_open,
.release =
call_release,
};
int call_init( void )
{
int
result;
printk( "call_init\n");
//문자 디바이스 등록
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 );
}
module_init(
call_init );
module_exit(
call_exit );
MODULE_LICENSE("Dual BSD/GPL");
Makefile
이로써 디바이스 드라이버가 준비 되었습니다.
(make 해주세요~)
위 소스코드는 꼭 손으로 치면서 주석을 읽어 보시고 가볍게 머리에 담아 두세요!! (이해하기 좋습니다.ㅎㅎ)
다음은 이 디바이스 드라이버를 사용하는 으용프로그램을 만들어 보겠습니다.
call_app.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;
dev = open( DEVICE_FILENAME, O_RDWR |
O_NDELAY );
if( dev
>= 0 )
{
close( dev );
}
return
0;
으용프로그램은 다음과 같이 컴파일 해주시면 파일이 생성 됩니다.
arm-generic-linux-gnueabi-gcc-4.3.2 call_app.c -o call_app
위와 같이 2개의 파일이 있으면 ok입니다. 문론 call_app도 /nfs 폴더로 복사해주세요~
(cp call_app /nfs 입니다.)
3. 동작 및 설명
자! 드디어 동작을 확인해 보도록 하겠습니다.
포드를 컴퓨터에 연결하시고 minicom을 실행해 주세요!
mount 연결하시고 파일을 확인해 봅시다.
그럼 먼저 디바이스 드라이버 부터 등록을 해보겠습니다.
오늘은 귀찮은 작업을 하나 해줘야해요 무엇일까요?
위에서 문자 디바이스 드라이버는 파일처럼 읽고 쓴다고 했죠?
바로 파일을 만들어 주어야 합니다.
파일 만드는 방법은 mknod 명령을 이용해야 합니다.
mknod 뒤에 옵션들을 알아 보겠습니다.
/dev/call_dev -> /dev 폴더 안에 call_dev 파일을 만드는 겁니다.
c -> 파일 속성으로 문자 디바이스 드라이버라는 것을 알려줍니다.
240 0 -> 디바이스의 주번호와 부번호입니다.( 리눅스는 친절하게 테스트용으로 쓰라고 240을 남겨 주셨습니다 ㅎㅎ)
insmod를 하면 call_init이 호출 되겠죠?
여기서 register_chrdev 함수를 호출하여 문자 디바이스드라이버를 등록합니다.
파일의 이름과 디바이스번호, 그리고 file_operations 구조체를 넘겨 줍니다.
file_operations구조체는 간단하게 응용프로그램의 시스템 콜(open 등)과
디바이스 드라이버의 실제 동작하는 함수를 연결해주는 구조체입니다.
여기까지만 알아두시고 응용프로그램을 실해해 보겠습니다.
응용프로그램은 딱 2가지 일을 하죠? open과 close입니다.
하지만 위에 주황색 박스친 메시지가 호출되었습니다.
이메시지는 디바이스 드라이버에서 나온 메시지입니다.
(pc에서 했다면 안보일 수 있습니다. 커널 메시지는 평소에 숨겨두니까요
지금은 임베디드 환경이라 커널 메시지와 터미널 메시지가 같이 시리얼로 넘어옵니다)
응용프로그램에서 open 함수를 호출하니 디바이스 드라이버의 call_open이 호출되었습니다.
생각보다 간단하죠? 오늘은 여기까지 하겠습니다.
다음 시간에는 read, write를 해보도록 하겠습니다.
file_operations나 call_open의 동작이 궁금 하신분은 책을사세요!!
공짜로 얻어지는건 없습니다!! 디바이스드라이버 저자 유영창 <- 이책 잘 나와있습니다.
(실은 다른책이 없어요 ㅎㅎ 번역서는 품절! 그렇다고 책이 나쁘다는건 아닙니다. )
그럼 다음 시간에 만나요~~
빠른만남을 원하시면 http://ms-osek.org/ 여기로 찾아오세요~