fb.c revision 1.5 1 1.5 jmcneill /* $NetBSD: fb.c,v 1.5 2017/08/27 02:19:08 jmcneill 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.5 jmcneill __RCSID("$NetBSD: fb.c,v 1.5 2017/08/27 02:19:08 jmcneill 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.5 jmcneill struct wsdisplay_fbinfo fbinfo;
73 1.5 jmcneill u_int linebytes;
74 1.1 takemura int y;
75 1.1 takemura size_t size;
76 1.1 takemura
77 1.1 takemura fb->fd = fd;
78 1.1 takemura fb->linecache_y = INVALID_CACHE;
79 1.1 takemura fb->conf.hf_conf_index = HPCFB_CURRENT_CONFIG;
80 1.1 takemura if (ioctl(fb->fd, WSDISPLAYIO_GMODE, &fb->dispmode) < 0)
81 1.1 takemura return (-1);
82 1.5 jmcneill if (ioctl(fb->fd, HPCFBIO_GCONF, &fb->conf) < 0) {
83 1.5 jmcneill if (ioctl(fb->fd, WSDISPLAYIO_GINFO, &fbinfo) < 0 ||
84 1.5 jmcneill ioctl(fb->fd, WSDISPLAYIO_LINEBYTES, &linebytes) < 0)
85 1.5 jmcneill return (-1);
86 1.5 jmcneill memset(&fb->conf, 0, sizeof(fb->conf));
87 1.5 jmcneill fb->conf.hf_width = fbinfo.width;
88 1.5 jmcneill fb->conf.hf_height = fbinfo.height;
89 1.5 jmcneill fb->conf.hf_bytes_per_line = linebytes;
90 1.5 jmcneill fb->conf.hf_nplanes = 1;
91 1.5 jmcneill fb->conf.hf_bytes_per_plane = fbinfo.height * linebytes;
92 1.5 jmcneill fb->conf.hf_pack_width = fbinfo.depth;
93 1.5 jmcneill fb->conf.hf_pixels_per_pack = 1;
94 1.5 jmcneill fb->conf.hf_pixel_width = 1;
95 1.5 jmcneill fb->conf.hf_access_flags = HPCFB_ACCESS_STATIC |
96 1.5 jmcneill HPCFB_ACCESS_BYTE | HPCFB_ACCESS_WORD | HPCFB_ACCESS_DWORD;
97 1.5 jmcneill }
98 1.1 takemura
99 1.1 takemura if (fb_dispmode(fb, WSDISPLAYIO_MODE_MAPPED) < 0)
100 1.1 takemura return (-1);
101 1.1 takemura
102 1.1 takemura size = (size_t)fb->conf.hf_bytes_per_line * fb->conf.hf_height;
103 1.1 takemura size += fb->conf.hf_offset;
104 1.1 takemura size = ALIGN(size, getpagesize());
105 1.1 takemura fb->baseaddr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,0);
106 1.1 takemura if (fb->baseaddr == MAP_FAILED)
107 1.1 takemura return (-1);
108 1.1 takemura fb->baseaddr += fb->conf.hf_offset;
109 1.1 takemura
110 1.1 takemura size = ALIGN(fb->conf.hf_bytes_per_line, 16);
111 1.1 takemura fb->linecache = (fb_pixel_t*)malloc(size);
112 1.1 takemura if (fb->linecache == NULL)
113 1.1 takemura return (-1);
114 1.1 takemura fb->workbuf = (fb_pixel_t*)malloc(size);
115 1.1 takemura if (fb->workbuf == NULL)
116 1.1 takemura return (-1);
117 1.1 takemura
118 1.1 takemura if (fb->conf.hf_access_flags & HPCFB_ACCESS_REVERSE) {
119 1.1 takemura fb->white = 0;
120 1.1 takemura fb->black = ~0;
121 1.1 takemura } else {
122 1.1 takemura fb->white = ~0;
123 1.1 takemura fb->black = 0;
124 1.1 takemura }
125 1.1 takemura
126 1.1 takemura /*
127 1.1 takemura * clear screen
128 1.1 takemura */
129 1.1 takemura for (y = 0; y < fb->conf.hf_height; y++) {
130 1.1 takemura fb_getline(fb, y);
131 1.1 takemura memset(fb->linecache, fb->black,
132 1.1 takemura ALIGN(fb->conf.hf_bytes_per_line, 16));
133 1.1 takemura fb_putline(fb, y);
134 1.1 takemura }
135 1.1 takemura
136 1.1 takemura return (0);
137 1.1 takemura }
138 1.1 takemura
139 1.1 takemura static void
140 1.1 takemura __fb_swap_workbuf(struct fb *fb)
141 1.1 takemura {
142 1.1 takemura int i, n;
143 1.1 takemura
144 1.1 takemura n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t);
145 1.1 takemura if (fb->conf.hf_order_flags & HPCFB_REVORDER_BYTE) {
146 1.1 takemura for (i = 0; i < n; i++)
147 1.1 takemura fb->workbuf[i] =
148 1.1 takemura ((fb->workbuf[i] << 8) & 0xff00ff00) |
149 1.1 takemura ((fb->workbuf[i] >> 8) & 0x00ff00ff);
150 1.1 takemura }
151 1.1 takemura if (fb->conf.hf_order_flags & HPCFB_REVORDER_WORD) {
152 1.1 takemura for (i = 0; i < n; i++)
153 1.1 takemura fb->workbuf[i] =
154 1.1 takemura ((fb->workbuf[i] << 16) & 0xffff0000) |
155 1.1 takemura ((fb->workbuf[i] >> 16) & 0x0000ffff);
156 1.1 takemura }
157 1.1 takemura if (fb->conf.hf_order_flags & HPCFB_REVORDER_DWORD) {
158 1.1 takemura for (i = 0; i < n; i += 2) {
159 1.1 takemura fb_pixel_t tmp;
160 1.1 takemura tmp = fb->workbuf[i];
161 1.1 takemura fb->workbuf[i] = fb->workbuf[i + 1];
162 1.1 takemura fb->workbuf[i + 1] = tmp;
163 1.1 takemura }
164 1.1 takemura }
165 1.1 takemura if (fb->conf.hf_order_flags & HPCFB_REVORDER_QWORD) {
166 1.1 takemura for (i = 0; i < n; i += 4) {
167 1.1 takemura fb_pixel_t tmp;
168 1.1 takemura tmp = fb->workbuf[i + 0];
169 1.1 takemura fb->workbuf[i + 0] = fb->workbuf[i + 2];
170 1.1 takemura fb->workbuf[i + 2] = tmp;
171 1.1 takemura tmp = fb->workbuf[i + 1];
172 1.1 takemura fb->workbuf[i + 1] = fb->workbuf[i + 3];
173 1.1 takemura fb->workbuf[i + 3] = tmp;
174 1.1 takemura }
175 1.1 takemura }
176 1.1 takemura }
177 1.1 takemura
178 1.1 takemura static void
179 1.1 takemura __fb_put_pixel(struct fb *fb, fb_pixel_t pixel, int width, int x)
180 1.1 takemura {
181 1.1 takemura fb_pixel_t mask = (1 << width) - 1;
182 1.1 takemura
183 1.1 takemura x -= (bitsizeof(fb_pixel_t) - width);
184 1.1 takemura if (x < 0) {
185 1.1 takemura pixel <<= -x;
186 1.1 takemura mask <<= -x;
187 1.1 takemura fb->linecache[0] = (fb->linecache[0]&~mask) | (pixel&~mask);
188 1.1 takemura } else {
189 1.1 takemura fb_pixel_t *dst = &fb->linecache[x / bitsizeof(fb_pixel_t)];
190 1.1 takemura x %= bitsizeof(fb_pixel_t);
191 1.1 takemura *dst = (*dst & ~(mask>>x)) | ((pixel>>x) & (mask>>x));
192 1.1 takemura dst++;
193 1.1 takemura if (x == 0)
194 1.1 takemura return;
195 1.1 takemura x = bitsizeof(fb_pixel_t) - x;
196 1.1 takemura *dst = (*dst & ~(mask<<x)) | ((pixel<<x) & (mask<<x));
197 1.1 takemura }
198 1.1 takemura }
199 1.1 takemura
200 1.1 takemura void
201 1.1 takemura fb_getline(struct fb *fb, int y)
202 1.1 takemura {
203 1.1 takemura int i, n;
204 1.1 takemura unsigned char *src;
205 1.1 takemura fb_pixel_t *dst;
206 1.1 takemura
207 1.1 takemura src = fb->baseaddr + fb->conf.hf_bytes_per_line * y;
208 1.1 takemura dst = fb->workbuf;
209 1.1 takemura n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t);
210 1.1 takemura for (i = 0; i < n; i++) {
211 1.1 takemura *dst++ = ((fb_pixel_t)src[0] << 24) |
212 1.1 takemura ((fb_pixel_t)src[1] << 16) |
213 1.1 takemura ((fb_pixel_t)src[2] << 8) |
214 1.1 takemura ((fb_pixel_t)src[3] << 0);
215 1.1 takemura src += 4;
216 1.1 takemura }
217 1.1 takemura
218 1.1 takemura __fb_swap_workbuf(fb);
219 1.1 takemura memcpy(fb->linecache, fb->workbuf, n * sizeof(fb_pixel_t));
220 1.1 takemura }
221 1.1 takemura
222 1.1 takemura void
223 1.1 takemura fb_putline(struct fb *fb, int y)
224 1.1 takemura {
225 1.1 takemura int i, n;
226 1.1 takemura unsigned char *dst;
227 1.1 takemura fb_pixel_t *src;
228 1.1 takemura
229 1.1 takemura src = fb->workbuf;
230 1.1 takemura dst = fb->baseaddr + fb->conf.hf_bytes_per_line * y;
231 1.1 takemura n = ALIGN(fb->conf.hf_bytes_per_line, 16) / sizeof(fb_pixel_t);
232 1.1 takemura memcpy(fb->workbuf, fb->linecache, n * sizeof(fb_pixel_t));
233 1.1 takemura __fb_swap_workbuf(fb);
234 1.1 takemura for (i = 0; i < n; i++) {
235 1.1 takemura *dst++ = (*src >> 24) & 0xff;
236 1.1 takemura *dst++ = (*src >> 16) & 0xff;
237 1.1 takemura *dst++ = (*src >> 8) & 0xff;
238 1.1 takemura *dst++ = (*src >> 0) & 0xff;
239 1.1 takemura src++;
240 1.1 takemura }
241 1.1 takemura }
242 1.1 takemura
243 1.1 takemura void
244 1.1 takemura fb_fetchline(struct fb *fb, int y)
245 1.1 takemura {
246 1.1 takemura if (fb->linecache_y == y)
247 1.1 takemura return;
248 1.1 takemura fb_getline(fb, y);
249 1.1 takemura fb->linecache_y = y;
250 1.1 takemura }
251 1.1 takemura
252 1.1 takemura void
253 1.1 takemura fb_flush(struct fb *fb)
254 1.1 takemura {
255 1.1 takemura if (fb->linecache_y != INVALID_CACHE)
256 1.1 takemura fb_putline(fb, fb->linecache_y);
257 1.1 takemura }
258 1.1 takemura
259 1.1 takemura void
260 1.1 takemura fb_drawpixel(struct fb *fb, int x, int y, fb_pixel_t pixel)
261 1.1 takemura {
262 1.1 takemura int pack;
263 1.1 takemura
264 1.1 takemura if (fb->conf.hf_access_flags & HPCFB_ACCESS_Y_TO_X)
265 1.1 takemura SWAP(x, y);
266 1.1 takemura if (fb->conf.hf_access_flags & HPCFB_ACCESS_R_TO_L)
267 1.1 takemura x = fb->conf.hf_width - x - 1;
268 1.1 takemura if (fb->conf.hf_access_flags & HPCFB_ACCESS_B_TO_T)
269 1.1 takemura y = fb->conf.hf_height - y - 1;
270 1.1 takemura
271 1.1 takemura if (x < 0 || y < 0 || fb->conf.hf_width <= x || fb->conf.hf_height < y)
272 1.1 takemura return;
273 1.1 takemura
274 1.1 takemura pack = x / fb->conf.hf_pixels_per_pack;
275 1.1 takemura x %= fb->conf.hf_pixels_per_pack;
276 1.1 takemura if (fb->conf.hf_access_flags & HPCFB_ACCESS_LSB_TO_MSB)
277 1.1 takemura x = fb->conf.hf_pixels_per_pack - x - 1;
278 1.1 takemura x *= fb->conf.hf_pixel_width;
279 1.1 takemura if (fb->conf.hf_access_flags & HPCFB_ACCESS_PACK_BLANK)
280 1.1 takemura x += (fb->conf.hf_pack_width -
281 1.1 takemura fb->conf.hf_pixel_width * fb->conf.hf_pixels_per_pack);
282 1.1 takemura x += pack * fb->conf.hf_pack_width;
283 1.1 takemura
284 1.1 takemura if (fb->linecache_y != y) {
285 1.1 takemura fb_flush(fb);
286 1.1 takemura fb_fetchline(fb, y);
287 1.1 takemura }
288 1.1 takemura
289 1.1 takemura __fb_put_pixel(fb, pixel, fb->conf.hf_pixel_width, x);
290 1.1 takemura }
291 1.1 takemura
292 1.1 takemura void
293 1.1 takemura fb_drawline(struct fb *fb, int x0, int y0, int x1, int y1, fb_pixel_t pixel)
294 1.1 takemura {
295 1.1 takemura int i, dx, dy, d, incdec;
296 1.1 takemura
297 1.1 takemura dx = ABS(x1 - x0);
298 1.1 takemura dy = ABS(y1 - y0);
299 1.1 takemura if (dx < dy) {
300 1.1 takemura if (y1 < y0) {
301 1.1 takemura SWAP(x0, x1);
302 1.1 takemura SWAP(y0, y1);
303 1.1 takemura }
304 1.1 takemura if (x0 < x1)
305 1.1 takemura incdec = 1;
306 1.1 takemura else
307 1.1 takemura incdec = -1;
308 1.1 takemura d = -dy;
309 1.1 takemura dx *= 2;
310 1.1 takemura dy *= 2;
311 1.1 takemura for (i = y0; i <= y1; i++) {
312 1.1 takemura fb_drawpixel(fb, x0, i, pixel);
313 1.1 takemura d += dx;
314 1.1 takemura if (0 <= d) {
315 1.1 takemura d -= dy;
316 1.1 takemura x0 += incdec;
317 1.1 takemura }
318 1.1 takemura }
319 1.1 takemura } else {
320 1.1 takemura if (x1 < x0) {
321 1.1 takemura SWAP(x0, x1);
322 1.1 takemura SWAP(y0, y1);
323 1.1 takemura }
324 1.1 takemura if (y0 < y1)
325 1.1 takemura incdec = 1;
326 1.1 takemura else
327 1.1 takemura incdec = -1;
328 1.1 takemura d = -dx;
329 1.1 takemura dx *= 2;
330 1.1 takemura dy *= 2;
331 1.1 takemura for (i = x0; i <= x1; i++) {
332 1.1 takemura fb_drawpixel(fb, i, y0, pixel);
333 1.1 takemura d += dy;
334 1.1 takemura if (0 <= d) {
335 1.1 takemura d -= dx;
336 1.1 takemura y0 += incdec;
337 1.1 takemura }
338 1.1 takemura }
339 1.1 takemura }
340 1.1 takemura }
341