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