-
ioctl()
는 하드웨어의 제어와 상태 정보를 얻기 위해 제공되는 함수이다. -
데이터를 읽고 쓰는 등의 기능은
read()
,write()
를 사용하지만, 하드웨어를 제어하거나 상태 정보를 확인하려면ioctl()
를 이용해야한다.
-
d
: open한 디바이스 드라이버의 fd 값이다 -
request
: 디바이스에게 전달할 명령이다. 이 명령에 따라서 디바이스를 컨트롤 할 수 있다. -
/usr/include/asm/ioctl.h
헤더파일에 ioctl의 커맨드 번호를 작성하는데 사용해야하는 매크로가 정의되어있다.-
_IO(int type, int number)
: type, number 값만 전달하는 단순한 ioctl에 사용 -
IOR(int type, int number, data_type)
: 디바이스 드라이버에서 데이터를 읽는 ioctl에 사용 -
_IOW(int type, int number, data_type)
: 디바이스 드라이버에서 데이터를 쓰는 ioctl에 사용 -
_IORW(int type, int number, data_type)
: 디바이스 드라이버에서 데이터를 쓰고 읽는 ioctl에 사용 -
위 매크로 이외에도
ioctl.h
헤더파일에 다양한 매크로가 있다. -
각 매크로에 들어가는 인자는 다음과 같다
-
type
: 디바이스 드라이버에 고유하게 할당된 1바이트 정수 -
number
: ioctl 명령마다의 고유 번호 -
data_type
: 클라이언트와 드라이버간에 교환되는 바이트 수를 계산하는데 사용되는 유형 -
데이터의 입력, 출력, 쓰기가 가능한 매크로를 다음과 같이 선언할 수 있다.
위 코드에서 SET_DATA 매크로는
IOW()
매크로를 사용했으며 type에는'G'
를 할당했다.
또한 number에는 IOR 매크로와 서로 다른 번호를 할당했다. data_type에는ioctl_info
구조체를 할당했다.
-
-
IOCTL 사용법
-
유저 영역에서
ioctl()
을 호출하면, 시스템 콜을 통해서 sys_ioctl이 호출되고 file_operations 구조체에 등록된 ioctl 함수가 수행된다. 이게 바로 위 코드에선chardev_ioctl()
이다. -
ioctl 두번째 인자로 들어온 커맨드에 따라서 분기를 하게 되는데,
SET_DATA
커맨드이면 선언한 매크로가 수행되고,copy_from_user()
함수를 통해 arg에 담긴 값이 inof 구조체에 저장된다. 즉 유저영역의 값이 커널영역에 저장된다.GET_DATA
커맨드가 들어오면copy_to_user()
함수에 의해 커널에 저장된 값을 arg로 복사한다. -
makefile을 이용해서 빌드해보자.
-
성공적으로 빌드 되었다. 이제 insmod로
chardev.ko
모듈을 올리면/dev/chardev0
디바이스 파일이 생성될 것이다. -
이제 테스트 코드로
ioctl()
이 정상적으로 동작하는지 확인해보자. -
chardev.h
에 구현한 ioctl_info 구조체 변수를 두개 선언한다.(set_info, get_info)
.strncpy()
함수를 이용하여set_info.buf
필드에 문자열을 복사한다. -
그다음 생성된
/dev/chardev0
파일을 열고,ioctl()
함수로set_info
구조체를 커널영역의 버퍼에 복사한다. 즉 위에서 복사한 문자열이 커널 버퍼에 복사될 것이다. -
마지막으로
ioctl()
함수로 GET_DATA 매크로와 get_info 구조체를 인자로 주어 아까 복사한 데이터를 get_info 구조체 변수에 복사한다.ioctl()
을 통해 정상적으로 데이터를 읽어왔다면,get_info.buf
필드에"lazenca.0x0"
이 출력될 것이다. -
dmesg 결과와
./test
를 실행해보면, 생각한대로 잘 출력된다. 즉ioctl()
이 정상동작하여 input, output이 잘 구현되었다.
참고