/***********************************************************************
 *
 * poke.c
 * Tom Kelliher
 * Jan. 20, 2000
 *
 * Copyright (C) 2000 Thomas P. Kelliher, Goucher College
 *
 * Poke a byte value to the data register of a parallel port in Linux.
 * By default, the parallel port at 0x378 is used.  This program should
 * be used with ports in SPP (unidirectional) or PS/2 (bidirectional)
 * modes.  Results with ports in EPP or ECP modes are undefined.
 *
 * This program leaves the host with data line drivers enabled.
 *
 * WARNING: IT IS YOUR RESPONSIBILITY TO ENSURE THAT HOST DATA LINE
 * DRIVERS AND PERIPHERAL DATA LINE DRIVERS ARE NOT SIMULTANEOUSLY
 * ENABLED.  Ignoring this warning may result in damage to the host,
 * the peripheral, and your wallet.
 *
 * Compiling note: You must use gcc's "-O" switch.
 *
 * Running notes: 
 *    This program must run with root privileges.
 *    This program takes one argument: a value from 0 to 255.  It may
 *       be given in hex, octal, or decimal form.
 *
 ***********************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <asm/io.h>


/* base of the parallel port.  this is the location of the data */
/* register.                                                    */

#define BASE 0x378

/* offset of the control register */

#define CONTROL 2


/* function prototypes */

void error(char *s);


/***********************************************************************
 *
 * main()
 *
 ***********************************************************************/

int main(int argc, char *argv[])
{
   long value;               /* command line value */
   unsigned char control;    /* value of the control register */

   if (argc != 2)
      error("One argument expected\n");

   value = strtol(argv[1], (char **)NULL, 0);

   if (value > 255 || value < 0)
      error("Value will not fit in a byte\n");

   /* try to open the entire port space.  must be root for this to work */

   if (iopl(3))
      error("Could't get the port addresses\n");

   /* enable data register output by bringing bit 5 of control */
   /* register low                                             */

   control = inb(BASE + CONTROL);
   outb(control & ~0x20, BASE + CONTROL);

   /* write the value */

   outb((unsigned char) value, BASE);

   /* can we read it back? */

   if (inb(BASE) == (unsigned char) value)
      printf("Port 0x%x set to 0x%x\n", BASE, value);
   else
      error("Couldn't write port\n");

   return 0;
}


/***********************************************************************
 *
 * error()
 *
 * Print an error message and terminate with an error code of 1.
 *
 * The error message to print is passed in as s.
 *
 ***********************************************************************/

void error(char *s)
{
   printf("%s", s);
   exit(1);
}
