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:
parent
132a2981b1
commit
b1323e193a
14 changed files with 860 additions and 32 deletions
|
|
@ -4,7 +4,8 @@
|
|||
//
|
||||
// /sys/bus/pci/devices/0000:00:1f.2/ vendor device class revision irq
|
||||
// subsystem_vendor subsystem_device
|
||||
// resource config uevent
|
||||
// resource config uevent boot_vga
|
||||
// enable graphics/fb0/
|
||||
// /sys/bus/usb/devices/1-3.2/ idVendor idProduct bcdDevice busnum
|
||||
// devnum speed bDevice* uevent
|
||||
// /sys/firmware/acpi/tables/DSDT the tables, byte for byte
|
||||
|
|
@ -40,6 +41,7 @@
|
|||
#include "dev/pci.h"
|
||||
#include "dev/usb.h"
|
||||
#include "core/hwinfo.h"
|
||||
#include "gfx/gfx.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Inode numbers: kind, index, file -- the whole identity, since iget gives
|
||||
|
|
@ -87,11 +89,43 @@ static const struct { const char *name; int parent; } dirs[D_NDIRS] = {
|
|||
|
||||
static const char *const pcifiles[] = {
|
||||
0, "vendor", "device", "class", "revision", "subsystem_vendor",
|
||||
"subsystem_device", "irq", "resource", "config", "uevent",
|
||||
"subsystem_device", "irq", "resource", "config", "uevent", "boot_vga",
|
||||
"enable",
|
||||
};
|
||||
#define PCI_CONFIG 9
|
||||
#define PCI_ENABLE 12
|
||||
#define NPCIFILES ((int)(sizeof pcifiles / sizeof pcifiles[0]))
|
||||
|
||||
// Two directories under the display device only: graphics/ and graphics/fb0/.
|
||||
// Xorg's fbdev driver finds the framebuffer that belongs to a PCI device by
|
||||
// looking for exactly that path, and libpciaccess picks the primary card by
|
||||
// boot_vga. Empty, because the path existing is the whole answer.
|
||||
#define PCI_GRAPHICS 13
|
||||
#define PCI_FB0 14
|
||||
|
||||
// The display device: the one whose memory the framebuffer is in, which is
|
||||
// what boot_vga means on Linux -- the card firmware brought up and drew on.
|
||||
// Failing that, the first display controller. -1 when there is neither.
|
||||
static int
|
||||
boot_vga_idx(void)
|
||||
{
|
||||
uint64 fb = gfx_fb_phys();
|
||||
int first = -1;
|
||||
|
||||
for (int i = 0; i < pci_count(); i++) {
|
||||
struct pci_dev *d = pci_get(i);
|
||||
if (d->class != 0x03)
|
||||
continue;
|
||||
if (first < 0)
|
||||
first = i;
|
||||
for (int b = 0; fb && b < 6; b++)
|
||||
if (!d->bar[b].is_io && d->bar[b].base && fb >= d->bar[b].base &&
|
||||
fb < d->bar[b].base + d->bar[b].size)
|
||||
return i;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
static const char *const usbfiles[] = {
|
||||
0, "idVendor", "idProduct", "bcdDevice", "busnum", "devnum", "speed",
|
||||
"bDeviceClass", "bDeviceSubClass", "bDeviceProtocol", "bNumConfigurations",
|
||||
|
|
@ -276,6 +310,12 @@ children(uint64 dino, child_fn cb, void *ctx)
|
|||
for (int f = 1; f < NPCIFILES; f++)
|
||||
if (cb(ctx, INO(K_PCI, idx, f), 0, pcifiles[f]))
|
||||
return 1;
|
||||
if (idx == boot_vga_idx() && gfx_fb_phys() &&
|
||||
cb(ctx, INO(K_PCI, idx, PCI_GRAPHICS), 1, "graphics"))
|
||||
return 1;
|
||||
} else if (kind == K_PCI && I_FILE(dino) == PCI_GRAPHICS) {
|
||||
if (cb(ctx, INO(K_PCI, idx, PCI_FB0), 1, "fb0"))
|
||||
return 1;
|
||||
} else if (kind == K_USB && I_FILE(dino) == 0) {
|
||||
for (int f = 1; f < NUSBFILES; f++)
|
||||
if (cb(ctx, INO(K_USB, idx, f), 0, usbfiles[f]))
|
||||
|
|
@ -293,7 +333,10 @@ parent_of(uint64 dino)
|
|||
{
|
||||
switch (I_KIND(dino)) {
|
||||
case K_DIR: return INO(K_DIR, dirs[I_IDX(dino)].parent, 0);
|
||||
case K_PCI: return INO(K_DIR, D_PCIDEV, 0);
|
||||
case K_PCI:
|
||||
if (I_FILE(dino) == PCI_GRAPHICS) return INO(K_PCI, I_IDX(dino), 0);
|
||||
if (I_FILE(dino) == PCI_FB0) return INO(K_PCI, I_IDX(dino), PCI_GRAPHICS);
|
||||
return INO(K_DIR, D_PCIDEV, 0);
|
||||
case K_USB: return INO(K_DIR, D_USBDEV, 0);
|
||||
case K_MEMMAP: return INO(K_DIR, D_MEMMAP, 0);
|
||||
}
|
||||
|
|
@ -363,6 +406,13 @@ gen_pci(struct out *o, struct pci_dev *d, int f)
|
|||
case 5: puts_(o, "0x"); putx(o, svid, 4, 0); break;
|
||||
case 6: puts_(o, "0x"); putx(o, sdid, 4, 0); break;
|
||||
case 7: putu(o, d->irq == 0xFF ? 0 : d->irq); break;
|
||||
case 11: putc_(o, d == pci_get(boot_vga_idx()) ? '1' : '0'); break;
|
||||
case PCI_ENABLE: {
|
||||
// Whether memory or I/O decoding is on: what "enabled" amounts to.
|
||||
uint32 cmd = pci_read32(d->bus, d->slot, d->func, 0x04);
|
||||
putc_(o, (cmd & 3) ? '1' : '0');
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
// start, end, flags per BAR, then the ROM, as Linux prints them.
|
||||
for (int b = 0; b < 7; b++) {
|
||||
|
|
@ -487,6 +537,8 @@ exists_dir(uint64 ino)
|
|||
case K_DIR:
|
||||
return I_IDX(ino) < D_NDIRS && (I_IDX(ino) != D_EFI || boot_is_efi());
|
||||
case K_PCI:
|
||||
if (I_FILE(ino) == PCI_GRAPHICS || I_FILE(ino) == PCI_FB0)
|
||||
return I_IDX(ino) == boot_vga_idx() && gfx_fb_phys() != 0;
|
||||
return I_IDX(ino) < pci_count();
|
||||
case K_USB: {
|
||||
struct usb_info u;
|
||||
|
|
@ -514,7 +566,9 @@ sysfs_iload(struct inode *ip)
|
|||
ip->size = 0;
|
||||
ip->nlink = 1;
|
||||
|
||||
if (I_FILE(ino) == 0 && exists_dir(ino)) {
|
||||
int subdir = I_KIND(ino) == K_PCI &&
|
||||
(I_FILE(ino) == PCI_GRAPHICS || I_FILE(ino) == PCI_FB0);
|
||||
if ((I_FILE(ino) == 0 || subdir) && exists_dir(ino)) {
|
||||
ip->type = T_DIR;
|
||||
ip->nlink = 2;
|
||||
return;
|
||||
|
|
@ -533,6 +587,8 @@ sysfs_iload(struct inode *ip)
|
|||
kmfree(buf);
|
||||
if (n >= 0) {
|
||||
ip->type = T_FILE;
|
||||
if (I_KIND(ino) == K_PCI && I_FILE(ino) == PCI_ENABLE)
|
||||
ip->rwmode = 3;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -585,9 +641,18 @@ sysfs_read(struct inode *ip, int user_dst, uint64 dst, uint64 off, uint n)
|
|||
return r;
|
||||
}
|
||||
|
||||
// Only `enable`, which libpciaccess writes before it touches a device. The
|
||||
// kernel's drivers already turned decoding on for every device they use, and
|
||||
// one nobody drives does not need it -- so the write is accepted and changes
|
||||
// nothing, which is what it would have done on Linux for a device already on.
|
||||
static int
|
||||
sysfs_write(struct inode *ip, int u, uint64 s, uint64 o, uint n)
|
||||
{ (void)ip; (void)u; (void)s; (void)o; (void)n; return -EROFS; }
|
||||
{
|
||||
(void)u; (void)s; (void)o;
|
||||
if (I_KIND(ip->inum) == K_PCI && I_FILE(ip->inum) == PCI_ENABLE)
|
||||
return (int)n;
|
||||
return -EROFS;
|
||||
}
|
||||
|
||||
struct find { const char *name; uint64 ino; };
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue