blob: bdb7c9a8839652902cb926a568fa845a2a58d4c5 [file] [log] [blame]
Norman James26072c02015-08-25 07:14:29 -05001#include <stdint.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <fcntl.h>
6#include <unistd.h>
7#include <sys/stat.h>
8#include <sys/mman.h>
Norman James8abb50c2015-09-16 10:58:16 -05009#include <syslog.h>
Norman James362a80f2015-09-14 14:04:39 -050010#include "interfaces/openbmc_intf.h"
Norman James10ff6a32015-08-27 14:24:17 -050011#include "openbmc.h"
12#include "gpio.h"
Norman Jamese2765102015-08-19 22:00:55 -050013
14/* ---------------------------------------------------------------------------------------------------- */
Norman James362a80f2015-09-14 14:04:39 -050015static const gchar* dbus_object_path = "/org/openbmc/control";
Norman James26072c02015-08-25 07:14:29 -050016static const gchar* dbus_name = "org.openbmc.control.Power";
17
Norman James32e74e22015-09-15 21:28:06 -050018//This object will use these GPIOs
Norman James3f97c5d2015-08-26 17:44:14 -050019GPIO power_pin = (GPIO){ "POWER_PIN" };
20GPIO pgood = (GPIO){ "PGOOD" };
Norman Jamese2765102015-08-19 22:00:55 -050021
22static GDBusObjectManagerServer *manager = NULL;
Norman Jamese2765102015-08-19 22:00:55 -050023
Norman James88872672015-09-21 16:51:35 -050024time_t pgood_timeout_start = 0;
Norman James362a80f2015-09-14 14:04:39 -050025
Norman James3d3b7fb2015-10-06 16:54:06 -050026// TODO: Change to interrupt driven instead of polling
Norman Jamesce46e3e2015-08-30 22:25:55 -050027static gboolean poll_pgood(gpointer user_data)
28{
29 ControlPower *control_power = object_get_control_power((Object*)user_data);
30 Control* control = object_get_control((Object*)user_data);
Norman Jamesbd4abd12015-09-16 22:43:46 -050031
32 //send the heartbeat
Norman Jamesce46e3e2015-08-30 22:25:55 -050033 control_emit_heartbeat(control,dbus_name);
Norman James32e74e22015-09-15 21:28:06 -050034 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
Norman Jamesce46e3e2015-08-30 22:25:55 -050035
Norman James6a1283c2015-09-16 22:21:11 -050036 guint poll_int = control_get_poll_interval(control);
37 if (poll_int == 0)
38 {
Norman James2891c532015-10-06 08:01:56 -050039 printf("ERROR PowerControl: Poll interval cannot be 0\n");
Norman James6a1283c2015-09-16 22:21:11 -050040 return FALSE;
41 }
Norman James88872672015-09-21 16:51:35 -050042 //handle timeout
43 time_t current_time = time(NULL);
44 if (difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
45 && pgood_timeout_start != 0)
Norman James32e74e22015-09-15 21:28:06 -050046 {
Norman James2891c532015-10-06 08:01:56 -050047 printf("ERROR PowerControl: Pgood poll timeout\n");
Norman Jamesbd4abd12015-09-16 22:43:46 -050048 // set timeout to 0 so timeout doesn't happen again
Norman James32e74e22015-09-15 21:28:06 -050049 control_power_set_pgood_timeout(control_power,0);
Norman James88872672015-09-21 16:51:35 -050050 pgood_timeout_start = 0;
Norman James8abb50c2015-09-16 10:58:16 -050051 return TRUE;
Norman James32e74e22015-09-15 21:28:06 -050052 }
Norman James32e74e22015-09-15 21:28:06 -050053 uint8_t gpio;
Norman James88872672015-09-21 16:51:35 -050054
55 int rc = gpio_open(&pgood);
56 rc = gpio_read(&pgood,&gpio);
57 gpio_close(&pgood);
Norman James32e74e22015-09-15 21:28:06 -050058 if (rc == GPIO_OK)
Norman James362a80f2015-09-14 14:04:39 -050059 {
Norman James32e74e22015-09-15 21:28:06 -050060 //if changed, set property and emit signal
61 if (gpio != control_power_get_pgood(control_power))
62 {
63 control_power_set_pgood(control_power,gpio);
64 if (gpio==0)
65 {
66 control_power_emit_power_lost(control_power);
Norman Jamesa3e47c42015-10-18 14:43:10 -050067 control_emit_goto_system_state(control,"HOST_POWERED_OFF");
Norman James32e74e22015-09-15 21:28:06 -050068 }
69 else
70 {
71 control_power_emit_power_good(control_power);
Norman Jamesa3e47c42015-10-18 14:43:10 -050072 control_emit_goto_system_state(control,"HOST_POWERED_ON");
Norman James32e74e22015-09-15 21:28:06 -050073 }
74 }
75 } else {
Norman James2891c532015-10-06 08:01:56 -050076 printf("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",pgood.name,rc);
Norman Jamesa3e47c42015-10-18 14:43:10 -050077 //return false so poll won't get called anymore
78 return FALSE;
Norman James32e74e22015-09-15 21:28:06 -050079 }
80 //pgood is not at desired state yet
81 if (gpio != control_power_get_state(control_power) &&
Norman James88872672015-09-21 16:51:35 -050082 control_power_get_pgood_timeout(control_power) > 0)
Norman James32e74e22015-09-15 21:28:06 -050083 {
Norman James88872672015-09-21 16:51:35 -050084 if (pgood_timeout_start == 0 ) {
85 pgood_timeout_start = current_time;
86 }
Norman James32e74e22015-09-15 21:28:06 -050087 }
88 else
89 {
Norman James88872672015-09-21 16:51:35 -050090 pgood_timeout_start = 0;
Norman James362a80f2015-09-14 14:04:39 -050091 }
Norman Jamesce46e3e2015-08-30 22:25:55 -050092 return TRUE;
93}
94
95
96
Norman Jamese2765102015-08-19 22:00:55 -050097static gboolean
Norman James3f97c5d2015-08-26 17:44:14 -050098on_set_power_state (ControlPower *pwr,
Norman Jamese2765102015-08-19 22:00:55 -050099 GDBusMethodInvocation *invocation,
100 guint state,
101 gpointer user_data)
102{
Norman James362a80f2015-09-14 14:04:39 -0500103 Control* control = object_get_control((Object*)user_data);
Norman James32e74e22015-09-15 21:28:06 -0500104 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
Norman James3f97c5d2015-08-26 17:44:14 -0500105 if (state > 1)
106 {
107 g_dbus_method_invocation_return_dbus_error (invocation,
108 "org.openbmc.ControlPower.Error.Failed",
109 "Invalid power state");
110 return TRUE;
111 }
Norman James9e6acf92015-09-08 07:00:04 -0500112 // return from method call
113 control_power_complete_set_power_state(pwr,invocation);
Norman James3f97c5d2015-08-26 17:44:14 -0500114 if (state == control_power_get_state(pwr))
115 {
Norman James9e6acf92015-09-08 07:00:04 -0500116 g_print("Power already at requested state: %d\n",state);
Norman James3f97c5d2015-08-26 17:44:14 -0500117 }
Norman James9e6acf92015-09-08 07:00:04 -0500118 else
119 {
Norman James32e74e22015-09-15 21:28:06 -0500120 int error = 0;
121 do {
Norman James19e45912015-10-04 20:19:41 -0500122 if (state == 1) {
Norman Jamesa3e47c42015-10-18 14:43:10 -0500123 control_emit_goto_system_state(control,"HOST_POWERING_ON");
Norman James19e45912015-10-04 20:19:41 -0500124 } else {
Norman Jamesa3e47c42015-10-18 14:43:10 -0500125 control_emit_goto_system_state(control,"HOST_POWERING_OFF");
Norman James19e45912015-10-04 20:19:41 -0500126 }
Norman James32e74e22015-09-15 21:28:06 -0500127 error = gpio_open(&power_pin);
Norman James88872672015-09-21 16:51:35 -0500128 if (error != GPIO_OK) { break; }
Norman James32e74e22015-09-15 21:28:06 -0500129 error = gpio_write(&power_pin,!state);
Norman James88872672015-09-21 16:51:35 -0500130 if (error != GPIO_OK) { break; }
Norman James32e74e22015-09-15 21:28:06 -0500131 gpio_close(&power_pin);
132 control_power_set_state(pwr,state);
Norman James32e74e22015-09-15 21:28:06 -0500133 } while(0);
134 if (error != GPIO_OK)
Norman James362a80f2015-09-14 14:04:39 -0500135 {
Norman James2891c532015-10-06 08:01:56 -0500136 printf("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
Norman James362a80f2015-09-14 14:04:39 -0500137 }
Norman James9e6acf92015-09-08 07:00:04 -0500138 }
139 return TRUE;
140}
Norman Jamese2765102015-08-19 22:00:55 -0500141
Norman James9e6acf92015-09-08 07:00:04 -0500142static gboolean
143on_init (Control *control,
144 GDBusMethodInvocation *invocation,
145 gpointer user_data)
146{
Norman James88872672015-09-21 16:51:35 -0500147 pgood_timeout_start = 0;
Norman James9e6acf92015-09-08 07:00:04 -0500148 guint poll_interval = control_get_poll_interval(control);
149 g_timeout_add(poll_interval, poll_pgood, user_data);
150 control_complete_init(control,invocation);
Norman James3f97c5d2015-08-26 17:44:14 -0500151 return TRUE;
Norman Jamese2765102015-08-19 22:00:55 -0500152}
153
154static gboolean
Norman James3f97c5d2015-08-26 17:44:14 -0500155on_get_power_state (ControlPower *pwr,
Norman Jamese2765102015-08-19 22:00:55 -0500156 GDBusMethodInvocation *invocation,
157 gpointer user_data)
158{
Norman James3f97c5d2015-08-26 17:44:14 -0500159 guint pgood = control_power_get_pgood(pwr);
160 control_power_complete_get_power_state(pwr,invocation,pgood);
161 return TRUE;
Norman Jamese2765102015-08-19 22:00:55 -0500162}
163
164static void
165on_bus_acquired (GDBusConnection *connection,
166 const gchar *name,
167 gpointer user_data)
168{
Norman James3f97c5d2015-08-26 17:44:14 -0500169 ObjectSkeleton *object;
Norman James10ff6a32015-08-27 14:24:17 -0500170 cmdline *cmd = user_data;
171 if (cmd->argc < 2)
172 {
173 g_print("No objects created. Put object name(s) on command line\n");
174 return;
175 }
176 manager = g_dbus_object_manager_server_new (dbus_object_path);
Norman James88872672015-09-21 16:51:35 -0500177 gchar *s;
178 s = g_strdup_printf ("%s/%s",dbus_object_path,cmd->argv[1]);
Norman James88872672015-09-21 16:51:35 -0500179 object = object_skeleton_new (s);
180 g_free (s);
Norman Jamese2765102015-08-19 22:00:55 -0500181
Norman James88872672015-09-21 16:51:35 -0500182 ControlPower* control_power = control_power_skeleton_new ();
183 object_skeleton_set_control_power (object, control_power);
184 g_object_unref (control_power);
185
186 Control* control = control_skeleton_new ();
187 object_skeleton_set_control (object, control);
188 g_object_unref (control);
Norman Jamese2765102015-08-19 22:00:55 -0500189
Norman James88872672015-09-21 16:51:35 -0500190 //define method callbacks here
191 g_signal_connect (control_power,
192 "handle-set-power-state",
193 G_CALLBACK (on_set_power_state),
194 object); /* user_data */
Norman Jamesce46e3e2015-08-30 22:25:55 -0500195
Norman James88872672015-09-21 16:51:35 -0500196 g_signal_connect (control_power,
197 "handle-get-power-state",
198 G_CALLBACK (on_get_power_state),
199 NULL); /* user_data */
Norman Jamese2765102015-08-19 22:00:55 -0500200
Norman James88872672015-09-21 16:51:35 -0500201 g_signal_connect (control,
202 "handle-init",
203 G_CALLBACK (on_init),
204 object); /* user_data */
Norman James9e6acf92015-09-08 07:00:04 -0500205
206
Norman James88872672015-09-21 16:51:35 -0500207 /* Export the object (@manager takes its own reference to @object) */
208 g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
209 g_object_unref (object);
Norman Jamesce46e3e2015-08-30 22:25:55 -0500210
Norman James3f97c5d2015-08-26 17:44:14 -0500211 /* Export all objects */
212 g_dbus_object_manager_server_set_connection (manager, connection);
213
214 // get gpio device paths
Norman Jamesbd4abd12015-09-16 22:43:46 -0500215 int rc = GPIO_OK;
Norman James32e74e22015-09-15 21:28:06 -0500216 do {
Norman James32e74e22015-09-15 21:28:06 -0500217 rc = gpio_init(connection,&power_pin);
218 if (rc != GPIO_OK) { break; }
219 rc = gpio_init(connection,&pgood);
220 if (rc != GPIO_OK) { break; }
Norman James65a295a2015-09-26 22:21:10 -0500221 uint8_t gpio;
Norman James32e74e22015-09-15 21:28:06 -0500222 rc = gpio_open(&pgood);
Norman James65a295a2015-09-26 22:21:10 -0500223 if (rc != GPIO_OK) { break; }
224 rc = gpio_read(&pgood,&gpio);
225 if (rc != GPIO_OK) { break; }
226 gpio_close(&pgood);
227 control_power_set_pgood(control_power,gpio);
Norman Jamesf66005a2015-10-08 15:11:44 -0500228 printf("Pgood state: %d\n",gpio);
Norman James32e74e22015-09-15 21:28:06 -0500229 } while(0);
Norman Jamesbd4abd12015-09-16 22:43:46 -0500230 if (rc != GPIO_OK)
231 {
Norman James2891c532015-10-06 08:01:56 -0500232 printf("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
Norman James65a295a2015-09-26 22:21:10 -0500233 }
Norman Jamese2765102015-08-19 22:00:55 -0500234}
235
236static void
237on_name_acquired (GDBusConnection *connection,
238 const gchar *name,
239 gpointer user_data)
240{
Norman Jamese2765102015-08-19 22:00:55 -0500241}
242
243static void
244on_name_lost (GDBusConnection *connection,
245 const gchar *name,
246 gpointer user_data)
247{
Norman Jamese2765102015-08-19 22:00:55 -0500248}
249
Norman Jamese2765102015-08-19 22:00:55 -0500250
Norman James3f97c5d2015-08-26 17:44:14 -0500251
252
253/*----------------------------------------------------------------*/
254/* Main Event Loop */
255
Norman Jamese2765102015-08-19 22:00:55 -0500256gint
257main (gint argc, gchar *argv[])
258{
259 GMainLoop *loop;
Norman James90caa3c2015-08-27 21:28:48 -0500260 cmdline cmd;
261 cmd.argc = argc;
262 cmd.argv = argv;
Norman Jamese2765102015-08-19 22:00:55 -0500263
264 guint id;
Norman Jamese2765102015-08-19 22:00:55 -0500265 loop = g_main_loop_new (NULL, FALSE);
266
Norman James5e792e32015-10-07 17:36:17 -0500267 id = g_bus_own_name (DBUS_TYPE,
Norman James26072c02015-08-25 07:14:29 -0500268 dbus_name,
Norman Jamese2765102015-08-19 22:00:55 -0500269 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
270 G_BUS_NAME_OWNER_FLAGS_REPLACE,
271 on_bus_acquired,
272 on_name_acquired,
273 on_name_lost,
Norman James90caa3c2015-08-27 21:28:48 -0500274 &cmd,
Norman Jamese2765102015-08-19 22:00:55 -0500275 NULL);
276
Norman Jamesce46e3e2015-08-30 22:25:55 -0500277 g_main_loop_run (loop);
Norman Jamese2765102015-08-19 22:00:55 -0500278
279 g_bus_unown_name (id);
280 g_main_loop_unref (loop);
281 return 0;
282}