IOCTL(9)

NAME
ioctl, _IO, _IOR, _IOW, _IOWR - how to implement a new ioctl call to access device drivers

SYNOPSIS
#include <sys/ioccom.h>
_IO(g, t);
_IOR(g, n, t);
_IOW(g, n, t);
_IOWR(g, n, t);

DESCRIPTION
Whenever an ioctl(2) call is made, the kernel dispatches it to the device driver which can then interpret the request number and data in a specialized manner. Ioctls are defined as:

    #define MYDEVIOCTL   fun(g, n, t)

where the different symbols correspond to:

MYDEVIOCTL
    The name which will later be given in the ioctl(2) system call as second argument, e.g.,

        ioctl(fd, MYDEVIOCTL, ...)

fun()
    A macro which can be one of:

    _IO()
        The call is a simple message to the kernel by itself. It does not copy anything into the kernel, nor does it want anything back.

    _IOR()
        The call only reads parameters from the kernel and does not pass any to it.

    _IOW()
        The call only writes parameters to the kernel, but does not want anything back.

    _IOWR()
        The call writes data to the kernel and wants information back.

    We always consider reading or writing to the kernel, from the user perspective.

g   This integer describes to which subsystem the ioctl applies. Here are some examples:

    '8' aac(4)
    'a' nata(4)
    'B' bpf(4)
    'C' cam(4)
    'C' ciss(4)
    'd' disklabel(5)
    'd' diskslice
    'd' drm(4)
    'f' generic file-descriptor
    'F' frame buffer
    'h' HAMMER(5)
    'i' iic(4)
    'i' carp(4)
    'i' gre(4)
    'k' keyboard(4) and syscons(4)
    'm' mem(4)
    'm' /dev/midi
    'm' mtio(4)
    'M' sound(4) mixer
    'n' smb(4)
    'p' /dev/dsp and /dev/audio
    'p' pci(4)
    'p' ppbus(4)
    'p' procfs(5)
    'q' /dev/sequencer
    'r' random number generator
    't' tty(4)
    't' tap(4)
    't' tun(4)
    't' SLIP ttys
    'T' snp(4)

n   This number uniquely identifies the ioctl within the group. That said, two subsystems may share the same g, but there may be only one n for a given g. This is an unsigned 8 bit number.

t   This specifies the type of the passed parameter. This one gets internally transformed to the size of the parameter, so for example, if you want to pass a structure, then you have to specify that structure and not a pointer to it or sizeof(struct MYDEV).

In order for the new ioctl to be visible to the system, it is installed in either <sys/ioctl.h> or one of the files that are reached from <sys/ioctl.h>.

RETURN VALUES
A distinction must be made at this point. All *_ioctl() routines from within kernel should return either 0 for success or a defined error code, as described in <sys/errno.h>. At the libc level though a conversion takes place, so that eventually ioctl(2) returns either 0 for success or -1 for failure, in which case the errno variable is set accordingly.

The use of magic numbers such as -1, to indicate that a given ioctl code was not handled, is strongly discouraged. The value -1 is bound to the ERESTART pseudo-error, which is returned inside kernel to modify return to process.

EXAMPLES
Let's suppose that we want to pass an integer value to the kernel. From the user point of view, this is like writing to the kernel. So we define the ioctl as:

    #define	MYDEVIOCTL	_IOW('i', 25, int)

Within the *_ioctl() routine of the driver, it can be then accessed like:

    int
    mydev_ioctl(struct dev_ioctl_args *ap)
    {
    	int error;
    	int *a;
    	switch (ap->a_cmd) {
    	case MYDEVIOCTL:
    		a = (int *)ap->data;
    		kprintf("Value passed from userspace: %d\n", *a);
    		return (0);    /* Success */
    		break;
    	/* Handle other ioctls here */
            default:
                    /* Inappropriate ioctl for device */
                    error = ENOTTY;
    		break;
    	}
    	return (error);
    }

In userspace:

    int a = 101;
    if (ioctl(fd, MYDEVIOCTL, a) == -1) {
    	/* Handle failure */
    }

SEE ALSO
ioctl(2)