[Linux-parport] [patch] PCI IRQ lockup solved

vdb128 at picaros.org vdb128 at picaros.org
Mon Mar 1 01:35:33 GMT 2004


Dear parport maintainers,

This patch solves PCI lockups if the IRQ is in use by another driver.

  Note that the parport_EPP_sup test must disable IRQs.  Otherwise the 
  already installed handler is called at initialization ... for ever 
  ... until reboot.

It also allows for PCI interrupt use, specify irq=auto, detects a level 
coupled INTX# and disables interrupts if necessary.

Below are the debug messages of two systems, both with a motherboard IO 
controller and a PCI card.  Differences are accounted for in the interrupt 
handler via the  our  integer:

  our &   1 : we are the only interrupt source
  our &   2 : awaiting int and DSR nINT active -> signal good chipset
  our &   4 : awaiting int and not a good chipset -> take it (... false_alarm)
  our &   8 : nINT still active after reset, ints were disabled
  our &0x10 : ECP ecr int expected and found, unassert PCI INTX#, as in line 
              with ECP register specifications.

Also, the patch below allows to initialize selected PCI devices by specifying 
their bus/slot/function address, via 'io=-1 io_hi=0x<bus><slot><function>'.

Furthermore, the EPP Intel test is skipped except for a base address of 
0x378, 0x278 or 0x3bc.  This seems reasonable since most (all ?) onboard 
chipsets are only configurable at those addresses, and since Intel has not 
manufacturerd any stand-alone PCI controller AFAIK.

Servaas Vandenberghe

*********************************** stargate ******************************
asus p4b533 super IO controller : int at rising ACK#, but nINT==1
vscom Oxford Semi ox12pci840 1415:8403 : int at rising ACK#, full nINT support

stargate:~# modprobe cmpci

cmpci: version $Revision: 6.16 $ time 18:31:07 Feb 23 2004
PCI: Found IRQ 5 for device 02:03.0
cmpci: found CM8738 adapter at io 0xb800 irq 5
cmpci: chip version = 055

stargate:~# modprobe parport_pc verbose_probing=1

parport_ECR_present(@3bc): ok=-1
parport_SPP_supported(@3bc): dsr=0xff ok=0
frob_econtrol(@378,ff,34): 35 -> 34
frob_econtrol(@378,e0,00): 35 -> 15
parport_ECR_present(@378): ok=1
parport_SPP_supported(@378): dsr=0xde ok=1
frob_econtrol(parport0,ff,94): 15 -> 94
frob_econtrol(parport0,e0,00): 95 -> 15
frob_econtrol(parport0,ff,15): 15 -> 15
parport_EPP_supported(parport0): Intel bug ? result=-10
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,15): 35 -> 15
parport_PS2_supported(parport0): ok=2
frob_econtrol(parport0,ff,e0): 15 -> e0
frob_econtrol(parport0,ff,15): e5 -> 15
programmable_irq_support(parport0): irq=-1
frob_econtrol(parport0,ff,00): 15 -> 00
frob_econtrol(parport0,ff,c4): 05 -> c4
frob_econtrol(parport0,ff,c0): c5 -> c0
frob_econtrol(parport0,ff,14): c6 -> 14
irq_probe_ECP(parport0): irq=7 irqs=0xffff24c8 fifo=16
parport0: irq 7 detected
parport0: irq=7/-1 dsr=0xde/0xde ecr=0x15 our=0x00 0
parport0: PC-style at 0x378 (0x778), irqshare 7 [PCSPP,TRISTATE]
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,34): 35 -> 34
parport0: Printer, Hewlett-Packard OfficeJet  K80

parport_ECR_present(@278): ok=-1
parport_SPP_supported(@278): dsr=0xff ok=0
PCI: Found IRQ 5 for device 02:0c.0
parport_pc_pci_probe: PCI parallel port 1415:8403, I/O at 0xa800(0xa400)
frob_econtrol(@a800,ff,34): 35 -> 34
frob_econtrol(@a800,e0,00): 35 -> 15
parport_ECR_present(@a800): ok=1
parport_SPP_supported(@a800): dsr=0xdf ok=1
frob_econtrol(parport1,ff,94): 15 -> 94
frob_econtrol(parport1,ff,15): 95 -> 15
parport_EPP_supported(parport1): result=1
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,15): 35 -> 15
parport_PS2_supported(parport1): ok=2
parport1: PC-style at 0xa800 (0xa400), irqshare 5 [PCSPP,TRISTATE,EPP]
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,34): 35 -> 34
parport1: Printer, Hewlett-Packard HP LaserJet 6MP

stargate:~# echo -n abc >/dev/lp0

lp0: using parport0 (polling).
lp1: using parport1 (polling).
frob_econtrol(parport0,ff,34): 35 -> 34
frob_econtrol(parport0,ff,35): 35 -> 35

stargate:~# echo -n abc >/dev/lp1

frob_econtrol(parport1,ff,34): 35 -> 34
frob_econtrol(parport1,ff,35): 35 -> 35

stargate:~# echo -n z >/dev/dsp0

parport1: irq=5/-1 dsr=0xdf/0xdf ecr=0x35 our=0x00 1


stargate:~# rmmod parport_pc && modprobe parport_pc verbose_probing=1 irq=auto

rport_ECR_present(@3bc): ok=-1
parport_SPP_supported(@3bc): dsr=0xff ok=0
frob_econtrol(@378,ff,34): 35 -> 34
frob_econtrol(@378,e0,00): 35 -> 15
parport_ECR_present(@378): ok=1
parport_SPP_supported(@378): dsr=0xde ok=1
frob_econtrol(parport0,ff,94): 15 -> 94
frob_econtrol(parport0,e0,00): 95 -> 15
frob_econtrol(parport0,ff,15): 15 -> 15
parport_EPP_supported(parport0): Intel bug ? result=-10
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,15): 35 -> 15
parport_PS2_supported(parport0): ok=2
frob_econtrol(parport0,ff,e0): 15 -> e0
frob_econtrol(parport0,ff,15): e5 -> 15
programmable_irq_support(parport0): irq=-1
frob_econtrol(parport0,ff,00): 15 -> 00
frob_econtrol(parport0,ff,c4): 05 -> c4
frob_econtrol(parport0,ff,c0): c5 -> c0
frob_econtrol(parport0,ff,14): c6 -> 14
irq_probe_ECP(parport0): irq=7 irqs=0xffff24c8 fifo=16
parport0: irq=7/7 dsr=0xde/0xde ecr=0x15 our=0x00 0
parport0: PC-style at 0x378 (0x778), irq 7, irqshare 7 [PCSPP,TRISTATE]
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,34): 35 -> 34
parport0: Printer, Hewlett-Packard OfficeJet  K80

parport_ECR_present(@278): ok=-1
parport_SPP_supported(@278): dsr=0xff ok=0
PCI: Found IRQ 5 for device 02:0c.0
parport_pc_pci_probe: PCI parallel port 1415:8403, I/O at 0xa800(0xa400)
frob_econtrol(@a800,ff,34): 35 -> 34
frob_econtrol(@a800,e0,00): 35 -> 15
parport_ECR_present(@a800): ok=1
parport_SPP_supported(@a800): dsr=0xdf ok=1
frob_econtrol(parport1,ff,94): 15 -> 94
frob_econtrol(parport1,ff,15): 95 -> 15
parport_EPP_supported(parport1): result=1
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,15): 35 -> 15
parport_PS2_supported(parport1): ok=2
parport1: PC-style at 0xa800 (0xa400), irq 5, irqshare 5 [PCSPP,TRISTATE,EPP]
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,34): 35 -> 34
parport1: Printer, Hewlett-Packard HP LaserJet 6MP

stargate:~# echo -n abc >/dev/lp1

lp0: using parport0 (interrupt-driven).
lp1: using parport1 (interrupt-driven).
frob_econtrol(parport1,ff,34): 35 -> 34
frob_econtrol(parport1,ff,35): 35 -> 35
parport1: irq=5/5 dsr=0xdb/0xdf nINT-OK our=0x02
parport1: irq=5/5 dsr=0xdb/0xdf ecr=0x35 our=0x02 1
parport1: irq=5/5 dsr=0xdb/0xdf ecr=0x35 our=0x02 2
parport1: irq=5/5 dsr=0xdb/0xdf ecr=0x35 our=0x02 3
parport1: irq=5/5 dsr=0xdb/0xdf ecr=0x35 our=0x02 4

stargate:~# echo -n z >/dev/dsp0

parport1: irq=5/5 dsr=0xdf/0xdf ecr=0x35 our=0x00 5

stargate:~# echo -n abc >/dev/lp0

frob_econtrol(parport0,ff,34): 35 -> 34
frob_econtrol(parport0,ff,35): 35 -> 35
parport0: irq=7/7 dsr=0xde/0xde ecr=0x35 our=0x04 6
parport0: irq=7/7 dsr=0xde/0xde ecr=0x35 our=0x04 7
parport0: irq=7/7 dsr=0xde/0xde ecr=0x35 our=0x04 8


02:0c.0 Class 0701: 1415:8403 (prog-if 03)
        Parallel controller: Oxford Semiconductor Ltd VScom 011H-EP1 1 port parallel adaptor (prog-if 03 [IEEE1284])
        Subsystem: 1415:0000
        Subsystem: Oxford Semiconductor Ltd: Unknown device 0000
        Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
        Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort
- <MAbort- >SERR- <PERR-
        Interrupt: pin A routed to IRQ 5
        Region 0: I/O ports at a800 [size=8]
        Region 1: I/O ports at a400 [size=4]
        Region 2: I/O ports at a000 [size=32]
        Region 3: Memory at f2800000 (32-bit, non-prefetchable) [size=4K]
        Capabilities: [40] Power Management version 1
          Flags: PMEClk- DSI- D1- D2+ AuxCurrent=0mA PME(D0+,D1-,D2+,D3hot+,D3cold-)
          Status: D0 PME-Enable- DSel=0 DScale=0 PME-

*********************************** reddwarf ******************************
National PC87306B  : int at rising ACK#, but nINT==1
Netmos   9710:9815 : INTX#==ACK#, nINT reset impossible if ACK#==0

reddwarf:~# modprobe parport_pc verbose_probing=1

parport_ECR_present(@3bc): ok=-1
parport_SPP_supported(@3bc): dsr=0xff ok=0
frob_econtrol(@378,ff,34): 35 -> 34
frob_econtrol(@378,e0,00): 35 -> 15
parport_ECR_present(@378): ok=1
parport_SPP_supported(@378): dsr=0xdf ok=1
frob_econtrol(parport0,ff,94): 15 -> 94
frob_econtrol(parport0,ff,15): 95 -> 15
parport_EPP_supported(parport0): result=-1
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,15): 35 -> 15
parport_PS2_supported(parport0): ok=2
frob_econtrol(parport0,ff,e0): 15 -> e0
frob_econtrol(parport0,ff,15): e1 -> 15
programmable_irq_support(parport0): irq=7
parport0: irq 7 detected
parport0: PC-style at 0x378 (0x778), irqshare 7 [PCSPP,TRISTATE]
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,34): 35 -> 34
frob_econtrol(parport0,ff,34): 35 -> 34

parport_ECR_present(@278): ok=-1
parport_SPP_supported(@278): dsr=0xff ok=0
parport_pc_pci_probe: PCI parallel port 9710:9815, I/O at 0xfff0(0xffe0)
frob_econtrol(@fff0,ff,34): 35 -> 34
frob_econtrol(@fff0,e0,00): 35 -> 15
parport_ECR_present(@fff0): ok=1
parport_SPP_supported(@fff0): dsr=0x78 ok=1
frob_econtrol(parport1,ff,94): 15 -> 94
frob_econtrol(parport1,ff,15): 95 -> 15
parport_EPP_supported(parport1): result=1
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,15): 35 -> 15
parport_PS2_supported(parport1): ok=2
parport1: PC-style at 0xfff0 (0xffe0), irqshare 10 [PCSPP,TRISTATE,EPP]
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,34): 35 -> 34
frob_econtrol(parport1,ff,34): 35 -> 34

parport_pc_pci_probe: PCI parallel port 9710:9815, I/O at 0xffa8(0xffa0)
frob_econtrol(@ffa8,ff,34): 35 -> 34
frob_econtrol(@ffa8,e0,00): 35 -> 15
parport_ECR_present(@ffa8): ok=1
parport_SPP_supported(@ffa8): dsr=0x78 ok=1
frob_econtrol(parport2,ff,94): 15 -> 94
frob_econtrol(parport2,ff,15): 95 -> 15
parport_EPP_supported(parport2): result=1
parport2: PC-style at 0xffa8 (0xffa0), irqshare 10 [PCSPP,TRISTATE,EPP]
frob_econtrol(parport2,ff,34): 15 -> 34
frob_econtrol(parport2,ff,34): 35 -> 34
frob_econtrol(parport2,ff,34): 35 -> 34

reddwarf:~# echo -n abc >/dev/lp0

lp0: using parport0 (polling).
lp1: using parport1 (polling).
lp2: using parport2 (polling).
frob_econtrol(parport0,ff,34): 35 -> 34
frob_econtrol(parport0,ff,35): 35 -> 35


reddwarf:~# rmmod parport_pc && modprobe parport_pc verbose_probing=1 irq=auto

parport_ECR_present(@3bc): ok=-1
parport_SPP_supported(@3bc): dsr=0xff ok=0
frob_econtrol(@378,ff,34): 35 -> 34
frob_econtrol(@378,e0,00): 35 -> 15
parport_ECR_present(@378): ok=1
parport_SPP_supported(@378): dsr=0xdf ok=1
frob_econtrol(parport0,ff,94): 15 -> 94
frob_econtrol(parport0,ff,15): 95 -> 15
parport_EPP_supported(parport0): result=-1
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,15): 35 -> 15
parport_PS2_supported(parport0): ok=2
frob_econtrol(parport0,ff,e0): 15 -> e0
frob_econtrol(parport0,ff,15): e1 -> 15
programmable_irq_support(parport0): irq=7
parport0: PC-style at 0x378 (0x778), irq 7, irqshare 7 [PCSPP,TRISTATE]
frob_econtrol(parport0,ff,34): 15 -> 34
frob_econtrol(parport0,ff,34): 35 -> 34
frob_econtrol(parport0,ff,34): 35 -> 34

parport_ECR_present(@278): ok=-1
parport_SPP_supported(@278): dsr=0xff ok=0
parport_pc_pci_probe: PCI parallel port 9710:9815, I/O at 0xfff0(0xffe0)
frob_econtrol(@fff0,ff,34): 35 -> 34
frob_econtrol(@fff0,e0,00): 35 -> 15
parport_ECR_present(@fff0): ok=1
parport_SPP_supported(@fff0): dsr=0x78 ok=1
frob_econtrol(parport1,ff,94): 15 -> 94
frob_econtrol(parport1,ff,15): 95 -> 15
parport_EPP_supported(parport1): result=1
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,15): 35 -> 15
parport_PS2_supported(parport1): ok=2
parport1: PC-style at 0xfff0 (0xffe0), irq 10, irqshare 10 [PCSPP,TRISTATE,EPP]
frob_econtrol(parport1,ff,34): 15 -> 34
frob_econtrol(parport1,ff,34): 35 -> 34
frob_econtrol(parport1,ff,34): 35 -> 34

parport_pc_pci_probe: PCI parallel port 9710:9815, I/O at 0xffa8(0xffa0)
frob_econtrol(@ffa8,ff,34): 35 -> 34
frob_econtrol(@ffa8,e0,00): 35 -> 15
parport_ECR_present(@ffa8): ok=1
parport_SPP_supported(@ffa8): dsr=0x78 ok=1
frob_econtrol(parport2,ff,94): 15 -> 94
frob_econtrol(parport2,ff,15): 95 -> 15
parport_EPP_supported(parport2): result=1
frob_econtrol(parport2,ff,34): 15 -> 34
frob_econtrol(parport2,ff,15): 35 -> 15
parport_PS2_supported(parport2): ok=2
parport2: PC-style at 0xffa8 (0xffa0), irq 10, irqshare 10 [PCSPP,TRISTATE,EPP]
frob_econtrol(parport2,ff,34): 15 -> 34
frob_econtrol(parport2,ff,34): 35 -> 34
frob_econtrol(parport2,ff,34): 35 -> 34

reddwarf:~# echo -n abc >/dev/lp0

lp0: using parport0 (interrupt-driven).
lp1: using parport1 (interrupt-driven).
lp2: using parport2 (interrupt-driven).
frob_econtrol(parport0,ff,34): 35 -> 34
frob_econtrol(parport0,ff,35): 35 -> 35
parport0: irq=7/7 dsr=0xdf/0xdf ecr=0x35 our=0x04 0
parport0: irq=7/7 dsr=0xdf/0xdf ecr=0x35 our=0x04 1
parport0: irq=7/7 dsr=0xdf/0xdf ecr=0x35 our=0x04 2

reddwarf:~# echo -n abc >/dev/lp1

frob_econtrol(parport1,ff,34): 35 -> 34
frob_econtrol(parport1,ff,35): 35 -> 35
parport1: irq=10/10 dsr=0x98/0x98 ecr=0x35 our=0x0a 3
parport2: irq=10/10 dsr=0x78/0x78 ecr=0x35 our=0x00 4


00:10.0 Communication controller: Unknown device 9710:9815 (rev 01)
        Subsystem: Unknown device 1000:0020
        Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Step
ping- SERR+ FastB2B-
        Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort
- <MAbort- >SERR- <PERR-
        Interrupt: pin A routed to IRQ 10
        Region 0: I/O ports at fff0
        Region 1: I/O ports at ffe0
        Region 2: I/O ports at ffa8
        Region 3: I/O ports at ffa0
        Region 4: I/O ports at ff98
        Region 5: I/O ports at ff80

****************************** patch ************************************
--- linux-2.4.23/drivers/parport/parport_pc-dist.c	Fri Jun 13 16:51:35 2003
+++ linux-2.4.23/drivers/parport/parport_pc.c	Mon Mar  1 00:46:52 2004
@@ -77,6 +77,7 @@
 #define ECR_WRITE(p,v) frob_econtrol((p),0xff,(v))
 
 #undef DEBUG
+#define DEBUG 1
 
 #ifdef DEBUG
 #define DPRINTK  printk
@@ -93,24 +94,27 @@
 } superios[NR_SUPERIOS] __devinitdata = { {0,},};
 
 static int user_specified __devinitdata = 0;
-#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
-static int verbose_probing;
-#endif
+static int verbose_probing=0;
 static int registered_parport;
+static int parport_pc_pci_autoirq __devinitdata =PARPORT_IRQ_NONE;
 
 /* frob_control, but for ECR */
 static void frob_econtrol (struct parport *pb, unsigned char m,
 			   unsigned char v)
 {
-	unsigned char ectr = 0;
+	unsigned char ecr = 0;
+	struct parport_pc_private *priv=
+	  (struct parport_pc_private *) pb->private_data;
 
+#ifdef DEBUG
+	ecr = inb (ECONTROL (pb));
+	printk(KERN_DEBUG "frob_econtrol(%s,%02x,%02x): %02x -> %02x\n",
+	       pb->name, m, v, ecr, (ecr & ~m) ^ v);
+#endif
 	if (m != 0xff)
-		ectr = inb (ECONTROL (pb));
+		ecr = inb (ECONTROL (pb));
 
-	DPRINTK (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
-		m, v, ectr, (ectr & ~m) ^ v);
-
-	outb ((ectr & ~m) ^ v, ECONTROL (pb));
+	outb ((priv->ecr=(ecr & ~m) ^ v), ECONTROL (pb));
 }
 
 static void __inline__ frob_set_mode (struct parport *p, int mode)
@@ -133,7 +137,7 @@
 
 	DPRINTK(KERN_INFO "parport change_mode ECP-ISA to mode 0x%02x\n",m);
 
-	if (!priv->ecr) {
+	if (!priv->ecrok) {
 		printk (KERN_DEBUG "change_mode: but there's no ECR!\n");
 		return 0;
 	}
@@ -263,6 +267,74 @@
 
 static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct parport *pb=(struct parport *)dev_id;
+	struct parport_pc_private *priv=
+	  (struct parport_pc_private *) pb->private_data;
+	unsigned char dsr, dsr2, ecr=0;
+	int our=0;
+
+	/* The level sensitive PCI INTX# is held until DSR is read.
+	 * Even worse, some boards just route ACK# to INTX#.  It must
+	 * be cleared since the IRQ controller otherwise retriggers when
+	 * this handler returns (locking up the system). */
+	dsr=inb(STATUS(pb));
+
+	if(priv->irqshare == PARPORT_IRQ_NONE) our|=1;
+
+	/* Bit 2 nINT resets on DSR read for true PS2 ports.
+	 * Oxford 12pci840 1415:8403 : int at rising ACK#, full nINT support
+	 * National PC87306B         : int at rising ACK#, but nINT==1
+	 * Netmos          9710:9815 : INTX#==ACK#, nINT reset fails if ACK#==0
+	 */
+	if(priv->ctr & 0x10) {      /* ACK# irq enabled */
+	  if(!(dsr & 0x04))
+	    our|=2;            /* got nINT */
+	  else if(!priv->irqok) 
+	    our|=4;            /* fallback to false alarm */
+	}
+	dsr2=inb(STATUS(pb));
+	if(our & 2) {
+	  if(!(dsr2 & 0x04)) { /* nINT is still zero: level coupled ACK# */
+	    our|=8;
+	    priv->ctr&=~0x10;
+	    outb(priv->ctr, CONTROL(pb)); /* mask PCI INTX# */ 
+	    dsr2=inb(STATUS(pb));
+	  }
+	  if(!priv->irqok) {
+	    priv->irqok=our;   /* signal working nINT */
+	    if(verbose_probing && !(our&8)) 
+	      printk(KERN_DEBUG "%s: irq=%d/%d dsr=0x%02x/0x%02x nINT-OK"
+		     " our=0x%02x\n", pb->name, irq, pb->irq, dsr, dsr2, our);
+	  }
+	} /* our & 2 */
+
+	if(priv->ecrok) {
+	  ecr=inb(ECONTROL(pb));
+
+	  /* Bit 2 is set for an nErrIntrEn or serviceIntr if enabled. */
+	  if((ecr & 0x04) && (priv->ecr & 0x14)!=0x14) {
+	    our|=0x10;
+	    priv->ecr=ecr | 0x14;
+	    outb(priv->ecr, ECONTROL(pb)); /* unassert INTX# */
+	  }
+	}
+
+#ifdef DEBUG
+	{ static int cnt=0;
+    	  if(cnt<512) {
+	    printk(KERN_DEBUG "%s: irq=%d/%d dsr=0x%02x/0x%02x ecr=0x%02x"
+		   " our=0x%02x %d\n",
+		   pb->name, irq, pb->irq, dsr, dsr2, ecr, our, cnt);
+	    cnt++;
+	  } 
+#if DEBUG>1
+	  else {
+	    disable_irq_nosync(irq);
+	  }
+#endif
+	}
+#endif
+	if(our)
 	parport_generic_irq(irq, (struct parport *) dev_id, regs);
 }
 
@@ -341,8 +413,7 @@
 
 void parport_pc_enable_irq(struct parport *p)
 {
-	if (p->irq != PARPORT_IRQ_NONE)
-		__parport_pc_frob_control (p, 0x10, 0x10);
+	__parport_pc_frob_control (p, 0x10, 0x10);  /* NOP if _IRQ_NONE */
 }
 
 void parport_pc_data_forward (struct parport *p)
@@ -363,15 +434,15 @@
 		/* Set ackIntEn */
 		s->u.pc.ctr |= 0x10;
 
-	s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24;
-			     * D.Gruszka VScom */
+	s->u.pc.ecr = 0x34; 
+	/* NetMos chip can cause problems 0x24; D.Gruszka VScom */
 }
 
 void parport_pc_save_state(struct parport *p, struct parport_state *s)
 {
 	const struct parport_pc_private *priv = p->physport->private_data;
 	s->u.pc.ctr = priv->ctr;
-	if (priv->ecr)
+	if (priv->ecrok)
 		s->u.pc.ecr = inb (ECONTROL (p));
 }
 
@@ -381,7 +452,7 @@
 	register unsigned char c = s->u.pc.ctr & priv->ctr_writable;
 	outb (c, CONTROL (p));
 	priv->ctr = c;
-	if (priv->ecr)
+	if (priv->ecrok)
 		ECR_WRITE (p, s->u.pc.ecr);
 }
 
@@ -1645,6 +1716,7 @@
 static int __devinit parport_SPP_supported(struct parport *pb)
 {
 	unsigned char r, w;
+	int ok=0;
 
 	/*
 	 * first clear an eventually pending EPP timeout 
@@ -1669,8 +1741,10 @@
 		outb (w, CONTROL (pb));
 		r = inb (CONTROL (pb));
 		outb (0xc, CONTROL (pb));
-		if ((r & 0xf) == w)
-			return PARPORT_MODE_PCSPP;
+		if ((r & 0xf) == w) {
+			ok=PARPORT_MODE_PCSPP;
+			goto end;
+		}
 	}
 
 	if (user_specified)
@@ -1688,8 +1762,10 @@
 		w = 0x55;
 		parport_pc_write_data (pb, w);
 		r = parport_pc_read_data (pb);
-		if (r == w)
-			return PARPORT_MODE_PCSPP;
+		if (r == w) {
+			ok=PARPORT_MODE_PCSPP;
+			goto end;
+		}
 	}
 
 	if (user_specified) {
@@ -1705,9 +1781,15 @@
 	/* It's possible that we can't read the control register or
 	 * the data register.  In that case just believe the user. */
 	if (user_specified)
-		return PARPORT_MODE_PCSPP;
+		ok=PARPORT_MODE_PCSPP;
 
-	return 0;
+ end:
+	if (verbose_probing) {
+	  unsigned char dsr=parport_pc_read_status(pb);
+	  printk (KERN_DEBUG "parport_SPP_supported(%s): dsr=0x%02x ok=%d\n", 
+		  pb->name, dsr, ok);
+	}
+	return(ok);
 }
 
 /* Check for ECR
@@ -1727,6 +1809,7 @@
 {
 	struct parport_pc_private *priv = pb->private_data;
 	unsigned char r = 0xc;
+	int ok=0;
 
 	outb (r, CONTROL (pb));
 	if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
@@ -1737,24 +1820,27 @@
 			goto no_reg; /* Sure that no ECR register exists */
 	}
 	
-	if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1)
+	if ((inb (ECONTROL (pb)) & 0x3 ) != 0x1) {
+		ok=-1;
 		goto no_reg;
-
+	}
 	ECR_WRITE (pb, 0x34);
-	if (inb (ECONTROL (pb)) != 0x35)
+	if (inb (ECONTROL (pb)) != 0x35) {
+		ok=-2;
 		goto no_reg;
-
-	priv->ecr = 1;
-	outb (0xc, CONTROL (pb));
+	}
+	ok=priv->ecrok = 1;
 	
 	/* Go to mode 000 */
 	frob_set_mode (pb, ECR_SPP);
 
-	return 1;
-
  no_reg:
 	outb (0xc, CONTROL (pb));
-	return 0; 
+
+	if (verbose_probing) 
+	  printk (KERN_DEBUG "parport_ECR_present(%s): ok=%d\n", pb->name, ok);
+	if(ok<0) ok=0;
+	return(ok); 
 }
 
 #ifdef CONFIG_PARPORT_1284
@@ -1777,7 +1863,14 @@
 
 static int __devinit parport_PS2_supported(struct parport *pb)
 {
+	struct parport_pc_private *priv = pb->private_data;
 	int ok = 0;
+  	unsigned char oecr=0x34;
+
+	if (priv->ecrok) {
+	  oecr = inb (ECONTROL (pb));
+	  ECR_WRITE (pb, ECR_PS2<<5 | 0x14);  /* and disable PCI interrupts */
+	}
   
 	clear_epp_timeout(pb);
 
@@ -1793,13 +1886,17 @@
 	/* cancel input mode */
 	parport_pc_data_forward (pb);
 
-	if (ok) {
+	if (ok)
 		pb->modes |= PARPORT_MODE_TRISTATE;
-	} else {
-		struct parport_pc_private *priv = pb->private_data;
+	else
 		priv->ctr_writable &= ~0x20;
-	}
 
+	if(priv->ecrok)
+	  ECR_WRITE (pb, oecr);
+
+	if (verbose_probing) 
+	  printk (KERN_DEBUG "parport_PS2_supported(%s): ok=%d\n", 
+		  pb->name, ok);
 	return ok;
 }
 
@@ -1814,7 +1911,7 @@
 	static const int intrline[]= { 0, 7, 9, 10, 11, 14, 15, 5 }; 
 
 	/* If there is no ECR, we have no hope of supporting ECP. */
-	if (!priv->ecr)
+	if (!priv->ecrok)
 		return 0;
 
 	/* Find out FIFO depth */
@@ -1931,27 +2028,20 @@
 }
 #endif
 
-static int __devinit parport_ECPPS2_supported(struct parport *pb)
-{
-	const struct parport_pc_private *priv = pb->private_data;
-	int result;
-	unsigned char oecr;
-
-	if (!priv->ecr)
-		return 0;
-
-	oecr = inb (ECONTROL (pb));
-	ECR_WRITE (pb, ECR_PS2 << 5);
-	result = parport_PS2_supported(pb);
-	ECR_WRITE (pb, oecr);
-	return result;
-}
-
 /* EPP mode detection  */
 
 static int __devinit parport_EPP_supported(struct parport *pb)
 {
-	const struct parport_pc_private *priv = pb->private_data;
+	struct parport_pc_private *priv = pb->private_data;
+	int result=0;
+	unsigned char oecr=0x34;
+
+	if (priv->ecrok) {
+	  oecr = inb (ECONTROL (pb));
+	  /* Search for SMC style EPP+ECP mode */
+	  ECR_WRITE (pb, ECR_EPP<<5 | 0x14);   /* EPP no interrupts for PCI */
+	  outb (0x04, CONTROL (pb));
+	}
 
 	/*
 	 * Theory:
@@ -1961,24 +2051,33 @@
 	 *	the byte transfer, an EPP timeout occurs if the attached
 	 *	device fails to respond after 10 micro seconds).
 	 *
-	 *	This bit is cleared by either reading it (National Semi)
+	 *	This bit is cleared by either reading it (National Semi, 
+	 *	Netmos, Oxford Semi)
 	 *	or writing a 1 to the bit (SMC, UMC, WinBond), others ???
-	 *	This bit is always high in non EPP modes.
+	 *	This bit is always high in non EPP modes.  (except Netmos)
 	 */
 
 	/* If EPP timeout bit clear then EPP available */
 	if (!clear_epp_timeout(pb)) {
-		return 0;  /* No way to clear timeout */
+	        result=-1;
+		goto end;  /* No way to clear timeout */
 	}
 
-	/* Check for Intel bug. */
-	if (priv->ecr) {
-		unsigned char i;
-		for (i = 0x00; i < 0x80; i += 0x20) {
-			ECR_WRITE (pb, i);
-			if (clear_epp_timeout (pb)) {
+	/* Check for Intel bug.  Bad chipsets do not timeout and HALT the bus. 
+	 * David Campbell jan 1999.  BIOS allows 378(=auto), 278 or 3bc.
+	 */
+	if (priv->ecrok
+	    && (pb->base==0x378 || pb->base==0x278 || pb->base==0x3bc)) {
+		int i;
+		unsigned char mode[5]={
+		  ECR_SPP, ECR_PS2, ECR_PPF, ECR_ECP, ECR_EPP
+		};
+		for (i = 0; i < 5; i++) {
+		  frob_set_mode (pb, mode[i]);
+		  if (mode[i]!=ECR_EPP && clear_epp_timeout (pb)) {
 				/* Phony EPP in ECP. */
-				return 0;
+		    result=-10-i;
+		    goto end;
 			}
 		}
 	}
@@ -1986,33 +2085,12 @@
 	pb->modes |= PARPORT_MODE_EPP;
 
 	/* Set up access functions to use EPP hardware. */
+	if(!priv->ecrok) {
 	pb->ops->epp_read_data = parport_pc_epp_read_data;
 	pb->ops->epp_write_data = parport_pc_epp_write_data;
 	pb->ops->epp_read_addr = parport_pc_epp_read_addr;
 	pb->ops->epp_write_addr = parport_pc_epp_write_addr;
-
-	return 1;
-}
-
-static int __devinit parport_ECPEPP_supported(struct parport *pb)
-{
-	struct parport_pc_private *priv = pb->private_data;
-	int result;
-	unsigned char oecr;
-
-	if (!priv->ecr) {
-		return 0;
-	}
-
-	oecr = inb (ECONTROL (pb));
-	/* Search for SMC style EPP+ECP mode */
-	ECR_WRITE (pb, 0x80);
-	outb (0x04, CONTROL (pb));
-	result = parport_EPP_supported(pb);
-
-	ECR_WRITE (pb, oecr);
-
-	if (result) {
+	} else {
 		/* Set up access functions to use ECP+EPP hardware. */
 		pb->ops->epp_read_data = parport_pc_ecpepp_read_data;
 		pb->ops->epp_write_data = parport_pc_ecpepp_write_data;
@@ -2020,19 +2098,26 @@
 		pb->ops->epp_write_addr = parport_pc_ecpepp_write_addr;
 	}
 
-	return result;
+	result=1;
+ end:
+	if (priv->ecrok) 
+	  ECR_WRITE (pb, oecr);
+
+	if (verbose_probing) {
+	  char iyes[]=" Intel bug ?", ino[]="";
+	  char *ibug= result<=-10 ? iyes : ino;
+	  printk (KERN_DEBUG "parport_EPP_supported(%s):%s result=%d\n", 
+		  pb->name, ibug, result);
+	}
+	if(result<0) result=0;
+	return(result);
 }
 
 #else /* No IEEE 1284 support */
 
 /* Don't bother probing for modes we know we won't use. */
 static int __devinit parport_PS2_supported(struct parport *pb) { return 0; }
-#ifdef CONFIG_PARPORT_PC_FIFO
-static int __devinit parport_ECP_supported(struct parport *pb) { return 0; }
-#endif
 static int __devinit parport_EPP_supported(struct parport *pb) { return 0; }
-static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;}
-static int __devinit parport_ECPPS2_supported(struct parport *pb){return 0;}
 
 #endif /* No IEEE 1284 support */
 
@@ -2053,6 +2138,10 @@
 	irq = lookup[intrLine];
 
 	ECR_WRITE (pb, oecr);
+
+	if (verbose_probing) 
+	  printk (KERN_DEBUG "programmable_irq_support(%s): irq=%d\n", 
+		  pb->name, irq);
 	return irq;
 }
 
@@ -2071,13 +2160,21 @@
 	/* If Full FIFO sure that writeIntrThreshold is generated */
 	for (i=0; i < 1024 && !(inb (ECONTROL (pb)) & 0x02) ; i++) 
 		outb (0xaa, FIFO (pb));
-		
+	if(i<1024) {
+	  struct parport_pc_private *priv = pb->private_data;
+	  priv->fifo_depth = i;
+	}
+	udelay (10);
+	ECR_WRITE (pb, ECR_SPP << 5 | 0x14); /* disable shared PCI INTX# */
 	pb->irq = probe_irq_off(irqs);
-	ECR_WRITE (pb, ECR_SPP << 5);
 
 	if (pb->irq <= 0)
 		pb->irq = PARPORT_IRQ_NONE;
 
+	if (verbose_probing) 
+	  printk (KERN_DEBUG "irq_probe_ECP(%s): irq=%d irqs=0x%08lx"
+		  " fifo=%d\n", pb->name, pb->irq, irqs, i);
+
 	return pb->irq;
 }
 
@@ -2121,6 +2218,8 @@
 	if (pb->irq <= 0)
 		pb->irq = PARPORT_IRQ_NONE;
 
+	if (verbose_probing) 
+	  printk (KERN_DEBUG "irq_probe_EPP(%s): irq=%d\n", pb->name, pb->irq);
 	return pb->irq;
 #endif /* Advanced detection */
 }
@@ -2142,14 +2241,14 @@
 {
 	struct parport_pc_private *priv = pb->private_data;
 
-	if (priv->ecr) {
+	if (priv->ecrok) {
 		pb->irq = programmable_irq_support(pb);
 
 		if (pb->irq == PARPORT_IRQ_NONE)
 			pb->irq = irq_probe_ECP(pb);
 	}
 
-	if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr &&
+	if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecrok &&
 	    (pb->modes & PARPORT_MODE_EPP))
 		pb->irq = irq_probe_EPP(pb);
 
@@ -2192,7 +2291,7 @@
 static int __devinit parport_dma_probe (struct parport *p)
 {
 	const struct parport_pc_private *priv = p->private_data;
-	if (priv->ecr)
+	if (priv->ecrok)
 		p->dma = programmable_dma_support(p); /* ask ECP chipset first */
 	if (p->dma == PARPORT_DMA_NONE) {
 		/* ask known Super-IO chips proper, although these
@@ -2216,6 +2315,8 @@
 	struct parport tmp;
 	struct parport *p = &tmp;
 	int probedirq = PARPORT_IRQ_NONE;
+	char tmpname[16]="@";
+
 	if (check_region(base, 3)) return NULL;
 	priv = kmalloc (sizeof (struct parport_pc_private), GFP_KERNEL);
 	if (!priv) {
@@ -2232,13 +2333,18 @@
 	memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations));
 	priv->ctr = 0xc;
 	priv->ctr_writable = ~0x10;
-	priv->ecr = 0;
+	priv->irqshare = PARPORT_IRQ_AUTO;
+	priv->irqok = 0;
+	priv->ecrok = 0;
+	priv->ecr = 0x34;
 	priv->fifo_depth = 0;
 	priv->dma_buf = 0;
 	priv->dma_handle = 0;
 	priv->dev = dev;
 	p->base = base;
 	p->base_hi = base_hi;
+	sprintf(&tmpname[1],"%lx", base);
+	p->name= tmpname;
 	p->irq = irq;
 	p->dma = dma;
 	p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
@@ -2249,40 +2355,31 @@
 	if (base_hi && !check_region(base_hi,3))
 		parport_ECR_present(p);
 
-	if (base != 0x3bc) {
-		if (!check_region(base+0x3, 5)) {
-			if (!parport_EPP_supported(p))
-				parport_ECPEPP_supported(p);
-		}
-	}
 	if (!parport_SPP_supported (p)) {
 		/* No port. */
 		kfree (priv);
 		kfree (ops);
 		return NULL;
 	}
-	if (priv->ecr)
-		parport_ECPPS2_supported(p);
-	else
-		parport_PS2_supported (p);
 
-	if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
-					PARPORT_DMA_NONE, ops))) {
+	if (!(p = parport_register_port(base, irq, dma, ops))) {
 		kfree (priv);
 		kfree (ops);
 		return NULL;
 	}
-
 	p->base_hi = base_hi;
 	p->modes = tmp.modes;
-	p->size = (p->modes & PARPORT_MODE_EPP)?8:3;
 	p->private_data = priv;
+	p->size = 3;
 
-	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
-	if (p->base_hi && priv->ecr)
-		printk(" (0x%lx)", p->base_hi);
-	p->irq = irq;
-	p->dma = dma;
+	if (base != 0x3bc && !check_region(base+0x3, 5))
+		parport_EPP_supported(p);
+
+	parport_PS2_supported (p);
+
+	if(p->modes & PARPORT_MODE_EPP)	p->size = 8;
+
+	/* irq setup */
 	if (p->irq == PARPORT_IRQ_AUTO) {
 		p->irq = PARPORT_IRQ_NONE;
 		parport_irq_probe(p);
@@ -2293,7 +2390,6 @@
 		p->irq = PARPORT_IRQ_NONE;
 	}
 	if (p->irq != PARPORT_IRQ_NONE) {
-		printk(", irq %d", p->irq);
 		priv->ctr_writable |= 0x10;
 
 		if (p->dma == PARPORT_DMA_AUTO) {
@@ -2301,8 +2397,60 @@
 			parport_dma_probe(p);
 		}
 	}
-	if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq
-                                           is mandatory (see above) */
+	if (probedirq != PARPORT_IRQ_NONE) {
+	  if(dev && dev->irq!=probedirq) 
+	    printk(KERN_WARNING "%s: irq %d detected, but PCI routed to %d\n", 
+		   p->name, probedirq, dev->irq);
+	  else 
+	    printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
+	}
+	if(priv->irqshare == PARPORT_IRQ_AUTO) {
+	  if(probedirq != PARPORT_IRQ_NONE) priv->irqshare=probedirq;
+	  else if(dev && dev->irq) priv->irqshare=dev->irq;
+	  else if(p->modes & PARPORT_MODE_TRISTATE) priv->irqshare=p->irq;
+	  else priv->irqshare=PARPORT_IRQ_NONE;
+	} 
+
+	parport_proc_register(p);
+
+	request_region (p->base, 3, p->name);
+	if (p->size > 3)
+		request_region (p->base + 3, p->size - 3, p->name);
+	if (priv->ecrok)
+		request_region (p->base_hi, 3, p->name);
+
+	/* irq handler request */
+	if(p->irq != PARPORT_IRQ_NONE) {
+	  unsigned long flags= 
+	    priv->irqshare!=PARPORT_IRQ_NONE ? SA_SHIRQ : 0;
+	  if(request_irq (p->irq, parport_pc_interrupt,
+			   flags, p->name, p)) {
+	    printk (KERN_WARNING "%s: irq %d in use,"
+		    " resorting to polled operation\n", p->name, p->irq);
+	    p->irq = PARPORT_IRQ_NONE;
+	    p->dma = PARPORT_DMA_NONE;
+	    priv->irqshare= PARPORT_IRQ_NONE;
+	  } 
+	} else if(priv->irqshare != PARPORT_IRQ_NONE) { 
+	  /* handler for spurious IRQs */
+	  if (request_irq (priv->irqshare, parport_pc_interrupt, 
+			   SA_SHIRQ, p->name, p)) {
+	    printk (KERN_DEBUG "%s: irq %d in use, handler not installed\n",
+		    p->name, priv->irqshare);
+	    priv->irqshare=PARPORT_IRQ_NONE;
+	  }
+	}
+
+	printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
+	if (p->base_hi && priv->ecrok)
+		printk(" (0x%lx)", p->base_hi);
+	if (p->irq != PARPORT_IRQ_NONE) 
+		printk(", irq %d", p->irq);
+	if(priv->irqshare != PARPORT_IRQ_NONE) 
+		printk(", irqshare %d", priv->irqshare);
+
+	/* To use DMA, giving the irq is mandatory (see above) */
+	if (p->dma == PARPORT_DMA_AUTO) 
 		p->dma = PARPORT_DMA_NONE;
 
 #ifdef CONFIG_PARPORT_PC_FIFO
@@ -2343,28 +2491,10 @@
 	printk ("(,...)");
 #endif /* CONFIG_PARPORT_1284 */
 	printk("]\n");
-	if (probedirq != PARPORT_IRQ_NONE) 
-		printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
-	parport_proc_register(p);
-
-	request_region (p->base, 3, p->name);
-	if (p->size > 3)
-		request_region (p->base + 3, p->size - 3, p->name);
-	if (p->modes & PARPORT_MODE_ECP)
-		request_region (p->base_hi, 3, p->name);
-
-	if (p->irq != PARPORT_IRQ_NONE) {
-		if (request_irq (p->irq, parport_pc_interrupt,
-				 0, p->name, p)) {
-			printk (KERN_WARNING "%s: irq %d in use, "
-				"resorting to polled operation\n",
-				p->name, p->irq);
-			p->irq = PARPORT_IRQ_NONE;
-			p->dma = PARPORT_DMA_NONE;
-		}
 
+	/* dma request */
 #ifdef CONFIG_PARPORT_PC_FIFO
-		if (p->dma != PARPORT_DMA_NONE) {
+	if (p->irq != PARPORT_IRQ_NONE && p->dma != PARPORT_DMA_NONE) {
 			if (request_dma (p->dma, p->name)) {
 				printk (KERN_WARNING "%s: dma %d in use, "
 					"resorting to PIO operation\n",
@@ -2386,10 +2516,9 @@
 			}
 		}
 #endif /* CONFIG_PARPORT_PC_FIFO */
-	}
 
 	/* Done probing.  Now put the port into a sensible start-up state. */
-	if (priv->ecr)
+	if (priv->ecrok)
 		/*
 		 * Put the ECP detected port in PS2 mode.
 		 * Do this also for ports that have ECR but don't do ECP.
@@ -2409,18 +2538,18 @@
 
 void parport_pc_unregister_port (struct parport *p)
 {
-#ifdef CONFIG_PARPORT_PC_FIFO
 	struct parport_pc_private *priv = p->private_data;
-#endif /* CONFIG_PARPORT_PC_FIFO */
 	struct parport_operations *ops = p->ops;
+	int irqeff= p->irq!=PARPORT_IRQ_NONE ? p->irq : priv->irqshare;
+
 	if (p->dma != PARPORT_DMA_NONE)
 		free_dma(p->dma);
-	if (p->irq != PARPORT_IRQ_NONE)
-		free_irq(p->irq, p);
+	if (irqeff != PARPORT_IRQ_NONE)
+		free_irq(irqeff, p);
 	release_region(p->base, 3);
 	if (p->size > 3)
 		release_region(p->base + 3, p->size - 3);
-	if (p->modes & PARPORT_MODE_ECP)
+	if (priv->ecrok)
 		release_region(p->base_hi, 3);
 	parport_proc_unregister(p);
 #ifdef CONFIG_PARPORT_PC_FIFO
@@ -2429,7 +2558,7 @@
 				    priv->dma_buf,
 				    priv->dma_handle);
 #endif /* CONFIG_PARPORT_PC_FIFO */
-	kfree (p->private_data);
+	kfree (priv);
 	parport_unregister_port(p);
 	kfree (ops); /* hope no-one cached it */
 }
@@ -2699,7 +2828,10 @@
 	oxsemi_840,
 	aks_0100,
 	mobility_pp,
-};
+ 	vscom_010s,
+ 	vscom_020s,
+ 	oxsemi_952,
+}; /* 45 entries */
 
 
 /* each element directly indexed from enum list, above 
@@ -2765,10 +2897,13 @@
 	/* The Oxford Semi cards are unusual: 954 doesn't support ECP,
 	 * and 840 locks up if you write 1 to bit 2! */
 	/* oxsemi_954 */		{ 1, { { 0, -1 }, } },
-	/* oxsemi_840 */		{ 1, { { 0, -1 }, } },
+	/* oxsemi_840 */		{ 1, { { 0, 1 }, } },
 	/* aks_0100 */			{ 1, { { 0, -1 }, } },
 	/* mobility_pp */		{ 1, { { 0, 1 }, } },
-};
+ 	/* vscom_010s */		{ 1, { { 2, 1 }, } },
+ 	/* vscom_020s */		{ 2, { { 2, -1 },{3,-1}} },
+ 	/* oxsemi_952 */		{ 1, { { 0, 1 }, } },
+}; /* 45 entries */
 
 static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
 	/* Super-IO onboard chips */
@@ -2795,6 +2930,9 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar },
 	{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
 	  PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0,0, plx_9050 },
+	/* VScom / Titan parallel ports */
+	{ PCI_VENDOR_ID_PLX, 0x1147, PCI_ANY_ID, PCI_ANY_ID, 0,0, vscom_020s },
+	{ PCI_VENDOR_ID_PLX, 0x1146, PCI_ANY_ID, PCI_ANY_ID, 0,0, vscom_010s },
 	/* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/
 	{ 0x1409, 0x7168, 0x1409, 0x4078, 0, 0, timedia_4078a },
 	{ 0x1409, 0x7168, 0x1409, 0x4079, 0, 0, timedia_4079h },
@@ -2827,6 +2965,10 @@
 	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l },
 	{ 0x9710, 0x9815, 0x1000, 0x0020, 0, 0, titan_1284p2 },
+	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010H,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 },
+	{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010HV2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_952 },
 	/* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/
 	{ 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, /* AFAVLAB_TK9902 */
 	{ 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p},
@@ -2862,20 +3004,25 @@
 		int lo = cards[i].addr[n].lo;
 		int hi = cards[i].addr[n].hi;
 		unsigned long io_lo, io_hi;
+		int irq;
+
 		io_lo = pci_resource_start (dev, lo);
 		io_hi = 0;
 		if ((hi >= 0) && (hi <= 6))
 			io_hi = pci_resource_start (dev, hi);
 		else if (hi > 6)
 			io_lo += hi; /* Reinterpret the meaning of
-                                        "hi" as an offset (see SYBA
-                                        def.) */
+                                        "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);
-		if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
+		if(parport_pc_pci_autoirq == PARPORT_IRQ_AUTO && dev->irq) 
+		  irq=dev->irq;
+		else 
+		  irq=PARPORT_IRQ_NONE;
+
+		printk (KERN_DEBUG "parport_pc_pci_probe: PCI parallel port"
+			" %04x:%04x, I/O at %#lx(%#lx)\n", 
+			id->vendor, id->device, io_lo, io_hi);
+		if (parport_pc_probe_port (io_lo, io_hi, irq,
 					   PARPORT_DMA_NONE, dev))
 			count++;
 	}
@@ -2883,7 +3030,7 @@
 	if (cards[i].postinit_hook)
 		cards[i].postinit_hook (dev, count == 0);
 
-	return count == 0 ? -ENODEV : 0;
+	return(!count ? -ENODEV : count);
 }
 
 static struct pci_driver parport_pc_pci_driver = {
@@ -2957,28 +3104,96 @@
 	/* ISA ports and whatever (see asm/parport.h). */
 	count += parport_pc_find_nonpci_ports (autoirq, autodma);
 
+	parport_pc_pci_autoirq=autoirq;
 	r = pci_register_driver (&parport_pc_pci_driver);
 	if (r >= 0) {
 		registered_parport = 1;
-		count += r;
+		count += r; /* number of claimed PCI devices <=parports */
 	}
 
 	return count;
 }
 
+/* PCI mode 
+ *   io   = -1 
+ *   io_hi= 0x<bus><slot><func>
+ * where 
+ *   bus     = bus number 0x00 .. 0xff
+ *   slot    = phys slot  0x00 .. 0x1f
+ *   function= chip function 0 .. 7
+ *   e.g. 02:0c.0 --> io=-1 io_hi=0x020c00
+ * note
+ *   devfn= bit mapped slot/function address of the device
+ *   bits 7:3=slot  2:0=function  (02:0c.0 -> 0x0260)
+ */
 int __init parport_pc_init (int *io, int *io_hi, int *irq, int *dma)
 {
-	int count = 0, i = 0;
+	int count = 0;
 
 	if (io && *io) {
+	  int i = 0;
 		/* Only probe the ports we were given. */
 		user_specified = 1;
 		do {
-			if ((*io_hi) == PARPORT_IOHI_AUTO)
+	    if(*io == -1) {  /* PCI mode */
+#ifdef CONFIG_PCI
+	      struct pci_dev *dev;
+	      const struct pci_device_id *id;
+	      unsigned bus, slot, func, devfn;
+	      int err;
+
+	      if(*io_hi == PARPORT_IOHI_AUTO) {
+		printk (KERN_WARNING "parport_pc: bad PCI io_hi=%d\n", *io_hi);
+		goto pci_end;
+	      }
+
+	      bus  = (unsigned )*io_hi;
+	      func = bus & 0xff;
+	      bus>>= 8;
+	      slot = bus & 0xff;
+	      bus>>= 8;
+	      devfn=PCI_DEVFN(slot, func);
+
+	      dev=pci_find_slot(bus, devfn);
+	      if(!dev) {
+		printk (KERN_WARNING "parport_pc: no PCI dev at"
+			" %02x:%02x.%02x (:%02x)\n", bus, slot, func, devfn);
+		goto pci_end;
+	      }
+
+	      id=pci_match_device(parport_pc_pci_tbl, dev);
+	      if(!id) {
+		printk (KERN_WARNING "parport_pc: unknown PCI dev"
+			" %02x:%02x.%02x (:%02x) %04x:%04x\n", 
+			bus, slot, func, devfn, dev->vendor, dev->device);
+		goto pci_end;
+	      }
+
+	      parport_pc_pci_autoirq=*irq;
+	      err=parport_pc_pci_probe(dev, id);
+	      if(err<0) {
+		printk (KERN_WARNING "parport_pc: failed PCI dev"
+			" %02x:%02x.%02x (:%02x) dev=%04x:%04x id=%04x:%04x\n",
+			bus, slot, func, devfn, dev->vendor, dev->device,
+			id->vendor, id->device);
+		goto pci_end;
+	      }
+	      count+=err;
+
+	    pci_end:
+#else
+	      printk (KERN_WARNING "parport_pc: No PCI support\n")
+#endif /* CONFIG_PCI */
+	    } else {
+	      if (*io_hi == PARPORT_IOHI_AUTO)
 			       *io_hi = 0x400 + *io;
-			if (parport_pc_probe_port(*(io++), *(io_hi++),
-						  *(irq++), *(dma++), NULL))
+	      if (parport_pc_probe_port(*io, *io_hi, *irq, *dma, NULL))
 				count++;
+	    }
+	    io++;
+	    io_hi++;
+	    irq++;
+	    dma++;
 		} while (*io && (++i < PARPORT_PC_MAX_PORTS));
 	} else {
 		count += parport_pc_find_ports (irq[0], dma[0]);
@@ -3012,10 +3227,8 @@
 MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
 MODULE_PARM_DESC(dma, "DMA channel");
 MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
 MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
 MODULE_PARM(verbose_probing, "i");
-#endif
 
 int init_module(void)
 {	
--- linux-2.4.23/drivers/parport/ieee1284_ops-dist.c	Fri Dec 21 18:41:55 2001
+++ linux-2.4.23/drivers/parport/ieee1284_ops.c	Wed Dec  3 01:04:36 2003
@@ -40,7 +40,7 @@
 				      const void *buffer, size_t len,
 				      int flags)
 {
-	int no_irq = 1;
+	int no_irq = port->irq == PARPORT_IRQ_NONE ? 1 : 0;
 	ssize_t count = 0;
 	const unsigned char *addr = buffer;
 	unsigned char byte;
@@ -48,10 +48,7 @@
 	unsigned char ctl = (PARPORT_CONTROL_SELECT
 			     | PARPORT_CONTROL_INIT);
 
-	if (port->irq != PARPORT_IRQ_NONE) {
-		parport_enable_irq (port);
-		no_irq = 0;
-	}
+	if (!no_irq) parport_enable_irq (port);
 
 	port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
 	parport_write_control (port, ctl);
--- linux-2.4.23/include/linux/pci_ids-dist.h	Fri Nov 28 19:26:21 2003
+++ linux-2.4.23/include/linux/pci_ids.h	Wed Dec  3 01:15:29 2003
@@ -1638,10 +1638,19 @@
 #define PCI_DEVICE_ID_TITAN_210L	0x8021
 #define PCI_DEVICE_ID_TITAN_400L	0x8040
 #define PCI_DEVICE_ID_TITAN_800L	0x8080
+#define PCI_DEVICE_ID_TITAN_430L	0x8043
+#define PCI_DEVICE_ID_TITAN_420L	0x8042
 #define PCI_DEVICE_ID_TITAN_100		0xA001
 #define PCI_DEVICE_ID_TITAN_200		0xA005
 #define PCI_DEVICE_ID_TITAN_400		0xA003
 #define PCI_DEVICE_ID_TITAN_800B	0xA004
+/* d.gruszka VScom (R) */
+#define PCI_DEVICE_ID_TITAN_200I	0x8028
+#define PCI_DEVICE_ID_TITAN_100HV2	0xE010
+#define PCI_DEVICE_ID_TITAN_200HV2	0xE020
+#define PCI_DEVICE_ID_TITAN_010HV2	0xE001
+#define PCI_DEVICE_ID_TITAN_010H	0xA000
+#define PCI_DEVICE_ID_TITAN_210S	0x1078
 
 #define PCI_VENDOR_ID_PANACOM		0x14d4
 #define PCI_DEVICE_ID_PANACOM_QUADMODEM	0x0400
--- linux-2.4.23/include/linux/parport_pc-dist.h	Wed Nov 14 23:52:47 2001
+++ linux-2.4.23/include/linux/parport_pc.h	Thu Dec  4 04:39:55 2003
@@ -22,8 +22,17 @@
 	/* Bitmask of writable CTR bits. */
 	unsigned char ctr_writable;
 
+	/* A value >=0 signals the shared irq line */
+	int irqshare;
+
+	/* Set nonzero when DSR bit 2 nINT works */
+	int irqok;
+
 	/* Whether or not there's an ECR. */
-	int ecr;
+	int ecrok;
+
+	/* Last value written for shared IRQ detection */
+	unsigned char ecr;
 
 	/* Number of PWords that FIFO will hold. */
 	int fifo_depth;
@@ -111,17 +120,26 @@
 							   unsigned char val)
 {
 	struct parport_pc_private *priv = p->physport->private_data;
-	unsigned char ctr = priv->ctr;
+	unsigned char ctr;
 #ifdef DEBUG_PARPORT
+	ctr = priv->ctr;
 	printk (KERN_DEBUG
 		"__parport_pc_frob_control(%02x,%02x): %02x -> %02x\n",
 		mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
 #endif
-	ctr = (ctr & ~mask) ^ val;
+	/* The PCI irq handler modifies priv->ctr typically when we are 
+	 * raising STB# (end of +5V/0V/+5V strobe) 
+	 * STB# ------+ +-------
+	 *            +-+
+	 *             ^^^^^^^^printer lowers ACK# here
+	 */
+	cli();
+	ctr = (priv->ctr & ~mask) ^ val;
 	ctr &= priv->ctr_writable; /* only write writable bits. */
-	outb (ctr, CONTROL (p));
 	priv->ctr = ctr;	/* Update soft copy */
-	return ctr;
+	sti();
+	outb (priv->ctr, CONTROL (p));
+	return priv->ctr;
 }
 
 extern __inline__ void parport_pc_data_reverse (struct parport *p)



More information about the Linux-parport mailing list