[summary] linux device driver
디바이스드라이버의 역할은?
- 응용프로그램이 H/W를 제어할 수 있도록 Interface를 제공해 주는 것이다.
- 시스템이 지원하는 하드웨어를 응용프로그램에서 사용할 수 있도록 커널에서 제공하는 라이브러리다.
- 디바이스와 시스템메모리 간에 데이터의 전달을 담당하는 커널 내부 기능이다.
- 디바이스를 제어하는 함수 집합
디바이스드라이버의 인터페이스
- 일반적으로 위로는 파일시스템(file system)과 아래로는 실제 디바이스와 인터페이스를 갖는다.
응용프로그램이 커널에게 자원 처리를 요청하는 두 가지 방법
- System call (S/W ISR)
- File I/O (Device Driver)
커널소스탐색
- http://lxr.linux.no/linux/
grep 명령의 활용
ex) grep readb * -r | grep include
이외에 include/linux, include/asm 활용. 한편, SourceInsight 는 코드 분석을 위해 유용하다.
module programming의 장점
부팅 중에도 디바이스드라이버를 수정할 수 있다.
리눅스에서 동작하는 프로그램은 H/W를 제어하기 위해 디바이스 파일을 이용해야만 한다.
디바이스 파일은 mknod로 생성한다. 이 파일에 대한 I/O는 저수준 함수를 사용한다.
open, close, read, write, ioctl, fsync, lseek
int fd = open("/dev/mem", O_RDWR | O_NONBLOCK); ....
문자 디바이스 드라이버(버퍼없는 디바이스드라이버)
- ex) 터미널 드라이버
http://lxr.linux.no/linux/drivers/char/tty_io.c
http://lxr.linux.no/linux/drivers/char/serial167.c
통합형 디바이스 드라이버란?
- ?
하나의 디바이스는 여러 개의 드라이버에 의해 동작할 수 있다.
Bus는 직/간접적으로 프로세서에 연결되고, 디바이스는 하나의 버스에 연결된다.
디바이스파일의 목적
- H/W 를 다루는 드라이버의 정보를 커널에 제공하는 데 있다.
- 응용프로그램은 시스템에 의해 할당된 메모리와 파일만 제어할 수 있고, H/W에 직접 접근할 수는 없다. 그래서, 디바이스파일이라는 특수 파일을 이용한다.
- 디바이스파일은 H/W를 제어하는 디바이스드라이버와 연결된다.
주번호와 부번호
- 주번호가 같다는 것은 같은 드라이버에 의해서 구동될 수 있다는 의미가 된다.
(문자)디바이스드라이버 구현 순서
1. 디바이스드라이버 함수 구현
2. 디바이스드라이버 커널 등록 (register_chrdev()) http://lxr.linux.no/linux/fs/char_dev.c#L266
3. 디바이스 파일 생성 (mknod)
문자디바이스드라이버 sample
- http://halkamalka.tistory.com/29
디바이스드라이버 read/write 구현 시 알아야 할 사항
1. User memory space와 Kernel memory space 사이에 데이터 이동
read 의 인자는 드라이버의 xxx_read의 인자로 연결되지만, User application에서 전달된 인자의 buffer에 드라이버에서 직접 접근할 수는 없다. 왜냐하면, 메모리 공간이 각각 Kernel과 User로 서로 다르기 때문이다. 따라서, 이렇게 다른 영역에 데이터를 전송하기 위해서는 다음의 함수를 사용한다.
- copy_to_user(to, from, n); // Kernel에서 User로 n만큼
- put_user(x, ptr) // 커널의 x값을 사용자 메모리(ptr) 값에 대입한다.
- H/W에서 직접 읽기: inb, outb, readb, writeb etc
cf) copy_from_user(to, from, n) , get_user(x, ptr)
위 함수들을 사용하기 위해서는 다음 header를 포함시켜야 한다.
#include <asm/uaccess.h>
verify_area example
{
int err;
err = verify_area(VERIFY_WRITE, (void*) arg, size);
if(err < 0)
return err;
return 0;
}
ssize_t xxx_read(struct file* file, const char* buffer, size_t count, loff_t* f_pos)
{
int err;
err = verify_area(VERIFY_WRITE, (void*) arg, size);
if(err < 0)
return err;
return 0;
}
copy_to_user example
{
char* temp;
int err;
temp = kmalloc(count, GFP_KERNEL);
if(err = copy_to_user(temp, buf, count) < 0)
return err;
kfree(temp);
}
{
char* temp;
int err;
temp = kmalloc(count, GFP_KERNEL);
if(err = copy_to_user(temp, buf, count) < 0)
return err;
kfree(temp);
}
copy_from_user example
{
char* temp;
int err;
temp = kmalloc(count, GFP_KERNEL);
if(err = copy_from_user(temp, buf, count) < 0)
return err;
kfree(temp);
}
{
char* temp;
int err;
temp = kmalloc(count, GFP_KERNEL);
if(err = copy_from_user(temp, buf, count) < 0)
return err;
kfree(temp);
}
2. 처리 조건이 되지 않았을 때의 blocking처리
3. H/W 제어 함수
4. 여러 프로세스가 동시에 접근했을 때의 경쟁 처리
5. ISR와의 경쟁 처리
전역 변수 할당 시 참고 기준
1. H/W 관련 제어 변수는 전역 변수로 만든다.
2. 단독으로 사용되는 ISR에서 사용되는 변수들은 전역 변수로 만든다.
3. 프로세스마다 따로 관리해야 하는 변수(REENTRANT를 고려해야 하는) 들은 file구조체의 private_date필드 변수에 할당한다.
4. H/W와 연동하는 대기 큐는 전역 변수로 만든다.
I/O처리
H/W는 프로세서 입장에서 I/O 주소 영역으로 표현되는 메모리 공간이다. 이 메모리 공간을 제어하는 방법은 시스템마다 다르므로 이를 통일하기 위해 몇 가지 함수를 정의한다.
1. I/O mapped 입출력 함수
inb, inw, inl, insb, insw, insl : H/W에서 데이터를 읽는다.
outb, outw, outl, outsb, outsw, outsl : H/W에 데이터를 쓴다.
* 위 함수들은 MACRO이며, #include <asm/io.h>에 정의되어 있다.
* arch 마다 다르게 구현되어 있으므로, 참고할 필요가 있다.
2. Memory mapped I/O 함수
PCI 디바이스나 ARM같은 프로세서는 H/W가 I/O port에 연결되어 있지 않고 메모리 공간에 연결된다.
readb, readw, readl, memcpy_fromio
writeb, writew, writel, memcpy_toio
'Computer Science' 카테고리의 다른 글
MS Windows에서 DevC++로 GTK프로그래밍하기 (0) | 2009.08.17 |
---|---|
임베디드 OS란 무엇인가 (0) | 2009.08.15 |
Getting started with an embedded Linux system emulator (0) | 2009.08.09 |
[컬럼] 초보자를 위한 임베디드 리눅스 학습 가이드 (0) | 2009.08.02 |
리눅스 디바이스 드라이버 개요 및 실습 (0) | 2009.08.02 |