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 +}