/*
- * PC/HW routine collection v1.3 for DOS/DJGPP
+ * PC/HW routine collection v1.4 for DOS/DJGPP
*
* Copyright (C) 2002 - Borca Daniel
* Email : dborca@yahoo.com
#include <pc.h>
+#include <string.h>
#include "pc_hw.h"
#define PIT_FREQ 0x1234DD
+#define ADJUST(timer, basefreq) timer.counter = PIT_FREQ * timer.freq / SQR(basefreq)
+
#define unvolatile(__v, __t) __extension__ ({union { volatile __t __cp; __t __p; } __q; __q.__cp = __v; __q.__p;})
static int timer_installed;
static TIMER timer_main, timer_func[MAX_TIMERS];
+
+
+/* Desc: main timer callback
+ *
+ * In : -
+ * Out : 0 to bypass BIOS, 1 to chain to BIOS
+ *
+ * Note: -
+ */
static int timer ()
{
int i;
- for (i=0;i<MAX_TIMERS;i++) {
+ for (i = 0; i < MAX_TIMERS; i++) {
TIMER *t = &timer_func[i];
if (t->func) {
t->clock_ticks += t->counter;
- if (t->clock_ticks>=timer_main.counter) {
+ if (t->clock_ticks >= timer_main.counter) {
t->clock_ticks -= timer_main.counter;
t->func(unvolatile(t->parm, void *));
}
}
timer_main.clock_ticks += timer_main.counter;
- if (timer_main.clock_ticks>=0x10000) {
+ if (timer_main.clock_ticks >= 0x10000) {
timer_main.clock_ticks -= 0x10000;
return 1;
} else {
}
} ENDOFUNC(timer)
+
+
+/* Desc: uninstall timer engine
+ *
+ * In : -
+ * Out : -
+ *
+ * Note: -
+ */
void pc_remove_timer (void)
{
if (timer_installed) {
}
}
+
+
+/* Desc: install timer engine
+ *
+ * In : -
+ * Out : 0 for success
+ *
+ * Note: initial frequency is 18.2 Hz
+ */
static int install_timer (void)
{
- if (timer_installed||pc_install_irq(TIMER_IRQ, timer)) {
+ if (timer_installed || pc_install_irq(TIMER_IRQ, timer)) {
return -1;
} else {
+ memset(timer_func, 0, sizeof(timer_func));
+
LOCKDATA(timer_func);
LOCKDATA(timer_main);
LOCKFUNC(timer);
}
}
-static TIMER *find_slot (PFUNC func)
+
+
+/* Desc: install timerfunc
+ *
+ * In : callback function, opaque pointer to be passed to callee, freq (Hz)
+ * Out : timerfunc id (0 .. MAX_TIMERS-1)
+ *
+ * Note: returns -1 if error
+ */
+int pc_install_int (PFUNC func, void *parm, unsigned int freq)
{
int i;
+ TIMER *t = NULL;
- for (i=0;i<MAX_TIMERS;i++) {
- if (timer_func[i].func==func) {
- return &timer_func[i];
- }
+ /* ensure the timer engine is set up */
+ if (!timer_installed) {
+ if (install_timer()) {
+ return -1;
+ }
}
- for (i=0;i<MAX_TIMERS;i++) {
+
+ /* find an empty slot */
+ for (i = 0; i < MAX_TIMERS; i++) {
if (!timer_func[i].func) {
- return &timer_func[i];
+ t = &timer_func[i];
+ break;
}
}
+ if (t == NULL) {
+ return -1;
+ }
+
+ DISABLE();
+
+ t->func = func;
+ t->parm = parm;
+ t->freq = freq;
+ t->clock_ticks = 0;
+
+ /* update main timer / sons to match highest frequency */
+ if (freq > timer_main.freq) {
+ unsigned int new_counter = PIT_FREQ / freq;
+
+ for (i = 0; i < MAX_TIMERS; i++) {
+ if (timer_func[i].func) {
+ ADJUST(timer_func[i], freq);
+ }
+ }
- return NULL;
+ outportb(0x43, 0x34);
+ outportb(0x40, (unsigned char)new_counter);
+ outportb(0x40, (unsigned char)(new_counter>>8));
+ timer_main.clock_ticks = 0;
+ timer_main.counter = new_counter;
+ timer_main.freq = freq;
+ } else {
+ /* t == &timer_func[i] */
+ ADJUST(timer_func[i], timer_main.freq);
+ }
+
+ ENABLE();
+
+ return t - timer_func;
}
-int pc_install_int (PFUNC func, void *parm, unsigned int freq)
+
+
+/* Desc: remove timerfunc
+ *
+ * In : timerfunc id
+ * Out : 0 if success
+ *
+ * Note: tries to relax the main timer whenever possible
+ */
+int pc_remove_int (int fid)
{
int i;
- TIMER *t;
+ unsigned int freq = 0;
+ /* are we installed? */
if (!timer_installed) {
- if (install_timer()) {
- return -1;
- }
+ return -1;
}
- if ((t=find_slot(func))!=NULL) {
+ /* sanity check */
+ if ((fid < 0) || (fid >= MAX_TIMERS) || (timer_func[fid].func == NULL)) {
+ return -1;
+ }
+ timer_func[fid].func = NULL;
+
+ /* scan for maximum frequency */
+ for (i = 0; i < MAX_TIMERS; i++) {
+ TIMER *t = &timer_func[i];
+ if (t->func) {
+ if (freq < t->freq) {
+ freq = t->freq;
+ }
+ }
+ }
+
+ /* if there are no callbacks left, cleanup */
+ if (!freq) {
+ pc_remove_timer();
+ return 0;
+ }
+
+ /* if we just lowered the maximum frequency, try to relax the timer engine */
+ if (freq < timer_main.freq) {
unsigned int new_counter = PIT_FREQ / freq;
DISABLE();
- t->func = func;
- t->parm = parm;
- t->freq = freq;
- t->clock_ticks = 0;
-
- if (new_counter < timer_main.counter) {
- for (i=0;i<MAX_TIMERS;i++) {
- if (timer_func[i].func) {
- timer_func[i].counter = new_counter * timer_func[i].freq / freq;
- }
- }
- outportb(0x43, 0x34);
- outportb(0x40, (unsigned char)new_counter);
- outportb(0x40, (unsigned char)(new_counter>>8));
- timer_main.clock_ticks = 0;
- timer_main.counter = new_counter;
- timer_main.freq = freq;
- } else {
- t->counter = PIT_FREQ * freq / (timer_main.freq * timer_main.freq);
+ for (i = 0; i < MAX_TIMERS; i++) {
+ if (timer_func[i].func) {
+ ADJUST(timer_func[i], freq);
+ }
}
- ENABLE();
+ outportb(0x43, 0x34);
+ outportb(0x40, (unsigned char)new_counter);
+ outportb(0x40, (unsigned char)(new_counter>>8));
+ timer_main.clock_ticks = 0;
+ timer_main.counter = new_counter;
+ timer_main.freq = freq;
- return 0;
+ ENABLE();
}
- return -1;
+ return 0;
+}
+
+
+
+/* Desc: adjust timerfunc
+ *
+ * In : timerfunc id, new frequency (Hz)
+ * Out : 0 if success
+ *
+ * Note: might change the main timer frequency
+ */
+int pc_adjust_int (int fid, unsigned int freq)
+{
+ int i;
+
+ /* are we installed? */
+ if (!timer_installed) {
+ return -1;
+ }
+
+ /* sanity check */
+ if ((fid < 0) || (fid >= MAX_TIMERS) || (timer_func[fid].func == NULL)) {
+ return -1;
+ }
+ timer_func[fid].freq = freq;
+
+ /* scan for maximum frequency */
+ freq = 0;
+ for (i = 0; i < MAX_TIMERS; i++) {
+ TIMER *t = &timer_func[i];
+ if (t->func) {
+ if (freq < t->freq) {
+ freq = t->freq;
+ }
+ }
+ }
+
+ /* update main timer / sons to match highest frequency */
+ DISABLE();
+
+ /* using '>' is correct still (and avoids updating
+ * the HW timer too often), but doesn't relax the timer!
+ */
+ if (freq != timer_main.freq) {
+ unsigned int new_counter = PIT_FREQ / freq;
+
+ for (i = 0; i < MAX_TIMERS; i++) {
+ if (timer_func[i].func) {
+ ADJUST(timer_func[i], freq);
+ }
+ }
+
+ outportb(0x43, 0x34);
+ outportb(0x40, (unsigned char)new_counter);
+ outportb(0x40, (unsigned char)(new_counter>>8));
+ timer_main.clock_ticks = 0;
+ timer_main.counter = new_counter;
+ timer_main.freq = freq;
+ } else {
+ ADJUST(timer_func[fid], timer_main.freq);
+ }
+
+ ENABLE();
+
+ return 0;
}