162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/macintosh/adbhid.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * ADB HID driver for Power Macintosh computers.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl.
862306a36Sopenharmony_ci * drivers/macintosh/mac_keyb.c was Copyright (C) 1996 Paul Mackerras
962306a36Sopenharmony_ci * with considerable contributions from Ben Herrenschmidt and others.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Copyright (C) 2000 Franz Sirl.
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * Adapted to ADB changes and support for more devices by
1462306a36Sopenharmony_ci * Benjamin Herrenschmidt. Adapted from code in MkLinux
1562306a36Sopenharmony_ci * and reworked.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Supported devices:
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * - Standard 1 button mouse
2062306a36Sopenharmony_ci * - All standard Apple Extended protocol (handler ID 4)
2162306a36Sopenharmony_ci * - mouseman and trackman mice & trackballs
2262306a36Sopenharmony_ci * - PowerBook Trackpad (default setup: enable tapping)
2362306a36Sopenharmony_ci * - MicroSpeed mouse & trackball (needs testing)
2462306a36Sopenharmony_ci * - CH Products Trackball Pro (needs testing)
2562306a36Sopenharmony_ci * - Contour Design (Contour Mouse)
2662306a36Sopenharmony_ci * - Hunter digital (NoHandsMouse)
2762306a36Sopenharmony_ci * - Kensignton TurboMouse 5 (needs testing)
2862306a36Sopenharmony_ci * - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
2962306a36Sopenharmony_ci * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * To do:
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * Improve Kensington support.
3462306a36Sopenharmony_ci * Split mouse/kbd
3562306a36Sopenharmony_ci * Move to syfs
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include <linux/module.h>
3962306a36Sopenharmony_ci#include <linux/slab.h>
4062306a36Sopenharmony_ci#include <linux/init.h>
4162306a36Sopenharmony_ci#include <linux/notifier.h>
4262306a36Sopenharmony_ci#include <linux/input.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include <linux/adb.h>
4562306a36Sopenharmony_ci#include <linux/cuda.h>
4662306a36Sopenharmony_ci#include <linux/pmu.h>
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#include <asm/machdep.h>
4962306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC
5062306a36Sopenharmony_ci#include <asm/backlight.h>
5162306a36Sopenharmony_ci#include <asm/pmac_feature.h>
5262306a36Sopenharmony_ci#endif
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciMODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int restore_capslock_events;
5762306a36Sopenharmony_cimodule_param(restore_capslock_events, int, 0644);
5862306a36Sopenharmony_ciMODULE_PARM_DESC(restore_capslock_events,
5962306a36Sopenharmony_ci	"Produce keypress events for capslock on both keyup and keydown.");
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define KEYB_KEYREG	0	/* register # for key up/down data */
6262306a36Sopenharmony_ci#define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
6362306a36Sopenharmony_ci#define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int adb_message_handler(struct notifier_block *, unsigned long, void *);
6662306a36Sopenharmony_cistatic struct notifier_block adbhid_adb_notifier = {
6762306a36Sopenharmony_ci	.notifier_call	= adb_message_handler,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Some special keys */
7162306a36Sopenharmony_ci#define ADB_KEY_DEL		0x33
7262306a36Sopenharmony_ci#define ADB_KEY_CMD		0x37
7362306a36Sopenharmony_ci#define ADB_KEY_CAPSLOCK	0x39
7462306a36Sopenharmony_ci#define ADB_KEY_FN		0x3f
7562306a36Sopenharmony_ci#define ADB_KEY_FWDEL		0x75
7662306a36Sopenharmony_ci#define ADB_KEY_POWER_OLD	0x7e
7762306a36Sopenharmony_ci#define ADB_KEY_POWER		0x7f
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic const u16 adb_to_linux_keycodes[128] = {
8062306a36Sopenharmony_ci	/* 0x00 */ KEY_A, 		/*  30 */
8162306a36Sopenharmony_ci	/* 0x01 */ KEY_S, 		/*  31 */
8262306a36Sopenharmony_ci	/* 0x02 */ KEY_D,		/*  32 */
8362306a36Sopenharmony_ci	/* 0x03 */ KEY_F,		/*  33 */
8462306a36Sopenharmony_ci	/* 0x04 */ KEY_H,		/*  35 */
8562306a36Sopenharmony_ci	/* 0x05 */ KEY_G,		/*  34 */
8662306a36Sopenharmony_ci	/* 0x06 */ KEY_Z,		/*  44 */
8762306a36Sopenharmony_ci	/* 0x07 */ KEY_X,		/*  45 */
8862306a36Sopenharmony_ci	/* 0x08 */ KEY_C,		/*  46 */
8962306a36Sopenharmony_ci	/* 0x09 */ KEY_V,		/*  47 */
9062306a36Sopenharmony_ci	/* 0x0a */ KEY_102ND,		/*  86 */
9162306a36Sopenharmony_ci	/* 0x0b */ KEY_B,		/*  48 */
9262306a36Sopenharmony_ci	/* 0x0c */ KEY_Q,		/*  16 */
9362306a36Sopenharmony_ci	/* 0x0d */ KEY_W,		/*  17 */
9462306a36Sopenharmony_ci	/* 0x0e */ KEY_E,		/*  18 */
9562306a36Sopenharmony_ci	/* 0x0f */ KEY_R,		/*  19 */
9662306a36Sopenharmony_ci	/* 0x10 */ KEY_Y,		/*  21 */
9762306a36Sopenharmony_ci	/* 0x11 */ KEY_T,		/*  20 */
9862306a36Sopenharmony_ci	/* 0x12 */ KEY_1,		/*   2 */
9962306a36Sopenharmony_ci	/* 0x13 */ KEY_2,		/*   3 */
10062306a36Sopenharmony_ci	/* 0x14 */ KEY_3,		/*   4 */
10162306a36Sopenharmony_ci	/* 0x15 */ KEY_4,		/*   5 */
10262306a36Sopenharmony_ci	/* 0x16 */ KEY_6,		/*   7 */
10362306a36Sopenharmony_ci	/* 0x17 */ KEY_5,		/*   6 */
10462306a36Sopenharmony_ci	/* 0x18 */ KEY_EQUAL,		/*  13 */
10562306a36Sopenharmony_ci	/* 0x19 */ KEY_9,		/*  10 */
10662306a36Sopenharmony_ci	/* 0x1a */ KEY_7,		/*   8 */
10762306a36Sopenharmony_ci	/* 0x1b */ KEY_MINUS,		/*  12 */
10862306a36Sopenharmony_ci	/* 0x1c */ KEY_8,		/*   9 */
10962306a36Sopenharmony_ci	/* 0x1d */ KEY_0,		/*  11 */
11062306a36Sopenharmony_ci	/* 0x1e */ KEY_RIGHTBRACE,	/*  27 */
11162306a36Sopenharmony_ci	/* 0x1f */ KEY_O,		/*  24 */
11262306a36Sopenharmony_ci	/* 0x20 */ KEY_U,		/*  22 */
11362306a36Sopenharmony_ci	/* 0x21 */ KEY_LEFTBRACE,	/*  26 */
11462306a36Sopenharmony_ci	/* 0x22 */ KEY_I,		/*  23 */
11562306a36Sopenharmony_ci	/* 0x23 */ KEY_P,		/*  25 */
11662306a36Sopenharmony_ci	/* 0x24 */ KEY_ENTER,		/*  28 */
11762306a36Sopenharmony_ci	/* 0x25 */ KEY_L,		/*  38 */
11862306a36Sopenharmony_ci	/* 0x26 */ KEY_J,		/*  36 */
11962306a36Sopenharmony_ci	/* 0x27 */ KEY_APOSTROPHE,	/*  40 */
12062306a36Sopenharmony_ci	/* 0x28 */ KEY_K,		/*  37 */
12162306a36Sopenharmony_ci	/* 0x29 */ KEY_SEMICOLON,	/*  39 */
12262306a36Sopenharmony_ci	/* 0x2a */ KEY_BACKSLASH,	/*  43 */
12362306a36Sopenharmony_ci	/* 0x2b */ KEY_COMMA,		/*  51 */
12462306a36Sopenharmony_ci	/* 0x2c */ KEY_SLASH,		/*  53 */
12562306a36Sopenharmony_ci	/* 0x2d */ KEY_N,		/*  49 */
12662306a36Sopenharmony_ci	/* 0x2e */ KEY_M,		/*  50 */
12762306a36Sopenharmony_ci	/* 0x2f */ KEY_DOT,		/*  52 */
12862306a36Sopenharmony_ci	/* 0x30 */ KEY_TAB,		/*  15 */
12962306a36Sopenharmony_ci	/* 0x31 */ KEY_SPACE,		/*  57 */
13062306a36Sopenharmony_ci	/* 0x32 */ KEY_GRAVE,		/*  41 */
13162306a36Sopenharmony_ci	/* 0x33 */ KEY_BACKSPACE,	/*  14 */
13262306a36Sopenharmony_ci	/* 0x34 */ KEY_KPENTER,		/*  96 */
13362306a36Sopenharmony_ci	/* 0x35 */ KEY_ESC,		/*   1 */
13462306a36Sopenharmony_ci	/* 0x36 */ KEY_LEFTCTRL,	/*  29 */
13562306a36Sopenharmony_ci	/* 0x37 */ KEY_LEFTMETA,	/* 125 */
13662306a36Sopenharmony_ci	/* 0x38 */ KEY_LEFTSHIFT,	/*  42 */
13762306a36Sopenharmony_ci	/* 0x39 */ KEY_CAPSLOCK,	/*  58 */
13862306a36Sopenharmony_ci	/* 0x3a */ KEY_LEFTALT,		/*  56 */
13962306a36Sopenharmony_ci	/* 0x3b */ KEY_LEFT,		/* 105 */
14062306a36Sopenharmony_ci	/* 0x3c */ KEY_RIGHT,		/* 106 */
14162306a36Sopenharmony_ci	/* 0x3d */ KEY_DOWN,		/* 108 */
14262306a36Sopenharmony_ci	/* 0x3e */ KEY_UP,		/* 103 */
14362306a36Sopenharmony_ci	/* 0x3f */ KEY_FN,		/* 0x1d0 */
14462306a36Sopenharmony_ci	/* 0x40 */ 0,
14562306a36Sopenharmony_ci	/* 0x41 */ KEY_KPDOT,		/*  83 */
14662306a36Sopenharmony_ci	/* 0x42 */ 0,
14762306a36Sopenharmony_ci	/* 0x43 */ KEY_KPASTERISK,	/*  55 */
14862306a36Sopenharmony_ci	/* 0x44 */ 0,
14962306a36Sopenharmony_ci	/* 0x45 */ KEY_KPPLUS,		/*  78 */
15062306a36Sopenharmony_ci	/* 0x46 */ 0,
15162306a36Sopenharmony_ci	/* 0x47 */ KEY_NUMLOCK,		/*  69 */
15262306a36Sopenharmony_ci	/* 0x48 */ 0,
15362306a36Sopenharmony_ci	/* 0x49 */ 0,
15462306a36Sopenharmony_ci	/* 0x4a */ 0,
15562306a36Sopenharmony_ci	/* 0x4b */ KEY_KPSLASH,		/*  98 */
15662306a36Sopenharmony_ci	/* 0x4c */ KEY_KPENTER,		/*  96 */
15762306a36Sopenharmony_ci	/* 0x4d */ 0,
15862306a36Sopenharmony_ci	/* 0x4e */ KEY_KPMINUS,		/*  74 */
15962306a36Sopenharmony_ci	/* 0x4f */ 0,
16062306a36Sopenharmony_ci	/* 0x50 */ 0,
16162306a36Sopenharmony_ci	/* 0x51 */ KEY_KPEQUAL,		/* 117 */
16262306a36Sopenharmony_ci	/* 0x52 */ KEY_KP0,		/*  82 */
16362306a36Sopenharmony_ci	/* 0x53 */ KEY_KP1,		/*  79 */
16462306a36Sopenharmony_ci	/* 0x54 */ KEY_KP2,		/*  80 */
16562306a36Sopenharmony_ci	/* 0x55 */ KEY_KP3,		/*  81 */
16662306a36Sopenharmony_ci	/* 0x56 */ KEY_KP4,		/*  75 */
16762306a36Sopenharmony_ci	/* 0x57 */ KEY_KP5,		/*  76 */
16862306a36Sopenharmony_ci	/* 0x58 */ KEY_KP6,		/*  77 */
16962306a36Sopenharmony_ci	/* 0x59 */ KEY_KP7,		/*  71 */
17062306a36Sopenharmony_ci	/* 0x5a */ 0,
17162306a36Sopenharmony_ci	/* 0x5b */ KEY_KP8,		/*  72 */
17262306a36Sopenharmony_ci	/* 0x5c */ KEY_KP9,		/*  73 */
17362306a36Sopenharmony_ci	/* 0x5d */ KEY_YEN,		/* 124 */
17462306a36Sopenharmony_ci	/* 0x5e */ KEY_RO,		/*  89 */
17562306a36Sopenharmony_ci	/* 0x5f */ KEY_KPCOMMA,		/* 121 */
17662306a36Sopenharmony_ci	/* 0x60 */ KEY_F5,		/*  63 */
17762306a36Sopenharmony_ci	/* 0x61 */ KEY_F6,		/*  64 */
17862306a36Sopenharmony_ci	/* 0x62 */ KEY_F7,		/*  65 */
17962306a36Sopenharmony_ci	/* 0x63 */ KEY_F3,		/*  61 */
18062306a36Sopenharmony_ci	/* 0x64 */ KEY_F8,		/*  66 */
18162306a36Sopenharmony_ci	/* 0x65 */ KEY_F9,		/*  67 */
18262306a36Sopenharmony_ci	/* 0x66 */ KEY_HANJA,		/* 123 */
18362306a36Sopenharmony_ci	/* 0x67 */ KEY_F11,		/*  87 */
18462306a36Sopenharmony_ci	/* 0x68 */ KEY_HANGEUL,		/* 122 */
18562306a36Sopenharmony_ci	/* 0x69 */ KEY_SYSRQ,		/*  99 */
18662306a36Sopenharmony_ci	/* 0x6a */ 0,
18762306a36Sopenharmony_ci	/* 0x6b */ KEY_SCROLLLOCK,	/*  70 */
18862306a36Sopenharmony_ci	/* 0x6c */ 0,
18962306a36Sopenharmony_ci	/* 0x6d */ KEY_F10,		/*  68 */
19062306a36Sopenharmony_ci	/* 0x6e */ KEY_COMPOSE,		/* 127 */
19162306a36Sopenharmony_ci	/* 0x6f */ KEY_F12,		/*  88 */
19262306a36Sopenharmony_ci	/* 0x70 */ 0,
19362306a36Sopenharmony_ci	/* 0x71 */ KEY_PAUSE,		/* 119 */
19462306a36Sopenharmony_ci	/* 0x72 */ KEY_INSERT,		/* 110 */
19562306a36Sopenharmony_ci	/* 0x73 */ KEY_HOME,		/* 102 */
19662306a36Sopenharmony_ci	/* 0x74 */ KEY_PAGEUP,		/* 104 */
19762306a36Sopenharmony_ci	/* 0x75 */ KEY_DELETE,		/* 111 */
19862306a36Sopenharmony_ci	/* 0x76 */ KEY_F4,		/*  62 */
19962306a36Sopenharmony_ci	/* 0x77 */ KEY_END,		/* 107 */
20062306a36Sopenharmony_ci	/* 0x78 */ KEY_F2,		/*  60 */
20162306a36Sopenharmony_ci	/* 0x79 */ KEY_PAGEDOWN,	/* 109 */
20262306a36Sopenharmony_ci	/* 0x7a */ KEY_F1,		/*  59 */
20362306a36Sopenharmony_ci	/* 0x7b */ KEY_RIGHTSHIFT,	/*  54 */
20462306a36Sopenharmony_ci	/* 0x7c */ KEY_RIGHTALT,	/* 100 */
20562306a36Sopenharmony_ci	/* 0x7d */ KEY_RIGHTCTRL,	/*  97 */
20662306a36Sopenharmony_ci	/* 0x7e */ KEY_RIGHTMETA,	/* 126 */
20762306a36Sopenharmony_ci	/* 0x7f */ KEY_POWER,		/* 116 */
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistruct adbhid {
21162306a36Sopenharmony_ci	struct input_dev *input;
21262306a36Sopenharmony_ci	int id;
21362306a36Sopenharmony_ci	int default_id;
21462306a36Sopenharmony_ci	int original_handler_id;
21562306a36Sopenharmony_ci	int current_handler_id;
21662306a36Sopenharmony_ci	int mouse_kind;
21762306a36Sopenharmony_ci	u16 *keycode;
21862306a36Sopenharmony_ci	char name[64];
21962306a36Sopenharmony_ci	char phys[32];
22062306a36Sopenharmony_ci	int flags;
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci#define FLAG_FN_KEY_PRESSED		0x00000001
22462306a36Sopenharmony_ci#define FLAG_POWER_FROM_FN		0x00000002
22562306a36Sopenharmony_ci#define FLAG_EMU_FWDEL_DOWN		0x00000004
22662306a36Sopenharmony_ci#define FLAG_CAPSLOCK_TRANSLATE		0x00000008
22762306a36Sopenharmony_ci#define FLAG_CAPSLOCK_DOWN		0x00000010
22862306a36Sopenharmony_ci#define FLAG_CAPSLOCK_IGNORE_NEXT	0x00000020
22962306a36Sopenharmony_ci#define FLAG_POWER_KEY_PRESSED		0x00000040
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic struct adbhid *adbhid[16];
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic void adbhid_probe(void);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void adbhid_input_keycode(int, int, int);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic void init_trackpad(int id);
23862306a36Sopenharmony_cistatic void init_trackball(int id);
23962306a36Sopenharmony_cistatic void init_turbomouse(int id);
24062306a36Sopenharmony_cistatic void init_microspeed(int id);
24162306a36Sopenharmony_cistatic void init_ms_a3(int id);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic struct adb_ids keyboard_ids;
24462306a36Sopenharmony_cistatic struct adb_ids mouse_ids;
24562306a36Sopenharmony_cistatic struct adb_ids buttons_ids;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/* Kind of keyboard, see Apple technote 1152  */
24862306a36Sopenharmony_ci#define ADB_KEYBOARD_UNKNOWN	0
24962306a36Sopenharmony_ci#define ADB_KEYBOARD_ANSI	0x0100
25062306a36Sopenharmony_ci#define ADB_KEYBOARD_ISO	0x0200
25162306a36Sopenharmony_ci#define ADB_KEYBOARD_JIS	0x0300
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci/* Kind of mouse  */
25462306a36Sopenharmony_ci#define ADBMOUSE_STANDARD_100	0	/* Standard 100cpi mouse (handler 1) */
25562306a36Sopenharmony_ci#define ADBMOUSE_STANDARD_200	1	/* Standard 200cpi mouse (handler 2) */
25662306a36Sopenharmony_ci#define ADBMOUSE_EXTENDED	2	/* Apple Extended mouse (handler 4) */
25762306a36Sopenharmony_ci#define ADBMOUSE_TRACKBALL	3	/* TrackBall (handler 4) */
25862306a36Sopenharmony_ci#define ADBMOUSE_TRACKPAD       4	/* Apple's PowerBook trackpad (handler 4) */
25962306a36Sopenharmony_ci#define ADBMOUSE_TURBOMOUSE5    5	/* Turbomouse 5 (previously req. mousehack) */
26062306a36Sopenharmony_ci#define ADBMOUSE_MICROSPEED	6	/* Microspeed mouse (&trackball ?), MacPoint */
26162306a36Sopenharmony_ci#define ADBMOUSE_TRACKBALLPRO	7	/* Trackball Pro (special buttons) */
26262306a36Sopenharmony_ci#define ADBMOUSE_MS_A3		8	/* Mouse systems A3 trackball (handler 3) */
26362306a36Sopenharmony_ci#define ADBMOUSE_MACALLY2	9	/* MacAlly 2-button mouse */
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic void
26662306a36Sopenharmony_ciadbhid_keyboard_input(unsigned char *data, int nb, int apoll)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	int id = (data[0] >> 4) & 0x0f;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (!adbhid[id]) {
27162306a36Sopenharmony_ci		pr_err("ADB HID on ID %d not yet registered, packet %#02x, %#02x, %#02x, %#02x\n",
27262306a36Sopenharmony_ci		       id, data[0], data[1], data[2], data[3]);
27362306a36Sopenharmony_ci		return;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* first check this is from register 0 */
27762306a36Sopenharmony_ci	if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
27862306a36Sopenharmony_ci		return;		/* ignore it */
27962306a36Sopenharmony_ci	adbhid_input_keycode(id, data[1], 0);
28062306a36Sopenharmony_ci	if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
28162306a36Sopenharmony_ci		adbhid_input_keycode(id, data[2], 0);
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic void
28562306a36Sopenharmony_ciadbhid_input_keycode(int id, int scancode, int repeat)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct adbhid *ahid = adbhid[id];
28862306a36Sopenharmony_ci	int keycode, up_flag, key;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	keycode = scancode & 0x7f;
29162306a36Sopenharmony_ci	up_flag = scancode & 0x80;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	if (restore_capslock_events) {
29462306a36Sopenharmony_ci		if (keycode == ADB_KEY_CAPSLOCK && !up_flag) {
29562306a36Sopenharmony_ci			/* Key pressed, turning on the CapsLock LED.
29662306a36Sopenharmony_ci			 * The next 0xff will be interpreted as a release. */
29762306a36Sopenharmony_ci			if (ahid->flags & FLAG_CAPSLOCK_IGNORE_NEXT) {
29862306a36Sopenharmony_ci				/* Throw away this key event if it happens
29962306a36Sopenharmony_ci				 * just after resume. */
30062306a36Sopenharmony_ci				ahid->flags &= ~FLAG_CAPSLOCK_IGNORE_NEXT;
30162306a36Sopenharmony_ci				return;
30262306a36Sopenharmony_ci			} else {
30362306a36Sopenharmony_ci				ahid->flags |= FLAG_CAPSLOCK_TRANSLATE
30462306a36Sopenharmony_ci					| FLAG_CAPSLOCK_DOWN;
30562306a36Sopenharmony_ci			}
30662306a36Sopenharmony_ci		} else if (scancode == 0xff &&
30762306a36Sopenharmony_ci			   !(ahid->flags & FLAG_POWER_KEY_PRESSED)) {
30862306a36Sopenharmony_ci			/* Scancode 0xff usually signifies that the capslock
30962306a36Sopenharmony_ci			 * key was either pressed or released, or that the
31062306a36Sopenharmony_ci			 * power button was released. */
31162306a36Sopenharmony_ci			if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) {
31262306a36Sopenharmony_ci				keycode = ADB_KEY_CAPSLOCK;
31362306a36Sopenharmony_ci				if (ahid->flags & FLAG_CAPSLOCK_DOWN) {
31462306a36Sopenharmony_ci					/* Key released */
31562306a36Sopenharmony_ci					up_flag = 1;
31662306a36Sopenharmony_ci					ahid->flags &= ~FLAG_CAPSLOCK_DOWN;
31762306a36Sopenharmony_ci				} else {
31862306a36Sopenharmony_ci					/* Key pressed */
31962306a36Sopenharmony_ci					up_flag = 0;
32062306a36Sopenharmony_ci					ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE;
32162306a36Sopenharmony_ci				}
32262306a36Sopenharmony_ci			} else {
32362306a36Sopenharmony_ci				pr_info("Spurious caps lock event (scancode 0xff).\n");
32462306a36Sopenharmony_ci			}
32562306a36Sopenharmony_ci		}
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	switch (keycode) {
32962306a36Sopenharmony_ci	case ADB_KEY_CAPSLOCK:
33062306a36Sopenharmony_ci		if (!restore_capslock_events) {
33162306a36Sopenharmony_ci			/* Generate down/up events for CapsLock every time. */
33262306a36Sopenharmony_ci			input_report_key(ahid->input, KEY_CAPSLOCK, 1);
33362306a36Sopenharmony_ci			input_sync(ahid->input);
33462306a36Sopenharmony_ci			input_report_key(ahid->input, KEY_CAPSLOCK, 0);
33562306a36Sopenharmony_ci			input_sync(ahid->input);
33662306a36Sopenharmony_ci			return;
33762306a36Sopenharmony_ci		}
33862306a36Sopenharmony_ci		break;
33962306a36Sopenharmony_ci#ifdef CONFIG_PPC_PMAC
34062306a36Sopenharmony_ci	case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
34162306a36Sopenharmony_ci		switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO,
34262306a36Sopenharmony_ci			NULL, PMAC_MB_INFO_MODEL, 0)) {
34362306a36Sopenharmony_ci		case PMAC_TYPE_COMET:
34462306a36Sopenharmony_ci		case PMAC_TYPE_HOOPER:
34562306a36Sopenharmony_ci		case PMAC_TYPE_KANGA:
34662306a36Sopenharmony_ci			keycode = ADB_KEY_POWER;
34762306a36Sopenharmony_ci		}
34862306a36Sopenharmony_ci		break;
34962306a36Sopenharmony_ci	case ADB_KEY_POWER:
35062306a36Sopenharmony_ci		/* Keep track of the power key state */
35162306a36Sopenharmony_ci		if (up_flag)
35262306a36Sopenharmony_ci			ahid->flags &= ~FLAG_POWER_KEY_PRESSED;
35362306a36Sopenharmony_ci		else
35462306a36Sopenharmony_ci			ahid->flags |= FLAG_POWER_KEY_PRESSED;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		/* Fn + Command will produce a bogus "power" keycode */
35762306a36Sopenharmony_ci		if (ahid->flags & FLAG_FN_KEY_PRESSED) {
35862306a36Sopenharmony_ci			keycode = ADB_KEY_CMD;
35962306a36Sopenharmony_ci			if (up_flag)
36062306a36Sopenharmony_ci				ahid->flags &= ~FLAG_POWER_FROM_FN;
36162306a36Sopenharmony_ci			else
36262306a36Sopenharmony_ci				ahid->flags |= FLAG_POWER_FROM_FN;
36362306a36Sopenharmony_ci		} else if (ahid->flags & FLAG_POWER_FROM_FN) {
36462306a36Sopenharmony_ci			keycode = ADB_KEY_CMD;
36562306a36Sopenharmony_ci			ahid->flags &= ~FLAG_POWER_FROM_FN;
36662306a36Sopenharmony_ci		}
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci	case ADB_KEY_FN:
36962306a36Sopenharmony_ci		/* Keep track of the Fn key state */
37062306a36Sopenharmony_ci		if (up_flag) {
37162306a36Sopenharmony_ci			ahid->flags &= ~FLAG_FN_KEY_PRESSED;
37262306a36Sopenharmony_ci			/* Emulate Fn+delete = forward delete */
37362306a36Sopenharmony_ci			if (ahid->flags & FLAG_EMU_FWDEL_DOWN) {
37462306a36Sopenharmony_ci				ahid->flags &= ~FLAG_EMU_FWDEL_DOWN;
37562306a36Sopenharmony_ci				keycode = ADB_KEY_FWDEL;
37662306a36Sopenharmony_ci				break;
37762306a36Sopenharmony_ci			}
37862306a36Sopenharmony_ci		} else
37962306a36Sopenharmony_ci			ahid->flags |= FLAG_FN_KEY_PRESSED;
38062306a36Sopenharmony_ci		break;
38162306a36Sopenharmony_ci	case ADB_KEY_DEL:
38262306a36Sopenharmony_ci		/* Emulate Fn+delete = forward delete */
38362306a36Sopenharmony_ci		if (ahid->flags & FLAG_FN_KEY_PRESSED) {
38462306a36Sopenharmony_ci			keycode = ADB_KEY_FWDEL;
38562306a36Sopenharmony_ci			if (up_flag)
38662306a36Sopenharmony_ci				ahid->flags &= ~FLAG_EMU_FWDEL_DOWN;
38762306a36Sopenharmony_ci			else
38862306a36Sopenharmony_ci				ahid->flags |= FLAG_EMU_FWDEL_DOWN;
38962306a36Sopenharmony_ci		}
39062306a36Sopenharmony_ci		break;
39162306a36Sopenharmony_ci#endif /* CONFIG_PPC_PMAC */
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	key = adbhid[id]->keycode[keycode];
39562306a36Sopenharmony_ci	if (key) {
39662306a36Sopenharmony_ci		input_report_key(adbhid[id]->input, key, !up_flag);
39762306a36Sopenharmony_ci		input_sync(adbhid[id]->input);
39862306a36Sopenharmony_ci	} else
39962306a36Sopenharmony_ci		pr_info("Unhandled ADB key (scancode %#02x) %s.\n", keycode,
40062306a36Sopenharmony_ci			up_flag ? "released" : "pressed");
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic void
40562306a36Sopenharmony_ciadbhid_mouse_input(unsigned char *data, int nb, int autopoll)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	int id = (data[0] >> 4) & 0x0f;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (!adbhid[id]) {
41062306a36Sopenharmony_ci		pr_err("ADB HID on ID %d not yet registered\n", id);
41162306a36Sopenharmony_ci		return;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci  /*
41562306a36Sopenharmony_ci    Handler 1 -- 100cpi original Apple mouse protocol.
41662306a36Sopenharmony_ci    Handler 2 -- 200cpi original Apple mouse protocol.
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci    For Apple's standard one-button mouse protocol the data array will
41962306a36Sopenharmony_ci    contain the following values:
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci                BITS    COMMENTS
42262306a36Sopenharmony_ci    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
42362306a36Sopenharmony_ci    data[1] = bxxx xxxx First button and x-axis motion.
42462306a36Sopenharmony_ci    data[2] = byyy yyyy Second button and y-axis motion.
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci    Handler 4 -- Apple Extended mouse protocol.
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci    For Apple's 3-button mouse protocol the data array will contain the
42962306a36Sopenharmony_ci    following values:
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		BITS    COMMENTS
43262306a36Sopenharmony_ci    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
43362306a36Sopenharmony_ci    data[1] = bxxx xxxx Left button and x-axis motion.
43462306a36Sopenharmony_ci    data[2] = byyy yyyy Second button and y-axis motion.
43562306a36Sopenharmony_ci    data[3] = byyy bxxx Third button and fourth button.  Y is additional
43662306a36Sopenharmony_ci	      high bits of y-axis motion.  XY is additional
43762306a36Sopenharmony_ci	      high bits of x-axis motion.
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci    MacAlly 2-button mouse protocol.
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci    For MacAlly 2-button mouse protocol the data array will contain the
44262306a36Sopenharmony_ci    following values:
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		BITS    COMMENTS
44562306a36Sopenharmony_ci    data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd.
44662306a36Sopenharmony_ci    data[1] = bxxx xxxx Left button and x-axis motion.
44762306a36Sopenharmony_ci    data[2] = byyy yyyy Right button and y-axis motion.
44862306a36Sopenharmony_ci    data[3] = ???? ???? unknown
44962306a36Sopenharmony_ci    data[4] = ???? ???? unknown
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci  */
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	/* If it's a trackpad, we alias the second button to the first.
45462306a36Sopenharmony_ci	   NOTE: Apple sends an ADB flush command to the trackpad when
45562306a36Sopenharmony_ci	         the first (the real) button is released. We could do
45662306a36Sopenharmony_ci		 this here using async flush requests.
45762306a36Sopenharmony_ci	*/
45862306a36Sopenharmony_ci	switch (adbhid[id]->mouse_kind)
45962306a36Sopenharmony_ci	{
46062306a36Sopenharmony_ci	    case ADBMOUSE_TRACKPAD:
46162306a36Sopenharmony_ci		data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
46262306a36Sopenharmony_ci		data[2] = data[2] | 0x80;
46362306a36Sopenharmony_ci		break;
46462306a36Sopenharmony_ci	    case ADBMOUSE_MICROSPEED:
46562306a36Sopenharmony_ci		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
46662306a36Sopenharmony_ci		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
46762306a36Sopenharmony_ci		data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
46862306a36Sopenharmony_ci			| (data[3] & 0x08);
46962306a36Sopenharmony_ci		break;
47062306a36Sopenharmony_ci	    case ADBMOUSE_TRACKBALLPRO:
47162306a36Sopenharmony_ci		data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
47262306a36Sopenharmony_ci			& ((data[3] & 0x08) << 4));
47362306a36Sopenharmony_ci		data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
47462306a36Sopenharmony_ci		data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6);
47562306a36Sopenharmony_ci		break;
47662306a36Sopenharmony_ci	    case ADBMOUSE_MS_A3:
47762306a36Sopenharmony_ci		data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
47862306a36Sopenharmony_ci		data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
47962306a36Sopenharmony_ci		data[3] = ((data[3] & 0x04) << 5);
48062306a36Sopenharmony_ci		break;
48162306a36Sopenharmony_ci            case ADBMOUSE_MACALLY2:
48262306a36Sopenharmony_ci		data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
48362306a36Sopenharmony_ci		data[2] |= 0x80;  /* Right button is mapped as button 3 */
48462306a36Sopenharmony_ci		nb=4;
48562306a36Sopenharmony_ci                break;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	input_report_key(adbhid[id]->input, BTN_LEFT,   !((data[1] >> 7) & 1));
48962306a36Sopenharmony_ci	input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	if (nb >= 4 && adbhid[id]->mouse_kind != ADBMOUSE_TRACKPAD)
49262306a36Sopenharmony_ci		input_report_key(adbhid[id]->input, BTN_RIGHT,  !((data[3] >> 7) & 1));
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	input_report_rel(adbhid[id]->input, REL_X,
49562306a36Sopenharmony_ci			 ((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ));
49662306a36Sopenharmony_ci	input_report_rel(adbhid[id]->input, REL_Y,
49762306a36Sopenharmony_ci			 ((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 ));
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	input_sync(adbhid[id]->input);
50062306a36Sopenharmony_ci}
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic void
50362306a36Sopenharmony_ciadbhid_buttons_input(unsigned char *data, int nb, int autopoll)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	int id = (data[0] >> 4) & 0x0f;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (!adbhid[id]) {
50862306a36Sopenharmony_ci		pr_err("ADB HID on ID %d not yet registered\n", id);
50962306a36Sopenharmony_ci		return;
51062306a36Sopenharmony_ci	}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	switch (adbhid[id]->original_handler_id) {
51362306a36Sopenharmony_ci	default:
51462306a36Sopenharmony_ci	case 0x02: /* Adjustable keyboard button device */
51562306a36Sopenharmony_ci	  {
51662306a36Sopenharmony_ci		int down = (data[1] == (data[1] & 0xf));
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		switch (data[1] & 0x0f) {
51962306a36Sopenharmony_ci		case 0x0:	/* microphone */
52062306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_SOUND, down);
52162306a36Sopenharmony_ci			break;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		case 0x1:	/* mute */
52462306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_MUTE, down);
52562306a36Sopenharmony_ci			break;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		case 0x2:	/* volume decrease */
52862306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_VOLUMEDOWN, down);
52962306a36Sopenharmony_ci			break;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		case 0x3:	/* volume increase */
53262306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_VOLUMEUP, down);
53362306a36Sopenharmony_ci			break;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci		default:
53662306a36Sopenharmony_ci			pr_info("Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
53762306a36Sopenharmony_ci				data[0], data[1], data[2], data[3]);
53862306a36Sopenharmony_ci			break;
53962306a36Sopenharmony_ci		}
54062306a36Sopenharmony_ci	  }
54162306a36Sopenharmony_ci	  break;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	case 0x1f: /* Powerbook button device */
54462306a36Sopenharmony_ci	  {
54562306a36Sopenharmony_ci		int down = (data[1] == (data[1] & 0xf));
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci		/*
54862306a36Sopenharmony_ci		 * XXX: Where is the contrast control for the passive?
54962306a36Sopenharmony_ci		 *  -- Cort
55062306a36Sopenharmony_ci		 */
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		switch (data[1] & 0x0f) {
55362306a36Sopenharmony_ci		case 0x8:	/* mute */
55462306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_MUTE, down);
55562306a36Sopenharmony_ci			break;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci		case 0x7:	/* volume decrease */
55862306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_VOLUMEDOWN, down);
55962306a36Sopenharmony_ci			break;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci		case 0x6:	/* volume increase */
56262306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_VOLUMEUP, down);
56362306a36Sopenharmony_ci			break;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		case 0xb:	/* eject */
56662306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_EJECTCD, down);
56762306a36Sopenharmony_ci			break;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci		case 0xa:	/* brightness decrease */
57062306a36Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT
57162306a36Sopenharmony_ci			if (down)
57262306a36Sopenharmony_ci				pmac_backlight_key_down();
57362306a36Sopenharmony_ci#endif
57462306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
57562306a36Sopenharmony_ci			break;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		case 0x9:	/* brightness increase */
57862306a36Sopenharmony_ci#ifdef CONFIG_PMAC_BACKLIGHT
57962306a36Sopenharmony_ci			if (down)
58062306a36Sopenharmony_ci				pmac_backlight_key_up();
58162306a36Sopenharmony_ci#endif
58262306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
58362306a36Sopenharmony_ci			break;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		case 0xc:	/* videomode switch */
58662306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_SWITCHVIDEOMODE, down);
58762306a36Sopenharmony_ci			break;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci		case 0xd:	/* keyboard illumination toggle */
59062306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_KBDILLUMTOGGLE, down);
59162306a36Sopenharmony_ci			break;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		case 0xe:	/* keyboard illumination decrease */
59462306a36Sopenharmony_ci			input_report_key(adbhid[id]->input, KEY_KBDILLUMDOWN, down);
59562306a36Sopenharmony_ci			break;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		case 0xf:
59862306a36Sopenharmony_ci			switch (data[1]) {
59962306a36Sopenharmony_ci			case 0x8f:
60062306a36Sopenharmony_ci			case 0x0f:
60162306a36Sopenharmony_ci				/* keyboard illumination increase */
60262306a36Sopenharmony_ci				input_report_key(adbhid[id]->input, KEY_KBDILLUMUP, down);
60362306a36Sopenharmony_ci				break;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci			case 0x7f:
60662306a36Sopenharmony_ci			case 0xff:
60762306a36Sopenharmony_ci				/* keypad overlay toogle */
60862306a36Sopenharmony_ci				break;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci			default:
61162306a36Sopenharmony_ci				pr_info("Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
61262306a36Sopenharmony_ci					data[0], data[1], data[2], data[3]);
61362306a36Sopenharmony_ci				break;
61462306a36Sopenharmony_ci			}
61562306a36Sopenharmony_ci			break;
61662306a36Sopenharmony_ci		default:
61762306a36Sopenharmony_ci			pr_info("Unhandled ADB_MISC event %02x, %02x, %02x, %02x\n",
61862306a36Sopenharmony_ci				data[0], data[1], data[2], data[3]);
61962306a36Sopenharmony_ci			break;
62062306a36Sopenharmony_ci		}
62162306a36Sopenharmony_ci	  }
62262306a36Sopenharmony_ci	  break;
62362306a36Sopenharmony_ci	}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	input_sync(adbhid[id]->input);
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_cistatic struct adb_request led_request;
62962306a36Sopenharmony_cistatic int leds_pending[16];
63062306a36Sopenharmony_cistatic int leds_req_pending;
63162306a36Sopenharmony_cistatic int pending_devs[16];
63262306a36Sopenharmony_cistatic int pending_led_start;
63362306a36Sopenharmony_cistatic int pending_led_end;
63462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(leds_lock);
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic void leds_done(struct adb_request *req)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	int leds = 0, device = 0, pending = 0;
63962306a36Sopenharmony_ci	unsigned long flags;
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci	spin_lock_irqsave(&leds_lock, flags);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (pending_led_start != pending_led_end) {
64462306a36Sopenharmony_ci		device = pending_devs[pending_led_start];
64562306a36Sopenharmony_ci		leds = leds_pending[device] & 0xff;
64662306a36Sopenharmony_ci		leds_pending[device] = 0;
64762306a36Sopenharmony_ci		pending_led_start++;
64862306a36Sopenharmony_ci		pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
64962306a36Sopenharmony_ci		pending = leds_req_pending;
65062306a36Sopenharmony_ci	} else
65162306a36Sopenharmony_ci		leds_req_pending = 0;
65262306a36Sopenharmony_ci	spin_unlock_irqrestore(&leds_lock, flags);
65362306a36Sopenharmony_ci	if (pending)
65462306a36Sopenharmony_ci		adb_request(&led_request, leds_done, 0, 3,
65562306a36Sopenharmony_ci			    ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds);
65662306a36Sopenharmony_ci}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_cistatic void real_leds(unsigned char leds, int device)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	unsigned long flags;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	spin_lock_irqsave(&leds_lock, flags);
66362306a36Sopenharmony_ci	if (!leds_req_pending) {
66462306a36Sopenharmony_ci		leds_req_pending = 1;
66562306a36Sopenharmony_ci		spin_unlock_irqrestore(&leds_lock, flags);
66662306a36Sopenharmony_ci		adb_request(&led_request, leds_done, 0, 3,
66762306a36Sopenharmony_ci			    ADB_WRITEREG(device, KEYB_LEDREG), 0xff, ~leds);
66862306a36Sopenharmony_ci		return;
66962306a36Sopenharmony_ci	} else {
67062306a36Sopenharmony_ci		if (!(leds_pending[device] & 0x100)) {
67162306a36Sopenharmony_ci			pending_devs[pending_led_end] = device;
67262306a36Sopenharmony_ci			pending_led_end++;
67362306a36Sopenharmony_ci			pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci		leds_pending[device] = leds | 0x100;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	spin_unlock_irqrestore(&leds_lock, flags);
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci/*
68162306a36Sopenharmony_ci * Event callback from the input module. Events that change the state of
68262306a36Sopenharmony_ci * the hardware are processed here.
68362306a36Sopenharmony_ci */
68462306a36Sopenharmony_cistatic int adbhid_kbd_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	struct adbhid *adbhid = input_get_drvdata(dev);
68762306a36Sopenharmony_ci	unsigned char leds;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	switch (type) {
69062306a36Sopenharmony_ci	case EV_LED:
69162306a36Sopenharmony_ci		leds =  (test_bit(LED_SCROLLL, dev->led) ? 4 : 0) |
69262306a36Sopenharmony_ci			(test_bit(LED_NUML,    dev->led) ? 1 : 0) |
69362306a36Sopenharmony_ci			(test_bit(LED_CAPSL,   dev->led) ? 2 : 0);
69462306a36Sopenharmony_ci		real_leds(leds, adbhid->id);
69562306a36Sopenharmony_ci		return 0;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	return -1;
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistatic void
70262306a36Sopenharmony_ciadbhid_kbd_capslock_remember(void)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	struct adbhid *ahid;
70562306a36Sopenharmony_ci	int i;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	for (i = 1; i < 16; i++) {
70862306a36Sopenharmony_ci		ahid = adbhid[i];
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		if (ahid && ahid->id == ADB_KEYBOARD)
71162306a36Sopenharmony_ci			if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE)
71262306a36Sopenharmony_ci				ahid->flags |= FLAG_CAPSLOCK_IGNORE_NEXT;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci}
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_cistatic int
71762306a36Sopenharmony_ciadb_message_handler(struct notifier_block *this, unsigned long code, void *x)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	switch (code) {
72062306a36Sopenharmony_ci	case ADB_MSG_PRE_RESET:
72162306a36Sopenharmony_ci	case ADB_MSG_POWERDOWN:
72262306a36Sopenharmony_ci		/* Stop the repeat timer. Autopoll is already off at this point */
72362306a36Sopenharmony_ci		{
72462306a36Sopenharmony_ci			int i;
72562306a36Sopenharmony_ci			for (i = 1; i < 16; i++) {
72662306a36Sopenharmony_ci				if (adbhid[i])
72762306a36Sopenharmony_ci					del_timer_sync(&adbhid[i]->input->timer);
72862306a36Sopenharmony_ci			}
72962306a36Sopenharmony_ci		}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		/* Stop pending led requests */
73262306a36Sopenharmony_ci		while (leds_req_pending)
73362306a36Sopenharmony_ci			adb_poll();
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		/* After resume, and if the capslock LED is on, the PMU will
73662306a36Sopenharmony_ci		 * send a "capslock down" key event. This confuses the
73762306a36Sopenharmony_ci		 * restore_capslock_events logic. Remember if the capslock
73862306a36Sopenharmony_ci		 * LED was on before suspend so the unwanted key event can
73962306a36Sopenharmony_ci		 * be ignored after resume. */
74062306a36Sopenharmony_ci		if (restore_capslock_events)
74162306a36Sopenharmony_ci			adbhid_kbd_capslock_remember();
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci		break;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	case ADB_MSG_POST_RESET:
74662306a36Sopenharmony_ci		adbhid_probe();
74762306a36Sopenharmony_ci		break;
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci	return NOTIFY_DONE;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_cistatic int
75362306a36Sopenharmony_ciadbhid_input_register(int id, int default_id, int original_handler_id,
75462306a36Sopenharmony_ci		      int current_handler_id, int mouse_kind)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct adbhid *hid;
75762306a36Sopenharmony_ci	struct input_dev *input_dev;
75862306a36Sopenharmony_ci	int err;
75962306a36Sopenharmony_ci	int i;
76062306a36Sopenharmony_ci	char *keyboard_type;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (adbhid[id]) {
76362306a36Sopenharmony_ci		pr_err("Trying to reregister ADB HID on ID %d\n", id);
76462306a36Sopenharmony_ci		return -EEXIST;
76562306a36Sopenharmony_ci	}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	adbhid[id] = hid = kzalloc(sizeof(struct adbhid), GFP_KERNEL);
76862306a36Sopenharmony_ci	input_dev = input_allocate_device();
76962306a36Sopenharmony_ci	if (!hid || !input_dev) {
77062306a36Sopenharmony_ci		err = -ENOMEM;
77162306a36Sopenharmony_ci		goto fail;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	sprintf(hid->phys, "adb%d:%d.%02x/input", id, default_id, original_handler_id);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	hid->input = input_dev;
77762306a36Sopenharmony_ci	hid->id = default_id;
77862306a36Sopenharmony_ci	hid->original_handler_id = original_handler_id;
77962306a36Sopenharmony_ci	hid->current_handler_id = current_handler_id;
78062306a36Sopenharmony_ci	hid->mouse_kind = mouse_kind;
78162306a36Sopenharmony_ci	hid->flags = 0;
78262306a36Sopenharmony_ci	input_set_drvdata(input_dev, hid);
78362306a36Sopenharmony_ci	input_dev->name = hid->name;
78462306a36Sopenharmony_ci	input_dev->phys = hid->phys;
78562306a36Sopenharmony_ci	input_dev->id.bustype = BUS_ADB;
78662306a36Sopenharmony_ci	input_dev->id.vendor = 0x0001;
78762306a36Sopenharmony_ci	input_dev->id.product = (id << 12) | (default_id << 8) | original_handler_id;
78862306a36Sopenharmony_ci	input_dev->id.version = 0x0100;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	switch (default_id) {
79162306a36Sopenharmony_ci	case ADB_KEYBOARD:
79262306a36Sopenharmony_ci		hid->keycode = kmemdup(adb_to_linux_keycodes,
79362306a36Sopenharmony_ci				       sizeof(adb_to_linux_keycodes), GFP_KERNEL);
79462306a36Sopenharmony_ci		if (!hid->keycode) {
79562306a36Sopenharmony_ci			err = -ENOMEM;
79662306a36Sopenharmony_ci			goto fail;
79762306a36Sopenharmony_ci		}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		sprintf(hid->name, "ADB keyboard");
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		switch (original_handler_id) {
80262306a36Sopenharmony_ci		default:
80362306a36Sopenharmony_ci			keyboard_type = "<unknown>";
80462306a36Sopenharmony_ci			input_dev->id.version = ADB_KEYBOARD_UNKNOWN;
80562306a36Sopenharmony_ci			break;
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		case 0x01: case 0x02: case 0x03: case 0x06: case 0x08:
80862306a36Sopenharmony_ci		case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C:
80962306a36Sopenharmony_ci		case 0xC0: case 0xC3: case 0xC6:
81062306a36Sopenharmony_ci			keyboard_type = "ANSI";
81162306a36Sopenharmony_ci			input_dev->id.version = ADB_KEYBOARD_ANSI;
81262306a36Sopenharmony_ci			break;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D:
81562306a36Sopenharmony_ci		case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1:
81662306a36Sopenharmony_ci		case 0xC4: case 0xC7:
81762306a36Sopenharmony_ci			keyboard_type = "ISO, swapping keys";
81862306a36Sopenharmony_ci			input_dev->id.version = ADB_KEYBOARD_ISO;
81962306a36Sopenharmony_ci			swap(hid->keycode[10], hid->keycode[50]);
82062306a36Sopenharmony_ci			break;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci		case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A:
82362306a36Sopenharmony_ci		case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
82462306a36Sopenharmony_ci			keyboard_type = "JIS";
82562306a36Sopenharmony_ci			input_dev->id.version = ADB_KEYBOARD_JIS;
82662306a36Sopenharmony_ci			break;
82762306a36Sopenharmony_ci		}
82862306a36Sopenharmony_ci		pr_info("Detected ADB keyboard, type %s.\n", keyboard_type);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		for (i = 0; i < 128; i++)
83162306a36Sopenharmony_ci			if (hid->keycode[i])
83262306a36Sopenharmony_ci				set_bit(hid->keycode[i], input_dev->keybit);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
83562306a36Sopenharmony_ci			BIT_MASK(EV_REP);
83662306a36Sopenharmony_ci		input_dev->ledbit[0] = BIT_MASK(LED_SCROLLL) |
83762306a36Sopenharmony_ci			BIT_MASK(LED_CAPSL) | BIT_MASK(LED_NUML);
83862306a36Sopenharmony_ci		input_dev->event = adbhid_kbd_event;
83962306a36Sopenharmony_ci		input_dev->keycodemax = KEY_FN;
84062306a36Sopenharmony_ci		input_dev->keycodesize = sizeof(hid->keycode[0]);
84162306a36Sopenharmony_ci		break;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	case ADB_MOUSE:
84462306a36Sopenharmony_ci		sprintf(hid->name, "ADB mouse");
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
84762306a36Sopenharmony_ci		input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
84862306a36Sopenharmony_ci			BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
84962306a36Sopenharmony_ci		input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
85062306a36Sopenharmony_ci		break;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	case ADB_MISC:
85362306a36Sopenharmony_ci		switch (original_handler_id) {
85462306a36Sopenharmony_ci		case 0x02: /* Adjustable keyboard button device */
85562306a36Sopenharmony_ci			sprintf(hid->name, "ADB adjustable keyboard buttons");
85662306a36Sopenharmony_ci			input_dev->evbit[0] = BIT_MASK(EV_KEY) |
85762306a36Sopenharmony_ci				BIT_MASK(EV_REP);
85862306a36Sopenharmony_ci			set_bit(KEY_SOUND, input_dev->keybit);
85962306a36Sopenharmony_ci			set_bit(KEY_MUTE, input_dev->keybit);
86062306a36Sopenharmony_ci			set_bit(KEY_VOLUMEUP, input_dev->keybit);
86162306a36Sopenharmony_ci			set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
86262306a36Sopenharmony_ci			break;
86362306a36Sopenharmony_ci		case 0x1f: /* Powerbook button device */
86462306a36Sopenharmony_ci			sprintf(hid->name, "ADB Powerbook buttons");
86562306a36Sopenharmony_ci			input_dev->evbit[0] = BIT_MASK(EV_KEY) |
86662306a36Sopenharmony_ci				BIT_MASK(EV_REP);
86762306a36Sopenharmony_ci			set_bit(KEY_MUTE, input_dev->keybit);
86862306a36Sopenharmony_ci			set_bit(KEY_VOLUMEUP, input_dev->keybit);
86962306a36Sopenharmony_ci			set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
87062306a36Sopenharmony_ci			set_bit(KEY_BRIGHTNESSUP, input_dev->keybit);
87162306a36Sopenharmony_ci			set_bit(KEY_BRIGHTNESSDOWN, input_dev->keybit);
87262306a36Sopenharmony_ci			set_bit(KEY_EJECTCD, input_dev->keybit);
87362306a36Sopenharmony_ci			set_bit(KEY_SWITCHVIDEOMODE, input_dev->keybit);
87462306a36Sopenharmony_ci			set_bit(KEY_KBDILLUMTOGGLE, input_dev->keybit);
87562306a36Sopenharmony_ci			set_bit(KEY_KBDILLUMDOWN, input_dev->keybit);
87662306a36Sopenharmony_ci			set_bit(KEY_KBDILLUMUP, input_dev->keybit);
87762306a36Sopenharmony_ci			break;
87862306a36Sopenharmony_ci		}
87962306a36Sopenharmony_ci		if (hid->name[0])
88062306a36Sopenharmony_ci			break;
88162306a36Sopenharmony_ci		fallthrough;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	default:
88462306a36Sopenharmony_ci		pr_info("Trying to register unknown ADB device to input layer.\n");
88562306a36Sopenharmony_ci		err = -ENODEV;
88662306a36Sopenharmony_ci		goto fail;
88762306a36Sopenharmony_ci	}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	input_dev->keycode = hid->keycode;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	err = input_register_device(input_dev);
89262306a36Sopenharmony_ci	if (err)
89362306a36Sopenharmony_ci		goto fail;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (default_id == ADB_KEYBOARD) {
89662306a36Sopenharmony_ci		/* HACK WARNING!! This should go away as soon there is an utility
89762306a36Sopenharmony_ci		 * to control that for event devices.
89862306a36Sopenharmony_ci		 */
89962306a36Sopenharmony_ci		input_dev->rep[REP_DELAY] = 500;   /* input layer default: 250 */
90062306a36Sopenharmony_ci		input_dev->rep[REP_PERIOD] = 66; /* input layer default: 33 */
90162306a36Sopenharmony_ci	}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	return 0;
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci fail:	input_free_device(input_dev);
90662306a36Sopenharmony_ci	if (hid) {
90762306a36Sopenharmony_ci		kfree(hid->keycode);
90862306a36Sopenharmony_ci		kfree(hid);
90962306a36Sopenharmony_ci	}
91062306a36Sopenharmony_ci	adbhid[id] = NULL;
91162306a36Sopenharmony_ci	return err;
91262306a36Sopenharmony_ci}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic void adbhid_input_unregister(int id)
91562306a36Sopenharmony_ci{
91662306a36Sopenharmony_ci	input_unregister_device(adbhid[id]->input);
91762306a36Sopenharmony_ci	kfree(adbhid[id]->keycode);
91862306a36Sopenharmony_ci	kfree(adbhid[id]);
91962306a36Sopenharmony_ci	adbhid[id] = NULL;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_cistatic u16
92462306a36Sopenharmony_ciadbhid_input_reregister(int id, int default_id, int org_handler_id,
92562306a36Sopenharmony_ci			int cur_handler_id, int mk)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	if (adbhid[id]) {
92862306a36Sopenharmony_ci		if (adbhid[id]->input->id.product !=
92962306a36Sopenharmony_ci		    ((id << 12)|(default_id << 8)|org_handler_id)) {
93062306a36Sopenharmony_ci			adbhid_input_unregister(id);
93162306a36Sopenharmony_ci			adbhid_input_register(id, default_id, org_handler_id,
93262306a36Sopenharmony_ci					      cur_handler_id, mk);
93362306a36Sopenharmony_ci		}
93462306a36Sopenharmony_ci	} else
93562306a36Sopenharmony_ci		adbhid_input_register(id, default_id, org_handler_id,
93662306a36Sopenharmony_ci				      cur_handler_id, mk);
93762306a36Sopenharmony_ci	return 1<<id;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic void
94162306a36Sopenharmony_ciadbhid_input_devcleanup(u16 exist)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	int i;
94462306a36Sopenharmony_ci	for(i=1; i<16; i++)
94562306a36Sopenharmony_ci		if (adbhid[i] && !(exist&(1<<i)))
94662306a36Sopenharmony_ci			adbhid_input_unregister(i);
94762306a36Sopenharmony_ci}
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void
95062306a36Sopenharmony_ciadbhid_probe(void)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct adb_request req;
95362306a36Sopenharmony_ci	int i, default_id, org_handler_id, cur_handler_id;
95462306a36Sopenharmony_ci	u16 reg = 0;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	adb_register(ADB_MOUSE, 0, &mouse_ids, adbhid_mouse_input);
95762306a36Sopenharmony_ci	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, adbhid_keyboard_input);
95862306a36Sopenharmony_ci	adb_register(ADB_MISC, 0, &buttons_ids, adbhid_buttons_input);
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	for (i = 0; i < keyboard_ids.nids; i++) {
96162306a36Sopenharmony_ci		int id = keyboard_ids.id[i];
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		adb_get_infos(id, &default_id, &org_handler_id);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci		/* turn off all leds */
96662306a36Sopenharmony_ci		adb_request(&req, NULL, ADBREQ_SYNC, 3,
96762306a36Sopenharmony_ci			    ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		/* Enable full feature set of the keyboard
97062306a36Sopenharmony_ci		   ->get it to send separate codes for left and right shift,
97162306a36Sopenharmony_ci		   control, option keys */
97262306a36Sopenharmony_ci#if 0		/* handler 5 doesn't send separate codes for R modifiers */
97362306a36Sopenharmony_ci		if (!adb_try_handler_change(id, 5))
97462306a36Sopenharmony_ci#endif
97562306a36Sopenharmony_ci		adb_try_handler_change(id, 3);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci		adb_get_infos(id, &default_id, &cur_handler_id);
97862306a36Sopenharmony_ci		printk(KERN_DEBUG "ADB keyboard at %d has handler 0x%X\n",
97962306a36Sopenharmony_ci		       id, cur_handler_id);
98062306a36Sopenharmony_ci		reg |= adbhid_input_reregister(id, default_id, org_handler_id,
98162306a36Sopenharmony_ci					       cur_handler_id, 0);
98262306a36Sopenharmony_ci	}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	for (i = 0; i < buttons_ids.nids; i++) {
98562306a36Sopenharmony_ci		int id = buttons_ids.id[i];
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		adb_get_infos(id, &default_id, &org_handler_id);
98862306a36Sopenharmony_ci		reg |= adbhid_input_reregister(id, default_id, org_handler_id,
98962306a36Sopenharmony_ci					       org_handler_id, 0);
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	/* Try to switch all mice to handler 4, or 2 for three-button
99362306a36Sopenharmony_ci	   mode and full resolution. */
99462306a36Sopenharmony_ci	for (i = 0; i < mouse_ids.nids; i++) {
99562306a36Sopenharmony_ci		int id = mouse_ids.id[i];
99662306a36Sopenharmony_ci		int mouse_kind;
99762306a36Sopenharmony_ci		char *desc = "standard";
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci		adb_get_infos(id, &default_id, &org_handler_id);
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		if (adb_try_handler_change(id, 4)) {
100262306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_EXTENDED;
100362306a36Sopenharmony_ci		}
100462306a36Sopenharmony_ci		else if (adb_try_handler_change(id, 0x2F)) {
100562306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_MICROSPEED;
100662306a36Sopenharmony_ci		}
100762306a36Sopenharmony_ci		else if (adb_try_handler_change(id, 0x42)) {
100862306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_TRACKBALLPRO;
100962306a36Sopenharmony_ci		}
101062306a36Sopenharmony_ci		else if (adb_try_handler_change(id, 0x66)) {
101162306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_MICROSPEED;
101262306a36Sopenharmony_ci		}
101362306a36Sopenharmony_ci		else if (adb_try_handler_change(id, 0x5F)) {
101462306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_MICROSPEED;
101562306a36Sopenharmony_ci		}
101662306a36Sopenharmony_ci		else if (adb_try_handler_change(id, 3)) {
101762306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_MS_A3;
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci		else if (adb_try_handler_change(id, 2)) {
102062306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_STANDARD_200;
102162306a36Sopenharmony_ci		}
102262306a36Sopenharmony_ci		else {
102362306a36Sopenharmony_ci			mouse_kind = ADBMOUSE_STANDARD_100;
102462306a36Sopenharmony_ci		}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci		if ((mouse_kind == ADBMOUSE_TRACKBALLPRO)
102762306a36Sopenharmony_ci		    || (mouse_kind == ADBMOUSE_MICROSPEED)) {
102862306a36Sopenharmony_ci			desc = "Microspeed/MacPoint or compatible";
102962306a36Sopenharmony_ci			init_microspeed(id);
103062306a36Sopenharmony_ci		} else if (mouse_kind == ADBMOUSE_MS_A3) {
103162306a36Sopenharmony_ci			desc = "Mouse Systems A3 Mouse or compatible";
103262306a36Sopenharmony_ci			init_ms_a3(id);
103362306a36Sopenharmony_ci		} else if (mouse_kind ==  ADBMOUSE_EXTENDED) {
103462306a36Sopenharmony_ci			desc = "extended";
103562306a36Sopenharmony_ci			/*
103662306a36Sopenharmony_ci			 * Register 1 is usually used for device
103762306a36Sopenharmony_ci			 * identification.  Here, we try to identify
103862306a36Sopenharmony_ci			 * a known device and call the appropriate
103962306a36Sopenharmony_ci			 * init function.
104062306a36Sopenharmony_ci			 */
104162306a36Sopenharmony_ci			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
104262306a36Sopenharmony_ci				    ADB_READREG(id, 1));
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci			if ((req.reply_len) &&
104562306a36Sopenharmony_ci			    (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
104662306a36Sopenharmony_ci			    	|| (req.reply[2] == 0x20))) {
104762306a36Sopenharmony_ci				mouse_kind = ADBMOUSE_TRACKBALL;
104862306a36Sopenharmony_ci				desc = "trackman/mouseman";
104962306a36Sopenharmony_ci				init_trackball(id);
105062306a36Sopenharmony_ci			}
105162306a36Sopenharmony_ci			else if ((req.reply_len >= 4) &&
105262306a36Sopenharmony_ci			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
105362306a36Sopenharmony_ci			    (req.reply[3] == 0x61) && (req.reply[4] == 0x64)) {
105462306a36Sopenharmony_ci				mouse_kind = ADBMOUSE_TRACKPAD;
105562306a36Sopenharmony_ci				desc = "trackpad";
105662306a36Sopenharmony_ci				init_trackpad(id);
105762306a36Sopenharmony_ci			}
105862306a36Sopenharmony_ci			else if ((req.reply_len >= 4) &&
105962306a36Sopenharmony_ci			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
106062306a36Sopenharmony_ci			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31)) {
106162306a36Sopenharmony_ci				mouse_kind = ADBMOUSE_TURBOMOUSE5;
106262306a36Sopenharmony_ci				desc = "TurboMouse 5";
106362306a36Sopenharmony_ci				init_turbomouse(id);
106462306a36Sopenharmony_ci			}
106562306a36Sopenharmony_ci			else if ((req.reply_len == 9) &&
106662306a36Sopenharmony_ci			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
106762306a36Sopenharmony_ci			    (req.reply[3] == 0x49) && (req.reply[4] == 0x54)) {
106862306a36Sopenharmony_ci				if (adb_try_handler_change(id, 0x42)) {
106962306a36Sopenharmony_ci					mouse_kind = ADBMOUSE_MACALLY2;
107062306a36Sopenharmony_ci					desc = "MacAlly 2-button";
107162306a36Sopenharmony_ci				}
107262306a36Sopenharmony_ci			}
107362306a36Sopenharmony_ci		}
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci		adb_get_infos(id, &default_id, &cur_handler_id);
107662306a36Sopenharmony_ci		printk(KERN_DEBUG "ADB mouse (%s) at %d has handler 0x%X\n",
107762306a36Sopenharmony_ci		       desc, id, cur_handler_id);
107862306a36Sopenharmony_ci		reg |= adbhid_input_reregister(id, default_id, org_handler_id,
107962306a36Sopenharmony_ci					       cur_handler_id, mouse_kind);
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci	adbhid_input_devcleanup(reg);
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic void
108562306a36Sopenharmony_ciinit_trackpad(int id)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct adb_request req;
108862306a36Sopenharmony_ci	unsigned char r1_buffer[8];
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
109162306a36Sopenharmony_ci		    ADB_READREG(id,1));
109262306a36Sopenharmony_ci	if (req.reply_len < 8)
109362306a36Sopenharmony_ci		pr_err("%s: bad length for reg. 1\n", __func__);
109462306a36Sopenharmony_ci	else
109562306a36Sopenharmony_ci	{
109662306a36Sopenharmony_ci	    memcpy(r1_buffer, &req.reply[1], 8);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
109962306a36Sopenharmony_ci	        ADB_WRITEREG(id,1),
110062306a36Sopenharmony_ci	            r1_buffer[0],
110162306a36Sopenharmony_ci	            r1_buffer[1],
110262306a36Sopenharmony_ci	            r1_buffer[2],
110362306a36Sopenharmony_ci	            r1_buffer[3],
110462306a36Sopenharmony_ci	            r1_buffer[4],
110562306a36Sopenharmony_ci	            r1_buffer[5],
110662306a36Sopenharmony_ci	            0x0d,
110762306a36Sopenharmony_ci	            r1_buffer[7]);
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci            adb_request(&req, NULL, ADBREQ_SYNC, 9,
111062306a36Sopenharmony_ci	        ADB_WRITEREG(id,2),
111162306a36Sopenharmony_ci	    	    0x99,
111262306a36Sopenharmony_ci	    	    0x94,
111362306a36Sopenharmony_ci	    	    0x19,
111462306a36Sopenharmony_ci	    	    0xff,
111562306a36Sopenharmony_ci	    	    0xb2,
111662306a36Sopenharmony_ci	    	    0x8a,
111762306a36Sopenharmony_ci	    	    0x1b,
111862306a36Sopenharmony_ci	    	    0x50);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
112162306a36Sopenharmony_ci	        ADB_WRITEREG(id,1),
112262306a36Sopenharmony_ci	            r1_buffer[0],
112362306a36Sopenharmony_ci	            r1_buffer[1],
112462306a36Sopenharmony_ci	            r1_buffer[2],
112562306a36Sopenharmony_ci	            r1_buffer[3],
112662306a36Sopenharmony_ci	            r1_buffer[4],
112762306a36Sopenharmony_ci	            r1_buffer[5],
112862306a36Sopenharmony_ci	            0x03, /*r1_buffer[6],*/
112962306a36Sopenharmony_ci	            r1_buffer[7]);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	    /* Without this flush, the trackpad may be locked up */
113262306a36Sopenharmony_ci	    adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
113362306a36Sopenharmony_ci        }
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_cistatic void
113762306a36Sopenharmony_ciinit_trackball(int id)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	struct adb_request req;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
114262306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 00,0x81);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
114562306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 01,0x81);
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
114862306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 02,0x81);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
115162306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 03,0x38);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
115462306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 00,0x81);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
115762306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 01,0x81);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
116062306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 02,0x81);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
116362306a36Sopenharmony_ci	ADB_WRITEREG(id,1), 03,0x38);
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic void
116762306a36Sopenharmony_ciinit_turbomouse(int id)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	struct adb_request req;
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 9,
117662306a36Sopenharmony_ci	ADB_WRITEREG(3,2),
117762306a36Sopenharmony_ci	    0xe7,
117862306a36Sopenharmony_ci	    0x8c,
117962306a36Sopenharmony_ci	    0,
118062306a36Sopenharmony_ci	    0,
118162306a36Sopenharmony_ci	    0,
118262306a36Sopenharmony_ci	    0xff,
118362306a36Sopenharmony_ci	    0xff,
118462306a36Sopenharmony_ci	    0x94);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 9,
118962306a36Sopenharmony_ci	ADB_WRITEREG(3,2),
119062306a36Sopenharmony_ci	    0xa5,
119162306a36Sopenharmony_ci	    0x14,
119262306a36Sopenharmony_ci	    0,
119362306a36Sopenharmony_ci	    0,
119462306a36Sopenharmony_ci	    0x69,
119562306a36Sopenharmony_ci	    0xff,
119662306a36Sopenharmony_ci	    0xff,
119762306a36Sopenharmony_ci	    0x27);
119862306a36Sopenharmony_ci}
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic void
120162306a36Sopenharmony_ciinit_microspeed(int id)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	struct adb_request req;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/* This will initialize mice using the Microspeed, MacPoint and
120862306a36Sopenharmony_ci	   other compatible firmware. Bit 12 enables extended protocol.
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	   Register 1 Listen (4 Bytes)
121162306a36Sopenharmony_ci            0 -  3     Button is mouse (set also for double clicking!!!)
121262306a36Sopenharmony_ci            4 -  7     Button is locking (affects change speed also)
121362306a36Sopenharmony_ci            8 - 11     Button changes speed
121462306a36Sopenharmony_ci           12          1 = Extended mouse mode, 0 = normal mouse mode
121562306a36Sopenharmony_ci           13 - 15     unused 0
121662306a36Sopenharmony_ci           16 - 23     normal speed
121762306a36Sopenharmony_ci           24 - 31     changed speed
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci       Register 1 talk holds version and product identification information.
122062306a36Sopenharmony_ci       Register 1 Talk (4 Bytes):
122162306a36Sopenharmony_ci            0 -  7     Product code
122262306a36Sopenharmony_ci            8 - 23     undefined, reserved
122362306a36Sopenharmony_ci           24 - 31     Version number
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci       Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
122662306a36Sopenharmony_ci */
122762306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 5,
122862306a36Sopenharmony_ci	ADB_WRITEREG(id,1),
122962306a36Sopenharmony_ci	    0x20,	/* alt speed = 0x20 (rather slow) */
123062306a36Sopenharmony_ci	    0x00,	/* norm speed = 0x00 (fastest) */
123162306a36Sopenharmony_ci	    0x10,	/* extended protocol, no speed change */
123262306a36Sopenharmony_ci	    0x07);	/* all buttons enabled as mouse buttons, no locking */
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic void
123962306a36Sopenharmony_ciinit_ms_a3(int id)
124062306a36Sopenharmony_ci{
124162306a36Sopenharmony_ci	struct adb_request req;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	adb_request(&req, NULL, ADBREQ_SYNC, 3,
124462306a36Sopenharmony_ci	ADB_WRITEREG(id, 0x2),
124562306a36Sopenharmony_ci	    0x00,
124662306a36Sopenharmony_ci	    0x07);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci 	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic int __init adbhid_init(void)
125262306a36Sopenharmony_ci{
125362306a36Sopenharmony_ci#ifndef CONFIG_MAC
125462306a36Sopenharmony_ci	if (!machine_is(chrp) && !machine_is(powermac))
125562306a36Sopenharmony_ci		return 0;
125662306a36Sopenharmony_ci#endif
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	led_request.complete = 1;
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	adbhid_probe();
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	blocking_notifier_chain_register(&adb_client_list,
126362306a36Sopenharmony_ci			&adbhid_adb_notifier);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	return 0;
126662306a36Sopenharmony_ci}
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_cistatic void __exit adbhid_exit(void)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cimodule_init(adbhid_init);
127362306a36Sopenharmony_cimodule_exit(adbhid_exit);
1274