/* * shschip.c */ /* SHSMODe -- Serial High Speed Mode enabler/patcher V1.91releas for Linux */ /* Written by gigo http://homepage1.nifty.com/gigo/ (imaizumi@nisiq.net) */ /* Modified and Distributed by Device Drivers Limited(tom@devdrv.com) */ /* Special thanks for h-mio@mx5.nisiq.net */ /* V1.0f Modified for Linux by mizuhara@acm.org */ /* V1.6 Modified for Linux by ytakeuch@po.iijnet.or.jp */ /* compiler DOS:MSC6.00A with /AH option, Linux:gcc */ #ifndef _SHS_INTERNAL #define _SHS_INTERNAL #endif _SHS_INTERNAL int chip(int n,char opr) { int v, i; unsigned int iop; unsigned char id = 0; unsigned char rev = 0; #if defined(DEBUG) printf("\n%s\n",idnt[n].name); #endif _disable(); /* cli */ /* write ini value to enter config mode */ if (idnt[n].type == 50) { /* is VIA ? */ v = via686a(0, 0, 0); id = (unsigned char) (v >> 8); rev = (unsigned char) (v & 0xFF); } else if (idnt[n].type == 16 || idnt[n].type == 17) { /* is ITE ? */ iop = idnt[n].type == 16 ? 0x279 : 0x02E; outp(iop, idnt[n].id); outp(iop, idnt[n].ini1); outp(iop, idnt[n].ini2); outp(iop, idnt[n].idx); if(idnt[n].type == 16) for(i = 0; i < 32; i++) outp(idnt[n].port, pnpkey[i]); outp(idnt[n].port, 0x20); id = (unsigned char) inp(idnt[n].port+1); } else { if (idnt[n].ini1) outp(idnt[n].port,idnt[n].ini1); if (idnt[n].ini2) outp(idnt[n].port,idnt[n].ini2); if (idnt[n].type != 8) { outp(idnt[n].port,idnt[n].idx); id = (unsigned char)inp(idnt[n].port+1); } else { outp(idnt[n].port+1,idnt[n].idx); id = (unsigned char)inp(idnt[n].port+2); } } switch (idnt[n].type) { case 30: outp(idnt[n].port,idnt[n].idx-1); if (inp(idnt[n].port+1)!=0) return -1; outp(idnt[n].port,idnt[n].idx+1); rev = (unsigned char)inp(idnt[n].port+1); break; case 31: outp(idnt[n].port,idnt[n].idx-1); if (inp(idnt[n].port+1)==0) return -1; outp(idnt[n].port,0x2c); rev = (unsigned char)inp(idnt[n].port+1); if (rev & 0x20) ndev = 11; else ndev = 5; outp(idnt[n].port,idnt[n].idx+1); rev = (unsigned char)inp(idnt[n].port+1); break; default: outp(idnt[n].port,idnt[n].idx+1); rev = (unsigned char)inp(idnt[n].port+1); break; case 8: case 9: id = (unsigned char)(id&0xf); rev = 0xff; break; case 20: case 22: case 28: id = (unsigned char) (id & ~7); rev = (unsigned char)(id & 7); break; case 21: case 23: rev = 0xff; break; case 50: break; case 16: case 17: outp(idnt[n].port, 0x21); rev = (unsigned char) inp(idnt[n].port+1); break; } if (idnt[n].fin) outp(idnt[n].port,idnt[n].fin); /* exit config mode */ if (idnt[n].type == 16 || idnt[n].type == 17) outp(idnt[n].port+1,idnt[n].fin); /* exit config mode */ _enable(); /* sti */ if (opr == 'C') printf("*Check %s(%d): port=%04x, ini1=%02x, ini2=%02x, idx=%02x -> id=%02x, rev=%02x\n" ,idnt[n].name,n,idnt[n].port,idnt[n].ini1,idnt[n].ini2,idnt[n].idx,id,rev); if (idnt[n].id == id && idnt[n].type > 1) { /* ID matched ! */ if (idnt[n].rev == rev) { /* Revision matched exactly */ return n; } else if (idnt[n].fab == 6) { /* ITE */ printf("*ITE Chip ID = IT%02x%02x%s", id, rev, (id == 0x87 && rev == 0x05 ? "/SiS950\n" : "\n")); return n; } else if (idnt[n].type > 2 && idnt[n].fab != 2) { /* Neither Winbond nor 665IR/666IR/665GT/666GT */ return n; } /* Those are Winbond Check. */ else if (idnt[n].rev == 0x00) /* No revision check is needed */ return n; else if ((idnt[n].rev & 0x0F) == 0x00 && idnt[n].rev == (unsigned char) (rev & 0xF0)) /* Special revison check for Winbond */ return n; } return -1; } _SHS_INTERNAL int ope(int n, char opr, int portNo) { unsigned char cr1,cr2; unsigned int iop; int i,dvofs,nxt; unsigned char r = 0; unsigned char v = 0; #if defined(BIOSCOM) int j,warn; #endif typedef unsigned char UCH; if (opr == 'P') return 0; switch(idnt[n].type) { case 0: /* Unknown */ case 1: /* 665GT,666GT */ default: /* internal error.. */ break; case 2: /* 665IR,666IR */ _disable(); /* cli */ /* write ini value 2 times to enter config mode */ outp(idnt[n].port,idnt[n].ini1); outp(idnt[n].port,idnt[n].ini2); outp(idnt[n].port,0x01); cr1 = (unsigned char) inp(idnt[n].port+1); outp(idnt[n].port,0x02); cr2 = (unsigned char) inp(idnt[n].port+1); /* select sr0c */ outp(idnt[n].port,0x0c); r = (unsigned char) inp(idnt[n].port+1); if (opr == 'H') r |= portNo; if (opr == 'L') r &= ~portNo; outp(idnt[n].port+1,r); r = (unsigned char) inp(idnt[n].port+1); outp(idnt[n].port,idnt[n].fin); /* exit config mode */ _enable(); /* sti */ for (v=0x40,i=1;i<=2;++i) { if (cr2 & 0x4) { switch (cr2 & 0x3) { case 00: portAdr[i]=0x3F8;break; case 01: portAdr[i]=0x2F8;break; case 02: switch(cr1 & 0x30){ case 0x00: portAdr[i]=0x338;break; case 0x10: portAdr[i]=0x3E8;break; case 0x20: portAdr[i]=0x2E8;break; case 0x30: portAdr[i]=0x220;break; } break; case 03: switch(cr1 & 0x30){ case 0x00: portAdr[i]=0x238;break; case 0x10: portAdr[i]=0x2E8;break; case 0x20: portAdr[i]=0x2E0;break; case 0x30: portAdr[i]=0x228;break; } break; } portStat[i] = v&r; } else { portStat[i] = -1; } cr2 >>= 4; v <<= 1; } break; case 3: /* 669 */ _disable(); /* cli */ /* write ini value 2 times to enter config mode */ outp(idnt[n].port,idnt[n].ini1); outp(idnt[n].port,idnt[n].ini2); outp(idnt[n].port,0x24); portAdr[1] = (inp(idnt[n].port+1) & 0xFE) << 2; outp(idnt[n].port,0x25); portAdr[2] = (inp(idnt[n].port+1) & 0xFE) << 2; /* select sr0c */ outp(idnt[n].port,0x0c); r = (unsigned char) inp(idnt[n].port+1); if (opr == 'H') r |= portNo; if (opr == 'L') r &= ~portNo; outp(idnt[n].port+1,r); r = (unsigned char) inp(idnt[n].port+1); outp(idnt[n].port,idnt[n].fin); /* exit config mode */ _enable(); /* sti */ for (v=0x40,i=1;i<=2;++i) { if (portAdr[i] & 0x300) portStat[i] = v&r; else portStat[i] = -1; v <<= 1; } break; case 8: /* W83877TF native */ case 9: /* W83877TF emulate mode */ _disable(); /* cli */ /* write ini value 2 times to enter config mode */ outp(idnt[n].port,idnt[n].ini1); if (idnt[n].type != 8) outp(idnt[n].port,idnt[n].ini2); else idnt[n].port++; outp(idnt[n].port,0x24); portAdr[1] = (inp(idnt[n].port+1) & 0xFE) << 2; outp(idnt[n].port,0x25); portAdr[2] = (inp(idnt[n].port+1) & 0xFE) << 2; /* select sr19 */ outp(idnt[n].port,0x19); r = (unsigned char) inp(idnt[n].port+1); v = 0; if (portNo & 0x40) v = 0x2; if (portNo & 0x80) v |= 0x1; if (opr == 'H') r |= v; if (opr == 'L') r &= ~v; outp(idnt[n].port+1,r); r = (unsigned char) inp(idnt[n].port+1); outp(idnt[n].port,idnt[n].fin); /* exit config mode */ _enable(); /* sti */ for (v=0x02,i=1;i<=2;++i) { if (portAdr[i] & 0x300) portStat[i] = v&r; else portStat[i] = -1; v >>= 1; } if (idnt[n].type == 8) idnt[n].port--; break; case 4: /* 67x,68x,93x,957 dev 4,5*/ case 30: /* ALI M1543 dev 4,5*/ case 31: /* ALI M1543C dev 4,5*/ case 10: /* W83977TF dev 2,3*/ case 20: /* NS PC8xxxxx dev 6,5*/ case 21: /* NS PC9xxxxx dev 6,5*/ case 22: /* NS PC8xxxxx dev 6,5*/ case 23: /* NS PC9xxxxx dev 3,2*/ switch(idnt[n].type) { /* dvofs */ case 20: case 21: case 22: dvofs = 6; /* 5:port2, 6:port1 87307/97037/87308/87317/97317 */ nxt = -1; break; case 23: dvofs = 3; /* 2:port2, 3:port1 87309 */ nxt = -1; break; case 10: /* WinBond */ dvofs = 2; /* 2:port1, 3:port2 */ nxt = 1; break; case 31: /* ALI 1543C */ dvofs = 4; /* 4:port1, 5:port2 */ nxt = 1; if (ndev == 11) nxt = 7;/* 4:port1, 11:port2 */ break; default: /* SMC,ALI */ dvofs = 4; /* 4:port1, 5:port2 */ nxt = 1; break; } /* dvofs */ for (i = 1; i <=2 ; ++i, dvofs += nxt) { _disable(); /* cli */ /* write ini value 2 times to enter config mode */ if (idnt[n].ini1) outp(idnt[n].port,idnt[n].ini1); if (idnt[n].ini2) outp(idnt[n].port,idnt[n].ini2); outp(idnt[n].port,0x07);/* Select device register */ outp(idnt[n].port+1,dvofs); /* Set device value */ outp(idnt[n].port,0x60); /* get port addr. */ portAdr[i] = inp(idnt[n].port+1) << 8; outp(idnt[n].port,0x61); portAdr[i] |= inp(idnt[n].port+1); #if defined(CHKENB) outp(idnt[n].port,0x30); /* enabled ? */ if (inp(idnt[n].port+1)==0) portAdr[i] = 0; #endif outp(idnt[n].port,0xF0);/* Select serial config register */ r = (unsigned char)inp(idnt[n].port+1); switch (idnt[n].type) { case 4: /* SMC */ case 30: /* ALI */ case 31: /* ALI 1543C */ if ((0x20 << i) & portNo) { if (opr == 'H') r |= 2; if (opr == 'L') r &= ~2; outp(idnt[n].port+1,r); } r = (unsigned char)inp(idnt[n].port+1); v = (unsigned char)((r&0x3) == 0x2); break; case 10: /* Winbond 83977TF */ if ((0x20 << i) & portNo) { if (opr == 'H') r |= 3; if (opr == 'L') r &= ~3; outp(idnt[n].port+1,r); } r = (unsigned char)inp(idnt[n].port+1); v = (unsigned char)((r&0x3) == 0x3); break; case 20: /* NS 87308 */ #if 0 if ((0x20 << i) & portNo) if (opr == 'H') outp(idnt[n].port+1,r|0x80); /* bank select enable */ v = (unsigned char) (inp(idnt[n].port+1) & 0x80); break; #endif case 21: /* NS */ case 22: /* NS */ case 23: /* NS */ if ((0x20 << i) & portNo) { if (opr == 'H') outp(idnt[n].port+1,r|0x80); /* bank select enable */ if (divisor>=0) { v = (unsigned char)inp(portAdr[i] + 0x03); /* save LCR for 83708 */ outp(portAdr[i] + 0x03 ,0xe0 ); /* Select Bank2 */ /* outp(portAdr[i] + 0x02 ,0x41 ); *//* Select Extended mode */ r = (unsigned char) inp(portAdr[i] + 0x04); if (divisor==0) outp(portAdr[i] + 0x04,r & 0x7F);/* clear LOCK */ else { outp(portAdr[i] + 0x04,r | 0x90);/* LOCK,1.625 */ outp(portAdr[i] , divisor ); outp(portAdr[i] + 1, divisor >> 8 ); } outp(portAdr[i] + 0x03 , v); /* Restore LCR */ } } v = (unsigned char)(inp(idnt[n].port+1)&0x80); break; default: break; } /* switch */ outp(idnt[n].port,idnt[n].fin); /* exit config mode */ _enable(); /* sti */ if (opr == 'C') printf("*Check srf0/EXCR2: %02x -- ",r); if (portAdr[i]) portStat[i] = v; else portStat[i] = -1; } break; #if 1 /* defined(PC87338) */ case 28: /* PC87338 */ _disable(); outp(idnt[n].port,0x00); /* get FER 3:FDC 2:SCC2 1:SCC1 0:PPA */ cr1 = (unsigned char) inp(idnt[n].port+1); outp(idnt[n].port,0x01); /* get FAR 7:6-COM34 5:4-SCC2 3:2-SCC1 1:0-PPA */ cr2 = (unsigned char) inp(idnt[n].port+1); for (i=1;i<=2;++i) { if ((cr1 & (1 << i) )==0) { portStat[i] = -1; continue; } outp(idnt[n].port,0x1b); /* get PNP0 */ if (inp(idnt[n].port+1) & 0x08) { /* PNP Mode */ outp(idnt[n].port,0x42+2*i); portAdr[i] = (inp(idnt[n].port+1)&0xfe) << 2; outp(idnt[n].port,0x42+2*i+1); portAdr[i] |= (inp(idnt[n].port+1)&0xfc) <<8; } else { /* legacy mode */ switch ((cr2>>(2*i)) & 0x03) { case 00: portAdr[i]=0x3F8;break; case 01: portAdr[i]=0x2F8;break; case 02: /* com3 */ switch(cr2 & 0xc0){ case 0x00: portAdr[i]=0x3E8;break; case 0x40: portAdr[i]=0x338;break; case 0x80: portAdr[i]=0x2E8;break; case 0xc0: portAdr[i]=0x220;break; } break; case 03: /* com4 */ switch(cr2 & 0xc0){ case 0x00: portAdr[i]=0x2E8;break; case 0x40: portAdr[i]=0x238;break; case 0x80: portAdr[i]=0x2E0;break; case 0xc0: portAdr[i]=0x228;break; } break; } /* switch */ } if ((0x20 << i) & portNo) { if (opr == 'H') { outp(idnt[n].port,0x40); /* enable bank select */ outp(idnt[n].port+1,inp(idnt[n].port+1)| (0x10 << (3*(i-1))) ); } if (divisor>=0) { v = (unsigned char)inp(portAdr[i] + 0x03); /* save LCR for 83708 */ outp(portAdr[i] + 0x03 ,0xe0 ); /* Select Bank2 */ /* outp(portAdr[i] + 0x02 ,0x41 ); *//* Select Extended mode */ r = (unsigned char) inp(portAdr[i] + 0x04); if (divisor==0) outp(portAdr[i] + 0x04,r & 0x7F);/* clear LOCK */ else { outp(portAdr[i] + 0x04,r | 0x90);/* LOCK,1.625 */ outp(portAdr[i] , divisor ); outp(portAdr[i] + 1, divisor >> 8 ); } outp(portAdr[i] + 0x03 , v); /* Restore LCR */ } } v = (unsigned char)(inp(idnt[n].port+1)& (0x10 << (3*(i-1))) ); if (opr == 'C') printf("*Check EXCR2: %02x -- ",r); portStat[i] = v; } /* for */ _enable(); break; #endif case 50: /* VIA */ if (!portNo) { /* for interface match */ portNo = 0xC0; opr = 'D'; } _disable(); i = via686a(portNo >> 6, (opr == 'H' ? 2 : (opr == 'L' ? 1 : 0 )), &portAdr[1]); _enable(); portStat[1] = i & 0x40; portStat[2] = i & 0x80; for(i = 1; i < 2; i++) { if (!portAdr[i]) portStat[i] = -1; } break; case 16: /* ITE IT86xx */ case 17: /* ITE IT87xx */ _disable(); iop = idnt[n].type == 16 ? 0x279 : 0x02E; outp(iop, idnt[n].id); outp(iop, idnt[n].ini1); outp(iop, idnt[n].ini2); outp(iop, idnt[n].idx); if(idnt[n].type == 16) for(i = 0; i < 32; i++) outp(idnt[n].port, pnpkey[i]); for(i = 1; i <= 2; i++) { outp(idnt[n].port, 0x07); outp(idnt[n].port+1, (UCH)i); /* UART# */ outp(idnt[n].port, 0xF0); /* Config Reg. */ v = (UCH) inp(idnt[n].port+1); #ifdef DEBUG_ITE printf("ITE UART%d Config = %02x\n", i, (int) v); #endif if((portNo & (0x20 << i)) /* 0x40 or 0x80 ? */ && (opr == 'H' || opr == 'L')) { #ifdef DEBUG_ITE printf("%d: port = %02x, mode = %c\n", i, portNo, opr); #endif if (opr == 'H') v |= 0x04; /* 0x04 */ else if(opr == 'L') v &= ~0x04; /* 0x04 */ } outp(idnt[n].port, 0xF0); /* Config Reg. */ outp(idnt[n].port+1, v); outp(idnt[n].port, 0xF0); /* Config Reg. */ v = (UCH) inp(idnt[n].port+1); portStat[i] = v & 0x40; #ifdef DEBUG_ITE printf("UART%d*Config = %02x\n", i, (int) v); #endif outp(idnt[n].port, 0x60); /* Addr Reg. */ v = (UCH) inp(idnt[n].port+1); portAdr[i] = (unsigned int) (v << 8); outp(idnt[n].port, 0x61); /* Addr Reg. */ v = (UCH) inp(idnt[n].port+1); portAdr[i] |= v; } #if 0 /* for Sys-Clock Control test */ outp(idnt[n].port, 0x23); /* Config Reg. */ v = (UCH) inp(idnt[n].port+1); printf(" Clock = %02x\n", (int) v); if (mode == MODE_HI) { outp(idnt[n].port, 0x23); outp(idnt[n].port+1, (v | 0x01)); } else if (mode == MODE_LO) { outp(idnt[n].port, 0x23); outp(idnt[n].port+1, (v & ~0x01)); } outp(idnt[n].port, 0x23); /* Config Reg. */ v = (UCH) inp(idnt[n].port+1); printf("*Clock = %02x\n", (int) v); #endif /* finish */ outp(idnt[n].port, idnt[n].fin); outp(idnt[n].port+1, idnt[n].fin); _enable(); for(i = 1; i < 2; i++) { if (!portAdr[i]) portStat[i] = -1; } break; } /* switch */ #if defined(BIOSCOM) warn = 0; r = 0x01; v = 0; for (j = 1; j < 3; ++j, r <<= 1) { printf("COM%d (%04xh): ", j, portAdr[j]); bioscomp = (void *)0x400; for(i = 0; i < 4; ++i,++bioscomp) { #if 0 /* for debug*/ printf("bios: %04lxh = %04lxh (%04lxh:%04lxh)\n", bioscomp, (long) *bioscomp, (long) portAdr[j], (long) portStat[j]); #endif if (*bioscomp != 0) { if ((portAdr[j] == *bioscomp) && (portStat[j] >= 0)) { printf("Supported, Mode = %s\n", portStat[j]?"High":"Low" ); if (portStat[j]) v |= r; break; } } } if (i >= 4) { printf("Unsupported.\n"); if (portAdr[j]) warn++; } } if ((idnt[n].type < 6) || (idnt[n].type >= 30)) /* SMC and ALI */ return v; /* no problem */ if ((idnt[n].type >= 6) && (idnt[n].type < 30)) { /* if ( (*((char *)0x410) & 4) == 0) { */ bioscomp = (void *)0x410; if ( v == 0x03 && (*bioscomp & 4) == 0) { printf("Warning -- Both ports are High Mode and PS/2 Mouse not equipped.\n"); printf(" Can't use the serial mouse at High Mode.\n"); printf(" You must set low for serial mouse port.\n"); } else if(*bioscomp & 4) printf("Notify -- PS/2 Mouse detected(%02x, %04x)\n", v, *bioscomp); } if (warn) { printf("Warning -- This system has unsupported UART chip or external serial chip.\n"); printf(" The patch may cause problem.\n"); } #else for (i=1;i<3;++i) { printf("Port%d",i); if (portStat[i] >= 0) { printf("(%04xh) Serial Speed Mode: %s\n", portAdr[i],portStat[i]?"High":"Low" ); } else printf(" disabled\n"); } #endif return v; }