[PARPORT] Patch-2.3.50pre1: Super-IO cont.

From: Gunther Mayer (gunther.mayer@braunschweig.netsurf.de)
Date: Sun Mar 05 2000 - 14:35:39 EST

  • Next message: DAANEN Vincent: "[PARPORT] Parport use"

    Hi,
    this patch adds detetction of more chiptypes.
    Feel free to test, apply and report.

    Regards, Gunther

    diff -ur linux-2.3.50p1-orig/drivers/parport/init.c linux/drivers/parport/init.c
    --- linux-2.3.50p1-orig/drivers/parport/init.c Wed Jan 26 21:45:20 2000
    +++ linux/drivers/parport/init.c Sun Mar 5 16:03:13 2000
    @@ -121,6 +121,7 @@
     #ifdef CONFIG_SYSCTL
             parport_default_proc_register ();
     #endif
    + printk("parport - Parallel Port Manager for Linux module V0.90 loaded.\n");
             return 0;
     }
     
    diff -ur linux-2.3.50p1-orig/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
    --- linux-2.3.50p1-orig/drivers/parport/parport_pc.c Sun Mar 5 16:15:12 2000
    +++ linux/drivers/parport/parport_pc.c Sun Mar 5 16:12:00 2000
    @@ -1015,7 +1015,144 @@
             parport_ieee1284_read_byte,
     };
     
    -/* Super-IO chipset detection, Winbond, SMSC */
    +/* Super-IO chipset detection, Winbond, SMSC, National Semiconductor (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> 03/04/2000 gm.
    +
    + Another effect for your comfort is improved autodetection of IO/IRQ/DMA and mode of your
    + parallel port. Some missing piece of this effort that needs further investigation is
    + support for EPP-BIOS (Enhanced Parallel Port) as this should help here too.
    +
    + Notes:
    + (1) EPP-BIOS has nothing to to with EPP-mode, either IEEE1284(EPP1.9) or 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 :-)
    + */
    +
    +
    +void 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+SPP",
    + "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");
    + }
    +}
     
     static void show_parconfig_smsc37c669(int io, int key)
     {
    @@ -1056,7 +1193,7 @@
                    (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],
    - (cr4 & 40) ? "1.7" : "1.9");
    + (cr4 & 0x40) ? "1.7" : "1.9");
     
             /* Heuristics ! BIOS setup for this mainboard device limits
                the choices to standard settings, i.e. io-address and IRQ
    @@ -1168,46 +1305,71 @@
     
             /* Values are from public data sheets pdf files, I can just
                confirm 83977TF is correct :-) */
    - if (id == 0x9773) type="83977TF";
    + if (id == 0x9773) type="83977TF / SMSC 97w33x/97x34x";
    + else if (id == 0x9771) type="83977F/AF";
             else if (id == 0x9774) type="83977ATF";
             else if ((id & ~0x0f) == 0x5270) type="83977CTF / SMSC 97w36x";
    - else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97x35x";
    + else if ((id & ~0x0f) == 0x52f0) type="83977EF / SMSC 97w35x";
             else if ((id & ~0x0f) == 0x5210) type="83627";
             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 ) == 0x0c) { type="83877ATF"; progif=1;}
    + else if ((oldid &0x0f ) == 0x0d) { type="83877ATF"; progif=1;}
             else progif=0;
     
             if(type==NULL)
                     printk("Winbond unkown chip type\n");
    - else
    + else {
                      printk("Winbond chip type %s\n",type);
    -
    - if(progif==2)
    - show_parconfig_winbond(efer,key);
    + if(progif==2)
    + show_parconfig_winbond(efer,key);
    + else /* progif==1 */
    + show_parconfig_winbond_877(efer,key,oldid);
    + }
             return;
     }
     
    -static void decode_smsc(int efer, int key, int devid, int devrev)
    +static void 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;
    + int idrev,oldidrev;
     
    - if (devid == devrev)
    + if ((oldid == oldrev) && (id == rev))
                     /* simple heuristics, we happened to read some
    - non-winbond register */
    + non-smsc 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";
    + 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"; func=show_parconfig_smsc37c669;}
    + else if (oldid==0x40) type="37c669FR";
    + else if (oldidrev==0x6582) type="37c665IR";
    + else if ((oldidrev==0x6502) && (key==0x44)) type="37c665GT";
    + else if ((oldidrev==0x6502) && (key==0x55)) type="37c666GT";
    + else if (oldid==0x28) type="37n869"; /* "n" notifies notebook ? */
    + else if (oldid==0x29) type="37n769";
    + else if (oldid==0x78) type="FDC37c78"; /* Floppy disk only */
    + else if (idrev==0x0201) type="37c93x";
    + else if (idrev==0x0301) type="37c83xFR";
    + else if (idrev==0x3001) type="37c93xAPM";
    + else if (id==0x09) type="37n958";
    + else if (id==0x09) type="37n971";
    + else if (id==0x0a) type="37n972";
    + else if (id==0x40) type="37c67";
    + else if (id==0x42) type="37m70 / 37b80";
    + else if (id==0x43) type="37b77";
    + else if (id==0x44) type="37b78";
    + else if (id==0x47) type="37m60";
    + else if (id==0x48) type="37c68";
    + else if (id==0x4c) type="37b72";
    + else if (id==0x4d) type="37m81";
     
             if(type==NULL)
                     printk("SMSC unknown chip type\n");
    @@ -1237,7 +1399,7 @@
             decode_winbond(io,key,devid,devrev,oldid);
     }
     
    -static void winbond_check2(int io,int key)
    +static void winbond_check1(int io,int key)
     {
             int devid,devrev,oldid;
     
    @@ -1256,20 +1418,79 @@
     
     static void smsc_check(int io, int key)
     {
    - int devid,devrev;
    + int id,rev,oldid,oldrev;
     
             outb(key,io);
             outb(key,io); /* Write Magic Sequence to EFER, extended
                                  funtion enable register */
             outb(0x0d,io); /* Write EFIR, extended function index register */
    - devid=inb(io+1); /* Read EFDR, extended function data register */
    + oldid=inb(io+1); /* Read EFDR, extended function data register */
             outb(0x0e,io);
    - devrev=inb(io+1);
    + oldrev=inb(io+1);
    + outb(0x20,io);
    + id=inb(io+1);
    + outb(0x21,io);
    + rev=inb(io+1);
             outb(0xaa,io); /* Magic Seal */
     
    - decode_smsc(io,key,devid,devrev);
    + decode_smsc(io,key,oldid,oldrev,id,rev);
     }
     
    +static void ns_check(int io) /* No key !? */
    +{
    + int id,cr8,cr21;
    + char *type=NULL;
    +
    + outb(0x20,io); /* Write EFIR, extended function index register */
    + id=inb(io+1);
    + outb(0x21,io);
    + cr21=inb(io+1);
    + outb(0x08,io);
    + 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 cr8=0x%02x",
    + io,id,cr21,cr8);
    + switch(id) {
    + case 0xc0: type="PC87307"; break;
    + case 0xcf: type="PC97307"; break;
    + case 0xd0: type="PC87317"; break;
    + case 0xdf: type="PC97317"; break;
    + case 0xe0: type="PC87309"; break;
    + case 0xe2: type="PC87351"; break;
    + }
    + if((id==0) && ((cr8&0xf0) ==0xb0)) type="PC87338";
    +
    + if(type)
    + printk("National Semiconductor chip type %s\n",type);
    + else
    + printk("National Semiconductor unknown chip type\n");
    +}
    +
    +static void ns_check94(int io)
    +{
    + int r;
    + char *type="unknown";
    +
    + outb(0xff,io);
    + r=inb(io);
    +
    + if(r==0xff)
    + return;
    +
    + if(r==0x07) type="perhaps PC87322"; /* Bits 3-7 read back as zero */
    + if(r==0x03) type="perhaps 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 detect_and_report_winbond (void)
     {
    @@ -1278,10 +1499,10 @@
             winbond_check(0x3f0,0x87);
             winbond_check(0x370,0x87);
             winbond_check(0x2e ,0x87);
    - winbond_check(0x4e ,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 detect_and_report_smsc (void)
    @@ -1293,6 +1514,17 @@
             smsc_check(0x370,0x44);
     }
     
    +static void detect_and_report_natsemi (void)
    +{
    + printk("National Semiconductor Super-IO detection,now testing port 2E,15C,26E,398 ...\n");
    + ns_check(0x2e);
    + ns_check(0x15c);
    + ns_check(0x398); /* PC87338 !? */
    + ns_check94(0x26e); /* these port were used until 1994 */
    + ns_check94(0x398);
    +}
    +
    +
     static int get_superio_dma (struct parport *p)
     {
             int i=0;
    @@ -2394,7 +2626,7 @@
     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");
    -MODULE_PARM_DESC(superio, "Enable Super-IO chipset probe");
    +MODULE_PARM_DESC(superio, "Enable Super-IO chipset probe (Experimental!)");
     MODULE_PARM(superio, "i");
     
     int init_module(void)
    @@ -2403,8 +2635,10 @@
                the irq values. */
             unsigned int i;
             if (superio) {
    + printk("Super I/O ISA chipset probe is experimental, so don't trust it blindly.\n");
                     detect_and_report_winbond ();
                     detect_and_report_smsc ();
    + detect_and_report_natsemi();
             }
             for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++);
             if (i) {

    -- 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 : Sun Mar 05 2000 - 14:46:40 EST