xref: /openbmc/qemu/hw/char/parallel.c (revision ee3d1f1b)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU Parallel PORT emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2003-2005 Fabrice Bellard
549ab747fSPaolo Bonzini  * Copyright (c) 2007 Marko Kohtala
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  */
250b8fa32fSMarkus Armbruster 
26b6a0aa05SPeter Maydell #include "qemu/osdep.h"
27da34e65cSMarkus Armbruster #include "qapi/error.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
297566c6efSMarc-André Lureau #include "chardev/char-parallel.h"
30ef26fc47SIgor Mammedov #include "hw/acpi/acpi_aml_interface.h"
31a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
32ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
33d6454270SMarkus Armbruster #include "migration/vmstate.h"
349cc44d9bSBernhard Beschow #include "hw/char/parallel-isa.h"
35bb3d5ea8SPhilippe Mathieu-Daudé #include "hw/char/parallel.h"
3671e8a915SMarkus Armbruster #include "sysemu/reset.h"
3749ab747fSPaolo Bonzini #include "sysemu/sysemu.h"
38cb2d721cSPhilippe Mathieu-Daudé #include "trace.h"
39db1015e9SEduardo Habkost #include "qom/object.h"
4049ab747fSPaolo Bonzini 
4149ab747fSPaolo Bonzini //#define DEBUG_PARALLEL
4249ab747fSPaolo Bonzini 
4349ab747fSPaolo Bonzini #ifdef DEBUG_PARALLEL
4449ab747fSPaolo Bonzini #define pdebug(fmt, ...) printf("pp: " fmt, ## __VA_ARGS__)
4549ab747fSPaolo Bonzini #else
4649ab747fSPaolo Bonzini #define pdebug(fmt, ...) ((void)0)
4749ab747fSPaolo Bonzini #endif
4849ab747fSPaolo Bonzini 
4949ab747fSPaolo Bonzini #define PARA_REG_DATA 0
5049ab747fSPaolo Bonzini #define PARA_REG_STS 1
5149ab747fSPaolo Bonzini #define PARA_REG_CTR 2
5249ab747fSPaolo Bonzini #define PARA_REG_EPP_ADDR 3
5349ab747fSPaolo Bonzini #define PARA_REG_EPP_DATA 4
5449ab747fSPaolo Bonzini 
5549ab747fSPaolo Bonzini /*
5649ab747fSPaolo Bonzini  * These are the definitions for the Printer Status Register
5749ab747fSPaolo Bonzini  */
5849ab747fSPaolo Bonzini #define PARA_STS_BUSY   0x80    /* Busy complement */
5949ab747fSPaolo Bonzini #define PARA_STS_ACK    0x40    /* Acknowledge */
6049ab747fSPaolo Bonzini #define PARA_STS_PAPER  0x20    /* Out of paper */
6149ab747fSPaolo Bonzini #define PARA_STS_ONLINE 0x10    /* Online */
6249ab747fSPaolo Bonzini #define PARA_STS_ERROR  0x08    /* Error complement */
6349ab747fSPaolo Bonzini #define PARA_STS_TMOUT  0x01    /* EPP timeout */
6449ab747fSPaolo Bonzini 
6549ab747fSPaolo Bonzini /*
6649ab747fSPaolo Bonzini  * These are the definitions for the Printer Control Register
6749ab747fSPaolo Bonzini  */
6849ab747fSPaolo Bonzini #define PARA_CTR_DIR    0x20    /* Direction (1=read, 0=write) */
6949ab747fSPaolo Bonzini #define PARA_CTR_INTEN  0x10    /* IRQ Enable */
7049ab747fSPaolo Bonzini #define PARA_CTR_SELECT 0x08    /* Select In complement */
7149ab747fSPaolo Bonzini #define PARA_CTR_INIT   0x04    /* Initialize Printer complement */
7249ab747fSPaolo Bonzini #define PARA_CTR_AUTOLF 0x02    /* Auto linefeed complement */
7349ab747fSPaolo Bonzini #define PARA_CTR_STROBE 0x01    /* Strobe complement */
7449ab747fSPaolo Bonzini 
7549ab747fSPaolo Bonzini #define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
7649ab747fSPaolo Bonzini 
parallel_update_irq(ParallelState * s)7749ab747fSPaolo Bonzini static void parallel_update_irq(ParallelState *s)
7849ab747fSPaolo Bonzini {
7949ab747fSPaolo Bonzini     if (s->irq_pending)
8049ab747fSPaolo Bonzini         qemu_irq_raise(s->irq);
8149ab747fSPaolo Bonzini     else
8249ab747fSPaolo Bonzini         qemu_irq_lower(s->irq);
8349ab747fSPaolo Bonzini }
8449ab747fSPaolo Bonzini 
8549ab747fSPaolo Bonzini static void
parallel_ioport_write_sw(void * opaque,uint32_t addr,uint32_t val)8649ab747fSPaolo Bonzini parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
8749ab747fSPaolo Bonzini {
8849ab747fSPaolo Bonzini     ParallelState *s = opaque;
8949ab747fSPaolo Bonzini 
9049ab747fSPaolo Bonzini     addr &= 7;
91cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_write("SW", addr, val);
9249ab747fSPaolo Bonzini     switch(addr) {
9349ab747fSPaolo Bonzini     case PARA_REG_DATA:
9449ab747fSPaolo Bonzini         s->dataw = val;
9549ab747fSPaolo Bonzini         parallel_update_irq(s);
9649ab747fSPaolo Bonzini         break;
9749ab747fSPaolo Bonzini     case PARA_REG_CTR:
9849ab747fSPaolo Bonzini         val |= 0xc0;
9949ab747fSPaolo Bonzini         if ((val & PARA_CTR_INIT) == 0 ) {
10049ab747fSPaolo Bonzini             s->status = PARA_STS_BUSY;
10149ab747fSPaolo Bonzini             s->status |= PARA_STS_ACK;
10249ab747fSPaolo Bonzini             s->status |= PARA_STS_ONLINE;
10349ab747fSPaolo Bonzini             s->status |= PARA_STS_ERROR;
10449ab747fSPaolo Bonzini         }
10549ab747fSPaolo Bonzini         else if (val & PARA_CTR_SELECT) {
10649ab747fSPaolo Bonzini             if (val & PARA_CTR_STROBE) {
10749ab747fSPaolo Bonzini                 s->status &= ~PARA_STS_BUSY;
10849ab747fSPaolo Bonzini                 if ((s->control & PARA_CTR_STROBE) == 0)
1096ab3fc32SDaniel P. Berrange                     /* XXX this blocks entire thread. Rewrite to use
1106ab3fc32SDaniel P. Berrange                      * qemu_chr_fe_write and background I/O callbacks */
1115345fdb4SMarc-André Lureau                     qemu_chr_fe_write_all(&s->chr, &s->dataw, 1);
11249ab747fSPaolo Bonzini             } else {
11349ab747fSPaolo Bonzini                 if (s->control & PARA_CTR_INTEN) {
11449ab747fSPaolo Bonzini                     s->irq_pending = 1;
11549ab747fSPaolo Bonzini                 }
11649ab747fSPaolo Bonzini             }
11749ab747fSPaolo Bonzini         }
11849ab747fSPaolo Bonzini         parallel_update_irq(s);
11949ab747fSPaolo Bonzini         s->control = val;
12049ab747fSPaolo Bonzini         break;
12149ab747fSPaolo Bonzini     }
12249ab747fSPaolo Bonzini }
12349ab747fSPaolo Bonzini 
parallel_ioport_write_hw(void * opaque,uint32_t addr,uint32_t val)12449ab747fSPaolo Bonzini static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
12549ab747fSPaolo Bonzini {
12649ab747fSPaolo Bonzini     ParallelState *s = opaque;
12749ab747fSPaolo Bonzini     uint8_t parm = val;
12849ab747fSPaolo Bonzini     int dir;
12949ab747fSPaolo Bonzini 
13049ab747fSPaolo Bonzini     /* Sometimes programs do several writes for timing purposes on old
13149ab747fSPaolo Bonzini        HW. Take care not to waste time on writes that do nothing. */
13249ab747fSPaolo Bonzini 
13349ab747fSPaolo Bonzini     s->last_read_offset = ~0U;
13449ab747fSPaolo Bonzini 
13549ab747fSPaolo Bonzini     addr &= 7;
136cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_write("HW", addr, val);
13749ab747fSPaolo Bonzini     switch(addr) {
13849ab747fSPaolo Bonzini     case PARA_REG_DATA:
13949ab747fSPaolo Bonzini         if (s->dataw == val)
14049ab747fSPaolo Bonzini             return;
14149ab747fSPaolo Bonzini         pdebug("wd%02x\n", val);
1425345fdb4SMarc-André Lureau         qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
14349ab747fSPaolo Bonzini         s->dataw = val;
14449ab747fSPaolo Bonzini         break;
14549ab747fSPaolo Bonzini     case PARA_REG_STS:
14649ab747fSPaolo Bonzini         pdebug("ws%02x\n", val);
14749ab747fSPaolo Bonzini         if (val & PARA_STS_TMOUT)
14849ab747fSPaolo Bonzini             s->epp_timeout = 0;
14949ab747fSPaolo Bonzini         break;
15049ab747fSPaolo Bonzini     case PARA_REG_CTR:
15149ab747fSPaolo Bonzini         val |= 0xc0;
15249ab747fSPaolo Bonzini         if (s->control == val)
15349ab747fSPaolo Bonzini             return;
15449ab747fSPaolo Bonzini         pdebug("wc%02x\n", val);
15549ab747fSPaolo Bonzini 
15649ab747fSPaolo Bonzini         if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) {
15749ab747fSPaolo Bonzini             if (val & PARA_CTR_DIR) {
15849ab747fSPaolo Bonzini                 dir = 1;
15949ab747fSPaolo Bonzini             } else {
16049ab747fSPaolo Bonzini                 dir = 0;
16149ab747fSPaolo Bonzini             }
1625345fdb4SMarc-André Lureau             qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_DATA_DIR, &dir);
16349ab747fSPaolo Bonzini             parm &= ~PARA_CTR_DIR;
16449ab747fSPaolo Bonzini         }
16549ab747fSPaolo Bonzini 
1665345fdb4SMarc-André Lureau         qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
16749ab747fSPaolo Bonzini         s->control = val;
16849ab747fSPaolo Bonzini         break;
16949ab747fSPaolo Bonzini     case PARA_REG_EPP_ADDR:
17049ab747fSPaolo Bonzini         if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
17149ab747fSPaolo Bonzini             /* Controls not correct for EPP address cycle, so do nothing */
17249ab747fSPaolo Bonzini             pdebug("wa%02x s\n", val);
17349ab747fSPaolo Bonzini         else {
17449ab747fSPaolo Bonzini             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
1755345fdb4SMarc-André Lureau             if (qemu_chr_fe_ioctl(&s->chr,
176becdfa00SMarc-André Lureau                                   CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
17749ab747fSPaolo Bonzini                 s->epp_timeout = 1;
17849ab747fSPaolo Bonzini                 pdebug("wa%02x t\n", val);
17949ab747fSPaolo Bonzini             }
18049ab747fSPaolo Bonzini             else
18149ab747fSPaolo Bonzini                 pdebug("wa%02x\n", val);
18249ab747fSPaolo Bonzini         }
18349ab747fSPaolo Bonzini         break;
18449ab747fSPaolo Bonzini     case PARA_REG_EPP_DATA:
18549ab747fSPaolo Bonzini         if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
18649ab747fSPaolo Bonzini             /* Controls not correct for EPP data cycle, so do nothing */
18749ab747fSPaolo Bonzini             pdebug("we%02x s\n", val);
18849ab747fSPaolo Bonzini         else {
18949ab747fSPaolo Bonzini             struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
1905345fdb4SMarc-André Lureau             if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
19149ab747fSPaolo Bonzini                 s->epp_timeout = 1;
19249ab747fSPaolo Bonzini                 pdebug("we%02x t\n", val);
19349ab747fSPaolo Bonzini             }
19449ab747fSPaolo Bonzini             else
19549ab747fSPaolo Bonzini                 pdebug("we%02x\n", val);
19649ab747fSPaolo Bonzini         }
19749ab747fSPaolo Bonzini         break;
19849ab747fSPaolo Bonzini     }
19949ab747fSPaolo Bonzini }
20049ab747fSPaolo Bonzini 
20149ab747fSPaolo Bonzini static void
parallel_ioport_eppdata_write_hw2(void * opaque,uint32_t addr,uint32_t val)20249ab747fSPaolo Bonzini parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
20349ab747fSPaolo Bonzini {
20449ab747fSPaolo Bonzini     ParallelState *s = opaque;
20549ab747fSPaolo Bonzini     uint16_t eppdata = cpu_to_le16(val);
20649ab747fSPaolo Bonzini     int err;
20749ab747fSPaolo Bonzini     struct ParallelIOArg ioarg = {
20849ab747fSPaolo Bonzini         .buffer = &eppdata, .count = sizeof(eppdata)
20949ab747fSPaolo Bonzini     };
210cb2d721cSPhilippe Mathieu-Daudé 
211cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_write("EPP", addr, val);
21249ab747fSPaolo Bonzini     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
21349ab747fSPaolo Bonzini         /* Controls not correct for EPP data cycle, so do nothing */
21449ab747fSPaolo Bonzini         pdebug("we%04x s\n", val);
21549ab747fSPaolo Bonzini         return;
21649ab747fSPaolo Bonzini     }
2175345fdb4SMarc-André Lureau     err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
21849ab747fSPaolo Bonzini     if (err) {
21949ab747fSPaolo Bonzini         s->epp_timeout = 1;
22049ab747fSPaolo Bonzini         pdebug("we%04x t\n", val);
22149ab747fSPaolo Bonzini     }
22249ab747fSPaolo Bonzini     else
22349ab747fSPaolo Bonzini         pdebug("we%04x\n", val);
22449ab747fSPaolo Bonzini }
22549ab747fSPaolo Bonzini 
22649ab747fSPaolo Bonzini static void
parallel_ioport_eppdata_write_hw4(void * opaque,uint32_t addr,uint32_t val)22749ab747fSPaolo Bonzini parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
22849ab747fSPaolo Bonzini {
22949ab747fSPaolo Bonzini     ParallelState *s = opaque;
23049ab747fSPaolo Bonzini     uint32_t eppdata = cpu_to_le32(val);
23149ab747fSPaolo Bonzini     int err;
23249ab747fSPaolo Bonzini     struct ParallelIOArg ioarg = {
23349ab747fSPaolo Bonzini         .buffer = &eppdata, .count = sizeof(eppdata)
23449ab747fSPaolo Bonzini     };
235cb2d721cSPhilippe Mathieu-Daudé 
236cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_write("EPP", addr, val);
23749ab747fSPaolo Bonzini     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
23849ab747fSPaolo Bonzini         /* Controls not correct for EPP data cycle, so do nothing */
23949ab747fSPaolo Bonzini         pdebug("we%08x s\n", val);
24049ab747fSPaolo Bonzini         return;
24149ab747fSPaolo Bonzini     }
2425345fdb4SMarc-André Lureau     err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
24349ab747fSPaolo Bonzini     if (err) {
24449ab747fSPaolo Bonzini         s->epp_timeout = 1;
24549ab747fSPaolo Bonzini         pdebug("we%08x t\n", val);
24649ab747fSPaolo Bonzini     }
24749ab747fSPaolo Bonzini     else
24849ab747fSPaolo Bonzini         pdebug("we%08x\n", val);
24949ab747fSPaolo Bonzini }
25049ab747fSPaolo Bonzini 
parallel_ioport_read_sw(void * opaque,uint32_t addr)25149ab747fSPaolo Bonzini static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
25249ab747fSPaolo Bonzini {
25349ab747fSPaolo Bonzini     ParallelState *s = opaque;
25449ab747fSPaolo Bonzini     uint32_t ret = 0xff;
25549ab747fSPaolo Bonzini 
25649ab747fSPaolo Bonzini     addr &= 7;
25749ab747fSPaolo Bonzini     switch(addr) {
25849ab747fSPaolo Bonzini     case PARA_REG_DATA:
25949ab747fSPaolo Bonzini         if (s->control & PARA_CTR_DIR)
26049ab747fSPaolo Bonzini             ret = s->datar;
26149ab747fSPaolo Bonzini         else
26249ab747fSPaolo Bonzini             ret = s->dataw;
26349ab747fSPaolo Bonzini         break;
26449ab747fSPaolo Bonzini     case PARA_REG_STS:
26549ab747fSPaolo Bonzini         ret = s->status;
26649ab747fSPaolo Bonzini         s->irq_pending = 0;
26749ab747fSPaolo Bonzini         if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
26849ab747fSPaolo Bonzini             /* XXX Fixme: wait 5 microseconds */
26949ab747fSPaolo Bonzini             if (s->status & PARA_STS_ACK)
27049ab747fSPaolo Bonzini                 s->status &= ~PARA_STS_ACK;
27149ab747fSPaolo Bonzini             else {
27249ab747fSPaolo Bonzini                 /* XXX Fixme: wait 5 microseconds */
27349ab747fSPaolo Bonzini                 s->status |= PARA_STS_ACK;
27449ab747fSPaolo Bonzini                 s->status |= PARA_STS_BUSY;
27549ab747fSPaolo Bonzini             }
27649ab747fSPaolo Bonzini         }
27749ab747fSPaolo Bonzini         parallel_update_irq(s);
27849ab747fSPaolo Bonzini         break;
27949ab747fSPaolo Bonzini     case PARA_REG_CTR:
28049ab747fSPaolo Bonzini         ret = s->control;
28149ab747fSPaolo Bonzini         break;
28249ab747fSPaolo Bonzini     }
283cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_read("SW", addr, ret);
28449ab747fSPaolo Bonzini     return ret;
28549ab747fSPaolo Bonzini }
28649ab747fSPaolo Bonzini 
parallel_ioport_read_hw(void * opaque,uint32_t addr)28749ab747fSPaolo Bonzini static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
28849ab747fSPaolo Bonzini {
28949ab747fSPaolo Bonzini     ParallelState *s = opaque;
29049ab747fSPaolo Bonzini     uint8_t ret = 0xff;
29149ab747fSPaolo Bonzini     addr &= 7;
29249ab747fSPaolo Bonzini     switch(addr) {
29349ab747fSPaolo Bonzini     case PARA_REG_DATA:
2945345fdb4SMarc-André Lureau         qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
29549ab747fSPaolo Bonzini         if (s->last_read_offset != addr || s->datar != ret)
29649ab747fSPaolo Bonzini             pdebug("rd%02x\n", ret);
29749ab747fSPaolo Bonzini         s->datar = ret;
29849ab747fSPaolo Bonzini         break;
29949ab747fSPaolo Bonzini     case PARA_REG_STS:
3005345fdb4SMarc-André Lureau         qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
30149ab747fSPaolo Bonzini         ret &= ~PARA_STS_TMOUT;
30249ab747fSPaolo Bonzini         if (s->epp_timeout)
30349ab747fSPaolo Bonzini             ret |= PARA_STS_TMOUT;
30449ab747fSPaolo Bonzini         if (s->last_read_offset != addr || s->status != ret)
30549ab747fSPaolo Bonzini             pdebug("rs%02x\n", ret);
30649ab747fSPaolo Bonzini         s->status = ret;
30749ab747fSPaolo Bonzini         break;
30849ab747fSPaolo Bonzini     case PARA_REG_CTR:
30949ab747fSPaolo Bonzini         /* s->control has some bits fixed to 1. It is zero only when
31049ab747fSPaolo Bonzini            it has not been yet written to.  */
31149ab747fSPaolo Bonzini         if (s->control == 0) {
3125345fdb4SMarc-André Lureau             qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
31349ab747fSPaolo Bonzini             if (s->last_read_offset != addr)
31449ab747fSPaolo Bonzini                 pdebug("rc%02x\n", ret);
31549ab747fSPaolo Bonzini             s->control = ret;
31649ab747fSPaolo Bonzini         }
31749ab747fSPaolo Bonzini         else {
31849ab747fSPaolo Bonzini             ret = s->control;
31949ab747fSPaolo Bonzini             if (s->last_read_offset != addr)
32049ab747fSPaolo Bonzini                 pdebug("rc%02x\n", ret);
32149ab747fSPaolo Bonzini         }
32249ab747fSPaolo Bonzini         break;
32349ab747fSPaolo Bonzini     case PARA_REG_EPP_ADDR:
324becdfa00SMarc-André Lureau         if ((s->control & (PARA_CTR_DIR | PARA_CTR_SIGNAL)) !=
325becdfa00SMarc-André Lureau             (PARA_CTR_DIR | PARA_CTR_INIT))
32649ab747fSPaolo Bonzini             /* Controls not correct for EPP addr cycle, so do nothing */
32749ab747fSPaolo Bonzini             pdebug("ra%02x s\n", ret);
32849ab747fSPaolo Bonzini         else {
32949ab747fSPaolo Bonzini             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
3305345fdb4SMarc-André Lureau             if (qemu_chr_fe_ioctl(&s->chr,
331becdfa00SMarc-André Lureau                                   CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
33249ab747fSPaolo Bonzini                 s->epp_timeout = 1;
33349ab747fSPaolo Bonzini                 pdebug("ra%02x t\n", ret);
33449ab747fSPaolo Bonzini             }
33549ab747fSPaolo Bonzini             else
33649ab747fSPaolo Bonzini                 pdebug("ra%02x\n", ret);
33749ab747fSPaolo Bonzini         }
33849ab747fSPaolo Bonzini         break;
33949ab747fSPaolo Bonzini     case PARA_REG_EPP_DATA:
340becdfa00SMarc-André Lureau         if ((s->control & (PARA_CTR_DIR | PARA_CTR_SIGNAL)) !=
341becdfa00SMarc-André Lureau             (PARA_CTR_DIR | PARA_CTR_INIT))
34249ab747fSPaolo Bonzini             /* Controls not correct for EPP data cycle, so do nothing */
34349ab747fSPaolo Bonzini             pdebug("re%02x s\n", ret);
34449ab747fSPaolo Bonzini         else {
34549ab747fSPaolo Bonzini             struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
3465345fdb4SMarc-André Lureau             if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
34749ab747fSPaolo Bonzini                 s->epp_timeout = 1;
34849ab747fSPaolo Bonzini                 pdebug("re%02x t\n", ret);
34949ab747fSPaolo Bonzini             }
35049ab747fSPaolo Bonzini             else
35149ab747fSPaolo Bonzini                 pdebug("re%02x\n", ret);
35249ab747fSPaolo Bonzini         }
35349ab747fSPaolo Bonzini         break;
35449ab747fSPaolo Bonzini     }
355cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_read("HW", addr, ret);
35649ab747fSPaolo Bonzini     s->last_read_offset = addr;
35749ab747fSPaolo Bonzini     return ret;
35849ab747fSPaolo Bonzini }
35949ab747fSPaolo Bonzini 
36049ab747fSPaolo Bonzini static uint32_t
parallel_ioport_eppdata_read_hw2(void * opaque,uint32_t addr)36149ab747fSPaolo Bonzini parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
36249ab747fSPaolo Bonzini {
36349ab747fSPaolo Bonzini     ParallelState *s = opaque;
36449ab747fSPaolo Bonzini     uint32_t ret;
36549ab747fSPaolo Bonzini     uint16_t eppdata = ~0;
36649ab747fSPaolo Bonzini     int err;
36749ab747fSPaolo Bonzini     struct ParallelIOArg ioarg = {
36849ab747fSPaolo Bonzini         .buffer = &eppdata, .count = sizeof(eppdata)
36949ab747fSPaolo Bonzini     };
37049ab747fSPaolo Bonzini     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
37149ab747fSPaolo Bonzini         /* Controls not correct for EPP data cycle, so do nothing */
37249ab747fSPaolo Bonzini         pdebug("re%04x s\n", eppdata);
37349ab747fSPaolo Bonzini         return eppdata;
37449ab747fSPaolo Bonzini     }
3755345fdb4SMarc-André Lureau     err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
37649ab747fSPaolo Bonzini     ret = le16_to_cpu(eppdata);
37749ab747fSPaolo Bonzini 
37849ab747fSPaolo Bonzini     if (err) {
37949ab747fSPaolo Bonzini         s->epp_timeout = 1;
38049ab747fSPaolo Bonzini         pdebug("re%04x t\n", ret);
38149ab747fSPaolo Bonzini     }
38249ab747fSPaolo Bonzini     else
38349ab747fSPaolo Bonzini         pdebug("re%04x\n", ret);
384cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_read("EPP", addr, ret);
38549ab747fSPaolo Bonzini     return ret;
38649ab747fSPaolo Bonzini }
38749ab747fSPaolo Bonzini 
38849ab747fSPaolo Bonzini static uint32_t
parallel_ioport_eppdata_read_hw4(void * opaque,uint32_t addr)38949ab747fSPaolo Bonzini parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
39049ab747fSPaolo Bonzini {
39149ab747fSPaolo Bonzini     ParallelState *s = opaque;
39249ab747fSPaolo Bonzini     uint32_t ret;
39349ab747fSPaolo Bonzini     uint32_t eppdata = ~0U;
39449ab747fSPaolo Bonzini     int err;
39549ab747fSPaolo Bonzini     struct ParallelIOArg ioarg = {
39649ab747fSPaolo Bonzini         .buffer = &eppdata, .count = sizeof(eppdata)
39749ab747fSPaolo Bonzini     };
39849ab747fSPaolo Bonzini     if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
39949ab747fSPaolo Bonzini         /* Controls not correct for EPP data cycle, so do nothing */
40049ab747fSPaolo Bonzini         pdebug("re%08x s\n", eppdata);
40149ab747fSPaolo Bonzini         return eppdata;
40249ab747fSPaolo Bonzini     }
4035345fdb4SMarc-André Lureau     err = qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
40449ab747fSPaolo Bonzini     ret = le32_to_cpu(eppdata);
40549ab747fSPaolo Bonzini 
40649ab747fSPaolo Bonzini     if (err) {
40749ab747fSPaolo Bonzini         s->epp_timeout = 1;
40849ab747fSPaolo Bonzini         pdebug("re%08x t\n", ret);
40949ab747fSPaolo Bonzini     }
41049ab747fSPaolo Bonzini     else
41149ab747fSPaolo Bonzini         pdebug("re%08x\n", ret);
412cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_read("EPP", addr, ret);
41349ab747fSPaolo Bonzini     return ret;
41449ab747fSPaolo Bonzini }
41549ab747fSPaolo Bonzini 
parallel_ioport_ecp_write(void * opaque,uint32_t addr,uint32_t val)41649ab747fSPaolo Bonzini static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
41749ab747fSPaolo Bonzini {
418cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_write("ECP", addr & 7, val);
41949ab747fSPaolo Bonzini     pdebug("wecp%d=%02x\n", addr & 7, val);
42049ab747fSPaolo Bonzini }
42149ab747fSPaolo Bonzini 
parallel_ioport_ecp_read(void * opaque,uint32_t addr)42249ab747fSPaolo Bonzini static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
42349ab747fSPaolo Bonzini {
42449ab747fSPaolo Bonzini     uint8_t ret = 0xff;
42549ab747fSPaolo Bonzini 
426cb2d721cSPhilippe Mathieu-Daudé     trace_parallel_ioport_read("ECP", addr & 7, ret);
42749ab747fSPaolo Bonzini     pdebug("recp%d:%02x\n", addr & 7, ret);
42849ab747fSPaolo Bonzini     return ret;
42949ab747fSPaolo Bonzini }
43049ab747fSPaolo Bonzini 
parallel_reset(void * opaque)43149ab747fSPaolo Bonzini static void parallel_reset(void *opaque)
43249ab747fSPaolo Bonzini {
43349ab747fSPaolo Bonzini     ParallelState *s = opaque;
43449ab747fSPaolo Bonzini 
43549ab747fSPaolo Bonzini     s->datar = ~0;
43649ab747fSPaolo Bonzini     s->dataw = ~0;
43749ab747fSPaolo Bonzini     s->status = PARA_STS_BUSY;
43849ab747fSPaolo Bonzini     s->status |= PARA_STS_ACK;
43949ab747fSPaolo Bonzini     s->status |= PARA_STS_ONLINE;
44049ab747fSPaolo Bonzini     s->status |= PARA_STS_ERROR;
44149ab747fSPaolo Bonzini     s->status |= PARA_STS_TMOUT;
44249ab747fSPaolo Bonzini     s->control = PARA_CTR_SELECT;
44349ab747fSPaolo Bonzini     s->control |= PARA_CTR_INIT;
44449ab747fSPaolo Bonzini     s->control |= 0xc0;
44549ab747fSPaolo Bonzini     s->irq_pending = 0;
44649ab747fSPaolo Bonzini     s->hw_driver = 0;
44749ab747fSPaolo Bonzini     s->epp_timeout = 0;
44849ab747fSPaolo Bonzini     s->last_read_offset = ~0U;
44949ab747fSPaolo Bonzini }
45049ab747fSPaolo Bonzini 
45149ab747fSPaolo Bonzini static const int isa_parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
45249ab747fSPaolo Bonzini 
45349ab747fSPaolo Bonzini static const MemoryRegionPortio isa_parallel_portio_hw_list[] = {
45449ab747fSPaolo Bonzini     { 0, 8, 1,
45549ab747fSPaolo Bonzini       .read = parallel_ioport_read_hw,
45649ab747fSPaolo Bonzini       .write = parallel_ioport_write_hw },
45749ab747fSPaolo Bonzini     { 4, 1, 2,
45849ab747fSPaolo Bonzini       .read = parallel_ioport_eppdata_read_hw2,
45949ab747fSPaolo Bonzini       .write = parallel_ioport_eppdata_write_hw2 },
46049ab747fSPaolo Bonzini     { 4, 1, 4,
46149ab747fSPaolo Bonzini       .read = parallel_ioport_eppdata_read_hw4,
46249ab747fSPaolo Bonzini       .write = parallel_ioport_eppdata_write_hw4 },
46349ab747fSPaolo Bonzini     { 0x400, 8, 1,
46449ab747fSPaolo Bonzini       .read = parallel_ioport_ecp_read,
46549ab747fSPaolo Bonzini       .write = parallel_ioport_ecp_write },
46649ab747fSPaolo Bonzini     PORTIO_END_OF_LIST(),
46749ab747fSPaolo Bonzini };
46849ab747fSPaolo Bonzini 
46949ab747fSPaolo Bonzini static const MemoryRegionPortio isa_parallel_portio_sw_list[] = {
47049ab747fSPaolo Bonzini     { 0, 8, 1,
47149ab747fSPaolo Bonzini       .read = parallel_ioport_read_sw,
47249ab747fSPaolo Bonzini       .write = parallel_ioport_write_sw },
47349ab747fSPaolo Bonzini     PORTIO_END_OF_LIST(),
47449ab747fSPaolo Bonzini };
47549ab747fSPaolo Bonzini 
476461a2753SPavel Dovgalyuk 
477461a2753SPavel Dovgalyuk static const VMStateDescription vmstate_parallel_isa = {
478461a2753SPavel Dovgalyuk     .name = "parallel_isa",
479461a2753SPavel Dovgalyuk     .version_id = 1,
480461a2753SPavel Dovgalyuk     .minimum_version_id = 1,
4812f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
482461a2753SPavel Dovgalyuk         VMSTATE_UINT8(state.dataw, ISAParallelState),
483461a2753SPavel Dovgalyuk         VMSTATE_UINT8(state.datar, ISAParallelState),
484461a2753SPavel Dovgalyuk         VMSTATE_UINT8(state.status, ISAParallelState),
485461a2753SPavel Dovgalyuk         VMSTATE_UINT8(state.control, ISAParallelState),
486461a2753SPavel Dovgalyuk         VMSTATE_INT32(state.irq_pending, ISAParallelState),
487461a2753SPavel Dovgalyuk         VMSTATE_INT32(state.epp_timeout, ISAParallelState),
488461a2753SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
489461a2753SPavel Dovgalyuk     }
490461a2753SPavel Dovgalyuk };
491461a2753SPavel Dovgalyuk 
parallel_can_receive(void * opaque)49298fab4c1SPeng Hao static int parallel_can_receive(void *opaque)
49398fab4c1SPeng Hao {
49498fab4c1SPeng Hao      return 1;
49598fab4c1SPeng Hao }
496461a2753SPavel Dovgalyuk 
parallel_isa_realizefn(DeviceState * dev,Error ** errp)497db895a1eSAndreas Färber static void parallel_isa_realizefn(DeviceState *dev, Error **errp)
49849ab747fSPaolo Bonzini {
49949ab747fSPaolo Bonzini     static int index;
500db895a1eSAndreas Färber     ISADevice *isadev = ISA_DEVICE(dev);
501b0dc5ee6SAndreas Färber     ISAParallelState *isa = ISA_PARALLEL(dev);
50249ab747fSPaolo Bonzini     ParallelState *s = &isa->state;
50349ab747fSPaolo Bonzini     int base;
50449ab747fSPaolo Bonzini     uint8_t dummy;
50549ab747fSPaolo Bonzini 
50630650701SAnton Nefedov     if (!qemu_chr_fe_backend_connected(&s->chr)) {
507db895a1eSAndreas Färber         error_setg(errp, "Can't create parallel device, empty char device");
508db895a1eSAndreas Färber         return;
50949ab747fSPaolo Bonzini     }
51049ab747fSPaolo Bonzini 
511db895a1eSAndreas Färber     if (isa->index == -1) {
51249ab747fSPaolo Bonzini         isa->index = index;
513db895a1eSAndreas Färber     }
514db895a1eSAndreas Färber     if (isa->index >= MAX_PARALLEL_PORTS) {
515db895a1eSAndreas Färber         error_setg(errp, "Max. supported number of parallel ports is %d.",
516db895a1eSAndreas Färber                    MAX_PARALLEL_PORTS);
517db895a1eSAndreas Färber         return;
518db895a1eSAndreas Färber     }
519db895a1eSAndreas Färber     if (isa->iobase == -1) {
52049ab747fSPaolo Bonzini         isa->iobase = isa_parallel_io[isa->index];
521db895a1eSAndreas Färber     }
52249ab747fSPaolo Bonzini     index++;
52349ab747fSPaolo Bonzini 
52449ab747fSPaolo Bonzini     base = isa->iobase;
525215caca6SBernhard Beschow     s->irq = isa_get_irq(isadev, isa->isairq);
52649ab747fSPaolo Bonzini     qemu_register_reset(parallel_reset, s);
52749ab747fSPaolo Bonzini 
52898fab4c1SPeng Hao     qemu_chr_fe_set_handlers(&s->chr, parallel_can_receive, NULL,
52998fab4c1SPeng Hao                              NULL, NULL, s, NULL, true);
5305345fdb4SMarc-André Lureau     if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
53149ab747fSPaolo Bonzini         s->hw_driver = 1;
53249ab747fSPaolo Bonzini         s->status = dummy;
53349ab747fSPaolo Bonzini     }
53449ab747fSPaolo Bonzini 
535*ee3d1f1bSBernhard Beschow     isa_register_portio_list(isadev, &isa->portio_list, base,
53649ab747fSPaolo Bonzini                              (s->hw_driver
53749ab747fSPaolo Bonzini                               ? &isa_parallel_portio_hw_list[0]
53849ab747fSPaolo Bonzini                               : &isa_parallel_portio_sw_list[0]),
53949ab747fSPaolo Bonzini                              s, "parallel");
54049ab747fSPaolo Bonzini }
54149ab747fSPaolo Bonzini 
parallel_isa_build_aml(AcpiDevAmlIf * adev,Aml * scope)542ef26fc47SIgor Mammedov static void parallel_isa_build_aml(AcpiDevAmlIf *adev, Aml *scope)
543ed003c8cSGerd Hoffmann {
544ef26fc47SIgor Mammedov     ISAParallelState *isa = ISA_PARALLEL(adev);
545ed003c8cSGerd Hoffmann     Aml *dev;
546ed003c8cSGerd Hoffmann     Aml *crs;
547ed003c8cSGerd Hoffmann 
548ed003c8cSGerd Hoffmann     crs = aml_resource_template();
549ed003c8cSGerd Hoffmann     aml_append(crs, aml_io(AML_DECODE16, isa->iobase, isa->iobase, 0x08, 0x08));
550ed003c8cSGerd Hoffmann     aml_append(crs, aml_irq_no_flags(isa->isairq));
551ed003c8cSGerd Hoffmann 
552ed003c8cSGerd Hoffmann     dev = aml_device("LPT%d", isa->index + 1);
553ed003c8cSGerd Hoffmann     aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0400")));
554ed003c8cSGerd Hoffmann     aml_append(dev, aml_name_decl("_UID", aml_int(isa->index + 1)));
555ed003c8cSGerd Hoffmann     aml_append(dev, aml_name_decl("_STA", aml_int(0xf)));
556ed003c8cSGerd Hoffmann     aml_append(dev, aml_name_decl("_CRS", crs));
557ed003c8cSGerd Hoffmann 
558ed003c8cSGerd Hoffmann     aml_append(scope, dev);
559ed003c8cSGerd Hoffmann }
560ed003c8cSGerd Hoffmann 
56149ab747fSPaolo Bonzini /* Memory mapped interface */
parallel_mm_readfn(void * opaque,hwaddr addr,unsigned size)56205b4940bSPeter Maydell static uint64_t parallel_mm_readfn(void *opaque, hwaddr addr, unsigned size)
56349ab747fSPaolo Bonzini {
56449ab747fSPaolo Bonzini     ParallelState *s = opaque;
56549ab747fSPaolo Bonzini 
56605b4940bSPeter Maydell     return parallel_ioport_read_sw(s, addr >> s->it_shift) &
56705b4940bSPeter Maydell         MAKE_64BIT_MASK(0, size * 8);
56849ab747fSPaolo Bonzini }
56949ab747fSPaolo Bonzini 
parallel_mm_writefn(void * opaque,hwaddr addr,uint64_t value,unsigned size)57005b4940bSPeter Maydell static void parallel_mm_writefn(void *opaque, hwaddr addr,
57105b4940bSPeter Maydell                                 uint64_t value, unsigned size)
57249ab747fSPaolo Bonzini {
57349ab747fSPaolo Bonzini     ParallelState *s = opaque;
57449ab747fSPaolo Bonzini 
57505b4940bSPeter Maydell     parallel_ioport_write_sw(s, addr >> s->it_shift,
57605b4940bSPeter Maydell                              value & MAKE_64BIT_MASK(0, size * 8));
57749ab747fSPaolo Bonzini }
57849ab747fSPaolo Bonzini 
57949ab747fSPaolo Bonzini static const MemoryRegionOps parallel_mm_ops = {
58005b4940bSPeter Maydell     .read = parallel_mm_readfn,
58105b4940bSPeter Maydell     .write = parallel_mm_writefn,
58205b4940bSPeter Maydell     .valid.min_access_size = 1,
58305b4940bSPeter Maydell     .valid.max_access_size = 4,
58449ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
58549ab747fSPaolo Bonzini };
58649ab747fSPaolo Bonzini 
58749ab747fSPaolo Bonzini /* If fd is zero, it means that the parallel device uses the console */
parallel_mm_init(MemoryRegion * address_space,hwaddr base,int it_shift,qemu_irq irq,Chardev * chr)58849ab747fSPaolo Bonzini bool parallel_mm_init(MemoryRegion *address_space,
58949ab747fSPaolo Bonzini                       hwaddr base, int it_shift, qemu_irq irq,
5900ec7b3e7SMarc-André Lureau                       Chardev *chr)
59149ab747fSPaolo Bonzini {
59249ab747fSPaolo Bonzini     ParallelState *s;
59349ab747fSPaolo Bonzini 
594b21e2380SMarkus Armbruster     s = g_new0(ParallelState, 1);
59549ab747fSPaolo Bonzini     s->irq = irq;
596becdfa00SMarc-André Lureau     qemu_chr_fe_init(&s->chr, chr, &error_abort);
59749ab747fSPaolo Bonzini     s->it_shift = it_shift;
59849ab747fSPaolo Bonzini     qemu_register_reset(parallel_reset, s);
59949ab747fSPaolo Bonzini 
6002c9b15caSPaolo Bonzini     memory_region_init_io(&s->iomem, NULL, &parallel_mm_ops, s,
60149ab747fSPaolo Bonzini                           "parallel", 8 << it_shift);
60249ab747fSPaolo Bonzini     memory_region_add_subregion(address_space, base, &s->iomem);
60349ab747fSPaolo Bonzini     return true;
60449ab747fSPaolo Bonzini }
60549ab747fSPaolo Bonzini 
60649ab747fSPaolo Bonzini static Property parallel_isa_properties[] = {
60749ab747fSPaolo Bonzini     DEFINE_PROP_UINT32("index", ISAParallelState, index,   -1),
608c7bcc85dSPaolo Bonzini     DEFINE_PROP_UINT32("iobase", ISAParallelState, iobase,  -1),
60949ab747fSPaolo Bonzini     DEFINE_PROP_UINT32("irq",   ISAParallelState, isairq,  7),
61049ab747fSPaolo Bonzini     DEFINE_PROP_CHR("chardev",  ISAParallelState, state.chr),
61149ab747fSPaolo Bonzini     DEFINE_PROP_END_OF_LIST(),
61249ab747fSPaolo Bonzini };
61349ab747fSPaolo Bonzini 
parallel_isa_class_initfn(ObjectClass * klass,void * data)61449ab747fSPaolo Bonzini static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
61549ab747fSPaolo Bonzini {
61649ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
617ef26fc47SIgor Mammedov     AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
618db895a1eSAndreas Färber 
619db895a1eSAndreas Färber     dc->realize = parallel_isa_realizefn;
620461a2753SPavel Dovgalyuk     dc->vmsd = &vmstate_parallel_isa;
621ef26fc47SIgor Mammedov     adevc->build_dev_aml = parallel_isa_build_aml;
6224f67d30bSMarc-André Lureau     device_class_set_props(dc, parallel_isa_properties);
623125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
62449ab747fSPaolo Bonzini }
62549ab747fSPaolo Bonzini 
62649ab747fSPaolo Bonzini static const TypeInfo parallel_isa_info = {
627b0dc5ee6SAndreas Färber     .name          = TYPE_ISA_PARALLEL,
62849ab747fSPaolo Bonzini     .parent        = TYPE_ISA_DEVICE,
62949ab747fSPaolo Bonzini     .instance_size = sizeof(ISAParallelState),
63049ab747fSPaolo Bonzini     .class_init    = parallel_isa_class_initfn,
631ef26fc47SIgor Mammedov     .interfaces = (InterfaceInfo[]) {
632ef26fc47SIgor Mammedov         { TYPE_ACPI_DEV_AML_IF },
633ef26fc47SIgor Mammedov         { },
634ef26fc47SIgor Mammedov     },
63549ab747fSPaolo Bonzini };
63649ab747fSPaolo Bonzini 
parallel_register_types(void)63749ab747fSPaolo Bonzini static void parallel_register_types(void)
63849ab747fSPaolo Bonzini {
63949ab747fSPaolo Bonzini     type_register_static(&parallel_isa_info);
64049ab747fSPaolo Bonzini }
64149ab747fSPaolo Bonzini 
64249ab747fSPaolo Bonzini type_init(parallel_register_types)
643