Home | History | Annotate | Download | only in vgabios
      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, write to the Free Software
     18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     19 //
     20 
     21 //#define CIRRUS_VESA3_PMINFO
     22 #ifdef VBE
     23 #undef CIRRUS_VESA3_PMINFO
     24 #endif
     25 
     26 #define PM_BIOSMEM_CURRENT_MODE 0x449
     27 #define PM_BIOSMEM_CRTC_ADDRESS 0x463
     28 #define PM_BIOSMEM_VBE_MODE 0x4BA
     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, #0x100 ;; 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   mov ax, #0x1013 ;; vendor Cirrus
    952   call _pci_get_lfb_addr
    953   stosw
    954   or ax, ax
    955   jz cirrus_vesa_01h_4
    956   push di
    957   mov di, bp
    958  db 0x26 ;; es:
    959   mov ax, [di]
    960   or ax, #0x0080 ;; mode bit 7:LFB
    961   stosw
    962   pop di
    963 cirrus_vesa_01h_4:
    964 
    965   xor ax, ax
    966   stosw ; reserved
    967   stosw ; reserved
    968   stosw ; reserved
    969 
    970   mov ax, #0x004F
    971   mov di, bp
    972   pop bx
    973   pop dx
    974   pop cx
    975   pop si
    976   pop ds
    977 
    978   test cx, #0x4000 ;; LFB flag
    979   jz cirrus_vesa_01h_5
    980   push cx
    981  db 0x26 ;; es:
    982   mov cx, [di]
    983   cmp cx, #0x0080 ;; is LFB supported?
    984   jnz cirrus_vesa_01h_6
    985   mov ax, #0x014F ;; error - no LFB
    986 cirrus_vesa_01h_6:
    987   pop cx
    988 cirrus_vesa_01h_5:
    989   ret
    990 
    991 cirrus_vesa_02h:
    992   ;; XXX support CRTC registers
    993   test bx, #0x3e00
    994   jnz cirrus_vesa_02h_2 ;; unknown flags
    995   mov ax, bx
    996   and ax, #0x1ff ;; bit 8-0 mode
    997   cmp ax, #0x100 ;; legacy VGA mode
    998   jb cirrus_vesa_02h_legacy
    999   call cirrus_vesamode_to_mode
   1000   cmp ax, #0xffff
   1001   jnz cirrus_vesa_02h_1
   1002 cirrus_vesa_02h_2:
   1003   jmp cirrus_vesa_unimplemented
   1004 cirrus_vesa_02h_legacy:
   1005 #ifdef CIRRUS_VESA3_PMINFO
   1006  db 0x2e ;; cs:
   1007   cmp byte ptr [cirrus_vesa_is_protected_mode], #0
   1008   jnz cirrus_vesa_02h_2
   1009 #endif // CIRRUS_VESA3_PMINFO
   1010   int #0x10
   1011   mov ax, #0x004F
   1012   ret
   1013 cirrus_vesa_02h_1:
   1014   push si
   1015   push ax
   1016   call cirrus_get_modeentry_nomask
   1017   call cirrus_switch_mode
   1018   test bx, #0x4000 ;; LFB
   1019   jnz cirrus_vesa_02h_3
   1020   call cirrus_enable_16k_granularity
   1021 cirrus_vesa_02h_3:
   1022   test bx, #0x8000 ;; no clear
   1023   jnz cirrus_vesa_02h_4
   1024   push ax
   1025   xor ax,ax
   1026   call cirrus_clear_vram
   1027   pop ax
   1028 cirrus_vesa_02h_4:
   1029   pop ax
   1030   push ds
   1031 #ifdef CIRRUS_VESA3_PMINFO
   1032  db 0x2e ;; cs:
   1033   mov si, [cirrus_vesa_sel0000_data]
   1034 #else
   1035   xor si, si
   1036 #endif
   1037   mov ds, si
   1038   mov [PM_BIOSMEM_CURRENT_MODE], al
   1039   mov [PM_BIOSMEM_VBE_MODE], bx
   1040   pop ds
   1041   pop si
   1042   mov ax, #0x004F
   1043   ret
   1044 
   1045 cirrus_vesa_03h:
   1046   push ds
   1047 #ifdef CIRRUS_VESA3_PMINFO
   1048  db 0x2e ;; cs:
   1049   mov ax, [cirrus_vesa_sel0000_data]
   1050 #else
   1051   xor ax, ax
   1052 #endif
   1053   mov  ds, ax
   1054   mov  bx, # PM_BIOSMEM_VBE_MODE
   1055   mov  ax, [bx]
   1056   mov  bx, ax
   1057   test bx, bx
   1058   jnz   cirrus_vesa_03h_1
   1059   mov  bx, # PM_BIOSMEM_CURRENT_MODE
   1060   mov  al, [bx]
   1061   mov  bl, al
   1062   xor  bh, bh
   1063 cirrus_vesa_03h_1:
   1064   mov  ax, #0x004f
   1065   pop  ds
   1066   ret
   1067 
   1068 cirrus_vesa_05h_farentry:
   1069   call cirrus_vesa_05h
   1070   retf
   1071 
   1072 cirrus_vesa_05h:
   1073   cmp bl, #0x01
   1074   ja cirrus_vesa_05h_1
   1075   cmp bh, #0x00
   1076   jz cirrus_vesa_05h_setmempage
   1077   cmp bh, #0x01
   1078   jz cirrus_vesa_05h_getmempage
   1079 cirrus_vesa_05h_1:
   1080   jmp cirrus_vesa_unimplemented
   1081 cirrus_vesa_05h_setmempage:
   1082   or dh, dh ; address must be < 0x100
   1083   jnz cirrus_vesa_05h_1
   1084   push dx
   1085   mov al, bl ;; bl=bank number
   1086   add al, #0x09
   1087   mov ah, dl ;; dx=window address in granularity
   1088   mov dx, #0x3ce
   1089   out dx, ax
   1090   pop dx
   1091   mov ax, #0x004F
   1092   ret
   1093 cirrus_vesa_05h_getmempage:
   1094   mov al, bl ;; bl=bank number
   1095   add al, #0x09
   1096   mov dx, #0x3ce
   1097   out dx, al
   1098   inc dx
   1099   in al, dx
   1100   xor dx, dx
   1101   mov dl, al ;; dx=window address in granularity
   1102   mov ax, #0x004F
   1103   ret
   1104 
   1105 cirrus_vesa_06h:
   1106   mov  ax, cx
   1107   cmp  bl, #0x01
   1108   je   cirrus_vesa_06h_3
   1109   cmp  bl, #0x02
   1110   je   cirrus_vesa_06h_2
   1111   jb   cirrus_vesa_06h_1
   1112   mov  ax, #0x0100
   1113   ret
   1114 cirrus_vesa_06h_1:
   1115   call cirrus_get_bpp_bytes
   1116   mov  bl, al
   1117   xor  bh, bh
   1118   mov  ax, cx
   1119   mul  bx
   1120 cirrus_vesa_06h_2:
   1121   call cirrus_set_line_offset
   1122 cirrus_vesa_06h_3:
   1123   call cirrus_get_bpp_bytes
   1124   mov  bl, al
   1125   xor  bh, bh
   1126   xor  dx, dx
   1127   call cirrus_get_line_offset
   1128   push ax
   1129   div  bx
   1130   mov  cx, ax
   1131   pop  bx
   1132   call cirrus_extbios_85h ;; al=vram in 64k
   1133   xor  dx, dx
   1134   mov  dl, al
   1135   xor  ax, ax
   1136   div  bx
   1137   mov  dx, ax
   1138   mov  ax, #0x004f
   1139   ret
   1140 
   1141 cirrus_vesa_07h:
   1142   cmp  bl, #0x80
   1143   je   cirrus_vesa_07h_1
   1144   cmp  bl, #0x01
   1145   je   cirrus_vesa_07h_2
   1146   jb   cirrus_vesa_07h_1
   1147   mov  ax, #0x0100
   1148   ret
   1149 cirrus_vesa_07h_1:
   1150   push dx
   1151   call cirrus_get_bpp_bytes
   1152   mov  bl, al
   1153   xor  bh, bh
   1154   mov  ax, cx
   1155   mul  bx
   1156   pop  bx
   1157   push ax
   1158   call cirrus_get_line_offset
   1159   mul  bx
   1160   pop  bx
   1161   add  ax, bx
   1162   jnc  cirrus_vesa_07h_3
   1163   inc  dx
   1164 cirrus_vesa_07h_3:
   1165   push dx
   1166   and  dx, #0x0003
   1167   mov  bx, #0x04
   1168   div  bx
   1169   pop  dx
   1170   shr  dx, #2
   1171   call cirrus_set_start_addr
   1172   mov  ax, #0x004f
   1173   ret
   1174 cirrus_vesa_07h_2:
   1175   call cirrus_get_start_addr
   1176   shl  dx, #2
   1177   push dx
   1178   mov  bx, #0x04
   1179   mul  bx
   1180   pop  bx
   1181   or   dx, bx
   1182   push ax
   1183   call cirrus_get_line_offset
   1184   mov  bx, ax
   1185   pop  ax
   1186   div  bx
   1187   push ax
   1188   push dx
   1189   call cirrus_get_bpp_bytes
   1190   mov  bl, al
   1191   xor  bh, bh
   1192   pop  ax
   1193   xor  dx, dx
   1194   div  bx
   1195   mov  cx, ax
   1196   pop  dx
   1197   mov  ax, #0x004f
   1198   ret
   1199 
   1200 cirrus_vesa_10h:
   1201   cmp bl, #0x00
   1202   jne cirrus_vesa_10h_01
   1203   mov bx, #0x0f30
   1204   mov ax, #0x004f
   1205   ret
   1206 cirrus_vesa_10h_01:
   1207   cmp bl, #0x01
   1208   jne cirrus_vesa_10h_02
   1209   push dx
   1210   push ds
   1211   mov dx, #0x40
   1212   mov ds, dx
   1213   mov [0xb9], bh
   1214   pop ds
   1215   pop dx
   1216   mov ax, #0x004f
   1217   ret
   1218 cirrus_vesa_10h_02:
   1219   cmp bl, #0x02
   1220   jne cirrus_vesa_unimplemented
   1221   push dx
   1222   push ds
   1223   mov dx, #0x40
   1224   mov ds, dx
   1225   mov bh, [0xb9]
   1226   pop ds
   1227   pop dx
   1228   mov ax, #0x004f
   1229   ret
   1230 
   1231 cirrus_vesa_unimplemented:
   1232   mov ax, #0x014F ;; not implemented
   1233   ret
   1234 
   1235 
   1236 ;; in ax:vesamode, out ax:cirrusmode
   1237 cirrus_vesamode_to_mode:
   1238   push ds
   1239   push cx
   1240   push si
   1241   push cs
   1242   pop ds
   1243   mov cx, #0xffff
   1244   mov si, #_cirrus_vesa_modelist
   1245 cvtm_1:
   1246   cmp [si],ax
   1247   jz cvtm_2
   1248   cmp [si],cx
   1249   jz cvtm_2
   1250   add si, #4
   1251   jmp cvtm_1
   1252 cvtm_2:
   1253   mov ax,[si+2]
   1254   pop si
   1255   pop cx
   1256   pop ds
   1257   ret
   1258 
   1259   ; cirrus_get_crtc
   1260   ;; NOTE - may be called in protected mode
   1261 cirrus_get_crtc:
   1262   push ds
   1263   push ax
   1264   mov  dx, #0x3cc
   1265   in   al, dx
   1266   and  al, #0x01
   1267   shl  al, #5
   1268   mov  dx, #0x3b4
   1269   add  dl, al
   1270   pop  ax
   1271   pop  ds
   1272   ret
   1273 
   1274 ;; in - al:mode, out - cflag:result, si:table, ax:destroyed
   1275 cirrus_get_modeentry:
   1276   and al, #0x7f
   1277 cirrus_get_modeentry_nomask:
   1278   mov si, #_cirrus_modes
   1279 cgm_1:
   1280  db 0x2e ;; cs:
   1281   mov ah, [si]
   1282   cmp al, ah
   1283   jz cgm_2
   1284   cmp ah, #0xff
   1285   jz cgm_4
   1286   add si, # CIRRUS_MODE_SIZE
   1287   jmp cgm_1
   1288 cgm_4:
   1289   xor si, si
   1290   stc ;; video mode is not supported
   1291   jmp cgm_3
   1292 cgm_2:
   1293   clc ;; video mode is supported
   1294 cgm_3:
   1295   ret
   1296 
   1297 ;; out - al:bytes per pixel
   1298 cirrus_get_bpp_bytes:
   1299   push dx
   1300   mov  dx, #0x03c4
   1301   mov  al, #0x07
   1302   out  dx, al
   1303   inc  dx
   1304   in   al, dx
   1305   and  al, #0x0e
   1306   cmp  al, #0x06
   1307   jne  cirrus_get_bpp_bytes_1
   1308   and  al, #0x02
   1309 cirrus_get_bpp_bytes_1:
   1310   shr  al, #1
   1311   cmp  al, #0x04
   1312   je  cirrus_get_bpp_bytes_2
   1313   inc  al
   1314 cirrus_get_bpp_bytes_2:
   1315   pop  dx
   1316   ret
   1317 
   1318 ;; in - ax: new line offset
   1319 cirrus_set_line_offset:
   1320   shr  ax, #3
   1321   push ax
   1322   call cirrus_get_crtc
   1323   mov  al, #0x13
   1324   out  dx, al
   1325   inc  dx
   1326   pop  ax
   1327   out  dx, al
   1328   dec  dx
   1329   mov  al, #0x1b
   1330   out  dx, al
   1331   inc  dx
   1332   shl  ah, #4
   1333   in   al, dx
   1334   and  al, #ef
   1335   or   al, ah
   1336   out  dx, al
   1337   ret
   1338 
   1339 ;; out - ax: active line offset
   1340 cirrus_get_line_offset:
   1341   push dx
   1342   push bx
   1343   call cirrus_get_crtc
   1344   mov  al, #0x13
   1345   out  dx, al
   1346   inc  dx
   1347   in   al, dx
   1348   mov  bl, al
   1349   dec  dx
   1350   mov  al, #0x1b
   1351   out  dx, al
   1352   inc  dx
   1353   in   al, dx
   1354   mov  ah, al
   1355   shr  ah, #4
   1356   and  ah, #0x01
   1357   mov  al, bl
   1358   shl  ax, #3
   1359   pop  bx
   1360   pop  dx
   1361   ret
   1362 
   1363 ;; in - si: table
   1364 ;; out - ax: line offset for mode
   1365 cirrus_get_line_offset_entry:
   1366   push bx
   1367   mov  bx, [si+14] ;; crtc table
   1368   push bx
   1369 offset_loop1:
   1370   mov  ax, [bx]
   1371   cmp  al, #0x13
   1372   je   offset_found1
   1373   inc  bx
   1374   inc  bx
   1375   jnz  offset_loop1
   1376 offset_found1:
   1377   xor  al, al
   1378   shr  ax, #5
   1379   pop  bx
   1380   push ax
   1381 offset_loop2:
   1382   mov  ax, [bx]
   1383   cmp  al, #0x1b
   1384   je offset_found2
   1385   inc  bx
   1386   inc  bx
   1387   jnz offset_loop2
   1388 offset_found2:
   1389   pop  bx
   1390   and  ax, #0x1000
   1391   shr  ax, #1
   1392   or   ax, bx
   1393   pop  bx
   1394   ret
   1395 
   1396 ;; in - new address in DX:AX
   1397 cirrus_set_start_addr:
   1398   push bx
   1399   push dx
   1400   push ax
   1401   call cirrus_get_crtc
   1402   mov  al, #0x0d
   1403   out  dx, al
   1404   inc  dx
   1405   pop  ax
   1406   out  dx, al
   1407   dec  dx
   1408   mov  al, #0x0c
   1409   out  dx, al
   1410   inc  dx
   1411   mov  al, ah
   1412   out  dx, al
   1413   dec  dx
   1414   mov  al, #0x1d
   1415   out  dx, al
   1416   inc  dx
   1417   in   al, dx
   1418   and  al, #0x7f
   1419   pop  bx
   1420   mov  ah, bl
   1421   shl  bl, #4
   1422   and  bl, #0x80
   1423   or   al, bl
   1424   out  dx, al
   1425   dec  dx
   1426   mov  bl, ah
   1427   and  ah, #0x01
   1428   shl  bl, #1
   1429   and  bl, #0x0c
   1430   or   ah, bl
   1431   mov  al, #0x1b
   1432   out  dx, al
   1433   inc  dx
   1434   in   al, dx
   1435   and  al, #0xf2
   1436   or   al, ah
   1437   out  dx, al
   1438   pop  bx
   1439   ret
   1440 
   1441 ;; out - current address in DX:AX
   1442 cirrus_get_start_addr:
   1443   push bx
   1444   call cirrus_get_crtc
   1445   mov  al, #0x0c
   1446   out  dx, al
   1447   inc  dx
   1448   in   al, dx
   1449   mov  ah, al
   1450   dec  dx
   1451   mov  al, #0x0d
   1452   out  dx, al
   1453   inc  dx
   1454   in   al, dx
   1455   push ax
   1456   dec  dx
   1457   mov  al, #0x1b
   1458   out  dx, al
   1459   inc  dx
   1460   in   al, dx
   1461   dec  dx
   1462   mov  bl, al
   1463   and  al, #0x01
   1464   and  bl, #0x0c
   1465   shr  bl, #1
   1466   or   bl, al
   1467   mov  al, #0x1d
   1468   out  dx, al
   1469   inc  dx
   1470   in   al, dx
   1471   and  al, #0x80
   1472   shr  al, #4
   1473   or   bl, al
   1474   mov  dl, bl
   1475   xor  dh, dh
   1476   pop  ax
   1477   pop  bx
   1478   ret
   1479 
   1480 cirrus_clear_vram:
   1481   pusha
   1482   push es
   1483   mov si, ax
   1484 
   1485   call cirrus_enable_16k_granularity
   1486   call cirrus_extbios_85h
   1487   shl al, #2
   1488   mov bl, al
   1489   xor ah,ah
   1490 cirrus_clear_vram_1:
   1491   mov al, #0x09
   1492   mov dx, #0x3ce
   1493   out dx, ax
   1494   push ax
   1495   mov cx, #0xa000
   1496   mov es, cx
   1497   xor di, di
   1498   mov ax, si
   1499   mov cx, #8192
   1500   cld
   1501   rep
   1502       stosw
   1503   pop ax
   1504   inc ah
   1505   cmp ah, bl
   1506   jne cirrus_clear_vram_1
   1507 
   1508   xor ah,ah
   1509   mov dx, #0x3ce
   1510   out dx, ax
   1511 
   1512   pop es
   1513   popa
   1514   ret
   1515 
   1516 cirrus_extbios_handlers:
   1517   ;; 80h
   1518   dw cirrus_extbios_80h
   1519   dw cirrus_extbios_81h
   1520   dw cirrus_extbios_82h
   1521   dw cirrus_extbios_unimplemented
   1522   ;; 84h
   1523   dw cirrus_extbios_unimplemented
   1524   dw cirrus_extbios_85h
   1525   dw cirrus_extbios_unimplemented
   1526   dw cirrus_extbios_unimplemented
   1527   ;; 88h
   1528   dw cirrus_extbios_unimplemented
   1529   dw cirrus_extbios_unimplemented
   1530   dw cirrus_extbios_unimplemented
   1531   dw cirrus_extbios_unimplemented
   1532   ;; 8Ch
   1533   dw cirrus_extbios_unimplemented
   1534   dw cirrus_extbios_unimplemented
   1535   dw cirrus_extbios_unimplemented
   1536   dw cirrus_extbios_unimplemented
   1537   ;; 90h
   1538   dw cirrus_extbios_unimplemented
   1539   dw cirrus_extbios_unimplemented
   1540   dw cirrus_extbios_unimplemented
   1541   dw cirrus_extbios_unimplemented
   1542   ;; 94h
   1543   dw cirrus_extbios_unimplemented
   1544   dw cirrus_extbios_unimplemented
   1545   dw cirrus_extbios_unimplemented
   1546   dw cirrus_extbios_unimplemented
   1547   ;; 98h
   1548   dw cirrus_extbios_unimplemented
   1549   dw cirrus_extbios_unimplemented
   1550   dw cirrus_extbios_9Ah
   1551   dw cirrus_extbios_unimplemented
   1552   ;; 9Ch
   1553   dw cirrus_extbios_unimplemented
   1554   dw cirrus_extbios_unimplemented
   1555   dw cirrus_extbios_unimplemented
   1556   dw cirrus_extbios_unimplemented
   1557   ;; A0h
   1558   dw cirrus_extbios_A0h
   1559   dw cirrus_extbios_A1h
   1560   dw cirrus_extbios_A2h
   1561   dw cirrus_extbios_unimplemented
   1562   ;; A4h
   1563   dw cirrus_extbios_unimplemented
   1564   dw cirrus_extbios_unimplemented
   1565   dw cirrus_extbios_unimplemented
   1566   dw cirrus_extbios_unimplemented
   1567   ;; A8h
   1568   dw cirrus_extbios_unimplemented
   1569   dw cirrus_extbios_unimplemented
   1570   dw cirrus_extbios_unimplemented
   1571   dw cirrus_extbios_unimplemented
   1572   ;; ACh
   1573   dw cirrus_extbios_unimplemented
   1574   dw cirrus_extbios_unimplemented
   1575   dw cirrus_extbios_AEh
   1576   dw cirrus_extbios_unimplemented
   1577 
   1578 cirrus_vesa_handlers:
   1579   ;; 00h
   1580   dw cirrus_vesa_00h
   1581   dw cirrus_vesa_01h
   1582   dw cirrus_vesa_02h
   1583   dw cirrus_vesa_03h
   1584   ;; 04h
   1585   dw cirrus_vesa_unimplemented
   1586   dw cirrus_vesa_05h
   1587   dw cirrus_vesa_06h
   1588   dw cirrus_vesa_07h
   1589   ;; 08h
   1590   dw cirrus_vesa_unimplemented
   1591   dw cirrus_vesa_unimplemented
   1592   dw cirrus_vesa_unimplemented
   1593   dw cirrus_vesa_unimplemented
   1594   ;; 0Ch
   1595   dw cirrus_vesa_unimplemented
   1596   dw cirrus_vesa_unimplemented
   1597   dw cirrus_vesa_unimplemented
   1598   dw cirrus_vesa_unimplemented
   1599   ;; 10h
   1600   dw cirrus_vesa_10h
   1601 
   1602 
   1603 ASM_END
   1604 
   1605 #ifdef CIRRUS_VESA3_PMINFO
   1606 ASM_START
   1607 cirrus_vesa_pminfo:
   1608   /* + 0 */
   1609   .byte 0x50,0x4d,0x49,0x44 ;; signature[4]
   1610   /* + 4 */
   1611   dw cirrus_vesa_pmbios_entry ;; entry_bios
   1612   dw cirrus_vesa_pmbios_init  ;; entry_init
   1613   /* + 8 */
   1614 cirrus_vesa_sel0000_data:
   1615   dw 0x0000 ;; sel_00000
   1616 cirrus_vesa_selA000_data:
   1617   dw 0xA000 ;; sel_A0000
   1618   /* +12 */
   1619 cirrus_vesa_selB000_data:
   1620   dw 0xB000 ;; sel_B0000
   1621 cirrus_vesa_selB800_data:
   1622   dw 0xB800 ;; sel_B8000
   1623   /* +16 */
   1624 cirrus_vesa_selC000_data:
   1625   dw 0xC000 ;; sel_C0000
   1626 cirrus_vesa_is_protected_mode:
   1627   ;; protected mode flag and checksum
   1628   dw (~((0xf2 + (cirrus_vesa_pmbios_entry >> 8) + (cirrus_vesa_pmbios_entry) \
   1629      + (cirrus_vesa_pmbios_init >> 8) + (cirrus_vesa_pmbios_init)) & 0xff) << 8) + 0x01
   1630 ASM_END
   1631 #endif // CIRRUS_VESA3_PMINFO
   1632 
   1633 
   1634 #ifdef CIRRUS_DEBUG
   1635 static void cirrus_debugmsg(DI, SI, BP, SP, BX, DX, CX, AX, DS, ES, FLAGS)
   1636   Bit16u DI, SI, BP, SP, BX, DX, CX, AX, ES, DS, FLAGS;
   1637 {
   1638  if((GET_AH()!=0x0E)&&(GET_AH()!=0x02)&&(GET_AH()!=0x09)&&(AX!=0x4F05))
   1639   printf("vgabios call ah%02x al%02x bx%04x cx%04x dx%04x\n",GET_AH(),GET_AL(),BX,CX,DX);
   1640 }
   1641 #endif
   1642