1/*
2 * linux/atari/atakeyb.c
3 *
4 * Atari Keyboard driver for 680x0 Linux
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License.  See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11/*
12 * Atari support by Robert de Vries
13 * enhanced by Bjoern Brauel and Roman Hodek
14 */
15
16#include <linux/sched.h>
17#include <linux/kernel.h>
18#include <linux/interrupt.h>
19#include <linux/errno.h>
20#include <linux/keyboard.h>
21#include <linux/delay.h>
22#include <linux/timer.h>
23#include <linux/kd.h>
24#include <linux/random.h>
25#include <linux/init.h>
26#include <linux/kbd_kern.h>
27
28#include <asm/atariints.h>
29#include <asm/atarihw.h>
30#include <asm/atarikb.h>
31#include <asm/atari_joystick.h>
32#include <asm/irq.h>
33
34static void atakeyb_rep(unsigned long ignore);
35extern unsigned int keymap_count;
36
37/* Hook for MIDI serial driver */
38void (*atari_MIDI_interrupt_hook) (void);
39/* Hook for mouse driver */
40void (*atari_mouse_interrupt_hook) (char *);
41/* Hook for keyboard inputdev  driver */
42void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
43/* Hook for mouse inputdev  driver */
44void (*atari_input_mouse_interrupt_hook) (char *);
45
46/* variables for IKBD self test: */
47
48/* state: 0: off; >0: in progress; >1: 0xf1 received */
49static volatile int ikbd_self_test;
50/* timestamp when last received a char */
51static volatile unsigned long self_test_last_rcv;
52/* bitmap of keys reported as broken */
53static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, };
54
55#define BREAK_MASK	(0x80)
56
57/*
58 * ++roman: The following changes were applied manually:
59 *
60 *  - The Alt (= Meta) key works in combination with Shift and
61 *    Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
62 *    Meta-Ctrl-A (0x81) ...
63 *
64 *  - The parentheses on the keypad send '(' and ')' with all
65 *    modifiers (as would do e.g. keypad '+'), but they cannot be used as
66 *    application keys (i.e. sending Esc O c).
67 *
68 *  - HELP and UNDO are mapped to be F21 and F24, resp, that send the
69 *    codes "\E[M" and "\E[P". (This is better than the old mapping to
70 *    F11 and F12, because these codes are on Shift+F1/2 anyway.) This
71 *    way, applications that allow their own keyboard mappings
72 *    (e.g. tcsh, X Windows) can be configured to use them in the way
73 *    the label suggests (providing help or undoing).
74 *
75 *  - Console switching is done with Alt+Fx (consoles 1..10) and
76 *    Shift+Alt+Fx (consoles 11..20).
77 *
78 *  - The misc. special function implemented in the kernel are mapped
79 *    to the following key combinations:
80 *
81 *      ClrHome          -> Home/Find
82 *      Shift + ClrHome  -> End/Select
83 *      Shift + Up       -> Page Up
84 *      Shift + Down     -> Page Down
85 *      Alt + Help       -> show system status
86 *      Shift + Help     -> show memory info
87 *      Ctrl + Help      -> show registers
88 *      Ctrl + Alt + Del -> Reboot
89 *      Alt + Undo       -> switch to last console
90 *      Shift + Undo     -> send interrupt
91 *      Alt + Insert     -> stop/start output (same as ^S/^Q)
92 *      Alt + Up         -> Scroll back console (if implemented)
93 *      Alt + Down       -> Scroll forward console (if implemented)
94 *      Alt + CapsLock   -> NumLock
95 *
96 * ++Andreas:
97 *
98 *  - Help mapped to K_HELP
99 *  - Undo mapped to K_UNDO (= K_F246)
100 *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
101 */
102
103static u_short ataplain_map[NR_KEYS] __initdata = {
104	0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
105	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
106	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
107	0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73,
108	0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b,
109	0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76,
110	0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200,
111	0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
112	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
113	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
114	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
115	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
116	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
117	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
118	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
119	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
120};
121
122typedef enum kb_state_t {
123	KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
124} KB_STATE_T;
125
126#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
127
128typedef struct keyboard_state {
129	unsigned char buf[6];
130	int len;
131	KB_STATE_T state;
132} KEYBOARD_STATE;
133
134KEYBOARD_STATE kb_state;
135
136#define	DEFAULT_KEYB_REP_DELAY	(HZ/4)
137#define	DEFAULT_KEYB_REP_RATE	(HZ/25)
138
139/* These could be settable by some ioctl() in future... */
140static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
141static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
142
143static unsigned char rep_scancode;
144static struct timer_list atakeyb_rep_timer = {
145	.function = atakeyb_rep,
146};
147
148static void atakeyb_rep(unsigned long ignore)
149{
150	/* Disable keyboard for the time we call handle_scancode(), else a race
151	 * in the keyboard tty queue may happen */
152	atari_disable_irq(IRQ_MFP_ACIA);
153	del_timer(&atakeyb_rep_timer);
154
155	/* A keyboard int may have come in before we disabled the irq, so
156	 * double-check whether rep_scancode is still != 0 */
157	if (rep_scancode) {
158		init_timer(&atakeyb_rep_timer);
159		atakeyb_rep_timer.expires = jiffies + key_repeat_rate;
160		add_timer(&atakeyb_rep_timer);
161
162		//handle_scancode(rep_scancode, 1);
163		if (atari_input_keyboard_interrupt_hook)
164			atari_input_keyboard_interrupt_hook(rep_scancode, 1);
165	}
166
167	atari_enable_irq(IRQ_MFP_ACIA);
168}
169
170
171/* ++roman: If a keyboard overrun happened, we can't tell in general how much
172 * bytes have been lost and in which state of the packet structure we are now.
173 * This usually causes keyboards bytes to be interpreted as mouse movements
174 * and vice versa, which is very annoying. It seems better to throw away some
175 * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I
176 * introduced the RESYNC state for IKBD data. In this state, the bytes up to
177 * one that really looks like a key event (0x04..0xf2) or the start of a mouse
178 * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
179 * speeds up the resynchronization of the event structure, even if maybe a
180 * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
181 * it's really hard to decide whether they're mouse or keyboard bytes. Since
182 * overruns usually occur when moving the Atari mouse rapidly, they're seen as
183 * mouse bytes here. If this is wrong, only a make code of the keyboard gets
184 * lost, which isn't too bad. Loosing a break code would be disastrous,
185 * because then the keyboard repeat strikes...
186 */
187
188static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
189{
190	u_char acia_stat;
191	int scancode;
192	int break_flag;
193
194repeat:
195	if (acia.mid_ctrl & ACIA_IRQ)
196		if (atari_MIDI_interrupt_hook)
197			atari_MIDI_interrupt_hook();
198	acia_stat = acia.key_ctrl;
199	/* check out if the interrupt came from this ACIA */
200	if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
201		return IRQ_HANDLED;
202
203	if (acia_stat & ACIA_OVRN) {
204		/* a very fast typist or a slow system, give a warning */
205		/* ...happens often if interrupts were disabled for too long */
206		printk(KERN_DEBUG "Keyboard overrun\n");
207		scancode = acia.key_data;
208		/* Turn off autorepeating in case a break code has been lost */
209		del_timer(&atakeyb_rep_timer);
210		rep_scancode = 0;
211		if (ikbd_self_test)
212			/* During self test, don't do resyncing, just process the code */
213			goto interpret_scancode;
214		else if (IS_SYNC_CODE(scancode)) {
215			/* This code seem already to be the start of a new packet or a
216			 * single scancode */
217			kb_state.state = KEYBOARD;
218			goto interpret_scancode;
219		} else {
220			/* Go to RESYNC state and skip this byte */
221			kb_state.state = RESYNC;
222			kb_state.len = 1;	/* skip max. 1 another byte */
223			goto repeat;
224		}
225	}
226
227	if (acia_stat & ACIA_RDRF) {
228		/* received a character */
229		scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
230		tasklet_schedule(&keyboard_tasklet);
231	interpret_scancode:
232		switch (kb_state.state) {
233		case KEYBOARD:
234			switch (scancode) {
235			case 0xF7:
236				kb_state.state = AMOUSE;
237				kb_state.len = 0;
238				break;
239
240			case 0xF8:
241			case 0xF9:
242			case 0xFA:
243			case 0xFB:
244				kb_state.state = RMOUSE;
245				kb_state.len = 1;
246				kb_state.buf[0] = scancode;
247				break;
248
249			case 0xFC:
250				kb_state.state = CLOCK;
251				kb_state.len = 0;
252				break;
253
254			case 0xFE:
255			case 0xFF:
256				kb_state.state = JOYSTICK;
257				kb_state.len = 1;
258				kb_state.buf[0] = scancode;
259				break;
260
261			case 0xF1:
262				/* during self-test, note that 0xf1 received */
263				if (ikbd_self_test) {
264					++ikbd_self_test;
265					self_test_last_rcv = jiffies;
266					break;
267				}
268				/* FALL THROUGH */
269
270			default:
271				break_flag = scancode & BREAK_MASK;
272				scancode &= ~BREAK_MASK;
273				if (ikbd_self_test) {
274					/* Scancodes sent during the self-test stand for broken
275					 * keys (keys being down). The code *should* be a break
276					 * code, but nevertheless some AT keyboard interfaces send
277					 * make codes instead. Therefore, simply ignore
278					 * break_flag...
279					 */
280					int keyval = plain_map[scancode], keytyp;
281
282					set_bit(scancode, broken_keys);
283					self_test_last_rcv = jiffies;
284					keyval = plain_map[scancode];
285					keytyp = KTYP(keyval) - 0xf0;
286					keyval = KVAL(keyval);
287
288					printk(KERN_WARNING "Key with scancode %d ", scancode);
289					if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
290						if (keyval < ' ')
291							printk("('^%c') ", keyval + '@');
292						else
293							printk("('%c') ", keyval);
294					}
295					printk("is broken -- will be ignored.\n");
296					break;
297				} else if (test_bit(scancode, broken_keys))
298					break;
299
300
301				// handle_scancode(scancode, !break_flag);
302				if (atari_input_keyboard_interrupt_hook)
303					atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
304				break;
305			}
306			break;
307
308		case AMOUSE:
309			kb_state.buf[kb_state.len++] = scancode;
310			if (kb_state.len == 5) {
311				kb_state.state = KEYBOARD;
312				/* not yet used */
313				/* wake up someone waiting for this */
314			}
315			break;
316
317		case RMOUSE:
318			kb_state.buf[kb_state.len++] = scancode;
319			if (kb_state.len == 3) {
320				kb_state.state = KEYBOARD;
321				if (atari_mouse_interrupt_hook)
322					atari_mouse_interrupt_hook(kb_state.buf);
323			}
324			break;
325
326		case JOYSTICK:
327			kb_state.buf[1] = scancode;
328			kb_state.state = KEYBOARD;
329#ifdef FIXED_ATARI_JOYSTICK
330			atari_joystick_interrupt(kb_state.buf);
331#endif
332			break;
333
334		case CLOCK:
335			kb_state.buf[kb_state.len++] = scancode;
336			if (kb_state.len == 6) {
337				kb_state.state = KEYBOARD;
338				/* wake up someone waiting for this.
339				   But will this ever be used, as Linux keeps its own time.
340				   Perhaps for synchronization purposes? */
341				/* wake_up_interruptible(&clock_wait); */
342			}
343			break;
344
345		case RESYNC:
346			if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
347				kb_state.state = KEYBOARD;
348				goto interpret_scancode;
349			}
350			kb_state.len--;
351			break;
352		}
353	}
354
355
356	if (acia_stat & (ACIA_FE | ACIA_PE)) {
357		printk("Error in keyboard communication\n");
358	}
359
360	/* handle_scancode() can take a lot of time, so check again if
361	 * some character arrived
362	 */
363	goto repeat;
364}
365
366/*
367 * I write to the keyboard without using interrupts, I poll instead.
368 * This takes for the maximum length string allowed (7) at 7812.5 baud
369 * 8 data 1 start 1 stop bit: 9.0 ms
370 * If this takes too long for normal operation, interrupt driven writing
371 * is the solution. (I made a feeble attempt in that direction but I
372 * kept it simple for now.)
373 */
374void ikbd_write(const char *str, int len)
375{
376	u_char acia_stat;
377
378	if ((len < 1) || (len > 7))
379		panic("ikbd: maximum string length exceeded");
380	while (len) {
381		acia_stat = acia.key_ctrl;
382		if (acia_stat & ACIA_TDRE) {
383			acia.key_data = *str++;
384			len--;
385		}
386	}
387}
388
389/* Reset (without touching the clock) */
390void ikbd_reset(void)
391{
392	static const char cmd[2] = { 0x80, 0x01 };
393
394	ikbd_write(cmd, 2);
395
396	/*
397	 * if all's well code 0xF1 is returned, else the break codes of
398	 * all keys making contact
399	 */
400}
401
402/* Set mouse button action */
403void ikbd_mouse_button_action(int mode)
404{
405	char cmd[2] = { 0x07, mode };
406
407	ikbd_write(cmd, 2);
408}
409
410/* Set relative mouse position reporting */
411void ikbd_mouse_rel_pos(void)
412{
413	static const char cmd[1] = { 0x08 };
414
415	ikbd_write(cmd, 1);
416}
417
418/* Set absolute mouse position reporting */
419void ikbd_mouse_abs_pos(int xmax, int ymax)
420{
421	char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
422
423	ikbd_write(cmd, 5);
424}
425
426/* Set mouse keycode mode */
427void ikbd_mouse_kbd_mode(int dx, int dy)
428{
429	char cmd[3] = { 0x0A, dx, dy };
430
431	ikbd_write(cmd, 3);
432}
433
434/* Set mouse threshold */
435void ikbd_mouse_thresh(int x, int y)
436{
437	char cmd[3] = { 0x0B, x, y };
438
439	ikbd_write(cmd, 3);
440}
441
442/* Set mouse scale */
443void ikbd_mouse_scale(int x, int y)
444{
445	char cmd[3] = { 0x0C, x, y };
446
447	ikbd_write(cmd, 3);
448}
449
450/* Interrogate mouse position */
451void ikbd_mouse_pos_get(int *x, int *y)
452{
453	static const char cmd[1] = { 0x0D };
454
455	ikbd_write(cmd, 1);
456
457	/* wait for returning bytes */
458}
459
460/* Load mouse position */
461void ikbd_mouse_pos_set(int x, int y)
462{
463	char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
464
465	ikbd_write(cmd, 6);
466}
467
468/* Set Y=0 at bottom */
469void ikbd_mouse_y0_bot(void)
470{
471	static const char cmd[1] = { 0x0F };
472
473	ikbd_write(cmd, 1);
474}
475
476/* Set Y=0 at top */
477void ikbd_mouse_y0_top(void)
478{
479	static const char cmd[1] = { 0x10 };
480
481	ikbd_write(cmd, 1);
482}
483
484/* Resume */
485void ikbd_resume(void)
486{
487	static const char cmd[1] = { 0x11 };
488
489	ikbd_write(cmd, 1);
490}
491
492/* Disable mouse */
493void ikbd_mouse_disable(void)
494{
495	static const char cmd[1] = { 0x12 };
496
497	ikbd_write(cmd, 1);
498}
499
500/* Pause output */
501void ikbd_pause(void)
502{
503	static const char cmd[1] = { 0x13 };
504
505	ikbd_write(cmd, 1);
506}
507
508/* Set joystick event reporting */
509void ikbd_joystick_event_on(void)
510{
511	static const char cmd[1] = { 0x14 };
512
513	ikbd_write(cmd, 1);
514}
515
516/* Set joystick interrogation mode */
517void ikbd_joystick_event_off(void)
518{
519	static const char cmd[1] = { 0x15 };
520
521	ikbd_write(cmd, 1);
522}
523
524/* Joystick interrogation */
525void ikbd_joystick_get_state(void)
526{
527	static const char cmd[1] = { 0x16 };
528
529	ikbd_write(cmd, 1);
530}
531
532
533/* some joystick routines not in yet (0x18-0x19) */
534
535/* Disable joysticks */
536void ikbd_joystick_disable(void)
537{
538	static const char cmd[1] = { 0x1A };
539
540	ikbd_write(cmd, 1);
541}
542
543/* Time-of-day clock set */
544void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second)
545{
546	char cmd[7] = { 0x1B, year, month, day, hour, minute, second };
547
548	ikbd_write(cmd, 7);
549}
550
551/* Interrogate time-of-day clock */
552void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second)
553{
554	static const char cmd[1] = { 0x1C };
555
556	ikbd_write(cmd, 1);
557}
558
559/* Memory load */
560void ikbd_mem_write(int address, int size, char *data)
561{
562	panic("Attempt to write data into keyboard memory");
563}
564
565/* Memory read */
566void ikbd_mem_read(int address, char data[6])
567{
568	char cmd[3] = { 0x21, address>>8, address&0xFF };
569
570	ikbd_write(cmd, 3);
571
572	/* receive data and put it in data */
573}
574
575/* Controller execute */
576void ikbd_exec(int address)
577{
578	char cmd[3] = { 0x22, address>>8, address&0xFF };
579
580	ikbd_write(cmd, 3);
581}
582
583/* Status inquiries (0x87-0x9A) not yet implemented */
584
585/* Set the state of the caps lock led. */
586void atari_kbd_leds(unsigned int leds)
587{
588	char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0};
589
590	ikbd_write(cmd, 6);
591}
592
593/*
594 * The original code sometimes left the interrupt line of
595 * the ACIAs low forever. I hope, it is fixed now.
596 *
597 * Martin Rogge, 20 Aug 1995
598 */
599
600static int atari_keyb_done = 0;
601
602int __init atari_keyb_init(void)
603{
604	if (atari_keyb_done)
605		return 0;
606
607	/* setup key map */
608	memcpy(key_maps[0], ataplain_map, sizeof(plain_map));
609
610	kb_state.state = KEYBOARD;
611	kb_state.len = 0;
612
613	request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW,
614		    "keyboard/mouse/MIDI", atari_keyboard_interrupt);
615
616	atari_turnoff_irq(IRQ_MFP_ACIA);
617	do {
618		/* reset IKBD ACIA */
619		acia.key_ctrl = ACIA_RESET |
620				(atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0;
621		(void)acia.key_ctrl;
622		(void)acia.key_data;
623
624		/* reset MIDI ACIA */
625		acia.mid_ctrl = ACIA_RESET |
626				(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
627		(void)acia.mid_ctrl;
628		(void)acia.mid_data;
629
630		/* divide 500kHz by 64 gives 7812.5 baud */
631		/* 8 data no parity 1 start 1 stop bit */
632		/* receive interrupt enabled */
633		/* RTS low (except if switch selected), transmit interrupt disabled */
634		acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
635				((atari_switches & ATARI_SWITCH_IKBD) ?
636				 ACIA_RHTID : ACIA_RLTID);
637
638		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
639				(atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0;
640
641	/* make sure the interrupt line is up */
642	} while ((mfp.par_dt_reg & 0x10) == 0);
643
644	/* enable ACIA Interrupts */
645	mfp.active_edge &= ~0x10;
646	atari_turnon_irq(IRQ_MFP_ACIA);
647
648	ikbd_self_test = 1;
649	ikbd_reset();
650	/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
651	 * self-test is finished */
652	self_test_last_rcv = jiffies;
653	while (time_before(jiffies, self_test_last_rcv + HZ/4))
654		barrier();
655	/* if not incremented: no 0xf1 received */
656	if (ikbd_self_test == 1)
657		printk(KERN_ERR "WARNING: keyboard self test failed!\n");
658	ikbd_self_test = 0;
659
660	ikbd_mouse_disable();
661	ikbd_joystick_disable();
662
663#ifdef FIXED_ATARI_JOYSTICK
664	atari_joystick_init();
665#endif
666
667	// flag init done
668	atari_keyb_done = 1;
669	return 0;
670}
671
672
673int atari_kbdrate(struct kbd_repeat *k)
674{
675	if (k->delay > 0) {
676		/* convert from msec to jiffies */
677		key_repeat_delay = (k->delay * HZ + 500) / 1000;
678		if (key_repeat_delay < 1)
679			key_repeat_delay = 1;
680	}
681	if (k->period > 0) {
682		key_repeat_rate = (k->period * HZ + 500) / 1000;
683		if (key_repeat_rate < 1)
684			key_repeat_rate = 1;
685	}
686
687	k->delay  = key_repeat_delay * 1000 / HZ;
688	k->period = key_repeat_rate  * 1000 / HZ;
689
690	return 0;
691}
692
693int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
694{
695#ifdef CONFIG_MAGIC_SYSRQ
696	/* ALT+HELP pressed? */
697	if ((keycode == 98) && ((shift_state & 0xff) == 8))
698		*keycodep = 0xff;
699	else
700#endif
701		*keycodep = keycode;
702	return 1;
703}
704