]> git.hungrycats.org Git - linux/commitdiff
[PATCH] mips: DECstation Turbochannel updates
authorRalf Bächle <ralf@linux-mips.org>
Wed, 2 Feb 2005 00:44:48 +0000 (16:44 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Wed, 2 Feb 2005 00:44:48 +0000 (16:44 -0800)
Update Turbochannel code.  Right now the code is basically still at the state
of 2.3; with this patch applied it'll roughly on the level of the TC code in
early 2.4 with a bunch of 2.6 fixes on top.  Not great but will bring the code
closer into touch with reality until Maciej has a chance to finally tackle
things.

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/tc/lk201.c
drivers/tc/lk201.h
drivers/tc/tc.c
drivers/tc/zs.c
drivers/tc/zs.h

index bfd602a6514b64a0f7ada482cd946e2a57333342..cf10d5cdfb931ce1e3a08806c7e8b6d38f2c7854 100644 (file)
@@ -4,20 +4,44 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * Copyright (C) 1999-2002 Harald Koerfgen <hkoerfg@web.de>
+ * Copyright (C) 2001, 2002, 2003, 2004  Maciej W. Rozycki
  */
+
+#include <linux/config.h>
+
 #include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/kbd_ll.h>
-#include <asm/wbflush.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+
+#include <asm/keyboard.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/machtype.h>
+#include <asm/dec/serial.h>
 
-#include "zs.h"
 #include "lk201.h"
 
+/*
+ * Only handle DECstations that have an LK201 interface.
+ * Maxine uses LK501 at the Access.Bus and various DECsystems
+ * have no keyboard interface at all.
+ */
+#define LK_IFACE       (mips_machtype == MACH_DS23100    || \
+                        mips_machtype == MACH_DS5000_200 || \
+                        mips_machtype == MACH_DS5000_1XX || \
+                        mips_machtype == MACH_DS5000_2X0)
+/*
+ * These use the Z8530 SCC.  Others use the DZ11.
+ */
+#define LK_IFACE_ZS    (mips_machtype == MACH_DS5000_1XX || \
+                        mips_machtype == MACH_DS5000_2X0)
+
 /* Simple translation table for the SysRq keys */
 
 #ifdef CONFIG_MAGIC_SYSRQ
  */
 unsigned char lk201_sysrq_xlate[128];
 unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate;
+
+unsigned char kbd_sysrq_key = -1;
 #endif
 
 #define KEYB_LINE      3
 
-static int __init lk201_init(struct dec_serial *);
-static void __init lk201_info(struct dec_serial *);
-static void lk201_kbd_rx_char(unsigned char, unsigned char);
+static int __init lk201_init(void *);
+static void __init lk201_info(void *);
+static void lk201_rx_char(unsigned char, unsigned char);
 
-struct zs_hook lk201_kbdhook = {
-       .init_channel   = lk201_init,
-       .init_info      = lk201_info,
-       .cflags         = B4800 | CS8 | CSTOPB | CLOCAL
+static struct dec_serial_hook lk201_hook = {
+       .init_channel   = lk201_init,
+       .init_info      = lk201_info,
+       .rx_char        = NULL,
+       .poll_rx_char   = NULL,
+       .poll_tx_char   = NULL,
+       .cflags         = B4800 | CS8 | CSTOPB | CLOCAL,
 };
 
 /*
  * This is used during keyboard initialisation
  */
 static unsigned char lk201_reset_string[] = {
-       LK_CMD_LEDS_ON, LK_PARAM_LED_MASK(0xf), /* show we are resetting */
        LK_CMD_SET_DEFAULTS,
        LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
        LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
@@ -61,28 +89,199 @@ static unsigned char lk201_reset_string[] = {
        LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
        LK_CMD_MODE(LK_MODE_DOWN, 13),
        LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
-       LK_CMD_ENB_RPT,
        LK_CMD_DIS_KEYCLK,
-       LK_CMD_RESUME,
        LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
-       LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf)
 };
 
-static int __init lk201_reset(struct dec_serial *info)
+static void *lk201_handle;
+
+static int lk201_send(unsigned char ch)
+{
+       if (lk201_hook.poll_tx_char(lk201_handle, ch)) {
+               printk(KERN_ERR "lk201: transmit timeout\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static inline int lk201_get_id(void)
+{
+       return lk201_send(LK_CMD_REQ_ID);
+}
+
+static int lk201_reset(void)
+{
+       int i, r;
+
+       for (i = 0; i < sizeof(lk201_reset_string); i++) {
+               r = lk201_send(lk201_reset_string[i]);
+               if (r < 0)
+                       return r;
+       }
+       return 0;
+}
+
+static void lk201_report(unsigned char id[6])
+{
+       char *report = "lk201: keyboard attached, ";
+
+       switch (id[2]) {
+       case LK_STAT_PWRUP_OK:
+               printk(KERN_INFO "%sself-test OK\n", report);
+               break;
+       case LK_STAT_PWRUP_KDOWN:
+               /* The keyboard will resend the power-up ID
+                  after all keys are released, so we don't
+                  bother handling the error specially.  Still
+                  there may be a short-circuit inside.
+                */
+               printk(KERN_ERR "%skey down (stuck?), code: 0x%02x\n",
+                      report, id[3]);
+               break;
+       case LK_STAT_PWRUP_ERROR:
+               printk(KERN_ERR "%sself-test failure\n", report);
+               break;
+       default:
+               printk(KERN_ERR "%sunknown error: 0x%02x\n",
+                      report, id[2]);
+       }
+}
+
+static void lk201_id(unsigned char id[6])
+{
+       /*
+        * Report whether there is an LK201 or an LK401
+        * The LK401 has ALT keys...
+        */
+       switch (id[4]) {
+       case 1:
+               printk(KERN_INFO "lk201: LK201 detected\n");
+               break;
+       case 2:
+               printk(KERN_INFO "lk201: LK401 detected\n");
+               break;
+       case 3:
+               printk(KERN_INFO "lk201: LK443 detected\n");
+               break;
+       case 4:
+               printk(KERN_INFO "lk201: LK421 detected\n");
+               break;
+       default:
+               printk(KERN_WARNING
+                      "lk201: unknown keyboard detected, ID %d\n", id[4]);
+               printk(KERN_WARNING "lk201: ... please report to "
+                      "<linux-mips@linux-mips.org>\n");
+       }
+}
+
+#define DEFAULT_KEYB_REP_DELAY (250/5) /* [5ms] */
+#define DEFAULT_KEYB_REP_RATE  30      /* [cps] */
+
+static struct kbd_repeat kbdrate = {
+       DEFAULT_KEYB_REP_DELAY,
+       DEFAULT_KEYB_REP_RATE
+};
+
+static void parse_kbd_rate(struct kbd_repeat *r)
 {
+       if (r->delay <= 0)
+               r->delay = kbdrate.delay;
+       if (r->rate <= 0)
+               r->rate = kbdrate.rate;
+
+       if (r->delay < 5)
+               r->delay = 5;
+       if (r->delay > 630)
+               r->delay = 630;
+       if (r->rate < 12)
+               r->rate = 12;
+       if (r->rate > 127)
+               r->rate = 127;
+       if (r->rate == 125)
+               r->rate = 124;
+}
+
+static int write_kbd_rate(struct kbd_repeat *rep)
+{
+       int delay, rate;
        int i;
 
-       for (i = 0; i < sizeof(lk201_reset_string); i++)
-               if (info->hook->poll_tx_char(info, lk201_reset_string[i])) {
-                       printk("%s transmit timeout\n", __FUNCTION__);
-                       return -EIO;
-               }
+       delay = rep->delay / 5;
+       rate = rep->rate;
+       for (i = 0; i < 4; i++) {
+               if (lk201_hook.poll_tx_char(lk201_handle,
+                                           LK_CMD_RPT_RATE(i)))
+                       return 1;
+               if (lk201_hook.poll_tx_char(lk201_handle,
+                                           LK_PARAM_DELAY(delay)))
+                       return 1;
+               if (lk201_hook.poll_tx_char(lk201_handle,
+                                           LK_PARAM_RATE(rate)))
+                       return 1;
+       }
+       return 0;
+}
+
+static int lk201_kbd_rate(struct kbd_repeat *rep)
+{
+       if (rep == NULL)
+               return -EINVAL;
+
+       parse_kbd_rate(rep);
+
+       if (write_kbd_rate(rep)) {
+               memcpy(rep, &kbdrate, sizeof(struct kbd_repeat));
+               return -EIO;
+       }
+
+       memcpy(&kbdrate, rep, sizeof(struct kbd_repeat));
+
        return 0;
 }
 
+static void lk201_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+       if (!ticks)
+               return;
+
+       /*
+        * Can't set frequency and we "approximate"
+        * duration by volume. ;-)
+        */
+       ticks /= HZ / 32;
+       if (ticks > 7)
+               ticks = 7;
+       ticks = 7 - ticks;
+
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_ENB_BELL))
+               return;
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_VOLUME(ticks)))
+               return;
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_BELL))
+               return;
+}
+
 void kbd_leds(unsigned char leds)
 {
-       return;
+       unsigned char l = 0;
+
+       if (!lk201_handle)              /* FIXME */
+               return;
+
+       /* FIXME -- Only Hold and Lock LEDs for now. --macro */
+       if (leds & LED_SCR)
+               l |= LK_LED_HOLD;
+       if (leds & LED_CAP)
+               l |= LK_LED_LOCK;
+
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_ON))
+               return;
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(l)))
+               return;
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_OFF))
+               return;
+       if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(~l)))
+               return;
 }
 
 int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
@@ -107,128 +306,136 @@ char kbd_unexpected_up(unsigned char keycode)
        return 0x80;
 }
 
-static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
+static void lk201_rx_char(unsigned char ch, unsigned char fl)
 {
+       static unsigned char id[6];
+       static int id_i;
+
        static int shift_state = 0;
        static int prev_scancode;
        unsigned char c = scancodeRemap[ch];
 
-       if (!stat || stat == 4) {
-               switch (ch) {
-               case LK_KEY_ACK:
-                       break;
-               case LK_KEY_LOCK:
-                       shift_state ^= LK_LOCK;
-                       handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
-                       break;
-               case LK_KEY_SHIFT:
-                       shift_state ^= LK_SHIFT;
-                       handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
-                       break;
-               case LK_KEY_CTRL:
-                       shift_state ^= LK_CTRL;
-                       handle_scancode(c, shift_state && LK_CTRL ? 1 : 0);
-                       break;
-               case LK_KEY_COMP:
-                       shift_state ^= LK_COMP;
-                       handle_scancode(c, shift_state && LK_COMP ? 1 : 0);
-                       break;
-               case LK_KEY_RELEASE:
-                       if (shift_state & LK_SHIFT)
-                               handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
-                       if (shift_state & LK_CTRL)
-                               handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
-                       if (shift_state & LK_COMP)
-                               handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
-                       if (shift_state & LK_LOCK)
-                               handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
-                       shift_state = 0;
-                       break;
-               case LK_KEY_REPEAT:
-                       handle_scancode(prev_scancode, 1);
-                       break;
-               default:
-                       prev_scancode = c;
-                       handle_scancode(c, 1);
-                       break;
+       if (fl != TTY_NORMAL && fl != TTY_OVERRUN) {
+               printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n", fl);
+               return;
+       }
+
+       /* Assume this is a power-up ID. */
+       if (ch == LK_STAT_PWRUP_ID && !id_i) {
+               id[id_i++] = ch;
+               return;
+       }
+
+       /* Handle the power-up sequence. */
+       if (id_i) {
+               id[id_i++] = ch;
+               if (id_i == 4) {
+                       /* OK, the power-up concluded. */
+                       lk201_report(id);
+                       if (id[2] == LK_STAT_PWRUP_OK)
+                               lk201_get_id();
+                       else {
+                               id_i = 0;
+                               printk(KERN_ERR "lk201: keyboard power-up "
+                                      "error, skipping initialization\n");
+                       }
+               } else if (id_i == 6) {
+                       /* We got the ID; report it and start operation. */
+                       id_i = 0;
+                       lk201_id(id);
+                       lk201_reset();
                }
-       } else
-               printk("Error reading LKx01 keyboard: 0x%02x\n", stat);
+               return;
+       }
+
+       /* Everything else is a scancode/status response. */
+       id_i = 0;
+       switch (ch) {
+       case LK_STAT_RESUME_ERR:
+       case LK_STAT_ERROR:
+       case LK_STAT_INHIBIT_ACK:
+       case LK_STAT_TEST_ACK:
+       case LK_STAT_MODE_KEYDOWN:
+       case LK_STAT_MODE_ACK:
+               break;
+       case LK_KEY_LOCK:
+               shift_state ^= LK_LOCK;
+               handle_scancode(c, (shift_state & LK_LOCK) ? 1 : 0);
+               break;
+       case LK_KEY_SHIFT:
+               shift_state ^= LK_SHIFT;
+               handle_scancode(c, (shift_state & LK_SHIFT) ? 1 : 0);
+               break;
+       case LK_KEY_CTRL:
+               shift_state ^= LK_CTRL;
+               handle_scancode(c, (shift_state & LK_CTRL) ? 1 : 0);
+               break;
+       case LK_KEY_COMP:
+               shift_state ^= LK_COMP;
+               handle_scancode(c, (shift_state & LK_COMP) ? 1 : 0);
+               break;
+       case LK_KEY_RELEASE:
+               if (shift_state & LK_SHIFT)
+                       handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
+               if (shift_state & LK_CTRL)
+                       handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
+               if (shift_state & LK_COMP)
+                       handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
+               if (shift_state & LK_LOCK)
+                       handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
+               shift_state = 0;
+               break;
+       case LK_KEY_REPEAT:
+               handle_scancode(prev_scancode, 1);
+               break;
+       default:
+               prev_scancode = c;
+               handle_scancode(c, 1);
+               break;
+       }
+       tasklet_schedule(&keyboard_tasklet);
 }
 
-static void __init lk201_info(struct dec_serial *info)
+static void __init lk201_info(void *handle)
 {
 }
 
-static int __init lk201_init(struct dec_serial *info)
+static int __init lk201_init(void *handle)
 {
-       unsigned int ch, id = 0;
-       int result;
+       /* First install handlers. */
+       lk201_handle = handle;
+       kbd_rate = lk201_kbd_rate;
+       kd_mksound = lk201_kd_mksound;
 
-       printk("DECstation LK keyboard driver v0.04... ");
+       lk201_hook.rx_char = lk201_rx_char;
 
-       result = lk201_reset(info);
-       if (result)
-               return result;
-       mdelay(10);
-
-       /*
-        * Detect whether there is an LK201 or an LK401
-        * The LK401 has ALT keys...
-        */
-       info->hook->poll_tx_char(info, LK_CMD_REQ_ID);
-       while ((ch = info->hook->poll_rx_char(info)) > 0)
-               id = ch;
-
-       switch (id) {
-       case 1:
-               printk("LK201 detected\n");
-               break;
-       case 2:
-               printk("LK401 detected\n");
-               break;
-       default:
-               printk("unknown keyboard, ID %d,\n", id);
-               printk("... please report to <linux-mips@oss.sgi.com>\n");
-       }
-
-       /*
-        * now we're ready
-        */
-       info->hook->rx_char = lk201_kbd_rx_char;
+       /* Then just issue a reset -- the handlers will do the rest. */
+       lk201_send(LK_CMD_POWER_UP);
 
        return 0;
 }
 
 void __init kbd_init_hw(void)
 {
-       extern int register_zs_hook(unsigned int, struct zs_hook *);
-       extern int unregister_zs_hook(unsigned int);
-
-       if (TURBOCHANNEL) {
-               if (mips_machtype != MACH_DS5000_XX) {
-                       /*
-                        * This is not a MAXINE, so:
-                        *
-                        * kbd_init_hw() is being called before
-                        * rs_init() so just register the kbd hook
-                        * and let zs_init do the rest :-)
-                        */
-                       if (mips_machtype == MACH_DS5000_200)
-                               printk("LK201 Support for DS5000/200 not yet ready ...\n");
-                       else
-                               if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
-                                       unregister_zs_hook(KEYB_LINE);
-               }
+       /* Maxine uses LK501 at the Access.Bus. */
+       if (!LK_IFACE)
+               return;
+
+       printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n");
+
+       if (LK_IFACE_ZS) {
+               /*
+                * kbd_init_hw() is being called before
+                * rs_init() so just register the kbd hook
+                * and let zs_init do the rest :-)
+                */
+               if (!register_dec_serial_hook(KEYB_LINE, &lk201_hook))
+                       unregister_dec_serial_hook(KEYB_LINE);
        } else {
                /*
                 * TODO: modify dz.c to allow similar hooks
                 * for LK201 handling on DS2100, DS3100, and DS5000/200
                 */
-               printk("LK201 Support for DS3100 not yet ready ...\n");
+               printk(KERN_ERR "lk201: support for DZ11 not yet ready.\n");
        }
 }
-
-
-
-
index 5a7450e8320b4982afd8c0976d320a2a03ac3145..99f3203c41b86c80d87c60de28cd1ff83425a12a 100644 (file)
  *     Commands to the keyboard processor
  */
 
-#define        LK_PARAM                0x80    /* start/end parameter list */
-
-#define        LK_CMD_RESUME           0x8b
-#define        LK_CMD_INHIBIT          0xb9
-#define        LK_CMD_LEDS_ON          0x13    /* 1 param: led bitmask */
-#define        LK_CMD_LEDS_OFF         0x11    /* 1 param: led bitmask */
-#define        LK_CMD_DIS_KEYCLK       0x99
-#define        LK_CMD_ENB_KEYCLK       0x1b    /* 1 param: volume */
-#define        LK_CMD_DIS_CTLCLK       0xb9
-#define        LK_CMD_ENB_CTLCLK       0xbb
-#define        LK_CMD_SOUND_CLK        0x9f
-#define        LK_CMD_DIS_BELL         0xa1
-#define        LK_CMD_ENB_BELL         0x23    /* 1 param: volume */
-#define        LK_CMD_BELL             0xa7
-#define        LK_CMD_TMP_NORPT        0xc1
-#define        LK_CMD_ENB_RPT          0xe3
-#define        LK_CMD_DIS_RPT          0xe1
-#define        LK_CMD_RPT_TO_DOWN      0xd9
-#define        LK_CMD_REQ_ID           0xab
-#define        LK_CMD_POWER_UP         0xfd
-#define        LK_CMD_TEST_MODE        0xcb
-#define        LK_CMD_SET_DEFAULTS     0xd3
+#define LK_PARAM               0x80    /* start/end parameter list */
+
+#define LK_CMD_RESUME          0x8b    /* resume transmission to the host */
+#define LK_CMD_INHIBIT         0x89    /* stop transmission to the host */
+#define LK_CMD_LEDS_ON         0x13    /* light LEDs */
+                                       /* 1st param: led bitmask */
+#define LK_CMD_LEDS_OFF                0x11    /* turn off LEDs */
+                                       /* 1st param: led bitmask */
+#define LK_CMD_DIS_KEYCLK      0x99    /* disable the keyclick */
+#define LK_CMD_ENB_KEYCLK      0x1b    /* enable the keyclick */
+                                       /* 1st param: volume */
+#define LK_CMD_DIS_CTLCLK      0xb9    /* disable the Ctrl keyclick */
+#define LK_CMD_ENB_CTLCLK      0xbb    /* enable the Ctrl keyclick */
+#define LK_CMD_SOUND_CLK       0x9f    /* emit a keyclick */
+#define LK_CMD_DIS_BELL                0xa1    /* disable the bell */
+#define LK_CMD_ENB_BELL                0x23    /* enable the bell */
+                                       /* 1st param: volume */
+#define LK_CMD_BELL            0xa7    /* emit a bell */
+#define LK_CMD_TMP_NORPT       0xd1    /* disable typematic */
+                                       /* for the currently pressed key */
+#define LK_CMD_ENB_RPT         0xe3    /* enable typematic */
+                                       /* for RPT_DOWN groups */
+#define LK_CMD_DIS_RPT         0xe1    /* disable typematic */
+                                       /* for RPT_DOWN groups */
+#define LK_CMD_RPT_TO_DOWN     0xd9    /* set RPT_DOWN groups to DOWN */
+#define LK_CMD_REQ_ID          0xab    /* request the keyboard ID */
+#define LK_CMD_POWER_UP                0xfd    /* init power-up sequence */
+#define LK_CMD_TEST_MODE       0xcb    /* enter the factory test mode */
+#define LK_CMD_TEST_EXIT       0x80    /* exit the factory test mode */
+#define LK_CMD_SET_DEFAULTS    0xd3    /* set power-up defaults */
+
+#define LK_CMD_MODE(m,div)     (LK_PARAM|(((div)&0xf)<<3)|(((m)&0x3)<<1))
+                                       /* select the repeat mode */
+                                       /* for the selected key group */
+#define LK_CMD_MODE_AR(m,div)  ((((div)&0xf)<<3)|(((m)&0x3)<<1))
+                                       /* select the repeat mode */
+                                       /* and the repeat register */
+                                       /* for the selected key group */
+                                       /* 1st param: register number */
+#define LK_CMD_RPT_RATE(r)     (0x78|(((r)&0x3)<<1))
+                                       /* set the delay and repeat rate */
+                                       /* for the selected repeat register */
+                                       /* 1st param: initial delay */
+                                       /* 2nd param: repeat rate */
 
 /* there are 4 leds, represent them in the low 4 bits of a byte */
-#define        LK_PARAM_LED_MASK(ledbmap)      (LK_PARAM|(ledbmap))
+#define LK_PARAM_LED_MASK(ledbmap)     (LK_PARAM|((ledbmap)&0xf))
+#define LK_LED_WAIT            0x1     /* Wait LED */
+#define LK_LED_COMP            0x2     /* Compose LED */
+#define LK_LED_LOCK            0x4     /* Lock LED */
+#define LK_LED_HOLD            0x8     /* Hold Screen LED */
 
 /* max volume is 0, lowest is 0x7 */
-#define        LK_PARAM_VOLUME(v)              (LK_PARAM|((v)&0x7))
+#define LK_PARAM_VOLUME(v)             (LK_PARAM|((v)&0x7))
+
+/* mode set command details, div is a key group number */
+#define LK_MODE_DOWN           0x0     /* make only */
+#define LK_MODE_RPT_DOWN       0x1     /* make and typematic */
+#define LK_MODE_DOWN_UP                0x3     /* make and release */
 
-/* mode set command(s) details */
-#define        LK_MODE_DOWN            0x0
-#define        LK_MODE_RPT_DOWN        0x2
-#define        LK_MODE_DOWN_UP         0x6
-#define        LK_CMD_MODE(m,div)      (LK_PARAM|(div<<3)|m)
+/* there are 4 repeat registers */
+#define LK_PARAM_AR(r)         (LK_PARAM|((v)&0x3))
+
+/*
+ * Mappings between key groups and keycodes are as follows:
+ *
+ *  1: 0xbf - 0xff -- alphanumeric,
+ *  2: 0x91 - 0xa5 -- numeric keypad,
+ *  3: 0xbc        -- Backspace,
+ *  4: 0xbd - 0xbe -- Tab, Return,
+ *  5: 0xb0 - 0xb2 -- Lock, Compose Character,
+ *  6: 0xad - 0xaf -- Ctrl, Shift,
+ *  7: 0xa6 - 0xa8 -- Left Arrow, Right Arrow,
+ *  8: 0xa9 - 0xac -- Up Arrow, Down Arrow, Right Shift,
+ *  9: 0x88 - 0x90 -- editor keypad,
+ * 10: 0x56 - 0x62 -- F1 - F5,
+ * 11: 0x63 - 0x6e -- F6 - F10,
+ * 12: 0x6f - 0x7a -- F11 - F14,
+ * 13: 0x7b - 0x7d -- Help, Do,
+ * 14: 0x7e - 0x87 -- F17 - F20.
+ *
+ * Notes:
+ * 1. Codes in the 0x00 - 0x40 range are reserved.
+ * 2. The assignment of the 0x41 - 0x55 range is undiscovered, probably 10.
+ */
+
+/* delay is 5 - 630 ms; 0x00 and 0x7f are reserved */
+#define LK_PARAM_DELAY(t)      ((t)&0x7f)
+
+/* rate is 12 - 127 Hz; 0x00 - 0x0b and 0x7d (power-up!) are reserved */
+#define LK_PARAM_RATE(r)       (LK_PARAM|((r)&0x7f))
 
 #define LK_SHIFT 1<<0
 #define LK_CTRL 1<<1
 #define LK_LOCK 1<<2
 #define LK_COMP 1<<3
 
-#define LK_KEY_SHIFT 174
-#define LK_KEY_CTRL 175
-#define LK_KEY_LOCK 176
-#define LK_KEY_COMP 177
-#define LK_KEY_RELEASE 179
-#define LK_KEY_REPEAT 180
-#define LK_KEY_ACK 186
+#define LK_KEY_SHIFT           0xae
+#define LK_KEY_CTRL            0xaf
+#define LK_KEY_LOCK            0xb0
+#define LK_KEY_COMP            0xb1
+
+#define LK_KEY_RELEASE         0xb3    /* all keys released */
+#define LK_KEY_REPEAT          0xb4    /* repeat the last key */
+
+/* status responses */
+#define LK_STAT_RESUME_ERR     0xb5    /* keystrokes lost while inhibited */
+#define LK_STAT_ERROR          0xb6    /* an invalid command received */
+#define LK_STAT_INHIBIT_ACK    0xb7    /* transmission inhibited */
+#define LK_STAT_TEST_ACK       0xb8    /* the factory test mode entered */
+#define LK_STAT_MODE_KEYDOWN   0xb9    /* a key is down on a change */
+                                       /* to the DOWN_UP mode; */
+                                       /* the keycode follows */
+#define LK_STAT_MODE_ACK       0xba    /* the mode command succeeded */
+
+#define LK_STAT_PWRUP_ID       0x01    /* the power-up response start mark */
+#define LK_STAT_PWRUP_OK       0x00    /* the power-up self test OK */
+#define LK_STAT_PWRUP_KDOWN    0x3d    /* a key was down during the test */
+#define LK_STAT_PWRUP_ERROR    0x3e    /* keyboard self test failure */
 
-extern unsigned char scancodeRemap[256];
\ No newline at end of file
+extern unsigned char scancodeRemap[256];
index 066170aabe2e37c63b983c6efb0b82ec96d52fde..a89ef4df80c3efbb72fbdefbedfc27a328bd4a8f 100644 (file)
@@ -8,46 +8,46 @@
  * for more details.
  *
  * Copyright (c) Harald Koerfgen, 1998
+ * Copyright (c) 2001, 2003  Maciej W. Rozycki
  */
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
 #include <asm/addrspace.h>
 #include <asm/errno.h>
 #include <asm/dec/machtype.h>
+#include <asm/dec/prom.h>
 #include <asm/dec/tcinfo.h>
 #include <asm/dec/tcmodule.h>
 #include <asm/dec/interrupts.h>
-
+#include <asm/paccess.h>
 #include <asm/ptrace.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
 
 #define TC_DEBUG
 
 MODULE_LICENSE("GPL");
 slot_info tc_bus[MAX_SLOT];
-static int max_tcslot;
+static int num_tcslots;
 static tcinfo *info;
 
 unsigned long system_base;
 
-extern void (*dbe_board_handler)(struct pt_regs *regs);
-extern unsigned long *(*rex_slot_address)(int);
-extern void *(*rex_gettcinfo)(void);
-
 /*
  * Interface to the world. Read comment in include/asm-mips/tc.h.
  */
 
-int search_tc_card(char *name)
+int search_tc_card(const char *name)
 {
        int slot;
        slot_info *sip;
 
-       for (slot = 0; slot <= max_tcslot; slot++) {
+       for (slot = 0; slot < num_tcslots; slot++) {
                sip = &tc_bus[slot];
-               if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) {
+               if ((sip->flags & FREE) &&
+                   (strncmp(sip->name, name, strlen(name)) == 0)) {
                        return slot;
                }
        }
@@ -68,7 +68,8 @@ void claim_tc_card(int slot)
 void release_tc_card(int slot)
 {
        if (tc_bus[slot].flags & FREE) {
-               printk("release_tc_card: attempting to release a card already free\n");
+               printk("release_tc_card: "
+                      "attempting to release a card already free\n");
                return;
        }
        tc_bus[slot].flags &= ~IN_USE;
@@ -93,73 +94,84 @@ unsigned long get_tc_speed(void)
 /*
  * Probing for TURBOchannel modules
  */
-static void __init my_dbe_handler(struct pt_regs *regs)
+static void __init tc_probe(unsigned long startaddr, unsigned long size,
+                           int slots)
 {
-       regs->cp0_epc += 4;
-}
-
-static void __init tc_probe(unsigned long startaddr, unsigned long size, int max_slot)
-{
-       int i, slot;
+       int i, slot, err;
        long offset;
+       unsigned char pattern[4];
        unsigned char *module;
-       void (*old_be_handler)(struct pt_regs *regs);
-
-       /* Install our exception handler temporarily */
 
-       old_be_handler = dbe_board_handler;
-       dbe_board_handler = my_dbe_handler;
-       for (slot = 0; slot <= max_slot; slot++) {
+       for (slot = 0; slot < slots; slot++) {
                module = (char *)(startaddr + slot * size);
-               offset = -1;
-               if (module[OLDCARD + TC_PATTERN0] == 0x55 && module[OLDCARD + TC_PATTERN1] == 0x00
-                 && module[OLDCARD + TC_PATTERN2] == 0xaa && module[OLDCARD + TC_PATTERN3] == 0xff)
-                       offset = OLDCARD;
-               if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00
-                 && module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
-                       offset = 0;
-
-               if (offset != -1) {
-                       tc_bus[slot].base_addr = (unsigned long)module;
-                       for(i = 0; i < 8; i++) {
-                               tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i];
-                               tc_bus[slot].vendor[i] = module[TC_VENDOR + offset + 4 * i];
-                               tc_bus[slot].name[i] = module[TC_MODULE + offset + 4 * i];
-                       }
-                       tc_bus[slot].firmware[8] = 0;
-                       tc_bus[slot].vendor[8] = 0;
-                       tc_bus[slot].name[8] = 0;
-                       /*
-                        * Looks unneccesary, but we may change
-                        * TC? in the future
-                        */
-                       switch (slot) {
-                       case 0:
-                               tc_bus[slot].interrupt = TC0;
-                               break;
-                       case 1:
-                               tc_bus[slot].interrupt = TC1;
-                               break;
-                       case 2:
-                               tc_bus[slot].interrupt = TC2;
-                               break;
-                       /*
-                        * Yuck! DS5000/200 onboard devices
-                        */
-                       case 5:
-                               tc_bus[slot].interrupt = SCSI_INT;
-                               break;
-                       case 6:
-                               tc_bus[slot].interrupt = ETHER;
-                               break;
-                       default:
-                               tc_bus[slot].interrupt = -1;
-                               break;
-                       }       
+
+               offset = OLDCARD;
+
+               err = 0;
+               err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
+               err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
+               err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
+               err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
+               if (err)
+                       continue;
+
+               if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
+                   pattern[2] != 0xaa || pattern[3] != 0xff) {
+                       offset = NEWCARD;
+
+                       err = 0;
+                       err |= get_dbe(pattern[0], module + TC_PATTERN0);
+                       err |= get_dbe(pattern[1], module + TC_PATTERN1);
+                       err |= get_dbe(pattern[2], module + TC_PATTERN2);
+                       err |= get_dbe(pattern[3], module + TC_PATTERN3);
+                       if (err)
+                               continue;
                }
-       }
 
-       dbe_board_handler = old_be_handler;
+               if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
+                   pattern[2] != 0xaa || pattern[3] != 0xff)
+                       continue;
+
+               tc_bus[slot].base_addr = (unsigned long)module;
+               for(i = 0; i < 8; i++) {
+                       tc_bus[slot].firmware[i] =
+                               module[TC_FIRM_VER + offset + 4 * i];
+                       tc_bus[slot].vendor[i] =
+                               module[TC_VENDOR + offset + 4 * i];
+                       tc_bus[slot].name[i] =
+                               module[TC_MODULE + offset + 4 * i];
+               }
+               tc_bus[slot].firmware[8] = 0;
+               tc_bus[slot].vendor[8] = 0;
+               tc_bus[slot].name[8] = 0;
+               /*
+                * Looks unneccesary, but we may change
+                * TC? in the future
+                */
+               switch (slot) {
+               case 0:
+                       tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
+                       break;
+               case 1:
+                       tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
+                       break;
+               case 2:
+                       tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
+                       break;
+               /*
+                * Yuck! DS5000/200 onboard devices
+                */
+               case 5:
+                       tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
+                       break;
+               case 6:
+                       tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
+                       break;
+               default:
+                       tc_bus[slot].interrupt = -1;
+                       break;
+               }
+       }
 }
 
 /*
@@ -189,15 +201,16 @@ void __init tc_init(void)
 
        switch (mips_machtype) {
        case MACH_DS5000_200:
-               max_tcslot = 6;
+               num_tcslots = 7;
                break;
        case MACH_DS5000_1XX:
        case MACH_DS5000_2X0:
-               max_tcslot = 2;
+       case MACH_DS5900:
+               num_tcslots = 3;
                break;
        case MACH_DS5000_XX:
        default:
-               max_tcslot = 1;
+               num_tcslots = 2;
                break;
        }
 
@@ -210,22 +223,22 @@ void __init tc_init(void)
 
                slot_size = info->slot_size << 20;
 
-               tc_probe(slot0addr, slot_size, max_tcslot);
+               tc_probe(slot0addr, slot_size, num_tcslots);
 
                /*
                 * All TURBOchannel DECstations have the onboard devices
-                * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
+                * where the (num_tcslots + 0 or 1 on DS5k/xx) Option Module
                 * would be.
                 */
                if(mips_machtype == MACH_DS5000_XX)
-                       i = 2;
-               else
                        i = 1;
-               
-               system_base = slot0addr + slot_size * (max_tcslot + i);
+               else
+                       i = 0;
+
+               system_base = slot0addr + slot_size * (num_tcslots + i);
 
 #ifdef TC_DEBUG
-               for (i = 0; i <= max_tcslot; i++)
+               for (i = 0; i < num_tcslots; i++)
                        if (tc_bus[i].base_addr) {
                                printk("    slot %d: ", i);
                                printk("%s %s %s\n", tc_bus[i].vendor,
@@ -244,4 +257,4 @@ EXPORT_SYMBOL(release_tc_card);
 EXPORT_SYMBOL(get_tc_base_addr);
 EXPORT_SYMBOL(get_tc_irq_nr);
 EXPORT_SYMBOL(get_tc_speed);
-
+EXPORT_SYMBOL(system_base);
index a8c4d1163e682142bf4fab88f066db0b826a096e..0f0d879bd1bf09e1adfd0f5b61c2b5d9cd7140a2 100644 (file)
@@ -6,7 +6,7 @@
  *
  * DECstation changes
  * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000,2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004  Maciej W. Rozycki
  *
  * For the rest of the code the original Copyright applies:
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
@@ -55,8 +55,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/bitops.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 #include <linux/console.h>
 #endif
 
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/wbflush.h>
 #include <asm/bootinfo.h>
+#include <asm/dec/serial.h>
+
 #ifdef CONFIG_MACH_DECSTATION
 #include <asm/dec/interrupts.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/ioasic_addrs.h>
 #endif
-#ifdef CONFIG_BAGET_MIPS
-#include <asm/baget/baget.h>
-unsigned long system_base;
-#endif
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -94,7 +90,7 @@ unsigned long system_base;
 #define NUM_SERIAL     2               /* Max number of ZS chips supported */
 #define NUM_CHANNELS   (NUM_SERIAL * 2)        /* 2 channels per chip */
 #define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
-                                        /* Number of channel A in the chip */ 
+                                        /* Number of channel A in the chip */
 #define ZS_CHAN_IO_SIZE 8
 #define ZS_CLOCK        7372800        /* Z8530 RTxC input clock rate */
 
@@ -105,7 +101,8 @@ struct zs_parms {
        unsigned long scc1;
        int channel_a_offset;
        int channel_b_offset;
-       int irq;
+       int irq0;
+       int irq1;
        int clock;
 };
 
@@ -113,24 +110,15 @@ static struct zs_parms *zs_parms;
 
 #ifdef CONFIG_MACH_DECSTATION
 static struct zs_parms ds_parms = {
-       scc0 : SCC0,
-       scc1 : SCC1,
+       scc0 : IOASIC_SCC0,
+       scc1 : IOASIC_SCC1,
        channel_a_offset : 1,
        channel_b_offset : 9,
-       irq : SERIAL,
+       irq0 : -1,
+       irq1 : -1,
        clock : ZS_CLOCK
 };
 #endif
-#ifdef CONFIG_BAGET_MIPS
-static struct zs_parms baget_parms = {
-       scc0 : UNI_SCC0,
-       scc1 : UNI_SCC1,
-       channel_a_offset : 9,
-       channel_b_offset : 1,
-       irq : BAGET_SCC_IRQ,
-       clock : 14745000
-};
-#endif
 
 #ifdef CONFIG_MACH_DECSTATION
 #define DS_BUS_PRESENT (IOASIC)
@@ -138,13 +126,7 @@ static struct zs_parms baget_parms = {
 #define DS_BUS_PRESENT 0
 #endif
 
-#ifdef CONFIG_BAGET_MIPS
-#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
-#else
-#define BAGET_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+#define BUS_PRESENT (DS_BUS_PRESENT)
 
 struct dec_zschannel zs_channels[NUM_CHANNELS];
 struct dec_serial zs_soft[NUM_CHANNELS];
@@ -153,28 +135,28 @@ struct dec_serial *zs_chain;      /* list of all channels */
 
 struct tty_struct zs_ttys[NUM_CHANNELS];
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 static struct console sercons;
 #endif
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \
-    && !defined(MODULE)
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+   !defined(MODULE)
 static unsigned long break_pressed; /* break, really ... */
 #endif
 
 static unsigned char zs_init_regs[16] __initdata = {
-       0,                           /* write 0 */
-       0,                           /* write 1 */
-       0xf0,                        /* write 2 */
-       (Rx8),                       /* write 3 */
-       (X16CLK | SB1),              /* write 4 */
-       (Tx8),                       /* write 5 */
-       0, 0, 0,                     /* write 6, 7, 8 */
-       (VIS),                       /* write 9 */
-       (NRZ),                       /* write 10 */
-       (TCBR | RCBR),               /* write 11 */
-       0, 0,                        /* BRG time constant, write 12 + 13 */
-       (BRSRC | BRENABL),           /* write 14 */
-       0                            /* write 15 */
+       0,                              /* write 0 */
+       0,                              /* write 1 */
+       0,                              /* write 2 */
+       0,                              /* write 3 */
+       (X16CLK),                       /* write 4 */
+       0,                              /* write 5 */
+       0, 0, 0,                        /* write 6, 7, 8 */
+       (MIE | DLC | NV),               /* write 9 */
+       (NRZ),                          /* write 10 */
+       (TCBR | RCBR),                  /* write 11 */
+       0, 0,                           /* BRG time constant, write 12 + 13 */
+       (BRSRC | BRENABL),              /* write 14 */
+       0                               /* write 15 */
 };
 
 DECLARE_TASK_QUEUE(tq_zs_serial);
@@ -190,7 +172,6 @@ static struct tty_driver *serial_driver;
 /*
  * Debugging.
  */
-#undef SERIAL_DEBUG_INTR
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
 #undef SERIAL_DEBUG_THROTTLE
@@ -251,7 +232,7 @@ static int baud_table[] = {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
        9600, 19200, 38400, 57600, 115200, 0 };
 
-/* 
+/*
  * Reading and writing Z8530 registers.
  */
 static inline unsigned char read_zsreg(struct dec_zschannel *channel,
@@ -261,7 +242,7 @@ static inline unsigned char read_zsreg(struct dec_zschannel *channel,
 
        if (reg != 0) {
                *channel->control = reg & 0xf;
-               wbflush(); RECOVERY_DELAY;
+               fast_iob(); RECOVERY_DELAY;
        }
        retval = *channel->control;
        RECOVERY_DELAY;
@@ -273,10 +254,10 @@ static inline void write_zsreg(struct dec_zschannel *channel,
 {
        if (reg != 0) {
                *channel->control = reg & 0xf;
-               wbflush(); RECOVERY_DELAY;
+               fast_iob(); RECOVERY_DELAY;
        }
        *channel->control = value;
-       wbflush(); RECOVERY_DELAY;
+       fast_iob(); RECOVERY_DELAY;
        return;
 }
 
@@ -293,7 +274,7 @@ static inline void write_zsdata(struct dec_zschannel *channel,
                                unsigned char value)
 {
        *channel->data = value;
-       wbflush(); RECOVERY_DELAY;
+       fast_iob(); RECOVERY_DELAY;
        return;
 }
 
@@ -303,9 +284,9 @@ static inline void load_zsregs(struct dec_zschannel *channel,
 /*     ZS_CLEARERR(channel);
        ZS_CLEARFIFO(channel); */
        /* Load 'em up */
-       write_zsreg(channel, R4, regs[R4]);
        write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
        write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+       write_zsreg(channel, R4, regs[R4]);
        write_zsreg(channel, R9, regs[R9]);
        write_zsreg(channel, R1, regs[R1]);
        write_zsreg(channel, R2, regs[R2]);
@@ -372,8 +353,6 @@ static inline void rs_recv_clear(struct dec_zschannel *zsc)
  * -----------------------------------------------------------------------
  */
 
-static int tty_break;  /* Set whenever BREAK condition is detected.  */
-
 /*
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
@@ -397,23 +376,18 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
                stat = read_zsreg(info->zs_channel, R1);
                ch = read_zsdata(info->zs_channel);
 
-               if (!tty && !info->hook && !info->hook->rx_char)
+               if (!tty && (!info->hook || !info->hook->rx_char))
                        continue;
 
-               if (tty_break) {
-                       tty_break = 0;
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
-                       if (info->line == sercons.index) {
-                               if (!break_pressed) {
-                                       break_pressed = jiffies;
-                                       goto ignore_char;
-                               }
-                               break_pressed = 0;
-                       }
-#endif
+               flag = TTY_NORMAL;
+               if (info->tty_break) {
+                       info->tty_break = 0;
                        flag = TTY_BREAK;
                        if (info->flags & ZILOG_SAK)
                                do_SAK(tty);
+                       /* Ignore the null char got when BREAK is removed.  */
+                       if (ch == 0)
+                               continue;
                } else {
                        if (stat & Rx_OVR) {
                                flag = TTY_OVERRUN;
@@ -421,20 +395,22 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
                                flag = TTY_FRAME;
                        } else if (stat & PAR_ERR) {
                                flag = TTY_PARITY;
-                       } else
-                               flag = 0;
-                       if (flag)
+                       }
+                       if (flag != TTY_NORMAL)
                                /* reset the error indication */
                                write_zsreg(info->zs_channel, R0, ERR_RES);
                }
 
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+   !defined(MODULE)
                if (break_pressed && info->line == sercons.index) {
-                       if (ch != 0 &&
-                           time_before(jiffies, break_pressed + HZ*5)) {
+                       /* Ignore the null char got when BREAK is removed.  */
+                       if (ch == 0)
+                               continue;
+                       if (time_before(jiffies, break_pressed + HZ * 5)) {
                                handle_sysrq(ch, regs, NULL);
                                break_pressed = 0;
-                               goto ignore_char;
+                               continue;
                        }
                        break_pressed = 0;
                }
@@ -444,22 +420,8 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
                        (*info->hook->rx_char)(ch, flag);
                        return;
                }
-               
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-                       static int flip_buf_ovf;
-                       ++flip_buf_ovf;
-                       continue;
-               }
-               tty->flip.count++;
-               {
-                       static int flip_max_cnt;
-                       if (flip_max_cnt < tty->flip.count)
-                               flip_max_cnt = tty->flip.count;
-               }
 
-               *tty->flip.flag_buf_ptr++ = flag;
-               *tty->flip.char_buf_ptr++ = ch;
-       ignore_char:
+               tty_insert_flip_char(tty, ch, flag);
        }
        if (tty)
                tty_flip_buffer_push(tty);
@@ -501,18 +463,22 @@ static _INLINE_ void status_handle(struct dec_serial *info)
        /* Get status from Read Register 0 */
        stat = read_zsreg(info->zs_channel, R0);
 
-       if (stat & BRK_ABRT) {
-#ifdef SERIAL_DEBUG_INTR
-               printk("handling break....");
+       if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+   !defined(MODULE)
+               if (info->line == sercons.index) {
+                       if (!break_pressed)
+                               break_pressed = jiffies;
+               } else
 #endif
-               tty_break = 1;
+                       info->tty_break = 1;
        }
 
        if (info->zs_channel != info->zs_chan_a) {
 
-               /* FIXEM: Check for DCD transitions */
-               if (((stat ^ info->read_reg_zero) & DCD) != 0
-                   && info->tty && !C_CLOCAL(info->tty)) {
+               /* Check for DCD transitions */
+               if (info->tty && !C_CLOCAL(info->tty) &&
+                   ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
                        if (stat & DCD) {
                                wake_up_interruptible(&info->open_wait);
                        } else {
@@ -563,7 +529,7 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                shift = 0;      /* Channel B */
 
        for (;;) {
-               zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; 
+               zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
                if ((zs_intreg & CHAN_IRQMASK) == 0)
                        break;
 
@@ -577,7 +543,7 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                        status_handle(info);
                }
        }
-       
+
        /* Why do we need this ? */
        write_zsreg(info->zs_channel, 0, RES_H_IUS);
 }
@@ -586,14 +552,14 @@ void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 void zs_dump (void) {
        int i, j;
        for (i = 0; i < zs_channels_found; i++) {
-               struct dec_zschannel *ch = &zs_channels[i]; 
+               struct dec_zschannel *ch = &zs_channels[i];
                if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
                        for (j = 0; j < 15; j++) {
-                               printk("W%d = 0x%x\t", 
+                               printk("W%d = 0x%x\t",
                                       j, (int)ch->curregs[j]);
                        }
                        for (j = 0; j < 15; j++) {
-                               printk("R%d = 0x%x\t", 
+                               printk("R%d = 0x%x\t",
                                       j, (int)read_zsreg(ch,j));
                        }
                        printk("\n\n");
@@ -622,7 +588,7 @@ static void rs_stop(struct tty_struct *tty)
 
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
                return;
-       
+
 #if 1
        save_flags(flags); cli();
        if (info->zs_channel->curregs[5] & TxENAB) {
@@ -637,10 +603,10 @@ static void rs_start(struct tty_struct *tty)
 {
        struct dec_serial *info = (struct dec_serial *)tty->driver_data;
        unsigned long flags;
-       
+
        if (serial_paranoia_check(info, tty->name, "rs_start"))
                return;
-       
+
        save_flags(flags); cli();
 #if 1
        if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
@@ -673,7 +639,7 @@ static void do_softint(void *private_)
 {
        struct dec_serial       *info = (struct dec_serial *) private_;
        struct tty_struct       *tty;
-       
+
        tty = info->tty;
        if (!tty)
                return;
@@ -711,8 +677,13 @@ int zs_startup(struct dec_serial * info)
        /*
         * Clear the interrupt registers.
         */
-       write_zsreg(info->zs_channel, 0, ERR_RES);
-       write_zsreg(info->zs_channel, 0, RES_H_IUS);
+       write_zsreg(info->zs_channel, R0, ERR_RES);
+       write_zsreg(info->zs_channel, R0, RES_H_IUS);
+
+       /*
+        * Set the speed of the serial port
+        */
+       change_speed(info);
 
        /*
         * Turn on RTS and DTR.
@@ -722,35 +693,30 @@ int zs_startup(struct dec_serial * info)
        /*
         * Finally, enable sequencing and interrupts
         */
-       info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
-       info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
-       info->zs_channel->curregs[5] |= (TxENAB | Tx8);
-       info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
-       info->zs_channel->curregs[9] |= (VIS | MIE);
-       write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
-       write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-       write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-       write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]);
-       write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+       info->zs_channel->curregs[R1] &= ~RxINT_MASK;
+       info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
+                                         EXT_INT_ENAB);
+       info->zs_channel->curregs[R3] |= RxENABLE;
+       info->zs_channel->curregs[R5] |= TxENAB;
+       info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
+       write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
+       write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
+       write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
+       write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
 
        /*
         * And clear the interrupt registers again for luck.
         */
-       write_zsreg(info->zs_channel, 0, ERR_RES);
-       write_zsreg(info->zs_channel, 0, RES_H_IUS);
+       write_zsreg(info->zs_channel, R0, ERR_RES);
+       write_zsreg(info->zs_channel, R0, RES_H_IUS);
+
+       /* Save the current value of RR0 */
+       info->read_reg_zero = read_zsreg(info->zs_channel, R0);
 
        if (info->tty)
                clear_bit(TTY_IO_ERROR, &info->tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-       /*
-        * Set the speed of the serial port
-        */
-       change_speed(info);
-
-       /* Save the current value of RR0 */
-       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
        info->flags |= ZILOG_INITIALIZED;
        restore_flags(flags);
        return 0;
@@ -771,9 +737,9 @@ static void shutdown(struct dec_serial * info)
        printk("Shutting down serial port %d (irq %d)....", info->line,
               info->irq);
 #endif
-       
+
        save_flags(flags); cli(); /* Disable interrupts */
-       
+
        if (info->xmit_buf) {
                free_page((unsigned long) info->xmit_buf);
                info->xmit_buf = 0;
@@ -833,13 +799,11 @@ static void change_speed(struct dec_serial *info)
 
        save_flags(flags); cli();
        info->zs_baud = baud_table[i];
-       info->clk_divisor = 16;
        if (info->zs_baud) {
-               info->zs_channel->curregs[4] = X16CLK;
                brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
                info->zs_channel->curregs[12] = (brg & 255);
                info->zs_channel->curregs[13] = ((brg >> 8) & 255);
-               zs_rtsdtr(info, DTR, 1); 
+               zs_rtsdtr(info, DTR, 1);
        } else {
                zs_rtsdtr(info, RTS | DTR, 0);
                return;
@@ -942,13 +906,21 @@ static int rs_write(struct tty_struct * tty,
 
        save_flags(flags);
        while (1) {
-               cli();          
-               c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-                                         SERIAL_XMIT_SIZE - info->xmit_head));
+               cli();
+               c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                  SERIAL_XMIT_SIZE - info->xmit_head));
                if (c <= 0)
                        break;
 
-               memcpy(info->xmit_buf + info->xmit_head, buf, c);
+               if (from_user) {
+                       down(&tmp_buf_sem);
+                       copy_from_user(tmp_buf, buf, c);
+                       c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+                                      SERIAL_XMIT_SIZE - info->xmit_head));
+                       memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+                       up(&tmp_buf_sem);
+               } else
+                       memcpy(info->xmit_buf + info->xmit_head, buf, c);
                info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt += c;
                restore_flags(flags);
@@ -968,7 +940,7 @@ static int rs_write_room(struct tty_struct *tty)
 {
        struct dec_serial *info = (struct dec_serial *)tty->driver_data;
        int     ret;
-                               
+
        if (serial_paranoia_check(info, tty->name, "rs_write_room"))
                return 0;
        ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -980,7 +952,7 @@ static int rs_write_room(struct tty_struct *tty)
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
        struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-                       
+
        if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
                return 0;
        return info->xmit_cnt;
@@ -989,7 +961,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-                               
+
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
                return;
        cli();
@@ -1001,7 +973,7 @@ static void rs_flush_buffer(struct tty_struct *tty)
 /*
  * ------------------------------------------------------------
  * rs_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
@@ -1013,14 +985,14 @@ static void rs_throttle(struct tty_struct * tty)
 
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
-       
+
        printk("throttle %s: %d....\n", _tty_name(tty, buf),
               tty->ldisc.chars_in_buffer(tty));
 #endif
 
        if (serial_paranoia_check(info, tty->name, "rs_throttle"))
                return;
-       
+
        if (I_IXOFF(tty)) {
                save_flags(flags); cli();
                info->x_char = STOP_CHAR(tty);
@@ -1041,14 +1013,14 @@ static void rs_unthrottle(struct tty_struct * tty)
 
 #ifdef SERIAL_DEBUG_THROTTLE
        char    buf[64];
-       
+
        printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
               tty->ldisc.chars_in_buffer(tty));
 #endif
 
        if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
                return;
-       
+
        if (I_IXOFF(tty)) {
                save_flags(flags); cli();
                if (info->x_char)
@@ -1145,7 +1117,7 @@ check_and_exit:
  *         release the bus after transmitting. This must be done when
  *         the transmit shift register is empty, not be done when the
  *         transmit holding register is empty.  This functionality
- *         allows an RS485 driver to be written in user space. 
+ *         allows an RS485 driver to be written in user space.
  */
 static int get_lsr_info(struct dec_serial * info, unsigned int *value)
 {
@@ -1192,7 +1164,7 @@ static int rs_tiocmget(struct tty_struct *tty, struct file *file)
 }
 
 static int rs_tiocmset(struct tty_struct *tty, struct file *file,
-                      unsigned int set, unsigned int clear)
+                       unsigned int set, unsigned int clear)
 {
        struct dec_serial * info = (struct dec_serial *)tty->driver_data;
        int error;
@@ -1210,6 +1182,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file,
        if (info->zs_channel == info->zs_chan_a)
                return 0;
 
+       get_user(arg, value);
        cli();
        if (set & TIOCM_RTS)
                info->zs_chan_a->curregs[5] |= RTS;
@@ -1264,38 +1237,38 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                if (tty->flags & (1 << TTY_IO_ERROR))
                    return -EIO;
        }
-       
+
        switch (cmd) {
-               case TIOCGSERIAL:
-                       error = verify_area(VERIFY_WRITE, (void *) arg,
-                                               sizeof(struct serial_struct));
-                       if (error)
-                               return error;
-                       return get_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSSERIAL:
-                       return set_serial_info(info,
-                                              (struct serial_struct *) arg);
-               case TIOCSERGETLSR: /* Get line status register */
-                       error = verify_area(VERIFY_WRITE, (void *) arg,
-                               sizeof(unsigned int));
-                       if (error)
-                               return error;
-                       else
-                           return get_lsr_info(info, (unsigned int *) arg);
-
-               case TIOCSERGSTRUCT:
-                       error = verify_area(VERIFY_WRITE, (void *) arg,
-                                               sizeof(struct dec_serial));
-                       if (error)
-                               return error;
-                       copy_from_user((struct dec_serial *) arg,
-                                      info, sizeof(struct dec_serial));
-                       return 0;
-                       
-               default:
-                       return -ENOIOCTLCMD;
-               }
+       case TIOCGSERIAL:
+               error = verify_area(VERIFY_WRITE, (void *)arg,
+                                   sizeof(struct serial_struct));
+               if (error)
+                       return error;
+               return get_serial_info(info, (struct serial_struct *)arg);
+
+       case TIOCSSERIAL:
+               return set_serial_info(info, (struct serial_struct *)arg);
+
+       case TIOCSERGETLSR:                     /* Get line status register */
+               error = verify_area(VERIFY_WRITE, (void *)arg,
+                                   sizeof(unsigned int));
+               if (error)
+                       return error;
+               else
+                       return get_lsr_info(info, (unsigned int *)arg);
+
+       case TIOCSERGSTRUCT:
+               error = verify_area(VERIFY_WRITE, (void *)arg,
+                                   sizeof(struct dec_serial));
+               if (error)
+                       return error;
+               copy_from_user((struct dec_serial *)arg, info,
+                              sizeof(struct dec_serial));
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
        return 0;
 }
 
@@ -1317,7 +1290,7 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
 /*
  * ------------------------------------------------------------
  * rs_close()
- * 
+ *
  * This routine is called when the serial port gets closed.
  * Wait for the last remaining data to be sent.
  * ------------------------------------------------------------
@@ -1329,14 +1302,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 
        if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
                return;
-       
+
        save_flags(flags); cli();
-       
+
        if (tty_hung_up_p(filp)) {
                restore_flags(flags);
                return;
        }
-       
+
 #ifdef SERIAL_DEBUG_OPEN
        printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
 #endif
@@ -1363,7 +1336,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        }
        info->flags |= ZILOG_CLOSING;
        /*
-        * Now we wait for the transmit buffer to clear; and we notify 
+        * Now we wait for the transmit buffer to clear; and we notify
         * the line discipline to only process XON/XOFF characters.
         */
        tty->closing = 1;
@@ -1411,7 +1384,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 {
        struct dec_serial *info = (struct dec_serial *) tty->driver_data;
-       unsigned long orig_jiffies, char_time;
+       unsigned long orig_jiffies;
+       int char_time;
 
        if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
                return;
@@ -1427,7 +1401,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
        if (char_time == 0)
                char_time = 1;
        if (timeout)
-               char_time = min_t(unsigned long, char_time, timeout);
+               char_time = min(char_time, timeout);
        while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
                current->state = TASK_INTERRUPTIBLE;
                schedule_timeout(char_time);
@@ -1484,11 +1458,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
 #endif
        }
 
-       /*
-        * If this is a callout device, then just make sure the normal
-        * device isn't being used.
-        */
-       
        /*
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
@@ -1516,7 +1485,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
               info->line, info->count);
 #endif
        cli();
-       if (!tty_hung_up_p(filp)) 
+       if (!tty_hung_up_p(filp))
                info->count--;
        sti();
        info->blocked_open++;
@@ -1532,7 +1501,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                        if (info->flags & ZILOG_HUP_NOTIFY)
                                retval = -EAGAIN;
                        else
-                               retval = -ERESTARTSYS;  
+                               retval = -ERESTARTSYS;
 #else
                        retval = -EAGAIN;
 #endif
@@ -1564,7 +1533,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                return retval;
        info->flags |= ZILOG_NORMAL_ACTIVE;
        return 0;
-}      
+}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -1626,7 +1595,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
                return retval;
        }
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
        if (sercons.cflag && sercons.index == line) {
                tty->termios->c_cflag = sercons.cflag;
                sercons.cflag = 0;
@@ -1645,7 +1614,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
 
 static void __init show_serial_version(void)
 {
-       printk("DECstation Z8530 serial driver version 0.05\n");
+       printk("DECstation Z8530 serial driver version 0.09\n");
 }
 
 /*  Initialize Z8530s zs_channels
@@ -1655,6 +1624,7 @@ static void __init probe_sccs(void)
 {
        struct dec_serial **pp;
        int i, n, n_chips = 0, n_channels, chip, channel;
+       unsigned long flags;
 
        /*
         * did we get here by accident?
@@ -1663,7 +1633,7 @@ static void __init probe_sccs(void)
                printk("Not on JUNKIO machine, skipping probe_sccs\n");
                return;
        }
-       
+
        /*
         * When serial console is activated, tc_init has not been called yet
         * and system_base is undefined. Unfortunately we have to hardcode
@@ -1672,27 +1642,25 @@ static void __init probe_sccs(void)
        switch(mips_machtype) {
 #ifdef CONFIG_MACH_DECSTATION
        case MACH_DS5000_2X0:
-               system_base = 0xbf800000;
+       case MACH_DS5900:
+               system_base = KSEG1ADDR(0x1f800000);
                n_chips = 2;
                zs_parms = &ds_parms;
+               zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+               zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
                break;
        case MACH_DS5000_1XX:
-               system_base = 0xbc000000;
+               system_base = KSEG1ADDR(0x1c000000);
                n_chips = 2;
                zs_parms = &ds_parms;
+               zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+               zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
                break;
        case MACH_DS5000_XX:
-               system_base = 0xbc000000;
+               system_base = KSEG1ADDR(0x1c000000);
                n_chips = 1;
                zs_parms = &ds_parms;
-               break;
-#endif
-#ifdef CONFIG_BAGET_MIPS
-       case MACH_BAGET202:
-               system_base = UNI_IO_BASE;
-               n_chips = 2;
-               zs_parms = &baget_parms;
-               zs_init_regs[2] = 0x8;
+               zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
                break;
 #endif
        default:
@@ -1710,15 +1678,15 @@ static void __init probe_sccs(void)
                        /*
                         * The sccs reside on the high byte of the 16 bit IOBUS
                         */
-                       zs_channels[n_channels].control = 
-                               (volatile unsigned char *)system_base + 
-                         (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + 
-                         (0 == channel ? zs_parms->channel_a_offset : 
+                       zs_channels[n_channels].control =
+                               (volatile unsigned char *)system_base +
+                         (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
+                         (0 == channel ? zs_parms->channel_a_offset :
                                          zs_parms->channel_b_offset);
-                       zs_channels[n_channels].data = 
+                       zs_channels[n_channels].data =
                                zs_channels[n_channels].control + 4;
 
-#ifndef CONFIG_SERIAL_CONSOLE
+#ifndef CONFIG_SERIAL_DEC_CONSOLE
                        /*
                         * We're called early and memory managment isn't up, yet.
                         * Thus check_region would fail.
@@ -1729,20 +1697,24 @@ static void __init probe_sccs(void)
                                panic("SCC I/O region is not free");
 #endif
                        zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
-                       zs_soft[n_channels].irq = zs_parms->irq;
+                       /* HACK alert! */
+                       if (!(chip & 1))
+                               zs_soft[n_channels].irq = zs_parms->irq0;
+                       else
+                               zs_soft[n_channels].irq = zs_parms->irq1;
 
-                       /* 
+                       /*
                         *  Identification of channel A. Location of channel A
                          *  inside chip depends on mapping of internal address
                         *  the chip decodes channels by.
-                        *  CHANNEL_A_NR returns either 0 (in case of 
+                        *  CHANNEL_A_NR returns either 0 (in case of
                         *  DECstations) or 1 (in case of Baget).
                         */
                        if (CHANNEL_A_NR == channel)
-                               zs_soft[n_channels].zs_chan_a = 
+                               zs_soft[n_channels].zs_chan_a =
                                    &zs_channels[n_channels+1-2*CHANNEL_A_NR];
                        else
-                               zs_soft[n_channels].zs_chan_a = 
+                               zs_soft[n_channels].zs_chan_a =
                                    &zs_channels[n_channels];
 
                        *pp = &zs_soft[n_channels];
@@ -1760,16 +1732,17 @@ static void __init probe_sccs(void)
                }
        }
 
-/*     save_and_cli(flags);
+       save_and_cli(flags);
        for (n = 0; n < zs_channels_found; n++) {
-               if (((int)zs_channels[n].control & 0xf) == 1) {
+               if (n % 2 == 0) {
                        write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
-                       mdelay(10);
+                       udelay(10);
                        write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
                }
-               load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
-       } 
-       restore_flags(flags); */
+               load_zsregs(zs_soft[n].zs_channel,
+                           zs_soft[n].zs_channel->curregs);
+       }
+       restore_flags(flags);
 }
 
 static struct tty_operations serial_ops = {
@@ -1797,7 +1770,6 @@ static struct tty_operations serial_ops = {
 int __init zs_init(void)
 {
        int channel, i;
-       unsigned long flags;
        struct dec_serial *info;
 
        if(!BUS_PRESENT)
@@ -1809,7 +1781,6 @@ int __init zs_init(void)
        /* Find out how many Z8530 SCCs we have */
        if (zs_chain == 0)
                probe_sccs();
-
        serial_driver = alloc_tty_driver(zs_channels_found);
        if (!serial_driver)
                return -ENOMEM;
@@ -1833,39 +1804,25 @@ int __init zs_init(void)
        tty_set_operations(serial_driver, &serial_ops);
 
        if (tty_register_driver(serial_driver))
-               panic("Couldn't register serial driver\n");
-
-       save_flags(flags); cli();
-
-       for (channel = 0; channel < zs_channels_found; ++channel) {
-               if (zs_soft[channel].hook &&
-                   zs_soft[channel].hook->init_channel)
-                       (*zs_soft[channel].hook->init_channel)
-                               (&zs_soft[channel]);
+               panic("Couldn't register serial driver");
 
-               zs_soft[channel].clk_divisor = 16;
-               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+       for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
 
-               if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
-                               "SCC", &zs_soft[channel]))
-                       printk(KERN_ERR "decserial: can't get irq %d\n",
-                              zs_parms->irq);
-       }
+               /* Needed before interrupts are enabled. */
+               info->tty = 0;
+               info->x_char = 0;
 
-       for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-       {
                if (info->hook && info->hook->init_info) {
                        (*info->hook->init_info)(info);
                        continue;
                }
+
                info->magic = SERIAL_MAGIC;
                info->port = (int) info->zs_channel->control;
                info->line = i;
-               info->tty = 0;
                info->custom_divisor = 16;
                info->close_delay = 50;
                info->closing_wait = 3000;
-               info->x_char = 0;
                info->event = 0;
                info->count = 0;
                info->blocked_open = 0;
@@ -1873,94 +1830,83 @@ int __init zs_init(void)
                info->tqueue.data = info;
                init_waitqueue_head(&info->open_wait);
                init_waitqueue_head(&info->close_wait);
-               printk("ttyS%d at 0x%08x (irq = %d)", info->line,
-                      info->port, info->irq);
-               printk(" is a Z85C30 SCC\n");
+               printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
+                      info->line, info->port, info->irq);
                tty_register_device(serial_driver, info->line, NULL);
+
        }
 
-       restore_flags(flags);
+       for (channel = 0; channel < zs_channels_found; ++channel) {
+               zs_soft[channel].clk_divisor = 16;
+               zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
 
-       return 0;
-}
+               if (request_irq(zs_soft[channel].irq, rs_interrupt, SA_SHIRQ,
+                               "scc", &zs_soft[channel]))
+                       printk(KERN_ERR "decserial: can't get irq %d\n",
+                              zs_soft[channel].irq);
 
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
-       return -1;
-}
+               if (zs_soft[channel].hook) {
+                       zs_startup(&zs_soft[channel]);
+                       if (zs_soft[channel].hook->init_channel)
+                               (*zs_soft[channel].hook->init_channel)
+                                       (&zs_soft[channel]);
+               }
+       }
 
-void unregister_serial(int line)
-{
-       return;
+       return 0;
 }
 
 /*
  * polling I/O routines
  */
 static int
-zs_poll_tx_char(struct dec_serial *info, unsigned char ch)
+zs_poll_tx_char(void *handle, unsigned char ch)
 {
+       struct dec_serial *info = handle;
        struct dec_zschannel *chan = info->zs_channel;
        int    ret;
 
        if(chan) {
                int loops = 10000;
-//             int nine = read_zsreg(chan, R9);
-
-               RECOVERY_DELAY;
-//             write_zsreg(chan, R9, nine & ~MIE);
-                       wbflush();
-               RECOVERY_DELAY;
-
-               while (!(*(chan->control) & Tx_BUF_EMP) && --loops)
-                       RECOVERY_DELAY;
-
-                if (loops) {
-                        ret = 0;
-                       *(chan->data) = ch;
-                       wbflush();
-                       RECOVERY_DELAY;
-                } else
-                        ret = -EAGAIN;
 
-//             write_zsreg(chan, R9, nine);
-                       wbflush();
-               RECOVERY_DELAY;
+               while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
+                       loops--;
 
-                return ret;
-        }
+               if (loops) {
+                       write_zsdata(chan, ch);
+                       ret = 0;
+               } else
+                       ret = -EAGAIN;
 
-       return -ENODEV;
+               return ret;
+       } else
+               return -ENODEV;
 }
 
 static int
-zs_poll_rx_char(struct dec_serial *info)
+zs_poll_rx_char(void *handle)
 {
+       struct dec_serial *info = handle;
         struct dec_zschannel *chan = info->zs_channel;
         int    ret;
 
        if(chan) {
                 int loops = 10000;
 
-                while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-                       loops--;
+               while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
+                       loops--;
 
                 if (loops)
                         ret = read_zsdata(chan);
                 else
                         ret = -EAGAIN;
 
-                return ret;
-        } else
-                return -ENODEV;
+               return ret;
+       } else
+               return -ENODEV;
 }
 
-unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
+int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
 {
        struct dec_serial *info = &zs_soft[channel];
 
@@ -1970,22 +1916,15 @@ unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
 
                return 0;
        } else {
-               info->hook = hook;
-
-               if (zs_chain == 0)
-                       probe_sccs();
-
-               if (!(info->flags & ZILOG_INITIALIZED))
-                       zs_startup(info);
-
                hook->poll_rx_char = zs_poll_rx_char;
                hook->poll_tx_char = zs_poll_tx_char;
+               info->hook = hook;
 
                return 1;
        }
 }
 
-unsigned int unregister_zs_hook(unsigned int channel)
+int unregister_zs_hook(unsigned int channel)
 {
        struct dec_serial *info = &zs_soft[channel];
 
@@ -2004,7 +1943,7 @@ unsigned int unregister_zs_hook(unsigned int channel)
  * Serial console driver
  * ------------------------------------------------------------
  */
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 
 
 /*
@@ -2041,11 +1980,13 @@ static struct tty_driver *serial_console_device(struct console *c, int *index)
 static int __init serial_console_setup(struct console *co, char *options)
 {
        struct dec_serial *info;
-       int     baud = 9600;
-       int     bits = 8;
-       int     parity = 'n';
-       int     cflag = CREAD | HUPCL | CLOCAL;
-       char    *s;
+       int baud = 9600;
+       int bits = 8;
+       int parity = 'n';
+       int cflag = CREAD | HUPCL | CLOCAL;
+       int clk_divisor = 16;
+       int brg;
+       char *s;
        unsigned long flags;
 
        if(!BUS_PRESENT)
@@ -2097,6 +2038,10 @@ static int __init serial_console_setup(struct console *co, char *options)
        case 9600:
        default:
                cflag |= B9600;
+               /*
+                * Set this to a sane value to prevent a divide error.
+                */
+               baud  = 9600;
                break;
        }
        switch(bits) {
@@ -2117,43 +2062,64 @@ static int __init serial_console_setup(struct console *co, char *options)
                break;
        }
        co->cflag = cflag;
-#if 1 
+
        save_and_cli(flags);
 
+       /*
+        * Set up the baud rate generator.
+        */
+       brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
+       info->zs_channel->curregs[R12] = (brg & 255);
+       info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
+
+       /*
+        * Set byte size and parity.
+        */
+       if (bits == 7) {
+               info->zs_channel->curregs[R3] |= Rx7;
+               info->zs_channel->curregs[R5] |= Tx7;
+       } else {
+               info->zs_channel->curregs[R3] |= Rx8;
+               info->zs_channel->curregs[R5] |= Tx8;
+       }
+       if (cflag & PARENB) {
+               info->zs_channel->curregs[R4] |= PAR_ENA;
+       }
+       if (!(cflag & PARODD)) {
+               info->zs_channel->curregs[R4] |= PAR_EVEN;
+       }
+       info->zs_channel->curregs[R4] |= SB1;
+
        /*
         * Turn on RTS and DTR.
         */
        zs_rtsdtr(info, RTS | DTR, 1);
 
        /*
-        * Finally, enable sequencing
+        * Finally, enable sequencing.
         */
-       info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
-       info->zs_channel->curregs[5] |= (TxENAB | Tx8);
-       info->zs_channel->curregs[9] |= (VIS);
-       write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-       write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-       write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+       info->zs_channel->curregs[R3] |= RxENABLE;
+       info->zs_channel->curregs[R5] |= TxENAB;
 
        /*
         * Clear the interrupt registers.
         */
-       write_zsreg(info->zs_channel, 0, ERR_RES);
-       write_zsreg(info->zs_channel, 0, RES_H_IUS);
+       write_zsreg(info->zs_channel, R0, ERR_RES);
+       write_zsreg(info->zs_channel, R0, RES_H_IUS);
 
        /*
-        * Set the speed of the serial port
+        * Load up the new values.
         */
-       change_speed(info);
+       load_zsregs(info->zs_channel, info->zs_channel->curregs);
 
        /* Save the current value of RR0 */
-       info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+       info->read_reg_zero = read_zsreg(info->zs_channel, R0);
 
-       zs_soft[co->index].clk_divisor = 16;
+       zs_soft[co->index].clk_divisor = clk_divisor;
        zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
 
        restore_flags(flags);
-#endif
+
        return 0;
 }
 
@@ -2173,7 +2139,7 @@ void __init zs_serial_console_init(void)
 {
        register_console(&sercons);
 }
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
 
 #ifdef CONFIG_KGDB
 struct dec_zschannel *zs_kgdbchan;
@@ -2211,7 +2177,7 @@ void kgdb_interruptible(int yes)
        int one, nine;
        nine = read_zsreg(chan, 9);
        if (yes == 1) {
-               one = EXT_INT_ENAB|INT_ALL_Rx;
+               one = EXT_INT_ENAB|RxINT_ALL;
                nine |= MIE;
                printk("turning serial ints on\n");
        } else {
@@ -2223,22 +2189,23 @@ void kgdb_interruptible(int yes)
        write_zsreg(chan, 9, nine);
 }
 
-static int kgdbhook_init_channel(struct dec_serial* info) 
+static int kgdbhook_init_channel(void *handle)
 {
        return 0;
 }
 
-static void kgdbhook_init_info(struct dec_serial* info)
+static void kgdbhook_init_info(void *handle)
 {
 }
 
-static void kgdbhook_rx_char(struct dec_serial* info, 
-                            unsigned char ch, unsigned char stat)
+static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
 {
+       struct dec_serial *info = handle;
+
+       if (fl != TTY_NORMAL)
+               return;
        if (ch == 0x03 || ch == '$')
                breakpoint();
-       if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-               write_zsreg(info->zs_channel, 0, ERR_RES);
 }
 
 /* This sets up the serial port we're using, and turns on
@@ -2264,11 +2231,11 @@ static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
  * for /dev/ttyb which is determined in setup_arch() from the
  * boot command line flags.
  */
-struct zs_hook zs_kgdbhook = {
-       init_channel : kgdbhook_init_channel,
-       init_info    : kgdbhook_init_info,
-       cflags       : B38400|CS8|CLOCAL,
-       rx_char      : kgdbhook_rx_char,
+struct dec_serial_hook zs_kgdbhook = {
+       .init_channel   = kgdbhook_init_channel,
+       .init_info      = kgdbhook_init_info,
+       .rx_char        = kgdbhook_rx_char,
+       .cflags         = B38400 | CS8 | CLOCAL,
 }
 
 void __init zs_kgdb_hook(int tty_num)
index 72f555f00aa7ac3c63833bf10347a6d914956825..c52edffa6049675f6fc47321412665cceae0e6ea 100644 (file)
@@ -1,14 +1,18 @@
 /*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
  *
  * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
  *
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004  Maciej W. Rozycki
  */
 #ifndef _DECSERIAL_H
 #define _DECSERIAL_H
 
+#include <asm/dec/serial.h>
+
 #define NUM_ZSREGS    16
 
 struct serial_struct {
@@ -89,61 +93,48 @@ struct dec_zschannel {
        unsigned char curregs[NUM_ZSREGS];
 };
 
-struct dec_serial;
-
-struct zs_hook {
-       int (*init_channel)(struct dec_serial* info);
-       void (*init_info)(struct dec_serial* info);
-       void (*rx_char)(unsigned char ch, unsigned char stat);
-       int  (*poll_rx_char)(struct dec_serial* info);
-       int  (*poll_tx_char)(struct dec_serial* info,
-                            unsigned char ch);
-       unsigned cflags;
-};
-
 struct dec_serial {
-       struct dec_serial *zs_next;     /* For IRQ servicing chain */
-       struct dec_zschannel *zs_channel; /* Channel registers */
-       struct dec_zschannel *zs_chan_a;        /* A side registers */
-       unsigned char read_reg_zero;
-
-       char soft_carrier;  /* Use soft carrier on this channel */
-       char break_abort;   /* Is serial console in, so process brk/abrt */
-       struct zs_hook *hook;  /* Hook on this channel */
-       char is_cons;       /* Is this our console. */
-       unsigned char tx_active; /* character is being xmitted */
-       unsigned char tx_stopped; /* output is suspended */
-
-       /* We need to know the current clock divisor
-        * to read the bps rate the chip has currently
-        * loaded.
+       struct dec_serial       *zs_next;       /* For IRQ servicing chain.  */
+       struct dec_zschannel    *zs_channel;    /* Channel registers.  */
+       struct dec_zschannel    *zs_chan_a;     /* A side registers.  */
+       unsigned char           read_reg_zero;
+
+       struct dec_serial_hook  *hook;          /* Hook on this channel.  */
+       int                     tty_break;      /* Set on BREAK condition.  */
+       int                     is_cons;        /* Is this our console.  */
+       int                     tx_active;      /* Char is being xmitted.  */
+       int                     tx_stopped;     /* Output is suspended.  */
+
+       /*
+        * We need to know the current clock divisor
+        * to read the bps rate the chip has currently loaded.
         */
-       unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-       int zs_baud;
+       int                     clk_divisor;    /* May be 1, 16, 32, or 64.  */
+       int                     zs_baud;
 
-       char change_needed;
+       char                    change_needed;
 
        int                     magic;
        int                     baud_base;
        int                     port;
        int                     irq;
-       int                     flags;          /* defined in tty.h */
-       int                     type;           /* UART type */
+       int                     flags;          /* Defined in tty.h.  */
+       int                     type;           /* UART type */
        struct tty_struct       *tty;
        int                     read_status_mask;
        int                     ignore_status_mask;
        int                     timeout;
        int                     xmit_fifo_size;
        int                     custom_divisor;
-       int                     x_char; /* xon/xoff character */
+       int                     x_char;         /* XON/XOFF character.  */
        int                     close_delay;
        unsigned short          closing_wait;
        unsigned short          closing_wait2;
        unsigned long           event;
        unsigned long           last_active;
        int                     line;
-       int                     count;      /* # of fd on device */
-       int                     blocked_open; /* # of blocked opens */
+       int                     count;          /* # of fds on device.  */
+       int                     blocked_open;   /* # of blocked opens.  */
        unsigned char           *xmit_buf;
        int                     xmit_head;
        int                     xmit_tail;
@@ -219,8 +210,9 @@ struct dec_serial {
 
 #define        RxINT_DISAB     0       /* Rx Int Disable */
 #define        RxINT_FCERR     0x8     /* Rx Int on First Character Only or Error */
-#define        INT_ALL_Rx      0x10    /* Int on all Rx Characters or error */
-#define        INT_ERR_Rx      0x18    /* Int on error only */
+#define        RxINT_ALL       0x10    /* Int on all Rx Characters or error */
+#define        RxINT_ERR       0x18    /* Int on error only */
+#define        RxINT_MASK      0x18
 
 #define        WT_RDY_RT       0x20    /* Wait/Ready on R/T */
 #define        WT_FN_RDYFN     0x40    /* Wait/FN/Ready FN */