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