gfx: the console and the crash screen stop drawing on a driver by name
Same disease as the network stack, one subsystem over. kernel/dev/vga.c
was three things wearing one name: the owner of the framebuffer, a
bitmap drawing library, and the text console. Only the first is a
driver, and because they shared a file they shared a prefix -- so
panic.c drew the crash screen with vga_fill_rect, console.c printed with
vga_putc, /dev/fb0 handed out vga_fb_phys, and every one of those files
named a display driver it had no business knowing about.
Split three ways:
- kernel/drivers/gpu/vga/vga_fb.c owns the VBE framebuffer -- the mode
the loader programmed and handed over, the aperture, and the display
class vtable. It is a driver and now lives with the driver that
finds the card on the bus.
- kernel/dev/gfx.c draws: pixels, shapes, glyphs, the cursor, scroll,
the ANSI erase operations. It names no driver. The framebuffer
arrives through gfx_attach_scanout(), so a driver publishes what it
owns and this file draws on it without knowing what it is.
- include/gfx.h is the interface, and says why it is deliberately not
the display class: that one is about frames -- acquire, present,
vblank -- and the crash screen has to work when nothing else does.
main() no longer calls a display driver. platform_register_devices()
takes the framebuffer address and brings up whatever owns it, which is
where driver names belong; kernel/drivers/registry.c is the file whose
entire job is naming every driver in the kernel.
virtio-gpu got the e1000 treatment as well: instances in an array, the
instance hung on dev->priv by an `attached` hook, and every op reading
it rather than a file-static. It refused the second adapter outright
before, which is not hypothetical -- integrated plus discrete is an
ordinary laptop. The VGA driver deliberately has no such hook, and says
so: there is one framebuffer the loader programmed however many
VGA-class controllers the bus turns up, and a second one publishing the
same scanout is the truth rather than a bug.
Private headers moved next to their drivers: include/virtio.h and
include/xhci.h each had exactly one includer. include/ is for headers
the rest of the kernel needs.
Deleted rather than moved: consoleinit() programmed the sixteen ANSI
colours into the VGA DAC and disabled text-mode blink, by writing ports
0x3C0-0x3C9 from the console. The comment three lines above the colour
table already said this does nothing in a 32bpp linear mode -- there is
no palette to index -- so it was both dead and in the wrong file.
Verified, and this is a refactor so the evidence is that nothing moved:
- bootcheck -Fb -Net: 59 [ok], no failures. That covers the console
through every command, /dev/fb0's geometry, writing pixels through
write() and mapping the framebuffer through mmap.
- make crashshot: the crash screen renders exactly as before --
shapes, glyphs, logo and QR code -- which is the whole of gfx.c
exercised at once, in a panic, with the scanout attached by a driver.
- make schcom-test: five pixel assertions from the host oracle still
pass, so the display class and the compositor above it are unmoved.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
20cc673a41
commit
817d666068
22 changed files with 942 additions and 752 deletions
|
|
@ -491,32 +491,10 @@ void uartinit(void);
|
|||
void uartintr(void);
|
||||
void uartputc(int);
|
||||
|
||||
// vga.c
|
||||
void vga_init(uint64);
|
||||
void vga_draw_pixel(int, int, uint32);
|
||||
void vga_draw_char(int, int, uchar, uint32);
|
||||
void vga_puts(int, int, char*, uint32);
|
||||
void vga_putc(int, uint32);
|
||||
void vga_clear(uint32);
|
||||
void vga_screen_reset(void);
|
||||
void vga_set_bg(uint32);
|
||||
// The mode actually in use. The resolution is a boot-time choice now, so no
|
||||
// caller may hardcode it.
|
||||
uint32 vga_get_width(void);
|
||||
uint32 vga_get_height(void);
|
||||
// Crash-screen primitives: the panic handler lays itself out rather than
|
||||
// printing. See kernel/core/panic.c.
|
||||
int vga_ready(void);
|
||||
void vga_dims(int *w, int *h);
|
||||
int vga_char_w(void);
|
||||
int vga_char_h(void);
|
||||
// Framebuffer geometry. vga.c reads the VBE mode info, so it is the only
|
||||
// thing that knows where the framebuffer is; nobody else may assume.
|
||||
uint64 vga_fb_phys(void);
|
||||
uint64 vga_fb_size(void);
|
||||
uint32 vga_fb_stride(void);
|
||||
uint32 vga_fb_bpp(void);
|
||||
volatile uchar *vga_fb_ptr(void);
|
||||
// Drawing, the text console and the framebuffer geometry are NOT declared
|
||||
// here: they live in include/gfx.h, and the display drivers that back them in
|
||||
// include/display.h. Declaring vga_fill_rect() here is what let the crash
|
||||
// screen draw on one named driver.
|
||||
|
||||
// fb.c -- /dev/fb0, major 2.
|
||||
void fbclose(struct inode*);
|
||||
|
|
@ -554,22 +532,17 @@ struct netif *net_eth_netif(int i);
|
|||
struct device *net_eth_device(int i);
|
||||
|
||||
// registry.c
|
||||
void platform_register_devices(void);
|
||||
// Platform devices, and the boot framebuffer. Takes the framebuffer address
|
||||
// the loader handed over, because bringing that up is the first thing it does.
|
||||
void platform_register_devices(uint64 fb_addr);
|
||||
// drivers/gpu/vga -- the VBE framebuffer the loader programmed. Called only
|
||||
// from registry.c; everything else draws through include/gfx.h.
|
||||
void vga_fb_init(uint64 phys_addr);
|
||||
uint64 vga_fb_phys(void);
|
||||
uint64 vga_fb_size(void);
|
||||
|
||||
void e820_init(void);
|
||||
int acpi_init(void);
|
||||
void vga_fill_rect(int x, int y, int w, int h, uint32);
|
||||
void vga_fill_circle(int cx, int cy, int r, uint32);
|
||||
void vga_text_at(int, int, const char*, uint32);
|
||||
void vga_draw_logo(int x, int y, uint32 color, uint32 bg);
|
||||
void vga_logo_centered(int cy, uint32 color, uint32 bg);
|
||||
// Cursor addressing and erasing, for the console's ANSI escape parser.
|
||||
int vga_cols(void);
|
||||
int vga_rows(void);
|
||||
void vga_cursor_get(int *col, int *row);
|
||||
void vga_cursor_set(int col, int row);
|
||||
void vga_erase_display(int mode);
|
||||
void vga_erase_line(int mode);
|
||||
|
||||
// console.c / panic.c
|
||||
void cons_panic_mode(void);
|
||||
|
|
|
|||
78
include/gfx.h
Normal file
78
include/gfx.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#pragma once
|
||||
|
||||
// Drawing, and the text console under it, on whatever display is bound.
|
||||
//
|
||||
// This was kernel/dev/vga.c, and every consumer called it by that name:
|
||||
// panic.c drew the crash screen with vga_fill_rect, the console printed with
|
||||
// vga_putc, /dev/fb0 handed out vga_fb_phys(). None of that code has anything
|
||||
// to do with a VGA -- it is bitmap drawing over a linear framebuffer, and the
|
||||
// only VGA-specific part was where the framebuffer came from.
|
||||
//
|
||||
// So the driver pushes its scanout in here (gfx_attach_scanout) and everything
|
||||
// above draws through these calls. A second display driver becomes a second
|
||||
// caller of one function rather than an edit to the crash screen. This is the
|
||||
// same arrangement as include/netdev.h, for the same reason.
|
||||
//
|
||||
// Not the same thing as the display class in include/display.h. That is the
|
||||
// compositor's interface -- acquire a back buffer, present a rectangle, wait
|
||||
// for vblank -- and it is about *frames*. This is the kernel's own drawing
|
||||
// surface, used by the console and the crash screen, which do not double
|
||||
// buffer and must keep working when nothing else in the system does.
|
||||
|
||||
// A linear framebuffer, exactly as the hardware presents it.
|
||||
struct fb_info {
|
||||
volatile uchar *ptr; // kernel-mapped base, or 0 if there is none
|
||||
uint64 phys; // physical base, for mmap and for page tables
|
||||
uint64 size; // bytes, stride * height rather than w * h * bpp
|
||||
uint32 stride; // bytes per row, which may exceed width * bpp/8
|
||||
uint32 bpp;
|
||||
uint32 width, height;
|
||||
};
|
||||
|
||||
// A driver publishing the framebuffer it owns. Called once, early: the console
|
||||
// draws long before any bus is enumerated, so whoever owns the display the
|
||||
// loader left running has to say so before then.
|
||||
void gfx_attach_scanout(const struct fb_info *);
|
||||
|
||||
// The scanout as attached, for the few callers that need the memory itself --
|
||||
// /dev/fb0 maps it, and fork copies the mapping. Returns 0 if none.
|
||||
const struct fb_info *gfx_scanout(void);
|
||||
|
||||
int gfx_ready(void);
|
||||
void gfx_dims(int *w, int *h);
|
||||
uint32 gfx_width(void);
|
||||
uint32 gfx_height(void);
|
||||
uint64 gfx_fb_phys(void);
|
||||
uint64 gfx_fb_size(void);
|
||||
uint32 gfx_fb_stride(void);
|
||||
uint32 gfx_fb_bpp(void);
|
||||
volatile uchar *gfx_fb_ptr(void);
|
||||
|
||||
// Pixels and shapes.
|
||||
void gfx_draw_pixel(int x, int y, uint32 color);
|
||||
void gfx_clear(uint32 color);
|
||||
void gfx_fill_rect(int x, int y, int w, int h, uint32 color);
|
||||
void gfx_fill_circle(int cx, int cy, int r, uint32 color);
|
||||
void gfx_draw_logo(int x, int y, uint32 color, uint32 bg);
|
||||
void gfx_logo_centered(int cy, uint32 color, uint32 bg);
|
||||
|
||||
// The built-in 8x16 font: glyphs at a position, and text that leaves the
|
||||
// cursor alone. The crash screen lays itself out rather than printing, which
|
||||
// is what needs the second one.
|
||||
void gfx_draw_char(int x, int y, uchar c, uint32 color);
|
||||
void gfx_text_at(int x, int y, const char *s, uint32 color);
|
||||
int gfx_char_w(void);
|
||||
int gfx_char_h(void);
|
||||
|
||||
// The text console: a cursor, scrolling, and the erase operations an ANSI
|
||||
// escape parser needs. See kernel/core/console.c.
|
||||
void gfx_putc(int c, uint32 color);
|
||||
void gfx_puts(int x, int y, char *s, uint32 color);
|
||||
void gfx_set_bg(uint32 color);
|
||||
void gfx_screen_reset(void);
|
||||
int gfx_cols(void);
|
||||
int gfx_rows(void);
|
||||
void gfx_cursor_get(int *col, int *row);
|
||||
void gfx_cursor_set(int col, int row);
|
||||
void gfx_erase_display(int mode);
|
||||
void gfx_erase_line(int mode);
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
// types, no code — because stage2 is compiled 32-bit against a different
|
||||
// world than the kernel.
|
||||
//
|
||||
// Colours are 0xRRGGBB. vga_draw_pixel packs them for whatever depth the
|
||||
// Colours are 0xRRGGBB. gfx_draw_pixel packs them for whatever depth the
|
||||
// framebuffer actually is.
|
||||
|
||||
// --- the product ---------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ int getpid(void);
|
|||
char* sbrk(uint64);
|
||||
int sleep(int);
|
||||
int uptime(void);
|
||||
int vga_sync(void*);
|
||||
int vga_sync(void*); // legacy no-op syscall; the name is ABI, not this layer
|
||||
int getmouse(struct mouse_data*);
|
||||
int reboot(void);
|
||||
int shutdown(void);
|
||||
|
|
|
|||
174
include/virtio.h
174
include/virtio.h
|
|
@ -1,174 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// virtio 1.0 over PCI — the transport, and virtio-gpu's 2D protocol.
|
||||
//
|
||||
// Written from the OASIS specification (virtio 1.1, chapters 2, 4.1 and 5.7),
|
||||
// which is a public document with no licence on what you write from it. Same
|
||||
// reasoning as kernel/drivers/xhci.c.
|
||||
//
|
||||
// Why virtio-gpu at all, when there is already a framebuffer: the VBE
|
||||
// framebuffer is a flat block of memory the loader happened to be told about.
|
||||
// It has no mode setting, no notion of a frame being complete, and no way to
|
||||
// ask the host to present anything -- so a compositor drawing into it is
|
||||
// racing the scanout with no way to synchronise. virtio-gpu has resources,
|
||||
// explicit transfer and an explicit flush, which is the model every real GPU
|
||||
// driver has. It is the smallest device that teaches the right shape.
|
||||
|
||||
// --- PCI transport ---------------------------------------------------------
|
||||
|
||||
#define VIRTIO_VENDOR 0x1AF4
|
||||
// Modern (1.0) device IDs are 0x1040 + the virtio device type. GPU is type 16.
|
||||
#define VIRTIO_DEV_GPU 0x1050
|
||||
|
||||
// Vendor-specific PCI capability, which is how a virtio device says where in
|
||||
// its BARs each configuration structure lives.
|
||||
#define PCI_CAP_ID_VNDR 0x09
|
||||
|
||||
#define VIRTIO_PCI_CAP_COMMON_CFG 1
|
||||
#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
|
||||
#define VIRTIO_PCI_CAP_ISR_CFG 3
|
||||
#define VIRTIO_PCI_CAP_DEVICE_CFG 4
|
||||
|
||||
// Offsets within the common configuration structure. Written out rather than
|
||||
// declared as a struct: the fields are little-endian by specification and of
|
||||
// mixed width, and a struct invites the compiler to pad or a caller to forget
|
||||
// that these are MMIO and must be accessed at exactly the stated width.
|
||||
#define VCOMMON_DFEAT_SEL 0x00 // le32
|
||||
#define VCOMMON_DFEAT 0x04 // le32
|
||||
#define VCOMMON_GFEAT_SEL 0x08 // le32
|
||||
#define VCOMMON_GFEAT 0x0C // le32
|
||||
#define VCOMMON_MSIX_CFG 0x10 // le16
|
||||
#define VCOMMON_NUM_QUEUES 0x12 // le16
|
||||
#define VCOMMON_STATUS 0x14 // u8
|
||||
#define VCOMMON_CFG_GEN 0x15 // u8
|
||||
#define VCOMMON_Q_SELECT 0x16 // le16
|
||||
#define VCOMMON_Q_SIZE 0x18 // le16
|
||||
#define VCOMMON_Q_MSIX 0x1A // le16
|
||||
#define VCOMMON_Q_ENABLE 0x1C // le16
|
||||
#define VCOMMON_Q_NOTIFY_OFF 0x1E // le16
|
||||
#define VCOMMON_Q_DESC 0x20 // le64
|
||||
#define VCOMMON_Q_DRIVER 0x28 // le64
|
||||
#define VCOMMON_Q_DEVICE 0x30 // le64
|
||||
|
||||
// device_status bits, set in this order during bring-up.
|
||||
#define VSTATUS_ACK 1
|
||||
#define VSTATUS_DRIVER 2
|
||||
#define VSTATUS_DRIVER_OK 4
|
||||
#define VSTATUS_FEATURES_OK 8
|
||||
#define VSTATUS_FAILED 0x80
|
||||
|
||||
#define VIRTIO_F_VERSION_1 32 // feature bit: this is a 1.0 device
|
||||
|
||||
// --- split virtqueue -------------------------------------------------------
|
||||
|
||||
#define VRING_DESC_F_NEXT 1
|
||||
#define VRING_DESC_F_WRITE 2 // device writes it; i.e. this is our buffer
|
||||
|
||||
struct vring_desc {
|
||||
uint64 addr;
|
||||
uint32 len;
|
||||
uint16 flags;
|
||||
uint16 next;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct vring_avail {
|
||||
uint16 flags;
|
||||
uint16 idx;
|
||||
uint16 ring[];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct vring_used_elem {
|
||||
uint32 id;
|
||||
uint32 len;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct vring_used {
|
||||
uint16 flags;
|
||||
uint16 idx;
|
||||
struct vring_used_elem ring[];
|
||||
} __attribute__((packed));
|
||||
|
||||
// --- virtio-gpu, 2D --------------------------------------------------------
|
||||
|
||||
#define VIRTIO_GPU_CMD_GET_DISPLAY_INFO 0x0100
|
||||
#define VIRTIO_GPU_CMD_RESOURCE_CREATE_2D 0x0101
|
||||
#define VIRTIO_GPU_CMD_RESOURCE_UNREF 0x0102
|
||||
#define VIRTIO_GPU_CMD_SET_SCANOUT 0x0103
|
||||
#define VIRTIO_GPU_CMD_RESOURCE_FLUSH 0x0104
|
||||
#define VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D 0x0105
|
||||
#define VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING 0x0106
|
||||
|
||||
#define VIRTIO_GPU_RESP_OK_NODATA 0x1100
|
||||
#define VIRTIO_GPU_RESP_OK_DISPLAY_INFO 0x1101
|
||||
|
||||
#define VIRTIO_GPU_MAX_SCANOUTS 16
|
||||
|
||||
// B8G8R8X8, which is what a 32-bit little-endian 0x00RRGGBB word looks like in
|
||||
// memory -- the same layout vga.c already draws into, so a framebuffer can be
|
||||
// handed over without a conversion pass.
|
||||
#define VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM 2
|
||||
|
||||
struct virtio_gpu_ctrl_hdr {
|
||||
uint32 type;
|
||||
uint32 flags;
|
||||
uint64 fence_id;
|
||||
uint32 ctx_id;
|
||||
uint32 padding;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_rect {
|
||||
uint32 x, y, width, height;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_display_one {
|
||||
struct virtio_gpu_rect r;
|
||||
uint32 enabled;
|
||||
uint32 flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_resp_display_info {
|
||||
struct virtio_gpu_ctrl_hdr hdr;
|
||||
struct virtio_gpu_display_one pmodes[VIRTIO_GPU_MAX_SCANOUTS];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_resource_create_2d {
|
||||
struct virtio_gpu_ctrl_hdr hdr;
|
||||
uint32 resource_id;
|
||||
uint32 format;
|
||||
uint32 width;
|
||||
uint32 height;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_mem_entry {
|
||||
uint64 addr;
|
||||
uint32 length;
|
||||
uint32 padding;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_resource_attach_backing {
|
||||
struct virtio_gpu_ctrl_hdr hdr;
|
||||
uint32 resource_id;
|
||||
uint32 nr_entries;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_set_scanout {
|
||||
struct virtio_gpu_ctrl_hdr hdr;
|
||||
struct virtio_gpu_rect r;
|
||||
uint32 scanout_id;
|
||||
uint32 resource_id;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_transfer_to_host_2d {
|
||||
struct virtio_gpu_ctrl_hdr hdr;
|
||||
struct virtio_gpu_rect r;
|
||||
uint64 offset;
|
||||
uint32 resource_id;
|
||||
uint32 padding;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct virtio_gpu_resource_flush {
|
||||
struct virtio_gpu_ctrl_hdr hdr;
|
||||
struct virtio_gpu_rect r;
|
||||
uint32 resource_id;
|
||||
uint32 padding;
|
||||
} __attribute__((packed));
|
||||
161
include/xhci.h
161
include/xhci.h
|
|
@ -1,161 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
// eXtensible Host Controller Interface -- the register and data-structure
|
||||
// definitions from the xHCI 1.2 specification.
|
||||
//
|
||||
// Why xHCI and not UHCI/OHCI/EHCI: xHCI is the only host controller interface
|
||||
// that speaks every USB speed, so one driver covers USB 1.1 through 3.x. The
|
||||
// older controllers would each need their own, and a machine with all of them
|
||||
// needs the companion-controller handover dance on top. There is no hardware
|
||||
// worth supporting that has no xHCI.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Capability registers -- at the start of BAR0, read-only
|
||||
// ---------------------------------------------------------------------------
|
||||
#define XHCI_CAPLENGTH 0x00 // byte: where the operational regs begin
|
||||
#define XHCI_HCIVERSION 0x02 // word
|
||||
#define XHCI_HCSPARAMS1 0x04
|
||||
#define XHCI_HCSPARAMS2 0x08
|
||||
#define XHCI_HCSPARAMS3 0x0C
|
||||
#define XHCI_HCCPARAMS1 0x10
|
||||
#define XHCI_DBOFF 0x14 // doorbell array offset from BAR0
|
||||
#define XHCI_RTSOFF 0x18 // runtime register offset from BAR0
|
||||
|
||||
#define HCS1_MAXSLOTS(x) ((x) & 0xFF)
|
||||
#define HCS1_MAXINTRS(x) (((x) >> 8) & 0x7FF)
|
||||
#define HCS1_MAXPORTS(x) (((x) >> 24) & 0xFF)
|
||||
|
||||
// Scratchpad buffer count is split across two fields, high part first.
|
||||
#define HCS2_SPB_HI(x) (((x) >> 21) & 0x1F)
|
||||
#define HCS2_SPB_LO(x) (((x) >> 27) & 0x1F)
|
||||
|
||||
#define HCC1_AC64 (1 << 0) // 64-bit addressing
|
||||
#define HCC1_CSZ (1 << 2) // contexts are 64 bytes, not 32
|
||||
#define HCC1_XECP(x) (((x) >> 16) & 0xFFFF) // extended caps, in dwords
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Operational registers -- at BAR0 + CAPLENGTH
|
||||
// ---------------------------------------------------------------------------
|
||||
#define XHCI_USBCMD 0x00
|
||||
#define XHCI_USBSTS 0x04
|
||||
#define XHCI_PAGESIZE 0x08
|
||||
#define XHCI_DNCTRL 0x14
|
||||
#define XHCI_CRCR 0x18 // 64-bit
|
||||
#define XHCI_DCBAAP 0x30 // 64-bit
|
||||
#define XHCI_CONFIG 0x38
|
||||
#define XHCI_PORTSC(p) (0x400 + 0x10 * ((p) - 1)) // ports are 1-based
|
||||
|
||||
#define CMD_RS (1 << 0) // run/stop
|
||||
#define CMD_HCRST (1 << 1) // host controller reset
|
||||
#define CMD_INTE (1 << 2) // interrupter enable
|
||||
#define CMD_HSEE (1 << 3)
|
||||
|
||||
#define STS_HCH (1 << 0) // halted
|
||||
#define STS_HSE (1 << 2) // host system error
|
||||
#define STS_EINT (1 << 3) // event interrupt (write 1 to clear)
|
||||
#define STS_PCD (1 << 4) // port change detect (write 1 to clear)
|
||||
#define STS_CNR (1 << 11) // controller not ready
|
||||
|
||||
#define CRCR_RCS (1 << 0) // ring cycle state
|
||||
|
||||
// PORTSC. The change bits are write-1-to-clear, and so is PED -- writing back
|
||||
// a value read from this register clears whatever happened to be set. Every
|
||||
// write has to mask them off first.
|
||||
#define PORT_CCS (1 << 0) // current connect status
|
||||
#define PORT_PED (1 << 1) // port enabled (RW1C!)
|
||||
#define PORT_OCA (1 << 3)
|
||||
#define PORT_PR (1 << 4) // port reset
|
||||
#define PORT_PLS(x) (((x) >> 5) & 0xF)
|
||||
#define PORT_PP (1 << 9) // port power
|
||||
#define PORT_SPEED(x) (((x) >> 10) & 0xF)
|
||||
#define PORT_CSC (1 << 17)
|
||||
#define PORT_PEC (1 << 18)
|
||||
#define PORT_PRC (1 << 21)
|
||||
#define PORT_RW1C 0x00FE0002u // change bits 17..23, plus PED
|
||||
|
||||
// PORTSC speed encoding. These are the same numbers as USB_SPEED_* in usb.h,
|
||||
// which is not a coincidence -- the core uses this encoding directly so that
|
||||
// nothing has to be translated on its way to a slot context.
|
||||
#define XSPEED_FULL USB_SPEED_FULL
|
||||
#define XSPEED_LOW USB_SPEED_LOW
|
||||
#define XSPEED_HIGH USB_SPEED_HIGH
|
||||
#define XSPEED_SUPER USB_SPEED_SUPER
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Runtime registers -- at BAR0 + RTSOFF. Interrupter n is at 0x20 + 32*n.
|
||||
// ---------------------------------------------------------------------------
|
||||
#define XHCI_MFINDEX 0x00
|
||||
#define XHCI_IR0 0x20
|
||||
#define IR_IMAN 0x00
|
||||
#define IR_IMOD 0x04
|
||||
#define IR_ERSTSZ 0x08
|
||||
#define IR_ERSTBA 0x10 // 64-bit
|
||||
#define IR_ERDP 0x18 // 64-bit
|
||||
|
||||
#define IMAN_IP (1 << 0) // interrupt pending (RW1C)
|
||||
#define IMAN_IE (1 << 1) // interrupt enable
|
||||
#define ERDP_EHB (1 << 3) // event handler busy (RW1C)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Transfer Request Blocks
|
||||
// ---------------------------------------------------------------------------
|
||||
struct trb {
|
||||
uint64 param;
|
||||
uint32 status;
|
||||
uint32 control;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define TRB_TYPE(t) (((t) & 0x3F) << 10)
|
||||
#define TRB_GET_TYPE(c) (((c) >> 10) & 0x3F)
|
||||
#define TRB_C (1 << 0) // cycle bit
|
||||
#define TRB_TC (1 << 1) // toggle cycle (link TRBs)
|
||||
#define TRB_ISP (1 << 2)
|
||||
#define TRB_CH (1 << 4) // chain
|
||||
#define TRB_IOC (1 << 5) // interrupt on completion
|
||||
#define TRB_IDT (1 << 6) // immediate data
|
||||
#define TRB_SLOT(s) ((uint32)(s) << 24)
|
||||
#define TRB_GET_SLOT(c) (((c) >> 24) & 0xFF)
|
||||
#define TRB_GET_EPID(c) (((c) >> 16) & 0x1F) // transfer events
|
||||
|
||||
// Transfer TRBs
|
||||
#define TRB_NORMAL 1
|
||||
#define TRB_SETUP 2
|
||||
#define TRB_DATA 3
|
||||
#define TRB_STATUS 4
|
||||
#define TRB_LINK 6
|
||||
// Command TRBs
|
||||
#define TRB_ENABLE_SLOT 9
|
||||
#define TRB_DISABLE_SLOT 10
|
||||
#define TRB_ADDRESS_DEV 11
|
||||
#define TRB_CONFIG_EP 12
|
||||
#define TRB_EVAL_CTX 13
|
||||
#define TRB_RESET_EP 14
|
||||
#define TRB_NOOP_CMD 23
|
||||
// Event TRBs
|
||||
#define TRB_XFER_EVENT 32
|
||||
#define TRB_CMD_COMPLETE 33
|
||||
#define TRB_PORT_STATUS 34
|
||||
|
||||
#define TRB_CC(status) (((status) >> 24) & 0xFF)
|
||||
#define CC_SUCCESS 1
|
||||
#define CC_SHORT_PACKET 13
|
||||
|
||||
// Setup Stage transfer type, and Data Stage direction.
|
||||
#define TRT_NONE 0
|
||||
#define TRT_OUT 2
|
||||
#define TRT_IN 3
|
||||
#define DIR_IN (1 << 16)
|
||||
|
||||
// Endpoint types in an endpoint context. Direction is part of the type, and
|
||||
// the numbering is not arbitrary: OUT types are 1-3, control is 4, and the IN
|
||||
// types are the OUT ones plus four.
|
||||
#define EPTYPE_ISOCH_OUT 1
|
||||
#define EPTYPE_BULK_OUT 2
|
||||
#define EPTYPE_INT_OUT 3
|
||||
#define EPTYPE_CONTROL 4
|
||||
#define EPTYPE_ISOCH_IN 5
|
||||
#define EPTYPE_BULK_IN 6
|
||||
#define EPTYPE_INT_IN 7
|
||||
|
||||
// Doorbell targets: 0 is the command ring; for a device slot, DCI 1 is EP0.
|
||||
#define DCI_EP0 1
|
||||
Loading…
Reference in a new issue