[Previous][Up][Next] |
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.
{$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.