diff -urN linux-2.6.6.orig/drivers/pci/proc.c linux-2.6.6.sigirq/drivers/pci/proc.c --- linux-2.6.6.orig/drivers/pci/proc.c 2004-05-10 03:32:38.000000000 +0100 +++ linux-2.6.6.sigirq/drivers/pci/proc.c 2004-06-15 04:22:25.217724016 +0100 @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -199,8 +200,43 @@ struct pci_filp_private { enum pci_mmap_state mmap_state; int write_combine; + pid_t sigpid; + int signum; + void *sigptr; }; +#ifdef HAVE_PCI_MMAP +static irqreturn_t user_irqhandler(int irq, void *p, struct pt_regs *regs) +{ + struct file *f = p; + struct inode *inode = f->f_dentry->d_inode; + struct pci_filp_private *fpriv = f->private_data; + const struct proc_dir_entry *dp = PDE(inode); + struct pci_dev *dev = dp->data; + struct task_struct *tsk; + static siginfo_t si; + + read_lock(&tasklist_lock); + + /* Serialised under tasklist_lock so can be static */ + memset(&si, 0, sizeof(si)); + si.si_signo = fpriv->signum; + si.si_code = irq; + + if ( fpriv->sigpid ) { + tsk = find_task_by_pid(fpriv->sigpid); + + if ( tsk ) + send_sig_info(fpriv->signum, &si, tsk); + else + free_irq(dev->irq, p); + } + + read_unlock(&tasklist_lock); + return IRQ_HANDLED; +} +#endif + static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { const struct proc_dir_entry *dp = PDE(inode); @@ -216,6 +252,44 @@ break; #ifdef HAVE_PCI_MMAP + case PCIIOC_SIGIRQ: { + struct pci_sigirq t; + + if (copy_from_user(&t, (void __user *)arg, sizeof(t))) + return -EFAULT; + + if ( dev->irq == 0 ) { + ret = -ESRCH; + break; + } + + /* This approach races between an IRQ happening on another + * CPU, but the race is small, and the fix pointless? + */ + if ( fpriv->signum ) { + free_irq(dev->irq, file); + fpriv->sigpid = 0; + fpriv->signum = 0; + fpriv->sigptr = NULL; + } + + if ( t.sig ) { + fpriv->sigpid = current->pid; + fpriv->signum = t.sig; + fpriv->sigptr = t.ptr; + ret = request_irq(dev->irq, + user_irqhandler, + 0, "pci", + file); + if ( ret ) { + fpriv->signum = 0; + return -EIO; + } + } + + break; + } + case PCIIOC_MMAP_IS_IO: fpriv->mmap_state = pci_mmap_io; break; @@ -271,6 +345,9 @@ fpriv->mmap_state = pci_mmap_io; fpriv->write_combine = 0; + fpriv->sigpid = 0; + fpriv->signum = 0; + fpriv->sigptr = NULL; file->private_data = fpriv; @@ -279,6 +356,12 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file) { + struct pci_filp_private *fpriv = file->private_data; + const struct proc_dir_entry *dp = PDE(inode); + struct pci_dev *dev = dp->data; + + if ( fpriv->signum ) + free_irq(dev->irq, file); kfree(file->private_data); file->private_data = NULL; diff -urN linux-2.6.6.orig/include/linux/pci.h linux-2.6.6.sigirq/include/linux/pci.h --- linux-2.6.6.orig/include/linux/pci.h 2004-05-10 03:32:29.000000000 +0100 +++ linux-2.6.6.sigirq/include/linux/pci.h 2004-06-15 04:22:32.166667616 +0100 @@ -411,6 +411,11 @@ #define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01) /* Set mmap state to I/O space. */ #define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ #define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ +#define PCIIOC_SIGIRQ (PCIIOC_BASE | 0x04) /* Send user-defined rtsignal for irqs */ +struct pci_sigirq { + int sig; + void *ptr; +}; #ifdef __KERNEL__