1 /* $NetBSD: gfb.c,v 1.1 2009/12/29 06:55:55 macallan Exp $ */
4 * Copyright (c) 2009 Michael Lorenz
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * A console driver for Sun XVR-1000 graphics cards
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: gfb.c,v 1.1 2009/12/29 06:55:55 macallan Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/device.h>
39 #include <sys/malloc.h>
41 #include <sys/kauth.h>
44 #include <uvm/uvm_extern.h>
46 #include <dev/videomode/videomode.h>
48 #include <machine/bus.h>
49 #include <machine/autoconf.h>
50 #include <machine/openfirm.h>
52 #include <dev/wscons/wsdisplayvar.h>
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wsfont/wsfont.h>
55 #include <dev/rasops/rasops.h>
56 #include <dev/wscons/wsdisplay_vconsvar.h>
62 bus_space_tag_t sc_memt
;
64 bus_space_handle_t sc_fbh
;
65 bus_addr_t sc_fb_paddr
;
67 int sc_width
, sc_height
, sc_depth
, sc_stride
, sc_fblen
;
69 void *sc_fbaddr
, *sc_shadow
;
70 struct vcons_screen sc_console_screen
;
71 struct wsscreen_descr sc_defaultscreen_descr
;
72 const struct wsscreen_descr
*sc_screens
[1];
73 struct wsscreen_list sc_screenlist
;
77 u_char sc_cmap_red
[256];
78 u_char sc_cmap_green
[256];
79 u_char sc_cmap_blue
[256];
82 static int gfb_match(device_t
, cfdata_t
, void *);
83 static void gfb_attach(device_t
, device_t
, void *);
85 CFATTACH_DECL_NEW(gfb
, sizeof(struct gfb_softc
),
86 gfb_match
, gfb_attach
, NULL
, NULL
);
88 extern const u_char rasops_cmap
[768];
90 static int gfb_ioctl(void *, void *, u_long
, void *, int,
92 static paddr_t
gfb_mmap(void *, void *, off_t
, int);
93 static void gfb_init_screen(void *, struct vcons_screen
*, int, long *);
95 static int gfb_putcmap(struct gfb_softc
*, struct wsdisplay_cmap
*);
96 static int gfb_getcmap(struct gfb_softc
*, struct wsdisplay_cmap
*);
97 static void gfb_restore_palette(struct gfb_softc
*);
98 static int gfb_putpalreg(struct gfb_softc
*, uint8_t, uint8_t,
101 struct wsdisplay_accessops gfb_accessops
= {
104 NULL
, /* alloc_screen */
105 NULL
, /* free_screen */
106 NULL
, /* show_screen */
107 NULL
, /* load_font */
112 extern int prom_stdout_node
;
115 gfb_match(device_t parent
, cfdata_t match
, void *aux
)
117 struct mainbus_attach_args
*ma
= aux
;
119 if (strcmp(ma
->ma_name
, "SUNW,gfb") == 0 )
125 gfb_attach(device_t parent
, device_t self
, void *aux
)
127 struct gfb_softc
*sc
= device_private(self
);
128 struct mainbus_attach_args
*ma
= aux
;
129 struct rasops_info
*ri
;
130 struct wsemuldisplaydev_attach_args aa
;
131 unsigned long defattr
;
135 sc
->sc_memt
= ma
->ma_bustag
;
137 sc
->sc_node
= ma
->ma_node
;
139 if (ma
->ma_nreg
< 7) {
140 aprint_error("%s: can't find the fb range\n",
145 is_console
= (prom_stdout_node
== ma
->ma_node
);
147 aprint_normal(": Sun XVR-1000%s\n", is_console
? " (console)" : "");
150 sc
->sc_stride
= 0x4000;
151 sc
->sc_height
= prom_getpropint(sc
->sc_node
, "height", 0);
152 sc
->sc_width
= prom_getpropint(sc
->sc_node
, "width", 0);
153 sc
->sc_fblen
= sc
->sc_stride
* sc
->sc_height
;
155 if (sc
->sc_fblen
== 0) {
156 aprint_error("%s: not set up by firmware, can't continue.\n",
161 sc
->sc_shadow
= kmem_alloc(sc
->sc_fblen
, KM_SLEEP
);
163 sc
->sc_mode
= WSDISPLAYIO_MODE_EMUL
;
165 if (bus_space_map(sc
->sc_memt
, ma
->ma_reg
[6].ur_paddr
,
166 sc
->sc_fblen
, BUS_SPACE_MAP_LINEAR
, &sc
->sc_fbh
)) {
167 printf(": failed to map the framebuffer\n");
170 sc
->sc_fbaddr
= bus_space_vaddr(sc
->sc_memt
, sc
->sc_fbh
);
171 sc
->sc_fb_paddr
= ma
->ma_reg
[6].ur_paddr
;
173 sc
->sc_defaultscreen_descr
= (struct wsscreen_descr
){
178 WSSCREEN_WSCOLORS
| WSSCREEN_HILIT
,
181 sc
->sc_screens
[0] = &sc
->sc_defaultscreen_descr
;
182 sc
->sc_screenlist
= (struct wsscreen_list
){1, sc
->sc_screens
};
183 sc
->sc_mode
= WSDISPLAYIO_MODE_EMUL
;
186 vcons_init(&sc
->vd
, sc
, &sc
->sc_defaultscreen_descr
,
188 sc
->vd
.init_screen
= gfb_init_screen
;
190 ri
= &sc
->sc_console_screen
.scr_ri
;
193 for (i
= 0; i
< (1 << sc
->sc_depth
); i
++) {
195 sc
->sc_cmap_red
[i
] = rasops_cmap
[j
];
196 sc
->sc_cmap_green
[i
] = rasops_cmap
[j
+ 1];
197 sc
->sc_cmap_blue
[i
] = rasops_cmap
[j
+ 2];
198 gfb_putpalreg(sc
, i
, rasops_cmap
[j
], rasops_cmap
[j
+ 1],
204 vcons_init_screen(&sc
->vd
, &sc
->sc_console_screen
, 1,
206 sc
->sc_console_screen
.scr_flags
|= VCONS_SCREEN_IS_STATIC
;
209 gfb_rectfill(sc
, 0, 0, sc
->sc_width
, sc
->sc_height
,
210 ri
->ri_devcmap
[(defattr
>> 16) & 0xff]);
212 sc
->sc_defaultscreen_descr
.textops
= &ri
->ri_ops
;
213 sc
->sc_defaultscreen_descr
.capabilities
= ri
->ri_caps
;
214 sc
->sc_defaultscreen_descr
.nrows
= ri
->ri_rows
;
215 sc
->sc_defaultscreen_descr
.ncols
= ri
->ri_cols
;
216 wsdisplay_cnattach(&sc
->sc_defaultscreen_descr
, ri
, 0, 0,
218 vcons_replay_msgbuf(&sc
->sc_console_screen
);
221 * since we're not the console we can postpone the rest
222 * until someone actually allocates a screen for us
224 (*ri
->ri_ops
.allocattr
)(ri
, 0, 0, 0, &defattr
);
227 aa
.console
= is_console
;
228 aa
.scrdata
= &sc
->sc_screenlist
;
229 aa
.accessops
= &gfb_accessops
;
230 aa
.accesscookie
= &sc
->vd
;
232 config_found(sc
->sc_dev
, &aa
, wsemuldisplaydevprint
);
236 gfb_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
,
239 struct vcons_data
*vd
= v
;
240 struct gfb_softc
*sc
= vd
->cookie
;
241 struct wsdisplay_fbinfo
*wdf
;
242 struct vcons_screen
*ms
= vd
->active
;
246 case WSDISPLAYIO_GTYPE
:
247 *(u_int
*)data
= WSDISPLAY_TYPE_XVR1000
;
250 case WSDISPLAYIO_GINFO
:
254 wdf
->height
= ms
->scr_ri
.ri_height
;
255 wdf
->width
= ms
->scr_ri
.ri_width
;
256 wdf
->depth
= ms
->scr_ri
.ri_depth
;
260 case WSDISPLAYIO_GETCMAP
:
261 return gfb_getcmap(sc
,
262 (struct wsdisplay_cmap
*)data
);
264 case WSDISPLAYIO_PUTCMAP
:
265 return gfb_putcmap(sc
,
266 (struct wsdisplay_cmap
*)data
);
268 case WSDISPLAYIO_LINEBYTES
:
269 *(u_int
*)data
= sc
->sc_stride
;
272 case WSDISPLAYIO_SMODE
:
274 int new_mode
= *(int*)data
;
276 /* notify the bus backend */
277 if (new_mode
!= sc
->sc_mode
) {
278 sc
->sc_mode
= new_mode
;
279 if(new_mode
== WSDISPLAYIO_MODE_EMUL
) {
280 gfb_restore_palette(sc
);
281 vcons_redraw_screen(ms
);
291 gfb_mmap(void *v
, void *vs
, off_t offset
, int prot
)
293 struct vcons_data
*vd
= v
;
294 struct gfb_softc
*sc
= vd
->cookie
;
297 /* 'regular' framebuffer mmap()ing */
298 if (offset
< sc
->sc_fblen
) {
299 pa
= bus_space_mmap(sc
->sc_memt
, sc
->sc_fb_paddr
+ offset
, 0,
300 prot
, BUS_SPACE_MAP_LINEAR
);
305 * restrict all other mappings to processes with superuser privileges
306 * or the kernel itself
308 if (kauth_authorize_generic(kauth_cred_get(), KAUTH_GENERIC_ISSUSER
,
310 aprint_normal("%s: mmap() rejected.\n",
311 device_xname(sc
->sc_dev
));
315 /* let userland map other ranges */
321 gfb_init_screen(void *cookie
, struct vcons_screen
*scr
,
322 int existing
, long *defattr
)
324 struct gfb_softc
*sc
= cookie
;
325 struct rasops_info
*ri
= &scr
->scr_ri
;
327 ri
->ri_depth
= sc
->sc_depth
;
328 ri
->ri_width
= sc
->sc_width
;
329 ri
->ri_height
= sc
->sc_height
;
330 ri
->ri_stride
= sc
->sc_stride
;
331 ri
->ri_flg
= RI_CENTER
| RI_FULLCLEAR
;
333 ri
->ri_bits
= sc
->sc_shadow
;
334 ri
->ri_hwbits
= (char *)sc
->sc_fbaddr
;
337 ri
->ri_flg
|= RI_CLEAR
;
340 rasops_init(ri
, sc
->sc_height
/ 8, sc
->sc_width
/ 8);
341 ri
->ri_caps
= WSSCREEN_WSCOLORS
;
343 rasops_reconfig(ri
, sc
->sc_height
/ ri
->ri_font
->fontheight
,
344 sc
->sc_width
/ ri
->ri_font
->fontwidth
);
348 ri
->ri_ops
.copyrows
= gfb_copyrows
;
349 ri
->ri_ops
.copycols
= gfb_copycols
;
350 ri
->ri_ops
.cursor
= gfb_cursor
;
351 ri
->ri_ops
.eraserows
= gfb_eraserows
;
352 ri
->ri_ops
.erasecols
= gfb_erasecols
;
353 ri
->ri_ops
.putchar
= gfb_putchar
;
358 gfb_putcmap(struct gfb_softc
*sc
, struct wsdisplay_cmap
*cm
)
361 u_int index
= cm
->index
;
362 u_int count
= cm
->count
;
364 u_char rbuf
[256], gbuf
[256], bbuf
[256];
367 aprint_debug("putcmap: %d %d\n",index
, count
);
369 if (cm
->index
>= 256 || cm
->count
> 256 ||
370 (cm
->index
+ cm
->count
) > 256)
372 error
= copyin(cm
->red
, &rbuf
[index
], count
);
375 error
= copyin(cm
->green
, &gbuf
[index
], count
);
378 error
= copyin(cm
->blue
, &bbuf
[index
], count
);
382 memcpy(&sc
->sc_cmap_red
[index
], &rbuf
[index
], count
);
383 memcpy(&sc
->sc_cmap_green
[index
], &gbuf
[index
], count
);
384 memcpy(&sc
->sc_cmap_blue
[index
], &bbuf
[index
], count
);
386 r
= &sc
->sc_cmap_red
[index
];
387 g
= &sc
->sc_cmap_green
[index
];
388 b
= &sc
->sc_cmap_blue
[index
];
390 for (i
= 0; i
< count
; i
++) {
391 gfb_putpalreg(sc
, index
, *r
, *g
, *b
);
399 gfb_getcmap(struct gfb_softc
*sc
, struct wsdisplay_cmap
*cm
)
401 u_int index
= cm
->index
;
402 u_int count
= cm
->count
;
405 if (index
>= 255 || count
> 256 || index
+ count
> 256)
408 error
= copyout(&sc
->sc_cmap_red
[index
], cm
->red
, count
);
411 error
= copyout(&sc
->sc_cmap_green
[index
], cm
->green
, count
);
414 error
= copyout(&sc
->sc_cmap_blue
[index
], cm
->blue
, count
);
422 gfb_restore_palette(struct gfb_softc
*sc
)
426 for (i
= 0; i
< (1 << sc
->sc_depth
); i
++) {
427 gfb_putpalreg(sc
, i
, sc
->sc_cmap_red
[i
],
428 sc
->sc_cmap_green
[i
], sc
->sc_cmap_blue
[i
]);
433 gfb_putpalreg(struct gfb_softc
*sc
, uint8_t idx
, uint8_t r
, uint8_t g
,