interrupts: I'm still waiting ;-)

Hello!
I’m novice in QNX… I installed qnx 6.2 from .iso provided for free in
qnx.com
The problem is the following:
I have a timers PCI card . The card have a external interrupt line,too.

I’m trying to make interrupts working with no success. I’m using
pci_* functions to extract info from the pci configuration space…(ie:
inf.Irq =10)
It yields no problems with ioaddresses and timers configurations. But
when I add interrupt support using interruptwait () the program loops
forever.
Please, let me know what is wrong, or some special qcc options, etc. Or
“link me” to other source of info
thank in advance
Here is the code:

ps: some vars are in globals.h , like inf

#include <stdio.h>
#include <string.h>
#include <sys/neutrino.h>
#include <sys/mman.h>
#include <sys/siginfo.h>
#include <hw/pci.h>
#include <hw/inout.h>
#include <atomic.h>

#include “definic.h”
#include “globales.h”

struct sigevent evento;

//HERE IS THE INT HANDLER
const struct sigevent *isr_func( void *arg, int id )
{
//ENMASCARA INTERRUPCION
InterruptMask( inf.Irq, -1 );

//DO SOMETHING
atomic_add( &ii, 1 );

return (&evento);
}


//MAIN FUNCTION
void main(void)
{
//
int handle = pci_attach(0);
if ( handle == -1 )
{
printf(“Error: pci_attach\n”);
return 0;
}

//INICIALIZA ESTRUCTURA PCI_DEV_INFO
memset( &inf, 0, sizeof( inf ) );
inf.VendorId = VENDOR_ID;
inf.DeviceId = DEVICE_ID;

//BUSCA DEVICE Y LLENA ESTRUCTURA PCI_INFO
void * hdl = pci_attach_device( NULL, PCI_INIT_ALL, 0, &inf );
if ( hdl == NULL )
{
printf( “Error: pci_attach_device\n” );
return 0;
}

//LEE EL ESPACIO DE CONFIGURACION PCI PARA OBTENER LA DIRECCION BASE
int base_addr;
pci_read_config32( inf.BusNumber, inf.DevFunc, 24, 1, &base_addr );

//COPIA VALOR A VARIABLE GLOBAL (Y MATA EL ULTIMO BIT)
Base_Addr = base_addr & 0xFFFE;

//DA ACCESO A LOS PUERTOS I/O
ThreadCtl( _NTO_TCTL_IO, 0 );

//MAP 20 I/O
IOBase = mmap_device_io( 20, Base_Addr );

//CFG TIMER 11 MODE 0
out8( IOBase+15, 0xB0 ); //TIMER CHIP 4, CFG REGISTER

//SETS COUNT
out8( IOBase+14, 0x00 ); //TIMER CHIP 4, TIMER 3
out8( IOBase+14, 0x20 );

//INIC EVENTO
SIGEV_INTR_INIT( &evento );

//ATTACH INTERRUPTION
int idint = InterruptAttach( inf.Irq, isr_func, NULL, 0, 0 ); //I ALSO
FLAG TO PUT ISR AT THE END OF THE ISR CHAIN
if ( idint == -1 )
{
printf( “Error: InterruptAttach\n” );
pci_detach( handle );
return 0;
}

//ENABLE INTERRUPTS IN TIMERS PCI CARD
out8( IOBase+20, 0x01 );

//MAIN LOOP
while ( ii < 100 )
{
//WAIT
InterruptWait( NULL, 0 ); //I ALSO TRIED I_W_(0, NULL)

//DO SOMETHING
printf( “%d\n”, ii );

// SETS A NEW COUNT TIMER
out8( IOBase+14, 0x00 );
out8( IOBase+14, 0xFF );

//UNMASK
// InterruptUnmask( inf.Irq, -1 );
}

//CLOSE APP
InterruptDetach( idint );
pci_detach( handle );
}

After a quick scan, I noticed that you have the call to InterruptUnmask()
commented out at the end of the while loop, but the call to InterruptMask()
is still present in the ISR. If the ISR masks the interrupt and you don’t
unmask it anywhere else, you shouldn’t see any more interrupts from the
inf.Irq source. Do you see any errors returned from InterruptWait()?

“Mauricio Manterola” <me@piracy.net> wrote in message
news:3E25FB28.3905CEF3@piracy.net

Hello!
I’m novice in QNX… I installed qnx 6.2 from .iso provided for free in
qnx.com
The problem is the following:
I have a timers PCI card . The card have a external interrupt line,too.

I’m trying to make interrupts working with no success. I’m using
pci_* functions to extract info from the pci configuration space…(ie:
inf.Irq =10)
It yields no problems with ioaddresses and timers configurations. But
when I add interrupt support using interruptwait () the program loops
forever.
Please, let me know what is wrong, or some special qcc options, etc. Or
“link me” to other source of info
thank in advance
Here is the code:

ps: some vars are in globals.h , like inf

#include <stdio.h
#include <string.h
#include <sys/neutrino.h
#include <sys/mman.h
#include <sys/siginfo.h
#include <hw/pci.h
#include <hw/inout.h
#include <atomic.h

#include “definic.h”
#include “globales.h”

struct sigevent evento;

//HERE IS THE INT HANDLER
const struct sigevent *isr_func( void *arg, int id )
{
//ENMASCARA INTERRUPCION
InterruptMask( inf.Irq, -1 );

//DO SOMETHING
atomic_add( &ii, 1 );

return (&evento);
}


//MAIN FUNCTION
void main(void)
{
//
int handle = pci_attach(0);
if ( handle == -1 )
{
printf(“Error: pci_attach\n”);
return 0;
}

//INICIALIZA ESTRUCTURA PCI_DEV_INFO
memset( &inf, 0, sizeof( inf ) );
inf.VendorId = VENDOR_ID;
inf.DeviceId = DEVICE_ID;

//BUSCA DEVICE Y LLENA ESTRUCTURA PCI_INFO
void * hdl = pci_attach_device( NULL, PCI_INIT_ALL, 0, &inf );
if ( hdl == NULL )
{
printf( “Error: pci_attach_device\n” );
return 0;
}

//LEE EL ESPACIO DE CONFIGURACION PCI PARA OBTENER LA DIRECCION BASE
int base_addr;
pci_read_config32( inf.BusNumber, inf.DevFunc, 24, 1, &base_addr );

//COPIA VALOR A VARIABLE GLOBAL (Y MATA EL ULTIMO BIT)
Base_Addr = base_addr & 0xFFFE;

//DA ACCESO A LOS PUERTOS I/O
ThreadCtl( _NTO_TCTL_IO, 0 );

//MAP 20 I/O
IOBase = mmap_device_io( 20, Base_Addr );

//CFG TIMER 11 MODE 0
out8( IOBase+15, 0xB0 ); //TIMER CHIP 4, CFG REGISTER

//SETS COUNT
out8( IOBase+14, 0x00 ); //TIMER CHIP 4, TIMER 3
out8( IOBase+14, 0x20 );

//INIC EVENTO
SIGEV_INTR_INIT( &evento );

//ATTACH INTERRUPTION
int idint = InterruptAttach( inf.Irq, isr_func, NULL, 0, 0 ); //I ALSO
FLAG TO PUT ISR AT THE END OF THE ISR CHAIN
if ( idint == -1 )
{
printf( “Error: InterruptAttach\n” );
pci_detach( handle );
return 0;
}

//ENABLE INTERRUPTS IN TIMERS PCI CARD
out8( IOBase+20, 0x01 );

//MAIN LOOP
while ( ii < 100 )
{
//WAIT
InterruptWait( NULL, 0 ); //I ALSO TRIED I_W_(0, NULL)

//DO SOMETHING
printf( “%d\n”, ii );

// SETS A NEW COUNT TIMER
out8( IOBase+14, 0x00 );
out8( IOBase+14, 0xFF );

//UNMASK
// InterruptUnmask( inf.Irq, -1 );
}

//CLOSE APP
InterruptDetach( idint );
pci_detach( handle );
}
\

Hi…
Firstly, Are there a charter or some document to undertand this news server
hierarchy?

Secondly, I just tried uncommenting that code line… the source code I
posted was just a try and I forgot to uncomment that line.

Finally, How I can see what InterruptWait return is? I tried to do :
printf("%d\n", InterruptWait()); with no success.

At that point I want to thanks for the useful help and info found here.

Mauricio M.


Brian Meinke wrote:

After a quick scan, I noticed that you have the call to InterruptUnmask()
commented out at the end of the while loop, but the call to InterruptMask()
is still present in the ISR. If the ISR masks the interrupt and you don’t
unmask it anywhere else, you shouldn’t see any more interrupts from the
inf.Irq source. Do you see any errors returned from InterruptWait()?

“Mauricio Manterola” <> me@piracy.net> > wrote in message
news:> 3E25FB28.3905CEF3@piracy.net> …
Hello!
I’m novice in QNX… I installed qnx 6.2 from .iso provided for free in
qnx.com
The problem is the following:
I have a timers PCI card . The card have a external interrupt line,too.

I’m trying to make interrupts working with no success. I’m using
pci_* functions to extract info from the pci configuration space…(ie:
inf.Irq =10)
It yields no problems with ioaddresses and timers configurations. But
when I add interrupt support using interruptwait () the program loops
forever.
Please, let me know what is wrong, or some special qcc options, etc. Or
“link me” to other source of info
thank in advance
Here is the code:

ps: some vars are in globals.h , like inf

#include <stdio.h
#include <string.h
#include <sys/neutrino.h
#include <sys/mman.h
#include <sys/siginfo.h
#include <hw/pci.h
#include <hw/inout.h
#include <atomic.h

#include “definic.h”
#include “globales.h”

struct sigevent evento;

//HERE IS THE INT HANDLER
const struct sigevent *isr_func( void *arg, int id )
{
//ENMASCARA INTERRUPCION
InterruptMask( inf.Irq, -1 );

//DO SOMETHING
atomic_add( &ii, 1 );

return (&evento);
}


//MAIN FUNCTION
void main(void)
{
//
int handle = pci_attach(0);
if ( handle == -1 )
{
printf(“Error: pci_attach\n”);
return 0;
}

//INICIALIZA ESTRUCTURA PCI_DEV_INFO
memset( &inf, 0, sizeof( inf ) );
inf.VendorId = VENDOR_ID;
inf.DeviceId = DEVICE_ID;

//BUSCA DEVICE Y LLENA ESTRUCTURA PCI_INFO
void * hdl = pci_attach_device( NULL, PCI_INIT_ALL, 0, &inf );
if ( hdl == NULL )
{
printf( “Error: pci_attach_device\n” );
return 0;
}

//LEE EL ESPACIO DE CONFIGURACION PCI PARA OBTENER LA DIRECCION BASE
int base_addr;
pci_read_config32( inf.BusNumber, inf.DevFunc, 24, 1, &base_addr );

//COPIA VALOR A VARIABLE GLOBAL (Y MATA EL ULTIMO BIT)
Base_Addr = base_addr & 0xFFFE;

//DA ACCESO A LOS PUERTOS I/O
ThreadCtl( _NTO_TCTL_IO, 0 );

//MAP 20 I/O
IOBase = mmap_device_io( 20, Base_Addr );

//CFG TIMER 11 MODE 0
out8( IOBase+15, 0xB0 ); //TIMER CHIP 4, CFG REGISTER

//SETS COUNT
out8( IOBase+14, 0x00 ); //TIMER CHIP 4, TIMER 3
out8( IOBase+14, 0x20 );

//INIC EVENTO
SIGEV_INTR_INIT( &evento );

//ATTACH INTERRUPTION
int idint = InterruptAttach( inf.Irq, isr_func, NULL, 0, 0 ); //I ALSO
FLAG TO PUT ISR AT THE END OF THE ISR CHAIN
if ( idint == -1 )
{
printf( “Error: InterruptAttach\n” );
pci_detach( handle );
return 0;
}

//ENABLE INTERRUPTS IN TIMERS PCI CARD
out8( IOBase+20, 0x01 );

//MAIN LOOP
while ( ii < 100 )
{
//WAIT
InterruptWait( NULL, 0 ); //I ALSO TRIED I_W_(0, NULL)

//DO SOMETHING
printf( “%d\n”, ii );

// SETS A NEW COUNT TIMER
out8( IOBase+14, 0x00 );
out8( IOBase+14, 0xFF );

//UNMASK
// InterruptUnmask( inf.Irq, -1 );
}

//CLOSE APP
InterruptDetach( idint );
pci_detach( handle );
}
\

Perhaps you should start with pci_attach pci_attach_device to make sure
the pci device is in use, perhaps there are some configs inside which
enable the irq’s. And start writing english comments in your code.
Did you measured if the irq physically really happens?

Mauricio Manterola wrote:

Hello!
I’m novice in QNX… I installed qnx 6.2 from .iso provided for free in
qnx.com
The problem is the following:
I have a timers PCI card . The card have a external interrupt line,too.

I’m trying to make interrupts working with no success. I’m using
pci_* functions to extract info from the pci configuration space…(ie:
inf.Irq =10)
It yields no problems with ioaddresses and timers configurations. But
when I add interrupt support using interruptwait () the program loops
forever.
Please, let me know what is wrong, or some special qcc options, etc. Or
“link me” to other source of info
thank in advance
Here is the code:

ps: some vars are in globals.h , like inf

#include <stdio.h
#include <string.h
#include <sys/neutrino.h
#include <sys/mman.h
#include <sys/siginfo.h
#include <hw/pci.h
#include <hw/inout.h
#include <atomic.h

#include “definic.h”
#include “globales.h”

struct sigevent evento;

//HERE IS THE INT HANDLER
const struct sigevent *isr_func( void *arg, int id )
{
//ENMASCARA INTERRUPCION
InterruptMask( inf.Irq, -1 );

//DO SOMETHING
atomic_add( &ii, 1 );

return (&evento);
}


//MAIN FUNCTION
void main(void)
{
//
int handle = pci_attach(0);
if ( handle == -1 )
{
printf(“Error: pci_attach\n”);
return 0;
}

//INICIALIZA ESTRUCTURA PCI_DEV_INFO
memset( &inf, 0, sizeof( inf ) );
inf.VendorId = VENDOR_ID;
inf.DeviceId = DEVICE_ID;

//BUSCA DEVICE Y LLENA ESTRUCTURA PCI_INFO
void * hdl = pci_attach_device( NULL, PCI_INIT_ALL, 0, &inf );
if ( hdl == NULL )
{
printf( “Error: pci_attach_device\n” );
return 0;
}

//LEE EL ESPACIO DE CONFIGURACION PCI PARA OBTENER LA DIRECCION BASE
int base_addr;
pci_read_config32( inf.BusNumber, inf.DevFunc, 24, 1, &base_addr );

//COPIA VALOR A VARIABLE GLOBAL (Y MATA EL ULTIMO BIT)
Base_Addr = base_addr & 0xFFFE;

//DA ACCESO A LOS PUERTOS I/O
ThreadCtl( _NTO_TCTL_IO, 0 );

//MAP 20 I/O
IOBase = mmap_device_io( 20, Base_Addr );

//CFG TIMER 11 MODE 0
out8( IOBase+15, 0xB0 ); //TIMER CHIP 4, CFG REGISTER

//SETS COUNT
out8( IOBase+14, 0x00 ); //TIMER CHIP 4, TIMER 3
out8( IOBase+14, 0x20 );

//INIC EVENTO
SIGEV_INTR_INIT( &evento );

//ATTACH INTERRUPTION
int idint = InterruptAttach( inf.Irq, isr_func, NULL, 0, 0 ); //I ALSO
FLAG TO PUT ISR AT THE END OF THE ISR CHAIN
if ( idint == -1 )
{
printf( “Error: InterruptAttach\n” );
pci_detach( handle );
return 0;
}

//ENABLE INTERRUPTS IN TIMERS PCI CARD
out8( IOBase+20, 0x01 );

//MAIN LOOP
while ( ii < 100 )
{
//WAIT
InterruptWait( NULL, 0 ); //I ALSO TRIED I_W_(0, NULL)

//DO SOMETHING
printf( “%d\n”, ii );

// SETS A NEW COUNT TIMER
out8( IOBase+14, 0x00 );
out8( IOBase+14, 0xFF );

//UNMASK
// InterruptUnmask( inf.Irq, -1 );
}

//CLOSE APP
InterruptDetach( idint );
pci_detach( handle );
}
\

Mauricio,

Why do you call InterruptMask() in your ISR?

dB

“Tiemo Krueger - mycable GmbH” <tk@mycable.de> wrote in message
news:b70qj4$99o$1@inn.qnx.com

Perhaps you should start with pci_attach pci_attach_device to make sure
the pci device is in use, perhaps there are some configs inside which
enable the irq’s. And start writing english comments in your code.
Did you measured if the irq physically really happens?

Mauricio Manterola wrote:
Hello!
I’m novice in QNX… I installed qnx 6.2 from .iso provided for free in
qnx.com
The problem is the following:
I have a timers PCI card . The card have a external interrupt line,too.

I’m trying to make interrupts working with no success. I’m using
pci_* functions to extract info from the pci configuration space…(ie:
inf.Irq =10)
It yields no problems with ioaddresses and timers configurations. But
when I add interrupt support using interruptwait () the program loops
forever.
Please, let me know what is wrong, or some special qcc options, etc. Or
“link me” to other source of info
thank in advance
Here is the code:

ps: some vars are in globals.h , like inf

#include <stdio.h
#include <string.h
#include <sys/neutrino.h
#include <sys/mman.h
#include <sys/siginfo.h
#include <hw/pci.h
#include <hw/inout.h
#include <atomic.h

#include “definic.h”
#include “globales.h”

struct sigevent evento;

//HERE IS THE INT HANDLER
const struct sigevent *isr_func( void *arg, int id )
{
//ENMASCARA INTERRUPCION
InterruptMask( inf.Irq, -1 );

//DO SOMETHING
atomic_add( &ii, 1 );

return (&evento);
}


//MAIN FUNCTION
void main(void)
{
//
int handle = pci_attach(0);
if ( handle == -1 )
{
printf(“Error: pci_attach\n”);
return 0;
}

//INICIALIZA ESTRUCTURA PCI_DEV_INFO
memset( &inf, 0, sizeof( inf ) );
inf.VendorId = VENDOR_ID;
inf.DeviceId = DEVICE_ID;

//BUSCA DEVICE Y LLENA ESTRUCTURA PCI_INFO
void * hdl = pci_attach_device( NULL, PCI_INIT_ALL, 0, &inf );
if ( hdl == NULL )
{
printf( “Error: pci_attach_device\n” );
return 0;
}

//LEE EL ESPACIO DE CONFIGURACION PCI PARA OBTENER LA DIRECCION BASE
int base_addr;
pci_read_config32( inf.BusNumber, inf.DevFunc, 24, 1, &base_addr );

//COPIA VALOR A VARIABLE GLOBAL (Y MATA EL ULTIMO BIT)
Base_Addr = base_addr & 0xFFFE;

//DA ACCESO A LOS PUERTOS I/O
ThreadCtl( _NTO_TCTL_IO, 0 );

//MAP 20 I/O
IOBase = mmap_device_io( 20, Base_Addr );

//CFG TIMER 11 MODE 0
out8( IOBase+15, 0xB0 ); //TIMER CHIP 4, CFG REGISTER

//SETS COUNT
out8( IOBase+14, 0x00 ); //TIMER CHIP 4, TIMER 3
out8( IOBase+14, 0x20 );

//INIC EVENTO
SIGEV_INTR_INIT( &evento );

//ATTACH INTERRUPTION
int idint = InterruptAttach( inf.Irq, isr_func, NULL, 0, 0 ); //I ALSO
FLAG TO PUT ISR AT THE END OF THE ISR CHAIN
if ( idint == -1 )
{
printf( “Error: InterruptAttach\n” );
pci_detach( handle );
return 0;
}

//ENABLE INTERRUPTS IN TIMERS PCI CARD
out8( IOBase+20, 0x01 );

//MAIN LOOP
while ( ii < 100 )
{
//WAIT
InterruptWait( NULL, 0 ); //I ALSO TRIED I_W_(0, NULL)

//DO SOMETHING
printf( “%d\n”, ii );

// SETS A NEW COUNT TIMER
out8( IOBase+14, 0x00 );
out8( IOBase+14, 0xFF );

//UNMASK
// InterruptUnmask( inf.Irq, -1 );
}

//CLOSE APP
InterruptDetach( idint );
pci_detach( handle );
}

\

I retract the question I asked yesterday, thanks to Chris McKillop’s
reminding me that you do indeed need to mask off the interrupt until you
have cleared its source. (For a PC timer, you don’t have to worry about
that, because the kernel clears it.)

Is the pair of out8() invocations after the comment “SETS A NEW COUNT TIMER”
supposed to do that clearing for your timer?

Also, when you say your program “loops forever”, do you really just mean
that it fails to return from InterruptWait()? (If you mean the main loop
keeps executing, what value does it print for ii?)

dB

David Bacon <dbacon@qnx.com> wrote in message
news:b7no8a$3jt$1@nntp.qnx.com

Mauricio,

Why do you call InterruptMask() in your ISR?

dB

“Tiemo Krueger - mycable GmbH” <> tk@mycable.de> > wrote in message
news:b70qj4$99o$> 1@inn.qnx.com> …
Perhaps you should start with pci_attach pci_attach_device to make sure
the pci device is in use, perhaps there are some configs inside which
enable the irq’s. And start writing english comments in your code.
Did you measured if the irq physically really happens?

Mauricio Manterola wrote:
Hello!
I’m novice in QNX… I installed qnx 6.2 from .iso provided for free
in
qnx.com
The problem is the following:
I have a timers PCI card . The card have a external interrupt
line,too.

I’m trying to make interrupts working with no success. I’m using
pci_* functions to extract info from the pci configuration
space…(ie:
inf.Irq =10)
It yields no problems with ioaddresses and timers configurations. But
when I add interrupt support using interruptwait () the program loops
forever.
Please, let me know what is wrong, or some special qcc options, etc.
Or
“link me” to other source of info
thank in advance
Here is the code:

ps: some vars are in globals.h , like inf

#include <stdio.h
#include <string.h
#include <sys/neutrino.h
#include <sys/mman.h
#include <sys/siginfo.h
#include <hw/pci.h
#include <hw/inout.h
#include <atomic.h

#include “definic.h”
#include “globales.h”

struct sigevent evento;

//HERE IS THE INT HANDLER
const struct sigevent *isr_func( void *arg, int id )
{
//ENMASCARA INTERRUPCION
InterruptMask( inf.Irq, -1 );

//DO SOMETHING
atomic_add( &ii, 1 );

return (&evento);
}


//MAIN FUNCTION
void main(void)
{
//
int handle = pci_attach(0);
if ( handle == -1 )
{
printf(“Error: pci_attach\n”);
return 0;
}

//INICIALIZA ESTRUCTURA PCI_DEV_INFO
memset( &inf, 0, sizeof( inf ) );
inf.VendorId = VENDOR_ID;
inf.DeviceId = DEVICE_ID;

//BUSCA DEVICE Y LLENA ESTRUCTURA PCI_INFO
void * hdl = pci_attach_device( NULL, PCI_INIT_ALL, 0, &inf );
if ( hdl == NULL )
{
printf( “Error: pci_attach_device\n” );
return 0;
}

//LEE EL ESPACIO DE CONFIGURACION PCI PARA OBTENER LA DIRECCION BASE
int base_addr;
pci_read_config32( inf.BusNumber, inf.DevFunc, 24, 1, &base_addr );

//COPIA VALOR A VARIABLE GLOBAL (Y MATA EL ULTIMO BIT)
Base_Addr = base_addr & 0xFFFE;

//DA ACCESO A LOS PUERTOS I/O
ThreadCtl( _NTO_TCTL_IO, 0 );

//MAP 20 I/O
IOBase = mmap_device_io( 20, Base_Addr );

//CFG TIMER 11 MODE 0
out8( IOBase+15, 0xB0 ); //TIMER CHIP 4, CFG REGISTER

//SETS COUNT
out8( IOBase+14, 0x00 ); //TIMER CHIP 4, TIMER 3
out8( IOBase+14, 0x20 );

//INIC EVENTO
SIGEV_INTR_INIT( &evento );

//ATTACH INTERRUPTION
int idint = InterruptAttach( inf.Irq, isr_func, NULL, 0, 0 ); //I
ALSO
FLAG TO PUT ISR AT THE END OF THE ISR CHAIN
if ( idint == -1 )
{
printf( “Error: InterruptAttach\n” );
pci_detach( handle );
return 0;
}

//ENABLE INTERRUPTS IN TIMERS PCI CARD
out8( IOBase+20, 0x01 );

//MAIN LOOP
while ( ii < 100 )
{
//WAIT
InterruptWait( NULL, 0 ); //I ALSO TRIED I_W_(0, NULL)

//DO SOMETHING
printf( “%d\n”, ii );

// SETS A NEW COUNT TIMER
out8( IOBase+14, 0x00 );
out8( IOBase+14, 0xFF );

//UNMASK
// InterruptUnmask( inf.Irq, -1 );
}

//CLOSE APP
InterruptDetach( idint );
pci_detach( handle );
}



\