Hi,
I have written a device driver that gives you two possibilities to
use harware interrupts. First you can use use signals. You get a signal
when the interrupt occurs. This is most "interrupt-like".
If you want to simply block, waiting for interrupt, you can issue
a read from the interrupt device, which will block until the interrupt
occurs.
Figure out the manual from the source.....
Anybody interested in this, I have no (longer any) use for this, so I
cannot really test it. It compiles though. :-)
Roger.
/*
* interrupt.c V0.2
*
* Copyright (C) by R.E.Wolff -- R.E.Wolff@BitWizard.nl
*
* This software may be used and distributed according to the terms
* of the GNU Public License, incorporated herein by reference.
*
* I prefer if you try to contact me if you have enhancements,
* instead of forking off a different branch.....
*
* date by what
* Written: Jul 11 1996 REW initial revision
* Changed: Jul 11 1997 REW Added blocking read functionality.
*
* who-is-who:
* initials full name Email address
* REW Roger E. Wolff R.E.Wolff@BitWizard.nl
*
* /dev/irq<num> with major INT_MAJOR (currently default 61) and minor
* <num> allows a user process access to hardware interrupt <num>.
*
* Simply open the device to be notified of the occurrance of the
* interrupt. Close it when you are done.
* read/writes to the device will return EINVAL or something like
* that.....
*
* Open a file descriptor to this device. This will cause your program
* to recieve a SIGUSR1 whenever the interrupt occurs.
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#ifndef INT_MAJOR
#define INT_MAJOR 61
#endif
struct test {
int minor;
struct task_struct * ts;
int pid;
};
struct wait_queue *locks[16];
static int int_read(struct inode *inode, struct file *file, char *buf, int count)
{
int minor = MINOR(inode->i_rdev);
interruptible_sleep_on (& locks[minor & 0x0f]);
return count;
}
static void int_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct test *t = (struct test *) dev_id;
printk ("Got irq %d, minor = %d for process %d.\n",irq,t->minor,t->pid);
if (t->minor & 0x10) {
wake_up_interruptible (&locks[irq]);
} else {
send_sig(SIGALRM, t->ts, 1);
}
}
static int int_open(struct inode * inode, struct file * file)
{
int minor = MINOR(inode->i_rdev);
struct test *t;
pr_debug ("int_open called. Minor = %d.\n", minor);
t = kmalloc (sizeof (struct test), GFP_KERNEL);
t->pid = current-> pid;
t->minor = minor;
t->ts = current;
if (request_irq (minor, int_intr, SA_SHIRQ, "int", t)) {
return -EBUSY;
}
MOD_INC_USE_COUNT;
return 0;
}
static void int_release(struct inode * inode, struct file * file)
{
int minor = MINOR(inode->i_rdev);
free_irq (minor,current);
MOD_DEC_USE_COUNT;
}
static struct file_operations int_fops = {
NULL, /* int_lseek */
int_read, /* int_read */
NULL, /* int_write */
NULL, /* int_readdir */
NULL, /* int_select */
NULL, /* int_ioctl */
NULL, /* int_mmap */
int_open, /* int_open */
int_release /* int_release */
};
#ifdef MODULE
int init_module (void)
{
if (register_chrdev(INT_MAJOR,"int",&int_fops)) {
printk("int: unable to get major %d\n", INT_MAJOR);
return -EIO;
}
printk ("int driver installed.\n");
return 0;
}
void cleanup_module(void)
{
/* Most modules don't check this it must be ok to continue anyway.... */
if (MOD_IN_USE) {
printk ("int module is still in use. Now what?\n");
/* return; */
}
unregister_chrdev(INT_MAJOR,"int");
printk ("int_cleanup: Bye bye...\n");
}
#else
#warning I am not sure if you can compile this into the kernel.....
#warning For instance the initialization is never called....
#endif