162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  atakbd.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2005 Michael Schmitz
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Based on amikbd.c, which is
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci *  Copyright (c) 2000-2001 Vojtech Pavlik
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci *  Based on the work of:
1262306a36Sopenharmony_ci *	Hamish Macdonald
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Atari keyboard driver for Linux/m68k
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c
1962306a36Sopenharmony_ci * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard
2062306a36Sopenharmony_ci * interrupt is shared with the MIDI ACIA so MIDI data also get handled there).
2162306a36Sopenharmony_ci * This driver only deals with handing key events off to the input layer.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/module.h>
2562306a36Sopenharmony_ci#include <linux/init.h>
2662306a36Sopenharmony_ci#include <linux/input.h>
2762306a36Sopenharmony_ci#include <linux/delay.h>
2862306a36Sopenharmony_ci#include <linux/interrupt.h>
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#include <asm/atariints.h>
3162306a36Sopenharmony_ci#include <asm/atarihw.h>
3262306a36Sopenharmony_ci#include <asm/atarikb.h>
3362306a36Sopenharmony_ci#include <asm/irq.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ciMODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>");
3662306a36Sopenharmony_ciMODULE_DESCRIPTION("Atari keyboard driver");
3762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci 0x47: KP_7     71
4162306a36Sopenharmony_ci 0x48: KP_8     72
4262306a36Sopenharmony_ci 0x49: KP_9     73
4362306a36Sopenharmony_ci 0x62: KP_/     98
4462306a36Sopenharmony_ci 0x4b: KP_4     75
4562306a36Sopenharmony_ci 0x4c: KP_5     76
4662306a36Sopenharmony_ci 0x4d: KP_6     77
4762306a36Sopenharmony_ci 0x37: KP_*     55
4862306a36Sopenharmony_ci 0x4f: KP_1     79
4962306a36Sopenharmony_ci 0x50: KP_2     80
5062306a36Sopenharmony_ci 0x51: KP_3     81
5162306a36Sopenharmony_ci 0x4a: KP_-     74
5262306a36Sopenharmony_ci 0x52: KP_0     82
5362306a36Sopenharmony_ci 0x53: KP_.     83
5462306a36Sopenharmony_ci 0x4e: KP_+     78
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci 0x67: Up       103
5762306a36Sopenharmony_ci 0x6c: Down     108
5862306a36Sopenharmony_ci 0x69: Left     105
5962306a36Sopenharmony_ci 0x6a: Right    106
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic unsigned char atakbd_keycode[0x73] = {	/* American layout */
6462306a36Sopenharmony_ci	[1]	 = KEY_ESC,
6562306a36Sopenharmony_ci	[2]	 = KEY_1,
6662306a36Sopenharmony_ci	[3]	 = KEY_2,
6762306a36Sopenharmony_ci	[4]	 = KEY_3,
6862306a36Sopenharmony_ci	[5]	 = KEY_4,
6962306a36Sopenharmony_ci	[6]	 = KEY_5,
7062306a36Sopenharmony_ci	[7]	 = KEY_6,
7162306a36Sopenharmony_ci	[8]	 = KEY_7,
7262306a36Sopenharmony_ci	[9]	 = KEY_8,
7362306a36Sopenharmony_ci	[10]	 = KEY_9,
7462306a36Sopenharmony_ci	[11]	 = KEY_0,
7562306a36Sopenharmony_ci	[12]	 = KEY_MINUS,
7662306a36Sopenharmony_ci	[13]	 = KEY_EQUAL,
7762306a36Sopenharmony_ci	[14]	 = KEY_BACKSPACE,
7862306a36Sopenharmony_ci	[15]	 = KEY_TAB,
7962306a36Sopenharmony_ci	[16]	 = KEY_Q,
8062306a36Sopenharmony_ci	[17]	 = KEY_W,
8162306a36Sopenharmony_ci	[18]	 = KEY_E,
8262306a36Sopenharmony_ci	[19]	 = KEY_R,
8362306a36Sopenharmony_ci	[20]	 = KEY_T,
8462306a36Sopenharmony_ci	[21]	 = KEY_Y,
8562306a36Sopenharmony_ci	[22]	 = KEY_U,
8662306a36Sopenharmony_ci	[23]	 = KEY_I,
8762306a36Sopenharmony_ci	[24]	 = KEY_O,
8862306a36Sopenharmony_ci	[25]	 = KEY_P,
8962306a36Sopenharmony_ci	[26]	 = KEY_LEFTBRACE,
9062306a36Sopenharmony_ci	[27]	 = KEY_RIGHTBRACE,
9162306a36Sopenharmony_ci	[28]	 = KEY_ENTER,
9262306a36Sopenharmony_ci	[29]	 = KEY_LEFTCTRL,
9362306a36Sopenharmony_ci	[30]	 = KEY_A,
9462306a36Sopenharmony_ci	[31]	 = KEY_S,
9562306a36Sopenharmony_ci	[32]	 = KEY_D,
9662306a36Sopenharmony_ci	[33]	 = KEY_F,
9762306a36Sopenharmony_ci	[34]	 = KEY_G,
9862306a36Sopenharmony_ci	[35]	 = KEY_H,
9962306a36Sopenharmony_ci	[36]	 = KEY_J,
10062306a36Sopenharmony_ci	[37]	 = KEY_K,
10162306a36Sopenharmony_ci	[38]	 = KEY_L,
10262306a36Sopenharmony_ci	[39]	 = KEY_SEMICOLON,
10362306a36Sopenharmony_ci	[40]	 = KEY_APOSTROPHE,
10462306a36Sopenharmony_ci	[41]	 = KEY_GRAVE,
10562306a36Sopenharmony_ci	[42]	 = KEY_LEFTSHIFT,
10662306a36Sopenharmony_ci	[43]	 = KEY_BACKSLASH,
10762306a36Sopenharmony_ci	[44]	 = KEY_Z,
10862306a36Sopenharmony_ci	[45]	 = KEY_X,
10962306a36Sopenharmony_ci	[46]	 = KEY_C,
11062306a36Sopenharmony_ci	[47]	 = KEY_V,
11162306a36Sopenharmony_ci	[48]	 = KEY_B,
11262306a36Sopenharmony_ci	[49]	 = KEY_N,
11362306a36Sopenharmony_ci	[50]	 = KEY_M,
11462306a36Sopenharmony_ci	[51]	 = KEY_COMMA,
11562306a36Sopenharmony_ci	[52]	 = KEY_DOT,
11662306a36Sopenharmony_ci	[53]	 = KEY_SLASH,
11762306a36Sopenharmony_ci	[54]	 = KEY_RIGHTSHIFT,
11862306a36Sopenharmony_ci	[55]	 = KEY_KPASTERISK,
11962306a36Sopenharmony_ci	[56]	 = KEY_LEFTALT,
12062306a36Sopenharmony_ci	[57]	 = KEY_SPACE,
12162306a36Sopenharmony_ci	[58]	 = KEY_CAPSLOCK,
12262306a36Sopenharmony_ci	[59]	 = KEY_F1,
12362306a36Sopenharmony_ci	[60]	 = KEY_F2,
12462306a36Sopenharmony_ci	[61]	 = KEY_F3,
12562306a36Sopenharmony_ci	[62]	 = KEY_F4,
12662306a36Sopenharmony_ci	[63]	 = KEY_F5,
12762306a36Sopenharmony_ci	[64]	 = KEY_F6,
12862306a36Sopenharmony_ci	[65]	 = KEY_F7,
12962306a36Sopenharmony_ci	[66]	 = KEY_F8,
13062306a36Sopenharmony_ci	[67]	 = KEY_F9,
13162306a36Sopenharmony_ci	[68]	 = KEY_F10,
13262306a36Sopenharmony_ci	[71]	 = KEY_HOME,
13362306a36Sopenharmony_ci	[72]	 = KEY_UP,
13462306a36Sopenharmony_ci	[74]	 = KEY_KPMINUS,
13562306a36Sopenharmony_ci	[75]	 = KEY_LEFT,
13662306a36Sopenharmony_ci	[77]	 = KEY_RIGHT,
13762306a36Sopenharmony_ci	[78]	 = KEY_KPPLUS,
13862306a36Sopenharmony_ci	[80]	 = KEY_DOWN,
13962306a36Sopenharmony_ci	[82]	 = KEY_INSERT,
14062306a36Sopenharmony_ci	[83]	 = KEY_DELETE,
14162306a36Sopenharmony_ci	[96]	 = KEY_102ND,
14262306a36Sopenharmony_ci	[97]	 = KEY_UNDO,
14362306a36Sopenharmony_ci	[98]	 = KEY_HELP,
14462306a36Sopenharmony_ci	[99]	 = KEY_KPLEFTPAREN,
14562306a36Sopenharmony_ci	[100]	 = KEY_KPRIGHTPAREN,
14662306a36Sopenharmony_ci	[101]	 = KEY_KPSLASH,
14762306a36Sopenharmony_ci	[102]	 = KEY_KPASTERISK,
14862306a36Sopenharmony_ci	[103]	 = KEY_KP7,
14962306a36Sopenharmony_ci	[104]	 = KEY_KP8,
15062306a36Sopenharmony_ci	[105]	 = KEY_KP9,
15162306a36Sopenharmony_ci	[106]	 = KEY_KP4,
15262306a36Sopenharmony_ci	[107]	 = KEY_KP5,
15362306a36Sopenharmony_ci	[108]	 = KEY_KP6,
15462306a36Sopenharmony_ci	[109]	 = KEY_KP1,
15562306a36Sopenharmony_ci	[110]	 = KEY_KP2,
15662306a36Sopenharmony_ci	[111]	 = KEY_KP3,
15762306a36Sopenharmony_ci	[112]	 = KEY_KP0,
15862306a36Sopenharmony_ci	[113]	 = KEY_KPDOT,
15962306a36Sopenharmony_ci	[114]	 = KEY_KPENTER,
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic struct input_dev *atakbd_dev;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic void atakbd_interrupt(unsigned char scancode, char down)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (scancode < 0x73) {		/* scancodes < 0xf3 are keys */
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci		// report raw events here?
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci		scancode = atakbd_keycode[scancode];
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		input_report_key(atakbd_dev, scancode, down);
17462306a36Sopenharmony_ci		input_sync(atakbd_dev);
17562306a36Sopenharmony_ci	} else				/* scancodes >= 0xf3 are mouse data, most likely */
17662306a36Sopenharmony_ci		printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	return;
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int __init atakbd_init(void)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	int i, error;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
18662306a36Sopenharmony_ci		return -ENODEV;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	// need to init core driver if not already done so
18962306a36Sopenharmony_ci	error = atari_keyb_init();
19062306a36Sopenharmony_ci	if (error)
19162306a36Sopenharmony_ci		return error;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	atakbd_dev = input_allocate_device();
19462306a36Sopenharmony_ci	if (!atakbd_dev)
19562306a36Sopenharmony_ci		return -ENOMEM;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	atakbd_dev->name = "Atari Keyboard";
19862306a36Sopenharmony_ci	atakbd_dev->phys = "atakbd/input0";
19962306a36Sopenharmony_ci	atakbd_dev->id.bustype = BUS_HOST;
20062306a36Sopenharmony_ci	atakbd_dev->id.vendor = 0x0001;
20162306a36Sopenharmony_ci	atakbd_dev->id.product = 0x0001;
20262306a36Sopenharmony_ci	atakbd_dev->id.version = 0x0100;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	atakbd_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
20562306a36Sopenharmony_ci	atakbd_dev->keycode = atakbd_keycode;
20662306a36Sopenharmony_ci	atakbd_dev->keycodesize = sizeof(unsigned char);
20762306a36Sopenharmony_ci	atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	for (i = 1; i < 0x72; i++) {
21062306a36Sopenharmony_ci		set_bit(atakbd_keycode[i], atakbd_dev->keybit);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* error check */
21462306a36Sopenharmony_ci	error = input_register_device(atakbd_dev);
21562306a36Sopenharmony_ci	if (error) {
21662306a36Sopenharmony_ci		input_free_device(atakbd_dev);
21762306a36Sopenharmony_ci		return error;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	atari_input_keyboard_interrupt_hook = atakbd_interrupt;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return 0;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic void __exit atakbd_exit(void)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	atari_input_keyboard_interrupt_hook = NULL;
22862306a36Sopenharmony_ci	input_unregister_device(atakbd_dev);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cimodule_init(atakbd_init);
23262306a36Sopenharmony_cimodule_exit(atakbd_exit);
233