[Previous]
[Contents]
[Next]

qnx_hint_attach()

attach a handler to a hardware interrupt

Synopsis:

#include <sys/irqinfo.h>

int qnx_hint_attach( unsigned intnum,
                     void __far *handler,
                     unsigned ds );

Description:

The qnx_hint_attach() function attaches the interrupt function handler to hardware interrupt intnum, where intnum must be between 0 and 15, inclusive, on an AT.

The following list contains typical interrupt assignments. Note that a request for interrupt 2 on an AT is changed to interrupt 9, since 2 is used internally to connect the slave 8259.

Interrupt Assignment
-1 fixed 50 ms timer
0 timer
1 keyboard
2 slave
3 com2
4 com1
5 net card / other
6 floppy
7 parallel printer / net card / other
8 realtime clock
9 remapped interrupt 2
10
11
12
13 NDP co-processor
14 AT hard disk
15 second hd controller (standard)

Note: Interrupts 8 through 15 are mapped to a single (round-robin) priority.

If you pass a value of -1 for intnum, your handler is invoked every 50 milliseconds. This time period won't change, even if you program the physical timer (interrupt 0) to run faster using the clock_setres() function. This timer interrupt is driven from the timer, and scaled in software, to provide a fixed time interval of 50 milliseconds.


Note: The handler function is invoked via a far call (not an interrupt), and runs in the environment of your process (Local Descriptor Table set). The data segment is set to the ds parameter. The SS register is set to a special kernel stack, which will differ from your data segment (DS). For this reason, you must disable stack checking in the interrupt handler function and any functions that it calls.

Most functions in the system library are compiled with stack checking disabled; routines that require a significant amount of stack might not. The latter tend to be functions that may not be called at interrupt time anyway, such as printf() and open(). If your functions contain any auto variables on the stack, we highly recommend that you place the interrupt function in its own file and compile it with the -zu option, which instructs the compiler that SS != DS.

Any variables modified by the handler should be specified with the volatile keyword.

The return value of the handler function must be 0, or a valid proxy pid that will be triggered to send a message.


Note: The interrupt structure allows interrupts to be shared. For example, if two processes take over the same physical interrupt, both handlers are invoked consecutively. Interrupts (sti) are enabled during the execution of your handler. However, interrupts at your level and those of lower priority are masked out. You shouldn't attempt to talk to the 8259 interrupt controller chip yourself. The end of interrupt is issued by the operating system after processing all handlers at a given level.

If you are the first process to attach to the interrupt, the interrupt is unmasked. When the last process detaches from an interrupt the system masks it.

The following important guidelines should be followed when writing interrupt handlers:

  1. Only talk to your own hardware (for example, this might be necessary to clear the state of the interrupting device). DON'T reprogram the 8259 interrupt controller.
  2. Keep your interrupt handler as short as possible. If a significant amount of work needs to be done, the handler should trigger a proxy to awaken a process to do the work.
  3. Your handler cannot call library routines that contain kernel calls.
  4. An interrupt handler MUST be a far function.
  5. The interrupt handler should be in its own module.
  6. Regardless of how the other modules in your program are compiled, the module that contains your handler MUST be compiled with the -zu and -s options (-zu and -Wc,-s if you're using cc). These options ensure that the compiler assumes that SS != DS and that stack checking is disabled.

Returns:

An interrupt handler ID (a small positive int) on success. On error, -1 is returned, and errno is set.

Errors:

EPERM
The calling process doesn't have sufficient privilege to attach an interrupt handler.
EAGAIN
The maximum number of handlers in the system have been used. You'll have to wait for one to free up.
EINVAL
The parameter intnum refers to a hardware interrupt that doesn't exist on this machine.

Examples:

/*
 * Please note that stack checking must be disabled in your
 * handler. Use the "-Wc,-s" option to the cc command.
 * It's also a good idea to put the interrupt handler
 * in its own module.
 */
#include <stdio.h>
#include <sys/irqinfo.h>
#include <sys/proxy.h>
#include <sys/kernel.h>

pid_t proxy;
volatile unsigned counter;

/* The hardware interrupt handler */
pid_t far handler()
  {

    /* Kick a proxy every 100 timer interrupts */
    if( (++counter % 100) == 0 )
      return( proxy );

    return( 0 );
  }

void main()
  {
    int id, i;

    /* Get a proxy for the interrupt handler to kick */
    if( ( proxy = qnx_proxy_attach( 0, 0, 0, -1 ) )
       == -1 ) {
      printf( " Unable to attach proxy. " );
      return;
    }

    /* Attach to the timer */
    if( ( id = qnx_hint_attach( 0, &handler,
            FP_SEG( &counter ) ) ) == -1 ) {
      printf( "Unable to attach interrupt." );
      return;
    }

    /* Wait for the proxy */
    for( i = 0 ; i < 10 ; ++i ) {
      Receive( proxy, 0, 0 );
      printf( "100 ticks.\n" );
    }

    qnx_hint_detach( id );
  }

Classification:

QNX

Safety:
Interrupt handler No
Signal handler Yes, but modifies errno
Thread Yes

Caveats:

If your application calls this function, it must run as root.

See also:

errno, qnx_hint_detach(), qnx_hint_query()


[Previous]
[Contents]
[Next]