127cf7d04SAleksandr Rybalko /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3718cf2ccSPedro F. Giffuni * 427cf7d04SAleksandr Rybalko * Copyright (c) 2013 The FreeBSD Foundation 527cf7d04SAleksandr Rybalko * 627cf7d04SAleksandr Rybalko * This software was developed by Aleksandr Rybalko under sponsorship from the 727cf7d04SAleksandr Rybalko * FreeBSD Foundation. 827cf7d04SAleksandr Rybalko * 927cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 1027cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1127cf7d04SAleksandr Rybalko * are met: 1227cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1327cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1427cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1527cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1627cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 1727cf7d04SAleksandr Rybalko * 1827cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1927cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2027cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2127cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2227cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2327cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2427cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2527cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2627cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2727cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2827cf7d04SAleksandr Rybalko * SUCH DAMAGE. 2927cf7d04SAleksandr Rybalko */ 3027cf7d04SAleksandr Rybalko 3127cf7d04SAleksandr Rybalko #include <sys/param.h> 3227cf7d04SAleksandr Rybalko #include <sys/systm.h> 3327cf7d04SAleksandr Rybalko #include <sys/malloc.h> 3427cf7d04SAleksandr Rybalko #include <sys/queue.h> 3527cf7d04SAleksandr Rybalko #include <sys/fbio.h> 36df1bc27aSToomas Soome #include <sys/kernel.h> 3727cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 3827cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h> 3927cf7d04SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h> 4027cf7d04SAleksandr Rybalko 41a985ae9bSHans Petter Selasky #include <vm/vm.h> 42a985ae9bSHans Petter Selasky #include <vm/pmap.h> 43a985ae9bSHans Petter Selasky 4427cf7d04SAleksandr Rybalko static struct vt_driver vt_fb_driver = { 454dde1640SAleksandr Rybalko .vd_name = "fb", 4627cf7d04SAleksandr Rybalko .vd_init = vt_fb_init, 4776e2f976SJean-Sébastien Pédron .vd_fini = vt_fb_fini, 4827cf7d04SAleksandr Rybalko .vd_blank = vt_fb_blank, 49c285e4a5SJean-Sébastien Pédron .vd_bitblt_text = vt_fb_bitblt_text, 50ee97b233SColin Percival .vd_invalidate_text = vt_fb_invalidate_text, 51631bb572SJean-Sébastien Pédron .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 52*b93028d8SEmmanuel Vadot .vd_bitblt_argb = vt_fb_bitblt_argb, 539e497e7bSAleksandr Rybalko .vd_drawrect = vt_fb_drawrect, 549e497e7bSAleksandr Rybalko .vd_setpixel = vt_fb_setpixel, 5527cf7d04SAleksandr Rybalko .vd_postswitch = vt_fb_postswitch, 5627cf7d04SAleksandr Rybalko .vd_priority = VD_PRIORITY_GENERIC+10, 577a1a32c4SAleksandr Rybalko .vd_fb_ioctl = vt_fb_ioctl, 587a1a32c4SAleksandr Rybalko .vd_fb_mmap = vt_fb_mmap, 596dfa4578SAndriy Gapon .vd_suspend = vt_fb_suspend, 606dfa4578SAndriy Gapon .vd_resume = vt_fb_resume, 6127cf7d04SAleksandr Rybalko }; 6227cf7d04SAleksandr Rybalko 634dde1640SAleksandr Rybalko VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 644dde1640SAleksandr Rybalko 659ed297c8SNathan Whitehorn static void 669ed297c8SNathan Whitehorn vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 679ed297c8SNathan Whitehorn { 689ed297c8SNathan Whitehorn 699ed297c8SNathan Whitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 709ed297c8SNathan Whitehorn *(uint8_t *)(sc->fb_vbase + o) = v; 719ed297c8SNathan Whitehorn } 729ed297c8SNathan Whitehorn 739ed297c8SNathan Whitehorn static void 749ed297c8SNathan Whitehorn vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 759ed297c8SNathan Whitehorn { 769ed297c8SNathan Whitehorn 779ed297c8SNathan Whitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 789ed297c8SNathan Whitehorn *(uint16_t *)(sc->fb_vbase + o) = v; 799ed297c8SNathan Whitehorn } 809ed297c8SNathan Whitehorn 819ed297c8SNathan Whitehorn static void 829ed297c8SNathan Whitehorn vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 839ed297c8SNathan Whitehorn { 849ed297c8SNathan Whitehorn 859ed297c8SNathan Whitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 869ed297c8SNathan Whitehorn *(uint32_t *)(sc->fb_vbase + o) = v; 879ed297c8SNathan Whitehorn } 889ed297c8SNathan Whitehorn 8960d7ea3dSNathan Whitehorn int 907a1a32c4SAleksandr Rybalko vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 917a1a32c4SAleksandr Rybalko { 927a1a32c4SAleksandr Rybalko struct fb_info *info; 9360d7ea3dSNathan Whitehorn int error = 0; 947a1a32c4SAleksandr Rybalko 957a1a32c4SAleksandr Rybalko info = vd->vd_softc; 967a1a32c4SAleksandr Rybalko 9760d7ea3dSNathan Whitehorn switch (cmd) { 9860d7ea3dSNathan Whitehorn case FBIOGTYPE: 9960d7ea3dSNathan Whitehorn bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 10060d7ea3dSNathan Whitehorn break; 1017a1a32c4SAleksandr Rybalko 10260d7ea3dSNathan Whitehorn case FBIO_GETWINORG: /* get frame buffer window origin */ 10360d7ea3dSNathan Whitehorn *(u_int *)data = 0; 10460d7ea3dSNathan Whitehorn break; 10560d7ea3dSNathan Whitehorn 10660d7ea3dSNathan Whitehorn case FBIO_GETDISPSTART: /* get display start address */ 10760d7ea3dSNathan Whitehorn ((video_display_start_t *)data)->x = 0; 10860d7ea3dSNathan Whitehorn ((video_display_start_t *)data)->y = 0; 10960d7ea3dSNathan Whitehorn break; 11060d7ea3dSNathan Whitehorn 11160d7ea3dSNathan Whitehorn case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 11260d7ea3dSNathan Whitehorn *(u_int *)data = info->fb_stride; 11360d7ea3dSNathan Whitehorn break; 11460d7ea3dSNathan Whitehorn 11560d7ea3dSNathan Whitehorn case FBIO_BLANK: /* blank display */ 11660d7ea3dSNathan Whitehorn if (vd->vd_driver->vd_blank == NULL) 11760d7ea3dSNathan Whitehorn return (ENODEV); 11860d7ea3dSNathan Whitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 11960d7ea3dSNathan Whitehorn break; 12060d7ea3dSNathan Whitehorn 121b9f3b63aSLeandro Lupori case FBIO_GETRGBOFFS: /* get RGB offsets */ 122b9f3b63aSLeandro Lupori if (info->fb_rgboffs.red == 0 && info->fb_rgboffs.green == 0 && 123b9f3b63aSLeandro Lupori info->fb_rgboffs.blue == 0) 124b9f3b63aSLeandro Lupori return (ENOTTY); 125b9f3b63aSLeandro Lupori memcpy((struct fb_rgboffs *)data, &info->fb_rgboffs, 126b9f3b63aSLeandro Lupori sizeof(struct fb_rgboffs)); 127b9f3b63aSLeandro Lupori break; 128b9f3b63aSLeandro Lupori 12960d7ea3dSNathan Whitehorn default: 13060d7ea3dSNathan Whitehorn error = ENOIOCTL; 13160d7ea3dSNathan Whitehorn break; 1327a1a32c4SAleksandr Rybalko } 1337a1a32c4SAleksandr Rybalko 13460d7ea3dSNathan Whitehorn return (error); 13560d7ea3dSNathan Whitehorn } 13660d7ea3dSNathan Whitehorn 13760d7ea3dSNathan Whitehorn int 1385beb07abSAleksandr Rybalko vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 1395beb07abSAleksandr Rybalko int prot, vm_memattr_t *memattr) 1407a1a32c4SAleksandr Rybalko { 1417a1a32c4SAleksandr Rybalko struct fb_info *info; 1427a1a32c4SAleksandr Rybalko 1437a1a32c4SAleksandr Rybalko info = vd->vd_softc; 1447a1a32c4SAleksandr Rybalko 14560d7ea3dSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOMMAP) 14660d7ea3dSNathan Whitehorn return (ENODEV); 1477a1a32c4SAleksandr Rybalko 148f9cc8410SEric van Gyzen if (offset < info->fb_size) { 149a985ae9bSHans Petter Selasky if (info->fb_pbase == 0) { 150a985ae9bSHans Petter Selasky *paddr = vtophys((uint8_t *)info->fb_vbase + offset); 151a985ae9bSHans Petter Selasky } else { 15260d7ea3dSNathan Whitehorn *paddr = info->fb_pbase + offset; 153823cdec7SJustin Hibbits if (info->fb_flags & FB_FLAG_MEMATTR) 154823cdec7SJustin Hibbits *memattr = info->fb_memattr; 15560d7ea3dSNathan Whitehorn #ifdef VM_MEMATTR_WRITE_COMBINING 156823cdec7SJustin Hibbits else 15760d7ea3dSNathan Whitehorn *memattr = VM_MEMATTR_WRITE_COMBINING; 15860d7ea3dSNathan Whitehorn #endif 159a985ae9bSHans Petter Selasky } 16060d7ea3dSNathan Whitehorn return (0); 16160d7ea3dSNathan Whitehorn } 16260d7ea3dSNathan Whitehorn 16360d7ea3dSNathan Whitehorn return (EINVAL); 1647a1a32c4SAleksandr Rybalko } 1657a1a32c4SAleksandr Rybalko 1661365d077SJean-Sébastien Pédron void 1679e497e7bSAleksandr Rybalko vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 1689e497e7bSAleksandr Rybalko { 1699e497e7bSAleksandr Rybalko struct fb_info *info; 1709e497e7bSAleksandr Rybalko uint32_t c; 1719e497e7bSAleksandr Rybalko u_int o; 1729e497e7bSAleksandr Rybalko 1739e497e7bSAleksandr Rybalko info = vd->vd_softc; 1749e497e7bSAleksandr Rybalko c = info->fb_cmap[color]; 1759e497e7bSAleksandr Rybalko o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 1769e497e7bSAleksandr Rybalko 177f1d2752fSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 178f1d2752fSNathan Whitehorn return; 179f1d2752fSNathan Whitehorn 1809ed297c8SNathan Whitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 1819ed297c8SNathan Whitehorn 1829e497e7bSAleksandr Rybalko switch (FBTYPE_GET_BYTESPP(info)) { 1839e497e7bSAleksandr Rybalko case 1: 1849ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, c); 1859e497e7bSAleksandr Rybalko break; 1869e497e7bSAleksandr Rybalko case 2: 1879ed297c8SNathan Whitehorn vt_fb_mem_wr2(info, o, c); 1889e497e7bSAleksandr Rybalko break; 1899e497e7bSAleksandr Rybalko case 3: 1909ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 1919ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 1929ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 2, c & 0xff); 1939e497e7bSAleksandr Rybalko break; 1949e497e7bSAleksandr Rybalko case 4: 1959ed297c8SNathan Whitehorn vt_fb_mem_wr4(info, o, c); 1969e497e7bSAleksandr Rybalko break; 1979e497e7bSAleksandr Rybalko default: 1989e497e7bSAleksandr Rybalko /* panic? */ 1999e497e7bSAleksandr Rybalko return; 2009e497e7bSAleksandr Rybalko } 2019e497e7bSAleksandr Rybalko } 2029e497e7bSAleksandr Rybalko 2031365d077SJean-Sébastien Pédron void 2049e497e7bSAleksandr Rybalko vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 2059e497e7bSAleksandr Rybalko term_color_t color) 2069e497e7bSAleksandr Rybalko { 2079e497e7bSAleksandr Rybalko int x, y; 2089e497e7bSAleksandr Rybalko 2099e497e7bSAleksandr Rybalko for (y = y1; y <= y2; y++) { 2109e497e7bSAleksandr Rybalko if (fill || (y == y1) || (y == y2)) { 2119e497e7bSAleksandr Rybalko for (x = x1; x <= x2; x++) 2129e497e7bSAleksandr Rybalko vt_fb_setpixel(vd, x, y, color); 2139e497e7bSAleksandr Rybalko } else { 2149e497e7bSAleksandr Rybalko vt_fb_setpixel(vd, x1, y, color); 2159e497e7bSAleksandr Rybalko vt_fb_setpixel(vd, x2, y, color); 2169e497e7bSAleksandr Rybalko } 2179e497e7bSAleksandr Rybalko } 2189e497e7bSAleksandr Rybalko } 2199e497e7bSAleksandr Rybalko 2209e497e7bSAleksandr Rybalko void 22127cf7d04SAleksandr Rybalko vt_fb_blank(struct vt_device *vd, term_color_t color) 22227cf7d04SAleksandr Rybalko { 22327cf7d04SAleksandr Rybalko struct fb_info *info; 22427cf7d04SAleksandr Rybalko uint32_t c; 22560d7ea3dSNathan Whitehorn u_int o, h; 22627cf7d04SAleksandr Rybalko 22727cf7d04SAleksandr Rybalko info = vd->vd_softc; 22827cf7d04SAleksandr Rybalko c = info->fb_cmap[color]; 22927cf7d04SAleksandr Rybalko 230f1d2752fSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 231f1d2752fSNathan Whitehorn return; 232f1d2752fSNathan Whitehorn 2339ed297c8SNathan Whitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 2349ed297c8SNathan Whitehorn 23527cf7d04SAleksandr Rybalko switch (FBTYPE_GET_BYTESPP(info)) { 23627cf7d04SAleksandr Rybalko case 1: 23735e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 23827cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o++) 2399ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 24027cf7d04SAleksandr Rybalko break; 24127cf7d04SAleksandr Rybalko case 2: 24235e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 2432efe3be9SEd Maste for (o = 0; o < info->fb_stride - 1; o += 2) 2449ed297c8SNathan Whitehorn vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 24527cf7d04SAleksandr Rybalko break; 24627cf7d04SAleksandr Rybalko case 3: 24735e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 2482efe3be9SEd Maste for (o = 0; o < info->fb_stride - 2; o += 3) { 2499ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, 25060d7ea3dSNathan Whitehorn (c >> 16) & 0xff); 2519ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 25260d7ea3dSNathan Whitehorn (c >> 8) & 0xff); 2539ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 25460d7ea3dSNathan Whitehorn c & 0xff); 25527cf7d04SAleksandr Rybalko } 25627cf7d04SAleksandr Rybalko break; 25727cf7d04SAleksandr Rybalko case 4: 25835e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 2592efe3be9SEd Maste for (o = 0; o < info->fb_stride - 3; o += 4) 2609ed297c8SNathan Whitehorn vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 26127cf7d04SAleksandr Rybalko break; 26227cf7d04SAleksandr Rybalko default: 26327cf7d04SAleksandr Rybalko /* panic? */ 26427cf7d04SAleksandr Rybalko return; 26527cf7d04SAleksandr Rybalko } 26627cf7d04SAleksandr Rybalko } 26727cf7d04SAleksandr Rybalko 268631bb572SJean-Sébastien Pédron void 269c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 270c285e4a5SJean-Sébastien Pédron const uint8_t *pattern, const uint8_t *mask, 271c285e4a5SJean-Sébastien Pédron unsigned int width, unsigned int height, 272c285e4a5SJean-Sébastien Pédron unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 27327cf7d04SAleksandr Rybalko { 27427cf7d04SAleksandr Rybalko struct fb_info *info; 27527cf7d04SAleksandr Rybalko uint32_t fgc, bgc, cc, o; 2762c48063bSEd Maste int bpp, bpl, xi, yi; 2772c48063bSEd Maste int bit, byte; 27827cf7d04SAleksandr Rybalko 27927cf7d04SAleksandr Rybalko info = vd->vd_softc; 28027cf7d04SAleksandr Rybalko bpp = FBTYPE_GET_BYTESPP(info); 28127cf7d04SAleksandr Rybalko fgc = info->fb_cmap[fg]; 28227cf7d04SAleksandr Rybalko bgc = info->fb_cmap[bg]; 2832c48063bSEd Maste bpl = (width + 7) / 8; /* Bytes per source line. */ 28427cf7d04SAleksandr Rybalko 285f1d2752fSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 286f1d2752fSNathan Whitehorn return; 287f1d2752fSNathan Whitehorn 2889ed297c8SNathan Whitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 2899ed297c8SNathan Whitehorn 2902c48063bSEd Maste /* Bound by right and bottom edges. */ 2912c48063bSEd Maste if (y + height > vw->vw_draw_area.tr_end.tp_row) { 2922c48063bSEd Maste if (y >= vw->vw_draw_area.tr_end.tp_row) 2932c48063bSEd Maste return; 2942c48063bSEd Maste height = vw->vw_draw_area.tr_end.tp_row - y; 29527cf7d04SAleksandr Rybalko } 2962c48063bSEd Maste if (x + width > vw->vw_draw_area.tr_end.tp_col) { 2972c48063bSEd Maste if (x >= vw->vw_draw_area.tr_end.tp_col) 2982c48063bSEd Maste return; 2992c48063bSEd Maste width = vw->vw_draw_area.tr_end.tp_col - x; 3002c48063bSEd Maste } 3012c48063bSEd Maste for (yi = 0; yi < height; yi++) { 3022c48063bSEd Maste for (xi = 0; xi < width; xi++) { 3032c48063bSEd Maste byte = yi * bpl + xi / 8; 3042c48063bSEd Maste bit = 0x80 >> (xi % 8); 3052c48063bSEd Maste /* Skip pixel write, if mask bit not set. */ 3062c48063bSEd Maste if (mask != NULL && (mask[byte] & bit) == 0) 3072c48063bSEd Maste continue; 3082c48063bSEd Maste o = (y + yi) * info->fb_stride + (x + xi) * bpp; 309ec6b1f6aSMarcel Moolenaar o += vd->vd_transpose; 3102c48063bSEd Maste cc = pattern[byte] & bit ? fgc : bgc; 31127cf7d04SAleksandr Rybalko 31227cf7d04SAleksandr Rybalko switch(bpp) { 31327cf7d04SAleksandr Rybalko case 1: 3149ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, cc); 31527cf7d04SAleksandr Rybalko break; 31627cf7d04SAleksandr Rybalko case 2: 3179ed297c8SNathan Whitehorn vt_fb_mem_wr2(info, o, cc); 31827cf7d04SAleksandr Rybalko break; 31927cf7d04SAleksandr Rybalko case 3: 32027cf7d04SAleksandr Rybalko /* Packed mode, so unaligned. Byte access. */ 3219ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 3229ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 3239ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 2, cc & 0xff); 32427cf7d04SAleksandr Rybalko break; 32527cf7d04SAleksandr Rybalko case 4: 3269ed297c8SNathan Whitehorn vt_fb_mem_wr4(info, o, cc); 32727cf7d04SAleksandr Rybalko break; 32827cf7d04SAleksandr Rybalko default: 32927cf7d04SAleksandr Rybalko /* panic? */ 33027cf7d04SAleksandr Rybalko break; 33127cf7d04SAleksandr Rybalko } 33227cf7d04SAleksandr Rybalko } 33327cf7d04SAleksandr Rybalko } 33427cf7d04SAleksandr Rybalko } 33527cf7d04SAleksandr Rybalko 336*b93028d8SEmmanuel Vadot int 337*b93028d8SEmmanuel Vadot vt_fb_bitblt_argb(struct vt_device *vd, const struct vt_window *vw, 338*b93028d8SEmmanuel Vadot const uint8_t *argb, 339*b93028d8SEmmanuel Vadot unsigned int width, unsigned int height, 340*b93028d8SEmmanuel Vadot unsigned int x, unsigned int y) 341*b93028d8SEmmanuel Vadot { 342*b93028d8SEmmanuel Vadot struct fb_info *info; 343*b93028d8SEmmanuel Vadot uint32_t o, cc; 344*b93028d8SEmmanuel Vadot int bpp, xi, yi; 345*b93028d8SEmmanuel Vadot 346*b93028d8SEmmanuel Vadot info = vd->vd_softc; 347*b93028d8SEmmanuel Vadot bpp = FBTYPE_GET_BYTESPP(info); 348*b93028d8SEmmanuel Vadot if (bpp != 4) 349*b93028d8SEmmanuel Vadot return (EOPNOTSUPP); 350*b93028d8SEmmanuel Vadot 351*b93028d8SEmmanuel Vadot if (info->fb_flags & FB_FLAG_NOWRITE) 352*b93028d8SEmmanuel Vadot return (0); 353*b93028d8SEmmanuel Vadot 354*b93028d8SEmmanuel Vadot KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 355*b93028d8SEmmanuel Vadot 356*b93028d8SEmmanuel Vadot /* Bound by right and bottom edges. */ 357*b93028d8SEmmanuel Vadot if (y + height > vw->vw_draw_area.tr_end.tp_row) { 358*b93028d8SEmmanuel Vadot if (y >= vw->vw_draw_area.tr_end.tp_row) 359*b93028d8SEmmanuel Vadot return (EINVAL); 360*b93028d8SEmmanuel Vadot height = vw->vw_draw_area.tr_end.tp_row - y; 361*b93028d8SEmmanuel Vadot } 362*b93028d8SEmmanuel Vadot if (x + width > vw->vw_draw_area.tr_end.tp_col) { 363*b93028d8SEmmanuel Vadot if (x >= vw->vw_draw_area.tr_end.tp_col) 364*b93028d8SEmmanuel Vadot return (EINVAL); 365*b93028d8SEmmanuel Vadot width = vw->vw_draw_area.tr_end.tp_col - x; 366*b93028d8SEmmanuel Vadot } 367*b93028d8SEmmanuel Vadot for (yi = 0; yi < height; yi++) { 368*b93028d8SEmmanuel Vadot for (xi = 0; xi < (width * 4); xi += 4) { 369*b93028d8SEmmanuel Vadot o = (y + yi) * info->fb_stride + (x + (xi / 4)) * bpp; 370*b93028d8SEmmanuel Vadot o += vd->vd_transpose; 371*b93028d8SEmmanuel Vadot cc = (argb[yi * width * 4 + xi] << 16) | 372*b93028d8SEmmanuel Vadot (argb[yi * width * 4 + xi + 1] << 8) | 373*b93028d8SEmmanuel Vadot (argb[yi * width * 4 + xi + 2]) | 374*b93028d8SEmmanuel Vadot (argb[yi * width * 4 + xi + 3] << 24); 375*b93028d8SEmmanuel Vadot vt_fb_mem_wr4(info, o, cc); 376*b93028d8SEmmanuel Vadot } 377*b93028d8SEmmanuel Vadot } 378*b93028d8SEmmanuel Vadot 379*b93028d8SEmmanuel Vadot return (0); 380*b93028d8SEmmanuel Vadot } 381*b93028d8SEmmanuel Vadot 38227cf7d04SAleksandr Rybalko void 383c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 384c285e4a5SJean-Sébastien Pédron const term_rect_t *area) 385c285e4a5SJean-Sébastien Pédron { 386c285e4a5SJean-Sébastien Pédron unsigned int col, row, x, y; 387c285e4a5SJean-Sébastien Pédron struct vt_font *vf; 388c285e4a5SJean-Sébastien Pédron term_char_t c; 389c285e4a5SJean-Sébastien Pédron term_color_t fg, bg; 390c285e4a5SJean-Sébastien Pédron const uint8_t *pattern; 391ee97b233SColin Percival size_t z; 392c285e4a5SJean-Sébastien Pédron 393c285e4a5SJean-Sébastien Pédron vf = vw->vw_font; 394c285e4a5SJean-Sébastien Pédron 395c285e4a5SJean-Sébastien Pédron for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 396c285e4a5SJean-Sébastien Pédron for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 397c285e4a5SJean-Sébastien Pédron ++col) { 39883fbb296SJean-Sébastien Pédron x = col * vf->vf_width + 39983fbb296SJean-Sébastien Pédron vw->vw_draw_area.tr_begin.tp_col; 40083fbb296SJean-Sébastien Pédron y = row * vf->vf_height + 40183fbb296SJean-Sébastien Pédron vw->vw_draw_area.tr_begin.tp_row; 402c285e4a5SJean-Sébastien Pédron 403c285e4a5SJean-Sébastien Pédron c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 404c285e4a5SJean-Sébastien Pédron pattern = vtfont_lookup(vf, c); 405c285e4a5SJean-Sébastien Pédron vt_determine_colors(c, 406c285e4a5SJean-Sébastien Pédron VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 407c285e4a5SJean-Sébastien Pédron 408ee97b233SColin Percival z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 409dbc7ca59SEd Maste if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * 410dbc7ca59SEd Maste PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 411dbc7ca59SEd Maste continue; 412ee97b233SColin Percival if (vd->vd_drawn && (vd->vd_drawn[z] == c) && 413ee97b233SColin Percival vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && 414ee97b233SColin Percival vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) 415ee97b233SColin Percival continue; 416ee97b233SColin Percival 417c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(vd, vw, 418c285e4a5SJean-Sébastien Pédron pattern, NULL, vf->vf_width, vf->vf_height, 419c285e4a5SJean-Sébastien Pédron x, y, fg, bg); 420ee97b233SColin Percival 421ee97b233SColin Percival if (vd->vd_drawn) 422ee97b233SColin Percival vd->vd_drawn[z] = c; 423ee97b233SColin Percival if (vd->vd_drawnfg) 424ee97b233SColin Percival vd->vd_drawnfg[z] = fg; 425ee97b233SColin Percival if (vd->vd_drawnbg) 426ee97b233SColin Percival vd->vd_drawnbg[z] = bg; 427c285e4a5SJean-Sébastien Pédron } 428c285e4a5SJean-Sébastien Pédron } 429c285e4a5SJean-Sébastien Pédron 430c285e4a5SJean-Sébastien Pédron #ifndef SC_NO_CUTPASTE 431c285e4a5SJean-Sébastien Pédron if (!vd->vd_mshown) 432c285e4a5SJean-Sébastien Pédron return; 433c285e4a5SJean-Sébastien Pédron 434c285e4a5SJean-Sébastien Pédron term_rect_t drawn_area; 435c285e4a5SJean-Sébastien Pédron 43684d623c6SJean-Sébastien Pédron drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 43784d623c6SJean-Sébastien Pédron drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 43884d623c6SJean-Sébastien Pédron drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 43984d623c6SJean-Sébastien Pédron drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 440c285e4a5SJean-Sébastien Pédron 441c285e4a5SJean-Sébastien Pédron if (vt_is_cursor_in_area(vd, &drawn_area)) { 442c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(vd, vw, 443c285e4a5SJean-Sébastien Pédron vd->vd_mcursor->map, vd->vd_mcursor->mask, 444c285e4a5SJean-Sébastien Pédron vd->vd_mcursor->width, vd->vd_mcursor->height, 44584d623c6SJean-Sébastien Pédron vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 44684d623c6SJean-Sébastien Pédron vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 447c285e4a5SJean-Sébastien Pédron vd->vd_mcursor_fg, vd->vd_mcursor_bg); 448c285e4a5SJean-Sébastien Pédron } 449c285e4a5SJean-Sébastien Pédron #endif 450c285e4a5SJean-Sébastien Pédron } 451c285e4a5SJean-Sébastien Pédron 452c285e4a5SJean-Sébastien Pédron void 453ee97b233SColin Percival vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area) 454ee97b233SColin Percival { 455ee97b233SColin Percival unsigned int col, row; 456ee97b233SColin Percival size_t z; 457ee97b233SColin Percival 458ee97b233SColin Percival for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 459ee97b233SColin Percival for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 460ee97b233SColin Percival ++col) { 461ee97b233SColin Percival z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 462dbc7ca59SEd Maste if (z >= PIXEL_HEIGHT(VT_FB_MAX_HEIGHT) * 463dbc7ca59SEd Maste PIXEL_WIDTH(VT_FB_MAX_WIDTH)) 464dbc7ca59SEd Maste continue; 465ee97b233SColin Percival if (vd->vd_drawn) 466ee97b233SColin Percival vd->vd_drawn[z] = 0; 467ee97b233SColin Percival if (vd->vd_drawnfg) 468ee97b233SColin Percival vd->vd_drawnfg[z] = 0; 469ee97b233SColin Percival if (vd->vd_drawnbg) 470ee97b233SColin Percival vd->vd_drawnbg[z] = 0; 471ee97b233SColin Percival } 472ee97b233SColin Percival } 473ee97b233SColin Percival } 474ee97b233SColin Percival 475ee97b233SColin Percival void 47627cf7d04SAleksandr Rybalko vt_fb_postswitch(struct vt_device *vd) 47727cf7d04SAleksandr Rybalko { 47827cf7d04SAleksandr Rybalko struct fb_info *info; 47927cf7d04SAleksandr Rybalko 48027cf7d04SAleksandr Rybalko info = vd->vd_softc; 48127cf7d04SAleksandr Rybalko 48227cf7d04SAleksandr Rybalko if (info->enter != NULL) 48327cf7d04SAleksandr Rybalko info->enter(info->fb_priv); 48427cf7d04SAleksandr Rybalko } 48527cf7d04SAleksandr Rybalko 48627cf7d04SAleksandr Rybalko static int 487b9f3b63aSLeandro Lupori vt_fb_init_colors(struct fb_info *info) 48827cf7d04SAleksandr Rybalko { 48927cf7d04SAleksandr Rybalko 490b9f3b63aSLeandro Lupori switch (FBTYPE_GET_BPP(info)) { 49127cf7d04SAleksandr Rybalko case 8: 492b9f3b63aSLeandro Lupori return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 49327cf7d04SAleksandr Rybalko 0x7, 5, 0x7, 2, 0x3, 0)); 49427cf7d04SAleksandr Rybalko case 15: 495b9f3b63aSLeandro Lupori return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 49627cf7d04SAleksandr Rybalko 0x1f, 10, 0x1f, 5, 0x1f, 0)); 49727cf7d04SAleksandr Rybalko case 16: 498b9f3b63aSLeandro Lupori return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 49927cf7d04SAleksandr Rybalko 0x1f, 11, 0x3f, 5, 0x1f, 0)); 50027cf7d04SAleksandr Rybalko case 24: 50127cf7d04SAleksandr Rybalko case 32: /* Ignore alpha. */ 502b9f3b63aSLeandro Lupori return (vt_config_cons_colors(info, COLOR_FORMAT_RGB, 50319e2ce2dSJean-Sébastien Pédron 0xff, 16, 0xff, 8, 0xff, 0)); 50427cf7d04SAleksandr Rybalko default: 50527cf7d04SAleksandr Rybalko return (1); 50627cf7d04SAleksandr Rybalko } 50727cf7d04SAleksandr Rybalko } 50827cf7d04SAleksandr Rybalko 50927cf7d04SAleksandr Rybalko int 51027cf7d04SAleksandr Rybalko vt_fb_init(struct vt_device *vd) 51127cf7d04SAleksandr Rybalko { 51227cf7d04SAleksandr Rybalko struct fb_info *info; 513ec6b1f6aSMarcel Moolenaar u_int margin; 514df1bc27aSToomas Soome int bg, err; 515df1bc27aSToomas Soome term_color_t c; 51627cf7d04SAleksandr Rybalko 51727cf7d04SAleksandr Rybalko info = vd->vd_softc; 518f41bde66SConrad Meyer vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); 519ec6b1f6aSMarcel Moolenaar margin = (info->fb_height - vd->vd_height) >> 1; 520ec6b1f6aSMarcel Moolenaar vd->vd_transpose = margin * info->fb_stride; 521f41bde66SConrad Meyer vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); 522ec6b1f6aSMarcel Moolenaar margin = (info->fb_width - vd->vd_width) >> 1; 523ec6b1f6aSMarcel Moolenaar vd->vd_transpose += margin * (info->fb_bpp / NBBY); 52476e2f976SJean-Sébastien Pédron vd->vd_video_dev = info->fb_video_dev; 52527cf7d04SAleksandr Rybalko 5269ed297c8SNathan Whitehorn if (info->fb_size == 0) 5279ed297c8SNathan Whitehorn return (CN_DEAD); 5289ed297c8SNathan Whitehorn 529a985ae9bSHans Petter Selasky if (info->fb_pbase == 0 && info->fb_vbase == 0) 5309ed297c8SNathan Whitehorn info->fb_flags |= FB_FLAG_NOMMAP; 5319ed297c8SNathan Whitehorn 53227cf7d04SAleksandr Rybalko if (info->fb_cmsize <= 0) { 533b9f3b63aSLeandro Lupori err = vt_fb_init_colors(info); 53427cf7d04SAleksandr Rybalko if (err) 53527cf7d04SAleksandr Rybalko return (CN_DEAD); 53627cf7d04SAleksandr Rybalko info->fb_cmsize = 16; 53727cf7d04SAleksandr Rybalko } 53827cf7d04SAleksandr Rybalko 539df1bc27aSToomas Soome c = TC_BLACK; 54029f7096dSToomas Soome if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) { 541df1bc27aSToomas Soome if (bg == TC_WHITE) 542df1bc27aSToomas Soome bg |= TC_LIGHT; 543df1bc27aSToomas Soome c = bg; 544df1bc27aSToomas Soome } 54527cf7d04SAleksandr Rybalko /* Clear the screen. */ 546df1bc27aSToomas Soome vd->vd_driver->vd_blank(vd, c); 54727cf7d04SAleksandr Rybalko 54827cf7d04SAleksandr Rybalko /* Wakeup screen. KMS need this. */ 54927cf7d04SAleksandr Rybalko vt_fb_postswitch(vd); 55027cf7d04SAleksandr Rybalko 55127cf7d04SAleksandr Rybalko return (CN_INTERNAL); 55227cf7d04SAleksandr Rybalko } 55327cf7d04SAleksandr Rybalko 55476e2f976SJean-Sébastien Pédron void 55576e2f976SJean-Sébastien Pédron vt_fb_fini(struct vt_device *vd, void *softc) 55676e2f976SJean-Sébastien Pédron { 55776e2f976SJean-Sébastien Pédron 55876e2f976SJean-Sébastien Pédron vd->vd_video_dev = NULL; 55976e2f976SJean-Sébastien Pédron } 56076e2f976SJean-Sébastien Pédron 56127cf7d04SAleksandr Rybalko int 56227cf7d04SAleksandr Rybalko vt_fb_attach(struct fb_info *info) 56327cf7d04SAleksandr Rybalko { 56429ab1945SJean-Sébastien Pédron int ret; 56527cf7d04SAleksandr Rybalko 56629ab1945SJean-Sébastien Pédron ret = vt_allocate(&vt_fb_driver, info); 56727cf7d04SAleksandr Rybalko 56829ab1945SJean-Sébastien Pédron return (ret); 56927cf7d04SAleksandr Rybalko } 57027cf7d04SAleksandr Rybalko 57176e2f976SJean-Sébastien Pédron int 57276e2f976SJean-Sébastien Pédron vt_fb_detach(struct fb_info *info) 57376e2f976SJean-Sébastien Pédron { 57429ab1945SJean-Sébastien Pédron int ret; 57576e2f976SJean-Sébastien Pédron 57629ab1945SJean-Sébastien Pédron ret = vt_deallocate(&vt_fb_driver, info); 57776e2f976SJean-Sébastien Pédron 57829ab1945SJean-Sébastien Pédron return (ret); 57976e2f976SJean-Sébastien Pédron } 58076e2f976SJean-Sébastien Pédron 58127cf7d04SAleksandr Rybalko void 5826dfa4578SAndriy Gapon vt_fb_suspend(struct vt_device *vd) 58327cf7d04SAleksandr Rybalko { 58427cf7d04SAleksandr Rybalko 5856dfa4578SAndriy Gapon vt_suspend(vd); 58627cf7d04SAleksandr Rybalko } 58727cf7d04SAleksandr Rybalko 58827cf7d04SAleksandr Rybalko void 5896dfa4578SAndriy Gapon vt_fb_resume(struct vt_device *vd) 59027cf7d04SAleksandr Rybalko { 59127cf7d04SAleksandr Rybalko 5926dfa4578SAndriy Gapon vt_resume(vd); 59327cf7d04SAleksandr Rybalko } 594