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