diff options
Diffstat (limited to 'hw/i8254.c')
-rw-r--r-- | hw/i8254.c | 92 |
1 files changed, 40 insertions, 52 deletions
diff --git a/hw/i8254.c b/hw/i8254.c index 481fc7b252..f30396af88 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -25,6 +25,7 @@ #include "pc.h" #include "isa.h" #include "qemu-timer.h" +#include "i8254.h" //#define DEBUG_PIT @@ -51,18 +52,16 @@ typedef struct PITChannelState { int64_t next_transition_time; QEMUTimer *irq_timer; qemu_irq irq; + uint32_t irq_disabled; } PITChannelState; typedef struct PITState { ISADevice dev; MemoryRegion ioports; - uint32_t irq; uint32_t iobase; PITChannelState channels[3]; } PITState; -static PITState pit_state; - static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); static int pit_get_count(PITChannelState *s) @@ -91,7 +90,7 @@ static int pit_get_count(PITChannelState *s) } /* get pit output bit */ -static int pit_get_out1(PITChannelState *s, int64_t current_time) +static int pit_get_out(PITChannelState *s, int64_t current_time) { uint64_t d; int out; @@ -123,13 +122,6 @@ static int pit_get_out1(PITChannelState *s, int64_t current_time) return out; } -int pit_get_out(ISADevice *dev, int channel, int64_t current_time) -{ - PITState *pit = DO_UPCAST(PITState, dev, dev); - PITChannelState *s = &pit->channels[channel]; - return pit_get_out1(s, current_time); -} - /* return -1 if no transition will occur. */ static int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) @@ -216,25 +208,15 @@ void pit_set_gate(ISADevice *dev, int channel, int val) s->gate = val; } -int pit_get_gate(ISADevice *dev, int channel) -{ - PITState *pit = DO_UPCAST(PITState, dev, dev); - PITChannelState *s = &pit->channels[channel]; - return s->gate; -} - -int pit_get_initial_count(ISADevice *dev, int channel) +void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info) { PITState *pit = DO_UPCAST(PITState, dev, dev); PITChannelState *s = &pit->channels[channel]; - return s->count; -} -int pit_get_mode(ISADevice *dev, int channel) -{ - PITState *pit = DO_UPCAST(PITState, dev, dev); - PITChannelState *s = &pit->channels[channel]; - return s->mode; + info->gate = s->gate; + info->mode = s->mode; + info->initial_count = s->count; + info->out = pit_get_out(s, qemu_get_clock_ns(vm_clock)); } static inline void pit_load_count(PITChannelState *s, int val) @@ -275,7 +257,9 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) if (!(val & 0x10) && !s->status_latched) { /* status latch */ /* XXX: add BCD and null count */ - s->status = (pit_get_out1(s, qemu_get_clock_ns(vm_clock)) << 7) | + s->status = + (pit_get_out(s, + qemu_get_clock_ns(vm_clock)) << 7) | (s->rw_mode << 4) | (s->mode << 1) | s->bcd; @@ -378,10 +362,11 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) int64_t expire_time; int irq_level; - if (!s->irq_timer) + if (!s->irq_timer || s->irq_disabled) { return; + } expire_time = pit_get_next_transition_time(s, current_time); - irq_level = pit_get_out1(s, current_time); + irq_level = pit_get_out(s, current_time); qemu_set_irq(s->irq, irq_level); #ifdef DEBUG_PIT printf("irq_level=%d next_delay=%f\n", @@ -450,6 +435,7 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id) qemu_get_8s(f, &s->bcd); qemu_get_8s(f, &s->gate); s->count_load_time=qemu_get_be64(f); + s->irq_disabled = 0; if (s->irq_timer) { s->next_transition_time=qemu_get_be64(f); qemu_get_timer(f, s->irq_timer); @@ -460,11 +446,12 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id) static const VMStateDescription vmstate_pit = { .name = "i8254", - .version_id = 2, + .version_id = 3, .minimum_version_id = 2, .minimum_version_id_old = 1, .load_state_old = pit_load_old, .fields = (VMStateField []) { + VMSTATE_UINT32_V(channels[0].irq_disabled, PITState, 3), VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState), VMSTATE_TIMER(channels[0].irq_timer, PITState), VMSTATE_END_OF_LIST() @@ -481,30 +468,30 @@ static void pit_reset(DeviceState *dev) s = &pit->channels[i]; s->mode = 3; s->gate = (i != 2); - pit_load_count(s, 0); + s->count_load_time = qemu_get_clock_ns(vm_clock); + s->count = 0x10000; + if (i == 0 && !s->irq_disabled) { + s->next_transition_time = + pit_get_next_transition_time(s, s->count_load_time); + qemu_mod_timer(s->irq_timer, s->next_transition_time); + } } } -/* When HPET is operating in legacy mode, i8254 timer0 is disabled */ -void hpet_pit_disable(void) { - PITChannelState *s; - s = &pit_state.channels[0]; - if (s->irq_timer) - qemu_del_timer(s->irq_timer); -} - -/* When HPET is reset or leaving legacy mode, it must reenable i8254 - * timer 0 - */ - -void hpet_pit_enable(void) +/* When HPET is operating in legacy mode, suppress the ignored timer IRQ, + * reenable it when legacy mode is left again. */ +static void pit_irq_control(void *opaque, int n, int enable) { - PITState *pit = &pit_state; - PITChannelState *s; - s = &pit->channels[0]; - s->mode = 3; - s->gate = 1; - pit_load_count(s, 0); + PITState *pit = opaque; + PITChannelState *s = &pit->channels[0]; + + if (enable) { + s->irq_disabled = 0; + pit_irq_timer_update(s, qemu_get_clock_ns(vm_clock)); + } else { + s->irq_disabled = 1; + qemu_del_timer(s->irq_timer); + } } static const MemoryRegionPortio pit_portio[] = { @@ -525,18 +512,19 @@ static int pit_initfn(ISADevice *dev) s = &pit->channels[0]; /* the timer 0 is connected to an IRQ */ s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s); - s->irq = isa_get_irq(dev, pit->irq); + qdev_init_gpio_out(&dev->qdev, &s->irq, 1); memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4); isa_register_ioport(dev, &pit->ioports, pit->iobase); + qdev_init_gpio_in(&dev->qdev, pit_irq_control, 1); + qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2); return 0; } static Property pit_properties[] = { - DEFINE_PROP_UINT32("irq", PITState, irq, -1), DEFINE_PROP_HEX32("iobase", PITState, iobase, -1), DEFINE_PROP_END_OF_LIST(), }; |