From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:34476) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RsLRB-0002cu-Er for qemu-devel@nongnu.org; Tue, 31 Jan 2012 16:40:29 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RsLR3-0006sR-HE for qemu-devel@nongnu.org; Tue, 31 Jan 2012 16:40:25 -0500 Received: from mail-pw0-f45.google.com ([209.85.160.45]:50834) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RsLR3-0006sI-4U for qemu-devel@nongnu.org; Tue, 31 Jan 2012 16:40:17 -0500 Received: by pbaa11 with SMTP id a11so669430pba.4 for ; Tue, 31 Jan 2012 13:40:15 -0800 (PST) Message-ID: <4F285FBA.5050607@codemonkey.ws> Date: Tue, 31 Jan 2012 15:40:10 -0600 From: Anthony Liguori MIME-Version: 1.0 References: <1e206a3b5dbd396606099fdbd9abd8c00bbdda31.1328035554.git.jan.kiszka@siemens.com> In-Reply-To: <1e206a3b5dbd396606099fdbd9abd8c00bbdda31.1328035554.git.jan.kiszka@siemens.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Qemu-devel] [PATCH 1/4] i8254: Factor out base class for KVM reuse List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Jan Kiszka Cc: Anthony Liguori , Marcelo Tosatti , Avi Kivity , kvm@vger.kernel.org, qemu-devel On 01/31/2012 12:46 PM, Jan Kiszka wrote: > Applying the concept used for the *PICs once again: establish a base > class for the i8254 that can be used both by the current user space > emulation and the upcoming KVM in-kernel version. We share most of the > public interface of the i8254, specifically to the pcspk, vmstate, reset > and certain init parts. > > Signed-off-by: Jan Kiszka Now that we have QOM bits, there's no need to factor out a common base class. Just make the methods that you want to override virtual with the default implementation and then make a KVMPIT that inherits from the PIT and then overrides whatever virtual functions it needs to. Regards, Anthony Liguori > --- > Makefile.objs | 2 +- > hw/i8254.c | 277 ++++++--------------------------------------- > hw/i8254_common.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++ > hw/i8254_internal.h | 87 ++++++++++++++ > 4 files changed, 434 insertions(+), 243 deletions(-) > create mode 100644 hw/i8254_common.c > create mode 100644 hw/i8254_internal.h > > diff --git a/Makefile.objs b/Makefile.objs > index b942625..6a733fa 100644 > --- a/Makefile.objs > +++ b/Makefile.objs > @@ -210,7 +210,7 @@ hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o > > hw-obj-$(CONFIG_SERIAL) += serial.o > hw-obj-$(CONFIG_PARALLEL) += parallel.o > -hw-obj-$(CONFIG_I8254) += i8254.o > +hw-obj-$(CONFIG_I8254) += i8254_common.o i8254.o > hw-obj-$(CONFIG_PCSPK) += pcspk.o > hw-obj-$(CONFIG_PCKBD) += pckbd.o > hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o > diff --git a/hw/i8254.c b/hw/i8254.c > index ff253bb..90e9a87 100644 > --- a/hw/i8254.c > +++ b/hw/i8254.c > @@ -26,6 +26,7 @@ > #include "isa.h" > #include "qemu-timer.h" > #include "i8254.h" > +#include "i8254_internal.h" > > //#define DEBUG_PIT > > @@ -34,34 +35,6 @@ > #define RW_STATE_WORD0 3 > #define RW_STATE_WORD1 4 > > -typedef struct PITChannelState { > - int count; /* can be 65536 */ > - uint16_t latched_count; > - uint8_t count_latched; > - uint8_t status_latched; > - uint8_t status; > - uint8_t read_state; > - uint8_t write_state; > - uint8_t write_latch; > - uint8_t rw_mode; > - uint8_t mode; > - uint8_t bcd; /* not supported */ > - uint8_t gate; /* timer start */ > - int64_t count_load_time; > - /* irq handling */ > - 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 iobase; > - PITChannelState channels[3]; > -} PITState; > - > static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); > > static int pit_get_count(PITChannelState *s) > @@ -89,99 +62,11 @@ static int pit_get_count(PITChannelState *s) > return counter; > } > > -/* get pit output bit */ > -static int pit_get_out(PITChannelState *s, int64_t current_time) > -{ > - uint64_t d; > - int out; > - > - d = muldiv64(current_time - s->count_load_time, PIT_FREQ, > - get_ticks_per_sec()); > - switch(s->mode) { > - default: > - case 0: > - out = (d>= s->count); > - break; > - case 1: > - out = (d< s->count); > - break; > - case 2: > - if ((d % s->count) == 0&& d != 0) > - out = 1; > - else > - out = 0; > - break; > - case 3: > - out = (d % s->count)< ((s->count + 1)>> 1); > - break; > - case 4: > - case 5: > - out = (d == s->count); > - break; > - } > - return out; > -} > - > -/* return -1 if no transition will occur. */ > -static int64_t pit_get_next_transition_time(PITChannelState *s, > - int64_t current_time) > -{ > - uint64_t d, next_time, base; > - int period2; > - > - d = muldiv64(current_time - s->count_load_time, PIT_FREQ, > - get_ticks_per_sec()); > - switch(s->mode) { > - default: > - case 0: > - case 1: > - if (d< s->count) > - next_time = s->count; > - else > - return -1; > - break; > - case 2: > - base = (d / s->count) * s->count; > - if ((d - base) == 0&& d != 0) > - next_time = base + s->count; > - else > - next_time = base + s->count + 1; > - break; > - case 3: > - base = (d / s->count) * s->count; > - period2 = ((s->count + 1)>> 1); > - if ((d - base)< period2) > - next_time = base + period2; > - else > - next_time = base + s->count; > - break; > - case 4: > - case 5: > - if (d< s->count) > - next_time = s->count; > - else if (d == s->count) > - next_time = s->count + 1; > - else > - return -1; > - break; > - } > - /* convert to timer units */ > - next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(), > - PIT_FREQ); > - /* fix potential rounding problems */ > - /* XXX: better solution: use a clock at PIT_FREQ Hz */ > - if (next_time<= current_time) > - next_time = current_time + 1; > - return next_time; > -} > - > /* val must be 0 or 1 */ > -void pit_set_gate(ISADevice *dev, int channel, int val) > +static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc, > + int val) > { > - PITState *pit = DO_UPCAST(PITState, dev, dev); > - PITChannelState *s =&pit->channels[channel]; > - > - switch(s->mode) { > + switch (sc->mode) { > default: > case 0: > case 4: > @@ -189,34 +74,23 @@ void pit_set_gate(ISADevice *dev, int channel, int val) > break; > case 1: > case 5: > - if (s->gate< val) { > + if (sc->gate< val) { > /* restart counting on rising edge */ > - s->count_load_time = qemu_get_clock_ns(vm_clock); > - pit_irq_timer_update(s, s->count_load_time); > + sc->count_load_time = qemu_get_clock_ns(vm_clock); > + pit_irq_timer_update(sc, sc->count_load_time); > } > break; > case 2: > case 3: > - if (s->gate< val) { > + if (sc->gate< val) { > /* restart counting on rising edge */ > - s->count_load_time = qemu_get_clock_ns(vm_clock); > - pit_irq_timer_update(s, s->count_load_time); > + sc->count_load_time = qemu_get_clock_ns(vm_clock); > + pit_irq_timer_update(sc, sc->count_load_time); > } > /* XXX: disable/enable counting */ > break; > } > - s->gate = val; > -} > - > -void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info) > -{ > - PITState *pit = DO_UPCAST(PITState, dev, dev); > - PITChannelState *s =&pit->channels[channel]; > - > - 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)); > + sc->gate = val; > } > > static inline void pit_load_count(PITChannelState *s, int val) > @@ -239,7 +113,7 @@ static void pit_latch_count(PITChannelState *s) > > static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) > { > - PITState *pit = opaque; > + PITCommonState *pit = opaque; > int channel, access; > PITChannelState *s; > > @@ -306,7 +180,7 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val) > > static uint32_t pit_ioport_read(void *opaque, uint32_t addr) > { > - PITState *pit = opaque; > + PITCommonState *pit = opaque; > int ret, count; > PITChannelState *s; > > @@ -387,94 +261,16 @@ static void pit_irq_timer(void *opaque) > pit_irq_timer_update(s, s->next_transition_time); > } > > -static const VMStateDescription vmstate_pit_channel = { > - .name = "pit channel", > - .version_id = 2, > - .minimum_version_id = 2, > - .minimum_version_id_old = 2, > - .fields = (VMStateField []) { > - VMSTATE_INT32(count, PITChannelState), > - VMSTATE_UINT16(latched_count, PITChannelState), > - VMSTATE_UINT8(count_latched, PITChannelState), > - VMSTATE_UINT8(status_latched, PITChannelState), > - VMSTATE_UINT8(status, PITChannelState), > - VMSTATE_UINT8(read_state, PITChannelState), > - VMSTATE_UINT8(write_state, PITChannelState), > - VMSTATE_UINT8(write_latch, PITChannelState), > - VMSTATE_UINT8(rw_mode, PITChannelState), > - VMSTATE_UINT8(mode, PITChannelState), > - VMSTATE_UINT8(bcd, PITChannelState), > - VMSTATE_UINT8(gate, PITChannelState), > - VMSTATE_INT64(count_load_time, PITChannelState), > - VMSTATE_INT64(next_transition_time, PITChannelState), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -static int pit_load_old(QEMUFile *f, void *opaque, int version_id) > +static void pit_reset(DeviceState *dev) > { > - PITState *pit = opaque; > + PITCommonState *pit = DO_UPCAST(PITCommonState, dev.qdev, dev); > PITChannelState *s; > - int i; > - > - if (version_id != 1) > - return -EINVAL; > - > - for(i = 0; i< 3; i++) { > - s =&pit->channels[i]; > - s->count=qemu_get_be32(f); > - qemu_get_be16s(f,&s->latched_count); > - qemu_get_8s(f,&s->count_latched); > - qemu_get_8s(f,&s->status_latched); > - qemu_get_8s(f,&s->status); > - qemu_get_8s(f,&s->read_state); > - qemu_get_8s(f,&s->write_state); > - qemu_get_8s(f,&s->write_latch); > - qemu_get_8s(f,&s->rw_mode); > - qemu_get_8s(f,&s->mode); > - 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); > - } > - } > - return 0; > -} > > -static const VMStateDescription vmstate_pit = { > - .name = "i8254", > - .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() > - } > -}; > + pit_reset_common(pit); > > -static void pit_reset(DeviceState *dev) > -{ > - PITState *pit = container_of(dev, PITState, dev.qdev); > - PITChannelState *s; > - int i; > - > - for(i = 0;i< 3; i++) { > - s =&pit->channels[i]; > - s->mode = 3; > - s->gate = (i != 2); > - 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); > - } > + s =&pit->channels[0]; > + if (!s->irq_disabled) { > + qemu_mod_timer(s->irq_timer, s->next_transition_time); > } > } > > @@ -482,7 +278,7 @@ static void pit_reset(DeviceState *dev) > * reenable it when legacy mode is left again. */ > static void pit_irq_control(void *opaque, int n, int enable) > { > - PITState *pit = opaque; > + PITCommonState *pit = opaque; > PITChannelState *s =&pit->channels[0]; > > if (enable) { > @@ -504,47 +300,44 @@ static const MemoryRegionOps pit_ioport_ops = { > .old_portio = pit_portio > }; > > -static int pit_initfn(ISADevice *dev) > +static int pit_initfn(PITCommonState *pit) > { > - PITState *pit = DO_UPCAST(PITState, dev, dev); > PITChannelState *s; > > 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); > - qdev_init_gpio_out(&dev->qdev,&s->irq, 1); > + qdev_init_gpio_out(&pit->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); > + qdev_init_gpio_in(&pit->dev.qdev, pit_irq_control, 1); > > return 0; > } > > -static void pit_class_initfn(ObjectClass *klass, void *data) > +static void pit_class_init(ObjectClass *klass, void *data) > { > - ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); > - ic->init = pit_initfn; > + PITCommonClass *k = PIT_COMMON_CLASS(klass); > + > + k->init = pit_initfn; > + k->set_channel_gate = pit_set_channel_gate; > + k->get_channel_info = pit_get_channel_info_common; > } > > static DeviceInfo pit_info = { > - .name = "isa-pit", > - .size = sizeof(PITState), > - .vmsd =&vmstate_pit, > - .reset = pit_reset, > - .no_user = 1, > - .class_init = pit_class_initfn, > + .name = "isa-pit", > + .size = sizeof(PITCommonState), > + .reset = pit_reset, > + .class_init = pit_class_init, > .props = (Property[]) { > - DEFINE_PROP_HEX32("iobase", PITState, iobase, -1), > + DEFINE_PROP_HEX32("iobase", PITCommonState, iobase, -1), > DEFINE_PROP_END_OF_LIST(), > }, > }; > > static void pit_register(void) > { > - isa_qdev_register(&pit_info); > + pit_qdev_register(&pit_info); > } > device_init(pit_register) > diff --git a/hw/i8254_common.c b/hw/i8254_common.c > new file mode 100644 > index 0000000..6ff91fb > --- /dev/null > +++ b/hw/i8254_common.c > @@ -0,0 +1,311 @@ > +/* > + * QEMU 8253/8254 - common bits of emulated and KVM kernel model > + * > + * Copyright (c) 2003-2004 Fabrice Bellard > + * Copyright (c) 2012 Jan Kiszka, Siemens AG > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > +#include "hw.h" > +#include "pc.h" > +#include "isa.h" > +#include "qemu-timer.h" > +#include "i8254.h" > +#include "i8254_internal.h" > + > +/* val must be 0 or 1 */ > +void pit_set_gate(ISADevice *dev, int channel, int val) > +{ > + PITCommonState *pit = PIT_COMMON(dev); > + PITChannelState *s =&pit->channels[channel]; > + PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); > + > + c->set_channel_gate(pit, s, val); > +} > + > +/* get pit output bit */ > +int pit_get_out(PITChannelState *s, int64_t current_time) > +{ > + uint64_t d; > + int out; > + > + d = muldiv64(current_time - s->count_load_time, PIT_FREQ, > + get_ticks_per_sec()); > + switch (s->mode) { > + default: > + case 0: > + out = (d>= s->count); > + break; > + case 1: > + out = (d< s->count); > + break; > + case 2: > + if ((d % s->count) == 0&& d != 0) { > + out = 1; > + } else { > + out = 0; > + } > + break; > + case 3: > + out = (d % s->count)< ((s->count + 1)>> 1); > + break; > + case 4: > + case 5: > + out = (d == s->count); > + break; > + } > + return out; > +} > + > +/* return -1 if no transition will occur. */ > +int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time) > +{ > + uint64_t d, next_time, base; > + int period2; > + > + d = muldiv64(current_time - s->count_load_time, PIT_FREQ, > + get_ticks_per_sec()); > + switch (s->mode) { > + default: > + case 0: > + case 1: > + if (d< s->count) { > + next_time = s->count; > + } else { > + return -1; > + } > + break; > + case 2: > + base = (d / s->count) * s->count; > + if ((d - base) == 0&& d != 0) { > + next_time = base + s->count; > + } else { > + next_time = base + s->count + 1; > + } > + break; > + case 3: > + base = (d / s->count) * s->count; > + period2 = ((s->count + 1)>> 1); > + if ((d - base)< period2) { > + next_time = base + period2; > + } else { > + next_time = base + s->count; > + } > + break; > + case 4: > + case 5: > + if (d< s->count) { > + next_time = s->count; > + } else if (d == s->count) { > + next_time = s->count + 1; > + } else { > + return -1; > + } > + break; > + } > + /* convert to timer units */ > + next_time = s->count_load_time + muldiv64(next_time, get_ticks_per_sec(), > + PIT_FREQ); > + /* fix potential rounding problems */ > + /* XXX: better solution: use a clock at PIT_FREQ Hz */ > + if (next_time<= current_time) { > + next_time = current_time + 1; > + } > + return next_time; > +} > + > +void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc, > + PITChannelInfo *info) > +{ > + info->gate = sc->gate; > + info->mode = sc->mode; > + info->initial_count = sc->count; > + info->out = pit_get_out(sc, qemu_get_clock_ns(vm_clock)); > +} > + > +void pit_get_channel_info(ISADevice *dev, int channel, PITChannelInfo *info) > +{ > + PITCommonState *pit = PIT_COMMON(dev); > + PITChannelState *s =&pit->channels[channel]; > + PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); > + > + c->get_channel_info(pit, s, info); > +} > + > +void pit_reset_common(PITCommonState *pit) > +{ > + PITChannelState *s; > + int i; > + > + for (i = 0; i< 3; i++) { > + s =&pit->channels[i]; > + s->mode = 3; > + s->gate = (i != 2); > + 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); > + } > + } > +} > + > +static int pit_init_common(ISADevice *dev) > +{ > + PITCommonState *pit = PIT_COMMON(dev); > + PITCommonClass *c = PIT_COMMON_GET_CLASS(pit); > + int ret; > + > + ret = c->init(pit); > + if (ret< 0) { > + return ret; > + } > + > + isa_register_ioport(dev,&pit->ioports, pit->iobase); > + > + qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2); > + > + return 0; > +} > + > +static const VMStateDescription vmstate_pit_channel = { > + .name = "pit channel", > + .version_id = 2, > + .minimum_version_id = 2, > + .minimum_version_id_old = 2, > + .fields = (VMStateField[]) { > + VMSTATE_INT32(count, PITChannelState), > + VMSTATE_UINT16(latched_count, PITChannelState), > + VMSTATE_UINT8(count_latched, PITChannelState), > + VMSTATE_UINT8(status_latched, PITChannelState), > + VMSTATE_UINT8(status, PITChannelState), > + VMSTATE_UINT8(read_state, PITChannelState), > + VMSTATE_UINT8(write_state, PITChannelState), > + VMSTATE_UINT8(write_latch, PITChannelState), > + VMSTATE_UINT8(rw_mode, PITChannelState), > + VMSTATE_UINT8(mode, PITChannelState), > + VMSTATE_UINT8(bcd, PITChannelState), > + VMSTATE_UINT8(gate, PITChannelState), > + VMSTATE_INT64(count_load_time, PITChannelState), > + VMSTATE_INT64(next_transition_time, PITChannelState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static int pit_load_old(QEMUFile *f, void *opaque, int version_id) > +{ > + PITCommonState *pit = opaque; > + PITChannelState *s; > + int i; > + > + if (version_id != 1) { > + return -EINVAL; > + } > + > + for (i = 0; i< 3; i++) { > + s =&pit->channels[i]; > + s->count = qemu_get_be32(f); > + qemu_get_be16s(f,&s->latched_count); > + qemu_get_8s(f,&s->count_latched); > + qemu_get_8s(f,&s->status_latched); > + qemu_get_8s(f,&s->status); > + qemu_get_8s(f,&s->read_state); > + qemu_get_8s(f,&s->write_state); > + qemu_get_8s(f,&s->write_latch); > + qemu_get_8s(f,&s->rw_mode); > + qemu_get_8s(f,&s->mode); > + 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); > + } > + } > + return 0; > +} > + > +static void pit_dispatch_pre_save(void *opaque) > +{ > + PITCommonState *s = opaque; > + PITCommonClass *c = PIT_COMMON_GET_CLASS(s); > + > + if (c->pre_save) { > + c->pre_save(s); > + } > +} > + > +static int pit_dispatch_post_load(void *opaque, int version_id) > +{ > + PITCommonState *s = opaque; > + PITCommonClass *c = PIT_COMMON_GET_CLASS(s); > + > + if (c->post_load) { > + c->post_load(s); > + } > + return 0; > +} > + > +static const VMStateDescription vmstate_pit_common = { > + .name = "i8254", > + .version_id = 3, > + .minimum_version_id = 2, > + .minimum_version_id_old = 1, > + .load_state_old = pit_load_old, > + .pre_save = pit_dispatch_pre_save, > + .post_load = pit_dispatch_post_load, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32_V(channels[0].irq_disabled, PITCommonState, 3), > + VMSTATE_STRUCT_ARRAY(channels, PITCommonState, 3, 2, > + vmstate_pit_channel, PITChannelState), > + VMSTATE_TIMER(channels[0].irq_timer, PITCommonState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void pit_common_class_init(ObjectClass *klass, void *data) > +{ > + ISADeviceClass *ic = ISA_DEVICE_CLASS(klass); > + > + ic->init = pit_init_common; > +} > + > +static TypeInfo pit_common_type = { > + .name = TYPE_PIT_COMMON, > + .parent = TYPE_ISA_DEVICE, > + .instance_size = sizeof(PITCommonState), > + .class_size = sizeof(PITCommonClass), > + .class_init = pit_common_class_init, > + .abstract = true, > +}; > + > +void pit_qdev_register(DeviceInfo *info) > +{ > + info->vmsd =&vmstate_pit_common; > + info->no_user = 1; > + isa_qdev_register_subclass(info, TYPE_PIT_COMMON); > +} > + > +static void register_devices(void) > +{ > + type_register_static(&pit_common_type); > +} > + > +device_init(register_devices); > diff --git a/hw/i8254_internal.h b/hw/i8254_internal.h > new file mode 100644 > index 0000000..a074aa0 > --- /dev/null > +++ b/hw/i8254_internal.h > @@ -0,0 +1,87 @@ > +/* > + * QEMU 8253/8254 - internal interfaces > + * > + * Copyright (c) 2011 Jan Kiszka, Siemens AG > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +#ifndef QEMU_I8254_INTERNAL_H > +#define QEMU_I8254_INTERNAL_H > + > +#include "hw.h" > +#include "pc.h" > +#include "isa.h" > + > +typedef struct PITChannelState { > + int count; /* can be 65536 */ > + uint16_t latched_count; > + uint8_t count_latched; > + uint8_t status_latched; > + uint8_t status; > + uint8_t read_state; > + uint8_t write_state; > + uint8_t write_latch; > + uint8_t rw_mode; > + uint8_t mode; > + uint8_t bcd; /* not supported */ > + uint8_t gate; /* timer start */ > + int64_t count_load_time; > + /* irq handling */ > + int64_t next_transition_time; > + QEMUTimer *irq_timer; > + qemu_irq irq; > + uint32_t irq_disabled; > +} PITChannelState; > + > +typedef struct PITCommonState { > + ISADevice dev; > + MemoryRegion ioports; > + uint32_t iobase; > + PITChannelState channels[3]; > +} PITCommonState; > + > +#define TYPE_PIT_COMMON "pit-common" > +#define PIT_COMMON(obj) \ > + OBJECT_CHECK(PITCommonState, (obj), TYPE_PIT_COMMON) > +#define PIT_COMMON_CLASS(klass) \ > + OBJECT_CLASS_CHECK(PITCommonClass, (klass), TYPE_PIT_COMMON) > +#define PIT_COMMON_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(PITCommonClass, (obj), TYPE_PIT_COMMON) > + > +typedef struct PITCommonClass { > + ISADeviceClass parent_class; > + > + int (*init)(PITCommonState *s); > + void (*set_channel_gate)(PITCommonState *s, PITChannelState *sc, int val); > + void (*get_channel_info)(PITCommonState *s, PITChannelState *sc, > + PITChannelInfo *info); > + void (*pre_save)(PITCommonState *s); > + void (*post_load)(PITCommonState *s); > +} PITCommonClass; > + > +int pit_get_out(PITChannelState *s, int64_t current_time); > +int64_t pit_get_next_transition_time(PITChannelState *s, int64_t current_time); > +void pit_get_channel_info_common(PITCommonState *s, PITChannelState *sc, > + PITChannelInfo *info); > +void pit_reset_common(PITCommonState *s); > + > +void pit_qdev_register(DeviceInfo *info); > + > +#endif /* !QEMU_I8254_INTERNAL_H */