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 @@
* 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
......@@ -27,25 +51,29 @@
*/
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");
}
}
......@@ -2,52 +2,124 @@
* 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];
......@@ -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);
......@@ -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
......@@ -65,18 +64,15 @@
#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 @@ static int set_serial_info(struct dec_serial * info,
* 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)
......
/*
* 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 */
......
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