1 //
2 //  QEMU Cirrus CLGD 54xx VGABIOS Extension.
3 //
4 //  Copyright (c) 2004 Makoto Suzuki (suzu)
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2 of the License, or (at your option) any later version.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 //#define CIRRUS_VESA3_PMINFO
21 #ifdef VBE
22 #undef CIRRUS_VESA3_PMINFO
23 #endif
24 
25 #define PM_BIOSMEM_CURRENT_MODE 0x449
26 #define PM_BIOSMEM_CRTC_ADDRESS 0x463
27 #define PM_BIOSMEM_VBE_MODE 0x4BA
28 #define PM_BIOSMEM_VBE_POWER 0x4BC
29 
30 typedef struct
31 {
32   /* + 0 */
33   unsigned short mode;
34   unsigned short width;
35   unsigned short height;
36   unsigned short depth;
37   /* + 8 */
38   unsigned short hidden_dac; /* 0x3c6 */
39   unsigned short *seq; /* 0x3c4 */
40   unsigned short *graph; /* 0x3ce */
41   unsigned short *crtc; /* 0x3d4 */
42   /* +16 */
43   unsigned char bitsperpixel;
44   unsigned char vesacolortype;
45   unsigned char vesaredmask;
46   unsigned char vesaredpos;
47   unsigned char vesagreenmask;
48   unsigned char vesagreenpos;
49   unsigned char vesabluemask;
50   unsigned char vesabluepos;
51   /* +24 */
52   unsigned char vesareservedmask;
53   unsigned char vesareservedpos;
54 } cirrus_mode_t;
55 #define CIRRUS_MODE_SIZE 26
56 
57 
58 /* For VESA BIOS 3.0 */
59 #define CIRRUS_PM16INFO_SIZE 20
60 
61 /* VGA */
62 unsigned short cseq_vga[] = {0x0007,0xffff};
63 unsigned short cgraph_vga[] = {0x0009,0x000a,0x000b,0xffff};
64 unsigned short ccrtc_vga[] = {0x001a,0x001b,0x001d,0xffff};
65 
66 /* extensions */
67 unsigned short cgraph_svgacolor[] = {
68 0x0000,0x0001,0x0002,0x0003,0x0004,0x4005,0x0506,0x0f07,0xff08,
69 0x0009,0x000a,0x000b,
70 0xffff
71 };
72 /* 640x480x8 */
73 unsigned short cseq_640x480x8[] = {
74 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
75 0x580b,0x580c,0x580d,0x580e,
76 0x0412,0x0013,0x2017,
77 0x331b,0x331c,0x331d,0x331e,
78 0xffff
79 };
80 unsigned short ccrtc_640x480x8[] = {
81 0x2c11,
82 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
83 0x4009,0x000c,0x000d,
84 0xea10,0xdf12,0x5013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
85 0x001a,0x221b,0x001d,
86 0xffff
87 };
88 /* 640x480x16 */
89 unsigned short cseq_640x480x16[] = {
90 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
91 0x580b,0x580c,0x580d,0x580e,
92 0x0412,0x0013,0x2017,
93 0x331b,0x331c,0x331d,0x331e,
94 0xffff
95 };
96 unsigned short ccrtc_640x480x16[] = {
97 0x2c11,
98 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
99 0x4009,0x000c,0x000d,
100 0xea10,0xdf12,0xa013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
101 0x001a,0x221b,0x001d,
102 0xffff
103 };
104 /* 640x480x24 */
105 unsigned short cseq_640x480x24[] = {
106 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
107 0x580b,0x580c,0x580d,0x580e,
108 0x0412,0x0013,0x2017,
109 0x331b,0x331c,0x331d,0x331e,
110 0xffff
111 };
112 unsigned short ccrtc_640x480x24[] = {
113 0x2c11,
114 0x5f00,0x4f01,0x4f02,0x8003,0x5204,0x1e05,0x0b06,0x3e07,
115 0x4009,0x000c,0x000d,
116 0xea10,0xdf12,0x0013,0x4014,0xdf15,0x0b16,0xc317,0xff18,
117 0x001a,0x321b,0x001d,
118 0xffff
119 };
120 /* 800x600x8 */
121 unsigned short cseq_800x600x8[] = {
122 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
123 0x230b,0x230c,0x230d,0x230e,
124 0x0412,0x0013,0x2017,
125 0x141b,0x141c,0x141d,0x141e,
126 0xffff
127 };
128 unsigned short ccrtc_800x600x8[] = {
129 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
130 0x6009,0x000c,0x000d,
131 0x7d10,0x5712,0x6413,0x4014,0x5715,0x9816,0xc317,0xff18,
132 0x001a,0x221b,0x001d,
133 0xffff
134 };
135 /* 800x600x16 */
136 unsigned short cseq_800x600x16[] = {
137 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
138 0x230b,0x230c,0x230d,0x230e,
139 0x0412,0x0013,0x2017,
140 0x141b,0x141c,0x141d,0x141e,
141 0xffff
142 };
143 unsigned short ccrtc_800x600x16[] = {
144 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
145 0x6009,0x000c,0x000d,
146 0x7d10,0x5712,0xc813,0x4014,0x5715,0x9816,0xc317,0xff18,
147 0x001a,0x221b,0x001d,
148 0xffff
149 };
150 /* 800x600x24 */
151 unsigned short cseq_800x600x24[] = {
152 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
153 0x230b,0x230c,0x230d,0x230e,
154 0x0412,0x0013,0x2017,
155 0x141b,0x141c,0x141d,0x141e,
156 0xffff
157 };
158 unsigned short ccrtc_800x600x24[] = {
159 0x2311,0x7d00,0x6301,0x6302,0x8003,0x6b04,0x1a05,0x9806,0xf007,
160 0x6009,0x000c,0x000d,
161 0x7d10,0x5712,0x2c13,0x4014,0x5715,0x9816,0xc317,0xff18,
162 0x001a,0x321b,0x001d,
163 0xffff
164 };
165 /* 1024x768x8 */
166 unsigned short cseq_1024x768x8[] = {
167 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
168 0x760b,0x760c,0x760d,0x760e,
169 0x0412,0x0013,0x2017,
170 0x341b,0x341c,0x341d,0x341e,
171 0xffff
172 };
173 unsigned short ccrtc_1024x768x8[] = {
174 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
175 0x6009,0x000c,0x000d,
176 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
177 0x001a,0x221b,0x001d,
178 0xffff
179 };
180 /* 1024x768x16 */
181 unsigned short cseq_1024x768x16[] = {
182 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
183 0x760b,0x760c,0x760d,0x760e,
184 0x0412,0x0013,0x2017,
185 0x341b,0x341c,0x341d,0x341e,
186 0xffff
187 };
188 unsigned short ccrtc_1024x768x16[] = {
189 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
190 0x6009,0x000c,0x000d,
191 0x0310,0xff12,0x0013,0x4014,0xff15,0x2416,0xc317,0xff18,
192 0x001a,0x321b,0x001d,
193 0xffff
194 };
195 /* 1024x768x24 */
196 unsigned short cseq_1024x768x24[] = {
197 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1507,
198 0x760b,0x760c,0x760d,0x760e,
199 0x0412,0x0013,0x2017,
200 0x341b,0x341c,0x341d,0x341e,
201 0xffff
202 };
203 unsigned short ccrtc_1024x768x24[] = {
204 0x2911,0xa300,0x7f01,0x7f02,0x8603,0x8304,0x9405,0x2406,0xf507,
205 0x6009,0x000c,0x000d,
206 0x0310,0xff12,0x8013,0x4014,0xff15,0x2416,0xc317,0xff18,
207 0x001a,0x321b,0x001d,
208 0xffff
209 };
210 /* 1280x1024x8 */
211 unsigned short cseq_1280x1024x8[] = {
212 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
213 0x760b,0x760c,0x760d,0x760e,
214 0x0412,0x0013,0x2017,
215 0x341b,0x341c,0x341d,0x341e,
216 0xffff
217 };
218 unsigned short ccrtc_1280x1024x8[] = {
219 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
220 0x6009,0x000c,0x000d,
221 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
222 0x001a,0x221b,0x001d,
223 0xffff
224 };
225 /* 1280x1024x16 */
226 unsigned short cseq_1280x1024x16[] = {
227 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1707,
228 0x760b,0x760c,0x760d,0x760e,
229 0x0412,0x0013,0x2017,
230 0x341b,0x341c,0x341d,0x341e,
231 0xffff
232 };
233 unsigned short ccrtc_1280x1024x16[] = {
234 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
235 0x6009,0x000c,0x000d,
236 0x0310,0xff12,0x4013,0x4014,0xff15,0x2416,0xc317,0xff18,
237 0x001a,0x321b,0x001d,
238 0xffff
239 };
240 
241 /* 1600x1200x8 */
242 unsigned short cseq_1600x1200x8[] = {
243 0x0300,0x2101,0x0f02,0x0003,0x0e04,0x1107,
244 0x760b,0x760c,0x760d,0x760e,
245 0x0412,0x0013,0x2017,
246 0x341b,0x341c,0x341d,0x341e,
247 0xffff
248 };
249 unsigned short ccrtc_1600x1200x8[] = {
250 0x2911,0xc300,0x9f01,0x9f02,0x8603,0x8304,0x9405,0x2406,0xf707,
251 0x6009,0x000c,0x000d,
252 0x0310,0xff12,0xa013,0x4014,0xff15,0x2416,0xc317,0xff18,
253 0x001a,0x221b,0x001d,
254 0xffff
255 };
256 
257 cirrus_mode_t cirrus_modes[] =
258 {
259  {0x5f,640,480,8,0x00,
260    cseq_640x480x8,cgraph_svgacolor,ccrtc_640x480x8,8,
261    4,0,0,0,0,0,0,0,0},
262  {0x64,640,480,16,0xe1,
263    cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
264    6,5,11,6,5,5,0,0,0},
265  {0x66,640,480,15,0xf0,
266    cseq_640x480x16,cgraph_svgacolor,ccrtc_640x480x16,16,
267    6,5,10,5,5,5,0,1,15},
268  {0x71,640,480,24,0xe5,
269    cseq_640x480x24,cgraph_svgacolor,ccrtc_640x480x24,24,
270    6,8,16,8,8,8,0,0,0},
271 
272  {0x5c,800,600,8,0x00,
273    cseq_800x600x8,cgraph_svgacolor,ccrtc_800x600x8,8,
274    4,0,0,0,0,0,0,0,0},
275  {0x65,800,600,16,0xe1,
276    cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
277    6,5,11,6,5,5,0,0,0},
278  {0x67,800,600,15,0xf0,
279    cseq_800x600x16,cgraph_svgacolor,ccrtc_800x600x16,16,
280    6,5,10,5,5,5,0,1,15},
281 
282  {0x60,1024,768,8,0x00,
283    cseq_1024x768x8,cgraph_svgacolor,ccrtc_1024x768x8,8,
284    4,0,0,0,0,0,0,0,0},
285  {0x74,1024,768,16,0xe1,
286    cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
287    6,5,11,6,5,5,0,0,0},
288  {0x68,1024,768,15,0xf0,
289    cseq_1024x768x16,cgraph_svgacolor,ccrtc_1024x768x16,16,
290    6,5,10,5,5,5,0,1,15},
291 
292  {0x78,800,600,24,0xe5,
293    cseq_800x600x24,cgraph_svgacolor,ccrtc_800x600x24,24,
294    6,8,16,8,8,8,0,0,0},
295  {0x79,1024,768,24,0xe5,
296    cseq_1024x768x24,cgraph_svgacolor,ccrtc_1024x768x24,24,
297    6,8,16,8,8,8,0,0,0},
298 
299  {0x6d,1280,1024,8,0x00,
300    cseq_1280x1024x8,cgraph_svgacolor,ccrtc_1280x1024x8,8,
301    4,0,0,0,0,0,0,0,0},
302  {0x69,1280,1024,15,0xf0,
303    cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
304    6,5,10,5,5,5,0,1,15},
305  {0x75,1280,1024,16,0xe1,
306    cseq_1280x1024x16,cgraph_svgacolor,ccrtc_1280x1024x16,16,
307    6,5,11,6,5,5,0,0,0},
308 
309  {0x7b,1600,1200,8,0x00,
310    cseq_1600x1200x8,cgraph_svgacolor,ccrtc_1600x1200x8,8,
311    4,0,0,0,0,0,0,0,0},
312 
313  {0xfe,0,0,0,0,cseq_vga,cgraph_vga,ccrtc_vga,0,
314    0xff,0,0,0,0,0,0,0,0},
315  {0xff,0,0,0,0,0,0,0,0,
316    0xff,0,0,0,0,0,0,0,0},
317 };
318 
319 unsigned char cirrus_id_table[] = {
320   // 5430
321   0xA0, 0x32,
322   // 5446
323   0xB8, 0x39,
324 
325   0xff, 0xff
326 };
327 
328 
329 unsigned short cirrus_vesa_modelist[] = {
330 // 640x480x8
331   0x101, 0x5f,
332 // 640x480x15
333   0x110, 0x66,
334 // 640x480x16
335   0x111, 0x64,
336 // 640x480x24
337   0x112, 0x71,
338 // 800x600x8
339   0x103, 0x5c,
340 // 800x600x15
341   0x113, 0x67,
342 // 800x600x16
343   0x114, 0x65,
344 // 800x600x24
345   0x115, 0x78,
346 // 1024x768x8
347   0x105, 0x60,
348 // 1024x768x15
349   0x116, 0x68,
350 // 1024x768x16
351   0x117, 0x74,
352 // 1024x768x24
353   0x118, 0x79,
354 // 1280x1024x8
355   0x107, 0x6d,
356 // 1280x1024x15
357   0x119, 0x69,
358 // 1280x1024x16
359   0x11a, 0x75,
360 // invalid
361   0xffff,0xffff
362 };
363 
364 
365 ASM_START
366 
367 cirrus_installed:
368 .ascii "cirrus-compatible VGA is detected"
369 .byte 0x0d,0x0a
370 .byte 0x0d,0x0a,0x00
371 
372 cirrus_not_installed:
373 .ascii "cirrus-compatible VGA is not detected"
374 .byte 0x0d,0x0a
375 .byte 0x0d,0x0a,0x00
376 
377 cirrus_vesa_vendorname:
378 cirrus_vesa_productname:
379 cirrus_vesa_oemname:
380 .ascii "VGABIOS Cirrus extension"
381 .byte 0
382 cirrus_vesa_productrevision:
383 .ascii "1.0"
384 .byte 0
385 
386 cirrus_init:
387   call cirrus_check
388   jnz no_cirrus
389   SET_INT_VECTOR(0x10, #0xC000, #cirrus_int10_handler)
390   mov al, #0x0f ; memory setup
391   mov dx, #0x3C4
392   out dx, al
393   inc dx
394   in  al, dx
395   and al, #0x18
396   mov ah, al
397   mov al, #0x0a
398   dec dx
399   out dx, ax
400   mov ax, #0x0007 ; set vga mode
401   out dx, ax
402   mov ax, #0x0431 ; reset bitblt
403   mov dx, #0x3CE
404   out dx, ax
405   mov ax, #0x0031
406   out dx, ax
407 no_cirrus:
408   ret
409 
410 cirrus_display_info:
411   push ds
412   push si
413   push cs
414   pop ds
415   call cirrus_check
416   mov si, #cirrus_not_installed
417   jnz cirrus_msgnotinstalled
418   mov si, #cirrus_installed
419 
420 cirrus_msgnotinstalled:
421   call _display_string
422   pop si
423   pop ds
424   ret
425 
426 cirrus_check:
427   push ax
428   push dx
429   mov ax, #0x9206
430   mov dx, #0x3C4
431   out dx, ax
432   inc dx
433   in al, dx
434   cmp al, #0x12
435   pop dx
436   pop ax
437   ret
438 
439 
440 cirrus_int10_handler:
441   pushf
442   push bp
443   cmp ah, #0x00  ;; set video mode
444   jz cirrus_set_video_mode
445   cmp ah, #0x12  ;; cirrus extension
446   jz cirrus_extbios
447   cmp ah, #0x4F  ;; VESA extension
448   jz cirrus_vesa
449 
450 cirrus_unhandled:
451   pop bp
452   popf
453   jmp vgabios_int10_handler
454 
455 cirrus_return:
456 #ifdef CIRRUS_DEBUG
457   call cirrus_debug_dump
458 #endif
459   pop bp
460   popf
461   iret
462 
463 cirrus_set_video_mode:
464 #ifdef CIRRUS_DEBUG
465   call cirrus_debug_dump
466 #endif
467   push si
468   push ax
469   push bx
470   push ds
471 #ifdef CIRRUS_VESA3_PMINFO
472  db 0x2e ;; cs:
473   mov si, [cirrus_vesa_sel0000_data]
474 #else
475   xor si, si
476 #endif
477   mov ds, si
478   xor bx, bx
479   mov [PM_BIOSMEM_VBE_MODE], bx
480   pop ds
481   pop bx
482   call cirrus_get_modeentry
483   jnc cirrus_set_video_mode_extended
484   mov al, #0xfe
485   call cirrus_get_modeentry_nomask
486   call cirrus_switch_mode
487   pop ax
488   pop si
489   jmp cirrus_unhandled
490 
491 cirrus_extbios:
492 #ifdef CIRRUS_DEBUG
493   call cirrus_debug_dump
494 #endif
495   cmp bl, #0x80
496   jb cirrus_unhandled
497   cmp bl, #0xAF
498   ja cirrus_unhandled
499   push bx
500   and bx, #0x7F
501   shl bx, 1
502  db 0x2e ;; cs:
503   mov bp, cirrus_extbios_handlers[bx]
504   pop bx
505   push #cirrus_return
506   push bp
507   ret
508 
509 cirrus_vesa:
510 #ifdef CIRRUS_DEBUG
511   call cirrus_debug_dump
512 #endif
513   cmp al, #0x10
514   ja cirrus_vesa_not_handled
515   push bx
516   xor bx, bx
517   mov bl, al
518   shl bx, 1
519  db 0x2e ;; cs:
520   mov bp, cirrus_vesa_handlers[bx]
521   pop bx
522   push #cirrus_return
523   push bp
524   ret
525 
526 cirrus_vesa_not_handled:
527   mov ax, #0x014F ;; not implemented
528   jmp cirrus_return
529 
530 #ifdef CIRRUS_DEBUG
531 cirrus_debug_dump:
532   push es
533   push ds
534   pusha
535   push cs
536   pop ds
537   call _cirrus_debugmsg
538   popa
539   pop ds
540   pop es
541   ret
542 #endif
543 
544 cirrus_set_video_mode_extended:
545   call cirrus_switch_mode
546   pop ax ;; mode
547   test al, #0x80
548   jnz cirrus_set_video_mode_extended_1
549   push ax
550   mov ax, #0xffff ; set to 0xff to keep win 2K happy
551   call cirrus_clear_vram
552   pop ax
553 cirrus_set_video_mode_extended_1:
554   and al, #0x7f
555 
556   push ds
557 #ifdef CIRRUS_VESA3_PMINFO
558  db 0x2e ;; cs:
559   mov si, [cirrus_vesa_sel0000_data]
560 #else
561   xor si, si
562 #endif
563   mov ds, si
564   mov [PM_BIOSMEM_CURRENT_MODE], al
565   pop ds
566 
567   mov al, #0x20
568 
569   pop si
570   jmp cirrus_return
571 
572 cirrus_vesa_pmbios_init:
573   retf
574 cirrus_vesa_pmbios_entry:
575   pushf
576   push bp
577   cmp ah, #0x4F
578   jnz cirrus_vesa_pmbios_unimplemented
579   cmp al, #0x0F
580   ja cirrus_vesa_pmbios_unimplemented
581   push bx
582   xor bx, bx
583   mov bl, al
584   shl bx, 1
585  db 0x2e ;; cs:
586   mov bp, cirrus_vesa_handlers[bx]
587   pop bx
588   push #cirrus_vesa_pmbios_return
589   push bp
590   ret
591 cirrus_vesa_pmbios_unimplemented:
592   mov ax, #0x014F
593 cirrus_vesa_pmbios_return:
594   pop bp
595   popf
596   retf
597 
598 ; in si:mode table
599 cirrus_switch_mode:
600   push ds
601   push bx
602   push dx
603   push cs
604   pop ds
605 
606   mov bx, [si+10] ;; seq
607   mov dx, #0x3c4
608   mov ax, #0x1206
609   out dx, ax ;; Unlock cirrus special
610   call cirrus_switch_mode_setregs
611 
612   mov bx, [si+12] ;; graph
613   mov dx, #0x3ce
614   call cirrus_switch_mode_setregs
615 
616   mov bx, [si+14] ;; crtc
617   call cirrus_get_crtc
618   call cirrus_switch_mode_setregs
619 
620   mov dx, #0x3c6
621   mov al, #0x00
622   out dx, al
623   in al, dx
624   in al, dx
625   in al, dx
626   in al, dx
627   mov al, [si+8]  ;; hidden dac
628   out dx, al
629   mov al, #0xff
630   out dx, al
631 
632   mov al, #0x00
633   mov bl, [si+17]  ;; memory model
634   or  bl, bl
635   jz is_text_mode
636   mov al, #0x01
637   cmp bl, #0x03
638   jnz is_text_mode
639   or al, #0x40
640 is_text_mode:
641   mov bl, #0x10
642   call biosfn_get_single_palette_reg
643   and bh, #0xfe
644   or bh, al
645   call biosfn_set_single_palette_reg
646 
647   pop dx
648   pop bx
649   pop ds
650   ret
651 
652 cirrus_enable_16k_granularity:
653   push ax
654   push dx
655   mov dx, #0x3ce
656   mov al, #0x0b
657   out dx, al
658   inc dx
659   in al, dx
660   or al, #0x20 ;; enable 16k
661   out dx, al
662   pop dx
663   pop ax
664   ret
665 
666 cirrus_switch_mode_setregs:
667 csms_1:
668   mov ax, [bx]
669   cmp ax, #0xffff
670   jz csms_2
671   out dx, ax
672   add bx, #0x2
673   jmp csms_1
674 csms_2:
675   ret
676 
677 cirrus_extbios_80h:
678   push dx
679   call cirrus_get_crtc
680   mov al, #0x27
681   out dx, al
682   inc dx
683   in al, dx
684   mov bx, #_cirrus_id_table
685 c80h_1:
686  db 0x2e ;; cs:
687   mov ah, [bx]
688   cmp ah, al
689   jz c80h_2
690   cmp ah, #0xff
691   jz c80h_2
692   inc bx
693   inc bx
694   jmp c80h_1
695 c80h_2:
696  db 0x2e ;; cs:
697   mov al, 0x1[bx]
698   pop dx
699   mov ah, #0x00
700   xor bx, bx
701   ret
702 
703 cirrus_extbios_81h:
704   mov ax, #0x103 ;; XXX
705   ret
706 cirrus_extbios_82h:
707   push dx
708   call cirrus_get_crtc
709   xor ax, ax
710   mov al, #0x27
711   out dx, al
712   inc dx
713   in al, dx
714   and al, #0x03
715   mov ah, #0xAF
716   pop dx
717   ret
718 
719 cirrus_extbios_85h:
720   push cx
721   push dx
722   mov dx, #0x3C4
723   mov al, #0x0f ;; get DRAM band width
724   out dx, al
725   inc dx
726   in al, dx
727   ;; al = 4 << bandwidth
728   mov cl, al
729   shr cl, #0x03
730   and cl, #0x03
731   cmp cl, #0x03
732   je c85h2
733   mov al, #0x04
734   shl al, cl
735   jmp c85h3
736 c85h2:
737 ;; 4MB or 2MB
738   and al, #0x80
739   mov al, #0x20 ;; 2 MB
740   je c85h3
741   mov al, #0x40 ;; 4 MB
742 c85h3:
743   pop dx
744   pop cx
745   ret
746 
747 cirrus_extbios_9Ah:
748   mov ax, #0x4060
749   mov cx, #0x1132
750   ret
751 
752 cirrus_extbios_A0h:
753   call cirrus_get_modeentry
754   mov ah, #0x01
755   sbb ah, #0x00
756   mov bx, cirrus_extbios_A0h_callback
757   mov si, #0xffff
758   mov di, bx
759   mov ds, bx
760   mov es, bx
761   ret
762 
763 cirrus_extbios_A0h_callback:
764   ;; fatal: not implemented yet
765   cli
766   hlt
767   retf
768 
769 cirrus_extbios_A1h:
770   mov bx, #0x0E00 ;; IBM 8512/8513, color
771   ret
772 
773 cirrus_extbios_A2h:
774   mov al, #0x07   ;; HSync 31.5 - 64.0 kHz
775   ret
776 
777 cirrus_extbios_AEh:
778   mov al, #0x01   ;; High Refresh 75Hz
779   ret
780 
781 cirrus_extbios_unimplemented:
782   ret
783 
784 cirrus_vesa_00h:
785   push ds
786   push si
787   mov bp, di
788   push es
789   pop ds
790   cld
791   mov ax, [di]
792   cmp ax, #0x4256 ;; VB
793   jnz cv00_1
794   mov ax, [di+2]
795   cmp ax, #0x3245 ;; E2
796   jnz cv00_1
797   ;; VBE2
798   lea di, 0x14[bp]
799   mov ax, #0x0100 ;; soft ver.
800   stosw
801   mov ax, # cirrus_vesa_vendorname
802   stosw
803   mov ax, cs
804   stosw
805   mov ax, # cirrus_vesa_productname
806   stosw
807   mov ax, cs
808   stosw
809   mov ax, # cirrus_vesa_productrevision
810   stosw
811   mov ax, cs
812   stosw
813 cv00_1:
814   mov di, bp
815   mov ax, #0x4556 ;; VE
816   stosw
817   mov ax, #0x4153 ;; SA
818   stosw
819   mov ax, #0x0200 ;; v2.00
820   stosw
821   mov ax, # cirrus_vesa_oemname
822   stosw
823   mov ax, cs
824   stosw
825   xor ax, ax ;; caps
826   stosw
827   stosw
828   lea ax, 0x40[bp]
829   stosw
830   mov ax, es
831   stosw
832   call cirrus_extbios_85h ;; vram in 64k
833   mov ah, #0x00
834   stosw
835 
836   push cs
837   pop ds
838   lea di, 0x40[bp]
839   mov si, #_cirrus_vesa_modelist
840 cv00_2:
841   lodsw
842   stosw
843   add si, #2
844   cmp ax, #0xffff
845   jnz cv00_2
846 
847   mov ax, #0x004F
848   mov di, bp
849   pop si
850   pop ds
851   ret
852 
853 cirrus_vesa_01h:
854   mov ax, cx
855   and ax, #0x3fff
856   call cirrus_vesamode_to_mode
857   cmp ax, #0xffff
858   jnz cirrus_vesa_01h_1
859   jmp cirrus_vesa_unimplemented
860 cirrus_vesa_01h_1:
861   push ds
862   push si
863   push cx
864   push dx
865   push bx
866   mov bp, di
867   cld
868   push cs
869   pop ds
870   call cirrus_get_modeentry_nomask
871 
872   push di
873   xor ax, ax
874   mov cx, #0x80
875   rep
876     stosw ;; clear buffer
877   pop di
878 
879   mov ax, #0x003b ;; mode
880   stosw
881   mov ax, #0x0007 ;; attr
882   stosw
883   mov ax, #0x0010 ;; granularity =16K
884   stosw
885   mov ax, #0x0040 ;; size =64K
886   stosw
887   mov ax, #0xA000 ;; segment A
888   stosw
889   xor ax, ax ;; no segment B
890   stosw
891   mov ax, #cirrus_vesa_05h_farentry
892   stosw
893   mov ax, cs
894   stosw
895   call cirrus_get_line_offset_entry
896   stosw ;; bytes per scan line
897   mov ax, [si+2] ;; width
898   stosw
899   mov ax, [si+4] ;; height
900   stosw
901   mov ax, #0x08
902   stosb
903   mov ax, #0x10
904   stosb
905   mov al, #1 ;; count of planes
906   stosb
907   mov al, [si+6] ;; bpp
908   stosb
909   mov al, #0x1 ;; XXX number of banks
910   stosb
911   mov al, [si+17]
912   stosb ;; memory model
913   mov al, #0x0   ;; XXX size of bank in K
914   stosb
915   call cirrus_get_line_offset_entry
916   mov bx, [si+4]
917   mul bx ;; dx:ax=vramdisp
918   or ax, ax
919   jz cirrus_vesa_01h_3
920   inc dx
921 cirrus_vesa_01h_3:
922   call cirrus_extbios_85h ;; al=vram in 64k
923   mov ah, #0x00
924   mov cx, dx
925   xor dx, dx
926   div cx
927   dec ax
928   stosb  ;; number of image pages = vramtotal/vramdisp-1
929   mov al, #0x00
930   stosb
931 
932   ;; v1.2+ stuffs
933   push si
934   add si, #18
935   movsw
936   movsw
937   movsw
938   movsw
939   pop si
940 
941   mov ah, [si+16]
942   mov al, #0x0
943   sub ah, #9
944   rcl al, #1 ; bit 0=palette flag
945   stosb ;; direct screen mode info
946 
947   ;; v2.0+ stuffs
948   ;; 32-bit LFB address
949   xor ax, ax
950   stosw
951   call cirrus_get_lfb_addr
952   stosw
953   or ax, ax
954   jz cirrus_vesa_01h_4
955   push di
956   mov di, bp
957  db 0x26 ;; es:
958   mov ax, [di]
959   or ax, #0x0080 ;; mode bit 7:LFB
960   stosw
961   pop di
962 cirrus_vesa_01h_4:
963 
964   xor ax, ax
965   stosw ; reserved
966   stosw ; reserved
967   stosw ; reserved
968 
969   mov ax, #0x004F
970   mov di, bp
971   pop bx
972   pop dx
973   pop cx
974   pop si
975   pop ds
976 
977   test cx, #0x4000 ;; LFB flag
978   jz cirrus_vesa_01h_5
979   push cx
980  db 0x26 ;; es:
981   mov cx, [di]
982   cmp cx, #0x0080 ;; is LFB supported?
983   jnz cirrus_vesa_01h_6
984   mov ax, #0x014F ;; error - no LFB
985 cirrus_vesa_01h_6:
986   pop cx
987 cirrus_vesa_01h_5:
988   ret
989 
990 cirrus_vesa_02h:
991   ;; XXX support CRTC registers
992   test bx, #0x3e00
993   jnz cirrus_vesa_02h_2 ;; unknown flags
994   mov ax, bx
995   and ax, #0x1ff ;; bit 8-0 mode
996   cmp ax, #0x100 ;; legacy VGA mode
997   jb cirrus_vesa_02h_legacy
998   call cirrus_vesamode_to_mode
999   cmp ax, #0xffff
1000   jnz cirrus_vesa_02h_1
1001 cirrus_vesa_02h_2:
1002   jmp cirrus_vesa_unimplemented
1003 cirrus_vesa_02h_legacy:
1004 #ifdef CIRRUS_VESA3_PMINFO
1005  db 0x2e ;; cs:
1006   cmp byte ptr [cirrus_vesa_is_protected_mode], #0
1007   jnz cirrus_vesa_02h_2
1008 #endif // CIRRUS_VESA3_PMINFO
1009   int #0x10
1010   mov ax, #0x004F
1011   ret
1012 cirrus_vesa_02h_1:
1013   push si
1014   push ax
1015   call cirrus_get_modeentry_nomask
1016   call cirrus_switch_mode
1017   test bx, #0x4000 ;; LFB
1018   jnz cirrus_vesa_02h_3
1019   call cirrus_enable_16k_granularity
1020 cirrus_vesa_02h_3:
1021   test bx, #0x8000 ;; no clear
1022   jnz cirrus_vesa_02h_4
1023   push ax
1024   xor ax,ax
1025   call cirrus_clear_vram
1026   pop ax
1027 cirrus_vesa_02h_4:
1028   pop ax
1029   push ds
1030 #ifdef CIRRUS_VESA3_PMINFO
1031  db 0x2e ;; cs:
1032   mov si, [cirrus_vesa_sel0000_data]
1033 #else
1034   xor si, si
1035 #endif
1036   mov ds, si
1037   mov [PM_BIOSMEM_CURRENT_MODE], al
1038   mov [PM_BIOSMEM_VBE_MODE], bx
1039   pop ds
1040   pop si
1041   mov ax, #0x004F
1042   ret
1043 
1044 cirrus_vesa_03h:
1045   push ds
1046 #ifdef CIRRUS_VESA3_PMINFO
1047  db 0x2e ;; cs:
1048   mov ax, [cirrus_vesa_sel0000_data]
1049 #else
1050   xor ax, ax
1051 #endif
1052   mov  ds, ax
1053   mov  bx, # PM_BIOSMEM_VBE_MODE
1054   mov  ax, [bx]
1055   mov  bx, ax
1056   test bx, bx
1057   jnz   cirrus_vesa_03h_1
1058   mov  bx, # PM_BIOSMEM_CURRENT_MODE
1059   mov  al, [bx]
1060   mov  bl, al
1061   xor  bh, bh
1062 cirrus_vesa_03h_1:
1063   mov  ax, #0x004f
1064   pop  ds
1065   ret
1066 
1067 cirrus_vesa_05h_farentry:
1068   call cirrus_vesa_05h
1069   retf
1070 
1071 cirrus_vesa_05h:
1072   cmp bl, #0x01
1073   ja cirrus_vesa_05h_1
1074   cmp bh, #0x00
1075   jz cirrus_vesa_05h_setmempage
1076   cmp bh, #0x01
1077   jz cirrus_vesa_05h_getmempage
1078 cirrus_vesa_05h_1:
1079   jmp cirrus_vesa_unimplemented
1080 cirrus_vesa_05h_setmempage:
1081   or dh, dh ; address must be < 0x100
1082   jnz cirrus_vesa_05h_1
1083   push dx
1084   mov al, bl ;; bl=bank number
1085   add al, #0x09
1086   mov ah, dl ;; dx=window address in granularity
1087   mov dx, #0x3ce
1088   out dx, ax
1089   pop dx
1090   mov ax, #0x004F
1091   ret
1092 cirrus_vesa_05h_getmempage:
1093   mov al, bl ;; bl=bank number
1094   add al, #0x09
1095   mov dx, #0x3ce
1096   out dx, al
1097   inc dx
1098   in al, dx
1099   xor dx, dx
1100   mov dl, al ;; dx=window address in granularity
1101   mov ax, #0x004F
1102   ret
1103 
1104 cirrus_vesa_06h:
1105   mov  ax, cx
1106   cmp  bl, #0x01
1107   je   cirrus_vesa_06h_3
1108   cmp  bl, #0x02
1109   je   cirrus_vesa_06h_2
1110   jb   cirrus_vesa_06h_1
1111   mov  ax, #0x0100
1112   ret
1113 cirrus_vesa_06h_1:
1114   call cirrus_get_bpp_bytes
1115   mov  bl, al
1116   xor  bh, bh
1117   mov  ax, cx
1118   mul  bx
1119 cirrus_vesa_06h_2:
1120   call cirrus_set_line_offset
1121 cirrus_vesa_06h_3:
1122   call cirrus_get_bpp_bytes
1123   mov  bl, al
1124   xor  bh, bh
1125   xor  dx, dx
1126   call cirrus_get_line_offset
1127   push ax
1128   div  bx
1129   mov  cx, ax
1130   pop  bx
1131   call cirrus_extbios_85h ;; al=vram in 64k
1132   xor  dx, dx
1133   mov  dl, al
1134   xor  ax, ax
1135   div  bx
1136   mov  dx, ax
1137   mov  ax, #0x004f
1138   ret
1139 
1140 cirrus_vesa_07h:
1141   cmp  bl, #0x80
1142   je   cirrus_vesa_07h_1
1143   cmp  bl, #0x01
1144   je   cirrus_vesa_07h_2
1145   jb   cirrus_vesa_07h_1
1146   mov  ax, #0x0100
1147   ret
1148 cirrus_vesa_07h_1:
1149   push dx
1150   call cirrus_get_bpp_bytes
1151   mov  bl, al
1152   xor  bh, bh
1153   mov  ax, cx
1154   mul  bx
1155   pop  bx
1156   push ax
1157   call cirrus_get_line_offset
1158   mul  bx
1159   pop  bx
1160   add  ax, bx
1161   jnc  cirrus_vesa_07h_3
1162   inc  dx
1163 cirrus_vesa_07h_3:
1164   push dx
1165   and  dx, #0x0003
1166   mov  bx, #0x04
1167   div  bx
1168   pop  dx
1169   shr  dx, #2
1170   call cirrus_set_start_addr
1171   mov  ax, #0x004f
1172   ret
1173 cirrus_vesa_07h_2:
1174   call cirrus_get_start_addr
1175   shl  dx, #2
1176   push dx
1177   mov  bx, #0x04
1178   mul  bx
1179   pop  bx
1180   or   dx, bx
1181   push ax
1182   call cirrus_get_line_offset
1183   mov  bx, ax
1184   pop  ax
1185   div  bx
1186   push ax
1187   push dx
1188   call cirrus_get_bpp_bytes
1189   mov  bl, al
1190   xor  bh, bh
1191   pop  ax
1192   xor  dx, dx
1193   div  bx
1194   mov  cx, ax
1195   pop  dx
1196   mov  ax, #0x004f
1197   ret
1198 
1199 cirrus_vesa_10h: ;; Power management functions
1200   ;; Set up DS to read stored power info from RAM
1201   push ds
1202 #ifdef CIRRUS_VESA3_PMINFO
1203  db 0x2e ;; cs:
1204   mov ax, [cirrus_vesa_sel0000_data]
1205 #else
1206   xor ax, ax
1207 #endif
1208   mov  ds, ax
1209   ;; Now choose the right function
1210   cmp  bl, #0x00
1211   ja   cirrus_vesa_10h_01
1212   ;;
1213   ;; Function 00h: Get capabilities
1214   ;;
1215   mov  bx, #0x0720 ;; 07: standby/suspend/off, 20: VBE/PM 2.0
1216   mov  ax, #0x004f
1217   jmp cirrus_vesa_10h_done
1218 cirrus_vesa_10h_01:
1219   cmp  bl, #0x01
1220   ja   cirrus_vesa_10h_02
1221   ;;
1222   ;; Function 01h: Set power state
1223   ;;
1224   mov  ax, bx
1225   mov  bx, # PM_BIOSMEM_VBE_POWER
1226   mov  [bx], ah
1227   mov  ax, #0x004f
1228   jmp cirrus_vesa_10h_done
1229 cirrus_vesa_10h_02:
1230   cmp  bl, #0x02
1231   ja   cirrus_vesa_10h_unimplemented
1232   ;;
1233   ;; Function 02h: Get power state
1234   ;;
1235   mov  bx, # PM_BIOSMEM_VBE_POWER
1236   mov  bh, [bx]
1237   mov  ax, #0x004f
1238   jmp cirrus_vesa_10h_done
1239 cirrus_vesa_10h_unimplemented:
1240   mov  ax, #0x014F ;; not implemented
1241 cirrus_vesa_10h_done:
1242   pop ds
1243   ret
1244 
1245 cirrus_vesa_unimplemented:
1246   mov ax, #0x014F ;; not implemented
1247   ret
1248 
1249 
1250 ;; in ax:vesamode, out ax:cirrusmode
1251 cirrus_vesamode_to_mode:
1252   push ds
1253   push cx
1254   push si
1255   push cs
1256   pop ds
1257   mov cx, #0xffff
1258   mov si, #_cirrus_vesa_modelist
1259 cvtm_1:
1260   cmp [si],ax
1261   jz cvtm_2
1262   cmp [si],cx
1263   jz cvtm_2
1264   add si, #4
1265   jmp cvtm_1
1266 cvtm_2:
1267   mov ax,[si+2]
1268   pop si
1269   pop cx
1270   pop ds
1271   ret
1272 
1273   ; cirrus_get_crtc
1274   ;; NOTE - may be called in protected mode
1275 cirrus_get_crtc:
1276   push ds
1277   push ax
1278   mov  dx, #0x3cc
1279   in   al, dx
1280   and  al, #0x01
1281   shl  al, #5
1282   mov  dx, #0x3b4
1283   add  dl, al
1284   pop  ax
1285   pop  ds
1286   ret
1287 
1288 ;; in - al:mode, out - cflag:result, si:table, ax:destroyed
1289 cirrus_get_modeentry:
1290   and al, #0x7f
1291 cirrus_get_modeentry_nomask:
1292   mov si, #_cirrus_modes
1293 cgm_1:
1294  db 0x2e ;; cs:
1295   mov ah, [si]
1296   cmp al, ah
1297   jz cgm_2
1298   cmp ah, #0xff
1299   jz cgm_4
1300   add si, # CIRRUS_MODE_SIZE
1301   jmp cgm_1
1302 cgm_4:
1303   xor si, si
1304   stc ;; video mode is not supported
1305   jmp cgm_3
1306 cgm_2:
1307   clc ;; video mode is supported
1308 cgm_3:
1309   ret
1310 
1311   ; get LFB address
1312   ; out - ax:LFB address (high 16 bit)
1313   ;; NOTE - may be called in protected mode
1314 cirrus_get_lfb_addr:
1315   push cx
1316   push dx
1317   push eax
1318     xor cx, cx
1319     mov dl, #0x00
1320     call cirrus_pci_read
1321     cmp ax, #0xffff
1322     jz cirrus_get_lfb_addr_5
1323  cirrus_get_lfb_addr_3:
1324     mov dl, #0x00
1325     call cirrus_pci_read
1326     cmp ax, #0x1013 ;; cirrus
1327     jz cirrus_get_lfb_addr_4
1328     add cx, #0x8
1329     cmp cx, #0x200 ;; search bus #0 and #1
1330     jb cirrus_get_lfb_addr_3
1331  cirrus_get_lfb_addr_5:
1332     xor dx, dx ;; no LFB
1333     jmp cirrus_get_lfb_addr_6
1334  cirrus_get_lfb_addr_4:
1335     mov dl, #0x10 ;; I/O space #0
1336     call cirrus_pci_read
1337     test ax, #0xfff1
1338     jnz cirrus_get_lfb_addr_5
1339     shr eax, #16
1340     mov dx, ax ;; LFB address
1341  cirrus_get_lfb_addr_6:
1342   pop eax
1343   mov ax, dx
1344   pop dx
1345   pop cx
1346   ret
1347 
1348 cirrus_pci_read:
1349   mov eax, #0x00800000
1350   mov ax, cx
1351   shl eax, #8
1352   mov al, dl
1353   mov dx, #0xcf8
1354   out dx, eax
1355   add dl, #4
1356   in  eax, dx
1357   ret
1358 
1359 ;; out - al:bytes per pixel
1360 cirrus_get_bpp_bytes:
1361   push dx
1362   mov  dx, #0x03c4
1363   mov  al, #0x07
1364   out  dx, al
1365   inc  dx
1366   in   al, dx
1367   and  al, #0x0e
1368   cmp  al, #0x06
1369   jne  cirrus_get_bpp_bytes_1
1370   and  al, #0x02
1371 cirrus_get_bpp_bytes_1:
1372   shr  al, #1
1373   cmp  al, #0x04
1374   je  cirrus_get_bpp_bytes_2
1375   inc  al
1376 cirrus_get_bpp_bytes_2:
1377   pop  dx
1378   ret
1379 
1380 ;; in - ax: new line offset
1381 cirrus_set_line_offset:
1382   shr  ax, #3
1383   push ax
1384   call cirrus_get_crtc
1385   mov  al, #0x13
1386   out  dx, al
1387   inc  dx
1388   pop  ax
1389   out  dx, al
1390   dec  dx
1391   mov  al, #0x1b
1392   out  dx, al
1393   inc  dx
1394   shl  ah, #4
1395   in   al, dx
1396   and  al, #ef
1397   or   al, ah
1398   out  dx, al
1399   ret
1400 
1401 ;; out - ax: active line offset
1402 cirrus_get_line_offset:
1403   push dx
1404   push bx
1405   call cirrus_get_crtc
1406   mov  al, #0x13
1407   out  dx, al
1408   inc  dx
1409   in   al, dx
1410   mov  bl, al
1411   dec  dx
1412   mov  al, #0x1b
1413   out  dx, al
1414   inc  dx
1415   in   al, dx
1416   mov  ah, al
1417   shr  ah, #4
1418   and  ah, #0x01
1419   mov  al, bl
1420   shl  ax, #3
1421   pop  bx
1422   pop  dx
1423   ret
1424 
1425 ;; in - si: table
1426 ;; out - ax: line offset for mode
1427 cirrus_get_line_offset_entry:
1428   push bx
1429   mov  bx, [si+14] ;; crtc table
1430   push bx
1431 offset_loop1:
1432   mov  ax, [bx]
1433   cmp  al, #0x13
1434   je   offset_found1
1435   inc  bx
1436   inc  bx
1437   jnz  offset_loop1
1438 offset_found1:
1439   xor  al, al
1440   shr  ax, #5
1441   pop  bx
1442   push ax
1443 offset_loop2:
1444   mov  ax, [bx]
1445   cmp  al, #0x1b
1446   je offset_found2
1447   inc  bx
1448   inc  bx
1449   jnz offset_loop2
1450 offset_found2:
1451   pop  bx
1452   and  ax, #0x1000
1453   shr  ax, #1
1454   or   ax, bx
1455   pop  bx
1456   ret
1457 
1458 ;; in - new address in DX:AX
1459 cirrus_set_start_addr:
1460   push bx
1461   push dx
1462   push ax
1463   call cirrus_get_crtc
1464   mov  al, #0x0d
1465   out  dx, al
1466   inc  dx
1467   pop  ax
1468   out  dx, al
1469   dec  dx
1470   mov  al, #0x0c
1471   out  dx, al
1472   inc  dx
1473   mov  al, ah
1474   out  dx, al
1475   dec  dx
1476   mov  al, #0x1d
1477   out  dx, al
1478   inc  dx
1479   in   al, dx
1480   and  al, #0x7f
1481   pop  bx
1482   mov  ah, bl
1483   shl  bl, #4
1484   and  bl, #0x80
1485   or   al, bl
1486   out  dx, al
1487   dec  dx
1488   mov  bl, ah
1489   and  ah, #0x01
1490   shl  bl, #1
1491   and  bl, #0x0c
1492   or   ah, bl
1493   mov  al, #0x1b
1494   out  dx, al
1495   inc  dx
1496   in   al, dx
1497   and  al, #0xf2
1498   or   al, ah
1499   out  dx, al
1500   pop  bx
1501   ret
1502 
1503 ;; out - current address in DX:AX
1504 cirrus_get_start_addr:
1505   push bx
1506   call cirrus_get_crtc
1507   mov  al, #0x0c
1508   out  dx, al
1509   inc  dx
1510   in   al, dx
1511   mov  ah, al
1512   dec  dx
1513   mov  al, #0x0d
1514   out  dx, al
1515   inc  dx
1516   in   al, dx
1517   push ax
1518   dec  dx
1519   mov  al, #0x1b
1520   out  dx, al
1521   inc  dx
1522   in   al, dx
1523   dec  dx
1524   mov  bl, al
1525   and  al, #0x01
1526   and  bl, #0x0c
1527   shr  bl, #1
1528   or   bl, al
1529   mov  al, #0x1d
1530   out  dx, al
1531   inc  dx
1532   in   al, dx
1533   and  al, #0x80
1534   shr  al, #4
1535   or   bl, al
1536   mov  dl, bl
1537   xor  dh, dh
1538   pop  ax
1539   pop  bx
1540   ret
1541 
1542 cirrus_clear_vram:
1543   pusha
1544   push es
1545   mov si, ax
1546 
1547   call cirrus_enable_16k_granularity
1548   call cirrus_extbios_85h
1549   shl al, #2
1550   mov bl, al
1551   xor ah,ah
1552 cirrus_clear_vram_1:
1553   mov al, #0x09
1554   mov dx, #0x3ce
1555   out dx, ax
1556   push ax
1557 
1558 ;; Windows Vista appears to be emulating this sequence as part of changing
1559 ;; screen resolution, but it generates 4096 writes per iteration.
1560 ;; Instead, use a magic register sequence to write the whole bank.
1561 ;;mov cx, #0xa000
1562 ;;mov es, cx
1563 ;;xor di, di
1564 ;;mov ax, si
1565 ;;mov cx, #8192
1566 ;;cld
1567 ;;rep
1568 ;;    stosw
1569   mov ax, si
1570   shl ax, #8
1571   mov al, #0xfe
1572   out dx, ax	;; Low byte of value to be written to the bank
1573   mov ax, si
1574   mov al, #0xff
1575   out dx, ax    ;; High byte and trigger the write
1576 
1577   pop ax
1578   inc ah
1579   cmp ah, bl
1580   jne cirrus_clear_vram_1
1581 
1582   xor ah,ah
1583   mov dx, #0x3ce
1584   out dx, ax
1585 
1586   pop es
1587   popa
1588   ret
1589 
1590 cirrus_extbios_handlers:
1591   ;; 80h
1592   dw cirrus_extbios_80h
1593   dw cirrus_extbios_81h
1594   dw cirrus_extbios_82h
1595   dw cirrus_extbios_unimplemented
1596   ;; 84h
1597   dw cirrus_extbios_unimplemented
1598   dw cirrus_extbios_85h
1599   dw cirrus_extbios_unimplemented
1600   dw cirrus_extbios_unimplemented
1601   ;; 88h
1602   dw cirrus_extbios_unimplemented
1603   dw cirrus_extbios_unimplemented
1604   dw cirrus_extbios_unimplemented
1605   dw cirrus_extbios_unimplemented
1606   ;; 8Ch
1607   dw cirrus_extbios_unimplemented
1608   dw cirrus_extbios_unimplemented
1609   dw cirrus_extbios_unimplemented
1610   dw cirrus_extbios_unimplemented
1611   ;; 90h
1612   dw cirrus_extbios_unimplemented
1613   dw cirrus_extbios_unimplemented
1614   dw cirrus_extbios_unimplemented
1615   dw cirrus_extbios_unimplemented
1616   ;; 94h
1617   dw cirrus_extbios_unimplemented
1618   dw cirrus_extbios_unimplemented
1619   dw cirrus_extbios_unimplemented
1620   dw cirrus_extbios_unimplemented
1621   ;; 98h
1622   dw cirrus_extbios_unimplemented
1623   dw cirrus_extbios_unimplemented
1624   dw cirrus_extbios_9Ah
1625   dw cirrus_extbios_unimplemented
1626   ;; 9Ch
1627   dw cirrus_extbios_unimplemented
1628   dw cirrus_extbios_unimplemented
1629   dw cirrus_extbios_unimplemented
1630   dw cirrus_extbios_unimplemented
1631   ;; A0h
1632   dw cirrus_extbios_A0h
1633   dw cirrus_extbios_A1h
1634   dw cirrus_extbios_A2h
1635   dw cirrus_extbios_unimplemented
1636   ;; A4h
1637   dw cirrus_extbios_unimplemented
1638   dw cirrus_extbios_unimplemented
1639   dw cirrus_extbios_unimplemented
1640   dw cirrus_extbios_unimplemented
1641   ;; A8h
1642   dw cirrus_extbios_unimplemented
1643   dw cirrus_extbios_unimplemented
1644   dw cirrus_extbios_unimplemented
1645   dw cirrus_extbios_unimplemented
1646   ;; ACh
1647   dw cirrus_extbios_unimplemented
1648   dw cirrus_extbios_unimplemented
1649   dw cirrus_extbios_AEh
1650   dw cirrus_extbios_unimplemented
1651 
1652 cirrus_vesa_handlers:
1653   ;; 00h
1654   dw cirrus_vesa_00h
1655   dw cirrus_vesa_01h
1656   dw cirrus_vesa_02h
1657   dw cirrus_vesa_03h
1658   ;; 04h
1659   dw cirrus_vesa_unimplemented
1660   dw cirrus_vesa_05h
1661   dw cirrus_vesa_06h
1662   dw cirrus_vesa_07h
1663   ;; 08h
1664   dw cirrus_vesa_unimplemented
1665   dw cirrus_vesa_unimplemented
1666   dw cirrus_vesa_unimplemented
1667   dw cirrus_vesa_unimplemented
1668   ;; 0Ch
1669   dw cirrus_vesa_unimplemented
1670   dw cirrus_vesa_unimplemented
1671   dw cirrus_vesa_unimplemented
1672   dw cirrus_vesa_unimplemented
1673   ;; 10h
1674   dw cirrus_vesa_10h
1675 
1676 
1677 
1678 ASM_END
1679 
1680 #ifdef CIRRUS_VESA3_PMINFO
1681 ASM_START
1682 cirrus_vesa_pminfo:
1683   /* + 0 */
1684   .byte 0x50,0x4d,0x49,0x44 ;; signature[4]
1685   /* + 4 */
1686   dw cirrus_vesa_pmbios_entry ;; entry_bios
1687   dw cirrus_vesa_pmbios_init  ;; entry_init
1688   /* + 8 */
1689 cirrus_vesa_sel0000_data:
1690   dw 0x0000 ;; sel_00000
1691 cirrus_vesa_selA000_data:
1692   dw 0xA000 ;; sel_A0000
1693   /* +12 */
1694 cirrus_vesa_selB000_data:
1695   dw 0xB000 ;; sel_B0000
1696 cirrus_vesa_selB800_data:
1697   dw 0xB800 ;; sel_B8000
1698   /* +16 */
1699 cirrus_vesa_selC000_data:
1700   dw 0xC000 ;; sel_C0000
1701 cirrus_vesa_is_protected_mode:
1702   ;; protected mode flag and checksum
1703   dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \
1704      + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01
1705 ASM_END
1706 #endif // CIRRUS_VESA3_PMINFO
1707 
1708 
1709 #ifdef CIRRUS_DEBUG
1710 static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
1711   Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
1712 {
1713  if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05))
1714   printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
1715 }
1716 #endif
1717