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;
No comments:
Post a Comment