vserver 1.9.3
[linux-2.6.git] / drivers / serial / sn_console.c
index 98b96c5..200bbce 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/miscdevice.h>
 #include <linux/serial_core.h>
 
+#include <asm/io.h>
 #include <asm/sn/simulator.h>
 #include <asm/sn/sn2/sn_private.h>
 #include <asm/sn/sn_sal.h>
 #define DEVICE_MAJOR 204
 #define DEVICE_MINOR 40
 
+#ifdef CONFIG_MAGIC_SYSRQ
+static char sysrq_serial_str[] = "\eSYS";
+static char *sysrq_serial_ptr = sysrq_serial_str;
+static unsigned long sysrq_requested;
+#endif /* CONFIG_MAGIC_SYSRQ */
+
 /*
  * Port definition - this kinda drives it all
  */
@@ -532,13 +539,15 @@ sn_debug_printf(const char *fmt, ...)
  * sn_receive_chars - Grab characters, pass them to tty layer
  * @port: Port to operate on
  * @regs: Saved registers (needed by uart_handle_sysrq_char)
+ * @flags: irq flags
  *
  * Note: If we're not registered with the serial core infrastructure yet,
  * we don't try to send characters to it...
  *
  */
 static void
-sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs)
+sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs,
+                unsigned long flags)
 {
        int ch;
        struct tty_struct *tty;
@@ -569,10 +578,34 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs)
                               "obtaining data from the console (0x%0x)\n", ch);
                        break;
                }
-#if defined(CONFIG_SERIAL_SGI_L1_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-               if (uart_handle_sysrq_char(&port->sc_port, ch, regs))
-                       continue;
-#endif                         /* CONFIG_SERIAL_SGI_L1_CONSOLE && CONFIG_MAGIC_SYSRQ */
+#ifdef CONFIG_MAGIC_SYSRQ
+                if (sysrq_requested) {
+                        unsigned long sysrq_timeout = sysrq_requested + HZ*5;
+
+                        sysrq_requested = 0;
+                        if (ch && time_before(jiffies, sysrq_timeout)) {
+                                spin_unlock_irqrestore(&port->sc_port.lock, flags);
+                                handle_sysrq(ch, regs, NULL);
+                                spin_lock_irqsave(&port->sc_port.lock, flags);
+                                /* ignore actual sysrq command char */
+                                continue;
+                        }
+                }
+                if (ch == *sysrq_serial_ptr) {
+                        if (!(*++sysrq_serial_ptr)) {
+                                sysrq_requested = jiffies;
+                                sysrq_serial_ptr = sysrq_serial_str;
+                        }
+                       /*
+                        * ignore the whole sysrq string except for the
+                        * leading escape
+                        */
+                       if (ch != '\e')
+                               continue;
+                }
+                else
+                       sysrq_serial_ptr = sysrq_serial_str;
+#endif /* CONFIG_MAGIC_SYSRQ */
 
                /* record the character to pass up to the tty layer */
                if (tty) {
@@ -583,8 +616,6 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs)
                        if (tty->flip.count == TTY_FLIPBUF_SIZE)
                                break;
                }
-               else {
-               }
                port->sc_port.icount.rx++;
        }
 
@@ -695,7 +726,7 @@ sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        spin_lock_irqsave(&port->sc_port.lock, flags);
        if (status & SAL_CONSOLE_INTR_RECV) {
-               sn_receive_chars(port, regs);
+               sn_receive_chars(port, regs, flags);
        }
        if (status & SAL_CONSOLE_INTR_XMIT) {
                sn_transmit_chars(port, TRANSMIT_BUFFERED);
@@ -714,7 +745,8 @@ sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 static int
 sn_sal_connect_interrupt(struct sn_cons_port *port)
 {
-       if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt, SA_INTERRUPT,
+       if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
+                       SA_INTERRUPT | SA_SHIRQ,
                        "SAL console driver", port) >= 0) {
                return SGI_UART_VECTOR;
        }
@@ -743,7 +775,7 @@ sn_sal_timer_poll(unsigned long data)
 
        if (!port->sc_port.irq) {
                spin_lock_irqsave(&port->sc_port.lock, flags);
-               sn_receive_chars(port, NULL);
+               sn_receive_chars(port, NULL, flags);
                sn_transmit_chars(port, TRANSMIT_RAW);
                spin_unlock_irqrestore(&port->sc_port.lock, flags);
                mod_timer(&port->sc_timer,
@@ -851,7 +883,6 @@ sn_sal_switch_to_interrupts(struct sn_cons_port *port)
  * Kernel console definitions
  */
 
-#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
 static void sn_sal_console_write(struct console *, const char *, unsigned);
 static int __init sn_sal_console_setup(struct console *, char *);
 extern struct uart_driver sal_console_uart;
@@ -867,9 +898,6 @@ static struct console sal_console = {
 };
 
 #define SAL_CONSOLE    &sal_console
-#else
-#define SAL_CONSOLE    0
-#endif                         /* CONFIG_SERIAL_SGI_L1_CONSOLE */
 
 static struct uart_driver sal_console_uart = {
        .owner = THIS_MODULE,
@@ -895,11 +923,11 @@ sn_sal_module_init(void)
 {
        int retval;
 
-       printk(KERN_INFO "sn_console: Console driver init\n");
-
        if (!ia64_platform_is("sn2"))
                return -ENODEV;
 
+       printk(KERN_INFO "sn_console: Console driver init\n");
+
        if (USE_DYNAMIC_MINOR == 1) {
                misc.minor = MISC_DYNAMIC_MINOR;
                misc.name = DEVICE_NAME_DYNAMIC;
@@ -969,8 +997,6 @@ sn_sal_module_exit(void)
 module_init(sn_sal_module_init);
 module_exit(sn_sal_module_exit);
 
-#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
-
 /**
  * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required
  * @puts_raw : puts function to do the writing
@@ -1085,7 +1111,9 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
                        spin_unlock_irqrestore(&port->sc_port.lock, flags);
 
                        puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
                }
+#endif
        }
        else {
                /* Not yet registered with serial core - simple case */
@@ -1190,5 +1218,3 @@ sn_sal_serial_console_init(void)
 }
 
 console_initcall(sn_sal_serial_console_init);
-
-#endif                         /* CONFIG_SERIAL_SGI_L1_CONSOLE */