qemu/hw/core/fdt_generic.c
<<
>>
Prefs
   1/*
   2 * Tables of FDT device models and their init functions. Keyed by compatibility
   3 * strings, device instance names.
   4 *
   5 * Copyright (c) 2010 PetaLogix Qld Pty Ltd.
   6 * Copyright (c) 2010 Peter A. G. Crosthwaite <peter.crosthwaite@petalogix.com>.
   7 *
   8 * Permission is hereby granted, free of charge, to any person obtaining a copy
   9 * of this software and associated documentation files (the "Software"), to deal
  10 * in the Software without restriction, including without limitation the rights
  11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 * copies of the Software, and to permit persons to whom the Software is
  13 * furnished to do so, subject to the following conditions:
  14 *
  15 * The above copyright notice and this permission notice shall be included in
  16 * all copies or substantial portions of the Software.
  17 *
  18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 * THE SOFTWARE.
  25 */
  26
  27#include "qemu/osdep.h"
  28#include "hw/fdt_generic.h"
  29#include "qemu/coroutine.h"
  30#include "qemu/log.h"
  31
  32#ifndef FDT_GENERIC_ERR_DEBUG
  33#define FDT_GENERIC_ERR_DEBUG 0
  34#endif
  35#define DB_PRINT(lvl, ...) do { \
  36    if (FDT_GENERIC_ERR_DEBUG > (lvl)) { \
  37        qemu_log_mask(lvl, ": %s: ", __func__); \
  38        qemu_log_mask(lvl, ## __VA_ARGS__); \
  39    } \
  40} while (0);
  41
  42#define FDT_GENERIC_MAX_PATTERN_LEN 1024
  43
  44typedef struct TableListNode {
  45    void *next;
  46    char key[FDT_GENERIC_MAX_PATTERN_LEN];
  47    FDTInitFn fdt_init;
  48    void *opaque;
  49} TableListNode;
  50
  51/* add a node to the table specified by *head_p */
  52
  53static void add_to_table(
  54        FDTInitFn fdt_init,
  55        const char *key,
  56        void *opaque,
  57        TableListNode **head_p)
  58{
  59    TableListNode *nn = malloc(sizeof(*nn));
  60    nn->next = (void *)(*head_p);
  61    strcpy(nn->key, key);
  62    nn->fdt_init = fdt_init;
  63    nn->opaque = opaque;
  64    *head_p = nn;
  65}
  66
  67/* FIXME: add return codes that differentiate between not found and error */
  68
  69/* search a table for a key string and call the fdt init function if found.
  70 * Returns 0 if a match is found, 1 otherwise
  71 */
  72
  73static int fdt_init_search_table(
  74        char *node_path,
  75        FDTMachineInfo *fdti,
  76        const char *key, /* string to match */
  77        TableListNode **head) /* head of the list to search */
  78{
  79    TableListNode *c = *head;
  80    if (c == NULL) {
  81        return 1;
  82    } else if (!strcmp(key, c->key)) {
  83        return c->fdt_init ? c->fdt_init(node_path, fdti, c->opaque) : 0;
  84    }
  85    return fdt_init_search_table(node_path, fdti, key,
  86        (TableListNode **)(&(*head)->next));
  87}
  88
  89TableListNode *compat_list_head;
  90
  91void add_to_compat_table(FDTInitFn fdt_init, const char *compat, void *opaque)
  92{
  93    add_to_table(fdt_init, compat, opaque, &compat_list_head);
  94}
  95
  96int fdt_init_compat(char *node_path, FDTMachineInfo *fdti, const char *compat)
  97{
  98    return fdt_init_search_table(node_path, fdti, compat, &compat_list_head);
  99}
 100
 101TableListNode *inst_bind_list_head;
 102
 103void add_to_inst_bind_table(FDTInitFn fdt_init, const char *name, void *opaque)
 104{
 105    add_to_table(fdt_init, name, opaque, &inst_bind_list_head);
 106}
 107
 108int fdt_init_inst_bind(char *node_path, FDTMachineInfo *fdti,
 109        const char *name)
 110{
 111    return fdt_init_search_table(node_path, fdti, name, &inst_bind_list_head);
 112}
 113
 114static void dump_table(TableListNode *head)
 115{
 116    if (head == NULL) {
 117        return;
 118    }
 119    printf("key : %s, opaque data %p\n", head->key, head->opaque);
 120    dump_table(head->next);
 121}
 122
 123void dump_compat_table(void)
 124{
 125    printf("FDT COMPATIBILITY TABLE:\n");
 126    dump_table(compat_list_head);
 127}
 128
 129void dump_inst_bind_table(void)
 130{
 131    printf("FDT INSTANCE BINDING TABLE:\n");
 132    dump_table(inst_bind_list_head);
 133}
 134
 135void fdt_init_yield(FDTMachineInfo *fdti)
 136{
 137    static int yield_index;
 138    int this_yield = yield_index++;
 139
 140    DB_PRINT(1, "Yield #%d\n", this_yield);
 141    qemu_co_queue_wait(fdti->cq);
 142    DB_PRINT(1, "Unyield #%d\n", this_yield);
 143}
 144
 145void fdt_init_set_opaque(FDTMachineInfo *fdti, char *node_path, void *opaque)
 146{
 147    FDTDevOpaque *dp;
 148    for (dp = fdti->dev_opaques;
 149        dp->node_path && strcmp(dp->node_path, node_path);
 150        dp++);
 151    if (!dp->node_path) {
 152        dp->node_path = strdup(node_path);
 153    }
 154    dp->opaque = opaque;
 155}
 156
 157int fdt_init_has_opaque(FDTMachineInfo *fdti, char *node_path)
 158{
 159    FDTDevOpaque *dp;
 160    for (dp = fdti->dev_opaques; dp->node_path; dp++) {
 161        if (!strcmp(dp->node_path, node_path)) {
 162            return 1;
 163         }
 164    }
 165    return 0;
 166}
 167
 168void *fdt_init_get_opaque(FDTMachineInfo *fdti, char *node_path)
 169{
 170    FDTDevOpaque *dp;
 171    for (dp = fdti->dev_opaques; dp->node_path; dp++) {
 172        if (!strcmp(dp->node_path, node_path)) {
 173            return dp->opaque;
 174        }
 175    }
 176    return NULL;
 177}
 178
 179FDTMachineInfo *fdt_init_new_fdti(void *fdt)
 180{
 181    FDTMachineInfo *fdti = g_malloc0(sizeof(*fdti));
 182    fdti->fdt = fdt;
 183    fdti->cq = g_malloc0(sizeof(*(fdti->cq)));
 184    qemu_co_queue_init(fdti->cq);
 185    fdti->dev_opaques = g_malloc0(sizeof(*(fdti->dev_opaques)) *
 186        (devtree_get_num_nodes(fdt) + 1));
 187    return fdti;
 188}
 189
 190void fdt_init_destroy_fdti(FDTMachineInfo *fdti)
 191{
 192    FDTDevOpaque *dp;
 193    for (dp = fdti->dev_opaques; dp->node_path; dp++) {
 194        g_free(dp->node_path);
 195    }
 196    g_free(fdti->dev_opaques);
 197    g_free(fdti);
 198}
 199