[PARPORT] [patch] PCI shared INTX# lockup solved 1/2

From: vdb128@stargate.kotnet.org
Date: Thu Dec 11 2003 - 19:12:30 EST

  • Next message: vdb128@stargate.kotnet.org: "[PARPORT] [patch] PCI shared INTX# lockup solved 0/2"

    --- linux-2.4.23/drivers/char/serial-dist.c Fri Nov 28 19:26:20 2003
    +++ linux-2.4.23/drivers/char/serial.c Wed Dec 3 01:18:54 2003
    @@ -4375,6 +4375,11 @@
             pbn_computone_4,
             pbn_computone_6,
             pbn_computone_8,
    + pbn_b1_1_921600,
    + pbn_b1_bt_2_921600,
    + pbn_b1_bt_4_921600,
    + pbn_b1_bt_8_921600,
    + pbn_b4_2_921600,
     };
     
     static struct pci_board pci_boards[] __devinitdata = {
    @@ -4483,6 +4488,11 @@
                     0x40, 2, NULL, 0x200 },
             { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */
                     0x40, 2, NULL, 0x200 },
    + { SPCI_FL_BASE1, 1, 921600}, /* IOMEM*/ /* pbn_b1_1_921600 */
    + { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600}, /* pbn_b1_bt_2_921600 */
    + { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 4, 921600}, /* pbn_b1_bt_4_921600 */
    + { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 8, 921600}, /* pbn_b1_bt_8_921600 */
    + { SPCI_FL_BASE4 , 2, 921600}, /* pbn_b4_2_921600 */
     };
     
     /*
    @@ -4764,19 +4774,22 @@
                     PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                     pbn_b0_4_921600 },
             { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
    - PCI_ANY_ID, PCI_ANY_ID,
    - SPCI_FL_BASE1, 1, 921600 },
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b1_1_921600},
             { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
    - PCI_ANY_ID, PCI_ANY_ID,
    - SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b1_bt_2_921600 },
             /* The 400L and 800L have a custom hack in get_pci_port */
    + /* changed by damian gruszka VScom (TM) VS Vision Systems GmbH */
             { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
    - PCI_ANY_ID, PCI_ANY_ID,
    - SPCI_FL_BASE_TABLE, 4, 921600 },
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b1_bt_4_921600},
             { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
    - PCI_ANY_ID, PCI_ANY_ID,
    - SPCI_FL_BASE_TABLE, 8, 921600 },
    -
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b1_bt_8_921600},
    + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b4_2_921600},
    + /* VScom HV2 cards damian gruszka VScom (TM) */
    + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100HV2,
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b0_1_921600},
    + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200HV2,
    + PCI_ANY_ID, PCI_ANY_ID,0,0,pbn_b0_bt_2_921600},
             { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
                     PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                     pbn_siig10x_0 },
    --- linux-2.4.23/drivers/parport/parport_serial-dist.c Sat Aug 3 02:39:44 2002
    +++ linux-2.4.23/drivers/parport/parport_serial.c Wed Dec 3 01:18:54 2003
    @@ -46,6 +46,10 @@
             siig_2p1s_20x,
             siig_1s1p_20x,
             siig_2s1p_20x,
    + /* d.gruszka VScom (R) */
    + vscom_2s1p_210s,
    + titan_430l,
    + titan_420l,
     };
     
     
    @@ -84,6 +88,9 @@
             /* siig_2p1s_20x */ { 2, { { 1, 2 }, { 3, 4 }, } },
             /* siig_1s1p_20x */ { 1, { { 1, 2 }, } },
             /* siig_2s1p_20x */ { 1, { { 2, 3 }, } },
    + /* vscom_2s1p_210s */ { 1, { { 5, -1}, } },
    + /* titan_430l */ { 3, { { 3, -1},{ 4, -1},{4,-1},}},
    + /* titan_420l */ { 2, { { 3, -1},{ 4, -1},}},
     };
     
     static struct pci_device_id parport_serial_pci_tbl[] __devinitdata = {
    @@ -132,7 +139,12 @@
               PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
             { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
               PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2s1p_20x },
    -
    + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_TITAN_210S,
    + PCI_ANY_ID, PCI_ANY_ID, 0, 0, vscom_2s1p_210s },
    + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_430L,
    + PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_430l },
    + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_420L,
    + PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_420l },
             { 0, } /* terminate list */
     };
     MODULE_DEVICE_TABLE(pci,parport_serial_pci_tbl);
    @@ -185,6 +197,10 @@
     /* siig_2p1s_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
     /* siig_1s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
     /* siig_2s1p_20x */ { SPCI_FL_BASE0, 1, 921600, 0, 0, siig20x_init_fn },
    +/* d.gruszka VScom (R) */
    +/* vscom_2s1p_210s */ { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
    +/* titan_420l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 4, 921600 },
    +/* titan_430l */ { SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 4, 921600 },
     };
     
     struct parport_serial_private {
    @@ -235,6 +251,12 @@
                             case 7: base_idx=idx-2; /* BAR 5*/
                     }
       
    + if((dev->vendor == PCI_VENDOR_ID_TITAN) &&
    + ((dev->device & 0xFF00) == 0x8000) && (idx >= 2))
    + {
    + base_idx = 4;
    + offset = 8 * (idx-2);
    + }
             port = pci_resource_start(dev, base_idx) + offset;
     
             if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
    @@ -321,6 +343,9 @@
                             io_lo += hi; /* Reinterpret the meaning of
                                             "hi" as an offset (see SYBA
                                             def.) */
    + /* D.Gruszka damian.gruszka@vscom.de */
    + if(((i == titan_430l) || (i == titan_420l )) && (n >= 1))
    + io_lo += 16+(n-1)*8;
                     /* TODO: test if sharing interrupts works */
                     printk (KERN_DEBUG "PCI parallel port detected: %04x:%04x, "
                             "I/O at %#lx(%#lx)\n",
    --- 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 Thu Dec 4 05:34:08 2003
    @@ -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,26 @@
     } 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;
     
     /* 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 +136,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 +266,68 @@
     
     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 aka nPRINT) resets on DSR read for true PS2 ports.
    + * ox12pci840 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 impossible if ACK#==0
    + */
    + if(priv->ctr & 0x10) { /* ACK# irq enabled */
    + if(!(dsr & 0x04)) { /* got nINT */
    + our|=2;
    + if(!priv->irqok) priv->irqok=our;
    + } else if(!priv->irqok) {
    + our|=4; /* fallback false alarm */
    + }
    + }
    + dsr2=inb(STATUS(pb));
    + if((our & 2) && !(dsr2 & 0x04)) {
    + our|=8;
    + priv->ctr&=~0x10;
    + outb(priv->ctr, CONTROL(pb)); /* mask INTX# level coupled ACK# */
    + dsr2=inb(STATUS(pb));
    + }
    +
    + if(priv->ecrok) {
    + ecr=inb(ECONTROL(pb));
    +
    + /* Bit 3 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 +406,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 +427,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 +445,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 +1709,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 +1734,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 +1755,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 +1774,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 +1802,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 +1813,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 +1856,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 +1879,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 +1904,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 +2021,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, 0x80 | 0x14); /* EPP no interrupts for PCI */
    + outb (0x04, CONTROL (pb));
    + }
     
             /*
              * Theory:
    @@ -1968,17 +2051,22 @@
     
             /* 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)) {
    + if (priv->ecrok) {
    + 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 +2074,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 +2087,23 @@
                     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)
    + printk (KERN_DEBUG "parport_EPP_supported(%s): result=%d\n",
    + pb->name, 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 +2124,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 +2146,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 i=%d\n",
    + pb->name, pb->irq, irqs, i);
    +
             return pb->irq;
     }
     
    @@ -2121,6 +2204,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 +2227,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 +2277,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 +2301,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 +2319,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 +2341,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 +2376,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 +2383,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 +2477,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 +2502,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 +2524,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 +2544,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 +2814,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 +2883,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 +2916,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 +2951,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},
    @@ -2840,6 +2968,7 @@
     };
     MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
     
    +static int pci_autoirq=PARPORT_IRQ_NONE;
     static int __devinit parport_pc_pci_probe (struct pci_dev *dev,
                                                const struct pci_device_id *id)
     {
    @@ -2862,20 +2991,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(pci_autoirq == PARPORT_IRQ_AUTO && dev->irq)
    + irq=dev->irq;
    + else
    + irq=PARPORT_IRQ_NONE;
    +
    + printk (KERN_DEBUG "PCI parallel port detected: %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++;
             }
    @@ -2957,6 +3091,9 @@
             /* ISA ports and whatever (see asm/parport.h). */
             count += parport_pc_find_nonpci_ports (autoirq, autodma);
     
    +#ifdef CONFIG_PCI
    + pci_autoirq=autoirq;
    +#endif /* CONFIG_PCI */
             r = pci_register_driver (&parport_pc_pci_driver);
             if (r >= 0) {
                     registered_parport = 1;
    @@ -3012,10 +3149,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 Wed Dec 3 22:53:31 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)

    -- To unsubscribe, send mail to: linux-parport-request@torque.net --
    -- with the single word "unsubscribe" in the body of the message. --



    This archive was generated by hypermail 2b29 : Thu Dec 11 2003 - 19:13:58 EST