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