[RFC] IRQ sharing for PCI parport cards
Hello, currently, the parport_pc driver doesn't use IRQs automatically for PCI devices. However, why is it not possible? It's no problem to find out the corresponding IRQ, and it should also be possible to use IRQ sharing. The following patch implements this. Could somebody tell me what's wrong with that approach? _If_ it would be that simple, I'm sure that sombody would have implemented this already. At least it works here. Thanks, Bernhard --- drivers/parport/parport_cs.c |2 +- drivers/parport/parport_pc.c | 39 +-- drivers/parport/parport_serial.c |2 +- include/linux/parport_pc.h |6 +- 4 files changed, 32 insertions(+), 17 deletions(-) --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -200,7 +200,7 @@ static int parport_config(struct pcmcia_ p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, link->irq.AssignedIRQ, PARPORT_DMA_NONE, - >dev); + >dev, 0); if (p == NULL) { printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at " "0x%3x, irq %u failed\n", link->io.BasePort1, --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -274,8 +274,14 @@ static int clear_epp_timeout(struct parp static irqreturn_t parport_pc_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, (struct parport *) dev_id); - /* FIXME! Was it really ours? */ + struct parport *pb = dev_id; + + /* for shared interrupt handlers */ + if (parport_pc_read_status(pb) & (1<<2)) + return IRQ_NONE; + + parport_generic_irq(irq, pb); + return IRQ_HANDLED; } @@ -2149,7 +2155,8 @@ static DEFINE_SPINLOCK(ports_lock); struct parport *parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, - struct device *dev) + struct device *dev, + unsigned int flags) { struct parport_pc_private *priv; struct parport_operations *ops; @@ -2301,8 +2308,10 @@ struct parport *parport_pc_probe_port (u EPP_res = NULL; } if (p->irq != PARPORT_IRQ_NONE) { + unsigned int irq_flags = flags & PARPORT_PC_SHARE_IRQ + ? IRQF_SHARED : 0; if (request_irq (p->irq, parport_pc_interrupt, -0, p->name, p)) { + irq_flags, p->name, p)) { printk (KERN_WARNING "%s: irq %d in use, " "resorting to polled operation\n", p->name, p->irq); @@ -2506,7 +2515,7 @@ static int __devinit sio_ite_8872_probe */ release_resource(base_res); if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi, - irq, PARPORT_DMA_NONE, >dev)) { + irq, PARPORT_DMA_NONE, >dev, 0)) { printk (KERN_INFO "parport_pc: ITE 8872 parallel port: io=0x%X", ite8872_lpt); @@ -2689,7 +2698,7 @@ static int __devinit sio_via_probe (stru } /* finally, do the probe with values obtained */ - if (parport_pc_probe_port (port1, port2, irq, dma, >dev)) { + if (parport_pc_probe_port (port1, port2, irq, dma, >dev, 0)) { printk (KERN_INFO "parport_pc: VIA parallel port: io=0x%X", port1); if (irq != PARPORT_IRQ_NONE) @@ -2980,14 +2989,16 @@ static int parport_pc_pci_probe (struct io_lo += hi; /* Reinterpret the meaning of "hi" as an offset (see SYBA def.) */ - /* TODO: test if sharing interrupts works */ printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " "I/O at %#lx(%#lx)\n", parport_pc_pci_tbl[i + last_sio].vendor, parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi); + /* according to PCI spec, IRQ sharing must be supported */ data->ports[count] = - parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, >dev); + parport_pc_probe_port (io_lo, io_hi, dev->irq, + PARPORT_DMA_NONE, + >dev, + PARPORT_PC_SHARE_IRQ); if (data->ports[count]) count++; } @@ -3095,7 +3106,7 @@ static int
[RFC] IRQ sharing for PCI parport cards
Hello, currently, the parport_pc driver doesn't use IRQs automatically for PCI devices. However, why is it not possible? It's no problem to find out the corresponding IRQ, and it should also be possible to use IRQ sharing. The following patch implements this. Could somebody tell me what's wrong with that approach? _If_ it would be that simple, I'm sure that sombody would have implemented this already. At least it works here. Thanks, Bernhard --- drivers/parport/parport_cs.c |2 +- drivers/parport/parport_pc.c | 39 +-- drivers/parport/parport_serial.c |2 +- include/linux/parport_pc.h |6 +- 4 files changed, 32 insertions(+), 17 deletions(-) --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c @@ -200,7 +200,7 @@ static int parport_config(struct pcmcia_ p = parport_pc_probe_port(link-io.BasePort1, link-io.BasePort2, link-irq.AssignedIRQ, PARPORT_DMA_NONE, - link-dev); + link-dev, 0); if (p == NULL) { printk(KERN_NOTICE parport_cs: parport_pc_probe_port() at 0x%3x, irq %u failed\n, link-io.BasePort1, --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -274,8 +274,14 @@ static int clear_epp_timeout(struct parp static irqreturn_t parport_pc_interrupt(int irq, void *dev_id) { - parport_generic_irq(irq, (struct parport *) dev_id); - /* FIXME! Was it really ours? */ + struct parport *pb = dev_id; + + /* for shared interrupt handlers */ + if (parport_pc_read_status(pb) (12)) + return IRQ_NONE; + + parport_generic_irq(irq, pb); + return IRQ_HANDLED; } @@ -2149,7 +2155,8 @@ static DEFINE_SPINLOCK(ports_lock); struct parport *parport_pc_probe_port (unsigned long int base, unsigned long int base_hi, int irq, int dma, - struct device *dev) + struct device *dev, + unsigned int flags) { struct parport_pc_private *priv; struct parport_operations *ops; @@ -2301,8 +2308,10 @@ struct parport *parport_pc_probe_port (u EPP_res = NULL; } if (p-irq != PARPORT_IRQ_NONE) { + unsigned int irq_flags = flags PARPORT_PC_SHARE_IRQ + ? IRQF_SHARED : 0; if (request_irq (p-irq, parport_pc_interrupt, -0, p-name, p)) { + irq_flags, p-name, p)) { printk (KERN_WARNING %s: irq %d in use, resorting to polled operation\n, p-name, p-irq); @@ -2506,7 +2515,7 @@ static int __devinit sio_ite_8872_probe */ release_resource(base_res); if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi, - irq, PARPORT_DMA_NONE, pdev-dev)) { + irq, PARPORT_DMA_NONE, pdev-dev, 0)) { printk (KERN_INFO parport_pc: ITE 8872 parallel port: io=0x%X, ite8872_lpt); @@ -2689,7 +2698,7 @@ static int __devinit sio_via_probe (stru } /* finally, do the probe with values obtained */ - if (parport_pc_probe_port (port1, port2, irq, dma, pdev-dev)) { + if (parport_pc_probe_port (port1, port2, irq, dma, pdev-dev, 0)) { printk (KERN_INFO parport_pc: VIA parallel port: io=0x%X, port1); if (irq != PARPORT_IRQ_NONE) @@ -2980,14 +2989,16 @@ static int parport_pc_pci_probe (struct io_lo += hi; /* Reinterpret the meaning of hi as an offset (see SYBA def.) */ - /* TODO: test if sharing interrupts works */ printk (KERN_DEBUG PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx)\n, parport_pc_pci_tbl[i + last_sio].vendor, parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi); + /* according to PCI spec, IRQ sharing must be supported */ data-ports[count] = - parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, - PARPORT_DMA_NONE, dev-dev); + parport_pc_probe_port (io_lo, io_hi, dev-irq, + PARPORT_DMA_NONE, + dev-dev, + PARPORT_PC_SHARE_IRQ); if (data-ports[count]) count++; } @@ -3095,7 +3106,7 @@ static int