kern

view 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 source
1 #include <stdio.h>
2 #include "intr.h"
3 #include "asmops.h"
4 #include "config.h"
6 /* frequency of the oscillator driving the 8254 timer */
7 #define OSC_FREQ_HZ 1193182
9 /* macro to divide and round to the nearest integer */
10 #define DIV_ROUND(a, b) ((a) / (b) + ((a) % (b)) / ((b) / 2))
12 /* I/O ports connected to the 8254 */
13 #define PORT_DATA0 0x40
14 #define PORT_DATA1 0x41
15 #define PORT_DATA2 0x42
16 #define PORT_CMD 0x43
18 /* command bits */
19 #define CMD_CHAN0 0
20 #define CMD_CHAN1 (1 << 6)
21 #define CMD_CHAN2 (2 << 6)
22 #define CMD_RDBACK (3 << 6)
24 #define CMD_LATCH 0
25 #define CMD_ACCESS_LOW (1 << 4)
26 #define CMD_ACCESS_HIGH (2 << 4)
27 #define CMD_ACCESS_BOTH (3 << 4)
29 #define CMD_OP_INT_TERM 0
30 #define CMD_OP_ONESHOT (1 << 1)
31 #define CMD_OP_RATE (2 << 1)
32 #define CMD_OP_SQWAVE (3 << 1)
33 #define CMD_OP_SOFT_STROBE (4 << 1)
34 #define CMD_OP_HW_STROBE (5 << 1)
36 #define CMD_MODE_BIN 0
37 #define CMD_MODE_BCD 1
40 static void intr_handler();
42 static unsigned long nticks;
45 void init_timer(void)
46 {
47 /* calculate the reset count: round(osc / freq) */
48 int reset_count = DIV_ROUND(OSC_FREQ_HZ, TICK_FREQ_HZ);
50 /* set the mode to square wave for channel 0, both low
51 * and high reset count bytes will follow...
52 */
53 outb(CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE, PORT_CMD);
55 /* write the low and high bytes of the reset count to the
56 * port for channel 0
57 */
58 outb(reset_count & 0xff, PORT_DATA0);
59 outb((reset_count >> 8) & 0xff, PORT_DATA0);
61 nticks = 0;
63 /* set the timer interrupt handler */
64 interrupt(32, intr_handler);
65 }
67 /* This will be called by the interrupt dispatcher approximately
68 * every 1/250th of a second, so it must be extremely fast.
69 * For now, just increasing a tick counter will suffice.
70 */
71 static void intr_handler()
72 {
73 nticks++;
75 if(nticks % TICK_FREQ_HZ == 0) {
76 printf("%lu sec\n", nticks / TICK_FREQ_HZ);
77 }
78 }