qemu/hw/core/or-irq.c
<<
>>
Prefs
   1/*
   2 * QEMU IRQ/GPIO common code.
   3 *
   4 * Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
   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
  25#include "qemu/osdep.h"
  26#include "hw/irq.h"
  27#include "hw/or-irq.h"
  28#include "hw/qdev-properties.h"
  29#include "migration/vmstate.h"
  30#include "qemu/module.h"
  31
  32static void or_irq_handler(void *opaque, int n, int level)
  33{
  34    qemu_or_irq *s = OR_IRQ(opaque);
  35    int or_level = 0;
  36    int i;
  37
  38    s->levels[n] = level;
  39
  40    for (i = 0; i < s->num_lines; i++) {
  41        or_level |= s->levels[i];
  42    }
  43
  44    qemu_set_irq(s->out_irq, or_level);
  45}
  46
  47static void or_irq_reset(DeviceState *dev)
  48{
  49    qemu_or_irq *s = OR_IRQ(dev);
  50    int i;
  51
  52    for (i = 0; i < MAX_OR_LINES; i++) {
  53        s->levels[i] = false;
  54    }
  55}
  56
  57static void or_irq_realize(DeviceState *dev, Error **errp)
  58{
  59    qemu_or_irq *s = OR_IRQ(dev);
  60
  61    assert(s->num_lines <= MAX_OR_LINES);
  62
  63    qdev_init_gpio_in(dev, or_irq_handler, s->num_lines);
  64}
  65
  66static void or_irq_init(Object *obj)
  67{
  68    qemu_or_irq *s = OR_IRQ(obj);
  69
  70    qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1);
  71}
  72
  73/* The original version of this device had a fixed 16 entries in its
  74 * VMState array; devices with more inputs than this need to
  75 * migrate the extra lines via a subsection.
  76 * The subsection migrates as much of the levels[] array as is needed
  77 * (including repeating the first 16 elements), to avoid the awkwardness
  78 * of splitting it in two to meet the requirements of VMSTATE_VARRAY_UINT16.
  79 */
  80#define OLD_MAX_OR_LINES 16
  81#if MAX_OR_LINES < OLD_MAX_OR_LINES
  82#error MAX_OR_LINES must be at least 16 for migration compatibility
  83#endif
  84
  85static bool vmstate_extras_needed(void *opaque)
  86{
  87    qemu_or_irq *s = OR_IRQ(opaque);
  88
  89    return s->num_lines >= OLD_MAX_OR_LINES;
  90}
  91
  92static const VMStateDescription vmstate_or_irq_extras = {
  93    .name = "or-irq-extras",
  94    .version_id = 1,
  95    .minimum_version_id = 1,
  96    .needed = vmstate_extras_needed,
  97    .fields = (VMStateField[]) {
  98        VMSTATE_VARRAY_UINT16_UNSAFE(levels, qemu_or_irq, num_lines, 0,
  99                                     vmstate_info_bool, bool),
 100        VMSTATE_END_OF_LIST(),
 101    },
 102};
 103
 104static const VMStateDescription vmstate_or_irq = {
 105    .name = TYPE_OR_IRQ,
 106    .version_id = 1,
 107    .minimum_version_id = 1,
 108    .fields = (VMStateField[]) {
 109        VMSTATE_BOOL_SUB_ARRAY(levels, qemu_or_irq, 0, OLD_MAX_OR_LINES),
 110        VMSTATE_END_OF_LIST(),
 111    },
 112    .subsections = (const VMStateDescription*[]) {
 113        &vmstate_or_irq_extras,
 114        NULL
 115    },
 116};
 117
 118static Property or_irq_properties[] = {
 119    DEFINE_PROP_UINT16("num-lines", qemu_or_irq, num_lines, 1),
 120    DEFINE_PROP_END_OF_LIST(),
 121};
 122
 123static void or_irq_class_init(ObjectClass *klass, void *data)
 124{
 125    DeviceClass *dc = DEVICE_CLASS(klass);
 126
 127    dc->reset = or_irq_reset;
 128    device_class_set_props(dc, or_irq_properties);
 129    dc->realize = or_irq_realize;
 130    dc->vmsd = &vmstate_or_irq;
 131
 132    /* Reason: Needs to be wired up to work, e.g. see stm32f205_soc.c */
 133    dc->user_creatable = false;
 134}
 135
 136static const TypeInfo or_irq_type_info = {
 137   .name = TYPE_OR_IRQ,
 138   .parent = TYPE_DEVICE,
 139   .instance_size = sizeof(qemu_or_irq),
 140   .instance_init = or_irq_init,
 141   .class_init = or_irq_class_init,
 142};
 143
 144static void or_irq_register_types(void)
 145{
 146    type_register_static(&or_irq_type_info);
 147}
 148
 149type_init(or_irq_register_types)
 150