xref: /openbmc/qemu/hw/isa/pc87312.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU National Semiconductor PC87312 (Super I/O)
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2010-2012 Herve Poussineau
549ab747fSPaolo Bonzini  * Copyright (c) 2011-2012 Andreas Färber
649ab747fSPaolo Bonzini  *
749ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
849ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
949ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1049ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1149ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1249ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1349ab747fSPaolo Bonzini  *
1449ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1549ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1649ab747fSPaolo Bonzini  *
1749ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1849ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1949ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2049ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2149ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2249ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2349ab747fSPaolo Bonzini  * THE SOFTWARE.
2449ab747fSPaolo Bonzini  */
2549ab747fSPaolo Bonzini 
260d75590dSPeter Maydell #include "qemu/osdep.h"
2749ab747fSPaolo Bonzini #include "hw/isa/pc87312.h"
28a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
29d6454270SMarkus Armbruster #include "migration/vmstate.h"
30da34e65cSMarkus Armbruster #include "qapi/error.h"
3149ab747fSPaolo Bonzini #include "qemu/error-report.h"
320b8fa32fSMarkus Armbruster #include "qemu/module.h"
3349ab747fSPaolo Bonzini #include "trace.h"
3449ab747fSPaolo Bonzini 
3549ab747fSPaolo Bonzini 
3649ab747fSPaolo Bonzini #define REG_FER 0
3749ab747fSPaolo Bonzini #define REG_FAR 1
3849ab747fSPaolo Bonzini #define REG_PTR 2
3949ab747fSPaolo Bonzini 
4049ab747fSPaolo Bonzini #define FER_PARALLEL_EN   0x01
4149ab747fSPaolo Bonzini #define FER_UART1_EN      0x02
4249ab747fSPaolo Bonzini #define FER_UART2_EN      0x04
4349ab747fSPaolo Bonzini #define FER_FDC_EN        0x08
4449ab747fSPaolo Bonzini #define FER_FDC_4         0x10
4549ab747fSPaolo Bonzini #define FER_FDC_ADDR      0x20
4649ab747fSPaolo Bonzini #define FER_IDE_EN        0x40
4749ab747fSPaolo Bonzini #define FER_IDE_ADDR      0x80
4849ab747fSPaolo Bonzini 
4949ab747fSPaolo Bonzini #define FAR_PARALLEL_ADDR 0x03
5049ab747fSPaolo Bonzini #define FAR_UART1_ADDR    0x0C
5149ab747fSPaolo Bonzini #define FAR_UART2_ADDR    0x30
5249ab747fSPaolo Bonzini #define FAR_UART_3_4      0xC0
5349ab747fSPaolo Bonzini 
5449ab747fSPaolo Bonzini #define PTR_POWER_DOWN    0x01
5549ab747fSPaolo Bonzini #define PTR_CLOCK_DOWN    0x02
5649ab747fSPaolo Bonzini #define PTR_PWDN          0x04
5749ab747fSPaolo Bonzini #define PTR_IRQ_5_7       0x08
5849ab747fSPaolo Bonzini #define PTR_UART1_TEST    0x10
5949ab747fSPaolo Bonzini #define PTR_UART2_TEST    0x20
6049ab747fSPaolo Bonzini #define PTR_LOCK_CONF     0x40
6149ab747fSPaolo Bonzini #define PTR_EPP_MODE      0x80
6249ab747fSPaolo Bonzini 
6349ab747fSPaolo Bonzini 
6449ab747fSPaolo Bonzini /* Parallel port */
6549ab747fSPaolo Bonzini 
is_parallel_enabled(ISASuperIODevice * sio,uint8_t index)664c3119a6SPhilippe Mathieu-Daudé static bool is_parallel_enabled(ISASuperIODevice *sio, uint8_t index)
6749ab747fSPaolo Bonzini {
684c3119a6SPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
694c3119a6SPhilippe Mathieu-Daudé     return index ? false : s->regs[REG_FER] & FER_PARALLEL_EN;
7049ab747fSPaolo Bonzini }
7149ab747fSPaolo Bonzini 
724e00105aSPhilippe Mathieu-Daudé static const uint16_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
7349ab747fSPaolo Bonzini 
get_parallel_iobase(ISASuperIODevice * sio,uint8_t index)744c3119a6SPhilippe Mathieu-Daudé static uint16_t get_parallel_iobase(ISASuperIODevice *sio, uint8_t index)
7549ab747fSPaolo Bonzini {
764c3119a6SPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
7749ab747fSPaolo Bonzini     return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR];
7849ab747fSPaolo Bonzini }
7949ab747fSPaolo Bonzini 
80818c9d99SPhilippe Mathieu-Daudé static const unsigned int parallel_irq[] = { 5, 7, 5, 0 };
8149ab747fSPaolo Bonzini 
get_parallel_irq(ISASuperIODevice * sio,uint8_t index)824c3119a6SPhilippe Mathieu-Daudé static unsigned int get_parallel_irq(ISASuperIODevice *sio, uint8_t index)
8349ab747fSPaolo Bonzini {
844c3119a6SPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
8549ab747fSPaolo Bonzini     int idx;
8649ab747fSPaolo Bonzini     idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR);
8749ab747fSPaolo Bonzini     if (idx == 0) {
8849ab747fSPaolo Bonzini         return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5;
8949ab747fSPaolo Bonzini     } else {
9049ab747fSPaolo Bonzini         return parallel_irq[idx];
9149ab747fSPaolo Bonzini     }
9249ab747fSPaolo Bonzini }
9349ab747fSPaolo Bonzini 
9449ab747fSPaolo Bonzini 
9549ab747fSPaolo Bonzini /* UARTs */
9649ab747fSPaolo Bonzini 
974e00105aSPhilippe Mathieu-Daudé static const uint16_t uart_base[2][4] = {
9849ab747fSPaolo Bonzini     { 0x3e8, 0x338, 0x2e8, 0x220 },
9949ab747fSPaolo Bonzini     { 0x2e8, 0x238, 0x2e0, 0x228 }
10049ab747fSPaolo Bonzini };
10149ab747fSPaolo Bonzini 
get_uart_iobase(ISASuperIODevice * sio,uint8_t i)102cd9526abSPhilippe Mathieu-Daudé static uint16_t get_uart_iobase(ISASuperIODevice *sio, uint8_t i)
10349ab747fSPaolo Bonzini {
104cd9526abSPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
10549ab747fSPaolo Bonzini     int idx;
10649ab747fSPaolo Bonzini     idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
10749ab747fSPaolo Bonzini     if (idx == 0) {
10849ab747fSPaolo Bonzini         return 0x3f8;
10949ab747fSPaolo Bonzini     } else if (idx == 1) {
11049ab747fSPaolo Bonzini         return 0x2f8;
11149ab747fSPaolo Bonzini     } else {
11249ab747fSPaolo Bonzini         return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6];
11349ab747fSPaolo Bonzini     }
11449ab747fSPaolo Bonzini }
11549ab747fSPaolo Bonzini 
get_uart_irq(ISASuperIODevice * sio,uint8_t i)116cd9526abSPhilippe Mathieu-Daudé static unsigned int get_uart_irq(ISASuperIODevice *sio, uint8_t i)
11749ab747fSPaolo Bonzini {
118cd9526abSPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
11949ab747fSPaolo Bonzini     int idx;
12049ab747fSPaolo Bonzini     idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
12149ab747fSPaolo Bonzini     return (idx & 1) ? 3 : 4;
12249ab747fSPaolo Bonzini }
12349ab747fSPaolo Bonzini 
is_uart_enabled(ISASuperIODevice * sio,uint8_t i)124cd9526abSPhilippe Mathieu-Daudé static bool is_uart_enabled(ISASuperIODevice *sio, uint8_t i)
12549ab747fSPaolo Bonzini {
126cd9526abSPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
12749ab747fSPaolo Bonzini     return s->regs[REG_FER] & (FER_UART1_EN << i);
12849ab747fSPaolo Bonzini }
12949ab747fSPaolo Bonzini 
13049ab747fSPaolo Bonzini 
13149ab747fSPaolo Bonzini /* Floppy controller */
13249ab747fSPaolo Bonzini 
is_fdc_enabled(ISASuperIODevice * sio,uint8_t index)1336f6695b1SPhilippe Mathieu-Daudé static bool is_fdc_enabled(ISASuperIODevice *sio, uint8_t index)
13449ab747fSPaolo Bonzini {
1356f6695b1SPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
1366f6695b1SPhilippe Mathieu-Daudé     assert(!index);
13749ab747fSPaolo Bonzini     return s->regs[REG_FER] & FER_FDC_EN;
13849ab747fSPaolo Bonzini }
13949ab747fSPaolo Bonzini 
get_fdc_iobase(ISASuperIODevice * sio,uint8_t index)1406f6695b1SPhilippe Mathieu-Daudé static uint16_t get_fdc_iobase(ISASuperIODevice *sio, uint8_t index)
14149ab747fSPaolo Bonzini {
1426f6695b1SPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
1436f6695b1SPhilippe Mathieu-Daudé     assert(!index);
14449ab747fSPaolo Bonzini     return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0;
14549ab747fSPaolo Bonzini }
14649ab747fSPaolo Bonzini 
get_fdc_irq(ISASuperIODevice * sio,uint8_t index)1476f6695b1SPhilippe Mathieu-Daudé static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index)
1486f6695b1SPhilippe Mathieu-Daudé {
1496f6695b1SPhilippe Mathieu-Daudé     assert(!index);
1506f6695b1SPhilippe Mathieu-Daudé     return 6;
1516f6695b1SPhilippe Mathieu-Daudé }
1526f6695b1SPhilippe Mathieu-Daudé 
15349ab747fSPaolo Bonzini 
15449ab747fSPaolo Bonzini /* IDE controller */
15549ab747fSPaolo Bonzini 
is_ide_enabled(ISASuperIODevice * sio,uint8_t index)156c16a4e1bSPhilippe Mathieu-Daudé static bool is_ide_enabled(ISASuperIODevice *sio, uint8_t index)
15749ab747fSPaolo Bonzini {
158c16a4e1bSPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
159c16a4e1bSPhilippe Mathieu-Daudé 
16049ab747fSPaolo Bonzini     return s->regs[REG_FER] & FER_IDE_EN;
16149ab747fSPaolo Bonzini }
16249ab747fSPaolo Bonzini 
get_ide_iobase(ISASuperIODevice * sio,uint8_t index)163c16a4e1bSPhilippe Mathieu-Daudé static uint16_t get_ide_iobase(ISASuperIODevice *sio, uint8_t index)
16449ab747fSPaolo Bonzini {
165c16a4e1bSPhilippe Mathieu-Daudé     PC87312State *s = PC87312(sio);
166c16a4e1bSPhilippe Mathieu-Daudé 
167c16a4e1bSPhilippe Mathieu-Daudé     if (index == 1) {
168c16a4e1bSPhilippe Mathieu-Daudé         return get_ide_iobase(sio, 0) + 0x206;
169c16a4e1bSPhilippe Mathieu-Daudé     }
17049ab747fSPaolo Bonzini     return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0;
17149ab747fSPaolo Bonzini }
17249ab747fSPaolo Bonzini 
get_ide_irq(ISASuperIODevice * sio,uint8_t index)173c16a4e1bSPhilippe Mathieu-Daudé static unsigned int get_ide_irq(ISASuperIODevice *sio, uint8_t index)
174c16a4e1bSPhilippe Mathieu-Daudé {
175c16a4e1bSPhilippe Mathieu-Daudé     assert(index == 0);
176c16a4e1bSPhilippe Mathieu-Daudé     return 14;
177c16a4e1bSPhilippe Mathieu-Daudé }
17849ab747fSPaolo Bonzini 
reconfigure_devices(PC87312State * s)17949ab747fSPaolo Bonzini static void reconfigure_devices(PC87312State *s)
18049ab747fSPaolo Bonzini {
18149ab747fSPaolo Bonzini     error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)",
18249ab747fSPaolo Bonzini                  s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]);
18349ab747fSPaolo Bonzini }
18449ab747fSPaolo Bonzini 
pc87312_soft_reset(PC87312State * s)18549ab747fSPaolo Bonzini static void pc87312_soft_reset(PC87312State *s)
18649ab747fSPaolo Bonzini {
18749ab747fSPaolo Bonzini     static const uint8_t fer_init[] = {
18849ab747fSPaolo Bonzini         0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b,
18949ab747fSPaolo Bonzini         0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f,
19049ab747fSPaolo Bonzini         0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07,
19149ab747fSPaolo Bonzini         0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00,
19249ab747fSPaolo Bonzini     };
19349ab747fSPaolo Bonzini     static const uint8_t far_init[] = {
19449ab747fSPaolo Bonzini         0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01,
19549ab747fSPaolo Bonzini         0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24,
19649ab747fSPaolo Bonzini         0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24,
19749ab747fSPaolo Bonzini         0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10,
19849ab747fSPaolo Bonzini     };
19949ab747fSPaolo Bonzini     static const uint8_t ptr_init[] = {
20049ab747fSPaolo Bonzini         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20149ab747fSPaolo Bonzini         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20249ab747fSPaolo Bonzini         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
20349ab747fSPaolo Bonzini         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
20449ab747fSPaolo Bonzini     };
20549ab747fSPaolo Bonzini 
20649ab747fSPaolo Bonzini     s->read_id_step = 0;
20749ab747fSPaolo Bonzini     s->selected_index = REG_FER;
20849ab747fSPaolo Bonzini 
20949ab747fSPaolo Bonzini     s->regs[REG_FER] = fer_init[s->config & 0x1f];
21049ab747fSPaolo Bonzini     s->regs[REG_FAR] = far_init[s->config & 0x1f];
21149ab747fSPaolo Bonzini     s->regs[REG_PTR] = ptr_init[s->config & 0x1f];
21249ab747fSPaolo Bonzini }
21349ab747fSPaolo Bonzini 
pc87312_hard_reset(PC87312State * s)21449ab747fSPaolo Bonzini static void pc87312_hard_reset(PC87312State *s)
21549ab747fSPaolo Bonzini {
21649ab747fSPaolo Bonzini     pc87312_soft_reset(s);
21749ab747fSPaolo Bonzini }
21849ab747fSPaolo Bonzini 
pc87312_io_write(void * opaque,hwaddr addr,uint64_t val,unsigned int size)21949ab747fSPaolo Bonzini static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val,
22049ab747fSPaolo Bonzini                              unsigned int size)
22149ab747fSPaolo Bonzini {
22249ab747fSPaolo Bonzini     PC87312State *s = opaque;
22349ab747fSPaolo Bonzini 
22449ab747fSPaolo Bonzini     trace_pc87312_io_write(addr, val);
22549ab747fSPaolo Bonzini 
22649ab747fSPaolo Bonzini     if ((addr & 1) == 0) {
22749ab747fSPaolo Bonzini         /* Index register */
22849ab747fSPaolo Bonzini         s->read_id_step = 2;
22949ab747fSPaolo Bonzini         s->selected_index = val;
23049ab747fSPaolo Bonzini     } else {
23149ab747fSPaolo Bonzini         /* Data register */
23249ab747fSPaolo Bonzini         if (s->selected_index < 3) {
23349ab747fSPaolo Bonzini             s->regs[s->selected_index] = val;
23449ab747fSPaolo Bonzini             reconfigure_devices(s);
23549ab747fSPaolo Bonzini         }
23649ab747fSPaolo Bonzini     }
23749ab747fSPaolo Bonzini }
23849ab747fSPaolo Bonzini 
pc87312_io_read(void * opaque,hwaddr addr,unsigned int size)23949ab747fSPaolo Bonzini static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size)
24049ab747fSPaolo Bonzini {
24149ab747fSPaolo Bonzini     PC87312State *s = opaque;
24249ab747fSPaolo Bonzini     uint32_t val;
24349ab747fSPaolo Bonzini 
24449ab747fSPaolo Bonzini     if ((addr & 1) == 0) {
24549ab747fSPaolo Bonzini         /* Index register */
24649ab747fSPaolo Bonzini         if (s->read_id_step++ == 0) {
24749ab747fSPaolo Bonzini             val = 0x88;
24849ab747fSPaolo Bonzini         } else if (s->read_id_step++ == 1) {
24949ab747fSPaolo Bonzini             val = 0;
25049ab747fSPaolo Bonzini         } else {
25149ab747fSPaolo Bonzini             val = s->selected_index;
25249ab747fSPaolo Bonzini         }
25349ab747fSPaolo Bonzini     } else {
25449ab747fSPaolo Bonzini         /* Data register */
25549ab747fSPaolo Bonzini         if (s->selected_index < 3) {
25649ab747fSPaolo Bonzini             val = s->regs[s->selected_index];
25749ab747fSPaolo Bonzini         } else {
25849ab747fSPaolo Bonzini             /* Invalid selected index */
25949ab747fSPaolo Bonzini             val = 0;
26049ab747fSPaolo Bonzini         }
26149ab747fSPaolo Bonzini     }
26249ab747fSPaolo Bonzini 
26349ab747fSPaolo Bonzini     trace_pc87312_io_read(addr, val);
26449ab747fSPaolo Bonzini     return val;
26549ab747fSPaolo Bonzini }
26649ab747fSPaolo Bonzini 
26749ab747fSPaolo Bonzini static const MemoryRegionOps pc87312_io_ops = {
26849ab747fSPaolo Bonzini     .read  = pc87312_io_read,
26949ab747fSPaolo Bonzini     .write = pc87312_io_write,
27049ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
27149ab747fSPaolo Bonzini     .valid = {
27249ab747fSPaolo Bonzini         .min_access_size = 1,
27349ab747fSPaolo Bonzini         .max_access_size = 1,
27449ab747fSPaolo Bonzini     },
27549ab747fSPaolo Bonzini };
27649ab747fSPaolo Bonzini 
pc87312_post_load(void * opaque,int version_id)27749ab747fSPaolo Bonzini static int pc87312_post_load(void *opaque, int version_id)
27849ab747fSPaolo Bonzini {
27949ab747fSPaolo Bonzini     PC87312State *s = opaque;
28049ab747fSPaolo Bonzini 
28149ab747fSPaolo Bonzini     reconfigure_devices(s);
28249ab747fSPaolo Bonzini     return 0;
28349ab747fSPaolo Bonzini }
28449ab747fSPaolo Bonzini 
pc87312_reset(DeviceState * d)28549ab747fSPaolo Bonzini static void pc87312_reset(DeviceState *d)
28649ab747fSPaolo Bonzini {
28749ab747fSPaolo Bonzini     PC87312State *s = PC87312(d);
28849ab747fSPaolo Bonzini 
28949ab747fSPaolo Bonzini     pc87312_soft_reset(s);
29049ab747fSPaolo Bonzini }
29149ab747fSPaolo Bonzini 
pc87312_realize(DeviceState * dev,Error ** errp)292db895a1eSAndreas Färber static void pc87312_realize(DeviceState *dev, Error **errp)
29349ab747fSPaolo Bonzini {
29449ab747fSPaolo Bonzini     PC87312State *s;
29549ab747fSPaolo Bonzini     ISADevice *isa;
29663f01a74SPhilippe Mathieu-Daudé     Error *local_err = NULL;
29749ab747fSPaolo Bonzini 
29849ab747fSPaolo Bonzini     s = PC87312(dev);
299db895a1eSAndreas Färber     isa = ISA_DEVICE(dev);
300db895a1eSAndreas Färber     isa_register_ioport(isa, &s->io, s->iobase);
30149ab747fSPaolo Bonzini     pc87312_hard_reset(s);
30249ab747fSPaolo Bonzini 
30363f01a74SPhilippe Mathieu-Daudé     ISA_SUPERIO_GET_CLASS(dev)->parent_realize(dev, &local_err);
30463f01a74SPhilippe Mathieu-Daudé     if (local_err) {
30563f01a74SPhilippe Mathieu-Daudé         error_propagate(errp, local_err);
30663f01a74SPhilippe Mathieu-Daudé         return;
30763f01a74SPhilippe Mathieu-Daudé     }
30849ab747fSPaolo Bonzini }
30949ab747fSPaolo Bonzini 
pc87312_initfn(Object * obj)31049ab747fSPaolo Bonzini static void pc87312_initfn(Object *obj)
31149ab747fSPaolo Bonzini {
31249ab747fSPaolo Bonzini     PC87312State *s = PC87312(obj);
31349ab747fSPaolo Bonzini 
3141437c94bSPaolo Bonzini     memory_region_init_io(&s->io, obj, &pc87312_io_ops, s, "pc87312", 2);
31549ab747fSPaolo Bonzini }
31649ab747fSPaolo Bonzini 
31749ab747fSPaolo Bonzini static const VMStateDescription vmstate_pc87312 = {
31849ab747fSPaolo Bonzini     .name = "pc87312",
31949ab747fSPaolo Bonzini     .version_id = 1,
32049ab747fSPaolo Bonzini     .minimum_version_id = 1,
32149ab747fSPaolo Bonzini     .post_load = pc87312_post_load,
322cbf19506SRichard Henderson     .fields = (const VMStateField[]) {
32349ab747fSPaolo Bonzini         VMSTATE_UINT8(read_id_step, PC87312State),
32449ab747fSPaolo Bonzini         VMSTATE_UINT8(selected_index, PC87312State),
32549ab747fSPaolo Bonzini         VMSTATE_UINT8_ARRAY(regs, PC87312State, 3),
32649ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
32749ab747fSPaolo Bonzini     }
32849ab747fSPaolo Bonzini };
32949ab747fSPaolo Bonzini 
33049ab747fSPaolo Bonzini static Property pc87312_properties[] = {
3314e00105aSPhilippe Mathieu-Daudé     DEFINE_PROP_UINT16("iobase", PC87312State, iobase, 0x398),
33249ab747fSPaolo Bonzini     DEFINE_PROP_UINT8("config", PC87312State, config, 1),
33349ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST()
33449ab747fSPaolo Bonzini };
33549ab747fSPaolo Bonzini 
pc87312_class_init(ObjectClass * klass,void * data)33649ab747fSPaolo Bonzini static void pc87312_class_init(ObjectClass *klass, void *data)
33749ab747fSPaolo Bonzini {
33849ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
33963f01a74SPhilippe Mathieu-Daudé     ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
34049ab747fSPaolo Bonzini 
341*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, pc87312_reset);
34249ab747fSPaolo Bonzini     dc->vmsd = &vmstate_pc87312;
343f669bd89SZhao Liu     device_class_set_parent_realize(dc, pc87312_realize,
344f669bd89SZhao Liu                                     &sc->parent_realize);
3454f67d30bSMarc-André Lureau     device_class_set_props(dc, pc87312_properties);
3464c3119a6SPhilippe Mathieu-Daudé 
3474c3119a6SPhilippe Mathieu-Daudé     sc->parallel = (ISASuperIOFuncs){
3484c3119a6SPhilippe Mathieu-Daudé         .count = 1,
3494c3119a6SPhilippe Mathieu-Daudé         .is_enabled = is_parallel_enabled,
3504c3119a6SPhilippe Mathieu-Daudé         .get_iobase = get_parallel_iobase,
3514c3119a6SPhilippe Mathieu-Daudé         .get_irq    = get_parallel_irq,
3524c3119a6SPhilippe Mathieu-Daudé     };
353cd9526abSPhilippe Mathieu-Daudé     sc->serial = (ISASuperIOFuncs){
354cd9526abSPhilippe Mathieu-Daudé         .count = 2,
355cd9526abSPhilippe Mathieu-Daudé         .is_enabled = is_uart_enabled,
356cd9526abSPhilippe Mathieu-Daudé         .get_iobase = get_uart_iobase,
357cd9526abSPhilippe Mathieu-Daudé         .get_irq    = get_uart_irq,
358cd9526abSPhilippe Mathieu-Daudé     };
3596f6695b1SPhilippe Mathieu-Daudé     sc->floppy = (ISASuperIOFuncs){
3606f6695b1SPhilippe Mathieu-Daudé         .count = 1,
3616f6695b1SPhilippe Mathieu-Daudé         .is_enabled = is_fdc_enabled,
3626f6695b1SPhilippe Mathieu-Daudé         .get_iobase = get_fdc_iobase,
3636f6695b1SPhilippe Mathieu-Daudé         .get_irq    = get_fdc_irq,
3646f6695b1SPhilippe Mathieu-Daudé     };
365c16a4e1bSPhilippe Mathieu-Daudé     sc->ide = (ISASuperIOFuncs){
366c16a4e1bSPhilippe Mathieu-Daudé         .count = 1,
367c16a4e1bSPhilippe Mathieu-Daudé         .is_enabled = is_ide_enabled,
368c16a4e1bSPhilippe Mathieu-Daudé         .get_iobase = get_ide_iobase,
369c16a4e1bSPhilippe Mathieu-Daudé         .get_irq    = get_ide_irq,
370c16a4e1bSPhilippe Mathieu-Daudé     };
37149ab747fSPaolo Bonzini }
37249ab747fSPaolo Bonzini 
37349ab747fSPaolo Bonzini static const TypeInfo pc87312_type_info = {
374b3270669SEduardo Habkost     .name          = TYPE_PC87312,
37563f01a74SPhilippe Mathieu-Daudé     .parent        = TYPE_ISA_SUPERIO,
37649ab747fSPaolo Bonzini     .instance_size = sizeof(PC87312State),
37749ab747fSPaolo Bonzini     .instance_init = pc87312_initfn,
37849ab747fSPaolo Bonzini     .class_init    = pc87312_class_init,
3796f6695b1SPhilippe Mathieu-Daudé     /* FIXME use a qdev drive property instead of drive_get() */
38049ab747fSPaolo Bonzini };
38149ab747fSPaolo Bonzini 
pc87312_register_types(void)38249ab747fSPaolo Bonzini static void pc87312_register_types(void)
38349ab747fSPaolo Bonzini {
38449ab747fSPaolo Bonzini     type_register_static(&pc87312_type_info);
38549ab747fSPaolo Bonzini }
38649ab747fSPaolo Bonzini 
38749ab747fSPaolo Bonzini type_init(pc87312_register_types)
388