|
|
1.1 root 1: /*
2: * QEMU VGA Emulator.
1.1.1.5 root 3: *
1.1 root 4: * Copyright (c) 2003 Fabrice Bellard
1.1.1.5 root 5: *
1.1 root 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: */
1.1.1.5 root 24: #include "hw.h"
25: #include "console.h"
26: #include "pc.h"
27: #include "pci.h"
1.1 root 28: #include "vga_int.h"
1.1.1.5 root 29: #include "pixel_ops.h"
1.1.1.6 root 30: #include "qemu-timer.h"
31: #include "kvm.h"
1.1 root 32:
33: //#define DEBUG_VGA
34: //#define DEBUG_VGA_MEM
35: //#define DEBUG_VGA_REG
36:
37: //#define DEBUG_BOCHS_VBE
38:
39: /* force some bits to zero */
40: const uint8_t sr_mask[8] = {
1.1.1.10 root 41: 0x03,
42: 0x3d,
43: 0x0f,
44: 0x3f,
45: 0x0e,
46: 0x00,
47: 0x00,
48: 0xff,
1.1 root 49: };
50:
51: const uint8_t gr_mask[16] = {
1.1.1.10 root 52: 0x0f, /* 0x00 */
53: 0x0f, /* 0x01 */
54: 0x0f, /* 0x02 */
55: 0x1f, /* 0x03 */
56: 0x03, /* 0x04 */
57: 0x7b, /* 0x05 */
58: 0x0f, /* 0x06 */
59: 0x0f, /* 0x07 */
60: 0xff, /* 0x08 */
61: 0x00, /* 0x09 */
62: 0x00, /* 0x0a */
63: 0x00, /* 0x0b */
64: 0x00, /* 0x0c */
65: 0x00, /* 0x0d */
66: 0x00, /* 0x0e */
67: 0x00, /* 0x0f */
1.1 root 68: };
69:
70: #define cbswap_32(__x) \
71: ((uint32_t)( \
72: (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
73: (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
74: (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
75: (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
76:
1.1.1.12 root 77: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 78: #define PAT(x) cbswap_32(x)
79: #else
80: #define PAT(x) (x)
81: #endif
82:
1.1.1.12 root 83: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 84: #define BIG 1
85: #else
86: #define BIG 0
87: #endif
88:
1.1.1.12 root 89: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 90: #define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
91: #else
92: #define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
93: #endif
94:
95: static const uint32_t mask16[16] = {
96: PAT(0x00000000),
97: PAT(0x000000ff),
98: PAT(0x0000ff00),
99: PAT(0x0000ffff),
100: PAT(0x00ff0000),
101: PAT(0x00ff00ff),
102: PAT(0x00ffff00),
103: PAT(0x00ffffff),
104: PAT(0xff000000),
105: PAT(0xff0000ff),
106: PAT(0xff00ff00),
107: PAT(0xff00ffff),
108: PAT(0xffff0000),
109: PAT(0xffff00ff),
110: PAT(0xffffff00),
111: PAT(0xffffffff),
112: };
113:
114: #undef PAT
115:
1.1.1.12 root 116: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 117: #define PAT(x) (x)
118: #else
119: #define PAT(x) cbswap_32(x)
120: #endif
121:
122: static const uint32_t dmask16[16] = {
123: PAT(0x00000000),
124: PAT(0x000000ff),
125: PAT(0x0000ff00),
126: PAT(0x0000ffff),
127: PAT(0x00ff0000),
128: PAT(0x00ff00ff),
129: PAT(0x00ffff00),
130: PAT(0x00ffffff),
131: PAT(0xff000000),
132: PAT(0xff0000ff),
133: PAT(0xff00ff00),
134: PAT(0xff00ffff),
135: PAT(0xffff0000),
136: PAT(0xffff00ff),
137: PAT(0xffffff00),
138: PAT(0xffffffff),
139: };
140:
141: static const uint32_t dmask4[4] = {
142: PAT(0x00000000),
143: PAT(0x0000ffff),
144: PAT(0xffff0000),
145: PAT(0xffffffff),
146: };
147:
148: static uint32_t expand4[256];
149: static uint16_t expand2[256];
150: static uint8_t expand4to8[16];
151:
1.1.1.2 root 152: static void vga_screen_dump(void *opaque, const char *filename);
1.1.1.10 root 153: static char *screen_dump_filename;
154: static DisplayChangeListener *screen_dump_dcl;
1.1.1.2 root 155:
1.1.1.12 root 156: static void vga_dumb_update_retrace_info(VGACommonState *s)
1.1.1.6 root 157: {
158: (void) s;
159: }
160:
1.1.1.12 root 161: static void vga_precise_update_retrace_info(VGACommonState *s)
1.1.1.6 root 162: {
163: int htotal_chars;
164: int hretr_start_char;
165: int hretr_skew_chars;
166: int hretr_end_char;
167:
168: int vtotal_lines;
169: int vretr_start_line;
170: int vretr_end_line;
171:
1.1.1.13 root 172: int dots;
173: #if 0
174: int div2, sldiv2;
175: #endif
1.1.1.6 root 176: int clocking_mode;
177: int clock_sel;
178: const int clk_hz[] = {25175000, 28322000, 25175000, 25175000};
179: int64_t chars_per_sec;
180: struct vga_precise_retrace *r = &s->retrace_info.precise;
181:
182: htotal_chars = s->cr[0x00] + 5;
183: hretr_start_char = s->cr[0x04];
184: hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
185: hretr_end_char = s->cr[0x05] & 0x1f;
186:
187: vtotal_lines = (s->cr[0x06]
188: | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
189: ;
190: vretr_start_line = s->cr[0x10]
191: | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
192: ;
193: vretr_end_line = s->cr[0x11] & 0xf;
194:
195:
196:
197: clocking_mode = (s->sr[0x01] >> 3) & 1;
198: clock_sel = (s->msr >> 2) & 3;
199: dots = (s->msr & 1) ? 8 : 9;
200:
201: chars_per_sec = clk_hz[clock_sel] / dots;
202:
203: htotal_chars <<= clocking_mode;
204:
205: r->total_chars = vtotal_lines * htotal_chars;
206: if (r->freq) {
1.1.1.12 root 207: r->ticks_per_char = get_ticks_per_sec() / (r->total_chars * r->freq);
1.1.1.6 root 208: } else {
1.1.1.12 root 209: r->ticks_per_char = get_ticks_per_sec() / chars_per_sec;
1.1.1.6 root 210: }
211:
212: r->vstart = vretr_start_line;
213: r->vend = r->vstart + vretr_end_line + 1;
214:
215: r->hstart = hretr_start_char + hretr_skew_chars;
216: r->hend = r->hstart + hretr_end_char + 1;
217: r->htotal = htotal_chars;
218:
219: #if 0
1.1.1.13 root 220: div2 = (s->cr[0x17] >> 2) & 1;
221: sldiv2 = (s->cr[0x17] >> 3) & 1;
1.1.1.6 root 222: printf (
223: "hz=%f\n"
224: "htotal = %d\n"
225: "hretr_start = %d\n"
226: "hretr_skew = %d\n"
227: "hretr_end = %d\n"
228: "vtotal = %d\n"
229: "vretr_start = %d\n"
230: "vretr_end = %d\n"
231: "div2 = %d sldiv2 = %d\n"
232: "clocking_mode = %d\n"
233: "clock_sel = %d %d\n"
234: "dots = %d\n"
1.1.1.13 root 235: "ticks/char = %" PRId64 "\n"
1.1.1.6 root 236: "\n",
1.1.1.12 root 237: (double) get_ticks_per_sec() / (r->ticks_per_char * r->total_chars),
1.1.1.6 root 238: htotal_chars,
239: hretr_start_char,
240: hretr_skew_chars,
241: hretr_end_char,
242: vtotal_lines,
243: vretr_start_line,
244: vretr_end_line,
245: div2, sldiv2,
246: clocking_mode,
247: clock_sel,
248: clk_hz[clock_sel],
249: dots,
250: r->ticks_per_char
251: );
252: #endif
253: }
254:
1.1.1.12 root 255: static uint8_t vga_precise_retrace(VGACommonState *s)
1.1.1.6 root 256: {
257: struct vga_precise_retrace *r = &s->retrace_info.precise;
258: uint8_t val = s->st01 & ~(ST01_V_RETRACE | ST01_DISP_ENABLE);
259:
260: if (r->total_chars) {
261: int cur_line, cur_line_char, cur_char;
262: int64_t cur_tick;
263:
264: cur_tick = qemu_get_clock(vm_clock);
265:
266: cur_char = (cur_tick / r->ticks_per_char) % r->total_chars;
267: cur_line = cur_char / r->htotal;
268:
269: if (cur_line >= r->vstart && cur_line <= r->vend) {
270: val |= ST01_V_RETRACE | ST01_DISP_ENABLE;
271: } else {
272: cur_line_char = cur_char % r->htotal;
273: if (cur_line_char >= r->hstart && cur_line_char <= r->hend) {
274: val |= ST01_DISP_ENABLE;
275: }
276: }
277:
278: return val;
279: } else {
280: return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
281: }
282: }
283:
1.1.1.12 root 284: static uint8_t vga_dumb_retrace(VGACommonState *s)
1.1.1.6 root 285: {
286: return s->st01 ^ (ST01_V_RETRACE | ST01_DISP_ENABLE);
287: }
288:
1.1.1.12 root 289: int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
1.1 root 290: {
1.1.1.12 root 291: if (s->msr & MSR_COLOR_EMULATION) {
292: /* Color */
293: return (addr >= 0x3b0 && addr <= 0x3bf);
294: } else {
295: /* Monochrome */
296: return (addr >= 0x3d0 && addr <= 0x3df);
297: }
298: }
299:
300: uint32_t vga_ioport_read(void *opaque, uint32_t addr)
301: {
302: VGACommonState *s = opaque;
1.1 root 303: int val, index;
304:
1.1.1.12 root 305: if (vga_ioport_invalid(s, addr)) {
1.1 root 306: val = 0xff;
307: } else {
308: switch(addr) {
309: case 0x3c0:
310: if (s->ar_flip_flop == 0) {
311: val = s->ar_index;
312: } else {
313: val = 0;
314: }
315: break;
316: case 0x3c1:
317: index = s->ar_index & 0x1f;
1.1.1.5 root 318: if (index < 21)
1.1 root 319: val = s->ar[index];
320: else
321: val = 0;
322: break;
323: case 0x3c2:
324: val = s->st00;
325: break;
326: case 0x3c4:
327: val = s->sr_index;
328: break;
329: case 0x3c5:
330: val = s->sr[s->sr_index];
331: #ifdef DEBUG_VGA_REG
332: printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
333: #endif
334: break;
335: case 0x3c7:
336: val = s->dac_state;
337: break;
1.1.1.12 root 338: case 0x3c8:
339: val = s->dac_write_index;
340: break;
1.1 root 341: case 0x3c9:
342: val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
343: if (++s->dac_sub_index == 3) {
344: s->dac_sub_index = 0;
345: s->dac_read_index++;
346: }
347: break;
348: case 0x3ca:
349: val = s->fcr;
350: break;
351: case 0x3cc:
352: val = s->msr;
353: break;
354: case 0x3ce:
355: val = s->gr_index;
356: break;
357: case 0x3cf:
358: val = s->gr[s->gr_index];
359: #ifdef DEBUG_VGA_REG
360: printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
361: #endif
362: break;
363: case 0x3b4:
364: case 0x3d4:
365: val = s->cr_index;
366: break;
367: case 0x3b5:
368: case 0x3d5:
369: val = s->cr[s->cr_index];
370: #ifdef DEBUG_VGA_REG
371: printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
372: #endif
373: break;
374: case 0x3ba:
375: case 0x3da:
376: /* just toggle to fool polling */
1.1.1.6 root 377: val = s->st01 = s->retrace(s);
1.1 root 378: s->ar_flip_flop = 0;
379: break;
380: default:
381: val = 0x00;
382: break;
383: }
384: }
385: #if defined(DEBUG_VGA)
386: printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
387: #endif
388: return val;
389: }
390:
1.1.1.12 root 391: void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
1.1 root 392: {
1.1.1.12 root 393: VGACommonState *s = opaque;
1.1 root 394: int index;
395:
396: /* check port range access depending on color/monochrome mode */
1.1.1.12 root 397: if (vga_ioport_invalid(s, addr)) {
1.1 root 398: return;
1.1.1.12 root 399: }
1.1 root 400: #ifdef DEBUG_VGA
401: printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
402: #endif
403:
404: switch(addr) {
405: case 0x3c0:
406: if (s->ar_flip_flop == 0) {
407: val &= 0x3f;
408: s->ar_index = val;
409: } else {
410: index = s->ar_index & 0x1f;
411: switch(index) {
412: case 0x00 ... 0x0f:
413: s->ar[index] = val & 0x3f;
414: break;
415: case 0x10:
416: s->ar[index] = val & ~0x10;
417: break;
418: case 0x11:
419: s->ar[index] = val;
420: break;
421: case 0x12:
422: s->ar[index] = val & ~0xc0;
423: break;
424: case 0x13:
425: s->ar[index] = val & ~0xf0;
426: break;
427: case 0x14:
428: s->ar[index] = val & ~0xf0;
429: break;
430: default:
431: break;
432: }
433: }
434: s->ar_flip_flop ^= 1;
435: break;
436: case 0x3c2:
437: s->msr = val & ~0x10;
1.1.1.6 root 438: s->update_retrace_info(s);
1.1 root 439: break;
440: case 0x3c4:
441: s->sr_index = val & 7;
442: break;
443: case 0x3c5:
444: #ifdef DEBUG_VGA_REG
445: printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
446: #endif
447: s->sr[s->sr_index] = val & sr_mask[s->sr_index];
1.1.1.6 root 448: if (s->sr_index == 1) s->update_retrace_info(s);
1.1 root 449: break;
450: case 0x3c7:
451: s->dac_read_index = val;
452: s->dac_sub_index = 0;
453: s->dac_state = 3;
454: break;
455: case 0x3c8:
456: s->dac_write_index = val;
457: s->dac_sub_index = 0;
458: s->dac_state = 0;
459: break;
460: case 0x3c9:
461: s->dac_cache[s->dac_sub_index] = val;
462: if (++s->dac_sub_index == 3) {
463: memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
464: s->dac_sub_index = 0;
465: s->dac_write_index++;
466: }
467: break;
468: case 0x3ce:
469: s->gr_index = val & 0x0f;
470: break;
471: case 0x3cf:
472: #ifdef DEBUG_VGA_REG
473: printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
474: #endif
475: s->gr[s->gr_index] = val & gr_mask[s->gr_index];
476: break;
477: case 0x3b4:
478: case 0x3d4:
479: s->cr_index = val;
480: break;
481: case 0x3b5:
482: case 0x3d5:
483: #ifdef DEBUG_VGA_REG
484: printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
485: #endif
486: /* handle CR0-7 protection */
487: if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
488: /* can always write bit 4 of CR7 */
489: if (s->cr_index == 7)
490: s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
491: return;
492: }
1.1.1.12 root 493: s->cr[s->cr_index] = val;
1.1.1.6 root 494:
495: switch(s->cr_index) {
496: case 0x00:
497: case 0x04:
498: case 0x05:
499: case 0x06:
500: case 0x07:
501: case 0x11:
502: case 0x17:
503: s->update_retrace_info(s);
504: break;
505: }
1.1 root 506: break;
507: case 0x3ba:
508: case 0x3da:
509: s->fcr = val & 0x10;
510: break;
511: }
512: }
513:
514: #ifdef CONFIG_BOCHS_VBE
515: static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
516: {
1.1.1.12 root 517: VGACommonState *s = opaque;
1.1 root 518: uint32_t val;
519: val = s->vbe_index;
520: return val;
521: }
522:
523: static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
524: {
1.1.1.12 root 525: VGACommonState *s = opaque;
1.1 root 526: uint32_t val;
527:
1.1.1.13 root 528: if (s->vbe_index < VBE_DISPI_INDEX_NB) {
1.1.1.3 root 529: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
530: switch(s->vbe_index) {
531: /* XXX: do not hardcode ? */
532: case VBE_DISPI_INDEX_XRES:
533: val = VBE_DISPI_MAX_XRES;
534: break;
535: case VBE_DISPI_INDEX_YRES:
536: val = VBE_DISPI_MAX_YRES;
537: break;
538: case VBE_DISPI_INDEX_BPP:
539: val = VBE_DISPI_MAX_BPP;
540: break;
541: default:
1.1.1.5 root 542: val = s->vbe_regs[s->vbe_index];
1.1.1.3 root 543: break;
544: }
545: } else {
1.1.1.5 root 546: val = s->vbe_regs[s->vbe_index];
1.1.1.3 root 547: }
1.1.1.13 root 548: } else if (s->vbe_index == VBE_DISPI_INDEX_VIDEO_MEMORY_64K) {
549: val = s->vram_size / (64 * 1024);
1.1.1.3 root 550: } else {
1.1 root 551: val = 0;
1.1.1.3 root 552: }
1.1 root 553: #ifdef DEBUG_BOCHS_VBE
554: printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
555: #endif
556: return val;
557: }
558:
559: static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
560: {
1.1.1.12 root 561: VGACommonState *s = opaque;
1.1 root 562: s->vbe_index = val;
563: }
564:
565: static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
566: {
1.1.1.12 root 567: VGACommonState *s = opaque;
1.1 root 568:
569: if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
570: #ifdef DEBUG_BOCHS_VBE
571: printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
572: #endif
573: switch(s->vbe_index) {
574: case VBE_DISPI_INDEX_ID:
575: if (val == VBE_DISPI_ID0 ||
576: val == VBE_DISPI_ID1 ||
1.1.1.4 root 577: val == VBE_DISPI_ID2 ||
578: val == VBE_DISPI_ID3 ||
579: val == VBE_DISPI_ID4) {
1.1 root 580: s->vbe_regs[s->vbe_index] = val;
581: }
582: break;
583: case VBE_DISPI_INDEX_XRES:
584: if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
585: s->vbe_regs[s->vbe_index] = val;
586: }
587: break;
588: case VBE_DISPI_INDEX_YRES:
589: if (val <= VBE_DISPI_MAX_YRES) {
590: s->vbe_regs[s->vbe_index] = val;
591: }
592: break;
593: case VBE_DISPI_INDEX_BPP:
594: if (val == 0)
595: val = 8;
1.1.1.5 root 596: if (val == 4 || val == 8 || val == 15 ||
1.1 root 597: val == 16 || val == 24 || val == 32) {
598: s->vbe_regs[s->vbe_index] = val;
599: }
600: break;
601: case VBE_DISPI_INDEX_BANK:
1.1.1.4 root 602: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
603: val &= (s->vbe_bank_mask >> 2);
604: } else {
605: val &= s->vbe_bank_mask;
606: }
1.1 root 607: s->vbe_regs[s->vbe_index] = val;
608: s->bank_offset = (val << 16);
609: break;
610: case VBE_DISPI_INDEX_ENABLE:
1.1.1.3 root 611: if ((val & VBE_DISPI_ENABLED) &&
612: !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
1.1 root 613: int h, shift_control;
614:
1.1.1.5 root 615: s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
1.1 root 616: s->vbe_regs[VBE_DISPI_INDEX_XRES];
1.1.1.5 root 617: s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
1.1 root 618: s->vbe_regs[VBE_DISPI_INDEX_YRES];
619: s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
620: s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
1.1.1.5 root 621:
1.1 root 622: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
623: s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
624: else
1.1.1.5 root 625: s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
1.1 root 626: ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
627: s->vbe_start_addr = 0;
1.1.1.3 root 628:
1.1 root 629: /* clear the screen (should be done in BIOS) */
630: if (!(val & VBE_DISPI_NOCLEARMEM)) {
1.1.1.5 root 631: memset(s->vram_ptr, 0,
1.1 root 632: s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
633: }
1.1.1.5 root 634:
1.1 root 635: /* we initialize the VGA graphic mode (should be done
636: in BIOS) */
637: s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
638: s->cr[0x17] |= 3; /* no CGA modes */
639: s->cr[0x13] = s->vbe_line_offset >> 3;
640: /* width */
641: s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
1.1.1.3 root 642: /* height (only meaningful if < 1024) */
1.1 root 643: h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
644: s->cr[0x12] = h;
1.1.1.5 root 645: s->cr[0x07] = (s->cr[0x07] & ~0x42) |
1.1 root 646: ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
647: /* line compare to 1023 */
648: s->cr[0x18] = 0xff;
649: s->cr[0x07] |= 0x10;
650: s->cr[0x09] |= 0x40;
1.1.1.5 root 651:
1.1 root 652: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
653: shift_control = 0;
654: s->sr[0x01] &= ~8; /* no double line */
655: } else {
656: shift_control = 2;
657: s->sr[4] |= 0x08; /* set chain 4 mode */
658: s->sr[2] |= 0x0f; /* activate all planes */
659: }
660: s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
661: s->cr[0x09] &= ~0x9f; /* no double scan */
662: } else {
663: /* XXX: the bios should do that */
664: s->bank_offset = 0;
665: }
1.1.1.4 root 666: s->dac_8bit = (val & VBE_DISPI_8BIT_DAC) > 0;
1.1 root 667: s->vbe_regs[s->vbe_index] = val;
668: break;
669: case VBE_DISPI_INDEX_VIRT_WIDTH:
670: {
671: int w, h, line_offset;
672:
673: if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
674: return;
675: w = val;
676: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
677: line_offset = w >> 1;
678: else
679: line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
680: h = s->vram_size / line_offset;
681: /* XXX: support weird bochs semantics ? */
682: if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
683: return;
684: s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
685: s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
686: s->vbe_line_offset = line_offset;
687: }
688: break;
689: case VBE_DISPI_INDEX_X_OFFSET:
690: case VBE_DISPI_INDEX_Y_OFFSET:
691: {
692: int x;
693: s->vbe_regs[s->vbe_index] = val;
694: s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
695: x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
696: if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
697: s->vbe_start_addr += x >> 1;
698: else
699: s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
700: s->vbe_start_addr >>= 2;
701: }
702: break;
703: default:
704: break;
705: }
706: }
707: }
708: #endif
709:
710: /* called for accesses between 0xa0000 and 0xc0000 */
711: uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
712: {
1.1.1.12 root 713: VGACommonState *s = opaque;
1.1 root 714: int memory_map_mode, plane;
715: uint32_t ret;
1.1.1.5 root 716:
1.1 root 717: /* convert to VGA memory offset */
718: memory_map_mode = (s->gr[6] >> 2) & 3;
719: addr &= 0x1ffff;
720: switch(memory_map_mode) {
721: case 0:
722: break;
723: case 1:
724: if (addr >= 0x10000)
725: return 0xff;
726: addr += s->bank_offset;
727: break;
728: case 2:
729: addr -= 0x10000;
730: if (addr >= 0x8000)
731: return 0xff;
732: break;
733: default:
734: case 3:
735: addr -= 0x18000;
736: if (addr >= 0x8000)
737: return 0xff;
738: break;
739: }
1.1.1.5 root 740:
1.1 root 741: if (s->sr[4] & 0x08) {
742: /* chain 4 mode : simplest access */
743: ret = s->vram_ptr[addr];
744: } else if (s->gr[5] & 0x10) {
745: /* odd/even mode (aka text mode mapping) */
746: plane = (s->gr[4] & 2) | (addr & 1);
747: ret = s->vram_ptr[((addr & ~1) << 1) | plane];
748: } else {
749: /* standard VGA latched access */
750: s->latch = ((uint32_t *)s->vram_ptr)[addr];
751:
752: if (!(s->gr[5] & 0x08)) {
753: /* read mode 0 */
754: plane = s->gr[4];
755: ret = GET_PLANE(s->latch, plane);
756: } else {
757: /* read mode 1 */
758: ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
759: ret |= ret >> 16;
760: ret |= ret >> 8;
761: ret = (~ret) & 0xff;
762: }
763: }
764: return ret;
765: }
766:
767: static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
768: {
769: uint32_t v;
770: v = vga_mem_readb(opaque, addr);
771: v |= vga_mem_readb(opaque, addr + 1) << 8;
772: return v;
773: }
774:
775: static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
776: {
777: uint32_t v;
778: v = vga_mem_readb(opaque, addr);
779: v |= vga_mem_readb(opaque, addr + 1) << 8;
780: v |= vga_mem_readb(opaque, addr + 2) << 16;
781: v |= vga_mem_readb(opaque, addr + 3) << 24;
782: return v;
783: }
784:
785: /* called for accesses between 0xa0000 and 0xc0000 */
786: void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
787: {
1.1.1.12 root 788: VGACommonState *s = opaque;
1.1 root 789: int memory_map_mode, plane, write_mode, b, func_select, mask;
790: uint32_t write_mask, bit_mask, set_mask;
791:
792: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 793: printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
1.1 root 794: #endif
795: /* convert to VGA memory offset */
796: memory_map_mode = (s->gr[6] >> 2) & 3;
797: addr &= 0x1ffff;
798: switch(memory_map_mode) {
799: case 0:
800: break;
801: case 1:
802: if (addr >= 0x10000)
803: return;
804: addr += s->bank_offset;
805: break;
806: case 2:
807: addr -= 0x10000;
808: if (addr >= 0x8000)
809: return;
810: break;
811: default:
812: case 3:
813: addr -= 0x18000;
814: if (addr >= 0x8000)
815: return;
816: break;
817: }
1.1.1.5 root 818:
1.1 root 819: if (s->sr[4] & 0x08) {
820: /* chain 4 mode : simplest access */
821: plane = addr & 3;
822: mask = (1 << plane);
823: if (s->sr[2] & mask) {
824: s->vram_ptr[addr] = val;
825: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 826: printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
1.1 root 827: #endif
828: s->plane_updated |= mask; /* only used to detect font change */
829: cpu_physical_memory_set_dirty(s->vram_offset + addr);
830: }
831: } else if (s->gr[5] & 0x10) {
832: /* odd/even mode (aka text mode mapping) */
833: plane = (s->gr[4] & 2) | (addr & 1);
834: mask = (1 << plane);
835: if (s->sr[2] & mask) {
836: addr = ((addr & ~1) << 1) | plane;
837: s->vram_ptr[addr] = val;
838: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 839: printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
1.1 root 840: #endif
841: s->plane_updated |= mask; /* only used to detect font change */
842: cpu_physical_memory_set_dirty(s->vram_offset + addr);
843: }
844: } else {
845: /* standard VGA latched access */
846: write_mode = s->gr[5] & 3;
847: switch(write_mode) {
848: default:
849: case 0:
850: /* rotate */
851: b = s->gr[3] & 7;
852: val = ((val >> b) | (val << (8 - b))) & 0xff;
853: val |= val << 8;
854: val |= val << 16;
855:
856: /* apply set/reset mask */
857: set_mask = mask16[s->gr[1]];
858: val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
859: bit_mask = s->gr[8];
860: break;
861: case 1:
862: val = s->latch;
863: goto do_write;
864: case 2:
865: val = mask16[val & 0x0f];
866: bit_mask = s->gr[8];
867: break;
868: case 3:
869: /* rotate */
870: b = s->gr[3] & 7;
871: val = (val >> b) | (val << (8 - b));
872:
873: bit_mask = s->gr[8] & val;
874: val = mask16[s->gr[0]];
875: break;
876: }
877:
878: /* apply logical operation */
879: func_select = s->gr[3] >> 3;
880: switch(func_select) {
881: case 0:
882: default:
883: /* nothing to do */
884: break;
885: case 1:
886: /* and */
887: val &= s->latch;
888: break;
889: case 2:
890: /* or */
891: val |= s->latch;
892: break;
893: case 3:
894: /* xor */
895: val ^= s->latch;
896: break;
897: }
898:
899: /* apply bit mask */
900: bit_mask |= bit_mask << 8;
901: bit_mask |= bit_mask << 16;
902: val = (val & bit_mask) | (s->latch & ~bit_mask);
903:
904: do_write:
905: /* mask data according to sr[2] */
906: mask = s->sr[2];
907: s->plane_updated |= mask; /* only used to detect font change */
908: write_mask = mask16[mask];
1.1.1.5 root 909: ((uint32_t *)s->vram_ptr)[addr] =
910: (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
1.1 root 911: (val & write_mask);
912: #ifdef DEBUG_VGA_MEM
1.1.1.10 root 913: printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
914: addr * 4, write_mask, val);
1.1 root 915: #endif
1.1.1.10 root 916: cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
1.1 root 917: }
918: }
919:
920: static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
921: {
922: vga_mem_writeb(opaque, addr, val & 0xff);
923: vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
924: }
925:
926: static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
927: {
928: vga_mem_writeb(opaque, addr, val & 0xff);
929: vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
930: vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
931: vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
932: }
933:
934: typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
935: const uint8_t *font_ptr, int h,
936: uint32_t fgcol, uint32_t bgcol);
937: typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
1.1.1.5 root 938: const uint8_t *font_ptr, int h,
1.1 root 939: uint32_t fgcol, uint32_t bgcol, int dup9);
1.1.1.12 root 940: typedef void vga_draw_line_func(VGACommonState *s1, uint8_t *d,
1.1 root 941: const uint8_t *s, int width);
942:
943: #define DEPTH 8
944: #include "vga_template.h"
945:
946: #define DEPTH 15
947: #include "vga_template.h"
948:
1.1.1.5 root 949: #define BGR_FORMAT
950: #define DEPTH 15
951: #include "vga_template.h"
952:
953: #define DEPTH 16
954: #include "vga_template.h"
955:
956: #define BGR_FORMAT
1.1 root 957: #define DEPTH 16
958: #include "vga_template.h"
959:
960: #define DEPTH 32
961: #include "vga_template.h"
962:
1.1.1.3 root 963: #define BGR_FORMAT
964: #define DEPTH 32
965: #include "vga_template.h"
966:
1.1 root 967: static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
968: {
969: unsigned int col;
970: col = rgb_to_pixel8(r, g, b);
971: col |= col << 8;
972: col |= col << 16;
973: return col;
974: }
975:
976: static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
977: {
978: unsigned int col;
979: col = rgb_to_pixel15(r, g, b);
980: col |= col << 16;
981: return col;
982: }
983:
1.1.1.5 root 984: static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
985: unsigned int b)
986: {
987: unsigned int col;
988: col = rgb_to_pixel15bgr(r, g, b);
989: col |= col << 16;
990: return col;
991: }
992:
1.1 root 993: static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
994: {
995: unsigned int col;
996: col = rgb_to_pixel16(r, g, b);
997: col |= col << 16;
998: return col;
999: }
1000:
1.1.1.5 root 1001: static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
1002: unsigned int b)
1003: {
1004: unsigned int col;
1005: col = rgb_to_pixel16bgr(r, g, b);
1006: col |= col << 16;
1007: return col;
1008: }
1009:
1.1 root 1010: static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
1011: {
1012: unsigned int col;
1013: col = rgb_to_pixel32(r, g, b);
1014: return col;
1015: }
1016:
1.1.1.3 root 1017: static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
1018: {
1019: unsigned int col;
1020: col = rgb_to_pixel32bgr(r, g, b);
1021: return col;
1022: }
1023:
1.1 root 1024: /* return true if the palette was modified */
1.1.1.12 root 1025: static int update_palette16(VGACommonState *s)
1.1 root 1026: {
1027: int full_update, i;
1028: uint32_t v, col, *palette;
1029:
1030: full_update = 0;
1031: palette = s->last_palette;
1032: for(i = 0; i < 16; i++) {
1033: v = s->ar[i];
1034: if (s->ar[0x10] & 0x80)
1035: v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
1036: else
1037: v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
1038: v = v * 3;
1.1.1.5 root 1039: col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1040: c6_to_8(s->palette[v + 1]),
1.1 root 1041: c6_to_8(s->palette[v + 2]));
1042: if (col != palette[i]) {
1043: full_update = 1;
1044: palette[i] = col;
1045: }
1046: }
1047: return full_update;
1048: }
1049:
1050: /* return true if the palette was modified */
1.1.1.12 root 1051: static int update_palette256(VGACommonState *s)
1.1 root 1052: {
1053: int full_update, i;
1054: uint32_t v, col, *palette;
1055:
1056: full_update = 0;
1057: palette = s->last_palette;
1058: v = 0;
1059: for(i = 0; i < 256; i++) {
1.1.1.4 root 1060: if (s->dac_8bit) {
1.1.1.5 root 1061: col = s->rgb_to_pixel(s->palette[v],
1062: s->palette[v + 1],
1.1.1.4 root 1063: s->palette[v + 2]);
1064: } else {
1.1.1.5 root 1065: col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
1066: c6_to_8(s->palette[v + 1]),
1.1.1.4 root 1067: c6_to_8(s->palette[v + 2]));
1068: }
1.1 root 1069: if (col != palette[i]) {
1070: full_update = 1;
1071: palette[i] = col;
1072: }
1073: v += 3;
1074: }
1075: return full_update;
1076: }
1077:
1.1.1.12 root 1078: static void vga_get_offsets(VGACommonState *s,
1.1.1.5 root 1079: uint32_t *pline_offset,
1.1.1.4 root 1080: uint32_t *pstart_addr,
1081: uint32_t *pline_compare)
1.1 root 1082: {
1.1.1.4 root 1083: uint32_t start_addr, line_offset, line_compare;
1.1 root 1084: #ifdef CONFIG_BOCHS_VBE
1085: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1086: line_offset = s->vbe_line_offset;
1087: start_addr = s->vbe_start_addr;
1.1.1.4 root 1088: line_compare = 65535;
1.1 root 1089: } else
1090: #endif
1.1.1.5 root 1091: {
1.1 root 1092: /* compute line_offset in bytes */
1093: line_offset = s->cr[0x13];
1094: line_offset <<= 3;
1095:
1096: /* starting address */
1097: start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
1.1.1.4 root 1098:
1099: /* line compare */
1.1.1.5 root 1100: line_compare = s->cr[0x18] |
1.1.1.4 root 1101: ((s->cr[0x07] & 0x10) << 4) |
1102: ((s->cr[0x09] & 0x40) << 3);
1.1 root 1103: }
1104: *pline_offset = line_offset;
1105: *pstart_addr = start_addr;
1.1.1.4 root 1106: *pline_compare = line_compare;
1.1 root 1107: }
1108:
1109: /* update start_addr and line_offset. Return TRUE if modified */
1.1.1.12 root 1110: static int update_basic_params(VGACommonState *s)
1.1 root 1111: {
1112: int full_update;
1113: uint32_t start_addr, line_offset, line_compare;
1.1.1.5 root 1114:
1.1 root 1115: full_update = 0;
1116:
1.1.1.4 root 1117: s->get_offsets(s, &line_offset, &start_addr, &line_compare);
1.1 root 1118:
1119: if (line_offset != s->line_offset ||
1120: start_addr != s->start_addr ||
1121: line_compare != s->line_compare) {
1122: s->line_offset = line_offset;
1123: s->start_addr = start_addr;
1124: s->line_compare = line_compare;
1125: full_update = 1;
1126: }
1127: return full_update;
1128: }
1129:
1.1.1.5 root 1130: #define NB_DEPTHS 7
1.1.1.3 root 1131:
1132: static inline int get_depth_index(DisplayState *s)
1.1 root 1133: {
1.1.1.6 root 1134: switch(ds_get_bits_per_pixel(s)) {
1.1 root 1135: default:
1136: case 8:
1137: return 0;
1138: case 15:
1.1.1.6 root 1139: return 1;
1.1 root 1140: case 16:
1.1.1.6 root 1141: return 2;
1.1 root 1142: case 32:
1.1.1.10 root 1143: if (is_surface_bgr(s->surface))
1144: return 4;
1145: else
1146: return 3;
1.1 root 1147: }
1148: }
1149:
1.1.1.13 root 1150: static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
1.1 root 1151: vga_draw_glyph8_8,
1152: vga_draw_glyph8_16,
1153: vga_draw_glyph8_16,
1154: vga_draw_glyph8_32,
1.1.1.3 root 1155: vga_draw_glyph8_32,
1.1.1.5 root 1156: vga_draw_glyph8_16,
1157: vga_draw_glyph8_16,
1.1 root 1158: };
1159:
1.1.1.13 root 1160: static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
1.1 root 1161: vga_draw_glyph16_8,
1162: vga_draw_glyph16_16,
1163: vga_draw_glyph16_16,
1164: vga_draw_glyph16_32,
1.1.1.3 root 1165: vga_draw_glyph16_32,
1.1.1.5 root 1166: vga_draw_glyph16_16,
1167: vga_draw_glyph16_16,
1.1 root 1168: };
1169:
1.1.1.13 root 1170: static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
1.1 root 1171: vga_draw_glyph9_8,
1172: vga_draw_glyph9_16,
1173: vga_draw_glyph9_16,
1174: vga_draw_glyph9_32,
1.1.1.3 root 1175: vga_draw_glyph9_32,
1.1.1.5 root 1176: vga_draw_glyph9_16,
1177: vga_draw_glyph9_16,
1.1 root 1178: };
1.1.1.5 root 1179:
1.1 root 1180: static const uint8_t cursor_glyph[32 * 4] = {
1181: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1182: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1183: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1184: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1185: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1186: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1187: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1188: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1189: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1190: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1191: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1192: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1193: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1194: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1195: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1196: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1.1.1.5 root 1197: };
1.1 root 1198:
1.1.1.12 root 1199: static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight,
1.1.1.6 root 1200: int *pcwidth, int *pcheight)
1201: {
1202: int width, cwidth, height, cheight;
1203:
1204: /* total width & height */
1205: cheight = (s->cr[9] & 0x1f) + 1;
1206: cwidth = 8;
1207: if (!(s->sr[1] & 0x01))
1208: cwidth = 9;
1209: if (s->sr[1] & 0x08)
1210: cwidth = 16; /* NOTE: no 18 pixel wide */
1211: width = (s->cr[0x01] + 1);
1212: if (s->cr[0x06] == 100) {
1213: /* ugly hack for CGA 160x100x16 - explain me the logic */
1214: height = 100;
1215: } else {
1216: height = s->cr[0x12] |
1217: ((s->cr[0x07] & 0x02) << 7) |
1218: ((s->cr[0x07] & 0x40) << 3);
1219: height = (height + 1) / cheight;
1220: }
1221:
1222: *pwidth = width;
1223: *pheight = height;
1224: *pcwidth = cwidth;
1225: *pcheight = cheight;
1226: }
1227:
1228: typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
1229:
1.1.1.13 root 1230: static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
1.1.1.6 root 1231: rgb_to_pixel8_dup,
1232: rgb_to_pixel15_dup,
1233: rgb_to_pixel16_dup,
1234: rgb_to_pixel32_dup,
1235: rgb_to_pixel32bgr_dup,
1236: rgb_to_pixel15bgr_dup,
1237: rgb_to_pixel16bgr_dup,
1238: };
1239:
1.1.1.5 root 1240: /*
1241: * Text mode update
1.1 root 1242: * Missing:
1243: * - double scan
1.1.1.5 root 1244: * - double width
1.1 root 1245: * - underline
1246: * - flashing
1247: */
1.1.1.12 root 1248: static void vga_draw_text(VGACommonState *s, int full_update)
1.1 root 1249: {
1250: int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
1.1.1.12 root 1251: int cx_min, cx_max, linesize, x_incr, line, line1;
1.1 root 1252: uint32_t offset, fgcol, bgcol, v, cursor_offset;
1.1.1.12 root 1253: uint8_t *d1, *d, *src, *dest, *cursor_ptr;
1.1 root 1254: const uint8_t *font_ptr, *font_base[2];
1255: int dup9, line_offset, depth_index;
1256: uint32_t *palette;
1257: uint32_t *ch_attr_ptr;
1258: vga_draw_glyph8_func *vga_draw_glyph8;
1259: vga_draw_glyph9_func *vga_draw_glyph9;
1260:
1261: /* compute font data address (in plane 2) */
1262: v = s->sr[3];
1263: offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
1264: if (offset != s->font_offsets[0]) {
1265: s->font_offsets[0] = offset;
1266: full_update = 1;
1267: }
1268: font_base[0] = s->vram_ptr + offset;
1269:
1270: offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
1271: font_base[1] = s->vram_ptr + offset;
1272: if (offset != s->font_offsets[1]) {
1273: s->font_offsets[1] = offset;
1274: full_update = 1;
1275: }
1276: if (s->plane_updated & (1 << 2)) {
1277: /* if the plane 2 was modified since the last display, it
1278: indicates the font may have been modified */
1279: s->plane_updated = 0;
1280: full_update = 1;
1281: }
1282: full_update |= update_basic_params(s);
1283:
1284: line_offset = s->line_offset;
1285:
1.1.1.6 root 1286: vga_get_text_resolution(s, &width, &height, &cw, &cheight);
1.1 root 1287: if ((height * width) > CH_ATTR_SIZE) {
1288: /* better than nothing: exit if transient size is too big */
1289: return;
1290: }
1291:
1292: if (width != s->last_width || height != s->last_height ||
1.1.1.6 root 1293: cw != s->last_cw || cheight != s->last_ch || s->last_depth) {
1.1 root 1294: s->last_scr_width = width * cw;
1295: s->last_scr_height = height * cheight;
1.1.1.6 root 1296: qemu_console_resize(s->ds, s->last_scr_width, s->last_scr_height);
1297: s->last_depth = 0;
1.1 root 1298: s->last_width = width;
1299: s->last_height = height;
1300: s->last_ch = cheight;
1301: s->last_cw = cw;
1302: full_update = 1;
1303: }
1.1.1.6 root 1304: s->rgb_to_pixel =
1305: rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1306: full_update |= update_palette16(s);
1307: palette = s->last_palette;
1308: x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1309:
1.1 root 1310: cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
1311: if (cursor_offset != s->cursor_offset ||
1312: s->cr[0xa] != s->cursor_start ||
1313: s->cr[0xb] != s->cursor_end) {
1314: /* if the cursor position changed, we update the old and new
1315: chars */
1316: if (s->cursor_offset < CH_ATTR_SIZE)
1317: s->last_ch_attr[s->cursor_offset] = -1;
1318: if (cursor_offset < CH_ATTR_SIZE)
1319: s->last_ch_attr[cursor_offset] = -1;
1320: s->cursor_offset = cursor_offset;
1321: s->cursor_start = s->cr[0xa];
1322: s->cursor_end = s->cr[0xb];
1323: }
1324: cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
1.1.1.5 root 1325:
1.1.1.3 root 1326: depth_index = get_depth_index(s->ds);
1.1 root 1327: if (cw == 16)
1328: vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
1329: else
1330: vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
1331: vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
1.1.1.5 root 1332:
1.1.1.6 root 1333: dest = ds_get_data(s->ds);
1334: linesize = ds_get_linesize(s->ds);
1.1 root 1335: ch_attr_ptr = s->last_ch_attr;
1.1.1.12 root 1336: line = 0;
1337: offset = s->start_addr * 4;
1.1 root 1338: for(cy = 0; cy < height; cy++) {
1339: d1 = dest;
1.1.1.12 root 1340: src = s->vram_ptr + offset;
1.1 root 1341: cx_min = width;
1342: cx_max = -1;
1343: for(cx = 0; cx < width; cx++) {
1344: ch_attr = *(uint16_t *)src;
1345: if (full_update || ch_attr != *ch_attr_ptr) {
1346: if (cx < cx_min)
1347: cx_min = cx;
1348: if (cx > cx_max)
1349: cx_max = cx;
1350: *ch_attr_ptr = ch_attr;
1.1.1.12 root 1351: #ifdef HOST_WORDS_BIGENDIAN
1.1 root 1352: ch = ch_attr >> 8;
1353: cattr = ch_attr & 0xff;
1354: #else
1355: ch = ch_attr & 0xff;
1356: cattr = ch_attr >> 8;
1357: #endif
1358: font_ptr = font_base[(cattr >> 3) & 1];
1359: font_ptr += 32 * 4 * ch;
1360: bgcol = palette[cattr >> 4];
1361: fgcol = palette[cattr & 0x0f];
1362: if (cw != 9) {
1.1.1.5 root 1363: vga_draw_glyph8(d1, linesize,
1.1 root 1364: font_ptr, cheight, fgcol, bgcol);
1365: } else {
1366: dup9 = 0;
1367: if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
1368: dup9 = 1;
1.1.1.5 root 1369: vga_draw_glyph9(d1, linesize,
1.1 root 1370: font_ptr, cheight, fgcol, bgcol, dup9);
1371: }
1372: if (src == cursor_ptr &&
1373: !(s->cr[0x0a] & 0x20)) {
1374: int line_start, line_last, h;
1375: /* draw the cursor */
1376: line_start = s->cr[0x0a] & 0x1f;
1377: line_last = s->cr[0x0b] & 0x1f;
1378: /* XXX: check that */
1379: if (line_last > cheight - 1)
1380: line_last = cheight - 1;
1381: if (line_last >= line_start && line_start < cheight) {
1382: h = line_last - line_start + 1;
1383: d = d1 + linesize * line_start;
1384: if (cw != 9) {
1.1.1.5 root 1385: vga_draw_glyph8(d, linesize,
1.1 root 1386: cursor_glyph, h, fgcol, bgcol);
1387: } else {
1.1.1.5 root 1388: vga_draw_glyph9(d, linesize,
1.1 root 1389: cursor_glyph, h, fgcol, bgcol, 1);
1390: }
1391: }
1392: }
1393: }
1394: d1 += x_incr;
1395: src += 4;
1396: ch_attr_ptr++;
1397: }
1398: if (cx_max != -1) {
1.1.1.5 root 1399: dpy_update(s->ds, cx_min * cw, cy * cheight,
1.1 root 1400: (cx_max - cx_min + 1) * cw, cheight);
1401: }
1402: dest += linesize * cheight;
1.1.1.12 root 1403: line1 = line + cheight;
1404: offset += line_offset;
1405: if (line < s->line_compare && line1 >= s->line_compare) {
1406: offset = 0;
1407: }
1408: line = line1;
1.1 root 1409: }
1410: }
1411:
1412: enum {
1413: VGA_DRAW_LINE2,
1414: VGA_DRAW_LINE2D2,
1415: VGA_DRAW_LINE4,
1416: VGA_DRAW_LINE4D2,
1417: VGA_DRAW_LINE8D2,
1418: VGA_DRAW_LINE8,
1419: VGA_DRAW_LINE15,
1420: VGA_DRAW_LINE16,
1421: VGA_DRAW_LINE24,
1422: VGA_DRAW_LINE32,
1423: VGA_DRAW_LINE_NB,
1424: };
1425:
1.1.1.13 root 1426: static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
1.1 root 1427: vga_draw_line2_8,
1428: vga_draw_line2_16,
1429: vga_draw_line2_16,
1430: vga_draw_line2_32,
1.1.1.3 root 1431: vga_draw_line2_32,
1.1.1.5 root 1432: vga_draw_line2_16,
1433: vga_draw_line2_16,
1.1 root 1434:
1435: vga_draw_line2d2_8,
1436: vga_draw_line2d2_16,
1437: vga_draw_line2d2_16,
1438: vga_draw_line2d2_32,
1.1.1.3 root 1439: vga_draw_line2d2_32,
1.1.1.5 root 1440: vga_draw_line2d2_16,
1441: vga_draw_line2d2_16,
1.1 root 1442:
1443: vga_draw_line4_8,
1444: vga_draw_line4_16,
1445: vga_draw_line4_16,
1446: vga_draw_line4_32,
1.1.1.3 root 1447: vga_draw_line4_32,
1.1.1.5 root 1448: vga_draw_line4_16,
1449: vga_draw_line4_16,
1.1 root 1450:
1451: vga_draw_line4d2_8,
1452: vga_draw_line4d2_16,
1453: vga_draw_line4d2_16,
1454: vga_draw_line4d2_32,
1.1.1.3 root 1455: vga_draw_line4d2_32,
1.1.1.5 root 1456: vga_draw_line4d2_16,
1457: vga_draw_line4d2_16,
1.1 root 1458:
1459: vga_draw_line8d2_8,
1460: vga_draw_line8d2_16,
1461: vga_draw_line8d2_16,
1462: vga_draw_line8d2_32,
1.1.1.3 root 1463: vga_draw_line8d2_32,
1.1.1.5 root 1464: vga_draw_line8d2_16,
1465: vga_draw_line8d2_16,
1.1 root 1466:
1467: vga_draw_line8_8,
1468: vga_draw_line8_16,
1469: vga_draw_line8_16,
1470: vga_draw_line8_32,
1.1.1.3 root 1471: vga_draw_line8_32,
1.1.1.5 root 1472: vga_draw_line8_16,
1473: vga_draw_line8_16,
1.1 root 1474:
1475: vga_draw_line15_8,
1476: vga_draw_line15_15,
1477: vga_draw_line15_16,
1478: vga_draw_line15_32,
1.1.1.3 root 1479: vga_draw_line15_32bgr,
1.1.1.5 root 1480: vga_draw_line15_15bgr,
1481: vga_draw_line15_16bgr,
1.1 root 1482:
1483: vga_draw_line16_8,
1484: vga_draw_line16_15,
1485: vga_draw_line16_16,
1486: vga_draw_line16_32,
1.1.1.3 root 1487: vga_draw_line16_32bgr,
1.1.1.5 root 1488: vga_draw_line16_15bgr,
1489: vga_draw_line16_16bgr,
1.1 root 1490:
1491: vga_draw_line24_8,
1492: vga_draw_line24_15,
1493: vga_draw_line24_16,
1494: vga_draw_line24_32,
1.1.1.3 root 1495: vga_draw_line24_32bgr,
1.1.1.5 root 1496: vga_draw_line24_15bgr,
1497: vga_draw_line24_16bgr,
1.1 root 1498:
1499: vga_draw_line32_8,
1500: vga_draw_line32_15,
1501: vga_draw_line32_16,
1502: vga_draw_line32_32,
1.1.1.3 root 1503: vga_draw_line32_32bgr,
1.1.1.5 root 1504: vga_draw_line32_15bgr,
1505: vga_draw_line32_16bgr,
1.1.1.3 root 1506: };
1507:
1.1.1.12 root 1508: static int vga_get_bpp(VGACommonState *s)
1.1 root 1509: {
1510: int ret;
1511: #ifdef CONFIG_BOCHS_VBE
1512: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1513: ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
1.1.1.5 root 1514: } else
1.1 root 1515: #endif
1516: {
1517: ret = 0;
1518: }
1519: return ret;
1520: }
1521:
1.1.1.12 root 1522: static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
1.1 root 1523: {
1524: int width, height;
1.1.1.5 root 1525:
1.1.1.3 root 1526: #ifdef CONFIG_BOCHS_VBE
1527: if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
1528: width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
1529: height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
1.1.1.5 root 1530: } else
1.1.1.3 root 1531: #endif
1532: {
1533: width = (s->cr[0x01] + 1) * 8;
1.1.1.5 root 1534: height = s->cr[0x12] |
1535: ((s->cr[0x07] & 0x02) << 7) |
1.1.1.3 root 1536: ((s->cr[0x07] & 0x40) << 3);
1537: height = (height + 1);
1538: }
1.1 root 1539: *pwidth = width;
1540: *pheight = height;
1541: }
1542:
1.1.1.12 root 1543: void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2)
1.1 root 1544: {
1545: int y;
1546: if (y1 >= VGA_MAX_HEIGHT)
1547: return;
1548: if (y2 >= VGA_MAX_HEIGHT)
1549: y2 = VGA_MAX_HEIGHT;
1550: for(y = y1; y < y2; y++) {
1551: s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
1552: }
1553: }
1554:
1.1.1.12 root 1555: static void vga_sync_dirty_bitmap(VGACommonState *s)
1.1.1.6 root 1556: {
1557: if (s->map_addr)
1558: cpu_physical_sync_dirty_bitmap(s->map_addr, s->map_end);
1559:
1560: if (s->lfb_vram_mapped) {
1561: cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa0000, 0xa8000);
1562: cpu_physical_sync_dirty_bitmap(isa_mem_base + 0xa8000, 0xb0000);
1563: }
1.1.1.12 root 1564:
1565: #ifdef CONFIG_BOCHS_VBE
1566: if (s->vbe_mapped) {
1567: cpu_physical_sync_dirty_bitmap(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1568: VBE_DISPI_LFB_PHYSICAL_ADDRESS + s->vram_size);
1569: }
1570: #endif
1571:
1572: }
1573:
1574: void vga_dirty_log_start(VGACommonState *s)
1575: {
1576: if (kvm_enabled() && s->map_addr)
1577: kvm_log_start(s->map_addr, s->map_end - s->map_addr);
1578:
1579: if (kvm_enabled() && s->lfb_vram_mapped) {
1580: kvm_log_start(isa_mem_base + 0xa0000, 0x8000);
1581: kvm_log_start(isa_mem_base + 0xa8000, 0x8000);
1582: }
1583:
1584: #ifdef CONFIG_BOCHS_VBE
1585: if (kvm_enabled() && s->vbe_mapped) {
1586: kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1587: }
1588: #endif
1589: }
1590:
1591: void vga_dirty_log_stop(VGACommonState *s)
1592: {
1593: if (kvm_enabled() && s->map_addr)
1594: kvm_log_stop(s->map_addr, s->map_end - s->map_addr);
1595:
1596: if (kvm_enabled() && s->lfb_vram_mapped) {
1.1.1.13 root 1597: kvm_log_stop(isa_mem_base + 0xa0000, 0x8000);
1598: kvm_log_stop(isa_mem_base + 0xa8000, 0x8000);
1.1.1.12 root 1599: }
1600:
1601: #ifdef CONFIG_BOCHS_VBE
1602: if (kvm_enabled() && s->vbe_mapped) {
1603: kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size);
1604: }
1605: #endif
1606: }
1607:
1608: void vga_dirty_log_restart(VGACommonState *s)
1609: {
1610: vga_dirty_log_stop(s);
1611: vga_dirty_log_start(s);
1.1.1.6 root 1612: }
1613:
1.1.1.5 root 1614: /*
1.1 root 1615: * graphic modes
1616: */
1.1.1.12 root 1617: static void vga_draw_graphic(VGACommonState *s, int full_update)
1.1 root 1618: {
1.1.1.10 root 1619: int y1, y, update, linesize, y_start, double_scan, mask, depth;
1620: int width, height, shift_control, line_offset, bwidth, bits;
1621: ram_addr_t page0, page1, page_min, page_max;
1.1 root 1622: int disp_width, multi_scan, multi_run;
1623: uint8_t *d;
1624: uint32_t v, addr1, addr;
1625: vga_draw_line_func *vga_draw_line;
1.1.1.5 root 1626:
1.1 root 1627: full_update |= update_basic_params(s);
1628:
1.1.1.6 root 1629: if (!full_update)
1630: vga_sync_dirty_bitmap(s);
1631:
1.1 root 1632: s->get_resolution(s, &width, &height);
1633: disp_width = width;
1634:
1635: shift_control = (s->gr[0x05] >> 5) & 3;
1636: double_scan = (s->cr[0x09] >> 7);
1637: if (shift_control != 1) {
1638: multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
1639: } else {
1640: /* in CGA modes, multi_scan is ignored */
1641: /* XXX: is it correct ? */
1642: multi_scan = double_scan;
1643: }
1644: multi_run = multi_scan;
1645: if (shift_control != s->shift_control ||
1646: double_scan != s->double_scan) {
1647: full_update = 1;
1648: s->shift_control = shift_control;
1649: s->double_scan = double_scan;
1650: }
1.1.1.5 root 1651:
1.1.1.8 root 1652: if (shift_control == 0) {
1653: if (s->sr[0x01] & 8) {
1654: disp_width <<= 1;
1655: }
1656: } else if (shift_control == 1) {
1657: if (s->sr[0x01] & 8) {
1658: disp_width <<= 1;
1659: }
1660: }
1661:
1.1.1.6 root 1662: depth = s->get_bpp(s);
1663: if (s->line_offset != s->last_line_offset ||
1664: disp_width != s->last_width ||
1665: height != s->last_height ||
1666: s->last_depth != depth) {
1.1.1.12 root 1667: #if defined(HOST_WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
1.1.1.6 root 1668: if (depth == 16 || depth == 32) {
1669: #else
1670: if (depth == 32) {
1671: #endif
1.1.1.10 root 1672: qemu_free_displaysurface(s->ds);
1673: s->ds->surface = qemu_create_displaysurface_from(disp_width, height, depth,
1674: s->line_offset,
1675: s->vram_ptr + (s->start_addr * 4));
1.1.1.12 root 1676: #if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
1.1.1.10 root 1677: s->ds->surface->pf = qemu_different_endianness_pixelformat(depth);
1.1.1.6 root 1678: #endif
1.1.1.10 root 1679: dpy_resize(s->ds);
1.1.1.6 root 1680: } else {
1681: qemu_console_resize(s->ds, disp_width, height);
1682: }
1683: s->last_scr_width = disp_width;
1684: s->last_scr_height = height;
1685: s->last_width = disp_width;
1686: s->last_height = height;
1687: s->last_line_offset = s->line_offset;
1688: s->last_depth = depth;
1689: full_update = 1;
1.1.1.10 root 1690: } else if (is_buffer_shared(s->ds->surface) &&
1.1.1.6 root 1691: (full_update || s->ds->surface->data != s->vram_ptr + (s->start_addr * 4))) {
1692: s->ds->surface->data = s->vram_ptr + (s->start_addr * 4);
1693: dpy_setdata(s->ds);
1694: }
1695:
1696: s->rgb_to_pixel =
1697: rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1698:
1.1 root 1699: if (shift_control == 0) {
1700: full_update |= update_palette16(s);
1701: if (s->sr[0x01] & 8) {
1702: v = VGA_DRAW_LINE4D2;
1703: } else {
1704: v = VGA_DRAW_LINE4;
1705: }
1.1.1.6 root 1706: bits = 4;
1.1 root 1707: } else if (shift_control == 1) {
1708: full_update |= update_palette16(s);
1709: if (s->sr[0x01] & 8) {
1710: v = VGA_DRAW_LINE2D2;
1711: } else {
1712: v = VGA_DRAW_LINE2;
1713: }
1.1.1.6 root 1714: bits = 4;
1.1 root 1715: } else {
1716: switch(s->get_bpp(s)) {
1717: default:
1718: case 0:
1719: full_update |= update_palette256(s);
1720: v = VGA_DRAW_LINE8D2;
1.1.1.6 root 1721: bits = 4;
1.1 root 1722: break;
1723: case 8:
1724: full_update |= update_palette256(s);
1725: v = VGA_DRAW_LINE8;
1.1.1.6 root 1726: bits = 8;
1.1 root 1727: break;
1728: case 15:
1729: v = VGA_DRAW_LINE15;
1.1.1.6 root 1730: bits = 16;
1.1 root 1731: break;
1732: case 16:
1733: v = VGA_DRAW_LINE16;
1.1.1.6 root 1734: bits = 16;
1.1 root 1735: break;
1736: case 24:
1737: v = VGA_DRAW_LINE24;
1.1.1.6 root 1738: bits = 24;
1.1 root 1739: break;
1740: case 32:
1741: v = VGA_DRAW_LINE32;
1.1.1.6 root 1742: bits = 32;
1.1 root 1743: break;
1744: }
1745: }
1.1.1.3 root 1746: vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
1.1 root 1747:
1.1.1.6 root 1748: if (!is_buffer_shared(s->ds->surface) && s->cursor_invalidate)
1.1 root 1749: s->cursor_invalidate(s);
1.1.1.5 root 1750:
1.1 root 1751: line_offset = s->line_offset;
1752: #if 0
1753: printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
1754: width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
1755: #endif
1756: addr1 = (s->start_addr * 4);
1.1.1.6 root 1757: bwidth = (width * bits + 7) / 8;
1.1 root 1758: y_start = -1;
1.1.1.10 root 1759: page_min = -1;
1760: page_max = 0;
1.1.1.6 root 1761: d = ds_get_data(s->ds);
1762: linesize = ds_get_linesize(s->ds);
1.1 root 1763: y1 = 0;
1764: for(y = 0; y < height; y++) {
1765: addr = addr1;
1766: if (!(s->cr[0x17] & 1)) {
1767: int shift;
1768: /* CGA compatibility handling */
1769: shift = 14 + ((s->cr[0x17] >> 6) & 1);
1770: addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
1771: }
1772: if (!(s->cr[0x17] & 2)) {
1773: addr = (addr & ~0x8000) | ((y1 & 2) << 14);
1774: }
1775: page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
1776: page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
1.1.1.5 root 1777: update = full_update |
1.1 root 1778: cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
1779: cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
1780: if ((page1 - page0) > TARGET_PAGE_SIZE) {
1781: /* if wide line, can use another page */
1.1.1.5 root 1782: update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
1.1 root 1783: VGA_DIRTY_FLAG);
1784: }
1785: /* explicit invalidation for the hardware cursor */
1786: update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
1787: if (update) {
1788: if (y_start < 0)
1789: y_start = y;
1790: if (page0 < page_min)
1791: page_min = page0;
1792: if (page1 > page_max)
1793: page_max = page1;
1.1.1.6 root 1794: if (!(is_buffer_shared(s->ds->surface))) {
1795: vga_draw_line(s, d, s->vram_ptr + addr, width);
1796: if (s->cursor_draw_line)
1797: s->cursor_draw_line(s, d, y);
1798: }
1.1 root 1799: } else {
1800: if (y_start >= 0) {
1801: /* flush to display */
1.1.1.5 root 1802: dpy_update(s->ds, 0, y_start,
1.1 root 1803: disp_width, y - y_start);
1804: y_start = -1;
1805: }
1806: }
1807: if (!multi_run) {
1808: mask = (s->cr[0x17] & 3) ^ 3;
1809: if ((y1 & mask) == mask)
1810: addr1 += line_offset;
1811: y1++;
1812: multi_run = multi_scan;
1813: } else {
1814: multi_run--;
1815: }
1816: /* line compare acts on the displayed lines */
1817: if (y == s->line_compare)
1818: addr1 = 0;
1819: d += linesize;
1820: }
1821: if (y_start >= 0) {
1822: /* flush to display */
1.1.1.5 root 1823: dpy_update(s->ds, 0, y_start,
1.1 root 1824: disp_width, y - y_start);
1825: }
1826: /* reset modified pages */
1.1.1.10 root 1827: if (page_max >= page_min) {
1.1 root 1828: cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
1829: VGA_DIRTY_FLAG);
1830: }
1831: memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
1832: }
1833:
1.1.1.12 root 1834: static void vga_draw_blank(VGACommonState *s, int full_update)
1.1 root 1835: {
1836: int i, w, val;
1837: uint8_t *d;
1838:
1839: if (!full_update)
1840: return;
1841: if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
1842: return;
1.1.1.6 root 1843:
1844: s->rgb_to_pixel =
1845: rgb_to_pixel_dup_table[get_depth_index(s->ds)];
1846: if (ds_get_bits_per_pixel(s->ds) == 8)
1.1 root 1847: val = s->rgb_to_pixel(0, 0, 0);
1848: else
1849: val = 0;
1.1.1.6 root 1850: w = s->last_scr_width * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
1851: d = ds_get_data(s->ds);
1.1 root 1852: for(i = 0; i < s->last_scr_height; i++) {
1853: memset(d, val, w);
1.1.1.6 root 1854: d += ds_get_linesize(s->ds);
1.1 root 1855: }
1.1.1.5 root 1856: dpy_update(s->ds, 0, 0,
1.1 root 1857: s->last_scr_width, s->last_scr_height);
1858: }
1859:
1860: #define GMODE_TEXT 0
1861: #define GMODE_GRAPH 1
1.1.1.5 root 1862: #define GMODE_BLANK 2
1.1 root 1863:
1.1.1.2 root 1864: static void vga_update_display(void *opaque)
1.1 root 1865: {
1.1.1.12 root 1866: VGACommonState *s = opaque;
1.1 root 1867: int full_update, graphic_mode;
1868:
1.1.1.6 root 1869: if (ds_get_bits_per_pixel(s->ds) == 0) {
1.1 root 1870: /* nothing to do */
1871: } else {
1.1.1.11 root 1872: full_update = 0;
1.1 root 1873: if (!(s->ar_index & 0x20)) {
1874: graphic_mode = GMODE_BLANK;
1875: } else {
1876: graphic_mode = s->gr[6] & 1;
1877: }
1878: if (graphic_mode != s->graphic_mode) {
1879: s->graphic_mode = graphic_mode;
1880: full_update = 1;
1881: }
1882: switch(graphic_mode) {
1883: case GMODE_TEXT:
1884: vga_draw_text(s, full_update);
1885: break;
1886: case GMODE_GRAPH:
1887: vga_draw_graphic(s, full_update);
1888: break;
1889: case GMODE_BLANK:
1890: default:
1891: vga_draw_blank(s, full_update);
1892: break;
1893: }
1894: }
1895: }
1896:
1897: /* force a full display refresh */
1.1.1.2 root 1898: static void vga_invalidate_display(void *opaque)
1.1 root 1899: {
1.1.1.12 root 1900: VGACommonState *s = opaque;
1.1.1.5 root 1901:
1.1.1.11 root 1902: s->last_width = -1;
1903: s->last_height = -1;
1.1 root 1904: }
1905:
1.1.1.12 root 1906: void vga_common_reset(VGACommonState *s)
1.1 root 1907: {
1.1.1.6 root 1908: s->lfb_addr = 0;
1909: s->lfb_end = 0;
1910: s->map_addr = 0;
1911: s->map_end = 0;
1912: s->lfb_vram_mapped = 0;
1913: s->sr_index = 0;
1914: memset(s->sr, '\0', sizeof(s->sr));
1915: s->gr_index = 0;
1916: memset(s->gr, '\0', sizeof(s->gr));
1917: s->ar_index = 0;
1918: memset(s->ar, '\0', sizeof(s->ar));
1919: s->ar_flip_flop = 0;
1920: s->cr_index = 0;
1921: memset(s->cr, '\0', sizeof(s->cr));
1922: s->msr = 0;
1923: s->fcr = 0;
1924: s->st00 = 0;
1925: s->st01 = 0;
1926: s->dac_state = 0;
1927: s->dac_sub_index = 0;
1928: s->dac_read_index = 0;
1929: s->dac_write_index = 0;
1930: memset(s->dac_cache, '\0', sizeof(s->dac_cache));
1931: s->dac_8bit = 0;
1932: memset(s->palette, '\0', sizeof(s->palette));
1933: s->bank_offset = 0;
1934: #ifdef CONFIG_BOCHS_VBE
1935: s->vbe_index = 0;
1936: memset(s->vbe_regs, '\0', sizeof(s->vbe_regs));
1.1.1.13 root 1937: s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID5;
1.1.1.6 root 1938: s->vbe_start_addr = 0;
1939: s->vbe_line_offset = 0;
1940: s->vbe_bank_mask = (s->vram_size >> 16) - 1;
1941: #endif
1942: memset(s->font_offsets, '\0', sizeof(s->font_offsets));
1.1 root 1943: s->graphic_mode = -1; /* force full update */
1.1.1.6 root 1944: s->shift_control = 0;
1945: s->double_scan = 0;
1946: s->line_offset = 0;
1947: s->line_compare = 0;
1948: s->start_addr = 0;
1949: s->plane_updated = 0;
1950: s->last_cw = 0;
1951: s->last_ch = 0;
1952: s->last_width = 0;
1953: s->last_height = 0;
1954: s->last_scr_width = 0;
1955: s->last_scr_height = 0;
1956: s->cursor_start = 0;
1957: s->cursor_end = 0;
1958: s->cursor_offset = 0;
1959: memset(s->invalidated_y_table, '\0', sizeof(s->invalidated_y_table));
1960: memset(s->last_palette, '\0', sizeof(s->last_palette));
1961: memset(s->last_ch_attr, '\0', sizeof(s->last_ch_attr));
1962: switch (vga_retrace_method) {
1963: case VGA_RETRACE_DUMB:
1964: break;
1965: case VGA_RETRACE_PRECISE:
1966: memset(&s->retrace_info, 0, sizeof (s->retrace_info));
1967: break;
1968: }
1969: }
1970:
1.1.1.12 root 1971: static void vga_reset(void *opaque)
1972: {
1973: VGACommonState *s = opaque;
1974: vga_common_reset(s);
1975: }
1976:
1.1.1.6 root 1977: #define TEXTMODE_X(x) ((x) % width)
1978: #define TEXTMODE_Y(x) ((x) / width)
1979: #define VMEM2CHTYPE(v) ((v & 0xff0007ff) | \
1980: ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
1981: /* relay text rendering to the display driver
1982: * instead of doing a full vga_update_display() */
1983: static void vga_update_text(void *opaque, console_ch_t *chardata)
1984: {
1.1.1.12 root 1985: VGACommonState *s = opaque;
1.1.1.6 root 1986: int graphic_mode, i, cursor_offset, cursor_visible;
1987: int cw, cheight, width, height, size, c_min, c_max;
1988: uint32_t *src;
1989: console_ch_t *dst, val;
1990: char msg_buffer[80];
1991: int full_update = 0;
1992:
1993: if (!(s->ar_index & 0x20)) {
1994: graphic_mode = GMODE_BLANK;
1995: } else {
1996: graphic_mode = s->gr[6] & 1;
1997: }
1998: if (graphic_mode != s->graphic_mode) {
1999: s->graphic_mode = graphic_mode;
2000: full_update = 1;
2001: }
2002: if (s->last_width == -1) {
2003: s->last_width = 0;
2004: full_update = 1;
2005: }
2006:
2007: switch (graphic_mode) {
2008: case GMODE_TEXT:
2009: /* TODO: update palette */
2010: full_update |= update_basic_params(s);
2011:
2012: /* total width & height */
2013: cheight = (s->cr[9] & 0x1f) + 1;
2014: cw = 8;
2015: if (!(s->sr[1] & 0x01))
2016: cw = 9;
2017: if (s->sr[1] & 0x08)
2018: cw = 16; /* NOTE: no 18 pixel wide */
2019: width = (s->cr[0x01] + 1);
2020: if (s->cr[0x06] == 100) {
2021: /* ugly hack for CGA 160x100x16 - explain me the logic */
2022: height = 100;
2023: } else {
2024: height = s->cr[0x12] |
2025: ((s->cr[0x07] & 0x02) << 7) |
2026: ((s->cr[0x07] & 0x40) << 3);
2027: height = (height + 1) / cheight;
2028: }
2029:
2030: size = (height * width);
2031: if (size > CH_ATTR_SIZE) {
2032: if (!full_update)
2033: return;
2034:
2035: snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Text mode",
2036: width, height);
2037: break;
2038: }
2039:
2040: if (width != s->last_width || height != s->last_height ||
2041: cw != s->last_cw || cheight != s->last_ch) {
2042: s->last_scr_width = width * cw;
2043: s->last_scr_height = height * cheight;
2044: s->ds->surface->width = width;
2045: s->ds->surface->height = height;
2046: dpy_resize(s->ds);
2047: s->last_width = width;
2048: s->last_height = height;
2049: s->last_ch = cheight;
2050: s->last_cw = cw;
2051: full_update = 1;
2052: }
2053:
2054: /* Update "hardware" cursor */
2055: cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
2056: if (cursor_offset != s->cursor_offset ||
2057: s->cr[0xa] != s->cursor_start ||
2058: s->cr[0xb] != s->cursor_end || full_update) {
2059: cursor_visible = !(s->cr[0xa] & 0x20);
2060: if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
2061: dpy_cursor(s->ds,
2062: TEXTMODE_X(cursor_offset),
2063: TEXTMODE_Y(cursor_offset));
2064: else
2065: dpy_cursor(s->ds, -1, -1);
2066: s->cursor_offset = cursor_offset;
2067: s->cursor_start = s->cr[0xa];
2068: s->cursor_end = s->cr[0xb];
2069: }
2070:
2071: src = (uint32_t *) s->vram_ptr + s->start_addr;
2072: dst = chardata;
2073:
2074: if (full_update) {
2075: for (i = 0; i < size; src ++, dst ++, i ++)
1.1.1.14! root 2076: console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
1.1.1.6 root 2077:
2078: dpy_update(s->ds, 0, 0, width, height);
2079: } else {
2080: c_max = 0;
2081:
2082: for (i = 0; i < size; src ++, dst ++, i ++) {
1.1.1.14! root 2083: console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1.1.1.6 root 2084: if (*dst != val) {
2085: *dst = val;
2086: c_max = i;
2087: break;
2088: }
2089: }
2090: c_min = i;
2091: for (; i < size; src ++, dst ++, i ++) {
1.1.1.14! root 2092: console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
1.1.1.6 root 2093: if (*dst != val) {
2094: *dst = val;
2095: c_max = i;
2096: }
2097: }
2098:
2099: if (c_min <= c_max) {
2100: i = TEXTMODE_Y(c_min);
2101: dpy_update(s->ds, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
2102: }
2103: }
2104:
2105: return;
2106: case GMODE_GRAPH:
2107: if (!full_update)
2108: return;
2109:
2110: s->get_resolution(s, &width, &height);
2111: snprintf(msg_buffer, sizeof(msg_buffer), "%i x %i Graphic mode",
2112: width, height);
2113: break;
2114: case GMODE_BLANK:
2115: default:
2116: if (!full_update)
2117: return;
2118:
2119: snprintf(msg_buffer, sizeof(msg_buffer), "VGA Blank mode");
2120: break;
2121: }
2122:
2123: /* Display a message */
2124: s->last_width = 60;
2125: s->last_height = height = 3;
2126: dpy_cursor(s->ds, -1, -1);
2127: s->ds->surface->width = s->last_width;
2128: s->ds->surface->height = height;
2129: dpy_resize(s->ds);
2130:
2131: for (dst = chardata, i = 0; i < s->last_width * height; i ++)
2132: console_write_ch(dst ++, ' ');
2133:
2134: size = strlen(msg_buffer);
2135: width = (s->last_width - size) / 2;
2136: dst = chardata + s->last_width + width;
2137: for (i = 0; i < size; i ++)
2138: console_write_ch(dst ++, 0x00200100 | msg_buffer[i]);
2139:
2140: dpy_update(s->ds, 0, 0, s->last_width, height);
1.1 root 2141: }
2142:
1.1.1.12 root 2143: CPUReadMemoryFunc * const vga_mem_read[3] = {
1.1 root 2144: vga_mem_readb,
2145: vga_mem_readw,
2146: vga_mem_readl,
2147: };
2148:
1.1.1.12 root 2149: CPUWriteMemoryFunc * const vga_mem_write[3] = {
1.1 root 2150: vga_mem_writeb,
2151: vga_mem_writew,
2152: vga_mem_writel,
2153: };
2154:
1.1.1.12 root 2155: static int vga_common_post_load(void *opaque, int version_id)
1.1 root 2156: {
1.1.1.12 root 2157: VGACommonState *s = opaque;
1.1 root 2158:
2159: /* force refresh */
2160: s->graphic_mode = -1;
2161: return 0;
2162: }
2163:
1.1.1.12 root 2164: const VMStateDescription vmstate_vga_common = {
2165: .name = "vga",
2166: .version_id = 2,
2167: .minimum_version_id = 2,
2168: .minimum_version_id_old = 2,
2169: .post_load = vga_common_post_load,
2170: .fields = (VMStateField []) {
2171: VMSTATE_UINT32(latch, VGACommonState),
2172: VMSTATE_UINT8(sr_index, VGACommonState),
2173: VMSTATE_PARTIAL_BUFFER(sr, VGACommonState, 8),
2174: VMSTATE_UINT8(gr_index, VGACommonState),
2175: VMSTATE_PARTIAL_BUFFER(gr, VGACommonState, 16),
2176: VMSTATE_UINT8(ar_index, VGACommonState),
2177: VMSTATE_BUFFER(ar, VGACommonState),
2178: VMSTATE_INT32(ar_flip_flop, VGACommonState),
2179: VMSTATE_UINT8(cr_index, VGACommonState),
2180: VMSTATE_BUFFER(cr, VGACommonState),
2181: VMSTATE_UINT8(msr, VGACommonState),
2182: VMSTATE_UINT8(fcr, VGACommonState),
2183: VMSTATE_UINT8(st00, VGACommonState),
2184: VMSTATE_UINT8(st01, VGACommonState),
2185:
2186: VMSTATE_UINT8(dac_state, VGACommonState),
2187: VMSTATE_UINT8(dac_sub_index, VGACommonState),
2188: VMSTATE_UINT8(dac_read_index, VGACommonState),
2189: VMSTATE_UINT8(dac_write_index, VGACommonState),
2190: VMSTATE_BUFFER(dac_cache, VGACommonState),
2191: VMSTATE_BUFFER(palette, VGACommonState),
1.1.1.4 root 2192:
1.1.1.12 root 2193: VMSTATE_INT32(bank_offset, VGACommonState),
2194: VMSTATE_UINT8_EQUAL(is_vbe_vmstate, VGACommonState),
2195: #ifdef CONFIG_BOCHS_VBE
2196: VMSTATE_UINT16(vbe_index, VGACommonState),
2197: VMSTATE_UINT16_ARRAY(vbe_regs, VGACommonState, VBE_DISPI_INDEX_NB),
2198: VMSTATE_UINT32(vbe_start_addr, VGACommonState),
2199: VMSTATE_UINT32(vbe_line_offset, VGACommonState),
2200: VMSTATE_UINT32(vbe_bank_mask, VGACommonState),
2201: #endif
2202: VMSTATE_END_OF_LIST()
1.1 root 2203: }
1.1.1.12 root 2204: };
1.1 root 2205:
1.1.1.12 root 2206: void vga_common_init(VGACommonState *s, int vga_ram_size)
1.1 root 2207: {
2208: int i, j, v, b;
2209:
2210: for(i = 0;i < 256; i++) {
2211: v = 0;
2212: for(j = 0; j < 8; j++) {
2213: v |= ((i >> j) & 1) << (j * 4);
2214: }
2215: expand4[i] = v;
2216:
2217: v = 0;
2218: for(j = 0; j < 4; j++) {
2219: v |= ((i >> (2 * j)) & 3) << (j * 4);
2220: }
2221: expand2[i] = v;
2222: }
2223: for(i = 0; i < 16; i++) {
2224: v = 0;
2225: for(j = 0; j < 4; j++) {
2226: b = ((i >> j) & 1);
2227: v |= b << (2 * j);
2228: v |= b << (2 * j + 1);
2229: }
2230: expand4to8[i] = v;
2231: }
2232:
1.1.1.12 root 2233: #ifdef CONFIG_BOCHS_VBE
2234: s->is_vbe_vmstate = 1;
2235: #else
2236: s->is_vbe_vmstate = 0;
2237: #endif
1.1.1.13 root 2238: s->vram_offset = qemu_ram_alloc(NULL, "vga.vram", vga_ram_size);
1.1.1.10 root 2239: s->vram_ptr = qemu_get_ram_ptr(s->vram_offset);
1.1 root 2240: s->vram_size = vga_ram_size;
2241: s->get_bpp = vga_get_bpp;
2242: s->get_offsets = vga_get_offsets;
2243: s->get_resolution = vga_get_resolution;
1.1.1.5 root 2244: s->update = vga_update_display;
2245: s->invalidate = vga_invalidate_display;
2246: s->screen_dump = vga_screen_dump;
1.1.1.6 root 2247: s->text_update = vga_update_text;
2248: switch (vga_retrace_method) {
2249: case VGA_RETRACE_DUMB:
2250: s->retrace = vga_dumb_retrace;
2251: s->update_retrace_info = vga_dumb_update_retrace_info;
2252: break;
2253:
2254: case VGA_RETRACE_PRECISE:
2255: s->retrace = vga_precise_retrace;
2256: s->update_retrace_info = vga_precise_update_retrace_info;
2257: break;
2258: }
1.1 root 2259: }
2260:
1.1.1.4 root 2261: /* used by both ISA and PCI */
1.1.1.12 root 2262: void vga_init(VGACommonState *s)
1.1 root 2263: {
1.1.1.4 root 2264: int vga_io_memory;
1.1 root 2265:
1.1.1.6 root 2266: qemu_register_reset(vga_reset, s);
1.1 root 2267:
2268: register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
2269:
2270: register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
2271: register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
2272: register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
2273: register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
2274:
2275: register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
2276:
2277: register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
2278: register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
2279: register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
2280: register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
2281: s->bank_offset = 0;
2282:
2283: #ifdef CONFIG_BOCHS_VBE
2284: #if defined (TARGET_I386)
2285: register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2286: register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
2287:
2288: register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2289: register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
2290: #else
2291: register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
2292: register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
2293:
2294: register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
2295: register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
2296: #endif
2297: #endif /* CONFIG_BOCHS_VBE */
2298:
1.1.1.14! root 2299: vga_io_memory = cpu_register_io_memory(vga_mem_read, vga_mem_write, s,
! 2300: DEVICE_LITTLE_ENDIAN);
1.1.1.5 root 2301: cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
1.1 root 2302: vga_io_memory);
1.1.1.6 root 2303: qemu_register_coalesced_mmio(isa_mem_base + 0x000a0000, 0x20000);
1.1.1.4 root 2304: }
1.1 root 2305:
1.1.1.12 root 2306: void vga_init_vbe(VGACommonState *s)
1.1.1.4 root 2307: {
1.1 root 2308: #ifdef CONFIG_BOCHS_VBE
1.1.1.4 root 2309: /* XXX: use optimized standard vga accesses */
1.1.1.5 root 2310: cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
1.1.1.10 root 2311: VGA_RAM_SIZE, s->vram_offset);
1.1.1.12 root 2312: s->vbe_mapped = 1;
2313: #endif
1.1.1.4 root 2314: }
1.1 root 2315: /********************************************************/
2316: /* vga screen dump */
2317:
1.1.1.10 root 2318: static void vga_save_dpy_update(DisplayState *ds,
1.1 root 2319: int x, int y, int w, int h)
2320: {
1.1.1.10 root 2321: if (screen_dump_filename) {
2322: ppm_save(screen_dump_filename, ds->surface);
2323: screen_dump_filename = NULL;
2324: }
1.1 root 2325: }
2326:
1.1.1.6 root 2327: static void vga_save_dpy_resize(DisplayState *s)
1.1 root 2328: {
2329: }
2330:
2331: static void vga_save_dpy_refresh(DisplayState *s)
2332: {
2333: }
2334:
1.1.1.6 root 2335: int ppm_save(const char *filename, struct DisplaySurface *ds)
1.1 root 2336: {
2337: FILE *f;
2338: uint8_t *d, *d1;
1.1.1.6 root 2339: uint32_t v;
1.1 root 2340: int y, x;
1.1.1.6 root 2341: uint8_t r, g, b;
1.1 root 2342:
2343: f = fopen(filename, "wb");
2344: if (!f)
2345: return -1;
2346: fprintf(f, "P6\n%d %d\n%d\n",
1.1.1.6 root 2347: ds->width, ds->height, 255);
2348: d1 = ds->data;
2349: for(y = 0; y < ds->height; y++) {
1.1 root 2350: d = d1;
1.1.1.6 root 2351: for(x = 0; x < ds->width; x++) {
2352: if (ds->pf.bits_per_pixel == 32)
2353: v = *(uint32_t *)d;
2354: else
2355: v = (uint32_t) (*(uint16_t *)d);
2356: r = ((v >> ds->pf.rshift) & ds->pf.rmax) * 256 /
2357: (ds->pf.rmax + 1);
2358: g = ((v >> ds->pf.gshift) & ds->pf.gmax) * 256 /
2359: (ds->pf.gmax + 1);
2360: b = ((v >> ds->pf.bshift) & ds->pf.bmax) * 256 /
2361: (ds->pf.bmax + 1);
2362: fputc(r, f);
2363: fputc(g, f);
2364: fputc(b, f);
2365: d += ds->pf.bytes_per_pixel;
1.1 root 2366: }
1.1.1.6 root 2367: d1 += ds->linesize;
1.1 root 2368: }
2369: fclose(f);
2370: return 0;
2371: }
2372:
1.1.1.10 root 2373: static DisplayChangeListener* vga_screen_dump_init(DisplayState *ds)
1.1.1.6 root 2374: {
1.1.1.10 root 2375: DisplayChangeListener *dcl;
1.1.1.6 root 2376:
1.1.1.10 root 2377: dcl = qemu_mallocz(sizeof(DisplayChangeListener));
2378: dcl->dpy_update = vga_save_dpy_update;
2379: dcl->dpy_resize = vga_save_dpy_resize;
2380: dcl->dpy_refresh = vga_save_dpy_refresh;
2381: register_displaychangelistener(ds, dcl);
2382: return dcl;
1.1.1.6 root 2383: }
2384:
2385: /* save the vga display in a PPM image even if no display is
2386: available */
2387: static void vga_screen_dump(void *opaque, const char *filename)
2388: {
1.1.1.12 root 2389: VGACommonState *s = opaque;
1.1.1.6 root 2390:
1.1.1.10 root 2391: if (!screen_dump_dcl)
2392: screen_dump_dcl = vga_screen_dump_init(s->ds);
2393:
2394: screen_dump_filename = (char *)filename;
1.1.1.9 root 2395: vga_invalidate_display(s);
1.1.1.10 root 2396: vga_hw_update();
1.1.1.6 root 2397: }
1.1.1.10 root 2398:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.