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