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