To define an ioctl command, you’d call one of the following macros: _IO
, _IOR
, _IOW
, or _IOWR
. An explanation of each macro is provided in Table 3-1.
Table 3-1. ioctl Command Macros
_IO
, _IOR
, _IOW
, and _IOWR
are defined in the <sys/ioccom.h>
header as follows:
#define _IO(g,n) _IOC(IOC_VOID, (g), (n), 0) #define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t)) #define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t)) #define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
The g
argument, which stands for group, expects an 8-bit magic number. You can choose any number—just use it throughout your driver.
The n
argument is the ordinal number. This number is used to differentiate your driver’s ioctl commands from one another.
Finally, the t
argument is the type of data transferred during the I/O operation. Obviously, the _IO
macro does not have a t
argument, because no data transfer occurs.
Generally, ioctl command definitions look like this:
#define FOO_DO_SOMETHING _IO('F', 1) #define FOO_GET_SOMETHING _IOR('F', 2, int) #define FOO_SET_SOMETHING _IOW('F', 3, int) #define FOO_SWITCH_SOMETHING _IOWR('F', 10, struct foo)
Here, 'F'
is the magic number for these ioctl commands. Customarily, the first letter of your driver’s name—in uppercase—is selected as the magic number.
Naturally, all of the ordinal numbers are unique. But they don’t have to be consecutive. You can leave gaps.
Lastly, note that you can pass structures as the t
argument. Using a structure is how you’ll pass multiple arguments to an ioctl-based operation.
18.226.187.24