blob: 72947f501e9c14bf23d0d40cad3bf9dd1bc02c45 [file] [log] [blame]
Brad Bishop77390492016-04-13 10:47:19 -04001#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>
9#include <syslog.h>
10#include "interfaces/openbmc_intf.h"
11#include "openbmc.h"
12#include "gpio.h"
13#include "object_mapper.h"
14
15/* ------------------------------------------------------------------------- */
16static const gchar* dbus_object_path = "/org/openbmc/control";
17static const gchar* instance_name = "power0";
18static const gchar* dbus_name = "org.openbmc.control.Power";
19
20//This object will use these GPIOs
21GPIO power_pin = (GPIO){ "POWER_PIN" };
22GPIO pgood = (GPIO){ "PGOOD" };
23GPIO usb_reset = (GPIO){ "USB_RESET" };
24GPIO pcie_reset = (GPIO){ "PCIE_RESET" };
25
26
27static GDBusObjectManagerServer *manager = NULL;
28
29time_t pgood_timeout_start = 0;
30
31// TODO: Change to interrupt driven instead of polling
32static gboolean
33poll_pgood(gpointer user_data)
34{
35 ControlPower *control_power = object_get_control_power((Object*)user_data);
36 Control* control = object_get_control((Object*)user_data);
37
38 //send the heartbeat
39 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
40
41 guint poll_int = control_get_poll_interval(control);
42 if(poll_int == 0)
43 {
44 printf("ERROR PowerControl: Poll interval cannot be 0\n");
45 return FALSE;
46 }
47 //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)
51 {
52 printf("ERROR PowerControl: Pgood poll timeout\n");
53 // set timeout to 0 so timeout doesn't happen again
54 control_power_set_pgood_timeout(control_power,0);
55 pgood_timeout_start = 0;
56 return TRUE;
57 }
58 uint8_t gpio;
59
60 int rc = gpio_open(&pgood);
61 rc = gpio_read(&pgood,&gpio);
62 gpio_close(&pgood);
63 if(rc == GPIO_OK)
64 {
65 //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);
72 control_emit_goto_system_state(control,"HOST_POWERED_OFF");
73 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
81 }
82 else
83 {
84 control_power_emit_power_good(control_power);
85 control_emit_goto_system_state(control,"HOST_POWERED_ON");
86 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);
93 }
94 }
95 } else {
96 printf("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",pgood.name,rc);
97 //return false so poll won't get called anymore
98 return FALSE;
99 }
100 //pgood is not at desired state yet
101 if(gpio != control_power_get_state(control_power) &&
102 control_power_get_pgood_timeout(control_power) > 0)
103 {
104 if(pgood_timeout_start == 0 ) {
105 pgood_timeout_start = current_time;
106 }
107 }
108 else
109 {
110 pgood_timeout_start = 0;
111 }
112 return TRUE;
113}
114
115static gboolean
116on_set_power_state(ControlPower *pwr,
117 GDBusMethodInvocation *invocation,
118 guint state,
119 gpointer user_data)
120{
121 Control* control = object_get_control((Object*)user_data);
122 const gchar* obj_path = g_dbus_object_get_object_path((GDBusObject*)user_data);
123 if(state > 1)
124 {
125 g_dbus_method_invocation_return_dbus_error(invocation,
126 "org.openbmc.ControlPower.Error.Failed",
127 "Invalid power state");
128 return TRUE;
129 }
130 // return from method call
131 control_power_complete_set_power_state(pwr,invocation);
132 if(state == control_power_get_state(pwr))
133 {
134 g_print("Power already at requested state: %d\n",state);
135 }
136 else
137 {
138 int error = 0;
139 do {
140 if(state == 1) {
141 control_emit_goto_system_state(control,"HOST_POWERING_ON");
142 } else {
143 control_emit_goto_system_state(control,"HOST_POWERING_OFF");
144 }
145 error = gpio_open(&power_pin);
146 if(error != GPIO_OK) { break; }
147 error = gpio_write(&power_pin,!state);
148 if(error != GPIO_OK) { break; }
149 gpio_close(&power_pin);
150 control_power_set_state(pwr,state);
151 } while(0);
152 if(error != GPIO_OK)
153 {
154 printf("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
155 }
156 }
157 return TRUE;
158}
159
160static gboolean
161on_init(Control *control,
162 GDBusMethodInvocation *invocation,
163 gpointer user_data)
164{
165 pgood_timeout_start = 0;
166 //guint poll_interval = control_get_poll_interval(control);
167 //g_timeout_add(poll_interval, poll_pgood, user_data);
168 control_complete_init(control,invocation);
169 return TRUE;
170}
171
172static gboolean
173on_get_power_state(ControlPower *pwr,
174 GDBusMethodInvocation *invocation,
175 gpointer user_data)
176{
177 guint pgood = control_power_get_pgood(pwr);
178 control_power_complete_get_power_state(pwr,invocation,pgood);
179 return TRUE;
180}
181
182static void
183on_bus_acquired(GDBusConnection *connection,
184 const gchar *name,
185 gpointer user_data)
186{
187 ObjectSkeleton *object;
188 cmdline *cmd = user_data;
189 if(cmd->argc < 3)
190 {
191 g_print("Usage: power_control.exe [poll interval] [timeout]\n");
192 return;
193 }
194 manager = g_dbus_object_manager_server_new(dbus_object_path);
195 gchar *s;
196 s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
197 object = object_skeleton_new(s);
198 g_free(s);
199
200 ControlPower* control_power = control_power_skeleton_new();
201 object_skeleton_set_control_power(object, control_power);
202 g_object_unref(control_power);
203
204 Control* control = control_skeleton_new();
205 object_skeleton_set_control(object, control);
206 g_object_unref(control);
207
208 ObjectMapper* mapper = object_mapper_skeleton_new();
209 object_skeleton_set_object_mapper(object, mapper);
210 g_object_unref(mapper);
211
212 //define method callbacks here
213 g_signal_connect(control_power,
214 "handle-set-power-state",
215 G_CALLBACK(on_set_power_state),
216 object); /* user_data */
217
218 g_signal_connect(control_power,
219 "handle-get-power-state",
220 G_CALLBACK(on_get_power_state),
221 NULL); /* user_data */
222
223 g_signal_connect(control,
224 "handle-init",
225 G_CALLBACK(on_init),
226 object); /* user_data */
227
228
229 /* Export the object (@manager takes its own reference to @object) */
230 g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
231 g_object_unref(object);
232
233 /* Export all objects */
234 g_dbus_object_manager_server_set_connection(manager, connection);
235
236 // get gpio device paths
237 int rc = GPIO_OK;
238 do {
239 rc = gpio_init(connection,&power_pin);
240 if(rc != GPIO_OK) { break; }
241 rc = gpio_init(connection,&pgood);
242 if(rc != GPIO_OK) { break; }
243 rc = gpio_init(connection,&pcie_reset);
244 if(rc != GPIO_OK) { break; }
245 rc = gpio_init(connection,&usb_reset);
246 if(rc != GPIO_OK) { break; }
247
248 uint8_t gpio;
249 rc = gpio_open(&pgood);
250 if(rc != GPIO_OK) { break; }
251 rc = gpio_read(&pgood,&gpio);
252 if(rc != GPIO_OK) { break; }
253 gpio_close(&pgood);
254 control_power_set_pgood(control_power,gpio);
255 control_power_set_state(control_power,gpio);
256 printf("Pgood state: %d\n",gpio);
257
258 } while(0);
259 if(rc != GPIO_OK)
260 {
261 printf("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
262 }
263 //start poll
264 pgood_timeout_start = 0;
265 int poll_interval = atoi(cmd->argv[1]);
266 int pgood_timeout = atoi(cmd->argv[2]);
267 if(poll_interval < 1000 || pgood_timeout <5) {
268 printf("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
269 } else {
270 control_set_poll_interval(control,poll_interval);
271 control_power_set_pgood_timeout(control_power,pgood_timeout);
272 g_timeout_add(poll_interval, poll_pgood, object);
273 }
274 emit_object_added((GDBusObjectManager*)manager);
275}
276
277static void
278on_name_acquired(GDBusConnection *connection,
279 const gchar *name,
280 gpointer user_data)
281{
282}
283
284static void
285on_name_lost(GDBusConnection *connection,
286 const gchar *name,
287 gpointer user_data)
288{
289}
290
291/*----------------------------------------------------------------*/
292/* Main Event Loop */
293
294gint
295main(gint argc, gchar *argv[])
296{
297 GMainLoop *loop;
298 cmdline cmd;
299 cmd.argc = argc;
300 cmd.argv = argv;
301
302 guint id;
303 loop = g_main_loop_new(NULL, FALSE);
304
305 id = g_bus_own_name(DBUS_TYPE,
306 dbus_name,
307 G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
308 G_BUS_NAME_OWNER_FLAGS_REPLACE,
309 on_bus_acquired,
310 on_name_acquired,
311 on_name_lost,
312 &cmd,
313 NULL);
314
315 g_main_loop_run(loop);
316
317 g_bus_unown_name(id);
318 g_main_loop_unref(loop);
319 return 0;
320}