input, fb, vt, sysfs: the kernel calls Xorg makes

Xorg on a framebuffer -- the fbdev video driver, the evdev input driver,
libpciaccess -- asks the kernel a fixed set of questions before it draws
anything, and gives up on the first wrong answer. These are those
answers.

evdev: EVIOCGVERSION, GID, GNAME, GPHYS, GUNIQ, GPROP, GBIT, GKEY, GABS,
GREP and the accepted setters. Xorg and libinput decide what a device
*is* from the capability bitmaps; /dev/input/eventN answered only
EVIOCGRAB, which reads as no device at all. Each device's bitmaps are
its defaults plus whatever it has reported, so a USB tablet makes the
pointer absolute.

fbdev: FBIOPUT_VSCREENINFO succeeds for the mode already set, as on
Linux -- the fbdev driver sets it every time it starts -- and still
refuses any other. FBIOPAN_DISPLAY to the origin; FBIOBLANK.

The console: KDSETMODE(KD_GRAPHICS) stops it drawing on a terminal,
KDSKBMODE(K_OFF) stops keys reaching its tty, and VT_PROCESS now does
the switch handshake: leaving the terminal sends relsig and waits for
VT_RELDISP, arriving sends acqsig. A terminal whose owner has died goes
back to the kernel whole, so a crashed X cannot leave the console dead.

/sys: boot_vga, a writable enable, and graphics/fb0 under the display
device, which is how the fbdev driver pairs a card with /dev/fb0.

ports/linux-headers: <linux/*.h> into musl's prefix, from sabotage-
linux's kernel-headers 4.19.88-2. Its checksum is recorded from the
first download; upstream publishes none.

cmd/xready makes each call and checks the answer, including the switch
handshake on tty2 and an owner that dies holding it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 12:06:04 +02:00
commit b1323e193a
14 changed files with 860 additions and 32 deletions

View file

@ -1544,7 +1544,8 @@ addr_t sys_ioctl(void)
struct vt_mode *m = (struct vt_mode*)user_ptr(argp, sizeof(*m));
if (!m) return -EFAULT;
if (m->mode != VT_AUTO && m->mode != VT_PROCESS) return -EINVAL;
vt_for_minor(f->ip->minor)->mode = m->mode;
vt_set_process(vt_for_minor(f->ip->minor), m->mode, m->relsig,
m->acqsig);
return 0;
}
// Which chord the kernel switches on. SchOS's own ioctl -- see the long
@ -1601,10 +1602,60 @@ addr_t sys_ioctl(void)
struct vt_mode *m = (struct vt_mode*)user_ptr(argp, sizeof(*m));
if (!m) return -EFAULT;
memset(m, 0, sizeof(*m));
m->mode = (char)vt_for_minor(f->ip->minor)->mode;
struct vt *v = vt_for_minor(f->ip->minor);
m->mode = (char)v->mode;
m->relsig = (short)v->relsig;
m->acqsig = (short)v->acqsig;
return 0;
}
// The display server's half of a switch; see vt_switch(). By value.
if (request == VT_RELDISP)
return vt_reldisp(vt_for_minor(f->ip->minor), (int)argp);
// Terminals are a fixed set here and are never freed.
if (request == VT_DISALLOCATE)
return 0;
if (request == KDSETMODE) {
if (argp != KD_TEXT && argp != KD_GRAPHICS) return -EINVAL;
vt_set_kdmode(vt_for_minor(f->ip->minor), (int)argp);
return 0;
}
if (request == KDGETMODE) {
int *out = (int*)user_ptr(argp, sizeof(int));
if (!out) return -EFAULT;
*out = vt_for_minor(f->ip->minor)->kdmode;
return 0;
}
if (request == KDSKBMODE) {
if (argp > K_OFF) return -EINVAL;
vt_for_minor(f->ip->minor)->kbmode = (int)argp;
return 0;
}
if (request == KDGKBMODE) {
int *out = (int*)user_ptr(argp, sizeof(int));
if (!out) return -EFAULT;
*out = vt_for_minor(f->ip->minor)->kbmode;
return 0;
}
if (request == KDGKBTYPE) {
char *out = (char*)user_ptr(argp, 1);
if (!out) return -EFAULT;
*out = KB_101;
return 0;
}
// LEDs and the bell: nothing to light and no speaker on this path.
if (request == KDGETLED || request == KDGKBLED) {
char *out = (char*)user_ptr(argp, 1);
if (!out) return -EFAULT;
*out = 0;
return 0;
}
if (request == KDSETLED || request == KDSKBLED ||
request == KIOCSOUND || request == KDMKTONE)
return 0;
return 0;
}