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