Commit 6f58fe85 authored by Ralf Bächle's avatar Ralf Bächle Committed by Linus Torvalds

[PATCH] mips: DECstation Turbochannel updates

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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 7f5d114c
...@@ -4,20 +4,44 @@ ...@@ -4,20 +4,44 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * 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/errno.h>
#include <linux/sched.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kbd_ll.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/tc.h>
#include <asm/dec/machtype.h> #include <asm/dec/machtype.h>
#include <asm/dec/serial.h>
#include "zs.h"
#include "lk201.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 */ /* Simple translation table for the SysRq keys */
#ifdef CONFIG_MAGIC_SYSRQ #ifdef CONFIG_MAGIC_SYSRQ
...@@ -27,25 +51,29 @@ ...@@ -27,25 +51,29 @@
*/ */
unsigned char lk201_sysrq_xlate[128]; unsigned char lk201_sysrq_xlate[128];
unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate; unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate;
unsigned char kbd_sysrq_key = -1;
#endif #endif
#define KEYB_LINE 3 #define KEYB_LINE 3
static int __init lk201_init(struct dec_serial *); static int __init lk201_init(void *);
static void __init lk201_info(struct dec_serial *); static void __init lk201_info(void *);
static void lk201_kbd_rx_char(unsigned char, unsigned char); static void lk201_rx_char(unsigned char, unsigned char);
struct zs_hook lk201_kbdhook = { static struct dec_serial_hook lk201_hook = {
.init_channel = lk201_init, .init_channel = lk201_init,
.init_info = lk201_info, .init_info = lk201_info,
.cflags = B4800 | CS8 | CSTOPB | CLOCAL .rx_char = NULL,
.poll_rx_char = NULL,
.poll_tx_char = NULL,
.cflags = B4800 | CS8 | CSTOPB | CLOCAL,
}; };
/* /*
* This is used during keyboard initialisation * This is used during keyboard initialisation
*/ */
static unsigned char lk201_reset_string[] = { 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_SET_DEFAULTS,
LK_CMD_MODE(LK_MODE_RPT_DOWN, 1), LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
LK_CMD_MODE(LK_MODE_RPT_DOWN, 2), LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
...@@ -61,27 +89,198 @@ static unsigned char lk201_reset_string[] = { ...@@ -61,27 +89,198 @@ static unsigned char lk201_reset_string[] = {
LK_CMD_MODE(LK_MODE_RPT_DOWN, 12), LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
LK_CMD_MODE(LK_MODE_DOWN, 13), LK_CMD_MODE(LK_MODE_DOWN, 13),
LK_CMD_MODE(LK_MODE_RPT_DOWN, 14), LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
LK_CMD_ENB_RPT,
LK_CMD_DIS_KEYCLK, LK_CMD_DIS_KEYCLK,
LK_CMD_RESUME,
LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4), 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; int i;
for (i = 0; i < sizeof(lk201_reset_string); i++) delay = rep->delay / 5;
if (info->hook->poll_tx_char(info, lk201_reset_string[i])) { rate = rep->rate;
printk("%s transmit timeout\n", __FUNCTION__); 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; return -EIO;
} }
memcpy(&kbdrate, rep, sizeof(struct kbd_repeat));
return 0; 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) void kbd_leds(unsigned char leds)
{ {
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; return;
} }
...@@ -107,31 +306,73 @@ char kbd_unexpected_up(unsigned char keycode) ...@@ -107,31 +306,73 @@ char kbd_unexpected_up(unsigned char keycode)
return 0x80; 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 shift_state = 0;
static int prev_scancode; static int prev_scancode;
unsigned char c = scancodeRemap[ch]; unsigned char c = scancodeRemap[ch];
if (!stat || stat == 4) { 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();
}
return;
}
/* Everything else is a scancode/status response. */
id_i = 0;
switch (ch) { switch (ch) {
case LK_KEY_ACK: 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; break;
case LK_KEY_LOCK: case LK_KEY_LOCK:
shift_state ^= LK_LOCK; shift_state ^= LK_LOCK;
handle_scancode(c, shift_state && LK_LOCK ? 1 : 0); handle_scancode(c, (shift_state & LK_LOCK) ? 1 : 0);
break; break;
case LK_KEY_SHIFT: case LK_KEY_SHIFT:
shift_state ^= LK_SHIFT; shift_state ^= LK_SHIFT;
handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0); handle_scancode(c, (shift_state & LK_SHIFT) ? 1 : 0);
break; break;
case LK_KEY_CTRL: case LK_KEY_CTRL:
shift_state ^= LK_CTRL; shift_state ^= LK_CTRL;
handle_scancode(c, shift_state && LK_CTRL ? 1 : 0); handle_scancode(c, (shift_state & LK_CTRL) ? 1 : 0);
break; break;
case LK_KEY_COMP: case LK_KEY_COMP:
shift_state ^= LK_COMP; shift_state ^= LK_COMP;
handle_scancode(c, shift_state && LK_COMP ? 1 : 0); handle_scancode(c, (shift_state & LK_COMP) ? 1 : 0);
break; break;
case LK_KEY_RELEASE: case LK_KEY_RELEASE:
if (shift_state & LK_SHIFT) if (shift_state & LK_SHIFT)
...@@ -152,83 +393,49 @@ static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat) ...@@ -152,83 +393,49 @@ static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
handle_scancode(c, 1); handle_scancode(c, 1);
break; break;
} }
} else tasklet_schedule(&keyboard_tasklet);
printk("Error reading LKx01 keyboard: 0x%02x\n", stat);
} }
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; /* First install handlers. */
int result; 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");
}
/* /* Then just issue a reset -- the handlers will do the rest. */
* now we're ready lk201_send(LK_CMD_POWER_UP);
*/
info->hook->rx_char = lk201_kbd_rx_char;
return 0; return 0;
} }
void __init kbd_init_hw(void) void __init kbd_init_hw(void)
{ {
extern int register_zs_hook(unsigned int, struct zs_hook *); /* Maxine uses LK501 at the Access.Bus. */
extern int unregister_zs_hook(unsigned int); if (!LK_IFACE)
return;
if (TURBOCHANNEL) { printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n");
if (mips_machtype != MACH_DS5000_XX) {
if (LK_IFACE_ZS) {
/* /*
* This is not a MAXINE, so:
*
* kbd_init_hw() is being called before * kbd_init_hw() is being called before
* rs_init() so just register the kbd hook * rs_init() so just register the kbd hook
* and let zs_init do the rest :-) * and let zs_init do the rest :-)
*/ */
if (mips_machtype == MACH_DS5000_200) if (!register_dec_serial_hook(KEYB_LINE, &lk201_hook))
printk("LK201 Support for DS5000/200 not yet ready ...\n"); unregister_dec_serial_hook(KEYB_LINE);
else
if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
unregister_zs_hook(KEYB_LINE);
}
} else { } else {
/* /*
* TODO: modify dz.c to allow similar hooks * TODO: modify dz.c to allow similar hooks
* for LK201 handling on DS2100, DS3100, and DS5000/200 * 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");
} }
} }
...@@ -4,50 +4,122 @@ ...@@ -4,50 +4,122 @@
#define LK_PARAM 0x80 /* start/end parameter list */ #define LK_PARAM 0x80 /* start/end parameter list */
#define LK_CMD_RESUME 0x8b #define LK_CMD_RESUME 0x8b /* resume transmission to the host */
#define LK_CMD_INHIBIT 0xb9 #define LK_CMD_INHIBIT 0x89 /* stop transmission to the host */
#define LK_CMD_LEDS_ON 0x13 /* 1 param: led bitmask */ #define LK_CMD_LEDS_ON 0x13 /* light LEDs */
#define LK_CMD_LEDS_OFF 0x11 /* 1 param: led bitmask */ /* 1st param: led bitmask */
#define LK_CMD_DIS_KEYCLK 0x99 #define LK_CMD_LEDS_OFF 0x11 /* turn off LEDs */
#define LK_CMD_ENB_KEYCLK 0x1b /* 1 param: volume */ /* 1st param: led bitmask */
#define LK_CMD_DIS_CTLCLK 0xb9 #define LK_CMD_DIS_KEYCLK 0x99 /* disable the keyclick */
#define LK_CMD_ENB_CTLCLK 0xbb #define LK_CMD_ENB_KEYCLK 0x1b /* enable the keyclick */
#define LK_CMD_SOUND_CLK 0x9f /* 1st param: volume */
#define LK_CMD_DIS_BELL 0xa1 #define LK_CMD_DIS_CTLCLK 0xb9 /* disable the Ctrl keyclick */
#define LK_CMD_ENB_BELL 0x23 /* 1 param: volume */ #define LK_CMD_ENB_CTLCLK 0xbb /* enable the Ctrl keyclick */
#define LK_CMD_BELL 0xa7 #define LK_CMD_SOUND_CLK 0x9f /* emit a keyclick */
#define LK_CMD_TMP_NORPT 0xc1 #define LK_CMD_DIS_BELL 0xa1 /* disable the bell */
#define LK_CMD_ENB_RPT 0xe3 #define LK_CMD_ENB_BELL 0x23 /* enable the bell */
#define LK_CMD_DIS_RPT 0xe1 /* 1st param: volume */
#define LK_CMD_RPT_TO_DOWN 0xd9 #define LK_CMD_BELL 0xa7 /* emit a bell */
#define LK_CMD_REQ_ID 0xab #define LK_CMD_TMP_NORPT 0xd1 /* disable typematic */
#define LK_CMD_POWER_UP 0xfd /* for the currently pressed key */
#define LK_CMD_TEST_MODE 0xcb #define LK_CMD_ENB_RPT 0xe3 /* enable typematic */
#define LK_CMD_SET_DEFAULTS 0xd3 /* 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 */ /* 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 */ /* 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(s) details */ /* mode set command details, div is a key group number */
#define LK_MODE_DOWN 0x0 #define LK_MODE_DOWN 0x0 /* make only */
#define LK_MODE_RPT_DOWN 0x2 #define LK_MODE_RPT_DOWN 0x1 /* make and typematic */
#define LK_MODE_DOWN_UP 0x6 #define LK_MODE_DOWN_UP 0x3 /* make and release */
#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_SHIFT 1<<0
#define LK_CTRL 1<<1 #define LK_CTRL 1<<1
#define LK_LOCK 1<<2 #define LK_LOCK 1<<2
#define LK_COMP 1<<3 #define LK_COMP 1<<3
#define LK_KEY_SHIFT 174 #define LK_KEY_SHIFT 0xae
#define LK_KEY_CTRL 175 #define LK_KEY_CTRL 0xaf
#define LK_KEY_LOCK 176 #define LK_KEY_LOCK 0xb0
#define LK_KEY_COMP 177 #define LK_KEY_COMP 0xb1
#define LK_KEY_RELEASE 179
#define LK_KEY_REPEAT 180 #define LK_KEY_RELEASE 0xb3 /* all keys released */
#define LK_KEY_ACK 186 #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]; extern unsigned char scancodeRemap[256];
...@@ -8,46 +8,46 @@ ...@@ -8,46 +8,46 @@
* for more details. * for more details.
* *
* Copyright (c) Harald Koerfgen, 1998 * Copyright (c) Harald Koerfgen, 1998
* Copyright (c) 2001, 2003 Maciej W. Rozycki
*/ */
#include <linux/string.h> #include <linux/string.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/addrspace.h> #include <asm/addrspace.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/dec/machtype.h> #include <asm/dec/machtype.h>
#include <asm/dec/prom.h>
#include <asm/dec/tcinfo.h> #include <asm/dec/tcinfo.h>
#include <asm/dec/tcmodule.h> #include <asm/dec/tcmodule.h>
#include <asm/dec/interrupts.h> #include <asm/dec/interrupts.h>
#include <asm/paccess.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <linux/kernel.h>
#include <linux/module.h>
#define TC_DEBUG #define TC_DEBUG
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
slot_info tc_bus[MAX_SLOT]; slot_info tc_bus[MAX_SLOT];
static int max_tcslot; static int num_tcslots;
static tcinfo *info; static tcinfo *info;
unsigned long system_base; 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. * 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; int slot;
slot_info *sip; slot_info *sip;
for (slot = 0; slot <= max_tcslot; slot++) { for (slot = 0; slot < num_tcslots; slot++) {
sip = &tc_bus[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; return slot;
} }
} }
...@@ -68,7 +68,8 @@ void claim_tc_card(int slot) ...@@ -68,7 +68,8 @@ void claim_tc_card(int slot)
void release_tc_card(int slot) void release_tc_card(int slot)
{ {
if (tc_bus[slot].flags & FREE) { 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; return;
} }
tc_bus[slot].flags &= ~IN_USE; tc_bus[slot].flags &= ~IN_USE;
...@@ -93,38 +94,52 @@ unsigned long get_tc_speed(void) ...@@ -93,38 +94,52 @@ unsigned long get_tc_speed(void)
/* /*
* Probing for TURBOchannel modules * 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; long offset;
unsigned char pattern[4];
unsigned char *module; unsigned char *module;
void (*old_be_handler)(struct pt_regs *regs);
/* Install our exception handler temporarily */ for (slot = 0; slot < slots; slot++) {
old_be_handler = dbe_board_handler;
dbe_board_handler = my_dbe_handler;
for (slot = 0; slot <= max_slot; slot++) {
module = (char *)(startaddr + slot * size); 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; offset = OLDCARD;
if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00
&& module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
offset = 0;
if (offset != -1) { 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;
}
if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
pattern[2] != 0xaa || pattern[3] != 0xff)
continue;
tc_bus[slot].base_addr = (unsigned long)module; tc_bus[slot].base_addr = (unsigned long)module;
for(i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i]; tc_bus[slot].firmware[i] =
tc_bus[slot].vendor[i] = module[TC_VENDOR + offset + 4 * i]; module[TC_FIRM_VER + offset + 4 * i];
tc_bus[slot].name[i] = module[TC_MODULE + 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].firmware[8] = 0;
tc_bus[slot].vendor[8] = 0; tc_bus[slot].vendor[8] = 0;
...@@ -135,31 +150,28 @@ static void __init tc_probe(unsigned long startaddr, unsigned long size, int max ...@@ -135,31 +150,28 @@ static void __init tc_probe(unsigned long startaddr, unsigned long size, int max
*/ */
switch (slot) { switch (slot) {
case 0: case 0:
tc_bus[slot].interrupt = TC0; tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
break; break;
case 1: case 1:
tc_bus[slot].interrupt = TC1; tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
break; break;
case 2: case 2:
tc_bus[slot].interrupt = TC2; tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
break; break;
/* /*
* Yuck! DS5000/200 onboard devices * Yuck! DS5000/200 onboard devices
*/ */
case 5: case 5:
tc_bus[slot].interrupt = SCSI_INT; tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
break; break;
case 6: case 6:
tc_bus[slot].interrupt = ETHER; tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
break; break;
default: default:
tc_bus[slot].interrupt = -1; tc_bus[slot].interrupt = -1;
break; break;
} }
} }
}
dbe_board_handler = old_be_handler;
} }
/* /*
...@@ -189,15 +201,16 @@ void __init tc_init(void) ...@@ -189,15 +201,16 @@ void __init tc_init(void)
switch (mips_machtype) { switch (mips_machtype) {
case MACH_DS5000_200: case MACH_DS5000_200:
max_tcslot = 6; num_tcslots = 7;
break; break;
case MACH_DS5000_1XX: case MACH_DS5000_1XX:
case MACH_DS5000_2X0: case MACH_DS5000_2X0:
max_tcslot = 2; case MACH_DS5900:
num_tcslots = 3;
break; break;
case MACH_DS5000_XX: case MACH_DS5000_XX:
default: default:
max_tcslot = 1; num_tcslots = 2;
break; break;
} }
...@@ -210,22 +223,22 @@ void __init tc_init(void) ...@@ -210,22 +223,22 @@ void __init tc_init(void)
slot_size = info->slot_size << 20; 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 * 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. * would be.
*/ */
if(mips_machtype == MACH_DS5000_XX) if(mips_machtype == MACH_DS5000_XX)
i = 2;
else
i = 1; i = 1;
else
i = 0;
system_base = slot0addr + slot_size * (max_tcslot + i); system_base = slot0addr + slot_size * (num_tcslots + i);
#ifdef TC_DEBUG #ifdef TC_DEBUG
for (i = 0; i <= max_tcslot; i++) for (i = 0; i < num_tcslots; i++)
if (tc_bus[i].base_addr) { if (tc_bus[i].base_addr) {
printk(" slot %d: ", i); printk(" slot %d: ", i);
printk("%s %s %s\n", tc_bus[i].vendor, printk("%s %s %s\n", tc_bus[i].vendor,
...@@ -244,4 +257,4 @@ EXPORT_SYMBOL(release_tc_card); ...@@ -244,4 +257,4 @@ EXPORT_SYMBOL(release_tc_card);
EXPORT_SYMBOL(get_tc_base_addr); EXPORT_SYMBOL(get_tc_base_addr);
EXPORT_SYMBOL(get_tc_irq_nr); EXPORT_SYMBOL(get_tc_irq_nr);
EXPORT_SYMBOL(get_tc_speed); EXPORT_SYMBOL(get_tc_speed);
EXPORT_SYMBOL(system_base);
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* DECstation changes * DECstation changes
* Copyright (C) 1998-2000 Harald Koerfgen * 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: * For the rest of the code the original Copyright applies:
* Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au) * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
...@@ -55,8 +55,7 @@ ...@@ -55,8 +55,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/bitops.h> #ifdef CONFIG_SERIAL_DEC_CONSOLE
#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h> #include <linux/console.h>
#endif #endif
...@@ -65,18 +64,15 @@ ...@@ -65,18 +64,15 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/wbflush.h>
#include <asm/bootinfo.h> #include <asm/bootinfo.h>
#include <asm/dec/serial.h>
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
#include <asm/dec/interrupts.h> #include <asm/dec/interrupts.h>
#include <asm/dec/machtype.h> #include <asm/dec/machtype.h>
#include <asm/dec/tc.h> #include <asm/dec/tc.h>
#include <asm/dec/ioasic_addrs.h> #include <asm/dec/ioasic_addrs.h>
#endif #endif
#ifdef CONFIG_BAGET_MIPS
#include <asm/baget/baget.h>
unsigned long system_base;
#endif
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
#include <asm/kgdb.h> #include <asm/kgdb.h>
#endif #endif
...@@ -105,7 +101,8 @@ struct zs_parms { ...@@ -105,7 +101,8 @@ struct zs_parms {
unsigned long scc1; unsigned long scc1;
int channel_a_offset; int channel_a_offset;
int channel_b_offset; int channel_b_offset;
int irq; int irq0;
int irq1;
int clock; int clock;
}; };
...@@ -113,24 +110,15 @@ static struct zs_parms *zs_parms; ...@@ -113,24 +110,15 @@ static struct zs_parms *zs_parms;
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
static struct zs_parms ds_parms = { static struct zs_parms ds_parms = {
scc0 : SCC0, scc0 : IOASIC_SCC0,
scc1 : SCC1, scc1 : IOASIC_SCC1,
channel_a_offset : 1, channel_a_offset : 1,
channel_b_offset : 9, channel_b_offset : 9,
irq : SERIAL, irq0 : -1,
irq1 : -1,
clock : ZS_CLOCK clock : ZS_CLOCK
}; };
#endif #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 #ifdef CONFIG_MACH_DECSTATION
#define DS_BUS_PRESENT (IOASIC) #define DS_BUS_PRESENT (IOASIC)
...@@ -138,13 +126,7 @@ static struct zs_parms baget_parms = { ...@@ -138,13 +126,7 @@ static struct zs_parms baget_parms = {
#define DS_BUS_PRESENT 0 #define DS_BUS_PRESENT 0
#endif #endif
#ifdef CONFIG_BAGET_MIPS #define BUS_PRESENT (DS_BUS_PRESENT)
#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
#else
#define BAGET_BUS_PRESENT 0
#endif
#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
struct dec_zschannel zs_channels[NUM_CHANNELS]; struct dec_zschannel zs_channels[NUM_CHANNELS];
struct dec_serial zs_soft[NUM_CHANNELS]; struct dec_serial zs_soft[NUM_CHANNELS];
...@@ -153,23 +135,23 @@ struct dec_serial *zs_chain; /* list of all channels */ ...@@ -153,23 +135,23 @@ struct dec_serial *zs_chain; /* list of all channels */
struct tty_struct zs_ttys[NUM_CHANNELS]; struct tty_struct zs_ttys[NUM_CHANNELS];
#ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_SERIAL_DEC_CONSOLE
static struct console sercons; static struct console sercons;
#endif #endif
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \ #if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
&& !defined(MODULE) !defined(MODULE)
static unsigned long break_pressed; /* break, really ... */ static unsigned long break_pressed; /* break, really ... */
#endif #endif
static unsigned char zs_init_regs[16] __initdata = { static unsigned char zs_init_regs[16] __initdata = {
0, /* write 0 */ 0, /* write 0 */
0, /* write 1 */ 0, /* write 1 */
0xf0, /* write 2 */ 0, /* write 2 */
(Rx8), /* write 3 */ 0, /* write 3 */
(X16CLK | SB1), /* write 4 */ (X16CLK), /* write 4 */
(Tx8), /* write 5 */ 0, /* write 5 */
0, 0, 0, /* write 6, 7, 8 */ 0, 0, 0, /* write 6, 7, 8 */
(VIS), /* write 9 */ (MIE | DLC | NV), /* write 9 */
(NRZ), /* write 10 */ (NRZ), /* write 10 */
(TCBR | RCBR), /* write 11 */ (TCBR | RCBR), /* write 11 */
0, 0, /* BRG time constant, write 12 + 13 */ 0, 0, /* BRG time constant, write 12 + 13 */
...@@ -190,7 +172,6 @@ static struct tty_driver *serial_driver; ...@@ -190,7 +172,6 @@ static struct tty_driver *serial_driver;
/* /*
* Debugging. * Debugging.
*/ */
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_FLOW
#undef SERIAL_DEBUG_THROTTLE #undef SERIAL_DEBUG_THROTTLE
...@@ -261,7 +242,7 @@ 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) { if (reg != 0) {
*channel->control = reg & 0xf; *channel->control = reg & 0xf;
wbflush(); RECOVERY_DELAY; fast_iob(); RECOVERY_DELAY;
} }
retval = *channel->control; retval = *channel->control;
RECOVERY_DELAY; RECOVERY_DELAY;
...@@ -273,10 +254,10 @@ static inline void write_zsreg(struct dec_zschannel *channel, ...@@ -273,10 +254,10 @@ static inline void write_zsreg(struct dec_zschannel *channel,
{ {
if (reg != 0) { if (reg != 0) {
*channel->control = reg & 0xf; *channel->control = reg & 0xf;
wbflush(); RECOVERY_DELAY; fast_iob(); RECOVERY_DELAY;
} }
*channel->control = value; *channel->control = value;
wbflush(); RECOVERY_DELAY; fast_iob(); RECOVERY_DELAY;
return; return;
} }
...@@ -293,7 +274,7 @@ static inline void write_zsdata(struct dec_zschannel *channel, ...@@ -293,7 +274,7 @@ static inline void write_zsdata(struct dec_zschannel *channel,
unsigned char value) unsigned char value)
{ {
*channel->data = value; *channel->data = value;
wbflush(); RECOVERY_DELAY; fast_iob(); RECOVERY_DELAY;
return; return;
} }
...@@ -303,9 +284,9 @@ static inline void load_zsregs(struct dec_zschannel *channel, ...@@ -303,9 +284,9 @@ static inline void load_zsregs(struct dec_zschannel *channel,
/* ZS_CLEARERR(channel); /* ZS_CLEARERR(channel);
ZS_CLEARFIFO(channel); */ ZS_CLEARFIFO(channel); */
/* Load 'em up */ /* Load 'em up */
write_zsreg(channel, R4, regs[R4]);
write_zsreg(channel, R3, regs[R3] & ~RxENABLE); write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
write_zsreg(channel, R5, regs[R5] & ~TxENAB); write_zsreg(channel, R5, regs[R5] & ~TxENAB);
write_zsreg(channel, R4, regs[R4]);
write_zsreg(channel, R9, regs[R9]); write_zsreg(channel, R9, regs[R9]);
write_zsreg(channel, R1, regs[R1]); write_zsreg(channel, R1, regs[R1]);
write_zsreg(channel, R2, regs[R2]); write_zsreg(channel, R2, regs[R2]);
...@@ -372,8 +353,6 @@ static inline void rs_recv_clear(struct dec_zschannel *zsc) ...@@ -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 * This routine is used by the interrupt handler to schedule
* processing in the software interrupt portion of the driver. * processing in the software interrupt portion of the driver.
...@@ -397,23 +376,18 @@ static _INLINE_ void receive_chars(struct dec_serial *info, ...@@ -397,23 +376,18 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
stat = read_zsreg(info->zs_channel, R1); stat = read_zsreg(info->zs_channel, R1);
ch = read_zsdata(info->zs_channel); ch = read_zsdata(info->zs_channel);
if (!tty && !info->hook && !info->hook->rx_char) if (!tty && (!info->hook || !info->hook->rx_char))
continue; continue;
if (tty_break) { flag = TTY_NORMAL;
tty_break = 0; if (info->tty_break) {
#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE) info->tty_break = 0;
if (info->line == sercons.index) {
if (!break_pressed) {
break_pressed = jiffies;
goto ignore_char;
}
break_pressed = 0;
}
#endif
flag = TTY_BREAK; flag = TTY_BREAK;
if (info->flags & ZILOG_SAK) if (info->flags & ZILOG_SAK)
do_SAK(tty); do_SAK(tty);
/* Ignore the null char got when BREAK is removed. */
if (ch == 0)
continue;
} else { } else {
if (stat & Rx_OVR) { if (stat & Rx_OVR) {
flag = TTY_OVERRUN; flag = TTY_OVERRUN;
...@@ -421,20 +395,22 @@ static _INLINE_ void receive_chars(struct dec_serial *info, ...@@ -421,20 +395,22 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
flag = TTY_FRAME; flag = TTY_FRAME;
} else if (stat & PAR_ERR) { } else if (stat & PAR_ERR) {
flag = TTY_PARITY; flag = TTY_PARITY;
} else }
flag = 0; if (flag != TTY_NORMAL)
if (flag)
/* reset the error indication */ /* reset the error indication */
write_zsreg(info->zs_channel, R0, ERR_RES); 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 (break_pressed && info->line == sercons.index) {
if (ch != 0 && /* Ignore the null char got when BREAK is removed. */
time_before(jiffies, break_pressed + HZ*5)) { if (ch == 0)
continue;
if (time_before(jiffies, break_pressed + HZ * 5)) {
handle_sysrq(ch, regs, NULL); handle_sysrq(ch, regs, NULL);
break_pressed = 0; break_pressed = 0;
goto ignore_char; continue;
} }
break_pressed = 0; break_pressed = 0;
} }
...@@ -445,21 +421,7 @@ static _INLINE_ void receive_chars(struct dec_serial *info, ...@@ -445,21 +421,7 @@ static _INLINE_ void receive_chars(struct dec_serial *info,
return; return;
} }
if (tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_insert_flip_char(tty, ch, flag);
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:
} }
if (tty) if (tty)
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
...@@ -501,18 +463,22 @@ static _INLINE_ void status_handle(struct dec_serial *info) ...@@ -501,18 +463,22 @@ static _INLINE_ void status_handle(struct dec_serial *info)
/* Get status from Read Register 0 */ /* Get status from Read Register 0 */
stat = read_zsreg(info->zs_channel, R0); stat = read_zsreg(info->zs_channel, R0);
if (stat & BRK_ABRT) { if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
#ifdef SERIAL_DEBUG_INTR #if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
printk("handling break...."); !defined(MODULE)
if (info->line == sercons.index) {
if (!break_pressed)
break_pressed = jiffies;
} else
#endif #endif
tty_break = 1; info->tty_break = 1;
} }
if (info->zs_channel != info->zs_chan_a) { if (info->zs_channel != info->zs_chan_a) {
/* FIXEM: Check for DCD transitions */ /* Check for DCD transitions */
if (((stat ^ info->read_reg_zero) & DCD) != 0 if (info->tty && !C_CLOCAL(info->tty) &&
&& info->tty && !C_CLOCAL(info->tty)) { ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
if (stat & DCD) { if (stat & DCD) {
wake_up_interruptible(&info->open_wait); wake_up_interruptible(&info->open_wait);
} else { } else {
...@@ -711,8 +677,13 @@ int zs_startup(struct dec_serial * info) ...@@ -711,8 +677,13 @@ int zs_startup(struct dec_serial * info)
/* /*
* Clear the interrupt registers. * Clear the interrupt registers.
*/ */
write_zsreg(info->zs_channel, 0, ERR_RES); write_zsreg(info->zs_channel, R0, ERR_RES);
write_zsreg(info->zs_channel, 0, RES_H_IUS); write_zsreg(info->zs_channel, R0, RES_H_IUS);
/*
* Set the speed of the serial port
*/
change_speed(info);
/* /*
* Turn on RTS and DTR. * Turn on RTS and DTR.
...@@ -722,35 +693,30 @@ int zs_startup(struct dec_serial * info) ...@@ -722,35 +693,30 @@ int zs_startup(struct dec_serial * info)
/* /*
* Finally, enable sequencing and interrupts * 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[R1] &= ~RxINT_MASK;
info->zs_channel->curregs[3] |= (RxENABLE | Rx8); info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
info->zs_channel->curregs[5] |= (TxENAB | Tx8); EXT_INT_ENAB);
info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE); info->zs_channel->curregs[R3] |= RxENABLE;
info->zs_channel->curregs[9] |= (VIS | MIE); info->zs_channel->curregs[R5] |= TxENAB;
write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]); write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]); write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
/* /*
* And clear the interrupt registers again for luck. * And clear the interrupt registers again for luck.
*/ */
write_zsreg(info->zs_channel, 0, ERR_RES); write_zsreg(info->zs_channel, R0, ERR_RES);
write_zsreg(info->zs_channel, 0, RES_H_IUS); 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) if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags); clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; 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; info->flags |= ZILOG_INITIALIZED;
restore_flags(flags); restore_flags(flags);
return 0; return 0;
...@@ -833,9 +799,7 @@ static void change_speed(struct dec_serial *info) ...@@ -833,9 +799,7 @@ static void change_speed(struct dec_serial *info)
save_flags(flags); cli(); save_flags(flags); cli();
info->zs_baud = baud_table[i]; info->zs_baud = baud_table[i];
info->clk_divisor = 16;
if (info->zs_baud) { if (info->zs_baud) {
info->zs_channel->curregs[4] = X16CLK;
brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor); brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
info->zs_channel->curregs[12] = (brg & 255); info->zs_channel->curregs[12] = (brg & 255);
info->zs_channel->curregs[13] = ((brg >> 8) & 255); info->zs_channel->curregs[13] = ((brg >> 8) & 255);
...@@ -943,11 +907,19 @@ static int rs_write(struct tty_struct * tty, ...@@ -943,11 +907,19 @@ static int rs_write(struct tty_struct * tty,
save_flags(flags); save_flags(flags);
while (1) { while (1) {
cli(); cli();
c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head)); SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0) if (c <= 0)
break; break;
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); memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c; info->xmit_cnt += c;
...@@ -1210,6 +1182,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file, ...@@ -1210,6 +1182,7 @@ static int rs_tiocmset(struct tty_struct *tty, struct file *file,
if (info->zs_channel == info->zs_chan_a) if (info->zs_channel == info->zs_chan_a)
return 0; return 0;
get_user(arg, value);
cli(); cli();
if (set & TIOCM_RTS) if (set & TIOCM_RTS)
info->zs_chan_a->curregs[5] |= RTS; info->zs_chan_a->curregs[5] |= RTS;
...@@ -1267,30 +1240,30 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1267,30 +1240,30 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd) { switch (cmd) {
case TIOCGSERIAL: case TIOCGSERIAL:
error = verify_area(VERIFY_WRITE, (void *) arg, error = verify_area(VERIFY_WRITE, (void *)arg,
sizeof(struct serial_struct)); sizeof(struct serial_struct));
if (error) if (error)
return error; return error;
return get_serial_info(info, return get_serial_info(info, (struct serial_struct *)arg);
(struct serial_struct *) arg);
case TIOCSSERIAL: case TIOCSSERIAL:
return set_serial_info(info, return set_serial_info(info, (struct serial_struct *)arg);
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */ case TIOCSERGETLSR: /* Get line status register */
error = verify_area(VERIFY_WRITE, (void *) arg, error = verify_area(VERIFY_WRITE, (void *)arg,
sizeof(unsigned int)); sizeof(unsigned int));
if (error) if (error)
return error; return error;
else else
return get_lsr_info(info, (unsigned int *) arg); return get_lsr_info(info, (unsigned int *)arg);
case TIOCSERGSTRUCT: case TIOCSERGSTRUCT:
error = verify_area(VERIFY_WRITE, (void *) arg, error = verify_area(VERIFY_WRITE, (void *)arg,
sizeof(struct dec_serial)); sizeof(struct dec_serial));
if (error) if (error)
return error; return error;
copy_from_user((struct dec_serial *) arg, copy_from_user((struct dec_serial *)arg, info,
info, sizeof(struct dec_serial)); sizeof(struct dec_serial));
return 0; return 0;
default: default:
...@@ -1411,7 +1384,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp) ...@@ -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) static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{ {
struct dec_serial *info = (struct dec_serial *) tty->driver_data; 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")) if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
return; return;
...@@ -1427,7 +1401,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) ...@@ -1427,7 +1401,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (char_time == 0) if (char_time == 0)
char_time = 1; char_time = 1;
if (timeout) 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) { while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
schedule_timeout(char_time); schedule_timeout(char_time);
...@@ -1484,11 +1458,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -1484,11 +1458,6 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
#endif #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, * If non-blocking mode is set, or the port is not enabled,
* then make the check up front and then exit. * then make the check up front and then exit.
...@@ -1626,7 +1595,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) ...@@ -1626,7 +1595,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
return retval; return retval;
} }
#ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_SERIAL_DEC_CONSOLE
if (sercons.cflag && sercons.index == line) { if (sercons.cflag && sercons.index == line) {
tty->termios->c_cflag = sercons.cflag; tty->termios->c_cflag = sercons.cflag;
sercons.cflag = 0; sercons.cflag = 0;
...@@ -1645,7 +1614,7 @@ int rs_open(struct tty_struct *tty, struct file * filp) ...@@ -1645,7 +1614,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
static void __init show_serial_version(void) 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 /* Initialize Z8530s zs_channels
...@@ -1655,6 +1624,7 @@ static void __init probe_sccs(void) ...@@ -1655,6 +1624,7 @@ static void __init probe_sccs(void)
{ {
struct dec_serial **pp; struct dec_serial **pp;
int i, n, n_chips = 0, n_channels, chip, channel; int i, n, n_chips = 0, n_channels, chip, channel;
unsigned long flags;
/* /*
* did we get here by accident? * did we get here by accident?
...@@ -1672,27 +1642,25 @@ static void __init probe_sccs(void) ...@@ -1672,27 +1642,25 @@ static void __init probe_sccs(void)
switch(mips_machtype) { switch(mips_machtype) {
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
case MACH_DS5000_2X0: case MACH_DS5000_2X0:
system_base = 0xbf800000; case MACH_DS5900:
system_base = KSEG1ADDR(0x1f800000);
n_chips = 2; n_chips = 2;
zs_parms = &ds_parms; zs_parms = &ds_parms;
zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
break; break;
case MACH_DS5000_1XX: case MACH_DS5000_1XX:
system_base = 0xbc000000; system_base = KSEG1ADDR(0x1c000000);
n_chips = 2; n_chips = 2;
zs_parms = &ds_parms; zs_parms = &ds_parms;
zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
break; break;
case MACH_DS5000_XX: case MACH_DS5000_XX:
system_base = 0xbc000000; system_base = KSEG1ADDR(0x1c000000);
n_chips = 1; n_chips = 1;
zs_parms = &ds_parms; zs_parms = &ds_parms;
break; zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
#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;
break; break;
#endif #endif
default: default:
...@@ -1718,7 +1686,7 @@ static void __init probe_sccs(void) ...@@ -1718,7 +1686,7 @@ static void __init probe_sccs(void)
zs_channels[n_channels].data = zs_channels[n_channels].data =
zs_channels[n_channels].control + 4; 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. * We're called early and memory managment isn't up, yet.
* Thus check_region would fail. * Thus check_region would fail.
...@@ -1729,7 +1697,11 @@ static void __init probe_sccs(void) ...@@ -1729,7 +1697,11 @@ static void __init probe_sccs(void)
panic("SCC I/O region is not free"); panic("SCC I/O region is not free");
#endif #endif
zs_soft[n_channels].zs_channel = &zs_channels[n_channels]; 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 * Identification of channel A. Location of channel A
...@@ -1760,16 +1732,17 @@ static void __init probe_sccs(void) ...@@ -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++) { 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); write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
mdelay(10); udelay(10);
write_zsreg(zs_soft[n].zs_chan_a, R9, 0); write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
} }
load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs); load_zsregs(zs_soft[n].zs_channel,
zs_soft[n].zs_channel->curregs);
} }
restore_flags(flags); */ restore_flags(flags);
} }
static struct tty_operations serial_ops = { static struct tty_operations serial_ops = {
...@@ -1797,7 +1770,6 @@ static struct tty_operations serial_ops = { ...@@ -1797,7 +1770,6 @@ static struct tty_operations serial_ops = {
int __init zs_init(void) int __init zs_init(void)
{ {
int channel, i; int channel, i;
unsigned long flags;
struct dec_serial *info; struct dec_serial *info;
if(!BUS_PRESENT) if(!BUS_PRESENT)
...@@ -1809,7 +1781,6 @@ int __init zs_init(void) ...@@ -1809,7 +1781,6 @@ int __init zs_init(void)
/* Find out how many Z8530 SCCs we have */ /* Find out how many Z8530 SCCs we have */
if (zs_chain == 0) if (zs_chain == 0)
probe_sccs(); probe_sccs();
serial_driver = alloc_tty_driver(zs_channels_found); serial_driver = alloc_tty_driver(zs_channels_found);
if (!serial_driver) if (!serial_driver)
return -ENOMEM; return -ENOMEM;
...@@ -1833,39 +1804,25 @@ int __init zs_init(void) ...@@ -1833,39 +1804,25 @@ int __init zs_init(void)
tty_set_operations(serial_driver, &serial_ops); tty_set_operations(serial_driver, &serial_ops);
if (tty_register_driver(serial_driver)) if (tty_register_driver(serial_driver))
panic("Couldn't register serial driver\n"); panic("Couldn't register serial driver");
save_flags(flags); cli();
for (channel = 0; channel < zs_channels_found; ++channel) { for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
if (zs_soft[channel].hook &&
zs_soft[channel].hook->init_channel)
(*zs_soft[channel].hook->init_channel)
(&zs_soft[channel]);
zs_soft[channel].clk_divisor = 16;
zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ, /* Needed before interrupts are enabled. */
"SCC", &zs_soft[channel])) info->tty = 0;
printk(KERN_ERR "decserial: can't get irq %d\n", info->x_char = 0;
zs_parms->irq);
}
for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
{
if (info->hook && info->hook->init_info) { if (info->hook && info->hook->init_info) {
(*info->hook->init_info)(info); (*info->hook->init_info)(info);
continue; continue;
} }
info->magic = SERIAL_MAGIC; info->magic = SERIAL_MAGIC;
info->port = (int) info->zs_channel->control; info->port = (int) info->zs_channel->control;
info->line = i; info->line = i;
info->tty = 0;
info->custom_divisor = 16; info->custom_divisor = 16;
info->close_delay = 50; info->close_delay = 50;
info->closing_wait = 3000; info->closing_wait = 3000;
info->x_char = 0;
info->event = 0; info->event = 0;
info->count = 0; info->count = 0;
info->blocked_open = 0; info->blocked_open = 0;
...@@ -1873,81 +1830,70 @@ int __init zs_init(void) ...@@ -1873,81 +1830,70 @@ int __init zs_init(void)
info->tqueue.data = info; info->tqueue.data = info;
init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->close_wait);
printk("ttyS%d at 0x%08x (irq = %d)", info->line, printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
info->port, info->irq); info->line, info->port, info->irq);
printk(" is a Z85C30 SCC\n");
tty_register_device(serial_driver, info->line, NULL); 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);
/* if (zs_soft[channel].hook) {
* register_serial and unregister_serial allows for serial ports to be zs_startup(&zs_soft[channel]);
* configured at run-time, to support PCMCIA modems. if (zs_soft[channel].hook->init_channel)
*/ (*zs_soft[channel].hook->init_channel)
/* PowerMac: Unused at this time, just here to make things link. */ (&zs_soft[channel]);
int register_serial(struct serial_struct *req) }
{ }
return -1;
}
void unregister_serial(int line) return 0;
{
return;
} }
/* /*
* polling I/O routines * polling I/O routines
*/ */
static int 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; struct dec_zschannel *chan = info->zs_channel;
int ret; int ret;
if(chan) { if(chan) {
int loops = 10000; 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) while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
RECOVERY_DELAY; loops--;
if (loops) { if (loops) {
write_zsdata(chan, ch);
ret = 0; ret = 0;
*(chan->data) = ch;
wbflush();
RECOVERY_DELAY;
} else } else
ret = -EAGAIN; ret = -EAGAIN;
// write_zsreg(chan, R9, nine);
wbflush();
RECOVERY_DELAY;
return ret; return ret;
} } else
return -ENODEV; return -ENODEV;
} }
static int 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; struct dec_zschannel *chan = info->zs_channel;
int ret; int ret;
if(chan) { if(chan) {
int loops = 10000; int loops = 10000;
while((read_zsreg(chan, 0) & Rx_CH_AV) == 0) while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
loops--; loops--;
if (loops) if (loops)
...@@ -1960,7 +1906,7 @@ zs_poll_rx_char(struct dec_serial *info) ...@@ -1960,7 +1906,7 @@ zs_poll_rx_char(struct dec_serial *info)
return -ENODEV; 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]; struct dec_serial *info = &zs_soft[channel];
...@@ -1970,22 +1916,15 @@ unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook) ...@@ -1970,22 +1916,15 @@ unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
return 0; return 0;
} else { } 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_rx_char = zs_poll_rx_char;
hook->poll_tx_char = zs_poll_tx_char; hook->poll_tx_char = zs_poll_tx_char;
info->hook = hook;
return 1; return 1;
} }
} }
unsigned int unregister_zs_hook(unsigned int channel) int unregister_zs_hook(unsigned int channel)
{ {
struct dec_serial *info = &zs_soft[channel]; struct dec_serial *info = &zs_soft[channel];
...@@ -2004,7 +1943,7 @@ unsigned int unregister_zs_hook(unsigned int channel) ...@@ -2004,7 +1943,7 @@ unsigned int unregister_zs_hook(unsigned int channel)
* Serial console driver * Serial console driver
* ------------------------------------------------------------ * ------------------------------------------------------------
*/ */
#ifdef CONFIG_SERIAL_CONSOLE #ifdef CONFIG_SERIAL_DEC_CONSOLE
/* /*
...@@ -2045,6 +1984,8 @@ static int __init serial_console_setup(struct console *co, char *options) ...@@ -2045,6 +1984,8 @@ static int __init serial_console_setup(struct console *co, char *options)
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
int cflag = CREAD | HUPCL | CLOCAL; int cflag = CREAD | HUPCL | CLOCAL;
int clk_divisor = 16;
int brg;
char *s; char *s;
unsigned long flags; unsigned long flags;
...@@ -2097,6 +2038,10 @@ static int __init serial_console_setup(struct console *co, char *options) ...@@ -2097,6 +2038,10 @@ static int __init serial_console_setup(struct console *co, char *options)
case 9600: case 9600:
default: default:
cflag |= B9600; cflag |= B9600;
/*
* Set this to a sane value to prevent a divide error.
*/
baud = 9600;
break; break;
} }
switch(bits) { switch(bits) {
...@@ -2117,43 +2062,64 @@ static int __init serial_console_setup(struct console *co, char *options) ...@@ -2117,43 +2062,64 @@ static int __init serial_console_setup(struct console *co, char *options)
break; break;
} }
co->cflag = cflag; co->cflag = cflag;
#if 1
save_and_cli(flags); 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. * Turn on RTS and DTR.
*/ */
zs_rtsdtr(info, RTS | DTR, 1); zs_rtsdtr(info, RTS | DTR, 1);
/* /*
* Finally, enable sequencing * Finally, enable sequencing.
*/ */
info->zs_channel->curregs[3] |= (RxENABLE | Rx8); info->zs_channel->curregs[R3] |= RxENABLE;
info->zs_channel->curregs[5] |= (TxENAB | Tx8); info->zs_channel->curregs[R5] |= TxENAB;
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]);
/* /*
* Clear the interrupt registers. * Clear the interrupt registers.
*/ */
write_zsreg(info->zs_channel, 0, ERR_RES); write_zsreg(info->zs_channel, R0, ERR_RES);
write_zsreg(info->zs_channel, 0, RES_H_IUS); 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 */ /* 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]); zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
restore_flags(flags); restore_flags(flags);
#endif
return 0; return 0;
} }
...@@ -2173,7 +2139,7 @@ void __init zs_serial_console_init(void) ...@@ -2173,7 +2139,7 @@ void __init zs_serial_console_init(void)
{ {
register_console(&sercons); register_console(&sercons);
} }
#endif /* ifdef CONFIG_SERIAL_CONSOLE */ #endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
#ifdef CONFIG_KGDB #ifdef CONFIG_KGDB
struct dec_zschannel *zs_kgdbchan; struct dec_zschannel *zs_kgdbchan;
...@@ -2211,7 +2177,7 @@ void kgdb_interruptible(int yes) ...@@ -2211,7 +2177,7 @@ void kgdb_interruptible(int yes)
int one, nine; int one, nine;
nine = read_zsreg(chan, 9); nine = read_zsreg(chan, 9);
if (yes == 1) { if (yes == 1) {
one = EXT_INT_ENAB|INT_ALL_Rx; one = EXT_INT_ENAB|RxINT_ALL;
nine |= MIE; nine |= MIE;
printk("turning serial ints on\n"); printk("turning serial ints on\n");
} else { } else {
...@@ -2223,22 +2189,23 @@ void kgdb_interruptible(int yes) ...@@ -2223,22 +2189,23 @@ void kgdb_interruptible(int yes)
write_zsreg(chan, 9, nine); write_zsreg(chan, 9, nine);
} }
static int kgdbhook_init_channel(struct dec_serial* info) static int kgdbhook_init_channel(void *handle)
{ {
return 0; 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, static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
unsigned char ch, unsigned char stat)
{ {
struct dec_serial *info = handle;
if (fl != TTY_NORMAL)
return;
if (ch == 0x03 || ch == '$') if (ch == 0x03 || ch == '$')
breakpoint(); 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 /* 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) ...@@ -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 * for /dev/ttyb which is determined in setup_arch() from the
* boot command line flags. * boot command line flags.
*/ */
struct zs_hook zs_kgdbhook = { struct dec_serial_hook zs_kgdbhook = {
init_channel : kgdbhook_init_channel, .init_channel = kgdbhook_init_channel,
init_info : kgdbhook_init_info, .init_info = kgdbhook_init_info,
cflags : B38400|CS8|CLOCAL, .rx_char = kgdbhook_rx_char,
rx_char : kgdbhook_rx_char, .cflags = B38400 | CS8 | CLOCAL,
} }
void __init zs_kgdb_hook(int tty_num) void __init zs_kgdb_hook(int tty_num)
......
/* /*
* 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/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) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 2004 Maciej W. Rozycki
*/ */
#ifndef _DECSERIAL_H #ifndef _DECSERIAL_H
#define _DECSERIAL_H #define _DECSERIAL_H
#include <asm/dec/serial.h>
#define NUM_ZSREGS 16 #define NUM_ZSREGS 16
struct serial_struct { struct serial_struct {
...@@ -89,36 +93,23 @@ struct dec_zschannel { ...@@ -89,36 +93,23 @@ struct dec_zschannel {
unsigned char curregs[NUM_ZSREGS]; 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 {
struct dec_serial *zs_next; /* For IRQ servicing chain */ struct dec_serial *zs_next; /* For IRQ servicing chain. */
struct dec_zschannel *zs_channel; /* Channel registers */ struct dec_zschannel *zs_channel; /* Channel registers. */
struct dec_zschannel *zs_chan_a; /* A side registers */ struct dec_zschannel *zs_chan_a; /* A side registers. */
unsigned char read_reg_zero; unsigned char read_reg_zero;
char soft_carrier; /* Use soft carrier on this channel */ struct dec_serial_hook *hook; /* Hook on this channel. */
char break_abort; /* Is serial console in, so process brk/abrt */ int tty_break; /* Set on BREAK condition. */
struct zs_hook *hook; /* Hook on this channel */ int is_cons; /* Is this our console. */
char is_cons; /* Is this our console. */ int tx_active; /* Char is being xmitted. */
unsigned char tx_active; /* character is being xmitted */ int tx_stopped; /* Output is suspended. */
unsigned char tx_stopped; /* output is suspended */
/* We need to know the current clock divisor /*
* to read the bps rate the chip has currently * We need to know the current clock divisor
* loaded. * to read the bps rate the chip has currently loaded.
*/ */
unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ int clk_divisor; /* May be 1, 16, 32, or 64. */
int zs_baud; int zs_baud;
char change_needed; char change_needed;
...@@ -127,23 +118,23 @@ struct dec_serial { ...@@ -127,23 +118,23 @@ struct dec_serial {
int baud_base; int baud_base;
int port; int port;
int irq; int irq;
int flags; /* defined in tty.h */ int flags; /* Defined in tty.h. */
int type; /* UART type */ int type; /* UART type. */
struct tty_struct *tty; struct tty_struct *tty;
int read_status_mask; int read_status_mask;
int ignore_status_mask; int ignore_status_mask;
int timeout; int timeout;
int xmit_fifo_size; int xmit_fifo_size;
int custom_divisor; int custom_divisor;
int x_char; /* xon/xoff character */ int x_char; /* XON/XOFF character. */
int close_delay; int close_delay;
unsigned short closing_wait; unsigned short closing_wait;
unsigned short closing_wait2; unsigned short closing_wait2;
unsigned long event; unsigned long event;
unsigned long last_active; unsigned long last_active;
int line; int line;
int count; /* # of fd on device */ int count; /* # of fds on device. */
int blocked_open; /* # of blocked opens */ int blocked_open; /* # of blocked opens. */
unsigned char *xmit_buf; unsigned char *xmit_buf;
int xmit_head; int xmit_head;
int xmit_tail; int xmit_tail;
...@@ -219,8 +210,9 @@ struct dec_serial { ...@@ -219,8 +210,9 @@ struct dec_serial {
#define RxINT_DISAB 0 /* Rx Int Disable */ #define RxINT_DISAB 0 /* Rx Int Disable */
#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ #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 RxINT_ALL 0x10 /* Int on all Rx Characters or error */
#define INT_ERR_Rx 0x18 /* Int on error only */ #define RxINT_ERR 0x18 /* Int on error only */
#define RxINT_MASK 0x18
#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ #define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ #define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment