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