blob: cdfb108f27d25c1bd56fc4fa58941178666f12d3 [file] [log] [blame]
/* Copyright 2012, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* platform.c: platform interface routines
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mosys/alloc.h"
#include "mosys/callbacks.h"
#include "mosys/globals.h"
#include "mosys/intf_list.h"
#include "mosys/kv_pair.h"
#include "mosys/log.h"
#include "mosys/platform.h"
#include "mosys/output.h"
#include "lib/string.h"
#ifndef LINE_MAX
#define LINE_MAX 64
#endif
/*
* mosys_platform_setup - identify platform, setup interfaces and commands
*
* @p_opt: Optional platform name given to bypass auto-detection
*
* returns pointer to identified platform interface
* returns NULL if platform not identified or other error
*/
struct platform_intf *mosys_platform_setup(const char *p_opt)
{
struct platform_intf **_intf, *intf;
struct platform_intf *ret = NULL;
int intf_found = 0;
/* attempt to probe platform name and match it to an interface */
for (_intf = platform_intf_list; _intf && *_intf; _intf++) {
intf = *_intf;
lprintf(LOG_DEBUG, "Checking platform %s\n", intf->name);
/* use common operations by default */
intf->op = &platform_common_op;
/* platform name specified by user */
if (p_opt) {
if (strlfind(p_opt, &intf->id_list[0], 0)) {
intf_found = 1;
break;
} else {
continue;
}
}
/* auto-detect */
if (intf->probe) {
int rc = intf->probe(intf);
if (rc < 0) {
lprintf(LOG_DEBUG, "Error encountered when "
"probing %s\n", intf->name);
continue;
} else if (rc > 0) {
lprintf(LOG_DEBUG, "Platform %s found (via "
"probing)\n", intf->name);
intf_found = 1;
break;
}
}
}
if (!intf_found)
goto mosys_platform_setup_exit;
/* call platform-specific setup if found */
if (intf->setup && intf->setup(intf) < 0)
goto mosys_platform_setup_exit;
/* prepare interface operations */
if (intf_op_setup(intf) < 0) {
if (intf->destroy)
intf->destroy(intf);
intf_op_destroy(intf);
goto mosys_platform_setup_exit;
}
/* call platform-specific post-setup if found */
if (intf->setup_post &&
intf->setup_post(intf) < 0) {
if (intf->destroy)
intf->destroy(intf);
goto mosys_platform_setup_exit;
}
ret = intf;
mosys_platform_setup_exit:
return ret;
}
/*
* mosys_platform_destroy - clean up platform interface
*
* @intf: platform interface
*/
void mosys_platform_destroy(struct platform_intf *intf)
{
/* Call the destroy callbacks and cleanup afterwards. */
// invoke_destroy_callbacks();
// cleanup_destroy_callbacks();
if (intf) {
/* cleanup interface */
if (intf->destroy)
intf->destroy(intf);
/* cleanup interface operations */
intf_op_destroy(intf);
}
}
/*
* platform_cmd_usage - print usage text for command
*
* @cmd: command pointer
*/
void platform_cmd_usage(struct platform_cmd *cmd)
{
printf("usage: %s %s\n\n", cmd->name, cmd->usage ? : "");
}
/*
* tree_sub - subcommand handler for print_tree
*
* @intf: platform interface
* @cmd: command to iterate thru
* @depth: depth of recursion (number of leading tabs to prepend)
* @str: string with full command name
*
* returns 0 to indicate success
* returns <0 to indicate failure (or end of command hierarchy)
*/
static int tree_subcommand(struct platform_intf *intf,
struct platform_cmd *cmd,
int depth, char *str)
{
struct platform_cmd *sub;
char *tabs;
int index;
tabs = mosys_malloc(depth + 1);
memset(tabs, '\t', depth);
tabs[depth] = '\0';
for (sub = cmd->arg.sub, index = 1; sub->name != NULL; sub++, index++) {
printf("%s", tabs);
if (sub->type == ARG_TYPE_SUB) {
int pos = 0, len = 0;
if (mosys_get_verbosity() >= LOG_NOTICE) {
printf("[branch] %s ", str);
/* add full command info */
pos = strlen(str);
len = LINE_MAX - strlen(str);
snprintf(str + pos, len, " %s", sub->name);
}
printf("%s\n", sub->name);
/* continue descending into the hierarchy */
tree_subcommand(intf, sub, depth + 1, str);
if (mosys_get_verbosity() >= LOG_NOTICE) {
memset(str + pos, 0, len);
}
} else if (sub->type == ARG_TYPE_GETTER) {
if (mosys_get_verbosity() >= LOG_NOTICE)
printf("[leaf] %s ", str);
printf("%s\n", sub->name);
} else if (sub->type == ARG_TYPE_SETTER) {
if (mosys_get_verbosity() >= LOG_NOTICE)
printf("[flur] %s ", str);
printf("%s\n", sub->name);
} else {
// not a subcommand or function?!?
return -1;
}
}
free(tabs);
return 0;
}
/*
* print_tree - print command tree for this platform
*
* @intf: platform interface
*/
void print_tree(struct platform_intf *intf)
{
int root;
char str[LINE_MAX];
for (root = 0; intf->sub[root] != NULL; root++) {
if (mosys_get_verbosity() >= LOG_NOTICE) {
printf("[root] ");
snprintf(str, sizeof(str), "mosys %s",
intf->sub[root]->name);
} else {
snprintf(str, sizeof(str), "%s", intf->sub[root]->name);
}
printf("%s\n", str);
if (tree_subcommand(intf, intf->sub[root], 1, str) < 0)
lprintf(LOG_DEBUG, "tree walking failed", str);
}
}
/*
* print_platforms - print platform ids
*
* returns 0 to indicate success
* returns <0 to indicate failure
*/
int print_platforms() {
struct platform_intf **_intf, *intf;
const char **id;
int rc;
/* go through all supported interfaces */
for (_intf = platform_intf_list; _intf && *_intf; _intf++) {
intf = *_intf;
if (intf->type == PLATFORM_DEFAULT)
continue;
for (id = intf->id_list; id && *id; id++) {
struct kv_pair *kv;
kv = kv_pair_new();
kv_pair_add(kv, "id", *id);
rc = kv_pair_print(kv);
kv_pair_free(kv);
if (rc)
return rc;
}
}
return rc;
}