blob: 54210745ead42ab7acf6055713aa8b689e5f9654 [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 Jamescfc2b442015-10-31 17:31:46 -050013#include "object_mapper.h"
Norman Jamese2765102015-08-19 22:00:55 -050014
15/* ---------------------------------------------------------------------------------------------------- */
Norman James362a80f2015-09-14 14:04:39 -050016static const gchar* dbus_object_path = "/org/openbmc/control";
Norman James8fee6f22015-10-28 12:48:43 -050017static const gchar* instance_name = "power0";
Norman James26072c02015-08-25 07:14:29 -050018static const gchar* dbus_name = "org.openbmc.control.Power";
19
Norman James32e74e22015-09-15 21:28:06 -050020//This object will use these GPIOs
Norman James3f97c5d2015-08-26 17:44:14 -050021GPIO power_pin = (GPIO){ "POWER_PIN" };
22GPIO pgood = (GPIO){ "PGOOD" };
Norman Jamescfc2b442015-10-31 17:31:46 -050023GPIO usb_reset = (GPIO){ "USB_RESET" };
24GPIO pcie_reset = (GPIO){ "PCIE_RESET" };
25
Norman Jamese2765102015-08-19 22:00:55 -050026
27static GDBusObjectManagerServer *manager = NULL;
Norman Jamese2765102015-08-19 22:00:55 -050028
Norman James88872672015-09-21 16:51:35 -050029time_t pgood_timeout_start = 0;
Norman James362a80f2015-09-14 14:04:39 -050030
Norman James3d3b7fb2015-10-06 16:54:06 -050031// TODO: Change to interrupt driven instead of polling
Norman Jamesce46e3e2015-08-30 22:25:55 -050032static gboolean poll_pgood(gpointer user_data)
33{
34 ControlPower *control_power = object_get_control_power((Object*)user_data);
35 Control* control = object_get_control((Object*)user_data);
Norman Jamesbd4abd12015-09-16 22:43:46 -050036
37 //send the heartbeat
Norman Jamesce46e3e2015-08-30 22:25:55 -050038 control_emit_heartbeat(control,dbus_name);
Norman James32e74e22015-09-15 21:28:06 -050039 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
Norman Jamesce46e3e2015-08-30 22:25:55 -050040
Norman James6a1283c2015-09-16 22:21:11 -050041 guint poll_int = control_get_poll_interval(control);
42 if (poll_int == 0)
43 {
Norman James2891c532015-10-06 08:01:56 -050044 printf("ERROR PowerControl: Poll interval cannot be 0\n");
Norman James6a1283c2015-09-16 22:21:11 -050045 return FALSE;
46 }
Norman James88872672015-09-21 16:51:35 -050047 //handle timeout
48 time_t current_time = time(NULL);
49 if (difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
50 && pgood_timeout_start != 0)
Norman James32e74e22015-09-15 21:28:06 -050051 {
Norman James2891c532015-10-06 08:01:56 -050052 printf("ERROR PowerControl: Pgood poll timeout\n");
Norman Jamesbd4abd12015-09-16 22:43:46 -050053 // set timeout to 0 so timeout doesn't happen again
Norman James32e74e22015-09-15 21:28:06 -050054 control_power_set_pgood_timeout(control_power,0);
Norman James88872672015-09-21 16:51:35 -050055 pgood_timeout_start = 0;
Norman James8abb50c2015-09-16 10:58:16 -050056 return TRUE;
Norman James32e74e22015-09-15 21:28:06 -050057 }
Norman James32e74e22015-09-15 21:28:06 -050058 uint8_t gpio;
Norman James88872672015-09-21 16:51:35 -050059
60 int rc = gpio_open(&pgood);
61 rc = gpio_read(&pgood,&gpio);
62 gpio_close(&pgood);
Norman James32e74e22015-09-15 21:28:06 -050063 if (rc == GPIO_OK)
Norman James362a80f2015-09-14 14:04:39 -050064 {
Norman James32e74e22015-09-15 21:28:06 -050065 //if changed, set property and emit signal
66 if (gpio != control_power_get_pgood(control_power))
67 {
68 control_power_set_pgood(control_power,gpio);
69 if (gpio==0)
70 {
71 control_power_emit_power_lost(control_power);
Norman Jamesa3e47c42015-10-18 14:43:10 -050072 control_emit_goto_system_state(control,"HOST_POWERED_OFF");
Norman Jamescfc2b442015-10-31 17:31:46 -050073 rc = gpio_open(&pcie_reset);
74 rc = gpio_write(&pcie_reset,0);
75 gpio_close(&pcie_reset);
76
77 rc = gpio_open(&usb_reset);
78 rc = gpio_write(&usb_reset,0);
79 gpio_close(&usb_reset);
80
Norman James32e74e22015-09-15 21:28:06 -050081 }
82 else
83 {
84 control_power_emit_power_good(control_power);
Norman Jamesa3e47c42015-10-18 14:43:10 -050085 control_emit_goto_system_state(control,"HOST_POWERED_ON");
Norman Jamescfc2b442015-10-31 17:31:46 -050086 rc = gpio_open(&pcie_reset);
87 rc = gpio_write(&pcie_reset,1);
88 gpio_close(&pcie_reset);
89
90 rc = gpio_open(&usb_reset);
91 rc = gpio_write(&usb_reset,1);
92 gpio_close(&usb_reset);
Norman James32e74e22015-09-15 21:28:06 -050093 }
94 }
95 } else {
Norman James2891c532015-10-06 08:01:56 -050096 printf("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",pgood.name,rc);
Norman Jamesa3e47c42015-10-18 14:43:10 -050097 //return false so poll won't get called anymore
98 return FALSE;
Norman James32e74e22015-09-15 21:28:06 -050099 }
100 //pgood is not at desired state yet
101 if (gpio != control_power_get_state(control_power) &&
Norman James88872672015-09-21 16:51:35 -0500102 control_power_get_pgood_timeout(control_power) > 0)
Norman James32e74e22015-09-15 21:28:06 -0500103 {
Norman James88872672015-09-21 16:51:35 -0500104 if (pgood_timeout_start == 0 ) {
105 pgood_timeout_start = current_time;
106 }
Norman James32e74e22015-09-15 21:28:06 -0500107 }
108 else
109 {
Norman James88872672015-09-21 16:51:35 -0500110 pgood_timeout_start = 0;
Norman James362a80f2015-09-14 14:04:39 -0500111 }
Norman Jamesce46e3e2015-08-30 22:25:55 -0500112 return TRUE;
113}
114
115
116
Norman Jamese2765102015-08-19 22:00:55 -0500117static gboolean
Norman James3f97c5d2015-08-26 17:44:14 -0500118on_set_power_state (ControlPower *pwr,
Norman Jamese2765102015-08-19 22:00:55 -0500119 GDBusMethodInvocation *invocation,
120 guint state,
121 gpointer user_data)
122{
Norman James362a80f2015-09-14 14:04:39 -0500123 Control* control = object_get_control((Object*)user_data);
Norman James32e74e22015-09-15 21:28:06 -0500124 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
Norman James3f97c5d2015-08-26 17:44:14 -0500125 if (state > 1)
126 {
127 g_dbus_method_invocation_return_dbus_error (invocation,
128 "org.openbmc.ControlPower.Error.Failed",
129 "Invalid power state");
130 return TRUE;
131 }
Norman James9e6acf92015-09-08 07:00:04 -0500132 // return from method call
133 control_power_complete_set_power_state(pwr,invocation);
Norman James3f97c5d2015-08-26 17:44:14 -0500134 if (state == control_power_get_state(pwr))
135 {
Norman James9e6acf92015-09-08 07:00:04 -0500136 g_print("Power already at requested state: %d\n",state);
Norman James3f97c5d2015-08-26 17:44:14 -0500137 }
Norman James9e6acf92015-09-08 07:00:04 -0500138 else
139 {
Norman James32e74e22015-09-15 21:28:06 -0500140 int error = 0;
141 do {
Norman James19e45912015-10-04 20:19:41 -0500142 if (state == 1) {
Norman Jamesa3e47c42015-10-18 14:43:10 -0500143 control_emit_goto_system_state(control,"HOST_POWERING_ON");
Norman James19e45912015-10-04 20:19:41 -0500144 } else {
Norman Jamesa3e47c42015-10-18 14:43:10 -0500145 control_emit_goto_system_state(control,"HOST_POWERING_OFF");
Norman James19e45912015-10-04 20:19:41 -0500146 }
Norman James32e74e22015-09-15 21:28:06 -0500147 error = gpio_open(&power_pin);
Norman James88872672015-09-21 16:51:35 -0500148 if (error != GPIO_OK) { break; }
Norman James32e74e22015-09-15 21:28:06 -0500149 error = gpio_write(&power_pin,!state);
Norman James88872672015-09-21 16:51:35 -0500150 if (error != GPIO_OK) { break; }
Norman James32e74e22015-09-15 21:28:06 -0500151 gpio_close(&power_pin);
152 control_power_set_state(pwr,state);
Norman James32e74e22015-09-15 21:28:06 -0500153 } while(0);
154 if (error != GPIO_OK)
Norman James362a80f2015-09-14 14:04:39 -0500155 {
Norman James2891c532015-10-06 08:01:56 -0500156 printf("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
Norman James362a80f2015-09-14 14:04:39 -0500157 }
Norman James9e6acf92015-09-08 07:00:04 -0500158 }
159 return TRUE;
160}
Norman Jamese2765102015-08-19 22:00:55 -0500161
Norman James9e6acf92015-09-08 07:00:04 -0500162static gboolean
163on_init (Control *control,
164 GDBusMethodInvocation *invocation,
165 gpointer user_data)
166{
Norman James88872672015-09-21 16:51:35 -0500167 pgood_timeout_start = 0;
Norman James8fee6f22015-10-28 12:48:43 -0500168 //guint poll_interval = control_get_poll_interval(control);
169 //g_timeout_add(poll_interval, poll_pgood, user_data);
Norman James9e6acf92015-09-08 07:00:04 -0500170 control_complete_init(control,invocation);
Norman James3f97c5d2015-08-26 17:44:14 -0500171 return TRUE;
Norman Jamese2765102015-08-19 22:00:55 -0500172}
173
174static gboolean
Norman James3f97c5d2015-08-26 17:44:14 -0500175on_get_power_state (ControlPower *pwr,
Norman Jamese2765102015-08-19 22:00:55 -0500176 GDBusMethodInvocation *invocation,
177 gpointer user_data)
178{
Norman James3f97c5d2015-08-26 17:44:14 -0500179 guint pgood = control_power_get_pgood(pwr);
180 control_power_complete_get_power_state(pwr,invocation,pgood);
181 return TRUE;
Norman Jamese2765102015-08-19 22:00:55 -0500182}
183
184static void
185on_bus_acquired (GDBusConnection *connection,
186 const gchar *name,
187 gpointer user_data)
188{
Norman James3f97c5d2015-08-26 17:44:14 -0500189 ObjectSkeleton *object;
Norman James10ff6a32015-08-27 14:24:17 -0500190 cmdline *cmd = user_data;
Norman James8fee6f22015-10-28 12:48:43 -0500191 if (cmd->argc < 3)
Norman James10ff6a32015-08-27 14:24:17 -0500192 {
Norman James8fee6f22015-10-28 12:48:43 -0500193 g_print("Usage: power_control.exe [poll interval] [timeout]\n");
Norman James10ff6a32015-08-27 14:24:17 -0500194 return;
195 }
196 manager = g_dbus_object_manager_server_new (dbus_object_path);
Norman James88872672015-09-21 16:51:35 -0500197 gchar *s;
Norman James8fee6f22015-10-28 12:48:43 -0500198 s = g_strdup_printf ("%s/%s",dbus_object_path,instance_name);
Norman James88872672015-09-21 16:51:35 -0500199 object = object_skeleton_new (s);
200 g_free (s);
Norman Jamese2765102015-08-19 22:00:55 -0500201
Norman James88872672015-09-21 16:51:35 -0500202 ControlPower* control_power = control_power_skeleton_new ();
203 object_skeleton_set_control_power (object, control_power);
204 g_object_unref (control_power);
205
206 Control* control = control_skeleton_new ();
207 object_skeleton_set_control (object, control);
208 g_object_unref (control);
Norman Jamese2765102015-08-19 22:00:55 -0500209
Norman Jamescfc2b442015-10-31 17:31:46 -0500210 ObjectMapper* mapper = object_mapper_skeleton_new ();
211 object_skeleton_set_object_mapper (object, mapper);
212 g_object_unref (mapper);
213
Norman James88872672015-09-21 16:51:35 -0500214 //define method callbacks here
215 g_signal_connect (control_power,
216 "handle-set-power-state",
217 G_CALLBACK (on_set_power_state),
218 object); /* user_data */
Norman Jamesce46e3e2015-08-30 22:25:55 -0500219
Norman James88872672015-09-21 16:51:35 -0500220 g_signal_connect (control_power,
221 "handle-get-power-state",
222 G_CALLBACK (on_get_power_state),
223 NULL); /* user_data */
Norman Jamese2765102015-08-19 22:00:55 -0500224
Norman James88872672015-09-21 16:51:35 -0500225 g_signal_connect (control,
226 "handle-init",
227 G_CALLBACK (on_init),
228 object); /* user_data */
Norman James9e6acf92015-09-08 07:00:04 -0500229
230
Norman James88872672015-09-21 16:51:35 -0500231 /* Export the object (@manager takes its own reference to @object) */
232 g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
233 g_object_unref (object);
Norman Jamesce46e3e2015-08-30 22:25:55 -0500234
Norman James3f97c5d2015-08-26 17:44:14 -0500235 /* Export all objects */
236 g_dbus_object_manager_server_set_connection (manager, connection);
237
238 // get gpio device paths
Norman Jamesbd4abd12015-09-16 22:43:46 -0500239 int rc = GPIO_OK;
Norman James32e74e22015-09-15 21:28:06 -0500240 do {
Norman James32e74e22015-09-15 21:28:06 -0500241 rc = gpio_init(connection,&power_pin);
242 if (rc != GPIO_OK) { break; }
243 rc = gpio_init(connection,&pgood);
244 if (rc != GPIO_OK) { break; }
Norman Jamescfc2b442015-10-31 17:31:46 -0500245 rc = gpio_init(connection,&pcie_reset);
246 if (rc != GPIO_OK) { break; }
247 rc = gpio_init(connection,&usb_reset);
248 if (rc != GPIO_OK) { break; }
249
Norman James65a295a2015-09-26 22:21:10 -0500250 uint8_t gpio;
Norman James32e74e22015-09-15 21:28:06 -0500251 rc = gpio_open(&pgood);
Norman James65a295a2015-09-26 22:21:10 -0500252 if (rc != GPIO_OK) { break; }
253 rc = gpio_read(&pgood,&gpio);
254 if (rc != GPIO_OK) { break; }
255 gpio_close(&pgood);
256 control_power_set_pgood(control_power,gpio);
Norman Jamesf66005a2015-10-08 15:11:44 -0500257 printf("Pgood state: %d\n",gpio);
Norman Jamescfc2b442015-10-31 17:31:46 -0500258
Norman James32e74e22015-09-15 21:28:06 -0500259 } while(0);
Norman Jamesbd4abd12015-09-16 22:43:46 -0500260 if (rc != GPIO_OK)
261 {
Norman James2891c532015-10-06 08:01:56 -0500262 printf("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
Norman James8fee6f22015-10-28 12:48:43 -0500263 }
264 //start poll
265 pgood_timeout_start = 0;
266 int poll_interval = atoi(cmd->argv[1]);
267 int pgood_timeout = atoi(cmd->argv[2]);
268 if (poll_interval < 1000 || pgood_timeout <5) {
269 printf("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
270 } else {
271 control_set_poll_interval(control,poll_interval);
272 control_power_set_pgood_timeout(control_power,pgood_timeout);
273 g_timeout_add(poll_interval, poll_pgood, object);
274 }
Norman Jamescfc2b442015-10-31 17:31:46 -0500275 emit_object_added((GDBusObjectManager*)manager);
Norman Jamese2765102015-08-19 22:00:55 -0500276}
277
278static void
279on_name_acquired (GDBusConnection *connection,
280 const gchar *name,
281 gpointer user_data)
282{
Norman Jamese2765102015-08-19 22:00:55 -0500283}
284
285static void
286on_name_lost (GDBusConnection *connection,
287 const gchar *name,
288 gpointer user_data)
289{
Norman Jamese2765102015-08-19 22:00:55 -0500290}
291
Norman Jamese2765102015-08-19 22:00:55 -0500292
Norman James3f97c5d2015-08-26 17:44:14 -0500293
294
295/*----------------------------------------------------------------*/
296/* Main Event Loop */
297
Norman Jamese2765102015-08-19 22:00:55 -0500298gint
299main (gint argc, gchar *argv[])
300{
301 GMainLoop *loop;
Norman James90caa3c2015-08-27 21:28:48 -0500302 cmdline cmd;
303 cmd.argc = argc;
304 cmd.argv = argv;
Norman Jamese2765102015-08-19 22:00:55 -0500305
306 guint id;
Norman Jamese2765102015-08-19 22:00:55 -0500307 loop = g_main_loop_new (NULL, FALSE);
308
Norman James5e792e32015-10-07 17:36:17 -0500309 id = g_bus_own_name (DBUS_TYPE,
Norman James26072c02015-08-25 07:14:29 -0500310 dbus_name,
Norman Jamese2765102015-08-19 22:00:55 -0500311 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
312 G_BUS_NAME_OWNER_FLAGS_REPLACE,
313 on_bus_acquired,
314 on_name_acquired,
315 on_name_lost,
Norman James90caa3c2015-08-27 21:28:48 -0500316 &cmd,
Norman Jamese2765102015-08-19 22:00:55 -0500317 NULL);
318
Norman Jamesce46e3e2015-08-30 22:25:55 -0500319 g_main_loop_run (loop);
Norman Jamese2765102015-08-19 22:00:55 -0500320
321 g_bus_unown_name (id);
322 g_main_loop_unref (loop);
323 return 0;
324}