디바이스 드라이버 개발 (1)
디바이스 드라이버의 종류
● 문자 디바이스 드라이버
- 대부분의 디바이스 드라이버가 이에 해당, 구현이 매우 간편
● 블록 디바이스 드라이버
- 대용량의 데이터를 저장하는 디바이스에 대해 사용
● 네트워크 디바이스 드라이버
- 외부와 통신을 하며 특히 소켓을 사용하여 통신하는 디바이스에 대해 사용
● 버스 디바이스 드라이버
- USB나 PCI등 여러 다른 디바이스가 꽂히는 포트 디바이스에 대해 사용
- 디바이스를 탐색하고 인식하는 것이 주역할
디바이스 노드
디바이스 드라이버를 다루기 위한 특수 파일
모든 디바이스 노드는 고유의 타입, 주번호, 부번호를 가짐
● 타입 : 문자형 (c), 블록형 (b)
● 주번호 : 디바이스 드라이버를 구분하기 위한 번호 (0~511)
● 부번호 : 디바이스를 구분하기 위한 번호 (0~1048576)
● 동일한 디바이스 드라이버를 사용하는 여러 디바이스가 존재할 수 있음
mknod <파일이름> <타입> <주번호> <부번호> : 디바이스 노드 파일을 생성하는 명령어
● 일반적으로 디바이스 노드는 /dev에만 생성하여 관리함
간단한 문자형 디바이스 드라이버 실습
커널 모듈을 만들 때 처럼 drivers 안에 폴더를 만들고 main.c를 구현하였다.
<linux/device.h>의 주요기능
헤더파일은 리눅스 커널에서 장치와 관련된 기능을 제공한다.
● struct device : 장치의 속성, 상태, 드라이버 등을 관리하는 구조체
● device_create() : 장치 파일을 생성
● device_destroy() : 장치 파일을 삭제
<linux/fs.h>의 주요기능
파일 시스템과 관련된 기능들을 제공한다.
● struct file_operations : 장치 드라이버에서 파일에 대한 연산(열기,읽기,쓰기,닫기 등)을 정의하는 함수 포인터들을 포함하고 있다. 이 구조체는 장치 드라이버가 구현해야하는 주요 인터페이스이다.
● open() : 장치 파일을 열 때 호출되는 함수
● read() : 장치 파일에서 데이터를 읽을 때 호출되는 함수
● write() : 장치 파일에 데이터를 쓸 때 호출되는 함수
● release() : 장치 파일을 닫을 때 호출되는 함수
장치의 이름과 주번호를 설정해준다.
inode는 파일 시스템 내에서 파일에 대한 정보를 담고 있는 구조체이다.
iminor(inode) 함수는 이 inode 구조체에서 minor번호를 추출한 다음 minor에 넘긴다.
file_operations 구조체를 통해 open,read,write,relaese,ioctl,mmap,flush 함수를 호출할 수 있다.
.open을 통해 장치 파일이 열릴 때 호출될 함수를 지정할 수 있다. 위에선 device_open함수를 지정해서 장치 파일에 대한 정보(minor번호)를 제공받아 장치와의 연결을 설정하였다.
모듈이 로드될 때 register_chrdev 함수를 통해 문자 장치를 등록한다. 모듈이 언로드될 때 문자 장치를 해제한다.
CROSS_COMPILE을 하면 커널 모듈 때와 동일하게 ko파일이 생성된다.
ko파일이 생성되면 mount를통해 복사를 해준다.
그 다음 qemu 가상머신에 들어가서 mknod 명령어를 통해 장치파일을 생성한다. 장치파일의 유형은 c(문자형)이고 문자 장치는 데이터를 바이트 단위로 처리한다. 150은 주 장치 번호로 위에 있는 MAJOR_NUMBER와 일치시켜야 한다. 주 번호는 커널에서 장치 드라이버를 식별하는 데 사용된다. 34는 부 장치 번호로 같은 장치 드라이버에서 서로 다른 인스턴스를 식별하는 데 사용된다.
그리고 cat 명령어를 사용해서 확인을 해보면 open을 할 수 없다고 나오는데 이는 드라이버가 로드되었지 않았기 때문에 발생하는 문제이다.
insmod를 통해 ko파일을 로드해준 후 다시 cat명령어를 사용하면 open은 되었지만 read를 구현하지 않았기 때문에 읽을 수 없다는 에러메시지가 뜬다.
ls -lah 명령어를 통해서 로드된 모듈을 살펴보면 주 번호와 부 번호 모두 설정한 값으로 들어간 것을 확인할 수 있다.