Re: Getting DMA and IRQ in userspace program

Rogier Wolff (R.E.Wolff@BitWizard.nl)
Fri, 11 Jul 1997 09:28:17 +0200 (MET DST)


Teunis Peters wrote:
>
> I suppose this is kind of a silly request, but I need access to hardware
> IRQ's (at least) if not also DMA on hardware devices.

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