diff -u -p linux/include/linux/serial_reg.brain.h linux/include/linux/serial_reg.h
--- linux/include/linux/serial_reg.brain.h	Mon Oct 29 15:55:04 2001
+++ linux/include/linux/serial_reg.h	Fri Oct 26 11:35:39 2001
@@ -126,6 +126,12 @@
 #define UART_MCR_OUT1	0x04	/* Out1 complement */
 #define UART_MCR_RTS	0x02	/* RTS complement */
 #define UART_MCR_DTR	0x01	/* DTR complement */
+/*
+ * Extra MCR bit for 16C950.
+ * Those bits are only available when the 950 mode is enable (EFR bit 4 = 1)
+ */
+#define UART_MCR_IRDA		0x40	/* Enable IrDA mode (SIR) */
+#define UART_MCR_PRESCALE	0x80	/* Enable clock prescaler */
 
 /*
  * These are the definitions for the Modem Status Register
@@ -163,7 +169,7 @@
 /* The 16950 ICR registers */
 #define UART_ACR	0x00	/* Additional Control Register */
 #define UART_CPR	0x01	/* Clock Prescalar Register */
-#define UART_TCR	0x02	/* Times Clock Register */
+#define UART_TCR	0x02	/* Times Clock Register (overclock) */
 #define UART_CKS	0x03	/* Clock Select Register */
 #define UART_TTL	0x04	/* Transmitter Interrupt Trigger Level */
 #define UART_RTL	0x05	/* Receiver Interrupt Trigger Level */
diff -u -p linux/include/linux/serialP.brain.h linux/include/linux/serialP.h
--- linux/include/linux/serialP.brain.h	Mon Oct 29 15:54:50 2001
+++ linux/include/linux/serialP.h	Mon Oct 29 17:49:36 2001
@@ -74,7 +74,9 @@ struct async_struct {
 	int			IER; 	/* Interrupt Enable Register */
 	int			MCR; 	/* Modem control register */
 	int			LCR; 	/* Line control register */
-	int			ACR;	 /* 16950 Additional Control Reg. */
+	int			ACR;	/* 16950 Additional Control Reg. */
+	int			CPR;	/* 16950 Clock prescaler. */
+	int			WMSR;	/* Custom write to MSR if >= 0x100 */
 	unsigned long		event;
 	unsigned long		last_active;
 	int			line;
diff -u -p linux/include/asm-i386/ioctls.brain.h linux/include/asm-i386/ioctls.h
--- linux/include/asm-i386/ioctls.brain.h	Mon Oct 29 15:54:10 2001
+++ linux/include/asm-i386/ioctls.h	Mon Oct 29 16:14:41 2001
@@ -68,6 +68,7 @@
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
 #define FIOQSIZE	0x5460
+#define TIOCSERSETWMSR  0x5461	/* Set custom write in Modem Status Register */
 
 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -u -p linux/drivers/char/serial.brain.c linux/drivers/char/serial.c
--- linux/drivers/char/serial.brain.c	Mon Oct 29 15:55:33 2001
+++ linux/drivers/char/serial.c	Tue Oct 30 13:25:09 2001
@@ -1268,6 +1268,36 @@ static int startup(struct async_struct *
 		serial_outp(info, UART_LCR, 0xBF);
 		serial_outp(info, UART_EFR, UART_EFR_ECB);
 		serial_outp(info, UART_LCR, 0);
+
+		/* If we don't have a value for CPR, try to guess one...
+		 * The 16C950 can use non standard UART clock frequencies,
+		 * the CPR register allow to convert this non standard clock
+		 * to the standard clock, allowing us to generate the proper
+		 * serial bit rate.
+		 * The UART clock is known only to the board designer, so we
+		 * can only attempt to guess the proper CPR value (see below).
+		 * The user can "fix" CPR by setting baud_base with setserial.
+		 * Jean II */
+		if(info->CPR == 0) {
+			/* Spec says : After reset, MCR[7] is set to the
+			 * complement of the value of pin CLKSEL.
+			 * To be compatible with 16C550, either use 1.8432MHz
+			 * clock with CLKSEL connected to VDD, or use
+			 * 7.3728MHz with CLKSEL connected to GND. */
+			if(serial_inp(info, UART_MCR) & UART_MCR_PRESCALE) {
+				/* Assume 7.3728MHz UART clock.
+				 * CPR will contain 0x20 == Divide by 4 */
+				info->CPR = serial_icr_read(info, UART_CPR);
+				state->baud_base = (115200 * info->CPR) / 0x8;
+			} else {
+				/* Assume standard 1.8432MHz UART clock */
+				info->CPR = 0x08;	/* Divide by 1 */
+				state->baud_base = 115200;
+			}
+#ifdef DEBUG_16C950_CPR
+			printk(KERN_DEBUG "16C950 read MCR = 0x%X, CPR = 0x%X ; assuming baud_base = %d, CPR = 0x%X\n", serial_inp(info, UART_MCR), serial_icr_read(info, UART_CPR), state->baud_base, info->CPR);
+#endif
+		}
 	}
 
 #ifdef CONFIG_SERIAL_RSA
@@ -1284,6 +1314,14 @@ static int startup(struct async_struct *
 	}
 #endif
 
+	/* Custom write to MSR (needed here because of UART soft reset) */
+	if(info->WMSR >= 0x100) {
+#ifdef DEBUG_16C950_WMSR
+		printk(KERN_DEBUG "16C950 Writing 0x%02X to MSR\n", info->WMSR & 0xFF);
+#endif
+		serial_out(info, UART_MSR, info->WMSR & 0xFF);
+	}
+
 	/*
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
@@ -1370,8 +1408,12 @@ static int startup(struct async_struct *
 	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
 
 	info->MCR = 0;
+	if (state->type == PORT_16C950)
+		/* For the 16C950, always enable the clock prescaler
+		 * it will be properly set in set_extra_speed_950() */
+		info->MCR |= UART_MCR_PRESCALE;
 	if (info->tty->termios->c_cflag & CBAUD)
-		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+		info->MCR |= UART_MCR_DTR | UART_MCR_RTS;
 #ifdef CONFIG_SERIAL_MANY_PORTS
 	if (info->flags & ASYNC_FOURPORT) {
 		if (state->irq == 0)
@@ -1601,6 +1643,103 @@ static int tty_get_baud_rate(struct tty_
 #endif
 
 /*
+ * Set the appropriate extra speed control register of the 16C950.
+ * Basically, we set the CPR prescaler register to match the assumed
+ * UART clock speed, and we set the TCR overclock register to enable
+ * to reach higher speed.
+ * We return the new apparent overclocked baud_base that will be used
+ * to calculate the proper divisor (quot).
+ * Jean II
+ */
+static int set_extra_speed_950(struct async_struct *info, int baud)
+{
+	/* baud_base need to be at least 25 bits to avoid overflow. */
+	long	baud_base = info->state->baud_base;
+	int	current_tcr;
+
+	/* Setting CPR (prescaler register)
+	 *
+	 * baud_base indicates by how much the present UART clock is faster
+	 * than the standard UART clock. In other words, if the UART clock
+	 * is 4 time faster than standard (7.3728MHz), you should set
+	 * baud_base to 4*115200 = 460800 (which is the max baud rate
+	 * with CPR=1 and TCR=16 mentionned in table 17 at page 30 of the
+	 * OX16C950 rev B spec sheet).
+	 * It seems that the prescaler must be greater than 1 (CPR >= 0x8).
+	 *
+	 * For now, we are pretty dumb in setting CPR. We just use the proper
+	 * prescaler value when we need to do standard speeds (up to 115200)
+	 * and we use no prescaler to reach higher speeds.
+	 * Remember that on top of that we can be overclocked up to 4 times
+	 * through TCR.
+	 * We could be much more clever, as in theory the CPR allow us
+	 * to generate any baud_base we want, so we can generate any
+	 * serial speed we want. I don't really know how well it works
+	 * in practice...
+	 */
+	if(baud > 115200) {
+		/* No prescaler - allow higher speeds */
+		info->CPR = 0x8;
+		/* No need to fudge baud_rate, it's the proper one */
+	} else {
+		/* Calculate prescaler - allow 550 compatible speeds */
+		info->CPR = (baud_base * 0x8) / 115200;
+		/* Check boundaries */
+		if(info->CPR < 8) {
+			info->CPR = 8;
+			printk(KERN_DEBUG "16C950 : Baud_base is to low (min 115200)\n");
+		}
+		if(info->CPR > 0xFF) {
+			info->CPR = 0xFF;
+			printk(KERN_DEBUG "16C950 : Baud_base is to high (max 3672000)\n");
+		}
+		/* Our apparent baud_base is now 550 compatible */
+		baud_base = 115200;
+	}
+	serial_icr_write(info, UART_CPR, info->CPR);
+
+	/* Setting TCR (overclock register)
+	 *
+	 * We try to minimise the use of overclocking to only when
+	 * it's really necessary : only when we can't reach
+	 * the speed through the prescaler.
+	 *
+	 * The 4 lowest bit of TCR represent the value of the clock
+	 * sampling. 0x0 in fact mean 0x10 = 16, which is the default
+	 * (550 compatible), and only values in the range 4 to 16 are
+	 * supported (0x4 -> 0xF + 0x0).
+	 * Moreover, it seems that only 0x4 and 0x0 are safe with older
+	 * revisions of the 16C950. We don't really need to intermediate
+	 * steppings because we could use the divisor & CPR to do it.
+	 */
+	if (baud <= baud_base)
+		current_tcr = 0x0;	/* Sampling clock = 16 = standard */
+        else if ((baud <= 2*baud_base) &&
+                 (info->state->revision != 0x5201) &&
+                 (info->state->revision != 0x5400)) {
+		current_tcr = 0x8;	/* Sampling clock = 8 = 2x overclock */
+		baud_base = baud_base * 2;
+	} else if (baud <= 4*baud_base) {
+		current_tcr = 0x4;	/* Sampling clock = 4 = 4x overclock */
+		baud_base = baud_base * 4;
+	} else {
+		/* Should do better ??? */
+		printk(KERN_DEBUG "16C950 : Can't reach desired speed %d\n",
+		       baud);
+		current_tcr = 0x0;	/* Sampling clock = 16 = standard */
+	}
+	serial_icr_write(info, UART_TCR, current_tcr);
+
+#ifdef DEBUG_16C950_CPR
+	printk(KERN_DEBUG "16C950 Set Extra speed : baud = %d, standard baud_base = %d\n", baud, info->state->baud_base);
+	printk(KERN_DEBUG "16C950 - apparent baud_base = %ld, CPR = 0x%X, TCR = 0x%X\n", baud_base, info->CPR, current_tcr);
+#endif
+
+	/* Return the aparent baud_base */
+	return(baud_base);
+}
+
+/*
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
  */
@@ -1654,16 +1793,8 @@ static void change_speed(struct async_st
 #endif
 	baud_base = info->state->baud_base;
 	if (info->state->type == PORT_16C950) {
-		if (baud <= baud_base)
-			serial_icr_write(info, UART_TCR, 0);
-		else if (baud <= 2*baud_base) {
-			serial_icr_write(info, UART_TCR, 0x8);
-			baud_base = baud_base * 2;
-		} else if (baud <= 4*baud_base) {
-			serial_icr_write(info, UART_TCR, 0x4);
-			baud_base = baud_base * 4;
-		} else
-			serial_icr_write(info, UART_TCR, 0);
+		/* Special processing for 16C950 */
+		baud_base = set_extra_speed_950(info, baud);
 	}
 	if (baud == 38400 &&
 	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
@@ -2339,6 +2470,44 @@ static int set_modem_info(struct async_s
 	return 0;
 }
 
+/*
+ * Some serial card take advantage that MSR is normally a read only register
+ * to define here an additional write only register (not part of the UART).
+ * In theory, writing to MSR is safe, but you never know... Also, in 650
+ * mode, this register is XOFF1 (enabled after writing 0xBF to LCR).
+ *
+ * One example is the Brainboxes 620 (Pcmcia Bluetooth card using 16C950
+ * UART) where writing to MSR set the UART clock frequency :
+ *	MSR[5:4] set to 0x0 ->  /8  ->  1.8432MHz UART clock
+ *	MSR[5:4] set to 0x1 ->  /4  ->  3.6864MHz UART clock
+ *	MSR[5:4] set to 0x2 ->  /2  ->  7.3728MHz UART clock
+ *	MSR[5:4] set to 0x3 ->  /1  -> 14.7456MHz UART clock
+ * Note : Most often, you want to set it to 0x30 (and baud_base to 921600)
+ * Jean II
+ */
+static int set_write_msr(struct async_struct * info, unsigned char *value)
+{
+	unsigned long flags;
+	unsigned char msr;
+	
+	if (copy_from_user(&msr, value, sizeof(unsigned char)))
+		return -EFAULT;
+
+#ifdef DEBUG_16C950_WMSR
+	printk(KERN_DEBUG "16C950 Setting WMSR to 0x%02X\n", msr);
+#endif
+
+	/* Save it for subsequent reset */
+	info->WMSR = 0x100 | msr;
+
+	/* Just do it ! */
+	save_flags(flags); cli();
+	serial_out(info, UART_MSR, info->WMSR & 0xFF);
+	restore_flags(flags);
+
+	return 0;
+}
+
 static int do_autoconfig(struct async_struct * info)
 {
 	int irq, retval;
@@ -2678,6 +2847,8 @@ static int rs_ioctl(struct tty_struct *t
 			/* "setserial -W" is called in Debian boot */
 			printk ("TIOCSER?WILD ioctl obsolete, ignored.\n");
 			return 0;
+		case TIOCSERSETWMSR:
+			return set_write_msr(info, (unsigned char *) arg);
 
 		default:
 			return -ENOIOCTLCMD;
