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