1*27cf7d04SAleksandr Rybalko /*- 2*27cf7d04SAleksandr Rybalko * Copyright (c) 2013 The FreeBSD Foundation 3*27cf7d04SAleksandr Rybalko * All rights reserved. 4*27cf7d04SAleksandr Rybalko * 5*27cf7d04SAleksandr Rybalko * This software was developed by Aleksandr Rybalko under sponsorship from the 6*27cf7d04SAleksandr Rybalko * FreeBSD Foundation. 7*27cf7d04SAleksandr Rybalko * 8*27cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 9*27cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 10*27cf7d04SAleksandr Rybalko * are met: 11*27cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 12*27cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 13*27cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 14*27cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 15*27cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 16*27cf7d04SAleksandr Rybalko * 17*27cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*27cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*27cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*27cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*27cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*27cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*27cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*27cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*27cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*27cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*27cf7d04SAleksandr Rybalko * SUCH DAMAGE. 28*27cf7d04SAleksandr Rybalko * 29*27cf7d04SAleksandr Rybalko * $FreeBSD$ 30*27cf7d04SAleksandr Rybalko */ 31*27cf7d04SAleksandr Rybalko 32*27cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 33*27cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 34*27cf7d04SAleksandr Rybalko 35*27cf7d04SAleksandr Rybalko #include <sys/param.h> 36*27cf7d04SAleksandr Rybalko #include <sys/systm.h> 37*27cf7d04SAleksandr Rybalko #include <sys/malloc.h> 38*27cf7d04SAleksandr Rybalko #include <sys/queue.h> 39*27cf7d04SAleksandr Rybalko #include <sys/fbio.h> 40*27cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 41*27cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h> 42*27cf7d04SAleksandr Rybalko #include <dev/vt/colors/vt_termcolors.h> 43*27cf7d04SAleksandr Rybalko 44*27cf7d04SAleksandr Rybalko static struct vt_driver vt_fb_driver = { 45*27cf7d04SAleksandr Rybalko .vd_init = vt_fb_init, 46*27cf7d04SAleksandr Rybalko .vd_blank = vt_fb_blank, 47*27cf7d04SAleksandr Rybalko .vd_bitbltchr = vt_fb_bitbltchr, 48*27cf7d04SAleksandr Rybalko .vd_postswitch = vt_fb_postswitch, 49*27cf7d04SAleksandr Rybalko .vd_priority = VD_PRIORITY_GENERIC+10, 50*27cf7d04SAleksandr Rybalko }; 51*27cf7d04SAleksandr Rybalko 52*27cf7d04SAleksandr Rybalko void 53*27cf7d04SAleksandr Rybalko vt_fb_blank(struct vt_device *vd, term_color_t color) 54*27cf7d04SAleksandr Rybalko { 55*27cf7d04SAleksandr Rybalko struct fb_info *info; 56*27cf7d04SAleksandr Rybalko uint32_t c; 57*27cf7d04SAleksandr Rybalko u_int o; 58*27cf7d04SAleksandr Rybalko 59*27cf7d04SAleksandr Rybalko info = vd->vd_softc; 60*27cf7d04SAleksandr Rybalko c = info->fb_cmap[color]; 61*27cf7d04SAleksandr Rybalko 62*27cf7d04SAleksandr Rybalko switch (FBTYPE_GET_BYTESPP(info)) { 63*27cf7d04SAleksandr Rybalko case 1: 64*27cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o++) 65*27cf7d04SAleksandr Rybalko info->wr1(info, o, c); 66*27cf7d04SAleksandr Rybalko break; 67*27cf7d04SAleksandr Rybalko case 2: 68*27cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 2) 69*27cf7d04SAleksandr Rybalko info->wr2(info, o, c); 70*27cf7d04SAleksandr Rybalko break; 71*27cf7d04SAleksandr Rybalko case 3: 72*27cf7d04SAleksandr Rybalko /* line 0 */ 73*27cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 3) { 74*27cf7d04SAleksandr Rybalko info->wr1(info, o, (c >> 16) & 0xff); 75*27cf7d04SAleksandr Rybalko info->wr1(info, o + 1, (c >> 8) & 0xff); 76*27cf7d04SAleksandr Rybalko info->wr1(info, o + 2, c & 0xff); 77*27cf7d04SAleksandr Rybalko } 78*27cf7d04SAleksandr Rybalko break; 79*27cf7d04SAleksandr Rybalko case 4: 80*27cf7d04SAleksandr Rybalko for (o = 0; o < info->fb_stride; o += 4) 81*27cf7d04SAleksandr Rybalko info->wr4(info, o, c); 82*27cf7d04SAleksandr Rybalko break; 83*27cf7d04SAleksandr Rybalko default: 84*27cf7d04SAleksandr Rybalko /* panic? */ 85*27cf7d04SAleksandr Rybalko return; 86*27cf7d04SAleksandr Rybalko } 87*27cf7d04SAleksandr Rybalko /* Copy line0 to all other lines. */ 88*27cf7d04SAleksandr Rybalko /* XXX will copy with borders. */ 89*27cf7d04SAleksandr Rybalko for (o = info->fb_stride; o < info->fb_size; o += info->fb_stride) { 90*27cf7d04SAleksandr Rybalko info->copy(info, o, 0, info->fb_stride); 91*27cf7d04SAleksandr Rybalko } 92*27cf7d04SAleksandr Rybalko } 93*27cf7d04SAleksandr Rybalko 94*27cf7d04SAleksandr Rybalko void 95*27cf7d04SAleksandr Rybalko vt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 96*27cf7d04SAleksandr Rybalko int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 97*27cf7d04SAleksandr Rybalko unsigned int height, term_color_t fg, term_color_t bg) 98*27cf7d04SAleksandr Rybalko { 99*27cf7d04SAleksandr Rybalko struct fb_info *info; 100*27cf7d04SAleksandr Rybalko uint32_t fgc, bgc, cc, o; 101*27cf7d04SAleksandr Rybalko int c, l, bpp; 102*27cf7d04SAleksandr Rybalko u_long line; 103*27cf7d04SAleksandr Rybalko uint8_t b, m; 104*27cf7d04SAleksandr Rybalko const uint8_t *ch; 105*27cf7d04SAleksandr Rybalko 106*27cf7d04SAleksandr Rybalko info = vd->vd_softc; 107*27cf7d04SAleksandr Rybalko bpp = FBTYPE_GET_BYTESPP(info); 108*27cf7d04SAleksandr Rybalko fgc = info->fb_cmap[fg]; 109*27cf7d04SAleksandr Rybalko bgc = info->fb_cmap[bg]; 110*27cf7d04SAleksandr Rybalko b = m = 0; 111*27cf7d04SAleksandr Rybalko if (bpl == 0) 112*27cf7d04SAleksandr Rybalko bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 113*27cf7d04SAleksandr Rybalko 114*27cf7d04SAleksandr Rybalko /* Don't try to put off screen pixels */ 115*27cf7d04SAleksandr Rybalko if (((left + width) > info->fb_width) || ((top + height) > 116*27cf7d04SAleksandr Rybalko info->fb_height)) 117*27cf7d04SAleksandr Rybalko return; 118*27cf7d04SAleksandr Rybalko 119*27cf7d04SAleksandr Rybalko line = (info->fb_stride * top) + (left * bpp); 120*27cf7d04SAleksandr Rybalko for (l = 0; l < height; l++) { 121*27cf7d04SAleksandr Rybalko ch = src; 122*27cf7d04SAleksandr Rybalko for (c = 0; c < width; c++) { 123*27cf7d04SAleksandr Rybalko if (c % 8 == 0) 124*27cf7d04SAleksandr Rybalko b = *ch++; 125*27cf7d04SAleksandr Rybalko else 126*27cf7d04SAleksandr Rybalko b <<= 1; 127*27cf7d04SAleksandr Rybalko if (mask != NULL) { 128*27cf7d04SAleksandr Rybalko if (c % 8 == 0) 129*27cf7d04SAleksandr Rybalko m = *mask++; 130*27cf7d04SAleksandr Rybalko else 131*27cf7d04SAleksandr Rybalko m <<= 1; 132*27cf7d04SAleksandr Rybalko /* Skip pixel write, if mask has no bit set. */ 133*27cf7d04SAleksandr Rybalko if ((m & 0x80) == 0) 134*27cf7d04SAleksandr Rybalko continue; 135*27cf7d04SAleksandr Rybalko } 136*27cf7d04SAleksandr Rybalko o = line + (c * bpp); 137*27cf7d04SAleksandr Rybalko cc = b & 0x80 ? fgc : bgc; 138*27cf7d04SAleksandr Rybalko 139*27cf7d04SAleksandr Rybalko switch(bpp) { 140*27cf7d04SAleksandr Rybalko case 1: 141*27cf7d04SAleksandr Rybalko info->wr1(info, o, cc); 142*27cf7d04SAleksandr Rybalko break; 143*27cf7d04SAleksandr Rybalko case 2: 144*27cf7d04SAleksandr Rybalko info->wr2(info, o, cc); 145*27cf7d04SAleksandr Rybalko break; 146*27cf7d04SAleksandr Rybalko case 3: 147*27cf7d04SAleksandr Rybalko /* Packed mode, so unaligned. Byte access. */ 148*27cf7d04SAleksandr Rybalko info->wr1(info, o, (cc >> 16) & 0xff); 149*27cf7d04SAleksandr Rybalko info->wr1(info, o + 1, (cc >> 8) & 0xff); 150*27cf7d04SAleksandr Rybalko info->wr1(info, o + 2, cc & 0xff); 151*27cf7d04SAleksandr Rybalko break; 152*27cf7d04SAleksandr Rybalko case 4: 153*27cf7d04SAleksandr Rybalko info->wr4(info, o, cc); 154*27cf7d04SAleksandr Rybalko break; 155*27cf7d04SAleksandr Rybalko default: 156*27cf7d04SAleksandr Rybalko /* panic? */ 157*27cf7d04SAleksandr Rybalko break; 158*27cf7d04SAleksandr Rybalko } 159*27cf7d04SAleksandr Rybalko } 160*27cf7d04SAleksandr Rybalko line += info->fb_stride; 161*27cf7d04SAleksandr Rybalko src += bpl; 162*27cf7d04SAleksandr Rybalko } 163*27cf7d04SAleksandr Rybalko } 164*27cf7d04SAleksandr Rybalko 165*27cf7d04SAleksandr Rybalko void 166*27cf7d04SAleksandr Rybalko vt_fb_postswitch(struct vt_device *vd) 167*27cf7d04SAleksandr Rybalko { 168*27cf7d04SAleksandr Rybalko struct fb_info *info; 169*27cf7d04SAleksandr Rybalko 170*27cf7d04SAleksandr Rybalko info = vd->vd_softc; 171*27cf7d04SAleksandr Rybalko 172*27cf7d04SAleksandr Rybalko if (info->enter != NULL) 173*27cf7d04SAleksandr Rybalko info->enter(info->fb_priv); 174*27cf7d04SAleksandr Rybalko } 175*27cf7d04SAleksandr Rybalko 176*27cf7d04SAleksandr Rybalko static int 177*27cf7d04SAleksandr Rybalko vt_fb_init_cmap(uint32_t *cmap, int depth) 178*27cf7d04SAleksandr Rybalko { 179*27cf7d04SAleksandr Rybalko 180*27cf7d04SAleksandr Rybalko switch (depth) { 181*27cf7d04SAleksandr Rybalko case 8: 182*27cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 183*27cf7d04SAleksandr Rybalko 0x7, 5, 0x7, 2, 0x3, 0)); 184*27cf7d04SAleksandr Rybalko case 15: 185*27cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 186*27cf7d04SAleksandr Rybalko 0x1f, 10, 0x1f, 5, 0x1f, 0)); 187*27cf7d04SAleksandr Rybalko case 16: 188*27cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 189*27cf7d04SAleksandr Rybalko 0x1f, 11, 0x3f, 5, 0x1f, 0)); 190*27cf7d04SAleksandr Rybalko case 24: 191*27cf7d04SAleksandr Rybalko case 32: /* Ignore alpha. */ 192*27cf7d04SAleksandr Rybalko return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 193*27cf7d04SAleksandr Rybalko 0xff, 0, 0xff, 8, 0xff, 16)); 194*27cf7d04SAleksandr Rybalko default: 195*27cf7d04SAleksandr Rybalko return (1); 196*27cf7d04SAleksandr Rybalko } 197*27cf7d04SAleksandr Rybalko } 198*27cf7d04SAleksandr Rybalko 199*27cf7d04SAleksandr Rybalko int 200*27cf7d04SAleksandr Rybalko vt_fb_init(struct vt_device *vd) 201*27cf7d04SAleksandr Rybalko { 202*27cf7d04SAleksandr Rybalko struct fb_info *info; 203*27cf7d04SAleksandr Rybalko int err; 204*27cf7d04SAleksandr Rybalko 205*27cf7d04SAleksandr Rybalko info = vd->vd_softc; 206*27cf7d04SAleksandr Rybalko vd->vd_height = info->fb_height; 207*27cf7d04SAleksandr Rybalko vd->vd_width = info->fb_width; 208*27cf7d04SAleksandr Rybalko 209*27cf7d04SAleksandr Rybalko if (info->fb_cmsize <= 0) { 210*27cf7d04SAleksandr Rybalko err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 211*27cf7d04SAleksandr Rybalko if (err) 212*27cf7d04SAleksandr Rybalko return (CN_DEAD); 213*27cf7d04SAleksandr Rybalko info->fb_cmsize = 16; 214*27cf7d04SAleksandr Rybalko } 215*27cf7d04SAleksandr Rybalko 216*27cf7d04SAleksandr Rybalko /* Clear the screen. */ 217*27cf7d04SAleksandr Rybalko vt_fb_blank(vd, TC_BLACK); 218*27cf7d04SAleksandr Rybalko 219*27cf7d04SAleksandr Rybalko /* Wakeup screen. KMS need this. */ 220*27cf7d04SAleksandr Rybalko vt_fb_postswitch(vd); 221*27cf7d04SAleksandr Rybalko 222*27cf7d04SAleksandr Rybalko return (CN_INTERNAL); 223*27cf7d04SAleksandr Rybalko } 224*27cf7d04SAleksandr Rybalko 225*27cf7d04SAleksandr Rybalko int 226*27cf7d04SAleksandr Rybalko vt_fb_attach(struct fb_info *info) 227*27cf7d04SAleksandr Rybalko { 228*27cf7d04SAleksandr Rybalko 229*27cf7d04SAleksandr Rybalko vt_allocate(&vt_fb_driver, info); 230*27cf7d04SAleksandr Rybalko 231*27cf7d04SAleksandr Rybalko return (0); 232*27cf7d04SAleksandr Rybalko } 233*27cf7d04SAleksandr Rybalko 234*27cf7d04SAleksandr Rybalko void 235*27cf7d04SAleksandr Rybalko vt_fb_resume(void) 236*27cf7d04SAleksandr Rybalko { 237*27cf7d04SAleksandr Rybalko 238*27cf7d04SAleksandr Rybalko vt_resume(); 239*27cf7d04SAleksandr Rybalko } 240*27cf7d04SAleksandr Rybalko 241*27cf7d04SAleksandr Rybalko void 242*27cf7d04SAleksandr Rybalko vt_fb_suspend(void) 243*27cf7d04SAleksandr Rybalko { 244*27cf7d04SAleksandr Rybalko 245*27cf7d04SAleksandr Rybalko vt_suspend(); 246*27cf7d04SAleksandr Rybalko } 247