// SPDX-License-Identifier: GPL-2.0-only /* * AT and PS/2 keyboard driver * * Copyright (c) 1999-2002 Vojtech Pavlik
*/
/* * This driver can handle standard AT keyboards and PS/2 keyboards in * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb * input-only controllers and AT keyboards connected over a one way RS232 * converter.
*/
staticbool atkbd_scroll;
module_param_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
staticbool atkbd_extra;
module_param_named(extra, atkbd_extra, bool, 0);
MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards");
staticbool atkbd_terminal;
module_param_named(terminal, atkbd_terminal, bool, 0);
MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
/* * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed.
*/ staticbool atkbd_skip_deactivate;
/* * Checks if we should mangle the scancode to extract 'release' bit * in translated mode.
*/ staticbool atkbd_need_xlate(unsignedlong xl_bit, unsignedchar code)
{ int i;
if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1) returnfalse;
for (i = 0; i < ARRAY_SIZE(xl_table); i++) if (code == xl_table[i]) return test_bit(i, &xl_bit);
returntrue;
}
/* * Calculates new value of xl_bit so the driver can distinguish * between make/break pair of scancodes for select keys and PS/2 * protocol responses.
*/ staticvoid atkbd_calculate_xl_bit(struct atkbd *atkbd, unsignedchar code)
{ int i;
for (i = 0; i < ARRAY_SIZE(xl_table); i++) { if (!((code ^ xl_table[i]) & 0x7f)) { if (code & 0x80)
__clear_bit(i, &atkbd->xl_bit); else
__set_bit(i, &atkbd->xl_bit); break;
}
}
}
/* * Encode the scancode, 0xe0 prefix, and high bit into a single integer, * keeping kernel 2.4 compatibility for set 2
*/ staticunsignedint atkbd_compat_scancode(struct atkbd *atkbd, unsignedint code)
{ if (atkbd->set == 3) { if (atkbd->emul == 1)
code |= 0x100;
} else {
code = (code & 0x7f) | ((code & 0x80) << 1); if (atkbd->emul == 1)
code |= 0x80;
}
return code;
}
/* * Tries to handle frame or parity error by requesting the keyboard controller * to resend the last byte. This historically not done on x86 as controllers * there typically do not implement this command.
*/ staticbool __maybe_unused atkbd_handle_frame_error(struct ps2dev *ps2dev,
u8 data, unsignedint flags)
{ struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev); struct serio *serio = ps2dev->serio;
if (!atkbd->emul)
atkbd_calculate_xl_bit(atkbd, data);
}
switch (code) { case ATKBD_RET_BAT:
atkbd->enabled = false;
serio_reconnect(atkbd->ps2dev.serio); return; case ATKBD_RET_EMUL0:
atkbd->emul = 1; return; case ATKBD_RET_EMUL1:
atkbd->emul = 2; return; case ATKBD_RET_RELEASE:
atkbd->release = true; return; case ATKBD_RET_ACK: case ATKBD_RET_NAK: if (printk_ratelimit())
dev_warn(&serio->dev, "Spurious %s on %s. " "Some program might be trying to access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); return; case ATKBD_RET_ERR:
atkbd->err_count++;
dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n",
serio->phys); return;
}
code = atkbd_compat_scancode(atkbd, code);
if (atkbd->emul && --atkbd->emul) return;
keycode = atkbd->keycode[code];
if (!(atkbd->release && test_bit(code, atkbd->force_release_mask))) if (keycode != ATKBD_KEY_NULL)
input_event(dev, EV_MSC, MSC_SCAN, code);
switch (keycode) { case ATKBD_KEY_NULL: break; case ATKBD_KEY_UNKNOWN:
dev_warn(&serio->dev, "Unknown key %s (%s set %d, code %#x on %s).\n",
atkbd->release ? "released" : "pressed",
atkbd->translated ? "translated" : "raw",
atkbd->set, code, serio->phys);
dev_warn(&serio->dev, "Use 'setkeycodes %s%02x ' to make it known.\n",
code & 0x80 ? "e0" : "", code & 0x7f);
input_sync(dev); break; case ATKBD_SCR_1:
scroll = 1; break; case ATKBD_SCR_2:
scroll = 2; break; case ATKBD_SCR_4:
scroll = 4; break; case ATKBD_SCR_8:
scroll = 8; break; case ATKBD_SCR_CLICK:
click = !atkbd->release; break; case ATKBD_SCR_LEFT:
hscroll = -1; break; case ATKBD_SCR_RIGHT:
hscroll = 1; break; default: if (atkbd->release) {
value = 0;
atkbd->last = 0;
} elseif (!atkbd->softrepeat && test_bit(keycode, dev->key)) { /* Workaround Toshiba laptop multiple keypress */
value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
} else {
value = 1;
atkbd->last = code;
atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
}
/* * atkbd_event_work() is used to complete processing of events that * can not be processed by input_event() which is often called from * interrupt context.
*/
if (!atkbd->enabled) { /* * Serio ports are resumed asynchronously so while driver core * thinks that device is already fully operational in reality * it may not be ready yet. In this case we need to keep * rescheduling till reconnect completes.
*/
schedule_delayed_work(&atkbd->event_work,
msecs_to_jiffies(100));
} else { if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
atkbd_set_leds(atkbd);
if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
atkbd_set_repeat_rate(atkbd);
}
}
/* * Schedule switch for execution. We need to throttle requests, * otherwise keyboard may become unresponsive.
*/ staticvoid atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
{ unsignedlong delay = msecs_to_jiffies(50);
if (time_after(jiffies, atkbd->event_jiffies + delay))
delay = 0;
/* * Event callback from the input module. Events that change the state of * the hardware are processed here. If action can not be performed in * interrupt context it is offloaded to atkbd_event_work.
*/
for (i = 0; i < ARRAY_SIZE(chassis_types); i++) if (dmi_match(DMI_CHASSIS_TYPE, chassis_types[i])) returntrue;
returnfalse;
}
/* * On many modern laptops ATKBD_CMD_GETID may cause problems, on these laptops * the controller is always in translated mode. In this mode mice/touchpads will * not work. So in this case simply assume a keyboard is connected to avoid * confusing some laptop keyboards. * * Skipping ATKBD_CMD_GETID ends up using a fake keyboard id. Using the standard * 0xab83 id is ok in translated mode, only atkbd_select_set() checks atkbd->id * and in translated mode that is a no-op.
*/ staticbool atkbd_skip_getid(struct atkbd *atkbd)
{ return atkbd->translated && atkbd_is_portable_device();
} #else staticinlinebool atkbd_skip_getid(struct atkbd *atkbd) { returnfalse; } #endif
/* * atkbd_probe() probes for an AT keyboard on a serio port.
*/
/* * Some systems, where the bit-twiddling when testing the io-lines of the * controller may confuse the keyboard need a full reset of the keyboard. On * these systems the BIOS also usually doesn't do it for us.
*/
if (atkbd_reset) if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
dev_warn(&ps2dev->serio->dev, "keyboard reset failed on %s\n",
ps2dev->serio->phys);
if (atkbd_skip_getid(atkbd)) {
atkbd->id = 0xab83; goto deactivate_kbd;
}
/* * Then we check the keyboard ID. We should get 0xab83 under normal conditions. * Some keyboards report different values, but the first byte is always 0xab or * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this * should make sure we don't try to set the LEDs on it.
*/
param[0] = param[1] = 0xa5; /* initialize with invalid values */ if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
/* * If the get ID command failed, we check if we can at least set * the LEDs on the keyboard. This should work on every keyboard out there. * It also turns the LEDs off, which we want anyway.
*/
param[0] = 0; if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) return -1;
atkbd->id = 0xabba; return 0;
}
if (!ps2_is_keyboard_id(param[0])) return -1;
atkbd->id = (param[0] << 8) | param[1];
if (atkbd->id == 0xaca1 && atkbd->translated) {
dev_err(&ps2dev->serio->dev, "NCD terminal keyboards are only supported on non-translating controllers. " "Use i8042.direct=1 to disable translation.\n"); return -1;
}
deactivate_kbd: /* * Make sure nothing is coming from the keyboard and disturbs our * internal state.
*/ if (!atkbd_skip_deactivate)
atkbd_deactivate(atkbd);
return 0;
}
/* * atkbd_select_set checks if a keyboard has a working Set 3 support, and * sets it into that. Unfortunately there are keyboards that can be switched * to Set 3, but don't work well in that (BTC Multimedia ...)
*/
staticint atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
{ struct ps2dev *ps2dev = &atkbd->ps2dev; unsignedchar param[2];
atkbd->extra = false; /* * For known special keyboards we can go ahead and set the correct set. * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards.
*/
/* * Make sure we don't have a command in flight. * Note that since atkbd->enabled is false event work will keep * rescheduling itself until it gets canceled and will not try * accessing freed input device or serio port.
*/
cancel_delayed_work_sync(&atkbd->event_work);
/* * generate release events for the keycodes given in data
*/ staticvoid atkbd_apply_forced_release_keylist(struct atkbd* atkbd, constvoid *data)
{ constunsignedint *keys = data; unsignedint i;
if (atkbd->set == 2) for (i = 0; keys[i] != -1U; i++)
__set_bit(keys[i], atkbd->force_release_mask);
}
/* * Most special keys (Fn+F?) on Dell laptops do not generate release * events so we have to do it ourselves.
*/ staticunsignedint atkbd_dell_laptop_forced_release_keys[] = {
0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U
};
/* * Perform fixup for HP system that doesn't generate release * for its video switch
*/ staticunsignedint atkbd_hp_forced_release_keys[] = {
0x94, -1U
};
/* * Samsung NC10,NC20 with Fn+F? key release not working
*/ staticunsignedint atkbd_samsung_forced_release_keys[] = {
0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U
};
/* * Amilo Pi 3525 key release for Fn+Volume keys not working
*/ staticunsignedint atkbd_amilo_pi3525_forced_release_keys[] = {
0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U
};
/* * Amilo Xi 3650 key release for light touch bar not working
*/ staticunsignedint atkbd_amilo_xi3650_forced_release_keys[] = {
0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U
};
/* * Soltech TA12 system with broken key release on volume keys and mute key
*/ staticunsignedint atkdb_soltech_ta12_forced_release_keys[] = {
0xa0, 0xae, 0xb0, -1U
};
/* * Many notebooks don't send key release event for volume up/down * keys, with key list below common among them
*/ staticunsignedint atkbd_volume_forced_release_keys[] = {
0xae, 0xb0, -1U
};
if (!atkbd_get_keymap_from_fwnode(atkbd)) {
dev_dbg(dev, "Using FW keymap\n");
} elseif (atkbd->translated) { for (i = 0; i < 128; i++) {
scancode = atkbd_unxlate_table[i];
atkbd->keycode[i] = atkbd_set2_keycode[scancode];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80]; if (atkbd->scroll) for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
}
} elseif (atkbd->set == 3) {
memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode));
} else {
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
if (atkbd->scroll) for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
scancode = atkbd_scroll_keys[i].set2;
atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
}
}
/* * HANGEUL and HANJA keys do not send release events so we need to * generate such events ourselves
*/
scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
atkbd->keycode[scancode] = KEY_HANGEUL;
__set_bit(scancode, atkbd->force_release_mask);
/* * atkbd_connect() is called when the serio module finds an interface * that isn't handled yet by an appropriate device driver. We check if * there is an AT keyboard out there and if yes, we register ourselves * to the input module.
*/
if (!atkbd || !drv) {
dev_dbg(&serio->dev, "reconnect request, but serio is disconnected, ignoring...\n"); return -1;
}
guard(mutex)(&atkbd->mutex);
atkbd_disable(atkbd);
if (atkbd->write) {
error = atkbd_probe(atkbd); if (error) return error;
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) return -EIO;
/* * Restore LED state and repeat rate. While input core * will do this for us at resume time reconnect may happen * because user requested it via sysfs or simply because * keyboard was unplugged and plugged in again so we need * to do it ourselves here.
*/
atkbd_set_leds(atkbd); if (!atkbd->softrepeat)
atkbd_set_repeat_rate(atkbd);
}
/* * Reset our state machine in case reconnect happened in the middle * of multi-byte scancode.
*/
atkbd->xl_bit = 0;
atkbd->emul = 0;
atkbd_enable(atkbd); if (atkbd->write)
atkbd_activate(atkbd);
err = kstrtouint(buf, 10, &value); if (err) return err;
if (value > 1) return -EINVAL;
if (atkbd->extra != value) { /* * Since device's properties will change we need to * unregister old device. But allocate and register * new one first to make sure we have it.
*/
old_dev = atkbd->dev;
old_extra = atkbd->extra;
old_set = atkbd->set;
new_dev = input_allocate_device(); if (!new_dev) return -ENOMEM;
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.