vesa.c revision 42235
1/*-
2 * Copyright (c) 1998 Kazutaka YOKOTA and Michael Smith
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer as
10 *    the first lines of this file unmodified.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $Id: vesa.c,v 1.10 1998/12/30 11:21:08 yokota Exp $
27 */
28
29#include "sc.h"
30#include "opt_vesa.h"
31#include "opt_vm86.h"
32
33#if (NSC > 0 && defined(VESA) && defined(VM86)) || defined(KLD_MODULE)
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/malloc.h>
40#include <vm/vm.h>
41#include <vm/pmap.h>
42
43#include <machine/console.h>
44#include <machine/md_var.h>
45#include <machine/vm86.h>
46#include <machine/pc/bios.h>
47#include <machine/pc/vesa.h>
48
49#include <i386/isa/videoio.h>
50
51/* VESA video adapter state buffer stub */
52struct adp_state {
53	int		sig;
54#define V_STATE_SIG	0x61736576
55	u_char		regs[1];
56};
57typedef struct adp_state adp_state_t;
58
59/* VESA video adapter */
60static video_adapter_t *vesa_adp = NULL;
61static int vesa_state_buf_size = 0;
62static void *vesa_state_buf = NULL;
63
64/* VESA functions */
65static vi_init_t		vesa_init;
66static vi_adapter_t		vesa_adapter;
67static vi_get_info_t		vesa_get_info;
68static vi_query_mode_t		vesa_query_mode;
69static vi_set_mode_t		vesa_set_mode;
70static vi_save_font_t		vesa_save_font;
71static vi_load_font_t		vesa_load_font;
72static vi_show_font_t		vesa_show_font;
73static vi_save_palette_t	vesa_save_palette;
74static vi_load_palette_t	vesa_load_palette;
75static vi_set_border_t		vesa_set_border;
76static vi_save_state_t		vesa_save_state;
77static vi_load_state_t		vesa_load_state;
78static vi_set_win_org_t		vesa_set_origin;
79static vi_read_hw_cursor_t	vesa_read_hw_cursor;
80static vi_set_hw_cursor_t	vesa_set_hw_cursor;
81static vi_diag_t		vesa_diag;
82
83static struct vidsw vesavidsw = {
84	vesa_init,	vesa_adapter,	vesa_get_info,	vesa_query_mode,
85	vesa_set_mode,	vesa_save_font,	vesa_load_font,	vesa_show_font,
86	vesa_save_palette,vesa_load_palette,vesa_set_border,vesa_save_state,
87	vesa_load_state,vesa_set_origin,vesa_read_hw_cursor,vesa_set_hw_cursor,
88	vesa_diag,
89};
90
91static struct vidsw prevvidsw;
92
93/* VESA BIOS video modes */
94#define VESA_MAXMODES	64
95#define EOT		(-1)
96#define NA		(-2)
97
98static video_info_t vesa_vmode[VESA_MAXMODES + 1] = {
99	{ EOT, },
100};
101
102static int vesa_init_done = FALSE;
103static int has_vesa_bios = FALSE;
104static struct vesa_info *vesa_adp_info = NULL;
105static u_int16_t *vesa_vmodetab = NULL;
106static char *vesa_oemstr = NULL;
107static char *vesa_venderstr = NULL;
108static char *vesa_prodstr = NULL;
109static char *vesa_revstr = NULL;
110
111/* local macros and functions */
112#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
113
114static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
115static int vesa_bios_set_mode(int mode);
116static int vesa_bios_set_dac(int bits);
117static int vesa_bios_save_palette(int start, int colors, u_char *palette);
118static int vesa_bios_load_palette(int start, int colors, u_char *palette);
119#define STATE_SIZE	0
120#define STATE_SAVE	1
121#define STATE_LOAD	2
122#define STATE_HW	(1<<0)
123#define STATE_DATA	(1<<1)
124#define STATE_DAC	(1<<2)
125#define STATE_REG	(1<<3)
126#define STATE_MOST	(STATE_HW | STATE_DATA | STATE_REG)
127#define STATE_ALL	(STATE_HW | STATE_DATA | STATE_DAC | STATE_REG)
128static int vesa_bios_state_buf_size(void);
129static int vesa_bios_save_restore(int code, void *p, size_t size);
130static int vesa_map_gen_mode_num(int type, int color, int mode);
131static int vesa_translate_flags(u_int16_t vflags);
132static void *vesa_fix_ptr(u_int32_t p, u_int16_t seg, u_int16_t off,
133			  u_char *buf);
134static int vesa_bios_init(void);
135static void vesa_clear_modes(video_info_t *info, int color);
136
137static void
138dump_buffer(u_char *buf, size_t len)
139{
140    int i;
141
142    for(i = 0; i < len;) {
143	printf("%02x ", buf[i]);
144	if ((++i % 16) == 0)
145	    printf("\n");
146    }
147}
148
149/* VESA BIOS calls */
150static int
151vesa_bios_get_mode(int mode, struct vesa_mode *vmode)
152{
153	struct vm86frame vmf;
154	u_char buf[256];
155	int err;
156
157	bzero(&vmf, sizeof(vmf));
158	bzero(buf, sizeof(buf));
159	vmf.vmf_eax = 0x4f01;
160	vmf.vmf_ecx = mode;
161	err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf),
162			  &vmf.vmf_es, &vmf.vmf_di);
163	if ((err != 0) || (vmf.vmf_eax != 0x4f))
164		return 1;
165	bcopy(buf, vmode, sizeof(*vmode));
166	return 0;
167}
168
169static int
170vesa_bios_set_mode(int mode)
171{
172	struct vm86frame vmf;
173	int err;
174
175	bzero(&vmf, sizeof(vmf));
176	vmf.vmf_eax = 0x4f02;
177	vmf.vmf_ebx = mode;
178	err = vm86_intcall(0x10, &vmf);
179	return ((err != 0) || (vmf.vmf_eax != 0x4f));
180}
181
182static int
183vesa_bios_set_dac(int bits)
184{
185	struct vm86frame vmf;
186	int err;
187
188	bzero(&vmf, sizeof(vmf));
189	vmf.vmf_eax = 0x4f08;
190	vmf.vmf_ebx = (bits << 8);
191	err = vm86_intcall(0x10, &vmf);
192	return ((err != 0) || (vmf.vmf_eax != 0x4f));
193}
194
195static int
196vesa_bios_save_palette(int start, int colors, u_char *palette)
197{
198	struct vm86frame vmf;
199	u_char *p;
200	int err;
201	int i;
202
203	p = malloc(colors*4, M_DEVBUF, M_WAITOK);
204
205	bzero(&vmf, sizeof(vmf));
206	vmf.vmf_eax = 0x4f09;
207	vmf.vmf_ebx = 1;	/* get primary palette data */
208	vmf.vmf_ecx = colors;
209	vmf.vmf_edx = start;
210	err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di);
211	if ((err != 0) || (vmf.vmf_eax != 0x4f)) {
212		free(p, M_DEVBUF);
213		return 1;
214	}
215
216	for (i = 0; i < colors; ++i) {
217		palette[i*3]     = p[i*4 + 1];
218		palette[i*3 + 1] = p[i*4 + 2];
219		palette[i*3 + 2] = p[i*4 + 3];
220	}
221	free(p, M_DEVBUF);
222	return 0;
223}
224
225static int
226vesa_bios_load_palette(int start, int colors, u_char *palette)
227{
228	struct vm86frame vmf;
229	u_char *p;
230	int err;
231	int i;
232
233	p = malloc(colors*4, M_DEVBUF, M_WAITOK);
234	for (i = 0; i < colors; ++i) {
235		p[i*4]     = 0;
236		p[i*4 + 1] = palette[i*3];
237		p[i*4 + 2] = palette[i*3 + 1];
238		p[i*4 + 3] = palette[i*3 + 2];
239	}
240
241	bzero(&vmf, sizeof(vmf));
242	vmf.vmf_eax = 0x4f09;
243	vmf.vmf_ebx = 0;	/* set primary palette data */
244	vmf.vmf_ecx = colors;
245	vmf.vmf_edx = start;
246	err = vm86_datacall(0x10, &vmf, p, colors*4, &vmf.vmf_es, &vmf.vmf_di);
247	free(p, M_DEVBUF);
248	return ((err != 0) || (vmf.vmf_eax != 0x4f));
249}
250
251static int
252vesa_bios_state_buf_size(void)
253{
254	struct vm86frame vmf;
255	int err;
256
257	bzero(&vmf, sizeof(vmf));
258	vmf.vmf_eax = 0x4f04;
259	vmf.vmf_ecx = STATE_MOST;
260	vmf.vmf_edx = STATE_SIZE;
261	err = vm86_intcall(0x10, &vmf);
262	if ((err != 0) || (vmf.vmf_eax != 0x4f))
263		return 0;
264	return vmf.vmf_ebx*64;
265}
266
267static int
268vesa_bios_save_restore(int code, void *p, size_t size)
269{
270	struct vm86frame vmf;
271	int err;
272
273	bzero(&vmf, sizeof(vmf));
274	vmf.vmf_eax = 0x4f04;
275	vmf.vmf_ecx = STATE_MOST;
276	vmf.vmf_edx = code;	/* STATE_SAVE/STATE_LOAD */
277	err = vm86_datacall(0x10, &vmf, (char *)p, size,
278			  &vmf.vmf_es, &vmf.vmf_bx);
279	return ((err != 0) || (vmf.vmf_eax != 0x4f));
280}
281
282/* map a generic video mode to a known mode */
283static int
284vesa_map_gen_mode_num(int type, int color, int mode)
285{
286    static struct {
287	int from;
288	int to;
289    } mode_map[] = {
290	{ M_TEXT_132x25, M_VESA_C132x25 },
291	{ M_TEXT_132x43, M_VESA_C132x43 },
292	{ M_TEXT_132x50, M_VESA_C132x50 },
293	{ M_TEXT_132x60, M_VESA_C132x60 },
294    };
295    int i;
296
297    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
298        if (mode_map[i].from == mode)
299            return mode_map[i].to;
300    }
301    return mode;
302}
303
304static int
305vesa_translate_flags(u_int16_t vflags)
306{
307	static struct {
308		u_int16_t mask;
309		int set;
310		int reset;
311	} ftable[] = {
312		{ V_MODECOLOR, V_INFO_COLOR, 0 },
313		{ V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 },
314		{ V_MODELFB, V_INFO_LINEAR, 0 },
315	};
316	int flags;
317	int i;
318
319	for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) {
320		flags |= (vflags & ftable[i].mask) ?
321			 ftable[i].set : ftable[i].reset;
322	}
323	return flags;
324}
325
326static void
327*vesa_fix_ptr(u_int32_t p, u_int16_t seg, u_int16_t off, u_char *buf)
328{
329	if (p == 0)
330		return NULL;
331	if (((p >> 16) == seg) && ((p & 0xffff) >= off))
332		return (void *)(buf + ((p & 0xffff) - off));
333	else {
334		p = BIOS_SADDRTOLADDR(p);
335		return (void *)BIOS_PADDRTOVADDR(p);
336	}
337}
338
339static int
340vesa_bios_init(void)
341{
342	static u_char buf[512];
343	struct vm86frame vmf;
344	struct vesa_mode vmode;
345	int modes;
346	int err;
347	int i;
348
349	if (vesa_init_done)
350		return 0;
351
352	has_vesa_bios = FALSE;
353	vesa_adp_info = NULL;
354	vesa_vmode[0].vi_mode = EOT;
355
356	bzero(&vmf, sizeof(vmf));	/* paranoia */
357	bzero(buf, sizeof(buf));
358	bcopy("VBE2", buf, 4);		/* try for VBE2 data */
359	vmf.vmf_eax = 0x4f00;
360	err = vm86_datacall(0x10, &vmf, (char *)buf, sizeof(buf),
361			  &vmf.vmf_es, &vmf.vmf_di);
362	if ((err != 0) || (vmf.vmf_eax != 0x4f) || bcmp("VESA", buf, 4))
363		return 1;
364	vesa_adp_info = (struct vesa_info *)buf;
365	if (bootverbose)
366		dump_buffer(buf, 64);
367	if (vesa_adp_info->v_flags & V_NONVGA)
368		return 1;
369
370	/* fix string ptrs */
371	vesa_oemstr = (char *)vesa_fix_ptr(vesa_adp_info->v_oemstr,
372					   vmf.vmf_es, vmf.vmf_di, buf);
373	if (vesa_adp_info->v_version >= 0x0200) {
374		vesa_venderstr =
375		    (char *)vesa_fix_ptr(vesa_adp_info->v_venderstr,
376					 vmf.vmf_es, vmf.vmf_di, buf);
377		vesa_prodstr =
378		    (char *)vesa_fix_ptr(vesa_adp_info->v_prodstr,
379					 vmf.vmf_es, vmf.vmf_di, buf);
380		vesa_revstr =
381		    (char *)vesa_fix_ptr(vesa_adp_info->v_revstr,
382					 vmf.vmf_es, vmf.vmf_di, buf);
383	}
384
385	/* obtain video mode information */
386	vesa_vmode[0].vi_mode = EOT;
387	vesa_vmodetab = (u_int16_t *)vesa_fix_ptr(vesa_adp_info->v_modetable,
388						  vmf.vmf_es, vmf.vmf_di, buf);
389	if (vesa_vmodetab == NULL)
390		return 1;
391	for (i = 0, modes = 0;
392		(i < (M_VESA_MODE_MAX - M_VESA_BASE + 1))
393		&& (vesa_vmodetab[i] != 0xffff); ++i) {
394		if (modes >= VESA_MAXMODES)
395			break;
396		if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
397			continue;
398
399		/* reject unsupported modes */
400#if 0
401		if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO
402					| V_MODENONVGA))
403		    != (V_MODESUPP | V_MODEOPTINFO))
404			continue;
405#else
406		if ((vmode.v_modeattr & (V_MODEOPTINFO | V_MODENONVGA))
407		    != (V_MODEOPTINFO))
408			continue;
409#endif
410
411		/* copy some fields */
412		bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes]));
413		vesa_vmode[modes].vi_mode = vesa_vmodetab[i];
414		vesa_vmode[modes].vi_width = vmode.v_width;
415		vesa_vmode[modes].vi_height = vmode.v_height;
416		vesa_vmode[modes].vi_depth = vmode.v_bpp;
417		vesa_vmode[modes].vi_planes = vmode.v_planes;
418		vesa_vmode[modes].vi_cwidth = vmode.v_cwidth;
419		vesa_vmode[modes].vi_cheight = vmode.v_cheight;
420		vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4;
421		/* XXX window B */
422		vesa_vmode[modes].vi_window_size = vmode.v_wsize*1024;
423		vesa_vmode[modes].vi_window_gran = vmode.v_wgran*1024;
424		vesa_vmode[modes].vi_buffer = vmode.v_lfb;
425		vesa_vmode[modes].vi_buffer_size = vmode.v_offscreen;
426		/* pixel format, memory model... */
427		vesa_vmode[modes].vi_flags
428			= vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA;
429		++modes;
430	}
431	vesa_vmode[modes].vi_mode = EOT;
432	if (bootverbose)
433		printf("VESA: %d mode(s) found\n", modes);
434
435	has_vesa_bios = (modes > 0);
436	return (has_vesa_bios ? 0 : 1);
437}
438
439static void
440vesa_clear_modes(video_info_t *info, int color)
441{
442	while (info->vi_mode != EOT) {
443		if ((info->vi_flags & V_INFO_COLOR) != color)
444			info->vi_mode = NA;
445		++info;
446	}
447}
448
449/* exported functions */
450
451static int
452vesa_init(void)
453{
454	int adapters;
455	int i;
456
457	adapters = (*prevvidsw.init)();
458	for (i = 0; i < adapters; ++i) {
459		if ((vesa_adp = (*prevvidsw.adapter)(i)) == NULL)
460			continue;
461		if (vesa_adp->va_type == KD_VGA) {
462			vesa_adp->va_flags |= V_ADP_VESA;
463			return adapters;
464		}
465	}
466	vesa_adp = NULL;
467	return adapters;
468}
469
470static video_adapter_t
471*vesa_adapter(int ad)
472{
473	return (*prevvidsw.adapter)(ad);
474}
475
476static int
477vesa_get_info(int ad, int mode, video_info_t *info)
478{
479	int i;
480
481	if ((*prevvidsw.get_info)(ad, mode, info) == 0)
482		return 0;
483
484	if (ad != vesa_adp->va_index)
485		return 1;
486
487	mode = vesa_map_gen_mode_num(vesa_adp->va_type,
488				     vesa_adp->va_flags & V_ADP_COLOR, mode);
489	for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
490		if (vesa_vmode[i].vi_mode == NA)
491			continue;
492		if (vesa_vmode[i].vi_mode == mode) {
493			*info = vesa_vmode[i];
494			return 0;
495		}
496	}
497	return 1;
498}
499
500static int
501vesa_query_mode(int ad, video_info_t *info)
502{
503	int i;
504
505	if ((i = (*prevvidsw.query_mode)(ad, info)) != -1)
506		return i;
507	if (ad != vesa_adp->va_index)
508		return -1;
509
510	for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
511		if ((info->vi_width != 0)
512		    && (info->vi_width != vesa_vmode[i].vi_width))
513			continue;
514		if ((info->vi_height != 0)
515		    && (info->vi_height != vesa_vmode[i].vi_height))
516			continue;
517		if ((info->vi_cwidth != 0)
518		    && (info->vi_cwidth != vesa_vmode[i].vi_cwidth))
519			continue;
520		if ((info->vi_cheight != 0)
521		    && (info->vi_cheight != vesa_vmode[i].vi_cheight))
522			continue;
523		if ((info->vi_depth != 0)
524		    && (info->vi_depth != vesa_vmode[i].vi_depth))
525			continue;
526		if ((info->vi_planes != 0)
527		    && (info->vi_planes != vesa_vmode[i].vi_planes))
528			continue;
529		/* pixel format, memory model */
530		if ((info->vi_flags != 0)
531		    && (info->vi_flags != vesa_vmode[i].vi_flags))
532			continue;
533		return vesa_vmode[i].vi_mode;
534	}
535	return -1;
536}
537
538static int
539vesa_set_mode(int ad, int mode)
540{
541	video_info_t info;
542	size_t len;
543
544	if (ad != vesa_adp->va_index)
545		return (*prevvidsw.set_mode)(ad, mode);
546
547	mode = vesa_map_gen_mode_num(vesa_adp->va_type,
548				     vesa_adp->va_flags & V_ADP_COLOR, mode);
549#ifdef SC_VIDEO_DEBUG
550	printf("VESA: set_mode(): %d(%x) -> %d(%x)\n",
551		vesa_adp->va_mode, vesa_adp->va_mode, mode, mode);
552#endif
553	/*
554	 * If the current mode is a VESA mode and the new mode is not,
555	 * restore the state of the adapter first, so that non-standard,
556	 * extended SVGA registers are set to the state compatible with
557	 * the standard VGA modes. Otherwise (*prevvidsw.set_mode)()
558	 * may not be able to set up the new mode correctly.
559	 */
560	if (VESA_MODE(vesa_adp->va_mode)) {
561		if ((*prevvidsw.get_info)(ad, mode, &info) == 0) {
562			/* assert(vesa_state_buf != NULL); */
563		    	if ((vesa_state_buf == NULL)
564			    || vesa_load_state(ad, vesa_state_buf))
565				return 1;
566			free(vesa_state_buf, M_DEVBUF);
567			vesa_state_buf = NULL;
568#ifdef SC_VIDEO_DEBUG
569			printf("VESA: restored\n");
570#endif
571		}
572		/*
573		 * once (*prevvidsw.get_info)() succeeded,
574		 * (*prevvidsw.set_mode)() below won't fail...
575		 */
576	}
577
578	/* we may not need to handle this mode after all... */
579	if ((*prevvidsw.set_mode)(ad, mode) == 0)
580		return 0;
581
582	/* is the new mode supported? */
583	if (vesa_get_info(ad, mode, &info))
584		return 1;
585	/* assert(VESA_MODE(mode)); */
586
587#ifdef SC_VIDEO_DEBUG
588	printf("VESA: about to set a VESA mode...\n");
589#endif
590	/*
591	 * If the current mode is not a VESA mode, save the current state
592	 * so that the adapter state can be restored later when a non-VESA
593	 * mode is to be set up. See above.
594	 */
595	if (!VESA_MODE(vesa_adp->va_mode) && (vesa_state_buf == NULL)) {
596		len = vesa_save_state(ad, NULL, 0);
597		vesa_state_buf = malloc(len, M_DEVBUF, M_WAITOK);
598		if (vesa_save_state(ad, vesa_state_buf, len)) {
599#ifdef SC_VIDEO_DEBUG
600			printf("VESA: state save failed! (len=%d)\n", len);
601#endif
602			free(vesa_state_buf, M_DEVBUF);
603			vesa_state_buf = NULL;
604			return 1;
605		}
606#ifdef SC_VIDEO_DEBUG
607		printf("VESA: saved (len=%d)\n", len);
608		dump_buffer(vesa_state_buf, len);
609#endif
610	}
611
612	if (vesa_bios_set_mode(mode))
613		return 1;
614
615#ifdef SC_VIDEO_DEBUG
616	printf("VESA: mode set!\n");
617#endif
618	vesa_adp->va_mode = mode;
619	vesa_adp->va_flags &= ~V_ADP_COLOR;
620	vesa_adp->va_flags |=
621		(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
622	vesa_adp->va_crtc_addr =
623		(vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_BASE : MONO_BASE;
624	vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
625	vesa_adp->va_window_size = info.vi_window_size;
626	vesa_adp->va_window_gran = info.vi_window_gran;
627	if (info.vi_buffer_size == 0) {
628		vesa_adp->va_buffer = 0;
629		vesa_adp->va_buffer_size = 0;
630	} else {
631		vesa_adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
632		vesa_adp->va_buffer_size = info.vi_buffer_size;
633	}
634
635	return 0;
636}
637
638static int
639vesa_save_font(int ad, int page, int fontsize, u_char *data, int ch, int count)
640{
641	return (*prevvidsw.save_font)(ad, page, fontsize, data, ch, count);
642}
643
644static int
645vesa_load_font(int ad, int page, int fontsize, u_char *data, int ch, int count)
646{
647	return (*prevvidsw.load_font)(ad, page, fontsize, data, ch, count);
648}
649
650static int
651vesa_show_font(int ad, int page)
652{
653	return (*prevvidsw.show_font)(ad, page);
654}
655
656static int
657vesa_save_palette(int ad, u_char *palette)
658{
659	if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8)
660	    || vesa_bios_set_dac(8))
661		return (*prevvidsw.save_palette)(ad, palette);
662
663	return vesa_bios_save_palette(0, 256, palette);
664}
665
666static int
667vesa_load_palette(int ad, u_char *palette)
668{
669	if ((ad != vesa_adp->va_index) || !(vesa_adp_info->v_flags & V_DAC8)
670	    || vesa_bios_set_dac(8))
671		return (*prevvidsw.load_palette)(ad, palette);
672
673	return vesa_bios_load_palette(0, 256, palette);
674}
675
676static int
677vesa_set_border(int ad, int color)
678{
679	return (*prevvidsw.set_border)(ad, color);
680}
681
682static int
683vesa_save_state(int ad, void *p, size_t size)
684{
685	if (ad != vesa_adp->va_index)
686		return (*prevvidsw.save_state)(ad, p, size);
687
688	if (vesa_state_buf_size == 0)
689		vesa_state_buf_size = vesa_bios_state_buf_size();
690	if (size == 0)
691		return (sizeof(int) + vesa_state_buf_size);
692	else if (size < (sizeof(int) + vesa_state_buf_size))
693		return 1;
694
695	((adp_state_t *)p)->sig = V_STATE_SIG;
696	bzero(((adp_state_t *)p)->regs, vesa_state_buf_size);
697	return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs,
698				      vesa_state_buf_size);
699}
700
701static int
702vesa_load_state(int ad, void *p)
703{
704	if ((ad != vesa_adp->va_index)
705	    || (((adp_state_t *)p)->sig != V_STATE_SIG))
706		return (*prevvidsw.load_state)(ad, p);
707
708	return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs,
709				      vesa_state_buf_size);
710}
711
712static int
713vesa_set_origin(int ad, off_t offset)
714{
715	struct vm86frame vmf;
716	int err;
717
718	/*
719	 * This function should return as quickly as possible to
720	 * maintain good performance of the system. For this reason,
721	 * error checking is kept minimal and let the VESA BIOS to
722	 * detect error.
723	 */
724	if (ad != vesa_adp->va_index)
725		return (*prevvidsw.set_win_org)(ad, offset);
726
727	if (vesa_adp->va_window_gran == 0)
728		return 1;
729	bzero(&vmf, sizeof(vmf));
730	vmf.vmf_eax = 0x4f05;
731	vmf.vmf_ebx = 0;		/* WINDOW_A, XXX */
732	vmf.vmf_edx = offset/vesa_adp->va_window_gran;
733	err = vm86_intcall(0x10, &vmf);
734	return ((err != 0) || (vmf.vmf_eax != 0x4f));
735}
736
737static int
738vesa_read_hw_cursor(int ad, int *col, int *row)
739{
740	return (*prevvidsw.read_hw_cursor)(ad, col, row);
741}
742
743static int
744vesa_set_hw_cursor(int ad, int col, int row)
745{
746	return (*prevvidsw.set_hw_cursor)(ad, col, row);
747}
748
749static int
750vesa_diag(int level)
751{
752	struct vesa_mode vmode;
753	int i;
754
755#ifndef KLD_MODULE
756	/* call the previous handler first */
757	(*prevvidsw.diag)(level);
758#endif
759
760	/* general adapter information */
761	printf("VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n",
762	       ((vesa_adp_info->v_version & 0xf000) >> 12) * 10
763		   + ((vesa_adp_info->v_version & 0x0f00) >> 8),
764	       ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10
765		   + (vesa_adp_info->v_version & 0x000f),
766	       vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags,
767	       vesa_vmodetab, vesa_adp_info->v_modetable);
768	/* OEM string */
769	if (vesa_oemstr != NULL)
770		printf("VESA: %s\n", vesa_oemstr);
771
772	if (level <= 0)
773		return 0;
774
775	if (vesa_adp_info->v_version >= 0x0200) {
776		/* vendor name */
777		if (vesa_venderstr != NULL)
778			printf("VESA: %s\n", vesa_venderstr);
779		/* product name */
780		if (vesa_prodstr != NULL)
781			printf("VESA: %s\n", vesa_prodstr);
782		/* product revision */
783		if (vesa_revstr != NULL)
784			printf("VESA: %s\n", vesa_revstr);
785	}
786
787	/* mode information */
788	for (i = 0;
789		(i < (M_VESA_MODE_MAX - M_VESA_BASE + 1))
790		&& (vesa_vmodetab[i] != 0xffff); ++i) {
791		if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
792			continue;
793
794		/* print something for diagnostic purpose */
795		printf("VESA: mode:0x%03x, flags:0x%04x",
796		       vesa_vmodetab[i], vmode.v_modeattr);
797		if (vmode.v_modeattr & V_MODEOPTINFO) {
798			if (vmode.v_modeattr & V_MODEGRAPHICS) {
799				printf(", G %dx%dx%d %d, ",
800				       vmode.v_width, vmode.v_height,
801				       vmode.v_bpp, vmode.v_planes);
802			} else {
803				printf(", T %dx%d, ",
804				       vmode.v_width, vmode.v_height);
805			}
806			printf("font:%dx%d",
807			       vmode.v_cwidth, vmode.v_cheight);
808		}
809		if (vmode.v_modeattr & V_MODELFB) {
810			printf(", mem:%d, LFB:0x%x, off:0x%x",
811			       vmode.v_memmodel, vmode.v_lfb,
812			       vmode.v_offscreen);
813		}
814		printf("\n");
815		printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ",
816		       vmode.v_waseg, vmode.v_waattr,
817		       vmode.v_wbseg, vmode.v_wbattr);
818		printf("size:%dk, gran:%dk\n",
819		       vmode.v_wsize, vmode.v_wgran);
820	}
821
822	return 0;
823}
824
825/* module loading */
826
827#ifdef KLD_MODULE
828static
829#endif
830int
831vesa_load(void)
832{
833	int adapters;
834	int error;
835#ifdef KLD_MODULE
836	int s;
837#endif
838	int i;
839
840	if (vesa_init_done)
841		return 0;
842
843	/*
844	 * If the VESA module is statically linked to the kernel, or
845	 * it has already been loaded, abort loading this module this time.
846	 */
847	vesa_adp = NULL;
848	adapters = (*biosvidsw.init)();
849	for (i = 0; i < adapters; ++i) {
850		if ((vesa_adp = (*biosvidsw.adapter)(i)) == NULL)
851			continue;
852		if (vesa_adp->va_flags & V_ADP_VESA)
853			return ENXIO;
854		if (vesa_adp->va_type == KD_VGA)
855			break;
856	}
857	/* if a VGA adapter is not found, abort */
858	if (i >= adapters)
859		return ENXIO;
860
861	if (vesa_bios_init())
862		return ENXIO;
863	vesa_adp->va_flags |= V_ADP_VESA;
864
865	/* remove conflicting modes if we have more than one adapter */
866	if (adapters > 1) {
867		vesa_clear_modes(vesa_vmode,
868				 (vesa_adp->va_flags & V_ADP_COLOR) ?
869				     V_INFO_COLOR : 0);
870	}
871
872#ifdef KLD_MODULE
873	s = spltty();
874#endif
875	if ((error = vesa_load_ioctl()) == 0) {
876		bcopy(&biosvidsw, &prevvidsw, sizeof(prevvidsw));
877		bcopy(&vesavidsw, &biosvidsw, sizeof(vesavidsw));
878		vesa_init_done = TRUE;
879	}
880#ifdef KLD_MODULE
881	splx(s);
882
883	if (error == 0)
884		vesa_diag(bootverbose);
885#endif
886
887	return error;
888}
889
890#ifdef KLD_MODULE
891
892static int
893vesa_unload(void)
894{
895	int error;
896	int s;
897
898	/* if the adapter is currently in a VESA mode, don't unload */
899	if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode))
900		return EBUSY;
901	/*
902	 * FIXME: if there is at least one vty which is in a VESA mode,
903	 * we shouldn't be unloading! XXX
904	 */
905
906	s = spltty();
907	if ((error = vesa_unload_ioctl()) == 0) {
908		if (vesa_adp)
909			vesa_adp->va_flags &= ~V_ADP_VESA;
910		bcopy(&prevvidsw, &biosvidsw, sizeof(biosvidsw));
911	}
912	splx(s);
913
914	return error;
915}
916
917static int
918vesa_mod_event(module_t mod, int type, void *data)
919{
920	switch (type) {
921	case MOD_LOAD:
922		return vesa_load();
923	case MOD_UNLOAD:
924		return vesa_unload();
925	default:
926		break;
927	}
928	return 0;
929}
930
931static moduledata_t vesa_mod = {
932	"vesa",
933	vesa_mod_event,
934	NULL,
935};
936
937DECLARE_MODULE(vesa, vesa_mod, SI_SUB_PSEUDO, SI_ORDER_MIDDLE);
938
939#endif /* KLD_MODULE */
940
941#endif /* (NSC > 0 && VESA && VM86) || KLD_MODULE */
942