일반적으로 디바이스란 컴퓨터에 물려있는 여러 주변장치들을 뜻한다. 네트워크 어댑터, LCD 디스플레이, 오디오, 터미널, 키보드, 하드디스크, 플로피디스크, 프린터 등이 바로 디바이스에 해당하고, 이러한 디바이스들을 컨트롤하기 위한 디바이스 드라이버가 존재한다.
디바이스 드라이버는 시스템이 지원하는 하드웨어를 사용자가 응용 프로그램에서 사용할 수 있도록 커널의 일부 영역을 사용하여 동작하는 일종의 프로그램이다.
리눅스에서는 모든 것을 파일로 간주하는데, 이러한 디바이스 드라이버 또한 파일로 관리된다.
/dev/ 아래에 들어있는 파일들이 바로 디바이스 드라이버 인터페이스이고, 하드웨어와는 독립적으로 응용프로그램이 파일 open, read, 같은 함수로 접근할 수 있다.
리눅스에서 사용자가 커널 모드의 디바이스 드라이버를 사용하여 실제 하드웨어 디바이스에 접근하고자 할 때 아래 그림과 같은 추상적인 계층들을 통과해야 한다.
커널 모듈
소스코드를 작성하고 컴파일을 한 뒤 insmod로 커널에 생성한 모듈을 적재한다.
그다음 만들 커널 모듈을 위한 디바이스 파일을 만들어야 하기 때문에 mknod 명령어를 이용한다.
장치파일은 블록 디바이스, 문자 디바이스라고 하는 파일을 생성할 때 사용하며 리눅스 시스템에 새로 장착되는 하드웨어의 장치 파일 생성 시에 주로 사용한다.
해당 명령어로 장치 파일(FIFO, Block, Character)을 만들었으면, 이제 응용 프로그램에서 open, read 등을 이용하여 디바이스 파일에 접근한다.
커널에서 모듈울 제거시 rmmod로 모듈을 제거할 수 있다.
디바이스 드라이버는 문자/블록/네트워크 디바이스 드라이버 세 종류가 있으며, 각 디바이스는 주 번호(Major number)와 부 번호(Minor number)를 갖고 있다.
디바이스 드라이버 종류
디바이스 드라이버 종류 | 설명 | 등록 함수 |
문자 디바이스 | device를 파일처럼 접근하여 직접 read/write 수행한다. data 형태는 stream 방식으로 전송 |
register_chrdev() |
블록 디바이스 | disk와 같은 file system을 기반으로 block 단위로 데이터를 read/write | register_blkdev() |
네트워크 디바이스 | network의 물리계층과 frame 단위의 데이터 송수신 | register_netdev() |
- 문자 디바이스 (char Device)
자료의 순차성을 지닌 장치로 버퍼 캐쉬를 사용하지 않음
장치의 raw data를 사용자에게 제공
시리얼, 키보드, 프린터, 마우스 등이 이에 속함
- 블록 디바이스 (Block Device)
블록 단위의 입출력이 가능한 장치를 뜻함
버퍼 캐시에 의한 내부 장치 표현
파일 시스템에 의해 마운트 되어 관리됨
하드 디스크 CD-ROM 등이 이에 속함
- 네트워크 디바이스 (Network Device)
네트워크 스택과 네트워크 하드웨어 사이에 위치해 데이터의 송수신을 담당
이더넷, 네트워크 인터페이스 카드 등이 이에 속함
모듈 관련 명령어
- insmod : 모듈을 커널에 적재
- modprobe : 모듈을 커널에 적재하건 insmod와 비슷하다 다만, 해당 모듈에 의존성이 있거나 해당모듈보다 선행되어야 하는 모듈이 있으면 그 모듈도 같이 올려준다
- depmod : 모듈 간 의존성 정보를 생성
- rmmod : 커널에서 모듈을 제거 의존관계에 있는 모듈들을 한꺼번에 제거할 경우 rmmod -r 옵션을 사용
- lsmod : 커널에 로딩된 목록을 출력
커널에 로드할 디바이스 드라이버 파일
드라이버는 커널에서 실행되는 프로그램이지만 커널의 라이브러리 함수를 사용한다.
드라이버 코드에는 하나의 진입 점과 하나의 종료 점이 있다.
드라이버를 커널에 로드하면 위 코드에서 test_init 함수 인 module_init 함수로 정의 된 함수가 실행되고, 드라이버가 커널에서 언로드 되면 module_exit 함수에 의해 정의 된 함수가 호출되는데, 위 코드에서 test_exit 함수이다.
아래 코드는 드라이버가 로드 될 때 TEST_MODULE_INIT를 출력하고 드라이버가 언로드 될 때 TEST_MODULE EXIT를 출력
// test_module.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
int test_init(void)
{
printk(KERN_INFO "TEST_MODULE_INIT\n");
return 0;
}
void test_exit(void)
{
printk(KERN_INFO "TEST_MODULE EXIT\n");
}
module_init(test_init);
module_exit(test_exit);
디바이스 드라이버 컴파일 Makefile
obj-m := test_module.o 명령을 통해 test_module.o를 test.ko로 컴파일하는 것을 의미하며 *.ko 파일은 커널 모듈 파일이다
obj-m := test_module.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.ko
rm -rf *.mod.*
rm -rf .*.cmd
rm -rf *.o
mknod를 이용한 장치 파일 생성하기
mknod ([옵션]) [장치명] [타입] ([주번호 부번호])
[타입]에는 "b", "c" 또는 "u"가 설정되며, 블록장치파일 또는 문자장치파일을 생성할 때 반드시 주번호와 부번호를 지정해야함
하지만 [타입]에 "p"를 지정하여 FIFO파일을 생성할 때에는 주번호와 부번호를 생략 가능
파일생성시 초기 퍼미션 = 0644
p = FIFO파일
b = Block특수파일
c,u = Character특수파일
/dev : 이 디렉토리에는 모든 장치에 대한 특수 장치 파일이 들어가있음
/proc/devices : 현재 실행중인 커널 (블록 및 문자)로 구성된 장치 드라이버 목록
커널에 모듈 적재 및 장치 파일 생성 쉘
## init_driver.sh
#! /bin/sh
module="test_module"
device="test_module"
group="root"
mode="666"
/sbin/insmod -f $module.ko $* || exit 1
rm -f /dev/${device}
mknod /dev/${device} c 60 0
chgrp $group /dev/${device}
chmod $mode /dev/${device}
커널에 적재된 모듈 제거 및 장치 파일 삭제 쉘
## remove_driver.sh
#! /bin/sh
module="test_module"
device="test_module"
/sbin/rmmod --force -v $module || exit 1
rm -f /dev/${device}
'Embedded SW 기초' 카테고리의 다른 글
Peripheral과의 통신 - 2. UART (0) | 2024.06.11 |
---|---|
Peripheral과의 통신 - 1. GPIO (0) | 2024.06.11 |
메모리 구조 (0) | 2024.06.10 |
임베디드 리눅스 부팅 절차 (0) | 2024.06.10 |
Yocto 기초 (0) | 2024.06.09 |