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