vt_fb.c revision 269437
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: head/sys/dev/vt/hw/fb/vt_fb.c 269437 2014-08-02 17:45:08Z nwhitehorn $ 30256904Sray */ 31256904Sray 32256904Sray#include <sys/cdefs.h> 33256904Sray__FBSDID("$FreeBSD: head/sys/dev/vt/hw/fb/vt_fb.c 269437 2014-08-02 17:45:08Z nwhitehorn $"); 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 44261552Srayvoid vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, 45261552Sray int fill, term_color_t color); 46261552Srayvoid vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color); 47259777Sray 48256904Sraystatic struct vt_driver vt_fb_driver = { 49265397Sray .vd_name = "fb", 50256904Sray .vd_init = vt_fb_init, 51256904Sray .vd_blank = vt_fb_blank, 52256904Sray .vd_bitbltchr = vt_fb_bitbltchr, 53265397Sray .vd_maskbitbltchr = vt_fb_maskbitbltchr, 54261552Sray .vd_drawrect = vt_fb_drawrect, 55261552Sray .vd_setpixel = vt_fb_setpixel, 56256904Sray .vd_postswitch = vt_fb_postswitch, 57256904Sray .vd_priority = VD_PRIORITY_GENERIC+10, 58259777Sray .vd_fb_ioctl = vt_fb_ioctl, 59259777Sray .vd_fb_mmap = vt_fb_mmap, 60256904Sray}; 61256904Sray 62265397SrayVT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 63265397Sray 64268771Snwhitehornint 65259777Srayvt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 66259777Sray{ 67259777Sray struct fb_info *info; 68268771Snwhitehorn int error = 0; 69259777Sray 70259777Sray info = vd->vd_softc; 71259777Sray 72268771Snwhitehorn switch (cmd) { 73268771Snwhitehorn case FBIOGTYPE: 74268771Snwhitehorn bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 75268771Snwhitehorn break; 76259777Sray 77268771Snwhitehorn case FBIO_GETWINORG: /* get frame buffer window origin */ 78268771Snwhitehorn *(u_int *)data = 0; 79268771Snwhitehorn break; 80268771Snwhitehorn 81268771Snwhitehorn case FBIO_GETDISPSTART: /* get display start address */ 82268771Snwhitehorn ((video_display_start_t *)data)->x = 0; 83268771Snwhitehorn ((video_display_start_t *)data)->y = 0; 84268771Snwhitehorn break; 85268771Snwhitehorn 86268771Snwhitehorn case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 87268771Snwhitehorn *(u_int *)data = info->fb_stride; 88268771Snwhitehorn break; 89268771Snwhitehorn 90268771Snwhitehorn case FBIO_BLANK: /* blank display */ 91268771Snwhitehorn if (vd->vd_driver->vd_blank == NULL) 92268771Snwhitehorn return (ENODEV); 93268771Snwhitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 94268771Snwhitehorn break; 95268771Snwhitehorn 96268771Snwhitehorn default: 97268771Snwhitehorn error = ENOIOCTL; 98268771Snwhitehorn break; 99268771Snwhitehorn } 100268771Snwhitehorn 101268771Snwhitehorn return (error); 102259777Sray} 103259777Sray 104268771Snwhitehornint 105260953Srayvt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 106260953Sray int prot, vm_memattr_t *memattr) 107259777Sray{ 108259777Sray struct fb_info *info; 109259777Sray 110259777Sray info = vd->vd_softc; 111259777Sray 112268771Snwhitehorn if (info->fb_flags & FB_FLAG_NOMMAP) 113268771Snwhitehorn return (ENODEV); 114259777Sray 115268771Snwhitehorn if (offset >= 0 && offset < info->fb_size) { 116268771Snwhitehorn *paddr = info->fb_pbase + offset; 117268771Snwhitehorn #ifdef VM_MEMATTR_WRITE_COMBINING 118268771Snwhitehorn *memattr = VM_MEMATTR_WRITE_COMBINING; 119268771Snwhitehorn #endif 120268771Snwhitehorn return (0); 121268771Snwhitehorn } 122268771Snwhitehorn 123268771Snwhitehorn return (EINVAL); 124259777Sray} 125259777Sray 126257725Srayvoid 127261552Srayvt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 128261552Sray{ 129261552Sray struct fb_info *info; 130261552Sray uint32_t c; 131261552Sray u_int o; 132261552Sray 133261552Sray info = vd->vd_softc; 134261552Sray c = info->fb_cmap[color]; 135261552Sray o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 136261552Sray 137261552Sray switch (FBTYPE_GET_BYTESPP(info)) { 138261552Sray case 1: 139261552Sray info->wr1(info, o, c); 140261552Sray break; 141261552Sray case 2: 142261552Sray info->wr2(info, o, c); 143261552Sray break; 144261552Sray case 3: 145261552Sray info->wr1(info, o, (c >> 16) & 0xff); 146261552Sray info->wr1(info, o + 1, (c >> 8) & 0xff); 147261552Sray info->wr1(info, o + 2, c & 0xff); 148261552Sray break; 149261552Sray case 4: 150261552Sray info->wr4(info, o, c); 151261552Sray break; 152261552Sray default: 153261552Sray /* panic? */ 154261552Sray return; 155261552Sray } 156261552Sray 157261552Sray} 158261552Sray 159261552Srayvoid 160261552Srayvt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 161261552Sray term_color_t color) 162261552Sray{ 163261552Sray int x, y; 164261552Sray 165261552Sray for (y = y1; y <= y2; y++) { 166261552Sray if (fill || (y == y1) || (y == y2)) { 167261552Sray for (x = x1; x <= x2; x++) 168261552Sray vt_fb_setpixel(vd, x, y, color); 169261552Sray } else { 170261552Sray vt_fb_setpixel(vd, x1, y, color); 171261552Sray vt_fb_setpixel(vd, x2, y, color); 172261552Sray } 173261552Sray } 174261552Sray} 175261552Sray 176261552Srayvoid 177256904Srayvt_fb_blank(struct vt_device *vd, term_color_t color) 178256904Sray{ 179256904Sray struct fb_info *info; 180256904Sray uint32_t c; 181268771Snwhitehorn u_int o, h; 182256904Sray 183256904Sray info = vd->vd_softc; 184256904Sray c = info->fb_cmap[color]; 185257725Sray 186256904Sray switch (FBTYPE_GET_BYTESPP(info)) { 187256904Sray case 1: 188268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 189268771Snwhitehorn for (o = 0; o < info->fb_stride; o++) 190268771Snwhitehorn info->wr1(info, h*info->fb_stride + o, c); 191256904Sray break; 192256904Sray case 2: 193268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 194268771Snwhitehorn for (o = 0; o < info->fb_stride; o += 2) 195268771Snwhitehorn info->wr2(info, h*info->fb_stride + o, c); 196256904Sray break; 197256904Sray case 3: 198268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 199268771Snwhitehorn for (o = 0; o < info->fb_stride; o += 3) { 200268771Snwhitehorn info->wr1(info, h*info->fb_stride + o, 201268771Snwhitehorn (c >> 16) & 0xff); 202268771Snwhitehorn info->wr1(info, h*info->fb_stride + o + 1, 203268771Snwhitehorn (c >> 8) & 0xff); 204268771Snwhitehorn info->wr1(info, h*info->fb_stride + o + 2, 205268771Snwhitehorn c & 0xff); 206268771Snwhitehorn } 207256904Sray break; 208256904Sray case 4: 209268796Snwhitehorn for (h = 0; h < info->fb_height; h++) 210268771Snwhitehorn for (o = 0; o < info->fb_stride; o += 4) 211268796Snwhitehorn info->wr4(info, h*info->fb_stride + o, c); 212256904Sray break; 213256904Sray default: 214256904Sray /* panic? */ 215256904Sray return; 216256904Sray } 217256904Sray} 218256904Sray 219257725Srayvoid 220257988Srayvt_fb_bitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 221257988Sray int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 222257988Sray unsigned int height, term_color_t fg, term_color_t bg) 223256904Sray{ 224256904Sray struct fb_info *info; 225256904Sray uint32_t fgc, bgc, cc, o; 226256904Sray int c, l, bpp; 227256904Sray u_long line; 228265397Sray uint8_t b; 229265397Sray const uint8_t *ch; 230265397Sray 231265397Sray info = vd->vd_softc; 232265397Sray bpp = FBTYPE_GET_BYTESPP(info); 233265397Sray fgc = info->fb_cmap[fg]; 234265397Sray bgc = info->fb_cmap[bg]; 235265397Sray b = 0; 236265397Sray if (bpl == 0) 237265397Sray bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 238265397Sray 239265397Sray /* Don't try to put off screen pixels */ 240265397Sray if (((left + width) > info->fb_width) || ((top + height) > 241265397Sray info->fb_height)) 242265397Sray return; 243265397Sray 244265397Sray line = (info->fb_stride * top) + (left * bpp); 245265397Sray for (l = 0; l < height; l++) { 246265397Sray ch = src; 247265397Sray for (c = 0; c < width; c++) { 248265397Sray if (c % 8 == 0) 249265397Sray b = *ch++; 250265397Sray else 251265397Sray b <<= 1; 252265397Sray o = line + (c * bpp); 253265397Sray cc = b & 0x80 ? fgc : bgc; 254265397Sray 255265397Sray switch(bpp) { 256265397Sray case 1: 257265397Sray info->wr1(info, o, cc); 258265397Sray break; 259265397Sray case 2: 260265397Sray info->wr2(info, o, cc); 261265397Sray break; 262265397Sray case 3: 263265397Sray /* Packed mode, so unaligned. Byte access. */ 264265397Sray info->wr1(info, o, (cc >> 16) & 0xff); 265265397Sray info->wr1(info, o + 1, (cc >> 8) & 0xff); 266265397Sray info->wr1(info, o + 2, cc & 0xff); 267265397Sray break; 268265397Sray case 4: 269265397Sray info->wr4(info, o, cc); 270265397Sray break; 271265397Sray default: 272265397Sray /* panic? */ 273265397Sray break; 274265397Sray } 275265397Sray } 276265397Sray line += info->fb_stride; 277265397Sray src += bpl; 278265397Sray } 279265397Sray} 280265397Sray 281265397Srayvoid 282265397Srayvt_fb_maskbitbltchr(struct vt_device *vd, const uint8_t *src, const uint8_t *mask, 283265397Sray int bpl, vt_axis_t top, vt_axis_t left, unsigned int width, 284265397Sray unsigned int height, term_color_t fg, term_color_t bg) 285265397Sray{ 286265397Sray struct fb_info *info; 287265397Sray uint32_t fgc, bgc, cc, o; 288265397Sray int c, l, bpp; 289265397Sray u_long line; 290257988Sray uint8_t b, m; 291257988Sray const uint8_t *ch; 292256904Sray 293256904Sray info = vd->vd_softc; 294256904Sray bpp = FBTYPE_GET_BYTESPP(info); 295256904Sray fgc = info->fb_cmap[fg]; 296256904Sray bgc = info->fb_cmap[bg]; 297258781Snwhitehorn b = m = 0; 298257988Sray if (bpl == 0) 299257988Sray bpl = (width + 7) >> 3; /* Bytes per sorce line. */ 300256904Sray 301257988Sray /* Don't try to put off screen pixels */ 302257988Sray if (((left + width) > info->fb_width) || ((top + height) > 303257988Sray info->fb_height)) 304257988Sray return; 305257988Sray 306256904Sray line = (info->fb_stride * top) + (left * bpp); 307256904Sray for (l = 0; l < height; l++) { 308257988Sray ch = src; 309256904Sray for (c = 0; c < width; c++) { 310256904Sray if (c % 8 == 0) 311257988Sray b = *ch++; 312256904Sray else 313256904Sray b <<= 1; 314257988Sray if (mask != NULL) { 315257988Sray if (c % 8 == 0) 316257988Sray m = *mask++; 317257988Sray else 318257988Sray m <<= 1; 319257988Sray /* Skip pixel write, if mask has no bit set. */ 320257988Sray if ((m & 0x80) == 0) 321257988Sray continue; 322257988Sray } 323256904Sray o = line + (c * bpp); 324256904Sray cc = b & 0x80 ? fgc : bgc; 325256904Sray 326256904Sray switch(bpp) { 327256904Sray case 1: 328256904Sray info->wr1(info, o, cc); 329256904Sray break; 330256904Sray case 2: 331256904Sray info->wr2(info, o, cc); 332256904Sray break; 333256904Sray case 3: 334256904Sray /* Packed mode, so unaligned. Byte access. */ 335256904Sray info->wr1(info, o, (cc >> 16) & 0xff); 336256904Sray info->wr1(info, o + 1, (cc >> 8) & 0xff); 337256904Sray info->wr1(info, o + 2, cc & 0xff); 338256904Sray break; 339256904Sray case 4: 340256904Sray info->wr4(info, o, cc); 341256904Sray break; 342256904Sray default: 343256904Sray /* panic? */ 344256904Sray break; 345256904Sray } 346256904Sray } 347256904Sray line += info->fb_stride; 348257988Sray src += bpl; 349256904Sray } 350256904Sray} 351256904Sray 352257725Srayvoid 353256904Srayvt_fb_postswitch(struct vt_device *vd) 354256904Sray{ 355256904Sray struct fb_info *info; 356256904Sray 357256904Sray info = vd->vd_softc; 358256904Sray 359256904Sray if (info->enter != NULL) 360256904Sray info->enter(info->fb_priv); 361256904Sray} 362256904Sray 363256904Sraystatic int 364256904Srayvt_fb_init_cmap(uint32_t *cmap, int depth) 365256904Sray{ 366256904Sray 367256904Sray switch (depth) { 368256904Sray case 8: 369256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 370256904Sray 0x7, 5, 0x7, 2, 0x3, 0)); 371256904Sray case 15: 372256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 373256904Sray 0x1f, 10, 0x1f, 5, 0x1f, 0)); 374256904Sray case 16: 375256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 376256904Sray 0x1f, 11, 0x3f, 5, 0x1f, 0)); 377256904Sray case 24: 378256904Sray case 32: /* Ignore alpha. */ 379256904Sray return (vt_generate_vga_palette(cmap, COLOR_FORMAT_RGB, 380256904Sray 0xff, 0, 0xff, 8, 0xff, 16)); 381256904Sray default: 382256904Sray return (1); 383256904Sray } 384256904Sray} 385256904Sray 386257725Srayint 387256904Srayvt_fb_init(struct vt_device *vd) 388256904Sray{ 389256904Sray struct fb_info *info; 390256904Sray int err; 391256904Sray 392256904Sray info = vd->vd_softc; 393256904Sray vd->vd_height = info->fb_height; 394256904Sray vd->vd_width = info->fb_width; 395256904Sray 396256904Sray if (info->fb_cmsize <= 0) { 397256904Sray err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 398256904Sray if (err) 399256904Sray return (CN_DEAD); 400256904Sray info->fb_cmsize = 16; 401256904Sray } 402256904Sray 403256904Sray /* Clear the screen. */ 404269437Snwhitehorn vd->vd_driver->vd_blank(vd, TC_BLACK); 405256904Sray 406256904Sray /* Wakeup screen. KMS need this. */ 407256904Sray vt_fb_postswitch(vd); 408256904Sray 409256904Sray return (CN_INTERNAL); 410256904Sray} 411256904Sray 412256904Srayint 413256904Srayvt_fb_attach(struct fb_info *info) 414256904Sray{ 415256904Sray 416256904Sray vt_allocate(&vt_fb_driver, info); 417257725Sray 418256904Sray return (0); 419256904Sray} 420257815Sray 421257815Srayvoid 422257815Srayvt_fb_resume(void) 423257815Sray{ 424257815Sray 425257815Sray vt_resume(); 426257815Sray} 427257815Sray 428257815Srayvoid 429257815Srayvt_fb_suspend(void) 430257815Sray{ 431257815Sray 432257815Sray vt_suspend(); 433257815Sray} 434