qemu/hw/ipmi/isa_ipmi_bt.c
<<
>>
Prefs
   1/*
   2 * QEMU ISA IPMI BT emulation
   3 *
   4 * Copyright (c) 2015 Corey Minyard, MontaVista Software, LLC
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include "qemu/osdep.h"
  25#include "qapi/error.h"
  26#include "hw/hw.h"
  27#include "hw/ipmi/ipmi.h"
  28#include "hw/isa/isa.h"
  29#include "hw/i386/pc.h"
  30
  31/* Control register */
  32#define IPMI_BT_CLR_WR_BIT         0
  33#define IPMI_BT_CLR_RD_BIT         1
  34#define IPMI_BT_H2B_ATN_BIT        2
  35#define IPMI_BT_B2H_ATN_BIT        3
  36#define IPMI_BT_SMS_ATN_BIT        4
  37#define IPMI_BT_HBUSY_BIT          6
  38#define IPMI_BT_BBUSY_BIT          7
  39
  40#define IPMI_BT_CLR_WR_MASK        (1 << IPMI_BT_CLR_WR_BIT)
  41#define IPMI_BT_GET_CLR_WR(d)      (((d) >> IPMI_BT_CLR_WR_BIT) & 0x1)
  42#define IPMI_BT_SET_CLR_WR(d, v)   (d) = (((d) & ~IPMI_BT_CLR_WR_MASK) | \
  43                                       (((v & 1) << IPMI_BT_CLR_WR_BIT)))
  44
  45#define IPMI_BT_CLR_RD_MASK        (1 << IPMI_BT_CLR_RD_BIT)
  46#define IPMI_BT_GET_CLR_RD(d)      (((d) >> IPMI_BT_CLR_RD_BIT) & 0x1)
  47#define IPMI_BT_SET_CLR_RD(d, v)   (d) = (((d) & ~IPMI_BT_CLR_RD_MASK) | \
  48                                       (((v & 1) << IPMI_BT_CLR_RD_BIT)))
  49
  50#define IPMI_BT_H2B_ATN_MASK       (1 << IPMI_BT_H2B_ATN_BIT)
  51#define IPMI_BT_GET_H2B_ATN(d)     (((d) >> IPMI_BT_H2B_ATN_BIT) & 0x1)
  52#define IPMI_BT_SET_H2B_ATN(d, v)  (d) = (((d) & ~IPMI_BT_H2B_ATN_MASK) | \
  53                                        (((v & 1) << IPMI_BT_H2B_ATN_BIT)))
  54
  55#define IPMI_BT_B2H_ATN_MASK       (1 << IPMI_BT_B2H_ATN_BIT)
  56#define IPMI_BT_GET_B2H_ATN(d)     (((d) >> IPMI_BT_B2H_ATN_BIT) & 0x1)
  57#define IPMI_BT_SET_B2H_ATN(d, v)  (d) = (((d) & ~IPMI_BT_B2H_ATN_MASK) | \
  58                                        (((v & 1) << IPMI_BT_B2H_ATN_BIT)))
  59
  60#define IPMI_BT_SMS_ATN_MASK       (1 << IPMI_BT_SMS_ATN_BIT)
  61#define IPMI_BT_GET_SMS_ATN(d)     (((d) >> IPMI_BT_SMS_ATN_BIT) & 0x1)
  62#define IPMI_BT_SET_SMS_ATN(d, v)  (d) = (((d) & ~IPMI_BT_SMS_ATN_MASK) | \
  63                                        (((v & 1) << IPMI_BT_SMS_ATN_BIT)))
  64
  65#define IPMI_BT_HBUSY_MASK         (1 << IPMI_BT_HBUSY_BIT)
  66#define IPMI_BT_GET_HBUSY(d)       (((d) >> IPMI_BT_HBUSY_BIT) & 0x1)
  67#define IPMI_BT_SET_HBUSY(d, v)    (d) = (((d) & ~IPMI_BT_HBUSY_MASK) | \
  68                                       (((v & 1) << IPMI_BT_HBUSY_BIT)))
  69
  70#define IPMI_BT_BBUSY_MASK         (1 << IPMI_BT_BBUSY_BIT)
  71#define IPMI_BT_GET_BBUSY(d)       (((d) >> IPMI_BT_BBUSY_BIT) & 0x1)
  72#define IPMI_BT_SET_BBUSY(d, v)    (d) = (((d) & ~IPMI_BT_BBUSY_MASK) | \
  73                                       (((v & 1) << IPMI_BT_BBUSY_BIT)))
  74
  75
  76/* Mask register */
  77#define IPMI_BT_B2H_IRQ_EN_BIT     0
  78#define IPMI_BT_B2H_IRQ_BIT        1
  79
  80#define IPMI_BT_B2H_IRQ_EN_MASK      (1 << IPMI_BT_B2H_IRQ_EN_BIT)
  81#define IPMI_BT_GET_B2H_IRQ_EN(d)    (((d) >> IPMI_BT_B2H_IRQ_EN_BIT) & 0x1)
  82#define IPMI_BT_SET_B2H_IRQ_EN(d, v) (d) = (((d) & ~IPMI_BT_B2H_IRQ_EN_MASK) | \
  83                                        (((v & 1) << IPMI_BT_B2H_IRQ_EN_BIT)))
  84
  85#define IPMI_BT_B2H_IRQ_MASK         (1 << IPMI_BT_B2H_IRQ_BIT)
  86#define IPMI_BT_GET_B2H_IRQ(d)       (((d) >> IPMI_BT_B2H_IRQ_BIT) & 0x1)
  87#define IPMI_BT_SET_B2H_IRQ(d, v)    (d) = (((d) & ~IPMI_BT_B2H_IRQ_MASK) | \
  88                                        (((v & 1) << IPMI_BT_B2H_IRQ_BIT)))
  89
  90typedef struct IPMIBT {
  91    IPMIBmc *bmc;
  92
  93    bool do_wake;
  94
  95    qemu_irq irq;
  96
  97    uint32_t io_base;
  98    unsigned long io_length;
  99    MemoryRegion io;
 100
 101    bool obf_irq_set;
 102    bool atn_irq_set;
 103    bool use_irq;
 104    bool irqs_enabled;
 105
 106    uint8_t outmsg[MAX_IPMI_MSG_SIZE];
 107    uint32_t outpos;
 108    uint32_t outlen;
 109
 110    uint8_t inmsg[MAX_IPMI_MSG_SIZE];
 111    uint32_t inlen;
 112
 113    uint8_t control_reg;
 114    uint8_t mask_reg;
 115
 116    /*
 117     * This is a response number that we send with the command to make
 118     * sure that the response matches the command.
 119     */
 120    uint8_t waiting_rsp;
 121    uint8_t waiting_seq;
 122} IPMIBT;
 123
 124#define IPMI_CMD_GET_BT_INTF_CAP        0x36
 125
 126static void ipmi_bt_handle_event(IPMIInterface *ii)
 127{
 128    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 129    IPMIBT *ib = iic->get_backend_data(ii);
 130
 131    if (ib->inlen < 4) {
 132        goto out;
 133    }
 134    /* Note that overruns are handled by handle_command */
 135    if (ib->inmsg[0] != (ib->inlen - 1)) {
 136        /* Length mismatch, just ignore. */
 137        IPMI_BT_SET_BBUSY(ib->control_reg, 1);
 138        ib->inlen = 0;
 139        goto out;
 140    }
 141    if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) &&
 142                        (ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) {
 143        /* We handle this one ourselves. */
 144        ib->outmsg[0] = 9;
 145        ib->outmsg[1] = ib->inmsg[1] | 0x04;
 146        ib->outmsg[2] = ib->inmsg[2];
 147        ib->outmsg[3] = ib->inmsg[3];
 148        ib->outmsg[4] = 0;
 149        ib->outmsg[5] = 1; /* Only support 1 outstanding request. */
 150        if (sizeof(ib->inmsg) > 0xff) { /* Input buffer size */
 151            ib->outmsg[6] = 0xff;
 152        } else {
 153            ib->outmsg[6] = (unsigned char) sizeof(ib->inmsg);
 154        }
 155        if (sizeof(ib->outmsg) > 0xff) { /* Output buffer size */
 156            ib->outmsg[7] = 0xff;
 157        } else {
 158            ib->outmsg[7] = (unsigned char) sizeof(ib->outmsg);
 159        }
 160        ib->outmsg[8] = 10; /* Max request to response time */
 161        ib->outmsg[9] = 0; /* Don't recommend retries */
 162        ib->outlen = 10;
 163        IPMI_BT_SET_BBUSY(ib->control_reg, 0);
 164        IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
 165        if (ib->use_irq && ib->irqs_enabled &&
 166                !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
 167                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 168            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 169            qemu_irq_raise(ib->irq);
 170        }
 171        goto out;
 172    }
 173    ib->waiting_seq = ib->inmsg[2];
 174    ib->inmsg[2] = ib->inmsg[1];
 175    {
 176        IPMIBmcClass *bk = IPMI_BMC_GET_CLASS(ib->bmc);
 177        bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2,
 178                           sizeof(ib->inmsg), ib->waiting_rsp);
 179    }
 180 out:
 181    return;
 182}
 183
 184static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id,
 185                                unsigned char *rsp, unsigned int rsp_len)
 186{
 187    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 188    IPMIBT *ib = iic->get_backend_data(ii);
 189
 190    if (ib->waiting_rsp == msg_id) {
 191        ib->waiting_rsp++;
 192        if (rsp_len > (sizeof(ib->outmsg) - 2)) {
 193            ib->outmsg[0] = 4;
 194            ib->outmsg[1] = rsp[0];
 195            ib->outmsg[2] = ib->waiting_seq;
 196            ib->outmsg[3] = rsp[1];
 197            ib->outmsg[4] = IPMI_CC_CANNOT_RETURN_REQ_NUM_BYTES;
 198            ib->outlen = 5;
 199        } else {
 200            ib->outmsg[0] = rsp_len + 1;
 201            ib->outmsg[1] = rsp[0];
 202            ib->outmsg[2] = ib->waiting_seq;
 203            memcpy(ib->outmsg + 3, rsp + 1, rsp_len - 1);
 204            ib->outlen = rsp_len + 2;
 205        }
 206        IPMI_BT_SET_BBUSY(ib->control_reg, 0);
 207        IPMI_BT_SET_B2H_ATN(ib->control_reg, 1);
 208        if (ib->use_irq && ib->irqs_enabled &&
 209                !IPMI_BT_GET_B2H_IRQ(ib->mask_reg) &&
 210                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 211            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 212            qemu_irq_raise(ib->irq);
 213        }
 214    }
 215}
 216
 217
 218static uint64_t ipmi_bt_ioport_read(void *opaque, hwaddr addr, unsigned size)
 219{
 220    IPMIInterface *ii = opaque;
 221    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 222    IPMIBT *ib = iic->get_backend_data(ii);
 223    uint32_t ret = 0xff;
 224
 225    switch (addr & 3) {
 226    case 0:
 227        ret = ib->control_reg;
 228        break;
 229    case 1:
 230        if (ib->outpos < ib->outlen) {
 231            ret = ib->outmsg[ib->outpos];
 232            ib->outpos++;
 233            if (ib->outpos == ib->outlen) {
 234                ib->outpos = 0;
 235                ib->outlen = 0;
 236            }
 237        } else {
 238            ret = 0xff;
 239        }
 240        break;
 241    case 2:
 242        ret = ib->mask_reg;
 243        break;
 244    }
 245    return ret;
 246}
 247
 248static void ipmi_bt_signal(IPMIBT *ib, IPMIInterface *ii)
 249{
 250    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 251
 252    ib->do_wake = 1;
 253    while (ib->do_wake) {
 254        ib->do_wake = 0;
 255        iic->handle_if_event(ii);
 256    }
 257}
 258
 259static void ipmi_bt_ioport_write(void *opaque, hwaddr addr, uint64_t val,
 260                                 unsigned size)
 261{
 262    IPMIInterface *ii = opaque;
 263    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 264    IPMIBT *ib = iic->get_backend_data(ii);
 265
 266    switch (addr & 3) {
 267    case 0:
 268        if (IPMI_BT_GET_CLR_WR(val)) {
 269            ib->inlen = 0;
 270        }
 271        if (IPMI_BT_GET_CLR_RD(val)) {
 272            ib->outpos = 0;
 273        }
 274        if (IPMI_BT_GET_B2H_ATN(val)) {
 275            IPMI_BT_SET_B2H_ATN(ib->control_reg, 0);
 276        }
 277        if (IPMI_BT_GET_SMS_ATN(val)) {
 278            IPMI_BT_SET_SMS_ATN(ib->control_reg, 0);
 279        }
 280        if (IPMI_BT_GET_HBUSY(val)) {
 281            /* Toggle */
 282            IPMI_BT_SET_HBUSY(ib->control_reg,
 283                              !IPMI_BT_GET_HBUSY(ib->control_reg));
 284        }
 285        if (IPMI_BT_GET_H2B_ATN(val)) {
 286            IPMI_BT_SET_BBUSY(ib->control_reg, 1);
 287            ipmi_bt_signal(ib, ii);
 288        }
 289        break;
 290
 291    case 1:
 292        if (ib->inlen < sizeof(ib->inmsg)) {
 293            ib->inmsg[ib->inlen] = val;
 294        }
 295        ib->inlen++;
 296        break;
 297
 298    case 2:
 299        if (IPMI_BT_GET_B2H_IRQ_EN(val) !=
 300                        IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 301            if (IPMI_BT_GET_B2H_IRQ_EN(val)) {
 302                if (IPMI_BT_GET_B2H_ATN(ib->control_reg) ||
 303                        IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
 304                    IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 305                    qemu_irq_raise(ib->irq);
 306                }
 307                IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 1);
 308            } else {
 309                if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 310                    IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 311                    qemu_irq_lower(ib->irq);
 312                }
 313                IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
 314            }
 315        }
 316        if (IPMI_BT_GET_B2H_IRQ(val) && IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 317            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 318            qemu_irq_lower(ib->irq);
 319        }
 320        break;
 321    }
 322}
 323
 324static const MemoryRegionOps ipmi_bt_io_ops = {
 325    .read = ipmi_bt_ioport_read,
 326    .write = ipmi_bt_ioport_write,
 327    .impl = {
 328        .min_access_size = 1,
 329        .max_access_size = 1,
 330    },
 331    .endianness = DEVICE_LITTLE_ENDIAN,
 332};
 333
 334static void ipmi_bt_set_atn(IPMIInterface *ii, int val, int irq)
 335{
 336    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 337    IPMIBT *ib = iic->get_backend_data(ii);
 338
 339    if (!!val == IPMI_BT_GET_SMS_ATN(ib->control_reg)) {
 340        return;
 341    }
 342
 343    IPMI_BT_SET_SMS_ATN(ib->control_reg, val);
 344    if (val) {
 345        if (irq && ib->use_irq && ib->irqs_enabled &&
 346                !IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
 347                IPMI_BT_GET_B2H_IRQ_EN(ib->mask_reg)) {
 348            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1);
 349            qemu_irq_raise(ib->irq);
 350        }
 351    } else {
 352        if (!IPMI_BT_GET_B2H_ATN(ib->control_reg) &&
 353                IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 354            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 355            qemu_irq_lower(ib->irq);
 356        }
 357    }
 358}
 359
 360static void ipmi_bt_handle_reset(IPMIInterface *ii, bool is_cold)
 361{
 362    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 363    IPMIBT *ib = iic->get_backend_data(ii);
 364
 365    if (is_cold) {
 366        /* Disable the BT interrupt on reset */
 367        if (IPMI_BT_GET_B2H_IRQ(ib->mask_reg)) {
 368            IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 0);
 369            qemu_irq_lower(ib->irq);
 370        }
 371        IPMI_BT_SET_B2H_IRQ_EN(ib->mask_reg, 0);
 372    }
 373}
 374
 375static void ipmi_bt_set_irq_enable(IPMIInterface *ii, int val)
 376{
 377    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 378    IPMIBT *ib = iic->get_backend_data(ii);
 379
 380    ib->irqs_enabled = val;
 381}
 382
 383static void ipmi_bt_init(IPMIInterface *ii, Error **errp)
 384{
 385    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 386    IPMIBT *ib = iic->get_backend_data(ii);
 387
 388    ib->io_length = 3;
 389
 390    memory_region_init_io(&ib->io, NULL, &ipmi_bt_io_ops, ii, "ipmi-bt", 3);
 391}
 392
 393static void ipmi_bt_class_init(IPMIInterfaceClass *iic)
 394{
 395    iic->init = ipmi_bt_init;
 396    iic->set_atn = ipmi_bt_set_atn;
 397    iic->handle_rsp = ipmi_bt_handle_rsp;
 398    iic->handle_if_event = ipmi_bt_handle_event;
 399    iic->set_irq_enable = ipmi_bt_set_irq_enable;
 400    iic->reset = ipmi_bt_handle_reset;
 401}
 402
 403
 404#define TYPE_ISA_IPMI_BT "isa-ipmi-bt"
 405#define ISA_IPMI_BT(obj) OBJECT_CHECK(ISAIPMIBTDevice, (obj), \
 406                                       TYPE_ISA_IPMI_BT)
 407
 408typedef struct ISAIPMIBTDevice {
 409    ISADevice dev;
 410    int32_t isairq;
 411    IPMIBT bt;
 412    IPMIFwInfo fwinfo;
 413} ISAIPMIBTDevice;
 414
 415static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp)
 416{
 417    ISADevice *isadev = ISA_DEVICE(dev);
 418    ISAIPMIBTDevice *iib = ISA_IPMI_BT(dev);
 419    IPMIInterface *ii = IPMI_INTERFACE(dev);
 420    IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii);
 421
 422    if (!iib->bt.bmc) {
 423        error_setg(errp, "IPMI device requires a bmc attribute to be set");
 424        return;
 425    }
 426
 427    iib->bt.bmc->intf = ii;
 428
 429    iic->init(ii, errp);
 430    if (*errp)
 431        return;
 432
 433    if (iib->isairq > 0) {
 434        isa_init_irq(isadev, &iib->bt.irq, iib->isairq);
 435        iib->bt.use_irq = 1;
 436    }
 437
 438    qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length);
 439
 440    isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base);
 441
 442    iib->fwinfo.interface_name = "bt";
 443    iib->fwinfo.interface_type = IPMI_SMBIOS_BT;
 444    iib->fwinfo.ipmi_spec_major_revision = 2;
 445    iib->fwinfo.ipmi_spec_minor_revision = 0;
 446    iib->fwinfo.base_address = iib->bt.io_base;
 447    iib->fwinfo.register_length = iib->bt.io_length;
 448    iib->fwinfo.register_spacing = 1;
 449    iib->fwinfo.memspace = IPMI_MEMSPACE_IO;
 450    iib->fwinfo.irq_type = IPMI_LEVEL_IRQ;
 451    iib->fwinfo.interrupt_number = iib->isairq;
 452    iib->fwinfo.acpi_parent = "\\_SB.PCI0.ISA";
 453    iib->fwinfo.i2c_slave_address = iib->bt.bmc->slave_addr;
 454    ipmi_add_fwinfo(&iib->fwinfo, errp);
 455}
 456
 457static const VMStateDescription vmstate_ISAIPMIBTDevice = {
 458    .name = TYPE_IPMI_INTERFACE,
 459    .version_id = 1,
 460    .minimum_version_id = 1,
 461    .fields      = (VMStateField[]) {
 462        VMSTATE_BOOL(bt.obf_irq_set, ISAIPMIBTDevice),
 463        VMSTATE_BOOL(bt.atn_irq_set, ISAIPMIBTDevice),
 464        VMSTATE_BOOL(bt.use_irq, ISAIPMIBTDevice),
 465        VMSTATE_BOOL(bt.irqs_enabled, ISAIPMIBTDevice),
 466        VMSTATE_UINT32(bt.outpos, ISAIPMIBTDevice),
 467        VMSTATE_VBUFFER_UINT32(bt.outmsg, ISAIPMIBTDevice, 1, NULL, 0,
 468                               bt.outlen),
 469        VMSTATE_VBUFFER_UINT32(bt.inmsg, ISAIPMIBTDevice, 1, NULL, 0,
 470                               bt.inlen),
 471        VMSTATE_UINT8(bt.control_reg, ISAIPMIBTDevice),
 472        VMSTATE_UINT8(bt.mask_reg, ISAIPMIBTDevice),
 473        VMSTATE_UINT8(bt.waiting_rsp, ISAIPMIBTDevice),
 474        VMSTATE_UINT8(bt.waiting_seq, ISAIPMIBTDevice),
 475        VMSTATE_END_OF_LIST()
 476    }
 477};
 478
 479static void isa_ipmi_bt_init(Object *obj)
 480{
 481    ISAIPMIBTDevice *iib = ISA_IPMI_BT(obj);
 482
 483    ipmi_bmc_find_and_link(obj, (Object **) &iib->bt.bmc);
 484
 485    vmstate_register(NULL, 0, &vmstate_ISAIPMIBTDevice, iib);
 486}
 487
 488static void *isa_ipmi_bt_get_backend_data(IPMIInterface *ii)
 489{
 490    ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii);
 491
 492    return &iib->bt;
 493}
 494
 495static Property ipmi_isa_properties[] = {
 496    DEFINE_PROP_UINT32("ioport", ISAIPMIBTDevice, bt.io_base,  0xe4),
 497    DEFINE_PROP_INT32("irq",   ISAIPMIBTDevice, isairq,  5),
 498    DEFINE_PROP_END_OF_LIST(),
 499};
 500
 501static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data)
 502{
 503    DeviceClass *dc = DEVICE_CLASS(oc);
 504    IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc);
 505
 506    dc->realize = isa_ipmi_bt_realize;
 507    dc->props = ipmi_isa_properties;
 508
 509    iic->get_backend_data = isa_ipmi_bt_get_backend_data;
 510    ipmi_bt_class_init(iic);
 511}
 512
 513static const TypeInfo isa_ipmi_bt_info = {
 514    .name          = TYPE_ISA_IPMI_BT,
 515    .parent        = TYPE_ISA_DEVICE,
 516    .instance_size = sizeof(ISAIPMIBTDevice),
 517    .instance_init = isa_ipmi_bt_init,
 518    .class_init    = isa_ipmi_bt_class_init,
 519    .interfaces = (InterfaceInfo[]) {
 520        { TYPE_IPMI_INTERFACE },
 521        { }
 522    }
 523};
 524
 525static void ipmi_register_types(void)
 526{
 527    type_register_static(&isa_ipmi_bt_info);
 528}
 529
 530type_init(ipmi_register_types)
 531