summaryrefslogtreecommitdiffstats
path: root/op-pwrctl
diff options
context:
space:
mode:
authorBrad Bishop <bradleyb@fuzziesquirrel.com>2016-05-28 18:41:04 -0400
committerBrad Bishop <bradleyb@fuzziesquirrel.com>2016-06-10 18:06:59 -0400
commit40a360c2a4feef97a8f7041e655b2a42e51e0224 (patch)
tree75dfea3064d7c3243788c72cb9f30e2ce6241dea /op-pwrctl
parenta73122191a7aba80f97332687a2e03cfb0336981 (diff)
downloadtalos-skeleton-40a360c2a4feef97a8f7041e655b2a42e51e0224.tar.gz
talos-skeleton-40a360c2a4feef97a8f7041e655b2a42e51e0224.zip
Reorganize directory structure
Moving to directory per-application layout. This facilitates building single applications which is useful in the Yocto build environment since different applications satisfy different OpenBMC build requirements. A number of issues are also addressed: - All applications were pulling in libsystemd and the gdbus libs irrespective of whether or not they were needed. - gpio.o duplicated in every application - moved to libopenbmc_intf - Added install target Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Diffstat (limited to 'op-pwrctl')
-rw-r--r--op-pwrctl/Makefile3
-rw-r--r--op-pwrctl/power_control_obj.c309
2 files changed, 312 insertions, 0 deletions
diff --git a/op-pwrctl/Makefile b/op-pwrctl/Makefile
new file mode 100644
index 0000000..b1188ae
--- /dev/null
+++ b/op-pwrctl/Makefile
@@ -0,0 +1,3 @@
+BINS=power_control
+include ../gdbus.mk
+include ../rules.mk
diff --git a/op-pwrctl/power_control_obj.c b/op-pwrctl/power_control_obj.c
new file mode 100644
index 0000000..85a8cff
--- /dev/null
+++ b/op-pwrctl/power_control_obj.c
@@ -0,0 +1,309 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <syslog.h>
+#include "interfaces/openbmc_intf.h"
+#include "openbmc.h"
+#include "gpio.h"
+
+/* ------------------------------------------------------------------------- */
+static const gchar* dbus_object_path = "/org/openbmc/control";
+static const gchar* instance_name = "power0";
+static const gchar* dbus_name = "org.openbmc.control.Power";
+
+//This object will use these GPIOs
+GPIO power_pin = (GPIO){ "POWER_PIN" };
+GPIO pgood = (GPIO){ "PGOOD" };
+GPIO usb_reset = (GPIO){ "USB_RESET" };
+GPIO pcie_reset = (GPIO){ "PCIE_RESET" };
+
+
+static GDBusObjectManagerServer *manager = NULL;
+
+time_t pgood_timeout_start = 0;
+
+// TODO: Change to interrupt driven instead of polling
+static gboolean
+poll_pgood(gpointer user_data)
+{
+ ControlPower *control_power = object_get_control_power((Object*)user_data);
+ Control* control = object_get_control((Object*)user_data);
+
+ //send the heartbeat
+ guint poll_int = control_get_poll_interval(control);
+ if(poll_int == 0)
+ {
+ printf("ERROR PowerControl: Poll interval cannot be 0\n");
+ return FALSE;
+ }
+ //handle timeout
+ time_t current_time = time(NULL);
+ if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
+ && pgood_timeout_start != 0)
+ {
+ printf("ERROR PowerControl: Pgood poll timeout\n");
+ // set timeout to 0 so timeout doesn't happen again
+ control_power_set_pgood_timeout(control_power,0);
+ pgood_timeout_start = 0;
+ return TRUE;
+ }
+ uint8_t gpio;
+
+ int rc = gpio_open(&pgood);
+ rc = gpio_read(&pgood,&gpio);
+ gpio_close(&pgood);
+ if(rc == GPIO_OK)
+ {
+ //if changed, set property and emit signal
+ if(gpio != control_power_get_pgood(control_power))
+ {
+ control_power_set_pgood(control_power,gpio);
+ if(gpio==0)
+ {
+ control_power_emit_power_lost(control_power);
+ control_emit_goto_system_state(control,"HOST_POWERED_OFF");
+ rc = gpio_open(&pcie_reset);
+ rc = gpio_write(&pcie_reset,0);
+ gpio_close(&pcie_reset);
+
+ rc = gpio_open(&usb_reset);
+ rc = gpio_write(&usb_reset,0);
+ gpio_close(&usb_reset);
+
+ }
+ else
+ {
+ control_power_emit_power_good(control_power);
+ control_emit_goto_system_state(control,"HOST_POWERED_ON");
+ rc = gpio_open(&pcie_reset);
+ rc = gpio_write(&pcie_reset,1);
+ gpio_close(&pcie_reset);
+
+ rc = gpio_open(&usb_reset);
+ rc = gpio_write(&usb_reset,1);
+ gpio_close(&usb_reset);
+ }
+ }
+ } else {
+ printf("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",pgood.name,rc);
+ //return false so poll won't get called anymore
+ return FALSE;
+ }
+ //pgood is not at desired state yet
+ if(gpio != control_power_get_state(control_power) &&
+ control_power_get_pgood_timeout(control_power) > 0)
+ {
+ if(pgood_timeout_start == 0 ) {
+ pgood_timeout_start = current_time;
+ }
+ }
+ else
+ {
+ pgood_timeout_start = 0;
+ }
+ return TRUE;
+}
+
+static gboolean
+on_set_power_state(ControlPower *pwr,
+ GDBusMethodInvocation *invocation,
+ guint state,
+ gpointer user_data)
+{
+ Control* control = object_get_control((Object*)user_data);
+ if(state > 1)
+ {
+ g_dbus_method_invocation_return_dbus_error(invocation,
+ "org.openbmc.ControlPower.Error.Failed",
+ "Invalid power state");
+ return TRUE;
+ }
+ // return from method call
+ control_power_complete_set_power_state(pwr,invocation);
+ if(state == control_power_get_state(pwr))
+ {
+ g_print("Power already at requested state: %d\n",state);
+ }
+ else
+ {
+ int error = 0;
+ do {
+ if(state == 1) {
+ control_emit_goto_system_state(control,"HOST_POWERING_ON");
+ } else {
+ control_emit_goto_system_state(control,"HOST_POWERING_OFF");
+ }
+ error = gpio_open(&power_pin);
+ if(error != GPIO_OK) { break; }
+ error = gpio_write(&power_pin,!state);
+ if(error != GPIO_OK) { break; }
+ gpio_close(&power_pin);
+ control_power_set_state(pwr,state);
+ } while(0);
+ if(error != GPIO_OK)
+ {
+ printf("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
+ }
+ }
+ return TRUE;
+}
+
+static gboolean
+on_init(Control *control,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ pgood_timeout_start = 0;
+ //guint poll_interval = control_get_poll_interval(control);
+ //g_timeout_add(poll_interval, poll_pgood, user_data);
+ control_complete_init(control,invocation);
+ return TRUE;
+}
+
+static gboolean
+on_get_power_state(ControlPower *pwr,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ guint pgood = control_power_get_pgood(pwr);
+ control_power_complete_get_power_state(pwr,invocation,pgood);
+ return TRUE;
+}
+
+static void
+on_bus_acquired(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ ObjectSkeleton *object;
+ cmdline *cmd = user_data;
+ if(cmd->argc < 3)
+ {
+ g_print("Usage: power_control.exe [poll interval] [timeout]\n");
+ return;
+ }
+ manager = g_dbus_object_manager_server_new(dbus_object_path);
+ gchar *s;
+ s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
+ object = object_skeleton_new(s);
+ g_free(s);
+
+ ControlPower* control_power = control_power_skeleton_new();
+ object_skeleton_set_control_power(object, control_power);
+ g_object_unref(control_power);
+
+ Control* control = control_skeleton_new();
+ object_skeleton_set_control(object, control);
+ g_object_unref(control);
+
+ //define method callbacks here
+ g_signal_connect(control_power,
+ "handle-set-power-state",
+ G_CALLBACK(on_set_power_state),
+ object); /* user_data */
+
+ g_signal_connect(control_power,
+ "handle-get-power-state",
+ G_CALLBACK(on_get_power_state),
+ NULL); /* user_data */
+
+ g_signal_connect(control,
+ "handle-init",
+ G_CALLBACK(on_init),
+ object); /* user_data */
+
+
+ /* Export the object (@manager takes its own reference to @object) */
+ g_dbus_object_manager_server_set_connection(manager, connection);
+ g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
+ g_object_unref(object);
+
+ // get gpio device paths
+ int rc = GPIO_OK;
+ do {
+ rc = gpio_init(connection,&power_pin);
+ if(rc != GPIO_OK) { break; }
+ rc = gpio_init(connection,&pgood);
+ if(rc != GPIO_OK) { break; }
+ rc = gpio_init(connection,&pcie_reset);
+ if(rc != GPIO_OK) { break; }
+ rc = gpio_init(connection,&usb_reset);
+ if(rc != GPIO_OK) { break; }
+
+ uint8_t gpio;
+ rc = gpio_open(&pgood);
+ if(rc != GPIO_OK) { break; }
+ rc = gpio_read(&pgood,&gpio);
+ if(rc != GPIO_OK) { break; }
+ gpio_close(&pgood);
+ control_power_set_pgood(control_power,gpio);
+ control_power_set_state(control_power,gpio);
+ printf("Pgood state: %d\n",gpio);
+
+ } while(0);
+ if(rc != GPIO_OK)
+ {
+ printf("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
+ }
+ //start poll
+ pgood_timeout_start = 0;
+ int poll_interval = atoi(cmd->argv[1]);
+ int pgood_timeout = atoi(cmd->argv[2]);
+ if(poll_interval < 1000 || pgood_timeout <5) {
+ printf("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
+ } else {
+ control_set_poll_interval(control,poll_interval);
+ control_power_set_pgood_timeout(control_power,pgood_timeout);
+ g_timeout_add(poll_interval, poll_pgood, object);
+ }
+}
+
+static void
+on_name_acquired(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+}
+
+static void
+on_name_lost(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+}
+
+/*----------------------------------------------------------------*/
+/* Main Event Loop */
+
+gint
+main(gint argc, gchar *argv[])
+{
+ GMainLoop *loop;
+ cmdline cmd;
+ cmd.argc = argc;
+ cmd.argv = argv;
+
+ guint id;
+ loop = g_main_loop_new(NULL, FALSE);
+
+ id = g_bus_own_name(DBUS_TYPE,
+ dbus_name,
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
+ G_BUS_NAME_OWNER_FLAGS_REPLACE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ &cmd,
+ NULL);
+
+ g_main_loop_run(loop);
+
+ g_bus_unown_name(id);
+ g_main_loop_unref(loop);
+ return 0;
+}
OpenPOWER on IntegriCloud