iiooccttll() -- System Call (libc)

Device-dependent control
#iinncclluuddee <tteerrmmiioo.hh>
iiooccttll(_f_d, _c_o_m_m_a_n_d, _a_r_g)
iinntt _f_d, _c_o_m_m_a_n_d; cchhaarr *_a_r_g;

iiooccttll() 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.

iiooccttll()  acts  upon   the  block-special  file  or  character-special  file
associated  with the  file descriptor  _f_d. _c_o_m_m_a_n_d  points to  the specific
request.

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

_a_r_g  passes  a  buffer   of  information  (defined  by  structures  in  the
appropriate  header files)  to  the driver.   For any  _c_o_m_m_a_n_d not  needing
additional information, this argument should be NULL.

Some iiooccttll() requests work on all files, and are not passed to any driver.

iiooccttll() returns -1  on errors, such as a bad  file descriptor.  Because the
call is device dependent, almost any other error could be returned.

_C_o_m_m_a_n_d_s
The  following  gives  the commands  that  can  be  used  with iiooccttll(),  as
extracted from COHERENT's header files.

ssyyss/ffddiiooccttll.hh
     This header file is used with the floppy-disk drive:

     FFDDFFOORRMMAATT       Format a track on a floppy disk.

ssyyss/vvttkkdd.hh
     This header file defines commands used with the keyboard driver:

     KKDDMMAAPPDDIISSPP
          Map the display into user space.
     KKDDSSKKBBMMOODDEE
          Toggle the scan code xxllaattee.
     KKDDMMEEMMDDIISSPP
          Dump a byte of virtual or physical memory.
     KKDDGGKKBBSSTTAATTEE
          Get the keyboard's shift state.

     KKIIOOCCIINNFFOO
          Determine workstation of the virtual terminal.
     KKIIOOCCSSOOUUNNDD
          Start sound generation.
     KKDDGGEETTLLEEDD
          Get the state of the keyboard's LEDs.
     KKDDSSEETTLLEEDD
          Set the state of the LEDs.

     The  following four  console iiooccttll() 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 SSIIGGSSEEGGVV 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 iinnbb(), oouuttbb(), etc., which are present in the kernel-support
     library /eettcc/ccoonnff/lliibb/kk338866.a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:

     KKDDEENNAABBIIOO
          Allow  the  user   process  permission  to  perform  input/output
          operations to all available I/O addresses.  The third argument to
          iiooccttll() is ignored.
     KKDDDDIISSAABBIIOO
          Prohibit user  processes from performing  input/output operations
          to all available I/O addresses.  The third argument to iiooccttll() 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 KKDDEENNAABBIIOO or KKDDAADDDDIIOO calls.

     KKDDAADDDDIIOO
          Allow user-level I/O to a port.  The third argument to iiooccttll() is
          an  uunnssiiggnneedd sshhoorrtt  that gives  the single  address value  of the
          port.

     KKDDDDEELLIIOO
          Disallow user-level I/O to a port.  The third argument to iiooccttll()
          is an  uunnssiiggnneedd sshhoorrtt 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 KKDDAADDDDIIOO calls.

     ssyyss/hhddiiooccttll.hh
          This header file is used with IDX hard-disk drives:

          HHDDGGEETTAA         Get drive attributes
          HHDDSSEETTAA         Set drive attributes.

     ssyyss/llppiiooccttll.hh
          This header file works with the line printer (parallel) device:

          LLPPRRAAWW          Set raw mode.  The port does not interpret special
                         characters.
          LLPPPPLLEENN         Set  page  length (non-raw).   The  default is  66
                         lines.
          LLPPLLLLEENN         Set  line length  (non-raw).  The  default  is 132
                         characters.

     ssyyss/ttaappee.hh
          Header file for interfacing with magnetic-tape devices:

          TT_EERRAASSEE        Erase tape.
          TT_LLOOAADD         Load.  Not used.
          TT_RRDDSSTTAATT       Read status.
          TT_RRSSTT          Reset.
          TT_RREETTEENNSSIIOONN    Retension tape.
          TT_RRWWDD          Rewind tape.
          TT_SSBBBB          Space  block  backward  --  move backward  by  _a_r_g
                         blocks.  Not used.
          TT_SSBBFF          Space Block Forward -- move forward by _a_r_g blocks.
                         Not used.
          TT_SSBBRREECC        Not used.
          TT_SSFFBB          Space Filemark  Backward -- move  backwards by _a_r_g
                         files.
          TT_SSFFFF          Space  Filemark  Forward --  move  forward by  _a_r_g
                         files.
          TT_SSFFRREECC        Not used.
          TT_TTIINNIITT        Not used.
          TT_UUNNLLOOAADD       Unload.  Not used.
          TT_WWRRFFIILLEEMM      Write file marks.  Not used.

     ssyyss/nnuullll.hh
          Commands for /ddeevv/nnuullll:

          NNLLIIDDLLEE         Read  the system's  idle time.   _a_r_g points  to an
                         array  of  two  lloonnggs.  The  first  lloonngg  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 iiooccttll(), see the Lexicon entry
                         for iiddllee.

     ssyyss/ssddiiooccttll.hh
          Commands used with SCSI  devices: The last command is a temporary
          addition for the hhaaii driver:

          SSCCSSII_HHAA_CCMMDD
          SSCCSSII_CCMMDD
          SSCCSSII_CCMMDD_IINN
          SSCCSSII_CCMMDD_OOUUTT
          SSDDGGTTIINNQQ        Get inquiry information.

     ssggttttyy.hh
          These  commands are  used with  the  ssggttttyy method  of controlling
          terminal  devices.  They  are documented  in  more detail  in the
          Lexicon entry for ssggttttyy:

          TTIIOOCCHHPPCCLL       Hang up on last close.
          TTIIOOCCGGEETTPP       Get modes (old ggttttyy).
          TTIIOOCCSSEETTPP       Set modes (old ssttttyy).
          TTIIOOCCSSEETTNN       Set modes without delay or flush.
          TTIIOOCCEEXXCCLL       Set exclusive use.
          TTIIOOCCNNXXCCLL       Set non-exclusive use.
          TTIIOOCCFFLLUUSSHH      Flush I/O queues.
          TTIIOOCCSSEETTCC       Set characters.
          TTIIOOCCGGEETTCC       Get characters.

     ssttrrooppttss.hh
          STREAMS commands:

          II_NNRREEAADD        Get message length, count.
          II_PPUUSSHH         Push named module.
          II_PPOOPP          Pop topmost module.
          II_LLOOOOKK         Get name of the topmost module.
          II_FFLLUUSSHH        Flush read/write side.
          II_SSRRDDOOPPTT       Set stream head read mode.
          II_GGRRDDOOPPTT       Get stream head read mode.
          II_SSTTRR          Send iiooccttll() message downstream.
          II_SSEETTSSIIGG       Register for signal SSIIGGPPOOLLLL.
          II_GGEETTSSIIGG       Return registered event mask.
          II_FFIINNDD         Locate named module on stream.
          II_LLIINNKK         Link two streams.
          II_UUNNLLIINNKK       Unlink two streams.
          II_RREECCVVFFDD       Receive file descriptor from pipe.
          II_PPEEEEKK         Examine stream head data.
          II_SSEENNDDFFDD       Send file descriptor to pipe.

          The following commands are not covered by iBCS2:

          II_SSWWRROOPPTT       Set stream write mode.
          II_GGWWRROOPPTT       Get stream write mode.
          II_LLIISSTT         Get name of all modules/drivers.
          II_PPLLIINNKK        Create persistent link.
          II_PPUUNNLLIINNKK      Undo persistent link.
          II_FFLLUUSSHHBBAANNDD    Flush priority band.
          II_CCKKBBAANNDD       Check for existence of priority band.
          II_GGEETTBBAANNDD      Get band of first message.
          II_AATTMMAARRKK       Check whether current message is marked.
          II_SSEETTCCLLTTIIMMEE    Set drain timeout for stream.
          II_GGEETTCCLLTTIIMMEE    Get the current close timeout.
          II_CCAANNPPUUTT       Check if band is writeable.

     tteerrmmiioo.hh
          The  following  commands  are  used  with  the tteerrmmiioo  method  of
          controlling a  terminal.  They are  documented in more  detail in
          the Lexicon entry for tteerrmmiioo:

          TTCCGGEETTAA         Get terminal parameters.
          TTCCSSEETTAA         Set terminal parameters.
          TTCCSSEETTAAWW        Wait for drain, set parameters.
          TTCCSSEETTAAFF        Wait for drain, flush input, set parms.
          TTCCSSBBRRKK         Send 0.25-second break.

          The following commands also take arguments when called iiooccttll():

          TTCCXXOONNCC         Start/stop control:  An argument of  zero suspends
                         output;  an  argument  of one  restarts  suspended
                         output.

          TTCCFFLLSSHH         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.

_E_x_a_m_p_l_e
The following program, by Udo Munk, demonstrates how to use iiooccttll() 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);
        }
    }
}

_S_e_e _A_l_s_o
ddeevviiccee  ddrriivveerrss, eexxeecc,  ggeettttyy, hheeaaddeerr ffiilleess,  lliibbcc, ooppeenn(),  rreeaadd(), ssggttttyy,
ssttttyy, tteerrmmiioo

_N_o_t_e_s
The type  of the  _a_r_g to iiooccttll()  is declared as  cchhaarr * mainly  to improve
portability.  In  most cases,  the actual  argument type will  be something
like  ssttrruucctt ssggttttyybb  *, depending  on the device  and command.   The actual
argument should be cast to type cchhaarr * to ensure cross-machine portability.

Under  COHERENT 286,  the main  header file for  iiooccttll() is  <ssggttttyy.hh> This
header file is also included with COHERENT 386 for compatibility with older
applications.
