간단한 임베디드 리눅스 드라이버 만들기
q 정의
¦ 장치 파일
– 장치를 접근할 수 있게 하는 파일
– 장치에 입출력 하는 것은 장치에 read/write하는것과 동일
¦ 장치번호
– 주번호(major number)와 부번호(minor number)
– /proc/devices에 사용중인 장치번호가 있음
– test 용으로 사용할 수 있는 major number
• 60~63, 120~127, 240~254
¦ 장치 유형(device type)
– 문자(character device)
– 블록(block device)
– 네트워크(network device)
q 디바이스 드라이버 읽기 쓰기 구조

q 디바이스 내부 구조
¦ 구성요소
– Initialization/termination interface
• init(), init_module(), exit_module()
– File system interface
• Well-defined interface : file_operations
• Character device : open, release, read, write, ioctl
• Block device : open, release, request, ioctl
• Network device : open, close, transmit, receive, ioctl
– Hardware interface
• inb(), inw(), inl(), insb(), insw(), insl()
• outb(), outw(), outl(), outsb(), outsw(), outsl()
• readb(), readw(), readl()
• writeb(), writew(), writel()
q 디바이스 만들기
¦ 순서
– 새 장치를 위한 주 번호를 할당(주 번호를 정하자)
– 디바이스 드라이버를 만들기
– Application 프로그램 만들기
– Make 파일 만들기
– 장치 파일을 생성함
• mknod /dev/mydrv [b|c] major_number minor_number
– 디바이스 드라이버를 컴파일(2가지 방법)
• 커널에 직접 포함하여 컴파일
• 모듈로서 컴파일하고, 나중에 모듈 형태로 삽입함
¦ 새 장치를 위한 주 번호 할당
– 본 예제에서는 주 번호를 240, 부 번호를 0으로 정함
¦ 디바이스 드라이버 만들기
– Source code
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define DEVICE_NAME "mydrv" // device name
#define MYDRV_MAJOR 240 // major number
volatile unsigned int *R_piol;
int mydrv_open(struct inode *inode, struct file *flip)
{
int num = MINOR(inode->i_rdev);
printk("my drv open : minor number is %d\n",num);
return 0;
}
ssize_t mydrv_read(struct file *flip, char *buf,size_t count, loff_t *_pos)
{
unsigned char status;
printk("my_drvread: buf is %d, countis %d \n",*buf,count);
return count;
}
ssize_t mydrv_write(struct file *flip, char *buf,size_t count, loff_t *_pos)
{
printk("my_drv_write: buf is %d, countis %d \n",*buf,count);
*buf=1;
return count;
}
int mydrv_release(struct file *flip, char *buf,size_t count, loff_t *_pos)
{
printk("my_drv_release: bufis %08X, countis %08X \n",buf,count);
return count;
}
int mydrv_ioctl(struct inode *inode, struct file *flip, int ioctl_param)
{
printk("mydrv_ioctl(): ioctl_param %d \n",ioctl_param);
return 0;
}
struct file_operations mydrv_fops ={
//llseek :mydrv_llseek,
read :mydrv_read,
write :mydrv_write,
ioctl :mydrv_ioctl,
open :mydrv_open,
release :mydrv_release
};
static int hello_init(void)
{
int result;
printk("init moudle \n");
result = register_chrdev(MYDRV_MAJOR,DEVICE_NAME,&mydrv_fops);
if(result<0){
printk("mydrv: device driver can't be registered\n");
return result;
}
return 0;
}
static void hello_exit(void)
{
printk("exit module\n");
}
void hello_cleanup(void)
{
printk("cleanup module \n");
unregister_chrdev(MYDRV_MAJOR,DEVICE_NAME);
}
module_init(hello_init); //커널을모듈에적재할때호출도리함수지정
module_exit(hello_exit); //커널을모듈에서제거할때호출될함수지정
MODULE_LICENSE("Dual BSD/GPL"); // 커널2.6의라이센스등록
¦ Application program 만들기
– Source code
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
int fd,ret,select=1;
int count,temp=0,DIP[8]={0};
unsigned char buf=0;
unsigned long flag = 0x01;
fd = open("/dev/mydrv",O_RDWR);
if(fd < 0)
{
printf("fd file open fail\n");
return -1;
}
write(fd,&buf,1);
read(fd,&buf,1);
ioctl(fd,1,2);
close(fd);
}
¦ Makefile 만들기
– Source
obj-m :=mydrv.o
KDIR :=/home/a/slc100/test_kernel/sl2c100_kernel_2.6.29_20100622
PWD :=$(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
cp mydrv.ko /nfsroot/RootFS-S5PC100/mydrv.ko
arm-s3c6410-linux-gnueabi-gcc -o test_app test_app.c
cp test_app /nfsroot/RootFS-S5PC100/test_app
clean:
rm -rf *.ko
rm -rf *.mod.*
rm -rf *.cmd
rm -rf *.o
rm -rf /nfsroot/RootFS-S5PC100/mydrv.ko
rm -rf /nfsroot/RootFS-S5PC100/test_app
¦ 장치파일 생성(타켓 보드에서 할 것)
– Mknod /dev/mydrv c 240 0( /dev폴더에 (주 240/부 0 )번호 mydrv 라는 장치파일을 생성)
¦ 모듈 적재
– lnsmod mydrv.ko
– lsmod : 적재된 모듈 출력 / rmmod : 정재된 모듈 삭제
¦ 어플리케션 실행
– ./test_app
¦ 실행화면

Open ->write(buf값 0을 1로 write)->read(buf 값 1을 확인)->ioctl(호출만하였음)->release