/* ----------------------------------------------------
 *  LISTING 6
 *
 *  Filename:           ctl.c
 *  Summary:            Test IOCTL program for tape
 *                      device driver
 *  Author:             T.W. Nelson
 *  Compile options:    
 *  Version:            1.00
 *  Date:               29-Sep-1991
 *  Notes:
 *
 * ------------------------------------------------- */

#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <dos.h>
#include <bios.h>
#include "tape.h"

#define IOCTL_OK    0x4000      //ioctl check bit
#define IM_A_DEVICE 0x0080      //device check bit
#define IO_BUF_SIZE sizeof(CMDARG)

union REGS regs;
struct SREGS sregs;
char Dname[] = "TAPEXXXX";
int ioHandle;
CMDARG ioArg;

char *Menu[] = {
    "",
    "Power ON .............0",
    "Power OFF ............1",
    "Insert Cassette ......2",
    "Eject Cassette .......3",
    "Record ...............4",
    "Play .................5",
    "Fast Forward .........6",
    "Rewind ...............7",
    "Check Status .........8",
    "Stop .................9",
    "Quit .................<Esc>",
    "",
    0
    };

extern int _doserrno;

int  _dos_dev_info( int handle,
                    size_t *info )
{
   /* Get information about specified handle assoc
    * with a file or device and return it in 'info'.
    * Returns 0 if successful, !0 if not.  Error code
    * contained in global '_doserrno'.
    */

    regs.x.ax = 0x4400;     //DOS IOCTL get device info
    regs.x.bx = handle;
    intdos( &regs, &regs );
    *info = regs.x.dx;      //assign device info word

    return regs.x.cflag;    //CY signals error
}

int _dos_ioctl_read( int handle,
                     void *iobuf,
                     size_t nbytes  )
{
   /* Read ioctl data from a character device driver
    * into 'iobuf'. Returns 0 if successful, !0 if not.
    * Error code contained in global '_doserrno'.  This
    * call ends up as the device driver's cmd code 3,
    * ioctl_read.
    */

    regs.x.ax = 0x4402;     //DOS read ioctl data
    regs.x.bx = handle;
    regs.x.cx = nbytes;
    sregs.ds = FP_SEG( iobuf );
    regs.x.dx = FP_OFF( iobuf );
    intdosx( &regs, &regs, &sregs );

    return regs.x.cflag;    //CY signals error
}

int _dos_ioctl_write( int handle,
                      void *iobuf,
                      size_t nbytes  )
{
   /* Write ioctl data to a character device driver
    * from 'iobuf'. Returns 0 if successful, !0 if not.
    * Error code contained in global '_doserrno'. This
    * call ends up as the device driver's cmd code 12,
    * ioctl_write.
    */

    regs.x.ax = 0x4403;     //DOS write ioctl data
    regs.x.bx = handle;
    regs.x.cx = nbytes;
    sregs.ds = FP_SEG( iobuf );
    regs.x.dx = FP_OFF( iobuf );
    intdosx( &regs, &regs, &sregs );

    return regs.x.cflag;    //CY signals error
}

void print_menu(void )
{
    char **p;

    for( p = Menu; *p; p++ )
        printf( "%s\n", *p );
}

main( int argc, char **argv )
{
    int cmd;
    size_t d_info;

    ioHandle = open( Dname, O_RDWR );

    if( ioHandle == -1 )  {
        printf( "Unable to open TAPE device\n" );
        return 1;
    }

    //Verify that TAPE is a device and that
    //it supports ioctl calls .....

    _dos_dev_info( ioHandle, &d_info );

    if( (d_info & IM_A_DEVICE) == 0 )  {
        printf("Sorry, '%s' is a file\n", Dname );
        return 1;
    }

    if( (d_info & IOCTL_OK) == 0 )  {
        printf("Sorry, TAPE doesn't support IOCTL\n");
        return 1;
    }

    //Initialize the device at 'boot-up' ....
    ioArg.c_state = OFF;
    ioArg.cmd = CMD_POWER_ON;
    _dos_ioctl_write( ioHandle, (void *) &ioArg,
                        IO_BUF_SIZE );

    //Execute user control loop .....
    while( 1 )  {
            print_menu();
            printf( "Enter selection: " );
            cmd = bioskey(0);
            cmd &= 0x00ff;     //zap scan code

            if( cmd == 27 )
                    break;

            printf( "%c\n\n", cmd );    //echo cmd
            ioArg.cmd = cmd - '0';      //to integer
            _dos_ioctl_read( ioHandle,
                        (void *) &ioArg,
                            IO_BUF_SIZE );
    }

    return 0;
}

/* ----- End of File ------------------------------- */
