Original-Received: by NeXT.Mailer (1.118.3) PP-warning: Illegal Received field on preceding line From: Timothy "J." Wood Date: Fri, 26 May 95 04:07:59 -0700 To: djgpp AT sun DOT soe DOT clarkson DOT edu Subject: Keyboard interrupt handler brokenness Reply-To: tjw AT omnigroup DOT com 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 #include #include #include #include #include #include #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(); }