Home | History | Annotate | Line # | Download | only in tpctl
fb.c revision 1.1
      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