127cf7d04SAleksandr Rybalko /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 427cf7d04SAleksandr Rybalko * Copyright (c) 2013 The FreeBSD Foundation 527cf7d04SAleksandr Rybalko * All rights reserved. 627cf7d04SAleksandr Rybalko * 727cf7d04SAleksandr Rybalko * This software was developed by Aleksandr Rybalko under sponsorship from the 827cf7d04SAleksandr Rybalko * FreeBSD Foundation. 927cf7d04SAleksandr Rybalko * 1027cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 1127cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1227cf7d04SAleksandr Rybalko * are met: 1327cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1427cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1527cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1627cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1727cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 1827cf7d04SAleksandr Rybalko * 1927cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2027cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2127cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2227cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2327cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2427cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2527cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2627cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2727cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2827cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2927cf7d04SAleksandr Rybalko * SUCH DAMAGE. 3027cf7d04SAleksandr Rybalko */ 3127cf7d04SAleksandr Rybalko 3227cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 3327cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3427cf7d04SAleksandr Rybalko 3527cf7d04SAleksandr Rybalko #include <sys/param.h> 3627cf7d04SAleksandr Rybalko #include <sys/systm.h> 3727cf7d04SAleksandr Rybalko #include <sys/malloc.h> 3827cf7d04SAleksandr Rybalko #include <sys/queue.h> 3927cf7d04SAleksandr Rybalko #include <sys/fbio.h> 40df1bc27aSToomas Soome #include <sys/kernel.h> 4127cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 4227cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h> 4327cf7d04SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h> 4427cf7d04SAleksandr Rybalko 45a985ae9bSHans Petter Selasky #include <vm/vm.h> 46a985ae9bSHans Petter Selasky #include <vm/pmap.h> 47a985ae9bSHans Petter Selasky 4827cf7d04SAleksandr Rybalko static struct vt_driver vt_fb_driver = { 494dde1640SAleksandr Rybalko .vd_name = "fb", 5027cf7d04SAleksandr Rybalko .vd_init = vt_fb_init, 5176e2f976SJean-Sébastien Pédron .vd_fini = vt_fb_fini, 5227cf7d04SAleksandr Rybalko .vd_blank = vt_fb_blank, 53c285e4a5SJean-Sébastien Pédron .vd_bitblt_text = vt_fb_bitblt_text, 54ee97b233SColin Percival .vd_invalidate_text = vt_fb_invalidate_text, 55631bb572SJean-Sébastien Pédron .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 569e497e7bSAleksandr Rybalko .vd_drawrect = vt_fb_drawrect, 579e497e7bSAleksandr Rybalko .vd_setpixel = vt_fb_setpixel, 5827cf7d04SAleksandr Rybalko .vd_postswitch = vt_fb_postswitch, 5927cf7d04SAleksandr Rybalko .vd_priority = VD_PRIORITY_GENERIC+10, 607a1a32c4SAleksandr Rybalko .vd_fb_ioctl = vt_fb_ioctl, 617a1a32c4SAleksandr Rybalko .vd_fb_mmap = vt_fb_mmap, 626dfa4578SAndriy Gapon .vd_suspend = vt_fb_suspend, 636dfa4578SAndriy Gapon .vd_resume = vt_fb_resume, 6427cf7d04SAleksandr Rybalko }; 6527cf7d04SAleksandr Rybalko 664dde1640SAleksandr Rybalko VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 674dde1640SAleksandr Rybalko 689ed297c8SNathan Whitehorn static void 699ed297c8SNathan Whitehorn vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 709ed297c8SNathan Whitehorn { 719ed297c8SNathan Whitehorn 729ed297c8SNathan Whitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 739ed297c8SNathan Whitehorn *(uint8_t *)(sc->fb_vbase + o) = v; 749ed297c8SNathan Whitehorn } 759ed297c8SNathan Whitehorn 769ed297c8SNathan Whitehorn static void 779ed297c8SNathan Whitehorn vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 789ed297c8SNathan Whitehorn { 799ed297c8SNathan Whitehorn 809ed297c8SNathan Whitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 819ed297c8SNathan Whitehorn *(uint16_t *)(sc->fb_vbase + o) = v; 829ed297c8SNathan Whitehorn } 839ed297c8SNathan Whitehorn 849ed297c8SNathan Whitehorn static void 859ed297c8SNathan Whitehorn vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 869ed297c8SNathan Whitehorn { 879ed297c8SNathan Whitehorn 889ed297c8SNathan Whitehorn KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 899ed297c8SNathan Whitehorn *(uint32_t *)(sc->fb_vbase + o) = v; 909ed297c8SNathan Whitehorn } 919ed297c8SNathan Whitehorn 9260d7ea3dSNathan Whitehorn int 937a1a32c4SAleksandr Rybalko vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 947a1a32c4SAleksandr Rybalko { 957a1a32c4SAleksandr Rybalko struct fb_info *info; 9660d7ea3dSNathan Whitehorn int error = 0; 977a1a32c4SAleksandr Rybalko 987a1a32c4SAleksandr Rybalko info = vd->vd_softc; 997a1a32c4SAleksandr Rybalko 10060d7ea3dSNathan Whitehorn switch (cmd) { 10160d7ea3dSNathan Whitehorn case FBIOGTYPE: 10260d7ea3dSNathan Whitehorn bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 10360d7ea3dSNathan Whitehorn break; 1047a1a32c4SAleksandr Rybalko 10560d7ea3dSNathan Whitehorn case FBIO_GETWINORG: /* get frame buffer window origin */ 10660d7ea3dSNathan Whitehorn *(u_int *)data = 0; 10760d7ea3dSNathan Whitehorn break; 10860d7ea3dSNathan Whitehorn 10960d7ea3dSNathan Whitehorn case FBIO_GETDISPSTART: /* get display start address */ 11060d7ea3dSNathan Whitehorn ((video_display_start_t *)data)->x = 0; 11160d7ea3dSNathan Whitehorn ((video_display_start_t *)data)->y = 0; 11260d7ea3dSNathan Whitehorn break; 11360d7ea3dSNathan Whitehorn 11460d7ea3dSNathan Whitehorn case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 11560d7ea3dSNathan Whitehorn *(u_int *)data = info->fb_stride; 11660d7ea3dSNathan Whitehorn break; 11760d7ea3dSNathan Whitehorn 11860d7ea3dSNathan Whitehorn case FBIO_BLANK: /* blank display */ 11960d7ea3dSNathan Whitehorn if (vd->vd_driver->vd_blank == NULL) 12060d7ea3dSNathan Whitehorn return (ENODEV); 12160d7ea3dSNathan Whitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 12260d7ea3dSNathan Whitehorn break; 12360d7ea3dSNathan Whitehorn 12460d7ea3dSNathan Whitehorn default: 12560d7ea3dSNathan Whitehorn error = ENOIOCTL; 12660d7ea3dSNathan Whitehorn break; 1277a1a32c4SAleksandr Rybalko } 1287a1a32c4SAleksandr Rybalko 12960d7ea3dSNathan Whitehorn return (error); 13060d7ea3dSNathan Whitehorn } 13160d7ea3dSNathan Whitehorn 13260d7ea3dSNathan Whitehorn int 1335beb07abSAleksandr Rybalko vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 1345beb07abSAleksandr Rybalko int prot, vm_memattr_t *memattr) 1357a1a32c4SAleksandr Rybalko { 1367a1a32c4SAleksandr Rybalko struct fb_info *info; 1377a1a32c4SAleksandr Rybalko 1387a1a32c4SAleksandr Rybalko info = vd->vd_softc; 1397a1a32c4SAleksandr Rybalko 14060d7ea3dSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOMMAP) 14160d7ea3dSNathan Whitehorn return (ENODEV); 1427a1a32c4SAleksandr Rybalko 14360d7ea3dSNathan Whitehorn if (offset >= 0 && offset < info->fb_size) { 144a985ae9bSHans Petter Selasky if (info->fb_pbase == 0) { 145a985ae9bSHans Petter Selasky *paddr = vtophys((uint8_t *)info->fb_vbase + offset); 146a985ae9bSHans Petter Selasky } else { 14760d7ea3dSNathan Whitehorn *paddr = info->fb_pbase + offset; 148823cdec7SJustin Hibbits if (info->fb_flags & FB_FLAG_MEMATTR) 149823cdec7SJustin Hibbits *memattr = info->fb_memattr; 15060d7ea3dSNathan Whitehorn #ifdef VM_MEMATTR_WRITE_COMBINING 151823cdec7SJustin Hibbits else 15260d7ea3dSNathan Whitehorn *memattr = VM_MEMATTR_WRITE_COMBINING; 15360d7ea3dSNathan Whitehorn #endif 154a985ae9bSHans Petter Selasky } 15560d7ea3dSNathan Whitehorn return (0); 15660d7ea3dSNathan Whitehorn } 15760d7ea3dSNathan Whitehorn 15860d7ea3dSNathan Whitehorn return (EINVAL); 1597a1a32c4SAleksandr Rybalko } 1607a1a32c4SAleksandr Rybalko 1611365d077SJean-Sébastien Pédron void 1629e497e7bSAleksandr Rybalko vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 1639e497e7bSAleksandr Rybalko { 1649e497e7bSAleksandr Rybalko struct fb_info *info; 1659e497e7bSAleksandr Rybalko uint32_t c; 1669e497e7bSAleksandr Rybalko u_int o; 1679e497e7bSAleksandr Rybalko 1689e497e7bSAleksandr Rybalko info = vd->vd_softc; 1699e497e7bSAleksandr Rybalko c = info->fb_cmap[color]; 1709e497e7bSAleksandr Rybalko o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 1719e497e7bSAleksandr Rybalko 172f1d2752fSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 173f1d2752fSNathan Whitehorn return; 174f1d2752fSNathan Whitehorn 1759ed297c8SNathan Whitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 1769ed297c8SNathan Whitehorn 1779e497e7bSAleksandr Rybalko switch (FBTYPE_GET_BYTESPP(info)) { 1789e497e7bSAleksandr Rybalko case 1: 1799ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, c); 1809e497e7bSAleksandr Rybalko break; 1819e497e7bSAleksandr Rybalko case 2: 1829ed297c8SNathan Whitehorn vt_fb_mem_wr2(info, o, c); 1839e497e7bSAleksandr Rybalko break; 1849e497e7bSAleksandr Rybalko case 3: 1859ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 1869ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 1879ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 2, c & 0xff); 1889e497e7bSAleksandr Rybalko break; 1899e497e7bSAleksandr Rybalko case 4: 1909ed297c8SNathan Whitehorn vt_fb_mem_wr4(info, o, c); 1919e497e7bSAleksandr Rybalko break; 1929e497e7bSAleksandr Rybalko default: 1939e497e7bSAleksandr Rybalko /* panic? */ 1949e497e7bSAleksandr Rybalko return; 1959e497e7bSAleksandr Rybalko } 1969e497e7bSAleksandr Rybalko } 1979e497e7bSAleksandr Rybalko 1981365d077SJean-Sébastien Pédron void 1999e497e7bSAleksandr Rybalko vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 2009e497e7bSAleksandr Rybalko term_color_t color) 2019e497e7bSAleksandr Rybalko { 2029e497e7bSAleksandr Rybalko int x, y; 2039e497e7bSAleksandr Rybalko 2049e497e7bSAleksandr Rybalko for (y = y1; y <= y2; y++) { 2059e497e7bSAleksandr Rybalko if (fill || (y == y1) || (y == y2)) { 2069e497e7bSAleksandr Rybalko for (x = x1; x <= x2; x++) 2079e497e7bSAleksandr Rybalko vt_fb_setpixel(vd, x, y, color); 2089e497e7bSAleksandr Rybalko } else { 2099e497e7bSAleksandr Rybalko vt_fb_setpixel(vd, x1, y, color); 2109e497e7bSAleksandr Rybalko vt_fb_setpixel(vd, x2, y, color); 2119e497e7bSAleksandr Rybalko } 2129e497e7bSAleksandr Rybalko } 2139e497e7bSAleksandr Rybalko } 2149e497e7bSAleksandr Rybalko 2159e497e7bSAleksandr Rybalko void 21627cf7d04SAleksandr Rybalko vt_fb_blank(struct vt_device *vd, term_color_t color) 21727cf7d04SAleksandr Rybalko { 21827cf7d04SAleksandr Rybalko struct fb_info *info; 21927cf7d04SAleksandr Rybalko uint32_t c; 22060d7ea3dSNathan Whitehorn u_int o, h; 22127cf7d04SAleksandr Rybalko 22227cf7d04SAleksandr Rybalko info = vd->vd_softc; 22327cf7d04SAleksandr Rybalko c = info->fb_cmap[color]; 22427cf7d04SAleksandr Rybalko 225f1d2752fSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 226f1d2752fSNathan Whitehorn return; 227f1d2752fSNathan Whitehorn 2289ed297c8SNathan Whitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 2299ed297c8SNathan Whitehorn 23027cf7d04SAleksandr Rybalko switch (FBTYPE_GET_BYTESPP(info)) { 23127cf7d04SAleksandr Rybalko case 1: 23235e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 23327cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o++) 2349ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 23527cf7d04SAleksandr Rybalko break; 23627cf7d04SAleksandr Rybalko case 2: 23735e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 23827cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 2) 2399ed297c8SNathan Whitehorn vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 24027cf7d04SAleksandr Rybalko break; 24127cf7d04SAleksandr Rybalko case 3: 24235e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 24327cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 3) { 2449ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o, 24560d7ea3dSNathan Whitehorn (c >> 16) & 0xff); 2469ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 24760d7ea3dSNathan Whitehorn (c >> 8) & 0xff); 2489ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 24960d7ea3dSNathan Whitehorn c & 0xff); 25027cf7d04SAleksandr Rybalko } 25127cf7d04SAleksandr Rybalko break; 25227cf7d04SAleksandr Rybalko case 4: 25335e6436eSNathan Whitehorn for (h = 0; h < info->fb_height; h++) 25427cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 4) 2559ed297c8SNathan Whitehorn vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 25627cf7d04SAleksandr Rybalko break; 25727cf7d04SAleksandr Rybalko default: 25827cf7d04SAleksandr Rybalko /* panic? */ 25927cf7d04SAleksandr Rybalko return; 26027cf7d04SAleksandr Rybalko } 26127cf7d04SAleksandr Rybalko } 26227cf7d04SAleksandr Rybalko 263631bb572SJean-Sébastien Pédron void 264c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 265c285e4a5SJean-Sébastien Pédron const uint8_t *pattern, const uint8_t *mask, 266c285e4a5SJean-Sébastien Pédron unsigned int width, unsigned int height, 267c285e4a5SJean-Sébastien Pédron unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 26827cf7d04SAleksandr Rybalko { 26927cf7d04SAleksandr Rybalko struct fb_info *info; 27027cf7d04SAleksandr Rybalko uint32_t fgc, bgc, cc, o; 2712c48063bSEd Maste int bpp, bpl, xi, yi; 2722c48063bSEd Maste int bit, byte; 27327cf7d04SAleksandr Rybalko 27427cf7d04SAleksandr Rybalko info = vd->vd_softc; 27527cf7d04SAleksandr Rybalko bpp = FBTYPE_GET_BYTESPP(info); 27627cf7d04SAleksandr Rybalko fgc = info->fb_cmap[fg]; 27727cf7d04SAleksandr Rybalko bgc = info->fb_cmap[bg]; 2782c48063bSEd Maste bpl = (width + 7) / 8; /* Bytes per source line. */ 27927cf7d04SAleksandr Rybalko 280f1d2752fSNathan Whitehorn if (info->fb_flags & FB_FLAG_NOWRITE) 281f1d2752fSNathan Whitehorn return; 282f1d2752fSNathan Whitehorn 2839ed297c8SNathan Whitehorn KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 2849ed297c8SNathan Whitehorn 2852c48063bSEd Maste /* Bound by right and bottom edges. */ 2862c48063bSEd Maste if (y + height > vw->vw_draw_area.tr_end.tp_row) { 2872c48063bSEd Maste if (y >= vw->vw_draw_area.tr_end.tp_row) 2882c48063bSEd Maste return; 2892c48063bSEd Maste height = vw->vw_draw_area.tr_end.tp_row - y; 29027cf7d04SAleksandr Rybalko } 2912c48063bSEd Maste if (x + width > vw->vw_draw_area.tr_end.tp_col) { 2922c48063bSEd Maste if (x >= vw->vw_draw_area.tr_end.tp_col) 2932c48063bSEd Maste return; 2942c48063bSEd Maste width = vw->vw_draw_area.tr_end.tp_col - x; 2952c48063bSEd Maste } 2962c48063bSEd Maste for (yi = 0; yi < height; yi++) { 2972c48063bSEd Maste for (xi = 0; xi < width; xi++) { 2982c48063bSEd Maste byte = yi * bpl + xi / 8; 2992c48063bSEd Maste bit = 0x80 >> (xi % 8); 3002c48063bSEd Maste /* Skip pixel write, if mask bit not set. */ 3012c48063bSEd Maste if (mask != NULL && (mask[byte] & bit) == 0) 3022c48063bSEd Maste continue; 3032c48063bSEd Maste o = (y + yi) * info->fb_stride + (x + xi) * bpp; 304ec6b1f6aSMarcel Moolenaar o += vd->vd_transpose; 3052c48063bSEd Maste cc = pattern[byte] & bit ? fgc : bgc; 30627cf7d04SAleksandr Rybalko 30727cf7d04SAleksandr Rybalko switch(bpp) { 30827cf7d04SAleksandr Rybalko case 1: 3099ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, cc); 31027cf7d04SAleksandr Rybalko break; 31127cf7d04SAleksandr Rybalko case 2: 3129ed297c8SNathan Whitehorn vt_fb_mem_wr2(info, o, cc); 31327cf7d04SAleksandr Rybalko break; 31427cf7d04SAleksandr Rybalko case 3: 31527cf7d04SAleksandr Rybalko /* Packed mode, so unaligned. Byte access. */ 3169ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 3179ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 3189ed297c8SNathan Whitehorn vt_fb_mem_wr1(info, o + 2, cc & 0xff); 31927cf7d04SAleksandr Rybalko break; 32027cf7d04SAleksandr Rybalko case 4: 3219ed297c8SNathan Whitehorn vt_fb_mem_wr4(info, o, cc); 32227cf7d04SAleksandr Rybalko break; 32327cf7d04SAleksandr Rybalko default: 32427cf7d04SAleksandr Rybalko /* panic? */ 32527cf7d04SAleksandr Rybalko break; 32627cf7d04SAleksandr Rybalko } 32727cf7d04SAleksandr Rybalko } 32827cf7d04SAleksandr Rybalko } 32927cf7d04SAleksandr Rybalko } 33027cf7d04SAleksandr Rybalko 33127cf7d04SAleksandr Rybalko void 332c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 333c285e4a5SJean-Sébastien Pédron const term_rect_t *area) 334c285e4a5SJean-Sébastien Pédron { 335c285e4a5SJean-Sébastien Pédron unsigned int col, row, x, y; 336c285e4a5SJean-Sébastien Pédron struct vt_font *vf; 337c285e4a5SJean-Sébastien Pédron term_char_t c; 338c285e4a5SJean-Sébastien Pédron term_color_t fg, bg; 339c285e4a5SJean-Sébastien Pédron const uint8_t *pattern; 340ee97b233SColin Percival size_t z; 341c285e4a5SJean-Sébastien Pédron 342c285e4a5SJean-Sébastien Pédron vf = vw->vw_font; 343c285e4a5SJean-Sébastien Pédron 344c285e4a5SJean-Sébastien Pédron for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 345c285e4a5SJean-Sébastien Pédron for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 346c285e4a5SJean-Sébastien Pédron ++col) { 34783fbb296SJean-Sébastien Pédron x = col * vf->vf_width + 34883fbb296SJean-Sébastien Pédron vw->vw_draw_area.tr_begin.tp_col; 34983fbb296SJean-Sébastien Pédron y = row * vf->vf_height + 35083fbb296SJean-Sébastien Pédron vw->vw_draw_area.tr_begin.tp_row; 351c285e4a5SJean-Sébastien Pédron 352c285e4a5SJean-Sébastien Pédron c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 353c285e4a5SJean-Sébastien Pédron pattern = vtfont_lookup(vf, c); 354c285e4a5SJean-Sébastien Pédron vt_determine_colors(c, 355c285e4a5SJean-Sébastien Pédron VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 356c285e4a5SJean-Sébastien Pédron 357ee97b233SColin Percival z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 358ee97b233SColin Percival if (vd->vd_drawn && (vd->vd_drawn[z] == c) && 359ee97b233SColin Percival vd->vd_drawnfg && (vd->vd_drawnfg[z] == fg) && 360ee97b233SColin Percival vd->vd_drawnbg && (vd->vd_drawnbg[z] == bg)) 361ee97b233SColin Percival continue; 362ee97b233SColin Percival 363c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(vd, vw, 364c285e4a5SJean-Sébastien Pédron pattern, NULL, vf->vf_width, vf->vf_height, 365c285e4a5SJean-Sébastien Pédron x, y, fg, bg); 366ee97b233SColin Percival 367ee97b233SColin Percival if (vd->vd_drawn) 368ee97b233SColin Percival vd->vd_drawn[z] = c; 369ee97b233SColin Percival if (vd->vd_drawnfg) 370ee97b233SColin Percival vd->vd_drawnfg[z] = fg; 371ee97b233SColin Percival if (vd->vd_drawnbg) 372ee97b233SColin Percival vd->vd_drawnbg[z] = bg; 373c285e4a5SJean-Sébastien Pédron } 374c285e4a5SJean-Sébastien Pédron } 375c285e4a5SJean-Sébastien Pédron 376c285e4a5SJean-Sébastien Pédron #ifndef SC_NO_CUTPASTE 377c285e4a5SJean-Sébastien Pédron if (!vd->vd_mshown) 378c285e4a5SJean-Sébastien Pédron return; 379c285e4a5SJean-Sébastien Pédron 380c285e4a5SJean-Sébastien Pédron term_rect_t drawn_area; 381c285e4a5SJean-Sébastien Pédron 38284d623c6SJean-Sébastien Pédron drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 38384d623c6SJean-Sébastien Pédron drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 38484d623c6SJean-Sébastien Pédron drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 38584d623c6SJean-Sébastien Pédron drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 386c285e4a5SJean-Sébastien Pédron 387c285e4a5SJean-Sébastien Pédron if (vt_is_cursor_in_area(vd, &drawn_area)) { 388c285e4a5SJean-Sébastien Pédron vt_fb_bitblt_bitmap(vd, vw, 389c285e4a5SJean-Sébastien Pédron vd->vd_mcursor->map, vd->vd_mcursor->mask, 390c285e4a5SJean-Sébastien Pédron vd->vd_mcursor->width, vd->vd_mcursor->height, 39184d623c6SJean-Sébastien Pédron vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 39284d623c6SJean-Sébastien Pédron vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 393c285e4a5SJean-Sébastien Pédron vd->vd_mcursor_fg, vd->vd_mcursor_bg); 394c285e4a5SJean-Sébastien Pédron } 395c285e4a5SJean-Sébastien Pédron #endif 396c285e4a5SJean-Sébastien Pédron } 397c285e4a5SJean-Sébastien Pédron 398c285e4a5SJean-Sébastien Pédron void 399ee97b233SColin Percival vt_fb_invalidate_text(struct vt_device *vd, const term_rect_t *area) 400ee97b233SColin Percival { 401ee97b233SColin Percival unsigned int col, row; 402ee97b233SColin Percival size_t z; 403ee97b233SColin Percival 404ee97b233SColin Percival for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 405ee97b233SColin Percival for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 406ee97b233SColin Percival ++col) { 407ee97b233SColin Percival z = row * PIXEL_WIDTH(VT_FB_MAX_WIDTH) + col; 408ee97b233SColin Percival if (vd->vd_drawn) 409ee97b233SColin Percival vd->vd_drawn[z] = 0; 410ee97b233SColin Percival if (vd->vd_drawnfg) 411ee97b233SColin Percival vd->vd_drawnfg[z] = 0; 412ee97b233SColin Percival if (vd->vd_drawnbg) 413ee97b233SColin Percival vd->vd_drawnbg[z] = 0; 414ee97b233SColin Percival } 415ee97b233SColin Percival } 416ee97b233SColin Percival } 417ee97b233SColin Percival 418ee97b233SColin Percival void 41927cf7d04SAleksandr Rybalko vt_fb_postswitch(struct vt_device *vd) 42027cf7d04SAleksandr Rybalko { 42127cf7d04SAleksandr Rybalko struct fb_info *info; 42227cf7d04SAleksandr Rybalko 42327cf7d04SAleksandr Rybalko info = vd->vd_softc; 42427cf7d04SAleksandr Rybalko 42527cf7d04SAleksandr Rybalko if (info->enter != NULL) 42627cf7d04SAleksandr Rybalko info->enter(info->fb_priv); 42727cf7d04SAleksandr Rybalko } 42827cf7d04SAleksandr Rybalko 42927cf7d04SAleksandr Rybalko static int 43027cf7d04SAleksandr Rybalko vt_fb_init_cmap(uint32_t *cmap, int depth) 43127cf7d04SAleksandr Rybalko { 43227cf7d04SAleksandr Rybalko 43327cf7d04SAleksandr Rybalko switch (depth) { 43427cf7d04SAleksandr Rybalko case 8: 43519e2ce2dSJean-Sébastien Pédron return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 43627cf7d04SAleksandr Rybalko 0x7, 5, 0x7, 2, 0x3, 0)); 43727cf7d04SAleksandr Rybalko case 15: 43819e2ce2dSJean-Sébastien Pédron return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 43927cf7d04SAleksandr Rybalko 0x1f, 10, 0x1f, 5, 0x1f, 0)); 44027cf7d04SAleksandr Rybalko case 16: 44119e2ce2dSJean-Sébastien Pédron return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 44227cf7d04SAleksandr Rybalko 0x1f, 11, 0x3f, 5, 0x1f, 0)); 44327cf7d04SAleksandr Rybalko case 24: 44427cf7d04SAleksandr Rybalko case 32: /* Ignore alpha. */ 44519e2ce2dSJean-Sébastien Pédron return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 44619e2ce2dSJean-Sébastien Pédron 0xff, 16, 0xff, 8, 0xff, 0)); 44727cf7d04SAleksandr Rybalko default: 44827cf7d04SAleksandr Rybalko return (1); 44927cf7d04SAleksandr Rybalko } 45027cf7d04SAleksandr Rybalko } 45127cf7d04SAleksandr Rybalko 45227cf7d04SAleksandr Rybalko int 45327cf7d04SAleksandr Rybalko vt_fb_init(struct vt_device *vd) 45427cf7d04SAleksandr Rybalko { 45527cf7d04SAleksandr Rybalko struct fb_info *info; 456ec6b1f6aSMarcel Moolenaar u_int margin; 457df1bc27aSToomas Soome int bg, err; 458df1bc27aSToomas Soome term_color_t c; 45927cf7d04SAleksandr Rybalko 46027cf7d04SAleksandr Rybalko info = vd->vd_softc; 461f41bde66SConrad Meyer vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); 462ec6b1f6aSMarcel Moolenaar margin = (info->fb_height - vd->vd_height) >> 1; 463ec6b1f6aSMarcel Moolenaar vd->vd_transpose = margin * info->fb_stride; 464f41bde66SConrad Meyer vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); 465ec6b1f6aSMarcel Moolenaar margin = (info->fb_width - vd->vd_width) >> 1; 466ec6b1f6aSMarcel Moolenaar vd->vd_transpose += margin * (info->fb_bpp / NBBY); 46776e2f976SJean-Sébastien Pédron vd->vd_video_dev = info->fb_video_dev; 46827cf7d04SAleksandr Rybalko 4699ed297c8SNathan Whitehorn if (info->fb_size == 0) 4709ed297c8SNathan Whitehorn return (CN_DEAD); 4719ed297c8SNathan Whitehorn 472a985ae9bSHans Petter Selasky if (info->fb_pbase == 0 && info->fb_vbase == 0) 4739ed297c8SNathan Whitehorn info->fb_flags |= FB_FLAG_NOMMAP; 4749ed297c8SNathan Whitehorn 47527cf7d04SAleksandr Rybalko if (info->fb_cmsize <= 0) { 47627cf7d04SAleksandr Rybalko err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 47727cf7d04SAleksandr Rybalko if (err) 47827cf7d04SAleksandr Rybalko return (CN_DEAD); 47927cf7d04SAleksandr Rybalko info->fb_cmsize = 16; 48027cf7d04SAleksandr Rybalko } 48127cf7d04SAleksandr Rybalko 482df1bc27aSToomas Soome c = TC_BLACK; 483*29f7096dSToomas Soome if (TUNABLE_INT_FETCH("teken.bg_color", &bg) != 0) { 484df1bc27aSToomas Soome if (bg == TC_WHITE) 485df1bc27aSToomas Soome bg |= TC_LIGHT; 486df1bc27aSToomas Soome c = bg; 487df1bc27aSToomas Soome } 48827cf7d04SAleksandr Rybalko /* Clear the screen. */ 489df1bc27aSToomas Soome vd->vd_driver->vd_blank(vd, c); 49027cf7d04SAleksandr Rybalko 49127cf7d04SAleksandr Rybalko /* Wakeup screen. KMS need this. */ 49227cf7d04SAleksandr Rybalko vt_fb_postswitch(vd); 49327cf7d04SAleksandr Rybalko 49427cf7d04SAleksandr Rybalko return (CN_INTERNAL); 49527cf7d04SAleksandr Rybalko } 49627cf7d04SAleksandr Rybalko 49776e2f976SJean-Sébastien Pédron void 49876e2f976SJean-Sébastien Pédron vt_fb_fini(struct vt_device *vd, void *softc) 49976e2f976SJean-Sébastien Pédron { 50076e2f976SJean-Sébastien Pédron 50176e2f976SJean-Sébastien Pédron vd->vd_video_dev = NULL; 50276e2f976SJean-Sébastien Pédron } 50376e2f976SJean-Sébastien Pédron 50427cf7d04SAleksandr Rybalko int 50527cf7d04SAleksandr Rybalko vt_fb_attach(struct fb_info *info) 50627cf7d04SAleksandr Rybalko { 50727cf7d04SAleksandr Rybalko 50827cf7d04SAleksandr Rybalko vt_allocate(&vt_fb_driver, info); 50927cf7d04SAleksandr Rybalko 51027cf7d04SAleksandr Rybalko return (0); 51127cf7d04SAleksandr Rybalko } 51227cf7d04SAleksandr Rybalko 51376e2f976SJean-Sébastien Pédron int 51476e2f976SJean-Sébastien Pédron vt_fb_detach(struct fb_info *info) 51576e2f976SJean-Sébastien Pédron { 51676e2f976SJean-Sébastien Pédron 51776e2f976SJean-Sébastien Pédron vt_deallocate(&vt_fb_driver, info); 51876e2f976SJean-Sébastien Pédron 51976e2f976SJean-Sébastien Pédron return (0); 52076e2f976SJean-Sébastien Pédron } 52176e2f976SJean-Sébastien Pédron 52227cf7d04SAleksandr Rybalko void 5236dfa4578SAndriy Gapon vt_fb_suspend(struct vt_device *vd) 52427cf7d04SAleksandr Rybalko { 52527cf7d04SAleksandr Rybalko 5266dfa4578SAndriy Gapon vt_suspend(vd); 52727cf7d04SAleksandr Rybalko } 52827cf7d04SAleksandr Rybalko 52927cf7d04SAleksandr Rybalko void 5306dfa4578SAndriy Gapon vt_fb_resume(struct vt_device *vd) 53127cf7d04SAleksandr Rybalko { 53227cf7d04SAleksandr Rybalko 5336dfa4578SAndriy Gapon vt_resume(vd); 53427cf7d04SAleksandr Rybalko } 535