lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Sat, 22 Sep 2007 23:32:53 +0200
From:	Bernhard Walle <bernhard.walle@....de>
To:	linux-parport@...ts.infradead.org
Cc:	linux-kernel@...r.kernel.org
Subject: [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) & (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, &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 parport_pc_pnp_probe(struct p
 		dma = PARPORT_DMA_NONE;
 
 	dev_info(&dev->dev, "reported by %s\n", dev->protocol->name);
-	if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, &dev->dev)))
+	if (!(pdata = parport_pc_probe_port (io_lo, io_hi, irq, dma, &dev->dev, 0)))
 		return -ENODEV;
 
 	pnp_set_drvdata(dev,pdata);
@@ -3141,11 +3152,11 @@ parport_pc_find_isa_ports (int autoirq, 
 {
 	int count = 0;
 
-	if (parport_pc_probe_port(0x3bc, 0x7bc, autoirq, autodma, NULL))
+	if (parport_pc_probe_port(0x3bc, 0x7bc, autoirq, autodma, NULL, 0))
 		count++;
-	if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL))
+	if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL, 0))
 		count++;
-	if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL))
+	if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL, 0))
 		count++;
 
 	return count;
@@ -3429,7 +3440,7 @@ static int __init parport_pc_init(void)
 			if ((io_hi[i]) == PARPORT_IOHI_AUTO)
 			       io_hi[i] = 0x400 + io[i];
 			parport_pc_probe_port(io[i], io_hi[i],
-						  irqval[i], dmaval[i], NULL);
+						  irqval[i], dmaval[i], NULL, 0);
 		}
 	} else
 		parport_pc_find_ports (irqval[0], dmaval[0]);
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -305,7 +305,7 @@ static int __devinit parport_register (s
 		dev_dbg(&dev->dev, "PCI parallel port detected: I/O at "
 			"%#lx(%#lx)\n", io_lo, io_hi);
 		port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
-					      PARPORT_DMA_NONE, &dev->dev);
+					      PARPORT_DMA_NONE, &dev->dev, 0);
 		if (port) {
 			priv->port[priv->num_par++] = port;
 			success = 1;
--- a/include/linux/parport_pc.h
+++ b/include/linux/parport_pc.h
@@ -227,11 +227,15 @@ extern void parport_pc_release_resources
 
 extern int parport_pc_claim_resources(struct parport *p);
 
+/* flags for parport_pc_probe_port */
+#define PARPORT_PC_SHARE_IRQ		(1<<0)
+
 /* PCMCIA code will want to get us to look at a port.  Provide a mechanism. */
 extern struct parport *parport_pc_probe_port (unsigned long base,
 					      unsigned long base_hi,
 					      int irq, int dma,
-					      struct device *dev);
+					      struct device *dev,
+					      unsigned int flags);
 extern void parport_pc_unregister_port (struct parport *p);
 
 #endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ