sysbus.c 4.5 KB
Newer Older
P
Paul Brook 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 *  System (CPU) Bus device support code
 *
 *  Copyright (c) 2009 CodeSourcery
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
P
Paul Brook 已提交
18 19 20 21
 */

#include "sysbus.h"
#include "sysemu.h"
22
#include "monitor.h"
P
Paul Brook 已提交
23

24 25 26 27 28 29 30 31
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent);

struct BusInfo system_bus_info = {
    .name       = "System",
    .size       = sizeof(BusState),
    .print_dev  = sysbus_dev_print,
};

P
Paul Brook 已提交
32 33 34
void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
{
    assert(n >= 0 && n < dev->num_irq);
35
    dev->irqs[n] = NULL;
P
Paul Brook 已提交
36 37 38 39 40
    if (dev->irqp[n]) {
        *dev->irqp[n] = irq;
    }
}

A
Anthony Liguori 已提交
41
void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
P
Paul Brook 已提交
42 43 44 45 46 47 48
{
    assert(n >= 0 && n < dev->num_mmio);

    if (dev->mmio[n].addr == addr) {
        /* ??? region already mapped here.  */
        return;
    }
A
Anthony Liguori 已提交
49
    if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
P
Paul Brook 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
        /* Unregister previous mapping.  */
        cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
                                     IO_MEM_UNASSIGNED);
    }
    dev->mmio[n].addr = addr;
    if (dev->mmio[n].cb) {
        dev->mmio[n].cb(dev, addr);
    } else {
        cpu_register_physical_memory(addr, dev->mmio[n].size,
                                     dev->mmio[n].iofunc);
    }
}


/* Request an IRQ source.  The actual IRQ object may be populated later.  */
void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
{
    int n;

    assert(dev->num_irq < QDEV_MAX_IRQ);
    n = dev->num_irq++;
    dev->irqp[n] = p;
}

/* Pass IRQs from a target device.  */
void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
{
    int i;
    assert(dev->num_irq == 0);
    dev->num_irq = target->num_irq;
    for (i = 0; i < dev->num_irq; i++) {
        dev->irqp[i] = target->irqp[i];
    }
}

A
Anthony Liguori 已提交
85
void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc)
P
Paul Brook 已提交
86 87 88 89 90 91 92 93 94 95
{
    int n;

    assert(dev->num_mmio < QDEV_MAX_MMIO);
    n = dev->num_mmio++;
    dev->mmio[n].addr = -1;
    dev->mmio[n].size = size;
    dev->mmio[n].iofunc = iofunc;
}

A
Anthony Liguori 已提交
96
void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
P
Paul Brook 已提交
97 98 99 100 101 102 103 104 105 106 107
                         mmio_mapfunc cb)
{
    int n;

    assert(dev->num_mmio < QDEV_MAX_MMIO);
    n = dev->num_mmio++;
    dev->mmio[n].addr = -1;
    dev->mmio[n].size = size;
    dev->mmio[n].cb = cb;
}

108
static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
P
Paul Brook 已提交
109
{
P
Paul Brook 已提交
110
    SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
P
Paul Brook 已提交
111

112
    return info->init(sysbus_from_qdev(dev));
P
Paul Brook 已提交
113 114
}

115
void sysbus_register_withprop(SysBusDeviceInfo *info)
P
Paul Brook 已提交
116
{
P
Paul Brook 已提交
117
    info->qdev.init = sysbus_device_init;
118
    info->qdev.bus_info = &system_bus_info;
P
Paul Brook 已提交
119

120 121
    assert(info->qdev.size >= sizeof(SysBusDevice));
    qdev_register(&info->qdev);
P
Paul Brook 已提交
122 123
}

P
Paul Brook 已提交
124 125 126 127 128
void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
{
    SysBusDeviceInfo *info;

    info = qemu_mallocz(sizeof(*info));
129 130
    info->qdev.name = qemu_strdup(name);
    info->qdev.size = size;
P
Paul Brook 已提交
131
    info->init = init;
132
    sysbus_register_withprop(info);
P
Paul Brook 已提交
133 134
}

P
Paul Brook 已提交
135
DeviceState *sysbus_create_varargs(const char *name,
A
Anthony Liguori 已提交
136
                                   target_phys_addr_t addr, ...)
P
Paul Brook 已提交
137 138 139 140 141 142 143 144 145 146
{
    DeviceState *dev;
    SysBusDevice *s;
    va_list va;
    qemu_irq irq;
    int n;

    dev = qdev_create(NULL, name);
    s = sysbus_from_qdev(dev);
    qdev_init(dev);
A
Anthony Liguori 已提交
147
    if (addr != (target_phys_addr_t)-1) {
P
Paul Brook 已提交
148 149 150 151 152 153 154 155 156 157 158 159 160 161
        sysbus_mmio_map(s, 0, addr);
    }
    va_start(va, addr);
    n = 0;
    while (1) {
        irq = va_arg(va, qemu_irq);
        if (!irq) {
            break;
        }
        sysbus_connect_irq(s, n, irq);
        n++;
    }
    return dev;
}
162

163
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
164 165 166 167 168 169 170 171 172
{
    SysBusDevice *s = sysbus_from_qdev(dev);
    int i;

    for (i = 0; i < s->num_mmio; i++) {
        monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
                       indent, "", s->mmio[i].addr, s->mmio[i].size);
    }
}