1 /* $NetBSD: fb.c,v 1.5 2017/08/27 02:19:08 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 TAKEMRUA Shin 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of The NetBSD Foundation nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <string.h> 33 #include <stdio.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <sys/ioctl.h> 37 #include <sys/fcntl.h> 38 #include <sys/mman.h> 39 40 #include "tpctl.h" 41 42 #ifndef lint 43 #include <sys/cdefs.h> 44 __RCSID("$NetBSD: fb.c,v 1.5 2017/08/27 02:19:08 jmcneill Exp $"); 45 #endif /* not lint */ 46 47 #define INVALID_CACHE -1 48 #define ALIGN(a, n) ((typeof(a))(((int)(a) + (n) - 1) / (n) * (n))) 49 #define ABS(a) ((a) < 0 ? -(a) : (a)) 50 #define SWAP(a, b) do { \ 51 typeof(a) tmp; \ 52 tmp = (a); (a) = (b); (b) = tmp; \ 53 } while(0) 54 #define bitsizeof(t) (sizeof(t) * 8) 55 56 int 57 fb_dispmode(struct fb *fb, int dispmode) 58 { 59 60 if (fb->dispmode != dispmode) { 61 if (ioctl(fb->fd, WSDISPLAYIO_SMODE, &dispmode) < 0) 62 return (-1); 63 fb->dispmode = dispmode; 64 } 65 66 return (0); 67 } 68 69 int 70 fb_init(struct fb *fb, int fd) 71 { 72 struct wsdisplay_fbinfo fbinfo; 73 u_int linebytes; 74 int y; 75 size_t size; 76 77 fb->fd = fd; 78 fb->linecache_y = INVALID_CACHE; 79 fb->conf.hf_conf_index = HPCFB_CURRENT_CONFIG; 80 if (ioctl(fb->fd, WSDISPLAYIO_GMODE, &fb->dispmode) < 0) 81 return (-1); 82 if (ioctl(fb->fd, HPCFBIO_GCONF, &fb->conf) < 0) { 83 if (ioctl(fb->fd, WSDISPLAYIO_GINFO, &fbinfo) < 0 || 84 ioctl(fb->fd, WSDISPLAYIO_LINEBYTES, &linebytes) < 0) 85 return (-1); 86 memset(&fb->conf, 0, sizeof(fb->conf)); 87 fb->conf.hf_width = fbinfo.width; 88 fb->conf.hf_height = fbinfo.height; 89 fb->conf.hf_bytes_per_line = linebytes; 90 fb->conf.hf_nplanes = 1; 91 fb->conf.hf_bytes_per_plane = fbinfo.height * linebytes; 92 fb->conf.hf_pack_width = fbinfo.depth; 93 fb->conf.hf_pixels_per_pack = 1; 94 fb->conf.hf_pixel_width = 1; 95 fb->conf.hf_access_flags = HPCFB_ACCESS_STATIC | 96 HPCFB_ACCESS_BYTE | HPCFB_ACCESS_WORD | HPCFB_ACCESS_DWORD; 97 } 98 99 if (fb_dispmode(fb, WSDISPLAYIO_MODE_MAPPED) < 0) 100 return (-1); 101 102 size = (size_t)fb->conf.hf_bytes_per_line * fb->conf.hf_height; 103 size += fb->conf.hf_offset; 104 size = ALIGN(size, getpagesize()); 105 fb->baseaddr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,0); 106 if (fb->baseaddr == MAP_FAILED) 107 return (-1); 108 fb->baseaddr += fb->conf.hf_offset; 109 110 size = ALIGN(fb->conf.hf_bytes_per_line, 16); 111 fb->linecache = (fb_pixel_t*)malloc(size); 112 if (fb->linecache == NULL) 113 return (-1); 114 fb->workbuf = (fb_pixel_t*)malloc(size); 115 if (fb->workbuf == NULL) 116 return (-1); 117 118 if (fb->conf.hf_access_flags & HPCFB_ACCESS_REVERSE) { 119 fb->white = 0; 120 fb->black = ~0; 121 } else { 122 fb->white = ~0; 123 fb->black = 0; 124 } 125 126 /* 127 * clear screen 128 */ 129 for (y = 0; y < fb->conf.hf_height; y++) { 130 fb_getline(fb, y); 131 memset(fb->linecache, fb->black, 132 ALIGN(fb->conf.hf_bytes_per_line, 16)); 133 fb_putline(fb, y); 134 } 135 136 return (0); 137 } 138 139 static void 140 __fb_swap_workbuf(struct fb *fb) 141 { 142 int i, n; 143 144 n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t); 145 if (fb->conf.hf_order_flags & HPCFB_REVORDER_BYTE) { 146 for (i = 0; i < n; i++) 147 fb->workbuf[i] = 148 ((fb->workbuf[i] << 8) & 0xff00ff00) | 149 ((fb->workbuf[i] >> 8) & 0x00ff00ff); 150 } 151 if (fb->conf.hf_order_flags & HPCFB_REVORDER_WORD) { 152 for (i = 0; i < n; i++) 153 fb->workbuf[i] = 154 ((fb->workbuf[i] << 16) & 0xffff0000) | 155 ((fb->workbuf[i] >> 16) & 0x0000ffff); 156 } 157 if (fb->conf.hf_order_flags & HPCFB_REVORDER_DWORD) { 158 for (i = 0; i < n; i += 2) { 159 fb_pixel_t tmp; 160 tmp = fb->workbuf[i]; 161 fb->workbuf[i] = fb->workbuf[i + 1]; 162 fb->workbuf[i + 1] = tmp; 163 } 164 } 165 if (fb->conf.hf_order_flags & HPCFB_REVORDER_QWORD) { 166 for (i = 0; i < n; i += 4) { 167 fb_pixel_t tmp; 168 tmp = fb->workbuf[i + 0]; 169 fb->workbuf[i + 0] = fb->workbuf[i + 2]; 170 fb->workbuf[i + 2] = tmp; 171 tmp = fb->workbuf[i + 1]; 172 fb->workbuf[i + 1] = fb->workbuf[i + 3]; 173 fb->workbuf[i + 3] = tmp; 174 } 175 } 176 } 177 178 static void 179 __fb_put_pixel(struct fb *fb, fb_pixel_t pixel, int width, int x) 180 { 181 fb_pixel_t mask = (1 << width) - 1; 182 183 x -= (bitsizeof(fb_pixel_t) - width); 184 if (x < 0) { 185 pixel <<= -x; 186 mask <<= -x; 187 fb->linecache[0] = (fb->linecache[0]&~mask) | (pixel&~mask); 188 } else { 189 fb_pixel_t *dst = &fb->linecache[x / bitsizeof(fb_pixel_t)]; 190 x %= bitsizeof(fb_pixel_t); 191 *dst = (*dst & ~(mask>>x)) | ((pixel>>x) & (mask>>x)); 192 dst++; 193 if (x == 0) 194 return; 195 x = bitsizeof(fb_pixel_t) - x; 196 *dst = (*dst & ~(mask<<x)) | ((pixel<<x) & (mask<<x)); 197 } 198 } 199 200 void 201 fb_getline(struct fb *fb, int y) 202 { 203 int i, n; 204 unsigned char *src; 205 fb_pixel_t *dst; 206 207 src = fb->baseaddr + fb->conf.hf_bytes_per_line * y; 208 dst = fb->workbuf; 209 n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t); 210 for (i = 0; i < n; i++) { 211 *dst++ = ((fb_pixel_t)src[0] << 24) | 212 ((fb_pixel_t)src[1] << 16) | 213 ((fb_pixel_t)src[2] << 8) | 214 ((fb_pixel_t)src[3] << 0); 215 src += 4; 216 } 217 218 __fb_swap_workbuf(fb); 219 memcpy(fb->linecache, fb->workbuf, n * sizeof(fb_pixel_t)); 220 } 221 222 void 223 fb_putline(struct fb *fb, int y) 224 { 225 int i, n; 226 unsigned char *dst; 227 fb_pixel_t *src; 228 229 src = fb->workbuf; 230 dst = fb->baseaddr + fb->conf.hf_bytes_per_line * y; 231 n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t); 232 memcpy(fb->workbuf, fb->linecache, n * sizeof(fb_pixel_t)); 233 __fb_swap_workbuf(fb); 234 for (i = 0; i < n; i++) { 235 *dst++ = (*src >> 24) & 0xff; 236 *dst++ = (*src >> 16) & 0xff; 237 *dst++ = (*src >> 8) & 0xff; 238 *dst++ = (*src >> 0) & 0xff; 239 src++; 240 } 241 } 242 243 void 244 fb_fetchline(struct fb *fb, int y) 245 { 246 if (fb->linecache_y == y) 247 return; 248 fb_getline(fb, y); 249 fb->linecache_y = y; 250 } 251 252 void 253 fb_flush(struct fb *fb) 254 { 255 if (fb->linecache_y != INVALID_CACHE) 256 fb_putline(fb, fb->linecache_y); 257 } 258 259 void 260 fb_drawpixel(struct fb *fb, int x, int y, fb_pixel_t pixel) 261 { 262 int pack; 263 264 if (fb->conf.hf_access_flags & HPCFB_ACCESS_Y_TO_X) 265 SWAP(x, y); 266 if (fb->conf.hf_access_flags & HPCFB_ACCESS_R_TO_L) 267 x = fb->conf.hf_width - x - 1; 268 if (fb->conf.hf_access_flags & HPCFB_ACCESS_B_TO_T) 269 y = fb->conf.hf_height - y - 1; 270 271 if (x < 0 || y < 0 || fb->conf.hf_width <= x || fb->conf.hf_height < y) 272 return; 273 274 pack = x / fb->conf.hf_pixels_per_pack; 275 x %= fb->conf.hf_pixels_per_pack; 276 if (fb->conf.hf_access_flags & HPCFB_ACCESS_LSB_TO_MSB) 277 x = fb->conf.hf_pixels_per_pack - x - 1; 278 x *= fb->conf.hf_pixel_width; 279 if (fb->conf.hf_access_flags & HPCFB_ACCESS_PACK_BLANK) 280 x += (fb->conf.hf_pack_width - 281 fb->conf.hf_pixel_width * fb->conf.hf_pixels_per_pack); 282 x += pack * fb->conf.hf_pack_width; 283 284 if (fb->linecache_y != y) { 285 fb_flush(fb); 286 fb_fetchline(fb, y); 287 } 288 289 __fb_put_pixel(fb, pixel, fb->conf.hf_pixel_width, x); 290 } 291 292 void 293 fb_drawline(struct fb *fb, int x0, int y0, int x1, int y1, fb_pixel_t pixel) 294 { 295 int i, dx, dy, d, incdec; 296 297 dx = ABS(x1 - x0); 298 dy = ABS(y1 - y0); 299 if (dx < dy) { 300 if (y1 < y0) { 301 SWAP(x0, x1); 302 SWAP(y0, y1); 303 } 304 if (x0 < x1) 305 incdec = 1; 306 else 307 incdec = -1; 308 d = -dy; 309 dx *= 2; 310 dy *= 2; 311 for (i = y0; i <= y1; i++) { 312 fb_drawpixel(fb, x0, i, pixel); 313 d += dx; 314 if (0 <= d) { 315 d -= dy; 316 x0 += incdec; 317 } 318 } 319 } else { 320 if (x1 < x0) { 321 SWAP(x0, x1); 322 SWAP(y0, y1); 323 } 324 if (y0 < y1) 325 incdec = 1; 326 else 327 incdec = -1; 328 d = -dx; 329 dx *= 2; 330 dy *= 2; 331 for (i = x0; i <= x1; i++) { 332 fb_drawpixel(fb, i, y0, pixel); 333 d += dy; 334 if (0 <= d) { 335 d -= dx; 336 y0 += incdec; 337 } 338 } 339 } 340 } 341