linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* Notifying a user space application
@ 2004-06-30 22:29 Christian Tröster
  2004-07-01  6:20 ` Stefan Nickl
  0 siblings, 1 reply; 3+ messages in thread
From: Christian Tröster @ 2004-06-30 22:29 UTC (permalink / raw)
  To: linuxppc-embedded



Hi!

I'd like to notify a user space application if an interrupt occurs. I had no
problems to install a custom signal handler but I am not sure what's the best
way to notify the application.

My first idea was to send a signal to the application. But as far as I know
one has to know the pid to send the signal. So I'd need some mechanism to get
this pid - perhaps via a /proc entry. Is this a clean solution?

Another idea was to create a (blocking) character device and have the
application listening on that using select() or something like that. But this
seems to be a little bit bloated just for one signal. :)

Are there any other better ways I am not yet aware of. What do you think?

Bye, Christian

- --
| Mail: c dot troester at gmx dot de | PGP-Id: FA006C74 |

** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Notifying a user space application
  2004-06-30 22:29 Notifying a user space application Christian Tröster
@ 2004-07-01  6:20 ` Stefan Nickl
  2004-07-01 12:33   ` Christian Tröster
  0 siblings, 1 reply; 3+ messages in thread
From: Stefan Nickl @ 2004-07-01  6:20 UTC (permalink / raw)
  To: Christian Tröster; +Cc: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 354 bytes --]

On Thu, 2004-07-01 at 00:29, Christian Tröster wrote:
> 
> Hi!
> 
> I'd like to notify a user space application if an interrupt occurs. I
> had no
> problems to install a custom signal handler but I am not sure what's
> the best
> way to notify the application.

Mostly a stripped-down ppdev.

-- 
Stefan Nickl
Kontron Modular Computers


[-- Attachment #2: waitforint.c --]
[-- Type: text/x-c, Size: 6427 bytes --]

/*
 * This driver allows user-space programs to wait for interrupts
 */

#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioctl.h>
#include <linux/ctype.h>
#include <linux/poll.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <asm/io.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
	#include <linux/devfs_fs_kernel.h>
#else
	#include "sysdep.h"
#endif

#include "waitforint.h"

#define WFI_VERSION "WaitForInt: user-space interrupt waiting"
#define CHRDEV "waitforint"
#define DEFAULT_MAJOR	245	/* from range for local/experimental use */
#define DEFAULT_IRQ	7	/* usually used for the first printer port */

static int major = -1;
MODULE_PARM(major, "i");

/* The interrupt line is undefined by default. "wfi_irq" is as above */
static int irq = -1;
static int wfi_irq = -1;
MODULE_PARM(irq, "i");

MODULE_AUTHOR ("Stefan Nickl");

/* ugly hack, throw out as soon as 2.2 compatibility is no longer required */
#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
#define DEVFS_FL_NONE           0x000
typedef struct devfs_entry * devfs_handle_t;
static inline int devfs_register_chrdev (unsigned int major, const char *name,
                                         struct file_operations *fops)
{
    return register_chrdev (major, name, fops);
}
static inline devfs_handle_t devfs_register (devfs_handle_t dir,
                                             const char *name,
                                             unsigned int flags,
                                             unsigned int major,
                                             unsigned int minor,
                                             umode_t mode,
                                             void *ops, void *info)
{
    return NULL;
}
static inline void devfs_unregister (devfs_handle_t de)
{
    return;
}
static inline int devfs_unregister_chrdev (unsigned int major,const char *name)
{
    return unregister_chrdev (major, name);
}
#endif


struct wfi_struct {
        wait_queue_head_t irq_wait;
        atomic_t irqc;
};
/* all entries of wfi_global have to be handled atomically! */
static struct wfi_struct wfi_global;


/*
 * This is an example for the parallel port, in real life
 * the user app should do this directly after ioperm(2)
 */
static inline void wfi_enable_irq ()
{
#ifdef DEBUG_PP
	/* Initialize the control register, turning on interrupts. */
	/* outb (SP_CR_IRQ | SP_CR_SELECT | SP_CR_INIT, 0x378 + SP_CONTROL); */
	outb (0x1c, 0x37a);
#endif
}
static inline void wfi_disable_irq ()
{
#ifdef DEBUG_PP
	/* outb(0x0, 0x378 + SP_CONTROL); */  /* disable the interrupt */
	outb(0x0, 0x37a);
#endif
}
static inline void wfi_clear_irq ()
{
}

/*
 * The interrupt handler.
 */
void wfi_interrupt(int irq, void *private, struct pt_regs *regs)
{
        struct wfi_struct * wfi = (struct wfi_struct *) private;

        atomic_inc (&wfi->irqc);
        wake_up_interruptible (&wfi->irq_wait);
}


/*
 * Open the device. It is single-open.
 */
int wfi_s_count = 0;
spinlock_t wfi_s_lock;

static int wfi_open (struct inode *inode, struct file *file)
{
        file->private_data = &wfi_global;

	spin_lock(&wfi_s_lock);
	if (wfi_s_count) {
        	spin_unlock(&wfi_s_lock);
        	return -EBUSY; /* already open */
	}
	wfi_s_count++;
	spin_unlock(&wfi_s_lock);

	return 0;
}

static int wfi_release (struct inode * inode, struct file * file)
{
	wfi_s_count--; /* release the device */
        return 0;
}

static int wfi_ioctl(struct inode *inode, struct file *file,
                    unsigned int cmd, unsigned long arg)
{
        unsigned int minor = MINOR(inode->i_rdev);
        struct wfi_struct *wfi = file->private_data;

        switch (cmd) {
                int ret;

        case WFICLRIRQ:
                ret = atomic_read (&wfi->irqc);
                if (copy_to_user ((int *) arg, &ret, sizeof (ret)))
                        return -EFAULT;
                atomic_sub (ret, &wfi->irqc);
		wfi_clear_irq();
                return 0;
       default:
                printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
                        cmd);
                return -EINVAL;
        }

        /* Keep the compiler happy */
        return 0;
}

static unsigned int wfi_poll (struct file * file, poll_table * wait)
{
        struct wfi_struct *wfi = file->private_data;
        unsigned int mask = 0;

        poll_wait (file, &wfi->irq_wait, wait);
        if (atomic_read (&wfi->irqc))
                mask |= POLLIN | POLLRDNORM;

        return mask;
}

struct file_operations wfi_fops = {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        owner:          THIS_MODULE,
        llseek:         no_llseek,
#endif
        poll:           wfi_poll,
        ioctl:          wfi_ioctl,
        open:           wfi_open,
        release:        wfi_release,
};



static devfs_handle_t devfs_handle;

/*
 * Module initialization
 */

static int __init wfi_init(void)
{
	int result;

	wfi_irq = irq;

	/* If no IRQ was explicitly requested, pick a default */
	if (wfi_irq < 0)
		wfi_irq = DEFAULT_IRQ;

	if (major <= 0)
		major = DEFAULT_MAJOR;

	/* interrupt count and waiting processes are managed globally */
	atomic_set (&wfi_global.irqc, 0);
	init_waitqueue_head (&wfi_global.irq_wait);

	/* Request the IRQ */
    	result = request_irq(wfi_irq, wfi_interrupt,
				SA_INTERRUPT,"waitforint", &wfi_global);
    	if (result) {
       		printk(KERN_INFO "waitforint: can't assign irq %i\n", wfi_irq);
		wfi_irq = -1;
		return result;
	}

        /* Tell the hardware to generate interrupts */
        wfi_enable_irq ();

	/* Register character device */
	if (devfs_register_chrdev (major, CHRDEV, &wfi_fops)) {
    		printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
			major);
		return -EIO;
	}

	devfs_handle = devfs_register (NULL, CHRDEV,
				DEVFS_FL_NONE, major, 0,
                              	S_IFCHR | S_IRUGO | S_IWUGO,
                               	&wfi_fops, NULL);

	printk (KERN_INFO WFI_VERSION " for irq %d\n", wfi_irq);
	return 0;
}

/* static void __exit wfi_cleanup(void) */
static void wfi_cleanup(void)
{
	/* Return the IRQ if we have one */
	if (wfi_irq >= 0) {
		wfi_disable_irq();
		free_irq(wfi_irq, &wfi_global);
	}

	devfs_unregister_chrdev (major, CHRDEV);
	devfs_unregister (devfs_handle);
}


module_init(wfi_init);
module_exit(wfi_cleanup);

EXPORT_NO_SYMBOLS;

[-- Attachment #3: waitforint.h --]
[-- Type: text/x-c-header, Size: 124 bytes --]

#define WFI_IOCTL        'w'

/* Clear (and return) interrupt count. */
#define WFICLRIRQ        _IOR(WFI_IOCTL, 0x93, int)

[-- Attachment #4: waitforint_user.c --]
[-- Type: text/x-c, Size: 1077 bytes --]

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "waitforint.h"


int wait_for_int(int fd);
int clear_int(int fd);

int main(){
	int fd;
	int c;

	fd = open("/dev/waitforint", O_RDONLY);
	if(fd < 0){
		perror("couldn't open waitforint device");
		exit(1);
	}

	while(1){
		c = wait_for_int(fd);
		printf("got int %d\n", c);
		sleep(1);
	}

	close(fd);

	return 0;
}

int clear_int(int fd) {
        int count;

        if( ioctl(fd, WFICLRIRQ, &count) < 0){
                perror("couldn't clear interrupt count");
                exit(5);
        }

        return count;
}

int wait_for_int(int fd){
        fd_set rfds;
        int retval;

        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);

        /* wait forever for a read event on fd */
        retval = select(fd+1, &rfds, NULL, NULL, NULL);

        if(retval)
                return clear_int(fd);
        else{
                perror("error waiting for interrupt");
                exit(5);
        }
}


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Notifying a user space application
  2004-07-01  6:20 ` Stefan Nickl
@ 2004-07-01 12:33   ` Christian Tröster
  0 siblings, 0 replies; 3+ messages in thread
From: Christian Tröster @ 2004-07-01 12:33 UTC (permalink / raw)
  To: linuxppc-embedded


Hi Stefan!

Stefan Nickl schrieb:
 > On Thu, 2004-07-01 at 00:29, Christian Tröster wrote:
 >>I'd like to notify a user space application if an interrupt occurs. I
 >>had no
 >>problems to install a custom signal handler but I am not sure what's
 >>the best
 >>way to notify the application.
 > Mostly a stripped-down ppdev.
Thanks for posting your code. It works perfectly. I only had to change
one line adding an initialization value for the spin lock.

 > /*
 >  * Open the device. It is single-open.
 >  */
 > int wfi_s_count = 0;
 > spinlock_t wfi_s_lock;
spinlock_t wfi_s_lock = SPIN_LOCK_UNLOCKED;

 > static int wfi_open (struct inode *inode, struct file *file)
 > {
 >         file->private_data = &wfi_global;

Bye, Christian

--
| Mail: c dot troester at gmx dot de | PGP-Id: FA006C74 |

** Sent via the linuxppc-embedded mail list. See http://lists.linuxppc.org/

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2004-07-01 12:33 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-06-30 22:29 Notifying a user space application Christian Tröster
2004-07-01  6:20 ` Stefan Nickl
2004-07-01 12:33   ` Christian Tröster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).