removed clang-format and clang_complete files from the repo
[dosdemo] / src / dos / timer.c
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.
3  */
4 #ifdef NO_SOUND
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <assert.h>
9 #include <conio.h>
10 #include <dos.h>
11
12 #ifdef __WATCOMC__
13 #include <i86.h>
14 #endif
15
16 #ifdef __DJGPP__
17 #include <dpmi.h>
18 #include <go32.h>
19 #include <pc.h>
20 #endif
21
22 #include "pit8254.h"
23 #include "inttypes.h"
24 #include "util.h"
25 #include "dosutil.h"
26
27 #define PIT_TIMER_INTR  8
28 #define DOS_TIMER_INTR  0x1c
29
30 /* macro to divide and round to the nearest integer */
31 #define DIV_ROUND(a, b) \
32         ((a) / (b) + ((a) % (b)) / ((b) / 2))
33
34 static void set_timer_reload(int reload_val);
35 static void cleanup(void);
36
37 #ifdef __WATCOMC__
38 #define INTERRUPT       __interrupt __far
39
40 static void INTERRUPT dos_timer_intr();
41
42 static void (INTERRUPT *prev_timer_intr)();
43 #endif
44
45 #ifdef __DJGPP__
46 #define INTERRUPT
47
48 static _go32_dpmi_seginfo intr, prev_intr;
49 #endif
50
51 static void INTERRUPT timer_irq();
52
53 static volatile unsigned long ticks;
54 static unsigned long tick_interval, ticks_per_dos_intr;
55 static int inum;
56
57 void init_timer(int res_hz)
58 {
59         _disable();
60
61         if(res_hz > 0) {
62                 int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
63                 set_timer_reload(reload_val);
64
65                 tick_interval = DIV_ROUND(1000, res_hz);
66                 ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
67
68                 inum = PIT_TIMER_INTR;
69 #ifdef __WATCOMC__
70                 prev_timer_intr = _dos_getvect(inum);
71                 _dos_setvect(inum, timer_irq);
72 #endif
73 #ifdef __DJGPP__
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);
79 #endif
80         } else {
81                 tick_interval = 55;
82
83                 inum = DOS_TIMER_INTR;
84 #ifdef __WATCOMC__
85                 prev_timer_intr = _dos_getvect(inum);
86                 _dos_setvect(inum, dos_timer_intr);
87 #endif
88 #ifdef __DJGPP__
89                 assert(0);
90 #endif
91         }
92         _enable();
93
94         atexit(cleanup);
95 }
96
97 static void cleanup(void)
98 {
99         if(!inum) {
100                 return; /* init hasn't ran, there's nothing to cleanup */
101         }
102
103         _disable();
104         if(inum == PIT_TIMER_INTR) {
105                 /* restore the original timer frequency */
106                 set_timer_reload(65535);
107         }
108
109         /* restore the original interrupt handler */
110 #ifdef __WATCOMC__
111         _dos_setvect(inum, prev_timer_intr);
112 #endif
113 #ifdef __DJGPP__
114         _go32_dpmi_set_protected_mode_interrupt_vector(inum, &prev_intr);
115         _go32_dpmi_free_iret_wrapper(&intr);
116 #endif
117
118         _enable();
119 }
120
121 void reset_timer(void)
122 {
123         ticks = 0;
124 }
125
126 unsigned long get_msec(void)
127 {
128         return ticks * tick_interval;
129 }
130
131 void sleep_msec(unsigned long msec)
132 {
133         unsigned long wakeup_time = ticks + msec / tick_interval;
134         while(ticks < wakeup_time) {
135 #ifdef USE_HLT
136                 halt();
137 #endif
138         }
139 }
140
141 static void set_timer_reload(int reload_val)
142 {
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);
146 }
147
148 #ifdef __WATCOMC__
149 static void INTERRUPT dos_timer_intr()
150 {
151         ticks++;
152         _chain_intr(prev_timer_intr);   /* DOES NOT RETURN */
153 }
154 #endif
155
156 /* first PIC command port */
157 #define PIC1_CMD        0x20
158 /* end of interrupt control word */
159 #define OCW2_EOI        (1 << 5)
160
161 static void INTERRUPT timer_irq()
162 {
163         static unsigned long dos_ticks;
164
165         ticks++;
166
167 #ifdef __WATCOMC__
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
171                  */
172                 dos_ticks = 0;
173                 _chain_intr(prev_timer_intr);   /* XXX DOES NOT RETURN */
174                 return; /* just for clarity */
175         }
176 #endif
177
178         /* send EOI to the PIC */
179         outp(PIC1_CMD, OCW2_EOI);
180 }
181
182 #endif  /* NO_SOUND */