Statistics
| Branch: | Revision:

root / hw / vga.c @ 4f2ac237

History | View | Annotate | Download (52 kB)

1
/*
2
 * QEMU VGA Emulator.
3
 * 
4
 * Copyright (c) 2003 Fabrice Bellard
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "vl.h"
25

    
26
//#define DEBUG_VGA
27
//#define DEBUG_VGA_MEM
28
//#define DEBUG_VGA_REG
29

    
30
//#define DEBUG_S3
31
//#define DEBUG_BOCHS_VBE
32

    
33
/* S3 VGA is deprecated - another graphic card will be emulated */
34
//#define CONFIG_S3VGA
35

    
36
#define MSR_COLOR_EMULATION 0x01
37
#define MSR_PAGE_SELECT     0x20
38

    
39
#define ST01_V_RETRACE      0x08
40
#define ST01_DISP_ENABLE    0x01
41

    
42
/* bochs VBE support */
43
#define CONFIG_BOCHS_VBE
44

    
45
#define VBE_DISPI_MAX_XRES              1024
46
#define VBE_DISPI_MAX_YRES              768
47

    
48
#define VBE_DISPI_INDEX_ID              0x0
49
#define VBE_DISPI_INDEX_XRES            0x1
50
#define VBE_DISPI_INDEX_YRES            0x2
51
#define VBE_DISPI_INDEX_BPP             0x3
52
#define VBE_DISPI_INDEX_ENABLE          0x4
53
#define VBE_DISPI_INDEX_BANK            0x5
54
#define VBE_DISPI_INDEX_VIRT_WIDTH      0x6
55
#define VBE_DISPI_INDEX_VIRT_HEIGHT     0x7
56
#define VBE_DISPI_INDEX_X_OFFSET        0x8
57
#define VBE_DISPI_INDEX_Y_OFFSET        0x9
58
#define VBE_DISPI_INDEX_NB              0xa
59
      
60
#define VBE_DISPI_ID0                   0xB0C0
61
#define VBE_DISPI_ID1                   0xB0C1
62
#define VBE_DISPI_ID2                   0xB0C2
63
  
64
#define VBE_DISPI_DISABLED              0x00
65
#define VBE_DISPI_ENABLED               0x01
66
#define VBE_DISPI_LFB_ENABLED           0x40
67
#define VBE_DISPI_NOCLEARMEM            0x80
68
  
69
#define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
70

    
71
typedef struct VGAState {
72
    uint8_t *vram_ptr;
73
    unsigned long vram_offset;
74
    unsigned int vram_size;
75
    uint32_t latch;
76
    uint8_t sr_index;
77
    uint8_t sr[8];
78
    uint8_t gr_index;
79
    uint8_t gr[16];
80
    uint8_t ar_index;
81
    uint8_t ar[21];
82
    int ar_flip_flop;
83
    uint8_t cr_index;
84
    uint8_t cr[256]; /* CRT registers */
85
    uint8_t msr; /* Misc Output Register */
86
    uint8_t fcr; /* Feature Control Register */
87
    uint8_t st00; /* status 0 */
88
    uint8_t st01; /* status 1 */
89
    uint8_t dac_state;
90
    uint8_t dac_sub_index;
91
    uint8_t dac_read_index;
92
    uint8_t dac_write_index;
93
    uint8_t dac_cache[3]; /* used when writing */
94
    uint8_t palette[768];
95
    int32_t bank_offset;
96
#ifdef CONFIG_BOCHS_VBE
97
    uint16_t vbe_index;
98
    uint16_t vbe_regs[VBE_DISPI_INDEX_NB];
99
    uint32_t vbe_start_addr;
100
    uint32_t vbe_line_offset;
101
    uint32_t vbe_bank_mask;
102
#endif
103
    /* display refresh support */
104
    DisplayState *ds;
105
    uint32_t font_offsets[2];
106
    int graphic_mode;
107
    uint8_t shift_control;
108
    uint8_t double_scan;
109
    uint32_t line_offset;
110
    uint32_t line_compare;
111
    uint32_t start_addr;
112
    uint8_t last_cw, last_ch;
113
    uint32_t last_width, last_height; /* in chars or pixels */
114
    uint32_t last_scr_width, last_scr_height; /* in pixels */
115
    uint8_t cursor_start, cursor_end;
116
    uint32_t cursor_offset;
117
    unsigned int (*rgb_to_pixel)(unsigned int r, unsigned int g, unsigned b);
118
    /* tell for each page if it has been updated since the last time */
119
    uint32_t last_palette[256];
120
#define CH_ATTR_SIZE (160 * 100)
121
    uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
122
} VGAState;
123

    
124
/* force some bits to zero */
125
static const uint8_t sr_mask[8] = {
126
    (uint8_t)~0xfc,
127
    (uint8_t)~0xc2,
128
    (uint8_t)~0xf0,
129
    (uint8_t)~0xc0,
130
    (uint8_t)~0xf1,
131
    (uint8_t)~0xff,
132
    (uint8_t)~0xff,
133
    (uint8_t)~0x00,
134
};
135

    
136
static const uint8_t gr_mask[16] = {
137
    (uint8_t)~0xf0, /* 0x00 */
138
    (uint8_t)~0xf0, /* 0x01 */
139
    (uint8_t)~0xf0, /* 0x02 */
140
    (uint8_t)~0xe0, /* 0x03 */
141
    (uint8_t)~0xfc, /* 0x04 */
142
    (uint8_t)~0x84, /* 0x05 */
143
    (uint8_t)~0xf0, /* 0x06 */
144
    (uint8_t)~0xf0, /* 0x07 */
145
    (uint8_t)~0x00, /* 0x08 */
146
    (uint8_t)~0xff, /* 0x09 */
147
    (uint8_t)~0xff, /* 0x0a */
148
    (uint8_t)~0xff, /* 0x0b */
149
    (uint8_t)~0xff, /* 0x0c */
150
    (uint8_t)~0xff, /* 0x0d */
151
    (uint8_t)~0xff, /* 0x0e */
152
    (uint8_t)~0xff, /* 0x0f */
153
};
154

    
155
#define cbswap_32(__x) \
156
((uint32_t)( \
157
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
158
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
159
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
160
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
161

    
162
#ifdef WORDS_BIGENDIAN
163
#define PAT(x) cbswap_32(x)
164
#else
165
#define PAT(x) (x)
166
#endif
167

    
168
#ifdef WORDS_BIGENDIAN
169
#define BIG 1
170
#else
171
#define BIG 0
172
#endif
173

    
174
#ifdef WORDS_BIGENDIAN
175
#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
176
#else
177
#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
178
#endif
179

    
180
static const uint32_t mask16[16] = {
181
    PAT(0x00000000),
182
    PAT(0x000000ff),
183
    PAT(0x0000ff00),
184
    PAT(0x0000ffff),
185
    PAT(0x00ff0000),
186
    PAT(0x00ff00ff),
187
    PAT(0x00ffff00),
188
    PAT(0x00ffffff),
189
    PAT(0xff000000),
190
    PAT(0xff0000ff),
191
    PAT(0xff00ff00),
192
    PAT(0xff00ffff),
193
    PAT(0xffff0000),
194
    PAT(0xffff00ff),
195
    PAT(0xffffff00),
196
    PAT(0xffffffff),
197
};
198

    
199
#undef PAT
200

    
201
#ifdef WORDS_BIGENDIAN
202
#define PAT(x) (x)
203
#else
204
#define PAT(x) cbswap_32(x)
205
#endif
206

    
207
static const uint32_t dmask16[16] = {
208
    PAT(0x00000000),
209
    PAT(0x000000ff),
210
    PAT(0x0000ff00),
211
    PAT(0x0000ffff),
212
    PAT(0x00ff0000),
213
    PAT(0x00ff00ff),
214
    PAT(0x00ffff00),
215
    PAT(0x00ffffff),
216
    PAT(0xff000000),
217
    PAT(0xff0000ff),
218
    PAT(0xff00ff00),
219
    PAT(0xff00ffff),
220
    PAT(0xffff0000),
221
    PAT(0xffff00ff),
222
    PAT(0xffffff00),
223
    PAT(0xffffffff),
224
};
225

    
226
static const uint32_t dmask4[4] = {
227
    PAT(0x00000000),
228
    PAT(0x0000ffff),
229
    PAT(0xffff0000),
230
    PAT(0xffffffff),
231
};
232

    
233
static uint32_t expand4[256];
234
static uint16_t expand2[256];
235
static uint8_t expand4to8[16];
236

    
237
VGAState vga_state;
238
int vga_io_memory;
239

    
240
static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
241
{
242
    VGAState *s = opaque;
243
    int val, index;
244

    
245
    /* check port range access depending on color/monochrome mode */
246
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
247
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
248
        val = 0xff;
249
    } else {
250
        switch(addr) {
251
        case 0x3c0:
252
            if (s->ar_flip_flop == 0) {
253
                val = s->ar_index;
254
            } else {
255
                val = 0;
256
            }
257
            break;
258
        case 0x3c1:
259
            index = s->ar_index & 0x1f;
260
            if (index < 21) 
261
                val = s->ar[index];
262
            else
263
                val = 0;
264
            break;
265
        case 0x3c2:
266
            val = s->st00;
267
            break;
268
        case 0x3c4:
269
            val = s->sr_index;
270
            break;
271
        case 0x3c5:
272
            val = s->sr[s->sr_index];
273
#ifdef DEBUG_VGA_REG
274
            printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
275
#endif
276
            break;
277
        case 0x3c7:
278
            val = s->dac_state;
279
            break;
280
        case 0x3c9:
281
            val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
282
            if (++s->dac_sub_index == 3) {
283
                s->dac_sub_index = 0;
284
                s->dac_read_index++;
285
            }
286
            break;
287
        case 0x3ca:
288
            val = s->fcr;
289
            break;
290
        case 0x3cc:
291
            val = s->msr;
292
            break;
293
        case 0x3ce:
294
            val = s->gr_index;
295
            break;
296
        case 0x3cf:
297
            val = s->gr[s->gr_index];
298
#ifdef DEBUG_VGA_REG
299
            printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
300
#endif
301
            break;
302
        case 0x3b4:
303
        case 0x3d4:
304
            val = s->cr_index;
305
            break;
306
        case 0x3b5:
307
        case 0x3d5:
308
            val = s->cr[s->cr_index];
309
#ifdef DEBUG_VGA_REG
310
            printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
311
#endif
312
#ifdef DEBUG_S3
313
            if (s->cr_index >= 0x20)
314
                printf("S3: CR read index=0x%x val=0x%x\n",
315
                       s->cr_index, val);
316
#endif
317
            break;
318
        case 0x3ba:
319
        case 0x3da:
320
            /* just toggle to fool polling */
321
            s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
322
            val = s->st01;
323
            s->ar_flip_flop = 0;
324
            break;
325
        default:
326
            val = 0x00;
327
            break;
328
        }
329
    }
330
#if defined(DEBUG_VGA)
331
    printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
332
#endif
333
    return val;
334
}
335

    
336
static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
337
{
338
    VGAState *s = opaque;
339
    int index;
340

    
341
    /* check port range access depending on color/monochrome mode */
342
    if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
343
        (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
344
        return;
345

    
346
#ifdef DEBUG_VGA
347
    printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
348
#endif
349

    
350
    switch(addr) {
351
    case 0x3c0:
352
        if (s->ar_flip_flop == 0) {
353
            val &= 0x3f;
354
            s->ar_index = val;
355
        } else {
356
            index = s->ar_index & 0x1f;
357
            switch(index) {
358
            case 0x00 ... 0x0f:
359
                s->ar[index] = val & 0x3f;
360
                break;
361
            case 0x10:
362
                s->ar[index] = val & ~0x10;
363
                break;
364
            case 0x11:
365
                s->ar[index] = val;
366
                break;
367
            case 0x12:
368
                s->ar[index] = val & ~0xc0;
369
                break;
370
            case 0x13:
371
                s->ar[index] = val & ~0xf0;
372
                break;
373
            case 0x14:
374
                s->ar[index] = val & ~0xf0;
375
                break;
376
            default:
377
                break;
378
            }
379
        }
380
        s->ar_flip_flop ^= 1;
381
        break;
382
    case 0x3c2:
383
        s->msr = val & ~0x10;
384
        break;
385
    case 0x3c4:
386
        s->sr_index = val & 7;
387
        break;
388
    case 0x3c5:
389
#ifdef DEBUG_VGA_REG
390
        printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
391
#endif
392
        s->sr[s->sr_index] = val & sr_mask[s->sr_index];
393
        break;
394
    case 0x3c7:
395
        s->dac_read_index = val;
396
        s->dac_sub_index = 0;
397
        s->dac_state = 3;
398
        break;
399
    case 0x3c8:
400
        s->dac_write_index = val;
401
        s->dac_sub_index = 0;
402
        s->dac_state = 0;
403
        break;
404
    case 0x3c9:
405
        s->dac_cache[s->dac_sub_index] = val;
406
        if (++s->dac_sub_index == 3) {
407
            memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
408
            s->dac_sub_index = 0;
409
            s->dac_write_index++;
410
        }
411
        break;
412
    case 0x3ce:
413
        s->gr_index = val & 0x0f;
414
        break;
415
    case 0x3cf:
416
#ifdef DEBUG_VGA_REG
417
        printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
418
#endif
419
        s->gr[s->gr_index] = val & gr_mask[s->gr_index];
420
        break;
421
    case 0x3b4:
422
    case 0x3d4:
423
        s->cr_index = val;
424
        break;
425
    case 0x3b5:
426
    case 0x3d5:
427
#ifdef DEBUG_VGA_REG
428
        printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
429
#endif
430
        /* handle CR0-7 protection */
431
        if ((s->cr[11] & 0x80) && s->cr_index <= 7) {
432
            /* can always write bit 4 of CR7 */
433
            if (s->cr_index == 7)
434
                s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
435
            return;
436
        }
437
        switch(s->cr_index) {
438
        case 0x01: /* horizontal display end */
439
        case 0x07:
440
        case 0x09:
441
        case 0x0c:
442
        case 0x0d:
443
        case 0x12: /* veritcal display end */
444
            s->cr[s->cr_index] = val;
445
            break;
446

    
447
#ifdef CONFIG_S3VGA
448
            /* S3 registers */
449
        case 0x2d:
450
        case 0x2e:
451
        case 0x2f:
452
        case 0x30:
453
            /* chip ID, cannot write */
454
            break;
455
        case 0x31:
456
            /* update start address */
457
            {
458
                int v;
459
                s->cr[s->cr_index] = val;
460
                v = (val >> 4) & 3;
461
                s->cr[0x69] = (s->cr[69] & ~0x03) | v;
462
            }
463
            break;
464
        case 0x51:
465
            /* update start address */
466
            {
467
                int v;
468
                s->cr[s->cr_index] = val;
469
                v = val & 3;
470
                s->cr[0x69] = (s->cr[69] & ~0x0c) | (v << 2);
471
            }
472
            break;
473
#endif
474
        default:
475
            s->cr[s->cr_index] = val;
476
            break;
477
        }
478
#ifdef DEBUG_S3
479
        if (s->cr_index >= 0x20)
480
            printf("S3: CR write index=0x%x val=0x%x\n",
481
                   s->cr_index, val);
482
#endif
483
        break;
484
    case 0x3ba:
485
    case 0x3da:
486
        s->fcr = val & 0x10;
487
        break;
488
    }
489
}
490

    
491
#ifdef CONFIG_BOCHS_VBE
492
static uint32_t vbe_ioport_read(void *opaque, uint32_t addr)
493
{
494
    VGAState *s = opaque;
495
    uint32_t val;
496

    
497
    addr &= 1;
498
    if (addr == 0) {
499
        val = s->vbe_index;
500
    } else {
501
        if (s->vbe_index <= VBE_DISPI_INDEX_NB)
502
            val = s->vbe_regs[s->vbe_index];
503
        else
504
            val = 0;
505
#ifdef DEBUG_BOCHS_VBE
506
        printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
507
#endif
508
    }
509
    return val;
510
}
511

    
512
static void vbe_ioport_write(void *opaque, uint32_t addr, uint32_t val)
513
{
514
    VGAState *s = opaque;
515

    
516
    addr &= 1;
517
    if (addr == 0) {
518
        s->vbe_index = val;
519
    } else if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
520
#ifdef DEBUG_BOCHS_VBE
521
        printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
522
#endif
523
        switch(s->vbe_index) {
524
        case VBE_DISPI_INDEX_ID:
525
            if (val == VBE_DISPI_ID0 ||
526
                val == VBE_DISPI_ID1 ||
527
                val == VBE_DISPI_ID2) {
528
                s->vbe_regs[s->vbe_index] = val;
529
            }
530
            break;
531
        case VBE_DISPI_INDEX_XRES:
532
            if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
533
                s->vbe_regs[s->vbe_index] = val;
534
            }
535
            break;
536
        case VBE_DISPI_INDEX_YRES:
537
            if (val <= VBE_DISPI_MAX_YRES) {
538
                s->vbe_regs[s->vbe_index] = val;
539
            }
540
            break;
541
        case VBE_DISPI_INDEX_BPP:
542
            if (val == 0)
543
                val = 8;
544
            if (val == 4 || val == 8 || val == 15 || 
545
                val == 16 || val == 24 || val == 32) {
546
                s->vbe_regs[s->vbe_index] = val;
547
            }
548
            break;
549
        case VBE_DISPI_INDEX_BANK:
550
            val &= s->vbe_bank_mask;
551
            s->vbe_regs[s->vbe_index] = val;
552
            s->bank_offset = (val << 16) - 0xa0000;
553
            break;
554
        case VBE_DISPI_INDEX_ENABLE:
555
            if (val & VBE_DISPI_ENABLED) {
556
                int h, shift_control;
557

    
558
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 
559
                    s->vbe_regs[VBE_DISPI_INDEX_XRES];
560
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = 
561
                    s->vbe_regs[VBE_DISPI_INDEX_YRES];
562
                s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
563
                s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
564
                
565
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
566
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
567
                else
568
                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * 
569
                        ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
570
                s->vbe_start_addr = 0;
571
                
572
                /* clear the screen (should be done in BIOS) */
573
                if (!(val & VBE_DISPI_NOCLEARMEM)) {
574
                    memset(s->vram_ptr, 0, 
575
                           s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
576
                }
577
                
578
                /* we initialize the VGA graphic mode (should be done
579
                   in BIOS) */
580
                s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
581
                s->cr[0x17] |= 3; /* no CGA modes */
582
                s->cr[0x13] = s->vbe_line_offset >> 3;
583
                /* width */
584
                s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
585
                /* height */
586
                h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
587
                s->cr[0x12] = h;
588
                s->cr[0x07] = (s->cr[0x07] & ~0x42) | 
589
                    ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
590
                /* line compare to 1023 */
591
                s->cr[0x18] = 0xff;
592
                s->cr[0x07] |= 0x10;
593
                s->cr[0x09] |= 0x40;
594
                
595
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
596
                    shift_control = 0;
597
                    s->sr[0x01] &= ~8; /* no double line */
598
                } else {
599
                    shift_control = 2;
600
                }
601
                s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
602
                s->cr[0x09] &= ~0x9f; /* no double scan */
603
                s->vbe_regs[s->vbe_index] = val;
604
            } else {
605
                /* XXX: the bios should do that */
606
                s->bank_offset = -0xa0000;
607
            }
608
            break;
609
        case VBE_DISPI_INDEX_VIRT_WIDTH:
610
            {
611
                int w, h, line_offset;
612

    
613
                if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
614
                    return;
615
                w = val;
616
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
617
                    line_offset = w >> 1;
618
                else
619
                    line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
620
                h = s->vram_size / line_offset;
621
                /* XXX: support weird bochs semantics ? */
622
                if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
623
                    return;
624
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
625
                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
626
                s->vbe_line_offset = line_offset;
627
            }
628
            break;
629
        case VBE_DISPI_INDEX_X_OFFSET:
630
        case VBE_DISPI_INDEX_Y_OFFSET:
631
            {
632
                int x;
633
                s->vbe_regs[s->vbe_index] = val;
634
                s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
635
                x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
636
                if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
637
                    s->vbe_start_addr += x >> 1;
638
                else
639
                    s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
640
                s->vbe_start_addr >>= 2;
641
            }
642
            break;
643
        default:
644
            break;
645
        }
646
    }
647
}
648
#endif
649

    
650
/* called for accesses between 0xa0000 and 0xc0000 */
651
static uint32_t vga_mem_readb(target_phys_addr_t addr)
652
{
653
    VGAState *s = &vga_state;
654
    int memory_map_mode, plane;
655
    uint32_t ret;
656
    
657
    /* convert to VGA memory offset */
658
    memory_map_mode = (s->gr[6] >> 2) & 3;
659
    switch(memory_map_mode) {
660
    case 0:
661
        addr -= 0xa0000;
662
        break;
663
    case 1:
664
        if (addr >= 0xb0000)
665
            return 0xff;
666
        addr += s->bank_offset;
667
        break;
668
    case 2:
669
        addr -= 0xb0000;
670
        if (addr >= 0x8000)
671
            return 0xff;
672
        break;
673
    default:
674
    case 3:
675
        addr -= 0xb8000;
676
        if (addr >= 0x8000)
677
            return 0xff;
678
        break;
679
    }
680
    
681
    if (s->sr[4] & 0x08) {
682
        /* chain 4 mode : simplest access */
683
        ret = s->vram_ptr[addr];
684
    } else if (s->gr[5] & 0x10) {
685
        /* odd/even mode (aka text mode mapping) */
686
        plane = (s->gr[4] & 2) | (addr & 1);
687
        ret = s->vram_ptr[((addr & ~1) << 1) | plane];
688
    } else {
689
        /* standard VGA latched access */
690
        s->latch = ((uint32_t *)s->vram_ptr)[addr];
691

    
692
        if (!(s->gr[5] & 0x08)) {
693
            /* read mode 0 */
694
            plane = s->gr[4];
695
            ret = GET_PLANE(s->latch, plane);
696
        } else {
697
            /* read mode 1 */
698
            ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
699
            ret |= ret >> 16;
700
            ret |= ret >> 8;
701
            ret = (~ret) & 0xff;
702
        }
703
    }
704
    return ret;
705
}
706

    
707
static uint32_t vga_mem_readw(target_phys_addr_t addr)
708
{
709
    uint32_t v;
710
    v = vga_mem_readb(addr);
711
    v |= vga_mem_readb(addr + 1) << 8;
712
    return v;
713
}
714

    
715
static uint32_t vga_mem_readl(target_phys_addr_t addr)
716
{
717
    uint32_t v;
718
    v = vga_mem_readb(addr);
719
    v |= vga_mem_readb(addr + 1) << 8;
720
    v |= vga_mem_readb(addr + 2) << 16;
721
    v |= vga_mem_readb(addr + 3) << 24;
722
    return v;
723
}
724

    
725
/* called for accesses between 0xa0000 and 0xc0000 */
726
static void vga_mem_writeb(target_phys_addr_t addr, uint32_t val)
727
{
728
    VGAState *s = &vga_state;
729
    int memory_map_mode, plane, write_mode, b, func_select;
730
    uint32_t write_mask, bit_mask, set_mask;
731

    
732
#ifdef DEBUG_VGA_MEM
733
    printf("vga: [0x%x] = 0x%02x\n", addr, val);
734
#endif
735
    /* convert to VGA memory offset */
736
    memory_map_mode = (s->gr[6] >> 2) & 3;
737
    switch(memory_map_mode) {
738
    case 0:
739
        addr -= 0xa0000;
740
        break;
741
    case 1:
742
        if (addr >= 0xb0000)
743
            return;
744
        addr += s->bank_offset;
745
        break;
746
    case 2:
747
        addr -= 0xb0000;
748
        if (addr >= 0x8000)
749
            return;
750
        break;
751
    default:
752
    case 3:
753
        addr -= 0xb8000;
754
        if (addr >= 0x8000)
755
            return;
756
        break;
757
    }
758
    
759
    if (s->sr[4] & 0x08) {
760
        /* chain 4 mode : simplest access */
761
        plane = addr & 3;
762
        if (s->sr[2] & (1 << plane)) {
763
            s->vram_ptr[addr] = val;
764
#ifdef DEBUG_VGA_MEM
765
            printf("vga: chain4: [0x%x]\n", addr);
766
#endif
767
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
768
        }
769
    } else if (s->gr[5] & 0x10) {
770
        /* odd/even mode (aka text mode mapping) */
771
        plane = (s->gr[4] & 2) | (addr & 1);
772
        if (s->sr[2] & (1 << plane)) {
773
            addr = ((addr & ~1) << 1) | plane;
774
            s->vram_ptr[addr] = val;
775
#ifdef DEBUG_VGA_MEM
776
            printf("vga: odd/even: [0x%x]\n", addr);
777
#endif
778
            cpu_physical_memory_set_dirty(s->vram_offset + addr);
779
        }
780
    } else {
781
        /* standard VGA latched access */
782
        write_mode = s->gr[5] & 3;
783
        switch(write_mode) {
784
        default:
785
        case 0:
786
            /* rotate */
787
            b = s->gr[3] & 7;
788
            val = ((val >> b) | (val << (8 - b))) & 0xff;
789
            val |= val << 8;
790
            val |= val << 16;
791

    
792
            /* apply set/reset mask */
793
            set_mask = mask16[s->gr[1]];
794
            val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
795
            bit_mask = s->gr[8];
796
            break;
797
        case 1:
798
            val = s->latch;
799
            goto do_write;
800
        case 2:
801
            val = mask16[val & 0x0f];
802
            bit_mask = s->gr[8];
803
            break;
804
        case 3:
805
            /* rotate */
806
            b = s->gr[3] & 7;
807
            val = (val >> b) | (val << (8 - b));
808

    
809
            bit_mask = s->gr[8] & val;
810
            val = mask16[s->gr[0]];
811
            break;
812
        }
813

    
814
        /* apply logical operation */
815
        func_select = s->gr[3] >> 3;
816
        switch(func_select) {
817
        case 0:
818
        default:
819
            /* nothing to do */
820
            break;
821
        case 1:
822
            /* and */
823
            val &= s->latch;
824
            break;
825
        case 2:
826
            /* or */
827
            val |= s->latch;
828
            break;
829
        case 3:
830
            /* xor */
831
            val ^= s->latch;
832
            break;
833
        }
834

    
835
        /* apply bit mask */
836
        bit_mask |= bit_mask << 8;
837
        bit_mask |= bit_mask << 16;
838
        val = (val & bit_mask) | (s->latch & ~bit_mask);
839

    
840
    do_write:
841
        /* mask data according to sr[2] */
842
        write_mask = mask16[s->sr[2]];
843
        ((uint32_t *)s->vram_ptr)[addr] = 
844
            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
845
            (val & write_mask);
846
#ifdef DEBUG_VGA_MEM
847
            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
848
                   addr * 4, write_mask, val);
849
#endif
850
            cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
851
    }
852
}
853

    
854
static void vga_mem_writew(target_phys_addr_t addr, uint32_t val)
855
{
856
    vga_mem_writeb(addr, val & 0xff);
857
    vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
858
}
859

    
860
static void vga_mem_writel(target_phys_addr_t addr, uint32_t val)
861
{
862
    vga_mem_writeb(addr, val & 0xff);
863
    vga_mem_writeb(addr + 1, (val >> 8) & 0xff);
864
    vga_mem_writeb(addr + 2, (val >> 16) & 0xff);
865
    vga_mem_writeb(addr + 3, (val >> 24) & 0xff);
866
}
867

    
868
typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
869
                             const uint8_t *font_ptr, int h,
870
                             uint32_t fgcol, uint32_t bgcol);
871
typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
872
                                  const uint8_t *font_ptr, int h, 
873
                                  uint32_t fgcol, uint32_t bgcol, int dup9);
874
typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
875
                                const uint8_t *s, int width);
876

    
877
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
878
{
879
    /* XXX: TODO */
880
    return 0;
881
}
882

    
883
static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
884
{
885
    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
886
}
887

    
888
static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
889
{
890
    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
891
}
892

    
893
static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
894
{
895
    return (r << 16) | (g << 8) | b;
896
}
897

    
898
#define DEPTH 8
899
#include "vga_template.h"
900

    
901
#define DEPTH 15
902
#include "vga_template.h"
903

    
904
#define DEPTH 16
905
#include "vga_template.h"
906

    
907
#define DEPTH 32
908
#include "vga_template.h"
909

    
910
static inline int c6_to_8(int v)
911
{
912
    int b;
913
    v &= 0x3f;
914
    b = v & 1;
915
    return (v << 2) | (b << 1) | b;
916
}
917

    
918
static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
919
{
920
    unsigned int col;
921
    col = rgb_to_pixel8(r, g, b);
922
    col |= col << 8;
923
    col |= col << 16;
924
    return col;
925
}
926

    
927
static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
928
{
929
    unsigned int col;
930
    col = rgb_to_pixel15(r, g, b);
931
    col |= col << 16;
932
    return col;
933
}
934

    
935
static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
936
{
937
    unsigned int col;
938
    col = rgb_to_pixel16(r, g, b);
939
    col |= col << 16;
940
    return col;
941
}
942

    
943
static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
944
{
945
    unsigned int col;
946
    col = rgb_to_pixel32(r, g, b);
947
    return col;
948
}
949

    
950
/* return true if the palette was modified */
951
static int update_palette16(VGAState *s)
952
{
953
    int full_update, i;
954
    uint32_t v, col, *palette;
955

    
956
    full_update = 0;
957
    palette = s->last_palette;
958
    for(i = 0; i < 16; i++) {
959
        v = s->ar[i];
960
        if (s->ar[0x10] & 0x80)
961
            v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
962
        else
963
            v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
964
        v = v * 3;
965
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
966
                              c6_to_8(s->palette[v + 1]), 
967
                              c6_to_8(s->palette[v + 2]));
968
        if (col != palette[i]) {
969
            full_update = 1;
970
            palette[i] = col;
971
        }
972
    }
973
    return full_update;
974
}
975

    
976
/* return true if the palette was modified */
977
static int update_palette256(VGAState *s)
978
{
979
    int full_update, i;
980
    uint32_t v, col, *palette;
981

    
982
    full_update = 0;
983
    palette = s->last_palette;
984
    v = 0;
985
    for(i = 0; i < 256; i++) {
986
        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
987
                              c6_to_8(s->palette[v + 1]), 
988
                              c6_to_8(s->palette[v + 2]));
989
        if (col != palette[i]) {
990
            full_update = 1;
991
            palette[i] = col;
992
        }
993
        v += 3;
994
    }
995
    return full_update;
996
}
997

    
998
/* update start_addr and line_offset. Return TRUE if modified */
999
static int update_basic_params(VGAState *s)
1000
{
1001
    int full_update;
1002
    uint32_t start_addr, line_offset, line_compare;
1003
    
1004
    full_update = 0;
1005

    
1006
#ifdef CONFIG_BOCHS_VBE
1007
    if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1008
        line_offset = s->vbe_line_offset;
1009
        start_addr = s->vbe_start_addr;
1010
    } else
1011
#endif
1012
    {  
1013
        /* compute line_offset in bytes */
1014
        line_offset = s->cr[0x13];
1015
#ifdef CONFIG_S3VGA
1016
        {
1017
            uinr32_t v;
1018
            v = (s->cr[0x51] >> 4) & 3; /* S3 extension */
1019
            if (v == 0)
1020
                v = (s->cr[0x43] >> 2) & 1; /* S3 extension */
1021
            line_offset |= (v << 8);
1022
        }
1023
#endif
1024
        line_offset <<= 3;
1025
        
1026
        /* starting address */
1027
        start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1028
#ifdef CONFIG_S3VGA
1029
        start_addr |= (s->cr[0x69] & 0x1f) << 16; /* S3 extension */
1030
#endif
1031
    }
1032
    
1033
    /* line compare */
1034
    line_compare = s->cr[0x18] | 
1035
        ((s->cr[0x07] & 0x10) << 4) |
1036
        ((s->cr[0x09] & 0x40) << 3);
1037

    
1038
    if (line_offset != s->line_offset ||
1039
        start_addr != s->start_addr ||
1040
        line_compare != s->line_compare) {
1041
        s->line_offset = line_offset;
1042
        s->start_addr = start_addr;
1043
        s->line_compare = line_compare;
1044
        full_update = 1;
1045
    }
1046
    return full_update;
1047
}
1048

    
1049
static inline int get_depth_index(int depth)
1050
{
1051
    switch(depth) {
1052
    default:
1053
    case 8:
1054
        return 0;
1055
    case 15:
1056
        return 1;
1057
    case 16:
1058
        return 2;
1059
    case 32:
1060
        return 3;
1061
    }
1062
}
1063

    
1064
static vga_draw_glyph8_func *vga_draw_glyph8_table[4] = {
1065
    vga_draw_glyph8_8,
1066
    vga_draw_glyph8_16,
1067
    vga_draw_glyph8_16,
1068
    vga_draw_glyph8_32,
1069
};
1070

    
1071
static vga_draw_glyph8_func *vga_draw_glyph16_table[4] = {
1072
    vga_draw_glyph16_8,
1073
    vga_draw_glyph16_16,
1074
    vga_draw_glyph16_16,
1075
    vga_draw_glyph16_32,
1076
};
1077

    
1078
static vga_draw_glyph9_func *vga_draw_glyph9_table[4] = {
1079
    vga_draw_glyph9_8,
1080
    vga_draw_glyph9_16,
1081
    vga_draw_glyph9_16,
1082
    vga_draw_glyph9_32,
1083
};
1084
    
1085
static const uint8_t cursor_glyph[32 * 4] = {
1086
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1087
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1088
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1089
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1090
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1091
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1092
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1093
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1094
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1095
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1096
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1097
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1098
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1099
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1100
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1101
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1102
};    
1103

    
1104
/* 
1105
 * Text mode update 
1106
 * Missing:
1107
 * - double scan
1108
 * - double width 
1109
 * - underline
1110
 * - flashing
1111
 */
1112
static void vga_draw_text(VGAState *s, int full_update)
1113
{
1114
    int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1115
    int cx_min, cx_max, linesize, x_incr;
1116
    uint32_t offset, fgcol, bgcol, v, cursor_offset;
1117
    uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
1118
    const uint8_t *font_ptr, *font_base[2];
1119
    int dup9, line_offset, depth_index;
1120
    uint32_t *palette;
1121
    uint32_t *ch_attr_ptr;
1122
    vga_draw_glyph8_func *vga_draw_glyph8;
1123
    vga_draw_glyph9_func *vga_draw_glyph9;
1124

    
1125
    full_update |= update_palette16(s);
1126
    palette = s->last_palette;
1127
    
1128
    /* compute font data address (in plane 2) */
1129
    v = s->sr[3];
1130
    offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1131
    if (offset != s->font_offsets[0]) {
1132
        s->font_offsets[0] = offset;
1133
        full_update = 1;
1134
    }
1135
    font_base[0] = s->vram_ptr + offset;
1136

    
1137
    offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1138
    font_base[1] = s->vram_ptr + offset;
1139
    if (offset != s->font_offsets[1]) {
1140
        s->font_offsets[1] = offset;
1141
        full_update = 1;
1142
    }
1143

    
1144
    full_update |= update_basic_params(s);
1145

    
1146
    line_offset = s->line_offset;
1147
    s1 = s->vram_ptr + (s->start_addr * 4);
1148

    
1149
    /* total width & height */
1150
    cheight = (s->cr[9] & 0x1f) + 1;
1151
    cw = 8;
1152
    if (!(s->sr[1] & 0x01))
1153
        cw = 9;
1154
    if (s->sr[1] & 0x08)
1155
        cw = 16; /* NOTE: no 18 pixel wide */
1156
    x_incr = cw * ((s->ds->depth + 7) >> 3);
1157
    width = (s->cr[0x01] + 1);
1158
    if (s->cr[0x06] == 100) {
1159
        /* ugly hack for CGA 160x100x16 - explain me the logic */
1160
        height = 100;
1161
    } else {
1162
        height = s->cr[0x12] | 
1163
            ((s->cr[0x07] & 0x02) << 7) | 
1164
            ((s->cr[0x07] & 0x40) << 3);
1165
        height = (height + 1) / cheight;
1166
    }
1167
    if ((height * width) > CH_ATTR_SIZE) {
1168
        /* better than nothing: exit if transient size is too big */
1169
        return;
1170
    }
1171

    
1172
    if (width != s->last_width || height != s->last_height ||
1173
        cw != s->last_cw || cheight != s->last_ch) {
1174
        s->last_scr_width = width * cw;
1175
        s->last_scr_height = height * cheight;
1176
        dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
1177
        s->last_width = width;
1178
        s->last_height = height;
1179
        s->last_ch = cheight;
1180
        s->last_cw = cw;
1181
        full_update = 1;
1182
    }
1183
    cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1184
    if (cursor_offset != s->cursor_offset ||
1185
        s->cr[0xa] != s->cursor_start ||
1186
        s->cr[0xb] != s->cursor_end) {
1187
      /* if the cursor position changed, we update the old and new
1188
         chars */
1189
        if (s->cursor_offset < CH_ATTR_SIZE)
1190
            s->last_ch_attr[s->cursor_offset] = -1;
1191
        if (cursor_offset < CH_ATTR_SIZE)
1192
            s->last_ch_attr[cursor_offset] = -1;
1193
        s->cursor_offset = cursor_offset;
1194
        s->cursor_start = s->cr[0xa];
1195
        s->cursor_end = s->cr[0xb];
1196
    }
1197
    cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1198
    
1199
    depth_index = get_depth_index(s->ds->depth);
1200
    if (cw == 16)
1201
        vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1202
    else
1203
        vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1204
    vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1205
    
1206
    dest = s->ds->data;
1207
    linesize = s->ds->linesize;
1208
    ch_attr_ptr = s->last_ch_attr;
1209
    for(cy = 0; cy < height; cy++) {
1210
        d1 = dest;
1211
        src = s1;
1212
        cx_min = width;
1213
        cx_max = -1;
1214
        for(cx = 0; cx < width; cx++) {
1215
            ch_attr = *(uint16_t *)src;
1216
            if (full_update || ch_attr != *ch_attr_ptr) {
1217
                if (cx < cx_min)
1218
                    cx_min = cx;
1219
                if (cx > cx_max)
1220
                    cx_max = cx;
1221
                *ch_attr_ptr = ch_attr;
1222
#ifdef WORDS_BIGENDIAN
1223
                ch = ch_attr >> 8;
1224
                cattr = ch_attr & 0xff;
1225
#else
1226
                ch = ch_attr & 0xff;
1227
                cattr = ch_attr >> 8;
1228
#endif
1229
                font_ptr = font_base[(cattr >> 3) & 1];
1230
                font_ptr += 32 * 4 * ch;
1231
                bgcol = palette[cattr >> 4];
1232
                fgcol = palette[cattr & 0x0f];
1233
                if (cw != 9) {
1234
                    vga_draw_glyph8(d1, linesize, 
1235
                                    font_ptr, cheight, fgcol, bgcol);
1236
                } else {
1237
                    dup9 = 0;
1238
                    if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1239
                        dup9 = 1;
1240
                    vga_draw_glyph9(d1, linesize, 
1241
                                    font_ptr, cheight, fgcol, bgcol, dup9);
1242
                }
1243
                if (src == cursor_ptr &&
1244
                    !(s->cr[0x0a] & 0x20)) {
1245
                    int line_start, line_last, h;
1246
                    /* draw the cursor */
1247
                    line_start = s->cr[0x0a] & 0x1f;
1248
                    line_last = s->cr[0x0b] & 0x1f;
1249
                    /* XXX: check that */
1250
                    if (line_last > cheight - 1)
1251
                        line_last = cheight - 1;
1252
                    if (line_last >= line_start && line_start < cheight) {
1253
                        h = line_last - line_start + 1;
1254
                        d = d1 + linesize * line_start;
1255
                        if (cw != 9) {
1256
                            vga_draw_glyph8(d, linesize, 
1257
                                            cursor_glyph, h, fgcol, bgcol);
1258
                        } else {
1259
                            vga_draw_glyph9(d, linesize, 
1260
                                            cursor_glyph, h, fgcol, bgcol, 1);
1261
                        }
1262
                    }
1263
                }
1264
            }
1265
            d1 += x_incr;
1266
            src += 4;
1267
            ch_attr_ptr++;
1268
        }
1269
        if (cx_max != -1) {
1270
            dpy_update(s->ds, cx_min * cw, cy * cheight, 
1271
                       (cx_max - cx_min + 1) * cw, cheight);
1272
        }
1273
        dest += linesize * cheight;
1274
        s1 += line_offset;
1275
    }
1276
}
1277

    
1278
enum {
1279
    VGA_DRAW_LINE2,
1280
    VGA_DRAW_LINE2D2,
1281
    VGA_DRAW_LINE4,
1282
    VGA_DRAW_LINE4D2,
1283
    VGA_DRAW_LINE8D2,
1284
    VGA_DRAW_LINE8,
1285
    VGA_DRAW_LINE15,
1286
    VGA_DRAW_LINE16,
1287
    VGA_DRAW_LINE24,
1288
    VGA_DRAW_LINE32,
1289
    VGA_DRAW_LINE_NB,
1290
};
1291

    
1292
static vga_draw_line_func *vga_draw_line_table[4 * VGA_DRAW_LINE_NB] = {
1293
    vga_draw_line2_8,
1294
    vga_draw_line2_16,
1295
    vga_draw_line2_16,
1296
    vga_draw_line2_32,
1297

    
1298
    vga_draw_line2d2_8,
1299
    vga_draw_line2d2_16,
1300
    vga_draw_line2d2_16,
1301
    vga_draw_line2d2_32,
1302

    
1303
    vga_draw_line4_8,
1304
    vga_draw_line4_16,
1305
    vga_draw_line4_16,
1306
    vga_draw_line4_32,
1307

    
1308
    vga_draw_line4d2_8,
1309
    vga_draw_line4d2_16,
1310
    vga_draw_line4d2_16,
1311
    vga_draw_line4d2_32,
1312

    
1313
    vga_draw_line8d2_8,
1314
    vga_draw_line8d2_16,
1315
    vga_draw_line8d2_16,
1316
    vga_draw_line8d2_32,
1317

    
1318
    vga_draw_line8_8,
1319
    vga_draw_line8_16,
1320
    vga_draw_line8_16,
1321
    vga_draw_line8_32,
1322

    
1323
    vga_draw_line15_8,
1324
    vga_draw_line15_15,
1325
    vga_draw_line15_16,
1326
    vga_draw_line15_32,
1327

    
1328
    vga_draw_line16_8,
1329
    vga_draw_line16_15,
1330
    vga_draw_line16_16,
1331
    vga_draw_line16_32,
1332

    
1333
    vga_draw_line24_8,
1334
    vga_draw_line24_15,
1335
    vga_draw_line24_16,
1336
    vga_draw_line24_32,
1337

    
1338
    vga_draw_line32_8,
1339
    vga_draw_line32_15,
1340
    vga_draw_line32_16,
1341
    vga_draw_line32_32,
1342
};
1343

    
1344
/* 
1345
 * graphic modes
1346
 * Missing:
1347
 * - double scan
1348
 * - double width 
1349
 */
1350
static void vga_draw_graphic(VGAState *s, int full_update)
1351
{
1352
    int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
1353
    int width, height, shift_control, line_offset, page0, page1, bwidth;
1354
    int disp_width, multi_scan, multi_run;
1355
    uint8_t *d;
1356
    uint32_t v, addr1, addr;
1357
    vga_draw_line_func *vga_draw_line;
1358
    
1359
    full_update |= update_basic_params(s);
1360

    
1361
    width = (s->cr[0x01] + 1) * 8;
1362
    height = s->cr[0x12] | 
1363
        ((s->cr[0x07] & 0x02) << 7) | 
1364
        ((s->cr[0x07] & 0x40) << 3);
1365
    height = (height + 1);
1366
    disp_width = width;
1367
    
1368
    shift_control = (s->gr[0x05] >> 5) & 3;
1369
    double_scan = (s->cr[0x09] & 0x80);
1370
    if (shift_control > 1) {
1371
        multi_scan = (s->cr[0x09] & 0x1f);
1372
    } else {
1373
        multi_scan = 0;
1374
    }
1375
    multi_run = multi_scan;
1376
    if (shift_control != s->shift_control ||
1377
        double_scan != s->double_scan) {
1378
        full_update = 1;
1379
        s->shift_control = shift_control;
1380
        s->double_scan = double_scan;
1381
    }
1382
    
1383
    if (shift_control == 0) {
1384
        full_update |= update_palette16(s);
1385
        if (s->sr[0x01] & 8) {
1386
            v = VGA_DRAW_LINE4D2;
1387
            disp_width <<= 1;
1388
        } else {
1389
            v = VGA_DRAW_LINE4;
1390
        }
1391
    } else if (shift_control == 1) {
1392
        full_update |= update_palette16(s);
1393
        if (s->sr[0x01] & 8) {
1394
            v = VGA_DRAW_LINE2D2;
1395
            disp_width <<= 1;
1396
        } else {
1397
            v = VGA_DRAW_LINE2;
1398
        }
1399
    } else {
1400
#ifdef CONFIG_BOCHS_VBE
1401
        if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1402
            switch(s->vbe_regs[VBE_DISPI_INDEX_BPP]) {
1403
            default:
1404
            case 8:
1405
                full_update |= update_palette256(s);
1406
                v = VGA_DRAW_LINE8;
1407
                break;
1408
            case 15:
1409
                v = VGA_DRAW_LINE15;
1410
                break;
1411
            case 16:
1412
                v = VGA_DRAW_LINE16;
1413
                break;
1414
            case 24:
1415
                v = VGA_DRAW_LINE24;
1416
                break;
1417
            case 32:
1418
                v = VGA_DRAW_LINE32;
1419
                break;
1420
            }
1421
        } else 
1422
#endif
1423
        {
1424
            full_update |= update_palette256(s);
1425
            v = VGA_DRAW_LINE8D2;
1426
        }
1427
    }
1428
    vga_draw_line = vga_draw_line_table[v * 4 + get_depth_index(s->ds->depth)];
1429

    
1430
    if (disp_width != s->last_width ||
1431
        height != s->last_height) {
1432
        dpy_resize(s->ds, disp_width, height);
1433
        s->last_scr_width = disp_width;
1434
        s->last_scr_height = height;
1435
        s->last_width = disp_width;
1436
        s->last_height = height;
1437
        full_update = 1;
1438
    }
1439

    
1440
    line_offset = s->line_offset;
1441
#if 0
1442
    printf("w=%d h=%d v=%d line_offset=%d double_scan=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=%02x\n",
1443
           width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1444
#endif
1445
    addr1 = (s->start_addr * 4);
1446
    bwidth = width * 4;
1447
    y_start = -1;
1448
    page_min = 0x7fffffff;
1449
    page_max = -1;
1450
    d = s->ds->data;
1451
    linesize = s->ds->linesize;
1452
    y1 = 0;
1453
    for(y = 0; y < height; y++) {
1454
        addr = addr1;
1455
        if (!(s->cr[0x17] & 1)) {
1456
            int shift;
1457
            /* CGA compatibility handling */
1458
            shift = 14 + ((s->cr[0x17] >> 6) & 1);
1459
            addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1460
        }
1461
        if (!(s->cr[0x17] & 2)) {
1462
            addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1463
        }
1464
        page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1465
        page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1466
        update = full_update | cpu_physical_memory_is_dirty(page0) |
1467
            cpu_physical_memory_is_dirty(page1);
1468
        if ((page1 - page0) > TARGET_PAGE_SIZE) {
1469
            /* if wide line, can use another page */
1470
            update |= cpu_physical_memory_is_dirty(page0 + TARGET_PAGE_SIZE);
1471
        }
1472
        if (update) {
1473
            if (y_start < 0)
1474
                y_start = y;
1475
            if (page0 < page_min)
1476
                page_min = page0;
1477
            if (page1 > page_max)
1478
                page_max = page1;
1479
            vga_draw_line(s, d, s->vram_ptr + addr, width);
1480
        } else {
1481
            if (y_start >= 0) {
1482
                /* flush to display */
1483
                dpy_update(s->ds, 0, y_start, 
1484
                           disp_width, y - y_start);
1485
                y_start = -1;
1486
            }
1487
        }
1488
        if (!multi_run) {
1489
            if (!double_scan || (y & 1) != 0) {
1490
                if (y1 == s->line_compare) {
1491
                    addr1 = 0;
1492
                } else {
1493
                    mask = (s->cr[0x17] & 3) ^ 3;
1494
                    if ((y1 & mask) == mask)
1495
                        addr1 += line_offset;
1496
                }
1497
                y1++;
1498
            }
1499
            multi_run = multi_scan;
1500
        } else {
1501
            multi_run--;
1502
            y1++;
1503
        }
1504
        d += linesize;
1505
    }
1506
    if (y_start >= 0) {
1507
        /* flush to display */
1508
        dpy_update(s->ds, 0, y_start, 
1509
                   disp_width, y - y_start);
1510
    }
1511
    /* reset modified pages */
1512
    if (page_max != -1) {
1513
        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
1514
    }
1515
}
1516

    
1517
static void vga_draw_blank(VGAState *s, int full_update)
1518
{
1519
    int i, w, val;
1520
    uint8_t *d;
1521

    
1522
    if (!full_update)
1523
        return;
1524
    if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1525
        return;
1526
    if (s->ds->depth == 8) 
1527
        val = s->rgb_to_pixel(0, 0, 0);
1528
    else
1529
        val = 0;
1530
    w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
1531
    d = s->ds->data;
1532
    for(i = 0; i < s->last_scr_height; i++) {
1533
        memset(d, val, w);
1534
        d += s->ds->linesize;
1535
    }
1536
    dpy_update(s->ds, 0, 0, 
1537
               s->last_scr_width, s->last_scr_height);
1538
}
1539

    
1540
#define GMODE_TEXT     0
1541
#define GMODE_GRAPH    1
1542
#define GMODE_BLANK 2 
1543

    
1544
void vga_update_display(void)
1545
{
1546
    VGAState *s = &vga_state;
1547
    int full_update, graphic_mode;
1548

    
1549
    if (s->ds->depth == 0) {
1550
        /* nothing to do */
1551
    } else {
1552
        switch(s->ds->depth) {
1553
        case 8:
1554
            s->rgb_to_pixel = rgb_to_pixel8_dup;
1555
            break;
1556
        case 15:
1557
            s->rgb_to_pixel = rgb_to_pixel15_dup;
1558
            break;
1559
        default:
1560
        case 16:
1561
            s->rgb_to_pixel = rgb_to_pixel16_dup;
1562
            break;
1563
        case 32:
1564
            s->rgb_to_pixel = rgb_to_pixel32_dup;
1565
            break;
1566
        }
1567
        
1568
        full_update = 0;
1569
        if (!(s->ar_index & 0x20)) {
1570
            graphic_mode = GMODE_BLANK;
1571
        } else {
1572
            graphic_mode = s->gr[6] & 1;
1573
        }
1574
        if (graphic_mode != s->graphic_mode) {
1575
            s->graphic_mode = graphic_mode;
1576
            full_update = 1;
1577
        }
1578
        switch(graphic_mode) {
1579
        case GMODE_TEXT:
1580
            vga_draw_text(s, full_update);
1581
            break;
1582
        case GMODE_GRAPH:
1583
            vga_draw_graphic(s, full_update);
1584
            break;
1585
        case GMODE_BLANK:
1586
        default:
1587
            vga_draw_blank(s, full_update);
1588
            break;
1589
        }
1590
    }
1591
}
1592

    
1593
static void vga_reset(VGAState *s)
1594
{
1595
    memset(s, 0, sizeof(VGAState));
1596
#ifdef CONFIG_S3VGA
1597
    /* chip ID for 8c968 */
1598
    s->cr[0x2d] = 0x88;
1599
    s->cr[0x2e] = 0xb0;
1600
    s->cr[0x2f] = 0x01; /* XXX: check revision code */
1601
    s->cr[0x30] = 0xe1;
1602
#endif
1603
    s->graphic_mode = -1; /* force full update */
1604
}
1605

    
1606
static CPUReadMemoryFunc *vga_mem_read[3] = {
1607
    vga_mem_readb,
1608
    vga_mem_readw,
1609
    vga_mem_readl,
1610
};
1611

    
1612
static CPUWriteMemoryFunc *vga_mem_write[3] = {
1613
    vga_mem_writeb,
1614
    vga_mem_writew,
1615
    vga_mem_writel,
1616
};
1617

    
1618
static void vga_save(QEMUFile *f, void *opaque)
1619
{
1620
    VGAState *s = opaque;
1621
    int i;
1622

    
1623
    qemu_put_be32s(f, &s->latch);
1624
    qemu_put_8s(f, &s->sr_index);
1625
    qemu_put_buffer(f, s->sr, 8);
1626
    qemu_put_8s(f, &s->gr_index);
1627
    qemu_put_buffer(f, s->gr, 16);
1628
    qemu_put_8s(f, &s->ar_index);
1629
    qemu_put_buffer(f, s->ar, 21);
1630
    qemu_put_be32s(f, &s->ar_flip_flop);
1631
    qemu_put_8s(f, &s->cr_index);
1632
    qemu_put_buffer(f, s->cr, 256);
1633
    qemu_put_8s(f, &s->msr);
1634
    qemu_put_8s(f, &s->fcr);
1635
    qemu_put_8s(f, &s->st00);
1636
    qemu_put_8s(f, &s->st01);
1637

    
1638
    qemu_put_8s(f, &s->dac_state);
1639
    qemu_put_8s(f, &s->dac_sub_index);
1640
    qemu_put_8s(f, &s->dac_read_index);
1641
    qemu_put_8s(f, &s->dac_write_index);
1642
    qemu_put_buffer(f, s->dac_cache, 3);
1643
    qemu_put_buffer(f, s->palette, 768);
1644

    
1645
    qemu_put_be32s(f, &s->bank_offset);
1646
#ifdef CONFIG_BOCHS_VBE
1647
    qemu_put_byte(f, 1);
1648
    qemu_put_be16s(f, &s->vbe_index);
1649
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1650
        qemu_put_be16s(f, &s->vbe_regs[i]);
1651
    qemu_put_be32s(f, &s->vbe_start_addr);
1652
    qemu_put_be32s(f, &s->vbe_line_offset);
1653
    qemu_put_be32s(f, &s->vbe_bank_mask);
1654
#else
1655
    qemu_put_byte(f, 0);
1656
#endif
1657
}
1658

    
1659
static int vga_load(QEMUFile *f, void *opaque, int version_id)
1660
{
1661
    VGAState *s = opaque;
1662
    int is_vbe, i;
1663

    
1664
    if (version_id != 1)
1665
        return -EINVAL;
1666

    
1667
    qemu_get_be32s(f, &s->latch);
1668
    qemu_get_8s(f, &s->sr_index);
1669
    qemu_get_buffer(f, s->sr, 8);
1670
    qemu_get_8s(f, &s->gr_index);
1671
    qemu_get_buffer(f, s->gr, 16);
1672
    qemu_get_8s(f, &s->ar_index);
1673
    qemu_get_buffer(f, s->ar, 21);
1674
    qemu_get_be32s(f, &s->ar_flip_flop);
1675
    qemu_get_8s(f, &s->cr_index);
1676
    qemu_get_buffer(f, s->cr, 256);
1677
    qemu_get_8s(f, &s->msr);
1678
    qemu_get_8s(f, &s->fcr);
1679
    qemu_get_8s(f, &s->st00);
1680
    qemu_get_8s(f, &s->st01);
1681

    
1682
    qemu_get_8s(f, &s->dac_state);
1683
    qemu_get_8s(f, &s->dac_sub_index);
1684
    qemu_get_8s(f, &s->dac_read_index);
1685
    qemu_get_8s(f, &s->dac_write_index);
1686
    qemu_get_buffer(f, s->dac_cache, 3);
1687
    qemu_get_buffer(f, s->palette, 768);
1688

    
1689
    qemu_get_be32s(f, &s->bank_offset);
1690
    is_vbe = qemu_get_byte(f);
1691
#ifdef CONFIG_BOCHS_VBE
1692
    if (!is_vbe)
1693
        return -EINVAL;
1694
    qemu_get_be16s(f, &s->vbe_index);
1695
    for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
1696
        qemu_get_be16s(f, &s->vbe_regs[i]);
1697
    qemu_get_be32s(f, &s->vbe_start_addr);
1698
    qemu_get_be32s(f, &s->vbe_line_offset);
1699
    qemu_get_be32s(f, &s->vbe_bank_mask);
1700
#else
1701
    if (is_vbe)
1702
        return -EINVAL;
1703
#endif
1704

    
1705
    /* force refresh */
1706
    s->graphic_mode = -1;
1707
    return 0;
1708
}
1709

    
1710
int vga_initialize(DisplayState *ds, uint8_t *vga_ram_base, 
1711
                   unsigned long vga_ram_offset, int vga_ram_size)
1712
{
1713
    VGAState *s = &vga_state;
1714
    int i, j, v, b;
1715

    
1716
    for(i = 0;i < 256; i++) {
1717
        v = 0;
1718
        for(j = 0; j < 8; j++) {
1719
            v |= ((i >> j) & 1) << (j * 4);
1720
        }
1721
        expand4[i] = v;
1722

    
1723
        v = 0;
1724
        for(j = 0; j < 4; j++) {
1725
            v |= ((i >> (2 * j)) & 3) << (j * 4);
1726
        }
1727
        expand2[i] = v;
1728
    }
1729
    for(i = 0; i < 16; i++) {
1730
        v = 0;
1731
        for(j = 0; j < 4; j++) {
1732
            b = ((i >> j) & 1);
1733
            v |= b << (2 * j);
1734
            v |= b << (2 * j + 1);
1735
        }
1736
        expand4to8[i] = v;
1737
    }
1738

    
1739
    vga_reset(s);
1740

    
1741
    s->vram_ptr = vga_ram_base;
1742
    s->vram_offset = vga_ram_offset;
1743
    s->vram_size = vga_ram_size;
1744
    s->ds = ds;
1745

    
1746
    register_savevm("vga", 0, 1, vga_save, vga_load, s);
1747

    
1748
    register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
1749

    
1750
    register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
1751
    register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
1752
    register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
1753
    register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
1754

    
1755
    register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
1756

    
1757
    register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
1758
    register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
1759
    register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
1760
    register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
1761
    s->bank_offset = -0xa0000;
1762

    
1763
#ifdef CONFIG_BOCHS_VBE
1764
    s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
1765
    s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
1766
    register_ioport_read(0x1ce, 1, 2, vbe_ioport_read, s);
1767
    register_ioport_read(0x1cf, 1, 2, vbe_ioport_read, s);
1768

    
1769
    register_ioport_write(0x1ce, 1, 2, vbe_ioport_write, s);
1770
    register_ioport_write(0x1cf, 1, 2, vbe_ioport_write, s);
1771
#endif
1772

    
1773
    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write);
1774
#if defined (TARGET_I386)
1775
    cpu_register_physical_memory(0x000a0000, 0x20000, vga_io_memory);
1776
#ifdef CONFIG_BOCHS_VBE
1777
    /* XXX: use optimized standard vga accesses */
1778
    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
1779
                                 vga_ram_size, vga_ram_offset);
1780
#endif
1781
#elif defined (TARGET_PPC)
1782
    cpu_register_physical_memory(0xf00a0000, 0x20000, vga_io_memory);
1783
#endif
1784
    return 0;
1785
}
1786

    
1787
/********************************************************/
1788
/* vga screen dump */
1789

    
1790
static int vga_save_w, vga_save_h;
1791

    
1792
static void vga_save_dpy_update(DisplayState *s, 
1793
                                int x, int y, int w, int h)
1794
{
1795
}
1796

    
1797
static void vga_save_dpy_resize(DisplayState *s, int w, int h)
1798
{
1799
    s->linesize = w * 4;
1800
    s->data = qemu_malloc(h * s->linesize);
1801
    vga_save_w = w;
1802
    vga_save_h = h;
1803
}
1804

    
1805
static void vga_save_dpy_refresh(DisplayState *s)
1806
{
1807
}
1808

    
1809
static int ppm_save(const char *filename, uint8_t *data, 
1810
                    int w, int h, int linesize)
1811
{
1812
    FILE *f;
1813
    uint8_t *d, *d1;
1814
    unsigned int v;
1815
    int y, x;
1816

    
1817
    f = fopen(filename, "wb");
1818
    if (!f)
1819
        return -1;
1820
    fprintf(f, "P6\n%d %d\n%d\n",
1821
            w, h, 255);
1822
    d1 = data;
1823
    for(y = 0; y < h; y++) {
1824
        d = d1;
1825
        for(x = 0; x < w; x++) {
1826
            v = *(uint32_t *)d;
1827
            fputc((v >> 16) & 0xff, f);
1828
            fputc((v >> 8) & 0xff, f);
1829
            fputc((v) & 0xff, f);
1830
            d += 4;
1831
        }
1832
        d1 += linesize;
1833
    }
1834
    fclose(f);
1835
    return 0;
1836
}
1837

    
1838
/* save the vga display in a PPM image even if no display is
1839
   available */
1840
void vga_screen_dump(const char *filename)
1841
{
1842
    VGAState *s = &vga_state;
1843
    DisplayState *saved_ds, ds1, *ds = &ds1;
1844
    
1845
    /* XXX: this is a little hackish */
1846
    s->last_width = -1;
1847
    s->last_height = -1;
1848
    saved_ds = s->ds;
1849

    
1850
    memset(ds, 0, sizeof(DisplayState));
1851
    ds->dpy_update = vga_save_dpy_update;
1852
    ds->dpy_resize = vga_save_dpy_resize;
1853
    ds->dpy_refresh = vga_save_dpy_refresh;
1854
    ds->depth = 32;
1855

    
1856
    s->ds = ds;
1857
    s->graphic_mode = -1;
1858
    vga_update_display();
1859
    
1860
    if (ds->data) {
1861
        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
1862
                 s->ds->linesize);
1863
        qemu_free(ds->data);
1864
    }
1865
    s->ds = saved_ds;
1866
}