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