Hi speed serials for 2.1.130

Pavel Machek (pavel@bug.ucw.cz)
Wed, 2 Dec 1998 12:14:28 +0100


Hi!

This is adapted patch from mizuhara@st.rim.or.jp, gigo@yk.rim.or.jp,
ytakeuch@po.iijnet.or.jp. It alows you to use speeds up-to
921kbit/second on modern chipsets. I've ported this patch to 2.1.130
and de-dosified it quite a bit. PLEASE TEST.
Pavel

--- clean//drivers/char/serial.c Tue Dec 1 22:11:36 1998
+++ serial.linux/drivers/char/serial.c Tue Dec 1 22:13:33 1998
@@ -60,8 +60,15 @@
* SERIAL_PARANOIA_CHECK
* Check the magic number for the async_structure where
* ever possible.
+ *
+ * CONFIG_HISPEED
+ * Enables support for High Speed mode, available with
+ * some SMC/NS/Winbond multi-I/O hispeed_chips.
*/

+#define CONFIG_HISPEED
+/* #define DEBUG_CONFIG_HISPEED */
+
#undef SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
@@ -1355,7 +1362,10 @@
serial_outp(info, UART_EFR,
(cflag & CRTSCTS) ? UART_EFR_CTS : 0);
}
- serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+ if (0)
+ serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
+ else
+ serial_outp(info, UART_LCR, 0xe0); /* select Bank 2 */
serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */
if (info->state->type == PORT_16750)
@@ -2803,6 +2813,10 @@
printk(" DETECT_IRQ");
#define SERIAL_OPT
#endif
+#ifdef CONFIG_HISPEED
+ printk(" HighSpeedMode V1.7a(Linux 06-Sep-98)");
+#define SERIAL_OPT
+#endif
#ifdef SERIAL_OPT
printk(" enabled\n");
#else
@@ -2811,6 +2825,633 @@
#undef SERIAL_OPT
}

+#ifdef CONFIG_HISPEED
+/*
+ * High Speed mode patch for SMC hispeed_chips by mizuhara@st.rim.or.jp
+ * Original idea and NT driver from gigo@yk.rim.or.jp
+ * 09/98 updated by ytakeuch@po.iijnet.or.jp
+ * Visit http://www.yk.rim.or.jp/~gigo/download.html
+ */
+#define PC87338
+/*
+#define CHKENB
+*/
+
+typedef struct idn {
+unsigned short port;
+unsigned char ini1;
+unsigned char ini2;
+unsigned char idx;
+unsigned char id;
+unsigned char rev;
+unsigned char fin;
+int pch;
+int type;
+char *name;
+} idn_t;
+
+idn_t idnt[] = {
+ { 0x3f0,0x55,0x55,0x20,0x4c,0x01,0xAA,1,4,"B72x" }, /*00:B72x */
+ { 0x370,0x55,0x55,0x20,0x4c,0x01,0xAA,1,4,"B72x" }, /*01:B72x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x43,0x01,0xAA,1,4,"B77x" }, /*02:B77x */
+ { 0x370,0x55,0x55,0x20,0x43,0x01,0xAA,1,4,"B77x" }, /*03:B77x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x44,0x01,0xAA,1,4,"B78x" }, /*04:B78x */
+ { 0x370,0x55,0x55,0x20,0x44,0x01,0xAA,1,4,"B78x" }, /*05:B78x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x42,0x01,0xAA,1,4,"B80x" }, /*06:B80x */
+ { 0x370,0x55,0x55,0x20,0x42,0x01,0xAA,1,4,"B80x" }, /*07:B80x at 0x370 */
+ { 0x3f0,0x55,0x55,0x0d,0x65,0x02,0xAA,0,1,"C665GT" }, /*08:C665GT */
+ { 0x3f0,0x44,0x44,0x0d,0x66,0x02,0xAA,0,1,"C666GT" }, /*09:C666GT */
+ { 0x3f0,0x55,0x55,0x0d,0x65,0x82,0xAA,1,2,"C665IR" }, /*10:C665IR */
+ { 0x3f0,0x44,0x44,0x0d,0x66,0x82,0xAA,1,2,"C666IR" }, /*11:C666IR */
+ { 0x3f0,0x55,0x55,0x0d,0x03,0x00,0xAA,1,3,"C669" }, /*12:C669 */
+ { 0x370,0x55,0x55,0x0d,0x03,0x00,0xAA,1,3,"C669" }, /*13:C669 at 0x370 */
+ { 0x3f0,0x55,0x55,0x0d,0x04,0x00,0xAA,1,3,"C669FR" }, /*14:C669FR */
+ { 0x370,0x55,0x55,0x0d,0x04,0x00,0xAA,1,3,"C669FR" }, /*15:C669FR at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x40,0x01,0xAA,1,4,"C67x" }, /*16:C67x */
+ { 0x370,0x55,0x55,0x20,0x40,0x01,0xAA,1,4,"C67x" }, /*17:C67x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x48,0x01,0xAA,1,4,"C68x" }, /*18:C68x */
+ { 0x370,0x55,0x55,0x20,0x48,0x01,0xAA,1,4,"C68x" }, /*19:C68x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x02,0x01,0xAA,1,4,"C93x" }, /*20:C93x */
+ { 0x370,0x55,0x55,0x20,0x02,0x01,0xAA,1,4,"C93x" }, /*21:C93x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x30,0x01,0xAA,1,4,"C93xAPM" }, /*22:C93xAPM */
+ { 0x370,0x55,0x55,0x20,0x30,0x01,0xAA,1,4,"C93xAPM" }, /*23:C93xAPM at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x03,0x01,0xAA,1,4,"C93xFR" }, /*24:C93xFR */
+ { 0x370,0x55,0x55,0x20,0x03,0x01,0xAA,1,4,"C93xFR" }, /*25:C93xFR at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x47,0x01,0xAA,1,4,"M60x" }, /*26:M60x */
+ { 0x370,0x55,0x55,0x20,0x47,0x01,0xAA,1,4,"M60x" }, /*27:M60x at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x46,0x01,0xAA,1,4,"M61x" }, /*28:M61x */
+ { 0x370,0x55,0x55,0x20,0x46,0x01,0xAA,1,4,"M61x" }, /*29:M61x at 0x370 */
+ { 0x3f0,0x55,0x55,0x0d,0x28,0x00,0xAA,1,3,"N769" }, /*30:N769FR */
+ { 0x370,0x55,0x55,0x0d,0x28,0x00,0xAA,1,3,"N769" }, /*31:N769FR at 0x370 */
+ { 0x3f0,0x55,0x55,0x20,0x09,0x01,0xAA,1,4,"N958FR" }, /*32:N958FR */
+ { 0x370,0x55,0x55,0x20,0x09,0x01,0xAA,1,4,"N958FR" }, /*33:N958FR at 0x370 */
+
+#if 0
+ /* deleted ? */
+ { 0x3f0,0x55,0x55,0x20,0x07,0x01,0xAA,1,4,"C957FR" }, /*34:C957FR */
+ { 0x370,0x55,0x55,0x20,0x07,0x01,0xAA,1,4,"C957FR" }, /*35:C957FR at 0x370 */
+ /* same ID as B80 ?? */
+ { 0x3f0,0x55,0x55,0x20,0x42,0x01,0xAA,1,4,"M70x" }, /*26:M70x */
+ { 0x370,0x55,0x55,0x20,0x42,0x01,0xAA,1,4,"M70x" }, /*27:M70x at 0x370 */
+ /* deleted ? */
+ { 0x3f0,0x55,0x55,0x20,0x43,0x01,0xAA,1,4,"M77x" }, /*28:M77x */
+ { 0x370,0x55,0x55,0x20,0x43,0x01,0xAA,1,4,"M77x" }, /*29:M77x at 0x370 */
+#endif
+#if 0
+ /* no function but detectable */
+ { 0x250,0x89,0x89,0x09,0x0a,0x01,0xAA,0,6,"W83877F"}, /*--:W83877F at 0x250 */
+ { 0x250,0x88,0x88,0x09,0x0a,0x01,0xAA,0,6,"W83877F"}, /*--:W83877F at 0x250 */
+ { 0x3F0,0x87,0x87,0x09,0x0a,0x01,0xAA,0,7,"W83877F"}, /*--:W83877F at 0x3f0 */
+ { 0x3F0,0x86,0x86,0x09,0x0a,0x01,0xAA,0,7,"W83877F"}, /*--:W83877F at 0x3f0 */
+#endif
+ { 0x250,0x89,0x89,0x09,0x0c,0x01,0xAA,2,8,"W83877TF"}, /*34:W83877TF at 0x250 */
+ { 0x250,0x88,0x88,0x09,0x0c,0x01,0xAA,2,8,"W83877TF"}, /*35:W83877TF at 0x250 */
+ { 0x3F0,0x87,0x87,0x09,0x0c,0x01,0xAA,2,9,"W83877TF"}, /*36:W83877TF at 0x3f0 */
+ { 0x3F0,0x86,0x86,0x09,0x0c,0x01,0xAA,2,9,"W83877TF"}, /*37:W83877TF at 0x3f0 */
+
+ { 0x3f0,0x87,0x87,0x20,0x97,0x71,0xAA,2,10,"W83977" }, /*38:W83977A/AF/TF/ATF at 0x3f0 */
+ { 0x370,0x87,0x87,0x20,0x97,0x71,0xAA,2,10,"W83977" }, /*39:W83977A/AF/TF/ATF at 0x370 */
+#if 0
+ /* no function but detectable */
+ { 0x02e,0x00,0x00,0x08,0x90,0x00,0xAA,3,01,"87336" }, /*--:PC87336 at 0x02e */
+ { 0x15c,0x00,0x00,0x08,0x90,0x00,0xAA,3,01,"87336" }, /*--:PC87336 at 0x15c */
+ { 0x398,0x00,0x00,0x08,0x90,0x00,0xAA,3,01,"87336" }, /*--:PC87336 at 0x398 */
+#endif
+ { 0x02e,0x00,0x00,0x20,0xa0,0x00,0xAA,3,20,"87308" }, /*40:PC87308 at 0x02e */
+ { 0x15c,0x00,0x00,0x20,0xa0,0x00,0xAA,3,20,"87308" }, /*41:PC87308 at 0x15c */
+#if defined(PC87338)
+ { 0x02e,0x00,0x00,0x08,0xb0,0x00,0xAA,3,28,"87338" }, /*42:PC87338 at 0x02e */
+ { 0x15c,0x00,0x00,0x08,0xb0,0x00,0xAA,3,28,"87338" }, /*43:PC87338 at 0x15c */
+ { 0x398,0x00,0x00,0x08,0xb0,0x00,0xAA,3,28,"87338" }, /*44:PC87338 at 0x398 */
+#endif
+ { 0x02e,0x00,0x00,0x20,0xc0,0x00,0xAA,3,22,"87307" }, /*45:PC87307 at 0x02e */
+ { 0x15c,0x00,0x00,0x20,0xc0,0x00,0xAA,3,22,"87307" }, /*46:PC87307 at 0x15c */
+ { 0x02e,0x00,0x00,0x20,0xcf,0x00,0xAA,3,21,"97307" }, /*47:PC97307 at 0x02e */
+ { 0x15c,0x00,0x00,0x20,0xcf,0x00,0xAA,3,21,"97307" }, /*48:PC97307 at 0x15c */
+ { 0x02e,0x00,0x00,0x20,0xd0,0x00,0xAA,3,22,"87317" }, /*49:PC87317 at 0x02e */
+ { 0x15c,0x00,0x00,0x20,0xd0,0x00,0xAA,3,22,"87317" }, /*50:PC87317 at 0x15c */
+ { 0x02e,0x00,0x00,0x20,0xdf,0x00,0xAA,3,21,"97317" }, /*51:PC87317 at 0x02e */
+ { 0x15c,0x00,0x00,0x20,0xdf,0x00,0xAA,3,21,"97317" }, /*52:PC87317 at 0x15c */
+ { 0x02e,0x00,0x00,0x20,0xe0,0x00,0xAA,3,23,"87309" }, /*53:PC87309 at 0x02e */
+ { 0x15c,0x00,0x00,0x20,0xe0,0x00,0xAA,3,23,"87309" }, /*54:PC87309 at 0x15c */
+ { 0x3f0,0x51,0x23,0x20,0x43,0x15,0xBB,4,30,"M1543" }, /*55:M1543 at 0x3f0 */
+ { 0x370,0x51,0x23,0x20,0x43,0x15,0xBB,4,30,"M1543" }, /*56:M1543 at 0x370 */
+ { 0, 0, 0, 0, 0, 0, 0,0, 0,"Other" }
+};
+
+#define OUTP0(x) outb(x, idnt[n].port)
+#define OUTP1(x) outb(x, idnt[n].port+1)
+#define INP1 ((unsigned char) inb(idnt[n].port+1))
+#define INP2 ((unsigned char) inb(idnt[n].port+2))
+
+static int
+hispeed_chip(int n)
+{
+ unsigned char id,rev;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ /* write ini value to enter config mode */
+ if (idnt[n].ini1) OUTP0(idnt[n].ini1);
+ if (idnt[n].ini2) OUTP0(idnt[n].ini2);
+ if (idnt[n].type != 8) {
+ OUTP0(idnt[n].idx);
+ id = INP1;
+ } else {
+ OUTP1(idnt[n].idx);
+ id = INP2;
+ }
+ switch (idnt[n].type) {
+ default:
+ OUTP0(idnt[n].idx+1);
+ rev = INP1;
+ 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;
+ }
+ OUTP0(idnt[n].fin); /* exit config mode */
+ restore_flags(flags);
+
+#ifdef DEBUG_CONFIG_HISPEED
+ printk("*Check %s: port=%04x, ini1=%02x, ini2=%02x, idx=%02x -> id=%02x, rev=%02x\n",
+ idnt[n].name,idnt[n].port,idnt[n].ini1,idnt[n].ini2,idnt[n].idx,id,rev);
+#endif /* DEBUG_CONFIG_HISPEED */
+
+ /* id & (rev or not 665IR/666IR) ? */
+ if ( (idnt[n].id==id) && ((idnt[n].rev==rev)||(idnt[n].type!=2)) && (idnt[n].type>1) )
+ return n;
+ return -1;
+}
+
+static void
+hispeed_natsemi_set(int portAdr, char opr, struct serial_state *state)
+{
+ int val;
+ if (opr == 'H') {
+ outb(0xe0, portAdr + UART_LCR); /* select Bank2 */
+#if 0
+ outb(0x41, portAdr + 0x02); /* set EXT_SL */
+#endif
+ val = inb(portAdr + 0x04); /* get EXCR2 */
+ val = (val & 0xcf) | 0x10; /* PRESL = 1.625 */
+ outb(val, portAdr + 0x04); /* set EXCR2 */
+ outb(0x00, portAdr + UART_LCR); /* select Bank0 */
+
+ state->baud_base = 921600;
+ }
+ if (opr == 'L') {
+ outb(0xe0, portAdr + UART_LCR); /* select Bank2 */
+#if 0
+ outb(0x40, portAdr + 0x02); /* clear EXT_SL */
+#endif
+ val = inb(portAdr + 0x04); /* get EXCR2 */
+ val = (val & 0xcf) | 0x00; /* PRESL = 13 */
+ outb(val, portAdr + 0x04); /* set EXCR2 */
+ outb(0x00, portAdr + UART_LCR); /* select Bank0 */
+ }
+}
+
+static int
+hispeed_operation(int n, char opr, int uart, int *portAdr, struct async_struct * info)
+{
+ unsigned char r,v,cr1,cr2;
+ int i,dvofs,nxt;
+ int portNo;
+ unsigned long flags;
+
+ portNo = 0x20 << uart;
+ v = 0;
+
+ switch(idnt[n].type) {
+ case 0: /* Unknown */
+ case 1: /* 665GT,666GT */
+ default: /* internal error.. */
+ break;
+ case 2: /* 665IR,666IR */
+ save_flags(flags); cli();
+ /* write ini value 2 times to enter config mode */
+ OUTP0(idnt[n].ini1);
+ OUTP0(idnt[n].ini2);
+ OUTP0(0x01);
+ cr1 = INP1;
+ OUTP0(0x02);
+ cr2 = INP1;
+ /* select sr0c */
+ OUTP0(0x0c);
+ r = INP1;
+ if (opr == 'H')
+ r |= portNo;
+ if (opr == 'L')
+ r &= ~portNo;
+ OUTP1(r);
+ r = INP1;
+ OUTP0(idnt[n].fin); /* exit config mode */
+ restore_flags(flags);
+ 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;
+ }
+ if ( i == uart ) {
+ v = v & r;
+ break;
+ }
+ } else {
+ if ( i == uart ) {
+ v = v & r;
+ portAdr[i] = 0;
+ break;
+ }
+ }
+ cr2 >>= 4;
+ v <<= 1;
+ }
+ break;
+ case 3: /* 669 */
+ save_flags(flags); cli();
+ /* write ini value 2 times to enter config mode */
+ OUTP0(idnt[n].ini1);
+ OUTP0(idnt[n].ini2);
+ OUTP0(0x24);
+ portAdr[1] = (INP1 & 0xFE) << 2;
+ OUTP0(0x25);
+ portAdr[2] = (INP1 & 0xFE) << 2;
+ /* select sr0c */
+ OUTP0(0x0c);
+ r = INP1;
+ if (opr == 'H')
+ r |= portNo;
+ if (opr == 'L')
+ r &= ~portNo;
+ OUTP1(r);
+ r = INP1;
+ OUTP0(idnt[n].fin); /* exit config mode */
+ restore_flags(flags);
+ for (v=0x40,i=1;i<=2;++i) {
+ if (portAdr[i] & 0x300) {
+ if ( i == uart ) {
+ v = v & r;
+ break;
+ }
+ } else {
+ if ( i == uart ) {
+ v = v & r;
+ portAdr[i] = 0;
+ break;
+ }
+ }
+ v <<= 1;
+ }
+ break;
+ case 8: /* W83877TF native */
+ case 9: /* W83877TF emulate mode */
+ save_flags(flags); cli(); /* cli */
+ /* write ini value 2 times to enter config mode */
+ OUTP0(idnt[n].ini1);
+ if (idnt[n].type != 8)
+ OUTP0(idnt[n].ini2);
+ else
+ idnt[n].port++;
+ OUTP0(0x24);
+ portAdr[1] = (INP1 & 0xFE) << 2;
+ OUTP0(0x25);
+ portAdr[2] = (INP1 & 0xFE) << 2;
+ /* select sr19 */
+ OUTP0(0x19);
+ r = INP1;
+ v = 0;
+ if (portNo & 0x40)
+ v = 0x2;
+ if (portNo & 0x80)
+ v |= 0x1;
+ if (opr == 'H')
+ r |= v;
+ if (opr == 'L')
+ r &= ~v;
+ OUTP1(r);
+ r = INP1;
+ OUTP0(idnt[n].fin); /* exit config mode */
+ restore_flags(flags); /* sti */
+ for (v=0x02,i=1;i<=2;++i) {
+ if (portAdr[i] & 0x300) {
+ if ( i == uart ) {
+ v = v & r;
+ if ( v )
+ info->state->baud_base = 921600;
+ break;
+ }
+ } else {
+ if ( i == uart ) {
+ v = v & r;
+ portAdr[i] = 0;
+ break;
+ }
+ }
+ 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 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) {
+ 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;
+ default: /* SMC,ALI */
+ dvofs = 4; /* 4:port1, 5:port2 */
+ nxt = 1;
+ break;
+ }
+
+ for (i = 1; i <=2 ; ++i, dvofs += nxt) {
+ save_flags(flags); cli(); /* cli */
+ /* write ini value 2 times to enter config mode */
+ if (idnt[n].ini1) OUTP0(idnt[n].ini1);
+ if (idnt[n].ini2) OUTP0(idnt[n].ini2);
+ OUTP0(0x07);/* Select device register */
+ OUTP1(dvofs); /* Set device value */
+ OUTP0(0x60); /* get port addr. */
+ portAdr[i] = ((int) INP1) << 8;
+ OUTP0(0x61);
+ portAdr[i] |= (int) INP1;
+#if defined(CHKENB)
+ OUTP0(0x30); /* enabled ? */
+ if (!INP1)
+ portAdr[i] = 0;
+#endif
+ OUTP1(0xF0);/* Select serial config register */
+ r = INP1;
+ switch (idnt[n].type) {
+ case 4: /* SMC */
+ case 30: /* ALI */
+ if ((0x20 << i) & portNo) {
+ if (opr == 'H')
+ r |= 2;
+ if (opr == 'L')
+ r &= ~2;
+ OUTP1(r);
+ }
+ r = INP1;
+ 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;
+ OUTP1(r);
+ }
+ r = INP1;
+ v = (unsigned char)((r&0x3) == 0x3);
+ if ( v )
+ info->state->baud_base = 921600;
+ break;
+ case 20: /* NS 87308 */
+ case 21: /* NS */
+ case 22: /* NS */
+ case 23: /* NS */
+ if ((0x20 << i) & portNo) {
+ OUTP0(0xf0);
+ OUTP1(r|0x80); /* enable Bank Select */
+ }
+ v = (unsigned char)(INP1&0x80);
+ if (v) hispeed_natsemi_set(portAdr[i], opr, info->state);
+ if ((0x20 << i) & portNo) {
+ if (opr == 'L') {
+ OUTP0(0xf0);
+ OUTP1(r&0x7f); /* disable Bank Select */
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ OUTP0(idnt[n].fin); /* exit config mode */
+ restore_flags(flags); /* sti */
+ if (portAdr[i]) {
+ if ( i == uart ) {
+ break;
+ }
+ } else {
+ if ( i == uart ) {
+ portAdr[i] = 0;
+ break;
+ }
+ }
+ }
+ break;
+#if defined(PC87338)
+ case 28: /* PC87338 */
+ OUTP0(0x00); /* get FER 3:FDC 2:SCC2 1:SCC1 0:PPA */
+ cr1 = INP1;
+ OUTP0(0x01); /* get FAR 7:6-COM34 5:4-SCC2 3:2-SCC1 2:1-PPA */
+ cr2 = INP1;
+
+ for (i=1;i<=2;++i) {
+ if ((cr1 & (1 << i) )==0) {
+ portAdr[i] = 0;
+ if ( i == uart ) {
+ v = 0;
+ break;
+ }
+ continue;
+ }
+ 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;
+ }
+ if ((0x20 << i) & portNo) {
+ OUTP0(0x40); /* enable Bank Select */
+ OUTP1(INP1 | (0x10 << (3*(i-1))) );
+ }
+ v = (unsigned char)(INP1 & (0x10 << (3*(i-1))) );
+ if ( v ) hispeed_natsemi_set(portAdr[i], opr, info->state);
+ if ((0x20 << i) & portNo) {
+ if (opr == 'L') {
+ OUTP0(0x40); /* disable Bank Select */
+ OUTP1(INP1 & ~(0x10 << (3*(i-1))) );
+ }
+ }
+ if ( i == uart )
+ break;
+ }
+ break;
+#endif
+ }
+
+ return v;
+}
+
+
+static void
+get_portAdr(int n, int *portAdr, struct async_struct * info)
+{
+ hispeed_operation(n, ' ', 2, portAdr, info);
+}
+
+
+static int
+enable_hispeed(struct async_struct * info)
+{
+ int result, n;
+ int uart;
+ char *fab;
+ int portAdr[3];
+
+ /* find what type of controller is used */
+ for (n = 0; idnt[n].port; n++) {
+ if ( hispeed_chip(n) != -1 ) break;
+ }
+ if ( idnt[n].port == 0 )
+ return 0;
+
+ /* what port? */
+ get_portAdr( n, portAdr, info );
+
+ uart = 0;
+ if ( portAdr[1] == info->port )
+ uart |= 1;
+ if ( portAdr[2] == info->port )
+ uart |= 2;
+
+ if ( uart == 0 || uart > 2) {
+ printk( "not there\n" );
+ return 0;
+ }
+
+ switch(idnt[n].pch) {
+ case 1:
+ fab = "SMC37";
+ break;
+ case 2:
+ fab = "Winbond ";
+ break;
+ case 3:
+ fab = "NS PC";
+ break;
+ case 4:
+ fab = "ALI ";
+ break;
+ default:
+ fab = "nowhere ";
+ break;
+ }
+ printk("(%s%s at %04xh",fab,idnt[n].name,idnt[n].port);
+
+ /* try to enable High Speed mode */
+ result = hispeed_operation(n, 'H', uart, portAdr, info);
+ if (result)
+ printk(", Serial Speed Mode: High)");
+ else
+ printk(")");
+
+ return result;
+}
+
+#ifdef MODULE
+static void
+disable_hispeed(void)
+{
+ int n;
+ int uart;
+ int portAdr[3];
+ int i;
+ struct serial_state * state;
+
+ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ if (state->type != PORT_16550A )
+ continue;
+
+ /* find what type of controller is used */
+ for (n = 0; idnt[n].port; n++) {
+ if ( hispeed_chip(n) != -1 ) break;
+ }
+ if ( idnt[n].port == 0 )
+ continue;
+
+ /* what port? */
+ get_portAdr( n, portAdr, state );
+
+ uart = 0;
+ if ( portAdr[1] == state->port )
+ uart |= 1;
+ if ( portAdr[2] == state->port )
+ uart |= 2;
+
+ if ( uart == 0 || uart > 2)
+ continue;
+
+ /* try to disable High Speed mode */
+ hispeed_operation(n, 'L', uart, portAdr, info);
+ }
+}
+#endif /* MODULE */
+#endif /* CONFIG_HISPEED */
+
/*
* This routine detect the IRQ of a serial port by clearing OUT2 when
* no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
@@ -2879,7 +3520,7 @@

/*
* This routine is called by rs_init() to initialize a specific serial
- * port. It determines what type of UART chip this serial port is
+ * port. It determines what type of UART hispeed_chip this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
* whether or not this UART is a 16550A or not, since this will
* determine whether or not we can use its FIFO features or not.
@@ -2927,7 +3568,7 @@

/*
* Check to see if a UART is really there. Certain broken
- * internal modems based on the Rockwell chipset fail this
+ * internal modems based on the Rockwell hispeed_chipset fail this
* test, because they apparently don't implement the loopback
* test mode. So this test is skipped on the COM 1 through
* COM 4 ports. This *should* be safe, since no board
@@ -3003,6 +3644,13 @@
if ((status1 != 0xa5) || (status2 != 0x5a))
state->type = PORT_8250;
}
+#ifdef CONFIG_HISPEED
+ if (state->type == PORT_16550A) {
+ printk( "Detecting hispeed chips... " );
+ enable_hispeed(info);
+ printk( "\n" );
+ }
+#endif
state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size;

if (state->type == PORT_UNKNOWN) {
@@ -3280,6 +3928,9 @@
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
}
+#ifdef CONFIG_HISPEED
+ disable_hispeed();
+#endif
}
#endif /* MODULE */

--- /dev/null Wed May 21 13:24:05 1997
+++ serial.linux/Documentation/shsmod-linux.txt Tue Dec 1 19:18:33 1998
@@ -0,0 +1,166 @@
+ Serial High Speed Mode Patch for Linux
+
+ June 15, 1997
+ MIZUHARA Bun
+ (mizuhara@st.rim.or.jp)
+
+ Sep 7, 1998
+ Updated by TAKEUCHI Yoji
+ (ytakeuch@po.iijnet.or.jp)
+
+1. Introduction
+
+Some SMC/NS/Winbond Multi-I/O chips and ALI south bridge chips have High
+Speed mode, in which baud rate can be set to 230400, 460800 (or 921600
+at NS/Winbond chips) bps. With this patch applied, the serial port driver
+automatically probe those chips and enable High Speed mode.
+
+This patch is created and tested for kernel 2.0.34.
+
+There is absolutely no warranty for this software.
+This software can be distributed or modified freely, provided that this
+documentation accompanies.
+However, it is encouraged to send comments or modifications to the author
+(mizuhara@st.rim.or.jp).
+
+Copyright 1996,1997 MIZUHARA Bun (mizuhara@st.rim.or.jp).
+
+
+2. History
+
+Spetember 7, 1998 Updated to V1.7a.
+ Updated features from original Shsmod V1.7a.
+
+June 15, 1997 Updated to v1.1.
+ Fixed a bug in 669 probing. Added support for new chips.
+
+November 3, 1996 Released first version.
+(My birthday!)
+
+
+3. System requirements
+
+OS: Linux kernel version 2.0.34 or later.
+
+I/O Chips:
+ ALI:
+ M1543(Aladdin V south bridge)
+
+ Serial ports provided by this chip will run at 230400 and 460800 bps.
+
+ NS:
+ PC87308
+ PC87307/87317
+ PC97307/97317
+ PC87309
+ PC87338
+
+ Serial ports provided by these chips will run at 230400/460800/921600(not tested) bps.
+
+ SMC:
+ 37C665IR/666IR
+ 37C669/669FR,37N769
+ 37B72x/77x/78x/80x,37C67x/68x/93x/93xAPM/93xFR,37M60x/61x,37N958FR
+
+ Serial ports provided by these chips will run at 230400 and 460800 bps.
+
+ WinBond:
+ W83877TF(TF ONLY, A/F/AF NOT supported)
+ W83977A/AF/TF/ATF
+
+ Serial ports provided by these chips will run at 230400 and 460800 bps.
+
+Visit http://www.yk.rim.or.jp/~gigo/download.html for detailed information
+and availability of patches for other OS.
+
+
+4. Installation and testing
+
+(1) Login as root.
+
+(2) Change directory to /usr/src (or a directory where linux kernel sources
+ reside).
+
+(3) Apply this patch.
+
+ # patch -p -s < shsmod17a-linux.patch
+
+ No messages should be displayed.
+
+(4) Rebuild the kernel.
+
+ If serial driver is compiled in the kernel (and LILO is used as a boot
+ loader), follow these steps:
+
+ # cd linux
+ # make zlilo
+
+ If serial driver is compiled as a module, follow these steps:
+
+ # cd linux
+ # make modules
+ # make modules_install
+
+(5) Reboot with the new kernel and watch messages carefully.
+
+ If you find messages like this, congratulations!
+
+ Serial driver version 4.13 with HighSpeedMode V1.7a(Linux 06-Sep-98) enabled
+ tty00 at 0x03f8 (irq = 4) is a 16550A(NS PC87308 at 002eh, Serial Speed Mode: High)
+ tty01 at 0x02f8 (irq = 3) is a 16550A(NS PC87308 at 002eh, Serial Speed Mode: High)
+
+ The first line shows that the driver supports High Speed mode.
+ It does not mean a chip used in your system supports High Speed mode.
+ The second and third line shows I/O chip type and wheather it supports
+ High Speed mode. If you cannot find "High Speed mode enabled" in the
+ messages, your chip does not support High Speed mode.
+ Try another motherboard or I/O card.
+
+
+5. How to use serial speed higher than 38400bps
+
+ From application's point of view, maximum speed of serial port is 38400bps
+ even if High Speed mode is enabled. Set it to 38400bps, and call a program
+ named "setserial" in order to use higher speed.
+
+ # setserial /dev/cua1 spd_hi
+ sets /dev/cua1 (com2) to 57600bps.
+
+ # setserial /dev/cua0 spd_vhi
+ sets /dev/cua0 (com1) to 115200bps.
+
+ for SMC/ALI chips
+ # setserial /dev/cua1 spd_cust divisor 0x8002
+ sets /dev/cua1 (com2) to 230400bps (with High Speed mode enabled).
+
+ # setserial /dev/cua0 spd_cust divisor 0x8001
+ sets /dev/cua0 (com1) to 460800bps (with High Speed mode enabled).
+
+ for NS/Winbond chips
+ # setserial /dev/cua1 spd_cust divisor 4
+ sets /dev/cua1 (com2) to 230400bps (with High Speed mode enabled).
+
+ # setserial /dev/cua0 spd_cust divisor 2
+ sets /dev/cua0 (com1) to 460800bps (with High Speed mode enabled).
+
+ # setserial /dev/cua0 spd_cust divisor 1
+ sets /dev/cua0 (com1) to 921600bps (with High Speed mode enabled).
+ !!! THIS MODE IS NOT TESTED !!!
+
+6. Bug reports
+
+ If you encounter problems, follow these steps.
+
+ (1) Recompile the driver with DEBUG_CONFIG_SHSMOD option enabled, if
+ possible. In the file linux/drivers/char/serial.c, you can find
+
+ /* #define DEBUG_CONFIG_SHSMOD */
+
+ at line number around 80. Uncomment this line and recompile, as
+ shown above.
+
+ (2) Reboot with the kernel, and watch messages. Write down relevant
+ messages. You can scroll up the screen by pressing Shift-PageUp.
+
+ (3) E-mail to me (ytakeuch@po.iijnet.or.jp) with detailed description
+ of the symptom, kernel messages, and hardware environment.

-- 
I'm really pavel@atrey.karlin.mff.cuni.cz. 	   Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/