ioctl
2025년 9월 8일
ioctl (I/O control) 이란? #
ioctl이라는건 외부에서 드라이버에게 하드웨어를 어떻게 조작할건지 요청하고 드라이버는 그걸 abi 형태로 인터페이스를 노출시켜놨다 이렇게 이해하면 되나?
유저공간 → 커널드라이버 로 제어 명령을 보내는 통로
드라이버는 이 제어 명령들을 UAPI(= 사용자 공간 ABI)로 문서화/노출합니다. 즉, request 번호와 그에 대응하는 구조체 레이아웃이 “계약(ABI)”이에요.
하드웨어 상태/모드 변경(전원, 클럭, 캘리브레이션, 포맷 설정 등)처럼 read/write로 하기 애매한 작업을 수행합니다.
단, 항상 하드웨어만은 아님: TUN/TAP, loop, 가상 장치처럼 소프트웨어 디바이스의 설정도 ioctl로 합니다.
1// int ioctl(int fd, unsigned long request, void *argp);
2
3// 드라이버가 헤더에 노출하는 명령들 ABI (번호는 0..N)
4#define MY_IOC_GET_VERSION _IOR(MY_IOC_MAGIC, 1, int) // 커널→유저로 int 읽음
5#define MY_IOC_SET_BUFSIZE _IOW(MY_IOC_MAGIC, 2, unsigned long) // 유저→커널로 ulong 씀
6struct my_echo { uint32_t len; char data[256]; };
7#define MY_IOC_ECHO _IOWR(MY_IOC_MAGIC, 3, struct my_echo) // 양방향
8
9// 유저영역에서 요청하는코드. 위에서 제공된 헤더를 include함
10int main(void) {
11 // 기기 fd 얻어오기
12 int fd = open("/dev/mydev", O_RDWR);
13 if (fd < 0) { perror("open"); return 1; }
14
15 // 장치에서 버전을 가져옴. 버전 가져오는 동작을 하는 ioctl 값과 버퍼를 넘겨주면 드라이버가 그걸 채워준다.
16 int ver;
17 if (ioctl(fd, MY_IOC_GET_VERSION, &ver) == -1) perror("GET_VERSION");
18 else printf("version=%d\n", ver);
19
20 // 내부 버퍼 사이즈 세팅하는 ioctl 요청
21 unsigned long sz = 4096;
22 if (ioctl(fd, MY_IOC_SET_BUFSIZE, &sz) == -1) perror("SET_BUFSIZE");
23
24 // 양방향 읽기쓰기 다함. 그냥 장치에서 읽은대로 다시 데이터를 채워준다.
25 struct my_echo e = { .len = 5 };
26 memcpy(e.data, "hello", 5);
27 if (ioctl(fd, MY_IOC_ECHO, &e) == -1) perror("ECHO");
28 else printf("echo back len=%u data=%.*s\n", e.len, (int)e.len, e.data);
29
30 // 소켓 닫고 종료
31 close(fd);
32 return 0;
33}