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 321198 2017-07-19 13:11:35Z emaste $ 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: stable/10/sys/dev/vt/hw/fb/vt_fb.c 321198 2017-07-19 13:11:35Z 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 struct vt_driver vt_fb_driver = { 45 .vd_name = "fb", 46 .vd_init = vt_fb_init, 47 .vd_blank = vt_fb_blank, 48 .vd_bitblt_text = vt_fb_bitblt_text, 49 .vd_bitblt_bmp = vt_fb_bitblt_bitmap, 50 .vd_drawrect = vt_fb_drawrect, 51 .vd_setpixel = vt_fb_setpixel, 52 .vd_postswitch = vt_fb_postswitch, 53 .vd_priority = VD_PRIORITY_GENERIC+10, 54 .vd_fb_ioctl = vt_fb_ioctl, 55 .vd_fb_mmap = vt_fb_mmap, 56 .vd_suspend = vt_fb_suspend, 57 .vd_resume = vt_fb_resume, 58}; 59 60VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 61 62static void 63vt_fb_mem_wr1(struct fb_info *sc, uint32_t o, uint8_t v) 64{ 65 66 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 67 *(uint8_t *)(sc->fb_vbase + o) = v; 68} 69 70static void 71vt_fb_mem_wr2(struct fb_info *sc, uint32_t o, uint16_t v) 72{ 73 74 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 75 *(uint16_t *)(sc->fb_vbase + o) = v; 76} 77 78static void 79vt_fb_mem_wr4(struct fb_info *sc, uint32_t o, uint32_t v) 80{ 81 82 KASSERT((o < sc->fb_size), ("Offset %#08x out of fb size", o)); 83 *(uint32_t *)(sc->fb_vbase + o) = v; 84} 85 86int 87vt_fb_ioctl(struct vt_device *vd, u_long cmd, caddr_t data, struct thread *td) 88{ 89 struct fb_info *info; 90 int error = 0; 91 92 info = vd->vd_softc; 93 94 switch (cmd) { 95 case FBIOGTYPE: 96 bcopy(info, (struct fbtype *)data, sizeof(struct fbtype)); 97 break; 98 99 case FBIO_GETWINORG: /* get frame buffer window origin */ 100 *(u_int *)data = 0; 101 break; 102 103 case FBIO_GETDISPSTART: /* get display start address */ 104 ((video_display_start_t *)data)->x = 0; 105 ((video_display_start_t *)data)->y = 0; 106 break; 107 108 case FBIO_GETLINEWIDTH: /* get scan line width in bytes */ 109 *(u_int *)data = info->fb_stride; 110 break; 111 112 case FBIO_BLANK: /* blank display */ 113 if (vd->vd_driver->vd_blank == NULL) 114 return (ENODEV); 115 vd->vd_driver->vd_blank(vd, TC_BLACK); 116 break; 117 118 default: 119 error = ENOIOCTL; 120 break; 121 } 122 123 return (error); 124} 125 126int 127vt_fb_mmap(struct vt_device *vd, vm_ooffset_t offset, vm_paddr_t *paddr, 128 int prot, vm_memattr_t *memattr) 129{ 130 struct fb_info *info; 131 132 info = vd->vd_softc; 133 134 if (info->fb_flags & FB_FLAG_NOMMAP) 135 return (ENODEV); 136 137 if (offset >= 0 && offset < info->fb_size) { 138 *paddr = info->fb_pbase + offset; 139 #ifdef VM_MEMATTR_WRITE_COMBINING 140 *memattr = VM_MEMATTR_WRITE_COMBINING; 141 #endif 142 return (0); 143 } 144 145 return (EINVAL); 146} 147 148void 149vt_fb_setpixel(struct vt_device *vd, int x, int y, term_color_t color) 150{ 151 struct fb_info *info; 152 uint32_t c; 153 u_int o; 154 155 info = vd->vd_softc; 156 c = info->fb_cmap[color]; 157 o = info->fb_stride * y + x * FBTYPE_GET_BYTESPP(info); 158 159 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 160 161 switch (FBTYPE_GET_BYTESPP(info)) { 162 case 1: 163 vt_fb_mem_wr1(info, o, c); 164 break; 165 case 2: 166 vt_fb_mem_wr2(info, o, c); 167 break; 168 case 3: 169 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 170 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 171 vt_fb_mem_wr1(info, o + 2, c & 0xff); 172 break; 173 case 4: 174 vt_fb_mem_wr4(info, o, c); 175 break; 176 default: 177 /* panic? */ 178 return; 179 } 180 181} 182 183void 184vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 185 term_color_t color) 186{ 187 int x, y; 188 189 for (y = y1; y <= y2; y++) { 190 if (fill || (y == y1) || (y == y2)) { 191 for (x = x1; x <= x2; x++) 192 vt_fb_setpixel(vd, x, y, color); 193 } else { 194 vt_fb_setpixel(vd, x1, y, color); 195 vt_fb_setpixel(vd, x2, y, color); 196 } 197 } 198} 199 200void 201vt_fb_blank(struct vt_device *vd, term_color_t color) 202{ 203 struct fb_info *info; 204 uint32_t c; 205 u_int o, h; 206 207 info = vd->vd_softc; 208 c = info->fb_cmap[color]; 209 210 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 211 212 switch (FBTYPE_GET_BYTESPP(info)) { 213 case 1: 214 for (h = 0; h < info->fb_height; h++) 215 for (o = 0; o < info->fb_stride; o++) 216 vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 217 break; 218 case 2: 219 for (h = 0; h < info->fb_height; h++) 220 for (o = 0; o < info->fb_stride; o += 2) 221 vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 222 break; 223 case 3: 224 for (h = 0; h < info->fb_height; h++) 225 for (o = 0; o < info->fb_stride; o += 3) { 226 vt_fb_mem_wr1(info, h*info->fb_stride + o, 227 (c >> 16) & 0xff); 228 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 229 (c >> 8) & 0xff); 230 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 231 c & 0xff); 232 } 233 break; 234 case 4: 235 for (h = 0; h < info->fb_height; h++) 236 for (o = 0; o < info->fb_stride; o += 4) 237 vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 238 break; 239 default: 240 /* panic? */ 241 return; 242 } 243} 244 245void 246vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 247 const uint8_t *pattern, const uint8_t *mask, 248 unsigned int width, unsigned int height, 249 unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 250{ 251 struct fb_info *info; 252 uint32_t fgc, bgc, cc, o; 253 int bpp, bpl, xi, yi; 254 int bit, byte; 255 256 info = vd->vd_softc; 257 bpp = FBTYPE_GET_BYTESPP(info); 258 fgc = info->fb_cmap[fg]; 259 bgc = info->fb_cmap[bg]; 260 bpl = (width + 7) / 8; /* Bytes per source line. */ 261 262 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 263 264 /* Bound by right and bottom edges. */ 265 if (y + height > vw->vw_draw_area.tr_end.tp_row) { 266 if (y >= vw->vw_draw_area.tr_end.tp_row) 267 return; 268 height = vw->vw_draw_area.tr_end.tp_row - y; 269 } 270 if (x + width > vw->vw_draw_area.tr_end.tp_col) { 271 if (x >= vw->vw_draw_area.tr_end.tp_col) 272 return; 273 width = vw->vw_draw_area.tr_end.tp_col - x; 274 } 275 for (yi = 0; yi < height; yi++) { 276 for (xi = 0; xi < width; xi++) { 277 byte = yi * bpl + xi / 8; 278 bit = 0x80 >> (xi % 8); 279 /* Skip pixel write, if mask bit not set. */ 280 if (mask != NULL && (mask[byte] & bit) == 0) 281 continue; 282 o = (y + yi) * info->fb_stride + (x + xi) * bpp; 283 o += vd->vd_transpose; 284 cc = pattern[byte] & bit ? fgc : bgc; 285 286 switch(bpp) { 287 case 1: 288 vt_fb_mem_wr1(info, o, cc); 289 break; 290 case 2: 291 vt_fb_mem_wr2(info, o, cc); 292 break; 293 case 3: 294 /* Packed mode, so unaligned. Byte access. */ 295 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 296 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 297 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 298 break; 299 case 4: 300 vt_fb_mem_wr4(info, o, cc); 301 break; 302 default: 303 /* panic? */ 304 break; 305 } 306 } 307 } 308} 309 310void 311vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 312 const term_rect_t *area) 313{ 314 unsigned int col, row, x, y; 315 struct vt_font *vf; 316 term_char_t c; 317 term_color_t fg, bg; 318 const uint8_t *pattern; 319 320 vf = vw->vw_font; 321 322 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 323 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 324 ++col) { 325 x = col * vf->vf_width + 326 vw->vw_draw_area.tr_begin.tp_col; 327 y = row * vf->vf_height + 328 vw->vw_draw_area.tr_begin.tp_row; 329 330 c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 331 pattern = vtfont_lookup(vf, c); 332 vt_determine_colors(c, 333 VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 334 335 vt_fb_bitblt_bitmap(vd, vw, 336 pattern, NULL, vf->vf_width, vf->vf_height, 337 x, y, fg, bg); 338 } 339 } 340 341#ifndef SC_NO_CUTPASTE 342 if (!vd->vd_mshown) 343 return; 344 345 term_rect_t drawn_area; 346 347 drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 348 drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 349 drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 350 drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 351 352 if (vt_is_cursor_in_area(vd, &drawn_area)) { 353 vt_fb_bitblt_bitmap(vd, vw, 354 vd->vd_mcursor->map, vd->vd_mcursor->mask, 355 vd->vd_mcursor->width, vd->vd_mcursor->height, 356 vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 357 vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 358 vd->vd_mcursor_fg, vd->vd_mcursor_bg); 359 } 360#endif 361} 362 363void 364vt_fb_postswitch(struct vt_device *vd) 365{ 366 struct fb_info *info; 367 368 info = vd->vd_softc; 369 370 if (info->enter != NULL) 371 info->enter(info->fb_priv); 372} 373 374static int 375vt_fb_init_cmap(uint32_t *cmap, int depth) 376{ 377 378 switch (depth) { 379 case 8: 380 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 381 0x7, 5, 0x7, 2, 0x3, 0)); 382 case 15: 383 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 384 0x1f, 10, 0x1f, 5, 0x1f, 0)); 385 case 16: 386 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 387 0x1f, 11, 0x3f, 5, 0x1f, 0)); 388 case 24: 389 case 32: /* Ignore alpha. */ 390 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 391 0xff, 16, 0xff, 8, 0xff, 0)); 392 default: 393 return (1); 394 } 395} 396 397int 398vt_fb_init(struct vt_device *vd) 399{ 400 struct fb_info *info; 401 u_int margin; 402 int err; 403 404 info = vd->vd_softc; 405 vd->vd_height = MIN(VT_FB_MAX_HEIGHT, info->fb_height); 406 margin = (info->fb_height - vd->vd_height) >> 1; 407 vd->vd_transpose = margin * info->fb_stride; 408 vd->vd_width = MIN(VT_FB_MAX_WIDTH, info->fb_width); 409 margin = (info->fb_width - vd->vd_width) >> 1; 410 vd->vd_transpose += margin * (info->fb_bpp / NBBY); 411 412 if (info->fb_size == 0) 413 return (CN_DEAD); 414 415 if (info->fb_pbase == 0) 416 info->fb_flags |= FB_FLAG_NOMMAP; 417 418 if (info->fb_cmsize <= 0) { 419 err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 420 if (err) 421 return (CN_DEAD); 422 info->fb_cmsize = 16; 423 } 424 425 /* Clear the screen. */ 426 vd->vd_driver->vd_blank(vd, TC_BLACK); 427 428 /* Wakeup screen. KMS need this. */ 429 vt_fb_postswitch(vd); 430 431 return (CN_INTERNAL); 432} 433 434int 435vt_fb_attach(struct fb_info *info) 436{ 437 438 vt_allocate(&vt_fb_driver, info); 439 440 return (0); 441} 442 443void 444vt_fb_suspend(struct vt_device *vd) 445{ 446 447 vt_suspend(vd); 448} 449 450void 451vt_fb_resume(struct vt_device *vd) 452{ 453 454 vt_resume(vd); 455} 456