blob: 97d1021adee62e85462373408b1463dadfb08a7f [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 James8fee6f22015-10-28 12:48:43 -050016static const gchar* instance_name = "power0";
Norman James26072c02015-08-25 07:14:29 -050017static const gchar* dbus_name = "org.openbmc.control.Power";
18
Norman James32e74e22015-09-15 21:28:06 -050019//This object will use these GPIOs
Norman James3f97c5d2015-08-26 17:44:14 -050020GPIO power_pin = (GPIO){ "POWER_PIN" };
21GPIO pgood = (GPIO){ "PGOOD" };
Norman Jamese2765102015-08-19 22:00:55 -050022
23static GDBusObjectManagerServer *manager = NULL;
Norman Jamese2765102015-08-19 22:00:55 -050024
Norman James88872672015-09-21 16:51:35 -050025time_t pgood_timeout_start = 0;
Norman James362a80f2015-09-14 14:04:39 -050026
Norman James3d3b7fb2015-10-06 16:54:06 -050027// TODO: Change to interrupt driven instead of polling
Norman Jamesce46e3e2015-08-30 22:25:55 -050028static gboolean poll_pgood(gpointer user_data)
29{
30 ControlPower *control_power = object_get_control_power((Object*)user_data);
31 Control* control = object_get_control((Object*)user_data);
Norman Jamesbd4abd12015-09-16 22:43:46 -050032
33 //send the heartbeat
Norman Jamesce46e3e2015-08-30 22:25:55 -050034 control_emit_heartbeat(control,dbus_name);
Norman James32e74e22015-09-15 21:28:06 -050035 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
Norman Jamesce46e3e2015-08-30 22:25:55 -050036
Norman James6a1283c2015-09-16 22:21:11 -050037 guint poll_int = control_get_poll_interval(control);
38 if (poll_int == 0)
39 {
Norman James2891c532015-10-06 08:01:56 -050040 printf("ERROR PowerControl: Poll interval cannot be 0\n");
Norman James6a1283c2015-09-16 22:21:11 -050041 return FALSE;
42 }
Norman James88872672015-09-21 16:51:35 -050043 //handle timeout
44 time_t current_time = time(NULL);
45 if (difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
46 && pgood_timeout_start != 0)
Norman James32e74e22015-09-15 21:28:06 -050047 {
Norman James2891c532015-10-06 08:01:56 -050048 printf("ERROR PowerControl: Pgood poll timeout\n");
Norman Jamesbd4abd12015-09-16 22:43:46 -050049 // set timeout to 0 so timeout doesn't happen again
Norman James32e74e22015-09-15 21:28:06 -050050 control_power_set_pgood_timeout(control_power,0);
Norman James88872672015-09-21 16:51:35 -050051 pgood_timeout_start = 0;
Norman James8abb50c2015-09-16 10:58:16 -050052 return TRUE;
Norman James32e74e22015-09-15 21:28:06 -050053 }
Norman James32e74e22015-09-15 21:28:06 -050054 uint8_t gpio;
Norman James88872672015-09-21 16:51:35 -050055
56 int rc = gpio_open(&pgood);
57 rc = gpio_read(&pgood,&gpio);
58 gpio_close(&pgood);
Norman James32e74e22015-09-15 21:28:06 -050059 if (rc == GPIO_OK)
Norman James362a80f2015-09-14 14:04:39 -050060 {
Norman James32e74e22015-09-15 21:28:06 -050061 //if changed, set property and emit signal
62 if (gpio != control_power_get_pgood(control_power))
63 {
64 control_power_set_pgood(control_power,gpio);
65 if (gpio==0)
66 {
67 control_power_emit_power_lost(control_power);
Norman Jamesa3e47c42015-10-18 14:43:10 -050068 control_emit_goto_system_state(control,"HOST_POWERED_OFF");
Norman James32e74e22015-09-15 21:28:06 -050069 }
70 else
71 {
72 control_power_emit_power_good(control_power);
Norman Jamesa3e47c42015-10-18 14:43:10 -050073 control_emit_goto_system_state(control,"HOST_POWERED_ON");
Norman James32e74e22015-09-15 21:28:06 -050074 }
75 }
76 } else {
Norman James2891c532015-10-06 08:01:56 -050077 printf("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",pgood.name,rc);
Norman Jamesa3e47c42015-10-18 14:43:10 -050078 //return false so poll won't get called anymore
79 return FALSE;
Norman James32e74e22015-09-15 21:28:06 -050080 }
81 //pgood is not at desired state yet
82 if (gpio != control_power_get_state(control_power) &&
Norman James88872672015-09-21 16:51:35 -050083 control_power_get_pgood_timeout(control_power) > 0)
Norman James32e74e22015-09-15 21:28:06 -050084 {
Norman James88872672015-09-21 16:51:35 -050085 if (pgood_timeout_start == 0 ) {
86 pgood_timeout_start = current_time;
87 }
Norman James32e74e22015-09-15 21:28:06 -050088 }
89 else
90 {
Norman James88872672015-09-21 16:51:35 -050091 pgood_timeout_start = 0;
Norman James362a80f2015-09-14 14:04:39 -050092 }
Norman Jamesce46e3e2015-08-30 22:25:55 -050093 return TRUE;
94}
95
96
97
Norman Jamese2765102015-08-19 22:00:55 -050098static gboolean
Norman James3f97c5d2015-08-26 17:44:14 -050099on_set_power_state (ControlPower *pwr,
Norman Jamese2765102015-08-19 22:00:55 -0500100 GDBusMethodInvocation *invocation,
101 guint state,
102 gpointer user_data)
103{
Norman James362a80f2015-09-14 14:04:39 -0500104 Control* control = object_get_control((Object*)user_data);
Norman James32e74e22015-09-15 21:28:06 -0500105 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
Norman James3f97c5d2015-08-26 17:44:14 -0500106 if (state > 1)
107 {
108 g_dbus_method_invocation_return_dbus_error (invocation,
109 "org.openbmc.ControlPower.Error.Failed",
110 "Invalid power state");
111 return TRUE;
112 }
Norman James9e6acf92015-09-08 07:00:04 -0500113 // return from method call
114 control_power_complete_set_power_state(pwr,invocation);
Norman James3f97c5d2015-08-26 17:44:14 -0500115 if (state == control_power_get_state(pwr))
116 {
Norman James9e6acf92015-09-08 07:00:04 -0500117 g_print("Power already at requested state: %d\n",state);
Norman James3f97c5d2015-08-26 17:44:14 -0500118 }
Norman James9e6acf92015-09-08 07:00:04 -0500119 else
120 {
Norman James32e74e22015-09-15 21:28:06 -0500121 int error = 0;
122 do {
Norman James19e45912015-10-04 20:19:41 -0500123 if (state == 1) {
Norman Jamesa3e47c42015-10-18 14:43:10 -0500124 control_emit_goto_system_state(control,"HOST_POWERING_ON");
Norman James19e45912015-10-04 20:19:41 -0500125 } else {
Norman Jamesa3e47c42015-10-18 14:43:10 -0500126 control_emit_goto_system_state(control,"HOST_POWERING_OFF");
Norman James19e45912015-10-04 20:19:41 -0500127 }
Norman James32e74e22015-09-15 21:28:06 -0500128 error = gpio_open(&power_pin);
Norman James88872672015-09-21 16:51:35 -0500129 if (error != GPIO_OK) { break; }
Norman James32e74e22015-09-15 21:28:06 -0500130 error = gpio_write(&power_pin,!state);
Norman James88872672015-09-21 16:51:35 -0500131 if (error != GPIO_OK) { break; }
Norman James32e74e22015-09-15 21:28:06 -0500132 gpio_close(&power_pin);
133 control_power_set_state(pwr,state);
Norman James32e74e22015-09-15 21:28:06 -0500134 } while(0);
135 if (error != GPIO_OK)
Norman James362a80f2015-09-14 14:04:39 -0500136 {
Norman James2891c532015-10-06 08:01:56 -0500137 printf("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
Norman James362a80f2015-09-14 14:04:39 -0500138 }
Norman James9e6acf92015-09-08 07:00:04 -0500139 }
140 return TRUE;
141}
Norman Jamese2765102015-08-19 22:00:55 -0500142
Norman James9e6acf92015-09-08 07:00:04 -0500143static gboolean
144on_init (Control *control,
145 GDBusMethodInvocation *invocation,
146 gpointer user_data)
147{
Norman James88872672015-09-21 16:51:35 -0500148 pgood_timeout_start = 0;
Norman James8fee6f22015-10-28 12:48:43 -0500149 //guint poll_interval = control_get_poll_interval(control);
150 //g_timeout_add(poll_interval, poll_pgood, user_data);
Norman James9e6acf92015-09-08 07:00:04 -0500151 control_complete_init(control,invocation);
Norman James3f97c5d2015-08-26 17:44:14 -0500152 return TRUE;
Norman Jamese2765102015-08-19 22:00:55 -0500153}
154
155static gboolean
Norman James3f97c5d2015-08-26 17:44:14 -0500156on_get_power_state (ControlPower *pwr,
Norman Jamese2765102015-08-19 22:00:55 -0500157 GDBusMethodInvocation *invocation,
158 gpointer user_data)
159{
Norman James3f97c5d2015-08-26 17:44:14 -0500160 guint pgood = control_power_get_pgood(pwr);
161 control_power_complete_get_power_state(pwr,invocation,pgood);
162 return TRUE;
Norman Jamese2765102015-08-19 22:00:55 -0500163}
164
165static void
166on_bus_acquired (GDBusConnection *connection,
167 const gchar *name,
168 gpointer user_data)
169{
Norman James3f97c5d2015-08-26 17:44:14 -0500170 ObjectSkeleton *object;
Norman James10ff6a32015-08-27 14:24:17 -0500171 cmdline *cmd = user_data;
Norman James8fee6f22015-10-28 12:48:43 -0500172 if (cmd->argc < 3)
Norman James10ff6a32015-08-27 14:24:17 -0500173 {
Norman James8fee6f22015-10-28 12:48:43 -0500174 g_print("Usage: power_control.exe [poll interval] [timeout]\n");
Norman James10ff6a32015-08-27 14:24:17 -0500175 return;
176 }
177 manager = g_dbus_object_manager_server_new (dbus_object_path);
Norman James88872672015-09-21 16:51:35 -0500178 gchar *s;
Norman James8fee6f22015-10-28 12:48:43 -0500179 s = g_strdup_printf ("%s/%s",dbus_object_path,instance_name);
Norman James88872672015-09-21 16:51:35 -0500180 object = object_skeleton_new (s);
181 g_free (s);
Norman Jamese2765102015-08-19 22:00:55 -0500182
Norman James88872672015-09-21 16:51:35 -0500183 ControlPower* control_power = control_power_skeleton_new ();
184 object_skeleton_set_control_power (object, control_power);
185 g_object_unref (control_power);
186
187 Control* control = control_skeleton_new ();
188 object_skeleton_set_control (object, control);
189 g_object_unref (control);
Norman Jamese2765102015-08-19 22:00:55 -0500190
Norman James88872672015-09-21 16:51:35 -0500191 //define method callbacks here
192 g_signal_connect (control_power,
193 "handle-set-power-state",
194 G_CALLBACK (on_set_power_state),
195 object); /* user_data */
Norman Jamesce46e3e2015-08-30 22:25:55 -0500196
Norman James88872672015-09-21 16:51:35 -0500197 g_signal_connect (control_power,
198 "handle-get-power-state",
199 G_CALLBACK (on_get_power_state),
200 NULL); /* user_data */
Norman Jamese2765102015-08-19 22:00:55 -0500201
Norman James88872672015-09-21 16:51:35 -0500202 g_signal_connect (control,
203 "handle-init",
204 G_CALLBACK (on_init),
205 object); /* user_data */
Norman James9e6acf92015-09-08 07:00:04 -0500206
207
Norman James88872672015-09-21 16:51:35 -0500208 /* Export the object (@manager takes its own reference to @object) */
209 g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
210 g_object_unref (object);
Norman Jamesce46e3e2015-08-30 22:25:55 -0500211
Norman James3f97c5d2015-08-26 17:44:14 -0500212 /* Export all objects */
213 g_dbus_object_manager_server_set_connection (manager, connection);
214
215 // get gpio device paths
Norman Jamesbd4abd12015-09-16 22:43:46 -0500216 int rc = GPIO_OK;
Norman James32e74e22015-09-15 21:28:06 -0500217 do {
Norman James32e74e22015-09-15 21:28:06 -0500218 rc = gpio_init(connection,&power_pin);
219 if (rc != GPIO_OK) { break; }
220 rc = gpio_init(connection,&pgood);
221 if (rc != GPIO_OK) { break; }
Norman James65a295a2015-09-26 22:21:10 -0500222 uint8_t gpio;
Norman James32e74e22015-09-15 21:28:06 -0500223 rc = gpio_open(&pgood);
Norman James65a295a2015-09-26 22:21:10 -0500224 if (rc != GPIO_OK) { break; }
225 rc = gpio_read(&pgood,&gpio);
226 if (rc != GPIO_OK) { break; }
227 gpio_close(&pgood);
228 control_power_set_pgood(control_power,gpio);
Norman Jamesf66005a2015-10-08 15:11:44 -0500229 printf("Pgood state: %d\n",gpio);
Norman James32e74e22015-09-15 21:28:06 -0500230 } while(0);
Norman Jamesbd4abd12015-09-16 22:43:46 -0500231 if (rc != GPIO_OK)
232 {
Norman James2891c532015-10-06 08:01:56 -0500233 printf("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
Norman James8fee6f22015-10-28 12:48:43 -0500234 }
235 //start poll
236 pgood_timeout_start = 0;
237 int poll_interval = atoi(cmd->argv[1]);
238 int pgood_timeout = atoi(cmd->argv[2]);
239 if (poll_interval < 1000 || pgood_timeout <5) {
240 printf("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
241 } else {
242 control_set_poll_interval(control,poll_interval);
243 control_power_set_pgood_timeout(control_power,pgood_timeout);
244 g_timeout_add(poll_interval, poll_pgood, object);
245 }
246
Norman Jamese2765102015-08-19 22:00:55 -0500247}
248
249static void
250on_name_acquired (GDBusConnection *connection,
251 const gchar *name,
252 gpointer user_data)
253{
Norman Jamese2765102015-08-19 22:00:55 -0500254}
255
256static void
257on_name_lost (GDBusConnection *connection,
258 const gchar *name,
259 gpointer user_data)
260{
Norman Jamese2765102015-08-19 22:00:55 -0500261}
262
Norman Jamese2765102015-08-19 22:00:55 -0500263
Norman James3f97c5d2015-08-26 17:44:14 -0500264
265
266/*----------------------------------------------------------------*/
267/* Main Event Loop */
268
Norman Jamese2765102015-08-19 22:00:55 -0500269gint
270main (gint argc, gchar *argv[])
271{
272 GMainLoop *loop;
Norman James90caa3c2015-08-27 21:28:48 -0500273 cmdline cmd;
274 cmd.argc = argc;
275 cmd.argv = argv;
Norman Jamese2765102015-08-19 22:00:55 -0500276
277 guint id;
Norman Jamese2765102015-08-19 22:00:55 -0500278 loop = g_main_loop_new (NULL, FALSE);
279
Norman James5e792e32015-10-07 17:36:17 -0500280 id = g_bus_own_name (DBUS_TYPE,
Norman James26072c02015-08-25 07:14:29 -0500281 dbus_name,
Norman Jamese2765102015-08-19 22:00:55 -0500282 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
283 G_BUS_NAME_OWNER_FLAGS_REPLACE,
284 on_bus_acquired,
285 on_name_acquired,
286 on_name_lost,
Norman James90caa3c2015-08-27 21:28:48 -0500287 &cmd,
Norman Jamese2765102015-08-19 22:00:55 -0500288 NULL);
289
Norman Jamesce46e3e2015-08-30 22:25:55 -0500290 g_main_loop_run (loop);
Norman Jamese2765102015-08-19 22:00:55 -0500291
292 g_bus_unown_name (id);
293 g_main_loop_unref (loop);
294 return 0;
295}