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