* 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).