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

@ -35,6 +35,9 @@ struct input_event {
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_LED 0x11
#define EV_REP 0x14
#define EV_MAX 0x1f
#define SYN_REPORT 0
@ -48,6 +51,8 @@ struct input_event {
#define REL_X 0x00
#define REL_Y 0x01
#define REL_WHEEL 0x08
#define REL_MAX 0x0f
#define ABS_MAX 0x3f
// Buttons live in the EV_KEY code space alongside keys, which is why the
// keyboard's codes stop well below 0x100.
@ -82,7 +87,7 @@ struct input_event {
#define KEY_LEFTMETA 125
#define KEY_RIGHTMETA 126
#define KEY_MAX 255
#define KEY_MAX 0x2ff // Linux's; the bitmaps are this wide
// EVIOCGRAB -- take/release exclusive access to a device.
//
@ -91,6 +96,59 @@ struct input_event {
// inventing a set just for this would be a bigger change than the feature.
// A non-zero argument grabs, zero releases; the argument is passed by value.
#define EVIOCGRAB 0x40044590
#define EVIOCREVOKE 0x40044591
// The queries a program makes before it reads anything: what the device is
// called, what it can report, what state it is in now. Xorg's evdev driver
// and libinput both decide what a device *is* -- keyboard, mouse, tablet --
// from the capability bitmaps alone, and treat a device that answers ENOTTY
// as no device at all.
//
// Linux's _IOC encoding: direction in bits 31:30 (2 read, 1 write), the size
// of the argument in 29:16, the type ('E') in 15:8, the number in 7:0. The
// variable-length ones carry the caller's buffer size in the size field, so
// they are matched with it masked out.
#define EVIOC_DIR(r) (((uint)(r) >> 30) & 3)
#define EVIOC_SIZE(r) (((uint)(r) >> 16) & 0x3fff)
#define EVIOC_TYPE(r) (((uint)(r) >> 8) & 0xff)
#define EVIOC_NR(r) ((uint)(r) & 0xff)
#define EVIOCGVERSION 0x80044501
#define EVIOCGID 0x80084502
#define EVIOCGREP 0x80084503
#define EVIOCSREP 0x40084503
#define EVIOCSCLOCKID 0x400445a0
// By number, with the length taken from the request:
#define EVIOCNR_GNAME 0x06
#define EVIOCNR_GPHYS 0x07
#define EVIOCNR_GUNIQ 0x08
#define EVIOCNR_GPROP 0x09
#define EVIOCNR_GKEY 0x18
#define EVIOCNR_GLED 0x19
#define EVIOCNR_GSND 0x1a
#define EVIOCNR_GSW 0x1b
#define EVIOCNR_GBIT 0x20 // + event type, 0x20..0x3f
#define EVIOCNR_GABS 0x40 // + axis, 0x40..0x7f
#define EVIOCNR_SABS 0xc0 // + axis
struct input_id {
uint16 bustype;
uint16 vendor;
uint16 product;
uint16 version;
};
struct input_absinfo {
int32 value;
int32 minimum;
int32 maximum;
int32 fuzz;
int32 flat;
int32 resolution;
};
#define BUS_I8042 0x11
#define INPUT_PROP_POINTER 0x00
// Which device an event came from. Both are minor numbers under the input
// major, and both are the index into the driver's array.

View file

@ -134,6 +134,12 @@ struct vt {
// VT_AUTO or VT_PROCESS. In VT_PROCESS a program has claimed switching and
// the kernel stops acting on the chord -- see vt_kernel_switches().
int mode;
int owner; // pid that set VT_PROCESS
int relsig, acqsig; // what to send it; see vt_switch()
int leaving_to; // a switch waiting on VT_RELDISP, or -1
int kdmode; // KD_TEXT, or KD_GRAPHICS: not drawn
int kbmode; // K_UNICODE..., or K_OFF: no keys
};
// The active terminal, and the one the framebuffer is showing.
@ -160,5 +166,9 @@ void vt_repaint(struct vt *v); // grid -> framebuffer, if active
uint32 vt_rgb(uint8 idx); // palette index -> RGB
int vt_index(struct vt *v); // 0-based number of a terminal
int vt_kernel_switches(void); // 0 if a program owns switching
int vt_reldisp(struct vt *v, int arg); // VT_RELDISP
void vt_set_process(struct vt *v, int mode, int relsig, int acqsig);
void vt_set_kdmode(struct vt *v, int mode);
int vt_takes_keys(struct vt *v); // 0 in K_OFF or a raw mode
#endif // VT_H

View file

@ -20,6 +20,7 @@
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOBLANK 0x4611
#define FBIOPAN_DISPLAY 0x4606
// fb_fix_screeninfo.type
#define FB_TYPE_PACKED_PIXELS 0

View file

@ -145,8 +145,34 @@ struct rlimit {
#define VT_GETMODE 0x5601
#define VT_SETMODE 0x5602
#define VT_GETSTATE 0x5603 // struct vt_stat
#define VT_RELDISP 0x5605 // by value: 1 release, 0 refuse, VT_ACKACQ
#define VT_ACTIVATE 0x5606
#define VT_WAITACTIVE 0x5607
#define VT_DISALLOCATE 0x5608
// The console's keyboard and display modes, which a display server sets on
// the terminal it takes: KD_GRAPHICS so the console stops drawing on it, and
// K_OFF so keys stop reaching its tty -- the server reads them from
// /dev/input instead. Linux's numbers.
#define KIOCSOUND 0x4B2F
#define KDMKTONE 0x4B30
#define KDGETLED 0x4B31
#define KDSETLED 0x4B32
#define KDGKBTYPE 0x4B33
#define KDSETMODE 0x4B3A
#define KDGETMODE 0x4B3B
#define KDGKBMODE 0x4B44
#define KDSKBMODE 0x4B45
#define KDGKBLED 0x4B64
#define KDSKBLED 0x4B65
#define KD_TEXT 0x00
#define KD_GRAPHICS 0x01
#define K_RAW 0x00
#define K_XLATE 0x01
#define K_MEDIUMRAW 0x02
#define K_UNICODE 0x03
#define K_OFF 0x04
#define KB_101 0x02
// VT_SETMODE modes. VT_AUTO is the kernel switching on its own; VT_PROCESS
// means a program has taken switching over and the kernel must keep its hands
@ -200,8 +226,8 @@ struct vt_chord {
struct vt_mode {
char mode; // VT_AUTO or VT_PROCESS
char waitv; // unused here
short relsig; // signal on release -- not delivered yet
short acqsig; // signal on acquire -- not delivered yet
short relsig; // signal on release; see vt_switch()
short acqsig; // signal on acquire
short frsig; // unused
};