FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/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 * $FreeBSD$
27 */
28
29 #include "vga.h"
30 #include "opt_vga.h"
31 #include "opt_vesa.h"
32 #include "opt_vm86.h"
33 #include "opt_fb.h"
34
35 #ifdef VGA_NO_MODE_CHANGE
36 #undef VESA
37 #endif
38
39 #if (NVGA > 0 && defined(VESA) && defined(VM86)) || defined(KLD_MODULE)
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/malloc.h>
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48
49 #include <machine/console.h>
50 #include <machine/md_var.h>
51 #include <machine/vm86.h>
52 #include <machine/pc/bios.h>
53 #include <machine/pc/vesa.h>
54
55 #include <dev/fb/fbreg.h>
56 #include <dev/fb/vgareg.h>
57
58 #ifndef __i386__
59 #include <isa/isareg.h>
60 #else
61 #include <i386/isa/isa.h>
62 #endif
63
64 #ifndef VESA_DEBUG
65 #define VESA_DEBUG 0
66 #endif
67
68 /* VESA video adapter state buffer stub */
69 struct adp_state {
70 int sig;
71 #define V_STATE_SIG 0x61736576
72 u_char regs[1];
73 };
74 typedef struct adp_state adp_state_t;
75
76 /* VESA video adapter */
77 static video_adapter_t *vesa_adp = NULL;
78 static int vesa_state_buf_size = 0;
79 #if 0
80 static void *vesa_state_buf = NULL;
81 #endif
82
83 /* VESA functions */
84 static int vesa_nop(void);
85 static vi_probe_t vesa_probe;
86 static vi_init_t vesa_init;
87 static vi_get_info_t vesa_get_info;
88 static vi_query_mode_t vesa_query_mode;
89 static vi_set_mode_t vesa_set_mode;
90 static vi_save_font_t vesa_save_font;
91 static vi_load_font_t vesa_load_font;
92 static vi_show_font_t vesa_show_font;
93 static vi_save_palette_t vesa_save_palette;
94 static vi_load_palette_t vesa_load_palette;
95 static vi_set_border_t vesa_set_border;
96 static vi_save_state_t vesa_save_state;
97 static vi_load_state_t vesa_load_state;
98 static vi_set_win_org_t vesa_set_origin;
99 static vi_read_hw_cursor_t vesa_read_hw_cursor;
100 static vi_set_hw_cursor_t vesa_set_hw_cursor;
101 static vi_set_hw_cursor_shape_t vesa_set_hw_cursor_shape;
102 static vi_mmap_t vesa_mmap;
103 static vi_diag_t vesa_diag;
104 static struct vm86context vesa_vmcontext;
105
106 static video_switch_t vesavidsw = {
107 vesa_probe,
108 vesa_init,
109 vesa_get_info,
110 vesa_query_mode,
111 vesa_set_mode,
112 vesa_save_font,
113 vesa_load_font,
114 vesa_show_font,
115 vesa_save_palette,
116 vesa_load_palette,
117 vesa_set_border,
118 vesa_save_state,
119 vesa_load_state,
120 vesa_set_origin,
121 vesa_read_hw_cursor,
122 vesa_set_hw_cursor,
123 vesa_set_hw_cursor_shape,
124 (vi_blank_display_t *)vesa_nop,
125 vesa_mmap,
126 vesa_diag,
127 };
128
129 static video_switch_t *prevvidsw;
130
131 /* VESA BIOS video modes */
132 #define VESA_MAXMODES 64
133 #define EOT (-1)
134 #define NA (-2)
135
136 static video_info_t vesa_vmode[VESA_MAXMODES + 1] = {
137 { EOT, },
138 };
139
140 static int vesa_init_done = FALSE;
141 static int has_vesa_bios = FALSE;
142 static struct vesa_info *vesa_adp_info = NULL;
143 static u_int16_t *vesa_vmodetab = NULL;
144 static char *vesa_oemstr = NULL;
145 static char *vesa_venderstr = NULL;
146 static char *vesa_prodstr = NULL;
147 static char *vesa_revstr = NULL;
148
149 /* local macros and functions */
150 #define BIOS_SADDRTOLADDR(p) ((((p) & 0xffff0000) >> 12) + ((p) & 0x0000ffff))
151
152 static int int10_set_mode(int mode);
153 static int vesa_bios_get_mode(int mode, struct vesa_mode *vmode);
154 static int vesa_bios_set_mode(int mode);
155 static int vesa_bios_get_dac(void);
156 static int vesa_bios_set_dac(int bits);
157 static int vesa_bios_save_palette(int start, int colors, u_char *palette,
158 int bits);
159 static int vesa_bios_load_palette(int start, int colors, u_char *palette,
160 int bits);
161 #define STATE_SIZE 0
162 #define STATE_SAVE 1
163 #define STATE_LOAD 2
164 #define STATE_HW (1<<0)
165 #define STATE_DATA (1<<1)
166 #define STATE_DAC (1<<2)
167 #define STATE_REG (1<<3)
168 #define STATE_MOST (STATE_HW | STATE_DATA | STATE_REG)
169 #define STATE_ALL (STATE_HW | STATE_DATA | STATE_DAC | STATE_REG)
170 static int vesa_bios_state_buf_size(void);
171 static int vesa_bios_save_restore(int code, void *p, size_t size);
172 static int vesa_bios_get_line_length(void);
173 static int vesa_map_gen_mode_num(int type, int color, int mode);
174 static int vesa_translate_flags(u_int16_t vflags);
175 static void *vesa_fix_ptr(u_int32_t p, u_int16_t seg, u_int16_t off,
176 u_char *buf);
177 static int vesa_bios_init(void);
178 static void vesa_clear_modes(video_info_t *info, int color);
179
180 static void
181 dump_buffer(u_char *buf, size_t len)
182 {
183 int i;
184
185 for(i = 0; i < len;) {
186 printf("%02x ", buf[i]);
187 if ((++i % 16) == 0)
188 printf("\n");
189 }
190 }
191
192 /* INT 10 BIOS calls */
193 static int
194 int10_set_mode(int mode)
195 {
196 struct vm86frame vmf;
197
198 bzero(&vmf, sizeof(vmf));
199 vmf.vmf_eax = 0x0000 | mode;
200 vm86_intcall(0x10, &vmf);
201 return 0;
202 }
203
204 /* VESA BIOS calls */
205 static int
206 vesa_bios_get_mode(int mode, struct vesa_mode *vmode)
207 {
208 struct vm86frame vmf;
209 u_char *buf;
210 int err;
211
212 bzero(&vmf, sizeof(vmf));
213 vmf.vmf_eax = 0x4f01;
214 vmf.vmf_ecx = mode;
215 buf = (u_char *)vm86_getpage(&vesa_vmcontext, 1);
216 vm86_getptr(&vesa_vmcontext, (vm_offset_t)buf, &vmf.vmf_es, &vmf.vmf_di);
217
218 err = vm86_datacall(0x10, &vmf, &vesa_vmcontext);
219 if ((err != 0) || (vmf.vmf_ax != 0x4f))
220 return 1;
221 bcopy(buf, vmode, sizeof(*vmode));
222 return 0;
223 }
224
225 static int
226 vesa_bios_set_mode(int mode)
227 {
228 struct vm86frame vmf;
229 int err;
230
231 bzero(&vmf, sizeof(vmf));
232 vmf.vmf_eax = 0x4f02;
233 vmf.vmf_ebx = mode;
234 err = vm86_intcall(0x10, &vmf);
235 return ((err != 0) || (vmf.vmf_ax != 0x4f));
236 }
237
238 static int
239 vesa_bios_get_dac(void)
240 {
241 struct vm86frame vmf;
242 int err;
243
244 bzero(&vmf, sizeof(vmf));
245 vmf.vmf_eax = 0x4f08;
246 vmf.vmf_ebx = 1; /* get DAC width */
247 err = vm86_intcall(0x10, &vmf);
248 if ((err != 0) || (vmf.vmf_ax != 0x4f))
249 return 6; /* XXX */
250 return ((vmf.vmf_ebx >> 8) & 0x00ff);
251 }
252
253 static int
254 vesa_bios_set_dac(int bits)
255 {
256 struct vm86frame vmf;
257 int err;
258
259 bzero(&vmf, sizeof(vmf));
260 vmf.vmf_eax = 0x4f08;
261 vmf.vmf_ebx = (bits << 8);
262 err = vm86_intcall(0x10, &vmf);
263 if ((err != 0) || (vmf.vmf_ax != 0x4f))
264 return 6; /* XXX */
265 return ((vmf.vmf_ebx >> 8) & 0x00ff);
266 }
267
268 static int
269 vesa_bios_save_palette(int start, int colors, u_char *palette, int bits)
270 {
271 struct vm86frame vmf;
272 u_char *p;
273 int err;
274 int i;
275
276 bzero(&vmf, sizeof(vmf));
277 vmf.vmf_eax = 0x4f09;
278 vmf.vmf_ebx = 1; /* get primary palette data */
279 vmf.vmf_ecx = colors;
280 vmf.vmf_edx = start;
281 p = (u_char *)vm86_getpage(&vesa_vmcontext, 1);
282 vm86_getptr(&vesa_vmcontext, (vm_offset_t)p, &vmf.vmf_es, &vmf.vmf_di);
283
284 err = vm86_datacall(0x10, &vmf, &vesa_vmcontext);
285 if ((err != 0) || (vmf.vmf_ax != 0x4f))
286 return 1;
287
288 bits = 8 - bits;
289 for (i = 0; i < colors; ++i) {
290 palette[i*3] = p[i*4 + 2] << bits;
291 palette[i*3 + 1] = p[i*4 + 1] << bits;
292 palette[i*3 + 2] = p[i*4] << bits;
293 }
294 return 0;
295 }
296
297 static int
298 vesa_bios_load_palette(int start, int colors, u_char *palette, int bits)
299 {
300 struct vm86frame vmf;
301 u_char *p;
302 int err;
303 int i;
304
305 p = (u_char *)vm86_getpage(&vesa_vmcontext, 1);
306 bits = 8 - bits;
307 for (i = 0; i < colors; ++i) {
308 p[i*4] = palette[i*3 + 2] >> bits;
309 p[i*4 + 1] = palette[i*3 + 1] >> bits;
310 p[i*4 + 2] = palette[i*3] >> bits;
311 p[i*4 + 3] = 0;
312 }
313
314 bzero(&vmf, sizeof(vmf));
315 vmf.vmf_eax = 0x4f09;
316 vmf.vmf_ebx = 0; /* set primary palette data */
317 vmf.vmf_ecx = colors;
318 vmf.vmf_edx = start;
319 vm86_getptr(&vesa_vmcontext, (vm_offset_t)p, &vmf.vmf_es, &vmf.vmf_di);
320
321 err = vm86_datacall(0x10, &vmf, &vesa_vmcontext);
322 return ((err != 0) || (vmf.vmf_ax != 0x4f));
323 }
324
325 static int
326 vesa_bios_state_buf_size(void)
327 {
328 struct vm86frame vmf;
329 int err;
330
331 bzero(&vmf, sizeof(vmf));
332 vmf.vmf_eax = 0x4f04;
333 vmf.vmf_ecx = STATE_MOST;
334 vmf.vmf_edx = STATE_SIZE;
335 err = vm86_intcall(0x10, &vmf);
336 if ((err != 0) || (vmf.vmf_ax != 0x4f))
337 return 0;
338 return vmf.vmf_bx*64;
339 }
340
341 static int
342 vesa_bios_save_restore(int code, void *p, size_t size)
343 {
344 struct vm86frame vmf;
345 u_char *buf;
346 int err;
347
348 bzero(&vmf, sizeof(vmf));
349 vmf.vmf_eax = 0x4f04;
350 vmf.vmf_ecx = STATE_MOST;
351 vmf.vmf_edx = code; /* STATE_SAVE/STATE_LOAD */
352 buf = (u_char *)vm86_getpage(&vesa_vmcontext, 1);
353 vm86_getptr(&vesa_vmcontext, (vm_offset_t)buf, &vmf.vmf_es, &vmf.vmf_di);
354 bcopy(p, buf, size);
355
356 err = vm86_datacall(0x10, &vmf, &vesa_vmcontext);
357 return ((err != 0) || (vmf.vmf_ax != 0x4f));
358 }
359
360 static int
361 vesa_bios_get_line_length(void)
362 {
363 struct vm86frame vmf;
364 int err;
365
366 bzero(&vmf, sizeof(vmf));
367 vmf.vmf_eax = 0x4f06;
368 vmf.vmf_ebx = 1; /* get scan line length */
369 err = vm86_intcall(0x10, &vmf);
370 if ((err != 0) || (vmf.vmf_ax != 0x4f))
371 return -1;
372 return vmf.vmf_bx; /* line length in bytes */
373 }
374
375 /* map a generic video mode to a known mode */
376 static int
377 vesa_map_gen_mode_num(int type, int color, int mode)
378 {
379 static struct {
380 int from;
381 int to;
382 } mode_map[] = {
383 { M_TEXT_132x25, M_VESA_C132x25 },
384 { M_TEXT_132x43, M_VESA_C132x43 },
385 { M_TEXT_132x50, M_VESA_C132x50 },
386 { M_TEXT_132x60, M_VESA_C132x60 },
387 };
388 int i;
389
390 for (i = 0; i < sizeof(mode_map)/sizeof(mode_map[0]); ++i) {
391 if (mode_map[i].from == mode)
392 return mode_map[i].to;
393 }
394 return mode;
395 }
396
397 static int
398 vesa_translate_flags(u_int16_t vflags)
399 {
400 static struct {
401 u_int16_t mask;
402 int set;
403 int reset;
404 } ftable[] = {
405 { V_MODECOLOR, V_INFO_COLOR, 0 },
406 { V_MODEGRAPHICS, V_INFO_GRAPHICS, 0 },
407 { V_MODELFB, V_INFO_LINEAR, 0 },
408 };
409 int flags;
410 int i;
411
412 for (flags = 0, i = 0; i < sizeof(ftable)/sizeof(ftable[0]); ++i) {
413 flags |= (vflags & ftable[i].mask) ?
414 ftable[i].set : ftable[i].reset;
415 }
416 return flags;
417 }
418
419 static void
420 *vesa_fix_ptr(u_int32_t p, u_int16_t seg, u_int16_t off, u_char *buf)
421 {
422 if (p == 0)
423 return NULL;
424 if (((p >> 16) == seg) && ((p & 0xffff) >= off))
425 return (void *)(buf + ((p & 0xffff) - off));
426 else {
427 p = BIOS_SADDRTOLADDR(p);
428 return (void *)BIOS_PADDRTOVADDR(p);
429 }
430 }
431
432 static int
433 vesa_bios_init(void)
434 {
435 static u_char buf[512];
436 struct vm86frame vmf;
437 struct vesa_mode vmode;
438 u_char *vmbuf;
439 int modes;
440 int err;
441 int i;
442
443 if (vesa_init_done)
444 return 0;
445
446 has_vesa_bios = FALSE;
447 vesa_adp_info = NULL;
448 vesa_vmode[0].vi_mode = EOT;
449
450 vmbuf = (u_char *)vm86_addpage(&vesa_vmcontext, 1, 0);
451 bzero(&vmf, sizeof(vmf)); /* paranoia */
452 bcopy("VBE2", vmbuf, 4); /* try for VBE2 data */
453 vmf.vmf_eax = 0x4f00;
454 vm86_getptr(&vesa_vmcontext, (vm_offset_t)vmbuf, &vmf.vmf_es, &vmf.vmf_di);
455
456 err = vm86_datacall(0x10, &vmf, &vesa_vmcontext);
457 if ((err != 0) || (vmf.vmf_ax != 0x4f) || bcmp("VESA", vmbuf, 4))
458 return 1;
459 bcopy(vmbuf, buf, sizeof(buf));
460 vesa_adp_info = (struct vesa_info *)buf;
461 if (bootverbose) {
462 printf("VESA: information block\n");
463 dump_buffer(buf, 64);
464 }
465 if (vesa_adp_info->v_flags & V_NONVGA)
466 return 1;
467
468 /* fix string ptrs */
469 vesa_oemstr = (char *)vesa_fix_ptr(vesa_adp_info->v_oemstr,
470 vmf.vmf_es, vmf.vmf_di, buf);
471 if (vesa_adp_info->v_version >= 0x0200) {
472 vesa_venderstr =
473 (char *)vesa_fix_ptr(vesa_adp_info->v_venderstr,
474 vmf.vmf_es, vmf.vmf_di, buf);
475 vesa_prodstr =
476 (char *)vesa_fix_ptr(vesa_adp_info->v_prodstr,
477 vmf.vmf_es, vmf.vmf_di, buf);
478 vesa_revstr =
479 (char *)vesa_fix_ptr(vesa_adp_info->v_revstr,
480 vmf.vmf_es, vmf.vmf_di, buf);
481 }
482
483 /* obtain video mode information */
484 vesa_vmode[0].vi_mode = EOT;
485 vesa_vmodetab = (u_int16_t *)vesa_fix_ptr(vesa_adp_info->v_modetable,
486 vmf.vmf_es, vmf.vmf_di, buf);
487 if (vesa_vmodetab == NULL)
488 return 1;
489 for (i = 0, modes = 0;
490 (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1))
491 && (vesa_vmodetab[i] != 0xffff); ++i) {
492 if (modes >= VESA_MAXMODES)
493 break;
494 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
495 continue;
496
497 /* reject unsupported modes */
498 #if 0
499 if ((vmode.v_modeattr & (V_MODESUPP | V_MODEOPTINFO
500 | V_MODENONVGA))
501 != (V_MODESUPP | V_MODEOPTINFO))
502 continue;
503 #else
504 if ((vmode.v_modeattr & (V_MODEOPTINFO | V_MODENONVGA))
505 != (V_MODEOPTINFO))
506 continue;
507 #endif
508
509 /* copy some fields */
510 bzero(&vesa_vmode[modes], sizeof(vesa_vmode[modes]));
511 vesa_vmode[modes].vi_mode = vesa_vmodetab[i];
512 vesa_vmode[modes].vi_width = vmode.v_width;
513 vesa_vmode[modes].vi_height = vmode.v_height;
514 vesa_vmode[modes].vi_depth = vmode.v_bpp;
515 vesa_vmode[modes].vi_planes = vmode.v_planes;
516 vesa_vmode[modes].vi_cwidth = vmode.v_cwidth;
517 vesa_vmode[modes].vi_cheight = vmode.v_cheight;
518 vesa_vmode[modes].vi_window = (u_int)vmode.v_waseg << 4;
519 /* XXX window B */
520 vesa_vmode[modes].vi_window_size = vmode.v_wsize*1024;
521 vesa_vmode[modes].vi_window_gran = vmode.v_wgran*1024;
522 vesa_vmode[modes].vi_buffer = vmode.v_lfb;
523 /* XXX */
524 if (vmode.v_offscreen > vmode.v_lfb)
525 vesa_vmode[modes].vi_buffer_size
526 = vmode.v_offscreen - vmode.v_lfb;
527 else
528 vesa_vmode[modes].vi_buffer_size = vmode.v_offscreen;
529 /* pixel format, memory model... */
530
531 vesa_vmode[modes].vi_flags
532 = vesa_translate_flags(vmode.v_modeattr) | V_INFO_VESA;
533 ++modes;
534 }
535 vesa_vmode[modes].vi_mode = EOT;
536 if (bootverbose)
537 printf("VESA: %d mode(s) found\n", modes);
538
539 has_vesa_bios = (modes > 0);
540 return (has_vesa_bios ? 0 : 1);
541 }
542
543 static void
544 vesa_clear_modes(video_info_t *info, int color)
545 {
546 while (info->vi_mode != EOT) {
547 if ((info->vi_flags & V_INFO_COLOR) != color)
548 info->vi_mode = NA;
549 ++info;
550 }
551 }
552
553 /* entry points */
554
555 static int
556 vesa_configure(int flags)
557 {
558 video_adapter_t *adp;
559 int adapters;
560 int error;
561 int i;
562
563 if (vesa_init_done)
564 return 0;
565 if (flags & VIO_PROBE_ONLY)
566 return 0; /* XXX */
567
568 /*
569 * If the VESA module has already been loaded, abort loading
570 * the module this time.
571 */
572 for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) {
573 if (adp->va_flags & V_ADP_VESA)
574 return ENXIO;
575 if (adp->va_type == KD_VGA)
576 break;
577 }
578 /*
579 * The VGA adapter is not found. This is because either
580 * 1) the VGA driver has not been initialized, or 2) the VGA card
581 * is not present. If 1) is the case, we shall defer
582 * initialization for now and try again later.
583 */
584 if (adp == NULL) {
585 vga_sub_configure = vesa_configure;
586 return ENODEV;
587 }
588
589 /* count number of registered adapters */
590 for (++i; vid_get_adapter(i) != NULL; ++i)
591 ;
592 adapters = i;
593
594 /* call VESA BIOS */
595 vesa_adp = adp;
596 if (vesa_bios_init()) {
597 vesa_adp = NULL;
598 return ENXIO;
599 }
600 vesa_adp->va_flags |= V_ADP_VESA;
601
602 /* remove conflicting modes if we have more than one adapter */
603 if (adapters > 1) {
604 vesa_clear_modes(vesa_vmode,
605 (vesa_adp->va_flags & V_ADP_COLOR) ?
606 V_INFO_COLOR : 0);
607 }
608
609 if ((error = vesa_load_ioctl()) == 0) {
610 prevvidsw = vidsw[vesa_adp->va_index];
611 vidsw[vesa_adp->va_index] = &vesavidsw;
612 vesa_init_done = TRUE;
613 } else {
614 vesa_adp = NULL;
615 return error;
616 }
617
618 return 0;
619 }
620
621 static int
622 vesa_nop(void)
623 {
624 return 0;
625 }
626
627 static int
628 vesa_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
629 {
630 return (*prevvidsw->probe)(unit, adpp, arg, flags);
631 }
632
633 static int
634 vesa_init(int unit, video_adapter_t *adp, int flags)
635 {
636 return (*prevvidsw->init)(unit, adp, flags);
637 }
638
639 static int
640 vesa_get_info(video_adapter_t *adp, int mode, video_info_t *info)
641 {
642 int i;
643
644 if ((*prevvidsw->get_info)(adp, mode, info) == 0)
645 return 0;
646
647 if (adp != vesa_adp)
648 return 1;
649
650 mode = vesa_map_gen_mode_num(vesa_adp->va_type,
651 vesa_adp->va_flags & V_ADP_COLOR, mode);
652 for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
653 if (vesa_vmode[i].vi_mode == NA)
654 continue;
655 if (vesa_vmode[i].vi_mode == mode) {
656 *info = vesa_vmode[i];
657 return 0;
658 }
659 }
660 return 1;
661 }
662
663 static int
664 vesa_query_mode(video_adapter_t *adp, video_info_t *info)
665 {
666 int i;
667
668 if ((*prevvidsw->query_mode)(adp, info) == 0)
669 return 0;
670 if (adp != vesa_adp)
671 return ENODEV;
672
673 for (i = 0; vesa_vmode[i].vi_mode != EOT; ++i) {
674 if ((info->vi_width != 0)
675 && (info->vi_width != vesa_vmode[i].vi_width))
676 continue;
677 if ((info->vi_height != 0)
678 && (info->vi_height != vesa_vmode[i].vi_height))
679 continue;
680 if ((info->vi_cwidth != 0)
681 && (info->vi_cwidth != vesa_vmode[i].vi_cwidth))
682 continue;
683 if ((info->vi_cheight != 0)
684 && (info->vi_cheight != vesa_vmode[i].vi_cheight))
685 continue;
686 if ((info->vi_depth != 0)
687 && (info->vi_depth != vesa_vmode[i].vi_depth))
688 continue;
689 if ((info->vi_planes != 0)
690 && (info->vi_planes != vesa_vmode[i].vi_planes))
691 continue;
692 /* pixel format, memory model */
693 if ((info->vi_flags != 0)
694 && (info->vi_flags != vesa_vmode[i].vi_flags))
695 continue;
696 *info = vesa_vmode[i];
697 return 0;
698 }
699 return ENODEV;
700 }
701
702 static int
703 vesa_set_mode(video_adapter_t *adp, int mode)
704 {
705 video_info_t info;
706 size_t len;
707
708 if (adp != vesa_adp)
709 return (*prevvidsw->set_mode)(adp, mode);
710
711 mode = vesa_map_gen_mode_num(vesa_adp->va_type,
712 vesa_adp->va_flags & V_ADP_COLOR, mode);
713 #if VESA_DEBUG > 0
714 printf("VESA: set_mode(): %d(%x) -> %d(%x)\n",
715 vesa_adp->va_mode, vesa_adp->va_mode, mode, mode);
716 #endif
717 /*
718 * If the current mode is a VESA mode and the new mode is not,
719 * restore the state of the adapter first, so that non-standard,
720 * extended SVGA registers are set to the state compatible with
721 * the standard VGA modes. Otherwise (*prevvidsw->set_mode)()
722 * may not be able to set up the new mode correctly.
723 */
724 if (VESA_MODE(vesa_adp->va_mode)) {
725 if ((*prevvidsw->get_info)(adp, mode, &info) == 0) {
726 int10_set_mode(vesa_adp->va_initial_bios_mode);
727 #if 0
728 /* assert(vesa_state_buf != NULL); */
729 if ((vesa_state_buf == NULL)
730 || vesa_load_state(adp, vesa_state_buf))
731 return 1;
732 free(vesa_state_buf, M_DEVBUF);
733 vesa_state_buf = NULL;
734 #if VESA_DEBUG > 0
735 printf("VESA: restored\n");
736 #endif
737 #endif /* 0 */
738 }
739 /*
740 * once (*prevvidsw->get_info)() succeeded,
741 * (*prevvidsw->set_mode)() below won't fail...
742 */
743 }
744
745 /* we may not need to handle this mode after all... */
746 if ((*prevvidsw->set_mode)(adp, mode) == 0)
747 return 0;
748
749 /* is the new mode supported? */
750 if (vesa_get_info(adp, mode, &info))
751 return 1;
752 /* assert(VESA_MODE(mode)); */
753
754 #if VESA_DEBUG > 0
755 printf("VESA: about to set a VESA mode...\n");
756 #endif
757 /*
758 * If the current mode is not a VESA mode, save the current state
759 * so that the adapter state can be restored later when a non-VESA
760 * mode is to be set up. See above.
761 */
762 #if 0
763 if (!VESA_MODE(vesa_adp->va_mode) && (vesa_state_buf == NULL)) {
764 len = vesa_save_state(adp, NULL, 0);
765 vesa_state_buf = malloc(len, M_DEVBUF, M_WAITOK);
766 if (vesa_save_state(adp, vesa_state_buf, len)) {
767 #if VESA_DEBUG > 0
768 printf("VESA: state save failed! (len=%d)\n", len);
769 #endif
770 free(vesa_state_buf, M_DEVBUF);
771 vesa_state_buf = NULL;
772 return 1;
773 }
774 #if VESA_DEBUG > 0
775 printf("VESA: saved (len=%d)\n", len);
776 dump_buffer(vesa_state_buf, len);
777 #endif
778 }
779 #endif /* 0 */
780
781 if (vesa_bios_set_mode(mode))
782 return 1;
783
784 #if VESA_DEBUG > 0
785 printf("VESA: mode set!\n");
786 #endif
787 vesa_adp->va_mode = mode;
788 vesa_adp->va_flags &= ~V_ADP_COLOR;
789 vesa_adp->va_flags |=
790 (info.vi_flags & V_INFO_COLOR) ? V_ADP_COLOR : 0;
791 vesa_adp->va_crtc_addr =
792 (vesa_adp->va_flags & V_ADP_COLOR) ? COLOR_CRTC : MONO_CRTC;
793 vesa_adp->va_window = BIOS_PADDRTOVADDR(info.vi_window);
794 vesa_adp->va_window_size = info.vi_window_size;
795 vesa_adp->va_window_gran = info.vi_window_gran;
796 if (info.vi_buffer_size == 0) {
797 vesa_adp->va_buffer = 0;
798 vesa_adp->va_buffer_size = 0;
799 } else {
800 vesa_adp->va_buffer = BIOS_PADDRTOVADDR(info.vi_buffer);
801 vesa_adp->va_buffer_size = info.vi_buffer_size;
802 }
803 len = vesa_bios_get_line_length();
804 if (len > 0) {
805 vesa_adp->va_line_width = len;
806 } else if (info.vi_flags & V_INFO_GRAPHICS) {
807 switch (info.vi_depth/info.vi_planes) {
808 case 1:
809 vesa_adp->va_line_width = info.vi_width/8;
810 break;
811 case 2:
812 vesa_adp->va_line_width = info.vi_width/4;
813 break;
814 case 4:
815 vesa_adp->va_line_width = info.vi_width/2;
816 break;
817 case 8:
818 default: /* shouldn't happen */
819 vesa_adp->va_line_width = info.vi_width;
820 break;
821 }
822 } else {
823 vesa_adp->va_line_width = info.vi_width;
824 }
825 #if VESA_DEBUG > 0
826 printf("vesa_set_mode(): vi_width:%d, len:%d, line_width:%d\n",
827 info.vi_width, len, vesa_adp->va_line_width);
828 #endif
829 bcopy(&info, &vesa_adp->va_info, sizeof(vesa_adp->va_info));
830
831 /* move hardware cursor out of the way */
832 (*vidsw[vesa_adp->va_index]->set_hw_cursor)(vesa_adp, -1, -1);
833
834 return 0;
835 }
836
837 static int
838 vesa_save_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
839 int ch, int count)
840 {
841 return (*prevvidsw->save_font)(adp, page, fontsize, data, ch, count);
842 }
843
844 static int
845 vesa_load_font(video_adapter_t *adp, int page, int fontsize, u_char *data,
846 int ch, int count)
847 {
848 return (*prevvidsw->load_font)(adp, page, fontsize, data, ch, count);
849 }
850
851 static int
852 vesa_show_font(video_adapter_t *adp, int page)
853 {
854 return (*prevvidsw->show_font)(adp, page);
855 }
856
857 static int
858 vesa_save_palette(video_adapter_t *adp, u_char *palette)
859 {
860 int bits;
861 int error;
862
863 if ((adp == vesa_adp) && (vesa_adp_info->v_flags & V_DAC8)
864 && VESA_MODE(adp->va_mode)) {
865 bits = vesa_bios_get_dac();
866 error = vesa_bios_save_palette(0, 256, palette, bits);
867 if (error == 0)
868 return 0;
869 if (bits != 6)
870 return error;
871 }
872
873 return (*prevvidsw->save_palette)(adp, palette);
874 }
875
876 static int
877 vesa_load_palette(video_adapter_t *adp, u_char *palette)
878 {
879 #if notyet
880 int bits;
881 int error;
882
883 if ((adp == vesa_adp) && (vesa_adp_info->v_flags & V_DAC8)
884 && VESA_MODE(adp->va_mode) && ((bits = vesa_bios_set_dac(8)) > 6)) {
885 error = vesa_bios_load_palette(0, 256, palette, bits);
886 if (error == 0)
887 return 0;
888 if (vesa_bios_set_dac(6) != 6)
889 return 1;
890 }
891 #endif /* notyet */
892
893 return (*prevvidsw->load_palette)(adp, palette);
894 }
895
896 static int
897 vesa_set_border(video_adapter_t *adp, int color)
898 {
899 return (*prevvidsw->set_border)(adp, color);
900 }
901
902 static int
903 vesa_save_state(video_adapter_t *adp, void *p, size_t size)
904 {
905 if (adp != vesa_adp)
906 return (*prevvidsw->save_state)(adp, p, size);
907
908 if (vesa_state_buf_size == 0)
909 vesa_state_buf_size = vesa_bios_state_buf_size();
910 if (size == 0)
911 return (sizeof(int) + vesa_state_buf_size);
912 else if (size < (sizeof(int) + vesa_state_buf_size))
913 return 1;
914
915 ((adp_state_t *)p)->sig = V_STATE_SIG;
916 bzero(((adp_state_t *)p)->regs, vesa_state_buf_size);
917 return vesa_bios_save_restore(STATE_SAVE, ((adp_state_t *)p)->regs,
918 vesa_state_buf_size);
919 }
920
921 static int
922 vesa_load_state(video_adapter_t *adp, void *p)
923 {
924 if ((adp != vesa_adp) || (((adp_state_t *)p)->sig != V_STATE_SIG))
925 return (*prevvidsw->load_state)(adp, p);
926
927 return vesa_bios_save_restore(STATE_LOAD, ((adp_state_t *)p)->regs,
928 vesa_state_buf_size);
929 }
930
931 static int
932 vesa_set_origin(video_adapter_t *adp, off_t offset)
933 {
934 struct vm86frame vmf;
935 int err;
936
937 /*
938 * This function should return as quickly as possible to
939 * maintain good performance of the system. For this reason,
940 * error checking is kept minimal and let the VESA BIOS to
941 * detect error.
942 */
943 if (adp != vesa_adp)
944 return (*prevvidsw->set_win_org)(adp, offset);
945
946 if (vesa_adp->va_window_gran == 0)
947 return 1;
948 bzero(&vmf, sizeof(vmf));
949 vmf.vmf_eax = 0x4f05;
950 vmf.vmf_ebx = 0; /* WINDOW_A, XXX */
951 vmf.vmf_edx = offset/vesa_adp->va_window_gran;
952 err = vm86_intcall(0x10, &vmf);
953 if ((err != 0) || (vmf.vmf_ax != 0x4f))
954 return 1;
955 bzero(&vmf, sizeof(vmf));
956 vmf.vmf_eax = 0x4f05;
957 vmf.vmf_ebx = 1; /* WINDOW_B, XXX */
958 vmf.vmf_edx = offset/vesa_adp->va_window_gran;
959 err = vm86_intcall(0x10, &vmf);
960 return 0; /* XXX */
961 }
962
963 static int
964 vesa_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
965 {
966 return (*prevvidsw->read_hw_cursor)(adp, col, row);
967 }
968
969 static int
970 vesa_set_hw_cursor(video_adapter_t *adp, int col, int row)
971 {
972 return (*prevvidsw->set_hw_cursor)(adp, col, row);
973 }
974
975 static int
976 vesa_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
977 int celsize, int blink)
978 {
979 return (*prevvidsw->set_hw_cursor_shape)(adp, base, height, celsize,
980 blink);
981 }
982
983 static int
984 vesa_mmap(video_adapter_t *adp, vm_offset_t offset)
985 {
986 return (*prevvidsw->mmap)(adp, offset);
987 }
988
989 static int
990 vesa_diag(video_adapter_t *adp, int level)
991 {
992 #if VESA_DEBUG > 1
993 struct vesa_mode vmode;
994 int i;
995 #endif
996
997 if (adp != vesa_adp)
998 return 1;
999
1000 #ifndef KLD_MODULE
1001 /* call the previous handler first */
1002 (*prevvidsw->diag)(adp, level);
1003 #endif
1004
1005 /* general adapter information */
1006 printf("VESA: v%d.%d, %dk memory, flags:0x%x, mode table:%p (%x)\n",
1007 ((vesa_adp_info->v_version & 0xf000) >> 12) * 10
1008 + ((vesa_adp_info->v_version & 0x0f00) >> 8),
1009 ((vesa_adp_info->v_version & 0x00f0) >> 4) * 10
1010 + (vesa_adp_info->v_version & 0x000f),
1011 vesa_adp_info->v_memsize * 64, vesa_adp_info->v_flags,
1012 vesa_vmodetab, vesa_adp_info->v_modetable);
1013 /* OEM string */
1014 if (vesa_oemstr != NULL)
1015 printf("VESA: %s\n", vesa_oemstr);
1016
1017 if (level <= 0)
1018 return 0;
1019
1020 if (vesa_adp_info->v_version >= 0x0200) {
1021 /* vendor name */
1022 if (vesa_venderstr != NULL)
1023 printf("VESA: %s\n", vesa_venderstr);
1024 /* product name */
1025 if (vesa_prodstr != NULL)
1026 printf("VESA: %s\n", vesa_prodstr);
1027 /* product revision */
1028 if (vesa_revstr != NULL)
1029 printf("VESA: %s\n", vesa_revstr);
1030 }
1031
1032 #if VESA_DEBUG > 1
1033 /* mode information */
1034 for (i = 0;
1035 (i < (M_VESA_MODE_MAX - M_VESA_BASE + 1))
1036 && (vesa_vmodetab[i] != 0xffff); ++i) {
1037 if (vesa_bios_get_mode(vesa_vmodetab[i], &vmode))
1038 continue;
1039
1040 /* print something for diagnostic purpose */
1041 printf("VESA: mode:0x%03x, flags:0x%04x",
1042 vesa_vmodetab[i], vmode.v_modeattr);
1043 if (vmode.v_modeattr & V_MODEOPTINFO) {
1044 if (vmode.v_modeattr & V_MODEGRAPHICS) {
1045 printf(", G %dx%dx%d %d, ",
1046 vmode.v_width, vmode.v_height,
1047 vmode.v_bpp, vmode.v_planes);
1048 } else {
1049 printf(", T %dx%d, ",
1050 vmode.v_width, vmode.v_height);
1051 }
1052 printf("font:%dx%d",
1053 vmode.v_cwidth, vmode.v_cheight);
1054 }
1055 if (vmode.v_modeattr & V_MODELFB) {
1056 printf(", mem:%d, LFB:0x%x, off:0x%x",
1057 vmode.v_memmodel, vmode.v_lfb,
1058 vmode.v_offscreen);
1059 }
1060 printf("\n");
1061 printf("VESA: window A:0x%x (%x), window B:0x%x (%x), ",
1062 vmode.v_waseg, vmode.v_waattr,
1063 vmode.v_wbseg, vmode.v_wbattr);
1064 printf("size:%dk, gran:%dk\n",
1065 vmode.v_wsize, vmode.v_wgran);
1066 }
1067 #endif
1068
1069 return 0;
1070 }
1071
1072 /* module loading */
1073
1074 static int
1075 vesa_load(void)
1076 {
1077 int error;
1078 int s;
1079
1080 if (vesa_init_done)
1081 return 0;
1082
1083 /* locate a VGA adapter */
1084 s = spltty();
1085 vesa_adp = NULL;
1086 error = vesa_configure(0);
1087 splx(s);
1088
1089 #ifdef KLD_MODULE
1090 if (error == 0)
1091 vesa_diag(vesa_adp, bootverbose);
1092 #endif
1093
1094 return error;
1095 }
1096
1097 #ifdef KLD_MODULE
1098
1099 static int
1100 vesa_unload(void)
1101 {
1102 u_char palette[256*3];
1103 int error;
1104 int bits;
1105 int s;
1106
1107 /* if the adapter is currently in a VESA mode, don't unload */
1108 if ((vesa_adp != NULL) && VESA_MODE(vesa_adp->va_mode))
1109 return EBUSY;
1110 /*
1111 * FIXME: if there is at least one vty which is in a VESA mode,
1112 * we shouldn't be unloading! XXX
1113 */
1114
1115 s = spltty();
1116 if ((error = vesa_unload_ioctl()) == 0) {
1117 if (vesa_adp != NULL) {
1118 if (vesa_adp_info->v_flags & V_DAC8) {
1119 bits = vesa_bios_get_dac();
1120 if (bits > 6) {
1121 vesa_bios_save_palette(0, 256,
1122 palette, bits);
1123 vesa_bios_set_dac(6);
1124 vesa_bios_load_palette(0, 256,
1125 palette, 6);
1126 }
1127 }
1128 vesa_adp->va_flags &= ~V_ADP_VESA;
1129 vidsw[vesa_adp->va_index] = prevvidsw;
1130 }
1131 }
1132 splx(s);
1133
1134 return error;
1135 }
1136
1137 static int
1138 vesa_mod_event(module_t mod, int type, void *data)
1139 {
1140 switch (type) {
1141 case MOD_LOAD:
1142 return vesa_load();
1143 case MOD_UNLOAD:
1144 return vesa_unload();
1145 default:
1146 break;
1147 }
1148 return 0;
1149 }
1150
1151 static moduledata_t vesa_mod = {
1152 "vesa",
1153 vesa_mod_event,
1154 NULL,
1155 };
1156
1157 DECLARE_MODULE(vesa, vesa_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
1158
1159 #else /* KLD_MODULE */
1160
1161 SYSINIT(vesa, SI_SUB_DRIVERS, SI_ORDER_MIDDLE,
1162 (void (*)(void *))vesa_load, NULL);
1163
1164 #endif /* KLD_MODULE */
1165
1166 #endif /* (NVGA > 0 && VESA && VM86) || KLD_MODULE */
Cache object: 299c6d3d642736cf8f8ab864cac308d3
|