Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c
new file mode 100644
index 0000000..cf10d5c
--- /dev/null
+++ b/drivers/tc/lk201.c
@@ -0,0 +1,441 @@
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * 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 <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 "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
+/*
+ * Actually no translation at all, at least until we figure out
+ * how to define SysRq for LK201 and friends. --macro
+ */
+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(void *);
+static void __init lk201_info(void *);
+static void lk201_rx_char(unsigned char, unsigned char);
+
+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_SET_DEFAULTS,
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 3),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 4),
+	LK_CMD_MODE(LK_MODE_DOWN_UP, 5),
+	LK_CMD_MODE(LK_MODE_DOWN_UP, 6),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 7),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 8),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 9),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 10),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 11),
+	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_DIS_KEYCLK,
+	LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
+};
+
+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;
+
+	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)
+{
+	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)
+{
+	return -EINVAL;
+}
+
+int kbd_getkeycode(unsigned int scancode)
+{
+	return -EINVAL;
+}
+
+int kbd_translate(unsigned char scancode, unsigned char *keycode,
+		  char raw_mode)
+{
+	*keycode = scancode;
+	return 1;
+}
+
+char kbd_unexpected_up(unsigned char keycode)
+{
+	return 0x80;
+}
+
+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 (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) {
+	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(void *handle)
+{
+}
+
+static int __init lk201_init(void *handle)
+{
+	/* First install handlers. */
+	lk201_handle = handle;
+	kbd_rate = lk201_kbd_rate;
+	kd_mksound = lk201_kd_mksound;
+
+	lk201_hook.rx_char = lk201_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)
+{
+	/* 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(KERN_ERR "lk201: support for DZ11 not yet ready.\n");
+	}
+}