Keyboard lights, TLB shootdowns, battery in sysfs, /proc/pid/maps
Caps, Num and Scroll Lock now light their LEDs on PS/2 and USB keyboards, share one state between keyboards, and stop toggling on key repeat. X sets them through evdev writes while it holds the keyboard. Unmapping memory in a process with threads on other CPUs now flushes their TLBs with an IPI. Without it a freed page stayed reachable through stale translations, which corrupted Epiphany's heap on SMP. ACPI batteries and AC adapters appear under /sys/class/power_supply. /proc/<pid>/maps lists file mappings, and a process killed by a fault names the file and offset it died in. r8169 gets a 256-entry RX ring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
73dcea7496
commit
438e7af141
18 changed files with 945 additions and 9 deletions
110
kernel/dev/kbd.c
110
kernel/dev/kbd.c
|
|
@ -1,6 +1,7 @@
|
|||
#include "core/types.h"
|
||||
#include "arch/x86.h"
|
||||
#include "core/defs.h"
|
||||
#include "core/spinlock.h"
|
||||
#include "dev/kbd.h"
|
||||
#include "uapi/posix.h"
|
||||
#include "dev/vt.h" /* NVT -- how many terminals the chords reach */
|
||||
|
|
@ -99,6 +100,104 @@ queue_utf8(uint32 cp)
|
|||
return pend[pend_i++];
|
||||
}
|
||||
|
||||
// --- the lock keys and their lights -------------------------------------------
|
||||
//
|
||||
// Caps, Num and Scroll Lock are one state for the machine, whichever keyboard
|
||||
// pressed them -- the laptop's own and a USB one agree -- and the lights on
|
||||
// every keyboard show it. They never did: caps lock worked and its light
|
||||
// stayed dark. Under X the server keeps its own lock state and sets the
|
||||
// lights through /dev/input (see inputwrite), so these are left to it while
|
||||
// it holds the keyboard.
|
||||
|
||||
static uint kbd_locks; // CAPSLOCK | NUMLOCK | SCROLLLOCK
|
||||
static uint lock_held; // lock keys down now: a held key repeats
|
||||
static struct spinlock ledlock;
|
||||
static int ledlock_ready;
|
||||
|
||||
// The PS/2 side is a two-byte command, 0xED and the lights, and each byte
|
||||
// must be acknowledged (0xFA) before the next is sent. That cannot be waited
|
||||
// for here -- this runs in the keyboard's interrupt, and the acknowledgement
|
||||
// *is* a keyboard interrupt -- so the second byte goes out when kbdgetc sees
|
||||
// the first one acknowledged.
|
||||
static int led_want = -1; // PS/2 light byte still to send
|
||||
static int led_stage; // 0 idle, 1 0xED sent, 2 the byte sent
|
||||
static uint led_since;
|
||||
|
||||
static void
|
||||
ps2_led_kick(void)
|
||||
{
|
||||
if (led_stage != 0 && ticks - led_since > HZ)
|
||||
led_stage = 0; // no keyboard answered: start over
|
||||
if (led_stage == 0 && led_want >= 0 && !(inb(KBSTATP) & 0x02)) {
|
||||
outb(KBDATAP, 0xED);
|
||||
led_stage = 1;
|
||||
led_since = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
// Show `locks` on every keyboard.
|
||||
void
|
||||
kbd_set_leds(uint locks)
|
||||
{
|
||||
if (!ledlock_ready) {
|
||||
initlock(&ledlock, "kbdled");
|
||||
ledlock_ready = 1;
|
||||
}
|
||||
acquire(&ledlock);
|
||||
led_want = ((locks & SCROLLLOCK) ? 1 : 0) | ((locks & NUMLOCK) ? 2 : 0) |
|
||||
((locks & CAPSLOCK) ? 4 : 0);
|
||||
ps2_led_kick();
|
||||
release(&ledlock);
|
||||
// USB numbers them the other way round: Num, Caps, Scroll.
|
||||
hid_leds_want(((locks & NUMLOCK) ? 1 : 0) | ((locks & CAPSLOCK) ? 2 : 0) |
|
||||
((locks & SCROLLLOCK) ? 4 : 0));
|
||||
}
|
||||
|
||||
// A lock key pressed, on any keyboard. `down` 0 is its release.
|
||||
void
|
||||
kbd_lock_key(uint lock, int down)
|
||||
{
|
||||
if (!down) {
|
||||
lock_held &= ~lock;
|
||||
return;
|
||||
}
|
||||
if (lock_held & lock)
|
||||
return; // the keyboard's repeat, not a new press
|
||||
lock_held |= lock;
|
||||
kbd_locks ^= lock;
|
||||
if (!input_is_grabbed(INPUT_KBD))
|
||||
kbd_set_leds(kbd_locks);
|
||||
}
|
||||
|
||||
uint
|
||||
kbd_lock_state(void)
|
||||
{
|
||||
return kbd_locks;
|
||||
}
|
||||
|
||||
// 0xFA and 0xFE from the keyboard: answers to a light command, not keys.
|
||||
static int
|
||||
ps2_led_answer(uint data)
|
||||
{
|
||||
if (led_stage == 0 || (data != 0xFA && data != 0xFE))
|
||||
return 0;
|
||||
if (!ledlock_ready)
|
||||
return 0;
|
||||
acquire(&ledlock);
|
||||
if (data == 0xFE) {
|
||||
led_stage = 0; // "resend": try again with the next change
|
||||
} else if (led_stage == 1 && led_want >= 0) {
|
||||
outb(KBDATAP, (uchar)led_want);
|
||||
led_want = -1;
|
||||
led_stage = 2;
|
||||
} else {
|
||||
led_stage = 0;
|
||||
ps2_led_kick(); // changed again meanwhile
|
||||
}
|
||||
release(&ledlock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
kbdgetc(void)
|
||||
{
|
||||
|
|
@ -119,6 +218,9 @@ kbdgetc(void)
|
|||
|
||||
data = inb(KBDATAP);
|
||||
|
||||
if(ps2_led_answer(data))
|
||||
return 0;
|
||||
|
||||
if(data == 0xE0){
|
||||
shift |= E0ESC;
|
||||
return 0;
|
||||
|
|
@ -137,9 +239,10 @@ kbdgetc(void)
|
|||
if(data & 0x80){
|
||||
data = (shift & E0ESC ? data : data & 0x7F);
|
||||
shift &= ~(shiftcode[data] | E0ESC);
|
||||
if(togglecode[data]) kbd_lock_key(togglecode[data], 0);
|
||||
} else {
|
||||
shift |= shiftcode[data];
|
||||
shift ^= togglecode[data];
|
||||
if(togglecode[data]) kbd_lock_key(togglecode[data], 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -147,6 +250,7 @@ kbdgetc(void)
|
|||
if(data & 0x80){
|
||||
data = (shift & E0ESC ? data : data & 0x7F);
|
||||
shift &= ~(shiftcode[data] | E0ESC);
|
||||
if(togglecode[data]) kbd_lock_key(togglecode[data], 0);
|
||||
return 0;
|
||||
} else if(shift & E0ESC){
|
||||
data |= 0x80;
|
||||
|
|
@ -154,7 +258,9 @@ kbdgetc(void)
|
|||
}
|
||||
|
||||
shift |= shiftcode[data];
|
||||
shift ^= togglecode[data];
|
||||
if(togglecode[data]) kbd_lock_key(togglecode[data], 1);
|
||||
// The locks are the machine's, not this keyboard's: see kbd_lock_key().
|
||||
shift = (shift & ~(CAPSLOCK | NUMLOCK | SCROLLLOCK)) | kbd_locks;
|
||||
|
||||
// The switch chord, before the character tables, because there is no
|
||||
// character to look up: it is a combination that means "show me a different
|
||||
|
|
|
|||
Loading…
Reference in a new issue