/*- * Copyright (c) 2003 Peter Grehan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include #include #include "fb_if.h" struct efifb_softc { device_t dev; device_t sc_fbd; struct fb_info sc_info; }; static int efifb_probe(device_t); static int efifb_attach(device_t); /* * Define the iso6429-1983 colormap */ #if 0 static struct { uint8_t red; uint8_t green; uint8_t blue; } efifb_cmap[16] = { /* # R G B Color */ /* - - - - ----- */ { 0x00, 0x00, 0x00 }, /* 0 0 0 0 Black */ { 0x00, 0x00, 0xaa }, /* 1 0 0 2/3 Blue */ { 0x00, 0xaa, 0x00 }, /* 2 0 2/3 0 Green */ { 0x00, 0xaa, 0xaa }, /* 3 0 2/3 2/3 Cyan */ { 0xaa, 0x00, 0x00 }, /* 4 2/3 0 0 Red */ { 0xaa, 0x00, 0xaa }, /* 5 2/3 0 2/3 Magenta */ { 0xaa, 0x55, 0x00 }, /* 6 2/3 1/3 0 Brown */ { 0xaa, 0xaa, 0xaa }, /* 7 2/3 2/3 2/3 White */ { 0x55, 0x55, 0x55 }, /* 8 1/3 1/3 1/3 Gray */ { 0x55, 0x55, 0xff }, /* 9 1/3 1/3 1 Bright Blue */ { 0x55, 0xff, 0x55 }, /* 10 1/3 1 1/3 Bright Green */ { 0x55, 0xff, 0xff }, /* 11 1/3 1 1 Bright Cyan */ { 0xff, 0x55, 0x55 }, /* 12 1 1/3 1/3 Bright Red */ { 0xff, 0x55, 0xff }, /* 13 1 1/3 1 Bright Magenta */ { 0xff, 0xff, 0x80 }, /* 14 1 1 1/3 Bright Yellow */ { 0xff, 0xff, 0xff } /* 15 1 1 1 Bright White */ }; #endif #define TODO printf("%s: unimplemented\n", __func__) int efifb_probed; static int efifb_probe(device_t dev) { //int error; efifb_probed++; device_set_desc(dev, "EFI framebuffer console"); #if 0 error = sc_probe_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD); if (error != 0) return (error); #endif /* This is a fake device, so make sure we added it ourselves */ return (BUS_PROBE_DEFAULT); } struct efifb_softc *global_sc; static int efifb_attach(device_t dev) { struct efifb_softc *sc = device_get_softc(dev); global_sc = sc; caddr_t kmdp; struct efi_header * efihdr; struct efi_fb * efifb; int disable; int depth, d; static int done = 0; disable = 0; TUNABLE_INT_FETCH("hw.syscons.disable", &disable); if (disable != 0) return (0); if (done != 0) return (0); done = 1; kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf64 kernel"); efihdr = (struct efi_header *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_EFI); if (!efihdr->fb.fb_present) return (0); efifb = &efihdr->fb; printf("%s>>> fb_present=%d\n", __func__, efifb->fb_present); printf("%s>>> fb_addr=0x%016jx\n", __func__, efifb->fb_addr); printf("%s>>> fb_size=%jx\n", __func__, efifb->fb_size); printf("%s>>> fb_height=%d\n", __func__, efifb->fb_height); printf("%s>>> fb_width=%d\n", __func__, efifb->fb_width); printf("%s>>> fb_stride=%d\n", __func__, efifb->fb_stride); printf("%s>>> fb_mask_red=%08x\n", __func__, efifb->fb_mask_red); printf("%s>>> fb_mask_green=%08x\n", __func__, efifb->fb_mask_green); printf("%s>>> fb_mask_blue=%08x\n", __func__, efifb->fb_mask_blue); printf("%s>>> fb_mask_reserved=%08x\n", __func__, efifb->fb_mask_reserved); sc->sc_info.fb_height = efifb->fb_height; sc->sc_info.fb_width = efifb->fb_width; #if 0 sc = &efifb_softc; sc->sc_console = 1; sc->sc_height = efifb->fb_height; sc->sc_width = efifb->fb_width; #endif depth = fls(efifb->fb_mask_red); d = fls(efifb->fb_mask_green); depth = d > depth ? d : depth; d = fls(efifb->fb_mask_blue); depth = d > depth ? d : depth; d = fls(efifb->fb_mask_reserved); depth = d > depth ? d : depth; sc->sc_info.fb_depth = depth; sc->sc_info.fb_cmsize = 16; sc->sc_info.fb_size = efifb->fb_size; //intptr_t fb_pbase; /* For FB mmap. */ /* * We could use pmap_mapdev here except that the kernel pmap * hasn't been created yet and hence any attempt to lock it will * fail. */ sc->sc_info.fb_vbase = PHYS_TO_DMAP(efifb->fb_addr); //void *fb_priv; /* First argument for read/write. */ sc->sc_info.fb_name = strdup("efifb", M_TEMP); //uint32_t fb_flags; sc->sc_info.fb_stride = efifb->fb_stride; sc->sc_info.fb_bpp = 32; #if 0 #define FB_FLAG_NOMMAP 1 /* mmap unsupported. */ uint32_t fb_cmap[16]; }; #endif #if 0 sc->sc_depth = depth; sc->sc_stride = efifb->fb_stride * (depth / 8); printf("%s>>> sc_stride=%d\n", __func__, sc->sc_stride); sc->sc_red_bits = fls(efifb->fb_mask_red) - ffs(efifb->fb_mask_red) + 1; sc->sc_red_shift = ffs(efifb->fb_mask_red) - 1; sc->sc_green_bits = fls(efifb->fb_mask_green) - ffs(efifb->fb_mask_green) + 1; sc->sc_green_shift = ffs(efifb->fb_mask_green) - 1; sc->sc_blue_bits = fls(efifb->fb_mask_blue) - ffs(efifb->fb_mask_blue) + 1; sc->sc_blue_shift = ffs(efifb->fb_mask_blue) - 1; switch (depth) { case 32: sc->sc_putc = efifb_putc32; sc->sc_putm = efifb_putm32; sc->sc_set_border = efifb_set_border32; break; case 8: sc->sc_putc = efifb_putc8; sc->sc_putm = efifb_putm8; sc->sc_set_border = efifb_set_border8; break; default: return (0); break; } #endif register_framebuffer(&sc->sc_info); return (0); #if 0 return (sc_attach_unit(device_get_unit(dev), device_get_flags(dev) | SC_AUTODETECT_KBD)); #endif } static struct fb_info * efifb_getinfo(device_t dev) { struct efifb_softc *sc = device_get_softc(dev); return (&sc->sc_info); } static device_method_t efifb_vt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, efifb_probe), DEVMETHOD(device_attach, efifb_attach), /* Framebuffer service methos */ DEVMETHOD(fb_getinfo, efifb_getinfo), { 0, 0 } }; static devclass_t efifb_devclass; static driver_t efifb_vt_driver = { "efifb", efifb_vt_methods, sizeof(sc_softc_t), }; DRIVER_MODULE(efifb, nexus, efifb_vt_driver, efifb_devclass, 0, 0);