qemu/hw/core/fdt_generic_util.c
<<
>>
Prefs
   1/*
   2 * Utility functions for fdt generic framework
   3 *
   4 * Copyright (c) 2009 Edgar E. Iglesias.
   5 * Copyright (c) 2009 Michal Simek.
   6 * Copyright (c) 2011 PetaLogix Qld Pty Ltd.
   7 * Copyright (c) 2011 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>.
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "hw/fdt_generic_util.h"
  30#include "hw/fdt_generic_devices.h"
  31#include "net/net.h"
  32#include "exec/memory.h"
  33#include "exec/address-spaces.h"
  34#include "hw/sysbus.h"
  35#include "qapi/error.h"
  36#include "sysemu/sysemu.h"
  37#include "qemu/log.h"
  38#include "qom/cpu.h"
  39
  40#ifndef FDT_GENERIC_UTIL_ERR_DEBUG
  41#define FDT_GENERIC_UTIL_ERR_DEBUG 3
  42#endif
  43#define DB_PRINT(lvl, ...) do { \
  44    if (FDT_GENERIC_UTIL_ERR_DEBUG > (lvl)) { \
  45        qemu_log_mask(LOG_FDT, ": %s: ", __func__); \
  46        qemu_log_mask(LOG_FDT, ## __VA_ARGS__); \
  47    } \
  48} while (0);
  49
  50#define DB_PRINT_NP(lvl, ...) do { \
  51    if (FDT_GENERIC_UTIL_ERR_DEBUG > (lvl)) { \
  52       qemu_log_mask(LOG_FDT, "%s", node_path); \
  53       DB_PRINT((lvl), ## __VA_ARGS__); \
  54    } \
  55} while (0);
  56
  57#include "hw/remote-port-device.h"
  58
  59/* FIXME: wrap direct calls into libfdt */
  60
  61#include <libfdt.h>
  62#include <stdlib.h>
  63
  64static int simple_bus_fdt_init(char *bus_node_path, FDTMachineInfo *fdti);
  65
  66typedef struct QEMUIRQSharedState {
  67    qemu_irq sink;
  68    int num;
  69    bool (*merge_fn)(bool *, int);
  70/* FIXME: remove artificial limit */
  71#define MAX_IRQ_SHARED_INPUTS 128
  72    bool inputs[MAX_IRQ_SHARED_INPUTS];
  73} QEMUIRQSharedState;
  74
  75static bool qemu_irq_shared_or_handler(bool *inputs, int n)
  76{
  77    int i;
  78
  79    assert(n < MAX_IRQ_SHARED_INPUTS);
  80
  81    for (i = 0; i < n; ++i) {
  82        if (inputs[i]) {
  83            return true;
  84        }
  85    }
  86    return false;
  87}
  88
  89static bool qemu_irq_shared_and_handler(bool *inputs, int n)
  90{
  91    int i;
  92
  93    assert(n < MAX_IRQ_SHARED_INPUTS);
  94
  95    for (i = 0; i < n; ++i) {
  96        if (!inputs[i]) {
  97            return false;
  98        }
  99    }
 100    return true;
 101}
 102
 103static void qemu_irq_shared_handler(void *opaque, int n, int level)
 104{
 105    QEMUIRQSharedState *s = opaque;
 106
 107    assert(n < MAX_IRQ_SHARED_INPUTS);
 108    s->inputs[n] = level;
 109    qemu_set_irq(s->sink, s->merge_fn(s->inputs, s->num));
 110}
 111
 112static void fdt_init_all_irqs(FDTMachineInfo *fdti)
 113{
 114    while (fdti->irqs) {
 115        FDTIRQConnection *first = fdti->irqs;
 116        qemu_irq sink = first->irq;
 117        bool (*merge_fn)(bool *, int) = first->merge_fn;
 118        int num_sources = 0;
 119        FDTIRQConnection *irq;
 120
 121        for (irq = first; irq; irq = irq->next) {
 122            if (irq->irq == sink) { /* Same sink */
 123                num_sources++;
 124            }
 125        }
 126        if (num_sources > 1) {
 127            QEMUIRQSharedState *s = g_malloc0(sizeof *s);
 128            s->sink = sink;
 129            s->merge_fn = merge_fn;
 130            qemu_irq *sources = qemu_allocate_irqs(qemu_irq_shared_handler, s,
 131                                                   num_sources);
 132            for (irq = first; irq; irq = irq->next) {
 133                if (irq->irq == sink) {
 134                    char *shared_irq_name = g_strdup_printf("shared-irq-%p",
 135                                                            *sources);
 136
 137                    if (irq->merge_fn != merge_fn) {
 138                        fprintf(stderr, "ERROR: inconsistent IRQ merge fns\n");
 139                        exit(1);
 140                    }
 141
 142                    object_property_add_child(OBJECT(irq->dev), shared_irq_name,
 143                                              OBJECT(*sources), &error_abort);
 144                    g_free(shared_irq_name);
 145                    irq->irq = *(sources++);
 146                    s->num++;
 147                }
 148            }
 149        }
 150        DB_PRINT(0, "%s: connected to %s irq line %d (%s)\n",
 151                 first->sink_info ? first->sink_info : "",
 152                 object_get_canonical_path(OBJECT(first->dev)),
 153                 first->i, first->name ? first->name : "");
 154
 155        qdev_connect_gpio_out_named(DEVICE(first->dev), first->name, first->i,
 156                                    first->irq);
 157        fdti->irqs = first->next;
 158        g_free(first);
 159    }
 160}
 161
 162FDTMachineInfo *fdt_generic_create_machine(void *fdt, qemu_irq *cpu_irq)
 163{
 164    char node_path[DT_PATH_LENGTH];
 165
 166    FDTMachineInfo *fdti = fdt_init_new_fdti(fdt);
 167
 168    fdti->irq_base = cpu_irq;
 169
 170    /* parse the device tree */
 171    if (!qemu_devtree_get_root_node(fdt, node_path)) {
 172        memory_region_transaction_begin();
 173        fdt_init_set_opaque(fdti, node_path, NULL);
 174        simple_bus_fdt_init(node_path, fdti);
 175        while (qemu_co_enter_next(fdti->cq));
 176        fdt_init_all_irqs(fdti);
 177        memory_region_transaction_commit();
 178    } else {
 179        fprintf(stderr, "FDT: ERROR: cannot get root node from device tree %s\n"
 180            , node_path);
 181    }
 182
 183    DB_PRINT(0, "FDT: Device tree scan complete\n");
 184    FDTMachineInfo *ret = g_malloc0(sizeof(*ret));
 185    return fdti;
 186}
 187
 188struct FDTInitNodeArgs {
 189    char *node_path;
 190    char *parent_path;
 191    FDTMachineInfo *fdti;
 192};
 193
 194static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat);
 195
 196static void fdt_init_node(void *args)
 197{
 198    struct FDTInitNodeArgs *a = args;
 199    char *node_path = a->node_path;
 200    FDTMachineInfo *fdti = a->fdti;
 201    g_free(a);
 202
 203    simple_bus_fdt_init(node_path, fdti);
 204
 205    char *all_compats = NULL, *compat, *node_name, *next_compat;
 206    char *device_type = NULL;
 207    int compat_len;
 208
 209    DB_PRINT_NP(1, "enter\n");
 210
 211    /* try instance binding first */
 212    node_name = qemu_devtree_get_node_name(fdti->fdt, node_path);
 213    DB_PRINT_NP(1, "node with name: %s\n", node_name ? node_name : "(none)");
 214    if (!node_name) {
 215        printf("FDT: ERROR: nameless node: %s\n", node_path);
 216    }
 217    if (!fdt_init_inst_bind(node_path, fdti, node_name)) {
 218        DB_PRINT_NP(0, "instance bind successful\n");
 219        goto exit;
 220    }
 221
 222    /* fallback to compatibility binding */
 223    all_compats = qemu_fdt_getprop(fdti->fdt, node_path, "compatible",
 224                                   &compat_len, false, NULL);
 225    if (!all_compats) {
 226        DB_PRINT_NP(0, "no compatibility found\n");
 227    }
 228
 229    for (compat = all_compats; compat && compat_len; compat = next_compat+1) {
 230        char *compat_prefixed = g_strdup_printf("compatible:%s", compat);
 231        if (!fdt_init_compat(node_path, fdti, compat_prefixed)) {
 232            goto exit;
 233        }
 234        g_free(compat_prefixed);
 235        if (!fdt_init_qdev(node_path, fdti, compat)) {
 236            goto exit;
 237        }
 238        next_compat = rawmemchr(compat, '\0');
 239        compat_len -= (next_compat + 1 - compat);
 240        if (compat_len > 0) {
 241            *next_compat = ' ';
 242        }
 243    }
 244
 245    device_type = qemu_fdt_getprop(fdti->fdt, node_path,
 246                                   "device_type", NULL, false, NULL);
 247    device_type = g_strdup_printf("device_type:%s", device_type);
 248    if (!fdt_init_compat(node_path, fdti, device_type)) {
 249        goto exit;
 250    }
 251
 252    /* Try to create the device using device_type property
 253     * Not every device tree node has compatible  property, so
 254     * try with device_type.
 255     */
 256    if (!fdt_init_qdev(node_path, fdti, device_type)) {
 257        goto exit;
 258    }
 259
 260    if (!all_compats) {
 261        goto exit;
 262    }
 263    DB_PRINT_NP(0, "FDT: Unsupported peripheral invalidated - "
 264                "compatibilities %s\n", all_compats);
 265    qemu_fdt_setprop_string(fdti->fdt, node_path, "compatible", "invalidated");
 266exit:
 267
 268    DB_PRINT_NP(1, "exit\n");
 269
 270    if (!fdt_init_has_opaque(fdti, node_path)) {
 271        fdt_init_set_opaque(fdti, node_path, NULL);
 272    }
 273    g_free(node_path);
 274    g_free(all_compats);
 275    g_free(device_type);
 276    return;
 277}
 278
 279static int simple_bus_fdt_init(char *node_path, FDTMachineInfo *fdti)
 280{
 281    int i;
 282    int num_children = qemu_devtree_get_num_children(fdti->fdt, node_path,
 283                                                        1);
 284    char **children = qemu_devtree_get_children(fdti->fdt, node_path, 1);
 285
 286    DB_PRINT_NP(num_children ? 0 : 1, "num child devices: %d\n", num_children);
 287
 288    for (i = 0; i < num_children; i++) {
 289        struct FDTInitNodeArgs *init_args = g_malloc0(sizeof(*init_args));
 290        init_args->node_path = children[i];
 291        init_args->fdti = fdti;
 292        qemu_coroutine_enter(qemu_coroutine_create(fdt_init_node), init_args);
 293    }
 294
 295    g_free(children);
 296    return 0;
 297}
 298
 299static qemu_irq fdt_get_gpio(FDTMachineInfo *fdti, char *node_path,
 300                             int* cur_cell, qemu_irq input,
 301                             const FDTGenericGPIOSet *gpio_set,
 302                             const char *debug_success, bool *end) {
 303    void *fdt = fdti->fdt;
 304    uint32_t parent_phandle, parent_cells = 0, cells[32];
 305    char parent_node_path[DT_PATH_LENGTH];
 306    DeviceState *parent;
 307    int i;
 308    Error *errp = NULL;
 309    const char *reason;
 310    bool free_reason = false;
 311    const char *propname = gpio_set->names->propname;
 312    const char *cells_propname = gpio_set->names->cells_propname;
 313
 314    cells[0] = 0;
 315
 316    parent_phandle = qemu_fdt_getprop_cell(fdt, node_path, propname,
 317                                           (*cur_cell)++, false, &errp);
 318    if (errp) {
 319        reason = g_strdup_printf("Cant get phandle from \"%s\" property\n",
 320                                 propname);
 321        *end = true;
 322        free_reason = true;
 323        goto fail_silent;
 324    }
 325    if (qemu_devtree_get_node_by_phandle(fdt, parent_node_path,
 326                                         parent_phandle)) {
 327        *end = true;
 328        reason = "cant get node from phandle\n";
 329        goto fail;
 330    }
 331    parent_cells = qemu_fdt_getprop_cell(fdt, parent_node_path,
 332                                         cells_propname, 0, false, &errp);
 333    if (errp) {
 334        *end = true;
 335        reason = g_strdup_printf("cant get the property \"%s\" from the " \
 336                                 "parent \"%s\"\n",
 337                                 cells_propname, parent_node_path);
 338        free_reason = true;
 339        goto fail;
 340    }
 341
 342    for (i = 0; i < parent_cells; ++i) {
 343        cells[i] = qemu_fdt_getprop_cell(fdt, node_path, propname,
 344                                         (*cur_cell)++, false, &errp);
 345        if (errp) {
 346            *end = true;
 347            reason = "cant get cell value";
 348            goto fail;
 349        }
 350    }
 351
 352    while (!fdt_init_has_opaque(fdti, parent_node_path)) {
 353        fdt_init_yield(fdti);
 354    }
 355    parent = DEVICE(fdt_init_get_opaque(fdti, parent_node_path));
 356
 357    if (!parent) {
 358        reason = "parent is not a device";
 359        goto fail_silent;
 360    }
 361
 362    while (!parent->realized) {
 363        fdt_init_yield(fdti);
 364    }
 365
 366    {
 367        const FDTGenericGPIOConnection *fgg_con = NULL;
 368        uint16_t range, idx;
 369        const char *gpio_name = NULL;
 370        qemu_irq ret;
 371
 372        if (object_dynamic_cast(OBJECT(parent), TYPE_FDT_GENERIC_GPIO)) {
 373            const FDTGenericGPIOSet *set;
 374            FDTGenericGPIOClass *parent_fggc =
 375                        FDT_GENERIC_GPIO_GET_CLASS(parent);
 376
 377            for (set = parent_fggc->controller_gpios; set && set->names;
 378                 set++) {
 379                if (!strcmp(gpio_set->names->cells_propname,
 380                            set->names->cells_propname)) {
 381                    fgg_con = set->gpios;
 382                    break;
 383                }
 384            }
 385        }
 386
 387        /* FIXME: cells[0] is not always the fdt indexing match system */
 388        idx = cells[0] & ~(1ul << 31);
 389        if (fgg_con) {
 390            range = fgg_con->range ? fgg_con->range : 1;
 391            while (!(idx >= fgg_con->fdt_index
 392                     && idx < (fgg_con->fdt_index + range))
 393                   && fgg_con->name) {
 394                fgg_con++;
 395            }
 396            if (!fgg_con) {
 397                goto fail;
 398            }
 399
 400            idx -= fgg_con->fdt_index;
 401            gpio_name = fgg_con->name;
 402        }
 403
 404        if (input) {
 405            FDTIRQConnection *irq = g_new0(FDTIRQConnection, 1);
 406            bool (*merge_fn)(bool *, int) = qemu_irq_shared_or_handler;
 407
 408            /* FIXME: I am kind of stealing here. Use the msb of the first
 409             * cell to indicate the merge function. This needs to be discussed
 410             * with device-tree community on how this should be done properly.
 411             */
 412            if (cells[0] & (1 << 31)) {
 413                merge_fn = qemu_irq_shared_and_handler;
 414            }
 415
 416            DB_PRINT_NP(1, "%s GPIO output %s[%d] on %s\n", debug_success,
 417                        gpio_name ? gpio_name : "unnamed", idx,
 418                        parent_node_path);
 419            *irq = (FDTIRQConnection) {
 420                .dev = parent,
 421                .name = gpio_name,
 422                .merge_fn = merge_fn,
 423                .i = idx,
 424                .irq = input,
 425                .sink_info = NULL, /* FIMXE */
 426                .next = fdti->irqs
 427            };
 428            fdti->irqs = irq;
 429        }
 430        ret = qdev_get_gpio_in_named(parent, gpio_name, idx);
 431
 432        if (ret) {
 433            DB_PRINT_NP(1, "wiring GPIO input %s on %s ... \n",
 434                        fgg_con ? fgg_con->name : "unnamed", parent_node_path);
 435        }
 436        return ret;
 437    }
 438fail:
 439    fprintf(stderr, "%s Failed: %s\n", node_path, reason);
 440fail_silent:
 441    if (free_reason) {
 442        g_free((void *)reason);
 443    }
 444    return NULL;
 445}
 446
 447static void fdt_get_irq_info_from_intc(FDTMachineInfo *fdti, qemu_irq *ret,
 448                                       char *intc_node_path,
 449                                       uint32_t *cells, uint32_t num_cells,
 450                                       uint32_t max, Error **errp)
 451{
 452    FDTGenericIntcClass *intc_fdt_class;
 453    DeviceState *intc;
 454
 455    while (!fdt_init_has_opaque(fdti, intc_node_path)) {
 456        fdt_init_yield(fdti);
 457    }
 458    intc = DEVICE(fdt_init_get_opaque(fdti, intc_node_path));
 459
 460    if (!intc) {
 461        goto fail;
 462    }
 463
 464    while (!intc->realized) {
 465        fdt_init_yield(fdti);
 466    }
 467
 468    intc_fdt_class = FDT_GENERIC_INTC_GET_CLASS(intc);
 469    if (!intc_fdt_class) {
 470        goto fail;
 471    }
 472
 473    intc_fdt_class->get_irq(FDT_GENERIC_INTC(intc), ret, cells, num_cells,
 474                            max, errp);
 475
 476    return;
 477fail:
 478    error_setg(errp, "%s", __func__);
 479}
 480
 481static uint32_t imap_cache[4096];
 482static bool imap_cached = false;
 483
 484qemu_irq *fdt_get_irq_info(FDTMachineInfo *fdti, char *node_path, int irq_idx,
 485                          char *info, bool *map_mode) {
 486    void *fdt = fdti->fdt;
 487    uint32_t intc_phandle, intc_cells, cells[32];
 488    char intc_node_path[DT_PATH_LENGTH];
 489    qemu_irq *ret = NULL;
 490    int i;
 491    Error *errp = NULL;
 492
 493    intc_phandle = qemu_fdt_getprop_cell(fdt, node_path, "interrupt-parent",
 494                                         0, true, &errp);
 495    if (errp) {
 496        errp = NULL;
 497        intc_cells = qemu_fdt_getprop_cell(fdt, node_path,
 498                                           "#interrupt-cells", 0, true, &errp);
 499        *map_mode = true;
 500    } else {
 501        if (qemu_devtree_get_node_by_phandle(fdt, intc_node_path,
 502                                             intc_phandle)) {
 503            goto fail;
 504        }
 505
 506        /* Check if the device is using interrupt-maps */
 507        qemu_fdt_getprop_cell(fdt, node_path, "interrupt-map-mask", 0,
 508                              false, &errp);
 509        if (!errp) {
 510            errp = NULL;
 511            intc_cells = qemu_fdt_getprop_cell(fdt, node_path,
 512                                               "#interrupt-cells", 0,
 513                                               true, &errp);
 514            *map_mode = true;
 515        } else {
 516            errp = NULL;
 517            intc_cells = qemu_fdt_getprop_cell(fdt, intc_node_path,
 518                                               "#interrupt-cells", 0,
 519                                               true, &errp);
 520            *map_mode = false;
 521        }
 522    }
 523
 524    if (errp) {
 525        goto fail;
 526    }
 527
 528    DB_PRINT_NP(2, "%s intc_phandle: %d\n", node_path, intc_phandle);
 529
 530    for (i = 0; i < intc_cells; ++i) {
 531        cells[i] = qemu_fdt_getprop_cell(fdt, node_path, "interrupts",
 532                                         intc_cells * irq_idx + i, false, &errp);
 533        if (errp) {
 534            goto fail;
 535        }
 536    }
 537
 538    if (*map_mode) {
 539        int k;
 540        ret = g_new0(qemu_irq, 1);
 541        int num_matches = 0;
 542        int len;
 543        uint32_t imap_mask[intc_cells];
 544        uint32_t *imap_p;
 545        uint32_t *imap;
 546        bool use_parent = false;
 547
 548        for (k = 0; k < intc_cells; ++k) {
 549            imap_mask[k] = qemu_fdt_getprop_cell(fdt, node_path,
 550                                                 "interrupt-map-mask", k + 2,
 551                                                 true, &errp);
 552            if (errp) {
 553                goto fail;
 554            }
 555        }
 556
 557        /* Check if the device has an interrupt-map property */
 558        imap = qemu_fdt_getprop(fdt, node_path, "interrupt-map", &len,
 559                                  use_parent, &errp);
 560
 561        if (!imap || errp) {
 562            /* If the device doesn't have an interrupt-map, try again with
 563             * inheritance. This will return the parents interrupt-map
 564             */
 565            use_parent = true;
 566            errp = NULL;
 567
 568            imap_p = qemu_fdt_getprop(fdt, node_path, "interrupt-map",
 569                                      &len, use_parent, &errp);
 570            if (!imap_cached) {
 571                memcpy(imap_cache, imap_p, len);
 572                imap_cached = true;
 573            }
 574            imap = imap_cache;
 575
 576            if (errp) {
 577                goto fail;
 578            }
 579        }
 580
 581        len /= sizeof(uint32_t);
 582
 583        i = 0;
 584        assert(imap);
 585        while (i < len) {
 586            if (!use_parent) {
 587                /* Only re-sync the interrupt-map when the device has it's
 588                 * own map, to save time.
 589                 */
 590                imap = qemu_fdt_getprop(fdt, node_path, "interrupt-map", &len,
 591                                          use_parent, &errp);
 592
 593                if (errp) {
 594                    goto fail;
 595                }
 596
 597                len /= sizeof(uint32_t);
 598            }
 599
 600            bool match = true;
 601            uint32_t new_intc_cells, new_cells[32];
 602            i++; i++; /* FIXME: do address cells properly */
 603            for (k = 0; k < intc_cells; ++k) {
 604                uint32_t  map_val = be32_to_cpu(imap[i++]);
 605                if ((cells[k] ^ map_val) & imap_mask[k]) {
 606                    match = false;
 607                }
 608            }
 609            /* when caching, we hackishly store the number of cells for
 610             * the parent in the MSB. +1, so zero MSB means non cachd
 611             * and the full lookup is needed.
 612             */
 613            intc_phandle = be32_to_cpu(imap[i++]);
 614            if (intc_phandle & (0xffu << 24)) {
 615                new_intc_cells = (intc_phandle >> 24) - 1;
 616            } else {
 617                if (qemu_devtree_get_node_by_phandle(fdt, intc_node_path,
 618                                                     intc_phandle)) {
 619                    goto fail;
 620                }
 621                new_intc_cells = qemu_fdt_getprop_cell(fdt, intc_node_path,
 622                                                       "#interrupt-cells", 0,
 623                                                       false, &errp);
 624                imap[i - 1] = cpu_to_be32(intc_phandle |
 625                                            (new_intc_cells + 1) << 24);
 626                if (errp) {
 627                    goto fail;
 628                }
 629            }
 630            for (k = 0; k < new_intc_cells; ++k) {
 631                new_cells[k] = be32_to_cpu(imap[i++]);
 632            }
 633            if (match) {
 634                num_matches++;
 635                ret = g_renew(qemu_irq, ret, num_matches + 1);
 636                if (intc_phandle & (0xffu << 24)) {
 637                    if (qemu_devtree_get_node_by_phandle(fdt, intc_node_path,
 638                                                         intc_phandle &
 639                                                         ((1 << 24) - 1))) {
 640                        goto fail;
 641                    }
 642                }
 643
 644                DB_PRINT_NP(2, "Getting IRQ information: %s -> 0x%x (%s)\n",
 645                            node_path, intc_phandle, intc_node_path);
 646
 647                memset(&ret[num_matches], 0, sizeof(*ret));
 648                fdt_get_irq_info_from_intc(fdti, &ret[num_matches-1], intc_node_path,
 649                                           new_cells, new_intc_cells, 1, &errp);
 650                if (info) {
 651                   sprintf(info, "%s", intc_node_path);
 652                   info += strlen(info) + 1;
 653                }
 654                if (errp) {
 655                    goto fail;
 656                }
 657            }
 658        }
 659        return ret;
 660    }
 661
 662    DB_PRINT_NP(2, "Getting IRQ information: %s -> %s\n",
 663                node_path, intc_node_path);
 664
 665    ret = g_new0(qemu_irq, fdt_generic_num_cpus + 2);
 666    fdt_get_irq_info_from_intc(fdti, ret, intc_node_path, cells, intc_cells,
 667                               fdt_generic_num_cpus, &errp);
 668
 669    if (errp) {
 670        goto fail;
 671    }
 672
 673    /* FIXME: Phase out this info bussiness */
 674    if (info) {
 675        sprintf(info, "%s", intc_node_path);
 676    }
 677
 678    return ret;
 679
 680fail:
 681    if (errp) {
 682        sprintf(info, "%s", error_get_pretty(errp));
 683    } else {
 684        sprintf(info, "(none)");
 685    }
 686    return NULL;
 687}
 688
 689qemu_irq *fdt_get_irq(FDTMachineInfo *fdti, char *node_path, int irq_idx,
 690                      bool *map_mode)
 691{
 692    return fdt_get_irq_info(fdti, node_path, irq_idx, NULL, map_mode);
 693}
 694
 695/* FIXME: figure out a real solution to this */
 696
 697#define DIGIT(a) ((a) >= '0' && (a) <= '9')
 698#define LOWER_CASE(a) ((a) >= 'a' && (a) <= 'z')
 699
 700static void trim_version(char *x)
 701{
 702    for (;;) {
 703        x = strchr(x, '-');
 704        if (!x) {
 705            return;
 706        }
 707        if (DIGIT(x[1])) {
 708            /* Try to trim Xilinx version suffix */
 709            char *p;
 710            if (strtol(x+1, &p, 0)) {
 711                p = p;  /* -Werror */
 712            }
 713            if ( *p == '.') {
 714                *x = 0;
 715                return;
 716            } else if ( *p == 0) {
 717                return;
 718            }
 719        } else if (x[1] == 'r' && x[3] == 'p') {
 720            /* Try to trim ARM version suffix */
 721            if (DIGIT(x[2]) && DIGIT(x[4])) {
 722                *x = 0;
 723                return;
 724            }
 725        }
 726        x++;
 727    }
 728}
 729
 730static void substitute_char(char *s, char a, char b)
 731{
 732    for (;;) {
 733        s = strchr(s, a);
 734        if (!s) {
 735            return;
 736        }
 737        *s = b;
 738        s++;
 739    }
 740}
 741
 742static inline const char *trim_vendor(const char *s)
 743{
 744    /* FIXME: be more intelligent */
 745    const char *ret = memchr(s, ',', strlen(s));
 746    return ret ? ret + 1 : s;
 747}
 748
 749static Object *fdt_create_from_compat(const char *compat, char **dev_type)
 750{
 751    Object *ret = NULL;
 752    char *c = g_strdup(compat);
 753
 754    /* Try to create the object */
 755    ret = object_new(c);
 756
 757    if (!ret) {
 758        /* Trim the version off the end and try again */
 759        trim_version(c);
 760        ret = object_new(c);
 761
 762        if (!ret) {
 763            /* Replace commas with full stops */
 764            substitute_char(c, ',', '.');
 765            ret = object_new(c);
 766        }
 767    }
 768
 769    if (!ret) {
 770        /* Restart with the orginal string and now replace commas with full stops
 771         * and try again. This means that versions are still included.
 772         */
 773        g_free(c);
 774        c = g_strdup(compat);
 775        substitute_char(c, ',', '.');
 776        ret = object_new(c);
 777    }
 778
 779    if (dev_type) {
 780        *dev_type = c;
 781    } else {
 782        g_free(c);
 783    }
 784
 785    if (!ret) {
 786        const char *no_vendor = trim_vendor(compat);
 787
 788        if (no_vendor != compat) {
 789            return fdt_create_from_compat(no_vendor, dev_type);
 790        }
 791    }
 792    return ret;
 793}
 794
 795/*FIXME: roll into device tree functionality */
 796
 797static inline uint64_t get_int_be(const void *p, int len)
 798{
 799    switch (len) {
 800    case 1:
 801        return *((uint8_t *)p);
 802    case 2:
 803        return be16_to_cpu(*((uint16_t *)p));
 804    case 4:
 805        return be32_to_cpu(*((uint32_t *)p));
 806    case 8:
 807        return be32_to_cpu(*((uint64_t *)p));
 808    default:
 809        fprintf(stderr, "unsupported integer length\n");
 810        abort();
 811    }
 812}
 813
 814/* FIXME: use structs instead of parallel arrays */
 815
 816static const char *fdt_generic_reg_size_prop_names[] = {
 817    "#address-cells",
 818    "#size-cells",
 819    "#bus-cells",
 820    "#priority-cells",
 821};
 822
 823static const int fdt_generic_reg_cells_defaults[] = {
 824    1,
 825    1,
 826    0,
 827    0,
 828};
 829
 830static int fdt_init_qdev(char *node_path, FDTMachineInfo *fdti, char *compat)
 831{
 832    Object *dev, *parent;
 833    char *dev_type = NULL;
 834    int is_intc;
 835    Error *errp = NULL;
 836    int i, j;
 837    QEMUDevtreeProp *prop, *props;
 838    char parent_node_path[DT_PATH_LENGTH];
 839    const FDTGenericGPIOSet *gpio_set = NULL;
 840    FDTGenericGPIOClass *fggc = NULL;
 841
 842    if (!compat) {
 843        return 1;
 844    }
 845    dev = fdt_create_from_compat(compat, &dev_type);
 846    if (!dev) {
 847        DB_PRINT_NP(1, "no match found for %s\n", compat);
 848        return 1;
 849    }
 850    DB_PRINT_NP(1, "matched compat %s\n", compat);
 851
 852    /* Do this super early so fdt_generic_num_cpus is correct ASAP */
 853    if (object_dynamic_cast(dev, TYPE_CPU)) {
 854        fdt_generic_num_cpus++;
 855        DB_PRINT_NP(0, "is a CPU - total so far %d\n", fdt_generic_num_cpus);
 856    }
 857
 858    if (qemu_devtree_getparent(fdti->fdt, parent_node_path, node_path)) {
 859        abort();
 860    }
 861    while (!fdt_init_has_opaque(fdti, parent_node_path)) {
 862        fdt_init_yield(fdti);
 863    }
 864    parent = fdt_init_get_opaque(fdti, parent_node_path);
 865    if (dev->parent) {
 866        DB_PRINT_NP(0, "Node already parented - skipping node\n");
 867    } else if (parent) {
 868        DB_PRINT_NP(1, "parenting node\n");
 869        object_property_add_child(OBJECT(parent),
 870                              qemu_devtree_get_node_name(fdti->fdt, node_path),
 871                              OBJECT(dev), NULL);
 872        if (object_dynamic_cast(dev, TYPE_DEVICE)) {
 873            Object *parent_bus = parent;
 874            unsigned int depth = 0;
 875
 876            DB_PRINT_NP(1, "bus parenting node\n");
 877            /* Look for an FDT ancestor that is a Bus.  */
 878            while (parent_bus && !object_dynamic_cast(parent_bus, TYPE_BUS)) {
 879                /*
 880                 * Assert against insanely deep hierarchies which are an
 881                 * indication of loops.
 882                 */
 883                assert(depth < 4096);
 884
 885                parent_bus = parent_bus->parent;
 886                depth++;
 887            }
 888
 889            if (!parent_bus
 890                && object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) {
 891                /*
 892                 * Didn't find any bus. Use the default sysbus one.
 893                 * This allows ad-hoc busses belonging to sysbus devices to be
 894                 * visible to -device bus=x.
 895                 */
 896                parent_bus = OBJECT(sysbus_get_default());
 897            }
 898
 899            if (parent_bus) {
 900                qdev_set_parent_bus(DEVICE(dev), BUS(parent_bus));
 901            }
 902        }
 903    } else {
 904        DB_PRINT_NP(1, "orphaning node\n");
 905        /* FIXME: Make this go away (centrally) */
 906        object_property_add_child(
 907                              object_get_root(),
 908                              qemu_devtree_get_node_name(fdti->fdt, node_path),
 909                              OBJECT(dev), NULL);
 910    }
 911    fdt_init_set_opaque(fdti, node_path, dev);
 912
 913    /* Set the default sync-quantum based on the global one. Node properties
 914     * in the dtb can later override this value.  */
 915    if (global_sync_quantum) {
 916        ObjectProperty *p;
 917
 918        p = object_property_find(OBJECT(dev), "sync-quantum", NULL);
 919        if (p) {
 920            object_property_set_int(OBJECT(dev), global_sync_quantum,
 921                                    "sync-quantum", &errp);
 922        }
 923    }
 924
 925    props = qemu_devtree_get_props(fdti->fdt, node_path);
 926    for (prop = props; prop->name; prop++) {
 927        const char *propname = trim_vendor(prop->name);
 928        int len = prop->len;
 929        void *val = prop->value;
 930
 931        ObjectProperty *p = object_property_find(OBJECT(dev), propname, NULL);
 932        if (p) {
 933            DB_PRINT_NP(1, "matched property: %s of type %s, len %d\n",
 934                                            propname, p->type, prop->len);
 935        }
 936        if (!p) {
 937            continue;
 938        }
 939
 940        if (!strcmp(propname, "type")) {
 941            continue;
 942        }
 943
 944        /* FIXME: handle generically using accessors and stuff */
 945        if (!strcmp(p->type, "uint8") || !strcmp(p->type, "uint16") ||
 946                !strcmp(p->type, "uint32") || !strcmp(p->type, "uint64")) {
 947            object_property_set_int(OBJECT(dev), get_int_be(val, len), propname,
 948                                    &error_abort);
 949            DB_PRINT_NP(0, "set property %s to %#llx\n", propname,
 950                        (unsigned long long)get_int_be(val, len));
 951        } else if (!strcmp(p->type, "boolean") || !strcmp(p->type, "bool")) {
 952            object_property_set_bool(OBJECT(dev), !!get_int_be(val, len),
 953                                     propname, &error_abort);
 954            DB_PRINT_NP(0, "set property %s to %s\n", propname,
 955                        get_int_be(val, len) ? "true" : "false");
 956        } else if (!strcmp(p->type, "string") || !strcmp(p->type, "str")) {
 957            object_property_set_str(OBJECT(dev), (const char *)val, propname,
 958                                    &error_abort);
 959            DB_PRINT_NP(0, "set property %s to %s\n", propname,
 960                        (const char *)val);
 961        } else if (!strncmp(p->type, "link", 4)) {
 962            char target_node_path[DT_PATH_LENGTH];
 963            char propname_target[1024];
 964            strcpy(propname_target, propname);
 965            strcat(propname_target, "-target");
 966
 967            Object *linked_dev, *proxy;
 968
 969            if (qemu_devtree_get_node_by_phandle(fdti->fdt, target_node_path,
 970                                                get_int_be(val, len))) {
 971                abort();
 972            }
 973            while (!fdt_init_has_opaque(fdti, target_node_path)) {
 974                fdt_init_yield(fdti);
 975            }
 976            linked_dev = fdt_init_get_opaque(fdti, target_node_path);
 977
 978            proxy = linked_dev ? object_property_get_link(linked_dev,
 979                                                          propname_target,
 980                                                          &errp) : NULL;
 981            if (!errp && proxy) {
 982                DB_PRINT_NP(0, "detected proxy object for %s connection\n",
 983                            propname);
 984                linked_dev = proxy;
 985            }
 986            errp = NULL;
 987            if (linked_dev) {
 988                object_property_set_link(OBJECT(dev), linked_dev, propname,
 989                                         &errp);
 990                if (errp) {
 991                    /* Unable to set the property, maybe it is a memory
 992                     * alias?
 993                     */
 994                    MemoryRegion *alias_mr;
 995                    int offset = len / 2;
 996                    alias_mr =
 997                        sysbus_mmio_get_region(SYS_BUS_DEVICE(linked_dev),
 998                                               get_int_be(val + offset,
 999                                                          len - offset));
1000
1001                    object_property_set_link(OBJECT(dev), OBJECT(alias_mr),
1002                                             propname, &error_abort);
1003
1004                    errp = NULL;
1005                }
1006                DB_PRINT_NP(0, "set link %s\n", propname);
1007            }
1008        } else {
1009            DB_PRINT_NP(0, "WARNING: property is of unknown type\n");
1010        }
1011    }
1012
1013    /* FIXME: not pretty, but is half a sane dts binding */
1014    if (object_dynamic_cast(dev, TYPE_REMOTE_PORT_DEVICE)) {
1015        int i;
1016
1017        for (i = 0;;++i) {
1018            char adaptor_node_path[DT_PATH_LENGTH];
1019            uint32_t adaptor_phandle, chan;
1020            DeviceState *adaptor;
1021            char *name;
1022
1023            adaptor_phandle = qemu_fdt_getprop_cell(fdti->fdt, node_path,
1024                                                    "remote-ports",
1025                                                    2 * i, false, &errp);
1026            if (errp) {
1027                DB_PRINT_NP(1, "cant get phandle from \"remote-ports\" "
1028                            "property\n");
1029                break;
1030            }
1031            if (qemu_devtree_get_node_by_phandle(fdti->fdt, adaptor_node_path,
1032                                                 adaptor_phandle)) {
1033                DB_PRINT_NP(1, "cant get node from phandle\n");
1034                break;
1035            }
1036            adaptor = DEVICE(fdt_init_get_opaque(fdti, adaptor_node_path));
1037            name = g_strdup_printf("rp-adaptor%" PRId32, i);
1038            object_property_set_link(OBJECT(dev), OBJECT(adaptor), name, &errp);
1039            DB_PRINT_NP(0, "connecting RP to adaptor %s channel %d",
1040                        object_get_canonical_path(OBJECT(adaptor)), i);
1041            g_free(name);
1042            if (errp) {
1043                DB_PRINT_NP(1, "cant set adaptor link for device property\n");
1044                break;
1045            }
1046
1047            chan = qemu_fdt_getprop_cell(fdti->fdt, node_path, "remote-ports",
1048                                         2 * i + 1, false, &errp);
1049            if (errp) {
1050                DB_PRINT_NP(1, "cant get channel from \"remote-ports\" "
1051                            "property\n");
1052                break;
1053            }
1054
1055            name = g_strdup_printf("rp-chan%" PRId32, i);
1056            object_property_set_int(OBJECT(dev), chan, name, &errp);
1057            /* Not critical - device has right to not care about channel
1058             * numbers if its a pure slave (only responses).
1059             */
1060            if (errp) {
1061                DB_PRINT_NP(1, "cant set %s property %s\n", name, error_get_pretty(errp));
1062                errp = NULL;
1063            }
1064            g_free(name);
1065
1066            name = g_strdup_printf("remote-port-dev%d", chan);
1067            object_property_set_link(OBJECT(adaptor), OBJECT(dev), name,
1068                                     &errp);
1069            g_free(name);
1070            if (errp) {
1071                DB_PRINT_NP(1, "cant set device link for adaptor\n");
1072                break;
1073            }
1074        }
1075        errp = NULL;
1076    }
1077
1078    if (object_dynamic_cast(dev, TYPE_DEVICE)) {
1079        DeviceClass *dc = DEVICE_GET_CLASS(dev);
1080        /* connect nic if appropriate */
1081        static int nics;
1082        const char *short_name = qemu_devtree_get_node_name(fdti->fdt, node_path);
1083
1084        if (object_property_find(OBJECT(dev), "mac", NULL) &&
1085                    object_property_find(OBJECT(dev), "netdev", NULL)) {
1086            qdev_set_nic_properties(DEVICE(dev), &nd_table[nics]);
1087        }
1088        if (nd_table[nics].instantiated) {
1089            DB_PRINT_NP(0, "NIC instantiated: %s\n", dev_type);
1090            nics++;
1091        }
1092
1093        /* Regular TYPE_DEVICE houskeeping */
1094        DB_PRINT_NP(0, "Short naming node: %s\n", short_name);
1095        (DEVICE(dev))->id = g_strdup(short_name);
1096        qdev_init_nofail(DEVICE(dev));
1097        qemu_register_reset((void (*)(void *))dc->reset, dev);
1098    }
1099
1100    if (object_dynamic_cast(dev, TYPE_SYS_BUS_DEVICE) || 
1101        object_dynamic_cast(dev, TYPE_FDT_GENERIC_MMAP)) {
1102        FDTGenericRegPropInfo reg = {0};
1103        char parent_path[DT_PATH_LENGTH];
1104        int cell_idx = 0;
1105        bool extended = true;
1106
1107        qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg-extended", 0, false,
1108                              &errp);
1109        if (errp) {
1110            error_free(errp);
1111            errp = NULL;
1112            extended = false;
1113            qemu_devtree_getparent(fdti->fdt, parent_path, node_path);
1114        }
1115
1116        for (reg.n = 0;; reg.n++) {
1117            char ph_parent[DT_PATH_LENGTH];
1118            const char *pnp = parent_path;
1119
1120            reg.parents = g_renew(Object *, reg.parents, reg.n + 1);
1121            reg.parents[reg.n] = parent;
1122
1123            if (extended) {
1124                int p_ph = qemu_fdt_getprop_cell(fdti->fdt, node_path,
1125                                                 "reg-extended", cell_idx++,
1126                                                 false, &errp);
1127                if (errp) {
1128                    error_free(errp);
1129                    errp = NULL;
1130                    goto exit_reg_parse;
1131                }
1132                if (qemu_devtree_get_node_by_phandle(fdti->fdt, ph_parent,
1133                                                     p_ph)) {
1134                    goto exit_reg_parse;
1135                }
1136                while (!fdt_init_has_opaque(fdti, ph_parent)) {
1137                    fdt_init_yield(fdti);
1138                }
1139                reg.parents[reg.n] = fdt_init_get_opaque(fdti, ph_parent);
1140                pnp = ph_parent;
1141            }
1142
1143            for (i = 0; i < FDT_GENERIC_REG_TUPLE_LENGTH; ++i) {
1144                const char *size_prop_name = fdt_generic_reg_size_prop_names[i];
1145                int nc = qemu_fdt_getprop_cell(fdti->fdt, pnp, size_prop_name,
1146                                               0, true, &errp);
1147
1148                if (errp) {
1149                    int size_default = fdt_generic_reg_cells_defaults[i];
1150
1151                    DB_PRINT_NP(0, "WARNING: no %s for %s container, assuming "
1152                                "default of %d\n", size_prop_name, pnp,
1153                                size_default);
1154                    nc = size_default;
1155                    error_free(errp);
1156                    errp = NULL;
1157                }
1158                
1159                reg.x[i] = g_renew(uint64_t, reg.x[i], reg.n + 1);
1160                reg.x[i][reg.n] = nc ?
1161                    qemu_fdt_getprop_sized_cell(fdti->fdt, node_path,
1162                                                extended ? "reg-extended"
1163                                                         : "reg",
1164                                                cell_idx, nc, &errp)
1165                    : 0;
1166                cell_idx += nc;
1167                if (errp) {
1168                    goto exit_reg_parse;
1169                }
1170            }
1171        }
1172exit_reg_parse:
1173
1174        if (object_dynamic_cast(dev, TYPE_FDT_GENERIC_MMAP)) {
1175            FDTGenericMMapClass *fmc = FDT_GENERIC_MMAP_GET_CLASS(dev);
1176            if (fmc->parse_reg) {
1177                while (fmc->parse_reg(FDT_GENERIC_MMAP(dev), reg,
1178                                      &error_abort)) {
1179                    fdt_init_yield(fdti);
1180                }
1181            }
1182        }
1183    }
1184    
1185    if (object_dynamic_cast(dev, TYPE_SYS_BUS_DEVICE)) {
1186        {
1187            int len;
1188            fdt_get_property(fdti->fdt, fdt_path_offset(fdti->fdt, node_path),
1189                                    "interrupt-controller", &len);
1190            is_intc = len >= 0;
1191            DB_PRINT_NP(is_intc ? 0 : 1, "is interrupt controller: %c\n",
1192                        is_intc ? 'y' : 'n');
1193        }
1194        /* connect irq */
1195        j = 0;
1196        for (i = 0;; i++) {
1197            char irq_info[1024];
1198            char *irq_info_p = irq_info;
1199            bool map_mode;
1200            int len = -1;
1201            qemu_irq *irqs = fdt_get_irq_info(fdti, node_path, i, irq_info,
1202                                              &map_mode);
1203            /* INTCs inferr their top level, if no IRQ connection specified */
1204            fdt_get_property(fdti->fdt, fdt_path_offset(fdti->fdt, node_path),
1205                             "interrupts-extended", &len);
1206            if (!irqs && is_intc && i == 0 && len <= 0) {
1207                FDTGenericIntc *id = (FDTGenericIntc *)object_dynamic_cast(
1208                                        dev, TYPE_FDT_GENERIC_INTC);
1209                FDTGenericIntcClass *idc = FDT_GENERIC_INTC_GET_CLASS(id);
1210                if (id && idc->auto_parent) {
1211                    Error *err = NULL;
1212                    idc->auto_parent(id, &err);
1213                } else {
1214                    irqs = fdti->irq_base;
1215                }
1216            }
1217            if (!irqs) {
1218                break;
1219            }
1220            while (*irqs) {
1221                FDTIRQConnection *irq = g_new0(FDTIRQConnection, 1);
1222                *irq = (FDTIRQConnection) {
1223                    .dev = DEVICE(dev),
1224                    .name = SYSBUS_DEVICE_GPIO_IRQ,
1225                    .merge_fn = qemu_irq_shared_or_handler,
1226                    .i = j,
1227                    .irq = *irqs,
1228                    .sink_info = g_strdup(irq_info_p),
1229                    .next = fdti->irqs
1230                };
1231                if (!map_mode) {
1232                    j++;
1233                } else {
1234                    irq_info_p += strlen(irq_info_p) + 1;
1235                }
1236                fdti->irqs = irq;
1237                irqs++;
1238            }
1239            if (map_mode) {
1240                j++;
1241            }
1242        }
1243    }
1244
1245    if (object_dynamic_cast(dev, TYPE_FDT_GENERIC_GPIO)) {
1246        fggc = FDT_GENERIC_GPIO_GET_CLASS(dev);
1247        gpio_set = fggc->client_gpios;
1248    }
1249
1250    if (!gpio_set) {
1251        gpio_set = default_gpio_sets;
1252    }
1253
1254    for (; object_dynamic_cast(dev, TYPE_DEVICE) && gpio_set->names;
1255           gpio_set++) {
1256        bool end = false;
1257        int cur_cell = 0;
1258
1259        for (i = 0; !end; i++) {
1260            char *debug_success;
1261            const FDTGenericGPIOConnection *c = gpio_set->gpios;
1262            const char *gpio_name = NULL;
1263            uint16_t named_idx = 0;
1264            qemu_irq input, output;
1265            memset(&input, 0, sizeof(input));
1266
1267            if (c) {
1268                uint16_t range = c->range ? c->range : 1;
1269                while ((c->fdt_index > i || c->fdt_index + range <= i)
1270                       && c->name) {
1271                    c++;
1272                }
1273                named_idx = i - c->fdt_index;
1274                gpio_name = c->name;
1275            }
1276            if (!gpio_name) {
1277                const char *names_propname = gpio_set->names->names_propname;
1278                gpio_name = qemu_fdt_getprop_string(fdti->fdt, node_path,
1279                                                    names_propname, i, false,
1280                                                    NULL);
1281            }
1282            if (!gpio_name) {
1283                input = qdev_get_gpio_in(DEVICE(dev), i);
1284            } else {
1285                input = qdev_get_gpio_in_named(DEVICE(dev), gpio_name,
1286                                               named_idx);
1287            }
1288            debug_success = g_strdup_printf("Wiring GPIO input %s[%" PRId16 "] "
1289                                            "to", gpio_name, named_idx);
1290            output = fdt_get_gpio(fdti, node_path, &cur_cell, input, gpio_set,
1291                                  debug_success, &end);
1292            g_free(debug_success);
1293            if (output) {
1294                FDTIRQConnection *irq = g_new0(FDTIRQConnection, 1);
1295                *irq = (FDTIRQConnection) {
1296                    .dev = DEVICE(dev),
1297                    .name = gpio_name,
1298                    .merge_fn = qemu_irq_shared_or_handler,
1299                    .i = named_idx,
1300                    .irq = output,
1301                    .sink_info = NULL, /*FIXME */
1302                    .next = fdti->irqs
1303                };
1304                fdti->irqs = irq;
1305                DB_PRINT_NP(1, "... GPIO output %s[%" PRId16 "]\n", gpio_name,
1306                            named_idx);
1307            }
1308        }
1309    }
1310
1311    if (dev_type) {
1312        g_free(dev_type);
1313    }
1314
1315    return 0;
1316}
1317
1318static const TypeInfo fdt_generic_intc_info = {
1319    .name          = TYPE_FDT_GENERIC_INTC,
1320    .parent        = TYPE_INTERFACE,
1321    .class_size = sizeof(FDTGenericIntcClass),
1322};
1323
1324static const TypeInfo fdt_generic_mmap_info = {
1325    .name          = TYPE_FDT_GENERIC_MMAP,
1326    .parent        = TYPE_INTERFACE,
1327    .class_size = sizeof(FDTGenericMMapClass),
1328};
1329
1330static const TypeInfo fdt_generic_gpio_info = {
1331    .name          = TYPE_FDT_GENERIC_GPIO,
1332    .parent        = TYPE_INTERFACE,
1333    .class_size = sizeof(FDTGenericGPIOClass),
1334};
1335
1336static void fdt_generic_intc_register_types(void)
1337{
1338    type_register_static(&fdt_generic_intc_info);
1339    type_register_static(&fdt_generic_mmap_info);
1340    type_register_static(&fdt_generic_gpio_info);
1341}
1342
1343type_init(fdt_generic_intc_register_types)
1344