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$ 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 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 44 static 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 60 VT_DRIVER_DECLARE(vt_fb, vt_fb_driver); 61 62 static void 63 vt_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 70 static void 71 vt_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 78 static void 79 vt_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 86 int 87 vt_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 126 int 127 vt_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 148 void 149 vt_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 if (info->fb_flags & FB_FLAG_NOWRITE) 160 return; 161 162 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 163 164 switch (FBTYPE_GET_BYTESPP(info)) { 165 case 1: 166 vt_fb_mem_wr1(info, o, c); 167 break; 168 case 2: 169 vt_fb_mem_wr2(info, o, c); 170 break; 171 case 3: 172 vt_fb_mem_wr1(info, o, (c >> 16) & 0xff); 173 vt_fb_mem_wr1(info, o + 1, (c >> 8) & 0xff); 174 vt_fb_mem_wr1(info, o + 2, c & 0xff); 175 break; 176 case 4: 177 vt_fb_mem_wr4(info, o, c); 178 break; 179 default: 180 /* panic? */ 181 return; 182 } 183 184 } 185 186 void 187 vt_fb_drawrect(struct vt_device *vd, int x1, int y1, int x2, int y2, int fill, 188 term_color_t color) 189 { 190 int x, y; 191 192 for (y = y1; y <= y2; y++) { 193 if (fill || (y == y1) || (y == y2)) { 194 for (x = x1; x <= x2; x++) 195 vt_fb_setpixel(vd, x, y, color); 196 } else { 197 vt_fb_setpixel(vd, x1, y, color); 198 vt_fb_setpixel(vd, x2, y, color); 199 } 200 } 201 } 202 203 void 204 vt_fb_blank(struct vt_device *vd, term_color_t color) 205 { 206 struct fb_info *info; 207 uint32_t c; 208 u_int o, h; 209 210 info = vd->vd_softc; 211 c = info->fb_cmap[color]; 212 213 if (info->fb_flags & FB_FLAG_NOWRITE) 214 return; 215 216 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 217 218 switch (FBTYPE_GET_BYTESPP(info)) { 219 case 1: 220 for (h = 0; h < info->fb_height; h++) 221 for (o = 0; o < info->fb_stride; o++) 222 vt_fb_mem_wr1(info, h*info->fb_stride + o, c); 223 break; 224 case 2: 225 for (h = 0; h < info->fb_height; h++) 226 for (o = 0; o < info->fb_stride; o += 2) 227 vt_fb_mem_wr2(info, h*info->fb_stride + o, c); 228 break; 229 case 3: 230 for (h = 0; h < info->fb_height; h++) 231 for (o = 0; o < info->fb_stride; o += 3) { 232 vt_fb_mem_wr1(info, h*info->fb_stride + o, 233 (c >> 16) & 0xff); 234 vt_fb_mem_wr1(info, h*info->fb_stride + o + 1, 235 (c >> 8) & 0xff); 236 vt_fb_mem_wr1(info, h*info->fb_stride + o + 2, 237 c & 0xff); 238 } 239 break; 240 case 4: 241 for (h = 0; h < info->fb_height; h++) 242 for (o = 0; o < info->fb_stride; o += 4) 243 vt_fb_mem_wr4(info, h*info->fb_stride + o, c); 244 break; 245 default: 246 /* panic? */ 247 return; 248 } 249 } 250 251 void 252 vt_fb_bitblt_bitmap(struct vt_device *vd, const struct vt_window *vw, 253 const uint8_t *pattern, const uint8_t *mask, 254 unsigned int width, unsigned int height, 255 unsigned int x, unsigned int y, term_color_t fg, term_color_t bg) 256 { 257 struct fb_info *info; 258 uint32_t fgc, bgc, cc, o; 259 int c, l, bpp, bpl; 260 u_long line; 261 uint8_t b, m; 262 const uint8_t *ch; 263 264 info = vd->vd_softc; 265 bpp = FBTYPE_GET_BYTESPP(info); 266 fgc = info->fb_cmap[fg]; 267 bgc = info->fb_cmap[bg]; 268 b = m = 0; 269 bpl = (width + 7) >> 3; /* Bytes per source line. */ 270 271 if (info->fb_flags & FB_FLAG_NOWRITE) 272 return; 273 274 KASSERT((info->fb_vbase != 0), ("Unmapped framebuffer")); 275 276 line = (info->fb_stride * y) + (x * bpp); 277 for (l = 0; 278 l < height && y + l < vw->vw_draw_area.tr_end.tp_row; 279 l++) { 280 ch = pattern; 281 for (c = 0; 282 c < width && x + c < vw->vw_draw_area.tr_end.tp_col; 283 c++) { 284 if (c % 8 == 0) 285 b = *ch++; 286 else 287 b <<= 1; 288 if (mask != NULL) { 289 if (c % 8 == 0) 290 m = *mask++; 291 else 292 m <<= 1; 293 /* Skip pixel write, if mask has no bit set. */ 294 if ((m & 0x80) == 0) 295 continue; 296 } 297 o = line + (c * bpp); 298 cc = b & 0x80 ? fgc : bgc; 299 300 switch(bpp) { 301 case 1: 302 vt_fb_mem_wr1(info, o, cc); 303 break; 304 case 2: 305 vt_fb_mem_wr2(info, o, cc); 306 break; 307 case 3: 308 /* Packed mode, so unaligned. Byte access. */ 309 vt_fb_mem_wr1(info, o, (cc >> 16) & 0xff); 310 vt_fb_mem_wr1(info, o + 1, (cc >> 8) & 0xff); 311 vt_fb_mem_wr1(info, o + 2, cc & 0xff); 312 break; 313 case 4: 314 vt_fb_mem_wr4(info, o, cc); 315 break; 316 default: 317 /* panic? */ 318 break; 319 } 320 } 321 line += info->fb_stride; 322 pattern += bpl; 323 } 324 } 325 326 void 327 vt_fb_bitblt_text(struct vt_device *vd, const struct vt_window *vw, 328 const term_rect_t *area) 329 { 330 unsigned int col, row, x, y; 331 struct vt_font *vf; 332 term_char_t c; 333 term_color_t fg, bg; 334 const uint8_t *pattern; 335 336 vf = vw->vw_font; 337 338 for (row = area->tr_begin.tp_row; row < area->tr_end.tp_row; ++row) { 339 for (col = area->tr_begin.tp_col; col < area->tr_end.tp_col; 340 ++col) { 341 x = col * vf->vf_width + 342 vw->vw_draw_area.tr_begin.tp_col; 343 y = row * vf->vf_height + 344 vw->vw_draw_area.tr_begin.tp_row; 345 346 c = VTBUF_GET_FIELD(&vw->vw_buf, row, col); 347 pattern = vtfont_lookup(vf, c); 348 vt_determine_colors(c, 349 VTBUF_ISCURSOR(&vw->vw_buf, row, col), &fg, &bg); 350 351 vt_fb_bitblt_bitmap(vd, vw, 352 pattern, NULL, vf->vf_width, vf->vf_height, 353 x, y, fg, bg); 354 } 355 } 356 357 #ifndef SC_NO_CUTPASTE 358 if (!vd->vd_mshown) 359 return; 360 361 term_rect_t drawn_area; 362 363 drawn_area.tr_begin.tp_col = area->tr_begin.tp_col * vf->vf_width; 364 drawn_area.tr_begin.tp_row = area->tr_begin.tp_row * vf->vf_height; 365 drawn_area.tr_end.tp_col = area->tr_end.tp_col * vf->vf_width; 366 drawn_area.tr_end.tp_row = area->tr_end.tp_row * vf->vf_height; 367 368 if (vt_is_cursor_in_area(vd, &drawn_area)) { 369 vt_fb_bitblt_bitmap(vd, vw, 370 vd->vd_mcursor->map, vd->vd_mcursor->mask, 371 vd->vd_mcursor->width, vd->vd_mcursor->height, 372 vd->vd_mx_drawn + vw->vw_draw_area.tr_begin.tp_col, 373 vd->vd_my_drawn + vw->vw_draw_area.tr_begin.tp_row, 374 vd->vd_mcursor_fg, vd->vd_mcursor_bg); 375 } 376 #endif 377 } 378 379 void 380 vt_fb_postswitch(struct vt_device *vd) 381 { 382 struct fb_info *info; 383 384 info = vd->vd_softc; 385 386 if (info->enter != NULL) 387 info->enter(info->fb_priv); 388 } 389 390 static int 391 vt_fb_init_cmap(uint32_t *cmap, int depth) 392 { 393 394 switch (depth) { 395 case 8: 396 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 397 0x7, 5, 0x7, 2, 0x3, 0)); 398 case 15: 399 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 400 0x1f, 10, 0x1f, 5, 0x1f, 0)); 401 case 16: 402 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 403 0x1f, 11, 0x3f, 5, 0x1f, 0)); 404 case 24: 405 case 32: /* Ignore alpha. */ 406 return (vt_generate_cons_palette(cmap, COLOR_FORMAT_RGB, 407 0xff, 16, 0xff, 8, 0xff, 0)); 408 default: 409 return (1); 410 } 411 } 412 413 int 414 vt_fb_init(struct vt_device *vd) 415 { 416 struct fb_info *info; 417 int err; 418 419 info = vd->vd_softc; 420 vd->vd_height = info->fb_height; 421 vd->vd_width = info->fb_width; 422 423 if (info->fb_size == 0) 424 return (CN_DEAD); 425 426 if (info->fb_pbase == 0) 427 info->fb_flags |= FB_FLAG_NOMMAP; 428 429 if (info->fb_cmsize <= 0) { 430 err = vt_fb_init_cmap(info->fb_cmap, FBTYPE_GET_BPP(info)); 431 if (err) 432 return (CN_DEAD); 433 info->fb_cmsize = 16; 434 } 435 436 /* Clear the screen. */ 437 vd->vd_driver->vd_blank(vd, TC_BLACK); 438 439 /* Wakeup screen. KMS need this. */ 440 vt_fb_postswitch(vd); 441 442 return (CN_INTERNAL); 443 } 444 445 int 446 vt_fb_attach(struct fb_info *info) 447 { 448 449 vt_allocate(&vt_fb_driver, info); 450 451 return (0); 452 } 453 454 void 455 vt_fb_suspend(struct vt_device *vd) 456 { 457 458 vt_suspend(vd); 459 } 460 461 void 462 vt_fb_resume(struct vt_device *vd) 463 { 464 465 vt_resume(vd); 466 } 467