2 * PC/HW routine collection v1.5 for DOS/DJGPP
4 * Copyright (C) 2002 - Daniel Borca
5 * Email : dborca@yahoo.com
6 * Web : http://www.geocities.com/dborca
19 #define PIT_FREQ 0x1234DD
21 #define ADJUST(timer, basefreq) timer.counter = PIT_FREQ * timer.freq / SQR(basefreq)
23 #define unvolatile(__v, __t) __extension__ ({union { volatile __t __cp; __t __p; } __q; __q.__cp = __v; __q.__p;})
25 static int timer_installed
;
28 volatile unsigned int counter
, clock_ticks
, freq
;
33 static TIMER timer_main
, timer_func
[MAX_TIMERS
];
36 /* Desc: main timer callback
39 * Out : 0 to bypass BIOS, 1 to chain to BIOS
48 for (i
= 0; i
< MAX_TIMERS
; i
++) {
49 TIMER
*t
= &timer_func
[i
];
51 t
->clock_ticks
+= t
->counter
;
52 if (t
->clock_ticks
>= timer_main
.counter
) {
53 t
->clock_ticks
-= timer_main
.counter
;
54 t
->func(unvolatile(t
->parm
, void *));
59 timer_main
.clock_ticks
+= timer_main
.counter
;
60 if (timer_main
.clock_ticks
>= 0x10000) {
61 timer_main
.clock_ticks
-= 0x10000;
70 /* Desc: uninstall timer engine
78 pc_remove_timer (void)
80 if (timer_installed
) {
81 timer_installed
= FALSE
;
82 pc_clexit(pc_remove_timer
);
90 pc_remove_irq(TIMER_IRQ
);
95 /* Desc: remove timerfunc
100 * Note: tries to relax the main timer whenever possible
103 pc_remove_int (int fid
)
106 unsigned int freq
= 0;
108 /* are we installed? */
109 if (!timer_installed
) {
114 if ((fid
< 0) || (fid
>= MAX_TIMERS
) || (timer_func
[fid
].func
== NULL
)) {
117 timer_func
[fid
].func
= NULL
;
119 /* scan for maximum frequency */
120 for (i
= 0; i
< MAX_TIMERS
; i
++) {
121 TIMER
*t
= &timer_func
[i
];
123 if (freq
< t
->freq
) {
129 /* if there are no callbacks left, cleanup */
135 /* if we just lowered the maximum frequency, try to relax the timer engine */
136 if (freq
< timer_main
.freq
) {
137 unsigned int new_counter
= PIT_FREQ
/ freq
;
141 for (i
= 0; i
< MAX_TIMERS
; i
++) {
142 if (timer_func
[i
].func
) {
143 ADJUST(timer_func
[i
], freq
);
147 outportb(0x43, 0x34);
148 outportb(0x40, (unsigned char)new_counter
);
149 outportb(0x40, (unsigned char)(new_counter
>>8));
150 timer_main
.clock_ticks
= 0;
151 timer_main
.counter
= new_counter
;
152 timer_main
.freq
= freq
;
158 } ENDOFUNC(pc_remove_int
)
161 /* Desc: adjust timerfunc
163 * In : timerfunc id, new frequency (Hz)
166 * Note: might change the main timer frequency
169 pc_adjust_int (int fid
, unsigned int freq
)
173 /* are we installed? */
174 if (!timer_installed
) {
179 if ((fid
< 0) || (fid
>= MAX_TIMERS
) || (timer_func
[fid
].func
== NULL
)) {
182 timer_func
[fid
].freq
= freq
;
184 /* scan for maximum frequency */
186 for (i
= 0; i
< MAX_TIMERS
; i
++) {
187 TIMER
*t
= &timer_func
[i
];
189 if (freq
< t
->freq
) {
195 /* update main timer / sons to match highest frequency */
198 /* using '>' is correct still (and avoids updating
199 * the HW timer too often), but doesn't relax the timer!
201 if (freq
!= timer_main
.freq
) {
202 unsigned int new_counter
= PIT_FREQ
/ freq
;
204 for (i
= 0; i
< MAX_TIMERS
; i
++) {
205 if (timer_func
[i
].func
) {
206 ADJUST(timer_func
[i
], freq
);
210 outportb(0x43, 0x34);
211 outportb(0x40, (unsigned char)new_counter
);
212 outportb(0x40, (unsigned char)(new_counter
>>8));
213 timer_main
.clock_ticks
= 0;
214 timer_main
.counter
= new_counter
;
215 timer_main
.freq
= freq
;
217 ADJUST(timer_func
[fid
], timer_main
.freq
);
223 } ENDOFUNC(pc_adjust_int
)
226 /* Desc: install timer engine
229 * Out : 0 for success
231 * Note: initial frequency is 18.2 Hz
236 if (timer_installed
|| pc_install_irq(TIMER_IRQ
, timer
)) {
239 memset(timer_func
, 0, sizeof(timer_func
));
241 LOCKDATA(timer_func
);
242 LOCKDATA(timer_main
);
244 LOCKFUNC(pc_adjust_int
);
245 LOCKFUNC(pc_remove_int
);
247 timer_main
.counter
= 0x10000;
250 outportb(0x43, 0x34);
253 timer_main
.clock_ticks
= 0;
256 pc_atexit(pc_remove_timer
);
257 timer_installed
= TRUE
;
263 /* Desc: install timerfunc
265 * In : callback function, opaque pointer to be passed to callee, freq (Hz)
266 * Out : timerfunc id (0 .. MAX_TIMERS-1)
268 * Note: returns -1 if error
271 pc_install_int (PFUNC func
, void *parm
, unsigned int freq
)
276 /* ensure the timer engine is set up */
277 if (!timer_installed
) {
278 if (install_timer()) {
283 /* find an empty slot */
284 for (i
= 0; i
< MAX_TIMERS
; i
++) {
285 if (!timer_func
[i
].func
) {
301 /* update main timer / sons to match highest frequency */
302 if (freq
> timer_main
.freq
) {
303 unsigned int new_counter
= PIT_FREQ
/ freq
;
305 for (i
= 0; i
< MAX_TIMERS
; i
++) {
306 if (timer_func
[i
].func
) {
307 ADJUST(timer_func
[i
], freq
);
311 outportb(0x43, 0x34);
312 outportb(0x40, (unsigned char)new_counter
);
313 outportb(0x40, (unsigned char)(new_counter
>>8));
314 timer_main
.clock_ticks
= 0;
315 timer_main
.counter
= new_counter
;
316 timer_main
.freq
= freq
;
318 /* t == &timer_func[i] */
319 ADJUST(timer_func
[i
], timer_main
.freq
);