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