[Previous][Up][Next] | Reference for unit 'go32' (#rtl)

## Hardware interrupts

Hardware interrupts are generated by hardware devices when something unusual happens; this could be a keypress or a mouse move or any other action. This is done to minimize CPU time, else the CPU would have to check all installed hardware for data in a big loop (this method is called 'polling') and this would take much time. A standard IBM-PC has two interrupt controllers, that are responsible for these hardware interrupts: both allow up to 8 different interrupt sources (IRQs, interrupt requests). The second controller is connected to the first through IRQ 2 for compatibility reasons, e.g. if controller 1 gets an IRQ 2, he hands the IRQ over to controller 2. Because of this up to 15 different hardware interrupt sources can be handled. IRQ 0 through IRQ 7 are mapped to interrupts 8h to Fh and the second controller (IRQ 8 to 15) is mapped to interrupt 70h to 77h. All of the code and data touched by these handlers MUST be locked (via the various locking functions) to avoid page faults at interrupt time. Because hardware interrupts are called (as in real mode) with interrupts disabled, the handler has to enable them before it returns to normal program execution. Additionally a hardware interrupt must send an EOI (end of interrupt) command to the responsible controller; this is acomplished by sending the value 20h to port 20h (for the first controller) or A0h (for the second controller). The following example shows how to redirect the keyboard interrupt.

## Example

    {$ASMMODE ATT}
    {$MODE FPC}

    uses
            crt,
            go32;

    const
            kbdint = $9;

    var
            oldint9_handler : tseginfo;
            newint9_handler : tseginfo;

            clickproc : pointer;
            backupDS : Word; external name '___v2prt0_ds_alias';

    procedure int9_handler; assembler;
    asm
            cli
            pushl %ds
            pushl %es
            pushl %fs
            pushl %gs
            pushal
            movw %cs:backupDS, %ax
            movw %ax, %ds
            movw %ax, %es
            movw dosmemselector, %ax
            movw %ax, %fs
            call *clickproc
            popal
            popl %gs
            popl %fs
            popl %es
            popl %ds
            ljmp %cs:oldint9_handler
    end;
    procedure int9_dummy; begin end;

    procedure clicker;
    begin
            sound(500); delay(10); nosound;
    end;
    procedure clicker_dummy; begin end;

    procedure install_click;
    begin
            clickproc := @clicker;
            lock_data(clickproc, sizeof(clickproc));
            lock_data(dosmemselector, sizeof(dosmemselector));

            lock_code(@clicker,
                    longint(@clicker_dummy) - longint(@clicker));
            lock_code(@int9_handler,
                    longint(@int9_dummy)-longint(@int9_handler));
            newint9_handler.offset := @int9_handler;
            newint9_handler.segment := get_cs;
            get_pm_interrupt(kbdint, oldint9_handler);
            set_pm_interrupt(kbdint, newint9_handler);
    end;

    procedure remove_click;
    begin
            set_pm_interrupt(kbdint, oldint9_handler);
            unlock_data(dosmemselector, sizeof(dosmemselector));
            unlock_data(clickproc, sizeof(clickproc));

            unlock_code(@clicker,
                    longint(@clicker_dummy)-longint(@clicker));
            unlock_code(@int9_handler,
                    longint(@int9_dummy)-longint(@int9_handler));
    end;

    var
            ch : char;

    begin
            install_click;
            Writeln('Enter any message. Press return when finished');
            while (ch <> #13) do begin
                    ch := readkey; write(ch);
            end;
            remove_click;
    end.

Documentation generated on: Feb 26 2014