vesa.c revision 203078
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
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/dev/fb/vesa.c 203078 2010-01-27 17:00:42Z jkim $");
29
30#include "opt_vga.h"
31#include "opt_vesa.h"
32
33#ifndef VGA_NO_MODE_CHANGE
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/malloc.h>
41#include <sys/fbio.h>
42
43#include <vm/vm.h>
44#include <vm/vm_extern.h>
45#include <vm/vm_kern.h>
46#include <vm/vm_param.h>
47#include <vm/pmap.h>
48
49#include <machine/pc/bios.h>
50#include <dev/fb/vesa.h>
51
52#include <dev/fb/fbreg.h>
53#include <dev/fb/vgareg.h>
54
55#include <dev/pci/pcivar.h>
56
57#include <isa/isareg.h>
58
59#include <compat/x86bios/x86bios.h>
60
61#define	VESA_VIA_CLE266		"VIA CLE266\r\n"
62
63#ifndef VESA_DEBUG
64#define VESA_DEBUG	0
65#endif
66
67/* VESA video adapter state buffer stub */
68struct adp_state {
69	int		sig;
70#define V_STATE_SIG	0x61736576
71	u_char		regs[1];
72};
73typedef struct adp_state adp_state_t;
74
75/* VESA video adapter */
76static video_adapter_t *vesa_adp = NULL;
77static ssize_t vesa_state_buf_size = -1;
78
79/* VESA functions */
80#if 0
81static int			vesa_nop(void);
82#endif
83static int			vesa_error(void);
84static vi_probe_t		vesa_probe;
85static vi_init_t		vesa_init;
86static vi_get_info_t		vesa_get_info;
87static vi_query_mode_t		vesa_query_mode;
88static vi_set_mode_t		vesa_set_mode;
89static vi_save_font_t		vesa_save_font;
90static vi_load_font_t		vesa_load_font;
91static vi_show_font_t		vesa_show_font;
92static vi_save_palette_t	vesa_save_palette;
93static vi_load_palette_t	vesa_load_palette;
94static vi_set_border_t		vesa_set_border;
95static vi_save_state_t		vesa_save_state;
96static vi_load_state_t		vesa_load_state;
97static vi_set_win_org_t		vesa_set_origin;
98static vi_read_hw_cursor_t	vesa_read_hw_cursor;
99static vi_set_hw_cursor_t	vesa_set_hw_cursor;
100static vi_set_hw_cursor_shape_t	vesa_set_hw_cursor_shape;
101static vi_blank_display_t	vesa_blank_display;
102static vi_mmap_t		vesa_mmap;
103static vi_ioctl_t		vesa_ioctl;
104static vi_clear_t		vesa_clear;
105static vi_fill_rect_t		vesa_fill_rect;
106static vi_bitblt_t		vesa_bitblt;
107static vi_diag_t		vesa_diag;
108static int			vesa_bios_info(int level);
109
110static video_switch_t vesavidsw = {
111	vesa_probe,
112	vesa_init,
113	vesa_get_info,
114	vesa_query_mode,
115	vesa_set_mode,
116	vesa_save_font,
117	vesa_load_font,
118	vesa_show_font,
119	vesa_save_palette,
120	vesa_load_palette,
121	vesa_set_border,
122	vesa_save_state,
123	vesa_load_state,
124	vesa_set_origin,
125	vesa_read_hw_cursor,
126	vesa_set_hw_cursor,
127	vesa_set_hw_cursor_shape,
128	vesa_blank_display,
129	vesa_mmap,
130	vesa_ioctl,
131	vesa_clear,
132	vesa_fill_rect,
133	vesa_bitblt,
134	vesa_error,
135	vesa_error,
136	vesa_diag,
137};
138
139static video_switch_t *prevvidsw;
140
141/* VESA BIOS video modes */
142#define VESA_MAXMODES	64
143#define EOT		(-1)
144#define NA		(-2)
145
146#define MODE_TABLE_DELTA 8
147
148static int vesa_vmode_max = 0;
149static video_info_t vesa_vmode_empty = { EOT };
150static video_info_t *vesa_vmode = &vesa_vmode_empty;
151
152static int vesa_init_done = FALSE;
153static int has_vesa_bios = FALSE;
154static struct vesa_info *vesa_adp_info = NULL;
155static u_int16_t *vesa_vmodetab = NULL;
156static char *vesa_oemstr = NULL;
157static char *vesa_venderstr = NULL;
158static char *vesa_prodstr = NULL;
159static char *vesa_revstr = NULL;
160
161/* local macros and functions */
162#define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
163
164static int int10_set_mode(int mode);
165static int vesa_bios_post(void);
166static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
167static int vesa_bios_set_mode(int mode);
168static int vesa_bios_get_dac(void);
169static int vesa_bios_set_dac(int bits);
170static int vesa_bios_save_palette(int start, int colors, u_char *palette,
171				  int bits);
172static int vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g,
173				   u_char *b, int bits);
174static int vesa_bios_load_palette(int start, int colors, u_char *palette,
175				  int bits);
176static int vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g,
177				   u_char *b, int bits);
178#define STATE_SIZE	0
179#define STATE_SAVE	1
180#define STATE_LOAD	2
181#define STATE_HW	(1<<0)
182#define STATE_DATA	(1<<1)
183#define STATE_DAC	(1<<2)
184#define STATE_REG	(1<<3)
185#define STATE_MOST	(STATE_HW | STATE_DATA | STATE_REG)
186#define STATE_ALL	(STATE_HW | STATE_DATA | STATE_DAC | STATE_REG)
187static ssize_t vesa_bios_state_buf_size(void);
188static int vesa_bios_save_restore(int code, void *p, size_t size);
189static int vesa_bios_get_line_length(void);
190static int vesa_bios_set_line_length(int pixel, int *bytes, int *lines);
191#if 0
192static int vesa_bios_get_start(int *x, int *y);
193#endif
194static int vesa_bios_set_start(int x, int y);
195static int vesa_map_gen_mode_num(int type, int color, int mode);
196static int vesa_translate_flags(u_int16_t vflags);
197static int vesa_translate_mmodel(u_int8_t vmodel);
198static int vesa_get_line_width(video_info_t *info);
199static int vesa_bios_init(void);
200static void vesa_clear_modes(video_info_t *info, int color);
201static vm_offset_t vesa_map_buffer(u_int paddr, size_t size);
202static void vesa_unmap_buffer(vm_offset_t vaddr, size_t size);
203
204#if 0
205static int vesa_get_origin(video_adapter_t *adp, off_t *offset);
206#endif
207
208static void
209dump_buffer(u_char *buf, size_t len)
210{
211    int i;
212
213    for(i = 0; i < len;) {
214	printf("%02x ", buf[i]);
215	if ((++i % 16) == 0)
216	    printf("\n");
217    }
218}
219
220/* INT 10 BIOS calls */
221static int
222int10_set_mode(int mode)
223{
224	x86regs_t regs;
225
226	x86bios_init_regs(&regs);
227	regs.R_AL = mode;
228
229	x86bios_intr(&regs, 0x10);
230
231	return (0);
232}
233
234static int
235vesa_bios_post(void)
236{
237	x86regs_t regs;
238	devclass_t dc;
239	device_t *devs;
240	device_t dev;
241	int count, i, is_pci;
242
243	if (x86bios_get_orm(0xc0000) == NULL)
244		return (1);
245
246	dev = NULL;
247	is_pci = 0;
248
249	/* Find the matching PCI video controller. */
250	dc = devclass_find("vgapci");
251	if (dc != NULL && devclass_get_devices(dc, &devs, &count) == 0) {
252		for (dev = NULL, i = 0; dev == NULL && i < count; devs++, i++)
253			if (device_get_flags(*devs) != 0 &&
254			    x86bios_match_device(0xc0000, *devs)) {
255				dev = *devs;
256				is_pci = 1;
257				break;
258			}
259		free(devs, M_TEMP);
260	}
261
262	/* Try VGA if a PCI device is not found. */
263	if (dev == NULL) {
264		dc = devclass_find(VGA_DRIVER_NAME);
265		if (dc != NULL)
266			dev = devclass_get_device(dc, 0);
267	}
268
269	if (bootverbose)
270		printf("%s: calling BIOS POST\n",
271		    dev == NULL ? "VESA" : device_get_nameunit(dev));
272
273	x86bios_init_regs(&regs);
274	if (is_pci) {
275		regs.R_AH = pci_get_bus(dev);
276		regs.R_AL = (pci_get_slot(dev) << 3) |
277		    (pci_get_function(dev) & 0x07);
278	}
279	regs.R_DL = 0x80;
280	x86bios_call(&regs, 0xc000, 0x0003);
281
282	if (x86bios_get_intr(0x10) == 0)
283		return (1);
284
285	return (0);
286}
287
288/* VESA BIOS calls */
289static int
290vesa_bios_get_mode(int mode, struct vesa_mode *vmode)
291{
292	x86regs_t regs;
293	uint32_t offs;
294	void *buf;
295
296	buf = x86bios_alloc(&offs, sizeof(*vmode));
297	if (buf == NULL)
298		return (1);
299
300	x86bios_init_regs(&regs);
301	regs.R_AX = 0x4f01;
302	regs.R_CX = mode;
303
304	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
305	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
306
307	x86bios_intr(&regs, 0x10);
308
309	if (regs.R_AX != 0x004f) {
310		x86bios_free(buf, sizeof(*vmode));
311		return (1);
312	}
313
314	bcopy(buf, vmode, sizeof(*vmode));
315	x86bios_free(buf, sizeof(*vmode));
316
317	return (0);
318}
319
320static int
321vesa_bios_set_mode(int mode)
322{
323	x86regs_t regs;
324
325	x86bios_init_regs(&regs);
326	regs.R_AX = 0x4f02;
327	regs.R_BX = mode;
328
329	x86bios_intr(&regs, 0x10);
330
331	return (regs.R_AX != 0x004f);
332}
333
334static int
335vesa_bios_get_dac(void)
336{
337	x86regs_t regs;
338
339	x86bios_init_regs(&regs);
340	regs.R_AX = 0x4f08;
341	regs.R_BL = 1;
342
343	x86bios_intr(&regs, 0x10);
344
345	if (regs.R_AX != 0x004f)
346		return (6);
347
348	return (regs.R_BH);
349}
350
351static int
352vesa_bios_set_dac(int bits)
353{
354	x86regs_t regs;
355
356	x86bios_init_regs(&regs);
357	regs.R_AX = 0x4f08;
358	/* regs.R_BL = 0; */
359	regs.R_BH = bits;
360
361	x86bios_intr(&regs, 0x10);
362
363	if (regs.R_AX != 0x004f)
364		return (6);
365
366	return (regs.R_BH);
367}
368
369static int
370vesa_bios_save_palette(int start, int colors, u_char *palette, int bits)
371{
372	x86regs_t regs;
373	uint32_t offs;
374	u_char *p;
375	int i;
376
377	p = (u_char *)x86bios_alloc(&offs, colors * 4);
378	if (p == NULL)
379		return (1);
380
381	x86bios_init_regs(&regs);
382	regs.R_AX = 0x4f09;
383	regs.R_BL = 1;
384	regs.R_CX = colors;
385	regs.R_DX = start;
386
387	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
388	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
389
390	x86bios_intr(&regs, 0x10);
391
392	if (regs.R_AX != 0x004f) {
393		x86bios_free(p, colors * 4);
394		return (1);
395	}
396
397	bits = 8 - bits;
398	for (i = 0; i < colors; ++i) {
399		palette[i * 3] = p[i * 4 + 2] << bits;
400		palette[i * 3 + 1] = p[i * 4 + 1] << bits;
401		palette[i * 3 + 2] = p[i * 4] << bits;
402	}
403	x86bios_free(p, colors * 4);
404
405	return (0);
406}
407
408static int
409vesa_bios_save_palette2(int start, int colors, u_char *r, u_char *g, u_char *b,
410			int bits)
411{
412	x86regs_t regs;
413	uint32_t offs;
414	u_char *p;
415	int i;
416
417	p = (u_char *)x86bios_alloc(&offs, colors * 4);
418	if (p == NULL)
419		return (1);
420
421	x86bios_init_regs(&regs);
422	regs.R_AX = 0x4f09;
423	regs.R_BL = 1;
424	regs.R_CX = colors;
425	regs.R_DX = start;
426
427	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
428	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
429
430	x86bios_intr(&regs, 0x10);
431
432	if (regs.R_AX != 0x004f) {
433		x86bios_free(p, colors * 4);
434		return (1);
435	}
436
437	bits = 8 - bits;
438	for (i = 0; i < colors; ++i) {
439		r[i] = p[i * 4 + 2] << bits;
440		g[i] = p[i * 4 + 1] << bits;
441		b[i] = p[i * 4] << bits;
442	}
443	x86bios_free(p, colors * 4);
444
445	return (0);
446}
447
448static int
449vesa_bios_load_palette(int start, int colors, u_char *palette, int bits)
450{
451	x86regs_t regs;
452	uint32_t offs;
453	u_char *p;
454	int i;
455
456	p = (u_char *)x86bios_alloc(&offs, colors * 4);
457	if (p == NULL)
458		return (1);
459
460	x86bios_init_regs(&regs);
461	regs.R_AX = 0x4f09;
462	/* regs.R_BL = 0; */
463	regs.R_CX = colors;
464	regs.R_DX = start;
465
466	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
467	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
468
469	bits = 8 - bits;
470	for (i = 0; i < colors; ++i) {
471		p[i * 4] = palette[i * 3 + 2] >> bits;
472		p[i * 4 + 1] = palette[i * 3 + 1] >> bits;
473		p[i * 4 + 2] = palette[i * 3] >> bits;
474		p[i * 4 + 3] = 0;
475	}
476	x86bios_intr(&regs, 0x10);
477	x86bios_free(p, colors * 4);
478
479	return (regs.R_AX != 0x004f);
480}
481
482static int
483vesa_bios_load_palette2(int start, int colors, u_char *r, u_char *g, u_char *b,
484			int bits)
485{
486	x86regs_t regs;
487	uint32_t offs;
488	u_char *p;
489	int i;
490
491	p = (u_char *)x86bios_alloc(&offs, colors * 4);
492	if (p == NULL)
493		return (1);
494
495	x86bios_init_regs(&regs);
496	regs.R_AX = 0x4f09;
497	/* regs.R_BL = 0; */
498	regs.R_CX = colors;
499	regs.R_DX = start;
500
501	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
502	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
503
504	bits = 8 - bits;
505	for (i = 0; i < colors; ++i) {
506		p[i * 4] = b[i] >> bits;
507		p[i * 4 + 1] = g[i] >> bits;
508		p[i * 4 + 2] = r[i] >> bits;
509		p[i * 4 + 3] = 0;
510	}
511	x86bios_intr(&regs, 0x10);
512	x86bios_free(p, colors * 4);
513
514	return (regs.R_AX != 0x004f);
515}
516
517static ssize_t
518vesa_bios_state_buf_size(void)
519{
520	x86regs_t regs;
521
522	x86bios_init_regs(&regs);
523	regs.R_AX = 0x4f04;
524	/* regs.R_DL = STATE_SIZE; */
525	regs.R_CX = STATE_ALL;
526
527	x86bios_intr(&regs, 0x10);
528
529	if (regs.R_AX != 0x004f)
530		return (0);
531
532	return (regs.R_BX * 64);
533}
534
535static int
536vesa_bios_save_restore(int code, void *p, size_t size)
537{
538	x86regs_t regs;
539	uint32_t offs;
540	void *buf;
541
542	if (code != STATE_SAVE && code != STATE_LOAD)
543		return (1);
544
545	buf = x86bios_alloc(&offs, size);
546
547	x86bios_init_regs(&regs);
548	regs.R_AX = 0x4f04;
549	regs.R_DL = code;
550	regs.R_CX = STATE_ALL;
551
552	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
553	regs.R_BX = X86BIOS_PHYSTOOFF(offs);
554
555	switch (code) {
556	case STATE_SAVE:
557		x86bios_intr(&regs, 0x10);
558		bcopy(buf, p, size);
559		break;
560	case STATE_LOAD:
561		bcopy(p, buf, size);
562		x86bios_intr(&regs, 0x10);
563		break;
564	}
565	x86bios_free(buf, size);
566
567	return (regs.R_AX != 0x004f);
568}
569
570static int
571vesa_bios_get_line_length(void)
572{
573	x86regs_t regs;
574
575	x86bios_init_regs(&regs);
576	regs.R_AX = 0x4f06;
577	regs.R_BL = 1;
578
579	x86bios_intr(&regs, 0x10);
580
581	if (regs.R_AX != 0x004f)
582		return (-1);
583
584	return (regs.R_BX);
585}
586
587static int
588vesa_bios_set_line_length(int pixel, int *bytes, int *lines)
589{
590	x86regs_t regs;
591
592	x86bios_init_regs(&regs);
593	regs.R_AX = 0x4f06;
594	/* regs.R_BL = 0; */
595	regs.R_CX = pixel;
596
597	x86bios_intr(&regs, 0x10);
598
599#if VESA_DEBUG > 1
600	printf("bx:%d, cx:%d, dx:%d\n", regs.R_BX, regs.R_CX, regs.R_DX);
601#endif
602	if (regs.R_AX != 0x004f)
603		return (-1);
604
605	if (bytes != NULL)
606		*bytes = regs.R_BX;
607	if (lines != NULL)
608		*lines = regs.R_DX;
609
610	return (0);
611}
612
613#if 0
614static int
615vesa_bios_get_start(int *x, int *y)
616{
617	x86regs_t regs;
618
619	x86bios_init_regs(&regs);
620	regs.R_AX = 0x4f07;
621	regs.R_BL = 1;
622
623	x86bios_intr(&regs, 0x10);
624
625	if (regs.R_AX != 0x004f)
626		return (-1);
627
628	*x = regs.R_CX;
629	*y = regs.R_DX;
630
631	return (0);
632}
633#endif
634
635static int
636vesa_bios_set_start(int x, int y)
637{
638	x86regs_t regs;
639
640	x86bios_init_regs(&regs);
641	regs.R_AX = 0x4f07;
642	regs.R_BL = 0x80;
643	regs.R_CX = x;
644	regs.R_DX = y;
645
646	x86bios_intr(&regs, 0x10);
647
648	return (regs.R_AX != 0x004f);
649}
650
651/* map a generic video mode to a known mode */
652static int
653vesa_map_gen_mode_num(int type, int color, int mode)
654{
655    static struct {
656	int from;
657	int to;
658    } mode_map[] = {
659	{ M_TEXT_132x25, M_VESA_C132x25 },
660	{ M_TEXT_132x43, M_VESA_C132x43 },
661	{ M_TEXT_132x50, M_VESA_C132x50 },
662	{ M_TEXT_132x60, M_VESA_C132x60 },
663    };
664    int i;
665
666    for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
667        if (mode_map[i].from == mode)
668            return (mode_map[i].to);
669    }
670    return (mode);
671}
672
673static int
674vesa_translate_flags(u_int16_t vflags)
675{
676	static struct {
677		u_int16_t mask;
678		int set;
679		int reset;
680	} ftable[] = {
681		{ V_MODECOLOR, V_INFO_COLOR, 0 },
682		{ V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 },
683		{ V_MODELFB, V_INFO_LINEAR, 0 },
684		{ V_MODENONVGA, V_INFO_NONVGA, 0 },
685	};
686	int flags;
687	int i;
688
689	for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) {
690		flags |= (vflags & ftable[i].mask) ?
691			 ftable[i].set : ftable[i].reset;
692	}
693	return (flags);
694}
695
696static int
697vesa_translate_mmodel(u_int8_t vmodel)
698{
699	static struct {
700		u_int8_t vmodel;
701		int mmodel;
702	} mtable[] = {
703		{ V_MMTEXT,	V_INFO_MM_TEXT },
704		{ V_MMCGA,	V_INFO_MM_CGA },
705		{ V_MMHGC,	V_INFO_MM_HGC },
706		{ V_MMEGA,	V_INFO_MM_PLANAR },
707		{ V_MMPACKED,	V_INFO_MM_PACKED },
708		{ V_MMDIRCOLOR,	V_INFO_MM_DIRECT },
709	};
710	int i;
711
712	for (i = 0; mtable[i].mmodel >= 0; ++i) {
713		if (mtable[i].vmodel == vmodel)
714			return (mtable[i].mmodel);
715	}
716	return (V_INFO_MM_OTHER);
717}
718
719static int
720vesa_get_line_width(video_info_t *info)
721{
722	int len;
723	int width;
724
725	width = info->vi_width;
726
727	if (info->vi_flags & V_INFO_GRAPHICS)
728		switch (info->vi_depth / info->vi_planes) {
729		case 1:
730			return (width / 8);
731		case 2:
732			return (width / 4);
733		case 4:
734			return (width / 2);
735		case 8:
736			return (width);
737		case 15:
738		case 16:
739			return (width * 2);
740		case 24:
741		case 32:
742			return (width * 4);
743		}
744
745	len = vesa_bios_get_line_length();
746
747	return (len > 0 ? len : width);
748}
749
750#define	VESA_MAXSTR		256
751
752#define	VESA_STRCPY(dst, src)	do {				\
753	char *str;						\
754	int i;							\
755	dst = malloc(VESA_MAXSTR, M_DEVBUF, M_WAITOK);		\
756	str = x86bios_offset(BIOS_SADDRTOLADDR(src));		\
757	for (i = 0; i < VESA_MAXSTR - 1 && str[i] != '\0'; i++)	\
758		dst[i] = str[i];				\
759	dst[i] = '\0';						\
760} while (0)
761
762static int
763vesa_bios_init(void)
764{
765	static struct vesa_info buf;
766	struct vesa_mode vmode;
767	video_info_t *p;
768	x86regs_t regs;
769	size_t bsize;
770	void *vmbuf;
771	uint32_t offs;
772	uint16_t vers;
773	int is_via_cle266;
774	int modes;
775	int i;
776
777	if (vesa_init_done)
778		return (0);
779
780	has_vesa_bios = FALSE;
781	vesa_adp_info = NULL;
782	vesa_vmode_max = 0;
783	vesa_vmode[0].vi_mode = EOT;
784
785	/*
786	 * If the VBE real mode interrupt vector is not found, try BIOS POST.
787	 */
788	if (x86bios_get_intr(0x10) == 0) {
789		if (vesa_bios_post() != 0)
790			return (1);
791		if (bootverbose) {
792			offs = x86bios_get_intr(0x10);
793			printf("VESA: interrupt vector installed (0x%x)\n",
794			    BIOS_SADDRTOLADDR(offs));
795		}
796	}
797
798	x86bios_init_regs(&regs);
799	regs.R_AX = 0x4f00;
800
801	vmbuf = x86bios_alloc(&offs, sizeof(buf));
802	if (vmbuf == NULL)
803		return (1);
804
805	regs.R_ES = X86BIOS_PHYSTOSEG(offs);
806	regs.R_DI = X86BIOS_PHYSTOOFF(offs);
807
808	bcopy("VBE2", vmbuf, 4);	/* try for VBE2 data */
809	x86bios_intr(&regs, 0x10);
810
811	if (regs.R_AX != 0x004f || bcmp("VESA", vmbuf, 4) != 0)
812		goto fail;
813
814	bcopy(vmbuf, &buf, sizeof(buf));
815
816	vesa_adp_info = &buf;
817	if (bootverbose) {
818		printf("VESA: information block\n");
819		dump_buffer((u_char *)&buf, sizeof(buf));
820	}
821
822	vers = buf.v_version = le16toh(buf.v_version);
823	buf.v_oemstr = le32toh(buf.v_oemstr);
824	buf.v_flags = le32toh(buf.v_flags);
825	buf.v_modetable = le32toh(buf.v_modetable);
826	buf.v_memsize = le16toh(buf.v_memsize);
827	buf.v_revision = le16toh(buf.v_revision);
828	buf.v_venderstr = le32toh(buf.v_venderstr);
829	buf.v_prodstr = le32toh(buf.v_prodstr);
830	buf.v_revstr = le32toh(buf.v_revstr);
831
832	if (vers < 0x0102) {
833		printf("VESA: VBE version %d.%d is not supported; "
834		       "version 1.2 or later is required.\n",
835		       ((vers & 0xf000) >> 12) * 10 + ((vers & 0x0f00) >> 8),
836		       ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f));
837		return (1);
838	}
839
840	VESA_STRCPY(vesa_oemstr, buf.v_oemstr);
841	if (vers >= 0x0200) {
842		VESA_STRCPY(vesa_venderstr, buf.v_venderstr);
843		VESA_STRCPY(vesa_prodstr, buf.v_prodstr);
844		VESA_STRCPY(vesa_revstr, buf.v_revstr);
845	}
846	is_via_cle266 = strncmp(vesa_oemstr, VESA_VIA_CLE266,
847	    sizeof(VESA_VIA_CLE266)) == 0;
848
849	if (buf.v_modetable == 0)
850		goto fail;
851
852	vesa_vmodetab = x86bios_offset(BIOS_SADDRTOLADDR(buf.v_modetable));
853
854	for (i = 0, modes = 0;
855		(i < (M_VESA_MODE_MAX - M_VESA_BASE + 1))
856		&& (vesa_vmodetab[i] != 0xffff); ++i) {
857		vesa_vmodetab[i] = le16toh(vesa_vmodetab[i]);
858		if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
859			continue;
860
861		vmode.v_modeattr = le16toh(vmode.v_modeattr);
862		vmode.v_wgran = le16toh(vmode.v_wgran);
863		vmode.v_wsize = le16toh(vmode.v_wsize);
864		vmode.v_waseg = le16toh(vmode.v_waseg);
865		vmode.v_wbseg = le16toh(vmode.v_wbseg);
866		vmode.v_posfunc = le32toh(vmode.v_posfunc);
867		vmode.v_bpscanline = le16toh(vmode.v_bpscanline);
868		vmode.v_width = le16toh(vmode.v_width);
869		vmode.v_height = le16toh(vmode.v_height);
870		vmode.v_lfb = le32toh(vmode.v_lfb);
871		vmode.v_offscreen = le32toh(vmode.v_offscreen);
872		vmode.v_offscreensize = le16toh(vmode.v_offscreensize);
873		vmode.v_linbpscanline = le16toh(vmode.v_linbpscanline);
874		vmode.v_maxpixelclock = le32toh(vmode.v_maxpixelclock);
875
876		/* reject unsupported modes */
877#if 0
878		if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO
879					| V_MODENONVGA))
880		    != (V_MODESUPP | V_MODEOPTINFO))
881			continue;
882#else
883		if ((vmode.v_modeattr & V_MODEOPTINFO) == 0) {
884#if VESA_DEBUG > 1
885			printf(
886		"Rejecting VESA %s mode: %d x %d x %d bpp  attr = %x\n",
887			    vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text",
888			    vmode.v_width, vmode.v_height, vmode.v_bpp,
889			    vmode.v_modeattr);
890#endif
891			continue;
892		}
893#endif
894
895		/* expand the array if necessary */
896		if (modes >= vesa_vmode_max) {
897			vesa_vmode_max += MODE_TABLE_DELTA;
898			p = malloc(sizeof(*vesa_vmode)*(vesa_vmode_max + 1),
899				   M_DEVBUF, M_WAITOK);
900#if VESA_DEBUG > 1
901			printf("vesa_bios_init(): modes:%d, vesa_mode_max:%d\n",
902			       modes, vesa_vmode_max);
903#endif
904			if (modes > 0) {
905				bcopy(vesa_vmode, p, sizeof(*vesa_vmode)*modes);
906				free(vesa_vmode, M_DEVBUF);
907			}
908			vesa_vmode = p;
909		}
910
911#if VESA_DEBUG > 1
912		printf("Found VESA %s mode: %d x %d x %d bpp\n",
913		    vmode.v_modeattr & V_MODEGRAPHICS ? "graphics" : "text",
914		    vmode.v_width, vmode.v_height, vmode.v_bpp);
915#endif
916		if (is_via_cle266) {
917		    if ((vmode.v_width & 0xff00) >> 8 == vmode.v_height - 1) {
918			vmode.v_width &= 0xff;
919			vmode.v_waseg = 0xb8000 >> 4;
920		    }
921		}
922
923		/* copy some fields */
924		bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes]));
925		vesa_vmode[modes].vi_mode = vesa_vmodetab[i];
926		vesa_vmode[modes].vi_width = vmode.v_width;
927		vesa_vmode[modes].vi_height = vmode.v_height;
928		vesa_vmode[modes].vi_depth = vmode.v_bpp;
929		vesa_vmode[modes].vi_planes = vmode.v_planes;
930		vesa_vmode[modes].vi_cwidth = vmode.v_cwidth;
931		vesa_vmode[modes].vi_cheight = vmode.v_cheight;
932		vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4;
933		/* XXX window B */
934		vesa_vmode[modes].vi_window_size = vmode.v_wsize*1024;
935		vesa_vmode[modes].vi_window_gran = vmode.v_wgran*1024;
936		if (vmode.v_modeattr & V_MODELFB)
937			vesa_vmode[modes].vi_buffer = vmode.v_lfb;
938		else
939			vesa_vmode[modes].vi_buffer = 0;
940		/* XXX */
941		vesa_vmode[modes].vi_buffer_size
942			= vesa_adp_info->v_memsize*64*1024;
943#if 0
944		if (vmode.v_offscreen > vmode.v_lfb)
945			vesa_vmode[modes].vi_buffer_size
946				= vmode.v_offscreen + vmode.v_offscreensize*1024
947				      - vmode.v_lfb;
948		else
949			vesa_vmode[modes].vi_buffer_size
950				= vmode.v_offscreen + vmode.v_offscreensize * 1024;
951#endif
952		vesa_vmode[modes].vi_mem_model
953			= vesa_translate_mmodel(vmode.v_memmodel);
954		vesa_vmode[modes].vi_pixel_fields[0] = 0;
955		vesa_vmode[modes].vi_pixel_fields[1] = 0;
956		vesa_vmode[modes].vi_pixel_fields[2] = 0;
957		vesa_vmode[modes].vi_pixel_fields[3] = 0;
958		vesa_vmode[modes].vi_pixel_fsizes[0] = 0;
959		vesa_vmode[modes].vi_pixel_fsizes[1] = 0;
960		vesa_vmode[modes].vi_pixel_fsizes[2] = 0;
961		vesa_vmode[modes].vi_pixel_fsizes[3] = 0;
962		if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_PACKED) {
963			vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8;
964		} else if (vesa_vmode[modes].vi_mem_model == V_INFO_MM_DIRECT) {
965			vesa_vmode[modes].vi_pixel_size = (vmode.v_bpp + 7)/8;
966			vesa_vmode[modes].vi_pixel_fields[0]
967			    = vmode.v_redfieldpos;
968			vesa_vmode[modes].vi_pixel_fields[1]
969			    = vmode.v_greenfieldpos;
970			vesa_vmode[modes].vi_pixel_fields[2]
971			    = vmode.v_bluefieldpos;
972			vesa_vmode[modes].vi_pixel_fields[3]
973			    = vmode.v_resfieldpos;
974			vesa_vmode[modes].vi_pixel_fsizes[0]
975			    = vmode.v_redmasksize;
976			vesa_vmode[modes].vi_pixel_fsizes[1]
977			    = vmode.v_greenmasksize;
978			vesa_vmode[modes].vi_pixel_fsizes[2]
979			    = vmode.v_bluemasksize;
980			vesa_vmode[modes].vi_pixel_fsizes[3]
981			    = vmode.v_resmasksize;
982		} else {
983			vesa_vmode[modes].vi_pixel_size = 0;
984		}
985
986		vesa_vmode[modes].vi_flags
987			= vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA;
988
989		/* Does it have enough memory to support this mode? */
990		bsize = vesa_get_line_width(&vesa_vmode[modes]);
991		bsize *= vesa_vmode[modes].vi_height;
992		if (bsize > vesa_vmode[modes].vi_buffer_size) {
993#if VESA_DEBUG > 1
994			printf(
995		"Rejecting VESA %s mode: %d x %d x %d bpp  attr = %x, not enough memory\n",
996			    (vmode.v_modeattr & V_MODEGRAPHICS) != 0 ? "graphics" : "text",
997			    vmode.v_width, vmode.v_height, vmode.v_bpp, vmode.v_modeattr);
998#endif
999			continue;
1000		}
1001
1002		++modes;
1003	}
1004	vesa_vmode[modes].vi_mode = EOT;
1005
1006	if (bootverbose)
1007		printf("VESA: %d mode(s) found\n", modes);
1008
1009	has_vesa_bios = (modes > 0);
1010	if (!has_vesa_bios)
1011		goto fail;
1012
1013	x86bios_free(vmbuf, sizeof(buf));
1014	return (0);
1015
1016fail:
1017	if (vmbuf != NULL)
1018		x86bios_free(vmbuf, sizeof(buf));
1019	if (vesa_oemstr != NULL) {
1020		free(vesa_oemstr, M_DEVBUF);
1021		vesa_oemstr = NULL;
1022	}
1023	if (vesa_venderstr != NULL) {
1024		free(vesa_venderstr, M_DEVBUF);
1025		vesa_venderstr = NULL;
1026	}
1027	if (vesa_prodstr != NULL) {
1028		free(vesa_prodstr, M_DEVBUF);
1029		vesa_prodstr = NULL;
1030	}
1031	if (vesa_revstr != NULL) {
1032		free(vesa_revstr, M_DEVBUF);
1033		vesa_revstr = NULL;
1034	}
1035	return (1);
1036}
1037
1038static void
1039vesa_clear_modes(video_info_t *info, int color)
1040{
1041	while (info->vi_mode != EOT) {
1042		if ((info->vi_flags & V_INFO_COLOR) != color)
1043			info->vi_mode = NA;
1044		++info;
1045	}
1046}
1047
1048static vm_offset_t
1049vesa_map_buffer(u_int paddr, size_t size)
1050{
1051	vm_offset_t vaddr;
1052	u_int off;
1053
1054	off = paddr - trunc_page(paddr);
1055	vaddr = (vm_offset_t)pmap_mapdev_attr(paddr - off, size + off,
1056	    PAT_WRITE_COMBINING);
1057#if VESA_DEBUG > 1
1058	printf("vesa_map_buffer: paddr:%x vaddr:%tx size:%zx off:%x\n",
1059	       paddr, vaddr, size, off);
1060#endif
1061	return (vaddr + off);
1062}
1063
1064static void
1065vesa_unmap_buffer(vm_offset_t vaddr, size_t size)
1066{
1067#if VESA_DEBUG > 1
1068	printf("vesa_unmap_buffer: vaddr:%tx size:%zx\n", vaddr, size);
1069#endif
1070	kmem_free(kernel_map, vaddr, size);
1071}
1072
1073/* entry points */
1074
1075static int
1076vesa_configure(int flags)
1077{
1078	video_adapter_t *adp;
1079	int adapters;
1080	int error;
1081	int i;
1082
1083	if (vesa_init_done)
1084		return (0);
1085	if (flags & VIO_PROBE_ONLY)
1086		return (0);
1087
1088	/*
1089	 * If the VESA module has already been loaded, abort loading
1090	 * the module this time.
1091	 */
1092	for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) {
1093		if (adp->va_flags & V_ADP_VESA)
1094			return (ENXIO);
1095		if (adp->va_type == KD_VGA)
1096			break;
1097	}
1098
1099	/*
1100	 * The VGA adapter is not found.  This is because either
1101	 * 1) the VGA driver has not been initialized, or 2) the VGA card
1102	 * is not present.  If 1) is the case, we shall defer
1103	 * initialization for now and try again later.
1104	 */
1105	if (adp == NULL) {
1106		vga_sub_configure = vesa_configure;
1107		return (ENODEV);
1108	}
1109
1110	/* count number of registered adapters */
1111	for (++i; vid_get_adapter(i) != NULL; ++i)
1112		;
1113	adapters = i;
1114
1115	/* call VESA BIOS */
1116	vesa_adp = adp;
1117	if (vesa_bios_init()) {
1118		vesa_adp = NULL;
1119		return (ENXIO);
1120	}
1121	vesa_adp->va_flags |= V_ADP_VESA;
1122
1123	/* remove conflicting modes if we have more than one adapter */
1124	if (adapters > 1) {
1125		vesa_clear_modes(vesa_vmode,
1126				 (vesa_adp->va_flags & V_ADP_COLOR) ?
1127				     V_INFO_COLOR : 0);
1128	}
1129
1130	if ((error = vesa_load_ioctl()) == 0) {
1131		prevvidsw = vidsw[vesa_adp->va_index];
1132		vidsw[vesa_adp->va_index] = &vesavidsw;
1133		vesa_init_done = TRUE;
1134	} else {
1135		vesa_adp = NULL;
1136		return (error);
1137	}
1138
1139	return (0);
1140}
1141
1142#if 0
1143static int
1144vesa_nop(void)
1145{
1146
1147	return (0);
1148}
1149#endif
1150
1151static int
1152vesa_error(void)
1153{
1154
1155	return (1);
1156}
1157
1158static int
1159vesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
1160{
1161
1162	return ((*prevvidsw->probe)(unit, adpp, arg, flags));
1163}
1164
1165static int
1166vesa_init(int unit, video_adapter_t *adp, int flags)
1167{
1168
1169	return ((*prevvidsw->init)(unit, adp, flags));
1170}
1171
1172static int
1173vesa_get_info(video_adapter_t *adp, int mode, video_info_t *info)
1174{
1175	int i;
1176
1177	if ((*prevvidsw->get_info)(adp, mode, info) == 0)
1178		return (0);
1179
1180	if (adp != vesa_adp)
1181		return (1);
1182
1183	mode = vesa_map_gen_mode_num(vesa_adp->va_type,
1184				     vesa_adp->va_flags & V_ADP_COLOR, mode);
1185	for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
1186		if (vesa_vmode[i].vi_mode == NA)
1187			continue;
1188		if (vesa_vmode[i].vi_mode == mode) {
1189			*info = vesa_vmode[i];
1190			return (0);
1191		}
1192	}
1193	return (1);
1194}
1195
1196static int
1197vesa_query_mode(video_adapter_t *adp, video_info_t *info)
1198{
1199	int i;
1200
1201	if ((*prevvidsw->query_mode)(adp, info) == 0)
1202		return (0);
1203	if (adp != vesa_adp)
1204		return (ENODEV);
1205
1206	for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
1207		if ((info->vi_width != 0)
1208		    && (info->vi_width != vesa_vmode[i].vi_width))
1209			continue;
1210		if ((info->vi_height != 0)
1211		    && (info->vi_height != vesa_vmode[i].vi_height))
1212			continue;
1213		if ((info->vi_cwidth != 0)
1214		    && (info->vi_cwidth != vesa_vmode[i].vi_cwidth))
1215			continue;
1216		if ((info->vi_cheight != 0)
1217		    && (info->vi_cheight != vesa_vmode[i].vi_cheight))
1218			continue;
1219		if ((info->vi_depth != 0)
1220		    && (info->vi_depth != vesa_vmode[i].vi_depth))
1221			continue;
1222		if ((info->vi_planes != 0)
1223		    && (info->vi_planes != vesa_vmode[i].vi_planes))
1224			continue;
1225		/* pixel format, memory model */
1226		if ((info->vi_flags != 0)
1227		    && (info->vi_flags != vesa_vmode[i].vi_flags))
1228			continue;
1229		*info = vesa_vmode[i];
1230		return (0);
1231	}
1232	return (ENODEV);
1233}
1234
1235static int
1236vesa_set_mode(video_adapter_t *adp, int mode)
1237{
1238	video_info_t info;
1239
1240	if (adp != vesa_adp)
1241		return ((*prevvidsw->set_mode)(adp, mode));
1242
1243	mode = vesa_map_gen_mode_num(adp->va_type,
1244				     adp->va_flags & V_ADP_COLOR, mode);
1245#if VESA_DEBUG > 0
1246	printf("VESA: set_mode(): %d(%x) -> %d(%x)\n",
1247		adp->va_mode, adp->va_mode, mode, mode);
1248#endif
1249	/*
1250	 * If the current mode is a VESA mode and the new mode is not,
1251	 * restore the state of the adapter first by setting one of the
1252	 * standard VGA mode, so that non-standard, extended SVGA registers
1253	 * are set to the state compatible with the standard VGA modes.
1254	 * Otherwise (*prevvidsw->set_mode)() may not be able to set up
1255	 * the new mode correctly.
1256	 */
1257	if (VESA_MODE(adp->va_mode)) {
1258		if (!VESA_MODE(mode) &&
1259		    (*prevvidsw->get_info)(adp, mode, &info) == 0) {
1260			int10_set_mode(adp->va_initial_bios_mode);
1261			if (adp->va_info.vi_flags & V_INFO_LINEAR)
1262				vesa_unmap_buffer(adp->va_buffer,
1263						  vesa_adp_info->v_memsize*64*1024);
1264			/*
1265			 * Once (*prevvidsw->get_info)() succeeded,
1266			 * (*prevvidsw->set_mode)() below won't fail...
1267			 */
1268		}
1269	}
1270
1271	/* we may not need to handle this mode after all... */
1272	if (!VESA_MODE(mode) && (*prevvidsw->set_mode)(adp, mode) == 0)
1273		return (0);
1274
1275	/* is the new mode supported? */
1276	if (vesa_get_info(adp, mode, &info))
1277		return (1);
1278	/* assert(VESA_MODE(mode)); */
1279
1280#if VESA_DEBUG > 0
1281	printf("VESA: about to set a VESA mode...\n");
1282#endif
1283	/* don't use the linear frame buffer for text modes. XXX */
1284	if (!(info.vi_flags & V_INFO_GRAPHICS))
1285		info.vi_flags &= ~V_INFO_LINEAR;
1286
1287	if (vesa_bios_set_mode(mode | ((info.vi_flags & V_INFO_LINEAR) ? 0x4000 : 0)))
1288		return (1);
1289
1290	if ((vesa_adp_info->v_flags & V_DAC8) != 0)
1291		vesa_bios_set_dac(8);
1292
1293	if (adp->va_info.vi_flags & V_INFO_LINEAR)
1294		vesa_unmap_buffer(adp->va_buffer,
1295				  vesa_adp_info->v_memsize*64*1024);
1296
1297#if VESA_DEBUG > 0
1298	printf("VESA: mode set!\n");
1299#endif
1300	vesa_adp->va_mode = mode;
1301	vesa_adp->va_flags &= ~V_ADP_COLOR;
1302	vesa_adp->va_flags |=
1303		(info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
1304	vesa_adp->va_crtc_addr =
1305		(vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
1306	if (info.vi_flags & V_INFO_LINEAR) {
1307#if VESA_DEBUG > 1
1308		printf("VESA: setting up LFB\n");
1309#endif
1310		vesa_adp->va_buffer =
1311			vesa_map_buffer(info.vi_buffer,
1312					vesa_adp_info->v_memsize*64*1024);
1313		vesa_adp->va_buffer_size = info.vi_buffer_size;
1314		vesa_adp->va_window = vesa_adp->va_buffer;
1315		vesa_adp->va_window_size = info.vi_buffer_size/info.vi_planes;
1316		vesa_adp->va_window_gran = info.vi_buffer_size/info.vi_planes;
1317	} else {
1318		vesa_adp->va_buffer = 0;
1319		vesa_adp->va_buffer_size = info.vi_buffer_size;
1320		vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
1321		vesa_adp->va_window_size = info.vi_window_size;
1322		vesa_adp->va_window_gran = info.vi_window_gran;
1323	}
1324	vesa_adp->va_window_orig = 0;
1325	vesa_adp->va_line_width = vesa_get_line_width(&info);
1326	vesa_adp->va_disp_start.x = 0;
1327	vesa_adp->va_disp_start.y = 0;
1328#if VESA_DEBUG > 0
1329	printf("vesa_set_mode(): vi_width:%d, line_width:%d\n",
1330	       info.vi_width, vesa_adp->va_line_width);
1331#endif
1332	bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info));
1333
1334	/* move hardware cursor out of the way */
1335	(*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1);
1336
1337	return (0);
1338}
1339
1340static int
1341vesa_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
1342	       u_char *data, int ch, int count)
1343{
1344
1345	return ((*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data,
1346	    ch, count));
1347}
1348
1349static int
1350vesa_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
1351	       u_char *data, int ch, int count)
1352{
1353
1354	return ((*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data,
1355		ch, count));
1356}
1357
1358static int
1359vesa_show_font(video_adapter_t *adp, int page)
1360{
1361
1362	return ((*prevvidsw->show_font)(adp, page));
1363}
1364
1365static int
1366vesa_save_palette(video_adapter_t *adp, u_char *palette)
1367{
1368	int bits;
1369
1370	if (adp == vesa_adp && VESA_MODE(adp->va_mode)) {
1371		bits = vesa_bios_get_dac();
1372		if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6)
1373			return (vesa_bios_save_palette(0, 256, palette, bits));
1374	}
1375
1376	return ((*prevvidsw->save_palette)(adp, palette));
1377}
1378
1379static int
1380vesa_load_palette(video_adapter_t *adp, u_char *palette)
1381{
1382	int bits;
1383
1384	if (adp == vesa_adp && VESA_MODE(adp->va_mode)) {
1385		bits = vesa_bios_get_dac();
1386		if ((adp->va_info.vi_flags & V_INFO_NONVGA) != 0 || bits > 6)
1387			return (vesa_bios_load_palette(0, 256, palette, bits));
1388	}
1389
1390	return ((*prevvidsw->load_palette)(adp, palette));
1391}
1392
1393static int
1394vesa_set_border(video_adapter_t *adp, int color)
1395{
1396
1397	return ((*prevvidsw->set_border)(adp, color));
1398}
1399
1400static int
1401vesa_save_state(video_adapter_t *adp, void *p, size_t size)
1402{
1403
1404	if (adp != vesa_adp)
1405		return ((*prevvidsw->save_state)(adp, p, size));
1406
1407	if (vesa_state_buf_size == -1) {
1408		vesa_state_buf_size = vesa_bios_state_buf_size();
1409		if (vesa_state_buf_size == 0)
1410			return (1);
1411	}
1412	if (size == 0)
1413		return (offsetof(adp_state_t, regs) + vesa_state_buf_size);
1414	else if (size < (offsetof(adp_state_t, regs) + vesa_state_buf_size))
1415		return (1);
1416
1417	((adp_state_t *)p)->sig = V_STATE_SIG;
1418	bzero(((adp_state_t *)p)->regs, vesa_state_buf_size);
1419	return (vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs,
1420	    vesa_state_buf_size));
1421}
1422
1423static int
1424vesa_load_state(video_adapter_t *adp, void *p)
1425{
1426
1427	if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG))
1428		return ((*prevvidsw->load_state)(adp, p));
1429
1430	if (vesa_state_buf_size <= 0)
1431		return (1);
1432
1433	/* Try BIOS POST to restore a sane state. */
1434	(void)vesa_bios_post();
1435	(void)int10_set_mode(adp->va_initial_bios_mode);
1436
1437	return (vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs,
1438	    vesa_state_buf_size));
1439}
1440
1441#if 0
1442static int
1443vesa_get_origin(video_adapter_t *adp, off_t *offset)
1444{
1445	x86regs_t regs;
1446
1447	x86bios_init_regs(&regs);
1448	regs.R_AX = 0x4f05;
1449	regs.R_BL = 0x10;
1450
1451	x86bios_intr(&regs, 0x10);
1452
1453	if (regs.R_AX != 0x004f)
1454		return (1);
1455	*offset = regs.DX * adp->va_window_gran;
1456
1457	return (0);
1458}
1459#endif
1460
1461static int
1462vesa_set_origin(video_adapter_t *adp, off_t offset)
1463{
1464	x86regs_t regs;
1465
1466	/*
1467	 * This function should return as quickly as possible to
1468	 * maintain good performance of the system. For this reason,
1469	 * error checking is kept minimal and let the VESA BIOS to
1470	 * detect error.
1471	 */
1472	if (adp != vesa_adp)
1473		return ((*prevvidsw->set_win_org)(adp, offset));
1474
1475	/* if this is a linear frame buffer, do nothing */
1476	if (adp->va_info.vi_flags & V_INFO_LINEAR)
1477		return (0);
1478	/* XXX */
1479	if (adp->va_window_gran == 0)
1480		return (1);
1481
1482	x86bios_init_regs(&regs);
1483	regs.R_AX = 0x4f05;
1484	regs.R_DX = offset / adp->va_window_gran;
1485
1486	x86bios_intr(&regs, 0x10);
1487
1488	if (regs.R_AX != 0x004f)
1489		return (1);
1490
1491	x86bios_init_regs(&regs);
1492	regs.R_AX = 0x4f05;
1493	regs.R_BL = 1;
1494	regs.R_DX = offset / adp->va_window_gran;
1495	x86bios_intr(&regs, 0x10);
1496
1497	adp->va_window_orig = (offset/adp->va_window_gran)*adp->va_window_gran;
1498	return (0);			/* XXX */
1499}
1500
1501static int
1502vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
1503{
1504
1505	return ((*prevvidsw->read_hw_cursor)(adp, col, row));
1506}
1507
1508static int
1509vesa_set_hw_cursor(video_adapter_t *adp, int col, int row)
1510{
1511
1512	return ((*prevvidsw->set_hw_cursor)(adp, col, row));
1513}
1514
1515static int
1516vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
1517			 int celsize, int blink)
1518{
1519
1520	return ((*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize,
1521	    blink));
1522}
1523
1524static int
1525vesa_blank_display(video_adapter_t *adp, int mode)
1526{
1527
1528	/* XXX: use VESA DPMS */
1529	return ((*prevvidsw->blank_display)(adp, mode));
1530}
1531
1532static int
1533vesa_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
1534	  int prot, vm_memattr_t *memattr)
1535{
1536
1537#if VESA_DEBUG > 0
1538	printf("vesa_mmap(): window:0x%tx, buffer:0x%tx, offset:0x%jx\n",
1539	       adp->va_info.vi_window, adp->va_info.vi_buffer, offset);
1540#endif
1541
1542	if ((adp == vesa_adp) &&
1543	    (adp->va_info.vi_flags & V_INFO_LINEAR) != 0) {
1544		/* va_window_size == va_buffer_size/vi_planes */
1545		/* XXX: is this correct? */
1546		if (offset > adp->va_window_size - PAGE_SIZE)
1547			return (-1);
1548		*paddr = adp->va_info.vi_buffer + offset;
1549		return (0);
1550	}
1551	return ((*prevvidsw->mmap)(adp, offset, paddr, prot, memattr));
1552}
1553
1554static int
1555vesa_clear(video_adapter_t *adp)
1556{
1557
1558	return ((*prevvidsw->clear)(adp));
1559}
1560
1561static int
1562vesa_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
1563{
1564
1565	return ((*prevvidsw->fill_rect)(adp, val, x, y, cx, cy));
1566}
1567
1568static int
1569vesa_bitblt(video_adapter_t *adp,...)
1570{
1571
1572	/* FIXME */
1573	return (1);
1574}
1575
1576static int
1577get_palette(video_adapter_t *adp, int base, int count,
1578	    u_char *red, u_char *green, u_char *blue, u_char *trans)
1579{
1580	u_char *r;
1581	u_char *g;
1582	u_char *b;
1583	int bits;
1584	int error;
1585
1586	if (base < 0 || base >= 256 || count < 0 || count > 256)
1587		return (1);
1588	if ((base + count) > 256)
1589		return (1);
1590	if (!VESA_MODE(adp->va_mode))
1591		return (1);
1592	bits = vesa_bios_get_dac();
1593	if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6)
1594		return (1);
1595
1596	r = malloc(count * 3, M_DEVBUF, M_WAITOK);
1597	g = r + count;
1598	b = g + count;
1599	error = vesa_bios_save_palette2(base, count, r, g, b, bits);
1600	if (error == 0) {
1601		copyout(r, red, count);
1602		copyout(g, green, count);
1603		copyout(b, blue, count);
1604		if (trans != NULL) {
1605			bzero(r, count);
1606			copyout(r, trans, count);
1607		}
1608	}
1609	free(r, M_DEVBUF);
1610
1611	return (error);
1612}
1613
1614static int
1615set_palette(video_adapter_t *adp, int base, int count,
1616	    u_char *red, u_char *green, u_char *blue, u_char *trans)
1617{
1618	u_char *r;
1619	u_char *g;
1620	u_char *b;
1621	int bits;
1622	int error;
1623
1624	if (base < 0 || base >= 256 || count < 0 || count > 256)
1625		return (1);
1626	if ((base + count) > 256)
1627		return (1);
1628	if (!VESA_MODE(adp->va_mode))
1629		return (1);
1630	bits = vesa_bios_get_dac();
1631	if ((adp->va_info.vi_flags & V_INFO_NONVGA) == 0 && bits <= 6)
1632		return (1);
1633
1634	r = malloc(count * 3, M_DEVBUF, M_WAITOK);
1635	g = r + count;
1636	b = g + count;
1637	copyin(red, r, count);
1638	copyin(green, g, count);
1639	copyin(blue, b, count);
1640
1641	error = vesa_bios_load_palette2(base, count, r, g, b, bits);
1642	free(r, M_DEVBUF);
1643
1644	return (error);
1645}
1646
1647static int
1648vesa_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
1649{
1650	int bytes;
1651
1652	if (adp != vesa_adp)
1653		return ((*prevvidsw->ioctl)(adp, cmd, arg));
1654
1655	switch (cmd) {
1656	case FBIO_SETWINORG:	/* set frame buffer window origin */
1657		if (!VESA_MODE(adp->va_mode))
1658			return (*prevvidsw->ioctl)(adp, cmd, arg);
1659		return (vesa_set_origin(adp, *(off_t *)arg) ? ENODEV : 0);
1660
1661	case FBIO_SETDISPSTART:	/* set display start address */
1662		if (!VESA_MODE(adp->va_mode))
1663			return ((*prevvidsw->ioctl)(adp, cmd, arg));
1664		if (vesa_bios_set_start(((video_display_start_t *)arg)->x,
1665					((video_display_start_t *)arg)->y))
1666			return (ENODEV);
1667		adp->va_disp_start.x = ((video_display_start_t *)arg)->x;
1668		adp->va_disp_start.y = ((video_display_start_t *)arg)->y;
1669		return (0);
1670
1671	case FBIO_SETLINEWIDTH:	/* set line length in pixel */
1672		if (!VESA_MODE(adp->va_mode))
1673			return ((*prevvidsw->ioctl)(adp, cmd, arg));
1674		if (vesa_bios_set_line_length(*(u_int *)arg, &bytes, NULL))
1675			return (ENODEV);
1676		adp->va_line_width = bytes;
1677#if VESA_DEBUG > 1
1678		printf("new line width:%d\n", adp->va_line_width);
1679#endif
1680		return (0);
1681
1682	case FBIO_GETPALETTE:	/* get color palette */
1683		if (get_palette(adp, ((video_color_palette_t *)arg)->index,
1684				((video_color_palette_t *)arg)->count,
1685				((video_color_palette_t *)arg)->red,
1686				((video_color_palette_t *)arg)->green,
1687				((video_color_palette_t *)arg)->blue,
1688				((video_color_palette_t *)arg)->transparent))
1689			return ((*prevvidsw->ioctl)(adp, cmd, arg));
1690		return (0);
1691
1692
1693	case FBIO_SETPALETTE:	/* set color palette */
1694		if (set_palette(adp, ((video_color_palette_t *)arg)->index,
1695				((video_color_palette_t *)arg)->count,
1696				((video_color_palette_t *)arg)->red,
1697				((video_color_palette_t *)arg)->green,
1698				((video_color_palette_t *)arg)->blue,
1699				((video_color_palette_t *)arg)->transparent))
1700			return ((*prevvidsw->ioctl)(adp, cmd, arg));
1701		return (0);
1702
1703	case FBIOGETCMAP:	/* get color palette */
1704		if (get_palette(adp, ((struct fbcmap *)arg)->index,
1705				((struct fbcmap *)arg)->count,
1706				((struct fbcmap *)arg)->red,
1707				((struct fbcmap *)arg)->green,
1708				((struct fbcmap *)arg)->blue, NULL))
1709			return ((*prevvidsw->ioctl)(adp, cmd, arg));
1710		return (0);
1711
1712	case FBIOPUTCMAP:	/* set color palette */
1713		if (set_palette(adp, ((struct fbcmap *)arg)->index,
1714				((struct fbcmap *)arg)->count,
1715				((struct fbcmap *)arg)->red,
1716				((struct fbcmap *)arg)->green,
1717				((struct fbcmap *)arg)->blue, NULL))
1718			return ((*prevvidsw->ioctl)(adp, cmd, arg));
1719		return (0);
1720
1721	default:
1722		return ((*prevvidsw->ioctl)(adp, cmd, arg));
1723	}
1724}
1725
1726static int
1727vesa_diag(video_adapter_t *adp, int level)
1728{
1729	int error;
1730
1731	/* call the previous handler first */
1732	error = (*prevvidsw->diag)(adp, level);
1733	if (error)
1734		return (error);
1735
1736	if (adp != vesa_adp)
1737		return (1);
1738
1739	if (level <= 0)
1740		return (0);
1741
1742	return (0);
1743}
1744
1745static int
1746vesa_bios_info(int level)
1747{
1748#if VESA_DEBUG > 1
1749	struct vesa_mode vmode;
1750	int i;
1751#endif
1752	uint16_t vers;
1753
1754	vers = vesa_adp_info->v_version;
1755
1756	if (bootverbose) {
1757		/* general adapter information */
1758		printf(
1759	"VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n",
1760		    (vers >> 12) * 10 + ((vers & 0x0f00) >> 8),
1761		    ((vers & 0x00f0) >> 4) * 10 + (vers & 0x000f),
1762		    vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags,
1763		    vesa_vmodetab, vesa_adp_info->v_modetable);
1764
1765		/* OEM string */
1766		if (vesa_oemstr != NULL)
1767			printf("VESA: %s\n", vesa_oemstr);
1768	}
1769
1770	if (level <= 0)
1771		return (0);
1772
1773	if (vers >= 0x0200 && bootverbose) {
1774		/* vender name, product name, product revision */
1775		printf("VESA: %s %s %s\n",
1776			(vesa_venderstr != NULL) ? vesa_venderstr : "unknown",
1777			(vesa_prodstr != NULL) ? vesa_prodstr : "unknown",
1778			(vesa_revstr != NULL) ? vesa_revstr : "?");
1779	}
1780
1781#if VESA_DEBUG > 1
1782	/* mode information */
1783	for (i = 0;
1784		(i < (M_VESA_MODE_MAX - M_VESA_BASE + 1))
1785		&& (vesa_vmodetab[i] != 0xffff); ++i) {
1786		if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
1787			continue;
1788
1789		/* print something for diagnostic purpose */
1790		printf("VESA: mode:0x%03x, flags:0x%04x",
1791		       vesa_vmodetab[i], vmode.v_modeattr);
1792		if (vmode.v_modeattr & V_MODEOPTINFO) {
1793			if (vmode.v_modeattr & V_MODEGRAPHICS) {
1794				printf(", G %dx%dx%d %d, ",
1795				       vmode.v_width, vmode.v_height,
1796				       vmode.v_bpp, vmode.v_planes);
1797			} else {
1798				printf(", T %dx%d, ",
1799				       vmode.v_width, vmode.v_height);
1800			}
1801			printf("font:%dx%d, ",
1802			       vmode.v_cwidth, vmode.v_cheight);
1803			printf("pages:%d, mem:%d",
1804			       vmode.v_ipages + 1, vmode.v_memmodel);
1805		}
1806		if (vmode.v_modeattr & V_MODELFB) {
1807			printf("\nVESA: LFB:0x%x, off:0x%x, off_size:0x%x",
1808			       vmode.v_lfb, vmode.v_offscreen,
1809			       vmode.v_offscreensize*1024);
1810		}
1811		printf("\n");
1812		printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ",
1813		       vmode.v_waseg, vmode.v_waattr,
1814		       vmode.v_wbseg, vmode.v_wbattr);
1815		printf("size:%dk, gran:%dk\n",
1816		       vmode.v_wsize, vmode.v_wgran);
1817	}
1818#endif /* VESA_DEBUG > 1 */
1819
1820	return (0);
1821}
1822
1823/* module loading */
1824
1825static int
1826vesa_load(void)
1827{
1828	int error;
1829	int s;
1830
1831	if (vesa_init_done)
1832		return (0);
1833
1834	/* locate a VGA adapter */
1835	s = spltty();
1836	vesa_adp = NULL;
1837	error = vesa_configure(0);
1838	splx(s);
1839
1840	if (error == 0)
1841		vesa_bios_info(bootverbose);
1842
1843	return (error);
1844}
1845
1846static int
1847vesa_unload(void)
1848{
1849	u_char palette[256*3];
1850	int error;
1851	int bits;
1852	int s;
1853
1854	/* if the adapter is currently in a VESA mode, don't unload */
1855	if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode))
1856		return (EBUSY);
1857	/*
1858	 * FIXME: if there is at least one vty which is in a VESA mode,
1859	 * we shouldn't be unloading! XXX
1860	 */
1861
1862	s = spltty();
1863	if ((error = vesa_unload_ioctl()) == 0) {
1864		if (vesa_adp != NULL) {
1865			if (vesa_adp_info->v_flags & V_DAC8)  {
1866				bits = vesa_bios_get_dac();
1867				if (bits > 6) {
1868					vesa_bios_save_palette(0, 256,
1869							       palette, bits);
1870					vesa_bios_set_dac(6);
1871					vesa_bios_load_palette(0, 256,
1872							       palette, 6);
1873				}
1874			}
1875			vesa_adp->va_flags &= ~V_ADP_VESA;
1876			vidsw[vesa_adp->va_index] = prevvidsw;
1877		}
1878	}
1879	splx(s);
1880
1881	if (vesa_oemstr != NULL)
1882		free(vesa_oemstr, M_DEVBUF);
1883	if (vesa_venderstr != NULL)
1884		free(vesa_venderstr, M_DEVBUF);
1885	if (vesa_prodstr != NULL)
1886		free(vesa_prodstr, M_DEVBUF);
1887	if (vesa_revstr != NULL)
1888		free(vesa_revstr, M_DEVBUF);
1889	if (vesa_vmode != &vesa_vmode_empty)
1890		free(vesa_vmode, M_DEVBUF);
1891	return (error);
1892}
1893
1894static int
1895vesa_mod_event(module_t mod, int type, void *data)
1896{
1897
1898	switch (type) {
1899	case MOD_LOAD:
1900		return (vesa_load());
1901	case MOD_UNLOAD:
1902		return (vesa_unload());
1903	}
1904	return (EOPNOTSUPP);
1905}
1906
1907static moduledata_t vesa_mod = {
1908	"vesa",
1909	vesa_mod_event,
1910	NULL,
1911};
1912
1913DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
1914MODULE_DEPEND(vesa, x86bios, 1, 1, 1);
1915
1916#endif	/* VGA_NO_MODE_CHANGE */
1917