/* pit.c 
 * Version 0.0
 *
 * Driver for the 8253 or 8254 programmable interval timer chip, attached to
 * the ISA bus or to the parallel port.
 *
 * This code's under the GNU General Public License.
 *
 * Written by Andy Goth <unununium@openverse.com>, 2003.
 *
 * Assignment for CSE 3442-001 lab 5.
 * Dr. Roger Walker, University of Texas at Arlington */

#include <linux/ioctl.h>

#ifdef _IO

/* Linux 2.4 and up has nifty macros to pick ioctl numbers.  Let's use 'em. */

#define  _PIT_IO(i)    _IO ('u', 0x20 + (i)   )
#define _PIT_IOR(i, t) _IOR('u', 0x20 + (i), t)
#define _PIT_IOW(i, t) _IOW('u', 0x20 + (i), t)

#else

/* Linux 2.2 and before doesn't have this magic, so I emulate it using the old
 * method of picking random numbers to identify my ioctls. */

#define  _PIT_IO(i, t) (0x3456 + 0 + (i) * 3)
#define _PIT_IOR(i, t) (0x3456 + 1 + (i) * 3)
#define _PIT_IOW(i, t) (0x3456 + 2 + (i) * 3)

#endif

/* PIT_IGNORE_TICKS:       Ignore all future timer tick interrupts.
 * PIT_ENABLE_TICKS:       Start/resume counting timer tick interrupts.
 *
 * Enabling and disabling tick counting will not restart the 8253 timer--- it
 * will continue to produce ticks at its previous rate and phase.
 *
 * These ioctls do not clear the tick counter: to do that, read from the device
 * file.  They also do not reset the counter; instead use PIT_RESET_TIME or
 * PIT_SET_DIVISOR.
 *
 * Upon device open, ticks are ignored. */

#define PIT_IGNORE_TICKS    _PIT_IO(0)
#define PIT_ENABLE_TICKS    _PIT_IO(1)

/* PIT_RESET_TIME:         The timer's internal counter is reset.
 *
 * This ioctl is a sort of restart button, setting the "zero" mark against
 * which all future timer ticks are relative.
 *
 * PIT_RESET_TIME is implemented by (re)writing the current divisor to the
 * counter.
 *
 * This ioctl does not reset the tick counter.  Again, this is performed by
 * reading from the device file. */

#define PIT_RESET_TIME      _PIT_IO(2)

/* Reads or sets the timer divisor.
 *
 * PIT_READ_DIVISOR:       The currently-set divisor values are returned.
 * PIT_SET_DIVISOR:        New divisor values are loaded into the 8253.
 *
 * The output frequency of the 8253 is equal to its input frequency divided by
 * the product of these factors.  Each of the 8253's clock elements is capable
 * of dividing by a value from 1 through 65536.  By chaining elements together,
 * the 8253 is able to divide by up to 281,474,976,710,656 (2 ** 48).
 *
 * Use struct pit_divisor to specify the three divisor values.  0 in any field
 * indicates a divisor of 65536.
 *
 * I'd rather use a long long, but at least with current versions of gcc, long
 * long and kernel code don't mix.  This gives more direct control anyhow.
 *
 * The default divisor is unspecified.  Therefore, PIT_SET_DIVISOR must be used
 * after opening /dev/pit.
 *
 * PIT_SET_DIVISOR implies PIT_RESET_TIME. */

typedef struct pit_divisor {
    unsigned short clk0, clk1, clk2;
} pit_divisor_t;

#define PIT_READ_DIVISOR    _PIT_IOR(3, pit_divisor_t)
#define PIT_SET_DIVISOR     _PIT_IOW(4, pit_divisor_t)

/* vim: set ts=4 sts=4 sw=4 tw=80 et: */
/* EOF */

