Mail Archives: djgpp/1995/05/26/08:19:49
I'm just starting my DOS hacking (having lived most of my life in
Unix) and I've just written my first DJGPP interrupt handler. This
does some simple keyboard operations -- detecting key down and up
and is pieced together from various pieces of examples that I've
found laying around.
Amazingly, it works. Well, mostly. Two problems. As written
below, eventually the keyboard will start beeping. Presumably it's
input buffer it filled. In fact, when I hit escape, a bunch of
stuff is printed out; the contents of the full buffer, I assume.
If I uncommend the real mode handler calls in main(), the beeping
doesn't happen, but if you type fast enough, the program will issue
the message 'Unsupported INT 0xd' followed a keypress or two later
by a segmentation fault.
Anyway, the code follows. If you have any suggestions about what
might be going wrong, that would be much appreciated. I've tweaked
it every which way I can find, and I'm reading through a stacks of
documentation I have and trying other tweaks, but this is probably
something obvious to someone who's programmed DOS for more than a
couple hours :)
-tim
/* key.c */
/* I'm compiling on a sparc.20 running NEXTSTEP with the following:
/usr/local/lib/djgpp/bin/gcc -Wall -B/usr/local/lib/djgpp/bin/
-nostdinc -I/usr/local/lib/djgpp/include -O1 -c key.c
/usr/local/lib/djgpp/bin/ld -nostartfiles
-L/usr/local/lib/djgpp/lib /usr/local/lib/djgpp/lib/crt0.o key.o
-lpc -lc -o key
My compiler flags will probably differ from anyone compiling
under DOS so the above is only a suggestion of what might work
for you.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <go32.h>
#include <dos.h>
#include <dpmi.h>
#include <pc.h>
#define KEY_INT 0x09
_go32_dpmi_seginfo oldirq_rm;
_go32_dpmi_registers rm_regs;
_go32_dpmi_seginfo rm_si;
_go32_dpmi_seginfo oldirq_pm;
_go32_dpmi_seginfo pm_si;
unsigned char key = 0;
static inline void _disable()
{
asm __volatile__ (
"cli"
);
}
static inline void _enable()
{
asm __volatile__ (
"sti"
);
}
static inline unsigned char inb(unsigned short port)
{
unsigned char data;
asm volatile(
"inb %1,%0"
: "=a"(data)
: "d"(port));
return (data);
}
static inline void outb(unsigned short port, unsigned char data)
{
asm volatile(
"outb %1,%0"
:
: "d" (port), "a" (data));
}
#define KEY_BUFFER 0x60
#define KEY_CONTROL 0x61
#define INT_CONTROL 0x20
static void key_intr(_go32_dpmi_registers *reg)
{
unsigned char control;
/* get the key */
key = inb(KEY_BUFFER);
/* reset the keyboard controller */
control = inb(KEY_CONTROL);
control |= 0x80; /* The code I saw used 0x82 here, but my docs
say to use 0x80, why? */
outb(KEY_CONTROL, control);
control &= 0x7f;
outb(KEY_CONTROL, control);
/* ack the interrupt */
outb(INT_CONTROL, 0x20);
_enable();
}
static void install_rm_interrupt()
{
int ret;
rm_si.pm_offset = (int)key_intr;
ret = _go32_dpmi_allocate_real_mode_callback_iret(&rm_si, &rm_regs);
if (ret != 0) {
printf("cannot allocate real mode callback, error=%04x\n", ret);
exit(1);
}
_disable();
_go32_dpmi_get_real_mode_interrupt_vector(KEY_INT, &oldirq_rm);
_go32_dpmi_set_real_mode_interrupt_vector(KEY_INT, &rm_si);
_enable();
}
static void cleanup_rm_interrupt()
{
_disable();
_go32_dpmi_set_real_mode_interrupt_vector(KEY_INT, &oldirq_rm);
_go32_dpmi_free_real_mode_callback(&rm_si);
_enable();
}
static void install_pm_interrupt()
{
_disable();
_go32_dpmi_get_protected_mode_interrupt_vector(KEY_INT, &oldirq_pm);
pm_si.pm_offset = (int)key_intr;
pm_si.pm_selector = _go32_my_cs();
_go32_dpmi_chain_protected_mode_interrupt_vector(KEY_INT, &pm_si);
_enable();
}
static void cleanup_pm_interrupt()
{
_disable();
_go32_dpmi_set_protected_mode_interrupt_vector(KEY_INT, &oldirq_pm);
_enable();
}
void main(int argc, char *argv[])
{
unsigned char oldKey = 0;
/*install_rm_interrupt();*/
install_pm_interrupt();
printf("Interrupt handlers installed\n");
while (1) {
if (oldKey != key) {
printf("key = %d\n", key);
if (key == 1) {
break;
}
oldKey = key;
}
}
/*cleanup_rm_interrupt();*/
cleanup_pm_interrupt();
}
- Raw text -