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