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