ioctl(9E)
NAME
ioctl - control a character device
SYNOPSIS
#include <sys/cred.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
int prefixioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *cred_p, int *rval_p);
INTERFACE LEVEL
Architecture independent level 1 (DDI/DKI). This entry point
is optional.
ARGUMENTS
dev Device number.
cmd Command argument the driver ioctl() routine inter-
prets as the operation to be performed.
arg Passes parameters between a user program and the
driver. When used with terminals, the argument is the
address of a user program structure containing driver
or hardware settings. Alternatively, the argument may
be a value that has meaning only to the driver. The
interpretation of the argument is driver dependent and
usually depends on the command type; the kernel does
not interpret the argument.
mode A bit field that contains:
o Information set when the device was opened. The
driver may use it to determine if the device was
opened for reading or writing. The driver can
make this determination by checking the FREAD
or FWRITE flags. See the flag argument descrip-
tion of the open() routine for further values.
o Information on whether the caller is a 32-bit or
64-bit thread.
o In some circumstances address space information
about the arg argument. See below.
cred_p
Pointer to the user credential structure.
rval_p
Pointer to return value for calling process. The
driver may elect to set the value which is valid only
if the ioctl() succeeds.
DESCRIPTION
ioctl() provides character-access drivers with an alternate
entry point that can be used for almost any operation other
than a simple transfer of characters in and out of buffers.
Most often, ioctl() is used to control device hardware
parameters and establish the protocol used by the driver in
processing data.
The kernel determines that this is a character device, and
looks up the entry point routines in cb_ops(9S). The kernel
then packages the user request and arguments as integers and
passes them to the driver's ioctl() routine. The kernel
itself does no processing of the passed command, so it is up
to the user program and the driver to agree on what the
arguments mean.
I/O control commands are used to implement the terminal set-
tings passed from ttymon(1M) and stty(1), to format disk
devices, to implement a trace driver for debugging, and to
clean up character queues. Since the kernel does not inter-
pret the command type that defines the operation, a driver
is free to define its own commands.
Drivers that use an ioctl() routine typically have a com-
mand to ``read'' the current ioctl() settings, and at least
one other that sets new settings. Drivers can use the mode
argument to determine if the device unit was opened for
reading or writing, if necessary, by checking the FREAD or
FWRITE setting.
If the third argument, arg, is a pointer to a user buffer,
the driver can call the copyin(9F) and copyout(9F) func-
tions to transfer data between kernel and user space.
Other kernel subsystems may need to call into the drivers
ioctl() routine. Drivers that intend to allow their ioctl()
routine to be used in this way should publish the ddi-
kernel-ioctl property on the associated devinfo node(s).
When the ddi-kernel-ioctl property is present, the mode
argument is used to pass address space information about arg
through to the driver. If the driver expects arg to contain
a buffer address, and the FKIOCTL flag is set in mode, then
the driver should assume that it is being handed a kernel
buffer address. Otherwise, arg may be the address of a
buffer from a user program. The driver can use
ddi_copyin(9F) and ddi_copyout(9F) perform the correct type
of copy operation for either kernel or user address spaces.
See the example on ddi_copyout(9F).
Drivers have to interact with 32-bit and 64-bit applica-
tions. If a device driver shares data structures with the
application (for example, through exported kernel memory)
and the driver gets recompiled for a 64-bit kernel but the
application remains 32-bit, binary layout of any data struc-
tures will be incompatible if they contain longs or
pointers. The driver needs to know whether there is a model
mismatch between the current thread and the kernel and take
necessary action. The mode argument has additional bits set
to determine the C Language Type Model which the current
thread expects. mode has FILP32 set if the current thread
expects 32-bit ( ILP32) semantics, or FLP64 if the current
thread expects 64-bit ( LP64) semantics. mode is used in
combination with ddi_model_convert_from(9F) and the FMODELS
mask to determine whether there is a data model mismatch
between the current thread and the device driver (see the
example below). The device driver might have to adjust the
shape of data structures before exporting them to a user
thread which supports a different data model.
To implement I/O control commands for a driver the following
two steps are required:
1. Define the I/O control command names and the associated
value in the driver's header and comment the commands.
2. Code the ioctl() routine in the driver that defines the
functionality for each I/O control command name that is
in the header.
The ioctl() routine is coded with instructions on the
proper action to take for each command. It is commonly a
switch statement, with each case definition corresponding
to an ioctl() name to identify the action that should be
taken. However, the command passed to the driver by the user
process is an integer value associated with the command name
in the header.
RETURN VALUES
ioctl() should return 0 on success, or the appropriate
error number. The driver may also set the value returned to
the calling process through rval_p.
EXAMPLES
Example 1: ioctl() entry point
The following is an example of the ioctl() entry point and
how to support 32-bit and 64-bit applications with the same
device driver.
struct passargs32 {
int len;
caddr32_t addr;
};
struct passargs {
int len;
caddr_t addr;
};
xxioctl(dev_t dev, int cmd, intptr_t arg, int mode,
cred_t *credp, int *rvalp) {
struct passargs pa;
#ifdef _MULTI_DATAMODEL
switch (ddi_model_convert_from(mode & FMODELS)) {
case DDI_MODEL_ILP32:
{
struct passargs32 pa32;
ddi_copyin(arg, &pa32, sizeof (struct passargs32), mode);
pa.len = pa32.len;
pa.address = pa32.address;
break;
}
case DDI_MODEL_NONE:
ddi_copyin(arg, &pa, sizeof (struct passargs), mode);
break;
}
#else /* _MULTI_DATAMODEL */
ddi_copyin(arg, &pa, sizeof (struct passargs), mode);
#endif /* _MULTI_DATAMODEL */
do_ioctl(&pa);
....
}
SEE ALSO
stty(1), ttymon(1M), dkio(7I), fbio(7I), termio(7I),
open(9E), put(9E), srv(9E), copyin(9F), copyout(9F),
ddi_copyin(9F), ddi_copyout(9F), ddi_model_convert_from(9F),
cb_ops(9S)
WARNINGS
Non-STREAMS driver ioctl() routines must make sure that
user data is copied into or out of the kernel address space
explicitly using copyin(9F), copyout(9F), ddi_copyin(9F),
or ddi_copyout(9F), as appropriate.
It is a severe error to simply dereference pointers to the
user address space, even when in user context.
Failure to use the appropriate copying routines can result
in panics under load on some platforms, and reproducible
panics on others.
NOTES
STREAMS drivers do not have ioctl() routines. The stream
head converts I/O control commands to M_IOCTL messages,
which are handled by the driver's put(9E) or srv(9E) rou-
tine.
Man(1) output converted with
man2html