kern

view src/timer.c @ 80:4db99a52863e

fixed the "endianess" of the text messages in the ATA identify info block. this is the first time I've seen wrong byteorder in ascii text, the ATA committee should be commended.
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 06 Dec 2011 13:35:39 +0200
parents f44bec97a0ec
children
line source
1 #include <stdio.h>
2 #include <time.h>
3 #include "intr.h"
4 #include "asmops.h"
5 #include "timer.h"
6 #include "proc.h"
7 #include "sched.h"
8 #include "config.h"
10 /* frequency of the oscillator driving the 8254 timer */
11 #define OSC_FREQ_HZ 1193182
13 /* macro to divide and round to the nearest integer */
14 #define DIV_ROUND(a, b) ((a) / (b) + ((a) % (b)) / ((b) / 2))
16 /* I/O ports connected to the 8254 */
17 #define PORT_DATA0 0x40
18 #define PORT_DATA1 0x41
19 #define PORT_DATA2 0x42
20 #define PORT_CMD 0x43
22 /* command bits */
23 #define CMD_CHAN0 0
24 #define CMD_CHAN1 (1 << 6)
25 #define CMD_CHAN2 (2 << 6)
26 #define CMD_RDBACK (3 << 6)
28 #define CMD_LATCH 0
29 #define CMD_ACCESS_LOW (1 << 4)
30 #define CMD_ACCESS_HIGH (2 << 4)
31 #define CMD_ACCESS_BOTH (3 << 4)
33 #define CMD_OP_INT_TERM 0
34 #define CMD_OP_ONESHOT (1 << 1)
35 #define CMD_OP_RATE (2 << 1)
36 #define CMD_OP_SQWAVE (3 << 1)
37 #define CMD_OP_SOFT_STROBE (4 << 1)
38 #define CMD_OP_HW_STROBE (5 << 1)
40 #define CMD_MODE_BIN 0
41 #define CMD_MODE_BCD 1
44 #define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000)
46 struct timer_event {
47 int dt; /* remaining ticks delta from the previous event */
48 struct timer_event *next;
49 };
52 static void timer_handler();
55 static struct timer_event *evlist;
58 void init_timer(void)
59 {
60 /* calculate the reload count: round(osc / freq) */
61 int reload_count = DIV_ROUND(OSC_FREQ_HZ, TICK_FREQ_HZ);
63 /* set the mode to square wave for channel 0, both low
64 * and high reload count bytes will follow...
65 */
66 outb(CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE, PORT_CMD);
68 /* write the low and high bytes of the reload count to the
69 * port for channel 0
70 */
71 outb(reload_count & 0xff, PORT_DATA0);
72 outb((reload_count >> 8) & 0xff, PORT_DATA0);
74 /* set the timer interrupt handler */
75 interrupt(IRQ_TO_INTR(0), timer_handler);
76 }
78 int sys_sleep(int sec)
79 {
80 printf("process %d will sleep for %d seconds\n", get_current_pid(), sec);
81 sleep(sec * 1000); /* timer.c */
83 /* TODO if interrupted, return the remaining seconds */
84 return 0;
85 }
87 void sleep(unsigned long msec)
88 {
89 int ticks, tsum, istate;
90 struct timer_event *ev, *node;
92 if((ticks = MSEC_TO_TICKS(msec)) <= 0) {
93 return;
94 }
96 if(!(ev = malloc(sizeof *ev))) {
97 printf("sleep: failed to allocate timer_event structure\n");
98 return;
99 }
101 istate = get_intr_state();
102 disable_intr();
104 /* insert at the beginning */
105 if(!evlist || ticks <= evlist->dt) {
106 ev->next = evlist;
107 evlist = ev;
109 ev->dt = ticks;
110 if(ev->next) {
111 ev->next->dt -= ticks;
112 }
113 } else {
115 tsum = evlist->dt;
116 node = evlist;
118 while(node->next && ticks > tsum + node->next->dt) {
119 tsum += node->next->dt;
120 node = node->next;
121 }
123 ev->next = node->next;
124 node->next = ev;
126 /* fix the relative times */
127 ev->dt = ticks - tsum;
128 if(ev->next) {
129 ev->next->dt -= ev->dt;
130 }
131 }
133 set_intr_state(istate);
135 /* wait on the address of this timer event */
136 wait(ev);
137 }
139 /* This will be called by the interrupt dispatcher approximately
140 * every 1/250th of a second, so it must be extremely fast.
141 * For now, just increasing a tick counter will suffice.
142 */
143 static void timer_handler(int inum)
144 {
145 int istate;
146 struct process *p;
148 nticks++;
150 /*printf("TICKS: %d\n", nticks);*/
152 istate = get_intr_state();
153 disable_intr();
155 /* find out if there are any timers that have to go off */
156 if(evlist) {
157 evlist->dt--;
159 while(evlist && evlist->dt <= 0) {
160 struct timer_event *ev = evlist;
161 evlist = evlist->next;
163 printf("timer going off!!!\n");
164 /* wake up all processes waiting on this address */
165 wakeup(ev);
166 free(ev);
167 }
168 }
170 /* decrement the process' ticks_left and call the scheduler to decide if
171 * it's time to switch processes
172 */
173 if((p = get_current_proc())) {
174 p->ticks_left--;
175 }
176 schedule();
178 set_intr_state(istate);
179 }