diff -urN a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt 2010-05-19 07:22:27.000000000 +0900 +++ b/Documentation/kernel-parameters.txt 2010-05-19 07:22:27.000000000 +0900 @@ -1831,9 +1831,15 @@ panic= [KNL] Kernel behaviour on panic Format: + panic_output= [KNL] Enable/disable the output devices of choice + panic_output=0: disable the signalling completely + panic_output=1: only blink the leds (the default) + panic_output=2: only beep + panic_output=3: do both panicblink= [KNL] The speed of panic blink (range is 1 to 100, the lower the slower, the higher the faster, default is 12) Should be 5 or less when running under a hypervisor + panicbeep= [KNL] The frequency of beep sound (default is 600 Hz) parkbd.port= [HW] Parallel port number the keyboard adapter is connected to, default is 0. diff -urN a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c --- a/drivers/input/misc/pcspkr.c 2010-05-17 06:17:36.000000000 +0900 +++ b/drivers/input/misc/pcspkr.c 2010-05-19 07:22:27.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/include/linux/kernel.h b/include/linux/kernel.h --- a/include/linux/kernel.h 2010-05-19 07:22:27.000000000 +0900 +++ b/include/linux/kernel.h 2010-05-19 07:22:27.000000000 +0900 @@ -171,6 +171,7 @@ extern struct atomic_notifier_head panic_notifier_list; extern long (*panic_blink)(int state); +extern void (*panic_beep)(int value); NORET_TYPE void panic(const char * fmt, ...) __attribute__ ((NORET_AND format (printf, 1, 2))) __cold; extern void oops_enter(void); diff -urN a/kernel/panic.c b/kernel/panic.c --- a/kernel/panic.c 2010-05-19 07:22:27.000000000 +0900 +++ b/kernel/panic.c 2010-05-19 07:22:27.000000000 +0900 @@ -24,6 +24,10 @@ #include #include +#define PANIC_OUTPUT_BLINK (1 << 0) +#define PANIC_OUTPUT_BLEEP (1 << 1) +#define PANIC_OUTPUT_ESTRADE (PANIC_OUTPUT_BLINK | PANIC_OUTPUT_BLEEP) + int panic_on_oops; static unsigned long tainted_mask; static int pause_on_oops; @@ -31,7 +35,9 @@ static DEFINE_SPINLOCK(pause_on_oops_lock); int panic_timeout; +static int panic_output = PANIC_OUTPUT_BLINK; static int panic_blink_wpm = 12; +static int panic_beep_hz = 600; ATOMIC_NOTIFIER_HEAD(panic_notifier_list); @@ -46,6 +52,13 @@ long (*panic_blink)(int state); EXPORT_SYMBOL(panic_blink); +static void no_beep(int value) +{ +} + +void (*panic_beep)(int value); +EXPORT_SYMBOL(panic_beep); + static long panic_blink_enter(long count) { int len; @@ -54,16 +67,24 @@ static int first = 1; static long next_count; + if (!(panic_output & PANIC_OUTPUT_ESTRADE)) + return 0; len = 3600 / panic_blink_wpm; if (!first && count - next_count < 0) return 0; if (state) { - delay += panic_blink(0); + if (panic_output & PANIC_OUTPUT_BLINK) + delay += panic_blink(0); + if (panic_output & PANIC_OUTPUT_BLEEP) + panic_beep(0); state = 0; if (first) first = 0; } else { - delay += panic_blink(1); + if (panic_output & PANIC_OUTPUT_BLINK) + delay += panic_blink(1); + if (panic_output & PANIC_OUTPUT_BLEEP) + panic_beep(panic_beep_hz); state = 1; } next_count = count + len; @@ -122,9 +143,12 @@ bust_spinlocks(0); panic_blink_wpm = clamp(panic_blink_wpm, 1, 100); + panic_beep_hz = clamp(panic_beep_hz, 50, 10000); if (!panic_blink) panic_blink = no_blink; + if (!panic_beep) + panic_beep = no_beep; /* * When running under a hypervisor a small mdelay may get @@ -441,5 +465,13 @@ #endif core_param(panic, panic_timeout, int, 0644); +/* "panic_output=0" disables the blinking as it caused problems with + * certain console switches. + * + * "panic_output | 1" does the show using kbd leds. + * "panic_output | 2" throws in bleeping via panic_beep(). + */ +core_param(panic_output, panic_output, int, 0644); core_param(panicblink, panic_blink_wpm, int, 0644); +core_param(panicbeep, panic_beep_hz, int, 0644); core_param(pause_on_oops, pause_on_oops, int, 0644);