1 /* for sound we use MIDAS, which takes over the PIT and we can't use it
2 * therefore only compile this file for NO_SOUND builds.
27 #define PIT_TIMER_INTR 8
28 #define DOS_TIMER_INTR 0x1c
30 /* macro to divide and round to the nearest integer */
31 #define DIV_ROUND(a, b) \
32 ((a) / (b) + ((a) % (b)) / ((b) / 2))
34 static void set_timer_reload(int reload_val);
35 static void cleanup(void);
38 #define INTERRUPT __interrupt __far
40 static void INTERRUPT dos_timer_intr();
42 static void (INTERRUPT *prev_timer_intr)();
48 static _go32_dpmi_seginfo intr, prev_intr;
51 static void INTERRUPT timer_irq();
53 static volatile unsigned long ticks;
54 static unsigned long tick_interval, ticks_per_dos_intr;
57 void init_timer(int res_hz)
62 int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
63 set_timer_reload(reload_val);
65 tick_interval = DIV_ROUND(1000, res_hz);
66 ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
68 inum = PIT_TIMER_INTR;
70 prev_timer_intr = _dos_getvect(inum);
71 _dos_setvect(inum, timer_irq);
74 _go32_dpmi_get_protected_mode_interrupt_vector(inum, &prev_intr);
75 intr.pm_offset = (intptr_t)timer_irq;
76 intr.pm_selector = _go32_my_cs();
77 _go32_dpmi_allocate_iret_wrapper(&intr);
78 _go32_dpmi_set_protected_mode_interrupt_vector(inum, &intr);
83 inum = DOS_TIMER_INTR;
85 prev_timer_intr = _dos_getvect(inum);
86 _dos_setvect(inum, dos_timer_intr);
97 static void cleanup(void)
100 return; /* init hasn't ran, there's nothing to cleanup */
104 if(inum == PIT_TIMER_INTR) {
105 /* restore the original timer frequency */
106 set_timer_reload(65535);
109 /* restore the original interrupt handler */
111 _dos_setvect(inum, prev_timer_intr);
114 _go32_dpmi_set_protected_mode_interrupt_vector(inum, &prev_intr);
115 _go32_dpmi_free_iret_wrapper(&intr);
121 void reset_timer(void)
126 unsigned long get_msec(void)
128 return ticks * tick_interval;
131 void sleep_msec(unsigned long msec)
133 unsigned long wakeup_time = ticks + msec / tick_interval;
134 while(ticks < wakeup_time) {
141 static void set_timer_reload(int reload_val)
143 outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
144 outp(PORT_DATA0, reload_val & 0xff);
145 outp(PORT_DATA0, (reload_val >> 8) & 0xff);
149 static void INTERRUPT dos_timer_intr()
152 _chain_intr(prev_timer_intr); /* DOES NOT RETURN */
156 /* first PIC command port */
157 #define PIC1_CMD 0x20
158 /* end of interrupt control word */
159 #define OCW2_EOI (1 << 5)
161 static void INTERRUPT timer_irq()
163 static unsigned long dos_ticks;
168 if(++dos_ticks >= ticks_per_dos_intr) {
169 /* I suppose the dos irq handler does the EOI so I shouldn't
170 * do it if I am to call the previous function
173 _chain_intr(prev_timer_intr); /* XXX DOES NOT RETURN */
174 return; /* just for clarity */
178 /* send EOI to the PIC */
179 outp(PIC1_CMD, OCW2_EOI);
182 #endif /* NO_SOUND */