diff --git a/sys/dev/virtio/gpu/virtio_gpu.c b/sys/dev/virtio/gpu/virtio_gpu.c index f18eef985cc6..eac5b5db21b9 100644 --- a/sys/dev/virtio/gpu/virtio_gpu.c +++ b/sys/dev/virtio/gpu/virtio_gpu.c @@ -1,697 +1,709 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013, Bryan Venteicher * All rights reserved. * Copyright (c) 2023, Arm Ltd * * 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 unmodified, 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 ``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 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. */ /* Driver for VirtIO GPU device. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fb_if.h" #define VTGPU_FEATURES 0 /* The guest can allocate resource IDs, we only need one */ #define VTGPU_RESOURCE_ID 1 struct vtgpu_softc { /* Must be first so we can cast from info -> softc */ struct fb_info vtgpu_fb_info; struct virtio_gpu_config vtgpu_gpucfg; device_t vtgpu_dev; uint64_t vtgpu_features; struct virtqueue *vtgpu_ctrl_vq; uint64_t vtgpu_next_fence; bool vtgpu_have_fb_info; }; static int vtgpu_modevent(module_t, int, void *); static int vtgpu_probe(device_t); static int vtgpu_attach(device_t); static int vtgpu_detach(device_t); static int vtgpu_negotiate_features(struct vtgpu_softc *); static int vtgpu_setup_features(struct vtgpu_softc *); static void vtgpu_read_config(struct vtgpu_softc *, struct virtio_gpu_config *); static int vtgpu_alloc_virtqueue(struct vtgpu_softc *); static int vtgpu_get_display_info(struct vtgpu_softc *); static int vtgpu_create_2d(struct vtgpu_softc *); static int vtgpu_attach_backing(struct vtgpu_softc *); static int vtgpu_set_scanout(struct vtgpu_softc *, uint32_t, uint32_t, uint32_t, uint32_t); static int vtgpu_transfer_to_host_2d(struct vtgpu_softc *, uint32_t, uint32_t, uint32_t, uint32_t); static int vtgpu_resource_flush(struct vtgpu_softc *, uint32_t, uint32_t, uint32_t, uint32_t); static vd_blank_t vtgpu_fb_blank; static vd_bitblt_text_t vtgpu_fb_bitblt_text; static vd_bitblt_bmp_t vtgpu_fb_bitblt_bitmap; static vd_drawrect_t vtgpu_fb_drawrect; static vd_setpixel_t vtgpu_fb_setpixel; +static vd_bitblt_argb_t vtgpu_fb_bitblt_argb; static struct vt_driver vtgpu_fb_driver = { .vd_name = "virtio_gpu", .vd_init = vt_fb_init, .vd_fini = vt_fb_fini, .vd_blank = vtgpu_fb_blank, .vd_bitblt_text = vtgpu_fb_bitblt_text, .vd_invalidate_text = vt_fb_invalidate_text, .vd_bitblt_bmp = vtgpu_fb_bitblt_bitmap, + .vd_bitblt_argb = vtgpu_fb_bitblt_argb, .vd_drawrect = vtgpu_fb_drawrect, .vd_setpixel = vtgpu_fb_setpixel, .vd_postswitch = vt_fb_postswitch, .vd_priority = VD_PRIORITY_GENERIC+10, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = NULL, /* No mmap as we need to signal the host */ .vd_suspend = vt_fb_suspend, .vd_resume = vt_fb_resume, }; VT_DRIVER_DECLARE(vt_vtgpu, vtgpu_fb_driver); static void vtgpu_fb_blank(struct vt_device *vd, term_color_t color) { struct vtgpu_softc *sc; struct fb_info *info; info = vd->vd_softc; sc = (struct vtgpu_softc *)info; vt_fb_blank(vd, color); vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width, sc->vtgpu_fb_info.fb_height); vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width, sc->vtgpu_fb_info.fb_height); } static void vtgpu_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { struct vtgpu_softc *sc; struct fb_info *info; int x, y, width, height; info = vd->vd_softc; sc = (struct vtgpu_softc *)info; vt_fb_bitblt_text(vd, vw, area); x = area->tr_begin.tp_col * vw->vw_font->vf_width + vw->vw_draw_area.tr_begin.tp_col; y = area->tr_begin.tp_row * vw->vw_font->vf_height + vw->vw_draw_area.tr_begin.tp_row; width = area->tr_end.tp_col * vw->vw_font->vf_width + vw->vw_draw_area.tr_begin.tp_col - x; height = area->tr_end.tp_row * vw->vw_font->vf_height + vw->vw_draw_area.tr_begin.tp_row - y; vtgpu_transfer_to_host_2d(sc, x, y, width, height); vtgpu_resource_flush(sc, x, y, width, height); } static void vtgpu_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, const uint8_t *pattern, const uint8_t *mask, unsigned int width, unsigned int height, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) { struct vtgpu_softc *sc; struct fb_info *info; info = vd->vd_softc; sc = (struct vtgpu_softc *)info; vt_fb_bitblt_bitmap(vd, vw, pattern, mask, width, height, x, y, fg, bg); vtgpu_transfer_to_host_2d(sc, x, y, width, height); vtgpu_resource_flush(sc, x, y, width, height); } +static int +vtgpu_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *argb, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y) +{ + + return (EOPNOTSUPP); +} + static void vtgpu_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, term_color_t color) { struct vtgpu_softc *sc; struct fb_info *info; int width, height; info = vd->vd_softc; sc = (struct vtgpu_softc *)info; vt_fb_drawrect(vd, x1, y1, x2, y2, fill, color); width = x2 - x1 + 1; height = y2 - y1 + 1; vtgpu_transfer_to_host_2d(sc, x1, y1, width, height); vtgpu_resource_flush(sc, x1, y1, width, height); } static void vtgpu_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) { struct vtgpu_softc *sc; struct fb_info *info; info = vd->vd_softc; sc = (struct vtgpu_softc *)info; vt_fb_setpixel(vd, x, y, color); vtgpu_transfer_to_host_2d(sc, x, y, 1, 1); vtgpu_resource_flush(sc, x, y, 1, 1); } static struct virtio_feature_desc vtgpu_feature_desc[] = { { VIRTIO_GPU_F_VIRGL, "VirGL" }, { VIRTIO_GPU_F_EDID, "EDID" }, { VIRTIO_GPU_F_RESOURCE_UUID, "ResUUID" }, { VIRTIO_GPU_F_RESOURCE_BLOB, "ResBlob" }, { VIRTIO_GPU_F_CONTEXT_INIT, "ContextInit" }, { 0, NULL } }; static device_method_t vtgpu_methods[] = { /* Device methods. */ DEVMETHOD(device_probe, vtgpu_probe), DEVMETHOD(device_attach, vtgpu_attach), DEVMETHOD(device_detach, vtgpu_detach), DEVMETHOD_END }; static driver_t vtgpu_driver = { "vtgpu", vtgpu_methods, sizeof(struct vtgpu_softc) }; VIRTIO_DRIVER_MODULE(virtio_gpu, vtgpu_driver, vtgpu_modevent, NULL); MODULE_VERSION(virtio_gpu, 1); MODULE_DEPEND(virtio_gpu, virtio, 1, 1, 1); VIRTIO_SIMPLE_PNPINFO(virtio_gpu, VIRTIO_ID_GPU, "VirtIO GPU"); static int vtgpu_modevent(module_t mod, int type, void *unused) { int error; switch (type) { case MOD_LOAD: case MOD_QUIESCE: case MOD_UNLOAD: case MOD_SHUTDOWN: error = 0; break; default: error = EOPNOTSUPP; break; } return (error); } static int vtgpu_probe(device_t dev) { return (VIRTIO_SIMPLE_PROBE(dev, virtio_gpu)); } static int vtgpu_attach(device_t dev) { struct vtgpu_softc *sc; int error; sc = device_get_softc(dev); sc->vtgpu_have_fb_info = false; sc->vtgpu_dev = dev; sc->vtgpu_next_fence = 1; virtio_set_feature_desc(dev, vtgpu_feature_desc); error = vtgpu_setup_features(sc); if (error != 0) { device_printf(dev, "cannot setup features\n"); goto fail; } vtgpu_read_config(sc, &sc->vtgpu_gpucfg); error = vtgpu_alloc_virtqueue(sc); if (error != 0) { device_printf(dev, "cannot allocate virtqueue\n"); goto fail; } virtio_setup_intr(dev, INTR_TYPE_TTY); /* Read the device info to get the display size */ error = vtgpu_get_display_info(sc); if (error != 0) { goto fail; } /* * TODO: This doesn't need to be contigmalloc as we * can use scatter-gather lists. */ sc->vtgpu_fb_info.fb_vbase = (vm_offset_t)contigmalloc( sc->vtgpu_fb_info.fb_size, M_DEVBUF, M_WAITOK|M_ZERO, 0, ~0, 4, 0); sc->vtgpu_fb_info.fb_pbase = pmap_kextract(sc->vtgpu_fb_info.fb_vbase); /* Create the 2d resource */ error = vtgpu_create_2d(sc); if (error != 0) { goto fail; } /* Attach the backing memory */ error = vtgpu_attach_backing(sc); if (error != 0) { goto fail; } /* Set the scanout to link the framebuffer to the display scanout */ error = vtgpu_set_scanout(sc, 0, 0, sc->vtgpu_fb_info.fb_width, sc->vtgpu_fb_info.fb_height); if (error != 0) { goto fail; } vt_allocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info); sc->vtgpu_have_fb_info = true; error = vtgpu_transfer_to_host_2d(sc, 0, 0, sc->vtgpu_fb_info.fb_width, sc->vtgpu_fb_info.fb_height); if (error != 0) goto fail; error = vtgpu_resource_flush(sc, 0, 0, sc->vtgpu_fb_info.fb_width, sc->vtgpu_fb_info.fb_height); fail: if (error != 0) vtgpu_detach(dev); return (error); } static int vtgpu_detach(device_t dev) { struct vtgpu_softc *sc; sc = device_get_softc(dev); if (sc->vtgpu_have_fb_info) vt_deallocate(&vtgpu_fb_driver, &sc->vtgpu_fb_info); if (sc->vtgpu_fb_info.fb_vbase != 0) { MPASS(sc->vtgpu_fb_info.fb_size != 0); contigfree((void *)sc->vtgpu_fb_info.fb_vbase, sc->vtgpu_fb_info.fb_size, M_DEVBUF); } /* TODO: Tell the host we are detaching */ return (0); } static int vtgpu_negotiate_features(struct vtgpu_softc *sc) { device_t dev; uint64_t features; dev = sc->vtgpu_dev; features = VTGPU_FEATURES; sc->vtgpu_features = virtio_negotiate_features(dev, features); return (virtio_finalize_features(dev)); } static int vtgpu_setup_features(struct vtgpu_softc *sc) { int error; error = vtgpu_negotiate_features(sc); if (error != 0) return (error); return (0); } static void vtgpu_read_config(struct vtgpu_softc *sc, struct virtio_gpu_config *gpucfg) { device_t dev; dev = sc->vtgpu_dev; bzero(gpucfg, sizeof(struct virtio_gpu_config)); #define VTGPU_GET_CONFIG(_dev, _field, _cfg) \ virtio_read_device_config(_dev, \ offsetof(struct virtio_gpu_config, _field), \ &(_cfg)->_field, sizeof((_cfg)->_field)) \ VTGPU_GET_CONFIG(dev, events_read, gpucfg); VTGPU_GET_CONFIG(dev, events_clear, gpucfg); VTGPU_GET_CONFIG(dev, num_scanouts, gpucfg); VTGPU_GET_CONFIG(dev, num_capsets, gpucfg); #undef VTGPU_GET_CONFIG } static int vtgpu_alloc_virtqueue(struct vtgpu_softc *sc) { device_t dev; struct vq_alloc_info vq_info[2]; int nvqs; dev = sc->vtgpu_dev; nvqs = 1; VQ_ALLOC_INFO_INIT(&vq_info[0], 0, NULL, sc, &sc->vtgpu_ctrl_vq, "%s control", device_get_nameunit(dev)); return (virtio_alloc_virtqueues(dev, nvqs, vq_info)); } static int vtgpu_req_resp(struct vtgpu_softc *sc, void *req, size_t reqlen, void *resp, size_t resplen) { struct sglist sg; struct sglist_seg segs[2]; int error; sglist_init(&sg, 2, segs); error = sglist_append(&sg, req, reqlen); if (error != 0) { device_printf(sc->vtgpu_dev, "Unable to append the request to the sglist: %d\n", error); return (error); } error = sglist_append(&sg, resp, resplen); if (error != 0) { device_printf(sc->vtgpu_dev, "Unable to append the response buffer to the sglist: %d\n", error); return (error); } error = virtqueue_enqueue(sc->vtgpu_ctrl_vq, resp, &sg, 1, 1); if (error != 0) { device_printf(sc->vtgpu_dev, "Enqueue failed: %d\n", error); return (error); } virtqueue_notify(sc->vtgpu_ctrl_vq); virtqueue_poll(sc->vtgpu_ctrl_vq, NULL); return (0); } static int vtgpu_get_display_info(struct vtgpu_softc *sc) { struct { struct virtio_gpu_ctrl_hdr req; char pad; struct virtio_gpu_resp_display_info resp; } s = { 0 }; int error; s.req.type = htole32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO); s.req.flags = htole32(VIRTIO_GPU_FLAG_FENCE); s.req.fence_id = htole64(atomic_fetchadd_64(&sc->vtgpu_next_fence, 1)); error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp, sizeof(s.resp)); if (error != 0) return (error); for (int i = 0; i < sc->vtgpu_gpucfg.num_scanouts; i++) { if (s.resp.pmodes[i].enabled != 0) MPASS(i == 0); sc->vtgpu_fb_info.fb_name = device_get_nameunit(sc->vtgpu_dev); sc->vtgpu_fb_info.fb_width = le32toh(s.resp.pmodes[i].r.width); sc->vtgpu_fb_info.fb_height = le32toh(s.resp.pmodes[i].r.height); /* 32 bits per pixel */ sc->vtgpu_fb_info.fb_bpp = 32; sc->vtgpu_fb_info.fb_depth = 32; sc->vtgpu_fb_info.fb_size = sc->vtgpu_fb_info.fb_width * sc->vtgpu_fb_info.fb_height * 4; sc->vtgpu_fb_info.fb_stride = sc->vtgpu_fb_info.fb_width * 4; return (0); } return (ENXIO); } static int vtgpu_create_2d(struct vtgpu_softc *sc) { struct { struct virtio_gpu_resource_create_2d req; char pad; struct virtio_gpu_ctrl_hdr resp; } s = { 0 }; int error; s.req.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D); s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE); s.req.hdr.fence_id = htole64( atomic_fetchadd_64(&sc->vtgpu_next_fence, 1)); s.req.resource_id = htole32(VTGPU_RESOURCE_ID); s.req.format = htole32(VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM); s.req.width = htole32(sc->vtgpu_fb_info.fb_width); s.req.height = htole32(sc->vtgpu_fb_info.fb_height); error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp, sizeof(s.resp)); if (error != 0) return (error); if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) { device_printf(sc->vtgpu_dev, "Invalid reponse type %x\n", le32toh(s.resp.type)); return (EINVAL); } return (0); } static int vtgpu_attach_backing(struct vtgpu_softc *sc) { struct { struct { struct virtio_gpu_resource_attach_backing backing; struct virtio_gpu_mem_entry mem[1]; } req; char pad; struct virtio_gpu_ctrl_hdr resp; } s = { 0 }; int error; s.req.backing.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING); s.req.backing.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE); s.req.backing.hdr.fence_id = htole64( atomic_fetchadd_64(&sc->vtgpu_next_fence, 1)); s.req.backing.resource_id = htole32(VTGPU_RESOURCE_ID); s.req.backing.nr_entries = htole32(1); s.req.mem[0].addr = htole64(sc->vtgpu_fb_info.fb_pbase); s.req.mem[0].length = htole32(sc->vtgpu_fb_info.fb_size); error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp, sizeof(s.resp)); if (error != 0) return (error); if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) { device_printf(sc->vtgpu_dev, "Invalid reponse type %x\n", le32toh(s.resp.type)); return (EINVAL); } return (0); } static int vtgpu_set_scanout(struct vtgpu_softc *sc, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { struct { struct virtio_gpu_set_scanout req; char pad; struct virtio_gpu_ctrl_hdr resp; } s = { 0 }; int error; s.req.hdr.type = htole32(VIRTIO_GPU_CMD_SET_SCANOUT); s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE); s.req.hdr.fence_id = htole64( atomic_fetchadd_64(&sc->vtgpu_next_fence, 1)); s.req.r.x = htole32(x); s.req.r.y = htole32(y); s.req.r.width = htole32(width); s.req.r.height = htole32(height); s.req.scanout_id = 0; s.req.resource_id = htole32(VTGPU_RESOURCE_ID); error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp, sizeof(s.resp)); if (error != 0) return (error); if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) { device_printf(sc->vtgpu_dev, "Invalid reponse type %x\n", le32toh(s.resp.type)); return (EINVAL); } return (0); } static int vtgpu_transfer_to_host_2d(struct vtgpu_softc *sc, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { struct { struct virtio_gpu_transfer_to_host_2d req; char pad; struct virtio_gpu_ctrl_hdr resp; } s = { 0 }; int error; s.req.hdr.type = htole32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D); s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE); s.req.hdr.fence_id = htole64( atomic_fetchadd_64(&sc->vtgpu_next_fence, 1)); s.req.r.x = htole32(x); s.req.r.y = htole32(y); s.req.r.width = htole32(width); s.req.r.height = htole32(height); s.req.offset = htole64((y * sc->vtgpu_fb_info.fb_width + x) * (sc->vtgpu_fb_info.fb_bpp / 8)); s.req.resource_id = htole32(VTGPU_RESOURCE_ID); error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp, sizeof(s.resp)); if (error != 0) return (error); if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) { device_printf(sc->vtgpu_dev, "Invalid reponse type %x\n", le32toh(s.resp.type)); return (EINVAL); } return (0); } static int vtgpu_resource_flush(struct vtgpu_softc *sc, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { struct { struct virtio_gpu_resource_flush req; char pad; struct virtio_gpu_ctrl_hdr resp; } s = { 0 }; int error; s.req.hdr.type = htole32(VIRTIO_GPU_CMD_RESOURCE_FLUSH); s.req.hdr.flags = htole32(VIRTIO_GPU_FLAG_FENCE); s.req.hdr.fence_id = htole64( atomic_fetchadd_64(&sc->vtgpu_next_fence, 1)); s.req.r.x = htole32(x); s.req.r.y = htole32(y); s.req.r.width = htole32(width); s.req.r.height = htole32(height); s.req.resource_id = htole32(VTGPU_RESOURCE_ID); error = vtgpu_req_resp(sc, &s.req, sizeof(s.req), &s.resp, sizeof(s.resp)); if (error != 0) return (error); if (s.resp.type != htole32(VIRTIO_GPU_RESP_OK_NODATA)) { device_printf(sc->vtgpu_dev, "Invalid reponse type %x\n", le32toh(s.resp.type)); return (EINVAL); } return (0); } diff --git a/sys/dev/vt/hw/efifb/efifb.c b/sys/dev/vt/hw/efifb/efifb.c index 805b36d499ae..cac6f93b7af1 100644 --- a/sys/dev/vt/hw/efifb/efifb.c +++ b/sys/dev/vt/hw/efifb/efifb.c @@ -1,180 +1,181 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2014 The FreeBSD Foundation * * This software was developed by Aleksandr Rybalko under sponsorship from the * FreeBSD Foundation. * * 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 #include #include #include #include #include "opt_platform.h" #include #include #include #include #include #include #include static vd_init_t vt_efifb_init; static vd_fini_t vt_efifb_fini; static vd_probe_t vt_efifb_probe; static struct vt_driver vt_efifb_driver = { .vd_name = "efifb", .vd_probe = vt_efifb_probe, .vd_init = vt_efifb_init, .vd_fini = vt_efifb_fini, .vd_blank = vt_fb_blank, .vd_bitblt_text = vt_fb_bitblt_text, .vd_invalidate_text = vt_fb_invalidate_text, .vd_bitblt_bmp = vt_fb_bitblt_bitmap, + .vd_bitblt_argb = vt_fb_bitblt_argb, .vd_drawrect = vt_fb_drawrect, .vd_setpixel = vt_fb_setpixel, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = vt_fb_mmap, .vd_suspend = vt_suspend, .vd_resume = vt_resume, /* Better than VGA, but still generic driver. */ .vd_priority = VD_PRIORITY_GENERIC + 1, }; static struct fb_info local_info; VT_DRIVER_DECLARE(vt_efifb, vt_efifb_driver); static int vt_efifb_probe(struct vt_device *vd) { int disabled; struct efi_fb *efifb; caddr_t kmdp; disabled = 0; TUNABLE_INT_FETCH("hw.syscons.disable", &disabled); if (disabled != 0) return (CN_DEAD); kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf64 kernel"); efifb = (struct efi_fb *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_EFI_FB); if (efifb == NULL) return (CN_DEAD); return (CN_INTERNAL); } static int vt_efifb_init(struct vt_device *vd) { struct fb_info *info; struct efi_fb *efifb; caddr_t kmdp; int memattr; int roff, goff, boff; char attr[16]; /* * XXX TODO: I think there's more nuance here than we're acknowledging, * and we should look into it. It may be that the framebuffer lives in * a segment of memory that doesn't support one or both of these. We * should likely be consulting the memory map for any applicable * cacheability attributes before making a final decision. */ memattr = VM_MEMATTR_WRITE_COMBINING; if (TUNABLE_STR_FETCH("hw.efifb.cache_attr", attr, sizeof(attr))) { /* * We'll allow WC but it's currently the default, UC is the only * other tested one at this time. */ if (strcasecmp(attr, "wc") != 0 && strcasecmp(attr, "uc") != 0) { printf("efifb: unsupported cache attr specified: %s\n", attr); printf("efifb: expected \"wc\" or \"uc\"\n"); } else if (strcasecmp(attr, "uc") == 0) { memattr = VM_MEMATTR_UNCACHEABLE; } } info = vd->vd_softc; if (info == NULL) info = vd->vd_softc = (void *)&local_info; kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf64 kernel"); efifb = (struct efi_fb *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_EFI_FB); if (efifb == NULL) return (CN_DEAD); info->fb_type = FBTYPE_EFIFB; info->fb_height = efifb->fb_height; info->fb_width = efifb->fb_width; info->fb_depth = fls(efifb->fb_mask_red | efifb->fb_mask_green | efifb->fb_mask_blue | efifb->fb_mask_reserved); /* Round to a multiple of the bits in a byte. */ info->fb_bpp = roundup2(info->fb_depth, NBBY); /* Stride in bytes, not pixels */ info->fb_stride = efifb->fb_stride * (info->fb_bpp / NBBY); roff = ffs(efifb->fb_mask_red) - 1; goff = ffs(efifb->fb_mask_green) - 1; boff = ffs(efifb->fb_mask_blue) - 1; vt_config_cons_colors(info, COLOR_FORMAT_RGB, efifb->fb_mask_red >> roff, roff, efifb->fb_mask_green >> goff, goff, efifb->fb_mask_blue >> boff, boff); info->fb_cmsize = NCOLORS; info->fb_size = info->fb_height * info->fb_stride; info->fb_pbase = efifb->fb_addr; info->fb_vbase = (intptr_t)pmap_mapdev_attr(info->fb_pbase, info->fb_size, memattr); vt_fb_init(vd); return (CN_INTERNAL); } static void vt_efifb_fini(struct vt_device *vd, void *softc) { struct fb_info *info = softc; vt_fb_fini(vd, softc); pmap_unmapdev((void *)info->fb_vbase, info->fb_size); } diff --git a/sys/dev/vt/hw/fb/vt_early_fb.c b/sys/dev/vt/hw/fb/vt_early_fb.c index 52241038ce35..9d66f5cd1398 100644 --- a/sys/dev/vt/hw/fb/vt_early_fb.c +++ b/sys/dev/vt/hw/fb/vt_early_fb.c @@ -1,293 +1,294 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013 The FreeBSD Foundation * * This software was developed by Aleksandr Rybalko under sponsorship from the * FreeBSD Foundation. * * 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 #include #include #include #include "opt_platform.h" #ifdef FDT #include #include #include #include #include #endif #include #include #include static vd_init_t vt_efb_init; static vd_probe_t vt_efb_probe; static struct vt_driver vt_fb_early_driver = { .vd_name = "efb", .vd_probe = vt_efb_probe, .vd_init = vt_efb_init, .vd_blank = vt_fb_blank, .vd_bitblt_text = vt_fb_bitblt_text, .vd_invalidate_text = vt_fb_invalidate_text, .vd_bitblt_bmp = vt_fb_bitblt_bitmap, + .vd_bitblt_argb = vt_fb_bitblt_argb, .vd_drawrect = vt_fb_drawrect, .vd_setpixel = vt_fb_setpixel, .vd_priority = VD_PRIORITY_GENERIC, }; static struct fb_info local_info; VT_DRIVER_DECLARE(vt_efb, vt_fb_early_driver); static void #ifdef FDT vt_efb_initialize(struct fb_info *info, phandle_t node) #else vt_efb_initialize(struct fb_info *info) #endif { #ifdef FDT char name[64]; cell_t retval; ihandle_t ih; int i; /* Open display device, thereby initializing it */ memset(name, 0, sizeof(name)); OF_package_to_path(node, name, sizeof(name)); ih = OF_open(name); #endif /* * Set up the color map */ switch (info->fb_depth) { case 8: vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0x7, 5, 0x7, 2, 0x3, 0); break; case 15: vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0x1f, 10, 0x1f, 5, 0x1f, 0); break; case 16: vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0x1f, 11, 0x3f, 5, 0x1f, 0); break; case 24: case 32: #if BYTE_ORDER == BIG_ENDIAN vt_config_cons_colors(info, COLOR_FORMAT_RGB, 255, 0, 255, 8, 255, 16); #else vt_config_cons_colors(info, COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); #endif #ifdef FDT for (i = 0; i < 16; i++) { OF_call_method("color!", ih, 4, 1, (cell_t)((info->fb_cmap[i] >> 16) & 0xff), (cell_t)((info->fb_cmap[i] >> 8) & 0xff), (cell_t)((info->fb_cmap[i] >> 0) & 0xff), (cell_t)i, &retval); } #endif break; default: panic("Unknown color space fb_depth %d", info->fb_depth); break; } } static phandle_t vt_efb_get_fbnode() { phandle_t chosen, node; ihandle_t stdout; char type[64]; chosen = OF_finddevice("/chosen"); OF_getprop(chosen, "stdout", &stdout, sizeof(stdout)); node = OF_instance_to_package(stdout); if (node != -1) { /* The "/chosen/stdout" present. */ OF_getprop(node, "device_type", type, sizeof(type)); /* Check if it has "display" type. */ if (strcmp(type, "display") == 0) return (node); } /* Try device with name "screen". */ node = OF_finddevice("screen"); return (node); } static int vt_efb_probe(struct vt_device *vd) { phandle_t node; node = vt_efb_get_fbnode(); if (node == -1) return (CN_DEAD); if ((OF_getproplen(node, "height") <= 0) || (OF_getproplen(node, "width") <= 0) || (OF_getproplen(node, "depth") <= 0) || (OF_getproplen(node, "linebytes") <= 0)) return (CN_DEAD); return (CN_INTERNAL); } static int vt_efb_init(struct vt_device *vd) { struct ofw_pci_register pciaddrs[8]; struct fb_info *info; int i, len, n_pciaddrs; phandle_t node; if (vd->vd_softc == NULL) vd->vd_softc = (void *)&local_info; info = vd->vd_softc; node = vt_efb_get_fbnode(); if (node == -1) return (CN_DEAD); #define GET(name, var) \ if (OF_getproplen(node, (name)) != sizeof(info->fb_##var)) \ return (CN_DEAD); \ OF_getencprop(node, (name), &info->fb_##var, sizeof(info->fb_##var)); \ if (info->fb_##var == 0) \ return (CN_DEAD); GET("height", height) GET("width", width) GET("depth", depth) GET("linebytes", stride) #undef GET info->fb_size = info->fb_height * info->fb_stride; /* * Get the PCI addresses of the adapter, if present. The node may be the * child of the PCI device: in that case, try the parent for * the assigned-addresses property. */ len = OF_getprop(node, "assigned-addresses", pciaddrs, sizeof(pciaddrs)); if (len == -1) { len = OF_getprop(OF_parent(node), "assigned-addresses", pciaddrs, sizeof(pciaddrs)); } if (len == -1) len = 0; n_pciaddrs = len / sizeof(struct ofw_pci_register); /* * Grab the physical address of the framebuffer, and then map it * into our memory space. If the MMU is not yet up, it will be * remapped for us when relocation turns on. */ if (OF_getproplen(node, "address") == sizeof(info->fb_pbase)) { /* XXX We assume #address-cells is 1 at this point. */ OF_getencprop(node, "address", &info->fb_pbase, sizeof(info->fb_pbase)); #if defined(__powerpc__) sc->sc_memt = &bs_be_tag; bus_space_map(sc->sc_memt, info->fb_pbase, info->fb_size, BUS_SPACE_MAP_PREFETCHABLE, &info->fb_vbase); #else bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, BUS_SPACE_MAP_PREFETCHABLE, (bus_space_handle_t *)&info->fb_vbase); #endif } else { /* * Some IBM systems don't have an address property. Try to * guess the framebuffer region from the assigned addresses. * This is ugly, but there doesn't seem to be an alternative. * Linux does the same thing. */ info->fb_pbase = n_pciaddrs; for (i = 0; i < n_pciaddrs; i++) { /* If it is too small, not the framebuffer */ if (pciaddrs[i].size_lo < info->fb_size) continue; /* If it is not memory, it isn't either */ if (!(pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_SPACE_MEM32)) continue; /* This could be the framebuffer */ info->fb_pbase = i; /* If it is prefetchable, it certainly is */ if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) break; } if (info->fb_pbase == n_pciaddrs) /* No candidates found */ return (CN_DEAD); #if defined(__powerpc__) OF_decode_addr(node, info->fb_pbase, &sc->sc_memt, &info->fb_vbase); #else bus_space_map(fdtbus_bs_tag, info->fb_pbase, info->fb_size, BUS_SPACE_MAP_PREFETCHABLE, (bus_space_handle_t *)&info->fb_vbase); #endif } /* blank full size */ len = info->fb_size / 4; for (i = 0; i < len; i++) { ((uint32_t *)info->fb_vbase)[i] = 0; } /* Get pixel storage size. */ info->fb_bpp = info->fb_stride / info->fb_width * 8; #ifdef FDT vt_efb_initialize(info, node); #else vt_efb_initialize(info); #endif vt_fb_init(vd); return (CN_INTERNAL); } diff --git a/sys/dev/vt/hw/fb/vt_fb.c b/sys/dev/vt/hw/fb/vt_fb.c index c1eeb5e69e08..5031ab946203 100644 --- a/sys/dev/vt/hw/fb/vt_fb.c +++ b/sys/dev/vt/hw/fb/vt_fb.c @@ -1,546 +1,593 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013 The FreeBSD Foundation * * This software was developed by Aleksandr Rybalko under sponsorship from the * FreeBSD Foundation. * * 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 #include #include #include #include #include #include #include #include #include #include static struct vt_driver vt_fb_driver = { .vd_name = "fb", .vd_init = vt_fb_init, .vd_fini = vt_fb_fini, .vd_blank = vt_fb_blank, .vd_bitblt_text = vt_fb_bitblt_text, .vd_invalidate_text = vt_fb_invalidate_text, .vd_bitblt_bmp = vt_fb_bitblt_bitmap, + .vd_bitblt_argb = vt_fb_bitblt_argb, .vd_drawrect = vt_fb_drawrect, .vd_setpixel = vt_fb_setpixel, .vd_postswitch = vt_fb_postswitch, .vd_priority = VD_PRIORITY_GENERIC+10, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = vt_fb_mmap, .vd_suspend = vt_fb_suspend, .vd_resume = vt_fb_resume, }; VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); static void vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) { KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); *(uint8_t *)(sc->fb_vbase + o) = v; } static void vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) { KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); *(uint16_t *)(sc->fb_vbase + o) = v; } static void vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) { KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); *(uint32_t *)(sc->fb_vbase + o) = v; } int vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) { struct fb_info *info; int error = 0; info = vd->vd_softc; switch (cmd) { case FBIOGTYPE: bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); break; case FBIO_GETWINORG: /* get frame buffer window origin */ *(u_int *)data = 0; break; case FBIO_GETDISPSTART: /* get display start address */ ((video_display_start_t *)data)->x = 0; ((video_display_start_t *)data)->y = 0; break; case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ *(u_int *)data = info->fb_stride; break; case FBIO_BLANK: /* blank display */ if (vd->vd_driver->vd_blank == NULL) return (ENODEV); vd->vd_driver->vd_blank(vd, TC_BLACK); break; case FBIO_GETRGBOFFS: /* get RGB offsets */ if (info->fb_rgboffs.red == 0 && info->fb_rgboffs.green == 0 && info->fb_rgboffs.blue == 0) return (ENOTTY); memcpy((struct fb_rgboffs *)data, &info->fb_rgboffs, sizeof(struct fb_rgboffs)); break; default: error = ENOIOCTL; break; } return (error); } int vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, int prot, vm_memattr_t *memattr) { struct fb_info *info; info = vd->vd_softc; if (info->fb_flags & FB_FLAG_NOMMAP) return (ENODEV); if (offset < info->fb_size) { if (info->fb_pbase == 0) { *paddr = vtophys((uint8_t *)info->fb_vbase + offset); } else { *paddr = info->fb_pbase + offset; if (info->fb_flags & FB_FLAG_MEMATTR) *memattr = info->fb_memattr; #ifdef VM_MEMATTR_WRITE_COMBINING else *memattr = VM_MEMATTR_WRITE_COMBINING; #endif } return (0); } return (EINVAL); } void vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) { struct fb_info *info; uint32_t c; u_int o; info = vd->vd_softc; c = info->fb_cmap[color]; o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); if (info->fb_flags & FB_FLAG_NOWRITE) return; KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); switch (FBTYPE_GET_BYTESPP(info)) { case 1: vt_fb_mem_wr1(info, o, c); break; case 2: vt_fb_mem_wr2(info, o, c); break; case 3: vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); vt_fb_mem_wr1(info, o + 2, c & 0xff); break; case 4: vt_fb_mem_wr4(info, o, c); break; default: /* panic? */ return; } } void vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, term_color_t color) { int x, y; for (y = y1; y <= y2; y++) { if (fill || (y == y1) || (y == y2)) { for (x = x1; x <= x2; x++) vt_fb_setpixel(vd, x, y, color); } else { vt_fb_setpixel(vd, x1, y, color); vt_fb_setpixel(vd, x2, y, color); } } } void vt_fb_blank(struct vt_device *vd, term_color_t color) { struct fb_info *info; uint32_t c; u_int o, h; info = vd->vd_softc; c = info->fb_cmap[color]; if (info->fb_flags & FB_FLAG_NOWRITE) return; KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); switch (FBTYPE_GET_BYTESPP(info)) { case 1: for (h = 0; h < info->fb_height; h++) for (o = 0; o < info->fb_stride; o++) vt_fb_mem_wr1(info, h*info->fb_stride + o, c); break; case 2: for (h = 0; h < info->fb_height; h++) for (o = 0; o < info->fb_stride - 1; o += 2) vt_fb_mem_wr2(info, h*info->fb_stride + o, c); break; case 3: for (h = 0; h < info->fb_height; h++) for (o = 0; o < info->fb_stride - 2; o += 3) { vt_fb_mem_wr1(info, h*info->fb_stride + o, (c >> 16) & 0xff); vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, (c >> 8) & 0xff); vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, c & 0xff); } break; case 4: for (h = 0; h < info->fb_height; h++) for (o = 0; o < info->fb_stride - 3; o += 4) vt_fb_mem_wr4(info, h*info->fb_stride + o, c); break; default: /* panic? */ return; } } void vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, const uint8_t *pattern, const uint8_t *mask, unsigned int width, unsigned int height, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) { struct fb_info *info; uint32_t fgc, bgc, cc, o; int bpp, bpl, xi, yi; int bit, byte; info = vd->vd_softc; bpp = FBTYPE_GET_BYTESPP(info); fgc = info->fb_cmap[fg]; bgc = info->fb_cmap[bg]; bpl = (width + 7) / 8; /* Bytes per source line. */ if (info->fb_flags & FB_FLAG_NOWRITE) return; KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); /* Bound by right and bottom edges. */ if (y + height > vw->vw_draw_area.tr_end.tp_row) { if (y >= vw->vw_draw_area.tr_end.tp_row) return; height = vw->vw_draw_area.tr_end.tp_row - y; } if (x + width > vw->vw_draw_area.tr_end.tp_col) { if (x >= vw->vw_draw_area.tr_end.tp_col) return; width = vw->vw_draw_area.tr_end.tp_col - x; } for (yi = 0; yi < height; yi++) { for (xi = 0; xi < width; xi++) { byte = yi * bpl + xi / 8; bit = 0x80 >> (xi % 8); /* Skip pixel write, if mask bit not set. */ if (mask != NULL && (mask[byte] & bit) == 0) continue; o = (y + yi) * info->fb_stride + (x + xi) * bpp; o += vd->vd_transpose; cc = pattern[byte] & bit ? fgc : bgc; switch(bpp) { case 1: vt_fb_mem_wr1(info, o, cc); break; case 2: vt_fb_mem_wr2(info, o, cc); break; case 3: /* Packed mode, so unaligned. Byte access. */ vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); vt_fb_mem_wr1(info, o + 2, cc & 0xff); break; case 4: vt_fb_mem_wr4(info, o, cc); break; default: /* panic? */ break; } } } } +int +vt_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *argb, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y) +{ + struct fb_info *info; + uint32_t o, cc; + int bpp, xi, yi; + + info = vd->vd_softc; + bpp = FBTYPE_GET_BYTESPP(info); + if (bpp != 4) + return (EOPNOTSUPP); + + if (info->fb_flags & FB_FLAG_NOWRITE) + return (0); + + KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); + + /* Bound by right and bottom edges. */ + if (y + height > vw->vw_draw_area.tr_end.tp_row) { + if (y >= vw->vw_draw_area.tr_end.tp_row) + return (EINVAL); + height = vw->vw_draw_area.tr_end.tp_row - y; + } + if (x + width > vw->vw_draw_area.tr_end.tp_col) { + if (x >= vw->vw_draw_area.tr_end.tp_col) + return (EINVAL); + width = vw->vw_draw_area.tr_end.tp_col - x; + } + for (yi = 0; yi < height; yi++) { + for (xi = 0; xi < (width * 4); xi += 4) { + o = (y + yi) * info->fb_stride + (x + (xi / 4)) * bpp; + o += vd->vd_transpose; + cc = (argb[yi * width * 4 + xi] << 16) | + (argb[yi * width * 4 + xi + 1] << 8) | + (argb[yi * width * 4 + xi + 2]) | + (argb[yi * width * 4 + xi + 3] << 24); + vt_fb_mem_wr4(info, o, cc); + } + } + + return (0); +} + void vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { unsigned int col, row, x, y; struct vt_font *vf; term_char_t c; term_color_t fg, bg; const uint8_t *pattern; size_t z; vf = vw->vw_font; for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; ++col) { x = col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col; y = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row; c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); pattern = vtfont_lookup(vf, c); vt_determine_colors(c, VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)) continue; if (vd->vd_drawn && (vd->vd_drawn[z] == c) && vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) continue; vt_fb_bitblt_bitmap(vd, vw, pattern, NULL, vf->vf_width, vf->vf_height, x, y, fg, bg); if (vd->vd_drawn) vd->vd_drawn[z] = c; if (vd->vd_drawnfg) vd->vd_drawnfg[z] = fg; if (vd->vd_drawnbg) vd->vd_drawnbg[z] = bg; } } #ifndef SC_NO_CUTPASTE if (!vd->vd_mshown) return; term_rect_t drawn_area; drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; if (vt_is_cursor_in_area(vd, &drawn_area)) { vt_fb_bitblt_bitmap(vd, vw, vd->vd_mcursor->map, vd->vd_mcursor->mask, vd->vd_mcursor->width, vd->vd_mcursor->height, vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, vd->vd_mcursor_fg, vd->vd_mcursor_bg); } #endif } void vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area) { unsigned int col, row; size_t z; for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; ++col) { z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)) continue; if (vd->vd_drawn) vd->vd_drawn[z] = 0; if (vd->vd_drawnfg) vd->vd_drawnfg[z] = 0; if (vd->vd_drawnbg) vd->vd_drawnbg[z] = 0; } } } void vt_fb_postswitch(struct vt_device *vd) { struct fb_info *info; info = vd->vd_softc; if (info->enter != NULL) info->enter(info->fb_priv); } static int vt_fb_init_colors(struct fb_info *info) { switch (FBTYPE_GET_BPP(info)) { case 8: return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0x7, 5, 0x7, 2, 0x3, 0)); case 15: return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0x1f, 10, 0x1f, 5, 0x1f, 0)); case 16: return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0x1f, 11, 0x3f, 5, 0x1f, 0)); case 24: case 32: /* Ignore alpha. */ return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 0xff, 16, 0xff, 8, 0xff, 0)); default: return (1); } } int vt_fb_init(struct vt_device *vd) { struct fb_info *info; u_int margin; int bg, err; term_color_t c; info = vd->vd_softc; vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); margin = (info->fb_height - vd->vd_height) >> 1; vd->vd_transpose = margin * info->fb_stride; vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); margin = (info->fb_width - vd->vd_width) >> 1; vd->vd_transpose += margin * (info->fb_bpp / NBBY); vd->vd_video_dev = info->fb_video_dev; if (info->fb_size == 0) return (CN_DEAD); if (info->fb_pbase == 0 && info->fb_vbase == 0) info->fb_flags |= FB_FLAG_NOMMAP; if (info->fb_cmsize <= 0) { err = vt_fb_init_colors(info); if (err) return (CN_DEAD); info->fb_cmsize = 16; } c = TC_BLACK; if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) { if (bg == TC_WHITE) bg |= TC_LIGHT; c = bg; } /* Clear the screen. */ vd->vd_driver->vd_blank(vd, c); /* Wakeup screen. KMS need this. */ vt_fb_postswitch(vd); return (CN_INTERNAL); } void vt_fb_fini(struct vt_device *vd, void *softc) { vd->vd_video_dev = NULL; } int vt_fb_attach(struct fb_info *info) { int ret; ret = vt_allocate(&vt_fb_driver, info); return (ret); } int vt_fb_detach(struct fb_info *info) { int ret; ret = vt_deallocate(&vt_fb_driver, info); return (ret); } void vt_fb_suspend(struct vt_device *vd) { vt_suspend(vd); } void vt_fb_resume(struct vt_device *vd) { vt_resume(vd); } diff --git a/sys/dev/vt/hw/fb/vt_fb.h b/sys/dev/vt/hw/fb/vt_fb.h index 54f7ba667eb1..fc3db42b2a15 100644 --- a/sys/dev/vt/hw/fb/vt_fb.h +++ b/sys/dev/vt/hw/fb/vt_fb.h @@ -1,51 +1,52 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2013 The FreeBSD Foundation * * This software was developed by Aleksandr Rybalko under sponsorship from the * FreeBSD Foundation. * * 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. */ #ifndef _DEV_VT_HW_FB_VT_FB_H_ #define _DEV_VT_HW_FB_VT_FB_H_ /* Generic framebuffer interface call vt_fb_attach to init VT(9) */ int vt_fb_attach(struct fb_info *info); void vt_fb_resume(struct vt_device *vd); void vt_fb_suspend(struct vt_device *vd); int vt_fb_detach(struct fb_info *info); vd_init_t vt_fb_init; vd_fini_t vt_fb_fini; vd_blank_t vt_fb_blank; vd_bitblt_text_t vt_fb_bitblt_text; vd_invalidate_text_t vt_fb_invalidate_text; vd_bitblt_bmp_t vt_fb_bitblt_bitmap; +vd_bitblt_argb_t vt_fb_bitblt_argb; vd_drawrect_t vt_fb_drawrect; vd_setpixel_t vt_fb_setpixel; vd_postswitch_t vt_fb_postswitch; vd_fb_ioctl_t vt_fb_ioctl; vd_fb_mmap_t vt_fb_mmap; #endif /* _DEV_VT_HW_FB_VT_FB_H_ */ diff --git a/sys/dev/vt/hw/ofwfb/ofwfb.c b/sys/dev/vt/hw/ofwfb/ofwfb.c index 6469240ed303..f5653b5f3ff2 100644 --- a/sys/dev/vt/hw/ofwfb/ofwfb.c +++ b/sys/dev/vt/hw/ofwfb/ofwfb.c @@ -1,702 +1,714 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2011 Nathan Whitehorn * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct ofwfb_softc { struct fb_info fb; phandle_t sc_node; ihandle_t sc_handle; bus_space_tag_t sc_memt; int iso_palette; int argb; int endian_flip; uint32_t vendor_id; }; #define PCI_VID_NVIDIA 0x10de /* NVIDIA Corporation */ #define PCI_VID_ASPEED 0x1a03 /* ASPEED Technology, Inc. */ static void ofwfb_initialize(struct vt_device *vd); static vd_probe_t ofwfb_probe; static vd_init_t ofwfb_init; static vd_bitblt_text_t ofwfb_bitblt_text; static vd_bitblt_bmp_t ofwfb_bitblt_bitmap; +static vd_bitblt_argb_t ofwfb_bitblt_argb; static const struct vt_driver vt_ofwfb_driver = { .vd_name = "ofwfb", .vd_probe = ofwfb_probe, .vd_init = ofwfb_init, .vd_blank = vt_fb_blank, .vd_bitblt_text = ofwfb_bitblt_text, .vd_bitblt_bmp = ofwfb_bitblt_bitmap, + .vd_bitblt_argb = ofwfb_bitblt_argb, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = vt_fb_mmap, .vd_priority = VD_PRIORITY_GENERIC+1, }; static unsigned char ofw_colors[16] = { /* See "16-color Text Extension" Open Firmware document, page 4 */ 0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15 }; static struct ofwfb_softc ofwfb_conssoftc; VT_DRIVER_DECLARE(vt_ofwfb, vt_ofwfb_driver); static int ofwfb_probe(struct vt_device *vd) { int disabled; phandle_t chosen, node; ihandle_t stdout; char buf[64]; disabled = 0; TUNABLE_INT_FETCH("hw.ofwfb.disable", &disabled); if (disabled) return (CN_DEAD); chosen = OF_finddevice("/chosen"); if (chosen == -1) return (CN_DEAD); node = -1; if (OF_getencprop(chosen, "stdout", &stdout, sizeof(stdout)) == sizeof(stdout)) node = OF_instance_to_package(stdout); if (node == -1) if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0) node = OF_finddevice(buf); if (node == -1) { /* * The "/chosen/stdout" does not exist try * using "screen" directly. */ node = OF_finddevice("screen"); } OF_getprop(node, "device_type", buf, sizeof(buf)); if (strcmp(buf, "display") != 0) return (CN_DEAD); /* Looks OK... */ return (CN_INTERNAL); } static void ofwfb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, const uint8_t *pattern, const uint8_t *mask, unsigned int width, unsigned int height, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) { struct fb_info *sc = vd->vd_softc; u_long line; uint32_t fgc, bgc; int c, l; uint8_t b, m; union { uint32_t l; uint8_t c[4]; } ch1, ch2; #ifdef __powerpc__ /* Deal with unmapped framebuffers */ if (sc->fb_flags & FB_FLAG_NOWRITE) { if (pmap_bootstrapped) { sc->fb_flags &= ~FB_FLAG_NOWRITE; ofwfb_initialize(vd); vd->vd_driver->vd_blank(vd, TC_BLACK); } else { return; } } #endif fgc = sc->fb_cmap[fg]; bgc = sc->fb_cmap[bg]; b = m = 0; if (((struct ofwfb_softc *)vd->vd_softc)->iso_palette) { fg = ofw_colors[fg]; bg = ofw_colors[bg]; } line = (sc->fb_stride * y) + x * sc->fb_bpp/8; if (mask == NULL && sc->fb_bpp == 8 && (width % 8 == 0)) { /* Don't try to put off screen pixels */ if (((x + width) > vd->vd_width) || ((y + height) > vd->vd_height)) return; for (; height > 0; height--) { for (c = 0; c < width; c += 8) { b = *pattern++; /* * Assume that there is more background than * foreground in characters and init accordingly */ ch1.l = ch2.l = (bg << 24) | (bg << 16) | (bg << 8) | bg; /* * Calculate 2 x 4-chars at a time, and then * write these out. */ if (b & 0x80) ch1.c[0] = fg; if (b & 0x40) ch1.c[1] = fg; if (b & 0x20) ch1.c[2] = fg; if (b & 0x10) ch1.c[3] = fg; if (b & 0x08) ch2.c[0] = fg; if (b & 0x04) ch2.c[1] = fg; if (b & 0x02) ch2.c[2] = fg; if (b & 0x01) ch2.c[3] = fg; *(uint32_t *)(sc->fb_vbase + line + c) = ch1.l; *(uint32_t *)(sc->fb_vbase + line + c + 4) = ch2.l; } line += sc->fb_stride; } } else { for (l = 0; l < height && y + l < vw->vw_draw_area.tr_end.tp_row; l++) { for (c = 0; c < width && x + c < vw->vw_draw_area.tr_end.tp_col; c++) { if (c % 8 == 0) b = *pattern++; else b <<= 1; if (mask != NULL) { if (c % 8 == 0) m = *mask++; else m <<= 1; /* Skip pixel write, if mask not set. */ if ((m & 0x80) == 0) continue; } switch(sc->fb_bpp) { case 8: *(uint8_t *)(sc->fb_vbase + line + c) = b & 0x80 ? fg : bg; break; case 32: *(uint32_t *)(sc->fb_vbase + line + 4*c) = (b & 0x80) ? fgc : bgc; break; default: /* panic? */ break; } } line += sc->fb_stride; } } } +static int +ofwfb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *argb, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y) +{ + + return (EOPNOTSUPP); +} + void ofwfb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { unsigned int col, row, x, y; struct vt_font *vf; term_char_t c; term_color_t fg, bg; const uint8_t *pattern; vf = vw->vw_font; for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; ++col) { x = col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col; y = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row; c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); pattern = vtfont_lookup(vf, c); vt_determine_colors(c, VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); ofwfb_bitblt_bitmap(vd, vw, pattern, NULL, vf->vf_width, vf->vf_height, x, y, fg, bg); } } #ifndef SC_NO_CUTPASTE if (!vd->vd_mshown) return; term_rect_t drawn_area; drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; if (vt_is_cursor_in_area(vd, &drawn_area)) { ofwfb_bitblt_bitmap(vd, vw, vd->vd_mcursor->map, vd->vd_mcursor->mask, vd->vd_mcursor->width, vd->vd_mcursor->height, vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, vd->vd_mcursor_fg, vd->vd_mcursor_bg); } #endif } /* * Decode OpenFirmware/IEEE 1275-1994 "ranges" property * * XXX: this is similar to ofw_pcib_fill_ranges but cannot use it here because * it's not possible to allocate memory at the moment this is funcion is * used. Since there are other similar functions dealing with "ranges" * property, a proper refactoring is suggested. */ static uint64_t decode_pci_ranges_host_addr(phandle_t pcinode) { struct simplebus_range { uint64_t bus; uint64_t host; uint64_t size; }; struct simplebus_range ranges[4]; int nranges, host_address_cells; pcell_t acells, scells; cell_t base_ranges[64]; ssize_t nbase_ranges; int i, j, k; if (!OF_hasprop(pcinode, "ranges")) return (0); if (OF_getencprop(pcinode, "#address-cells", &acells, sizeof(acells)) != sizeof(acells)) return (0); if (OF_getencprop(pcinode, "#size-cells", &scells, sizeof(scells)) != sizeof(scells)) return (0); if (OF_searchencprop(OF_parent(pcinode), "#address-cells", &host_address_cells, sizeof(host_address_cells)) != sizeof(host_address_cells)) return (0); nbase_ranges = OF_getproplen(pcinode, "ranges"); nranges = nbase_ranges / sizeof(cell_t) / (acells + host_address_cells + scells); /* prevent buffer overflow during iteration */ if (nranges > sizeof(ranges) / sizeof(ranges[0])) nranges = sizeof(ranges) / sizeof(ranges[0]); /* decode range value and return the first valid address */ OF_getencprop(pcinode, "ranges", base_ranges, nbase_ranges); for (i = 0, j = 0; i < nranges; i++) { ranges[i].bus = 0; for (k = 0; k < acells; k++) { ranges[i].bus <<= 32; ranges[i].bus |= base_ranges[j++]; } ranges[i].host = 0; for (k = 0; k < host_address_cells; k++) { ranges[i].host <<= 32; ranges[i].host |= base_ranges[j++]; } ranges[i].size = 0; for (k = 0; k < scells; k++) { ranges[i].size <<= 32; ranges[i].size |= base_ranges[j++]; } if (ranges[i].host != 0) return (ranges[i].host); } return (0); } static bus_addr_t find_pci_host_address(phandle_t node) { uint64_t addr; /* * According to IEEE STD 1275, if property "ranges" exists but has a * zero-length property value, the child address space is identical * to the parent address space. */ while (node) { if (OF_hasprop(node, "ranges")) { addr = decode_pci_ranges_host_addr(node); if (addr != 0) return ((bus_addr_t)addr); } node = OF_parent(node); } return (0); } static void ofwfb_initialize(struct vt_device *vd) { struct ofwfb_softc *sc = vd->vd_softc; int i, err, r, g, b; cell_t retval; sc->fb.fb_cmsize = 16; if (sc->fb.fb_flags & FB_FLAG_NOWRITE) return; /* * Set up the color map */ sc->iso_palette = 0; switch (sc->fb.fb_bpp) { case 8: /* * No color format issues here, since we are passing the RGB * components separately to Open Firmware. */ vt_config_cons_colors(&sc->fb, COLOR_FORMAT_RGB, 255, 16, 255, 8, 255, 0); for (i = 0; i < 16; i++) { err = OF_call_method("color!", sc->sc_handle, 4, 1, (cell_t)((sc->fb.fb_cmap[i] >> 16) & 0xff), (cell_t)((sc->fb.fb_cmap[i] >> 8) & 0xff), (cell_t)((sc->fb.fb_cmap[i] >> 0) & 0xff), (cell_t)i, &retval); if (err) break; } if (i != 16) sc->iso_palette = 1; break; case 32: /* * There are two main color formats in use. * ARGB32 is used mainly on hardware that was designed for * LE systems, and RGBA32 is used mainly on hardware designed * for BE systems. * * PowerMacs use either, depending on the video card option. * NVidia cards tend to be RGBA32, and ATI cards tend to be ARGB32. * * There is no good way to determine the correct option, as this * is independent of endian swapping. */ if (sc->vendor_id == PCI_VID_NVIDIA) sc->argb = 0; else sc->argb = 1; TUNABLE_INT_FETCH("hw.ofwfb.argb32_pixel", &sc->argb); if (sc->endian_flip) { if (sc->argb) r = 8, g = 16, b = 24; else r = 24, g = 16, b = 8; } else { if (sc->argb) r = 16, g = 8, b = 0; else r = 0, g = 8, b = 16; } vt_config_cons_colors(&sc->fb, COLOR_FORMAT_RGB, 255, r, 255, g, 255, b); break; default: panic("Unknown color space depth %d", sc->fb.fb_bpp); break; } } static int ofwfb_init(struct vt_device *vd) { struct ofwfb_softc *sc; char buf[64]; phandle_t chosen; phandle_t node; pcell_t depth, height, width, stride; uint32_t vendor_id = 0; cell_t adr[2]; uint64_t user_phys; bus_addr_t fb_phys; bus_size_t fb_phys_size; int i, j, len; /* Initialize softc */ vd->vd_softc = sc = &ofwfb_conssoftc; node = -1; chosen = OF_finddevice("/chosen"); if (OF_getencprop(chosen, "stdout", &sc->sc_handle, sizeof(ihandle_t)) == sizeof(ihandle_t)) node = OF_instance_to_package(sc->sc_handle); if (node == -1) /* Try "/chosen/stdout-path" now */ if (OF_getprop(chosen, "stdout-path", buf, sizeof(buf)) > 0) { node = OF_finddevice(buf); if (node != -1) sc->sc_handle = OF_open(buf); } if (node == -1) { /* * The "/chosen/stdout" does not exist try * using "screen" directly. */ node = OF_finddevice("screen"); sc->sc_handle = OF_open("screen"); } OF_getprop(node, "device_type", buf, sizeof(buf)); if (strcmp(buf, "display") != 0) return (CN_DEAD); /* * Retrieve vendor-id from /chosen parent node, usually pointing to * video card device. This is used to select pixel format later on * ofwfb_initialize() */ if (OF_getencprop(OF_parent(node), "vendor-id", &vendor_id, sizeof(vendor_id)) == sizeof(vendor_id)) sc->vendor_id = vendor_id; /* Keep track of the OF node */ sc->sc_node = node; /* * Try to use a 32-bit framebuffer if possible. This may be * unimplemented and fail. That's fine -- it just means we are * stuck with the defaults. */ OF_call_method("set-depth", sc->sc_handle, 1, 1, (cell_t)32, &i); /* Make sure we have needed properties */ if (OF_getproplen(node, "height") != sizeof(height) || OF_getproplen(node, "width") != sizeof(width) || OF_getproplen(node, "depth") != sizeof(depth)) return (CN_DEAD); /* Only support 8 and 32-bit framebuffers */ OF_getencprop(node, "depth", &depth, sizeof(depth)); if (depth != 8 && depth != 32) return (CN_DEAD); sc->fb.fb_bpp = sc->fb.fb_depth = depth; OF_getencprop(node, "height", &height, sizeof(height)); OF_getencprop(node, "width", &width, sizeof(width)); if (OF_getencprop(node, "linebytes", &stride, sizeof(stride)) != sizeof(stride)) stride = width*depth/8; sc->fb.fb_height = height; sc->fb.fb_width = width; sc->fb.fb_stride = stride; sc->fb.fb_size = sc->fb.fb_height * sc->fb.fb_stride; sc->endian_flip = 0; #if defined(__powerpc__) if (OF_hasprop(node, "little-endian")) { sc->sc_memt = &bs_le_tag; #if BYTE_ORDER == BIG_ENDIAN sc->endian_flip = 1; #endif } else if (OF_hasprop(node, "big-endian")) { sc->sc_memt = &bs_be_tag; #if BYTE_ORDER == LITTLE_ENDIAN sc->endian_flip = 1; #endif } else { /* Assume the framebuffer is in native endian. */ #if BYTE_ORDER == BIG_ENDIAN sc->sc_memt = &bs_be_tag; #else sc->sc_memt = &bs_le_tag; #endif } #elif defined(__arm__) sc->sc_memt = fdtbus_bs_tag; #else #error Unsupported platform! #endif /* * Grab the physical address of the framebuffer, and then map it * into our memory space. If the MMU is not yet up, it will be * remapped for us when relocation turns on. * * The ASPEED driver on recent petitboot versions doesn't expose the * physical address of framebuffer anymore for security. So it should * retrieve the address from PCI device properties. */ user_phys = 0; TUNABLE_UINT64_FETCH("hw.ofwfb.physaddr", &user_phys); if (user_phys) sc->fb.fb_pbase = (vm_paddr_t)user_phys; else if (sc->vendor_id == PCI_VID_ASPEED) sc->fb.fb_pbase = find_pci_host_address(node); else if (OF_hasprop(node, "address")) { switch (OF_getproplen(node, "address")) { case 4: OF_getencprop(node, "address", adr, 4); fb_phys = adr[0]; break; case 8: OF_getencprop(node, "address", adr, 8); fb_phys = ((uint64_t)adr[0] << 32) | adr[1]; break; default: /* Bad property? */ return (CN_DEAD); } sc->fb.fb_pbase = (vm_paddr_t)fb_phys; } else { #if defined(__powerpc__) /* * Some IBM systems don't have an address property. Try to * guess the framebuffer region from the assigned addresses. * This is ugly, but there doesn't seem to be an alternative. * Linux does the same thing. */ struct ofw_pci_register pciaddrs[8]; int num_pciaddrs = 0; /* * Get the PCI addresses of the adapter, if present. The node * may be the child of the PCI device: in that case, try the * parent for the assigned-addresses property. */ len = OF_getencprop(node, "assigned-addresses", (pcell_t *)pciaddrs, sizeof(pciaddrs)); if (len == -1) { len = OF_getencprop(OF_parent(node), "assigned-addresses", (pcell_t *)pciaddrs, sizeof(pciaddrs)); } if (len == -1) len = 0; num_pciaddrs = len / sizeof(struct ofw_pci_register); j = num_pciaddrs; for (i = 0; i < num_pciaddrs; i++) { /* If it is too small, not the framebuffer */ if (pciaddrs[i].size_lo < sc->fb.fb_stride * height) continue; /* If it is not memory, it isn't either */ if (!(pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_SPACE_MEM32)) continue; /* This could be the framebuffer */ j = i; /* If it is prefetchable, it certainly is */ if (pciaddrs[i].phys_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) break; } if (j == num_pciaddrs) /* No candidates found */ return (CN_DEAD); if (ofw_reg_to_paddr(node, j, &fb_phys, &fb_phys_size, NULL) < 0) return (CN_DEAD); sc->fb.fb_pbase = (vm_paddr_t)fb_phys; #else /* No ability to interpret assigned-addresses otherwise */ return (CN_DEAD); #endif } if (!sc->fb.fb_pbase) return (CN_DEAD); bus_space_map(sc->sc_memt, sc->fb.fb_pbase, sc->fb.fb_size, BUS_SPACE_MAP_PREFETCHABLE, (bus_space_handle_t *)&sc->fb.fb_vbase); #if defined(__powerpc__) /* * If we are running on PowerPC in real mode (supported only on AIM * CPUs), the frame buffer may be inaccessible (real mode does not * necessarily cover all RAM) and may also be mapped with the wrong * cache properties (all real mode accesses are assumed cacheable). * Just don't write to it for the time being. */ if (!(cpu_features & PPC_FEATURE_BOOKE) && !(mfmsr() & PSL_DR)) sc->fb.fb_flags |= FB_FLAG_NOWRITE; #endif ofwfb_initialize(vd); vt_fb_init(vd); return (CN_INTERNAL); } diff --git a/sys/dev/vt/hw/simplefb/simplefb.c b/sys/dev/vt/hw/simplefb/simplefb.c index c7381b102d3e..6983b41b3888 100644 --- a/sys/dev/vt/hw/simplefb/simplefb.c +++ b/sys/dev/vt/hw/simplefb/simplefb.c @@ -1,223 +1,235 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2014 The FreeBSD Foundation * Copyright (c) 2021 Andrew Turner * * Portions of this software was developed by Aleksandr Rybalko under * sponsorship from the FreeBSD Foundation. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include static vd_init_t vt_simplefb_init; static vd_fini_t vt_simplefb_fini; static vd_probe_t vt_simplefb_probe; +static vd_bitblt_argb_t vt_simplefb_bitblt_argb; static struct vt_driver vt_simplefb_driver = { .vd_name = "simplefb", .vd_probe = vt_simplefb_probe, .vd_init = vt_simplefb_init, .vd_fini = vt_simplefb_fini, .vd_blank = vt_fb_blank, .vd_bitblt_text = vt_fb_bitblt_text, .vd_invalidate_text = vt_fb_invalidate_text, .vd_bitblt_bmp = vt_fb_bitblt_bitmap, + .vd_bitblt_argb = vt_simplefb_bitblt_argb, .vd_drawrect = vt_fb_drawrect, .vd_setpixel = vt_fb_setpixel, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = vt_fb_mmap, .vd_suspend = vt_suspend, .vd_resume = vt_resume, /* Better than efifb, but still generic driver. */ .vd_priority = VD_PRIORITY_GENERIC + 2, }; struct { const char *name; int rbits, rshift; int gbits, gshift; int bbits, bshift; int depth; enum vt_color_format format; } simplefb_formats[] = { { .name = "r5g6b5", .rbits = 5, .rshift = 11, .gbits = 6, .gshift = 5, .bbits = 5, .bshift = 0, .depth = 16, .format = COLOR_FORMAT_RGB, }, { .name = "r8g8b8", .rbits = 8, .rshift = 16, .gbits = 8, .gshift = 8, .bbits = 8, .bshift = 0, .depth = 24, .format = COLOR_FORMAT_RGB, }, { .name = "a8r8g8b8", .rbits = 8, .rshift = 16, .gbits = 8, .gshift = 8, .bbits = 8, .bshift = 0, .depth = 32, .format = COLOR_FORMAT_RGB, }, { .name = "x8r8g8b8", .rbits = 8, .rshift = 16, .gbits = 8, .gshift = 8, .bbits = 8, .bshift = 0, .depth = 32, .format = COLOR_FORMAT_RGB, }, { .name = "x2r10g10b10", .rbits = 10, .rshift = 20, .gbits = 10, .gshift = 10, .bbits = 10, .bshift = 0, .depth = 32, .format = COLOR_FORMAT_RGB, }, }; static struct fb_info local_info; VT_DRIVER_DECLARE(vt_simplefb, vt_simplefb_driver); static bool vt_simplefb_node(phandle_t *nodep) { phandle_t chosen, node; chosen = OF_finddevice("/chosen"); if (chosen == -1) return (false); for (node = OF_child(chosen); node != 0; node = OF_peer(node)) { if (ofw_bus_node_is_compatible(node, "simple-framebuffer")) break; } if (node == 0) return (false); if (nodep != NULL) *nodep = node; return (true); } static int vt_simplefb_probe(struct vt_device *vd) { int disabled; disabled = 0; TUNABLE_INT_FETCH("hw.syscons.disable", &disabled); if (disabled != 0) return (CN_DEAD); if (!vt_simplefb_node(NULL)) return (CN_DEAD); return (CN_INTERNAL); } static int vt_simplefb_init(struct vt_device *vd) { char format[16]; pcell_t height, width, stride; struct fb_info *sc; phandle_t node; bus_size_t size; int error; /* Initialize softc */ vd->vd_softc = sc = &local_info; if (!vt_simplefb_node(&node)) return (CN_DEAD); if (OF_getencprop(node, "height", &height, sizeof(height)) == -1 || OF_getencprop(node, "width", &width, sizeof(width)) == -1 || OF_getencprop(node, "stride", &stride, sizeof(stride)) == -1 || OF_getprop(node, "format", format, sizeof(format)) == -1) { return (CN_DEAD); } sc->fb_height = height; sc->fb_width = width; sc->fb_stride = stride; sc->fb_cmsize = NCOLORS; error = 1; for (int i = 0; i < nitems(simplefb_formats); i++) { if (strcmp(format, simplefb_formats[i].name) == 0) { vt_config_cons_colors(sc, simplefb_formats[i].format, (1 << simplefb_formats[i].rbits) - 1, simplefb_formats[i].rshift, (1 << simplefb_formats[i].gbits) - 1, simplefb_formats[i].gshift, (1 << simplefb_formats[i].bbits) - 1, simplefb_formats[i].bshift); sc->fb_depth = sc->fb_bpp = simplefb_formats[i].depth; error = 0; break; } } if (error != 0) return (CN_DEAD); ofw_reg_to_paddr(node, 0, &sc->fb_pbase, &size, NULL); sc->fb_vbase = (intptr_t)pmap_mapdev_attr(sc->fb_pbase, size, VM_MEMATTR_WRITE_COMBINING); sc->fb_size = size; vt_fb_init(vd); return (CN_INTERNAL); } static void vt_simplefb_fini(struct vt_device *vd, void *softc) { struct fb_info *sc; sc = softc; vt_fb_fini(vd, softc); pmap_unmapdev((void *)sc->fb_vbase, sc->fb_size); } + +static int +vt_simplefb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *argb, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y) +{ + + return (EOPNOTSUPP); +} diff --git a/sys/dev/vt/hw/vbefb/vbefb.c b/sys/dev/vt/hw/vbefb/vbefb.c index bb4d88dd2ecf..2d6ada6002d0 100644 --- a/sys/dev/vt/hw/vbefb/vbefb.c +++ b/sys/dev/vt/hw/vbefb/vbefb.c @@ -1,160 +1,161 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2014 The FreeBSD Foundation * * This software was developed by Aleksandr Rybalko under sponsorship from the * FreeBSD Foundation. * * 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 #include #include #include #include #include "opt_platform.h" #include #include #include #include #include #include #include static vd_init_t vt_vbefb_init; static vd_fini_t vt_vbefb_fini; static vd_probe_t vt_vbefb_probe; static struct vt_driver vt_vbefb_driver = { .vd_name = "vbefb", .vd_probe = vt_vbefb_probe, .vd_init = vt_vbefb_init, .vd_fini = vt_vbefb_fini, .vd_blank = vt_fb_blank, .vd_bitblt_text = vt_fb_bitblt_text, .vd_invalidate_text = vt_fb_invalidate_text, .vd_bitblt_bmp = vt_fb_bitblt_bitmap, + .vd_bitblt_argb = vt_fb_bitblt_argb, .vd_drawrect = vt_fb_drawrect, .vd_setpixel = vt_fb_setpixel, .vd_fb_ioctl = vt_fb_ioctl, .vd_fb_mmap = vt_fb_mmap, .vd_suspend = vt_suspend, .vd_resume = vt_resume, /* Better than VGA, but still generic driver. */ .vd_priority = VD_PRIORITY_GENERIC + 1, }; static struct fb_info local_vbe_info; VT_DRIVER_DECLARE(vt_vbefb, vt_vbefb_driver); static int vt_vbefb_probe(struct vt_device *vd) { int disabled; struct vbe_fb *vbefb; caddr_t kmdp; disabled = 0; TUNABLE_INT_FETCH("hw.syscons.disable", &disabled); if (disabled != 0) return (CN_DEAD); kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf64 kernel"); vbefb = (struct vbe_fb *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_VBE_FB); if (vbefb == NULL) return (CN_DEAD); return (CN_INTERNAL); } static int vt_vbefb_init(struct vt_device *vd) { struct fb_info *info; struct vbe_fb *vbefb; caddr_t kmdp; int format, roff, goff, boff; info = vd->vd_softc; if (info == NULL) info = vd->vd_softc = (void *)&local_vbe_info; kmdp = preload_search_by_type("elf kernel"); if (kmdp == NULL) kmdp = preload_search_by_type("elf64 kernel"); vbefb = (struct vbe_fb *)preload_search_info(kmdp, MODINFO_METADATA | MODINFOMD_VBE_FB); if (vbefb == NULL) return (CN_DEAD); info->fb_height = vbefb->fb_height; info->fb_width = vbefb->fb_width; info->fb_depth = vbefb->fb_bpp; /* Round to a multiple of the bits in a byte. */ info->fb_bpp = roundup2(vbefb->fb_bpp, NBBY); /* Stride in bytes, not pixels */ info->fb_stride = vbefb->fb_stride * (info->fb_bpp / NBBY); if (info->fb_depth == 8) format = COLOR_FORMAT_VGA; else format = COLOR_FORMAT_RGB; roff = ffs(vbefb->fb_mask_red) - 1; goff = ffs(vbefb->fb_mask_green) - 1; boff = ffs(vbefb->fb_mask_blue) - 1; vt_config_cons_colors(info, format, vbefb->fb_mask_red >> roff, roff, vbefb->fb_mask_green >> goff, goff, vbefb->fb_mask_blue >> boff, boff); /* Mark cmap initialized. */ info->fb_cmsize = NCOLORS; info->fb_size = info->fb_height * info->fb_stride; info->fb_pbase = vbefb->fb_addr; info->fb_vbase = (intptr_t)pmap_mapdev_attr(info->fb_pbase, info->fb_size, VM_MEMATTR_WRITE_COMBINING); vt_fb_init(vd); return (CN_INTERNAL); } static void vt_vbefb_fini(struct vt_device *vd, void *softc) { struct fb_info *info = softc; vt_fb_fini(vd, softc); pmap_unmapdev((void *)info->fb_vbase, info->fb_size); } diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c index e2ae20894fc5..64039575c0ad 100644 --- a/sys/dev/vt/hw/vga/vt_vga.c +++ b/sys/dev/vt/hw/vga/vt_vga.c @@ -1,1390 +1,1402 @@ /*- * Copyright (c) 2005 Marcel Moolenaar * All rights reserved. * * Copyright (c) 2009 The FreeBSD Foundation * All rights reserved. * * Portions of this software were developed by Ed Schouten * under sponsorship from the FreeBSD Foundation. * * 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 "opt_acpi.h" #include #include #include #include #include #include #include #include #include #include #include #if defined(__amd64__) || defined(__i386__) #include #include #endif struct vga_softc { bus_space_tag_t vga_fb_tag; bus_space_handle_t vga_fb_handle; bus_space_tag_t vga_reg_tag; bus_space_handle_t vga_reg_handle; int vga_wmode; term_color_t vga_curfg, vga_curbg; boolean_t vga_enabled; }; /* Convenience macros. */ #define MEM_READ1(sc, ofs) \ bus_space_read_1(sc->vga_fb_tag, sc->vga_fb_handle, ofs) #define MEM_WRITE1(sc, ofs, val) \ bus_space_write_1(sc->vga_fb_tag, sc->vga_fb_handle, ofs, val) #define MEM_WRITE2(sc, ofs, val) \ bus_space_write_2(sc->vga_fb_tag, sc->vga_fb_handle, ofs, val) #define REG_READ1(sc, reg) \ bus_space_read_1(sc->vga_reg_tag, sc->vga_reg_handle, reg) #define REG_WRITE1(sc, reg, val) \ bus_space_write_1(sc->vga_reg_tag, sc->vga_reg_handle, reg, val) #define VT_VGA_WIDTH 640 #define VT_VGA_HEIGHT 480 #define VT_VGA_MEMSIZE (VT_VGA_WIDTH * VT_VGA_HEIGHT / 8) /* * VGA is designed to handle 8 pixels at a time (8 pixels in one byte of * memory). */ #define VT_VGA_PIXELS_BLOCK 8 /* * We use an off-screen addresses to: * o store the background color; * o store pixels pattern. * Those addresses are then loaded in the latches once. */ #define VT_VGA_BGCOLOR_OFFSET VT_VGA_MEMSIZE static vd_probe_t vga_probe; static vd_init_t vga_init; static vd_blank_t vga_blank; static vd_bitblt_text_t vga_bitblt_text; static vd_invalidate_text_t vga_invalidate_text; static vd_bitblt_bmp_t vga_bitblt_bitmap; +static vd_bitblt_argb_t vga_bitblt_argb; static vd_drawrect_t vga_drawrect; static vd_setpixel_t vga_setpixel; static vd_postswitch_t vga_postswitch; static const struct vt_driver vt_vga_driver = { .vd_name = "vga", .vd_probe = vga_probe, .vd_init = vga_init, .vd_blank = vga_blank, .vd_bitblt_text = vga_bitblt_text, .vd_invalidate_text = vga_invalidate_text, .vd_bitblt_bmp = vga_bitblt_bitmap, + .vd_bitblt_argb = vga_bitblt_argb, .vd_drawrect = vga_drawrect, .vd_setpixel = vga_setpixel, .vd_postswitch = vga_postswitch, .vd_priority = VD_PRIORITY_GENERIC, }; /* * Driver supports both text mode and graphics mode. Make sure the * buffer is always big enough to support both. */ static struct vga_softc vga_conssoftc; VT_DRIVER_DECLARE(vt_vga, vt_vga_driver); static inline void vga_setwmode(struct vt_device *vd, int wmode) { struct vga_softc *sc = vd->vd_softc; if (sc->vga_wmode == wmode) return; REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE); REG_WRITE1(sc, VGA_GC_DATA, wmode); sc->vga_wmode = wmode; switch (wmode) { case 3: /* Re-enable all planes. */ REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK); REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_MM_EM3 | VGA_SEQ_MM_EM2 | VGA_SEQ_MM_EM1 | VGA_SEQ_MM_EM0); break; } } static inline void vga_setfg(struct vt_device *vd, term_color_t color) { struct vga_softc *sc = vd->vd_softc; vga_setwmode(vd, 3); if (sc->vga_curfg == color) return; REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); REG_WRITE1(sc, VGA_GC_DATA, cons_to_vga_colors[color]); sc->vga_curfg = color; } static inline void vga_setbg(struct vt_device *vd, term_color_t color) { struct vga_softc *sc = vd->vd_softc; vga_setwmode(vd, 3); if (sc->vga_curbg == color) return; REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); REG_WRITE1(sc, VGA_GC_DATA, cons_to_vga_colors[color]); /* * Write 8 pixels using the background color to an off-screen * byte in the video memory. */ MEM_WRITE1(sc, VT_VGA_BGCOLOR_OFFSET, 0xff); /* * Read those 8 pixels back to load the background color in the * latches register. */ MEM_READ1(sc, VT_VGA_BGCOLOR_OFFSET); sc->vga_curbg = color; /* * The Set/Reset register doesn't contain the fg color anymore, * store an invalid color. */ sc->vga_curfg = 0xff; } /* * Binary searchable table for Unicode to CP437 conversion. */ struct unicp437 { uint16_t unicode_base; uint8_t cp437_base; uint8_t length; }; static const struct unicp437 cp437table[] = { { 0x0020, 0x20, 0x5e }, { 0x00a0, 0x20, 0x00 }, { 0x00a1, 0xad, 0x00 }, { 0x00a2, 0x9b, 0x00 }, { 0x00a3, 0x9c, 0x00 }, { 0x00a5, 0x9d, 0x00 }, { 0x00a6, 0x7c, 0x00 }, { 0x00a7, 0x15, 0x00 }, { 0x00aa, 0xa6, 0x00 }, { 0x00ab, 0xae, 0x00 }, { 0x00ac, 0xaa, 0x00 }, { 0x00b0, 0xf8, 0x00 }, { 0x00b1, 0xf1, 0x00 }, { 0x00b2, 0xfd, 0x00 }, { 0x00b5, 0xe6, 0x00 }, { 0x00b6, 0x14, 0x00 }, { 0x00b7, 0xfa, 0x00 }, { 0x00ba, 0xa7, 0x00 }, { 0x00bb, 0xaf, 0x00 }, { 0x00bc, 0xac, 0x00 }, { 0x00bd, 0xab, 0x00 }, { 0x00bf, 0xa8, 0x00 }, { 0x00c4, 0x8e, 0x01 }, { 0x00c6, 0x92, 0x00 }, { 0x00c7, 0x80, 0x00 }, { 0x00c9, 0x90, 0x00 }, { 0x00d1, 0xa5, 0x00 }, { 0x00d6, 0x99, 0x00 }, { 0x00dc, 0x9a, 0x00 }, { 0x00df, 0xe1, 0x00 }, { 0x00e0, 0x85, 0x00 }, { 0x00e1, 0xa0, 0x00 }, { 0x00e2, 0x83, 0x00 }, { 0x00e4, 0x84, 0x00 }, { 0x00e5, 0x86, 0x00 }, { 0x00e6, 0x91, 0x00 }, { 0x00e7, 0x87, 0x00 }, { 0x00e8, 0x8a, 0x00 }, { 0x00e9, 0x82, 0x00 }, { 0x00ea, 0x88, 0x01 }, { 0x00ec, 0x8d, 0x00 }, { 0x00ed, 0xa1, 0x00 }, { 0x00ee, 0x8c, 0x00 }, { 0x00ef, 0x8b, 0x00 }, { 0x00f0, 0xeb, 0x00 }, { 0x00f1, 0xa4, 0x00 }, { 0x00f2, 0x95, 0x00 }, { 0x00f3, 0xa2, 0x00 }, { 0x00f4, 0x93, 0x00 }, { 0x00f6, 0x94, 0x00 }, { 0x00f7, 0xf6, 0x00 }, { 0x00f8, 0xed, 0x00 }, { 0x00f9, 0x97, 0x00 }, { 0x00fa, 0xa3, 0x00 }, { 0x00fb, 0x96, 0x00 }, { 0x00fc, 0x81, 0x00 }, { 0x00ff, 0x98, 0x00 }, { 0x0192, 0x9f, 0x00 }, { 0x0393, 0xe2, 0x00 }, { 0x0398, 0xe9, 0x00 }, { 0x03a3, 0xe4, 0x00 }, { 0x03a6, 0xe8, 0x00 }, { 0x03a9, 0xea, 0x00 }, { 0x03b1, 0xe0, 0x01 }, { 0x03b4, 0xeb, 0x00 }, { 0x03b5, 0xee, 0x00 }, { 0x03bc, 0xe6, 0x00 }, { 0x03c0, 0xe3, 0x00 }, { 0x03c3, 0xe5, 0x00 }, { 0x03c4, 0xe7, 0x00 }, { 0x03c6, 0xed, 0x00 }, { 0x03d5, 0xed, 0x00 }, { 0x2010, 0x2d, 0x00 }, { 0x2013, 0x2d, 0x00 }, { 0x2014, 0x2d, 0x00 }, { 0x2018, 0x60, 0x00 }, { 0x2019, 0x27, 0x00 }, { 0x201c, 0x22, 0x00 }, { 0x201d, 0x22, 0x00 }, { 0x2022, 0x07, 0x00 }, { 0x203c, 0x13, 0x00 }, { 0x207f, 0xfc, 0x00 }, { 0x20a7, 0x9e, 0x00 }, { 0x20ac, 0xee, 0x00 }, { 0x2126, 0xea, 0x00 }, { 0x2190, 0x1b, 0x00 }, { 0x2191, 0x18, 0x00 }, { 0x2192, 0x1a, 0x00 }, { 0x2193, 0x19, 0x00 }, { 0x2194, 0x1d, 0x00 }, { 0x2195, 0x12, 0x00 }, { 0x21a8, 0x17, 0x00 }, { 0x2202, 0xeb, 0x00 }, { 0x2208, 0xee, 0x00 }, { 0x2211, 0xe4, 0x00 }, { 0x2212, 0x2d, 0x00 }, { 0x2219, 0xf9, 0x00 }, { 0x221a, 0xfb, 0x00 }, { 0x221e, 0xec, 0x00 }, { 0x221f, 0x1c, 0x00 }, { 0x2229, 0xef, 0x00 }, { 0x2248, 0xf7, 0x00 }, { 0x2261, 0xf0, 0x00 }, { 0x2264, 0xf3, 0x00 }, { 0x2265, 0xf2, 0x00 }, { 0x2302, 0x7f, 0x00 }, { 0x2310, 0xa9, 0x00 }, { 0x2320, 0xf4, 0x00 }, { 0x2321, 0xf5, 0x00 }, { 0x2500, 0xc4, 0x00 }, { 0x2502, 0xb3, 0x00 }, { 0x250c, 0xda, 0x00 }, { 0x2510, 0xbf, 0x00 }, { 0x2514, 0xc0, 0x00 }, { 0x2518, 0xd9, 0x00 }, { 0x251c, 0xc3, 0x00 }, { 0x2524, 0xb4, 0x00 }, { 0x252c, 0xc2, 0x00 }, { 0x2534, 0xc1, 0x00 }, { 0x253c, 0xc5, 0x00 }, { 0x2550, 0xcd, 0x00 }, { 0x2551, 0xba, 0x00 }, { 0x2552, 0xd5, 0x00 }, { 0x2553, 0xd6, 0x00 }, { 0x2554, 0xc9, 0x00 }, { 0x2555, 0xb8, 0x00 }, { 0x2556, 0xb7, 0x00 }, { 0x2557, 0xbb, 0x00 }, { 0x2558, 0xd4, 0x00 }, { 0x2559, 0xd3, 0x00 }, { 0x255a, 0xc8, 0x00 }, { 0x255b, 0xbe, 0x00 }, { 0x255c, 0xbd, 0x00 }, { 0x255d, 0xbc, 0x00 }, { 0x255e, 0xc6, 0x01 }, { 0x2560, 0xcc, 0x00 }, { 0x2561, 0xb5, 0x00 }, { 0x2562, 0xb6, 0x00 }, { 0x2563, 0xb9, 0x00 }, { 0x2564, 0xd1, 0x01 }, { 0x2566, 0xcb, 0x00 }, { 0x2567, 0xcf, 0x00 }, { 0x2568, 0xd0, 0x00 }, { 0x2569, 0xca, 0x00 }, { 0x256a, 0xd8, 0x00 }, { 0x256b, 0xd7, 0x00 }, { 0x256c, 0xce, 0x00 }, { 0x2580, 0xdf, 0x00 }, { 0x2584, 0xdc, 0x00 }, { 0x2588, 0xdb, 0x00 }, { 0x258c, 0xdd, 0x00 }, { 0x2590, 0xde, 0x00 }, { 0x2591, 0xb0, 0x02 }, { 0x25a0, 0xfe, 0x00 }, { 0x25ac, 0x16, 0x00 }, { 0x25b2, 0x1e, 0x00 }, { 0x25ba, 0x10, 0x00 }, { 0x25bc, 0x1f, 0x00 }, { 0x25c4, 0x11, 0x00 }, { 0x25cb, 0x09, 0x00 }, { 0x25d8, 0x08, 0x00 }, { 0x25d9, 0x0a, 0x00 }, { 0x263a, 0x01, 0x01 }, { 0x263c, 0x0f, 0x00 }, { 0x2640, 0x0c, 0x00 }, { 0x2642, 0x0b, 0x00 }, { 0x2660, 0x06, 0x00 }, { 0x2663, 0x05, 0x00 }, { 0x2665, 0x03, 0x01 }, { 0x266a, 0x0d, 0x00 }, { 0x266c, 0x0e, 0x00 }, { 0x2713, 0xfb, 0x00 }, { 0x27e8, 0x3c, 0x00 }, { 0x27e9, 0x3e, 0x00 }, }; static uint8_t vga_get_cp437(term_char_t c) { int min, mid, max; min = 0; max = nitems(cp437table) - 1; if (c < cp437table[0].unicode_base || c > cp437table[max].unicode_base + cp437table[max].length) return '?'; while (max >= min) { mid = (min + max) / 2; if (c < cp437table[mid].unicode_base) max = mid - 1; else if (c > cp437table[mid].unicode_base + cp437table[mid].length) min = mid + 1; else return (c - cp437table[mid].unicode_base + cp437table[mid].cp437_base); } return '?'; } static void vga_blank(struct vt_device *vd, term_color_t color) { struct vga_softc *sc = vd->vd_softc; u_int ofs; vga_setfg(vd, color); for (ofs = 0; ofs < VT_VGA_MEMSIZE; ofs++) MEM_WRITE1(sc, ofs, 0xff); } static inline void vga_bitblt_put(struct vt_device *vd, u_long dst, term_color_t color, uint8_t v) { struct vga_softc *sc = vd->vd_softc; /* Skip empty writes, in order to avoid palette changes. */ if (v != 0x00) { vga_setfg(vd, color); /* * When this MEM_READ1() gets disabled, all sorts of * artifacts occur. This is because this read loads the * set of 8 pixels that are about to be changed. There * is one scenario where we can avoid the read, namely * if all pixels are about to be overwritten anyway. */ if (v != 0xff) { MEM_READ1(sc, dst); /* The bg color was trashed by the reads. */ sc->vga_curbg = 0xff; } MEM_WRITE1(sc, dst, v); } } static void vga_setpixel(struct vt_device *vd, int x, int y, term_color_t color) { if (vd->vd_flags & VDF_TEXTMODE) return; vga_bitblt_put(vd, (y * VT_VGA_WIDTH / 8) + (x / 8), color, 0x80 >> (x % 8)); } static void vga_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, term_color_t color) { int x, y; if (vd->vd_flags & VDF_TEXTMODE) return; for (y = y1; y <= y2; y++) { if (fill || (y == y1) || (y == y2)) { for (x = x1; x <= x2; x++) vga_setpixel(vd, x, y, color); } else { vga_setpixel(vd, x1, y, color); vga_setpixel(vd, x2, y, color); } } } static void vga_compute_shifted_pattern(const uint8_t *src, unsigned int bytes, unsigned int src_x, unsigned int x_count, unsigned int dst_x, uint8_t *pattern, uint8_t *mask) { unsigned int n; n = src_x / 8; /* * This mask has bits set, where a pixel (ether 0 or 1) * comes from the source bitmap. */ if (mask != NULL) { *mask = (0xff >> (8 - x_count)) << (8 - x_count - dst_x); } if (n == (src_x + x_count - 1) / 8) { /* All the pixels we want are in the same byte. */ *pattern = src[n]; if (dst_x >= src_x) *pattern >>= (dst_x - src_x % 8); else *pattern <<= (src_x % 8 - dst_x); } else { /* The pixels we want are split into two bytes. */ if (dst_x >= src_x % 8) { *pattern = src[n] << (8 - dst_x - src_x % 8) | src[n + 1] >> (dst_x - src_x % 8); } else { *pattern = src[n] << (src_x % 8 - dst_x) | src[n + 1] >> (8 - src_x % 8 - dst_x); } } } static void vga_copy_bitmap_portion(uint8_t *pattern_2colors, uint8_t *pattern_ncolors, const uint8_t *src, const uint8_t *src_mask, unsigned int src_width, unsigned int src_x, unsigned int dst_x, unsigned int x_count, unsigned int src_y, unsigned int dst_y, unsigned int y_count, term_color_t fg, term_color_t bg, int overwrite) { unsigned int i, bytes; uint8_t pattern, relevant_bits, mask; bytes = (src_width + 7) / 8; for (i = 0; i < y_count; ++i) { vga_compute_shifted_pattern(src + (src_y + i) * bytes, bytes, src_x, x_count, dst_x, &pattern, &relevant_bits); if (src_mask == NULL) { /* * No src mask. Consider that all wanted bits * from the source are "authoritative". */ mask = relevant_bits; } else { /* * There's an src mask. We shift it the same way * we shifted the source pattern. */ vga_compute_shifted_pattern( src_mask + (src_y + i) * bytes, bytes, src_x, x_count, dst_x, &mask, NULL); /* Now, only keep the wanted bits among them. */ mask &= relevant_bits; } /* * Clear bits from the pattern which must be * transparent, according to the source mask. */ pattern &= mask; /* Set the bits in the 2-colors array. */ if (overwrite) pattern_2colors[dst_y + i] &= ~mask; pattern_2colors[dst_y + i] |= pattern; if (pattern_ncolors == NULL) continue; /* * Set the same bits in the n-colors array. This one * supports transparency, when a given bit is cleared in * all colors. */ if (overwrite) { /* * Ensure that the pixels used by this bitmap are * cleared in other colors. */ for (int j = 0; j < 16; ++j) pattern_ncolors[(dst_y + i) * 16 + j] &= ~mask; } pattern_ncolors[(dst_y + i) * 16 + fg] |= pattern; pattern_ncolors[(dst_y + i) * 16 + bg] |= (~pattern & mask); } } static void vga_bitblt_pixels_block_2colors(struct vt_device *vd, const uint8_t *masks, term_color_t fg, term_color_t bg, unsigned int x, unsigned int y, unsigned int height) { unsigned int i, offset; struct vga_softc *sc; /* * The great advantage of Write Mode 3 is that we just need * to load the foreground in the Set/Reset register, load the * background color in the latches register (this is done * through a write in offscreen memory followed by a read of * that data), then write the pattern to video memory. This * pattern indicates if the pixel should use the foreground * color (bit set) or the background color (bit cleared). */ vga_setbg(vd, bg); vga_setfg(vd, fg); sc = vd->vd_softc; offset = (VT_VGA_WIDTH * y + x) / 8; for (i = 0; i < height; ++i, offset += VT_VGA_WIDTH / 8) { MEM_WRITE1(sc, offset, masks[i]); } } static void vga_bitblt_pixels_block_ncolors(struct vt_device *vd, const uint8_t *masks, unsigned int x, unsigned int y, unsigned int height) { unsigned int i, j, plane, color, offset; struct vga_softc *sc; uint8_t mask, planes[height * 4]; sc = vd->vd_softc; memset(planes, 0, sizeof(planes)); /* * To write a group of pixels using 3 or more colors, we select * Write Mode 0 and write one byte to each plane separately. */ /* * We first compute each byte: each plane contains one bit of the * color code for each of the 8 pixels. * * For example, if the 8 pixels are like this: * GBBBBBBY * where: * G (gray) = 0b0111 * B (black) = 0b0000 * Y (yellow) = 0b0011 * * The corresponding for bytes are: * GBBBBBBY * Plane 0: 10000001 = 0x81 * Plane 1: 10000001 = 0x81 * Plane 2: 10000000 = 0x80 * Plane 3: 00000000 = 0x00 * | | | * | | +-> 0b0011 (Y) * | +-----> 0b0000 (B) * +--------> 0b0111 (G) */ for (i = 0; i < height; ++i) { for (color = 0; color < 16; ++color) { mask = masks[i * 16 + color]; if (mask == 0x00) continue; for (j = 0; j < 8; ++j) { if (!((mask >> (7 - j)) & 0x1)) continue; /* The pixel "j" uses color "color". */ for (plane = 0; plane < 4; ++plane) planes[i * 4 + plane] |= ((cons_to_vga_colors[color] >> plane) & 0x1) << (7 - j); } } } /* * The bytes are ready: we now switch to Write Mode 0 and write * all bytes, one plane at a time. */ vga_setwmode(vd, 0); REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK); for (plane = 0; plane < 4; ++plane) { /* Select plane. */ REG_WRITE1(sc, VGA_SEQ_DATA, 1 << plane); /* Write all bytes for this plane, from Y to Y+height. */ for (i = 0; i < height; ++i) { offset = (VT_VGA_WIDTH * (y + i) + x) / 8; MEM_WRITE1(sc, offset, planes[i * 4 + plane]); } } } static void vga_bitblt_one_text_pixels_block(struct vt_device *vd, const struct vt_window *vw, unsigned int x, unsigned int y) { const struct vt_buf *vb; const struct vt_font *vf; unsigned int i, col, row, src_x, x_count; unsigned int used_colors_list[16], used_colors; uint8_t pattern_2colors[vw->vw_font->vf_height]; uint8_t pattern_ncolors[vw->vw_font->vf_height * 16]; term_char_t c; term_color_t fg, bg; const uint8_t *src; vb = &vw->vw_buf; vf = vw->vw_font; /* * The current pixels block. * * We fill it with portions of characters, because both "grids" * may not match. * * i is the index in this pixels block. */ i = x; used_colors = 0; memset(used_colors_list, 0, sizeof(used_colors_list)); memset(pattern_2colors, 0, sizeof(pattern_2colors)); memset(pattern_ncolors, 0, sizeof(pattern_ncolors)); if (i < vw->vw_draw_area.tr_begin.tp_col) { /* * i is in the margin used to center the text area on * the screen. */ i = vw->vw_draw_area.tr_begin.tp_col; } while (i < x + VT_VGA_PIXELS_BLOCK && i < vw->vw_draw_area.tr_end.tp_col) { /* * Find which character is drawn on this pixel in the * pixels block. * * While here, record what colors it uses. */ col = (i - vw->vw_draw_area.tr_begin.tp_col) / vf->vf_width; row = (y - vw->vw_draw_area.tr_begin.tp_row) / vf->vf_height; c = VTBUF_GET_FIELD(vb, row, col); src = vtfont_lookup(vf, c); vt_determine_colors(c, VTBUF_ISCURSOR(vb, row, col), &fg, &bg); if ((used_colors_list[fg] & 0x1) != 0x1) used_colors++; if ((used_colors_list[bg] & 0x2) != 0x2) used_colors++; used_colors_list[fg] |= 0x1; used_colors_list[bg] |= 0x2; /* * Compute the portion of the character we want to draw, * because the pixels block may start in the middle of a * character. * * The first pixel to draw in the character is * the current position - * the start position of the character * * The last pixel to draw is either * - the last pixel of the character, or * - the pixel of the character matching the end of * the pixels block * whichever comes first. This position is then * changed to be relative to the start position of the * character. */ src_x = i - (col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col); x_count = min(min( (col + 1) * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col, x + VT_VGA_PIXELS_BLOCK), vw->vw_draw_area.tr_end.tp_col); x_count -= col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col; x_count -= src_x; /* Copy a portion of the character. */ vga_copy_bitmap_portion(pattern_2colors, pattern_ncolors, src, NULL, vf->vf_width, src_x, i % VT_VGA_PIXELS_BLOCK, x_count, 0, 0, vf->vf_height, fg, bg, 0); /* We move to the next portion. */ i += x_count; } #ifndef SC_NO_CUTPASTE /* * Copy the mouse pointer bitmap if it's over the current pixels * block. * * We use the saved cursor position (saved in vt_flush()), because * the current position could be different than the one used * to mark the area dirty. */ term_rect_t drawn_area; drawn_area.tr_begin.tp_col = x; drawn_area.tr_begin.tp_row = y; drawn_area.tr_end.tp_col = x + VT_VGA_PIXELS_BLOCK; drawn_area.tr_end.tp_row = y + vf->vf_height; if (vd->vd_mshown && vt_is_cursor_in_area(vd, &drawn_area)) { struct vt_mouse_cursor *cursor; unsigned int mx, my; unsigned int dst_x, src_y, dst_y, y_count; cursor = vd->vd_mcursor; mx = vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col; my = vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row; /* Compute the portion of the cursor we want to copy. */ src_x = x > mx ? x - mx : 0; dst_x = mx > x ? mx - x : 0; x_count = min(min(min( cursor->width - src_x, x + VT_VGA_PIXELS_BLOCK - mx), vw->vw_draw_area.tr_end.tp_col - mx), VT_VGA_PIXELS_BLOCK); /* * The cursor isn't aligned on the Y-axis with * characters, so we need to compute the vertical * start/count. */ src_y = y > my ? y - my : 0; dst_y = my > y ? my - y : 0; y_count = min( min(cursor->height - src_y, y + vf->vf_height - my), vf->vf_height); /* Copy the cursor portion. */ vga_copy_bitmap_portion(pattern_2colors, pattern_ncolors, cursor->map, cursor->mask, cursor->width, src_x, dst_x, x_count, src_y, dst_y, y_count, vd->vd_mcursor_fg, vd->vd_mcursor_bg, 1); if ((used_colors_list[vd->vd_mcursor_fg] & 0x1) != 0x1) used_colors++; if ((used_colors_list[vd->vd_mcursor_bg] & 0x2) != 0x2) used_colors++; } #endif /* * The pixels block is completed, we can now draw it on the * screen. */ if (used_colors == 2) vga_bitblt_pixels_block_2colors(vd, pattern_2colors, fg, bg, x, y, vf->vf_height); else vga_bitblt_pixels_block_ncolors(vd, pattern_ncolors, x, y, vf->vf_height); } static void vga_bitblt_text_gfxmode(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { const struct vt_font *vf; unsigned int col, row; unsigned int x1, y1, x2, y2, x, y; vf = vw->vw_font; /* * Compute the top-left pixel position aligned with the video * adapter pixels block size. * * This is calculated from the top-left column of te dirty area: * * 1. Compute the top-left pixel of the character: * col * font width + x offset * * NOTE: x offset is used to center the text area on the * screen. It's expressed in pixels, not in characters * col/row! * * 2. Find the pixel further on the left marking the start of * an aligned pixels block (eg. chunk of 8 pixels): * character's x / blocksize * blocksize * * The division, being made on integers, achieves the * alignment. * * For the Y-axis, we need to compute the character's y * coordinate, but we don't need to align it. */ col = area->tr_begin.tp_col; row = area->tr_begin.tp_row; x1 = (int)((col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col) / VT_VGA_PIXELS_BLOCK) * VT_VGA_PIXELS_BLOCK; y1 = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row; /* * Compute the bottom right pixel position, again, aligned with * the pixels block size. * * The same rules apply, we just add 1 to base the computation * on the "right border" of the dirty area. */ col = area->tr_end.tp_col; row = area->tr_end.tp_row; x2 = (int)howmany(col * vf->vf_width + vw->vw_draw_area.tr_begin.tp_col, VT_VGA_PIXELS_BLOCK) * VT_VGA_PIXELS_BLOCK; y2 = row * vf->vf_height + vw->vw_draw_area.tr_begin.tp_row; /* Clip the area to the screen size. */ x2 = min(x2, vw->vw_draw_area.tr_end.tp_col); y2 = min(y2, vw->vw_draw_area.tr_end.tp_row); /* * Now, we take care of N pixels line at a time (the first for * loop, N = font height), and for these lines, draw one pixels * block at a time (the second for loop), not a character at a * time. * * Therefore, on the X-axis, characters my be drawn partially if * they are not aligned on 8-pixels boundary. * * However, the operation is repeated for the full height of the * font before moving to the next character, because it allows * to keep the color settings and write mode, before perhaps * changing them with the next one. */ for (y = y1; y < y2; y += vf->vf_height) { for (x = x1; x < x2; x += VT_VGA_PIXELS_BLOCK) { vga_bitblt_one_text_pixels_block(vd, vw, x, y); } } } static void vga_bitblt_text_txtmode(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { struct vga_softc *sc; const struct vt_buf *vb; unsigned int col, row; term_char_t c; term_color_t fg, bg; uint8_t ch, attr; size_t z; sc = vd->vd_softc; vb = &vw->vw_buf; for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; ++col) { /* * Get next character and its associated fg/bg * colors. */ c = VTBUF_GET_FIELD(vb, row, col); vt_determine_colors(c, VTBUF_ISCURSOR(vb, row, col), &fg, &bg); z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)) continue; if (vd->vd_drawn && (vd->vd_drawn[z] == c) && vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) continue; /* * Convert character to CP437, which is the * character set used by the VGA hardware by * default. */ ch = vga_get_cp437(TCHAR_CHARACTER(c)); /* Convert colors to VGA attributes. */ attr = cons_to_vga_colors[bg] << 4 | cons_to_vga_colors[fg]; MEM_WRITE2(sc, (row * 80 + col) * 2 + 0, ch + ((uint16_t)(attr) << 8)); if (vd->vd_drawn) vd->vd_drawn[z] = c; if (vd->vd_drawnfg) vd->vd_drawnfg[z] = fg; if (vd->vd_drawnbg) vd->vd_drawnbg[z] = bg; } } } static void vga_bitblt_text(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area) { if (!(vd->vd_flags & VDF_TEXTMODE)) { vga_bitblt_text_gfxmode(vd, vw, area); } else { vga_bitblt_text_txtmode(vd, vw, area); } } void vga_invalidate_text(struct vt_device *vd, const term_rect_t *area) { unsigned int col, row; size_t z; for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; ++col) { z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * PIXEL_WIDTH(VT_FB_MAX_WIDTH)) continue; if (vd->vd_drawn) vd->vd_drawn[z] = 0; if (vd->vd_drawnfg) vd->vd_drawnfg[z] = 0; if (vd->vd_drawnbg) vd->vd_drawnbg[z] = 0; } } } static void vga_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, const uint8_t *pattern, const uint8_t *mask, unsigned int width, unsigned int height, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) { unsigned int x1, y1, x2, y2, i, j, src_x, dst_x, x_count; uint8_t pattern_2colors; /* Align coordinates with the 8-pxels grid. */ x1 = rounddown(x, VT_VGA_PIXELS_BLOCK); y1 = y; x2 = roundup(x + width, VT_VGA_PIXELS_BLOCK); y2 = y + height; x2 = min(x2, vd->vd_width - 1); y2 = min(y2, vd->vd_height - 1); for (j = y1; j < y2; ++j) { src_x = 0; dst_x = x - x1; x_count = VT_VGA_PIXELS_BLOCK - dst_x; for (i = x1; i < x2; i += VT_VGA_PIXELS_BLOCK) { pattern_2colors = 0; vga_copy_bitmap_portion( &pattern_2colors, NULL, pattern, mask, width, src_x, dst_x, x_count, j - y1, 0, 1, fg, bg, 0); vga_bitblt_pixels_block_2colors(vd, &pattern_2colors, fg, bg, i, j, 1); src_x += x_count; dst_x = (dst_x + x_count) % VT_VGA_PIXELS_BLOCK; x_count = min(width - src_x, VT_VGA_PIXELS_BLOCK); } } } +static int +vga_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *argb, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y) +{ + + return (EOPNOTSUPP); +} + static void vga_initialize_graphics(struct vt_device *vd) { struct vga_softc *sc = vd->vd_softc; /* Clock select. */ REG_WRITE1(sc, VGA_GEN_MISC_OUTPUT_W, VGA_GEN_MO_VSP | VGA_GEN_MO_HSP | VGA_GEN_MO_PB | VGA_GEN_MO_ER | VGA_GEN_MO_IOA); /* Set sequencer clocking and memory mode. */ REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_CLOCKING_MODE); REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_CM_89); REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MEMORY_MODE); REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_MM_OE | VGA_SEQ_MM_EM); /* Set the graphics controller in graphics mode. */ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MISCELLANEOUS); REG_WRITE1(sc, VGA_GC_DATA, 0x04 + VGA_GC_MISC_GA); /* Program the CRT controller. */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_HORIZ_TOTAL); REG_WRITE1(sc, VGA_CRTC_DATA, 0x5f); /* 760 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_HORIZ_DISP_END); REG_WRITE1(sc, VGA_CRTC_DATA, 0x4f); /* 640 - 8 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_START_HORIZ_BLANK); REG_WRITE1(sc, VGA_CRTC_DATA, 0x50); /* 640 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_END_HORIZ_BLANK); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_EHB_CR + 2); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_START_HORIZ_RETRACE); REG_WRITE1(sc, VGA_CRTC_DATA, 0x54); /* 672 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_END_HORIZ_RETRACE); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_EHR_EHB + 0); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_VERT_TOTAL); REG_WRITE1(sc, VGA_CRTC_DATA, 0x0b); /* 523 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_OVERFLOW); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_OF_VT9 | VGA_CRTC_OF_LC8 | VGA_CRTC_OF_VBS8 | VGA_CRTC_OF_VRS8 | VGA_CRTC_OF_VDE8); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_MAX_SCAN_LINE); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_MSL_LC9); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_VERT_RETRACE_START); REG_WRITE1(sc, VGA_CRTC_DATA, 0xea); /* 480 + 10 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_VERT_RETRACE_END); REG_WRITE1(sc, VGA_CRTC_DATA, 0x0c); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_VERT_DISPLAY_END); REG_WRITE1(sc, VGA_CRTC_DATA, 0xdf); /* 480 - 1*/ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_OFFSET); REG_WRITE1(sc, VGA_CRTC_DATA, 0x28); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_START_VERT_BLANK); REG_WRITE1(sc, VGA_CRTC_DATA, 0xe7); /* 480 + 7 */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_END_VERT_BLANK); REG_WRITE1(sc, VGA_CRTC_DATA, 0x04); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_MODE_CONTROL); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_MC_WB | VGA_CRTC_MC_AW | VGA_CRTC_MC_SRS | VGA_CRTC_MC_CMS); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_LINE_COMPARE); REG_WRITE1(sc, VGA_CRTC_DATA, 0xff); /* 480 + 31 */ REG_WRITE1(sc, VGA_GEN_FEATURE_CTRL_W, 0); REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_MAP_MASK); REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_MM_EM3 | VGA_SEQ_MM_EM2 | VGA_SEQ_MM_EM1 | VGA_SEQ_MM_EM0); REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_CHAR_MAP_SELECT); REG_WRITE1(sc, VGA_SEQ_DATA, 0); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_SET_RESET); REG_WRITE1(sc, VGA_GC_DATA, 0); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_ENABLE_SET_RESET); REG_WRITE1(sc, VGA_GC_DATA, 0x0f); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_COLOR_COMPARE); REG_WRITE1(sc, VGA_GC_DATA, 0); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_DATA_ROTATE); REG_WRITE1(sc, VGA_GC_DATA, 0); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_READ_MAP_SELECT); REG_WRITE1(sc, VGA_GC_DATA, 0); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE); REG_WRITE1(sc, VGA_GC_DATA, 0); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_COLOR_DONT_CARE); REG_WRITE1(sc, VGA_GC_DATA, 0x0f); REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_BIT_MASK); REG_WRITE1(sc, VGA_GC_DATA, 0xff); } static int vga_initialize(struct vt_device *vd, int textmode) { struct vga_softc *sc = vd->vd_softc; uint8_t x; int timeout; /* Make sure the VGA adapter is not in monochrome emulation mode. */ x = REG_READ1(sc, VGA_GEN_MISC_OUTPUT_R); REG_WRITE1(sc, VGA_GEN_MISC_OUTPUT_W, x | VGA_GEN_MO_IOA); /* Unprotect CRTC registers 0-7. */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_VERT_RETRACE_END); x = REG_READ1(sc, VGA_CRTC_DATA); REG_WRITE1(sc, VGA_CRTC_DATA, x & ~VGA_CRTC_VRE_PR); /* * Wait for the vertical retrace. * NOTE: this code reads the VGA_GEN_INPUT_STAT_1 register, which has * the side-effect of clearing the internal flip-flip of the attribute * controller's write register. This means that because this code is * here, we know for sure that the first write to the attribute * controller will be a write to the address register. Removing this * code therefore also removes that guarantee and appropriate measures * need to be taken. */ timeout = 10000; do { DELAY(10); x = REG_READ1(sc, VGA_GEN_INPUT_STAT_1); x &= VGA_GEN_IS1_VR | VGA_GEN_IS1_DE; } while (x != (VGA_GEN_IS1_VR | VGA_GEN_IS1_DE) && --timeout != 0); if (timeout == 0) { printf("Timeout initializing vt_vga\n"); return (ENXIO); } /* Now, disable the sync. signals. */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_MODE_CONTROL); x = REG_READ1(sc, VGA_CRTC_DATA); REG_WRITE1(sc, VGA_CRTC_DATA, x & ~VGA_CRTC_MC_HR); /* Asynchronous sequencer reset. */ REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_RESET); REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_RST_SR); if (!textmode) vga_initialize_graphics(vd); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_PRESET_ROW_SCAN); REG_WRITE1(sc, VGA_CRTC_DATA, 0); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_CURSOR_START); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_CS_COO); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_CURSOR_END); REG_WRITE1(sc, VGA_CRTC_DATA, 0); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_START_ADDR_HIGH); REG_WRITE1(sc, VGA_CRTC_DATA, 0); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_START_ADDR_LOW); REG_WRITE1(sc, VGA_CRTC_DATA, 0); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_CURSOR_LOC_HIGH); REG_WRITE1(sc, VGA_CRTC_DATA, 0); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_CURSOR_LOC_LOW); REG_WRITE1(sc, VGA_CRTC_DATA, 0x59); REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_UNDERLINE_LOC); REG_WRITE1(sc, VGA_CRTC_DATA, VGA_CRTC_UL_UL); if (textmode) { /* Set the attribute controller to blink disable. */ REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_MODE_CONTROL); REG_WRITE1(sc, VGA_AC_WRITE, 0); } else { /* Set the attribute controller in graphics mode. */ REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_MODE_CONTROL); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_MC_GA); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_HORIZ_PIXEL_PANNING); REG_WRITE1(sc, VGA_AC_WRITE, 0); } REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(0)); REG_WRITE1(sc, VGA_AC_WRITE, 0); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(1)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(2)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_G); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(3)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_G | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(4)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_R); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(5)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_R | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(6)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SG | VGA_AC_PAL_R); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(7)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_R | VGA_AC_PAL_G | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(8)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(9)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(10)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_G); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(11)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_G | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(12)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_R); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(13)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_R | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(14)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_R | VGA_AC_PAL_G); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PALETTE(15)); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_PAL_SR | VGA_AC_PAL_SG | VGA_AC_PAL_SB | VGA_AC_PAL_R | VGA_AC_PAL_G | VGA_AC_PAL_B); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_OVERSCAN_COLOR); REG_WRITE1(sc, VGA_AC_WRITE, 0); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_COLOR_PLANE_ENABLE); REG_WRITE1(sc, VGA_AC_WRITE, 0x0f); REG_WRITE1(sc, VGA_AC_WRITE, VGA_AC_COLOR_SELECT); REG_WRITE1(sc, VGA_AC_WRITE, 0); if (!textmode) { u_int ofs; /* * Done. Clear the frame buffer. All bit planes are * enabled, so a single-paged loop should clear all * planes. */ for (ofs = 0; ofs < VT_VGA_MEMSIZE; ofs++) { MEM_WRITE1(sc, ofs, 0); } } /* Re-enable the sequencer. */ REG_WRITE1(sc, VGA_SEQ_ADDRESS, VGA_SEQ_RESET); REG_WRITE1(sc, VGA_SEQ_DATA, VGA_SEQ_RST_SR | VGA_SEQ_RST_NAR); /* Re-enable the sync signals. */ REG_WRITE1(sc, VGA_CRTC_ADDRESS, VGA_CRTC_MODE_CONTROL); x = REG_READ1(sc, VGA_CRTC_DATA); REG_WRITE1(sc, VGA_CRTC_DATA, x | VGA_CRTC_MC_HR); if (!textmode) { /* Switch to write mode 3, because we'll mainly do bitblt. */ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_MODE); REG_WRITE1(sc, VGA_GC_DATA, 3); sc->vga_wmode = 3; /* * In Write Mode 3, Enable Set/Reset is ignored, but we * use Write Mode 0 to write a group of 8 pixels using * 3 or more colors. In this case, we want to disable * Set/Reset: set Enable Set/Reset to 0. */ REG_WRITE1(sc, VGA_GC_ADDRESS, VGA_GC_ENABLE_SET_RESET); REG_WRITE1(sc, VGA_GC_DATA, 0x00); /* * Clear the colors we think are loaded into Set/Reset or * the latches. */ sc->vga_curfg = sc->vga_curbg = 0xff; } return (0); } static bool vga_acpi_disabled(void) { #if defined(__amd64__) || defined(__i386__) uint16_t flags; int ignore; /* * Ignore the flag on real hardware: there's a lot of buggy firmware * that will wrongly set it. */ ignore = (vm_guest == VM_GUEST_NO); TUNABLE_INT_FETCH("hw.vga.acpi_ignore_no_vga", &ignore); if (ignore || !acpi_get_fadt_bootflags(&flags)) return (false); return ((flags & ACPI_FADT_NO_VGA) != 0); #else return (false); #endif } static int vga_probe(struct vt_device *vd) { return (vga_acpi_disabled() ? CN_DEAD : CN_INTERNAL); } static int vga_init(struct vt_device *vd) { struct vga_softc *sc; int textmode; if (vd->vd_softc == NULL) vd->vd_softc = (void *)&vga_conssoftc; sc = vd->vd_softc; if (vd->vd_flags & VDF_DOWNGRADE && vd->vd_video_dev != NULL) vga_pci_repost(vd->vd_video_dev); #if defined(__amd64__) || defined(__i386__) sc->vga_fb_tag = X86_BUS_SPACE_MEM; sc->vga_reg_tag = X86_BUS_SPACE_IO; #else # error "Architecture not yet supported!" #endif bus_space_map(sc->vga_reg_tag, VGA_REG_BASE, VGA_REG_SIZE, 0, &sc->vga_reg_handle); /* * If "hw.vga.textmode" is not set and we're running on hypervisor, * we use text mode by default, this is because when we're on * hypervisor, vt(4) is usually much slower in graphics mode than * in text mode, especially when we're on Hyper-V. */ textmode = vm_guest != VM_GUEST_NO; TUNABLE_INT_FETCH("hw.vga.textmode", &textmode); if (textmode) { vd->vd_flags |= VDF_TEXTMODE; vd->vd_width = 80; vd->vd_height = 25; bus_space_map(sc->vga_fb_tag, VGA_TXT_BASE, VGA_TXT_SIZE, 0, &sc->vga_fb_handle); } else { vd->vd_width = VT_VGA_WIDTH; vd->vd_height = VT_VGA_HEIGHT; bus_space_map(sc->vga_fb_tag, VGA_MEM_BASE, VGA_MEM_SIZE, 0, &sc->vga_fb_handle); } if (vga_initialize(vd, textmode) != 0) return (CN_DEAD); sc->vga_enabled = true; return (CN_INTERNAL); } static void vga_postswitch(struct vt_device *vd) { /* Reinit VGA mode, to restore view after app which change mode. */ vga_initialize(vd, (vd->vd_flags & VDF_TEXTMODE)); /* Ask vt(9) to update chars on visible area. */ vd->vd_flags |= VDF_INVALID; } /* Dummy NewBus functions to reserve the resources used by the vt_vga driver */ static void vtvga_identify(driver_t *driver, device_t parent) { if (!vga_conssoftc.vga_enabled) return; if (BUS_ADD_CHILD(parent, 0, driver->name, 0) == NULL) panic("Unable to attach vt_vga console"); } static int vtvga_probe(device_t dev) { device_set_desc(dev, "VT VGA driver"); return (BUS_PROBE_NOWILDCARD); } static int vtvga_attach(device_t dev) { struct resource *pseudo_phys_res; int res_id; res_id = 0; pseudo_phys_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &res_id, VGA_MEM_BASE, VGA_MEM_BASE + VGA_MEM_SIZE - 1, VGA_MEM_SIZE, RF_ACTIVE); if (pseudo_phys_res == NULL) panic("Unable to reserve vt_vga memory"); return (0); } /*-------------------- Private Device Attachment Data -----------------------*/ static device_method_t vtvga_methods[] = { /* Device interface */ DEVMETHOD(device_identify, vtvga_identify), DEVMETHOD(device_probe, vtvga_probe), DEVMETHOD(device_attach, vtvga_attach), DEVMETHOD_END }; DEFINE_CLASS_0(vtvga, vtvga_driver, vtvga_methods, 0); DRIVER_MODULE(vtvga, nexus, vtvga_driver, NULL, NULL); diff --git a/sys/dev/vt/vt.h b/sys/dev/vt/vt.h index 56a28c0420c7..8e35a81bc101 100644 --- a/sys/dev/vt/vt.h +++ b/sys/dev/vt/vt.h @@ -1,470 +1,475 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2009, 2013 The FreeBSD Foundation * * This software was developed by Ed Schouten under sponsorship from the * FreeBSD Foundation. * * Portions of this software were developed by Oleksandr Rybalko * under sponsorship from the FreeBSD Foundation. * * 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. */ #ifndef _DEV_VT_VT_H_ #define _DEV_VT_VT_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "opt_syscons.h" #include "opt_splash.h" #ifndef VT_MAXWINDOWS #ifdef MAXCONS #define VT_MAXWINDOWS MAXCONS #else #define VT_MAXWINDOWS 12 #endif #endif #ifndef VT_ALT_TO_ESC_HACK #define VT_ALT_TO_ESC_HACK 1 #endif #define VT_CONSWINDOW 0 #if defined(SC_TWOBUTTON_MOUSE) || defined(VT_TWOBUTTON_MOUSE) #define VT_MOUSE_PASTEBUTTON MOUSE_BUTTON3DOWN /* right button */ #define VT_MOUSE_EXTENDBUTTON MOUSE_BUTTON2DOWN /* not really used */ #else #define VT_MOUSE_PASTEBUTTON MOUSE_BUTTON2DOWN /* middle button */ #define VT_MOUSE_EXTENDBUTTON MOUSE_BUTTON3DOWN /* right button */ #endif /* defined(SC_TWOBUTTON_MOUSE) || defined(VT_TWOBUTTON_MOUSE) */ #define SC_DRIVER_NAME "vt" #ifdef VT_DEBUG #define DPRINTF(_l, ...) if (vt_debug > (_l)) printf( __VA_ARGS__ ) #define VT_CONSOLECTL_DEBUG #define VT_SYSMOUSE_DEBUG #else #define DPRINTF(_l, ...) do {} while (0) #endif #define ISSIGVALID(sig) ((sig) > 0 && (sig) < NSIG) #define VT_SYSCTL_INT(_name, _default, _descr) \ int vt_##_name = (_default); \ SYSCTL_INT(_kern_vt, OID_AUTO, _name, CTLFLAG_RWTUN, &vt_##_name, 0, _descr) struct vt_driver; int vt_allocate(const struct vt_driver *, void *); int vt_deallocate(const struct vt_driver *, void *); typedef unsigned int vt_axis_t; /* * List of locks * (d) locked by vd_lock * (b) locked by vb_lock * (G) locked by Giant * (u) unlocked, locked by higher levels * (c) const until freeing * (?) yet to be determined */ /* * Per-device datastructure. */ #ifndef SC_NO_CUTPASTE struct vt_mouse_cursor; #endif struct vt_pastebuf { term_char_t *vpb_buf; /* Copy-paste buffer. */ unsigned int vpb_bufsz; /* Buffer size. */ unsigned int vpb_len; /* Length of a last selection. */ }; struct vt_device { struct vt_window *vd_windows[VT_MAXWINDOWS]; /* (c) Windows. */ struct vt_window *vd_curwindow; /* (d) Current window. */ struct vt_window *vd_savedwindow;/* (?) Saved for suspend. */ struct vt_window *vd_grabwindow; /* (?) Saved before cngrab. */ struct vt_pastebuf vd_pastebuf; /* (?) Copy/paste buf. */ const struct vt_driver *vd_driver; /* (c) Graphics driver. */ void *vd_softc; /* (u) Driver data. */ const struct vt_driver *vd_prev_driver;/* (?) Previous driver. */ void *vd_prev_softc; /* (?) Previous driver data. */ device_t vd_video_dev; /* (?) Video adapter. */ #ifndef SC_NO_CUTPASTE struct vt_mouse_cursor *vd_mcursor; /* (?) Cursor bitmap. */ term_color_t vd_mcursor_fg; /* (?) Cursor fg color. */ term_color_t vd_mcursor_bg; /* (?) Cursor bg color. */ vt_axis_t vd_mx_drawn; /* (?) Mouse X and Y */ vt_axis_t vd_my_drawn; /* as of last redraw. */ int vd_mshown; /* (?) Mouse shown during */ #endif /* last redrawn. */ uint16_t vd_mx; /* (?) Current mouse X. */ uint16_t vd_my; /* (?) current mouse Y. */ uint32_t vd_mstate; /* (?) Mouse state. */ vt_axis_t vd_width; /* (?) Screen width. */ vt_axis_t vd_height; /* (?) Screen height. */ size_t vd_transpose; /* (?) Screen offset in FB */ struct mtx vd_lock; /* Per-device lock. */ struct cv vd_winswitch; /* (d) Window switch notify. */ struct callout vd_timer; /* (d) Display timer. */ volatile unsigned int vd_timer_armed;/* (?) Display timer started.*/ int vd_flags; /* (d) Device flags. */ #define VDF_TEXTMODE 0x01 /* Do text mode rendering. */ #define VDF_SPLASH 0x02 /* Splash screen active. */ #define VDF_ASYNC 0x04 /* vt_timer() running. */ #define VDF_INVALID 0x08 /* Entire screen should be re-rendered. */ #define VDF_DEAD 0x10 /* Early probing found nothing. */ #define VDF_INITIALIZED 0x20 /* vtterm_cnprobe already done. */ #define VDF_MOUSECURSOR 0x40 /* Mouse cursor visible. */ #define VDF_QUIET_BELL 0x80 /* Disable bell. */ #define VDF_SUSPENDED 0x100 /* Device has been suspended. */ #define VDF_DOWNGRADE 0x8000 /* The driver is being downgraded. */ struct keyboard *vd_keyboard; /* (G) Keyboard. */ unsigned int vd_kbstate; /* (?) Device unit. */ unsigned int vd_unit; /* (c) Device unit. */ int vd_altbrk; /* (?) Alt break seq. state */ term_char_t *vd_drawn; /* (?) Most recent char drawn. */ term_color_t *vd_drawnfg; /* (?) Most recent fg color drawn. */ term_color_t *vd_drawnbg; /* (?) Most recent bg color drawn. */ struct mtx vd_flush_lock; /* (?) vt_flush() lock. */ bool *vd_pos_to_flush;/* (?) Positions to flush. */ }; #define VD_PASTEBUF(vd) ((vd)->vd_pastebuf.vpb_buf) #define VD_PASTEBUFSZ(vd) ((vd)->vd_pastebuf.vpb_bufsz) #define VD_PASTEBUFLEN(vd) ((vd)->vd_pastebuf.vpb_len) #define VT_LOCK(vd) mtx_lock(&(vd)->vd_lock) #define VT_UNLOCK(vd) mtx_unlock(&(vd)->vd_lock) #define VT_LOCK_ASSERT(vd, what) mtx_assert(&(vd)->vd_lock, what) #define VT_FLUSH_LOCK(vd) \ if ((vd)->vd_driver->vd_bitblt_after_vtbuf_unlock) \ mtx_lock(&(vd)->vd_flush_lock) #define VT_FLUSH_UNLOCK(vd) \ if ((vd)->vd_driver->vd_bitblt_after_vtbuf_unlock) \ mtx_unlock(&(vd)->vd_flush_lock) void vt_resume(struct vt_device *vd); void vt_resume_flush_timer(struct vt_window *vw, int ms); void vt_suspend(struct vt_device *vd); /* * Per-window terminal screen buffer. * * Because redrawing is performed asynchronously, the buffer keeps track * of a rectangle that needs to be redrawn (vb_dirtyrect). Because this * approach seemed to cause suboptimal performance (when the top left * and the bottom right of the screen are modified), it also uses a set * of bitmasks to keep track of the rows and columns (mod 64) that have * been modified. */ struct vt_buf { struct mtx vb_lock; /* Buffer lock. */ struct terminal *vb_terminal; term_pos_t vb_scr_size; /* (b) Screen dimensions. */ int vb_flags; /* (b) Flags. */ #define VBF_CURSOR 0x1 /* Cursor visible. */ #define VBF_STATIC 0x2 /* Buffer is statically allocated. */ #define VBF_MTX_INIT 0x4 /* Mutex initialized. */ #define VBF_SCROLL 0x8 /* scroll locked mode. */ #define VBF_HISTORY_FULL 0x10 /* All rows filled. */ unsigned int vb_history_size; unsigned int vb_roffset; /* (b) History rows offset. */ unsigned int vb_curroffset; /* (b) Saved rows offset. */ term_pos_t vb_cursor; /* (u) Cursor position. */ term_pos_t vb_mark_start; /* (b) Copy region start. */ term_pos_t vb_mark_end; /* (b) Copy region end. */ int vb_mark_last; /* Last mouse event. */ term_rect_t vb_dirtyrect; /* (b) Dirty rectangle. */ term_char_t *vb_buffer; /* (u) Data buffer. */ term_char_t **vb_rows; /* (u) Array of rows */ }; #ifdef SC_HISTORY_SIZE #define VBF_DEFAULT_HISTORY_SIZE SC_HISTORY_SIZE #else #define VBF_DEFAULT_HISTORY_SIZE 500 #endif void vtbuf_lock(struct vt_buf *); void vtbuf_unlock(struct vt_buf *); void vtbuf_copy(struct vt_buf *, const term_rect_t *, const term_pos_t *); void vtbuf_fill(struct vt_buf *, const term_rect_t *, term_char_t); void vtbuf_init_early(struct vt_buf *); void vtbuf_init(struct vt_buf *, const term_pos_t *); void vtbuf_grow(struct vt_buf *, const term_pos_t *, unsigned int); void vtbuf_putchar(struct vt_buf *, const term_pos_t *, term_char_t); void vtbuf_cursor_position(struct vt_buf *, const term_pos_t *); void vtbuf_scroll_mode(struct vt_buf *vb, int yes); void vtbuf_dirty(struct vt_buf *vb, const term_rect_t *area); void vtbuf_undirty(struct vt_buf *, term_rect_t *); void vtbuf_sethistory_size(struct vt_buf *, unsigned int); void vtbuf_clearhistory(struct vt_buf *); int vtbuf_iscursor(const struct vt_buf *vb, int row, int col); void vtbuf_cursor_visibility(struct vt_buf *, int); #ifndef SC_NO_CUTPASTE int vtbuf_set_mark(struct vt_buf *vb, int type, int col, int row); int vtbuf_get_marked_len(struct vt_buf *vb); void vtbuf_extract_marked(struct vt_buf *vb, term_char_t *buf, int sz, int mark); #endif #define VTB_MARK_NONE 0 #define VTB_MARK_END 1 #define VTB_MARK_START 2 #define VTB_MARK_WORD 3 #define VTB_MARK_ROW 4 #define VTB_MARK_EXTEND 5 #define VTB_MARK_MOVE 6 #define VTBUF_SLCK_ENABLE(vb) vtbuf_scroll_mode((vb), 1) #define VTBUF_SLCK_DISABLE(vb) vtbuf_scroll_mode((vb), 0) #define VTBUF_MAX_HEIGHT(vb) \ ((vb)->vb_history_size) #define VTBUF_GET_ROW(vb, r) \ ((vb)->vb_rows[((vb)->vb_roffset + (r)) % VTBUF_MAX_HEIGHT(vb)]) #define VTBUF_GET_FIELD(vb, r, c) \ ((vb)->vb_rows[((vb)->vb_roffset + (r)) % VTBUF_MAX_HEIGHT(vb)][(c)]) #define VTBUF_FIELD(vb, r, c) \ ((vb)->vb_rows[((vb)->vb_curroffset + (r)) % VTBUF_MAX_HEIGHT(vb)][(c)]) #define VTBUF_ISCURSOR(vb, r, c) \ vtbuf_iscursor((vb), (r), (c)) #define VTBUF_DIRTYROW(mask, row) \ ((mask)->vbm_row & ((uint64_t)1 << ((row) % 64))) #define VTBUF_DIRTYCOL(mask, col) \ ((mask)->vbm_col & ((uint64_t)1 << ((col) % 64))) #define VTBUF_SPACE_CHAR(attr) (' ' | (attr)) #define VHS_SET 0 #define VHS_CUR 1 #define VHS_END 2 int vthistory_seek(struct vt_buf *, int offset, int whence); void vthistory_addlines(struct vt_buf *vb, int offset); void vthistory_getpos(const struct vt_buf *, unsigned int *offset); /* * Per-window datastructure. */ struct vt_window { struct vt_device *vw_device; /* (c) Device. */ struct terminal *vw_terminal; /* (c) Terminal. */ struct vt_buf vw_buf; /* (u) Screen buffer. */ struct vt_font *vw_font; /* (d) Graphical font. */ term_rect_t vw_draw_area; /* (?) Drawable area. */ unsigned int vw_number; /* (c) Window number. */ int vw_kbdmode; /* (?) Keyboard mode. */ int vw_prev_kbdmode;/* (?) Previous mode. */ int vw_kbdstate; /* (?) Keyboard state. */ int vw_grabbed; /* (?) Grab count. */ char *vw_kbdsq; /* Escape sequence queue*/ unsigned int vw_flags; /* (d) Per-window flags. */ int vw_mouse_level;/* Mouse op mode. */ #define VWF_BUSY 0x1 /* Busy reconfiguring device. */ #define VWF_OPENED 0x2 /* TTY in use. */ #define VWF_SCROLL 0x4 /* Keys influence scrollback. */ #define VWF_CONSOLE 0x8 /* Kernel message console window. */ #define VWF_VTYLOCK 0x10 /* Prevent window switch. */ #define VWF_MOUSE_HIDE 0x20 /* Disable mouse events processing. */ #define VWF_READY 0x40 /* Window fully initialized. */ #define VWF_GRAPHICS 0x80 /* Window in graphics mode (KDSETMODE). */ #define VWF_SWWAIT_REL 0x10000 /* Program wait for VT acquire is done. */ #define VWF_SWWAIT_ACQ 0x20000 /* Program wait for VT release is done. */ pid_t vw_pid; /* Terminal holding process */ struct proc *vw_proc; struct vt_mode vw_smode; /* switch mode */ struct timeout_task vw_timeout_task_dead; struct vt_window *vw_switch_to; int vw_bell_pitch; /* (?) Bell pitch */ sbintime_t vw_bell_duration; /* (?) Bell duration */ }; #define VT_AUTO 0 /* switching is automatic */ #define VT_PROCESS 1 /* switching controlled by prog */ #define VT_KERNEL 255 /* switching controlled in kernel */ #define IS_VT_PROC_MODE(vw) ((vw)->vw_smode.mode == VT_PROCESS) /* * Per-device driver routines. */ typedef int vd_init_t(struct vt_device *vd); typedef int vd_probe_t(struct vt_device *vd); typedef void vd_fini_t(struct vt_device *vd, void *softc); typedef void vd_postswitch_t(struct vt_device *vd); typedef void vd_blank_t(struct vt_device *vd, term_color_t color); typedef void vd_bitblt_text_t(struct vt_device *vd, const struct vt_window *vw, const term_rect_t *area); typedef void vd_invalidate_text_t(struct vt_device *vd, const term_rect_t *area); typedef void vd_bitblt_bmp_t(struct vt_device *vd, const struct vt_window *vw, const uint8_t *pattern, const uint8_t *mask, unsigned int width, unsigned int height, unsigned int x, unsigned int y, term_color_t fg, term_color_t bg); +typedef int vd_bitblt_argb_t(struct vt_device *vd, const struct vt_window *vw, + const uint8_t *argb, + unsigned int width, unsigned int height, + unsigned int x, unsigned int y); typedef int vd_fb_ioctl_t(struct vt_device *, u_long, caddr_t, struct thread *); typedef int vd_fb_mmap_t(struct vt_device *, vm_ooffset_t, vm_paddr_t *, int, vm_memattr_t *); typedef void vd_drawrect_t(struct vt_device *, int, int, int, int, int, term_color_t); typedef void vd_setpixel_t(struct vt_device *, int, int, term_color_t); typedef void vd_suspend_t(struct vt_device *); typedef void vd_resume_t(struct vt_device *); struct vt_driver { char vd_name[16]; /* Console attachment. */ vd_probe_t *vd_probe; vd_init_t *vd_init; vd_fini_t *vd_fini; /* Drawing. */ vd_blank_t *vd_blank; vd_drawrect_t *vd_drawrect; vd_setpixel_t *vd_setpixel; vd_bitblt_text_t *vd_bitblt_text; vd_invalidate_text_t *vd_invalidate_text; vd_bitblt_bmp_t *vd_bitblt_bmp; + vd_bitblt_argb_t *vd_bitblt_argb; /* Framebuffer ioctls, if present. */ vd_fb_ioctl_t *vd_fb_ioctl; /* Framebuffer mmap, if present. */ vd_fb_mmap_t *vd_fb_mmap; /* Update display setting on vt switch. */ vd_postswitch_t *vd_postswitch; /* Suspend/resume handlers. */ vd_suspend_t *vd_suspend; vd_resume_t *vd_resume; /* Priority to know which one can override */ int vd_priority; #define VD_PRIORITY_DUMB 10 #define VD_PRIORITY_GENERIC 100 #define VD_PRIORITY_SPECIFIC 1000 /* * Should vd_bitblt_text() be called after unlocking vtbuf? If true, * characters are copied before vd_bitblt_bmp() is called. * * This is only valid when the default bitblt_text callback is used. */ bool vd_bitblt_after_vtbuf_unlock; }; /* * Console device madness. * * Utility macro to make early vt(4) instances work. */ extern struct vt_device vt_consdev; void vt_upgrade(struct vt_device *vd); #define PIXEL_WIDTH(w) ((w) / 8) #define PIXEL_HEIGHT(h) ((h) / 16) #ifndef VT_FB_MAX_WIDTH #define VT_FB_MAX_WIDTH 4096 #endif #ifndef VT_FB_MAX_HEIGHT #define VT_FB_MAX_HEIGHT 2400 #endif /* name argument is not used yet. */ #define VT_DRIVER_DECLARE(name, drv) DATA_SET(vt_drv_set, drv) #ifndef SC_NO_CUTPASTE struct vt_mouse_cursor { uint8_t map[64 * 64 / 8]; uint8_t mask[64 * 64 / 8]; uint8_t width; uint8_t height; }; #endif const uint8_t *vtfont_lookup(const struct vt_font *vf, term_char_t c); struct vt_font *vtfont_ref(struct vt_font *vf); void vtfont_unref(struct vt_font *vf); int vtfont_load(vfnt_t *f, struct vt_font **ret); /* Sysmouse. */ void sysmouse_process_event(mouse_info_t *mi); #ifndef SC_NO_CUTPASTE void vt_mouse_event(int type, int x, int y, int event, int cnt, int mlevel); void vt_mouse_state(int show); #endif #define VT_MOUSE_SHOW 1 #define VT_MOUSE_HIDE 0 /* Utilities. */ void vt_compute_drawable_area(struct vt_window *); void vt_determine_colors(term_char_t c, int cursor, term_color_t *fg, term_color_t *bg); int vt_is_cursor_in_area(const struct vt_device *vd, const term_rect_t *area); void vt_termsize(struct vt_device *, struct vt_font *, term_pos_t *); void vt_winsize(struct vt_device *, struct vt_font *, struct winsize *); /* Logos-on-boot. */ #define VT_LOGOS_DRAW_BEASTIE 0 #define VT_LOGOS_DRAW_ALT_BEASTIE 1 #define VT_LOGOS_DRAW_ORB 2 extern int vt_draw_logo_cpus; extern int vt_splash_cpu; extern int vt_splash_ncpu; extern int vt_splash_cpu_style; extern int vt_splash_cpu_duration; extern const unsigned int vt_logo_sprite_height; extern const unsigned int vt_logo_sprite_width; void vtterm_draw_cpu_logos(struct vt_device *); #endif /* !_DEV_VT_VT_H_ */