ioctl()" -- System Call (libc)" "

Device-dependent control

##iinncclluuddee &&lltt;;uunniissttdd..hh&&ggtt;;
##iinncclluuddee &&lltt;;_h_e_a_d_e_r..hh&&ggtt;;
iiooccttll((_f_d,, _c_o_m_m_a_n_d,, _a_r_g))
iinntt _f_d,, _c_o_m_m_a_n_d;; cchhaarr **_a_r_g;;

ioctl() lets you interact directly with a device driver. You can use it to set or retrieve parameters for devices (line printers, communications lines, terminals), and non-standard spacing operations for tape drives.

ioctl() acts upon the block-special file or character-special file associated with the file descriptor fd. command points to the specific request.

header names the header file that defines symbolic commands for the device you wish to manipulate. Using the symbolic command definitions from the header files promotes device independence within each device type. A complete list of symbolic commands appears below.

arg passes a buffer of information (defined by structures in the appropriate header files) to the driver. For any command not needing additional information, this argument should be NULL.

Some ioctl() requests work on all files, and are not passed to any driver.

ioctl() returns -1 on errors, such as a bad file descriptor. Because the call is device dependent, almost any other error could be returned.

Commands

The following gives the commands that can be used with ioctl(), as extracted from COHERENT's header files. Please note the following caveats:

+o
New drivers are being added continually to COHERENT, both by Mark Williams Company and by users and third-party vendors. You should regard the following list as being tentative at best.

+o
Because the commands and arguments with with ioctl() are unique to COHERENT's suite of device drivers, ioctl() is one of the least portable of all system calls. If you want your code to run on multiple operating systems, you should use ioctl() judiciously.

&&lltt;;ssyyss//ccddrroomm..hh&&ggtt;;
Header file used to manipulate a CD-ROM device. Unless otherwise noted, arg is ignored:

CCDDRROOMMPPAAUUSSEE
Pause playing an audio CD.
CCDDRROOMMRREESSUUMMEE
Resume playing an audio CD.
CCDDRROOMMPPLLAAYYMMSSFF
Play an audio CD at a given minute-second frame (MSF) address. arg points to an array of six bytes that give the MSF address.
CCDDRROOMMPPLLAAYYTTRRKKIINNDD
Play a track on an audio CD. arg points to an array of four bytes that give, respectively, the start track, the start index, the end track, and the end index of the track to be played.
CCDDRROOMMRREEAADDTTOOCCHHDDRR
Read the CD's table-of-contents header. arg points to a structure of type cdrom_tochdr into which the header is written.
CCDDRROOMMRREEAADDTTOOCCEENNTTRRYY
Read an entry from the table-of-contents header. arg points to a structure of type cdrom_tocentry into which the entry is written.
CCDDRROOMMSSTTOOPP
Spin down the CD-ROM drive's motor.
CCDDRROOMMSSTTAARRTT
Turn on the CD-ROM drive's motor.
CCDDRROOMMEEJJEECCTT
Eject the CD-ROM. Note that this does not work on every variety of CD-ROM drive.
CCDDRROOMMVVOOLLCCTTRRLL
Control the volume on an audio CD. arg points to an array of four bytes that, respectively, set the the volume on channels zero through three.
CCDDRROOMMSSUUBBCCHHNNLL
Read data about a sub-channel. arg points to a structure of type cdrom_subchnl into which the information about the sub-channel is written.
CCDDRROOMMRREEAADDMMOODDEE11
Read type-1 data. arg points to a structure into which the data are written.
CCDDRROOMMRREEAADDMMOODDEE22
Read type-2 data. arg points to a structure into which the data are written.

&&lltt;;ssyyss//ffddiiooccttll..hh&&ggtt;;
This header file is used with the floppy-disk drive:

FFDDFFOORRMMAATT
Format a track on a floppy disk. arg points to a two-byte array that identifies, respectively, the cylinder and head to format.

&&lltt;;ssyyss//hhddiiooccttll..hh&&ggtt;;
This header file is used with AT-style hard-disk drives (i.e., IDE, ESDI, MFM, or RLL disks). arg gives the address in user memory where drive attributes reside, or to which they should be written:

HHDDGGEETTAA
Get drive attributes.
HHDDSSEETTAA
Set drive attributes.
HHDDGGEETTIIDDEEIINNFFOO
Get the attributes of an IDE drive. arg should point to a copy of the structure ide_info; this call to ioctl() initializes the structure with the requested information.

&&lltt;;ssyyss//nnuullll..hh&&ggtt;;
This header file defines ioctls that examine system memory:

NNLLFFRREEEE
Read the amounts of memory on your system that are available and free. arg gives the address of an object of type FREEMEM, which is defined in header file <null.h>. This type is an array of two longs: the first receives the amount of available memory, and the second the amount of free memory. For an example of a program that uses this ioctl(), see the Lexicon entry for freemem.
NNLLIIDDLLEE
Read the system's idle time. arg points to an array of two longs. The first long receives system's idle ticks; the second, the number of ticks since system startup. From reading these values repeatedly, you can compute the changes in system idle time and time since startup, and so see what the system's load is. For an example of how to this call to ioctl(), see the Lexicon entry for idle.

&&lltt;;ssyyss//ssddiiooccttll..hh&&ggtt;;
The commands defined in this header file are passed to the driver aha, which manipulates Adaptec SCSI disks. None does anything.

&&lltt;;ssggttttyy..hh&&ggtt;;
The following commands are used with the sgtty method of controlling terminal devices. They are documented in more detail in the Lexicon entry for sgtty. arg points to a structure of type sgttyb, which is defined in that header file:

TTIIOOCCHHPPCCLL
Hang up on last close.
TTIIOOCCGGEETTPP
Get modes (old ggttttyy).
TTIIOOCCSSEETTPP
Set modes (old ssttttyy).
TTIIOOCCSSEETTNN
Set modes without delay or flush.
TTIIOOCCEEXXCCLL
Set exclusive use.
TTIIOOCCNNXXCCLL
Set non-exclusive use.
TTIIOOCCFFLLUUSSHH
Flush I/O queues.
TTIIOOCCSSEETTCC
Set characters.
TTIIOOCCGGEETTCC
Get characters.

&&lltt;;ssttrrooppttss..hh&&ggtt;;
STREAMS commands. arg points to a STREAMS control block that will be used to generate an M_IOCTL message.

II__NNRREEAADD
Get message length, count.
II__PPUUSSHH
Push named module.
II__PPOOPP
Pop topmost module.
II__LLOOOOKK
Get name of the topmost module.
II__FFLLUUSSHH
Flush read/write side.
II__SSRRDDOOPPTT
Set stream head read mode.
II__GGRRDDOOPPTT
Get stream head read mode.
II__SSTTRR
Send ioctl() message downstream.
II__SSEETTSSIIGG
Register for signal SIGPOLL.
II__GGEETTSSIIGG
Return registered event mask.
II__FFIINNDD
Locate named module on stream.
II__LLIINNKK
Link two streams.
II__UUNNLLIINNKK
Unlink two streams.
II__RREECCVVFFDD
Receive file descriptor from pipe.
II__PPEEEEKK
Examine stream head data.
II__SSEENNDDFFDD
Send file descriptor to pipe.

The following commands are not covered by iBCS2:

II__SSWWRROOPPTT
Set stream write mode.
II__GGWWRROOPPTT
Get stream write mode.
II__LLIISSTT
Get name of all modules/drivers.
II__PPLLIINNKK
Create persistent link.
II__PPUUNNLLIINNKK
Undo persistent link.
II__FFLLUUSSHHBBAANNDD
Flush priority band.
II__CCKKBBAANNDD
Check for existence of priority band.
II__GGEETTBBAANNDD
Get band of first message.
II__AATTMMAARRKK
Check whether current message is marked.
II__SSEETTCCLLTTIIMMEE
Set drain timeout for stream.
II__GGEETTCCLLTTIIMMEE
Get the current close timeout.
II__CCAANNPPUUTT
Check if band is writeable.

&&lltt;;ssyyss//ttaappee..hh&&ggtt;;
Header file for interfacing with magnetic-tape devices. arg points to an area in user space that holds additional information for the tape device. A tape driver may recognize any of the following ioctl() commands:

TT__EERRAASSEE
Erase tape.
TT__LLOOAADD
Load. Not used.
TT__RRDDSSTTAATT
Read status.
TT__RRSSTT
Reset.
TT__RREETTEENNSSIIOONN
Retension tape.
TT__RRWWDD
Rewind tape.
TT__SSBBBB
Space block backward -- move backward by arg blocks. Not used.
TT__SSBBFF
Space Block Forward -- move forward by arg blocks. Not used.
TT__SSBBRREECC
Not used.
TT__SSFFBB
Space Filemark Backward -- move backwards by arg files.
TT__SSFFFF
Space Filemark Forward -- move forward by arg files.
TT__SSFFRREECC
Not used.
TT__TTIINNIITT
Not used.
TT__UUNNLLOOAADD
Unload. Not used.
TT__WWRRFFIILLEEMM
Write file marks. Not used.

&&lltt;;tteerrmmiioo..hh&&ggtt;;
The following commands are used with the termio method of controlling a terminal. They are documented in more detail in the Lexicon entry for termio. arg points to a structure of type sgttyb, which is described above.

TTCCGGEETTAA
Get terminal parameters.
TTCCSSEETTAA
Set terminal parameters.
TTCCSSEETTAAWW
Wait for drain, set parameters.
TTCCSSEETTAAFF
Wait for drain, flush input, set parms.
TTCCSSBBRRKK
Send 0.25-second break.

The following commands also take arguments when called via ioctl():

TTCCXXOONNCC
Start/stop control: An argument of zero suspends output; an argument of one restarts suspended output.

TTCCFFLLSSHH
Flush queues: An argument of zero flushes the input queue; an argument of one flushes the output queue; and an argument of two flushes both queues.

&&lltt;;ssyyss//vvttkkdd..hh&&ggtt;;
This header file defines commands used with the keyboard driver. arg points to a structure of type sgttyb, which is defined in header file sgtty.h.

KKDDMMAAPPDDIISSPP
Map the display into user space.
KKDDSSKKBBMMOODDEE
Toggle the scan code xxllaattee.
KKDDMMEEMMDDIISSPP
Dump a byte of virtual or physical memory.
KKDDGGKKBBSSTTAATTEE
Get the keyboard's shift state.
KKIIOOCCIINNFFOO
Determine the workstation of the virtual terminal.
KKIIOOCCSSOOUUNNDD
Start sound generation.
KKDDGGEETTLLEEDD
Get the state of the keyboard's LEDs.
KKDDSSEETTLLEEDD
Set the state of the LEDs.

The following four ioctl() commands allow user programs to perform I/O instructions directly, rather than going through the system-call interface and having the kernel perform the I/O. The most common need for these functions is in window managers and similar applications, where the usual kernel interface would be unacceptably slow.

Normally, any user program that attempts to execute I/O instructions directly to hardware will get an immediate SIGSEGV and be terminated. Use of the commands below allow user-level programs to perform I/O without being terminated. The I/O operations are available through functions inb(), outb(), etc., which are present in the kernel-support library /etc/conf/lib/k386.a and are documented in the manual to the COHERENT Device Driver Kit.

Access to any of these functions may be restricted to the superuser on some systems:

KKDDEENNAABBIIOO
Allow the user process permission to perform input/output operations to all available I/O addresses. The third argument to ioctl() is ignored.
KKDDDDIISSAABBIIOO
Prohibit user processes from performing input/output operations to all available I/O addresses. The third argument to ioctl() is ignored. It is normal for direct I/O to ports to be disallowed at user level. The main reason for this call is to undo the effect of preceding KDENABIO or KDADDIO calls.
KKDDAADDDDIIOO
Allow user-level I/O to a port. The third argument to ioctl() is an unsigned short that gives the single address value of the port.
KKDDDDEELLIIOO
Disallow user-level I/O to a port. The third argument to ioctl() is an unsigned short that gives the single address value of the port.

It is normal for direct I/O to ports to be disallowed at user level. The main reason for this call is to undo the effect of preceding KDADDIO calls.

Example

The following program, by Udo Munk, demonstrates how to use ioctl() to read a mouse plugged into a serial port. It takes one argument, the name of the port you wish to check.
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <termio.h>
char *mouse;
int mouse_fd;
struct termio old_tty, new_tty;
/* do the right thing by signals */
sig_handler()
{
     ioctl(mouse_fd, TCSETAF, &old_tty);
     exit(EXIT_SUCCESS);
}
/* cry and die */
void fatal(message)
char *message;
{
     fprintf (stderr, "%s\n", message);
     exit(EXIT_FAILURE);
}
/* run the whole shebang */
main(argc, argv)
int argc; char **argv;
{
     struct pollfd fds[1];
     if (argc != 2)
          fatal ("Usage: findmouse /dev/com[1-4]pl");
     if (strncmp(argv[1], "/dev/com1pl", 11) &&
               strncmp(argv[1], "/dev/com2pl", 11) &&
               strncmp(argv[1], "/dev/com3pl", 11) &&
               strncmp(argv[1], "/dev/com4pl", 11))
          fatal ("Usage: findmouse /dev/com[1-4]pl");
     mouse = argv[1];
     signal(SIGINT, sig_handler);
     signal(SIGQUIT, sig_handler);
     signal(SIGHUP, sig_handler);
     fprintf(stdout, "Trying to open %s ...\n", mouse);
     if ((mouse_fd = open(mouse, O_RDONLY)) < 0)
          fatal ("Cannot open this device.");
     fprintf(stdout, "Success.\n");
     fprintf(stdout, "Trying to read line mode of %s ...\n", mouse);
     if (ioctl(mouse_fd, TCGETA, &old_tty) < 0)
          fatal ("Cannot read this device'ss line mode.");
     fprintf(stdout, "Success.\n");
     new_tty = old_tty;
     new_tty.c_cflag &= ~(CBAUD | HUPCL);
     new_tty.c_cflag |= CLOCAL | B1200;
     new_tty.c_iflag = IGNBRK;
     new_tty.c_oflag = new_tty.c_lflag = 0;
     /*
      * VMIN = 0, VTIME = 0 has the same effect as setting O_NDELAY on the
      * input line.
      */
     new_tty.c_cc[VMIN] = 0;
     new_tty.c_cc[VTIME] = 0;
     /* Set up to poll the input line. */
     fds->fd = mouse_fd;
     fds->events = POLLIN;
     fprintf(stdout, "Trying to set new line mode for %s ...\n", mouse);
     if (ioctl(mouse_fd, TCSETAF, &new_tty) < 0)
          fatal ("Cannot set new tty line mode");
     fprintf(stdout, "Success.\n");
     fprintf(stdout, "\nI'm reading from %s. To exit, type <ctrl-C>.\n",
          mouse);
     fprintf(stdout,
          "If you see stuff on the screen when you move the mouse,\n");
     fprintf(stdout,
          "then you have found the mouse port.\n");
     fprintf(stdout, "\nNow wiggle your mouse:\n");
     for (;;) {
          size_t read_count;
          unsigned char mousebuf [128];
          /* Block waiting for mouse input. */
          if (poll (fds, 1, -1) < 0)
               break;
          /* Drain input in large chunks until it becomes time to block. */
          while ((read_count = read (mouse_fd, mousebuf,
                    sizeof (mousebuf))) != 0) {
               unsigned char * scan = mousebuf;
               do
                    printf ("%02x ", * scan ++);
               while (-- read_count != 0);
               fflush (stdout);
          }
     }
}

See Also

Notes

The type of the arg to ioctl() is declared as char * mainly to improve portability. In most cases, the actual argument type will be something like struct sgttyb *, depending on the device and command. The actual argument should be cast to type char * to ensure cross-machine portability.

A Under COHERENT 286, the main header file for ioctl() is <sgtty.h>. This header file is also included with COHERENT 386 for compatibility with older applications.