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