| IOCTL(9) | Kernel Developer's Manual | IOCTL(9) |
ioctl — how to
implement a new ioctl call to access device drivers
#include
<sys/ioctl.h>
#include <sys/ioccom.h>
int
ioctl(int,
unsigned long,
...);
ioctl are internally defined as
where the different variables and functions are:
FOOIOCTLioctl(s, FOOIOCTL,
...)fun()In order for the new ioctl to be known to the system it is installed in either ⟨sys/ioctl.h⟩ or one of the files that are reached from ⟨sys/ioctl.h⟩.
All ioctl() routines should return either
0 or a defined error code. The use of magic numbers such as -1, to indicate
that a given ioctl code was not handled is strongly discouraged. The value
-1 coincides with the historic value for ERESTART
which was shown to produce user space code that never returned from a call
to ioctl(2).
For ioctl codes that are not handled by a given routine, the
pseudo error value EPASSTHROUGH is provided.
EPASSTHROUGH indicates that no error occurred during
processing (it did not fail), but neither was anything processed (it did not
succeed). This supersedes the use of either ENOTTY
(which is an explicit failure) or -1 (which has no contextual meaning) as a
return value. ENOTTY will get passed directly back
to user space and bypass any further processing by other ioctl layers. Only
code that wishes to suppress possible further processing of an ioctl code
(e.g., the tty line discipline code) should return
ENOTTY. All other code should return
EPASSTHROUGH, even if it knows that no other layers
will be called upon.
If the value EPASSTHROUGH is returned to
sys_ioctl(), then it will there be changed to
ENOTTY to be returned to user space, thereby
providing the proper error notification to the application.
#define FOOIOCTL _IOWR('i', 23, int)
int a = 3;
error = ioctl(s, FOOICTL, &a);
Within the
ioctl()-routine of the
driver, it can be then accessed like
driver_ioctl(..., u_long cmd, void *data)
{
...
switch (cmd) {
case FOOIOCTL:
int *a = (int *)data;
printf(" Value passed: %d\n", *a);
break;
}
}
Note that if you for example try to read information from an
ethernet driver where the name of the card is included in the third argument
(e.g., ioctl(s, READFROMETH, struct ifreq *)), then you have to use the
_IOWR()
form not the
_IOR(),
as passing the name of the card to the kernel already consists of writing
data.
| July 7, 2022 | NetBSD 11.0 |