디바이스 드라이버
fnd 나 부저 같은 간단한 디바이스를 제어하기 위한 드라이버를 만들때 각각 만들어 구분해도 상관 없으나, 하나의 드라이버로 만들어 메이저 번호를 공통으로 하고 마이너 번호로 이들을 구분해 각각 따로 open 이 가능 한 형태로 사용 할 수도 있습니다.
fnd 제어 드라이버와 buzzer 드라이버를 하나의 메이저 아래 두개의 마이너로 구분해 사용 하는 방법을 알아보겠습니다.
1. 메이저 번호는 dev.h 파일에 아래와 같이 선언해 줍니다.
-----------------------------------------------------------------------
#define DEV_DRIVER_MAJOR 203
-----------------------------------------------------------------------
2. 먼저 minor 로 open 하기위해 아래와 같은 구조체가 필요합니다.
-----------------------------------------------------------------------
struct file_operations minor_fops=
{
.owner = THIS_MODULE,
.open = minor_open,
};
-----------------------------------------------------------------------
3. dev_init 함수에서 장치 파일등록
장치 파일을 등록 할때 _init int dev_init(void) 함수에서 아래와 같이 등록 합니다.
-----------------------------------------------------------------------
static __init int dev_init(void)
{
// 장치파일 등록
major &= 0xff;
register_chrdev( DEV_DRIVER_MAJOR, DEV_NAME, &minor_fops );
~ 생략 ~
}
4. 이제 minor_open 함수가 있어야 합니다.
실제 이 minor_open 함수에서 어플리케이션 으로부터 받은 마이너 번호에 따라 해당 디바이스의 드라이버를 open 하게 됩니다.
아래 minor_open 함수의 filp->f_op 값이 바로 어플리케이션 에서 넘어온 minor 번호가 됩니다.
-----------------------------------------------------------------------
int minor_open( struct inode *inode, struct file *filp)
{
switch(MINOR(inode->i_rdev))
{
case 1: filp->f_op = &minor_fnd_fops;break;
case 2: filp->f_op = &minor_buzzer_fops;break;
default : return -ENXIO;
}
if (filp->f_op && filp->f_op->open)
return filp->f_op->open(inode,filp);
return 0;
}
-----------------------------------------------------------------------
5. 드라이버 등록 구조체 선언
두 드라이버는 마이너 번호로 완젼 분리 되기 떄문에 각각 다른 드라이버 등록 구조체를 갖게 되며 따라서 따로 구조체를 선언
해 주어야 합니다.
------------------------------------------------------------------------
//------------------------------------------------------------------------------
// FND 드라이버 등록 구조체
//------------------------------------------------------------------------------
static struct file_operations minor_fnd_fops =
{
.owner = THIS_MODULE,
.open = fnd_open,
// .release = fnd_release,
// .read = fnd_read,
// .write = fnd_write,
.ioctl = fnd_ioctl,
// .poll = fnd_poll,
};
//------------------------------------------------------------------------------
// BUZZER 드라이버 등록 구조체
//------------------------------------------------------------------------------
static struct file_operations minor_buzzer_fops =
{
.owner = THIS_MODULE,
.open = buzzer_open,
// .release = buzzer_release,
// .read = buzzer_read,
// .write = buzzer_write,
.ioctl = buzzer_ioctl,
// .poll = buzzer_poll,
};
---------------------------------------------------------------------------------
6. 이제 각각의 드라이버 등록 구조체에 선언된 함수들을 구현 해 주면 됩니다.
이중에서 open,release,read,write,poll 은 사용 하지 않으므로 그냥 주석처리 해도 동작에 문제는 없습니다.
따라서 iotcl 함수만 각각 구현해 주면 됩니다.
//------------------------------------------------------------------------------
// BUZZER 드라이버 ioctl
//------------------------------------------------------------------------------
static int buzzer_ioctl( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg )
{
unsigned char u8val;
switch(cmd)
{
case IOCTL_BZR_OUT :
if(copy_from_user( &u8val, (void *)arg, sizeof(unsigned char) ))printk("copy_from_user error ! \n");
bzr_out(u8val );
return 0;
}
return -EINVAL;
}
7. 어플리케이션에서 open 하기
어플리케이션 에서는 마이너 번호로 open 할 것이기 때문에 두개의 드라이버 파일 포인터가 필요합니다.
--------------------------------------------------------------------------
int fnd_dev_fd;
int buzzer_dev_fd;
--------------------------------------------------------------------------
그리고 , open 할때 아래와 같이 마지막에 마이넌 번호를 넣어 주어야 합니다.
이 번호가 위에서 설명한 filp->f_op 값으로 넘어 가므로 해당 디바이스의 마이너 번호를 잘 확인해야 합니다.
-------------------------------------------------------------------------------------
fnd_dev_fd = dev_open( FND_DEVICE_FILENAME, DEV_DRIVER_MAJOR,1);
buzzer_dev_fd = dev_open( BUZZER_DEVICE_FILENAME, DEV_DRIVER_MAJOR,2);
-------------------------------------------------------------------------------------
실제 드라이버를 open 하는 함수(dev_open)는 아래와 같으며, 자세히 보면 마이너 번호 mknod 로 마이너 번호의
디바이스를 따로 생성해 주는 것을 볼 수 있습니다.
fnd_dev_fd = dev_open( FND_DEVICE_FILENAME, DEV_DRIVER_MAJOR,1); 이런식으로 하지 않고 아래 함수를
직접 풀어서 사용해도 무방하나 사용상 편의를 위해 dev_open 함수를 별도로 만들어 사용 합니다.
-----------------------------------------------------------------------------------------------------
int dev_open( char *fname, unsigned char major, unsigned char minor )
{
int dev;
dev = open( fname, O_RDWR|O_NDELAY );
if (dev < 0 )
{
if( access( fname, F_OK ) == 0 )
{
unlink( fname );
}
mknod( fname, (S_IRWXU|S_IRWXG|S_IFCHR), MKDEV(major,minor) );
dev = open( fname, O_RDWR|O_NDELAY );
if (dev < 0 )
{
printf( " Device OPEN FAIL %s\n", fname );
return -1;
}
}
return dev;
}
----------------------------------------------------------------------------------------------------
8. 어플리케이션 에서 사용하기
이제 하나의 메이저아래 두개의 마이너번호로 등록된 두개의 드라이버를 각각 따로 사용 할 수 있습니다.
-----------------------------------------------------------------------------------------------------
ioctl( fnd_dev_fd, IOCTL_FND_OUT, ¶m );
ioctl( buzzer_dev_fd, IOCTL_BZR_OUT, &command );
-----------------------------------------------------------------------------------------------------
물론 이 드라이버는 구분이 되기 때문에 fnd 와 buzzer 를 각각 따로 open 해서 사용 할 수 있습니다.
실제 타겟 보드에서 이 드라이버를 확인해보면 아래와 같습니다.
-----------------------------------------------------------------------------------
[root@falinux driver]$ cd /dev
[root@falinux dev]$ ll
crwxr-x--- 1 root root 203, 1 Jan 1 07:13 fnd
crwxr-x--- 1 root root 203, 2 Jan 1 07:07 buzzer
------------------------------------------------------------------------------------
이처럼 203 이라는 메이저번호에 1,2 번으로 마이너 번호를 갖는 두개의 드라이버가 올려진 것을 확인 할 수 있습니다.