delorie.com/djgpp/faq/lowlevel/hwint.html
|
search
|
How do I register my djgpp function as a hardware interrupt
handler?
The optimal set-up depends on the interrupt and on the environment
under which your program will run (VCPI, DPMI, etc.). Therefore, only
some basic considerations and techniques are listed below. What
combination of these is best for your application is up to you to
decide.
First, some background. Hardware interrupts can occur when the
processor is either in real mode (like when go32 calls some DOS
service) or in protected mode. When your program runs under a DPMI
host, hardware interrupts are always passed to protected mode first,
and only if unhandled, they are reflected to real mode. In non-DPMI
environment, this is only true for interrupts which occur in protected
mode; an interrupt which occurs in real mode is never passed to
protected mode. So, if your program runs in non-DPMI mode, it
must at least install a real-mode handler for the interrupt,
or else it will lose interrupts; it is best also to install a
protected-mode handler, otherwise for an interrupt which occurs in
protected mode, the CPU will have to switch mode twice, which will
hurt performance. In contrast, in DPMI mode you can get away by
installing only a protected-mode handler. (The tricky one is to write
a program which will run in both environments; this is left as an
exercise for the reader... ;-)
To install a protected-mode interrupt handler, you do this:
- Call _go32_dpmi_get_protected_mode_interrupt_vector()
and save the structure it returns (to restore the previous handler
address before your program exits).
- Call _go32_dpmi_allocate_iret_wrapper() passing it the
address of your functions as the pm_offset field. That field
will get replaced with the address of the wrapper function which is a
small assembler function that handles everything an interrupt handler
should do on entry and before exit (and what the code gcc
generates for an ordinary C function doesn't include); the effect is
similar to using interrupt or _interrupt keyword in
some DOS-based compilers.
- Call _go32_dpmi_set_protected_mode_interrupt_vector()
passing it the value of the pm_offset field as returned from
_go32_dpmi_allocate_iret_wrapper() and whatever
_go32_my_cs() returns as pm_selector.
- If you want your handler to chain to the previous handler,
call _go32_dpmi_chain_protected_mode_interrupt_vector().
This will set up a wrapper function which will automagically
jump to the previous handler after your handler returns, and
also installs that wrapper as the handler for the interrupt.
To install a real-mode interrupt handler, you do this:
- Call _go32_dpmi_get_real_mode_interrupt_vector() and
save the structure it returns (to restore the previous handler address
before your program exits).
- Call _go32_dpmi_allocate_real_mode_callback_iret()
passing it the address of your handler function in pm_offset.
This wraps your function with a short real-mode interrupt handler
which will switch to protected mode and call your function, then
switch back to real mode and do an iret.
- Call _go32_dpmi_set_real_mode_interrupt_vector() with
the structure which
_go32_dpmi_allocate_real_mode_callback_iret() returned.
- If you want your handler to chain to the previous real-mode
handler, then issue a _go32_dpmi_simulate_fcall_iret() just
before your handler returns, using the rm_segment and
rm_offset which were returned when you called
_go32_dpmi_get_real_mode_interrupt_vector().
For examples of installing and using hardware interrupt handlers, see
the files sb02.zip (Sound Blaster interrupt-driven functions)
and ldbgXXX.zip (interrupt-driven serial communications
code), both available in the djgpp distribution archive.