xref: /netbsd/usr.sbin/tpctl/fb.c (revision c4a72b64)
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