109 lines
3.2 KiB
C
109 lines
3.2 KiB
C
#include <socks/printk.h>
|
|
#include <socks/pci.h>
|
|
#include <socks/device.h>
|
|
#include <socks/kext.h>
|
|
#include <socks/machine/init.h>
|
|
#include <socks/libc/stdio.h>
|
|
|
|
#define VBE_DISPI_INDEX_ID 0x00u
|
|
#define VBE_DISPI_INDEX_XRES 0x01u
|
|
#define VBE_DISPI_INDEX_YRES 0x02u
|
|
#define VBE_DISPI_INDEX_BPP 0x03u
|
|
#define VBE_DISPI_INDEX_ENABLE 0x04u
|
|
#define VBE_DISPI_INDEX_BANK 0x05u
|
|
#define VBE_DISPI_INDEX_VIRT_WIDTH 0x06u
|
|
#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x07u
|
|
#define VBE_DISPI_INDEX_X_OFFSET 0x08u
|
|
#define VBE_DISPI_INDEX_Y_OFFSET 0x09u
|
|
|
|
#define VBE_DISPI_LFB_ENABLED 0x40
|
|
|
|
static struct pci_driver *qemufb_driver = NULL;
|
|
|
|
static struct pci_device_id qemufb_device_ids[] = {
|
|
PCI_DEVICE_ID(0x1234, 0x1111),
|
|
PCI_DEVICE_ID_INVALID,
|
|
};
|
|
|
|
static inline uint16_t dispi_mmio_offset(int index)
|
|
{
|
|
return (0x500 + (index << 1)) >> 1;
|
|
}
|
|
|
|
static kern_status_t qemufb_set_varinfo(struct device *dev, const struct framebuffer_varinfo *varinfo)
|
|
{
|
|
uint32_t mmio_base = pci_device_read_field(dev, PCI_REG_BAR2, 4);
|
|
uint16_t *mmio = vm_phys_to_virt(mmio_base);
|
|
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_ENABLE)] = 0;
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)] = varinfo->fb_xres;
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)] = varinfo->fb_yres;
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)] = varinfo->fb_bpp;
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_ENABLE)] = 1 | VBE_DISPI_LFB_ENABLED;
|
|
|
|
if (mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)] != varinfo->fb_xres ||
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)] != varinfo->fb_yres ||
|
|
mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)] != varinfo->fb_bpp) {
|
|
return KERN_UNSUPPORTED;
|
|
}
|
|
|
|
return KERN_OK;
|
|
}
|
|
|
|
static struct framebuffer_device_ops qemufb_ops = {
|
|
.set_varinfo = qemufb_set_varinfo,
|
|
};
|
|
|
|
static kern_status_t qemufb_probe(struct pci_driver *driver, struct device *dev)
|
|
{
|
|
struct framebuffer_device *fb = framebuffer_device_from_generic(dev);
|
|
(void)fb;
|
|
snprintf(dev->dev_name, sizeof dev->dev_name, "qemufb");
|
|
|
|
fb->fb_ops = &qemufb_ops;
|
|
|
|
uint32_t mmio_base = pci_device_read_field(dev, PCI_REG_BAR2, 4);
|
|
uint16_t *mmio = vm_phys_to_virt(mmio_base);
|
|
|
|
struct framebuffer_varinfo *varinfo = &fb->fb_varinfo;
|
|
struct framebuffer_fixedinfo *fixedinfo = &fb->fb_fixedinfo;
|
|
|
|
varinfo->fb_flags = FB_MODE_RGB;
|
|
varinfo->fb_xres = mmio[dispi_mmio_offset(VBE_DISPI_INDEX_XRES)];
|
|
varinfo->fb_yres = mmio[dispi_mmio_offset(VBE_DISPI_INDEX_YRES)];
|
|
varinfo->fb_bpp = mmio[dispi_mmio_offset(VBE_DISPI_INDEX_BPP)];
|
|
fixedinfo->fb_baseptr = pci_device_read_field(dev, PCI_REG_BAR0, 4);
|
|
|
|
if (!varinfo->fb_xres) {
|
|
/* no mode data. assume that we're in VGA text mode */
|
|
varinfo->fb_xres = 640;
|
|
varinfo->fb_yres = 400;
|
|
varinfo->fb_bpp = 16;
|
|
varinfo->fb_flags = FB_MODE_VGATEXT;
|
|
varinfo->fb_xcells = 80;
|
|
varinfo->fb_ycells = 25;
|
|
varinfo->fb_stride = 80 * 25 * 2;
|
|
fixedinfo->fb_baseptr = 0xb8000;
|
|
}
|
|
|
|
return device_register(dev, pci_driver_base(qemufb_driver), NULL);
|
|
}
|
|
|
|
static kern_status_t online(struct kext *self)
|
|
{
|
|
printk("qemufb: registering PCI driver");
|
|
qemufb_driver = pci_driver_create(self, "qemufb", qemufb_device_ids);
|
|
if (!qemufb_driver) {
|
|
return KERN_NO_MEMORY;
|
|
}
|
|
|
|
qemufb_driver->probe = qemufb_probe;
|
|
|
|
pci_driver_register(qemufb_driver);
|
|
return KERN_OK;
|
|
}
|
|
|
|
DEFINE_KEXT("net.doorstuck.socks.qemufb",
|
|
online, NULL,
|
|
PCI_SUBSYSTEM_KEXT_ID);
|