[PARPORT] Superio-4 for Linux-2.3-99pre6, please test

From: Gunther Mayer (gunther.mayer@braunschweig.okersurf.de)
Date: Mon May 01 2000 - 12:38:25 EDT

  • Next message: Andrew Godfrey: "Re: [Re: [PARPORT] Errors with cdrecord]"

    Hi,
    this new patch against linux-2.3.99pre6 detects nearly all super io
    chips
    from all vendors with publicly available data sheets (or at least
    data sheets I was able to find :-)

    This code autodetects DMA and IRQ when this
    info is easily available from the superio chipset.

    Please test with "insmod parport_pc irq=auto dma=auto"
    and report success and failure directly to me (please compare
    the reported chipset to your mainboard, too).

    Regards, Gunther

    NEW in this patch:
    - Rework for common MB-PnP mode
    - Detect ITE, ALI and Intel
    - Detect more SMSC and Nat Semi
    - Fixes
    - Set DMA and IRQ hints
    - incl. PCI SYBA patch and verbose PCI detection


    --- parport_pc.c-2.3.99pre7 Sat Apr 29 21:56:28 2000
    +++ parport_pc.c Mon May 1 18:21:33 2000
    @@ -1035,14 +1035,162 @@
     };
     
     #ifdef CONFIG_PARPORT_PC_SUPERIO
    -/* Super-IO chipset detection, Winbond, SMSC */
    +/* Super-IO chipset detection, Winbond, SMSC, National Semiconductor etc. (EXPERIMENTAL)
    +
    + Once upon a time there were single purpose chips or even dicrete TTL logic (e.g.
    + the parallel port) on ISA add-on cards. The register interface and functionality
    + was dictated by compatibilty to the de facto IBM PC-Standard. Many manufacturers
    + built these and some even improved functionality (e.g. serial FIFO) only to become
    + itself a de facto standard (e.g. 16550A compatible). Others introduced their own
    + hardware bugs or flaws, unfortunately.
    +
    + Soon some of these were integrated on a single chip. These Multi I/O chips
    + were jumper-configurable for IO, IRQ, etc. The Winbond 83757,777,778 is a popular example.
    + Configuration was error prone and uncomfortable for the user.
    +
    + The Super I/O chips were destined for mainboard integration and are fully software
    + configurable (although many can start with default compatible settings). Many aspects can
    + be configured by the BIOS, but the quality of support depends on the BIOS vendor.
    +
    + The configuration had to be done via IO accesses and there was no common method
    + (like ISA PnP) at these days. So vendors invented their own method: choose two
    + ports that don't conflict with legacy systems and use these as index and data register.
    + The ports chosen were e.g. Read-Only in legacy systems (e.g. 3F0, 370, ...), or otherwise
    + chosen (26E, 398, ...). (Note: the same applies to onboard integrated chipsets of these days
    + (e.g. Opti, Eteq, UMC, SiS, C&T, these used port 0x22,34,24, etc).
    + The configuration regoster layout was proprietary but since some years is oriented
    + on the ISA PnP standard (called mainboard PnP). Some newer chips have real ISAPnP modes.
    + Optionally you have to write a magic sequence of bytes to "open" and "close" configuration
    + mode.
    +
    + To protect against accidential access you can "lock" and hide the configuration by setting
    + some bits, or you can relocate the configuration register pair at your will. If this
    + is done by your BIOS there is no way to detect these...
    +
    + Astonishing it seems possible to identify these parts despite there was no cooperative
    + effort by the manufacturers and many BIOSes do not lock access or relocate:-)
    +
    + This probe currently does it's best being untested on most parts !!!
    + Currently it probes for ALL chips, although you should stop after having detected ONE super I/O
    + chipset. This shall help to identify false detections (negative and positive) and further
    + finetune the routines ...
    +
    + The parallel port suffered in early days by vendor dependend hardware flaws and features,
    + so it is necessary to identify these chips to improve quality of bug reports and further
    + developing. Now you can identify your chip without opening your case! And you are even
    + given further information on configuration aspects that could not be derived by other means.
    +
    + The right forum to discuss issues with this code is the Parport Mailing List on
    + <linux-parport@torque.net> 01apr2000 gm.
    +
    + Another effect for your comfort is improved autodetection of IO/IRQ/DMA and mode of your
    + parallel port. It is unclear if EPP-BIOS would be helpful as it is unknown how wide-spread
    + it's implementation in ROM-BIOS is. However EPP-BIOS would give IO, IRQ and port mode,
    + but it misses DMA channel.
    +
    + Notes:
    + (1) EPP-BIOS has nothing to to with EPP-mode, neither IEEE1284(EPP1.9) nor pre-IEEE1284(1.7),
    + Of course this BIOS supports IEEE1284-ECP mode in most cases.
    + (2) ECP is used with two different meanings:
    + a) ECP as IEEE1284-ECP mode.
    + A physical/electrical transfer protocol over the parallel port as defined by IEEE1284.
    + You can speak ECP mode even over a SPP (Standard Paralllel Port), although slower in
    + comparison to some chipsets that support this in hardware.
    + b) ECP as a ISA-ECP.
    + A register set standard for the ISA bus, as defined by Microsoft et al.
    + Of course ISA-ECP supports the IEEE1284-ECP mode :-)
    + This defines how to let your hardware speak ECP natively.
    +
    + Offtopic:
    + As another side effect other drivers could benefit from this detections as you can get
    + plenty of information about FDC, Serial Port, Infrared Support, Power Management (Legacy,
    + APM and ACPI), KBC, X-Bus, etc. Some newer chips integrate Hardware Monitoring, a watchdog
    + or even a smart card reader interface...
    + Hint: People with buggy APM-BIOS could use this to soft power off their machine directly by
    + fiddling with the right bits (don't ask, I never tried). This is the right place to dive into
    + SMM/SMI BIOS/chipset interactions for the adventureous hacker, too :-)
    + */
    +
    +static void __devinit show_parconfig_winbond_877(int io, int key, int oldid)
    +{
    + int cr0,cr3,cr4,cr5,cr9,cr17,cr23,cr26,cr27,cr31=0,cr32=0;
    + int efir,efdr;
    + char *modes[]= { "reserved", "EPP", "ECP", "ECP+EPP"};
    +
    + if(io==0x3f0) {
    + outb(key,io);
    + outb(key,io);
    + efir=io;
    + efdr=io+1;
    + } else { /* 0x250 */
    + outb(key,io);
    + efir=io+1;
    + efdr=io+2;
    + }
    +#define sreg(cr,x) { outb(x,efir); cr=inb(efdr); }
    + sreg(cr0,0);
    + sreg(cr3,3);
    + sreg(cr4,4);
    + sreg(cr5,5);
    + sreg(cr9,9);
    + sreg(cr17,0x17);
    + sreg(cr23,0x23);
    + sreg(cr26,0x26);
    + sreg(cr27,0x27);
    + if(oldid>0x0b) {
    + sreg(cr31,0x31);
    + sreg(cr32,0x32);
    + }
    +#undef sreg
    + outb(0xaa,io);
    +
    + printk("Winbond 83877xx LPT Config cr0=%02x cr3=%02x"
    + "cr4=%02x cr5=%02x cr9=%02x cr17=%02x cr23=%02x"
    + " cr26=%02x cr27=%02x cr31=%02x",
    + cr0,cr3,cr4,cr5,cr9,cr17,cr23,cr26,cr27,cr31);
    +
    + printk ("W83877 LPT Config: io=0x%04x, irq=%c, dma=%c, "
    + "fifo threshold=%d\n", cr23*4,
    + (cr27 &0x0f) ? 'A'-1+(cr27 &0x0f): '-',
    + (cr26 &0x0f) ? 'A'-1+(cr26 &0x0f): '-', cr5 & 0x0f);
    + printk("W83877 LPT Config: enabled=%s power=%s\n",
    + (cr23*4 >=0x100) ?"yes":"no", (cr4 & 0x80) ? "yes" : "no");
    + printk("W83877 LPT Config: Port mode=%s, EPP version =%s\n",
    + (cr9 & 0x80 ) ? modes[(cr0>>2) & 0x03] :
    + (((cr0>>2) & 0x03)?"non parallel": "SPP"),
    + (cr3 & 0x10) ? "1.7" : "1.9");
    + printk("W83877 LPT Config: IRQ line is totem pole in %s",
    + cr17 & 0x10 ? "all modes": "SPP mode/open drain in ECP/EPP");
    + printk("W83877 LPT Config: IRQ %ss AckIntEnable Bit\n",
    + cr17 &0x04 ? "ignore" : "obey");
    +
    + if(oldid>0x0b) {
    + if( cr31 &0x04) printk("W83877 in serial PCI-IRQ mode\n");
    + printk("W83877 Power Management=%sabled,"
    + "LPT auto power management=%sabled\n",
    + (cr32&0x80) ? "en": "dis", (cr32&0x08)? "en": "dis");
    + }
    +}
    +/* Fill out a hint derived from superio detection.
    + This can be picked up later by the normal autodetect code...
    + */
    +void set_superio_hint(int io,int irq,int dma)
    +{ int i=0;
    + while((superios[i].io!= 0) && (i<NR_SUPERIOS))
    + i++;
    + if(i==NR_SUPERIOS)
    + printk("Super-IO: too many chips!\n");
    + else {
    + superios[i].io = io;
    + superios[i].irq = irq;
    + superios[i].dma = dma;
    + }
    +}
    +
     static void __devinit show_parconfig_smsc37c669(int io, int key)
     {
    - int cr1,cr4,cra,cr23,cr26,cr27,i=0;
    - char *modes[]={ "SPP and Bidirectional (PS/2)",
    - "EPP and SPP",
    - "ECP",
    - "ECP and EPP"};
    + int cr1,cr4,cra,cr23,cr26,cr27;
    + char *modes[]={ "SPP+bidir", "EPP", "ECP", "ECP+EPP"};
     
             outb(key,io);
             outb(key,io);
    @@ -1074,7 +1222,7 @@
             printk("SMSC LPT Config: enabled=%s power=%s\n",
                    (cr23*4 >=0x100) ?"yes":"no", (cr1 & 4) ? "yes" : "no");
             printk("SMSC LPT Config: Port mode=%s, EPP version =%s\n",
    - (cr1 & 0x08 ) ? "Standard mode only (SPP)" : modes[cr4 & 0x03],
    + (cr1 & 0x08 ) ? "SPP" : modes[cr4 & 0x03],
                    (cr4 & 0x40) ? "1.7" : "1.9");
     
             /* Heuristics ! BIOS setup for this mainboard device limits
    @@ -1082,93 +1230,133 @@
                are related, however DMA can be 1 or 3, assume DMA_A=DMA1,
                DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */
             if(cr23*4 >=0x100) { /* if active */
    - while((superios[i].io!= 0) && (i<NR_SUPERIOS))
    - i++;
    - if(i==NR_SUPERIOS)
    - printk("Super-IO: too many chips!\n");
    - else {
    - int d;
    - switch (cr23*4) {
    - case 0x3bc:
    - superios[i].io = 0x3bc;
    - superios[i].irq = 7;
    - break;
    - case 0x378:
    - superios[i].io = 0x378;
    - superios[i].irq = 7;
    - break;
    - case 0x278:
    - superios[i].io = 0x278;
    - superios[i].irq = 5;
    - }
    - d=(cr26 &0x0f);
    - if((d==1) || (d==3))
    - superios[i].dma= d;
    - else
    - superios[i].dma= PARPORT_DMA_NONE;
    + int d,sio=0,irq=0;
    + d=(cr26 &0x0f);
    + switch (cr23*4) {
    + case 0x3bc:
    + sio = 0x3bc;
    + irq = 7;
    + break;
    + case 0x378:
    + sio = 0x378;
    + irq = 7;
    + break;
    + case 0x278:
    + sio = 0x278;
    + irq = 5;
                     }
    + set_superio_hint(sio,irq,((d==1) || (d==3))? d: PARPORT_DMA_NONE);
              }
     }
     
    +void show_parconfig_pc87306(int io)
    +{ int a=0,i=0,cr0,cr1,cr3,cr4,cr7,cr18,cr19,cr1b;
    +
    +#define sreg(cr,x) { outb(x,io); cr=inb(io+1); }
    + sreg(cr0,0);
    + sreg(cr1,1)
    + sreg(cr3,3);
    + sreg(cr4,4);
    + sreg(cr7,7);
    + sreg(cr18,0x18);
    + sreg(cr19,0x19);
    + sreg(cr1b,0x1b);
    +#undef sreg
    +
    + switch (cr1&0x03) {
    + case 0x00:
    + a=0x378; i=5;
    + if(cr1b & 0x20 ) i=7; /* see datasheet NOTE 1 */
    + break;
    + case 0x01:
    + a=0x3bc; i=7;
    + if(cr1b&0x40) a=cr19*4; /* see datasheet NOTE 2 */
    + break;
    + case 0x02: a=0x278; i=5; break;
    + case 0x03: a=0; break; /* reserved */
    + }
    +
    + if(cr1b & 0x10) { /* this overrides address dependent irq selection */
    + if(cr1b & 0x20 )
    + i=7;
    + else
    + i=5;
    + }
    +
    + printk("PC87306 LPT enabled=%s io=0x%04x irq=%d dmaLine=PDRQ%d (see ECPcnfgDMA)\n",
    + cr0&1? "yes":"no", a,i,cr18&0x08 ? 1:0);
    + /* This chip is EPP XOR ECP. Can select between 2 DMA Lines, but wiring up to vendor */
    + printk("PC87306 EPP=%s%s ECP=%s Bidir=%s\n",
    + cr4&0x01?"yes":"no" , cr4&0x01 ? ( cr4&0x02 ? "(1.9)": "(1.7)") : "",
    + cr4&0x04?"yes":"no" , cr3&0x80?"yes":"no");
    + printk("PC83706 IRQ polarity=%s, IRQ line=%s, ECPcnfgDMA=%d\n EPPtimeoutIRQ=%s",
    + cr4&0x10 ? "highLevel/negativePulse": "inverted(huh!?)",
    + cr4&0x20 ? "totem pole":"open drain", cr18&0x03,
    + cr7&0x04 ? "enabled":"masked");
    + /* set the hints for the normal autodetect code */
    + if(cr0 & 0x01)
    + set_superio_hint(a,i,PARPORT_DMA_NONE);
    +}
    +/* Read the common PnP registers for io,irq and dma,
    + Verbosely decode it,
    + Set the hint */
    +void read_and_decode_pnp(int io, int ldn)
    +{
    + int cr30,cr60,cr61,cr70,cr74;
    +
    + outb(7,io);
    + outb(ldn,io+1); /* Select LDN for parallel port */
    +
    +#define sreg(cr,x) { outb(x,io); cr=inb(io +1); }
    + /* Read PnP Register */
    + sreg(cr30,0x30); /* active */
    + sreg(cr60,0x60); /* io */
    + sreg(cr61,0x61);
    + sreg(cr70,0x70); /* irq */
    + sreg(cr74,0x74); /* dma */
    +#undef sreg
    +
    +
    + if(cr30 & 0x01) {
    + printk("LPT(MB-PnP) at 0x%x irq=", cr60*256+cr61);
    + if (cr70&0x0f)
    + printk("%d", cr70&0x0f);
    + else
    + printk("none");
    + if ((cr74&0x07) < 4)
    + printk(" dma=%d\n", cr74&0x07);
    + else
    + printk(" dma=none\n");
    +
    + /* fill out the hint for autodetect code ...*/
    + set_superio_hint( cr60*256+cr61,
    + (cr70&0x0f) ? (cr70&0x0f) : PARPORT_IRQ_NONE,
    + ((cr74&0x07) < 4) ? (cr74&0x07) : PARPORT_DMA_NONE);
    + }
    + else
    + printk("LPT has been disabled by your BIOS.\n");
    +}
    +
    +
     
     static void __devinit show_parconfig_winbond(int io, int key)
     {
    - int cr30,cr60,cr61,cr70,cr74,crf0,i=0;
    - char *modes[]={ "Standard (SPP) and Bidirectional(PS/2)", /* 0 */
    - "EPP-1.9 and SPP",
    - "ECP",
    - "ECP and EPP-1.9",
    - "Standard (SPP)",
    - "EPP-1.7 and SPP", /* 5 */
    - "undefined!",
    - "ECP and EPP-1.7"};
    + int crf0;
    + char *modes[]={ "SPP+bidir", "EPP-1.9", "ECP", "ECP+EPP-1.9",
    + "SPP", "EPP-1.7", "undefined!", "ECP+EPP-1.7"};
             char *irqtypes[]={"pulsed low, high-Z", "follows nACK"};
                     
    - /* The registers are called compatible-PnP because the
    - register layout is modelled after ISA-PnP, the access
    - method is just another ... */
    - outb(key,io);
    + outb(key,io); /* Open again */
             outb(key,io);
    - outb(0x07,io); /* Register 7: Select Logical Device */
    - outb(0x01,io+1); /* LD1 is Parallel Port */
    - outb(0x30,io);
    - cr30=inb(io+1);
    - outb(0x60,io);
    - cr60=inb(io+1);
    - outb(0x61,io);
    - cr61=inb(io+1);
    - outb(0x70,io);
    - cr70=inb(io+1);
    - outb(0x74,io);
    - cr74=inb(io+1);
    +
    + read_and_decode_pnp(io,1); /* LDN 1 is parallel port */
             outb(0xf0,io);
             crf0=inb(io+1);
    - outb(0xaa,io);
    + outb(0xaa,io); /* close config */
     
    - printk("Winbond LPT Config: cr_30=%02x 60,61=%02x%02x "
    - "70=%02x 74=%02x, f0=%02x\n", cr30,cr60,cr61,cr70,cr74,crf0);
    - printk("Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ",
    - (cr30 & 0x01) ? "yes":"no", cr60,cr61,cr70&0x0f );
    - if ((cr74 & 0x07) > 3)
    - printk("dma=none\n");
    - else
    - printk("dma=%d\n",cr74 & 0x07);
             printk("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n",
                    irqtypes[crf0>>7], (crf0>>3)&0x0f);
             printk("Winbond LPT Config: Port mode=%s\n", modes[crf0 & 0x07]);
    -
    - if(cr30 & 0x01) { /* the settings can be interrogated later ... */
    - while((superios[i].io!= 0) && (i<NR_SUPERIOS))
    - i++;
    - if(i==NR_SUPERIOS)
    - printk("Super-IO: too many chips!\n");
    - else {
    - superios[i].io = (cr60<<8)|cr61;
    - superios[i].irq = cr70&0x0f;
    - superios[i].dma = (((cr74 & 0x07) > 3) ?
    - PARPORT_DMA_NONE : (cr74 & 0x07));
    - }
    - }
     }
     
     static void __devinit decode_winbond(int efer, int key, int devid, int devrev, int oldid)
    @@ -1188,53 +1376,90 @@
             /* Values are from public data sheets pdf files, I can just
                confirm 83977TF is correct :-) */
             if (id == 0x9771) type="83977F/AF";
    - else if (id == 0x9773) type="83977TF / SMSC 97w33x/97w34x";
    - else if (id == 0x9774) type="83977ATF";
    + else if (id == 0x9773) type="83977TF / SMSC 97w33x";
    + else if (id == 0x9774) type="83977ATF / SMSC 97w34x";
             else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x";
             else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97w35x";
    - else if ((id & ~0x0f) == 0x5210) type="83627";
    + else if ((id & ~0x0f) == 0x5210) type="83627 / SMSC LPC61w49x";
             else if ((id & ~0x0f) == 0x6010) type="83697HF";
    - else if ((oldid &0x0f ) == 0x0a) { type="83877F"; progif=1;}
    - else if ((oldid &0x0f ) == 0x0b) { type="83877AF"; progif=1;}
    - else if ((oldid &0x0f ) == 0x0c) { type="83877TF"; progif=1;}
    + else if ((oldid &0x0f ) == 0x0a) { type="83877F /SMSC 87w22"; progif=1;}
    + else if ((oldid &0x0f ) == 0x0b) { type="83877AF /SMSC 87w21"; progif=1;}
    + else if ((oldid &0x0f ) == 0x0c) { type="83877TF /SMSC 87w23"; progif=1;}
             else if ((oldid &0x0f ) == 0x0d) { type="83877ATF"; progif=1;}
             else progif=0;
     
    - if(type==NULL)
    - printk("Winbond unknown chip type\n");
    - else
    - printk("Winbond chip type %s\n",type);
    + if(type==NULL)
    + printk("Winbond unknown chip type\n");
    + else {
    + printk("Winbond chip type %s\n",type);
    + if(progif==2)
    + show_parconfig_winbond(efer,key);
    + else /* progif==1 */
    + show_parconfig_winbond_877(efer,key,oldid);
    + }
     
    - if(progif==2)
    - show_parconfig_winbond(efer,key);
             return;
     }
     
    -static void __devinit decode_smsc(int efer, int key, int devid, int devrev)
    +static void __devinit decode_smsc(int efer, int key, int oldid, int oldrev, int id, int rev)
     {
             char *type=NULL;
    - void (*func)(int io, int key);
    - int id;
    -
    - if (devid == devrev)
    - /* simple heuristics, we happened to read some
    - non-winbond register */
    - return;
    -
    - func=NULL;
    - printk("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x\n",
    - efer,key,devid,devrev);
    - id=(devid<<8) | devrev;
    -
    - if (id==0x0302) {type="37c669"; func=show_parconfig_smsc37c669;}
    - else if (id==0x6582) type="37c665IR";
    - else if ((id==0x6502) && (key==0x44)) type="37c665GT";
    - else if ((id==0x6502) && (key==0x55)) type="37c666GT";
    + void (*func)(int io, int key)=NULL;
    + int idrev,oldidrev,ldn=-1;
    + char *modes[8]={ "SPP+bidir", "EPP1.9", "ECP", "ECP+EPP1.9",
    + "SPP", "EPP1.7", "reserved", "ECP+EPP1.7" };
    +
    + if ((oldid == oldrev) && (id == rev))
    + /* simple heuristics, we happened to read some
    + non-smsc register */
    + return;
    +
    + printk("SMSC chip at EFER=0x%x key=0x%02x id=%02x rev=%02x\n"
    + "oldid=0x%02x oldrev=0x%02x\n",
    + efer,key,id,rev,oldid,oldrev);
    + oldidrev=(oldid<<8) | oldrev;
    + idrev=(id<<8)|rev;
    +
    + if (oldidrev==0x0302) {type="37c669"; ldn=-1;
    + func=show_parconfig_smsc37c669;}
    + else if (oldid==0x40) { type="37c669FR"; ldn=-1;}
    + else if (oldidrev==0x6582) { type="37c665IR"; ldn=-1;}
    + else if (oldid==0x65) { type="37c665GT"; ldn=-1;}
    + else if (oldid==0x66) { type="37c666GT"; ldn=-1;}
    + else if (oldid==0x28) { type="37n869"; ldn=-1;/* "n" notifies notebook ? */ }
    + else if (oldid==0x29) { type="37n769"; ldn=-1;}
    + else if (oldid==0x5a) { type="47n227"; ldn=-1;}
    + else if (oldid==0x78) { type="FDC37c78"; ldn=-1; /* Floppy disk only */ }
    + else if (idrev==0x0201) { type="37c93x"; ldn=3;}
    + else if (idrev==0x0301) { type="37c93xFR"; ldn=3;}
    + else if (idrev==0x3001) { type="37c93xAPM"; ldn=3;}
    + else if (id==0x09) { type="37n958"; ldn=3;}
    + else if (id==0x0a) { type="37n971"; ldn=3;}
    + else if (id==0x0b) { type="37n972"; ldn=3;}
    + else if (id==0x40) { type="37c67"; ldn=3;}
    + else if (id==0x42) { type="37m70 / 37b80"; ldn=3;}
    + else if (id==0x43) { type="37b77"; ldn=3;}
    + else if (id==0x44) { type="37b78"; ldn=3;}
    + else if (id==0x47) { type="37m60"; ldn=3;}
    + else if (id==0x48) { type="37c68"; ldn=3;}
    + else if (id==0x4c) { type="37b72"; ldn=3;}
    + else if (id==0x4d) { type="37m81"; ldn=3;}
    + else if (id==0x51) { type="47b27"; ldn=3;}
    + else if (id==0x52) { type="47b37"; ldn=3;}
    + else if (id==0x54) { type="47u32/33"; ldn=3;}
    + else if (id==0x56) { type="47b34"; ldn=3;}
    + else if (id==0x57) { type="47s42"; ldn=3;}
    + else if (id==0x59) { type="47m10"; ldn=3;}
    +
    + if(ldn>0) {
    + int crf0;
    + read_and_decode_pnp(efer,ldn);
    + outb(0xf0,efer);
    + crf0=inb(efer+1);
    + printk("LPT mode=%s FIFO thresh.=%d\n", modes[crf0&7], (crf0>>3)&0x0f);
    + }
     
    - if(type==NULL)
    - printk("SMSC unknown chip type\n");
    - else
    - printk("SMSC chip type %s\n",type);
    + printk("SMSC chip type %s\n",type? type:"unknown");
     
             if(func) (func)(efer,key);
             return;
    @@ -1270,7 +1495,7 @@
             decode_winbond(io,key,devid,devrev,oldid);
     }
     
    -static void __devinit winbond_check2(int io,int key)
    +static void __devinit winbond_check1(int io,int key)
     {
             int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
     
    @@ -1323,17 +1548,284 @@
             id=inb(io+1);
             outb(0x21,io);
             rev=inb(io+1);
    - outb(0xaa,io); /* Magic Seal */
     
             if ((x_id == id) && (x_oldrev == oldrev) &&
                 (x_oldid == oldid) && (x_rev == rev))
                     return; /* protection against false positives */
     
    - decode_smsc(io,key,oldid,oldrev);
    + decode_smsc(io,key,oldid,oldrev,id,rev);
    + outb(0xaa,io); /* Magic Seal */
     }
     
    +static void ns_check(int io) /* No key !? */
    +{
    + int id,cr8,cr21,cr27,r,ldn=0;
    + char *type=NULL;
    + void (*func)(int io)=NULL;
    + char *modes[8]= { "SPP", "SPP+bidir", "EPP1.7", "EPP1.9",
    + "ECP", "reserved", "reserved", "ECP+EPP" };
    +
    + outb(0x20,io); /* Write EFIR, extended function index register */
    + r=inb(io);
    + if (r!=0x20) return; /* read back, all bits must be writable */
    + id=inb(io+1);
    + outb(0x21,io); /* ID for PnP chips */
    + cr21=inb(io+1);
    + outb(0x27,io); /* chip revision */
    + cr27=inb(io+1);
    + outb(0x08,io); /* ID for older chips */
    + cr8=inb(io+1);
    +
    + if ((id == cr21) && (id==cr8))
    + /* simple heuristics, we happened to read some
    + non-NS register */
    + return;
    +
    + printk("National Semiconductor chip at EFER=0x%x id=0x%02x cr21=0x%02x cr27=0x%02x cr8=0x%02x",
    + io,id,cr21,cr27,cr8);
    + switch(id) {
    + case 0xc0: type="PC87307"; ldn=4; break;
    + case 0xcf: type="PC97307"; ldn=4; break;
    + case 0xd0: type="PC87317"; ldn=4; break;
    + case 0xdf: type="PC97317"; ldn=4; break; /* modes OK*/
    + case 0xe0: type="PC87309"; ldn=1; break; /* modes OK */
    + case 0xe1: type="PC87360"; ldn=1; *modes=NULL; break;
    + case 0xe2: type="PC87351"; ldn=1; break; /*modes ok*/
    + case 0xe4: type="PC87364"; ldn=1; *modes=NULL; break;
    + case 0xe8: type="PC87363"; ldn=1; *modes=NULL; break;
    + case 0xe9: type="PC87366"; ldn=1; *modes=NULL; break;
    + }
    + if(id==0) {
    + switch(cr8&0xf0) { /* bits 0-2/3 for Revision */
    + case 0x10: type="PC87332"; break;
    + case 0x30: type="PC87303"; break;
    + case 0x50: type="PC87334"; break;
    + case 0x70: type="PC87306"; func=show_parconfig_pc87306; break;
    + case 0xb0: type="PC87338"; break;
    + }
    + }
    + if(ldn) {
    + int crf0;
    + read_and_decode_pnp(io,ldn);
    + outb(0xf0,io);
    + crf0=inb(io+1);
    + printk("LPT mode= %s\n", modes ? modes[(crf0>>5)&0x07]: "detection not yet here");
    + }
    + printk("National Semiconductor chip type %s\n",type ? type: "unknown");
    + if(func) (func)(io);
    +}
    +
    +static void ns_check94(int io)
    +{
    + int r;
    + char *type="";
    +
    + outb(0xff,io);
    + r=inb(io);
    +
    + if((r!=0x07 ) && (r!=0x03))
    + return;
    +
    + if(r==0x07) type="PC87322"; /* Bits 3-7 read back as zero */
    + if(r==0x03) type="PC87311/312"; /* Bits 2-7 read back as zero */
    +
    + printk("National Semiconductor chip at EFER=0x%x readback=0x%02x type %s\n"
    + ,io,r,type);
    +}
    +
    +static void intel_check_aip(int io)
    +{
    + int id,rev,rb;
    + outb(0x00,io); /* No key */
    + id=inb(io+1);
    + outb(0x01,io);
    + rev=inb(io+1);
    + outb(0xff,io);
    + rb=inb(io);
    +
    + if(id==0x0a) {
    + printk("Intel 82091AA chip at %x Rev=0x%02x rb=%02x\n",io,rev,rb);
    + }
    +}
    +
    +static void decode_ite(int io,int x_cr20,int x_cr21,int x_cr22,int cr20,int cr21,int cr22);
    +
    +static void ite_check_279(int a)
    +{ int i,cr20,cr21,cr22,x_cr20,x_cr21,x_cr22;
    + int pnpkey[32]={ 0x6a, 0xb5, 0xda, 0xed, 0xf6, 0xfb, 0x7d, 0xbe,
    + 0xdf, 0x6f, 0x37, 0x1b, 0x0d, 0x86, 0xc3, 0x61,
    + 0xb0, 0x58, 0x2c, 0x16, 0x8b, 0x45, 0xa2, 0xd1,
    + 0xe8, 0x74, 0x3a, 0x9d, 0xce, 0xe7, 0x73, 0x39 };
    +
    +#define sreg(cr,x) { outb(x,0x370); cr=inb(0x371); }
    +
    + sreg(x_cr20,0x20);
    + sreg(x_cr21,0x21);
    + sreg(x_cr22,0x22);
    +
    + outb(0,0x279);
    + outb(0,0x279); /* 2 writes to ensure known state of the key detect logic */
     
    -static void __devinit detect_and_report_winbond (void)
    + outb(0x86,0x279);
    + outb(a, 0x279);
    + outb(0xaa,0x279);
    + outb(0x55,0x279); /* Enable port 370 */
    +
    + for(i=0;i<32;i++)
    + outb(pnpkey[i],0x370); /* Enter MB PnP mode */
    +
    + sreg(cr20,0x20);
    + sreg(cr21,0x21);
    + sreg(cr22,0x22);
    +#undef sreg
    +
    + decode_ite(0x370,x_cr20,x_cr21,x_cr22,cr20,cr21,cr22);
    +}
    +static void ite_check_2e(int a)
    +{ int cr20,cr21,cr22,x_cr20,x_cr21,x_cr22;
    +
    +#define sreg(cr,x) { outb(x,0x2e); cr=inb(0x2e +1); }
    + sreg(x_cr20,0x20);
    + sreg(x_cr21,0x21);
    + sreg(x_cr22,0x22);
    +
    + outb(0x87,0x2e);
    + outb(a ,0x2e);
    + outb(0x55,0x2e);
    + /*enable MB PnP at port 4e. Avoid 0x55 for port 2e,
    + because of conflicts with LPC SMSC chips,
    + luckily this is even closed by 0xaa !
    + */
    + outb(0xAA,0x2e);
    +
    +#undef sreg
    +#define sreg(cr,x) { outb(x,0x4e); cr=inb(0x4e +1); }
    + sreg(cr20,0x20);
    + sreg(cr21,0x21);
    + sreg(cr22,0x22);
    +#undef sreg
    +
    + decode_ite(0x4e,x_cr20,x_cr21,x_cr22,cr20,cr21,cr22);
    +}
    +
    +static void decode_ite(int io,int x_cr20,int x_cr21,int x_cr22,int cr20,int cr21,int cr22)
    +{
    + int cr30,cr62,cr63,crf0;
    + char *types[4]= { "SPP/bidir", "EPP", "ECP", "ECP+EPP"};
    +
    + if((x_cr20==cr20)&& (x_cr21==cr21) && (x_cr22==cr22))
    + return; /* protect against false positives */
    +
    +
    + if( cr21 !=0x61)
    + read_and_decode_pnp(io,3); /* assume all ITE chips have LDN 3 for parallel port*/
    +#define sreg(cr,x) { outb(x,io); cr=inb(io +1); }
    + sreg(cr30,0x30);
    + sreg(cr62,0x62); /* hi io */
    + sreg(cr63,0x63);
    + sreg(crf0,0xf0);
    +#undef sreg
    +
    + outb(0x02,io); /* select cr2 */
    + outb(0x02,io+1); /* close device by setting bit 1 */
    +
    + printk("ITE chip %02X%02X Rev 0x%02x detected at port 0x%x\n",
    + cr20,cr21,cr22,io);
    + /* SiS6801/2 is the same as 8661 */
    +
    + if(cr21 ==0x61) {
    + printk("This ITE chip has no parallel port.\n");
    + return;
    + }
    +
    + if(cr30 & 0x01)
    + printk("LPT hi port=%x type=%s\n",cr62*256+cr63,types[crf0 &0x03]);
    +}
    +
    +void ali_check1(int io)
    +{ int rev,d,cr1,cra,crb,crc,iio=0,irq;
    + char *modes[4]={ "SPP+bidir", "EPP", "ECP", "ECP+EPP" };
    + char *eppmodes[4]={"1.7","1.7","1.9","brief"};
    +
    + outb(0x51,io);
    + outb(0x29,io);
    + if(inb(io) != 0x93 ) return; /* dummy read should return 0x93 ! */
    +
    + outb(0xff,io); /* register ff */
    + rev=inb(io);
    +#define sreg(cr,x) { outb(0x51,io); outb(0x29,io); d=inb(io); outb(x,io); cr=inb(io); }
    + sreg(cr1,0x11);
    + sreg(cra,0xaa);
    + sreg(crb,0xbb);
    + sreg(crc,0xcc);
    +#undef sreg
    +
    + printk("ALI 5113 detected at 0x%x, Rev=0x%02x cr a,b,c=0x%02x,%02x,%02x\n",
    + io,rev,cra,crb,crc);
    + if(cra & 0x01) {
    + switch((crb>>2)& 0x03) {
    + case 0 : iio=0; break;
    + case 1 : iio=0x3bc; break;
    + case 2 : iio=0x378; break;
    + case 3 : iio=0x278; break;
    + }
    + if(cr1 & 0x10)
    + irq=9;
    + else if (((crc>>6) & 3 ) == 3 )
    + irq=5;
    + else
    + irq=7;
    +
    + printk("LPT at 0x%x irq=%d dma=? mode=%s %s\n", iio, irq,
    + (crb&0x40) ? "SPP": modes[(crb>>4)& 3],
    + (crb&0x10) ? eppmodes[(cra>>2)&3] : "");
    + printk("LPT PP DMA burst mode=%s Auto Powerdown=%s FIFO Thres=%d\n",
    + (cra&1)? "yes":"no", (crb&0x80) ? "yes":"no",
    + ((cra>>4) & 0xf)? ((cra>>4) & 0xf) : 16);
    +
    + /* fill out the hint for autodetect code ...*/
    + set_superio_hint(iio,irq,PARPORT_DMA_NONE);
    + }
    + else
    + printk("LPT has been disabled by your BIOS!\n");
    +}
    +
    +void ali_check_pnp(int io)
    +{
    + int cr20,cr21,crf0,crf1,x_cr20,x_cr21,cr30;
    + char * modes[8]={ "SPP+bidir", "EPP1.9", "ECP", "ECP+EPP1.9",
    + "SPP", "EPP1.7", "undefined", "ECP+EPP1.7" };
    +#define sreg(cr,x) { outb(x,io); cr=inb(io +1); }
    + sreg(x_cr20,0x20);
    + sreg(x_cr21,0x21);
    +
    +
    + outb(0x51,io); /* key */
    + outb(0x23,io);
    +
    + sreg(cr20,0x20); /* ID */
    + sreg(cr21,0x21);
    + sreg(cr30,0x30);
    +
    + if((x_cr20==cr20) && (x_cr21==cr21))
    + return; /* protect against false positives */
    +
    + read_and_decode_pnp(io,3 ); /* Assume LDN for parallel port, true for 512x,513x */
    + sreg(crf0,0xf0);
    + sreg(crf1,0xf1);
    +#undef sreg
    +
    + outb(0xbb,io); /* close config */
    +
    + printk("ALI M%02x%02x at 0x%x detected\n",cr21,cr20,io);
    + if(cr30&0x1)
    + printk("LPT mode=%s, FIFO Thres=%d, EPP time-out irq=%sabled\n",
    + modes[crf0&7], (crf0 >> 3)&0x0f, (crf1 & 1) ? "en":"dis");
    +}
    +
    +
    +
    + void detect_and_report_winbond (void)
     {
             printk("Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n");
     
    @@ -1342,18 +1834,58 @@
             winbond_check(0x2e ,0x87);
             winbond_check(0x4e ,0x87);
             winbond_check(0x3f0,0x86);
    - winbond_check2(0x250,0x88);
    - winbond_check2(0x250,0x89);
    + winbond_check1(0x250,0x88);
    + winbond_check1(0x250,0x89);
     }
     
     static void __devinit detect_and_report_smsc (void)
     {
    - printk("SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n");
    + printk("SMSC Super-IO detection, now testing Ports 2F0, 370, 2E, 4E ...\n");
             smsc_check(0x3f0,0x55);
             smsc_check(0x370,0x55);
             smsc_check(0x3f0,0x44);
             smsc_check(0x370,0x44);
    + smsc_check(0x2e,0x55); /* LPC chips */
    + smsc_check(0x4e,0x55);
     }
    +static void detect_and_report_natsemi (void)
    +{
    + printk("National Semiconductor Super-IO detection,now testing port 2E,4E,15C,26E,398 ...\n");
    + ns_check(0x2e);
    + ns_check(0x4e); /* PC8736x */
    + ns_check(0x15c);
    + ns_check(0x26e);
    + ns_check(0x398); /* PC8733x /8731x !? */
    + ns_check94(0x26e); /* these port were used until 1994 ? */
    + ns_check94(0x398);
    + /* ns_check_87310(0x3f3); not yet */
    +}
    +
    +static void detect_and_report_ite (void)
    +{
    + printk("ITE Super-IO detection testing ports 2E,4E,279,370/371 ...\n");
    + ite_check_279(0x61);
    + ite_check_279(0x80);
    + ite_check_2e(0x01);
    + ite_check_2e(0x61);
    +}
    +
    +static void detect_and_report_ali(void)
    +{
    + printk("ALI Super-IO detection testing ports 370,398,3F0 ...\n");
    + ali_check1(0x3f1);
    + ali_check1(0x398);
    + ali_check_pnp(0x370);
    + ali_check_pnp(0x3f0);
    +}
    +
    +static void detect_and_report_intel(void)
    +{
    + printk("Intel Super-IO detection testing ports 26E, 398 ...\n");
    + intel_check_aip(0x26e);
    + intel_check_aip(0x398);
    +}
    +
     #endif /* CONFIG_PARPORT_PC_SUPERIO */
     
     static int __devinit get_superio_dma (struct parport *p)
    @@ -2263,6 +2795,7 @@
             plx_9050,
             afavlab_tk9902,
             timedia_1889,
    + syba_2p_epp,
     };
     
     
    @@ -2270,9 +2803,9 @@
      * (but offset by last_sio) */
     static struct parport_pc_pci {
             int numports;
    - struct {
    + struct { /* BAR (base address registers) numbers in the config space header*/
                     int lo;
    - int hi; /* -ve if not there */
    + int hi; /* ==-1 if not there, >6 for offset-method (max BAR is 6)*/
             } addr[4];
     } cards[] __devinitdata = {
             /* siig_1s1p_10x_550 */ { 1, { { 3, 4 }, } },
    @@ -2301,6 +2834,8 @@
             /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } },
             /* afavlab_tk9902 */ { 1, { { 0, 1 }, } },
             /* timedia_1889 */ { 1, { { 2, -1 }, } },
    + /* SYBA uses fixed offsets in a 1K io window*/
    + /* syba_2p_epp */ { 2,{ { 0, 0x078}, { 0, 0x178},} },
     };
     
     static struct pci_device_id parport_pc_pci_tbl[] __devinitdata = {
    @@ -2360,6 +2895,7 @@
               PCI_ANY_ID, PCI_ANY_ID, 0, 0, afavlab_tk9902 },
             { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
               PCI_ANY_ID, PCI_ANY_ID, 0, 0, timedia_1889 },
    + { 0x1592, 0x782, PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp },
             { 0, }, /* terminate list */
     };
     MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl);
    @@ -2384,9 +2920,14 @@
                     unsigned long io_lo, io_hi;
                     io_lo = pci_resource_start (dev, lo);
                     io_hi = 0;
    - if (hi >= 0)
    + if ((hi >= 0) && (hi <=6))
                             io_hi = pci_resource_start (dev, hi);
    + else if (hi > 6)
    + io_lo = io_lo + hi; /* Reinterpret the meaning of "hi" as
    + as an offset (see SYBA def.) */
                     /* TODO: test if sharing interrupts works */
    + printk("PCI parallel port detected at io=0x%lx irq=%d\n",io_lo,dev->irq);
    + set_superio_hint(io_lo,dev->irq,PARPORT_DMA_NONE);
                     if (parport_pc_probe_port (io_lo, io_hi, PARPORT_IRQ_NONE,
                                                PARPORT_DMA_NONE, dev))
                             count++;
    @@ -2452,6 +2993,10 @@
     #ifdef CONFIG_PARPORT_PC_SUPERIO
             detect_and_report_winbond ();
             detect_and_report_smsc ();
    + detect_and_report_natsemi();
    + detect_and_report_ite();
    + detect_and_report_ali();
    + detect_and_report_intel();
     #endif
     
             /* Onboard SuperIO chipsets that show themselves on the PCI bus. */

    -- 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 : Mon May 01 2000 - 12:44:48 EDT