boot menu: turn the touchpad driver off, and trace its steps
The ASUS TUF A15 freezes at the default resolution shortly after the loader hands over -- screen dark, Caps Lock dead -- and it is the only machine here with an I2C-HID touchpad, which the driver added in the same release now probes at boot. "Touchpad driver: on/off" in the F8 menu answers whether it is the cause on the machine itself, through a new SCHBOOT_OFF_FLAGS byte the kernel checks before starting the driver. A verbose boot now prints each step of the probe before taking it, so if it is the cause, the last line on the screen says which step. Also: S in the menu wrapped at five entries whatever the count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
d2c70c9129
commit
c79b1d6d6d
3 changed files with 49 additions and 16 deletions
|
|
@ -118,6 +118,9 @@ static int VERBOSE_BOOT;
|
||||||
// this particular moment.
|
// this particular moment.
|
||||||
static int DEBUG_BOOT;
|
static int DEBUG_BOOT;
|
||||||
|
|
||||||
|
// SCHBOOT_OFF_FLAGS: drivers turned off at the boot menu.
|
||||||
|
static int OFF_FLAGS;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
serial_putc(char c)
|
serial_putc(char c)
|
||||||
{
|
{
|
||||||
|
|
@ -1539,31 +1542,31 @@ boot_menu(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
|
||||||
// how to make it not refuse. An ISO built for anybody else has no way
|
// how to make it not refuse. An ISO built for anybody else has no way
|
||||||
// to turn a network debugger on, because the code that would set the
|
// to turn a network debugger on, because the code that would set the
|
||||||
// flag is not in it.
|
// flag is not in it.
|
||||||
const char *items[6];
|
const char *items[7];
|
||||||
int nitems = 5;
|
int nitems = 6;
|
||||||
items[0] = "Boot SchOS";
|
items[0] = "Boot SchOS";
|
||||||
items[1] = "Boot SchOS (verbose)";
|
items[1] = "Boot SchOS (verbose)";
|
||||||
items[2] = resbuf;
|
items[2] = resbuf;
|
||||||
items[3] = "System Information";
|
items[3] = (OFF_FLAGS & SCHBOOT_OFF_I2C_HID) ? "Touchpad driver: off"
|
||||||
items[4] = "Reboot to firmware";
|
: "Touchpad driver: on";
|
||||||
|
items[4] = "System Information";
|
||||||
|
items[5] = "Reboot to firmware";
|
||||||
#ifdef SCHOS_DEBUG
|
#ifdef SCHOS_DEBUG
|
||||||
items[5] = DEBUG_BOOT ? "Remote debugging: on (schdbgd, port 4444)"
|
items[6] = DEBUG_BOOT ? "Remote debugging: on (schdbgd, port 4444)"
|
||||||
: "Remote debugging: off";
|
: "Remote debugging: off";
|
||||||
nitems = 6;
|
nitems = 7;
|
||||||
#endif
|
#endif
|
||||||
|
const char *hint = nitems == 7 ? "W/S or 1-7 to choose, Enter to select"
|
||||||
|
: "W/S or 1-6 to choose, Enter to select";
|
||||||
|
|
||||||
ui_menu("Boot Manager", items, nitems, selected,
|
ui_menu("Boot Manager", items, nitems, selected, hint);
|
||||||
nitems == 6 ? "W/S or 1-6 to choose, Enter to select"
|
|
||||||
: "W/S or 1-5 to choose, Enter to select");
|
|
||||||
|
|
||||||
// The same menu on the serial line: the whole thing once, then one
|
// The same menu on the serial line: the whole thing once, then one
|
||||||
// line per *move*. Reprinting on every keypress would be correct and
|
// line per *move*. Reprinting on every keypress would be correct and
|
||||||
// unreadable -- a serial terminal has no cursor to paint over, so an
|
// unreadable -- a serial terminal has no cursor to paint over, so an
|
||||||
// unrecognised key would scroll the selection past again for nothing.
|
// unrecognised key would scroll the selection past again for nothing.
|
||||||
if (echoed < 0) {
|
if (echoed < 0) {
|
||||||
serial_menu("Boot Manager", items, nitems, selected,
|
serial_menu("Boot Manager", items, nitems, selected, hint, 1);
|
||||||
nitems == 6 ? "W/S or 1-6 to choose, Enter to select"
|
|
||||||
: "W/S or 1-5 to choose, Enter to select", 1);
|
|
||||||
} else if (echoed != selected) {
|
} else if (echoed != selected) {
|
||||||
serial_item(items, selected, selected, 1);
|
serial_item(items, selected, selected, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -1584,21 +1587,22 @@ boot_menu(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
|
||||||
if (scan == 0x01) { selected = (selected + nitems - 1) % nitems; continue; }
|
if (scan == 0x01) { selected = (selected + nitems - 1) % nitems; continue; }
|
||||||
if (scan == 0x02) { selected = (selected + 1) % nitems; continue; }
|
if (scan == 0x02) { selected = (selected + 1) % nitems; continue; }
|
||||||
if (c == L'w' || c == L'W') { selected = (selected + nitems - 1) % nitems; continue; }
|
if (c == L'w' || c == L'W') { selected = (selected + nitems - 1) % nitems; continue; }
|
||||||
if (c == L's' || c == L'S') { selected = (selected + 1) % 5; continue; }
|
if (c == L's' || c == L'S') { selected = (selected + 1) % nitems; continue; }
|
||||||
if (c >= L'1' && c <= L'0' + nitems) { selected = (int)(c - L'1'); continue; }
|
if (c >= L'1' && c <= L'0' + nitems) { selected = (int)(c - L'1'); continue; }
|
||||||
|
|
||||||
if (c == L'\r' || c == L'\n') {
|
if (c == L'\r' || c == L'\n') {
|
||||||
if (selected == 0) return 0;
|
if (selected == 0) return 0;
|
||||||
if (selected == 1) return 1;
|
if (selected == 1) return 1;
|
||||||
if (selected == 2) { res_choose(gop); continue; }
|
if (selected == 2) { res_choose(gop); continue; }
|
||||||
if (selected == 3) { sys_info(gop); continue; }
|
if (selected == 3) { OFF_FLAGS ^= SCHBOOT_OFF_I2C_HID; echoed = -1; continue; }
|
||||||
|
if (selected == 4) { sys_info(gop); continue; }
|
||||||
#ifdef SCHOS_DEBUG
|
#ifdef SCHOS_DEBUG
|
||||||
// A toggle rather than an action: picking it changes what the
|
// A toggle rather than an action: picking it changes what the
|
||||||
// entry says and leaves you in the menu, so the state you booted
|
// entry says and leaves you in the menu, so the state you booted
|
||||||
// with is the state you can see before you boot.
|
// with is the state you can see before you boot.
|
||||||
if (selected == 5) { DEBUG_BOOT = !DEBUG_BOOT; echoed = -1; continue; }
|
if (selected == 6) { DEBUG_BOOT = !DEBUG_BOOT; echoed = -1; continue; }
|
||||||
#endif
|
#endif
|
||||||
if (selected == 4) {
|
if (selected == 5) {
|
||||||
ui_clear();
|
ui_clear();
|
||||||
ui_text_centered((int)ui_height() / 2, "Halted -- reset to reach firmware setup",
|
ui_text_centered((int)ui_height() / 2, "Halted -- reset to reach firmware setup",
|
||||||
0xB9BEC7u);
|
0xB9BEC7u);
|
||||||
|
|
@ -2338,6 +2342,7 @@ EfiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
|
||||||
*(UINT32 *)SCHBOOT_EFI_FLAG = SCHBOOT_EFI_MAGIC;
|
*(UINT32 *)SCHBOOT_EFI_FLAG = SCHBOOT_EFI_MAGIC;
|
||||||
*(UINT8 *)SCHBOOT_VERBOSE_FLAG = (UINT8)VERBOSE_BOOT;
|
*(UINT8 *)SCHBOOT_VERBOSE_FLAG = (UINT8)VERBOSE_BOOT;
|
||||||
*(UINT8 *)SCHBOOT_DEBUG_FLAG = (UINT8)DEBUG_BOOT;
|
*(UINT8 *)SCHBOOT_DEBUG_FLAG = (UINT8)DEBUG_BOOT;
|
||||||
|
*(UINT8 *)SCHBOOT_OFF_FLAGS = (UINT8)OFF_FLAGS;
|
||||||
|
|
||||||
// The page tables mboot_entry would have built. entry64low's first act is
|
// The page tables mboot_entry would have built. entry64low's first act is
|
||||||
// a movabs to 0xffff8000...., so the high half must be mapped before the
|
// a movabs to 0xffff8000...., so the high half must be mapped before the
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,13 @@
|
||||||
// Zero on every ordinary boot, including every boot of a build made without
|
// Zero on every ordinary boot, including every boot of a build made without
|
||||||
// DEBUG=1 -- where the menu entry does not exist and nothing can set it.
|
// DEBUG=1 -- where the menu entry does not exist and nothing can set it.
|
||||||
#define SCHBOOT_DEBUG_FLAG (SCHBOOT_BASE + 0x102)
|
#define SCHBOOT_DEBUG_FLAG (SCHBOOT_BASE + 0x102)
|
||||||
|
|
||||||
|
// Drivers switched off at the boot menu, one bit each. For bisecting a machine
|
||||||
|
// that hangs during boot without a rebuild: the newest driver that touches
|
||||||
|
// hardware nobody tested it on is the first suspect, and turning it off from
|
||||||
|
// the menu answers the question on the machine itself.
|
||||||
|
#define SCHBOOT_OFF_FLAGS (SCHBOOT_BASE + 0x103)
|
||||||
|
#define SCHBOOT_OFF_I2C_HID 0x01 // kernel/acpi/i2c_hid.c: touchpads
|
||||||
#define SCHBOOT_MEDIA_CD 1
|
#define SCHBOOT_MEDIA_CD 1
|
||||||
|
|
||||||
// Real-mode spelling of the same byte, for cdboot.S which has no 32-bit
|
// Real-mode spelling of the same byte, for cdboot.S which has no 32-bit
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@
|
||||||
#include "core/param.h"
|
#include "core/param.h"
|
||||||
#include "core/spinlock.h"
|
#include "core/spinlock.h"
|
||||||
#include "arch/mmu.h"
|
#include "arch/mmu.h"
|
||||||
|
#include "arch/memlayout.h"
|
||||||
|
#include "arch/schboot.h"
|
||||||
#include "dev/hid.h"
|
#include "dev/hid.h"
|
||||||
#include "dev/acpi.h"
|
#include "dev/acpi.h"
|
||||||
|
|
||||||
|
|
@ -51,6 +53,10 @@
|
||||||
#include <uacpi/namespace.h>
|
#include <uacpi/namespace.h>
|
||||||
#include <uacpi/resources.h>
|
#include <uacpi/resources.h>
|
||||||
|
|
||||||
|
// Each step said before it is taken, in a verbose boot: a machine that stops
|
||||||
|
// here stops with the step it was on as the last line on the screen.
|
||||||
|
#define STEP(...) do { if(boot_verbose) cprintf(__VA_ARGS__); } while(0)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// DesignWare I2C
|
// DesignWare I2C
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
@ -171,6 +177,7 @@ dw_init(struct dwi2c *c, uacpi_namespace_node *node, uint32 speed)
|
||||||
c->regs = ioremap(c->phys, 0x1000);
|
c->regs = ioremap(c->phys, 0x1000);
|
||||||
if(c->regs == 0)
|
if(c->regs == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
STEP("i2c: controller registers at 0x%lx\n", c->phys);
|
||||||
type = rd(c, IC_COMP_TYPE);
|
type = rd(c, IC_COMP_TYPE);
|
||||||
if(type != DW_COMP_TYPE){
|
if(type != DW_COMP_TYPE){
|
||||||
cprintf("i2c: controller at 0x%lx is not DesignWare (0x%x)\n",
|
cprintf("i2c: controller at 0x%lx is not DesignWare (0x%x)\n",
|
||||||
|
|
@ -533,19 +540,24 @@ probe(void *user, uacpi_namespace_node *node, uacpi_u32 depth)
|
||||||
memset(d, 0, sizeof(*d));
|
memset(d, 0, sizeof(*d));
|
||||||
memmove(d->name, uacpi_namespace_node_name(node).text, 4);
|
memmove(d->name, uacpi_namespace_node_name(node).text, 4);
|
||||||
|
|
||||||
|
STEP("i2c-hid: %s: reading its resources\n", d->name);
|
||||||
if(resources(node, &f) < 0 || !f.i2c){
|
if(resources(node, &f) < 0 || !f.i2c){
|
||||||
cprintf("i2c-hid: %s has no I2C connection\n", d->name);
|
cprintf("i2c-hid: %s has no I2C connection\n", d->name);
|
||||||
return UACPI_ITERATION_DECISION_CONTINUE;
|
return UACPI_ITERATION_DECISION_CONTINUE;
|
||||||
}
|
}
|
||||||
|
STEP("i2c-hid: %s: _DSM\n", d->name);
|
||||||
if(hid_desc_register(node, &descreg) < 0){
|
if(hid_desc_register(node, &descreg) < 0){
|
||||||
cprintf("i2c-hid: %s: _DSM gave no descriptor register\n", d->name);
|
cprintf("i2c-hid: %s: _DSM gave no descriptor register\n", d->name);
|
||||||
return UACPI_ITERATION_DECISION_CONTINUE;
|
return UACPI_ITERATION_DECISION_CONTINUE;
|
||||||
}
|
}
|
||||||
|
STEP("i2c-hid: %s: controller %s, address 0x%x\n", d->name, f.bus, f.addr);
|
||||||
if((d->c = controller(f.bus, f.speed)) == 0)
|
if((d->c = controller(f.bus, f.speed)) == 0)
|
||||||
return UACPI_ITERATION_DECISION_CONTINUE;
|
return UACPI_ITERATION_DECISION_CONTINUE;
|
||||||
d->addr = f.addr;
|
d->addr = f.addr;
|
||||||
|
STEP("i2c-hid: %s: _PS0\n", d->name);
|
||||||
uacpi_execute(node, "_PS0", 0);
|
uacpi_execute(node, "_PS0", 0);
|
||||||
|
|
||||||
|
STEP("i2c-hid: %s: HID descriptor at register 0x%x\n", d->name, descreg);
|
||||||
if(reg_read(d, descreg, desc, sizeof(desc)) < 0 ||
|
if(reg_read(d, descreg, desc, sizeof(desc)) < 0 ||
|
||||||
(desc[0] | desc[1] << 8) != 30){
|
(desc[0] | desc[1] << 8) != 30){
|
||||||
cprintf("i2c-hid: %s at 0x%x does not answer\n", d->name, d->addr);
|
cprintf("i2c-hid: %s at 0x%x does not answer\n", d->name, d->addr);
|
||||||
|
|
@ -563,6 +575,8 @@ probe(void *user, uacpi_namespace_node *node, uacpi_u32 depth)
|
||||||
d->pin = interrupt_pin(&f);
|
d->pin = interrupt_pin(&f);
|
||||||
d->active_low = f.active_low;
|
d->active_low = f.active_low;
|
||||||
|
|
||||||
|
STEP("i2c-hid: %s: power on and reset, pin %s\n", d->name,
|
||||||
|
d->pin ? "watched" : "none");
|
||||||
command(d, OP_SET_POWER, 0); // 0 = on
|
command(d, OP_SET_POWER, 0); // 0 = on
|
||||||
wait_ticks(2);
|
wait_ticks(2);
|
||||||
command(d, OP_RESET, 0);
|
command(d, OP_RESET, 0);
|
||||||
|
|
@ -577,6 +591,7 @@ probe(void *user, uacpi_namespace_node *node, uacpi_u32 depth)
|
||||||
if(dw_xfer(d->c, d->addr, 0, 0, d->buf, d->maxin) < 0)
|
if(dw_xfer(d->c, d->addr, 0, 0, d->buf, d->maxin) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
STEP("i2c-hid: %s: report descriptor, %d bytes\n", d->name, rlen);
|
||||||
if(reg_read(d, rreg, rdesc, rlen) < 0){
|
if(reg_read(d, rreg, rdesc, rlen) < 0){
|
||||||
cprintf("i2c-hid: %s: report descriptor unreadable\n", d->name);
|
cprintf("i2c-hid: %s: report descriptor unreadable\n", d->name);
|
||||||
kfree((char *)rdesc);
|
kfree((char *)rdesc);
|
||||||
|
|
@ -603,7 +618,9 @@ i2c_hid_thread(void)
|
||||||
static const char *const ids[] = { "PNP0C50", "ACPI0C50", 0 };
|
static const char *const ids[] = { "PNP0C50", "ACPI0C50", 0 };
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
|
STEP("i2c-hid: looking for touchpads\n");
|
||||||
uacpi_find_devices_at(uacpi_namespace_root(), ids, probe, 0);
|
uacpi_find_devices_at(uacpi_namespace_root(), ids, probe, 0);
|
||||||
|
STEP("i2c-hid: %d found\n", ndev);
|
||||||
if(ndev == 0)
|
if(ndev == 0)
|
||||||
for(;;)
|
for(;;)
|
||||||
wait_ticks(1000000);
|
wait_ticks(1000000);
|
||||||
|
|
@ -630,6 +647,10 @@ i2c_hid_start(void)
|
||||||
{
|
{
|
||||||
if(acpi_rsdp_phys() == 0)
|
if(acpi_rsdp_phys() == 0)
|
||||||
return;
|
return;
|
||||||
|
if(*(volatile uchar *)P2V(SCHBOOT_OFF_FLAGS) & SCHBOOT_OFF_I2C_HID){
|
||||||
|
cprintf("i2c-hid: off, as chosen at the boot menu\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(kthread_create(i2c_hid_thread, "i2chid") < 0)
|
if(kthread_create(i2c_hid_thread, "i2chid") < 0)
|
||||||
cprintf("i2c-hid: no thread; touchpads will not work\n");
|
cprintf("i2c-hid: no thread; touchpads will not work\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue