devctl(),devctlv()
Control a device
Synopsis:
#include <sys/types.h>
#include <unistd.h>
#include <devctl.h>
int devctl( int filedes,
int dcmd,
void * dev_data_ptr,
size_t n_bytes,
int * dev_info_ptr );
int devctlv( int filedes,
int dcmd,
int sparts,
int rparts,
const iov_t *sv,
const iov_t *rv,
int *dev_info_ptr);
Arguments:
- filedes
- A file descriptor that you obtained by opening the device.
- dcmd
- A device-specific command for the process managing the open device.
The set of valid device-control commands, the associated data interpretation,
the returned dev_info_ptr values,
and the effect of the command on the device all depend on the device driver.
For: See: General information Device-control commands,
belowCommands for manipulating processes Controlling processes via the /proc filesystem
in the Processes chapter of the QNX OS Programmer's GuideSpecific commands Devctl and Ioctl Commands and the <sys/dcmd_*.h> header files - dev_data_ptr
- (devctl() only)
Depending on the command, this argument is one of:
- a pointer to a buffer containing data to be passed to the driver
- a receiving area for data coming from the driver
- both of the above
- NULL
- n_bytes
- (devctl() only) The size of the data to be sent to the driver, or the maximum size of the data to be received from the driver. If the size is greater than SSIZE_MAX - sizeof(io_devctl_t) (see <limits.h>), the function fails and sets errno to EOVERFLOW.
- sparts
- (devctlv() only) The number of elements in the sv array. The maximum number of entries is UIO_MAXIOV, and the sum of sparts and rparts must not exceed 524288, or the function fails and sets errno to EOVERFLOW.
- rparts
- (devctlv() only) The number of elements in the rv array. The maximum number of entries is UIO_MAXIOV, and the sum of sparts and rparts must not exceed 524288, or the function fails and sets errno to EOVERFLOW.
- sv
- (devctlv() only) An array of buffers that hold the data to send to the driver. The combined length of these buffers and those in rv must not exceed SSIZE_MAX, or the function fails and sets errno to EOVERFLOW.
- rv
- (devctlv() only) An array of buffers in which the driver can store data to return to the caller. The combined length of these buffers and those in sv must not exceed SSIZE_MAX, or the function fails and sets errno to EOVERFLOW.
- dev_info_ptr
- NULL, or a pointer to a location that the device can use to return additional status information on success, that is, the location is only updated when the function returns EOK. The data returned via dev_info_ptr depends on the device driver.
Library:
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
Description:
The devctl() function sends the device-specific command dcmd to the process managing the device opened as filedes. For example, you can send commands to specify properties for devices such as keyboards, sound cards or serial ports.
The devctlv() function is similar to devctl(), but uses I/O vectors for passing data to and from the driver.
Device-control commands
- __DIOF(class, cmd, data)
- Get information from the device.
- __DION(class, cmd)
- Send a command with no associated data.
- __DIOT(class, cmd, data)
- Pass information to the device.
- __DIOTF(class, cmd, data)
- Pass some information to the device, and get some from it.
- class
- The major category for the command.
The device-control commands are divided into the following classes to make organization easier:
- _DCMD_ALL — Common (all I/O servers).
- _DCMD_CAM — Low-level (Common Access Method) devices, such as disks or CD-ROMs.
- _DCMD_CHR — Character devices.
- _DCMD_FSYS, _DCMD_BLK — Filesystem/block I/O managers.
- _DCMD_INPUT — Input devices.
- _DCMD_IP — Internet Protocol.
- _DCMD_MEM — Memory card.
- _DCMD_MISC — Miscellaneous commands.
- _DCMD_MIXER — Mixer (Audio).
- _DCMD_NET — Network devices.
- _DCMD_PROC — Process manager.
- cmd
- The specific command in the class.
- data
- The type of data to pass to and/or from the device.
The dev_data_ptr argument to devctl() must be
a pointer to this type of data, and n_bytes is usually the
size of this type of data.
Note:The size of the structure that's passed as the last field to the __DIO* macros must be less than 2^14 == 16 KB. Anything larger than this interferes with the upper two directional bits.
- get_device_command(cmd)
- Extract the class and the specific device command from cmd (i.e., strip off the data type and the direction).
- get_device_direction(cmd)
- Get the direction of the command (DEVDIR_TO, DEVDIR_FROM, DEVDIR_TOFROM, or DEVDIR_NONE).
- get_device_size(cmd)
- Get the size of the device control structure used to define the dcmd.
Returns:
- EOK
- Success.
- EAGAIN
- Resource is temporarily unavailable; try again.
- EBADF
- Invalid open file descriptor, filedes.
- EINTR
- The devctl() function was interrupted by a signal.
- EINVAL
- The device driver detected an error in dev_data_ptr or n_bytes.
- EIO
- The devctl() function couldn't complete because of a hardware error.
- EFAULT
- A fault occurred trying to access the buffers provided.
- ENOTTY
- The device doesn't support the dcmd command.
- ENXIO
- No such device or address. For example, there's no media available to be loaded in the device represented by the file descriptor.
- EOVERFLOW
- One of the following occurred:
- An attempt was made to send or receive an amount of data that when added to the size of the device control structure exceeds the allowable limit.
- (devctlv() only) The sum of the IOV lengths for the send and receive buffers combined exceeds SSIZE_MAX, or the number of parts for the send and receive buffers combined exceeds 524288.
- EPERM
- The process doesn't have sufficient permission to carry out the requested command.
Specific devctl() commands might return other error codes; see Devctl and Ioctl Commands.
Examples:
Example 1: Setting RTS on a serial port
/* For "devctl()" */
#include <devctl.h>
#include <sys/dcmd_chr.h>
/* For "open()" */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* For "strerror()" */
#include <string.h>
/* For Errors */
#include <stdlib.h>
#include <stdio.h>
int check_RTS(int fd);
int main(void)
{
int data = 0, fd, error;
if((fd = open ("/dev/ser2", O_RDONLY)) == -1)
{
fprintf(stderr,
"Error with open() on /dev/ser2. Make sure it exists.\n");
perror (NULL);
exit(EXIT_FAILURE);
}
check_RTS(fd);
/* Let's turn ON RTS now. */
data = _CTL_RTS_CHG | _CTL_RTS;
if (error = devctl (fd, DCMD_CHR_SERCTL, &data,
sizeof(data), NULL))
{
fprintf(stderr, "Error setting RTS: %s\n",
strerror ( error ));
exit(EXIT_FAILURE);
}
/* RTS should now be ON. */
check_RTS(fd);
sleep (2);
/* Now let's turn RTS OFF. */
data = _CTL_RTS_CHG | 0;
if (error = devctl (fd, DCMD_CHR_SERCTL, &data,
sizeof(data), NULL))
{
fprintf(stderr, "Error setting RTS: %s\n",
strerror ( error ));
exit(EXIT_FAILURE);
}
/* RTS should now be OFF. */
check_RTS(fd);
close(fd);
return (1);
}
int check_RTS(int fd)
{
int data = 0, error;
/*
Let's see if RTS is set by using devctl() to get
line status information.
*/
if (error = devctl (fd, DCMD_CHR_LINESTATUS, &data,
sizeof(data), NULL))
{
fprintf(stderr, "Error getting RTS: %s\n",
strerror ( error ));
exit(EXIT_FAILURE);
}
if (data & _LINESTATUS_SER_RTS)
printf("RTS is SET!\n");
else
printf("RTS is NOT set\n");
return(1);
}
The two main areas of interest are the setting of data and the devctl() call. The data variable is used for both sending and receiving data.
If data equals: | RTS is turned: |
---|---|
_CTL_RTS_CHG | _CTL_RTS | ON |
_CTL_RTS_CHG | OFF |
When checking to see if RTS is set, we call devctl() with dcmd set to the DCMD_CHR_LINESTATUS macro and data containing any value (zero is clean). The devctl() function returns with data containing the Line Status value. This then can be used to determine what lines are set on that device. In our example, we check against _LINESTATUS_SER_RTS.
To find out what values to use with different DCMD_* commands, look in the appropriate <sys/dcmd_*.h> header file. For example, you'll find macros for the following values under DCMD_CHR_LINESTATUS in <sys/dcmd_chr.h>:
- Serial Port (DTR, RTS, CTS, DSR, RI, CD)
- Keyboard (Scroll/Caps/Num Lock, Shift, CTRL, ALT)
- Parallel Port (No Error, Selected, Paper Out, No Tack, Not Busy)
The value that's in the header is a bitwise AND with the value in data to see if the value is high for that line.
Example 2: Cycling through Caps Lock, Num Lock, and Scroll Lock
In the following example, we open the device /dev/kbd and we start applying changes to the Caps Lock, Scroll Lock, and Num Lock properties.
- _CONCTL_NUM_CHG (Console Control Num Lock Change) ORed together with _CONCTL_NUM (Console Control Num Lock) turns on Num Lock.
- _CONCTL_NUM_CHG on its own turns off Num Lock.
If data equals: | Num Lock is turned: |
---|---|
_CONCTL_NUM_CHG | _CONCTL_NUM | ON |
_CONCTL_NUM_CHG | OFF |
/* For "devctl()" */
#include <devctl.h>
#include <sys/dcmd_chr.h>
/* For "open()" */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
/* For "strerror()" */
#include <string.h>
/* For Errors */
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int data, fd, toggle = 1, error;
/* Open the device we wish to manipulate. */
if((fd = open ("/dev/kbd", O_RDONLY)) == -1)
{
fprintf(stderr,
"Error with open() on /dev/kbd. Make sure it exists.\n");
perror (NULL);
exit(EXIT_FAILURE);
}
while(1)
{
switch(toggle)
{
case 1:
{
/*
Turn on Num Lock and make sure that
Caps and Scroll lock are turned off.
*/
data = (_CONCTL_NUM_CHG | _CONCTL_NUM) | _CONCTL_CAPS_CHG |
_CONCTL_SCROLL_CHG;
break;
}
case 2:
{
/*
Turn off Num Lock and now turn on Caps Lock
(Scroll lock is already off).
*/
data = _CONCTL_NUM_CHG | (_CONCTL_CAPS_CHG | _CONCTL_CAPS);
break;
}
case 3:
{
/*
Turn off Caps lock and turn on Scroll lock
(Num lock is already off).
*/
data = _CONCTL_CAPS_CHG | (_CONCTL_SCROLL_CHG | _CONCTL_SCROLL);
toggle = 0;
break;
}
}
/* Explanation below. */
if (error = devctl (fd, DCMD_CHR_SERCTL, &data,
sizeof(data), NULL))
{
fprintf(stderr, "Error setting KBD: %s\n",
strerror ( error ));
exit(EXIT_FAILURE);
}
sleep(1);
toggle++;
}
return (1);
}
devctl (fd, DCMD_CHR_SERCTL, &data, sizeof(data), NULL)
The first parameter, fd, is the file descriptor of the device that's being changed.
The second parameter is the device class that's being changed.
In this case, it's a character device DCMD_CHR
,
with a subclass
of _SERCTL
.
The third parameter is the data variable; this is the ORed value.
Example 3: Duration example
#include <termios.h>
#include <devctl.h>
#include <errno.h>
#include <sys/dcmd_chr.h>
int tcdropline(int fd, int duration) {
int error;
duration = ((duration ? duration : 300) << 16) | _SERCTL_DTR_CHG | 0;
if ((error = devctl(fd, DCMD_CHR_SERCTL, &duration,
sizeof duration, 0)) != EOK) {
if (error == ENOSYS) {
errno = ENOTTY;
}
return -1;
}
return 0;
}
Classification:
Safety: | |
---|---|
Cancellation point | Yes |
Signal handler | Yes |
Thread | Yes |
Caveats:
When devctl() fails, the effect of the failed command depends on the device driver. The corresponding data might be transferred, partially transferred, or not transferred at all.
The devctl() function was originally part of the POSIX 1003.1d draft standard; but it was deprecated in the IEEE Approved Draft 10 standard.