Control a device
#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);
For: | See: |
---|---|
General information | Device-control commands, below |
Commands for manipulating processes | Controlling processes via the /proc filesystem in the Processes chapter of the QNX Neutrino Programmer's Guide |
Specific commands | Devctl and Ioctl Commands and the <sys/dcmd_*.h> header files |
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
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.
Specific devctl() commands might return other error codes; see Devctl and Ioctl Commands.
/* 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>:
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.
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.
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.
#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) == -1) { if(error == ENOSYS) { errno = ENOTTY; } return -1; } return 0; }
Safety: | |
---|---|
Cancellation point | Yes |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |
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.