Chapter 10. 디바이스의 제어
01. 디바이스 제어#
디바이스 제어 ioctl()함수의 역할#
read와 write 만으로 하드웨어를 제어할 수 없는 경우도 종종 발생한다. 시리얼 포트를 생각 해 보자. 시리얼 통신은 상호간에 통신을 수행하기 위해 전송 속도와 에러 처리 방식을 설정해야 한다. 하지만 wirte()함수나 read()함수 만으로는 전송될 데이터와 제어 데이터를 구분할 수 있는 방법이 없다. 또한 수신된 통신 데이터와 통신 상태 데이터를 구분할 수 없다. 또한 read() 함수와 write()함수는 요구된 처리 데이터가 모두 처리되는 것을 보장하지 않는다. 이런 문제점을 해결하기 위해 리눅스 커널에서는 ioctl()이라는 방식을 제공한다. ioctl()함수는 디바이스 파일 이외에는 사용할 수 없는 디바이스 파일 전용 함수 이므로 각 디바이스마다. 고유하게 선언하여 사용한다.
ret = ioctl( int fd, int request, char * argp)
int xxx_ioctl(struct inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
return ret;
}
request는 응용 프로그램이 디바이스 드라이버에게 요구하는 명령어고, 이 request에 대입된 값은 디바이스 드라이버의 매개변수 cmd에 그대로 전달된다.
매개변수 argp는 request에 따라서 선언해되 되고 선언하지 않아도 되는 가변 인자 매개변수다.(이 값은 request에 종속되어 디바이스에 전달한 정보를 담은 구조체 변수의 선도 주소를 전달하거나 디바이스 드라이버에서 얻고자 하는 정보를 담아올 수 있는 구조체 변수의 선두 주소를 전달한다.
iocrl()함수의 특징 정리
read(), write()함수와 같이 쓰기와 읽기 처리가 가능하다.
하드웨어의 제어나 상태를 얻기 위해 사용된다.
응용 프로그램의 명령에 따라 디바이스 드라이버의 매개변수 해석이 달라진다.
ioctl() 함수의 일반적인 형태#
응용 프로그램에서 ioctl() 함수를 이용하여 하드웨어를 제어하거나 상태를 일기 위해서는 디바이스 파일을 제어하는 디바이스 드라이버에서 해석 가능한 명령과 구조체를 상용해야 한다. 이 때는 공통된 헤더 파일을 사용하게 된다. 이 헤더 파일에서 ioctl에 전달되는 명령에 대한 선언과 명령을 처리하는 보조적인 정보를 주고받기 위한 구조체가 선언되어 있어야 한다. 비아이스 드라이버의 ioctl()함수는 가장 먼저 전달된 cmd명령이 유효한가를 확인한다. 이검사는 _IOC_NR과 _IOC_TYPE 라는 매크로 함수를 사용한다. 이 검사의 주 된 목적은 사용자 모드에서 메모리의 유효성을 검사하기 위해서다. 전달된 명령이 유효하지 않으면 EINVAL 이라는 음수값을 반환한다. 이와는 반대로 정상적인 명령어일 경우에는 명령이 읽기를 요구하는지 쓰기를 요구하는지를 검사한다. _IOC_DIR 사용.
int xxx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
//cmd 유효성 검사
//arg에 전달된 사용자 메모리 유효성 검사
switch(cmd)
{
case 구별상수1 : 처리루틴 1
break;
case 구별상수2 : 처리루틴 2
break;
}
return 0;
}
ioctl에 전달되는 cmd와 관련 매크로 함수#
cmd의 구성
응용프로그램이 디바이스 드라이버에게 요구한 처리를 구별하기 위한 구별값.
2Bit | 14Bit | 8bit | 8bit |
읽기 쓰기 구분 데이터 크기 매직번호 구분번호
구분번호 : 명령을 구분하는 명령어의 순차 번호
매직번호 : 다른 디바이스 드라이버의 ioctl 명령과 구분하기 위한 값
데이터 크기 : 매개변수를 arg를 통해 전달되는 메모리의 크기
읽기 쓰기 구분 : 읽기를 위한 요구 명령인지 쓰기를 위한 요구 명령인지를 구분하는 속성
구분번호
이 값은 같은 비아이스 드라이버에서는 중복해서 사용해도 된다. 예를 들어 읽기와 쓰기 각각의 명령에 같은 구분 번호를 사용해도 디바이스 드라이버는 이를 구분해서 사용할 수 있다. 이런 방식이 가능한 이유는 디바이스 드라이버에서 명령을 구분할 때 switch 문을 사용하면서 명령 매개변수인 cmd값을 그대로 사용하기 때문이다. 명령을 만드는 매크로에서 생성되는 값은 여러 필드를 조합하기 때문에 같은 구분 번호라 해도 다른 명령으로 인식할 수 있기 때문.
이 번호 추출을 위해 _IOC_NR(명령)을 사용한다.
하지만 switch 문에서 각각의 case에 적용하는 값은 일반적으로 명령 자체를 쓴다.
매직번호
0~255 사이다. 보통 영문자 'A'~'Z' 또는 'a'~'z'를 넣는다. 디바이스 드라이버에서 이 매직번호를 명령에서 추출하여 자신이 처리하는 매직 번호와 같은지를 비교하여 다르면 처리를 거부한다.
이 번호 추출을 위해 _IOC_TYPE(명령)을 사용한다.
매직 번호는 가급적 다른 디비아스 드라이버와 다르게 하는 것이 좋다. 그렇다고 무조건 다르게 해야만 한다는 것이 아니다. 다른 디바이스 드라이버에서 사용한 매직번호를 사용해도 상관없다.
변수형
숫자를 직접 대입하는 것이 아니고 변수형을 넣는다. 왜냐하면 명령을 만드는 매크로에 크기를 인식하는 sizeof란 컴파일 명령이 포함되어 있기 때문이다.
이 번호 추출을 위해 _IOC_SIZE(명령)을 사용한다.
매크로 함수
-cmd 명령을 만드는 매크로 함수
_IO(매직번호, 구분번호) : 부가적인 데이터가 없는 명령을 만드는 매크로
_IOR(매직번호, 구분번호, 변수형) : 디바이스 드라이버에서 데이터를 읽어 오기(R)위한 명령을 만드는 매크로
_IOW(매직번호, 구분번호, 변수형) : 디바이스 드라이버에서 데이터를 써넣기(W)위한 명령을 만드는 매크로
_IOWR(매직번호, 구분번호, 변수형) : 디바이스 드라이버에 읽고(R) 쓰기(W)를 수행하기 위한 명령을 만드는 매크로
-cmd 명령을 해석하는 매크로 함수
_IOC_NR : 구분 번호 필드값을 읽는 매크로
_IOC_TYPE : 매직 번호 필드값을 읽는 매크로
_IOC_SIZE : 데이터의 크기 필드값을 읽는 매크로
_IOC_DIR : 읽기와 쓰기 속성 필드값을 읽는 매크로
_IO 매크로 함수
이 매크로는 전달되는 매개변수가 없고, 단순히 명령만 전달할 때 사용한다.
#define TEST_DEV_RESET _IO('Q', 0)
이때 응용 프로그램에서 전달되는 arg 매개변수를읽 생략하거나 0을 대입한다.
ioctl(dev, TEST_DEV_RESET, 0); 또는 idctl(dev, TEST_DEV_RESET);
_IOR 매크로 함수
디바이스에서 데이터를 읽어오는 명령을 만들 때 사용한다.
#define TEST_DEV_READ _IOR('Q', 1, int)
이는 디바이스에서 응용 프로그램이 읽어올 데이터의 크기가 int 크기 만큼이라는 의미
반환되는 값의 종류는 다음과 같다.
_IOC_NONE : 속성이 없다.
_IOC_READ : 읽기 속성이다.
_IOC_WRITE : 쓰기 속성이다.
_IOC_READ |_IOC_WRITE : 읽기 쓰기 속성이다.
일반적으로 이 명령을 사용할 때 응용 프로그램에서 ioctl() 함수의 arg 매개변수값은 디바이스 드라이버에서 데이터를 읽기 위한 데이터 버너(구조체)의 주소를 지정한다.
_IOW 매크로 함수 / _IOWR 매크로 함수
디바이스에 데이터를 쓸 명령을 만들 때 사용한다.
그외의 내용은 _IRO와 같다.
p.307 의 예제에서 쓰인 verify_area() 함수는 2.6.14 버전에서 부터 삭제되었으며 access_ok() 함수로 대체되었음. 사용법은 verify_area() 함수와 같음.
- END OF FILE -
'Embeded' 카테고리의 다른 글
NTC100 살리기 (0) | 2010.05.18 |
---|---|
iperf cross compile 하기! 인터넷 속도측정 솔루션 (0) | 2010.04.19 |
Android에서 S3C6410 MTD yaffs2 사용하기 (0) | 2010.04.07 |