드라이브 시스템 구조
① 응용 프로그램(Application APP)
- 파일 함수 호출 : open("/dev/xxx"), read(), write()
② 시스템 콜 인터페이스(System call interface)
- SWI(Software interrupt)로 인해 전달된 파라미터의 값, 즉 Exception의 원인에 따라 다른 예외 처리 함수를 호출
③ 가상 파일 시스템(VFS, Virtual File System)
- sys_open, sys_read ...
- 열려 있는 여러 디바이스 파일에 따라 다른 드라이버를 찾아 해당 기능을 호출
- 예를 들어, 캐릭터 디바이스가 열려 있는 경우 커널에 의해 정의된 배열 chrdev[]를 확인
- 배열의 인덱스는 주 장치 번호이며, 내용은 file_operations 구조체
④ 하드웨어
캐릭터 디바이스 드라이버 작성 예제
캐릭터 디바이스 드라이버 작성 방법
- open(), read(), write() 등의 함수 사용
static int first_drv_open(struct inode* inode, struct file* file)
{
//printk("first_drv_open\n");
/*
* LED1, LED2, LED4 correspond to GPB5, GPB6, GPB7, GPB8
*/
/* Configure GPB5, 6, 7, 8 as output */
*gpbcon &= ~((0x3 << (5*2)) | (0x3 << (6*2)) | (0x3 << (7*2)) | (0x3 << (8*2));
*gpbcon |= ~((0x1 << (5*2)) | (0x1 << (6*2)) | (0x1 << (7*2)) | (0x1 << (8*2));
return 0;
}
static ssize_t first_drv_write(struct file* file, const char __user* buf, size_t count, loff_t* ppos)
{
int val;
//printk("first_drv_write\n");
copy_from_user(&val, buf, count); // copy_to_user();
if(val == 1)
{
//Light up
*gpbdat &= ~((1 << 5) | (1 << 6) | (1 << 7) | (1 << 8));
}
else
{
//Light off
*gpbdat |= (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8);
}
return 0;
}
커널이 캐릭터 디바이스 드라이버의 함수를 호출하도록 만드는 방법
① file_operations 구조체를 정의하고 아래의 방법을 사용하여 초기화
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE, /* This is a macro that pushes to the __this module variable created automatically when the module is compiled */
.open = first_drv_open,
.write = first_drv_write,
};
② 위 file_operations 구조체를 커널에 등록
major = register_chrdev(0, "first_drv", &first_drv_fops); // register, tell the kernel
③ 드라이버 모듈 작성
static struct class* firstdrv_class;
static struct class_device* firstdrv_class_dev;
static int first_drv_init(void)
{
major = register_chrdev(0, "first_drv", &first_drv_fops); // Register, tell the kernel to write 0 for the major device number -- the system will automatically assign us a vacant major device number
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */
gpbcon = (volatile unsigned long*) ioremap(0x56000010, 16); // ioremap -- map physical addresses to virtual addresses
gpbdat = gpbcon + 1;
return 0;
}
static void first_drv_exit(void)
{
unregister_chrdev(major, "first_drv"); // uninstall
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdev_class);
iounmap(gpbcon);
}
module_init(first_drv_init);
module_init(first_drv_exit);
MODULE_LICENSE("GPL");
위 코드로 캐릭터 디바이스 드라이버를 구현
④ Makefile을 작성하고 해당 드라이버를 커널 모듈로 컴파일
KERN_DIR = /work/system/linux-2.6.22.6 #Specify which Linux kernel to use
all:
make -C $(KERN_DIR) M = `pwd` modules # Compile into modules in the current directory
clean:
make -C $(KERN_DIR) M = `pwd` modules clean
rm -rf modules.order
obj-m += first_drv.o # obj-m compiled into a module
⑤ 드라이버 모듈 컴파일 및 로드
make led.ko # now you can see the files in the directory
insmod ./led.ko # load the driver
# if you want to uninstall the driver, you can use: rmmod led
응용 프로그램에서 디바이스 드라이버를 호출하는 방법
- 해당 드라이버에는 디바이스 노드를 자동으로 등록하는 기능이 이미 있음
- 다음 코드를 사용하여 수행
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class NULL, MKDEV(major, 0), NULL, "led");
위 작업이 성공하면, firstdrv 클래스의 디렉토리가 /sys/class/ 디렉토리에 나타나고,
./firstdrv/ 디렉토리 아래에 led 디렉토리가 있으며, ./led 디렉토리에는 dev 파일이 생김
#cat dev를 통해 주/부 디바이스 번호를 볼 수 있음
MKDEV(major, 0)는 해당 정보를 사용하여 디바이스 노드를 생성
아래의 테스트 프로그램(test.c) 코드에서 해당 디바이스 노드를 사용하여 led 하드웨어를 작동
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* firstdrvteset on
* firstdrvtest off
*/
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/xyz", O_RDWR);
if(fd < 0)
{
printf("can't open!\n");
}
if(argc != 2)
{
printf("Usage :\n");
printf("%s <on|off>\n", argv[0]);
return 0;
}
if(strcmp(argv[1], "on") == 0)
{
val = 1;
}
else
{
val = 0;
}
write(fd, &val, 4);
return 0;
}
insmod 및 rmmod를 실행하자마자 디바이스 노드가 자동으로 생성되고 삭제되는 이유
- 스크립트 파일 /etc/init.d/re.S에 echo/sbin/mdev > /proc/sys/kernel/hotplug를 추가했기 때문
- Hot Plug 기능을 지원하며, 장치 노드 생성을 자동으로 삽입하거나 분리함
참고 사이트
https://titanwolf.org/Network/Articles/Article?AID=cc3ae37e-d405-4abd-a771-031eecb99fa8#gsc.tab=0
'Study > Device Driver' 카테고리의 다른 글
[Device Driver] Led Device driver 제작 (0) | 2021.08.15 |
---|---|
[Device Driver] 리눅스 커널 (0) | 2021.08.13 |