patch-2.4.13 linux/drivers/sbus/char/sab82532.c
Next file: linux/drivers/sbus/char/su.c
Previous file: linux/drivers/sbus/char/jsflash.c
Back to the patch index
Back to the overall index
- Lines: 269
- Date:
Wed Oct 17 14:16:39 2001
- Orig file:
v2.4.12/linux/drivers/sbus/char/sab82532.c
- Orig date:
Thu Oct 11 08:02:26 2001
diff -u --recursive --new-file v2.4.12/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
@@ -1,4 +1,4 @@
-/* $Id: sab82532.c,v 1.64 2001/10/08 22:19:51 davem Exp $
+/* $Id: sab82532.c,v 1.65 2001/10/13 08:27:50 davem Exp $
* sab82532.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -6,6 +6,10 @@
* Rewrote buffer handling to use CIRC(Circular Buffer) macros.
* Maxim Krasnyanskiy <maxk@qualcomm.com>
*
+ * Fixed to use tty_get_baud_rate, and to allow for arbitrary baud
+ * rates to be programmed into the UART. Also eliminated a lot of
+ * duplicated code in the console setup.
+ * Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
*/
#include <linux/config.h>
@@ -147,45 +151,47 @@
* The formula is: Baud = BASE_BAUD / ((N + 1) * (1 << M)),
*
* with 0 <= N < 64 and 0 <= M < 16
- *
- * XXX: Speeds with M = 0 might not work properly for XTAL frequencies
- * above 10 MHz.
+ *
+ * 12-Oct-2001 - Replaced table driven approach with code written by
+ * Theodore Ts'o <tytso@alum.mit.edu> which exactly replicates the
+ * table. (Modulo bugs for the 307200 and 61440 baud rates, which
+ * were clearly incorrectly calculated in the original table. This is
+ * why tables filled with magic constants are evil.)
*/
-struct ebrg_struct {
- int baud;
- int n;
- int m;
-};
-static struct ebrg_struct ebrg_table[] = {
- { 0, 0, 0 },
- { 50, 35, 10 },
- { 75, 47, 9 },
- { 110, 32, 9 },
- { 134, 53, 8 },
- { 150, 47, 8 },
- { 200, 35, 8 },
- { 300, 47, 7 },
- { 600, 47, 6 },
- { 1200, 47, 5 },
- { 1800, 31, 5 },
- { 2400, 47, 4 },
- { 4800, 47, 3 },
- { 9600, 47, 2 },
- { 19200, 47, 1 },
- { 38400, 23, 1 },
- { 57600, 15, 1 },
- { 115200, 7, 1 },
- { 230400, 3, 1 },
- { 460800, 1, 1 },
- { 76800, 11, 1 },
- { 153600, 5, 1 },
- { 307200, 3, 1 },
- { 614400, 3, 0 },
- { 921600, 0, 1 },
-};
+static void calc_ebrg(int baud, int *n_ret, int *m_ret)
+{
+ int n, m;
-#define NR_EBRG_VALUES (sizeof(ebrg_table)/sizeof(struct ebrg_struct))
+ if (baud == 0) {
+ *n_ret = 0;
+ *m_ret = 0;
+ return;
+ }
+
+ /*
+ * We scale numbers by 10 so that we get better accuracy
+ * without having to use floating point. Here we increment m
+ * until n is within the valid range.
+ */
+ n = (BASE_BAUD*10) / baud;
+ m = 0;
+ while (n >= 640) {
+ n = n / 2;
+ m++;
+ }
+ n = (n+5) / 10;
+ /*
+ * We try very hard to avoid speeds with M == 0 since they may
+ * not work correctly for XTAL frequences above 10 MHz.
+ */
+ if ((m == 0) && ((n & 1) == 0)) {
+ n = n / 2;
+ m++;
+ }
+ *n_ret = n - 1;
+ *m_ret = m;
+}
#define SAB82532_MAX_TEC_TIMEOUT 200000 /* 1 character time (at 50 baud) */
#define SAB82532_MAX_CEC_TIMEOUT 50000 /* 2.5 TX CLKs (at 50 baud) */
@@ -939,7 +945,7 @@
unsigned int ebrg;
tcflag_t cflag;
unsigned char dafo;
- int i, bits;
+ int bits, n, m;
if (!info->tty || !info->tty->termios)
return;
@@ -982,18 +988,11 @@
}
/* Determine EBRG values based on baud rate */
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~(CBAUDEX);
- if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES))
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- i += 15;
- }
- ebrg = ebrg_table[i].n;
- ebrg |= (ebrg_table[i].m << 6);
+ info->baud = tty_get_baud_rate(info->tty);
+ calc_ebrg(info->baud, &n, &m);
+
+ ebrg = n | (m << 6);
- info->baud = ebrg_table[i].baud;
if (info->baud) {
info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
info->tec_timeout = (10 * 1000000) / info->baud;
@@ -2205,7 +2204,7 @@
static inline void __init show_serial_version(void)
{
- char *revision = "$Revision: 1.64 $";
+ char *revision = "$Revision: 1.65 $";
char *version, *p;
version = strchr(revision, ' ');
@@ -2558,12 +2557,11 @@
static int
sab82532_console_setup(struct console *con, char *options)
{
+ static struct tty_struct c_tty;
+ static struct termios c_termios;
struct sab82532 *info;
- unsigned int ebrg;
tcflag_t cflag;
- unsigned char dafo;
- int i, bits;
- unsigned long flags;
+ int i;
info = sab82532_chain;
for (i = con->index; i; i--) {
@@ -2595,92 +2593,28 @@
sunserial_console_termios(con);
cflag = con->cflag;
- /* Byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
- case CS6: dafo = SAB82532_DAFO_CHL6; bits = 8; break;
- case CS7: dafo = SAB82532_DAFO_CHL7; bits = 9; break;
- case CS8: dafo = SAB82532_DAFO_CHL8; bits = 10; break;
- /* Never happens, but GCC is too dumb to figure it out */
- default: dafo = SAB82532_DAFO_CHL5; bits = 7; break;
- }
-
- if (cflag & CSTOPB) {
- dafo |= SAB82532_DAFO_STOP;
- bits++;
- }
-
- if (cflag & PARENB) {
- dafo |= SAB82532_DAFO_PARE;
- bits++;
- }
-
- if (cflag & PARODD) {
-#ifdef CMSPAR
- if (cflag & CMSPAR)
- dafo |= SAB82532_DAFO_PAR_MARK;
- else
-#endif
- dafo |= SAB82532_DAFO_PAR_ODD;
- } else {
-#ifdef CMSPAR
- if (cflag & CMSPAR)
- dafo |= SAB82532_DAFO_PAR_SPACE;
- else
-#endif
- dafo |= SAB82532_DAFO_PAR_EVEN;
+ /*
+ * Fake up the tty and tty->termios structures so we can use
+ * change_speed (and eliminate a lot of duplicate code).
+ */
+ if (!info->tty) {
+ memset(&c_tty, 0, sizeof(c_tty));
+ info->tty = &c_tty;
}
-
- /* Determine EBRG values based on baud rate */
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~(CBAUDEX);
- if ((i < 1) || ((i + 15) >= NR_EBRG_VALUES))
- cflag &= ~CBAUDEX;
- else
- i += 15;
+ if (!info->tty->termios) {
+ memset(&c_termios, 0, sizeof(c_termios));
+ info->tty->termios = &c_termios;
}
- ebrg = ebrg_table[i].n;
- ebrg |= (ebrg_table[i].m << 6);
-
- info->baud = ebrg_table[i].baud;
- if (info->baud)
- info->timeout = (info->xmit_fifo_size * HZ * bits) / info->baud;
- else
- info->timeout = 0;
- info->timeout += HZ / 50; /* Add .02 seconds of slop */
-
- /* CTS flow control flags */
- if (cflag & CRTSCTS)
- info->flags |= ASYNC_CTS_FLOW;
- else
- info->flags &= ~(ASYNC_CTS_FLOW);
-
- if (cflag & CLOCAL)
- info->flags &= ~(ASYNC_CHECK_CD);
- else
- info->flags |= ASYNC_CHECK_CD;
+ info->tty->termios->c_cflag = con->cflag;
- save_flags(flags); cli();
- sab82532_cec_wait(info);
- sab82532_tec_wait(info);
- writeb(dafo, &info->regs->w.dafo);
- writeb(ebrg & 0xff, &info->regs->w.bgr);
- writeb(readb(&info->regs->rw.ccr2) & ~(0xc0), &info->regs->rw.ccr2);
- writeb(readb(&info->regs->rw.ccr2) | ((ebrg >> 2) & 0xc0), &info->regs->rw.ccr2);
- if (info->flags & ASYNC_CTS_FLOW) {
- writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode);
- writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode);
- writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FCTS), &info->regs->rw.mode);
- } else {
- writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RTS, &info->regs->rw.mode);
- writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_FRTS), &info->regs->rw.mode);
- writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FCTS, &info->regs->rw.mode);
- }
- writeb(~(info->pvr_dtr_bit), &info->regs->rw.pvr);
- writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_RAC, &info->regs->rw.mode);
- restore_flags(flags);
+ change_speed(info);
+ /* Now take out the pointers to static structures if necessary */
+ if (info->tty->termios == &c_termios)
+ info->tty->termios = 0;
+ if (info->tty == &c_tty)
+ info->tty = 0;
+
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)