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.
26 #define PIT_TIMER_INTR 8
27 #define DOS_TIMER_INTR 0x1c
29 /* macro to divide and round to the nearest integer */
30 #define DIV_ROUND(a, b) \
31 ((a) / (b) + ((a) % (b)) / ((b) / 2))
33 static void set_timer_reload(int reload_val);
34 static void cleanup(void);
37 #define INTERRUPT __interrupt __far
39 static void INTERRUPT dos_timer_intr();
41 static void (INTERRUPT *prev_timer_intr)();
47 static _go32_dpmi_seginfo intr, prev_intr;
49 #define outp(p, v) outportb(p, v)
52 static void INTERRUPT timer_irq();
54 static volatile unsigned long ticks;
55 static unsigned long tick_interval, ticks_per_dos_intr;
58 void init_timer(int res_hz)
63 int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
64 set_timer_reload(reload_val);
66 tick_interval = DIV_ROUND(1000, res_hz);
67 ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
69 inum = PIT_TIMER_INTR;
71 prev_timer_intr = _dos_getvect(inum);
72 _dos_setvect(inum, timer_irq);
75 _go32_dpmi_get_protected_mode_interrupt_vector(inum, &prev_intr);
76 intr.pm_offset = (intptr_t)timer_irq;
77 intr.pm_selector = _go32_my_cs();
78 _go32_dpmi_allocate_iret_wrapper(&intr);
79 _go32_dpmi_set_protected_mode_interrupt_vector(inum, &intr);
84 inum = DOS_TIMER_INTR;
86 prev_timer_intr = _dos_getvect(inum);
87 _dos_setvect(inum, dos_timer_intr);
98 static void cleanup(void)
101 return; /* init hasn't ran, there's nothing to cleanup */
105 if(inum == PIT_TIMER_INTR) {
106 /* restore the original timer frequency */
107 set_timer_reload(65535);
110 /* restore the original interrupt handler */
112 _dos_setvect(inum, prev_timer_intr);
115 _go32_dpmi_set_protected_mode_interrupt_vector(inum, &prev_intr);
116 _go32_dpmi_free_iret_wrapper(&intr);
122 void reset_timer(void)
127 unsigned long get_msec(void)
129 return ticks * tick_interval;
132 void sleep_msec(unsigned long msec)
134 unsigned long wakeup_time = ticks + msec / tick_interval;
135 while(ticks < wakeup_time) {
142 static void set_timer_reload(int reload_val)
144 outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
145 outp(PORT_DATA0, reload_val & 0xff);
146 outp(PORT_DATA0, (reload_val >> 8) & 0xff);
150 static void INTERRUPT dos_timer_intr()
153 _chain_intr(prev_timer_intr); /* DOES NOT RETURN */
157 /* first PIC command port */
158 #define PIC1_CMD 0x20
159 /* end of interrupt control word */
160 #define OCW2_EOI (1 << 5)
162 static void INTERRUPT timer_irq()
164 static unsigned long dos_ticks;
169 if(++dos_ticks >= ticks_per_dos_intr) {
170 /* I suppose the dos irq handler does the EOI so I shouldn't
171 * do it if I am to call the previous function
174 _chain_intr(prev_timer_intr); /* XXX DOES NOT RETURN */
175 return; /* just for clarity */
179 /* send EOI to the PIC */
180 outp(PIC1_CMD, OCW2_EOI);
183 #endif /* NO_SOUND */