kern

diff src/timer.c @ 33:373a9f50b4e6

8254 timer code
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 08 Jun 2011 03:02:42 +0300
parents
children 17433fcaa563
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/timer.c	Wed Jun 08 03:02:42 2011 +0300
     1.3 @@ -0,0 +1,78 @@
     1.4 +#include <stdio.h>
     1.5 +#include "intr.h"
     1.6 +#include "asmops.h"
     1.7 +#include "config.h"
     1.8 +
     1.9 +/* frequency of the oscillator driving the 8254 timer */
    1.10 +#define OSC_FREQ_HZ		1193182
    1.11 +
    1.12 +/* macro to divide and round to the nearest integer */
    1.13 +#define DIV_ROUND(a, b) ((a) / (b) + ((a) % (b)) / ((b) / 2))
    1.14 +
    1.15 +/* I/O ports connected to the 8254 */
    1.16 +#define PORT_DATA0	0x40
    1.17 +#define PORT_DATA1	0x41
    1.18 +#define PORT_DATA2	0x42
    1.19 +#define PORT_CMD	0x43
    1.20 +
    1.21 +/* command bits */
    1.22 +#define CMD_CHAN0			0
    1.23 +#define CMD_CHAN1			(1 << 6)
    1.24 +#define CMD_CHAN2			(2 << 6)
    1.25 +#define CMD_RDBACK			(3 << 6)
    1.26 +
    1.27 +#define CMD_LATCH			0
    1.28 +#define CMD_ACCESS_LOW		(1 << 4)
    1.29 +#define CMD_ACCESS_HIGH		(2 << 4)
    1.30 +#define CMD_ACCESS_BOTH		(3 << 4)
    1.31 +
    1.32 +#define CMD_OP_INT_TERM		0
    1.33 +#define CMD_OP_ONESHOT		(1 << 1)
    1.34 +#define CMD_OP_RATE			(2 << 1)
    1.35 +#define CMD_OP_SQWAVE		(3 << 1)
    1.36 +#define CMD_OP_SOFT_STROBE	(4 << 1)
    1.37 +#define CMD_OP_HW_STROBE	(5 << 1)
    1.38 +
    1.39 +#define CMD_MODE_BIN		0
    1.40 +#define CMD_MODE_BCD		1
    1.41 +
    1.42 +
    1.43 +static void intr_handler();
    1.44 +
    1.45 +static unsigned long nticks;
    1.46 +
    1.47 +
    1.48 +void init_timer(void)
    1.49 +{
    1.50 +	/* calculate the reset count: round(osc / freq) */
    1.51 +	int reset_count = DIV_ROUND(OSC_FREQ_HZ, TICK_FREQ_HZ);
    1.52 +
    1.53 +	/* set the mode to square wave for channel 0, both low
    1.54 +	 * and high reset count bytes will follow...
    1.55 +	 */
    1.56 +	outb(CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE, PORT_CMD);
    1.57 +
    1.58 +	/* write the low and high bytes of the reset count to the
    1.59 +	 * port for channel 0
    1.60 +	 */
    1.61 +	outb(reset_count & 0xff, PORT_DATA0);
    1.62 +	outb((reset_count >> 8) & 0xff, PORT_DATA0);
    1.63 +
    1.64 +	nticks = 0;
    1.65 +
    1.66 +	/* set the timer interrupt handler */
    1.67 +	interrupt(32, intr_handler);
    1.68 +}
    1.69 +
    1.70 +/* This will be called by the interrupt dispatcher approximately
    1.71 + * every 1/250th of a second, so it must be extremely fast.
    1.72 + * For now, just increasing a tick counter will suffice.
    1.73 + */
    1.74 +static void intr_handler()
    1.75 +{
    1.76 +	nticks++;
    1.77 +
    1.78 +	if(nticks % TICK_FREQ_HZ == 0) {
    1.79 +		printf("%lu sec\n", nticks / TICK_FREQ_HZ);
    1.80 +	}
    1.81 +}