1/* $NetBSD: fb.c,v 1.2 2003/07/08 23:33:50 uwe 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.2 2003/07/08 23:33:50 uwe 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 56int 57fb_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 69int 70fb_init(struct fb *fb, int fd) 71{ 72 int y; 73 size_t size; 74 75 fb->fd = fd; 76 fb->linecache_y = INVALID_CACHE; 77 fb->conf.hf_conf_index = HPCFB_CURRENT_CONFIG; 78 if (ioctl(fb->fd, WSDISPLAYIO_GMODE, &fb->dispmode) < 0) 79 return (-1); 80 if (ioctl(fb->fd, HPCFBIO_GCONF, &fb->conf) < 0) 81 return (-1); 82 83 if (fb_dispmode(fb, WSDISPLAYIO_MODE_MAPPED) < 0) 84 return (-1); 85 86 size = (size_t)fb->conf.hf_bytes_per_line * fb->conf.hf_height; 87 size += fb->conf.hf_offset; 88 size = ALIGN(size, getpagesize()); 89 fb->baseaddr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,0); 90 if (fb->baseaddr == MAP_FAILED) 91 return (-1); 92 fb->baseaddr += fb->conf.hf_offset; 93 94 size = ALIGN(fb->conf.hf_bytes_per_line, 16); 95 fb->linecache = (fb_pixel_t*)malloc(size); 96 if (fb->linecache == NULL) 97 return (-1); 98 fb->workbuf = (fb_pixel_t*)malloc(size); 99 if (fb->workbuf == NULL) 100 return (-1); 101 102 if (fb->conf.hf_access_flags & HPCFB_ACCESS_REVERSE) { 103 fb->white = 0; 104 fb->black = ~0; 105 } else { 106 fb->white = ~0; 107 fb->black = 0; 108 } 109 110 /* 111 * clear screen 112 */ 113 for (y = 0; y < fb->conf.hf_height; y++) { 114 fb_getline(fb, y); 115 memset(fb->linecache, fb->black, 116 ALIGN(fb->conf.hf_bytes_per_line, 16)); 117 fb_putline(fb, y); 118 } 119 120 return (0); 121} 122 123static void 124__fb_swap_workbuf(struct fb *fb) 125{ 126 int i, n; 127 128 n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t); 129 if (fb->conf.hf_order_flags & HPCFB_REVORDER_BYTE) { 130 for (i = 0; i < n; i++) 131 fb->workbuf[i] = 132 ((fb->workbuf[i] << 8) & 0xff00ff00) | 133 ((fb->workbuf[i] >> 8) & 0x00ff00ff); 134 } 135 if (fb->conf.hf_order_flags & HPCFB_REVORDER_WORD) { 136 for (i = 0; i < n; i++) 137 fb->workbuf[i] = 138 ((fb->workbuf[i] << 16) & 0xffff0000) | 139 ((fb->workbuf[i] >> 16) & 0x0000ffff); 140 } 141 if (fb->conf.hf_order_flags & HPCFB_REVORDER_DWORD) { 142 for (i = 0; i < n; i += 2) { 143 fb_pixel_t tmp; 144 tmp = fb->workbuf[i]; 145 fb->workbuf[i] = fb->workbuf[i + 1]; 146 fb->workbuf[i + 1] = tmp; 147 } 148 } 149 if (fb->conf.hf_order_flags & HPCFB_REVORDER_QWORD) { 150 for (i = 0; i < n; i += 4) { 151 fb_pixel_t tmp; 152 tmp = fb->workbuf[i + 0]; 153 fb->workbuf[i + 0] = fb->workbuf[i + 2]; 154 fb->workbuf[i + 2] = tmp; 155 tmp = fb->workbuf[i + 1]; 156 fb->workbuf[i + 1] = fb->workbuf[i + 3]; 157 fb->workbuf[i + 3] = tmp; 158 } 159 } 160} 161 162static void 163__fb_put_pixel(struct fb *fb, fb_pixel_t pixel, int width, int x) 164{ 165 fb_pixel_t mask = (1 << width) - 1; 166 167 x -= (bitsizeof(fb_pixel_t) - width); 168 if (x < 0) { 169 pixel <<= -x; 170 mask <<= -x; 171 fb->linecache[0] = (fb->linecache[0]&~mask) | (pixel&~mask); 172 } else { 173 fb_pixel_t *dst = &fb->linecache[x / bitsizeof(fb_pixel_t)]; 174 x %= bitsizeof(fb_pixel_t); 175 *dst = (*dst & ~(mask>>x)) | ((pixel>>x) & (mask>>x)); 176 dst++; 177 if (x == 0) 178 return; 179 x = bitsizeof(fb_pixel_t) - x; 180 *dst = (*dst & ~(mask<<x)) | ((pixel<<x) & (mask<<x)); 181 } 182} 183 184void 185fb_getline(struct fb *fb, int y) 186{ 187 int i, n; 188 unsigned char *src; 189 fb_pixel_t *dst; 190 191 src = fb->baseaddr + fb->conf.hf_bytes_per_line * y; 192 dst = fb->workbuf; 193 n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t); 194 for (i = 0; i < n; i++) { 195 *dst++ = ((fb_pixel_t)src[0] << 24) | 196 ((fb_pixel_t)src[1] << 16) | 197 ((fb_pixel_t)src[2] << 8) | 198 ((fb_pixel_t)src[3] << 0); 199 src += 4; 200 } 201 202 __fb_swap_workbuf(fb); 203 memcpy(fb->linecache, fb->workbuf, n * sizeof(fb_pixel_t)); 204} 205 206void 207fb_putline(struct fb *fb, int y) 208{ 209 int i, n; 210 unsigned char *dst; 211 fb_pixel_t *src; 212 213 src = fb->workbuf; 214 dst = fb->baseaddr + fb->conf.hf_bytes_per_line * y; 215 n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t); 216 memcpy(fb->workbuf, fb->linecache, n * sizeof(fb_pixel_t)); 217 __fb_swap_workbuf(fb); 218 for (i = 0; i < n; i++) { 219 *dst++ = (*src >> 24) & 0xff; 220 *dst++ = (*src >> 16) & 0xff; 221 *dst++ = (*src >> 8) & 0xff; 222 *dst++ = (*src >> 0) & 0xff; 223 src++; 224 } 225} 226 227void 228fb_fetchline(struct fb *fb, int y) 229{ 230 if (fb->linecache_y == y) 231 return; 232 fb_getline(fb, y); 233 fb->linecache_y = y; 234} 235 236void 237fb_flush(struct fb *fb) 238{ 239 if (fb->linecache_y != INVALID_CACHE) 240 fb_putline(fb, fb->linecache_y); 241} 242 243void 244fb_drawpixel(struct fb *fb, int x, int y, fb_pixel_t pixel) 245{ 246 int pack; 247 248 if (fb->conf.hf_access_flags & HPCFB_ACCESS_Y_TO_X) 249 SWAP(x, y); 250 if (fb->conf.hf_access_flags & HPCFB_ACCESS_R_TO_L) 251 x = fb->conf.hf_width - x - 1; 252 if (fb->conf.hf_access_flags & HPCFB_ACCESS_B_TO_T) 253 y = fb->conf.hf_height - y - 1; 254 255 if (x < 0 || y < 0 || fb->conf.hf_width <= x || fb->conf.hf_height < y) 256 return; 257 258 pack = x / fb->conf.hf_pixels_per_pack; 259 x %= fb->conf.hf_pixels_per_pack; 260 if (fb->conf.hf_access_flags & HPCFB_ACCESS_LSB_TO_MSB) 261 x = fb->conf.hf_pixels_per_pack - x - 1; 262 x *= fb->conf.hf_pixel_width; 263 if (fb->conf.hf_access_flags & HPCFB_ACCESS_PACK_BLANK) 264 x += (fb->conf.hf_pack_width - 265 fb->conf.hf_pixel_width * fb->conf.hf_pixels_per_pack); 266 x += pack * fb->conf.hf_pack_width; 267 268 if (fb->linecache_y != y) { 269 fb_flush(fb); 270 fb_fetchline(fb, y); 271 } 272 273 __fb_put_pixel(fb, pixel, fb->conf.hf_pixel_width, x); 274} 275 276void 277fb_drawline(struct fb *fb, int x0, int y0, int x1, int y1, fb_pixel_t pixel) 278{ 279 int i, dx, dy, d, incdec; 280 281 dx = ABS(x1 - x0); 282 dy = ABS(y1 - y0); 283 if (dx < dy) { 284 if (y1 < y0) { 285 SWAP(x0, x1); 286 SWAP(y0, y1); 287 } 288 if (x0 < x1) 289 incdec = 1; 290 else 291 incdec = -1; 292 d = -dy; 293 dx *= 2; 294 dy *= 2; 295 for (i = y0; i <= y1; i++) { 296 fb_drawpixel(fb, x0, i, pixel); 297 d += dx; 298 if (0 <= d) { 299 d -= dy; 300 x0 += incdec; 301 } 302 } 303 } else { 304 if (x1 < x0) { 305 SWAP(x0, x1); 306 SWAP(y0, y1); 307 } 308 if (y0 < y1) 309 incdec = 1; 310 else 311 incdec = -1; 312 d = -dx; 313 dx *= 2; 314 dy *= 2; 315 for (i = x0; i <= x1; i++) { 316 fb_drawpixel(fb, i, y0, pixel); 317 d += dy; 318 if (0 <= d) { 319 d -= dx; 320 y0 += incdec; 321 } 322 } 323 } 324} 325