vgafb.c revision 1.51
1/*	$OpenBSD: vgafb.c,v 1.51 2013/08/17 09:15:47 mpi Exp $	*/
2/*	$NetBSD: vga.c,v 1.3 1996/12/02 22:24:54 cgd Exp $	*/
3
4/*
5 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
6 * All rights reserved.
7 *
8 * Author: Chris G. Demetriou
9 *
10 * Permission to use, copy, modify and distribute this software and
11 * its documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
15 *
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23 *  School of Computer Science
24 *  Carnegie Mellon University
25 *  Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
29 */
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/device.h>
34
35#include <machine/bus.h>
36
37#include <dev/wscons/wsconsio.h>
38#include <dev/wscons/wsdisplayvar.h>
39#include <dev/rasops/rasops.h>
40
41#include <dev/ofw/openfirm.h>
42#include <macppc/macppc/ofw_machdep.h>
43#include <macppc/pci/vgafbvar.h>
44
45
46struct cfdriver vgafb_cd = {
47	NULL, "vgafb", DV_DULL,
48};
49
50int	vgafb_ioctl(void *, u_long, caddr_t, int, struct proc *);
51paddr_t	vgafb_mmap(void *, off_t, int);
52int	vgafb_alloc_screen(void *, const struct wsscreen_descr *, void **,
53	    int *, int *, long *);
54void	vgafb_free_screen(void *, void *);
55int	vgafb_show_screen(void *, void *, int, void (*cb)(void *, int, int),
56	    void *);
57void	vgafb_burn(void *v, u_int , u_int);
58void	vgafb_setcolor(struct vga_config *, u_int, uint8_t, uint8_t, uint8_t);
59void	vgafb_restore_default_colors(struct vga_config *);
60
61extern struct vga_config vgafbcn;
62
63struct wsscreen_descr vgafb_stdscreen = {
64	"std",
65	0, 0,
66	0,
67	0, 0,
68	WSSCREEN_UNDERLINE | WSSCREEN_HILIT |
69	WSSCREEN_REVERSE | WSSCREEN_WSCOLORS
70};
71
72const struct wsscreen_descr *vgafb_scrlist[] = {
73	&vgafb_stdscreen,
74};
75
76struct wsscreen_list vgafb_screenlist = {
77	nitems(vgafb_scrlist), vgafb_scrlist
78};
79
80struct wsdisplay_accessops vgafb_accessops = {
81	vgafb_ioctl,
82	vgafb_mmap,
83	vgafb_alloc_screen,
84	vgafb_free_screen,
85	vgafb_show_screen,
86	NULL,		/* load_font */
87	NULL,		/* scrollback */
88	NULL,		/* getchar */
89	vgafb_burn,	/* burner */
90};
91
92int	vgafb_getcmap(struct vga_config *vc, struct wsdisplay_cmap *cm);
93int	vgafb_putcmap(struct vga_config *vc, struct wsdisplay_cmap *cm);
94
95#ifdef APERTURE
96extern int allowaperture;
97#endif
98
99void
100vgafb_restore_default_colors(struct vga_config *vc)
101{
102	int i;
103
104	for (i = 0; i < 256; i++) {
105		const u_char *color;
106
107		color = &rasops_cmap[i * 3];
108		vgafb_setcolor(vc, i, color[0], color[1], color[2]);
109	}
110}
111
112void
113vgafb_wsdisplay_attach(struct device *parent, struct vga_config *vc,
114    int console)
115{
116	struct wsemuldisplaydev_attach_args aa;
117
118	/* Setup virtual console now that we can allocate resources. */
119	if (console) {
120		struct rasops_info *ri = &vc->ri;
121		long defattr;
122
123		ri->ri_flg |= RI_VCONS | RI_WRONLY;
124		rasops_init(ri, 160, 160);
125
126		ri->ri_ops.alloc_attr(ri->ri_active, 0, 0, 0, &defattr);
127		wsdisplay_cnattach(&vgafb_stdscreen, ri->ri_active,
128		    0, 0, defattr);
129	}
130
131	aa.console = console;
132	aa.scrdata = &vgafb_screenlist;
133	aa.accessops = &vgafb_accessops;
134	aa.accesscookie = vc;
135	aa.defaultscreens = 0;
136
137	/* no need to keep the burner function if no hw support */
138	if (cons_backlight_available == 0)
139		vgafb_accessops.burn_screen = NULL;
140	else {
141		vc->vc_backlight_on = WSDISPLAYIO_VIDEO_OFF;
142		vgafb_burn(vc, WSDISPLAYIO_VIDEO_ON, 0);	/* paranoia */
143	}
144
145	config_found(parent, &aa, wsemuldisplaydevprint);
146}
147
148int
149vgafb_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
150{
151	struct vga_config *vc = v;
152	struct wsdisplay_fbinfo *wdf;
153
154	switch (cmd) {
155	case WSDISPLAYIO_GTYPE:
156		*(u_int *)data = WSDISPLAY_TYPE_PCIVGA;
157		return 0;
158	case WSDISPLAYIO_GINFO:
159		wdf = (void *)data;
160		wdf->height = cons_height;
161		wdf->width  = cons_width;
162		wdf->depth  = cons_depth;
163		wdf->cmsize = 256;
164		return 0;
165
166	case WSDISPLAYIO_LINEBYTES:
167		*(u_int *)data = cons_linebytes;
168		return 0;
169
170	case WSDISPLAYIO_GETCMAP:
171		return vgafb_getcmap(vc, (struct wsdisplay_cmap *)data);
172
173	case WSDISPLAYIO_PUTCMAP:
174		return vgafb_putcmap(vc, (struct wsdisplay_cmap *)data);
175
176	case WSDISPLAYIO_SMODE:
177		vc->vc_mode = *(u_int *)data;
178		/* track the state of the display,
179		 * if returning to WSDISPLAYIO_MODE_EMUL
180		 * restore the last palette, workaround for
181		 * bad accellerated X servers that does not restore
182		 * the correct palette.
183		 */
184		if (cons_depth == 8)
185			vgafb_restore_default_colors(vc);
186		break;
187
188	case WSDISPLAYIO_GETPARAM:
189	{
190		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
191
192		switch (dp->param) {
193		case WSDISPLAYIO_PARAM_BRIGHTNESS:
194			if (cons_backlight_available != 0) {
195				dp->min = MIN_BRIGHTNESS;
196				dp->max = MAX_BRIGHTNESS;
197				dp->curval = cons_brightness;
198				return 0;
199			}
200			return -1;
201		case WSDISPLAYIO_PARAM_BACKLIGHT:
202			if (cons_backlight_available != 0) {
203				dp->min = 0;
204				dp->max = 1;
205				dp->curval = vc->vc_backlight_on;
206				return 0;
207			} else
208				return -1;
209		}
210	}
211		return -1;
212
213	case WSDISPLAYIO_SETPARAM:
214	{
215		struct wsdisplay_param *dp = (struct wsdisplay_param *)data;
216
217		switch (dp->param) {
218		case WSDISPLAYIO_PARAM_BRIGHTNESS:
219			if (cons_backlight_available == 1) {
220				of_setbrightness(dp->curval);
221				return 0;
222			} else
223				return -1;
224		case WSDISPLAYIO_PARAM_BACKLIGHT:
225			if (cons_backlight_available != 0) {
226				vgafb_burn(vc,
227				    dp->curval ? WSDISPLAYIO_VIDEO_ON :
228				      WSDISPLAYIO_VIDEO_OFF, 0);
229				return 0;
230			} else
231				return -1;
232		}
233	}
234		return -1;
235
236	case WSDISPLAYIO_SVIDEO:
237	case WSDISPLAYIO_GVIDEO:
238		break;
239
240	case WSDISPLAYIO_GCURPOS:
241	case WSDISPLAYIO_SCURPOS:
242	case WSDISPLAYIO_GCURMAX:
243	case WSDISPLAYIO_GCURSOR:
244	case WSDISPLAYIO_SCURSOR:
245	default:
246		return -1; /* not supported yet */
247	}
248
249	return (0);
250}
251
252paddr_t
253vgafb_mmap(void *v, off_t off, int prot)
254{
255	struct vga_config *vc = v;
256
257	if (off & PGOFSET)
258		return (-1);
259
260	switch (vc->vc_mode) {
261	case WSDISPLAYIO_MODE_MAPPED:
262#ifdef APERTURE
263		if (allowaperture == 0)
264			return (-1);
265#endif
266
267		if (vc->mmiosize == 0)
268			return (-1);
269
270		if (off >= vc->membase && off < (vc->membase + vc->memsize))
271			return (off);
272
273		if (off >= vc->mmiobase && off < (vc->mmiobase + vc->mmiosize))
274			return (off);
275		break;
276
277	case WSDISPLAYIO_MODE_DUMBFB:
278		if (off >= 0x00000 && off < vc->memsize)
279			return (vc->membase + off);
280		break;
281
282	}
283
284	return (-1);
285}
286
287int
288vgafb_is_console(int node)
289{
290	extern int fbnode;
291
292	return (fbnode == node);
293}
294
295int
296vgafb_cnattach(bus_space_tag_t iot, bus_space_tag_t memt, int type, int check)
297{
298	struct vga_config *vc = &vgafbcn;
299	struct rasops_info *ri = &vc->ri;
300	long defattr;
301
302	vc->vc_memt = memt;
303	vc->membase = cons_addr;
304	vc->memsize = cons_linebytes * cons_height;
305	vc->vc_memh = (bus_space_handle_t)mapiodev(vc->membase, vc->memsize);
306
307	if (cons_depth == 8)
308		vgafb_restore_default_colors(vc);
309
310	ri->ri_flg = RI_FULLCLEAR | RI_CLEAR;
311	ri->ri_depth = cons_depth;
312	ri->ri_bits = (void *)vc->vc_memh;
313	ri->ri_width = cons_width;
314	ri->ri_height = cons_height;
315	ri->ri_stride = cons_linebytes;
316	ri->ri_hw = vc;
317
318	rasops_init(ri, 160, 160);
319
320	vgafb_stdscreen.nrows = ri->ri_rows;
321	vgafb_stdscreen.ncols = ri->ri_cols;
322	vgafb_stdscreen.textops = &ri->ri_ops;
323
324	ri->ri_ops.alloc_attr(ri, 0, 0, 0, &defattr);
325
326	wsdisplay_cnattach(&vgafb_stdscreen, ri, 0, 0, defattr);
327
328	return (0);
329}
330
331struct {
332	u_int8_t r;
333	u_int8_t g;
334	u_int8_t b;
335} vgafb_color[256];
336
337void
338vgafb_setcolor(struct vga_config *vc, unsigned int index, u_int8_t r,
339    u_int8_t g, u_int8_t b)
340{
341	vc->vc_cmap_red[index] = r;
342	vc->vc_cmap_green[index] = g;
343	vc->vc_cmap_blue[index] = b;
344
345	vgafb_color[index].r = r;
346	vgafb_color[index].g = g;
347	vgafb_color[index].b = b;
348	OF_call_method_1("set-colors", cons_display_ofh, 3,
349	    &vgafb_color[index], index, 1);
350}
351
352int
353vgafb_getcmap(struct vga_config *vc, struct wsdisplay_cmap *cm)
354{
355	u_int index = cm->index;
356	u_int count = cm->count;
357	int error;
358
359	if (index >= 256 || count > 256 - index)
360		return EINVAL;
361
362	error = copyout(&vc->vc_cmap_red[index],   cm->red,   count);
363	if (error)
364		return error;
365	error = copyout(&vc->vc_cmap_green[index], cm->green, count);
366	if (error)
367		return error;
368	error = copyout(&vc->vc_cmap_blue[index],  cm->blue,  count);
369	if (error)
370		return error;
371
372	return 0;
373}
374
375int
376vgafb_putcmap(struct vga_config *vc, struct wsdisplay_cmap *cm)
377{
378	u_int index = cm->index;
379	u_int count = cm->count;
380	u_int i;
381	int error;
382	u_int8_t *r, *g, *b;
383
384	if (index >= 256 || count > 256 - index)
385		return EINVAL;
386
387	if ((error = copyin(cm->red, &vc->vc_cmap_red[index], count)) != 0)
388		return (error);
389	if ((error = copyin(cm->green, &vc->vc_cmap_green[index], count)) != 0)
390		return (error);
391	if ((error = copyin(cm->blue, &vc->vc_cmap_blue[index], count)) != 0)
392		return (error);
393
394	r = &(vc->vc_cmap_red[index]);
395	g = &(vc->vc_cmap_green[index]);
396	b = &(vc->vc_cmap_blue[index]);
397
398	for (i = 0; i < count; i++) {
399		vgafb_color[i].r = *r;
400		vgafb_color[i].g = *g;
401		vgafb_color[i].b = *b;
402		r++, g++, b++;
403	}
404	OF_call_method_1("set-colors", cons_display_ofh, 3,
405	    &vgafb_color, index, count);
406	return 0;
407}
408
409void
410vgafb_burn(void *v, u_int on, u_int flags)
411{
412	struct vga_config *vc = v;
413
414	if (cons_backlight_available == 1 &&
415	    vc->vc_backlight_on != on) {
416		if (on == WSDISPLAYIO_VIDEO_ON) {
417			OF_call_method_1("backlight-on", cons_display_ofh, 0);
418		} else {
419			OF_call_method_1("backlight-off", cons_display_ofh, 0);
420		}
421		vc->vc_backlight_on = on;
422	}
423}
424
425int
426vgafb_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
427    int *curxp, int *curyp, long *attrp)
428{
429	struct vga_config *vc = v;
430	struct rasops_info *ri = &vc->ri;
431
432	return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp);
433}
434
435void
436vgafb_free_screen(void *v, void *cookie)
437{
438	struct vga_config *vc = v;
439	struct rasops_info *ri = &vc->ri;
440
441	return rasops_free_screen(ri, cookie);
442}
443
444int
445vgafb_show_screen(void *v, void *cookie, int waitok,
446    void (*cb)(void *, int, int), void *cbarg)
447{
448	struct vga_config *vc = v;
449	struct rasops_info *ri = &vc->ri;
450
451	if (cookie == ri->ri_active)
452		return (0);
453
454	return rasops_show_screen(ri, cookie, waitok, cb, cbarg);
455}
456