[Back to KEYBOARD SWAG index]  [Back to Main SWAG index]  [Original]

Well, I got it figured out now!  Kudos go to you, to Ralf Brown and his
list of ports, the great state of Ohio, the Church of the SubGenius, and
most of all, Bill Seiler.

Who is Bill Seiler?  Well, did any of you ever play that old (1985-1986)
game called "Space War"?  I did, and still do; and in fact, I registered
the game (it IS shareware, after all), and got the source code.  It's all
in ASM, and a lot of it still mystifies me; but I was able to figure out
how he does his keyboard interrupt.  Yet another advantage of registering
this shareware product, five years ago!

Here's my Pascal version, with significant line numbers:

    var port60h, port61h: byte;
        keydown: array[0 .. 127] of boolean;

    procedure newkbdint; interrupt;
1     port60h := port[$60];
2     keydown[port60h and $7f] := (port60h <= $7f);
3     port61h := port[$61];
4     port[$61] := port61h or $80;
5     port[$61] := port61h;
6     port[$20] := $20;

1 - Read the port.
2 - Store the new key status for whatever key: either up or down.
3 - Read in port 61h, the system control port.
4 - Send the value back to 61h with the high bit set to "1" to reset
    the keyboard.
5 - Send the original, unadulterated value back to 61h.
6 - The boring old End of Interrupt instruction.  This line might not
    even be necessary!  It was only after testing that procedure out
    and pasting it into this message, that I noticed that I had left
    the EOI off the procedure.  But it seemed to work all right without
    it.  It seems to work just fine *with* it too, so it's probably
    best to keep it.

And, for the pure of heart: the same routine in BASM, which does not
need "port60h" and "port61h" for intermediate storage:

procedure newkbdint; assembler;       { new keyboard handler }
    push ax                           { push registers }
    push bx
    push ds
    mov ax, SEG @Data
    mov ds, ax
    in  al, 60h
    mov bx, ax
    and bx, 007fh                     { switch high bit of BX to zero }
    and al, 80h                       { check high bit of port value }
    jz @press
    @release:                         { high bit = 1: "release" code }
    mov byte ptr keydown[bx], 00h     { write 00 to "down" array element }
    jmp @done
    @press:                           { high bit = 0: "press" code }
    mov byte ptr keydown[bx], 01h     { write 01 to "down" array element }
    in al, 61h                        { read port 61h, system ctrl port }
    mov ah, al                        { save value to AH }
    or al, 80h                        { set top bit to "1" - reset kbd }
    out 61h, al                       { write out value to port }
    xchg ah, al                       { put original value back into AL }
    out 61h, al                       { rewrite original value in AL }
    mov al, 20h                       { generate End of Interrupt }
    out 20h, al
    pop ds                            { pop registers }
    pop bx
    pop ax
    iret                              { return }

[Back to KEYBOARD SWAG index]  [Back to Main SWAG index]  [Original]