nuclear@33: #include nuclear@37: #include nuclear@33: #include "intr.h" nuclear@33: #include "asmops.h" nuclear@34: #include "timer.h" nuclear@33: #include "config.h" nuclear@33: nuclear@33: /* frequency of the oscillator driving the 8254 timer */ nuclear@33: #define OSC_FREQ_HZ 1193182 nuclear@33: nuclear@33: /* macro to divide and round to the nearest integer */ nuclear@33: #define DIV_ROUND(a, b) ((a) / (b) + ((a) % (b)) / ((b) / 2)) nuclear@33: nuclear@33: /* I/O ports connected to the 8254 */ nuclear@33: #define PORT_DATA0 0x40 nuclear@33: #define PORT_DATA1 0x41 nuclear@33: #define PORT_DATA2 0x42 nuclear@33: #define PORT_CMD 0x43 nuclear@33: nuclear@33: /* command bits */ nuclear@33: #define CMD_CHAN0 0 nuclear@33: #define CMD_CHAN1 (1 << 6) nuclear@33: #define CMD_CHAN2 (2 << 6) nuclear@33: #define CMD_RDBACK (3 << 6) nuclear@33: nuclear@33: #define CMD_LATCH 0 nuclear@33: #define CMD_ACCESS_LOW (1 << 4) nuclear@33: #define CMD_ACCESS_HIGH (2 << 4) nuclear@33: #define CMD_ACCESS_BOTH (3 << 4) nuclear@33: nuclear@33: #define CMD_OP_INT_TERM 0 nuclear@33: #define CMD_OP_ONESHOT (1 << 1) nuclear@33: #define CMD_OP_RATE (2 << 1) nuclear@33: #define CMD_OP_SQWAVE (3 << 1) nuclear@33: #define CMD_OP_SOFT_STROBE (4 << 1) nuclear@33: #define CMD_OP_HW_STROBE (5 << 1) nuclear@33: nuclear@33: #define CMD_MODE_BIN 0 nuclear@33: #define CMD_MODE_BCD 1 nuclear@33: nuclear@33: nuclear@33: static void intr_handler(); nuclear@33: nuclear@33: nuclear@33: void init_timer(void) nuclear@33: { nuclear@34: /* calculate the reload count: round(osc / freq) */ nuclear@34: int reload_count = DIV_ROUND(OSC_FREQ_HZ, TICK_FREQ_HZ); nuclear@33: nuclear@33: /* set the mode to square wave for channel 0, both low nuclear@34: * and high reload count bytes will follow... nuclear@33: */ nuclear@33: outb(CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE, PORT_CMD); nuclear@33: nuclear@34: /* write the low and high bytes of the reload count to the nuclear@33: * port for channel 0 nuclear@33: */ nuclear@34: outb(reload_count & 0xff, PORT_DATA0); nuclear@34: outb((reload_count >> 8) & 0xff, PORT_DATA0); nuclear@33: nuclear@33: /* set the timer interrupt handler */ nuclear@35: interrupt(IRQ_TO_INTR(0), intr_handler); nuclear@33: } nuclear@33: nuclear@33: /* This will be called by the interrupt dispatcher approximately nuclear@33: * every 1/250th of a second, so it must be extremely fast. nuclear@33: * For now, just increasing a tick counter will suffice. nuclear@33: */ nuclear@33: static void intr_handler() nuclear@33: { nuclear@33: nticks++; nuclear@33: }