[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