cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

atakeyb.c (14510B)


      1/*
      2 * Atari Keyboard driver for 680x0 Linux
      3 *
      4 * This file is subject to the terms and conditions of the GNU General Public
      5 * License.  See the file COPYING in the main directory of this archive
      6 * for more details.
      7 */
      8
      9/*
     10 * Atari support by Robert de Vries
     11 * enhanced by Bjoern Brauel and Roman Hodek
     12 *
     13 * 2.6 and input cleanup (removed autorepeat stuff) for 2.6.21
     14 * 06/07 Michael Schmitz
     15 */
     16
     17#include <linux/module.h>
     18#include <linux/sched.h>
     19#include <linux/kernel.h>
     20#include <linux/interrupt.h>
     21#include <linux/errno.h>
     22#include <linux/keyboard.h>
     23#include <linux/delay.h>
     24#include <linux/timer.h>
     25#include <linux/kd.h>
     26#include <linux/random.h>
     27#include <linux/init.h>
     28#include <linux/kbd_kern.h>
     29
     30#include <asm/atariints.h>
     31#include <asm/atarihw.h>
     32#include <asm/atarikb.h>
     33#include <asm/atari_joystick.h>
     34#include <asm/irq.h>
     35
     36
     37/* Hook for MIDI serial driver */
     38void (*atari_MIDI_interrupt_hook) (void);
     39/* Hook for keyboard inputdev  driver */
     40void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
     41/* Hook for mouse inputdev  driver */
     42void (*atari_input_mouse_interrupt_hook) (char *);
     43EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
     44EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
     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
    103typedef enum kb_state_t {
    104	KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC
    105} KB_STATE_T;
    106
    107#define	IS_SYNC_CODE(sc)	((sc) >= 0x04 && (sc) <= 0xfb)
    108
    109typedef struct keyboard_state {
    110	unsigned char buf[6];
    111	int len;
    112	KB_STATE_T state;
    113} KEYBOARD_STATE;
    114
    115KEYBOARD_STATE kb_state;
    116
    117/* ++roman: If a keyboard overrun happened, we can't tell in general how much
    118 * bytes have been lost and in which state of the packet structure we are now.
    119 * This usually causes keyboards bytes to be interpreted as mouse movements
    120 * and vice versa, which is very annoying. It seems better to throw away some
    121 * bytes (that are usually mouse bytes) than to misinterpret them. Therefore I
    122 * introduced the RESYNC state for IKBD data. In this state, the bytes up to
    123 * one that really looks like a key event (0x04..0xf2) or the start of a mouse
    124 * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least
    125 * speeds up the resynchronization of the event structure, even if maybe a
    126 * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03,
    127 * it's really hard to decide whether they're mouse or keyboard bytes. Since
    128 * overruns usually occur when moving the Atari mouse rapidly, they're seen as
    129 * mouse bytes here. If this is wrong, only a make code of the keyboard gets
    130 * lost, which isn't too bad. Losing a break code would be disastrous,
    131 * because then the keyboard repeat strikes...
    132 */
    133
    134static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy)
    135{
    136	u_char acia_stat;
    137	int scancode;
    138	int break_flag;
    139
    140repeat:
    141	if (acia.mid_ctrl & ACIA_IRQ)
    142		if (atari_MIDI_interrupt_hook)
    143			atari_MIDI_interrupt_hook();
    144	acia_stat = acia.key_ctrl;
    145	/* check out if the interrupt came from this ACIA */
    146	if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ))
    147		return IRQ_HANDLED;
    148
    149	if (acia_stat & ACIA_OVRN) {
    150		/* a very fast typist or a slow system, give a warning */
    151		/* ...happens often if interrupts were disabled for too long */
    152		pr_debug("Keyboard overrun\n");
    153		scancode = acia.key_data;
    154		if (ikbd_self_test)
    155			/* During self test, don't do resyncing, just process the code */
    156			goto interpret_scancode;
    157		else if (IS_SYNC_CODE(scancode)) {
    158			/* This code seem already to be the start of a new packet or a
    159			 * single scancode */
    160			kb_state.state = KEYBOARD;
    161			goto interpret_scancode;
    162		} else {
    163			/* Go to RESYNC state and skip this byte */
    164			kb_state.state = RESYNC;
    165			kb_state.len = 1;	/* skip max. 1 another byte */
    166			goto repeat;
    167		}
    168	}
    169
    170	if (acia_stat & ACIA_RDRF) {
    171		/* received a character */
    172		scancode = acia.key_data;	/* get it or reset the ACIA, I'll get it! */
    173	interpret_scancode:
    174		switch (kb_state.state) {
    175		case KEYBOARD:
    176			switch (scancode) {
    177			case 0xF7:
    178				kb_state.state = AMOUSE;
    179				kb_state.len = 0;
    180				break;
    181
    182			case 0xF8:
    183			case 0xF9:
    184			case 0xFA:
    185			case 0xFB:
    186				kb_state.state = RMOUSE;
    187				kb_state.len = 1;
    188				kb_state.buf[0] = scancode;
    189				break;
    190
    191			case 0xFC:
    192				kb_state.state = CLOCK;
    193				kb_state.len = 0;
    194				break;
    195
    196			case 0xFE:
    197			case 0xFF:
    198				kb_state.state = JOYSTICK;
    199				kb_state.len = 1;
    200				kb_state.buf[0] = scancode;
    201				break;
    202
    203			case 0xF1:
    204				/* during self-test, note that 0xf1 received */
    205				if (ikbd_self_test) {
    206					++ikbd_self_test;
    207					self_test_last_rcv = jiffies;
    208					break;
    209				}
    210				fallthrough;
    211
    212			default:
    213				break_flag = scancode & BREAK_MASK;
    214				scancode &= ~BREAK_MASK;
    215				if (ikbd_self_test) {
    216					/* Scancodes sent during the self-test stand for broken
    217					 * keys (keys being down). The code *should* be a break
    218					 * code, but nevertheless some AT keyboard interfaces send
    219					 * make codes instead. Therefore, simply ignore
    220					 * break_flag...
    221					 */
    222					int keyval, keytyp;
    223
    224					set_bit(scancode, broken_keys);
    225					self_test_last_rcv = jiffies;
    226					/* new Linux scancodes; approx. */
    227					keyval = scancode;
    228					keytyp = KTYP(keyval) - 0xf0;
    229					keyval = KVAL(keyval);
    230
    231					pr_warn("Key with scancode %d ", scancode);
    232					if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
    233						if (keyval < ' ')
    234							pr_cont("('^%c') ", keyval + '@');
    235						else
    236							pr_cont("('%c') ", keyval);
    237					}
    238					pr_cont("is broken -- will be ignored.\n");
    239					break;
    240				} else if (test_bit(scancode, broken_keys))
    241					break;
    242
    243				if (atari_input_keyboard_interrupt_hook)
    244					atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag);
    245				break;
    246			}
    247			break;
    248
    249		case AMOUSE:
    250			kb_state.buf[kb_state.len++] = scancode;
    251			if (kb_state.len == 5) {
    252				kb_state.state = KEYBOARD;
    253				/* not yet used */
    254				/* wake up someone waiting for this */
    255			}
    256			break;
    257
    258		case RMOUSE:
    259			kb_state.buf[kb_state.len++] = scancode;
    260			if (kb_state.len == 3) {
    261				kb_state.state = KEYBOARD;
    262				if (atari_input_mouse_interrupt_hook)
    263					atari_input_mouse_interrupt_hook(kb_state.buf);
    264			}
    265			break;
    266
    267		case JOYSTICK:
    268			kb_state.buf[1] = scancode;
    269			kb_state.state = KEYBOARD;
    270#ifdef FIXED_ATARI_JOYSTICK
    271			atari_joystick_interrupt(kb_state.buf);
    272#endif
    273			break;
    274
    275		case CLOCK:
    276			kb_state.buf[kb_state.len++] = scancode;
    277			if (kb_state.len == 6) {
    278				kb_state.state = KEYBOARD;
    279				/* wake up someone waiting for this.
    280				   But will this ever be used, as Linux keeps its own time.
    281				   Perhaps for synchronization purposes? */
    282				/* wake_up_interruptible(&clock_wait); */
    283			}
    284			break;
    285
    286		case RESYNC:
    287			if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) {
    288				kb_state.state = KEYBOARD;
    289				goto interpret_scancode;
    290			}
    291			kb_state.len--;
    292			break;
    293		}
    294	}
    295
    296#if 0
    297	if (acia_stat & ACIA_CTS)
    298		/* cannot happen */;
    299#endif
    300
    301	if (acia_stat & (ACIA_FE | ACIA_PE)) {
    302		pr_err("Error in keyboard communication\n");
    303	}
    304
    305	/* handle_scancode() can take a lot of time, so check again if
    306	 * some character arrived
    307	 */
    308	goto repeat;
    309}
    310
    311/*
    312 * I write to the keyboard without using interrupts, I poll instead.
    313 * This takes for the maximum length string allowed (7) at 7812.5 baud
    314 * 8 data 1 start 1 stop bit: 9.0 ms
    315 * If this takes too long for normal operation, interrupt driven writing
    316 * is the solution. (I made a feeble attempt in that direction but I
    317 * kept it simple for now.)
    318 */
    319void ikbd_write(const char *str, int len)
    320{
    321	u_char acia_stat;
    322
    323	if ((len < 1) || (len > 7))
    324		panic("ikbd: maximum string length exceeded");
    325	while (len) {
    326		acia_stat = acia.key_ctrl;
    327		if (acia_stat & ACIA_TDRE) {
    328			acia.key_data = *str++;
    329			len--;
    330		}
    331	}
    332}
    333
    334/* Reset (without touching the clock) */
    335void ikbd_reset(void)
    336{
    337	static const char cmd[2] = { 0x80, 0x01 };
    338
    339	ikbd_write(cmd, 2);
    340
    341	/*
    342	 * if all's well code 0xF1 is returned, else the break codes of
    343	 * all keys making contact
    344	 */
    345}
    346
    347/* Set mouse button action */
    348void ikbd_mouse_button_action(int mode)
    349{
    350	char cmd[2] = { 0x07, mode };
    351
    352	ikbd_write(cmd, 2);
    353}
    354
    355/* Set relative mouse position reporting */
    356void ikbd_mouse_rel_pos(void)
    357{
    358	static const char cmd[1] = { 0x08 };
    359
    360	ikbd_write(cmd, 1);
    361}
    362EXPORT_SYMBOL(ikbd_mouse_rel_pos);
    363
    364/* Set absolute mouse position reporting */
    365void ikbd_mouse_abs_pos(int xmax, int ymax)
    366{
    367	char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF };
    368
    369	ikbd_write(cmd, 5);
    370}
    371
    372/* Set mouse keycode mode */
    373void ikbd_mouse_kbd_mode(int dx, int dy)
    374{
    375	char cmd[3] = { 0x0A, dx, dy };
    376
    377	ikbd_write(cmd, 3);
    378}
    379
    380/* Set mouse threshold */
    381void ikbd_mouse_thresh(int x, int y)
    382{
    383	char cmd[3] = { 0x0B, x, y };
    384
    385	ikbd_write(cmd, 3);
    386}
    387EXPORT_SYMBOL(ikbd_mouse_thresh);
    388
    389/* Set mouse scale */
    390void ikbd_mouse_scale(int x, int y)
    391{
    392	char cmd[3] = { 0x0C, x, y };
    393
    394	ikbd_write(cmd, 3);
    395}
    396
    397/* Interrogate mouse position */
    398void ikbd_mouse_pos_get(int *x, int *y)
    399{
    400	static const char cmd[1] = { 0x0D };
    401
    402	ikbd_write(cmd, 1);
    403
    404	/* wait for returning bytes */
    405}
    406
    407/* Load mouse position */
    408void ikbd_mouse_pos_set(int x, int y)
    409{
    410	char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF };
    411
    412	ikbd_write(cmd, 6);
    413}
    414
    415/* Set Y=0 at bottom */
    416void ikbd_mouse_y0_bot(void)
    417{
    418	static const char cmd[1] = { 0x0F };
    419
    420	ikbd_write(cmd, 1);
    421}
    422
    423/* Set Y=0 at top */
    424void ikbd_mouse_y0_top(void)
    425{
    426	static const char cmd[1] = { 0x10 };
    427
    428	ikbd_write(cmd, 1);
    429}
    430EXPORT_SYMBOL(ikbd_mouse_y0_top);
    431
    432/* Disable mouse */
    433void ikbd_mouse_disable(void)
    434{
    435	static const char cmd[1] = { 0x12 };
    436
    437	ikbd_write(cmd, 1);
    438}
    439EXPORT_SYMBOL(ikbd_mouse_disable);
    440
    441/* Set joystick event reporting */
    442void ikbd_joystick_event_on(void)
    443{
    444	static const char cmd[1] = { 0x14 };
    445
    446	ikbd_write(cmd, 1);
    447}
    448
    449/* Set joystick interrogation mode */
    450void ikbd_joystick_event_off(void)
    451{
    452	static const char cmd[1] = { 0x15 };
    453
    454	ikbd_write(cmd, 1);
    455}
    456
    457/* Joystick interrogation */
    458void ikbd_joystick_get_state(void)
    459{
    460	static const char cmd[1] = { 0x16 };
    461
    462	ikbd_write(cmd, 1);
    463}
    464
    465#if 0
    466/* This disables all other ikbd activities !!!! */
    467/* Set joystick monitoring */
    468void ikbd_joystick_monitor(int rate)
    469{
    470	static const char cmd[2] = { 0x17, rate };
    471
    472	ikbd_write(cmd, 2);
    473
    474	kb_state.state = JOYSTICK_MONITOR;
    475}
    476#endif
    477
    478/* some joystick routines not in yet (0x18-0x19) */
    479
    480/* Disable joysticks */
    481void ikbd_joystick_disable(void)
    482{
    483	static const char cmd[1] = { 0x1A };
    484
    485	ikbd_write(cmd, 1);
    486}
    487
    488/*
    489 * The original code sometimes left the interrupt line of
    490 * the ACIAs low forever. I hope, it is fixed now.
    491 *
    492 * Martin Rogge, 20 Aug 1995
    493 */
    494
    495static int atari_keyb_done = 0;
    496
    497int atari_keyb_init(void)
    498{
    499	int error;
    500
    501	if (atari_keyb_done)
    502		return 0;
    503
    504	kb_state.state = KEYBOARD;
    505	kb_state.len = 0;
    506
    507	error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, 0,
    508			    "keyboard,mouse,MIDI", atari_keyboard_interrupt);
    509	if (error)
    510		return error;
    511
    512	atari_turnoff_irq(IRQ_MFP_ACIA);
    513	do {
    514		/* reset IKBD ACIA */
    515		acia.key_ctrl = ACIA_RESET |
    516				((atari_switches & ATARI_SWITCH_IKBD) ?
    517				 ACIA_RHTID : 0);
    518		(void)acia.key_ctrl;
    519		(void)acia.key_data;
    520
    521		/* reset MIDI ACIA */
    522		acia.mid_ctrl = ACIA_RESET |
    523				((atari_switches & ATARI_SWITCH_MIDI) ?
    524				 ACIA_RHTID : 0);
    525		(void)acia.mid_ctrl;
    526		(void)acia.mid_data;
    527
    528		/* divide 500kHz by 64 gives 7812.5 baud */
    529		/* 8 data no parity 1 start 1 stop bit */
    530		/* receive interrupt enabled */
    531		/* RTS low (except if switch selected), transmit interrupt disabled */
    532		acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) |
    533				((atari_switches & ATARI_SWITCH_IKBD) ?
    534				 ACIA_RHTID : ACIA_RLTID);
    535
    536		acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S |
    537				((atari_switches & ATARI_SWITCH_MIDI) ?
    538				 ACIA_RHTID : 0);
    539
    540	/* make sure the interrupt line is up */
    541	} while ((st_mfp.par_dt_reg & 0x10) == 0);
    542
    543	/* enable ACIA Interrupts */
    544	st_mfp.active_edge &= ~0x10;
    545	atari_turnon_irq(IRQ_MFP_ACIA);
    546
    547	ikbd_self_test = 1;
    548	ikbd_reset();
    549	/* wait for a period of inactivity (here: 0.25s), then assume the IKBD's
    550	 * self-test is finished */
    551	self_test_last_rcv = jiffies;
    552	while (time_before(jiffies, self_test_last_rcv + HZ/4))
    553		barrier();
    554	/* if not incremented: no 0xf1 received */
    555	if (ikbd_self_test == 1)
    556		pr_err("Keyboard self test failed!\n");
    557	ikbd_self_test = 0;
    558
    559	ikbd_mouse_disable();
    560	ikbd_joystick_disable();
    561
    562#ifdef FIXED_ATARI_JOYSTICK
    563	atari_joystick_init();
    564#endif
    565
    566	// flag init done
    567	atari_keyb_done = 1;
    568	return 0;
    569}
    570EXPORT_SYMBOL_GPL(atari_keyb_init);