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