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