genfb.c revision 1.2.2.2 1 /* $NetBSD: genfb.c,v 1.2.2.2 2007/04/10 13:24:53 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2007 Michael Lorenz
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 <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: genfb.c,v 1.2.2.2 2007/04/10 13:24:53 ad Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/proc.h>
40 #include <sys/mutex.h>
41 #include <sys/ioctl.h>
42 #include <sys/kernel.h>
43 #include <sys/systm.h>
44
45 #include <dev/wscons/wsconsio.h>
46 #include <dev/wscons/wsdisplayvar.h>
47 #include <dev/rasops/rasops.h>
48 #include <dev/wsfont/wsfont.h>
49
50 #include <dev/wscons/wsdisplay_vconsvar.h>
51
52 #include <dev/wsfb/genfbvar.h>
53
54 #include "opt_genfb.h"
55 #include "opt_wsfb.h"
56
57 static int genfb_ioctl(void *, void *, u_long, void *, int, struct lwp *);
58 static paddr_t genfb_mmap(void *, void *, off_t, int);
59 static void genfb_init_screen(void *, struct vcons_screen *, int, long *);
60
61 static int genfb_putcmap(struct genfb_softc *, struct wsdisplay_cmap *);
62 static int genfb_getcmap(struct genfb_softc *, struct wsdisplay_cmap *);
63 static void genfb_restore_palette(struct genfb_softc *);
64 static int genfb_putpalreg(struct genfb_softc *, uint8_t, uint8_t,
65 uint8_t, uint8_t);
66
67 extern const u_char rasops_cmap[768];
68
69 struct wsdisplay_accessops genfb_accessops = {
70 genfb_ioctl,
71 genfb_mmap,
72 NULL, /* load_font */
73 NULL, /* polls */
74 NULL, /* scroll */
75 };
76
77 void
78 genfb_init(struct genfb_softc *sc)
79 {
80 prop_dictionary_t dict;
81 uint32_t fboffset;
82
83 dict = device_properties(&sc->sc_dev);
84 #ifdef GENFB_DEBUG
85 printf(prop_dictionary_externalize(dict));
86 #endif
87 if (!prop_dictionary_get_uint32(dict, "width", &sc->sc_width))
88 panic("no width property");
89 if (!prop_dictionary_get_uint32(dict, "height", &sc->sc_height))
90 panic("no height property");
91 if (!prop_dictionary_get_uint32(dict, "depth", &sc->sc_depth))
92 panic("no depth property");
93
94 /* XXX should be a 64bit value */
95 if (!prop_dictionary_get_uint32(dict, "address", &fboffset))
96 panic("no address property");
97 sc->sc_fboffset = fboffset;
98
99 if (!prop_dictionary_get_uint32(dict, "linebytes", &sc->sc_stride))
100 sc->sc_stride = (sc->sc_width * sc->sc_depth) >> 3;
101 sc->sc_fbsize = sc->sc_width * sc->sc_stride;
102 }
103
104 int
105 genfb_attach(struct genfb_softc *sc, struct genfb_ops *ops)
106 {
107 struct wsemuldisplaydev_attach_args aa;
108 prop_dictionary_t dict;
109 struct rasops_info *ri;
110 long defattr;
111 int console, i, j;
112
113 sc->sc_defaultscreen_descr = (struct wsscreen_descr){
114 "default",
115 0, 0,
116 NULL,
117 8, 16,
118 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
119 };
120 sc->sc_screens[0] = &sc->sc_defaultscreen_descr;
121 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens};
122 memcpy(&sc->sc_ops, ops, sizeof(struct genfb_ops));
123 sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
124
125 dict = device_properties(&sc->sc_dev);
126
127 prop_dictionary_get_bool(dict, "is_console", &console);
128
129 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr,
130 &genfb_accessops);
131 sc->vd.init_screen = genfb_init_screen;
132
133 ri = &sc->sc_console_screen.scr_ri;
134
135 if (console) {
136 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1,
137 &defattr);
138 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC;
139
140 sc->sc_defaultscreen_descr.textops = &ri->ri_ops;
141 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps;
142 sc->sc_defaultscreen_descr.nrows = ri->ri_rows;
143 sc->sc_defaultscreen_descr.ncols = ri->ri_cols;
144 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0,
145 defattr);
146 } else {
147 /*
148 * since we're not the console we can postpone the rest
149 * until someone actually allocates a screen for us
150 */
151 }
152
153 j = 0;
154 for (i = 0; i < 256; i++) {
155 genfb_putpalreg(sc, i, rasops_cmap[j], rasops_cmap[j + 1],
156 rasops_cmap[j + 2]);
157 j += 3;
158 }
159
160 aa.console = console;
161 aa.scrdata = &sc->sc_screenlist;
162 aa.accessops = &genfb_accessops;
163 aa.accesscookie = &sc->vd;
164
165 config_found(&sc->sc_dev, &aa, wsemuldisplaydevprint);
166
167 return 0;
168 }
169
170 static int
171 genfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag,
172 struct lwp *l)
173 {
174 struct vcons_data *vd = v;
175 struct genfb_softc *sc = vd->cookie;
176 struct wsdisplay_fbinfo *wdf;
177 struct vcons_screen *ms = vd->active;
178
179 switch (cmd) {
180
181 case WSDISPLAYIO_GINFO:
182 wdf = (void *)data;
183 wdf->height = ms->scr_ri.ri_height;
184 wdf->width = ms->scr_ri.ri_width;
185 wdf->depth = ms->scr_ri.ri_depth;
186 wdf->cmsize = 256;
187 return 0;
188
189 case WSDISPLAYIO_GETCMAP:
190 return genfb_getcmap(sc,
191 (struct wsdisplay_cmap *)data);
192
193 case WSDISPLAYIO_PUTCMAP:
194 return genfb_putcmap(sc,
195 (struct wsdisplay_cmap *)data);
196
197 case WSDISPLAYIO_SMODE:
198 {
199 int new_mode = *(int*)data;
200 if (new_mode != sc->sc_mode) {
201 sc->sc_mode = new_mode;
202 if(new_mode == WSDISPLAYIO_MODE_EMUL) {
203 genfb_restore_palette(sc);
204 vcons_redraw_screen(ms);
205 }
206 }
207 }
208 return 0;
209 default:
210 if (sc->sc_ops.genfb_ioctl)
211 return sc->sc_ops.genfb_ioctl(sc, vs, cmd,
212 data, flag, l);
213 }
214 return EPASSTHROUGH;
215 }
216
217 static paddr_t
218 genfb_mmap(void *v, void *vs, off_t offset, int prot)
219 {
220 struct vcons_data *vd = v;
221 struct genfb_softc *sc = vd->cookie;
222
223 if (sc->sc_ops.genfb_mmap)
224 return sc->sc_ops.genfb_mmap(sc, vs, offset, prot);
225
226 return -1;
227 }
228
229 static void
230 genfb_init_screen(void *cookie, struct vcons_screen *scr,
231 int existing, long *defattr)
232 {
233 struct genfb_softc *sc = cookie;
234 struct rasops_info *ri = &scr->scr_ri;
235
236 ri->ri_depth = sc->sc_depth;
237 ri->ri_width = sc->sc_width;
238 ri->ri_height = sc->sc_height;
239 ri->ri_stride = sc->sc_stride;
240 ri->ri_flg = RI_CENTER | RI_FULLCLEAR;
241
242 ri->ri_bits = (char *)sc->sc_fbaddr;
243
244 if (existing) {
245 ri->ri_flg |= RI_CLEAR;
246 }
247
248 rasops_init(ri, sc->sc_height / 8, sc->sc_width / 8);
249 ri->ri_caps = WSSCREEN_WSCOLORS;
250
251 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight,
252 sc->sc_width / ri->ri_font->fontwidth);
253
254 ri->ri_hw = scr;
255 }
256
257 static int
258 genfb_putcmap(struct genfb_softc *sc, struct wsdisplay_cmap *cm)
259 {
260 u_char *r, *g, *b;
261 u_int index = cm->index;
262 u_int count = cm->count;
263 int i, error;
264 u_char rbuf[256], gbuf[256], bbuf[256];
265
266 #ifdef GENFB_DEBUG
267 aprint_debug("putcmap: %d %d\n",index, count);
268 #endif
269 if (cm->index >= 256 || cm->count > 256 ||
270 (cm->index + cm->count) > 256)
271 return EINVAL;
272 error = copyin(cm->red, &rbuf[index], count);
273 if (error)
274 return error;
275 error = copyin(cm->green, &gbuf[index], count);
276 if (error)
277 return error;
278 error = copyin(cm->blue, &bbuf[index], count);
279 if (error)
280 return error;
281
282 memcpy(&sc->sc_cmap_red[index], &rbuf[index], count);
283 memcpy(&sc->sc_cmap_green[index], &gbuf[index], count);
284 memcpy(&sc->sc_cmap_blue[index], &bbuf[index], count);
285
286 r = &sc->sc_cmap_red[index];
287 g = &sc->sc_cmap_green[index];
288 b = &sc->sc_cmap_blue[index];
289
290 for (i = 0; i < count; i++) {
291 genfb_putpalreg(sc, index, *r, *g, *b);
292 index++;
293 r++, g++, b++;
294 }
295 return 0;
296 }
297
298 static int
299 genfb_getcmap(struct genfb_softc *sc, struct wsdisplay_cmap *cm)
300 {
301 u_int index = cm->index;
302 u_int count = cm->count;
303 int error;
304
305 if (index >= 255 || count > 256 || index + count > 256)
306 return EINVAL;
307
308 error = copyout(&sc->sc_cmap_red[index], cm->red, count);
309 if (error)
310 return error;
311 error = copyout(&sc->sc_cmap_green[index], cm->green, count);
312 if (error)
313 return error;
314 error = copyout(&sc->sc_cmap_blue[index], cm->blue, count);
315 if (error)
316 return error;
317
318 return 0;
319 }
320
321 static void
322 genfb_restore_palette(struct genfb_softc *sc)
323 {
324 int i;
325
326 for (i = 0; i < 256; i++) {
327 genfb_putpalreg(sc, i, sc->sc_cmap_red[i],
328 sc->sc_cmap_green[i], sc->sc_cmap_blue[i]);
329 }
330 }
331
332 static int
333 genfb_putpalreg(struct genfb_softc *sc, uint8_t idx, uint8_t r, uint8_t g,
334 uint8_t b)
335 {
336
337 return 0;
338 }
339
340