patch-2.3.43 linux/arch/ia64/kdb/kdb_io.c
Next file: linux/arch/ia64/kdb/kdb_traps.c
Previous file: linux/arch/ia64/kdb/kdb_bt.c
Back to the patch index
Back to the overall index
- Lines: 351
- Date:
Tue Feb 8 12:01:59 2000
- Orig file:
v2.3.42/linux/arch/ia64/kdb/kdb_io.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kdb/kdb_io.c linux/arch/ia64/kdb/kdb_io.c
@@ -0,0 +1,350 @@
+/*
+ * Kernel Debugger Console I/O handler
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Scott Lurndal (slurn@engr.sgi.com)
+ * Copyright (C) Scott Foehner (sfoehner@engr.sgi.com)
+ * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
+ *
+ * Written March 1999 by Scott Lurndal at Silicon Graphics, Inc.
+ *
+ * Modifications from:
+ * Chuck Fleckenstein 1999/07/20
+ * Move kdb_info struct declaration to this file
+ * for cases where serial support is not compiled into
+ * the kernel.
+ *
+ * Masahiro Adegawa 1999/07/20
+ * Handle some peculiarities of japanese 86/106
+ * keyboards.
+ *
+ * marc@mucom.co.il 1999/07/20
+ * Catch buffer overflow for serial input.
+ *
+ * Scott Foehner
+ * Port to ia64
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/serial_reg.h>
+#include <linux/spinlock.h>
+
+#include <asm/io.h>
+
+#include "pc_keyb.h"
+
+int kdb_port = 0;
+
+/*
+ * This module contains code to read characters from the keyboard or a serial
+ * port.
+ *
+ * It is used by the kernel debugger, and is polled, not interrupt driven.
+ *
+ */
+
+/*
+ * send: Send a byte to the keyboard controller. Used primarily to
+ * alter LED settings.
+ */
+
+static void
+kdb_kbdsend(unsigned char byte)
+{
+ while (inb(KBD_STATUS_REG) & KBD_STAT_IBF)
+ ;
+ outb(KBD_DATA_REG, byte);
+}
+
+static void
+kdb_kbdsetled(int leds)
+{
+ kdb_kbdsend(KBD_CMD_SET_LEDS);
+ kdb_kbdsend((unsigned char)leds);
+}
+
+static void
+console_read (char *buffer, size_t bufsize)
+{
+ struct console *in;
+ struct console *out;
+ char *cp, ch;
+
+ for (in = console_drivers; in; in = in->next) {
+ if ((in->flags & CON_ENABLED) && (in->read || in->wait_key))
+ break;
+ }
+ for (out = console_drivers; out; out = out->next) {
+ if ((out->flags & CON_ENABLED) && out->write)
+ break;
+ }
+
+ if ((!in->read && !in->wait_key) || !out->write) {
+ panic("kdb_io: can't do console i/o!");
+ }
+
+ if (in->read) {
+ /* this is untested... */
+ (*in->read)(in, buffer, bufsize);
+ return;
+ }
+
+ bufsize -= 2; /* leave room for CR & NUL terminator */
+ cp = buffer;
+ while (1) {
+ ch = (*in->wait_key)(in);
+ switch (ch) {
+ case '\b':
+ if (cp > buffer) {
+ --cp, ++bufsize;
+ (*out->write)(out, "\b \b", 3);
+ }
+ break;
+
+ case '\025':
+ while (cp > buffer) {
+ --cp, ++bufsize;
+ (*out->write)(out, "\b \b", 3);
+ }
+ break;
+
+ case '\r':
+ case '\n':
+ (*out->write)(out, "\r\n", 2);
+ *cp++ = '\n';
+ *cp++ = '\0';
+ return;
+
+ default:
+ if (bufsize > 0) {
+ (*out->write)(out, &ch, 1);
+ --bufsize;
+ *cp++ = ch;
+ }
+ break;
+ }
+ }
+}
+
+char *
+kdb_getscancode(char *buffer, size_t bufsize)
+{
+ /*
+ * XXX Shouldn't kdb _always_ use console based I/O? That's what the console
+ * abstraction is for, after all... ---davidm
+ */
+#ifdef CONFIG_IA64_HP_SIM
+ extern spinlock_t console_lock;
+ unsigned long flags;
+
+ spin_lock_irqsave(&console_lock, flags);
+ console_read(buffer, bufsize);
+ spin_unlock_irqrestore(&console_lock, flags);
+ return buffer;
+#else /* !CONFIG_IA64_HP_SIM */
+ char *cp = buffer;
+ int scancode, scanstatus;
+ static int shift_lock = 0; /* CAPS LOCK state (0-off, 1-on) */
+ static int shift_key = 0; /* Shift next keypress */
+ static int ctrl_key = 0;
+ static int leds = 2; /* Num lock */
+ u_short keychar;
+ extern u_short plain_map[], shift_map[], ctrl_map[];
+
+ bufsize -= 2; /* Reserve space for newline and null byte */
+
+ /*
+ * If we came in via a serial console, we allow that to
+ * be the input window for kdb.
+ */
+ if (kdb_port != 0) {
+ char ch;
+ int status;
+#define serial_inp(info, offset) inb((info) + (offset))
+#define serial_out(info, offset, v) outb((v), (info) + (offset))
+
+ while(1) {
+ while ((status = serial_inp(kdb_port, UART_LSR))
+ & UART_LSR_DR) {
+readchar:
+ ch = serial_inp(kdb_port, UART_RX);
+ if (ch == 8) { /* BS */
+ if (cp > buffer) {
+ --cp, bufsize++;
+ printk("%c %c", 0x08, 0x08);
+ }
+ continue;
+ }
+ serial_out(kdb_port, UART_TX, ch);
+ if (ch == 13) { /* CR */
+ *cp++ = '\n';
+ *cp++ = '\0';
+ serial_out(kdb_port, UART_TX, 10);
+ return(buffer);
+ }
+ /*
+ * Discard excess characters
+ */
+ if (bufsize > 0) {
+ *cp++ = ch;
+ bufsize--;
+ }
+ }
+ while (((status = serial_inp(kdb_port, UART_LSR))
+ & UART_LSR_DR) == 0);
+ }
+ }
+
+ while (1) {
+
+ /*
+ * Wait for a valid scancode
+ */
+
+ while ((inb(KBD_STATUS_REG) & KBD_STAT_OBF) == 0)
+ ;
+
+ /*
+ * Fetch the scancode
+ */
+ scancode = inb(KBD_DATA_REG);
+ scanstatus = inb(KBD_STATUS_REG);
+
+ /*
+ * Ignore mouse events.
+ */
+ if (scanstatus & KBD_STAT_MOUSE_OBF)
+ continue;
+
+ /*
+ * Ignore release, trigger on make
+ * (except for shift keys, where we want to
+ * keep the shift state so long as the key is
+ * held down).
+ */
+
+ if (((scancode&0x7f) == 0x2a)
+ || ((scancode&0x7f) == 0x36)) {
+ /*
+ * Next key may use shift table
+ */
+ if ((scancode & 0x80) == 0) {
+ shift_key=1;
+ } else {
+ shift_key=0;
+ }
+ continue;
+ }
+
+ if ((scancode&0x7f) == 0x1d) {
+ /*
+ * Left ctrl key
+ */
+ if ((scancode & 0x80) == 0) {
+ ctrl_key = 1;
+ } else {
+ ctrl_key = 0;
+ }
+ continue;
+ }
+
+ if ((scancode & 0x80) != 0)
+ continue;
+
+ scancode &= 0x7f;
+
+ /*
+ * Translate scancode
+ */
+
+ if (scancode == 0x3a) {
+ /*
+ * Toggle caps lock
+ */
+ shift_lock ^= 1;
+ leds ^= 0x4; /* toggle caps lock led */
+
+ kdb_kbdsetled(leds);
+ continue;
+ }
+
+ if (scancode == 0x0e) {
+ /*
+ * Backspace
+ */
+ if (cp > buffer) {
+ --cp, bufsize++;
+
+ /*
+ * XXX - erase character on screen
+ */
+ printk("%c %c", 0x08, 0x08);
+ }
+ continue;
+ }
+
+ if (scancode == 0xe0) {
+ continue;
+ }
+
+ /*
+ * For Japanese 86/106 keyboards
+ * See comment in drivers/char/pc_keyb.c.
+ * - Masahiro Adegawa
+ */
+ if (scancode == 0x73) {
+ scancode = 0x59;
+ } else if (scancode == 0x7d) {
+ scancode = 0x7c;
+ }
+
+ if (!shift_lock && !shift_key) {
+ keychar = plain_map[scancode];
+ } else if (shift_lock || shift_key) {
+ keychar = shift_map[scancode];
+ } else if (ctrl_key) {
+ keychar = ctrl_map[scancode];
+ } else {
+ keychar = 0x0020;
+ printk("Unknown state/scancode (%d)\n", scancode);
+ }
+
+ if ((scancode & 0x7f) == 0x1c) {
+ /*
+ * enter key. All done.
+ */
+ printk("\n");
+ break;
+ }
+
+ /*
+ * echo the character.
+ */
+ printk("%c", keychar&0xff);
+
+ if (bufsize) {
+ --bufsize;
+ *cp++ = keychar&0xff;
+ } else {
+ printk("buffer overflow\n");
+ break;
+ }
+
+ }
+
+ *cp++ = '\n'; /* White space for parser */
+ *cp++ = '\0'; /* String termination */
+
+#if defined(NOTNOW)
+ cp = buffer;
+ while (*cp) {
+ printk("char 0x%x\n", *cp++);
+ }
+#endif
+
+ return buffer;
+#endif /* !CONFIG_IA64_HP_SIM */
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)