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