vt_fb.c revision 271128
1/*- 2 * Copyright (c) 2013 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Aleksandr Rybalko under sponsorship from the 6 * FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 271128 2014-09-04 20:18:08Z emaste $ 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 271128 2014-09-04 20:18:08Z emaste $"); 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/malloc.h> 38#include <sys/queue.h> 39#include <sys/fbio.h> 40#include <dev/vt/vt.h> 41#include <dev/vt/hw/fb/vt_fb.h> 42#include <dev/vt/colors/vt_termcolors.h> 43 44static vd_drawrect_t vt_fb_drawrect; 45static vd_setpixel_t vt_fb_setpixel; 46 47static struct vt_driver vt_fb_driver = { 48 .vd_name = "fb", 49 .vd_init = vt_fb_init, 50 .vd_blank = vt_fb_blank, 51 .vd_bitblt_text = vt_fb_bitblt_text, 52 .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 53 .vd_drawrect = vt_fb_drawrect, 54 .vd_setpixel = vt_fb_setpixel, 55 .vd_postswitch = vt_fb_postswitch, 56 .vd_priority = VD_PRIORITY_GENERIC+10, 57 .vd_fb_ioctl = vt_fb_ioctl, 58 .vd_fb_mmap = vt_fb_mmap, 59}; 60 61VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 62 63static void 64vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 65{ 66 67 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 68 *(uint8_t *)(sc->fb_vbase + o) = v; 69} 70 71static void 72vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 73{ 74 75 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 76 *(uint16_t *)(sc->fb_vbase + o) = v; 77} 78 79static void 80vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 81{ 82 83 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 84 *(uint32_t *)(sc->fb_vbase + o) = v; 85} 86 87int 88vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 89{ 90 struct fb_info *info; 91 int error = 0; 92 93 info = vd->vd_softc; 94 95 switch (cmd) { 96 case FBIOGTYPE: 97 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 98 break; 99 100 case FBIO_GETWINORG: /* get frame buffer window origin */ 101 *(u_int *)data = 0; 102 break; 103 104 case FBIO_GETDISPSTART: /* get display start address */ 105 ((video_display_start_t *)data)->x = 0; 106 ((video_display_start_t *)data)->y = 0; 107 break; 108 109 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 110 *(u_int *)data = info->fb_stride; 111 break; 112 113 case FBIO_BLANK: /* blank display */ 114 if (vd->vd_driver->vd_blank == NULL) 115 return (ENODEV); 116 vd->vd_driver->vd_blank(vd, TC_BLACK); 117 break; 118 119 default: 120 error = ENOIOCTL; 121 break; 122 } 123 124 return (error); 125} 126 127int 128vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 129 int prot, vm_memattr_t *memattr) 130{ 131 struct fb_info *info; 132 133 info = vd->vd_softc; 134 135 if (info->fb_flags & FB_FLAG_NOMMAP) 136 return (ENODEV); 137 138 if (offset >= 0 && offset < info->fb_size) { 139 *paddr = info->fb_pbase + offset; 140 #ifdef VM_MEMATTR_WRITE_COMBINING 141 *memattr = VM_MEMATTR_WRITE_COMBINING; 142 #endif 143 return (0); 144 } 145 146 return (EINVAL); 147} 148 149static void 150vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 151{ 152 struct fb_info *info; 153 uint32_t c; 154 u_int o; 155 156 info = vd->vd_softc; 157 c = info->fb_cmap[color]; 158 o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 159 160 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 161 162 switch (FBTYPE_GET_BYTESPP(info)) { 163 case 1: 164 vt_fb_mem_wr1(info, o, c); 165 break; 166 case 2: 167 vt_fb_mem_wr2(info, o, c); 168 break; 169 case 3: 170 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 171 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 172 vt_fb_mem_wr1(info, o + 2, c & 0xff); 173 break; 174 case 4: 175 vt_fb_mem_wr4(info, o, c); 176 break; 177 default: 178 /* panic? */ 179 return; 180 } 181 182} 183 184static void 185vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 186 term_color_t color) 187{ 188 int x, y; 189 190 for (y = y1; y <= y2; y++) { 191 if (fill || (y == y1) || (y == y2)) { 192 for (x = x1; x <= x2; x++) 193 vt_fb_setpixel(vd, x, y, color); 194 } else { 195 vt_fb_setpixel(vd, x1, y, color); 196 vt_fb_setpixel(vd, x2, y, color); 197 } 198 } 199} 200 201void 202vt_fb_blank(struct vt_device *vd, term_color_t color) 203{ 204 struct fb_info *info; 205 uint32_t c; 206 u_int o, h; 207 208 info = vd->vd_softc; 209 c = info->fb_cmap[color]; 210 211 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 212 213 switch (FBTYPE_GET_BYTESPP(info)) { 214 case 1: 215 for (h = 0; h < info->fb_height; h++) 216 for (o = 0; o < info->fb_stride; o++) 217 vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 218 break; 219 case 2: 220 for (h = 0; h < info->fb_height; h++) 221 for (o = 0; o < info->fb_stride; o += 2) 222 vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 223 break; 224 case 3: 225 for (h = 0; h < info->fb_height; h++) 226 for (o = 0; o < info->fb_stride; o += 3) { 227 vt_fb_mem_wr1(info, h*info->fb_stride + o, 228 (c >> 16) & 0xff); 229 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 230 (c >> 8) & 0xff); 231 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 232 c & 0xff); 233 } 234 break; 235 case 4: 236 for (h = 0; h < info->fb_height; h++) 237 for (o = 0; o < info->fb_stride; o += 4) 238 vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 239 break; 240 default: 241 /* panic? */ 242 return; 243 } 244} 245 246void 247vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 248 const uint8_t *pattern, const uint8_t *mask, 249 unsigned int width, unsigned int height, 250 unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 251{ 252 struct fb_info *info; 253 uint32_t fgc, bgc, cc, o; 254 int c, l, bpp, bpl; 255 u_long line; 256 uint8_t b, m; 257 const uint8_t *ch; 258 259 info = vd->vd_softc; 260 bpp = FBTYPE_GET_BYTESPP(info); 261 fgc = info->fb_cmap[fg]; 262 bgc = info->fb_cmap[bg]; 263 b = m = 0; 264 bpl = (width + 7) >> 3; /* Bytes per source line. */ 265 266 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 267 268 line = (info->fb_stride * y) + (x * bpp); 269 for (l = 0; 270 l < height && y + l < vw->vw_draw_area.tr_end.tp_row; 271 l++) { 272 ch = pattern; 273 for (c = 0; 274 c < width && x + c < vw->vw_draw_area.tr_end.tp_col; 275 c++) { 276 if (c % 8 == 0) 277 b = *ch++; 278 else 279 b <<= 1; 280 if (mask != NULL) { 281 if (c % 8 == 0) 282 m = *mask++; 283 else 284 m <<= 1; 285 /* Skip pixel write, if mask has no bit set. */ 286 if ((m & 0x80) == 0) 287 continue; 288 } 289 o = line + (c * bpp); 290 cc = b & 0x80 ? fgc : bgc; 291 292 switch(bpp) { 293 case 1: 294 vt_fb_mem_wr1(info, o, cc); 295 break; 296 case 2: 297 vt_fb_mem_wr2(info, o, cc); 298 break; 299 case 3: 300 /* Packed mode, so unaligned. Byte access. */ 301 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 302 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 303 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 304 break; 305 case 4: 306 vt_fb_mem_wr4(info, o, cc); 307 break; 308 default: 309 /* panic? */ 310 break; 311 } 312 } 313 line += info->fb_stride; 314 pattern += bpl; 315 } 316} 317 318void 319vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 320 const term_rect_t *area) 321{ 322 unsigned int col, row, x, y; 323 struct vt_font *vf; 324 term_char_t c; 325 term_color_t fg, bg; 326 const uint8_t *pattern; 327 328 vf = vw->vw_font; 329 330 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 331 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 332 ++col) { 333 x = col * vf->vf_width + 334 vw->vw_draw_area.tr_begin.tp_col; 335 y = row * vf->vf_height + 336 vw->vw_draw_area.tr_begin.tp_row; 337 338 c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 339 pattern = vtfont_lookup(vf, c); 340 vt_determine_colors(c, 341 VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 342 343 vt_fb_bitblt_bitmap(vd, vw, 344 pattern, NULL, vf->vf_width, vf->vf_height, 345 x, y, fg, bg); 346 } 347 } 348 349#ifndef SC_NO_CUTPASTE 350 if (!vd->vd_mshown) 351 return; 352 353 term_rect_t drawn_area; 354 355 drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 356 drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 357 drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 358 drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 359 360 if (vt_is_cursor_in_area(vd, &drawn_area)) { 361 vt_fb_bitblt_bitmap(vd, vw, 362 vd->vd_mcursor->map, vd->vd_mcursor->mask, 363 vd->vd_mcursor->width, vd->vd_mcursor->height, 364 vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 365 vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 366 vd->vd_mcursor_fg, vd->vd_mcursor_bg); 367 } 368#endif 369} 370 371void 372vt_fb_postswitch(struct vt_device *vd) 373{ 374 struct fb_info *info; 375 376 info = vd->vd_softc; 377 378 if (info->enter != NULL) 379 info->enter(info->fb_priv); 380} 381 382static int 383vt_fb_init_cmap(uint32_t *cmap, int depth) 384{ 385 386 switch (depth) { 387 case 8: 388 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 389 0x7, 5, 0x7, 2, 0x3, 0)); 390 case 15: 391 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 392 0x1f, 10, 0x1f, 5, 0x1f, 0)); 393 case 16: 394 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 395 0x1f, 11, 0x3f, 5, 0x1f, 0)); 396 case 24: 397 case 32: /* Ignore alpha. */ 398 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 399 0xff, 16, 0xff, 8, 0xff, 0)); 400 default: 401 return (1); 402 } 403} 404 405int 406vt_fb_init(struct vt_device *vd) 407{ 408 struct fb_info *info; 409 int err; 410 411 info = vd->vd_softc; 412 vd->vd_height = info->fb_height; 413 vd->vd_width = info->fb_width; 414 415 if (info->fb_size == 0) 416 return (CN_DEAD); 417 418 if (info->fb_pbase == 0) 419 info->fb_flags |= FB_FLAG_NOMMAP; 420 421 if (info->fb_cmsize <= 0) { 422 err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 423 if (err) 424 return (CN_DEAD); 425 info->fb_cmsize = 16; 426 } 427 428 /* Clear the screen. */ 429 vd->vd_driver->vd_blank(vd, TC_BLACK); 430 431 /* Wakeup screen. KMS need this. */ 432 vt_fb_postswitch(vd); 433 434 return (CN_INTERNAL); 435} 436 437int 438vt_fb_attach(struct fb_info *info) 439{ 440 441 vt_allocate(&vt_fb_driver, info); 442 443 return (0); 444} 445 446void 447vt_fb_resume(void) 448{ 449 450 vt_resume(); 451} 452 453void 454vt_fb_suspend(void) 455{ 456 457 vt_suspend(); 458} 459