vesa.c revision 39287
168349Sobrien/*-
2133359Sobrien * Copyright (c) 1998 Kazutaka YOKOTA (yokota@zodiac.mech.utsunomiya-u.ac.jp)
3133359Sobrien * All rights reserved.
4133359Sobrien *
5133359Sobrien * Redistribution and use in source and binary forms, with or without
6133359Sobrien * modification, are permitted provided that the following conditions
7133359Sobrien * are met:
8133359Sobrien * 1. Redistributions of source code must retain the above copyright
9133359Sobrien *    notice, this list of conditions and the following disclaimer.
10133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11133359Sobrien *    notice, this list of conditions and the following disclaimer in the
12133359Sobrien *    documentation and/or other materials provided with the distribution.
13133359Sobrien * 3. The name of the author may not be used to endorse or promote
14133359Sobrien *    products derived from this software without specific prior written
15133359Sobrien *    permission.
16133359Sobrien *
17133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133359Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21133359Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133359Sobrien * SUCH DAMAGE.
28133359Sobrien *
2968349Sobrien * $Id$
3068349Sobrien */
31103373Sobrien
32103373Sobrien#include "sc.h"
33133359Sobrien#include "opt_vesa.h"
34133359Sobrien#include "opt_vm86.h"
35133359Sobrien
3668349Sobrien#if (NSC > 0 && defined(VESA) && defined(VM86)) || defined(VESA_MODULE)
3769216Sobrien
3868349Sobrien#include <sys/param.h>
39133359Sobrien#include <sys/systm.h>
4068349Sobrien#include <sys/kernel.h>
41133359Sobrien#include <sys/malloc.h>
4268349Sobrien#include <vm/vm.h>
4368349Sobrien#include <vm/pmap.h>
4468349Sobrien
4568349Sobrien#include <machine/console.h>
4668349Sobrien#include <machine/md_var.h>
4768349Sobrien#include <machine/vm86.h>
4868349Sobrien#include <machine/pc/bios.h>
4968349Sobrien#include <machine/pc/vesa.h>
5068349Sobrien
5168349Sobrien#include <i386/isa/videoio.h>
5268349Sobrien
5368349Sobrien#ifdef VESA_MODULE
5468349Sobrien#include <sys/exec.h>
5568349Sobrien#include <sys/sysent.h>
5668349Sobrien#include <sys/lkm.h>
5768349Sobrien
5868349SobrienMOD_MISC(vesa);
59133359Sobrien#endif
60133359Sobrien
61133359Sobrien/* VESA video adapter state buffer stub */
6268349Sobrienstruct adp_state {
63103373Sobrien	int		sig;
64103373Sobrien#define V_STATE_SIG	0x61736576
65133359Sobrien	u_char		regs[1];
66133359Sobrien};
67103373Sobrientypedef struct adp_state adp_state_t;
68103373Sobrien
6968349Sobrien/* VESA video adapter */
7068349Sobrienstatic video_adapter_t *vesa_adp = NULL;
7168349Sobrienstatic int vesa_state_buf_size = 0;
7268349Sobrienstatic void *vesa_state_buf = NULL;
7368349Sobrien
74169942Sobrien/* VESA functions */
7568349Sobrienstatic vi_init_t		vesa_init;
7668349Sobrienstatic vi_adapter_t		vesa_adapter;
7768349Sobrienstatic vi_get_info_t		vesa_get_info;
7868349Sobrienstatic vi_query_mode_t		vesa_query_mode;
79159764Sobrienstatic vi_set_mode_t		vesa_set_mode;
8068349Sobrienstatic vi_save_font_t		vesa_save_font;
81133359Sobrienstatic vi_load_font_t		vesa_load_font;
8268349Sobrienstatic vi_show_font_t		vesa_show_font;
8368349Sobrienstatic vi_save_palette_t	vesa_save_palette;
84169942Sobrienstatic vi_load_palette_t	vesa_load_palette;
85103373Sobrienstatic vi_set_border_t		vesa_set_border;
8668349Sobrienstatic vi_save_state_t		vesa_save_state;
8768349Sobrienstatic vi_load_state_t		vesa_load_state;
8868349Sobrienstatic vi_set_win_org_t		vesa_set_origin;
8968349Sobrienstatic vi_read_hw_cursor_t	vesa_read_hw_cursor;
90133359Sobrienstatic vi_set_hw_cursor_t	vesa_set_hw_cursor;
9168349Sobrienstatic vi_diag_t		vesa_diag;
92110949Sobrien
93169942Sobrienstatic struct vidsw vesavidsw = {
94169942Sobrien	vesa_init,	vesa_adapter,	vesa_get_info,	vesa_query_mode,
9568349Sobrien	vesa_set_mode,	vesa_save_font,	vesa_load_font,	vesa_show_font,
96133359Sobrien	vesa_save_palette,vesa_load_palette,vesa_set_border,vesa_save_state,
97133359Sobrien	vesa_load_state,vesa_set_origin,vesa_read_hw_cursor,vesa_set_hw_cursor,
98159764Sobrien	vesa_diag,
9968349Sobrien};
100133359Sobrien
10168349Sobrienstatic struct vidsw prevvidsw;
102133359Sobrien
10368349Sobrien/* VESA BIOS video modes */
104133359Sobrien#define VESA_MAXMODES	64
105133359Sobrien#define EOT		(-1)
106110949Sobrien#define NA		(-2)
107133359Sobrien
108103373Sobrienstatic video_info_t vesa_vmode[VESA_MAXMODES + 1] = {
10968349Sobrien	{ EOT, },
110133359Sobrien};
111133359Sobrien
11268349Sobrienstatic int vesa_init_done = FALSE;
11368349Sobrienstatic int has_vesa_bios = FALSE;
114103373Sobrienstatic struct vesa_info *vesa_adp_info = NULL;
115133359Sobrienstatic u_int16_t *vesa_vmodetab = NULL;
116133359Sobrien
11768349Sobrien/* local macros and functions */
118133359Sobrien#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
11968349Sobrien
12068349Sobrienstatic int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
12168349Sobrienstatic int vesa_bios_set_mode(int mode);
12268349Sobrienstatic int vesa_bios_set_dac(int bits);
123133359Sobrienstatic int vesa_bios_save_palette(int start, int colors, u_char *palette);
12468349Sobrienstatic int vesa_bios_load_palette(int start, int colors, u_char *palette);
12568349Sobrien#define STATE_SIZE	0
126133359Sobrien#define STATE_SAVE	1
127133359Sobrien#define STATE_LOAD	2
128133359Sobrien#define STATE_HW	(1<<0)
12980588Sobrien#define STATE_DATA	(1<<1)
130169942Sobrien#define STATE_DAC	(1<<2)
131169942Sobrien#define STATE_REG	(1<<3)
132110949Sobrien#define STATE_MOST	(STATE_HW | STATE_DATA | STATE_REG)
133103373Sobrien#define STATE_ALL	(STATE_HW | STATE_DATA | STATE_DAC | STATE_REG)
134169942Sobrienstatic int vesa_bios_state_buf_size(void);
135103373Sobrienstatic int vesa_bios_save_restore(int code, void *p, size_t size);
136103373Sobrienstatic int translate_flags(u_int16_t vflags);
137103373Sobrienstatic int vesa_bios_init(void);
138103373Sobrienstatic void clear_modes(video_info_t *info, int color);
139103373Sobrien
140103373Sobrienstatic void
141103373Sobriendump_buffer(u_char *buf, size_t len)
142110949Sobrien{
143103373Sobrien    int i;
144103373Sobrien
145103373Sobrien    for(i = 0; i < len;) {
146103373Sobrien	printf("%02x ", buf[i]);
147159764Sobrien	if ((++i % 16) == 0)
148103373Sobrien	    printf("\n");
149103373Sobrien    }
150133359Sobrien}
151133359Sobrien
152133359Sobrien/* VESA BIOS calls */
153103373Sobrienstatic int
154133359Sobrienvesa_bios_get_mode(int mode, struct vesa_mode *vmode)
155103373Sobrien{
156110949Sobrien	struct vm86frame vmf;
157103373Sobrien	u_char buf[256];
158103373Sobrien	int err;
159169942Sobrien
160103373Sobrien	bzero(&vmf, sizeof(vmf));
161103373Sobrien	bzero(buf, sizeof(buf));
162103373Sobrien	vmf.vmf_eax = 0x4f01;
16368349Sobrien	vmf.vmf_ecx = mode;
16468349Sobrien	err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf),
165159764Sobrien			  &vmf.vmf_es, &vmf.vmf_di);
166159764Sobrien	if ((err != 0) || (vmf.vmf_eax != 0x4f))
16768349Sobrien		return 1;
16868349Sobrien	bcopy(buf, vmode, sizeof(*vmode));
169103373Sobrien	return 0;
170103373Sobrien}
171103373Sobrien
172103373Sobrienstatic int
173103373Sobrienvesa_bios_set_mode(int mode)
17468349Sobrien{
17568349Sobrien	struct vm86frame vmf;
17668349Sobrien	int err;
17768349Sobrien
17868349Sobrien	bzero(&vmf, sizeof(vmf));
17980588Sobrien	vmf.vmf_eax = 0x4f02;
18080588Sobrien	vmf.vmf_ebx = mode;
18180588Sobrien	err = vm86_intcall(0x10, &vmf);
18280588Sobrien	return ((err != 0) || (vmf.vmf_eax != 0x4f));
18384685Sobrien}
184169942Sobrien
185169942Sobrienstatic int
18680588Sobrienvesa_bios_set_dac(int bits)
187169942Sobrien{
18880588Sobrien	struct vm86frame vmf;
18980588Sobrien	int err;
19080588Sobrien
19180588Sobrien	bzero(&vmf, sizeof(vmf));
19280588Sobrien	vmf.vmf_eax = 0x4f08;
19380588Sobrien	vmf.vmf_ebx = (bits << 8);
19468349Sobrien	err = vm86_intcall(0x10, &vmf);
195159764Sobrien	return ((err != 0) || (vmf.vmf_eax != 0x4f));
196159764Sobrien}
197159764Sobrien
198110949Sobrienstatic int
199103373Sobrienvesa_bios_save_palette(int start, int colors, u_char *palette)
200103373Sobrien{
201103373Sobrien	struct vm86frame vmf;
202103373Sobrien	u_char *p;
203103373Sobrien	int err;
20468349Sobrien	int i;
205110949Sobrien
206103373Sobrien	p = malloc(colors*4, M_DEVBUF, M_WAITOK);
207103373Sobrien
208103373Sobrien	bzero(&vmf, sizeof(vmf));
209103373Sobrien	vmf.vmf_eax = 0x4f09;
210103373Sobrien	vmf.vmf_ebx = 1;	/* get primary palette data */
211169942Sobrien	vmf.vmf_ecx = colors;
212169942Sobrien	vmf.vmf_edx = start;
213169942Sobrien	err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di);
21468349Sobrien	if ((err != 0) || (vmf.vmf_eax != 0x4f)) {
21568349Sobrien		free(p, M_DEVBUF);
21668349Sobrien		return 1;
21768349Sobrien	}
218133359Sobrien
21968349Sobrien	for (i = 0; i < colors; ++i) {
22074784Sobrien		palette[i*3]     = p[i*4 + 1];
221133359Sobrien		palette[i*3 + 1] = p[i*4 + 2];
22274784Sobrien		palette[i*3 + 2] = p[i*4 + 3];
22368349Sobrien	}
224133359Sobrien	free(p, M_DEVBUF);
22568349Sobrien	return 0;
22668349Sobrien}
227133359Sobrien
228133359Sobrienstatic int
229133359Sobrienvesa_bios_load_palette(int start, int colors, u_char *palette)
23068349Sobrien{
23168349Sobrien	struct vm86frame vmf;
23268349Sobrien	u_char *p;
233110949Sobrien	int err;
234133359Sobrien	int i;
235110949Sobrien
23668349Sobrien	p = malloc(colors*4, M_DEVBUF, M_WAITOK);
237133359Sobrien	for (i = 0; i < colors; ++i) {
23868349Sobrien		p[i*4]     = 0;
23968349Sobrien		p[i*4 + 1] = palette[i*3];
240133359Sobrien		p[i*4 + 2] = palette[i*3 + 1];
24168349Sobrien		p[i*4 + 3] = palette[i*3 + 2];
24268349Sobrien	}
24368349Sobrien
24468349Sobrien	bzero(&vmf, sizeof(vmf));
24568349Sobrien	vmf.vmf_eax = 0x4f09;
24668349Sobrien	vmf.vmf_ebx = 0;	/* set primary palette data */
24768349Sobrien	vmf.vmf_ecx = colors;
248110949Sobrien	vmf.vmf_edx = start;
249110949Sobrien	err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di);
250110949Sobrien	free(p, M_DEVBUF);
251133359Sobrien	return ((err != 0) || (vmf.vmf_eax != 0x4f));
252133359Sobrien}
253133359Sobrien
254133359Sobrienstatic int
255133359Sobrienvesa_bios_state_buf_size(void)
256133359Sobrien{
257133359Sobrien	struct vm86frame vmf;
258133359Sobrien	int err;
25968349Sobrien
260133359Sobrien	bzero(&vmf, sizeof(vmf));
26168349Sobrien	vmf.vmf_eax = 0x4f04;
26268349Sobrien	vmf.vmf_ecx = STATE_MOST;
263159764Sobrien	vmf.vmf_edx = STATE_SIZE;
26468349Sobrien	err = vm86_intcall(0x10, &vmf);
265159764Sobrien	if ((err != 0) || (vmf.vmf_eax != 0x4f))
26668349Sobrien		return 0;
26768349Sobrien	return vmf.vmf_ebx*64;
26868349Sobrien}
269133359Sobrien
27068349Sobrienstatic int
27168349Sobrienvesa_bios_save_restore(int code, void *p, size_t size)
27268349Sobrien{
273133359Sobrien	struct vm86frame vmf;
27468349Sobrien	int err;
275159764Sobrien
276159764Sobrien	bzero(&vmf, sizeof(vmf));
277159764Sobrien	vmf.vmf_eax = 0x4f04;
27868349Sobrien	vmf.vmf_ecx = STATE_MOST;
27968349Sobrien	vmf.vmf_edx = code;	/* STATE_SAVE/STATE_LOAD */
28068349Sobrien	err = vm86_datacall(0x10, &vmf, (char *)p, size,
28168349Sobrien			  &vmf.vmf_es, &vmf.vmf_bx);
28268349Sobrien	return ((err != 0) || (vmf.vmf_eax != 0x4f));
28368349Sobrien}
28468349Sobrien
28568349Sobrienstatic int
28674784Sobrientranslate_flags(u_int16_t vflags)
28768349Sobrien{
28868349Sobrien	static struct {
289133359Sobrien		u_int16_t mask;
290133359Sobrien		int set;
291133359Sobrien		int reset;
292133359Sobrien	} ftable[] = {
293133359Sobrien		{ V_MODECOLOR, V_INFO_COLOR, 0 },
294133359Sobrien		{ V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 },
295133359Sobrien		{ V_MODELFB, V_INFO_LENEAR, 0 },
296133359Sobrien	};
297133359Sobrien	int flags;
298133359Sobrien	int i;
299133359Sobrien
300133359Sobrien	for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) {
301133359Sobrien		flags |= (vflags & ftable[i].mask) ?
302133359Sobrien			 ftable[i].set : ftable[i].reset;
303133359Sobrien	}
304133359Sobrien	return flags;
305133359Sobrien}
306133359Sobrien
307133359Sobrienstatic int
308133359Sobrienvesa_bios_init(void)
30968349Sobrien{
31068349Sobrien	static u_char buf[512];
31168349Sobrien	struct vm86frame vmf;
31268349Sobrien	struct vesa_mode vmode;
31374784Sobrien	u_int32_t p;
31468349Sobrien	int modes;
31568349Sobrien	int err;
31668349Sobrien	int i;
31768349Sobrien
31868349Sobrien	if (vesa_init_done)
319133359Sobrien		return 0;
32068349Sobrien
32168349Sobrien	has_vesa_bios = FALSE;
32268349Sobrien	vesa_adp_info = NULL;
32368349Sobrien	vesa_vmode[0].vi_mode = EOT;
32468349Sobrien
32568349Sobrien	bzero(&vmf, sizeof(vmf));	/* paranoia */
32668349Sobrien	bzero(buf, sizeof(buf));
327139368Sobrien	bcopy("VBE2", buf, 4);		/* try for VBE2 data */
32868349Sobrien	vmf.vmf_eax = 0x4f00;
32968349Sobrien	err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf),
33068349Sobrien			  &vmf.vmf_es, &vmf.vmf_di);
33168349Sobrien	if ((err != 0) || (vmf.vmf_eax != 0x4f) || bcmp("VESA", buf, 4))
332133359Sobrien		return 1;
333159764Sobrien	vesa_adp_info = (struct vesa_info *)buf;
334133359Sobrien	if (bootverbose)
335133359Sobrien		dump_buffer(buf, 64);
336133359Sobrien	if (vesa_adp_info->v_flags & V_NONVGA)
337133359Sobrien		return 1;
338133359Sobrien
339133359Sobrien	/* obtain video mode information */
340133359Sobrien	p = BIOS_SADDRTOLADDR(vesa_adp_info->v_modetable);
341133359Sobrien	vesa_vmodetab = (u_int16_t *)BIOS_PADDRTOVADDR(p);
342133359Sobrien	for (i = 0, modes = 0; vesa_vmodetab[i] != 0xffff; ++i) {
343133359Sobrien		if (modes >= VESA_MAXMODES)
344133359Sobrien			break;
345133359Sobrien		if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
346133359Sobrien			continue;
347133359Sobrien
348133359Sobrien		/* reject unsupported modes */
349133359Sobrien#if 0
35068349Sobrien		if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO
35168349Sobrien					| V_MODENONVGA))
35268349Sobrien		    != (V_MODESUPP | V_MODEOPTINFO))
353133359Sobrien			continue;
354103373Sobrien#else
35568349Sobrien		if ((vmode.v_modeattr & (V_MODEOPTINFO | V_MODENONVGA))
35668349Sobrien		    != (V_MODEOPTINFO))
35768349Sobrien			continue;
35868349Sobrien#endif
359159764Sobrien
36068349Sobrien		/* copy some fields */
36168349Sobrien		bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes]));
36268349Sobrien		vesa_vmode[modes].vi_mode = vesa_vmodetab[i];
36368349Sobrien		vesa_vmode[modes].vi_width = vmode.v_width;
36468349Sobrien		vesa_vmode[modes].vi_height = vmode.v_height;
36568349Sobrien		vesa_vmode[modes].vi_depth = vmode.v_bpp;
366133359Sobrien		vesa_vmode[modes].vi_planes = vmode.v_planes;
367133359Sobrien		vesa_vmode[modes].vi_cwidth = vmode.v_cwidth;
368133359Sobrien		vesa_vmode[modes].vi_cheight = vmode.v_cheight;
36968349Sobrien		vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4;
37068349Sobrien		/* XXX window B */
37168349Sobrien		vesa_vmode[modes].vi_window_size = vmode.v_wsize;
372159764Sobrien		vesa_vmode[modes].vi_window_gran = vmode.v_wgran;
373159764Sobrien		vesa_vmode[modes].vi_buffer = vmode.v_lfb;
374159764Sobrien		vesa_vmode[modes].vi_buffer_size = vmode.v_offscreen;
375159764Sobrien		/* pixel format, memory model... */
37668349Sobrien		vesa_vmode[modes].vi_flags = translate_flags(vmode.v_modeattr)
37768349Sobrien					     | V_INFO_VESA;
37868349Sobrien		++modes;
37968349Sobrien	}
38068349Sobrien	vesa_vmode[modes].vi_mode = EOT;
38168349Sobrien	if (bootverbose)
38268349Sobrien		printf("VESA: %d mode(s) found\n", modes);
38368349Sobrien
384159764Sobrien	has_vesa_bios = TRUE;
385159764Sobrien	return 0;
386159764Sobrien}
38768349Sobrien
38868349Sobrienstatic void
389159764Sobrienclear_modes(video_info_t *info, int color)
39068349Sobrien{
39168349Sobrien	while (info->vi_mode != EOT) {
392159764Sobrien		if ((info->vi_flags & V_INFO_COLOR) != color)
39368349Sobrien			info->vi_mode = NA;
39468349Sobrien		++info;
395169942Sobrien	}
396169942Sobrien}
397169942Sobrien
398133359Sobrien/* exported functions */
399133359Sobrien
400133359Sobrienstatic int
401133359Sobrienvesa_init(void)
402133359Sobrien{
40368349Sobrien	int adapters;
404169942Sobrien	int i;
405169942Sobrien
406169942Sobrien	adapters = (*prevvidsw.init)();
407169942Sobrien	for (i = 0; i < adapters; ++i) {
408169942Sobrien		if ((vesa_adp = (*prevvidsw.adapter)(i)) == NULL)
409169942Sobrien			continue;
410169942Sobrien		if (vesa_adp->va_type == KD_VGA) {
411169942Sobrien			vesa_adp->va_flags |= V_ADP_VESA;
412169942Sobrien			return adapters;
413133359Sobrien		}
414133359Sobrien	}
415133359Sobrien	vesa_adp = NULL;
416159764Sobrien	return adapters;
417133359Sobrien}
418159764Sobrien
419133359Sobrienstatic video_adapter_t
420133359Sobrien*vesa_adapter(int ad)
421133359Sobrien{
42268349Sobrien	return (*prevvidsw.adapter)(ad);
42368349Sobrien}
42468349Sobrien
42568349Sobrienstatic int
42668349Sobrienvesa_get_info(int ad, int mode, video_info_t *info)
42768349Sobrien{
42868349Sobrien	int i;
42968349Sobrien
430133359Sobrien	if ((*prevvidsw.get_info)(ad, mode, info) == 0)
431103373Sobrien		return 0;
43268349Sobrien
43368349Sobrien	if (ad != vesa_adp->va_index)
43468349Sobrien		return 1;
43568349Sobrien	for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
43668349Sobrien		if (vesa_vmode[i].vi_mode == NA)
43768349Sobrien			continue;
43868349Sobrien		if (vesa_vmode[i].vi_mode == mode) {
43968349Sobrien			*info = vesa_vmode[i];
44068349Sobrien			return 0;
44168349Sobrien		}
44268349Sobrien	}
44368349Sobrien	return 1;
44468349Sobrien}
44568349Sobrien
44668349Sobrienstatic int
44768349Sobrienvesa_query_mode(int ad, video_info_t *info)
44868349Sobrien{
44968349Sobrien	int i;
45068349Sobrien
45168349Sobrien	if ((i = (*prevvidsw.query_mode)(ad, info)) != -1)
45268349Sobrien		return i;
45368349Sobrien	if (ad != vesa_adp->va_index)
45468349Sobrien		return -1;
45568349Sobrien
45668349Sobrien	for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
457133359Sobrien		if ((info->vi_width != 0)
458103373Sobrien		    && (info->vi_width != vesa_vmode[i].vi_width))
45968349Sobrien			continue;
46068349Sobrien		if ((info->vi_height != 0)
46168349Sobrien		    && (info->vi_height != vesa_vmode[i].vi_height))
46268349Sobrien			continue;
46368349Sobrien		if ((info->vi_cwidth != 0)
46468349Sobrien		    && (info->vi_cwidth != vesa_vmode[i].vi_cwidth))
46568349Sobrien			continue;
46668349Sobrien		if ((info->vi_cheight != 0)
46768349Sobrien		    && (info->vi_cheight != vesa_vmode[i].vi_cheight))
46868349Sobrien			continue;
46968349Sobrien		if ((info->vi_depth != 0)
47068349Sobrien		    && (info->vi_depth != vesa_vmode[i].vi_depth))
47168349Sobrien			continue;
47268349Sobrien		if ((info->vi_planes != 0)
47368349Sobrien		    && (info->vi_planes != vesa_vmode[i].vi_planes))
47468349Sobrien			continue;
47568349Sobrien		/* pixel format, memory model */
47668349Sobrien		if ((info->vi_flags != 0)
47768349Sobrien		    && (info->vi_flags != vesa_vmode[i].vi_flags))
47868349Sobrien			continue;
479133359Sobrien		return vesa_vmode[i].vi_mode;
480133359Sobrien	}
48168349Sobrien	return -1;
482133359Sobrien}
483133359Sobrien
484133359Sobrienstatic int
485133359Sobrienvesa_set_mode(int ad, int mode)
486133359Sobrien{
487133359Sobrien	video_info_t info;
48868349Sobrien	size_t len;
489133359Sobrien
490133359Sobrien	if (ad != vesa_adp->va_index)
491133359Sobrien		return (*prevvidsw.set_mode)(ad, mode);
492133359Sobrien
493133359Sobrien#ifdef SC_VIDEO_DEBUG
494133359Sobrien	printf("VESA: set_mode(): %d(%x) -> %d(%x)\n",
49568349Sobrien		vesa_adp->va_mode, vesa_adp->va_mode, mode, mode);
496133359Sobrien#endif
497133359Sobrien	/*
498133359Sobrien	 * If the current mode is a VESA mode and the new mode is not,
499133359Sobrien	 * restore the state of the adapter first, so that non-standard,
500133359Sobrien	 * extended SVGA registers are set to the state compatible with
501133359Sobrien	 * the standard VGA modes. Otherwise (*prevvidsw.set_mode)()
502133359Sobrien	 * may not be able to set up the new mode correctly.
503133359Sobrien	 */
50468349Sobrien	if (VESA_MODE(vesa_adp->va_mode)) {
505133359Sobrien		if ((*prevvidsw.get_info)(ad, mode, &info) == 0) {
50668349Sobrien			/* assert(vesa_state_buf != NULL); */
507133359Sobrien		    	if ((vesa_state_buf == NULL)
508133359Sobrien			    || vesa_load_state(ad, vesa_state_buf))
509133359Sobrien				return 1;
51068349Sobrien			free(vesa_state_buf, M_DEVBUF);
51168349Sobrien			vesa_state_buf = NULL;
51268349Sobrien#ifdef SC_VIDEO_DEBUG
513133359Sobrien			printf("VESA: restored\n");
514103373Sobrien#endif
51574784Sobrien		}
516133359Sobrien		/*
517110949Sobrien		 * once (*prevvidsw.get_info)() succeeded,
518103373Sobrien		 * (*prevvidsw.set_mode)() below won't fail...
519103373Sobrien		 */
52074784Sobrien	}
52174784Sobrien
522103373Sobrien	/* we may not need to handle this mode after all... */
523110949Sobrien	if ((*prevvidsw.set_mode)(ad, mode) == 0)
524133359Sobrien		return 0;
525103373Sobrien
526103373Sobrien	/* is the new mode supported? */
527159764Sobrien	if (vesa_get_info(ad, mode, &info))
528103373Sobrien		return 1;
529103373Sobrien	/* assert(VESA_MODE(mode)); */
530103373Sobrien
531103373Sobrien#ifdef SC_VIDEO_DEBUG
532103373Sobrien	printf("VESA: about to set a VESA mode...\n");
533103373Sobrien#endif
534103373Sobrien	/*
535103373Sobrien	 * If the current mode is not a VESA mode, save the current state
536103373Sobrien	 * so that the adapter state can be restored later when a non-VESA
537103373Sobrien	 * mode is to be set up. See above.
538103373Sobrien	 */
539133359Sobrien	if (!VESA_MODE(vesa_adp->va_mode) && (vesa_state_buf == NULL)) {
540103373Sobrien		len = vesa_save_state(ad, NULL, 0);
541103373Sobrien		vesa_state_buf = malloc(len, M_DEVBUF, M_WAITOK);
542103373Sobrien		if (vesa_save_state(ad, vesa_state_buf, len)) {
543103373Sobrien#ifdef SC_VIDEO_DEBUG
544133359Sobrien			printf("VESA: state save failed! (len=%d)\n", len);
545133359Sobrien#endif
546133359Sobrien			free(vesa_state_buf, M_DEVBUF);
547103373Sobrien			vesa_state_buf = NULL;
548103373Sobrien			return 1;
549103373Sobrien		}
550103373Sobrien#ifdef SC_VIDEO_DEBUG
551103373Sobrien		printf("VESA: saved (len=%d)\n", len);
552103373Sobrien		dump_buffer(vesa_state_buf, len);
553103373Sobrien#endif
554103373Sobrien	}
555
556	if (vesa_bios_set_mode(mode))
557		return 1;
558
559#ifdef SC_VIDEO_DEBUG
560	printf("VESA: mode set!\n");
561#endif
562	vesa_adp->va_mode = mode;
563	vesa_adp->va_flags &= ~V_ADP_COLOR;
564	vesa_adp->va_flags |=
565		(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
566	vesa_adp->va_crtc_addr =
567		(vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_BASE : MONO_BASE;
568	vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
569	vesa_adp->va_window_size = info.vi_window_size;
570	vesa_adp->va_window_gran = info.vi_window_gran;
571	if (info.vi_buffer_size == 0) {
572		vesa_adp->va_buffer = 0;
573		vesa_adp->va_buffer_size = 0;
574	} else {
575		vesa_adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
576		vesa_adp->va_buffer_size = info.vi_buffer_size;
577	}
578
579	return 0;
580}
581
582static int
583vesa_save_font(int ad, int page, int fontsize, u_char *data, int ch, int count)
584{
585	return (*prevvidsw.save_font)(ad, page, fontsize, data, ch, count);
586}
587
588static int
589vesa_load_font(int ad, int page, int fontsize, u_char *data, int ch, int count)
590{
591	return (*prevvidsw.load_font)(ad, page, fontsize, data, ch, count);
592}
593
594static int
595vesa_show_font(int ad, int page)
596{
597	return (*prevvidsw.show_font)(ad, page);
598}
599
600static int
601vesa_save_palette(int ad, u_char *palette)
602{
603	if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8)
604	    || vesa_bios_set_dac(8))
605		return (*prevvidsw.save_palette)(ad, palette);
606
607	return vesa_bios_save_palette(0, 256, palette);
608}
609
610static int
611vesa_load_palette(int ad, u_char *palette)
612{
613	if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8)
614	    || vesa_bios_set_dac(8))
615		return (*prevvidsw.load_palette)(ad, palette);
616
617	return vesa_bios_load_palette(0, 256, palette);
618}
619
620static int
621vesa_set_border(int ad, int color)
622{
623	return (*prevvidsw.set_border)(ad, color);
624}
625
626static int
627vesa_save_state(int ad, void *p, size_t size)
628{
629	if (ad != vesa_adp->va_index)
630		return (*prevvidsw.save_state)(ad, p, size);
631
632	if (vesa_state_buf_size == 0)
633		vesa_state_buf_size = vesa_bios_state_buf_size();
634	if (size == 0)
635		return (sizeof(int) + vesa_state_buf_size);
636	else if (size < (sizeof(int) + vesa_state_buf_size))
637		return 1;
638
639	((adp_state_t *)p)->sig = V_STATE_SIG;
640	bzero(((adp_state_t *)p)->regs, vesa_state_buf_size);
641	return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs,
642				      vesa_state_buf_size);
643}
644
645static int
646vesa_load_state(int ad, void *p)
647{
648	if ((ad != vesa_adp->va_index)
649	    || (((adp_state_t *)p)->sig != V_STATE_SIG))
650		return (*prevvidsw.load_state)(ad, p);
651
652	return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs,
653				      vesa_state_buf_size);
654}
655
656static int
657vesa_set_origin(int ad, off_t offset)
658{
659	struct vm86frame vmf;
660	int err;
661
662	/*
663	 * This function should return as quickly as possible to
664	 * maintain good performance of the system. For this reason,
665	 * error checking is kept minimal and let the VESA BIOS to
666	 * detect error.
667	 */
668	if (ad != vesa_adp->va_index)
669		return (*prevvidsw.set_win_org)(ad, offset);
670
671	if (vesa_adp->va_window_gran == 0)
672		return 1;
673	bzero(&vmf, sizeof(vmf));
674	vmf.vmf_eax = 0x4f05;
675	vmf.vmf_ebx = 0;		/* WINDOW_A, XXX */
676	vmf.vmf_edx = offset/vesa_adp->va_window_gran;
677	err = vm86_intcall(0x10, &vmf);
678	return ((err != 0) || (vmf.vmf_eax != 0x4f));
679}
680
681static int
682vesa_read_hw_cursor(int ad, int *col, int *row)
683{
684	return (*prevvidsw.read_hw_cursor)(ad, col, row);
685}
686
687static int
688vesa_set_hw_cursor(int ad, int col, int row)
689{
690	return (*prevvidsw.set_hw_cursor)(ad, col, row);
691}
692
693static int
694vesa_diag(int level)
695{
696	struct vesa_mode vmode;
697	u_int32_t p;
698	int i;
699
700	/* general adapter information */
701	printf("VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n",
702	       ((vesa_adp_info->v_version & 0xf000) >> 12) * 10
703		   + ((vesa_adp_info->v_version & 0x0f00) >> 8),
704	       ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10
705		   + (vesa_adp_info->v_version & 0x000f),
706	       vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags,
707	       vesa_vmodetab, vesa_adp_info->v_modetable);
708	/* OEM string */
709	p = BIOS_SADDRTOLADDR(vesa_adp_info->v_oemstr);
710	if (p != 0)
711		printf("VESA: %s\n", (char *)BIOS_PADDRTOVADDR(p));
712
713	if (level <= 0)
714		return 0;
715
716	if (vesa_adp_info->v_version >= 0x0200) {
717		/* vendor name */
718		p = BIOS_SADDRTOLADDR(vesa_adp_info->v_venderstr);
719		if (p != 0)
720			printf("VESA: %s, ", (char *)BIOS_PADDRTOVADDR(p));
721		/* product name */
722		p = BIOS_SADDRTOLADDR(vesa_adp_info->v_prodstr);
723		if (p != 0)
724			printf("%s, ", (char *)BIOS_PADDRTOVADDR(p));
725		/* product revision */
726		p = BIOS_SADDRTOLADDR(vesa_adp_info->v_revstr);
727		if (p != 0)
728			printf("%s\n", (char *)BIOS_PADDRTOVADDR(p));
729	}
730
731	/* mode information */
732	for (i = 0; vesa_vmodetab[i] != 0xffff; ++i) {
733		if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
734			continue;
735
736		/* print something for diagnostic purpose */
737		printf("VESA: mode:0x%03x, flags:0x%04x",
738		       vesa_vmodetab[i], vmode.v_modeattr);
739		if (vmode.v_modeattr & V_MODEOPTINFO) {
740			if (vmode.v_modeattr & V_MODEGRAPHICS) {
741				printf(", G %dx%dx%d %d, ",
742				       vmode.v_width, vmode.v_height,
743				       vmode.v_bpp, vmode.v_planes);
744			} else {
745				printf(", T %dx%d, ",
746				       vmode.v_width, vmode.v_height);
747			}
748			printf("font:%dx%d",
749			       vmode.v_cwidth, vmode.v_cheight);
750		}
751		if (vmode.v_modeattr & V_MODELFB) {
752			printf(", mem:%d, LFB:0x%x, off:0x%x",
753			       vmode.v_memmodel, vmode.v_lfb,
754			       vmode.v_offscreen);
755		}
756		printf("\n");
757		printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ",
758		       vmode.v_waseg, vmode.v_waattr,
759		       vmode.v_wbseg, vmode.v_wbattr);
760		printf("size:%dk, gran:%dk\n",
761		       vmode.v_wsize, vmode.v_wgran);
762	}
763
764	return 0;
765}
766
767/* module loading */
768
769#ifdef VESA_MODULE
770static int
771vesa_load(struct lkm_table *lkmtp, int cmd)
772#else
773int
774vesa_load(void)
775#endif
776{
777	int adapters;
778	int error;
779	int s;
780	int i;
781
782	if (vesa_init_done)
783		return 0;
784
785	/*
786	 * If the VESA module is statically linked to the kernel, or
787	 * it has already been loaded, abort loading this module this time.
788	 */
789	vesa_adp = NULL;
790	adapters = (*biosvidsw.init)();
791	for (i = 0; i < adapters; ++i) {
792		if ((vesa_adp = (*biosvidsw.adapter)(i)) == NULL)
793			continue;
794		if (vesa_adp->va_flags & V_ADP_VESA)
795			return ENXIO;
796		if (vesa_adp->va_type == KD_VGA)
797			break;
798	}
799	/* if a VGA adapter is not found, abort */
800	if (i >= adapters)
801		return ENXIO;
802
803	if (vesa_bios_init())
804		return ENXIO;
805	vesa_adp->va_flags |= V_ADP_VESA;
806
807	/* remove conflicting modes if we have more than one adapter */
808	if (adapters > 1) {
809		clear_modes(vesa_vmode,
810			    (vesa_adp->va_flags & V_ADP_COLOR) ?
811				V_INFO_COLOR : 0);
812	}
813
814#ifdef VESA_MODULE
815	s = spltty();
816#endif
817	if ((error = vesa_load_ioctl()) == 0) {
818		bcopy(&biosvidsw, &prevvidsw, sizeof(prevvidsw));
819		bcopy(&vesavidsw, &biosvidsw, sizeof(vesavidsw));
820		vesa_init_done = TRUE;
821	}
822#ifdef VESA_MODULE
823	splx(s);
824
825	if (error == 0)
826		vesa_diag(bootverbose);
827#endif
828
829	return error;
830}
831
832#ifdef VESA_MODULE
833
834static int
835vesa_unload(struct lkm_table *lkmtp, int cmd)
836{
837	int error;
838	int s;
839
840	/* if the adapter is currently in a VESA mode, don't unload */
841	if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode))
842		return EBUSY;
843	/*
844	 * FIXME: if there is at least one vty which is in a VESA mode,
845	 * we shouldn't be unloading! XXX
846	 */
847
848	s = spltty();
849	if ((error = vesa_unload_ioctl()) == 0) {
850		if (vesa_adp)
851			vesa_adp->va_flags &= ~V_ADP_VESA;
852		bcopy(&prevvidsw, &biosvidsw, sizeof(biosvidsw));
853	}
854	splx(s);
855
856	return error;
857}
858
859int
860vesa_mod(struct lkm_table *lkmtp, int cmd, int ver)
861{
862	MOD_DISPATCH(vesa, lkmtp, cmd, ver,
863		vesa_load, vesa_unload, lkm_nullcmd);
864}
865
866#endif /* VESA_MODULE */
867
868#endif /* (NSC > 0 && VESA && VM86) || VESA_MODULE */
869