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