// SPDX-License-Identifier: GPL-2.0 /* * drivers/macintosh/adbhid.c * * ADB HID driver for Power Macintosh computers. * * Adapted from drivers/macintosh/mac_keyb.c by Franz Sirl. * drivers/macintosh/mac_keyb.c was Copyright (C) 1996 Paul Mackerras * with considerable contributions from Ben Herrenschmidt and others. * * Copyright (C) 2000 Franz Sirl. * * Adapted to ADB changes and support for more devices by * Benjamin Herrenschmidt. Adapted from code in MkLinux * and reworked. * * Supported devices: * * - Standard 1 button mouse * - All standard Apple Extended protocol (handler ID 4) * - mouseman and trackman mice & trackballs * - PowerBook Trackpad (default setup: enable tapping) * - MicroSpeed mouse & trackball (needs testing) * - CH Products Trackball Pro (needs testing) * - Contour Design (Contour Mouse) * - Hunter digital (NoHandsMouse) * - Kensignton TurboMouse 5 (needs testing) * - Mouse Systems A3 mice and trackballs <aidan@kublai.com> * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it> * * To do: * * Improve Kensington support. * Split mouse/kbd * Move to syfs
*/
staticint restore_capslock_events;
module_param(restore_capslock_events, int, 0644);
MODULE_PARM_DESC(restore_capslock_events, "Produce keypress events for capslock on both keyup and keydown.");
#define KEYB_KEYREG 0 /* register # for key up/down data */ #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */
struct adbhid { struct input_dev *input; int id; int default_id; int original_handler_id; int current_handler_id; int mouse_kind;
u16 *keycode; char name[64]; char phys[32]; int flags;
};
if (restore_capslock_events) { if (keycode == ADB_KEY_CAPSLOCK && !up_flag) { /* Key pressed, turning on the CapsLock LED.
* The next 0xff will be interpreted as a release. */ if (ahid->flags & FLAG_CAPSLOCK_IGNORE_NEXT) { /* Throw away this key event if it happens
* just after resume. */
ahid->flags &= ~FLAG_CAPSLOCK_IGNORE_NEXT; return;
} else {
ahid->flags |= FLAG_CAPSLOCK_TRANSLATE
| FLAG_CAPSLOCK_DOWN;
}
} elseif (scancode == 0xff &&
!(ahid->flags & FLAG_POWER_KEY_PRESSED)) { /* Scancode 0xff usually signifies that the capslock * key was either pressed or released, or that the
* power button was released. */ if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) {
keycode = ADB_KEY_CAPSLOCK; if (ahid->flags & FLAG_CAPSLOCK_DOWN) { /* Key released */
up_flag = 1;
ahid->flags &= ~FLAG_CAPSLOCK_DOWN;
} else { /* Key pressed */
up_flag = 0;
ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE;
}
} else {
pr_info("Spurious caps lock event (scancode 0xff).\n");
}
}
}
switch (keycode) { case ADB_KEY_CAPSLOCK: if (!restore_capslock_events) { /* Generate down/up events for CapsLock every time. */
input_report_key(ahid->input, KEY_CAPSLOCK, 1);
input_sync(ahid->input);
input_report_key(ahid->input, KEY_CAPSLOCK, 0);
input_sync(ahid->input); return;
} break; #ifdef CONFIG_PPC_PMAC case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO,
NULL, PMAC_MB_INFO_MODEL, 0)) { case PMAC_TYPE_COMET: case PMAC_TYPE_HOOPER: case PMAC_TYPE_KANGA:
keycode = ADB_KEY_POWER;
} break; case ADB_KEY_POWER: /* Keep track of the power key state */ if (up_flag)
ahid->flags &= ~FLAG_POWER_KEY_PRESSED; else
ahid->flags |= FLAG_POWER_KEY_PRESSED;
/* Fn + Command will produce a bogus "power" keycode */ if (ahid->flags & FLAG_FN_KEY_PRESSED) {
keycode = ADB_KEY_CMD; if (up_flag)
ahid->flags &= ~FLAG_POWER_FROM_FN; else
ahid->flags |= FLAG_POWER_FROM_FN;
} elseif (ahid->flags & FLAG_POWER_FROM_FN) {
keycode = ADB_KEY_CMD;
ahid->flags &= ~FLAG_POWER_FROM_FN;
} break; case ADB_KEY_FN: /* Keep track of the Fn key state */ if (up_flag) {
ahid->flags &= ~FLAG_FN_KEY_PRESSED; /* Emulate Fn+delete = forward delete */ if (ahid->flags & FLAG_EMU_FWDEL_DOWN) {
ahid->flags &= ~FLAG_EMU_FWDEL_DOWN;
keycode = ADB_KEY_FWDEL; break;
}
} else
ahid->flags |= FLAG_FN_KEY_PRESSED; break; case ADB_KEY_DEL: /* Emulate Fn+delete = forward delete */ if (ahid->flags & FLAG_FN_KEY_PRESSED) {
keycode = ADB_KEY_FWDEL; if (up_flag)
ahid->flags &= ~FLAG_EMU_FWDEL_DOWN; else
ahid->flags |= FLAG_EMU_FWDEL_DOWN;
} break; #endif/* CONFIG_PPC_PMAC */
}
staticvoid
adbhid_mouse_input(unsignedchar *data, int nb, int autopoll)
{ int id = (data[0] >> 4) & 0x0f;
if (!adbhid[id]) {
pr_err("ADB HID on ID %d not yet registered\n", id); return;
}
/* Handler 1 -- 100cpi original Apple mouse protocol. Handler 2 -- 200cpi original Apple mouse protocol.
For Apple's standard one-button mouse protocol the data array will contain the following values:
BITS COMMENTS data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. data[1] = bxxx xxxx First button and x-axis motion. data[2] = byyy yyyy Second button and y-axis motion.
Handler 4 -- Apple Extended mouse protocol.
For Apple's 3-button mouse protocol the data array will contain the following values:
BITS COMMENTS data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. data[1] = bxxx xxxx Left button and x-axis motion. data[2] = byyy yyyy Second button and y-axis motion. data[3] = byyy bxxx Third button and fourth button. Y is additional high bits of y-axis motion. XY is additional high bits of x-axis motion.
MacAlly 2-button mouse protocol.
For MacAlly 2-button mouse protocol the data array will contain the following values:
BITS COMMENTS data[0] = dddd 1100 ADB command: Talk, register 0, for device dddd. data[1] = bxxx xxxx Left button and x-axis motion. data[2] = byyy yyyy Right button and y-axis motion. data[3] = ???? ???? unknown data[4] = ???? ???? unknown
*/
/* If it's a trackpad, we alias the second button to the first. NOTE: Apple sends an ADB flush command to the trackpad when the first (the real) button is released. We could do this here using async flush requests.
*/ switch (adbhid[id]->mouse_kind)
{ case ADBMOUSE_TRACKPAD:
data[1] = (data[1] & 0x7f) | ((data[1] & data[2]) & 0x80);
data[2] = data[2] | 0x80; break; case ADBMOUSE_MICROSPEED:
data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
data[3] = (data[3] & 0x77) | ((data[3] & 0x04) << 5)
| (data[3] & 0x08); break; case ADBMOUSE_TRACKBALLPRO:
data[1] = (data[1] & 0x7f) | (((data[3] & 0x04) << 5)
& ((data[3] & 0x08) << 4));
data[2] = (data[2] & 0x7f) | ((data[3] & 0x01) << 7);
data[3] = (data[3] & 0x77) | ((data[3] & 0x02) << 6); break; case ADBMOUSE_MS_A3:
data[1] = (data[1] & 0x7f) | ((data[3] & 0x01) << 7);
data[2] = (data[2] & 0x7f) | ((data[3] & 0x02) << 6);
data[3] = ((data[3] & 0x04) << 5); break; case ADBMOUSE_MACALLY2:
data[3] = (data[2] & 0x80) ? 0x80 : 0x00;
data[2] |= 0x80; /* Right button is mapped as button 3 */
nb=4; break;
}
/* * Event callback from the input module. Events that change the state of * the hardware are processed here.
*/ staticint adbhid_kbd_event(struct input_dev *dev, unsignedint type, unsignedint code, int value)
{ struct adbhid *adbhid = input_get_drvdata(dev); unsignedchar leds;
staticvoid
adbhid_kbd_capslock_remember(void)
{ struct adbhid *ahid; int i;
for (i = 1; i < 16; i++) {
ahid = adbhid[i];
if (ahid && ahid->id == ADB_KEYBOARD) if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE)
ahid->flags |= FLAG_CAPSLOCK_IGNORE_NEXT;
}
}
staticint
adb_message_handler(struct notifier_block *this, unsignedlong code, void *x)
{ switch (code) { case ADB_MSG_PRE_RESET: case ADB_MSG_POWERDOWN: /* Stop the repeat timer. Autopoll is already off at this point */
{ int i; for (i = 1; i < 16; i++) { if (adbhid[i])
timer_delete_sync(&adbhid[i]->input->timer);
}
}
/* Stop pending led requests */ while (leds_req_pending)
adb_poll();
/* After resume, and if the capslock LED is on, the PMU will * send a "capslock down" key event. This confuses the * restore_capslock_events logic. Remember if the capslock * LED was on before suspend so the unwanted key event can
* be ignored after resume. */ if (restore_capslock_events)
adbhid_kbd_capslock_remember();
break;
case ADB_MSG_POST_RESET:
adbhid_probe(); break;
} return NOTIFY_DONE;
}
staticint
adbhid_input_register(int id, int default_id, int original_handler_id, int current_handler_id, int mouse_kind)
{ struct adbhid *hid; struct input_dev *input_dev; int err; int i; char *keyboard_type;
if (adbhid[id]) {
pr_err("Trying to reregister ADB HID on ID %d\n", id); return -EEXIST;
}
case 0x01: case 0x02: case 0x03: case 0x06: case 0x08: case 0x0C: case 0x10: case 0x18: case 0x1B: case 0x1C: case 0xC0: case 0xC3: case 0xC6:
keyboard_type = "ANSI";
input_dev->id.version = ADB_KEYBOARD_ANSI; break;
case 0x04: case 0x05: case 0x07: case 0x09: case 0x0D: case 0x11: case 0x14: case 0x19: case 0x1D: case 0xC1: case 0xC4: case 0xC7:
keyboard_type = "ISO, swapping keys";
input_dev->id.version = ADB_KEYBOARD_ISO;
swap(hid->keycode[10], hid->keycode[50]); break;
case 0x12: case 0x15: case 0x16: case 0x17: case 0x1A: case 0x1E: case 0xC2: case 0xC5: case 0xC8: case 0xC9:
keyboard_type = "JIS";
input_dev->id.version = ADB_KEYBOARD_JIS; break;
}
pr_info("Detected ADB keyboard, type %s.\n", keyboard_type);
for (i = 0; i < 128; i++) if (hid->keycode[i])
set_bit(hid->keycode[i], input_dev->keybit);
default:
pr_info("Trying to register unknown ADB device to input layer.\n");
err = -ENODEV; goto fail;
}
input_dev->keycode = hid->keycode;
err = input_register_device(input_dev); if (err) goto fail;
if (default_id == ADB_KEYBOARD) { /* HACK WARNING!! This should go away as soon there is an utility * to control that for event devices.
*/
input_dev->rep[REP_DELAY] = 500; /* input layer default: 250 */
input_dev->rep[REP_PERIOD] = 66; /* input layer default: 33 */
}
for (i = 0; i < keyboard_ids.nids; i++) { int id = keyboard_ids.id[i];
adb_get_infos(id, &default_id, &org_handler_id);
/* turn off all leds */
adb_request(&req, NULL, ADBREQ_SYNC, 3,
ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
/* Enable full feature set of the keyboard ->get it to send separate codes for left and right shift,
control, option keys */ #if 0 /* handler 5 doesn't send separate codes for R modifiers */ if (!adb_try_handler_change(id, 5)) #endif
adb_try_handler_change(id, 3);
/* Try to switch all mice to handler 4, or 2 for three-button
mode and full resolution. */ for (i = 0; i < mouse_ids.nids; i++) { int id = mouse_ids.id[i]; int mouse_kind; char *desc = "standard";
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.