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