forked from mirrors/linux
		
	parport: Use the PCI IRQ if offered
PCI parallel port devices can IRQ share so we should stop them hogging the line and making a mess on modern PC systems. We know the sharing side works as the PCMCIA driver has shared the parallel port IRQ for some time. Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									8e7d91c975
								
							
						
					
					
						commit
						51dcdfec6a
					
				
					 4 changed files with 60 additions and 31 deletions
				
			
		|  | @ -43,6 +43,7 @@ | ||||||
| #include <linux/timer.h> | #include <linux/timer.h> | ||||||
| #include <linux/ioport.h> | #include <linux/ioport.h> | ||||||
| #include <linux/major.h> | #include <linux/major.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
| 
 | 
 | ||||||
| #include <linux/parport.h> | #include <linux/parport.h> | ||||||
| #include <linux/parport_pc.h> | #include <linux/parport_pc.h> | ||||||
|  | @ -192,7 +193,7 @@ static int parport_config(struct pcmcia_device *link) | ||||||
| 
 | 
 | ||||||
|     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, |     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2, | ||||||
| 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE, | 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE, | ||||||
| 			      &link->dev); | 			      &link->dev, IRQF_SHARED); | ||||||
|     if (p == NULL) { |     if (p == NULL) { | ||||||
| 	printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at " | 	printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at " | ||||||
| 	       "0x%3x, irq %u failed\n", link->io.BasePort1, | 	       "0x%3x, irq %u failed\n", link->io.BasePort1, | ||||||
|  |  | ||||||
|  | @ -2170,10 +2170,11 @@ static int parport_dma_probe (struct parport *p) | ||||||
| static LIST_HEAD(ports_list); | static LIST_HEAD(ports_list); | ||||||
| static DEFINE_SPINLOCK(ports_lock); | static DEFINE_SPINLOCK(ports_lock); | ||||||
| 
 | 
 | ||||||
| struct parport *parport_pc_probe_port (unsigned long int base, | struct parport *parport_pc_probe_port(unsigned long int base, | ||||||
| 				       unsigned long int base_hi, | 				      unsigned long int base_hi, | ||||||
| 				       int irq, int dma, | 				      int irq, int dma, | ||||||
| 				       struct device *dev) | 				      struct device *dev, | ||||||
|  | 				      int irqflags) | ||||||
| { | { | ||||||
| 	struct parport_pc_private *priv; | 	struct parport_pc_private *priv; | ||||||
| 	struct parport_operations *ops; | 	struct parport_operations *ops; | ||||||
|  | @ -2194,11 +2195,11 @@ struct parport *parport_pc_probe_port (unsigned long int base, | ||||||
| 		dev = &pdev->dev; | 		dev = &pdev->dev; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ops = kmalloc(sizeof (struct parport_operations), GFP_KERNEL); | 	ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); | ||||||
| 	if (!ops) | 	if (!ops) | ||||||
| 		goto out1; | 		goto out1; | ||||||
| 
 | 
 | ||||||
| 	priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL); | 	priv = kmalloc(sizeof(struct parport_pc_private), GFP_KERNEL); | ||||||
| 	if (!priv) | 	if (!priv) | ||||||
| 		goto out2; | 		goto out2; | ||||||
| 
 | 
 | ||||||
|  | @ -2325,8 +2326,8 @@ struct parport *parport_pc_probe_port (unsigned long int base, | ||||||
| 		EPP_res = NULL; | 		EPP_res = NULL; | ||||||
| 	} | 	} | ||||||
| 	if (p->irq != PARPORT_IRQ_NONE) { | 	if (p->irq != PARPORT_IRQ_NONE) { | ||||||
| 		if (request_irq (p->irq, parport_irq_handler, | 		if (request_irq(p->irq, parport_irq_handler, | ||||||
| 				 0, p->name, p)) { | 				 irqflags, p->name, p)) { | ||||||
| 			printk (KERN_WARNING "%s: irq %d in use, " | 			printk (KERN_WARNING "%s: irq %d in use, " | ||||||
| 				"resorting to polled operation\n", | 				"resorting to polled operation\n", | ||||||
| 				p->name, p->irq); | 				p->name, p->irq); | ||||||
|  | @ -2530,7 +2531,7 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, | ||||||
| 	 */ | 	 */ | ||||||
| 	release_resource(base_res); | 	release_resource(base_res); | ||||||
| 	if (parport_pc_probe_port (ite8872_lpt, ite8872_lpthi, | 	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 | 		printk (KERN_INFO | ||||||
| 			"parport_pc: ITE 8872 parallel port: io=0x%X", | 			"parport_pc: ITE 8872 parallel port: io=0x%X", | ||||||
| 			ite8872_lpt); | 			ite8872_lpt); | ||||||
|  | @ -2713,7 +2714,7 @@ static int __devinit sio_via_probe (struct pci_dev *pdev, int autoirq, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* finally, do the probe with values obtained */ | 	/* 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 | 		printk (KERN_INFO | ||||||
| 			"parport_pc: VIA parallel port: io=0x%X", port1); | 			"parport_pc: VIA parallel port: io=0x%X", port1); | ||||||
| 		if (irq != PARPORT_IRQ_NONE) | 		if (irq != PARPORT_IRQ_NONE) | ||||||
|  | @ -3018,6 +3019,7 @@ static int parport_pc_pci_probe (struct pci_dev *dev, | ||||||
| 	for (n = 0; n < cards[i].numports; n++) { | 	for (n = 0; n < cards[i].numports; n++) { | ||||||
| 		int lo = cards[i].addr[n].lo; | 		int lo = cards[i].addr[n].lo; | ||||||
| 		int hi = cards[i].addr[n].hi; | 		int hi = cards[i].addr[n].hi; | ||||||
|  | 		int irq; | ||||||
| 		unsigned long io_lo, io_hi; | 		unsigned long io_lo, io_hi; | ||||||
| 		io_lo = pci_resource_start (dev, lo); | 		io_lo = pci_resource_start (dev, lo); | ||||||
| 		io_hi = 0; | 		io_hi = 0; | ||||||
|  | @ -3028,13 +3030,25 @@ static int parport_pc_pci_probe (struct pci_dev *dev, | ||||||
|                                         "hi" as an offset (see SYBA |                                         "hi" as an offset (see SYBA | ||||||
|                                         def.) */ |                                         def.) */ | ||||||
| 		/* TODO: test if sharing interrupts works */ | 		/* TODO: test if sharing interrupts works */ | ||||||
| 		printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, " | 		irq = dev->irq; | ||||||
| 			"I/O at %#lx(%#lx)\n", | 		if (irq == IRQ_NONE) { | ||||||
| 			parport_pc_pci_tbl[i + last_sio].vendor, | 			printk (KERN_DEBUG | ||||||
| 			parport_pc_pci_tbl[i + last_sio].device, io_lo, io_hi); | 	"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); | ||||||
|  | 			irq = PARPORT_IRQ_NONE; | ||||||
|  | 		} else { | ||||||
|  | 			printk (KERN_DEBUG | ||||||
|  | 	"PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx), IRQ %d\n", | ||||||
|  | 				parport_pc_pci_tbl[i + last_sio].vendor, | ||||||
|  | 				parport_pc_pci_tbl[i + last_sio].device, | ||||||
|  | 				io_lo, io_hi, irq); | ||||||
|  | 		} | ||||||
| 		data->ports[count] = | 		data->ports[count] = | ||||||
| 			parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, | 			parport_pc_probe_port(io_lo, io_hi, irq, | ||||||
| 					       PARPORT_DMA_NONE, &dev->dev); | 					       PARPORT_DMA_NONE, &dev->dev, | ||||||
|  | 					       IRQF_SHARED); | ||||||
| 		if (data->ports[count]) | 		if (data->ports[count]) | ||||||
| 			count++; | 			count++; | ||||||
| 	} | 	} | ||||||
|  | @ -3143,7 +3157,8 @@ static int parport_pc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id | ||||||
| 		dma = PARPORT_DMA_NONE; | 		dma = PARPORT_DMA_NONE; | ||||||
| 
 | 
 | ||||||
| 	dev_info(&dev->dev, "reported by %s\n", dev->protocol->name); | 	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; | 		return -ENODEV; | ||||||
| 
 | 
 | ||||||
| 	pnp_set_drvdata(dev,pdata); | 	pnp_set_drvdata(dev,pdata); | ||||||
|  | @ -3192,11 +3207,11 @@ parport_pc_find_isa_ports (int autoirq, int autodma) | ||||||
| { | { | ||||||
| 	int count = 0; | 	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++; | 		count++; | ||||||
| 	if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL)) | 	if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL, 0)) | ||||||
| 		count++; | 		count++; | ||||||
| 	if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL)) | 	if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL, 0)) | ||||||
| 		count++; | 		count++; | ||||||
| 
 | 
 | ||||||
| 	return count; | 	return count; | ||||||
|  | @ -3481,7 +3496,7 @@ static int __init parport_pc_init(void) | ||||||
| 			if ((io_hi[i]) == PARPORT_IOHI_AUTO) | 			if ((io_hi[i]) == PARPORT_IOHI_AUTO) | ||||||
| 			       io_hi[i] = 0x400 + io[i]; | 			       io_hi[i] = 0x400 + io[i]; | ||||||
| 			parport_pc_probe_port(io[i], io_hi[i], | 			parport_pc_probe_port(io[i], io_hi[i], | ||||||
| 						  irqval[i], dmaval[i], NULL); | 					  irqval[i], dmaval[i], NULL, 0); | ||||||
| 		} | 		} | ||||||
| 	} else | 	} else | ||||||
| 		parport_pc_find_ports (irqval[0], dmaval[0]); | 		parport_pc_find_ports (irqval[0], dmaval[0]); | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/pci.h> | #include <linux/pci.h> | ||||||
|  | #include <linux/interrupt.h> | ||||||
| #include <linux/parport.h> | #include <linux/parport.h> | ||||||
| #include <linux/parport_pc.h> | #include <linux/parport_pc.h> | ||||||
| #include <linux/8250_pci.h> | #include <linux/8250_pci.h> | ||||||
|  | @ -311,6 +312,7 @@ static int __devinit parport_register (struct pci_dev *dev, | ||||||
| 		int lo = card->addr[n].lo; | 		int lo = card->addr[n].lo; | ||||||
| 		int hi = card->addr[n].hi; | 		int hi = card->addr[n].hi; | ||||||
| 		unsigned long io_lo, io_hi; | 		unsigned long io_lo, io_hi; | ||||||
|  | 		int irq; | ||||||
| 
 | 
 | ||||||
| 		if (priv->num_par == ARRAY_SIZE (priv->port)) { | 		if (priv->num_par == ARRAY_SIZE (priv->port)) { | ||||||
| 			printk (KERN_WARNING | 			printk (KERN_WARNING | ||||||
|  | @ -329,10 +331,20 @@ static int __devinit parport_register (struct pci_dev *dev, | ||||||
|                                         "hi" as an offset (see SYBA |                                         "hi" as an offset (see SYBA | ||||||
|                                         def.) */ |                                         def.) */ | ||||||
| 		/* TODO: test if sharing interrupts works */ | 		/* TODO: test if sharing interrupts works */ | ||||||
| 		dev_dbg(&dev->dev, "PCI parallel port detected: I/O at " | 		irq = dev->irq; | ||||||
| 			"%#lx(%#lx)\n", io_lo, io_hi); | 		if (irq == IRQ_NONE) { | ||||||
| 		port = parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE, | 			dev_dbg(&dev->dev, | ||||||
| 					      PARPORT_DMA_NONE, &dev->dev); | 			"PCI parallel port detected: I/O at %#lx(%#lx)\n", | ||||||
|  | 				io_lo, io_hi); | ||||||
|  | 			irq = PARPORT_IRQ_NONE; | ||||||
|  | 		} else { | ||||||
|  | 			dev_dbg(&dev->dev, | ||||||
|  | 		"PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n", | ||||||
|  | 				io_lo, io_hi, irq); | ||||||
|  | 			irq = PARPORT_IRQ_NONE; | ||||||
|  | 		} | ||||||
|  | 		port = parport_pc_probe_port (io_lo, io_hi, irq, | ||||||
|  | 			      PARPORT_DMA_NONE, &dev->dev, IRQF_SHARED); | ||||||
| 		if (port) { | 		if (port) { | ||||||
| 			priv->port[priv->num_par++] = port; | 			priv->port[priv->num_par++] = port; | ||||||
| 			success = 1; | 			success = 1; | ||||||
|  |  | ||||||
|  | @ -228,10 +228,11 @@ extern void parport_pc_release_resources(struct parport *p); | ||||||
| extern int parport_pc_claim_resources(struct parport *p); | extern int parport_pc_claim_resources(struct parport *p); | ||||||
| 
 | 
 | ||||||
| /* PCMCIA code will want to get us to look at a port.  Provide a mechanism. */ | /* 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, | extern struct parport *parport_pc_probe_port(unsigned long base, | ||||||
| 					      unsigned long base_hi, | 					     unsigned long base_hi, | ||||||
| 					      int irq, int dma, | 					     int irq, int dma, | ||||||
| 					      struct device *dev); | 					     struct device *dev, | ||||||
| extern void parport_pc_unregister_port (struct parport *p); | 					     int irqflags); | ||||||
|  | extern void parport_pc_unregister_port(struct parport *p); | ||||||
| 
 | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Alan Cox
						Alan Cox