qnx_hint_attach

attach a handler to a hardware interrupt

Synopsis:

#include <sys/irqinfo.h>
int qnx_hint_attach( 
        unsigned intnum,
        pid_t (* handler)(void),
        unsigned ds );

/* Note, in the 16-bit libraries, 
   the prototype is: */

int qnx_hint_attach( 
        unsigned intnum,
        pid_t (__far * __far handler)(void),
        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
-1fixed 50 ms timer
0timer
1keyboard
2slave
3com2
4com1
5net card / other
6floppy
7parallel printer / net card / other
8realtime clock
9remapped interrupt 2
10
11
12
13NDP co-processor
14AT hard disk
15second hd controller (standard)
Iterrupts 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.

The handler function is invoked via a far call (not an interrupt), and runs in the environment of your process (LDT 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.

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 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. 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:

The qnx_hint_attach() function returns an interrupt handler ID (a small positive int) on success. On error, a (-1) is returned, and errno is set.

Errors:

EPERM
The calling process does not 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.

See also:

errno, qnx_hint_detach(), qnx_hint_query()

Examples:

/*
 * Please note that stack checking must be disabled in your
 * handler. You can use the pragmas below and/or the
 * "-Wc,-s" option to the CC command.
 */
#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 */
#pragma off( check_stack );
pid_t far handler()
  {

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

    return( 0 );
  }
#pragma on( check_stack );

void main()
  {
    int id, i;

    /* Get a proxy for the interrupt handler to kick */
    if( ( proxy = qnx_proxy_attach( 0, 0, 0, 0 ) )
       == -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

Systems:

QNX