xref: /qemu/hw/ipack/tpci200.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
19c16fa79SAlberto Garcia /*
29c16fa79SAlberto Garcia  * QEMU TEWS TPCI200 IndustryPack carrier emulation
39c16fa79SAlberto Garcia  *
49c16fa79SAlberto Garcia  * Copyright (C) 2012 Igalia, S.L.
5b996aed5SAlberto Garcia  * Author: Alberto Garcia <berto@igalia.com>
69c16fa79SAlberto Garcia  *
79c16fa79SAlberto Garcia  * This code is licensed under the GNU GPL v2 or (at your option) any
89c16fa79SAlberto Garcia  * later version.
99c16fa79SAlberto Garcia  */
109c16fa79SAlberto Garcia 
110430891cSPeter Maydell #include "qemu/osdep.h"
12a7174d70SPhilippe Mathieu-Daudé #include "qemu/units.h"
131f9c4cfdSAndreas Färber #include "hw/ipack/ipack.h"
1464552b6bSMarkus Armbruster #include "hw/irq.h"
15edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
16d6454270SMarkus Armbruster #include "migration/vmstate.h"
179c16fa79SAlberto Garcia #include "qemu/bitops.h"
180b8fa32fSMarkus Armbruster #include "qemu/module.h"
19db1015e9SEduardo Habkost #include "qom/object.h"
209c16fa79SAlberto Garcia 
219c16fa79SAlberto Garcia /* #define DEBUG_TPCI */
229c16fa79SAlberto Garcia 
239c16fa79SAlberto Garcia #ifdef DEBUG_TPCI
249c16fa79SAlberto Garcia #define DPRINTF(fmt, ...) \
259c16fa79SAlberto Garcia     do { fprintf(stderr, "TPCI200: " fmt, ## __VA_ARGS__); } while (0)
269c16fa79SAlberto Garcia #else
279c16fa79SAlberto Garcia #define DPRINTF(fmt, ...) do { } while (0)
289c16fa79SAlberto Garcia #endif
299c16fa79SAlberto Garcia 
309c16fa79SAlberto Garcia #define N_MODULES 4
319c16fa79SAlberto Garcia 
329c16fa79SAlberto Garcia #define IP_ID_SPACE  2
339c16fa79SAlberto Garcia #define IP_INT_SPACE 3
349c16fa79SAlberto Garcia #define IP_IO_SPACE_ADDR_MASK  0x7F
359c16fa79SAlberto Garcia #define IP_ID_SPACE_ADDR_MASK  0x3F
369c16fa79SAlberto Garcia #define IP_INT_SPACE_ADDR_MASK 0x3F
379c16fa79SAlberto Garcia 
389c16fa79SAlberto Garcia #define STATUS_INT(IP, INTNO) BIT((IP) * 2 + (INTNO))
3909a021fbSStefan Weil #define STATUS_TIME(IP)       BIT((IP) + 12)
409c16fa79SAlberto Garcia #define STATUS_ERR_ANY        0xF00
419c16fa79SAlberto Garcia 
429c16fa79SAlberto Garcia #define CTRL_CLKRATE          BIT(0)
439c16fa79SAlberto Garcia #define CTRL_RECOVER          BIT(1)
449c16fa79SAlberto Garcia #define CTRL_TIME_INT         BIT(2)
459c16fa79SAlberto Garcia #define CTRL_ERR_INT          BIT(3)
469c16fa79SAlberto Garcia #define CTRL_INT_EDGE(INTNO)  BIT(4 + (INTNO))
479c16fa79SAlberto Garcia #define CTRL_INT(INTNO)       BIT(6 + (INTNO))
489c16fa79SAlberto Garcia 
499c16fa79SAlberto Garcia #define REG_REV_ID    0x00
509c16fa79SAlberto Garcia #define REG_IP_A_CTRL 0x02
519c16fa79SAlberto Garcia #define REG_IP_B_CTRL 0x04
529c16fa79SAlberto Garcia #define REG_IP_C_CTRL 0x06
539c16fa79SAlberto Garcia #define REG_IP_D_CTRL 0x08
549c16fa79SAlberto Garcia #define REG_RESET     0x0A
559c16fa79SAlberto Garcia #define REG_STATUS    0x0C
569c16fa79SAlberto Garcia #define IP_N_FROM_REG(REG) ((REG) / 2 - 1)
579c16fa79SAlberto Garcia 
58db1015e9SEduardo Habkost struct TPCI200State {
599c16fa79SAlberto Garcia     PCIDevice dev;
609c16fa79SAlberto Garcia     IPackBus bus;
619c16fa79SAlberto Garcia     MemoryRegion mmio;
629c16fa79SAlberto Garcia     MemoryRegion io;
639c16fa79SAlberto Garcia     MemoryRegion las0;
649c16fa79SAlberto Garcia     MemoryRegion las1;
659c16fa79SAlberto Garcia     MemoryRegion las2;
669c16fa79SAlberto Garcia     MemoryRegion las3;
679c16fa79SAlberto Garcia     bool big_endian[3];
689c16fa79SAlberto Garcia     uint8_t ctrl[N_MODULES];
699c16fa79SAlberto Garcia     uint16_t status;
709c16fa79SAlberto Garcia     uint8_t int_set;
71db1015e9SEduardo Habkost };
729c16fa79SAlberto Garcia 
739c16fa79SAlberto Garcia #define TYPE_TPCI200 "tpci200"
749c16fa79SAlberto Garcia 
758063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(TPCI200State, TPCI200)
769c16fa79SAlberto Garcia 
779c16fa79SAlberto Garcia static const uint8_t local_config_regs[] = {
789c16fa79SAlberto Garcia     0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xFC, 0xFF, 0x0F, 0x00, 0x00, 0x00,
799c16fa79SAlberto Garcia     0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
809c16fa79SAlberto Garcia     0x00, 0x08, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01,
819c16fa79SAlberto Garcia     0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x60, 0x41, 0xD4,
829c16fa79SAlberto Garcia     0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x41, 0x14, 0xA2, 0x20, 0x01,
839c16fa79SAlberto Garcia     0x14, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x08, 0x01, 0x02,
849c16fa79SAlberto Garcia     0x00, 0x04, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x80, 0x02, 0x41,
859c16fa79SAlberto Garcia     0x00, 0x00, 0x00, 0x00, 0x40, 0x7A, 0x00, 0x52, 0x92, 0x24, 0x02
869c16fa79SAlberto Garcia };
879c16fa79SAlberto Garcia 
adjust_addr(bool big_endian,hwaddr * addr,unsigned size)889c16fa79SAlberto Garcia static void adjust_addr(bool big_endian, hwaddr *addr, unsigned size)
899c16fa79SAlberto Garcia {
909c16fa79SAlberto Garcia     /* During 8 bit access in big endian mode,
919c16fa79SAlberto Garcia        odd and even addresses are swapped */
929c16fa79SAlberto Garcia     if (big_endian && size == 1) {
939c16fa79SAlberto Garcia         *addr ^= 1;
949c16fa79SAlberto Garcia     }
959c16fa79SAlberto Garcia }
969c16fa79SAlberto Garcia 
adjust_value(bool big_endian,uint64_t * val,unsigned size)979c16fa79SAlberto Garcia static uint64_t adjust_value(bool big_endian, uint64_t *val, unsigned size)
989c16fa79SAlberto Garcia {
999c16fa79SAlberto Garcia     /* Local spaces only support 8/16 bit access,
1009c16fa79SAlberto Garcia      * so there's no need to care for sizes > 2 */
1019c16fa79SAlberto Garcia     if (big_endian && size == 2) {
1029c16fa79SAlberto Garcia         *val = bswap16(*val);
1039c16fa79SAlberto Garcia     }
1049c16fa79SAlberto Garcia     return *val;
1059c16fa79SAlberto Garcia }
1069c16fa79SAlberto Garcia 
tpci200_set_irq(void * opaque,int intno,int level)1079c16fa79SAlberto Garcia static void tpci200_set_irq(void *opaque, int intno, int level)
1089c16fa79SAlberto Garcia {
1099c16fa79SAlberto Garcia     IPackDevice *ip = opaque;
1109c16fa79SAlberto Garcia     IPackBus *bus = IPACK_BUS(qdev_get_parent_bus(DEVICE(ip)));
1119c16fa79SAlberto Garcia     PCIDevice *pcidev = PCI_DEVICE(BUS(bus)->parent);
1129c16fa79SAlberto Garcia     TPCI200State *dev = TPCI200(pcidev);
1139c16fa79SAlberto Garcia     unsigned ip_n = ip->slot;
1149c16fa79SAlberto Garcia     uint16_t prev_status = dev->status;
1159c16fa79SAlberto Garcia 
1169c16fa79SAlberto Garcia     assert(ip->slot >= 0 && ip->slot < N_MODULES);
1179c16fa79SAlberto Garcia 
1189c16fa79SAlberto Garcia     /* The requested interrupt must be enabled in the IP CONTROL
1199c16fa79SAlberto Garcia      * register */
1209c16fa79SAlberto Garcia     if (!(dev->ctrl[ip_n] & CTRL_INT(intno))) {
1219c16fa79SAlberto Garcia         return;
1229c16fa79SAlberto Garcia     }
1239c16fa79SAlberto Garcia 
1249c16fa79SAlberto Garcia     /* Update the interrupt status in the IP STATUS register */
1259c16fa79SAlberto Garcia     if (level) {
1269c16fa79SAlberto Garcia         dev->status |=  STATUS_INT(ip_n, intno);
1279c16fa79SAlberto Garcia     } else {
1289c16fa79SAlberto Garcia         dev->status &= ~STATUS_INT(ip_n, intno);
1299c16fa79SAlberto Garcia     }
1309c16fa79SAlberto Garcia 
1319c16fa79SAlberto Garcia     /* Return if there are no changes */
1329c16fa79SAlberto Garcia     if (dev->status == prev_status) {
1339c16fa79SAlberto Garcia         return;
1349c16fa79SAlberto Garcia     }
1359c16fa79SAlberto Garcia 
1369c16fa79SAlberto Garcia     DPRINTF("IP %u INT%u#: %u\n", ip_n, intno, level);
1379c16fa79SAlberto Garcia 
1389c16fa79SAlberto Garcia     /* Check if the interrupt is edge sensitive */
1399c16fa79SAlberto Garcia     if (dev->ctrl[ip_n] & CTRL_INT_EDGE(intno)) {
1409c16fa79SAlberto Garcia         if (level) {
1419e64f8a3SMarcel Apfelbaum             pci_set_irq(&dev->dev, !dev->int_set);
1429e64f8a3SMarcel Apfelbaum             pci_set_irq(&dev->dev,  dev->int_set);
1439c16fa79SAlberto Garcia         }
1449c16fa79SAlberto Garcia     } else {
1459c16fa79SAlberto Garcia         unsigned i, j;
1469c16fa79SAlberto Garcia         uint16_t level_status = dev->status;
1479c16fa79SAlberto Garcia 
1489c16fa79SAlberto Garcia         /* Check if there are any level sensitive interrupts set by
1499c16fa79SAlberto Garcia            removing the ones that are edge sensitive from the status
1509c16fa79SAlberto Garcia            register */
1519c16fa79SAlberto Garcia         for (i = 0; i < N_MODULES; i++) {
1529c16fa79SAlberto Garcia             for (j = 0; j < 2; j++) {
1539c16fa79SAlberto Garcia                 if (dev->ctrl[i] & CTRL_INT_EDGE(j)) {
1549c16fa79SAlberto Garcia                     level_status &= ~STATUS_INT(i, j);
1559c16fa79SAlberto Garcia                 }
1569c16fa79SAlberto Garcia             }
1579c16fa79SAlberto Garcia         }
1589c16fa79SAlberto Garcia 
1599c16fa79SAlberto Garcia         if (level_status && !dev->int_set) {
1609e64f8a3SMarcel Apfelbaum             pci_irq_assert(&dev->dev);
1619c16fa79SAlberto Garcia             dev->int_set = 1;
1629c16fa79SAlberto Garcia         } else if (!level_status && dev->int_set) {
1639e64f8a3SMarcel Apfelbaum             pci_irq_deassert(&dev->dev);
1649c16fa79SAlberto Garcia             dev->int_set = 0;
1659c16fa79SAlberto Garcia         }
1669c16fa79SAlberto Garcia     }
1679c16fa79SAlberto Garcia }
1689c16fa79SAlberto Garcia 
tpci200_read_cfg(void * opaque,hwaddr addr,unsigned size)1699c16fa79SAlberto Garcia static uint64_t tpci200_read_cfg(void *opaque, hwaddr addr, unsigned size)
1709c16fa79SAlberto Garcia {
1719c16fa79SAlberto Garcia     TPCI200State *s = opaque;
1729c16fa79SAlberto Garcia     uint8_t ret = 0;
1739c16fa79SAlberto Garcia     if (addr < ARRAY_SIZE(local_config_regs)) {
1749c16fa79SAlberto Garcia         ret = local_config_regs[addr];
1759c16fa79SAlberto Garcia     }
1769c16fa79SAlberto Garcia     /* Endianness is stored in the first bit of these registers */
1779c16fa79SAlberto Garcia     if ((addr == 0x2b && s->big_endian[0]) ||
1789c16fa79SAlberto Garcia         (addr == 0x2f && s->big_endian[1]) ||
1799c16fa79SAlberto Garcia         (addr == 0x33 && s->big_endian[2])) {
1809c16fa79SAlberto Garcia         ret |= 1;
1819c16fa79SAlberto Garcia     }
1829c16fa79SAlberto Garcia     DPRINTF("Read from LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) ret);
1839c16fa79SAlberto Garcia     return ret;
1849c16fa79SAlberto Garcia }
1859c16fa79SAlberto Garcia 
tpci200_write_cfg(void * opaque,hwaddr addr,uint64_t val,unsigned size)1869c16fa79SAlberto Garcia static void tpci200_write_cfg(void *opaque, hwaddr addr, uint64_t val,
1879c16fa79SAlberto Garcia                               unsigned size)
1889c16fa79SAlberto Garcia {
1899c16fa79SAlberto Garcia     TPCI200State *s = opaque;
1909c16fa79SAlberto Garcia     /* Endianness is stored in the first bit of these registers */
1919c16fa79SAlberto Garcia     if (addr == 0x2b || addr == 0x2f || addr == 0x33) {
1929c16fa79SAlberto Garcia         unsigned las = (addr - 0x2b) / 4;
1939c16fa79SAlberto Garcia         s->big_endian[las] = val & 1;
1949c16fa79SAlberto Garcia         DPRINTF("LAS%u big endian mode: %u\n", las, (unsigned) val & 1);
1959c16fa79SAlberto Garcia     } else {
1969c16fa79SAlberto Garcia         DPRINTF("Write to LCR 0x%x: 0x%x\n", (unsigned) addr, (unsigned) val);
1979c16fa79SAlberto Garcia     }
1989c16fa79SAlberto Garcia }
1999c16fa79SAlberto Garcia 
tpci200_read_las0(void * opaque,hwaddr addr,unsigned size)2009c16fa79SAlberto Garcia static uint64_t tpci200_read_las0(void *opaque, hwaddr addr, unsigned size)
2019c16fa79SAlberto Garcia {
2029c16fa79SAlberto Garcia     TPCI200State *s = opaque;
2039c16fa79SAlberto Garcia     uint64_t ret = 0;
2049c16fa79SAlberto Garcia 
2059c16fa79SAlberto Garcia     switch (addr) {
2069c16fa79SAlberto Garcia 
2079c16fa79SAlberto Garcia     case REG_REV_ID:
2089c16fa79SAlberto Garcia         DPRINTF("Read REVISION ID\n"); /* Current value is 0x00 */
2099c16fa79SAlberto Garcia         break;
2109c16fa79SAlberto Garcia 
2119c16fa79SAlberto Garcia     case REG_IP_A_CTRL:
2129c16fa79SAlberto Garcia     case REG_IP_B_CTRL:
2139c16fa79SAlberto Garcia     case REG_IP_C_CTRL:
2149c16fa79SAlberto Garcia     case REG_IP_D_CTRL:
2159c16fa79SAlberto Garcia         {
2169c16fa79SAlberto Garcia             unsigned ip_n = IP_N_FROM_REG(addr);
2179c16fa79SAlberto Garcia             ret = s->ctrl[ip_n];
2189c16fa79SAlberto Garcia             DPRINTF("Read IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) ret);
2199c16fa79SAlberto Garcia         }
2209c16fa79SAlberto Garcia         break;
2219c16fa79SAlberto Garcia 
2229c16fa79SAlberto Garcia     case REG_RESET:
2239c16fa79SAlberto Garcia         DPRINTF("Read RESET\n"); /* Not implemented */
2249c16fa79SAlberto Garcia         break;
2259c16fa79SAlberto Garcia 
2269c16fa79SAlberto Garcia     case REG_STATUS:
2279c16fa79SAlberto Garcia         ret = s->status;
2289c16fa79SAlberto Garcia         DPRINTF("Read STATUS: 0x%x\n", (unsigned) ret);
2299c16fa79SAlberto Garcia         break;
2309c16fa79SAlberto Garcia 
2319c16fa79SAlberto Garcia     /* Reserved */
2329c16fa79SAlberto Garcia     default:
2339c16fa79SAlberto Garcia         DPRINTF("Unsupported read from LAS0 0x%x\n", (unsigned) addr);
2349c16fa79SAlberto Garcia         break;
2359c16fa79SAlberto Garcia     }
2369c16fa79SAlberto Garcia 
2379c16fa79SAlberto Garcia     return adjust_value(s->big_endian[0], &ret, size);
2389c16fa79SAlberto Garcia }
2399c16fa79SAlberto Garcia 
tpci200_write_las0(void * opaque,hwaddr addr,uint64_t val,unsigned size)2409c16fa79SAlberto Garcia static void tpci200_write_las0(void *opaque, hwaddr addr, uint64_t val,
2419c16fa79SAlberto Garcia                                unsigned size)
2429c16fa79SAlberto Garcia {
2439c16fa79SAlberto Garcia     TPCI200State *s = opaque;
2449c16fa79SAlberto Garcia 
2459c16fa79SAlberto Garcia     adjust_value(s->big_endian[0], &val, size);
2469c16fa79SAlberto Garcia 
2479c16fa79SAlberto Garcia     switch (addr) {
2489c16fa79SAlberto Garcia 
2499c16fa79SAlberto Garcia     case REG_REV_ID:
2509c16fa79SAlberto Garcia         DPRINTF("Write Revision ID: 0x%x\n", (unsigned) val); /* No effect */
2519c16fa79SAlberto Garcia         break;
2529c16fa79SAlberto Garcia 
2539c16fa79SAlberto Garcia     case REG_IP_A_CTRL:
2549c16fa79SAlberto Garcia     case REG_IP_B_CTRL:
2559c16fa79SAlberto Garcia     case REG_IP_C_CTRL:
2569c16fa79SAlberto Garcia     case REG_IP_D_CTRL:
2579c16fa79SAlberto Garcia         {
2589c16fa79SAlberto Garcia             unsigned ip_n = IP_N_FROM_REG(addr);
2599c16fa79SAlberto Garcia             s->ctrl[ip_n] = val;
2609c16fa79SAlberto Garcia             DPRINTF("Write IP %c CONTROL: 0x%x\n", 'A' + ip_n, (unsigned) val);
2619c16fa79SAlberto Garcia         }
2629c16fa79SAlberto Garcia         break;
2639c16fa79SAlberto Garcia 
2649c16fa79SAlberto Garcia     case REG_RESET:
2659c16fa79SAlberto Garcia         DPRINTF("Write RESET: 0x%x\n", (unsigned) val); /* Not implemented */
2669c16fa79SAlberto Garcia         break;
2679c16fa79SAlberto Garcia 
2689c16fa79SAlberto Garcia     case REG_STATUS:
2699c16fa79SAlberto Garcia         {
2709c16fa79SAlberto Garcia             unsigned i;
2719c16fa79SAlberto Garcia 
2729c16fa79SAlberto Garcia             for (i = 0; i < N_MODULES; i++) {
2739c16fa79SAlberto Garcia                 IPackDevice *ip = ipack_device_find(&s->bus, i);
2749c16fa79SAlberto Garcia 
2759c16fa79SAlberto Garcia                 if (ip != NULL) {
2769c16fa79SAlberto Garcia                     if (val & STATUS_INT(i, 0)) {
2779c16fa79SAlberto Garcia                         DPRINTF("Clear IP %c INT0# status\n", 'A' + i);
278d50280afSPhilippe Mathieu-Daudé                         qemu_irq_lower(&ip->irq[0]);
2799c16fa79SAlberto Garcia                     }
2809c16fa79SAlberto Garcia                     if (val & STATUS_INT(i, 1)) {
2819c16fa79SAlberto Garcia                         DPRINTF("Clear IP %c INT1# status\n", 'A' + i);
282d50280afSPhilippe Mathieu-Daudé                         qemu_irq_lower(&ip->irq[1]);
2839c16fa79SAlberto Garcia                     }
2849c16fa79SAlberto Garcia                 }
2859c16fa79SAlberto Garcia 
28609a021fbSStefan Weil                 if (val & STATUS_TIME(i)) {
2879c16fa79SAlberto Garcia                     DPRINTF("Clear IP %c timeout\n", 'A' + i);
28809a021fbSStefan Weil                     s->status &= ~STATUS_TIME(i);
2899c16fa79SAlberto Garcia                 }
2909c16fa79SAlberto Garcia             }
2919c16fa79SAlberto Garcia 
2929c16fa79SAlberto Garcia             if (val & STATUS_ERR_ANY) {
2939c16fa79SAlberto Garcia                 DPRINTF("Unexpected write to STATUS register: 0x%x\n",
2949c16fa79SAlberto Garcia                         (unsigned) val);
2959c16fa79SAlberto Garcia             }
2969c16fa79SAlberto Garcia         }
2979c16fa79SAlberto Garcia         break;
2989c16fa79SAlberto Garcia 
2999c16fa79SAlberto Garcia     /* Reserved */
3009c16fa79SAlberto Garcia     default:
3019c16fa79SAlberto Garcia         DPRINTF("Unsupported write to LAS0 0x%x: 0x%x\n",
3029c16fa79SAlberto Garcia                 (unsigned) addr, (unsigned) val);
3039c16fa79SAlberto Garcia         break;
3049c16fa79SAlberto Garcia     }
3059c16fa79SAlberto Garcia }
3069c16fa79SAlberto Garcia 
tpci200_read_las1(void * opaque,hwaddr addr,unsigned size)3079c16fa79SAlberto Garcia static uint64_t tpci200_read_las1(void *opaque, hwaddr addr, unsigned size)
3089c16fa79SAlberto Garcia {
3099c16fa79SAlberto Garcia     TPCI200State *s = opaque;
3109c16fa79SAlberto Garcia     IPackDevice *ip;
3119c16fa79SAlberto Garcia     uint64_t ret = 0;
3129c16fa79SAlberto Garcia     unsigned ip_n, space;
3139c16fa79SAlberto Garcia     uint8_t offset;
3149c16fa79SAlberto Garcia 
3159c16fa79SAlberto Garcia     adjust_addr(s->big_endian[1], &addr, size);
3169c16fa79SAlberto Garcia 
3179c16fa79SAlberto Garcia     /*
3189c16fa79SAlberto Garcia      * The address is divided into the IP module number (0-4), the IP
3199c16fa79SAlberto Garcia      * address space (I/O, ID, INT) and the offset within that space.
3209c16fa79SAlberto Garcia      */
3219c16fa79SAlberto Garcia     ip_n = addr >> 8;
3229c16fa79SAlberto Garcia     space = (addr >> 6) & 3;
3239c16fa79SAlberto Garcia     ip = ipack_device_find(&s->bus, ip_n);
3249c16fa79SAlberto Garcia 
3259c16fa79SAlberto Garcia     if (ip == NULL) {
3269c16fa79SAlberto Garcia         DPRINTF("Read LAS1: IP module %u not installed\n", ip_n);
3279c16fa79SAlberto Garcia     } else {
3289c16fa79SAlberto Garcia         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
3299c16fa79SAlberto Garcia         switch (space) {
3309c16fa79SAlberto Garcia 
3319c16fa79SAlberto Garcia         case IP_ID_SPACE:
3329c16fa79SAlberto Garcia             offset = addr & IP_ID_SPACE_ADDR_MASK;
3339c16fa79SAlberto Garcia             if (k->id_read) {
3349c16fa79SAlberto Garcia                 ret = k->id_read(ip, offset);
3359c16fa79SAlberto Garcia             }
3369c16fa79SAlberto Garcia             break;
3379c16fa79SAlberto Garcia 
3389c16fa79SAlberto Garcia         case IP_INT_SPACE:
3399c16fa79SAlberto Garcia             offset = addr & IP_INT_SPACE_ADDR_MASK;
3409c16fa79SAlberto Garcia 
3419c16fa79SAlberto Garcia             /* Read address 0 to ACK IP INT0# and address 2 to ACK IP INT1# */
3429c16fa79SAlberto Garcia             if (offset == 0 || offset == 2) {
3439c16fa79SAlberto Garcia                 unsigned intno = offset / 2;
3449c16fa79SAlberto Garcia                 bool int_set = s->status & STATUS_INT(ip_n, intno);
3459c16fa79SAlberto Garcia                 bool int_edge_sensitive = s->ctrl[ip_n] & CTRL_INT_EDGE(intno);
3469c16fa79SAlberto Garcia                 if (int_set && !int_edge_sensitive) {
347d50280afSPhilippe Mathieu-Daudé                     qemu_irq_lower(&ip->irq[intno]);
3489c16fa79SAlberto Garcia                 }
3499c16fa79SAlberto Garcia             }
3509c16fa79SAlberto Garcia 
3519c16fa79SAlberto Garcia             if (k->int_read) {
3529c16fa79SAlberto Garcia                 ret = k->int_read(ip, offset);
3539c16fa79SAlberto Garcia             }
3549c16fa79SAlberto Garcia             break;
3559c16fa79SAlberto Garcia 
3569c16fa79SAlberto Garcia         default:
3579c16fa79SAlberto Garcia             offset = addr & IP_IO_SPACE_ADDR_MASK;
3589c16fa79SAlberto Garcia             if (k->io_read) {
3599c16fa79SAlberto Garcia                 ret = k->io_read(ip, offset);
3609c16fa79SAlberto Garcia             }
3619c16fa79SAlberto Garcia             break;
3629c16fa79SAlberto Garcia         }
3639c16fa79SAlberto Garcia     }
3649c16fa79SAlberto Garcia 
3659c16fa79SAlberto Garcia     return adjust_value(s->big_endian[1], &ret, size);
3669c16fa79SAlberto Garcia }
3679c16fa79SAlberto Garcia 
tpci200_write_las1(void * opaque,hwaddr addr,uint64_t val,unsigned size)3689c16fa79SAlberto Garcia static void tpci200_write_las1(void *opaque, hwaddr addr, uint64_t val,
3699c16fa79SAlberto Garcia                                unsigned size)
3709c16fa79SAlberto Garcia {
3719c16fa79SAlberto Garcia     TPCI200State *s = opaque;
3729c16fa79SAlberto Garcia     IPackDevice *ip;
3739c16fa79SAlberto Garcia     unsigned ip_n, space;
3749c16fa79SAlberto Garcia     uint8_t offset;
3759c16fa79SAlberto Garcia 
3769c16fa79SAlberto Garcia     adjust_addr(s->big_endian[1], &addr, size);
3779c16fa79SAlberto Garcia     adjust_value(s->big_endian[1], &val, size);
3789c16fa79SAlberto Garcia 
3799c16fa79SAlberto Garcia     /*
3809c16fa79SAlberto Garcia      * The address is divided into the IP module number, the IP
3819c16fa79SAlberto Garcia      * address space (I/O, ID, INT) and the offset within that space.
3829c16fa79SAlberto Garcia      */
3839c16fa79SAlberto Garcia     ip_n = addr >> 8;
3849c16fa79SAlberto Garcia     space = (addr >> 6) & 3;
3859c16fa79SAlberto Garcia     ip = ipack_device_find(&s->bus, ip_n);
3869c16fa79SAlberto Garcia 
3879c16fa79SAlberto Garcia     if (ip == NULL) {
3889c16fa79SAlberto Garcia         DPRINTF("Write LAS1: IP module %u not installed\n", ip_n);
3899c16fa79SAlberto Garcia     } else {
3909c16fa79SAlberto Garcia         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
3919c16fa79SAlberto Garcia         switch (space) {
3929c16fa79SAlberto Garcia 
3939c16fa79SAlberto Garcia         case IP_ID_SPACE:
3949c16fa79SAlberto Garcia             offset = addr & IP_ID_SPACE_ADDR_MASK;
3959c16fa79SAlberto Garcia             if (k->id_write) {
3969c16fa79SAlberto Garcia                 k->id_write(ip, offset, val);
3979c16fa79SAlberto Garcia             }
3989c16fa79SAlberto Garcia             break;
3999c16fa79SAlberto Garcia 
4009c16fa79SAlberto Garcia         case IP_INT_SPACE:
4019c16fa79SAlberto Garcia             offset = addr & IP_INT_SPACE_ADDR_MASK;
4029c16fa79SAlberto Garcia             if (k->int_write) {
4039c16fa79SAlberto Garcia                 k->int_write(ip, offset, val);
4049c16fa79SAlberto Garcia             }
4059c16fa79SAlberto Garcia             break;
4069c16fa79SAlberto Garcia 
4079c16fa79SAlberto Garcia         default:
4089c16fa79SAlberto Garcia             offset = addr & IP_IO_SPACE_ADDR_MASK;
4099c16fa79SAlberto Garcia             if (k->io_write) {
4109c16fa79SAlberto Garcia                 k->io_write(ip, offset, val);
4119c16fa79SAlberto Garcia             }
4129c16fa79SAlberto Garcia             break;
4139c16fa79SAlberto Garcia         }
4149c16fa79SAlberto Garcia     }
4159c16fa79SAlberto Garcia }
4169c16fa79SAlberto Garcia 
tpci200_read_las2(void * opaque,hwaddr addr,unsigned size)4179c16fa79SAlberto Garcia static uint64_t tpci200_read_las2(void *opaque, hwaddr addr, unsigned size)
4189c16fa79SAlberto Garcia {
4199c16fa79SAlberto Garcia     TPCI200State *s = opaque;
4209c16fa79SAlberto Garcia     IPackDevice *ip;
4219c16fa79SAlberto Garcia     uint64_t ret = 0;
4229c16fa79SAlberto Garcia     unsigned ip_n;
4239c16fa79SAlberto Garcia     uint32_t offset;
4249c16fa79SAlberto Garcia 
4259c16fa79SAlberto Garcia     adjust_addr(s->big_endian[2], &addr, size);
4269c16fa79SAlberto Garcia 
4279c16fa79SAlberto Garcia     /*
4289c16fa79SAlberto Garcia      * The address is divided into the IP module number and the offset
4299c16fa79SAlberto Garcia      * within the IP module MEM space.
4309c16fa79SAlberto Garcia      */
4319c16fa79SAlberto Garcia     ip_n = addr >> 23;
4329c16fa79SAlberto Garcia     offset = addr & 0x7fffff;
4339c16fa79SAlberto Garcia     ip = ipack_device_find(&s->bus, ip_n);
4349c16fa79SAlberto Garcia 
4359c16fa79SAlberto Garcia     if (ip == NULL) {
4369c16fa79SAlberto Garcia         DPRINTF("Read LAS2: IP module %u not installed\n", ip_n);
4379c16fa79SAlberto Garcia     } else {
4389c16fa79SAlberto Garcia         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
4399c16fa79SAlberto Garcia         if (k->mem_read16) {
4409c16fa79SAlberto Garcia             ret = k->mem_read16(ip, offset);
4419c16fa79SAlberto Garcia         }
4429c16fa79SAlberto Garcia     }
4439c16fa79SAlberto Garcia 
4449c16fa79SAlberto Garcia     return adjust_value(s->big_endian[2], &ret, size);
4459c16fa79SAlberto Garcia }
4469c16fa79SAlberto Garcia 
tpci200_write_las2(void * opaque,hwaddr addr,uint64_t val,unsigned size)4479c16fa79SAlberto Garcia static void tpci200_write_las2(void *opaque, hwaddr addr, uint64_t val,
4489c16fa79SAlberto Garcia                                unsigned size)
4499c16fa79SAlberto Garcia {
4509c16fa79SAlberto Garcia     TPCI200State *s = opaque;
4519c16fa79SAlberto Garcia     IPackDevice *ip;
4529c16fa79SAlberto Garcia     unsigned ip_n;
4539c16fa79SAlberto Garcia     uint32_t offset;
4549c16fa79SAlberto Garcia 
4559c16fa79SAlberto Garcia     adjust_addr(s->big_endian[2], &addr, size);
4569c16fa79SAlberto Garcia     adjust_value(s->big_endian[2], &val, size);
4579c16fa79SAlberto Garcia 
4589c16fa79SAlberto Garcia     /*
4599c16fa79SAlberto Garcia      * The address is divided into the IP module number and the offset
4609c16fa79SAlberto Garcia      * within the IP module MEM space.
4619c16fa79SAlberto Garcia      */
4629c16fa79SAlberto Garcia     ip_n = addr >> 23;
4639c16fa79SAlberto Garcia     offset = addr & 0x7fffff;
4649c16fa79SAlberto Garcia     ip = ipack_device_find(&s->bus, ip_n);
4659c16fa79SAlberto Garcia 
4669c16fa79SAlberto Garcia     if (ip == NULL) {
4679c16fa79SAlberto Garcia         DPRINTF("Write LAS2: IP module %u not installed\n", ip_n);
4689c16fa79SAlberto Garcia     } else {
4699c16fa79SAlberto Garcia         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
4709c16fa79SAlberto Garcia         if (k->mem_write16) {
4719c16fa79SAlberto Garcia             k->mem_write16(ip, offset, val);
4729c16fa79SAlberto Garcia         }
4739c16fa79SAlberto Garcia     }
4749c16fa79SAlberto Garcia }
4759c16fa79SAlberto Garcia 
tpci200_read_las3(void * opaque,hwaddr addr,unsigned size)4769c16fa79SAlberto Garcia static uint64_t tpci200_read_las3(void *opaque, hwaddr addr, unsigned size)
4779c16fa79SAlberto Garcia {
4789c16fa79SAlberto Garcia     TPCI200State *s = opaque;
4799c16fa79SAlberto Garcia     IPackDevice *ip;
4809c16fa79SAlberto Garcia     uint64_t ret = 0;
4819c16fa79SAlberto Garcia     /*
4829c16fa79SAlberto Garcia      * The address is divided into the IP module number and the offset
4839c16fa79SAlberto Garcia      * within the IP module MEM space.
4849c16fa79SAlberto Garcia      */
4859c16fa79SAlberto Garcia     unsigned ip_n = addr >> 22;
4869c16fa79SAlberto Garcia     uint32_t offset = addr & 0x3fffff;
4879c16fa79SAlberto Garcia 
4889c16fa79SAlberto Garcia     ip = ipack_device_find(&s->bus, ip_n);
4899c16fa79SAlberto Garcia 
4909c16fa79SAlberto Garcia     if (ip == NULL) {
4919c16fa79SAlberto Garcia         DPRINTF("Read LAS3: IP module %u not installed\n", ip_n);
4929c16fa79SAlberto Garcia     } else {
4939c16fa79SAlberto Garcia         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
4949c16fa79SAlberto Garcia         if (k->mem_read8) {
4959c16fa79SAlberto Garcia             ret = k->mem_read8(ip, offset);
4969c16fa79SAlberto Garcia         }
4979c16fa79SAlberto Garcia     }
4989c16fa79SAlberto Garcia 
4999c16fa79SAlberto Garcia     return ret;
5009c16fa79SAlberto Garcia }
5019c16fa79SAlberto Garcia 
tpci200_write_las3(void * opaque,hwaddr addr,uint64_t val,unsigned size)5029c16fa79SAlberto Garcia static void tpci200_write_las3(void *opaque, hwaddr addr, uint64_t val,
5039c16fa79SAlberto Garcia                                unsigned size)
5049c16fa79SAlberto Garcia {
5059c16fa79SAlberto Garcia     TPCI200State *s = opaque;
5069c16fa79SAlberto Garcia     IPackDevice *ip;
5079c16fa79SAlberto Garcia     /*
5089c16fa79SAlberto Garcia      * The address is divided into the IP module number and the offset
5099c16fa79SAlberto Garcia      * within the IP module MEM space.
5109c16fa79SAlberto Garcia      */
5119c16fa79SAlberto Garcia     unsigned ip_n = addr >> 22;
5129c16fa79SAlberto Garcia     uint32_t offset = addr & 0x3fffff;
5139c16fa79SAlberto Garcia 
5149c16fa79SAlberto Garcia     ip = ipack_device_find(&s->bus, ip_n);
5159c16fa79SAlberto Garcia 
5169c16fa79SAlberto Garcia     if (ip == NULL) {
5179c16fa79SAlberto Garcia         DPRINTF("Write LAS3: IP module %u not installed\n", ip_n);
5189c16fa79SAlberto Garcia     } else {
5199c16fa79SAlberto Garcia         IPackDeviceClass *k = IPACK_DEVICE_GET_CLASS(ip);
5209c16fa79SAlberto Garcia         if (k->mem_write8) {
5219c16fa79SAlberto Garcia             k->mem_write8(ip, offset, val);
5229c16fa79SAlberto Garcia         }
5239c16fa79SAlberto Garcia     }
5249c16fa79SAlberto Garcia }
5259c16fa79SAlberto Garcia 
5269c16fa79SAlberto Garcia static const MemoryRegionOps tpci200_cfg_ops = {
5279c16fa79SAlberto Garcia     .read = tpci200_read_cfg,
5289c16fa79SAlberto Garcia     .write = tpci200_write_cfg,
5299c16fa79SAlberto Garcia     .endianness = DEVICE_NATIVE_ENDIAN,
5309c16fa79SAlberto Garcia     .valid =  {
5319c16fa79SAlberto Garcia         .min_access_size = 1,
5329c16fa79SAlberto Garcia         .max_access_size = 4
5339c16fa79SAlberto Garcia     },
5349c16fa79SAlberto Garcia     .impl = {
5359c16fa79SAlberto Garcia         .min_access_size = 1,
5369c16fa79SAlberto Garcia         .max_access_size = 1
5379c16fa79SAlberto Garcia     }
5389c16fa79SAlberto Garcia };
5399c16fa79SAlberto Garcia 
5409c16fa79SAlberto Garcia static const MemoryRegionOps tpci200_las0_ops = {
5419c16fa79SAlberto Garcia     .read = tpci200_read_las0,
5429c16fa79SAlberto Garcia     .write = tpci200_write_las0,
5439c16fa79SAlberto Garcia     .endianness = DEVICE_NATIVE_ENDIAN,
5449c16fa79SAlberto Garcia     .valid =  {
5459c16fa79SAlberto Garcia         .min_access_size = 2,
5469c16fa79SAlberto Garcia         .max_access_size = 2
5479c16fa79SAlberto Garcia     }
5489c16fa79SAlberto Garcia };
5499c16fa79SAlberto Garcia 
5509c16fa79SAlberto Garcia static const MemoryRegionOps tpci200_las1_ops = {
5519c16fa79SAlberto Garcia     .read = tpci200_read_las1,
5529c16fa79SAlberto Garcia     .write = tpci200_write_las1,
5539c16fa79SAlberto Garcia     .endianness = DEVICE_NATIVE_ENDIAN,
5549c16fa79SAlberto Garcia     .valid =  {
5559c16fa79SAlberto Garcia         .min_access_size = 1,
5569c16fa79SAlberto Garcia         .max_access_size = 2
5579c16fa79SAlberto Garcia     }
5589c16fa79SAlberto Garcia };
5599c16fa79SAlberto Garcia 
5609c16fa79SAlberto Garcia static const MemoryRegionOps tpci200_las2_ops = {
5619c16fa79SAlberto Garcia     .read = tpci200_read_las2,
5629c16fa79SAlberto Garcia     .write = tpci200_write_las2,
5639c16fa79SAlberto Garcia     .endianness = DEVICE_NATIVE_ENDIAN,
5649c16fa79SAlberto Garcia     .valid =  {
5659c16fa79SAlberto Garcia         .min_access_size = 1,
5669c16fa79SAlberto Garcia         .max_access_size = 2
5679c16fa79SAlberto Garcia     }
5689c16fa79SAlberto Garcia };
5699c16fa79SAlberto Garcia 
5709c16fa79SAlberto Garcia static const MemoryRegionOps tpci200_las3_ops = {
5719c16fa79SAlberto Garcia     .read = tpci200_read_las3,
5729c16fa79SAlberto Garcia     .write = tpci200_write_las3,
5739c16fa79SAlberto Garcia     .endianness = DEVICE_NATIVE_ENDIAN,
5749c16fa79SAlberto Garcia     .valid =  {
5759c16fa79SAlberto Garcia         .min_access_size = 1,
5769c16fa79SAlberto Garcia         .max_access_size = 1
5779c16fa79SAlberto Garcia     }
5789c16fa79SAlberto Garcia };
5799c16fa79SAlberto Garcia 
tpci200_realize(PCIDevice * pci_dev,Error ** errp)5809af21dbeSMarkus Armbruster static void tpci200_realize(PCIDevice *pci_dev, Error **errp)
5819c16fa79SAlberto Garcia {
5829c16fa79SAlberto Garcia     TPCI200State *s = TPCI200(pci_dev);
5839c16fa79SAlberto Garcia     uint8_t *c = s->dev.config;
5849c16fa79SAlberto Garcia 
5859c16fa79SAlberto Garcia     pci_set_word(c + PCI_COMMAND, 0x0003);
5869c16fa79SAlberto Garcia     pci_set_word(c + PCI_STATUS,  0x0280);
5879c16fa79SAlberto Garcia 
5889c16fa79SAlberto Garcia     pci_set_byte(c + PCI_INTERRUPT_PIN, 0x01); /* Interrupt pin A */
5899c16fa79SAlberto Garcia 
5909c16fa79SAlberto Garcia     pci_set_byte(c + PCI_CAPABILITY_LIST, 0x40);
5919c16fa79SAlberto Garcia     pci_set_long(c + 0x40, 0x48014801);
5929c16fa79SAlberto Garcia     pci_set_long(c + 0x48, 0x00024C06);
5939c16fa79SAlberto Garcia     pci_set_long(c + 0x4C, 0x00000003);
5949c16fa79SAlberto Garcia 
595300b1fc6SPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &tpci200_cfg_ops,
5969c16fa79SAlberto Garcia                           s, "tpci200_mmio", 128);
597300b1fc6SPaolo Bonzini     memory_region_init_io(&s->io, OBJECT(s),   &tpci200_cfg_ops,
5989c16fa79SAlberto Garcia                           s, "tpci200_io",   128);
599300b1fc6SPaolo Bonzini     memory_region_init_io(&s->las0, OBJECT(s), &tpci200_las0_ops,
6009c16fa79SAlberto Garcia                           s, "tpci200_las0", 256);
601300b1fc6SPaolo Bonzini     memory_region_init_io(&s->las1, OBJECT(s), &tpci200_las1_ops,
6029c16fa79SAlberto Garcia                           s, "tpci200_las1", 1024);
603300b1fc6SPaolo Bonzini     memory_region_init_io(&s->las2, OBJECT(s), &tpci200_las2_ops,
604a7174d70SPhilippe Mathieu-Daudé                           s, "tpci200_las2", 32 * MiB);
605300b1fc6SPaolo Bonzini     memory_region_init_io(&s->las3, OBJECT(s), &tpci200_las3_ops,
606a7174d70SPhilippe Mathieu-Daudé                           s, "tpci200_las3", 16 * MiB);
6079c16fa79SAlberto Garcia     pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio);
6089c16fa79SAlberto Garcia     pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_IO,     &s->io);
6099c16fa79SAlberto Garcia     pci_register_bar(&s->dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las0);
6109c16fa79SAlberto Garcia     pci_register_bar(&s->dev, 3, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las1);
6119c16fa79SAlberto Garcia     pci_register_bar(&s->dev, 4, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las2);
6129c16fa79SAlberto Garcia     pci_register_bar(&s->dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->las3);
6139c16fa79SAlberto Garcia 
61443417c0cSPeter Maydell     ipack_bus_init(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
6159c16fa79SAlberto Garcia                    N_MODULES, tpci200_set_irq);
6169c16fa79SAlberto Garcia }
6179c16fa79SAlberto Garcia 
6189c16fa79SAlberto Garcia static const VMStateDescription vmstate_tpci200 = {
6199c16fa79SAlberto Garcia     .name = "tpci200",
6209c16fa79SAlberto Garcia     .version_id = 1,
6219c16fa79SAlberto Garcia     .minimum_version_id = 1,
6228913d05dSRichard Henderson     .fields = (const VMStateField[]) {
6239c16fa79SAlberto Garcia         VMSTATE_PCI_DEVICE(dev, TPCI200State),
6249c16fa79SAlberto Garcia         VMSTATE_BOOL_ARRAY(big_endian, TPCI200State, 3),
6259c16fa79SAlberto Garcia         VMSTATE_UINT8_ARRAY(ctrl, TPCI200State, N_MODULES),
6269c16fa79SAlberto Garcia         VMSTATE_UINT16(status, TPCI200State),
6279c16fa79SAlberto Garcia         VMSTATE_UINT8(int_set, TPCI200State),
6289c16fa79SAlberto Garcia         VMSTATE_END_OF_LIST()
6299c16fa79SAlberto Garcia     }
6309c16fa79SAlberto Garcia };
6319c16fa79SAlberto Garcia 
tpci200_class_init(ObjectClass * klass,const void * data)63212d1a768SPhilippe Mathieu-Daudé static void tpci200_class_init(ObjectClass *klass, const void *data)
6339c16fa79SAlberto Garcia {
6349c16fa79SAlberto Garcia     DeviceClass *dc = DEVICE_CLASS(klass);
6359c16fa79SAlberto Garcia     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
6369c16fa79SAlberto Garcia 
6379af21dbeSMarkus Armbruster     k->realize = tpci200_realize;
6389c16fa79SAlberto Garcia     k->vendor_id = PCI_VENDOR_ID_TEWS;
6399c16fa79SAlberto Garcia     k->device_id = PCI_DEVICE_ID_TEWS_TPCI200;
6409c16fa79SAlberto Garcia     k->class_id = PCI_CLASS_BRIDGE_OTHER;
6419c16fa79SAlberto Garcia     k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS;
6429c16fa79SAlberto Garcia     k->subsystem_id = 0x300A;
643125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
6449c16fa79SAlberto Garcia     dc->desc = "TEWS TPCI200 IndustryPack carrier";
6459c16fa79SAlberto Garcia     dc->vmsd = &vmstate_tpci200;
6469c16fa79SAlberto Garcia }
6479c16fa79SAlberto Garcia 
6489c16fa79SAlberto Garcia static const TypeInfo tpci200_info = {
6499c16fa79SAlberto Garcia     .name          = TYPE_TPCI200,
6509c16fa79SAlberto Garcia     .parent        = TYPE_PCI_DEVICE,
6519c16fa79SAlberto Garcia     .instance_size = sizeof(TPCI200State),
6529c16fa79SAlberto Garcia     .class_init    = tpci200_class_init,
653*2cd09e47SPhilippe Mathieu-Daudé     .interfaces = (const InterfaceInfo[]) {
654fd3b02c8SEduardo Habkost         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
655fd3b02c8SEduardo Habkost         { },
656fd3b02c8SEduardo Habkost     },
6579c16fa79SAlberto Garcia };
6589c16fa79SAlberto Garcia 
tpci200_register_types(void)6599c16fa79SAlberto Garcia static void tpci200_register_types(void)
6609c16fa79SAlberto Garcia {
6619c16fa79SAlberto Garcia     type_register_static(&tpci200_info);
6629c16fa79SAlberto Garcia }
6639c16fa79SAlberto Garcia 
6649c16fa79SAlberto Garcia type_init(tpci200_register_types)
665