1256904Sray/*- 2256904Sray * Copyright (c) 2013 The FreeBSD Foundation 3256904Sray * All rights reserved. 4256904Sray * 5256904Sray * This software was developed by Aleksandr Rybalko under sponsorship from the 6256904Sray * FreeBSD Foundation. 7256904Sray * 8256904Sray * Redistribution and use in source and binary forms, with or without 9256904Sray * modification, are permitted provided that the following conditions 10256904Sray * are met: 11256904Sray * 1. Redistributions of source code must retain the above copyright 12256904Sray * notice, this list of conditions and the following disclaimer. 13256904Sray * 2. Redistributions in binary form must reproduce the above copyright 14256904Sray * notice, this list of conditions and the following disclaimer in the 15256904Sray * documentation and/or other materials provided with the distribution. 16256904Sray * 17256904Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18256904Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19256904Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20256904Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21256904Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22256904Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23256904Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24256904Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25256904Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26256904Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27256904Sray * SUCH DAMAGE. 28256904Sray * 29256904Sray * $FreeBSD$ 30256904Sray */ 31256904Sray 32256904Sray#include <sys/cdefs.h> 33256904Sray__FBSDID("$FreeBSD$"); 34256904Sray 35256904Sray#include <sys/param.h> 36256904Sray#include <sys/systm.h> 37256904Sray#include <sys/malloc.h> 38256904Sray#include <sys/queue.h> 39256904Sray#include <sys/fbio.h> 40256904Sray#include <dev/vt/vt.h> 41256904Sray#include <dev/vt/hw/fb/vt_fb.h> 42256904Sray#include <dev/vt/colors/vt_termcolors.h> 43256904Sray 44263817Sraystatic int vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, 45263817Sray struct thread *td); 46263817Sraystatic int vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, 47263817Sray vm_paddr_t *paddr, int prot, vm_memattr_t *memattr); 48263817Srayvoid vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, 49263817Sray int fill, term_color_t color); 50263817Srayvoid vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color); 51263817Sray 52256904Sraystatic struct vt_driver vt_fb_driver = { 53256904Sray .vd_init = vt_fb_init, 54256904Sray .vd_blank = vt_fb_blank, 55256904Sray .vd_bitbltchr = vt_fb_bitbltchr, 56263817Sray .vd_drawrect = vt_fb_drawrect, 57263817Sray .vd_setpixel = vt_fb_setpixel, 58256904Sray .vd_postswitch = vt_fb_postswitch, 59256904Sray .vd_priority = VD_PRIORITY_GENERIC+10, 60263817Sray .vd_fb_ioctl = vt_fb_ioctl, 61263817Sray .vd_fb_mmap = vt_fb_mmap, 62256904Sray}; 63256904Sray 64263817Sraystatic int 65263817Srayvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 66263817Sray{ 67263817Sray struct fb_info *info; 68263817Sray 69263817Sray info = vd->vd_softc; 70263817Sray 71263817Sray if (info->fb_ioctl == NULL) 72263817Sray return (-1); 73263817Sray 74263817Sray return (info->fb_ioctl(info->fb_cdev, cmd, data, 0, td)); 75263817Sray} 76263817Sray 77263817Sraystatic int 78263817Srayvt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 79263817Sray int prot, vm_memattr_t *memattr) 80263817Sray{ 81263817Sray struct fb_info *info; 82263817Sray 83263817Sray info = vd->vd_softc; 84263817Sray 85263817Sray if (info->fb_ioctl == NULL) 86263817Sray return (ENXIO); 87263817Sray 88263817Sray return (info->fb_mmap(info->fb_cdev, offset, paddr, prot, memattr)); 89263817Sray} 90263817Sray 91257725Srayvoid 92263817Srayvt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 93263817Sray{ 94263817Sray struct fb_info *info; 95263817Sray uint32_t c; 96263817Sray u_int o; 97263817Sray 98263817Sray info = vd->vd_softc; 99263817Sray c = info->fb_cmap[color]; 100263817Sray o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 101263817Sray 102263817Sray switch (FBTYPE_GET_BYTESPP(info)) { 103263817Sray case 1: 104263817Sray info->wr1(info, o, c); 105263817Sray break; 106263817Sray case 2: 107263817Sray info->wr2(info, o, c); 108263817Sray break; 109263817Sray case 3: 110263817Sray info->wr1(info, o, (c >> 16) & 0xff); 111263817Sray info->wr1(info, o + 1, (c >> 8) & 0xff); 112263817Sray info->wr1(info, o + 2, c & 0xff); 113263817Sray break; 114263817Sray case 4: 115263817Sray info->wr4(info, o, c); 116263817Sray break; 117263817Sray default: 118263817Sray /* panic? */ 119263817Sray return; 120263817Sray } 121263817Sray 122263817Sray} 123263817Sray 124263817Srayvoid 125263817Srayvt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 126263817Sray term_color_t color) 127263817Sray{ 128263817Sray int x, y; 129263817Sray 130263817Sray for (y = y1; y <= y2; y++) { 131263817Sray if (fill || (y == y1) || (y == y2)) { 132263817Sray for (x = x1; x <= x2; x++) 133263817Sray vt_fb_setpixel(vd, x, y, color); 134263817Sray } else { 135263817Sray vt_fb_setpixel(vd, x1, y, color); 136263817Sray vt_fb_setpixel(vd, x2, y, color); 137263817Sray } 138263817Sray } 139263817Sray} 140263817Sray 141263817Srayvoid 142256904Srayvt_fb_blank(struct vt_device *vd, term_color_t color) 143256904Sray{ 144256904Sray struct fb_info *info; 145256904Sray uint32_t c; 146256904Sray u_int o; 147256904Sray 148256904Sray info = vd->vd_softc; 149256904Sray c = info->fb_cmap[color]; 150257725Sray 151256904Sray switch (FBTYPE_GET_BYTESPP(info)) { 152256904Sray case 1: 153256904Sray for (o = 0; o < info->fb_stride; o++) 154256904Sray info->wr1(info, o, c); 155256904Sray break; 156256904Sray case 2: 157256904Sray for (o = 0; o < info->fb_stride; o += 2) 158256904Sray info->wr2(info, o, c); 159256904Sray break; 160256904Sray case 3: 161256904Sray /* line 0 */ 162256904Sray for (o = 0; o < info->fb_stride; o += 3) { 163256904Sray info->wr1(info, o, (c >> 16) & 0xff); 164256904Sray info->wr1(info, o + 1, (c >> 8) & 0xff); 165256904Sray info->wr1(info, o + 2, c & 0xff); 166256904Sray } 167256904Sray break; 168256904Sray case 4: 169256904Sray for (o = 0; o < info->fb_stride; o += 4) 170256904Sray info->wr4(info, o, c); 171256904Sray break; 172256904Sray default: 173256904Sray /* panic? */ 174256904Sray return; 175256904Sray } 176256904Sray /* Copy line0 to all other lines. */ 177256904Sray /* XXX will copy with borders. */ 178257013Sray for (o = info->fb_stride; o < info->fb_size; o += info->fb_stride) { 179257013Sray info->copy(info, o, 0, info->fb_stride); 180256904Sray } 181256904Sray} 182256904Sray 183257725Srayvoid 184257988Srayvt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 185257988Sray int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 186257988Sray unsigned int height, term_color_t fg, term_color_t bg) 187256904Sray{ 188256904Sray struct fb_info *info; 189256904Sray uint32_t fgc, bgc, cc, o; 190256904Sray int c, l, bpp; 191256904Sray u_long line; 192257988Sray uint8_t b, m; 193257988Sray const uint8_t *ch; 194256904Sray 195256904Sray info = vd->vd_softc; 196256904Sray bpp = FBTYPE_GET_BYTESPP(info); 197256904Sray fgc = info->fb_cmap[fg]; 198256904Sray bgc = info->fb_cmap[bg]; 199258781Snwhitehorn b = m = 0; 200257988Sray if (bpl == 0) 201257988Sray bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 202256904Sray 203257988Sray /* Don't try to put off screen pixels */ 204257988Sray if (((left + width) > info->fb_width) || ((top + height) > 205257988Sray info->fb_height)) 206257988Sray return; 207257988Sray 208256904Sray line = (info->fb_stride * top) + (left * bpp); 209256904Sray for (l = 0; l < height; l++) { 210257988Sray ch = src; 211256904Sray for (c = 0; c < width; c++) { 212256904Sray if (c % 8 == 0) 213257988Sray b = *ch++; 214256904Sray else 215256904Sray b <<= 1; 216257988Sray if (mask != NULL) { 217257988Sray if (c % 8 == 0) 218257988Sray m = *mask++; 219257988Sray else 220257988Sray m <<= 1; 221257988Sray /* Skip pixel write, if mask has no bit set. */ 222257988Sray if ((m & 0x80) == 0) 223257988Sray continue; 224257988Sray } 225256904Sray o = line + (c * bpp); 226256904Sray cc = b & 0x80 ? fgc : bgc; 227256904Sray 228256904Sray switch(bpp) { 229256904Sray case 1: 230256904Sray info->wr1(info, o, cc); 231256904Sray break; 232256904Sray case 2: 233256904Sray info->wr2(info, o, cc); 234256904Sray break; 235256904Sray case 3: 236256904Sray /* Packed mode, so unaligned. Byte access. */ 237256904Sray info->wr1(info, o, (cc >> 16) & 0xff); 238256904Sray info->wr1(info, o + 1, (cc >> 8) & 0xff); 239256904Sray info->wr1(info, o + 2, cc & 0xff); 240256904Sray break; 241256904Sray case 4: 242256904Sray info->wr4(info, o, cc); 243256904Sray break; 244256904Sray default: 245256904Sray /* panic? */ 246256904Sray break; 247256904Sray } 248256904Sray } 249256904Sray line += info->fb_stride; 250257988Sray src += bpl; 251256904Sray } 252256904Sray} 253256904Sray 254257725Srayvoid 255256904Srayvt_fb_postswitch(struct vt_device *vd) 256256904Sray{ 257256904Sray struct fb_info *info; 258256904Sray 259256904Sray info = vd->vd_softc; 260256904Sray 261256904Sray if (info->enter != NULL) 262256904Sray info->enter(info->fb_priv); 263256904Sray} 264256904Sray 265256904Sraystatic int 266256904Srayvt_fb_init_cmap(uint32_t *cmap, int depth) 267256904Sray{ 268256904Sray 269256904Sray switch (depth) { 270256904Sray case 8: 271256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 272256904Sray 0x7, 5, 0x7, 2, 0x3, 0)); 273256904Sray case 15: 274256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 275256904Sray 0x1f, 10, 0x1f, 5, 0x1f, 0)); 276256904Sray case 16: 277256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 278256904Sray 0x1f, 11, 0x3f, 5, 0x1f, 0)); 279256904Sray case 24: 280256904Sray case 32: /* Ignore alpha. */ 281256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 282256904Sray 0xff, 0, 0xff, 8, 0xff, 16)); 283256904Sray default: 284256904Sray return (1); 285256904Sray } 286256904Sray} 287256904Sray 288257725Srayint 289256904Srayvt_fb_init(struct vt_device *vd) 290256904Sray{ 291256904Sray struct fb_info *info; 292256904Sray int err; 293256904Sray 294256904Sray info = vd->vd_softc; 295256904Sray vd->vd_height = info->fb_height; 296256904Sray vd->vd_width = info->fb_width; 297256904Sray 298256904Sray if (info->fb_cmsize <= 0) { 299256904Sray err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 300256904Sray if (err) 301256904Sray return (CN_DEAD); 302256904Sray info->fb_cmsize = 16; 303256904Sray } 304256904Sray 305256904Sray /* Clear the screen. */ 306256904Sray vt_fb_blank(vd, TC_BLACK); 307256904Sray 308256904Sray /* Wakeup screen. KMS need this. */ 309256904Sray vt_fb_postswitch(vd); 310256904Sray 311256904Sray return (CN_INTERNAL); 312256904Sray} 313256904Sray 314256904Srayint 315256904Srayvt_fb_attach(struct fb_info *info) 316256904Sray{ 317256904Sray 318256904Sray vt_allocate(&vt_fb_driver, info); 319257725Sray 320256904Sray return (0); 321256904Sray} 322257815Sray 323257815Srayvoid 324257815Srayvt_fb_resume(void) 325257815Sray{ 326257815Sray 327257815Sray vt_resume(); 328257815Sray} 329257815Sray 330257815Srayvoid 331257815Srayvt_fb_suspend(void) 332257815Sray{ 333257815Sray 334257815Sray vt_suspend(); 335257815Sray} 336