xref: /qemu/hw/timer/i8254.c (revision 02520772)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU 8253/8254 interval timer emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2003-2004 Fabrice Bellard
549ab747fSPaolo Bonzini  *
649ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
749ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
849ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
949ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1049ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1149ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1249ab747fSPaolo Bonzini  *
1349ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1449ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1549ab747fSPaolo Bonzini  *
1649ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1749ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1849ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1949ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2049ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2149ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2249ab747fSPaolo Bonzini  * THE SOFTWARE.
2349ab747fSPaolo Bonzini  */
240b8fa32fSMarkus Armbruster 
25b6a0aa05SPeter Maydell #include "qemu/osdep.h"
2664552b6bSMarkus Armbruster #include "hw/irq.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
2849ab747fSPaolo Bonzini #include "qemu/timer.h"
2949ab747fSPaolo Bonzini #include "hw/timer/i8254.h"
3049ab747fSPaolo Bonzini #include "hw/timer/i8254_internal.h"
31db1015e9SEduardo Habkost #include "qom/object.h"
3249ab747fSPaolo Bonzini 
3349ab747fSPaolo Bonzini //#define DEBUG_PIT
3449ab747fSPaolo Bonzini 
3549ab747fSPaolo Bonzini #define RW_STATE_LSB 1
3649ab747fSPaolo Bonzini #define RW_STATE_MSB 2
3749ab747fSPaolo Bonzini #define RW_STATE_WORD0 3
3849ab747fSPaolo Bonzini #define RW_STATE_WORD1 4
3949ab747fSPaolo Bonzini 
40db1015e9SEduardo Habkost typedef struct PITClass PITClass;
418110fa1dSEduardo Habkost DECLARE_CLASS_CHECKERS(PITClass, PIT,
428110fa1dSEduardo Habkost                        TYPE_I8254)
43a15d0912SAndreas Färber 
44db1015e9SEduardo Habkost struct PITClass {
45a15d0912SAndreas Färber     PITCommonClass parent_class;
46a15d0912SAndreas Färber 
47a15d0912SAndreas Färber     DeviceRealize parent_realize;
48db1015e9SEduardo Habkost };
49a15d0912SAndreas Färber 
5049ab747fSPaolo Bonzini static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
5149ab747fSPaolo Bonzini 
pit_get_count(PITChannelState * s)5249ab747fSPaolo Bonzini static int pit_get_count(PITChannelState *s)
5349ab747fSPaolo Bonzini {
5449ab747fSPaolo Bonzini     uint64_t d;
5549ab747fSPaolo Bonzini     int counter;
5649ab747fSPaolo Bonzini 
57bc72ad67SAlex Bligh     d = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->count_load_time, PIT_FREQ,
5873bcb24dSRutuja Shah                  NANOSECONDS_PER_SECOND);
5949ab747fSPaolo Bonzini     switch(s->mode) {
6049ab747fSPaolo Bonzini     case 0:
6149ab747fSPaolo Bonzini     case 1:
6249ab747fSPaolo Bonzini     case 4:
6349ab747fSPaolo Bonzini     case 5:
6449ab747fSPaolo Bonzini         counter = (s->count - d) & 0xffff;
6549ab747fSPaolo Bonzini         break;
6649ab747fSPaolo Bonzini     case 3:
6749ab747fSPaolo Bonzini         /* XXX: may be incorrect for odd counts */
6849ab747fSPaolo Bonzini         counter = s->count - ((2 * d) % s->count);
6949ab747fSPaolo Bonzini         break;
7049ab747fSPaolo Bonzini     default:
7149ab747fSPaolo Bonzini         counter = s->count - (d % s->count);
7249ab747fSPaolo Bonzini         break;
7349ab747fSPaolo Bonzini     }
7449ab747fSPaolo Bonzini     return counter;
7549ab747fSPaolo Bonzini }
7649ab747fSPaolo Bonzini 
7749ab747fSPaolo Bonzini /* val must be 0 or 1 */
pit_set_channel_gate(PITCommonState * s,PITChannelState * sc,int val)7849ab747fSPaolo Bonzini static void pit_set_channel_gate(PITCommonState *s, PITChannelState *sc,
7949ab747fSPaolo Bonzini                                  int val)
8049ab747fSPaolo Bonzini {
8149ab747fSPaolo Bonzini     switch (sc->mode) {
8249ab747fSPaolo Bonzini     default:
8349ab747fSPaolo Bonzini     case 0:
8449ab747fSPaolo Bonzini     case 4:
8549ab747fSPaolo Bonzini         /* XXX: just disable/enable counting */
8649ab747fSPaolo Bonzini         break;
8749ab747fSPaolo Bonzini     case 1:
8849ab747fSPaolo Bonzini     case 5:
8949ab747fSPaolo Bonzini         if (sc->gate < val) {
9049ab747fSPaolo Bonzini             /* restart counting on rising edge */
91bc72ad67SAlex Bligh             sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
9249ab747fSPaolo Bonzini             pit_irq_timer_update(sc, sc->count_load_time);
9349ab747fSPaolo Bonzini         }
9449ab747fSPaolo Bonzini         break;
9549ab747fSPaolo Bonzini     case 2:
9649ab747fSPaolo Bonzini     case 3:
9749ab747fSPaolo Bonzini         if (sc->gate < val) {
9849ab747fSPaolo Bonzini             /* restart counting on rising edge */
99bc72ad67SAlex Bligh             sc->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
10049ab747fSPaolo Bonzini             pit_irq_timer_update(sc, sc->count_load_time);
10149ab747fSPaolo Bonzini         }
10249ab747fSPaolo Bonzini         /* XXX: disable/enable counting */
10349ab747fSPaolo Bonzini         break;
10449ab747fSPaolo Bonzini     }
10549ab747fSPaolo Bonzini     sc->gate = val;
10649ab747fSPaolo Bonzini }
10749ab747fSPaolo Bonzini 
pit_load_count(PITChannelState * s,int val)10849ab747fSPaolo Bonzini static inline void pit_load_count(PITChannelState *s, int val)
10949ab747fSPaolo Bonzini {
11049ab747fSPaolo Bonzini     if (val == 0)
11149ab747fSPaolo Bonzini         val = 0x10000;
112bc72ad67SAlex Bligh     s->count_load_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
11349ab747fSPaolo Bonzini     s->count = val;
11449ab747fSPaolo Bonzini     pit_irq_timer_update(s, s->count_load_time);
11549ab747fSPaolo Bonzini }
11649ab747fSPaolo Bonzini 
11749ab747fSPaolo Bonzini /* if already latched, do not latch again */
pit_latch_count(PITChannelState * s)11849ab747fSPaolo Bonzini static void pit_latch_count(PITChannelState *s)
11949ab747fSPaolo Bonzini {
12049ab747fSPaolo Bonzini     if (!s->count_latched) {
12149ab747fSPaolo Bonzini         s->latched_count = pit_get_count(s);
12249ab747fSPaolo Bonzini         s->count_latched = s->rw_mode;
12349ab747fSPaolo Bonzini     }
12449ab747fSPaolo Bonzini }
12549ab747fSPaolo Bonzini 
pit_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)12649ab747fSPaolo Bonzini static void pit_ioport_write(void *opaque, hwaddr addr,
12749ab747fSPaolo Bonzini                              uint64_t val, unsigned size)
12849ab747fSPaolo Bonzini {
12949ab747fSPaolo Bonzini     PITCommonState *pit = opaque;
13049ab747fSPaolo Bonzini     int channel, access;
13149ab747fSPaolo Bonzini     PITChannelState *s;
13249ab747fSPaolo Bonzini 
13349ab747fSPaolo Bonzini     addr &= 3;
13449ab747fSPaolo Bonzini     if (addr == 3) {
13549ab747fSPaolo Bonzini         channel = val >> 6;
13649ab747fSPaolo Bonzini         if (channel == 3) {
13749ab747fSPaolo Bonzini             /* read back command */
13849ab747fSPaolo Bonzini             for(channel = 0; channel < 3; channel++) {
13949ab747fSPaolo Bonzini                 s = &pit->channels[channel];
14049ab747fSPaolo Bonzini                 if (val & (2 << channel)) {
14149ab747fSPaolo Bonzini                     if (!(val & 0x20)) {
14249ab747fSPaolo Bonzini                         pit_latch_count(s);
14349ab747fSPaolo Bonzini                     }
14449ab747fSPaolo Bonzini                     if (!(val & 0x10) && !s->status_latched) {
14549ab747fSPaolo Bonzini                         /* status latch */
14649ab747fSPaolo Bonzini                         /* XXX: add BCD and null count */
14749ab747fSPaolo Bonzini                         s->status =
14849ab747fSPaolo Bonzini                             (pit_get_out(s,
149bc72ad67SAlex Bligh                                          qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) << 7) |
15049ab747fSPaolo Bonzini                             (s->rw_mode << 4) |
15149ab747fSPaolo Bonzini                             (s->mode << 1) |
15249ab747fSPaolo Bonzini                             s->bcd;
15349ab747fSPaolo Bonzini                         s->status_latched = 1;
15449ab747fSPaolo Bonzini                     }
15549ab747fSPaolo Bonzini                 }
15649ab747fSPaolo Bonzini             }
15749ab747fSPaolo Bonzini         } else {
15849ab747fSPaolo Bonzini             s = &pit->channels[channel];
15949ab747fSPaolo Bonzini             access = (val >> 4) & 3;
16049ab747fSPaolo Bonzini             if (access == 0) {
16149ab747fSPaolo Bonzini                 pit_latch_count(s);
16249ab747fSPaolo Bonzini             } else {
16349ab747fSPaolo Bonzini                 s->rw_mode = access;
16449ab747fSPaolo Bonzini                 s->read_state = access;
16549ab747fSPaolo Bonzini                 s->write_state = access;
16649ab747fSPaolo Bonzini 
16749ab747fSPaolo Bonzini                 s->mode = (val >> 1) & 7;
16849ab747fSPaolo Bonzini                 s->bcd = val & 1;
16949ab747fSPaolo Bonzini                 /* XXX: update irq timer ? */
17049ab747fSPaolo Bonzini             }
17149ab747fSPaolo Bonzini         }
17249ab747fSPaolo Bonzini     } else {
17349ab747fSPaolo Bonzini         s = &pit->channels[addr];
17449ab747fSPaolo Bonzini         switch(s->write_state) {
17549ab747fSPaolo Bonzini         default:
17649ab747fSPaolo Bonzini         case RW_STATE_LSB:
17749ab747fSPaolo Bonzini             pit_load_count(s, val);
17849ab747fSPaolo Bonzini             break;
17949ab747fSPaolo Bonzini         case RW_STATE_MSB:
18049ab747fSPaolo Bonzini             pit_load_count(s, val << 8);
18149ab747fSPaolo Bonzini             break;
18249ab747fSPaolo Bonzini         case RW_STATE_WORD0:
18349ab747fSPaolo Bonzini             s->write_latch = val;
18449ab747fSPaolo Bonzini             s->write_state = RW_STATE_WORD1;
18549ab747fSPaolo Bonzini             break;
18649ab747fSPaolo Bonzini         case RW_STATE_WORD1:
18749ab747fSPaolo Bonzini             pit_load_count(s, s->write_latch | (val << 8));
18849ab747fSPaolo Bonzini             s->write_state = RW_STATE_WORD0;
18949ab747fSPaolo Bonzini             break;
19049ab747fSPaolo Bonzini         }
19149ab747fSPaolo Bonzini     }
19249ab747fSPaolo Bonzini }
19349ab747fSPaolo Bonzini 
pit_ioport_read(void * opaque,hwaddr addr,unsigned size)19449ab747fSPaolo Bonzini static uint64_t pit_ioport_read(void *opaque, hwaddr addr,
19549ab747fSPaolo Bonzini                                 unsigned size)
19649ab747fSPaolo Bonzini {
19749ab747fSPaolo Bonzini     PITCommonState *pit = opaque;
19849ab747fSPaolo Bonzini     int ret, count;
19949ab747fSPaolo Bonzini     PITChannelState *s;
20049ab747fSPaolo Bonzini 
20149ab747fSPaolo Bonzini     addr &= 3;
202d4862a87SPetr Matousek 
203d4862a87SPetr Matousek     if (addr == 3) {
204d4862a87SPetr Matousek         /* Mode/Command register is write only, read is ignored */
205d4862a87SPetr Matousek         return 0;
206d4862a87SPetr Matousek     }
207d4862a87SPetr Matousek 
20849ab747fSPaolo Bonzini     s = &pit->channels[addr];
20949ab747fSPaolo Bonzini     if (s->status_latched) {
21049ab747fSPaolo Bonzini         s->status_latched = 0;
21149ab747fSPaolo Bonzini         ret = s->status;
21249ab747fSPaolo Bonzini     } else if (s->count_latched) {
21349ab747fSPaolo Bonzini         switch(s->count_latched) {
21449ab747fSPaolo Bonzini         default:
21549ab747fSPaolo Bonzini         case RW_STATE_LSB:
21649ab747fSPaolo Bonzini             ret = s->latched_count & 0xff;
21749ab747fSPaolo Bonzini             s->count_latched = 0;
21849ab747fSPaolo Bonzini             break;
21949ab747fSPaolo Bonzini         case RW_STATE_MSB:
22049ab747fSPaolo Bonzini             ret = s->latched_count >> 8;
22149ab747fSPaolo Bonzini             s->count_latched = 0;
22249ab747fSPaolo Bonzini             break;
22349ab747fSPaolo Bonzini         case RW_STATE_WORD0:
22449ab747fSPaolo Bonzini             ret = s->latched_count & 0xff;
22549ab747fSPaolo Bonzini             s->count_latched = RW_STATE_MSB;
22649ab747fSPaolo Bonzini             break;
22749ab747fSPaolo Bonzini         }
22849ab747fSPaolo Bonzini     } else {
22949ab747fSPaolo Bonzini         switch(s->read_state) {
23049ab747fSPaolo Bonzini         default:
23149ab747fSPaolo Bonzini         case RW_STATE_LSB:
23249ab747fSPaolo Bonzini             count = pit_get_count(s);
23349ab747fSPaolo Bonzini             ret = count & 0xff;
23449ab747fSPaolo Bonzini             break;
23549ab747fSPaolo Bonzini         case RW_STATE_MSB:
23649ab747fSPaolo Bonzini             count = pit_get_count(s);
23749ab747fSPaolo Bonzini             ret = (count >> 8) & 0xff;
23849ab747fSPaolo Bonzini             break;
23949ab747fSPaolo Bonzini         case RW_STATE_WORD0:
24049ab747fSPaolo Bonzini             count = pit_get_count(s);
24149ab747fSPaolo Bonzini             ret = count & 0xff;
24249ab747fSPaolo Bonzini             s->read_state = RW_STATE_WORD1;
24349ab747fSPaolo Bonzini             break;
24449ab747fSPaolo Bonzini         case RW_STATE_WORD1:
24549ab747fSPaolo Bonzini             count = pit_get_count(s);
24649ab747fSPaolo Bonzini             ret = (count >> 8) & 0xff;
24749ab747fSPaolo Bonzini             s->read_state = RW_STATE_WORD0;
24849ab747fSPaolo Bonzini             break;
24949ab747fSPaolo Bonzini         }
25049ab747fSPaolo Bonzini     }
25149ab747fSPaolo Bonzini     return ret;
25249ab747fSPaolo Bonzini }
25349ab747fSPaolo Bonzini 
pit_irq_timer_update(PITChannelState * s,int64_t current_time)25449ab747fSPaolo Bonzini static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
25549ab747fSPaolo Bonzini {
25649ab747fSPaolo Bonzini     int64_t expire_time;
25749ab747fSPaolo Bonzini     int irq_level;
25849ab747fSPaolo Bonzini 
25949ab747fSPaolo Bonzini     if (!s->irq_timer || s->irq_disabled) {
26049ab747fSPaolo Bonzini         return;
26149ab747fSPaolo Bonzini     }
26249ab747fSPaolo Bonzini     expire_time = pit_get_next_transition_time(s, current_time);
26349ab747fSPaolo Bonzini     irq_level = pit_get_out(s, current_time);
26449ab747fSPaolo Bonzini     qemu_set_irq(s->irq, irq_level);
26549ab747fSPaolo Bonzini #ifdef DEBUG_PIT
26649ab747fSPaolo Bonzini     printf("irq_level=%d next_delay=%f\n",
26749ab747fSPaolo Bonzini            irq_level,
26873bcb24dSRutuja Shah            (double)(expire_time - current_time) / NANOSECONDS_PER_SECOND);
26949ab747fSPaolo Bonzini #endif
27049ab747fSPaolo Bonzini     s->next_transition_time = expire_time;
27149ab747fSPaolo Bonzini     if (expire_time != -1)
272bc72ad67SAlex Bligh         timer_mod(s->irq_timer, expire_time);
27349ab747fSPaolo Bonzini     else
274bc72ad67SAlex Bligh         timer_del(s->irq_timer);
27549ab747fSPaolo Bonzini }
27649ab747fSPaolo Bonzini 
pit_irq_timer(void * opaque)27749ab747fSPaolo Bonzini static void pit_irq_timer(void *opaque)
27849ab747fSPaolo Bonzini {
27949ab747fSPaolo Bonzini     PITChannelState *s = opaque;
28049ab747fSPaolo Bonzini 
28149ab747fSPaolo Bonzini     pit_irq_timer_update(s, s->next_transition_time);
28249ab747fSPaolo Bonzini }
28349ab747fSPaolo Bonzini 
pit_reset(DeviceState * dev)28449ab747fSPaolo Bonzini static void pit_reset(DeviceState *dev)
28549ab747fSPaolo Bonzini {
2863afe7e14SAndreas Färber     PITCommonState *pit = PIT_COMMON(dev);
28749ab747fSPaolo Bonzini     PITChannelState *s;
28849ab747fSPaolo Bonzini 
28949ab747fSPaolo Bonzini     pit_reset_common(pit);
29049ab747fSPaolo Bonzini 
29149ab747fSPaolo Bonzini     s = &pit->channels[0];
29249ab747fSPaolo Bonzini     if (!s->irq_disabled) {
293bc72ad67SAlex Bligh         timer_mod(s->irq_timer, s->next_transition_time);
29449ab747fSPaolo Bonzini     }
29549ab747fSPaolo Bonzini }
29649ab747fSPaolo Bonzini 
29749ab747fSPaolo Bonzini /* When HPET is operating in legacy mode, suppress the ignored timer IRQ,
29849ab747fSPaolo Bonzini  * reenable it when legacy mode is left again. */
pit_irq_control(void * opaque,int n,int enable)29949ab747fSPaolo Bonzini static void pit_irq_control(void *opaque, int n, int enable)
30049ab747fSPaolo Bonzini {
30149ab747fSPaolo Bonzini     PITCommonState *pit = opaque;
30249ab747fSPaolo Bonzini     PITChannelState *s = &pit->channels[0];
30349ab747fSPaolo Bonzini 
30449ab747fSPaolo Bonzini     if (enable) {
30549ab747fSPaolo Bonzini         s->irq_disabled = 0;
306bc72ad67SAlex Bligh         pit_irq_timer_update(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
30749ab747fSPaolo Bonzini     } else {
30849ab747fSPaolo Bonzini         s->irq_disabled = 1;
309bc72ad67SAlex Bligh         timer_del(s->irq_timer);
31049ab747fSPaolo Bonzini     }
31149ab747fSPaolo Bonzini }
31249ab747fSPaolo Bonzini 
31349ab747fSPaolo Bonzini static const MemoryRegionOps pit_ioport_ops = {
31449ab747fSPaolo Bonzini     .read = pit_ioport_read,
31549ab747fSPaolo Bonzini     .write = pit_ioport_write,
31649ab747fSPaolo Bonzini     .impl = {
31749ab747fSPaolo Bonzini         .min_access_size = 1,
31849ab747fSPaolo Bonzini         .max_access_size = 1,
31949ab747fSPaolo Bonzini     },
32049ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
32149ab747fSPaolo Bonzini };
32249ab747fSPaolo Bonzini 
pit_post_load(PITCommonState * s)32349ab747fSPaolo Bonzini static void pit_post_load(PITCommonState *s)
32449ab747fSPaolo Bonzini {
32549ab747fSPaolo Bonzini     PITChannelState *sc = &s->channels[0];
32649ab747fSPaolo Bonzini 
327*c963fee4SPavel Dovgalyuk     if (sc->next_transition_time != -1 && !sc->irq_disabled) {
328bc72ad67SAlex Bligh         timer_mod(sc->irq_timer, sc->next_transition_time);
32949ab747fSPaolo Bonzini     } else {
330bc72ad67SAlex Bligh         timer_del(sc->irq_timer);
33149ab747fSPaolo Bonzini     }
33249ab747fSPaolo Bonzini }
33349ab747fSPaolo Bonzini 
pit_realizefn(DeviceState * dev,Error ** errp)334a7737e44SMarkus Armbruster static void pit_realizefn(DeviceState *dev, Error **errp)
33549ab747fSPaolo Bonzini {
336a15d0912SAndreas Färber     PITCommonState *pit = PIT_COMMON(dev);
337a15d0912SAndreas Färber     PITClass *pc = PIT_GET_CLASS(dev);
33849ab747fSPaolo Bonzini     PITChannelState *s;
33949ab747fSPaolo Bonzini 
34049ab747fSPaolo Bonzini     s = &pit->channels[0];
34149ab747fSPaolo Bonzini     /* the timer 0 is connected to an IRQ */
342bc72ad67SAlex Bligh     s->irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pit_irq_timer, s);
343a15d0912SAndreas Färber     qdev_init_gpio_out(dev, &s->irq, 1);
34449ab747fSPaolo Bonzini 
345853dca12SPaolo Bonzini     memory_region_init_io(&pit->ioports, OBJECT(pit), &pit_ioport_ops,
346853dca12SPaolo Bonzini                           pit, "pit", 4);
34749ab747fSPaolo Bonzini 
348a15d0912SAndreas Färber     qdev_init_gpio_in(dev, pit_irq_control, 1);
34949ab747fSPaolo Bonzini 
350a7737e44SMarkus Armbruster     pc->parent_realize(dev, errp);
35149ab747fSPaolo Bonzini }
35249ab747fSPaolo Bonzini 
pit_class_initfn(ObjectClass * klass,void * data)35349ab747fSPaolo Bonzini static void pit_class_initfn(ObjectClass *klass, void *data)
35449ab747fSPaolo Bonzini {
355a15d0912SAndreas Färber     PITClass *pc = PIT_CLASS(klass);
35649ab747fSPaolo Bonzini     PITCommonClass *k = PIT_COMMON_CLASS(klass);
35749ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
35849ab747fSPaolo Bonzini 
359bf853881SPhilippe Mathieu-Daudé     device_class_set_parent_realize(dc, pit_realizefn, &pc->parent_realize);
36049ab747fSPaolo Bonzini     k->set_channel_gate = pit_set_channel_gate;
36149ab747fSPaolo Bonzini     k->get_channel_info = pit_get_channel_info_common;
36249ab747fSPaolo Bonzini     k->post_load = pit_post_load;
36349ab747fSPaolo Bonzini     dc->reset = pit_reset;
36449ab747fSPaolo Bonzini }
36549ab747fSPaolo Bonzini 
36649ab747fSPaolo Bonzini static const TypeInfo pit_info = {
3673afe7e14SAndreas Färber     .name          = TYPE_I8254,
36849ab747fSPaolo Bonzini     .parent        = TYPE_PIT_COMMON,
36949ab747fSPaolo Bonzini     .instance_size = sizeof(PITCommonState),
37049ab747fSPaolo Bonzini     .class_init    = pit_class_initfn,
371a15d0912SAndreas Färber     .class_size    = sizeof(PITClass),
37249ab747fSPaolo Bonzini };
37349ab747fSPaolo Bonzini 
pit_register_types(void)37449ab747fSPaolo Bonzini static void pit_register_types(void)
37549ab747fSPaolo Bonzini {
37649ab747fSPaolo Bonzini     type_register_static(&pit_info);
37749ab747fSPaolo Bonzini }
37849ab747fSPaolo Bonzini 
37949ab747fSPaolo Bonzini type_init(pit_register_types)
380