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
|
|
@ -384,3 +384,145 @@ acpi_pci_route(void)
|
|||
kinfo("acpi: %d more on a second I/O APIC, which is not driven; "
|
||||
"those devices need MSI\n", beyond);
|
||||
}
|
||||
|
||||
// --- batteries and adapters --------------------------------------------------
|
||||
//
|
||||
// A laptop's battery is an ACPI device, PNP0C0A, with methods that answer in
|
||||
// packages: _BIX (or the older _BIF) for what it is -- capacities, units,
|
||||
// names -- and _BST for how it is now. The adapter is ACPI0003 and _PSR says
|
||||
// whether it is plugged in. Read on demand, from /sys/class/power_supply,
|
||||
// which is where fastfetch and every battery widget look.
|
||||
|
||||
#define MAXPSU 4
|
||||
static uacpi_namespace_node *psu_node[MAXPSU];
|
||||
static int psu_isbat[MAXPSU];
|
||||
static int npsu;
|
||||
|
||||
static uacpi_iteration_decision
|
||||
found_psu(void *user, uacpi_namespace_node *node, uacpi_u32 depth)
|
||||
{
|
||||
(void)depth;
|
||||
if (npsu < MAXPSU) {
|
||||
psu_node[npsu] = node;
|
||||
psu_isbat[npsu] = user != 0;
|
||||
npsu++;
|
||||
}
|
||||
return UACPI_ITERATION_DECISION_CONTINUE;
|
||||
}
|
||||
|
||||
static int psu_found;
|
||||
|
||||
static void
|
||||
psu_find(void)
|
||||
{
|
||||
if (psu_found || !ready)
|
||||
return;
|
||||
psu_found = 1;
|
||||
uacpi_find_devices("PNP0C0A", found_psu, (void *)1);
|
||||
uacpi_find_devices("ACPI0003", found_psu, 0);
|
||||
}
|
||||
|
||||
int
|
||||
acpi_psu_count(void)
|
||||
{
|
||||
psu_find();
|
||||
return npsu;
|
||||
}
|
||||
|
||||
static uint32
|
||||
pkg_int(uacpi_object_array *p, uacpi_size i)
|
||||
{
|
||||
uacpi_u64 v;
|
||||
if (i >= p->count || uacpi_object_get_integer(p->objects[i], &v) != UACPI_STATUS_OK)
|
||||
return ACPI_UNKNOWN;
|
||||
return (uint32)v;
|
||||
}
|
||||
|
||||
static void
|
||||
pkg_str(uacpi_object_array *p, uacpi_size i, char *out, int cap)
|
||||
{
|
||||
uacpi_data_view d;
|
||||
out[0] = 0;
|
||||
if (i >= p->count ||
|
||||
uacpi_object_get_string_or_buffer(p->objects[i], &d) != UACPI_STATUS_OK)
|
||||
return;
|
||||
int n = 0;
|
||||
for (uacpi_size k = 0; k < d.length && n < cap - 1 && d.const_text[k]; k++)
|
||||
if (d.const_text[k] >= ' ' && d.const_text[k] < 127)
|
||||
out[n++] = d.const_text[k];
|
||||
// Firmware pads with spaces.
|
||||
while (n > 0 && out[n - 1] == ' ')
|
||||
n--;
|
||||
out[n] = 0;
|
||||
}
|
||||
|
||||
int
|
||||
acpi_psu_get(int i, struct acpi_psu *b)
|
||||
{
|
||||
uacpi_object *o;
|
||||
uacpi_object_array p;
|
||||
uacpi_u32 sta = 0xF;
|
||||
|
||||
psu_find();
|
||||
if (i < 0 || i >= npsu)
|
||||
return -1;
|
||||
memset(b, 0, sizeof(*b));
|
||||
b->battery = psu_isbat[i];
|
||||
|
||||
if (!b->battery) {
|
||||
uacpi_u64 v = 0;
|
||||
uacpi_eval_simple_integer(psu_node[i], "_PSR", &v);
|
||||
b->online = v != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Bit 4 of _STA: a battery is in the bay. A missing _STA means present.
|
||||
uacpi_eval_sta(psu_node[i], &sta);
|
||||
b->present = (sta & 0x10) != 0;
|
||||
b->rate = b->remaining = b->voltage = ACPI_UNKNOWN;
|
||||
b->design = b->full = b->design_voltage = b->cycles = ACPI_UNKNOWN;
|
||||
if (!b->present)
|
||||
return 0;
|
||||
|
||||
// _BIX: a revision first, then _BIF's fields shifted by one, with the
|
||||
// cycle count after the design voltage's neighbours.
|
||||
if (uacpi_eval_package(psu_node[i], "_BIX", 0, &o) == UACPI_STATUS_OK) {
|
||||
if (uacpi_object_get_package(o, &p) == UACPI_STATUS_OK) {
|
||||
b->unit = (int)pkg_int(&p, 1);
|
||||
b->design = pkg_int(&p, 2);
|
||||
b->full = pkg_int(&p, 3);
|
||||
b->technology = (int)pkg_int(&p, 4);
|
||||
b->design_voltage = pkg_int(&p, 5);
|
||||
b->cycles = pkg_int(&p, 8);
|
||||
pkg_str(&p, 16, b->model, sizeof(b->model));
|
||||
pkg_str(&p, 17, b->serial, sizeof(b->serial));
|
||||
pkg_str(&p, 18, b->kind, sizeof(b->kind));
|
||||
pkg_str(&p, 19, b->oem, sizeof(b->oem));
|
||||
}
|
||||
uacpi_object_unref(o);
|
||||
} else if (uacpi_eval_package(psu_node[i], "_BIF", 0, &o) == UACPI_STATUS_OK) {
|
||||
if (uacpi_object_get_package(o, &p) == UACPI_STATUS_OK) {
|
||||
b->unit = (int)pkg_int(&p, 0);
|
||||
b->design = pkg_int(&p, 1);
|
||||
b->full = pkg_int(&p, 2);
|
||||
b->technology = (int)pkg_int(&p, 3);
|
||||
b->design_voltage = pkg_int(&p, 4);
|
||||
pkg_str(&p, 9, b->model, sizeof(b->model));
|
||||
pkg_str(&p, 10, b->serial, sizeof(b->serial));
|
||||
pkg_str(&p, 11, b->kind, sizeof(b->kind));
|
||||
pkg_str(&p, 12, b->oem, sizeof(b->oem));
|
||||
}
|
||||
uacpi_object_unref(o);
|
||||
}
|
||||
|
||||
if (uacpi_eval_package(psu_node[i], "_BST", 0, &o) == UACPI_STATUS_OK) {
|
||||
if (uacpi_object_get_package(o, &p) == UACPI_STATUS_OK) {
|
||||
b->state = pkg_int(&p, 0);
|
||||
b->rate = pkg_int(&p, 1);
|
||||
b->remaining = pkg_int(&p, 2);
|
||||
b->voltage = pkg_int(&p, 3);
|
||||
}
|
||||
uacpi_object_unref(o);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue