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