Home | History | Annotate | Download | only in hw
      1 /*
      2  *  System (CPU) Bus device support code
      3  *
      4  *  Copyright (c) 2009 CodeSourcery
      5  *
      6  * This library is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU Lesser General Public
      8  * License as published by the Free Software Foundation; either
      9  * version 2 of the License, or (at your option) any later version.
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  * You should have received a copy of the GNU Lesser General Public
     17  * License along with this library; if not, write to the Free Software
     18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
     19  */
     20 
     21 #include "sysbus.h"
     22 #include "sysemu.h"
     23 #include "monitor.h"
     24 
     25 void sysbus_connect_irq(SysBusDevice *dev, int n, qemu_irq irq)
     26 {
     27     assert(n >= 0 && n < dev->num_irq);
     28     dev->irqs[n] = 0;
     29     if (dev->irqp[n]) {
     30         *dev->irqp[n] = irq;
     31     }
     32 }
     33 
     34 void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr)
     35 {
     36     assert(n >= 0 && n < dev->num_mmio);
     37 
     38     if (dev->mmio[n].addr == addr) {
     39         /* ??? region already mapped here.  */
     40         return;
     41     }
     42     if (dev->mmio[n].addr != (target_phys_addr_t)-1) {
     43         /* Unregister previous mapping.  */
     44         cpu_register_physical_memory(dev->mmio[n].addr, dev->mmio[n].size,
     45                                      IO_MEM_UNASSIGNED);
     46     }
     47     dev->mmio[n].addr = addr;
     48     if (dev->mmio[n].cb) {
     49         dev->mmio[n].cb(dev, addr);
     50     } else {
     51         cpu_register_physical_memory(addr, dev->mmio[n].size,
     52                                      dev->mmio[n].iofunc);
     53     }
     54 }
     55 
     56 
     57 /* Request an IRQ source.  The actual IRQ object may be populated later.  */
     58 void sysbus_init_irq(SysBusDevice *dev, qemu_irq *p)
     59 {
     60     int n;
     61 
     62     assert(dev->num_irq < QDEV_MAX_IRQ);
     63     n = dev->num_irq++;
     64     dev->irqp[n] = p;
     65 }
     66 
     67 /* Pass IRQs from a target device.  */
     68 void sysbus_pass_irq(SysBusDevice *dev, SysBusDevice *target)
     69 {
     70     int i;
     71     assert(dev->num_irq == 0);
     72     dev->num_irq = target->num_irq;
     73     for (i = 0; i < dev->num_irq; i++) {
     74         dev->irqp[i] = target->irqp[i];
     75     }
     76 }
     77 
     78 void sysbus_init_mmio(SysBusDevice *dev, target_phys_addr_t size, int iofunc)
     79 {
     80     int n;
     81 
     82     assert(dev->num_mmio < QDEV_MAX_MMIO);
     83     n = dev->num_mmio++;
     84     dev->mmio[n].addr = -1;
     85     dev->mmio[n].size = size;
     86     dev->mmio[n].iofunc = iofunc;
     87 }
     88 
     89 void sysbus_init_mmio_cb(SysBusDevice *dev, target_phys_addr_t size,
     90                          mmio_mapfunc cb)
     91 {
     92     int n;
     93 
     94     assert(dev->num_mmio < QDEV_MAX_MMIO);
     95     n = dev->num_mmio++;
     96     dev->mmio[n].addr = -1;
     97     dev->mmio[n].size = size;
     98     dev->mmio[n].cb = cb;
     99 }
    100 
    101 static void sysbus_device_init(DeviceState *dev, DeviceInfo *base)
    102 {
    103     SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
    104 
    105     info->init(sysbus_from_qdev(dev));
    106 }
    107 
    108 void sysbus_register_withprop(SysBusDeviceInfo *info)
    109 {
    110     info->qdev.init = sysbus_device_init;
    111     info->qdev.bus_type = BUS_TYPE_SYSTEM;
    112 
    113     assert(info->qdev.size >= sizeof(SysBusDevice));
    114     qdev_register(&info->qdev);
    115 }
    116 
    117 void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
    118 {
    119     SysBusDeviceInfo *info;
    120 
    121     info = qemu_mallocz(sizeof(*info));
    122     info->qdev.name = qemu_strdup(name);
    123     info->qdev.size = size;
    124     info->init = init;
    125     sysbus_register_withprop(info);
    126 }
    127 
    128 DeviceState *sysbus_create_varargs(const char *name,
    129                                    target_phys_addr_t addr, ...)
    130 {
    131     DeviceState *dev;
    132     SysBusDevice *s;
    133     va_list va;
    134     qemu_irq irq;
    135     int n;
    136 
    137     dev = qdev_create(NULL, name);
    138     s = sysbus_from_qdev(dev);
    139     qdev_init(dev);
    140     if (addr != (target_phys_addr_t)-1) {
    141         sysbus_mmio_map(s, 0, addr);
    142     }
    143     va_start(va, addr);
    144     n = 0;
    145     while (1) {
    146         irq = va_arg(va, qemu_irq);
    147         if (!irq) {
    148             break;
    149         }
    150         sysbus_connect_irq(s, n, irq);
    151         n++;
    152     }
    153     return dev;
    154 }
    155 
    156 void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
    157 {
    158     SysBusDevice *s = sysbus_from_qdev(dev);
    159     int i;
    160 
    161     for (i = 0; i < s->num_mmio; i++) {
    162         monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
    163                        indent, "", s->mmio[i].addr, s->mmio[i].size);
    164     }
    165 }
    166