Commit 313aa567104a63fbe84d6ec2eeff5b5c81cb3524
1 parent
4cbf74b6
added VGA emulation - added PS/2 mouse and keyboard emulation - use SDL for VGA display
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@356 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
454 additions
and
120 deletions
vl.c
| ... | ... | @@ -74,6 +74,9 @@ |
| 74 | 74 | /* debug PC keyboard */ |
| 75 | 75 | //#define DEBUG_KBD |
| 76 | 76 | |
| 77 | +/* debug PC keyboard : only mouse */ | |
| 78 | +//#define DEBUG_MOUSE | |
| 79 | + | |
| 77 | 80 | #define PHYS_RAM_BASE 0xac000000 |
| 78 | 81 | #define PHYS_RAM_MAX_SIZE (256 * 1024 * 1024) |
| 79 | 82 | |
| ... | ... | @@ -81,6 +84,8 @@ |
| 81 | 84 | #define INITRD_LOAD_ADDR 0x00400000 |
| 82 | 85 | #define KERNEL_PARAMS_ADDR 0x00090000 |
| 83 | 86 | |
| 87 | +#define GUI_REFRESH_INTERVAL 30 | |
| 88 | + | |
| 84 | 89 | #define MAX_DISKS 2 |
| 85 | 90 | |
| 86 | 91 | /* from plex86 (BSD license) */ |
| ... | ... | @@ -198,9 +203,6 @@ struct __attribute__ ((packed)) linux_params { |
| 198 | 203 | #define KERNEL_CS 0x10 |
| 199 | 204 | #define KERNEL_DS 0x18 |
| 200 | 205 | |
| 201 | -typedef void (IOPortWriteFunc)(CPUX86State *env, uint32_t address, uint32_t data); | |
| 202 | -typedef uint32_t (IOPortReadFunc)(CPUX86State *env, uint32_t address); | |
| 203 | - | |
| 204 | 206 | #define MAX_IOPORTS 4096 |
| 205 | 207 | |
| 206 | 208 | static const char *interp_prefix = CONFIG_QEMU_PREFIX; |
| ... | ... | @@ -212,6 +214,11 @@ int loglevel; |
| 212 | 214 | IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS]; |
| 213 | 215 | IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; |
| 214 | 216 | BlockDriverState *bs_table[MAX_DISKS]; |
| 217 | +int vga_ram_size; | |
| 218 | +static DisplayState display_state; | |
| 219 | +int nodisp; | |
| 220 | +int term_inited; | |
| 221 | +int64_t ticks_per_sec; | |
| 215 | 222 | |
| 216 | 223 | /***********************************************************/ |
| 217 | 224 | /* x86 io ports */ |
| ... | ... | @@ -431,49 +438,6 @@ void hw_error(const char *fmt, ...) |
| 431 | 438 | } |
| 432 | 439 | |
| 433 | 440 | /***********************************************************/ |
| 434 | -/* vga emulation */ | |
| 435 | -static uint8_t vga_index; | |
| 436 | -static uint8_t vga_regs[256]; | |
| 437 | -static int last_cursor_pos; | |
| 438 | - | |
| 439 | -void update_console_messages(void) | |
| 440 | -{ | |
| 441 | - int c, i, cursor_pos, eol; | |
| 442 | - | |
| 443 | - cursor_pos = vga_regs[0x0f] | (vga_regs[0x0e] << 8); | |
| 444 | - eol = 0; | |
| 445 | - for(i = last_cursor_pos; i < cursor_pos; i++) { | |
| 446 | - c = phys_ram_base[0xb8000 + (i) * 2]; | |
| 447 | - if (c >= ' ') { | |
| 448 | - putchar(c); | |
| 449 | - eol = 0; | |
| 450 | - } else { | |
| 451 | - if (!eol) | |
| 452 | - putchar('\n'); | |
| 453 | - eol = 1; | |
| 454 | - } | |
| 455 | - } | |
| 456 | - fflush(stdout); | |
| 457 | - last_cursor_pos = cursor_pos; | |
| 458 | -} | |
| 459 | - | |
| 460 | -/* just to see first Linux console messages, we intercept cursor position */ | |
| 461 | -void vga_ioport_write(CPUX86State *env, uint32_t addr, uint32_t data) | |
| 462 | -{ | |
| 463 | - switch(addr) { | |
| 464 | - case 0x3d4: | |
| 465 | - vga_index = data; | |
| 466 | - break; | |
| 467 | - case 0x3d5: | |
| 468 | - vga_regs[vga_index] = data; | |
| 469 | - if (vga_index == 0x0f) | |
| 470 | - update_console_messages(); | |
| 471 | - break; | |
| 472 | - } | |
| 473 | - | |
| 474 | -} | |
| 475 | - | |
| 476 | -/***********************************************************/ | |
| 477 | 441 | /* cmos emulation */ |
| 478 | 442 | |
| 479 | 443 | #define RTC_SECONDS 0 |
| ... | ... | @@ -555,6 +519,7 @@ void cmos_init(void) |
| 555 | 519 | /* various important CMOS locations needed by PC/Bochs bios */ |
| 556 | 520 | |
| 557 | 521 | cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ |
| 522 | + cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ | |
| 558 | 523 | |
| 559 | 524 | /* memory size */ |
| 560 | 525 | val = (phys_ram_size / 1024) - 1024; |
| ... | ... | @@ -674,13 +639,13 @@ static void pic_update_irq(void) |
| 674 | 639 | int64_t irq_time[16]; |
| 675 | 640 | int64_t cpu_get_ticks(void); |
| 676 | 641 | #endif |
| 677 | -#ifdef DEBUG_PIC | |
| 642 | +#if defined(DEBUG_PIC) | |
| 678 | 643 | int irq_level[16]; |
| 679 | 644 | #endif |
| 680 | 645 | |
| 681 | 646 | void pic_set_irq(int irq, int level) |
| 682 | 647 | { |
| 683 | -#ifdef DEBUG_PIC | |
| 648 | +#if defined(DEBUG_PIC) | |
| 684 | 649 | if (level != irq_level[irq]) { |
| 685 | 650 | printf("pic_set_irq: irq=%d level=%d\n", irq, level); |
| 686 | 651 | irq_level[irq] = level; |
| ... | ... | @@ -702,7 +667,9 @@ int cpu_x86_get_pic_interrupt(CPUX86State *env) |
| 702 | 667 | /* signal the pic that the irq was acked by the CPU */ |
| 703 | 668 | irq = pic_irq_requested; |
| 704 | 669 | #ifdef DEBUG_IRQ_LATENCY |
| 705 | - printf("IRQ%d latency=%Ld\n", irq, cpu_get_ticks() - irq_time[irq]); | |
| 670 | + printf("IRQ%d latency=%0.3fus\n", | |
| 671 | + irq, | |
| 672 | + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); | |
| 706 | 673 | #endif |
| 707 | 674 | #ifdef DEBUG_PIC |
| 708 | 675 | printf("pic_interrupt: irq=%d\n", irq); |
| ... | ... | @@ -761,18 +728,22 @@ void pic_ioport_write(CPUX86State *env, uint32_t addr, uint32_t val) |
| 761 | 728 | } |
| 762 | 729 | if (val == 0xa0) |
| 763 | 730 | s->priority_add = (s->priority_add + 1) & 7; |
| 731 | + pic_update_irq(); | |
| 764 | 732 | break; |
| 765 | 733 | case 0x60 ... 0x67: |
| 766 | 734 | priority = val & 7; |
| 767 | 735 | s->isr &= ~(1 << priority); |
| 736 | + pic_update_irq(); | |
| 768 | 737 | break; |
| 769 | 738 | case 0xc0 ... 0xc7: |
| 770 | 739 | s->priority_add = (val + 1) & 7; |
| 740 | + pic_update_irq(); | |
| 771 | 741 | break; |
| 772 | 742 | case 0xe0 ... 0xe7: |
| 773 | 743 | priority = val & 7; |
| 774 | 744 | s->isr &= ~(1 << priority); |
| 775 | 745 | s->priority_add = (priority + 1) & 7; |
| 746 | + pic_update_irq(); | |
| 776 | 747 | break; |
| 777 | 748 | } |
| 778 | 749 | } |
| ... | ... | @@ -861,8 +832,6 @@ int speaker_data_on; |
| 861 | 832 | int dummy_refresh_clock; |
| 862 | 833 | int pit_min_timer_count = 0; |
| 863 | 834 | |
| 864 | -int64_t ticks_per_sec; | |
| 865 | - | |
| 866 | 835 | int64_t get_clock(void) |
| 867 | 836 | { |
| 868 | 837 | struct timeval tv; |
| ... | ... | @@ -1354,37 +1323,6 @@ void serial_received_byte(SerialState *s, int ch) |
| 1354 | 1323 | } |
| 1355 | 1324 | } |
| 1356 | 1325 | |
| 1357 | -/* init terminal so that we can grab keys */ | |
| 1358 | -static struct termios oldtty; | |
| 1359 | - | |
| 1360 | -static void term_exit(void) | |
| 1361 | -{ | |
| 1362 | - tcsetattr (0, TCSANOW, &oldtty); | |
| 1363 | -} | |
| 1364 | - | |
| 1365 | -static void term_init(void) | |
| 1366 | -{ | |
| 1367 | - struct termios tty; | |
| 1368 | - | |
| 1369 | - tcgetattr (0, &tty); | |
| 1370 | - oldtty = tty; | |
| 1371 | - | |
| 1372 | - tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | |
| 1373 | - |INLCR|IGNCR|ICRNL|IXON); | |
| 1374 | - tty.c_oflag |= OPOST; | |
| 1375 | - tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); | |
| 1376 | - tty.c_cflag &= ~(CSIZE|PARENB); | |
| 1377 | - tty.c_cflag |= CS8; | |
| 1378 | - tty.c_cc[VMIN] = 1; | |
| 1379 | - tty.c_cc[VTIME] = 0; | |
| 1380 | - | |
| 1381 | - tcsetattr (0, TCSANOW, &tty); | |
| 1382 | - | |
| 1383 | - atexit(term_exit); | |
| 1384 | - | |
| 1385 | - fcntl(0, F_SETFL, O_NONBLOCK); | |
| 1386 | -} | |
| 1387 | - | |
| 1388 | 1326 | void serial_init(void) |
| 1389 | 1327 | { |
| 1390 | 1328 | SerialState *s = &serial_ports[0]; |
| ... | ... | @@ -1393,8 +1331,6 @@ void serial_init(void) |
| 1393 | 1331 | |
| 1394 | 1332 | register_ioport_write(0x3f8, 8, serial_ioport_write, 1); |
| 1395 | 1333 | register_ioport_read(0x3f8, 8, serial_ioport_read, 1); |
| 1396 | - | |
| 1397 | - term_init(); | |
| 1398 | 1334 | } |
| 1399 | 1335 | |
| 1400 | 1336 | /***********************************************************/ |
| ... | ... | @@ -2597,69 +2533,111 @@ void ide_init(void) |
| 2597 | 2533 | #define KBD_MODE_RFU 0x80 |
| 2598 | 2534 | |
| 2599 | 2535 | /* Mouse Commands */ |
| 2600 | -#define AUX_SET_RES 0xE8 /* Set resolution */ | |
| 2601 | 2536 | #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ |
| 2602 | 2537 | #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ |
| 2538 | +#define AUX_SET_RES 0xE8 /* Set resolution */ | |
| 2603 | 2539 | #define AUX_GET_SCALE 0xE9 /* Get scaling factor */ |
| 2604 | 2540 | #define AUX_SET_STREAM 0xEA /* Set stream mode */ |
| 2541 | +#define AUX_POLL 0xEB /* Poll */ | |
| 2542 | +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ | |
| 2543 | +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ | |
| 2544 | +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ | |
| 2545 | +#define AUX_GET_TYPE 0xF2 /* Get type */ | |
| 2605 | 2546 | #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ |
| 2606 | 2547 | #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ |
| 2607 | 2548 | #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ |
| 2549 | +#define AUX_SET_DEFAULT 0xF6 | |
| 2608 | 2550 | #define AUX_RESET 0xFF /* Reset aux device */ |
| 2609 | 2551 | #define AUX_ACK 0xFA /* Command byte ACK. */ |
| 2610 | 2552 | |
| 2611 | -#define KBD_QUEUE_SIZE 64 | |
| 2553 | +#define MOUSE_STATUS_REMOTE 0x40 | |
| 2554 | +#define MOUSE_STATUS_ENABLED 0x20 | |
| 2555 | +#define MOUSE_STATUS_SCALE21 0x10 | |
| 2556 | + | |
| 2557 | +#define KBD_QUEUE_SIZE 256 | |
| 2612 | 2558 | |
| 2613 | 2559 | typedef struct { |
| 2614 | 2560 | uint8_t data[KBD_QUEUE_SIZE]; |
| 2615 | 2561 | int rptr, wptr, count; |
| 2616 | 2562 | } KBDQueue; |
| 2617 | 2563 | |
| 2618 | -enum KBDWriteState { | |
| 2619 | - KBD_STATE_CMD = 0, | |
| 2620 | - KBD_STATE_LED, | |
| 2621 | -}; | |
| 2622 | - | |
| 2623 | 2564 | typedef struct KBDState { |
| 2624 | 2565 | KBDQueue queues[2]; |
| 2625 | 2566 | uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ |
| 2626 | 2567 | uint8_t status; |
| 2627 | 2568 | uint8_t mode; |
| 2569 | + /* keyboard state */ | |
| 2628 | 2570 | int kbd_write_cmd; |
| 2629 | 2571 | int scan_enabled; |
| 2572 | + /* mouse state */ | |
| 2573 | + int mouse_write_cmd; | |
| 2574 | + uint8_t mouse_status; | |
| 2575 | + uint8_t mouse_resolution; | |
| 2576 | + uint8_t mouse_sample_rate; | |
| 2577 | + uint8_t mouse_wrap; | |
| 2578 | + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ | |
| 2579 | + uint8_t mouse_detect_state; | |
| 2580 | + int mouse_dx; /* current values, needed for 'poll' mode */ | |
| 2581 | + int mouse_dy; | |
| 2582 | + int mouse_dz; | |
| 2583 | + uint8_t mouse_buttons; | |
| 2630 | 2584 | } KBDState; |
| 2631 | 2585 | |
| 2632 | 2586 | KBDState kbd_state; |
| 2633 | 2587 | int reset_requested; |
| 2634 | 2588 | int a20_enabled; |
| 2635 | 2589 | |
| 2590 | +/* update irq and KBD_STAT_[MOUSE_]OBF */ | |
| 2636 | 2591 | static void kbd_update_irq(KBDState *s) |
| 2637 | 2592 | { |
| 2638 | - int level; | |
| 2639 | - | |
| 2640 | - level = ((s->status & KBD_STAT_OBF) && (s->mode & KBD_MODE_KBD_INT)); | |
| 2641 | - pic_set_irq(1, level); | |
| 2642 | - | |
| 2643 | - level = ((s->status & KBD_STAT_MOUSE_OBF) && (s->mode & KBD_MODE_MOUSE_INT)); | |
| 2644 | - pic_set_irq(12, level); | |
| 2593 | + int irq12_level, irq1_level; | |
| 2594 | + | |
| 2595 | + irq1_level = 0; | |
| 2596 | + irq12_level = 0; | |
| 2597 | + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); | |
| 2598 | + if (s->queues[0].count != 0 || | |
| 2599 | + s->queues[1].count != 0) { | |
| 2600 | + s->status |= KBD_STAT_OBF; | |
| 2601 | + if (s->queues[1].count != 0) { | |
| 2602 | + s->status |= KBD_STAT_MOUSE_OBF; | |
| 2603 | + if (s->mode & KBD_MODE_MOUSE_INT) | |
| 2604 | + irq12_level = 1; | |
| 2605 | + } else { | |
| 2606 | + if (s->mode & KBD_MODE_KBD_INT) | |
| 2607 | + irq1_level = 1; | |
| 2608 | + } | |
| 2609 | + } | |
| 2610 | + pic_set_irq(1, irq1_level); | |
| 2611 | + pic_set_irq(12, irq12_level); | |
| 2645 | 2612 | } |
| 2646 | 2613 | |
| 2647 | 2614 | static void kbd_queue(KBDState *s, int b, int aux) |
| 2648 | 2615 | { |
| 2649 | 2616 | KBDQueue *q = &kbd_state.queues[aux]; |
| 2650 | 2617 | |
| 2618 | +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) | |
| 2619 | + if (aux) | |
| 2620 | + printf("mouse event: 0x%02x\n", b); | |
| 2621 | +#ifdef DEBUG_KBD | |
| 2622 | + else | |
| 2623 | + printf("kbd event: 0x%02x\n", b); | |
| 2624 | +#endif | |
| 2625 | +#endif | |
| 2651 | 2626 | if (q->count >= KBD_QUEUE_SIZE) |
| 2652 | 2627 | return; |
| 2653 | 2628 | q->data[q->wptr] = b; |
| 2654 | 2629 | if (++q->wptr == KBD_QUEUE_SIZE) |
| 2655 | 2630 | q->wptr = 0; |
| 2656 | 2631 | q->count++; |
| 2657 | - s->status |= KBD_STAT_OBF; | |
| 2658 | - if (aux) | |
| 2659 | - s->status |= KBD_STAT_MOUSE_OBF; | |
| 2660 | 2632 | kbd_update_irq(s); |
| 2661 | 2633 | } |
| 2662 | 2634 | |
| 2635 | +void kbd_put_keycode(int keycode) | |
| 2636 | +{ | |
| 2637 | + KBDState *s = &kbd_state; | |
| 2638 | + kbd_queue(s, keycode, 0); | |
| 2639 | +} | |
| 2640 | + | |
| 2663 | 2641 | uint32_t kbd_read_status(CPUX86State *env, uint32_t addr) |
| 2664 | 2642 | { |
| 2665 | 2643 | KBDState *s = &kbd_state; |
| ... | ... | @@ -2745,9 +2723,9 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) |
| 2745 | 2723 | KBDQueue *q; |
| 2746 | 2724 | int val; |
| 2747 | 2725 | |
| 2748 | - q = &s->queues[1]; /* first check AUX data */ | |
| 2726 | + q = &s->queues[0]; /* first check KBD data */ | |
| 2749 | 2727 | if (q->count == 0) |
| 2750 | - q = &s->queues[0]; /* then check KBD data */ | |
| 2728 | + q = &s->queues[1]; /* then check AUX data */ | |
| 2751 | 2729 | if (q->count == 0) { |
| 2752 | 2730 | /* XXX: return something else ? */ |
| 2753 | 2731 | val = 0; |
| ... | ... | @@ -2756,14 +2734,14 @@ uint32_t kbd_read_data(CPUX86State *env, uint32_t addr) |
| 2756 | 2734 | if (++q->rptr == KBD_QUEUE_SIZE) |
| 2757 | 2735 | q->rptr = 0; |
| 2758 | 2736 | q->count--; |
| 2737 | + /* reading deasserts IRQ */ | |
| 2738 | + if (q == &s->queues[0]) | |
| 2739 | + pic_set_irq(1, 0); | |
| 2740 | + else | |
| 2741 | + pic_set_irq(12, 0); | |
| 2759 | 2742 | } |
| 2760 | - if (s->queues[1].count == 0) { | |
| 2761 | - s->status &= ~KBD_STAT_MOUSE_OBF; | |
| 2762 | - if (s->queues[0].count == 0) | |
| 2763 | - s->status &= ~KBD_STAT_OBF; | |
| 2764 | - kbd_update_irq(s); | |
| 2765 | - } | |
| 2766 | - | |
| 2743 | + /* reassert IRQs if data left */ | |
| 2744 | + kbd_update_irq(s); | |
| 2767 | 2745 | #ifdef DEBUG_KBD |
| 2768 | 2746 | printf("kbd: read data=0x%02x\n", val); |
| 2769 | 2747 | #endif |
| ... | ... | @@ -2820,12 +2798,212 @@ static void kbd_write_keyboard(KBDState *s, int val) |
| 2820 | 2798 | break; |
| 2821 | 2799 | case KBD_CMD_SET_LEDS: |
| 2822 | 2800 | kbd_queue(s, KBD_REPLY_ACK, 0); |
| 2801 | + s->kbd_write_cmd = -1; | |
| 2823 | 2802 | break; |
| 2824 | 2803 | case KBD_CMD_SET_RATE: |
| 2825 | 2804 | kbd_queue(s, KBD_REPLY_ACK, 0); |
| 2805 | + s->kbd_write_cmd = -1; | |
| 2806 | + break; | |
| 2807 | + } | |
| 2808 | +} | |
| 2809 | + | |
| 2810 | +static void kbd_mouse_send_packet(KBDState *s) | |
| 2811 | +{ | |
| 2812 | + unsigned int b; | |
| 2813 | + int dx1, dy1, dz1; | |
| 2814 | + | |
| 2815 | + dx1 = s->mouse_dx; | |
| 2816 | + dy1 = s->mouse_dy; | |
| 2817 | + dz1 = s->mouse_dz; | |
| 2818 | + /* XXX: increase range to 8 bits ? */ | |
| 2819 | + if (dx1 > 127) | |
| 2820 | + dx1 = 127; | |
| 2821 | + else if (dx1 < -127) | |
| 2822 | + dx1 = -127; | |
| 2823 | + if (dy1 > 127) | |
| 2824 | + dy1 = 127; | |
| 2825 | + else if (dy1 < -127) | |
| 2826 | + dy1 = -127; | |
| 2827 | + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); | |
| 2828 | + kbd_queue(s, b, 1); | |
| 2829 | + kbd_queue(s, dx1 & 0xff, 1); | |
| 2830 | + kbd_queue(s, dy1 & 0xff, 1); | |
| 2831 | + /* extra byte for IMPS/2 or IMEX */ | |
| 2832 | + switch(s->mouse_type) { | |
| 2833 | + default: | |
| 2834 | + break; | |
| 2835 | + case 3: | |
| 2836 | + if (dz1 > 127) | |
| 2837 | + dz1 = 127; | |
| 2838 | + else if (dz1 < -127) | |
| 2839 | + dz1 = -127; | |
| 2840 | + kbd_queue(s, dz1 & 0xff, 1); | |
| 2841 | + break; | |
| 2842 | + case 4: | |
| 2843 | + if (dz1 > 7) | |
| 2844 | + dz1 = 7; | |
| 2845 | + else if (dz1 < -7) | |
| 2846 | + dz1 = -7; | |
| 2847 | + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); | |
| 2848 | + kbd_queue(s, b, 1); | |
| 2849 | + break; | |
| 2850 | + } | |
| 2851 | + | |
| 2852 | + /* update deltas */ | |
| 2853 | + s->mouse_dx -= dx1; | |
| 2854 | + s->mouse_dy -= dy1; | |
| 2855 | + s->mouse_dz -= dz1; | |
| 2856 | +} | |
| 2857 | + | |
| 2858 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | |
| 2859 | +{ | |
| 2860 | + KBDState *s = &kbd_state; | |
| 2861 | + | |
| 2862 | + /* check if deltas are recorded when disabled */ | |
| 2863 | + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) | |
| 2864 | + return; | |
| 2865 | + | |
| 2866 | + s->mouse_dx += dx; | |
| 2867 | + s->mouse_dy -= dy; | |
| 2868 | + s->mouse_dz += dz; | |
| 2869 | + s->mouse_buttons = buttons_state; | |
| 2870 | + | |
| 2871 | + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && | |
| 2872 | + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { | |
| 2873 | + for(;;) { | |
| 2874 | + /* if not remote, send event. Multiple events are sent if | |
| 2875 | + too big deltas */ | |
| 2876 | + kbd_mouse_send_packet(s); | |
| 2877 | + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) | |
| 2878 | + break; | |
| 2879 | + } | |
| 2880 | + } | |
| 2881 | +} | |
| 2882 | + | |
| 2883 | +static void kbd_write_mouse(KBDState *s, int val) | |
| 2884 | +{ | |
| 2885 | +#ifdef DEBUG_MOUSE | |
| 2886 | + printf("kbd: write mouse 0x%02x\n", val); | |
| 2887 | +#endif | |
| 2888 | + switch(s->mouse_write_cmd) { | |
| 2889 | + default: | |
| 2890 | + case -1: | |
| 2891 | + /* mouse command */ | |
| 2892 | + if (s->mouse_wrap) { | |
| 2893 | + if (val == AUX_RESET_WRAP) { | |
| 2894 | + s->mouse_wrap = 0; | |
| 2895 | + kbd_queue(s, AUX_ACK, 1); | |
| 2896 | + return; | |
| 2897 | + } else if (val != AUX_RESET) { | |
| 2898 | + kbd_queue(s, val, 1); | |
| 2899 | + return; | |
| 2900 | + } | |
| 2901 | + } | |
| 2902 | + switch(val) { | |
| 2903 | + case AUX_SET_SCALE11: | |
| 2904 | + s->mouse_status &= ~MOUSE_STATUS_SCALE21; | |
| 2905 | + kbd_queue(s, AUX_ACK, 1); | |
| 2906 | + break; | |
| 2907 | + case AUX_SET_SCALE21: | |
| 2908 | + s->mouse_status |= MOUSE_STATUS_SCALE21; | |
| 2909 | + kbd_queue(s, AUX_ACK, 1); | |
| 2910 | + break; | |
| 2911 | + case AUX_SET_STREAM: | |
| 2912 | + s->mouse_status &= ~MOUSE_STATUS_REMOTE; | |
| 2913 | + kbd_queue(s, AUX_ACK, 1); | |
| 2914 | + break; | |
| 2915 | + case AUX_SET_WRAP: | |
| 2916 | + s->mouse_wrap = 1; | |
| 2917 | + kbd_queue(s, AUX_ACK, 1); | |
| 2918 | + break; | |
| 2919 | + case AUX_SET_REMOTE: | |
| 2920 | + s->mouse_status |= MOUSE_STATUS_REMOTE; | |
| 2921 | + kbd_queue(s, AUX_ACK, 1); | |
| 2922 | + break; | |
| 2923 | + case AUX_GET_TYPE: | |
| 2924 | + kbd_queue(s, AUX_ACK, 1); | |
| 2925 | + kbd_queue(s, s->mouse_type, 1); | |
| 2926 | + break; | |
| 2927 | + case AUX_SET_RES: | |
| 2928 | + case AUX_SET_SAMPLE: | |
| 2929 | + s->mouse_write_cmd = val; | |
| 2930 | + kbd_queue(s, AUX_ACK, 1); | |
| 2931 | + break; | |
| 2932 | + case AUX_GET_SCALE: | |
| 2933 | + kbd_queue(s, AUX_ACK, 1); | |
| 2934 | + kbd_queue(s, s->mouse_status, 1); | |
| 2935 | + kbd_queue(s, s->mouse_resolution, 1); | |
| 2936 | + kbd_queue(s, s->mouse_sample_rate, 1); | |
| 2937 | + break; | |
| 2938 | + case AUX_POLL: | |
| 2939 | + kbd_queue(s, AUX_ACK, 1); | |
| 2940 | + kbd_mouse_send_packet(s); | |
| 2941 | + break; | |
| 2942 | + case AUX_ENABLE_DEV: | |
| 2943 | + s->mouse_status |= MOUSE_STATUS_ENABLED; | |
| 2944 | + kbd_queue(s, AUX_ACK, 1); | |
| 2945 | + break; | |
| 2946 | + case AUX_DISABLE_DEV: | |
| 2947 | + s->mouse_status &= ~MOUSE_STATUS_ENABLED; | |
| 2948 | + kbd_queue(s, AUX_ACK, 1); | |
| 2949 | + break; | |
| 2950 | + case AUX_SET_DEFAULT: | |
| 2951 | + s->mouse_sample_rate = 100; | |
| 2952 | + s->mouse_resolution = 2; | |
| 2953 | + s->mouse_status = 0; | |
| 2954 | + kbd_queue(s, AUX_ACK, 1); | |
| 2955 | + break; | |
| 2956 | + case AUX_RESET: | |
| 2957 | + s->mouse_sample_rate = 100; | |
| 2958 | + s->mouse_resolution = 2; | |
| 2959 | + s->mouse_status = 0; | |
| 2960 | + kbd_queue(s, AUX_ACK, 1); | |
| 2961 | + kbd_queue(s, 0xaa, 1); | |
| 2962 | + kbd_queue(s, s->mouse_type, 1); | |
| 2963 | + break; | |
| 2964 | + default: | |
| 2965 | + break; | |
| 2966 | + } | |
| 2967 | + break; | |
| 2968 | + case AUX_SET_SAMPLE: | |
| 2969 | + s->mouse_sample_rate = val; | |
| 2970 | +#if 0 | |
| 2971 | + /* detect IMPS/2 or IMEX */ | |
| 2972 | + switch(s->mouse_detect_state) { | |
| 2973 | + default: | |
| 2974 | + case 0: | |
| 2975 | + if (val == 200) | |
| 2976 | + s->mouse_detect_state = 1; | |
| 2977 | + break; | |
| 2978 | + case 1: | |
| 2979 | + if (val == 100) | |
| 2980 | + s->mouse_detect_state = 2; | |
| 2981 | + else if (val == 200) | |
| 2982 | + s->mouse_detect_state = 3; | |
| 2983 | + else | |
| 2984 | + s->mouse_detect_state = 0; | |
| 2985 | + break; | |
| 2986 | + case 2: | |
| 2987 | + if (val == 80) | |
| 2988 | + s->mouse_type = 3; /* IMPS/2 */ | |
| 2989 | + s->mouse_detect_state = 0; | |
| 2990 | + break; | |
| 2991 | + case 3: | |
| 2992 | + if (val == 80) | |
| 2993 | + s->mouse_type = 4; /* IMEX */ | |
| 2994 | + s->mouse_detect_state = 0; | |
| 2995 | + break; | |
| 2996 | + } | |
| 2997 | +#endif | |
| 2998 | + kbd_queue(s, AUX_ACK, 1); | |
| 2999 | + s->mouse_write_cmd = -1; | |
| 3000 | + break; | |
| 3001 | + case AUX_SET_RES: | |
| 3002 | + s->mouse_resolution = val; | |
| 3003 | + kbd_queue(s, AUX_ACK, 1); | |
| 3004 | + s->mouse_write_cmd = -1; | |
| 2826 | 3005 | break; |
| 2827 | 3006 | } |
| 2828 | - s->kbd_write_cmd = -1; | |
| 2829 | 3007 | } |
| 2830 | 3008 | |
| 2831 | 3009 | void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) |
| ... | ... | @@ -2857,6 +3035,9 @@ void kbd_write_data(CPUX86State *env, uint32_t addr, uint32_t val) |
| 2857 | 3035 | cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); |
| 2858 | 3036 | } |
| 2859 | 3037 | break; |
| 3038 | + case KBD_CCMD_WRITE_MOUSE: | |
| 3039 | + kbd_write_mouse(s, val); | |
| 3040 | + break; | |
| 2860 | 3041 | default: |
| 2861 | 3042 | break; |
| 2862 | 3043 | } |
| ... | ... | @@ -2869,8 +3050,9 @@ void kbd_reset(KBDState *s) |
| 2869 | 3050 | int i; |
| 2870 | 3051 | |
| 2871 | 3052 | s->kbd_write_cmd = -1; |
| 3053 | + s->mouse_write_cmd = -1; | |
| 2872 | 3054 | s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; |
| 2873 | - s->status = KBD_MODE_SYS | KBD_MODE_NO_KEYLOCK; | |
| 3055 | + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; | |
| 2874 | 3056 | for(i = 0; i < 2; i++) { |
| 2875 | 3057 | q = &s->queues[i]; |
| 2876 | 3058 | q->rptr = 0; |
| ... | ... | @@ -2934,6 +3116,63 @@ void bochs_bios_init(void) |
| 2934 | 3116 | } |
| 2935 | 3117 | |
| 2936 | 3118 | /***********************************************************/ |
| 3119 | +/* dumb display */ | |
| 3120 | + | |
| 3121 | +/* init terminal so that we can grab keys */ | |
| 3122 | +static struct termios oldtty; | |
| 3123 | + | |
| 3124 | +static void term_exit(void) | |
| 3125 | +{ | |
| 3126 | + tcsetattr (0, TCSANOW, &oldtty); | |
| 3127 | +} | |
| 3128 | + | |
| 3129 | +static void term_init(void) | |
| 3130 | +{ | |
| 3131 | + struct termios tty; | |
| 3132 | + | |
| 3133 | + tcgetattr (0, &tty); | |
| 3134 | + oldtty = tty; | |
| 3135 | + | |
| 3136 | + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP | |
| 3137 | + |INLCR|IGNCR|ICRNL|IXON); | |
| 3138 | + tty.c_oflag |= OPOST; | |
| 3139 | + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); | |
| 3140 | + tty.c_cflag &= ~(CSIZE|PARENB); | |
| 3141 | + tty.c_cflag |= CS8; | |
| 3142 | + tty.c_cc[VMIN] = 1; | |
| 3143 | + tty.c_cc[VTIME] = 0; | |
| 3144 | + | |
| 3145 | + tcsetattr (0, TCSANOW, &tty); | |
| 3146 | + | |
| 3147 | + atexit(term_exit); | |
| 3148 | + | |
| 3149 | + fcntl(0, F_SETFL, O_NONBLOCK); | |
| 3150 | +} | |
| 3151 | + | |
| 3152 | +static void dumb_update(DisplayState *ds, int x, int y, int w, int h) | |
| 3153 | +{ | |
| 3154 | +} | |
| 3155 | + | |
| 3156 | +static void dumb_resize(DisplayState *ds, int w, int h) | |
| 3157 | +{ | |
| 3158 | +} | |
| 3159 | + | |
| 3160 | +static void dumb_refresh(DisplayState *ds) | |
| 3161 | +{ | |
| 3162 | + vga_update_display(); | |
| 3163 | +} | |
| 3164 | + | |
| 3165 | +void dumb_display_init(DisplayState *ds) | |
| 3166 | +{ | |
| 3167 | + ds->data = NULL; | |
| 3168 | + ds->linesize = 0; | |
| 3169 | + ds->depth = 0; | |
| 3170 | + ds->dpy_update = dumb_update; | |
| 3171 | + ds->dpy_resize = dumb_resize; | |
| 3172 | + ds->dpy_refresh = dumb_refresh; | |
| 3173 | +} | |
| 3174 | + | |
| 3175 | +/***********************************************************/ | |
| 2937 | 3176 | /* cpu signal handler */ |
| 2938 | 3177 | static void host_segv_handler(int host_signum, siginfo_t *info, |
| 2939 | 3178 | void *puc) |
| ... | ... | @@ -2947,6 +3186,9 @@ static void host_segv_handler(int host_signum, siginfo_t *info, |
| 2947 | 3186 | static int timer_irq_pending; |
| 2948 | 3187 | static int timer_irq_count; |
| 2949 | 3188 | |
| 3189 | +static int timer_ms; | |
| 3190 | +static int gui_refresh_pending, gui_refresh_count; | |
| 3191 | + | |
| 2950 | 3192 | static void host_alarm_handler(int host_signum, siginfo_t *info, |
| 2951 | 3193 | void *puc) |
| 2952 | 3194 | { |
| ... | ... | @@ -2958,9 +3200,17 @@ static void host_alarm_handler(int host_signum, siginfo_t *info, |
| 2958 | 3200 | if (timer_irq_count > 2) |
| 2959 | 3201 | timer_irq_count = 2; |
| 2960 | 3202 | timer_irq_count--; |
| 3203 | + timer_irq_pending = 1; | |
| 3204 | + } | |
| 3205 | + gui_refresh_count += timer_ms; | |
| 3206 | + if (gui_refresh_count >= GUI_REFRESH_INTERVAL) { | |
| 3207 | + gui_refresh_count = 0; | |
| 3208 | + gui_refresh_pending = 1; | |
| 3209 | + } | |
| 3210 | + | |
| 3211 | + if (gui_refresh_pending || timer_irq_pending) { | |
| 2961 | 3212 | /* just exit from the cpu to have a chance to handle timers */ |
| 2962 | 3213 | cpu_x86_interrupt(global_env, CPU_INTERRUPT_EXIT); |
| 2963 | - timer_irq_pending = 1; | |
| 2964 | 3214 | } |
| 2965 | 3215 | } |
| 2966 | 3216 | |
| ... | ... | @@ -2988,6 +3238,14 @@ int main_loop(void *opaque) |
| 2988 | 3238 | uint8_t ch; |
| 2989 | 3239 | CPUState *env = global_env; |
| 2990 | 3240 | |
| 3241 | + if (nodisp && !term_inited) { | |
| 3242 | + /* initialize terminal only there so that the user has a | |
| 3243 | + chance to stop QEMU with Ctrl-C before the gdb connection | |
| 3244 | + is launched */ | |
| 3245 | + term_inited = 1; | |
| 3246 | + term_init(); | |
| 3247 | + } | |
| 3248 | + | |
| 2991 | 3249 | for(;;) { |
| 2992 | 3250 | |
| 2993 | 3251 | ret = cpu_x86_exec(env); |
| ... | ... | @@ -3059,6 +3317,12 @@ int main_loop(void *opaque) |
| 3059 | 3317 | pic_set_irq(0, 0); |
| 3060 | 3318 | timer_irq_pending = 0; |
| 3061 | 3319 | } |
| 3320 | + | |
| 3321 | + /* VGA */ | |
| 3322 | + if (gui_refresh_pending) { | |
| 3323 | + display_state.dpy_refresh(&display_state); | |
| 3324 | + gui_refresh_pending = 0; | |
| 3325 | + } | |
| 3062 | 3326 | } |
| 3063 | 3327 | return EXCP_INTERRUPT; |
| 3064 | 3328 | } |
| ... | ... | @@ -3098,31 +3362,35 @@ struct option long_options[] = { |
| 3098 | 3362 | { "hdb", 1, NULL, 0, }, |
| 3099 | 3363 | { "snapshot", 0, NULL, 0, }, |
| 3100 | 3364 | { "hdachs", 1, NULL, 0, }, |
| 3365 | + { "nodisp", 0, NULL, 0, }, | |
| 3101 | 3366 | { NULL, 0, NULL, 0 }, |
| 3102 | 3367 | }; |
| 3103 | 3368 | |
| 3104 | 3369 | int main(int argc, char **argv) |
| 3105 | 3370 | { |
| 3106 | 3371 | int c, ret, initrd_size, i, use_gdbstub, gdbstub_port, long_index; |
| 3107 | - int snapshot, linux_boot; | |
| 3372 | + int snapshot, linux_boot, total_ram_size; | |
| 3108 | 3373 | struct linux_params *params; |
| 3109 | 3374 | struct sigaction act; |
| 3110 | 3375 | struct itimerval itv; |
| 3111 | 3376 | CPUX86State *env; |
| 3112 | 3377 | const char *tmpdir, *initrd_filename; |
| 3113 | 3378 | const char *hd_filename[MAX_DISKS]; |
| 3114 | - | |
| 3379 | + DisplayState *ds = &display_state; | |
| 3380 | + | |
| 3115 | 3381 | /* we never want that malloc() uses mmap() */ |
| 3116 | 3382 | mallopt(M_MMAP_THRESHOLD, 4096 * 1024); |
| 3117 | 3383 | initrd_filename = NULL; |
| 3118 | 3384 | for(i = 0; i < MAX_DISKS; i++) |
| 3119 | 3385 | hd_filename[i] = NULL; |
| 3120 | 3386 | phys_ram_size = 32 * 1024 * 1024; |
| 3387 | + vga_ram_size = VGA_RAM_SIZE; | |
| 3121 | 3388 | pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); |
| 3122 | 3389 | use_gdbstub = 0; |
| 3123 | 3390 | gdbstub_port = DEFAULT_GDBSTUB_PORT; |
| 3124 | 3391 | snapshot = 0; |
| 3125 | 3392 | linux_boot = 0; |
| 3393 | + nodisp = 0; | |
| 3126 | 3394 | for(;;) { |
| 3127 | 3395 | c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index); |
| 3128 | 3396 | if (c == -1) |
| ... | ... | @@ -3164,6 +3432,9 @@ int main(int argc, char **argv) |
| 3164 | 3432 | chs_fail: ; |
| 3165 | 3433 | } |
| 3166 | 3434 | break; |
| 3435 | + case 5: | |
| 3436 | + nodisp = 1; | |
| 3437 | + break; | |
| 3167 | 3438 | } |
| 3168 | 3439 | break; |
| 3169 | 3440 | case 'h': |
| ... | ... | @@ -3232,9 +3503,11 @@ int main(int argc, char **argv) |
| 3232 | 3503 | phys_ram_file); |
| 3233 | 3504 | exit(1); |
| 3234 | 3505 | } |
| 3235 | - ftruncate(phys_ram_fd, phys_ram_size); | |
| 3506 | + total_ram_size = phys_ram_size + vga_ram_size; | |
| 3507 | + ftruncate(phys_ram_fd, total_ram_size); | |
| 3236 | 3508 | unlink(phys_ram_file); |
| 3237 | - phys_ram_base = mmap(get_mmap_addr(phys_ram_size), phys_ram_size, | |
| 3509 | + phys_ram_base = mmap(get_mmap_addr(total_ram_size), | |
| 3510 | + total_ram_size, | |
| 3238 | 3511 | PROT_WRITE | PROT_READ, MAP_SHARED | MAP_FIXED, |
| 3239 | 3512 | phys_ram_fd, 0); |
| 3240 | 3513 | if (phys_ram_base == MAP_FAILED) { |
| ... | ... | @@ -3261,6 +3534,9 @@ int main(int argc, char **argv) |
| 3261 | 3534 | |
| 3262 | 3535 | init_ioports(); |
| 3263 | 3536 | |
| 3537 | + /* allocate RAM */ | |
| 3538 | + cpu_register_physical_memory(0, phys_ram_size, 0); | |
| 3539 | + | |
| 3264 | 3540 | if (linux_boot) { |
| 3265 | 3541 | /* now we can load the kernel */ |
| 3266 | 3542 | ret = load_kernel(argv[optind], phys_ram_base + KERNEL_LOAD_ADDR); |
| ... | ... | @@ -3366,11 +3642,23 @@ int main(int argc, char **argv) |
| 3366 | 3642 | bochs_bios_init(); |
| 3367 | 3643 | } |
| 3368 | 3644 | |
| 3645 | + /* terminal init */ | |
| 3646 | + if (nodisp) { | |
| 3647 | + dumb_display_init(ds); | |
| 3648 | + } else { | |
| 3649 | +#ifdef CONFIG_SDL | |
| 3650 | + sdl_display_init(ds); | |
| 3651 | + /* the pthreads modify sigaction. We don't want that. */ | |
| 3652 | +#define sigaction __sigaction | |
| 3653 | +#else | |
| 3654 | + dumb_display_init(ds); | |
| 3655 | +#endif | |
| 3656 | + } | |
| 3369 | 3657 | /* init basic PC hardware */ |
| 3370 | 3658 | register_ioport_write(0x80, 1, ioport80_write, 1); |
| 3371 | 3659 | |
| 3372 | - register_ioport_write(0x3d4, 2, vga_ioport_write, 1); | |
| 3373 | - | |
| 3660 | + vga_init(ds, phys_ram_base + phys_ram_size, phys_ram_size, | |
| 3661 | + vga_ram_size); | |
| 3374 | 3662 | cmos_init(); |
| 3375 | 3663 | pic_init(); |
| 3376 | 3664 | pit_init(); |
| ... | ... | @@ -3378,7 +3666,7 @@ int main(int argc, char **argv) |
| 3378 | 3666 | ne2000_init(); |
| 3379 | 3667 | ide_init(); |
| 3380 | 3668 | kbd_init(); |
| 3381 | - | |
| 3669 | + | |
| 3382 | 3670 | /* setup cpu signal handlers for MMU / self modifying code handling */ |
| 3383 | 3671 | sigfillset(&act.sa_mask); |
| 3384 | 3672 | act.sa_flags = SA_SIGINFO; |
| ... | ... | @@ -3397,6 +3685,7 @@ int main(int argc, char **argv) |
| 3397 | 3685 | /* we probe the tick duration of the kernel to inform the user if |
| 3398 | 3686 | the emulated kernel requested a too high timer frequency */ |
| 3399 | 3687 | getitimer(ITIMER_REAL, &itv); |
| 3688 | + timer_ms = itv.it_interval.tv_usec / 1000; | |
| 3400 | 3689 | pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * PIT_FREQ) / |
| 3401 | 3690 | 1000000; |
| 3402 | 3691 | ... | ... |
vl.h
| ... | ... | @@ -25,7 +25,22 @@ |
| 25 | 25 | #define VL_H |
| 26 | 26 | |
| 27 | 27 | /* vl.c */ |
| 28 | +struct CPUX86State; | |
| 29 | +extern int reset_requested; | |
| 30 | + | |
| 31 | +typedef void (IOPortWriteFunc)(struct CPUX86State *env, uint32_t address, uint32_t data); | |
| 32 | +typedef uint32_t (IOPortReadFunc)(struct CPUX86State *env, uint32_t address); | |
| 33 | + | |
| 28 | 34 | void *get_mmap_addr(unsigned long size); |
| 35 | +int register_ioport_read(int start, int length, IOPortReadFunc *func, int size); | |
| 36 | +int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size); | |
| 37 | + | |
| 38 | +void kbd_put_keycode(int keycode); | |
| 39 | + | |
| 40 | +#define MOUSE_EVENT_LBUTTON 0x01 | |
| 41 | +#define MOUSE_EVENT_RBUTTON 0x02 | |
| 42 | +#define MOUSE_EVENT_MBUTTON 0x04 | |
| 43 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state); | |
| 29 | 44 | |
| 30 | 45 | /* block.c */ |
| 31 | 46 | typedef struct BlockDriverState BlockDriverState; |
| ... | ... | @@ -52,4 +67,34 @@ struct cow_header_v2 { |
| 52 | 67 | uint32_t sectorsize; |
| 53 | 68 | }; |
| 54 | 69 | |
| 70 | +/* vga.c */ | |
| 71 | + | |
| 72 | +#define VGA_RAM_SIZE (8192 * 1024) | |
| 73 | + | |
| 74 | +typedef struct DisplayState { | |
| 75 | + uint8_t *data; | |
| 76 | + int linesize; | |
| 77 | + int depth; | |
| 78 | + void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h); | |
| 79 | + void (*dpy_resize)(struct DisplayState *s, int w, int h); | |
| 80 | + void (*dpy_refresh)(struct DisplayState *s); | |
| 81 | +} DisplayState; | |
| 82 | + | |
| 83 | +static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) | |
| 84 | +{ | |
| 85 | + s->dpy_update(s, x, y, w, h); | |
| 86 | +} | |
| 87 | + | |
| 88 | +static inline void dpy_resize(DisplayState *s, int w, int h) | |
| 89 | +{ | |
| 90 | + s->dpy_resize(s, w, h); | |
| 91 | +} | |
| 92 | + | |
| 93 | +int vga_init(DisplayState *ds, uint8_t *vga_ram_base, | |
| 94 | + unsigned long vga_ram_offset, int vga_ram_size); | |
| 95 | +void vga_update_display(void); | |
| 96 | + | |
| 97 | +/* sdl.c */ | |
| 98 | +void sdl_display_init(DisplayState *ds); | |
| 99 | + | |
| 55 | 100 | #endif /* VL_H */ | ... | ... |