diff -urN a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt 2010-02-25 03:52:17.000000000 +0900 +++ b/Documentation/kernel-parameters.txt 2010-04-10 12:24:29.000000000 +0900 @@ -899,9 +899,6 @@ controller i8042.nopnp [HW] Don't use ACPIPnP / PnPBIOS to discover KBD/AUX controllers - i8042.panicblink= - [HW] Frequency with which keyboard LEDs should blink - when kernel panics (default is 0.5 sec) i8042.reset [HW] Reset the controller during init and cleanup i8042.unlock [HW] Unlock (ignore) the keylock @@ -1825,6 +1822,21 @@ panic= [KNL] Kernel behaviour on panic Format: + panicmorse= [HW] Select the signal type and enable/disable the + morse output devices of choice when kernel panics + panicmorse=0: disable the signalling completely + panicmorse=1: only blink the leds + panicmorse=2: only beep + panicmorse=3: do both + panicmorse=4: disable the signalling completely + (bitflag to simplify signal "TTT...") + panicmorse=5: only blink the leds with simplified + signal (the default) + panicmorse=6: only beep with simplified signal + panicmorse=7: do both with simplified signal + panicmorse_wpm= [HW] The speed of morse code (default is 12 wpm) + panicmorse_hz= [HW] The frequency of beep sound (default is 600 Hz) + parkbd.port= [HW] Parallel port number the keyboard adapter is connected to, default is 0. Format: diff -urN a/arch/arm/mach-s3c2442/mach-gta02.c b/arch/arm/mach-s3c2442/mach-gta02.c --- a/arch/arm/mach-s3c2442/mach-gta02.c 2010-02-25 03:52:17.000000000 +0900 +++ b/arch/arm/mach-s3c2442/mach-gta02.c 2010-04-10 12:24:29.000000000 +0900 @@ -90,24 +90,17 @@ static struct pcf50633 *gta02_pcf; /* - * This gets called every 1ms when we paniced. + * This gets called frequently when we paniced. */ -static long gta02_panic_blink(long count) +static long gta02_panic_blink(int state) { long delay = 0; - static long last_blink; - static char led; + char led; - /* Fast blink: 200ms period. */ - if (count - last_blink < 100) - return 0; - - led ^= 1; + led = (state) ? 1 : 0; gpio_direction_output(GTA02_GPIO_AUX_LED, led); - last_blink = count; - return delay; } @@ -614,7 +607,7 @@ static void __init gta02_machine_init(void) { - /* Set the panic callback to make AUX LED blink at ~5Hz. */ + /* Set the panic callback to turn AUX LED on or off. */ panic_blink = gta02_panic_blink; s3c_pm_init(); diff -urN a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c --- a/drivers/input/misc/pcspkr.c 2010-02-25 03:52:17.000000000 +0900 +++ b/drivers/input/misc/pcspkr.c 2010-04-10 12:24:29.000000000 +0900 @@ -70,6 +70,34 @@ return 0; } +/* + * pcspkr_panic_beep() will beep the PC speaker on or off and is called + * when kernel panics. Beeping a speaker is useful for users running X + * who may not see the console and will help distingushing panics from + * "real" lockups. + */ + +static void pcspkr_panic_beep(int value) +{ + unsigned int count = 0; + + if (value > 20 && value < 32767) + count = PIT_TICK_RATE / value; + + if (count) { + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, 0x43); + /* select desired HZ */ + outb_p(count & 0xff, 0x42); + outb((count >> 8) & 0xff, 0x42); + /* enable counter 2 */ + outb_p(inb_p(0x61) | 3, 0x61); + } else { + /* disable counter 2 */ + outb(inb_p(0x61) & 0xFC, 0x61); + } +} + static int __devinit pcspkr_probe(struct platform_device *dev) { struct input_dev *pcspkr_dev; @@ -145,12 +173,16 @@ static int __init pcspkr_init(void) { + panic_beep = pcspkr_panic_beep; + return platform_driver_register(&pcspkr_platform_driver); } static void __exit pcspkr_exit(void) { platform_driver_unregister(&pcspkr_platform_driver); + + panic_beep = NULL; } module_init(pcspkr_init); diff -urN a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c --- a/drivers/input/serio/i8042.c 2010-02-25 03:52:17.000000000 +0900 +++ b/drivers/input/serio/i8042.c 2010-04-10 12:24:29.000000000 +0900 @@ -60,10 +60,6 @@ module_param_named(noloop, i8042_noloop, bool, 0); MODULE_PARM_DESC(noloop, "Disable the AUX Loopback command while probing for the AUX port"); -static unsigned int i8042_blink_frequency = 500; -module_param_named(panicblink, i8042_blink_frequency, uint, 0600); -MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics"); - #ifdef CONFIG_X86 static bool i8042_dritek; module_param_named(dritek, i8042_dritek, bool, 0); @@ -1031,8 +1027,8 @@ /* - * i8042_panic_blink() will flash the keyboard LEDs and is called when - * kernel panics. Flashing LEDs is useful for users running X who may + * i8042_panic_blink() will turn the keyboard LEDs on or off and is called + * when kernel panics. Flashing LEDs is useful for users running X who may * not see the console and will help distingushing panics from "real" * lockups. * @@ -1042,22 +1038,12 @@ #define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0) -static long i8042_panic_blink(long count) +static long i8042_panic_blink(int state) { long delay = 0; - static long last_blink; - static char led; - - /* - * We expect frequency to be about 1/2s. KDB uses about 1s. - * Make sure they are different. - */ - if (!i8042_blink_frequency) - return 0; - if (count - last_blink < i8042_blink_frequency) - return 0; + char led; - led ^= 0x01 | 0x04; + led = (state) ? 0x01 | 0x04 : 0; while (i8042_read_status() & I8042_STR_IBF) DELAY; dbg("%02x -> i8042 (panic blink)", 0xed); @@ -1070,7 +1056,6 @@ dbg("%02x -> i8042 (panic blink)", led); i8042_write_data(led); DELAY; - last_blink = count; return delay; } diff -urN a/include/linux/kernel.h b/include/linux/kernel.h --- a/include/linux/kernel.h 2010-02-25 03:52:17.000000000 +0900 +++ b/include/linux/kernel.h 2010-04-10 12:24:29.000000000 +0900 @@ -159,7 +159,8 @@ #endif extern struct atomic_notifier_head panic_notifier_list; -extern long (*panic_blink)(long time); +extern void (*panic_beep)(int value); +extern long (*panic_blink)(int state); NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))) __cold; extern void oops_enter(void); diff -urN a/include/linux/morseops.h b/include/linux/morseops.h --- a/include/linux/morseops.h 1970-01-01 09:00:00.000000000 +0900 +++ b/include/linux/morseops.h 2010-04-10 12:24:29.000000000 +0900 @@ -0,0 +1,17 @@ +/* Yes, it's morse code ops indeed. */ + +#ifndef _LINUX_MORSEOPS_H +#define _LINUX_MORSEOPS_H + +#include + +extern const unsigned char morsetable[]; /* in kernel/morse.c */ +long panic_morseblink(long count, char *buf); /* in kernel/morse.c */ + +static inline unsigned char tomorse(char c) +{ + c = toupper(c); + return (c >= '!' && c <= '_') ? morsetable[c - '!'] : 0; +} + +#endif /* _LINUX_MORSEOPS_H */ diff -urN a/kernel/Makefile b/kernel/Makefile --- a/kernel/Makefile 2010-02-25 03:52:17.000000000 +0900 +++ b/kernel/Makefile 2010-04-10 12:24:29.000000000 +0900 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y = sched.o fork.o exec_domain.o panic.o printk.o \ +obj-y = sched.o fork.o exec_domain.o panic.o morse.o printk.o \ cpu.o exit.o itimer.o time.o softirq.o resource.o \ sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \ signal.o sys.o kmod.o workqueue.o pid.o \ diff -urN a/kernel/morse.c b/kernel/morse.c --- a/kernel/morse.c 1970-01-01 09:00:00.000000000 +0900 +++ b/kernel/morse.c 2010-04-10 12:24:29.000000000 +0900 @@ -0,0 +1,301 @@ +/* + * kernel/morse.c + * + * Copyright (C) 2002 Andrew Rodland + * Copyright (C) 2003, 2009 Tomas Szepe + * Copyright (C) 2010 TAMUKI Shoichi + * + * Tell the user who may be running in X and not see the console that + * we have panic'd. This is to distingush panics from "real lockups." + * Could in theory send the panic message as morse, but that is left + * as an exercise for the reader. + * + * And now it's done! LED and speaker morse code by Andrew Rodland + * , with improvements based on suggestions from + * linux@horizon.com and a host of others. + * + * Initial 2.5 morsepanics port and cleanup by + * Tomas Szepe , January 2003. + * + * Cryptic morse code table replaced with meticulous macrowork by + * Jan-Benedict Glaw , February 2003. + * + * Updated for 2.6.29-rc1 by + * Tomas Szepe , January 2009. + * + * Several morse codes fixed and tunable speed/freq. implemented by + * TAMUKI Shoichi , May 2010. + */ + +#include +#include +#include + +#define MORSE_OUTPUT_BLINK (1 << 0) +#define MORSE_OUTPUT_BLEEP (1 << 1) +#define MORSE_OUTPUT_ESTRADE (MORSE_OUTPUT_BLINK | MORSE_OUTPUT_BLEEP) +#define MORSE_OUTPUT_SIMPLE (1 << 2) + +static int morse_setting = MORSE_OUTPUT_BLINK | MORSE_OUTPUT_SIMPLE; +static int morse_wpm_setting = 12; +static int morse_hz_setting = 600; + +/* The following macros are used to make up the morse code table. */ + +#define IS_DASH(letter, shift) \ + ((letter) == '-' ? (1 << (shift)) : (0 << (shift))) +#define MORSE(shift, b1, b2, b3, b4, b5, b6, b7) \ + (1 << (shift) | IS_DASH((b1), 6) | IS_DASH((b2), 5) \ + | IS_DASH((b3), 4) | IS_DASH((b4), 3) \ + | IS_DASH((b5), 2) | IS_DASH((b6), 1) \ + | IS_DASH((b7), 0)) +#define MORSE0(letter) \ + (0) +#define MORSE1(letter, b1) \ + MORSE(1, '.', '.', '.', '.', '.', '.', (b1)) +#define MORSE2(letter, b1, b2) \ + MORSE(2, '.', '.', '.', '.', '.', (b2), (b1)) +#define MORSE3(letter, b1, b2, b3) \ + MORSE(3, '.', '.', '.', '.', (b3), (b2), (b1)) +#define MORSE4(letter, b1, b2, b3, b4) \ + MORSE(4, '.', '.', '.', (b4), (b3), (b2), (b1)) +#define MORSE5(letter, b1, b2, b3, b4, b5) \ + MORSE(5, '.', '.', (b5), (b4), (b3), (b2), (b1)) +#define MORSE6(letter, b1, b2, b3, b4, b5, b6) \ + MORSE(6, '.', (b6), (b5), (b4), (b3), (b2), (b1)) +#define MORSE7(letter, b1, b2, b3, b4, b5, b6, b7) \ + MORSE(7, (b7), (b6), (b5), (b4), (b3), (b2), (b1)) + +/* Do not shuffle things about in here, the order matters. */ +const unsigned char morsetable[] = { + + /* 0165, 0122, 0, 0310, 0, 042, 0136, !"#$%&' */ + MORSE6('!', '-', '.', '-', '.', '-', '-'), + MORSE6('"', '.', '-', '.', '.', '-', '.'), + MORSE0('#'), + MORSE7('$', '.', '.', '.', '-', '.', '.', '-'), + MORSE0('%'), + MORSE5('&', '.', '-', '.', '.', '.'), + MORSE6('\'', '.', '-', '-', '-', '-', '.'), + + /* 055, 0155, 0, 052, 0163, 0141, 0152, 051, ()*+,-./ */ + MORSE5('(', '-', '.', '-', '-', '.'), + MORSE6(')', '-', '.', '-', '-', '.', '-'), + MORSE0('*'), + MORSE5('+', '.', '-', '.', '-', '.'), + MORSE6(',', '-', '-', '.', '.', '-', '-'), + MORSE6('-', '-', '.', '.', '.', '.', '-'), + MORSE6('.', '.', '-', '.', '-', '.', '-'), + MORSE5('/', '-', '.', '.', '-', '.'), + + /* 077, 076, 074, 070, 060, 040, 041, 043, 047, 057, 0-9 */ + MORSE5('0', '-', '-', '-', '-', '-'), + MORSE5('1', '.', '-', '-', '-', '-'), + MORSE5('2', '.', '.', '-', '-', '-'), + MORSE5('3', '.', '.', '.', '-', '-'), + MORSE5('4', '.', '.', '.', '.', '-'), + MORSE5('5', '.', '.', '.', '.', '.'), + MORSE5('6', '-', '.', '.', '.', '.'), + MORSE5('7', '-', '-', '.', '.', '.'), + MORSE5('8', '-', '-', '-', '.', '.'), + MORSE5('9', '-', '-', '-', '-', '.'), + + /* 0107, 0125, 0, 061, 0, 0114, 0126, :;<=>?@ */ + MORSE6(':', '-', '-', '-', '.', '.', '.'), + MORSE6(';', '-', '.', '-', '.', '-', '.'), + MORSE0('<'), + MORSE5('=', '-', '.', '.', '.', '-'), + MORSE0('>'), + MORSE6('?', '.', '.', '-', '-', '.', '.'), + MORSE6('@', '.', '-', '-', '.', '-', '.'), + + /* 006, 021, 025, 011, 002, 024, 013, 020, 004, A-I */ + MORSE2('A', '.', '-'), + MORSE4('B', '-', '.', '.', '.'), + MORSE4('C', '-', '.', '-', '.'), + MORSE3('D', '-', '.', '.'), + MORSE1('E', '.'), + MORSE4('F', '.', '.', '-', '.'), + MORSE3('G', '-', '-', '.'), + MORSE4('H', '.', '.', '.', '.'), + MORSE2('I', '.', '.'), + + /* 036, 015, 022, 007, 005, 017, 026, 033, 012, J-R */ + MORSE4('J', '.', '-', '-', '-'), + MORSE3('K', '-', '.', '-'), + MORSE4('L', '.', '-', '.', '.'), + MORSE2('M', '-', '-'), + MORSE2('N', '-', '.'), + MORSE3('O', '-', '-', '-'), + MORSE4('P', '.', '-', '-', '.'), + MORSE4('Q', '-', '-', '.', '-'), + MORSE3('R', '.', '-', '.'), + + /* 010, 003, 014, 030, 016, 031, 035, 023, S-Z */ + MORSE3('S', '.', '.', '.'), + MORSE1('T', '-'), + MORSE3('U', '.', '.', '-'), + MORSE4('V', '.', '.', '.', '-'), + MORSE3('W', '.', '-', '-'), + MORSE4('X', '-', '.', '.', '-'), + MORSE4('Y', '-', '.', '-', '-'), + MORSE4('Z', '-', '-', '.', '.'), + + /* 0, 0, 0, 0, 0154 [\]^_ */ + MORSE0('['), + MORSE0('\\'), + MORSE0(']'), + MORSE0('^'), + MORSE6('_', '.', '.', '-', '-', '.', '-'), +}; + +static void no_beep(int value) +{ +} + +void (*panic_beep)(int value); +EXPORT_SYMBOL(panic_beep); + +static long no_blink(int state) +{ + return 0; +} + +/* Returns how long it waited in ms */ +long (*panic_blink)(int state); +EXPORT_SYMBOL(panic_blink); + +long panic_morseblink(long count, char *buf) +{ + long delay = 0; + static long next_count = 0; + static char *bufpos = 0; + static unsigned char morse = 0; + static char state = 1; + int ditlen, dahlen, spacelen, freq; + + if (!(morse_setting & MORSE_OUTPUT_ESTRADE)) + return 0; + + if (morse_wpm_setting <= 0 || morse_wpm_setting > 100) + morse_wpm_setting = 12; + ditlen = 1200 / morse_wpm_setting; + dahlen = 3 * ditlen; + spacelen = 7 * ditlen; + + if (morse_hz_setting < 50 || morse_hz_setting > 10000) + morse_hz_setting = 600; + freq = morse_hz_setting; + + if (morse_setting & MORSE_OUTPUT_SIMPLE) + buf = "TTT"; + else if (!buf) + buf = "Uh oh, we lost the panic msg."; + + /* Waiting for something? */ + if (bufpos && count - next_count < 0) + return 0; + + if (!panic_beep) + panic_beep = no_beep; + + if (!panic_blink) + panic_blink = no_blink; + + if (state) { /* Coming off of a blink. */ + if (morse_setting & MORSE_OUTPUT_BLEEP) + panic_beep(0); + + if (morse_setting & MORSE_OUTPUT_BLINK) + delay += panic_blink(0); + + state = 0; + + if (morse > 1) { + /* Not done yet, just a one-dit pause. */ + next_count = count + ditlen; + } else { + /* Get a new char, figure out how much space. */ + + /* First time through. */ + if (!bufpos) + bufpos = buf; + + if (!*bufpos) { + /* Repeating. */ + bufpos = buf; + if (morse_setting & MORSE_OUTPUT_SIMPLE) + next_count = count + dahlen; + else + next_count = count + spacelen; + } else { + /* Inter-letter space. */ + next_count = count + dahlen; + } + + if (!(morse = tomorse(*bufpos))) { + next_count = count + spacelen; + state = 1; /* And get us back here. */ + } + bufpos++; + } + } else { + /* Starting a new blink. We have a valid code in morse. */ + int len; + + len = (morse & 0x01) ? dahlen : ditlen; + + if (morse_setting & MORSE_OUTPUT_BLEEP) + panic_beep(freq); + + if (morse_setting & MORSE_OUTPUT_BLINK) + delay += panic_blink(1); + + next_count = count + len; + + state = 1; + morse >>= 1; + } + return delay; +} + +static int __init panicmorse_setup(char *str) +{ + int par; + + if (get_option(&str, &par)) + morse_setting = par; + + return 1; +} + +static int __init panicmorse_wpm_setup(char *str) +{ + int par; + + if (get_option(&str, &par)) + morse_wpm_setting = par; + + return 1; +} + +static int __init panicmorse_hz_setup(char *str) +{ + int par; + + if (get_option(&str, &par)) + morse_hz_setting = par; + + return 1; +} + +/* "panicmorse=0" or "panicmorse=4" disables the blinking as it + * caused problems with certain console switches. + * + * "panicmorse | 1" does the show using kbd leds. + * "panicmorse | 2" throws in bleeping via panic_beep(). + * "panicmorse | 4" switches to simplified signal "TTT..." + */ +__setup("panicmorse=", panicmorse_setup); +__setup("panicmorse_wpm=", panicmorse_wpm_setup); +__setup("panicmorse_hz=", panicmorse_hz_setup); diff -urN a/kernel/panic.c b/kernel/panic.c --- a/kernel/panic.c 2010-02-25 03:52:17.000000000 +0900 +++ b/kernel/panic.c 2010-04-10 12:24:29.000000000 +0900 @@ -23,6 +23,7 @@ #include #include #include +#include int panic_on_oops; static unsigned long tainted_mask; @@ -36,15 +37,6 @@ EXPORT_SYMBOL(panic_notifier_list); -static long no_blink(long time) -{ - return 0; -} - -/* Returns how long it waited in ms */ -long (*panic_blink)(long time); -EXPORT_SYMBOL(panic_blink); - /** * panic - halt the system * @fmt: The text string to print @@ -95,9 +87,6 @@ bust_spinlocks(0); - if (!panic_blink) - panic_blink = no_blink; - if (panic_timeout > 0) { /* * Delay timeout seconds before rebooting the machine. @@ -107,7 +96,7 @@ for (i = 0; i < panic_timeout*1000; ) { touch_nmi_watchdog(); - i += panic_blink(i); + i += panic_morseblink(i, buf); mdelay(1); i++; } @@ -137,7 +126,7 @@ local_irq_enable(); for (i = 0; ; ) { touch_softlockup_watchdog(); - i += panic_blink(i); + i += panic_morseblink(i, buf); mdelay(1); i++; }