1 #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 <openbmc_intf.h>
11 #include <openbmc.h>
12 #include <gpio.h>
13 #include <power_gpio.h>
14 
15 /* ------------------------------------------------------------------------- */
16 static const gchar* dbus_object_path = "/org/openbmc/control";
17 static const gchar* instance_name = "power0";
18 static const gchar* dbus_name = "org.openbmc.control.Power";
19 
20 static PowerGpio g_power_gpio;
21 
22 static GDBusObjectManagerServer *manager = NULL;
23 
24 time_t pgood_timeout_start = 0;
25 
26 // TODO:  Change to interrupt driven instead of polling
27 static gboolean
28 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);
32 
33 	//send the heartbeat
34 	guint poll_int = control_get_poll_interval(control);
35 	if(poll_int == 0)
36 	{
37 		g_print("ERROR PowerControl: Poll interval cannot be 0\n");
38 		return FALSE;
39 	}
40 	//handle timeout
41 	time_t current_time = time(NULL);
42 	if(difftime(current_time,pgood_timeout_start) > control_power_get_pgood_timeout(control_power)
43 			&& pgood_timeout_start != 0)
44 	{
45 		g_print("ERROR PowerControl: Pgood poll timeout\n");
46 		// set timeout to 0 so timeout doesn't happen again
47 		control_power_set_pgood_timeout(control_power,0);
48 		pgood_timeout_start = 0;
49 		return TRUE;
50 	}
51 	uint8_t pgood_state;
52 
53 	int rc = gpio_open(&g_power_gpio.power_good_in);
54 	if(rc != GPIO_OK) {
55 		g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
56 				g_power_gpio.power_good_in.name, rc);
57 		return FALSE;
58 	}
59 	rc = gpio_read(&g_power_gpio.power_good_in, &pgood_state);
60 	gpio_close(&g_power_gpio.power_good_in);
61 	if(rc == GPIO_OK)
62 	{
63 		//if changed, set property and emit signal
64 		if(pgood_state != control_power_get_pgood(control_power))
65 		{
66 			int i;
67 			uint8_t reset_state;
68 			control_power_set_pgood(control_power, pgood_state);
69 			if(pgood_state == 0)
70 			{
71 				control_power_emit_power_lost(control_power);
72 				control_emit_goto_system_state(control,"HOST_POWERED_OFF");
73 			}
74 			else
75 			{
76 				control_power_emit_power_good(control_power);
77 				control_emit_goto_system_state(control,"HOST_POWERED_ON");
78 			}
79 
80 			for(i = 0; i < g_power_gpio.num_reset_outs; i++)
81 			{
82 				GPIO *reset_out = &g_power_gpio.reset_outs[i];
83 				rc = gpio_open(reset_out);
84 				if(rc != GPIO_OK)
85 				{
86 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
87 							reset_out->name, rc);
88 					continue;
89 				}
90 
91 				reset_state = pgood_state ^ g_power_gpio.reset_pols[i];
92 				g_print("PowerControl: setting reset %s to %d\n", reset_out->name,
93 						(int)reset_state);
94 				gpio_write(reset_out, reset_state);
95 				gpio_close(reset_out);
96 			}
97 		}
98 	} else {
99 		g_print("ERROR PowerControl: GPIO read error (gpio=%s,rc=%d)\n",
100 				g_power_gpio.power_good_in.name, rc);
101 		//return false so poll won't get called anymore
102 		return FALSE;
103 	}
104 	//pgood is not at desired state yet
105 	if(pgood_state != control_power_get_state(control_power) &&
106 			control_power_get_pgood_timeout(control_power) > 0)
107 	{
108 		if(pgood_timeout_start == 0 ) {
109 			pgood_timeout_start = current_time;
110 		}
111 	}
112 	else
113 	{
114 		pgood_timeout_start = 0;
115 	}
116 	return TRUE;
117 }
118 
119 static gboolean
120 on_set_power_state(ControlPower *pwr,
121 		GDBusMethodInvocation *invocation,
122 		guint state,
123 		gpointer user_data)
124 {
125 	Control* control = object_get_control((Object*)user_data);
126 	if(state > 1)
127 	{
128 		g_dbus_method_invocation_return_dbus_error(invocation,
129 				"org.openbmc.ControlPower.Error.Failed",
130 				"Invalid power state");
131 		return TRUE;
132 	}
133 	// return from method call
134 	control_power_complete_set_power_state(pwr,invocation);
135 	if(state == control_power_get_state(pwr))
136 	{
137 		g_print("Power already at requested state: %d\n",state);
138 	}
139 	else
140 	{
141 		int error = 0;
142 		do {
143 			int i;
144 			uint8_t power_up_out;
145 			if(state == 1) {
146 				control_emit_goto_system_state(control,"HOST_POWERING_ON");
147 			} else {
148 				control_emit_goto_system_state(control,"HOST_POWERING_OFF");
149 			}
150 			for (i = 0; i < g_power_gpio.num_power_up_outs; i++) {
151 				GPIO *power_pin = &g_power_gpio.power_up_outs[i];
152 				error = gpio_open(power_pin);
153 				if(error != GPIO_OK) {
154 					g_print("ERROR PowerControl: GPIO open error (gpio=%s,rc=%d)\n",
155 							g_power_gpio.power_up_outs[i].name, error);
156 					continue;
157 				}
158 				power_up_out = state ^ g_power_gpio.power_up_pols[i];
159 				g_print("PowerControl: setting power up %s to %d\n",
160 						g_power_gpio.power_up_outs[i].name, (int)power_up_out);
161 				error = gpio_write(power_pin, power_up_out);
162 				if(error != GPIO_OK) {
163 					continue;
164 				}
165 				gpio_close(power_pin);
166 			}
167 			if(error != GPIO_OK) { break;	}
168 			control_power_set_state(pwr,state);
169 		} while(0);
170 		if(error != GPIO_OK)
171 		{
172 			g_print("ERROR PowerControl: GPIO set power state (rc=%d)\n",error);
173 		}
174 	}
175 	return TRUE;
176 }
177 
178 static gboolean
179 on_init(Control *control,
180 		GDBusMethodInvocation *invocation,
181 		gpointer user_data)
182 {
183 	pgood_timeout_start = 0;
184 	//guint poll_interval = control_get_poll_interval(control);
185 	//g_timeout_add(poll_interval, poll_pgood, user_data);
186 	control_complete_init(control,invocation);
187 	return TRUE;
188 }
189 
190 static gboolean
191 on_get_power_state(ControlPower *pwr,
192 		GDBusMethodInvocation *invocation,
193 		gpointer user_data)
194 {
195 	guint pgood = control_power_get_pgood(pwr);
196 	control_power_complete_get_power_state(pwr,invocation,pgood);
197 	return TRUE;
198 }
199 
200 static int
201 set_up_gpio(GDBusConnection *connection,
202 		PowerGpio *power_gpio,
203 		ControlPower* control_power)
204 {
205 	int error = GPIO_OK;
206 	int rc;
207 	int i;
208 	uint8_t pgood_state;
209 
210 	// get gpio device paths
211 	if(power_gpio->latch_out.name != NULL) {  /* latch is optional */
212 		rc = gpio_init(connection, &power_gpio->latch_out);
213 		if(rc != GPIO_OK) {
214 			error = rc;
215 		}
216 	}
217 	rc = gpio_init(connection, &power_gpio->power_good_in);
218 	if(rc != GPIO_OK) {
219 		error = rc;
220 	}
221 	for(int i = 0; i < power_gpio->num_power_up_outs; i++) {
222 		rc = gpio_init(connection, &power_gpio->power_up_outs[i]);
223 		if(rc != GPIO_OK) {
224 			error = rc;
225 		}
226 	}
227 	for(int i = 0; i < power_gpio->num_reset_outs; i++) {
228 		rc = gpio_init(connection, &power_gpio->reset_outs[i]);
229 		if(rc != GPIO_OK) {
230 			error = rc;
231 		}
232 	}
233 
234 	/* If there's a latch, it only needs to be set once. */
235 	if(power_gpio->latch_out.name != NULL) {
236 		do {
237 			rc = gpio_open(&power_gpio->latch_out);
238 			if(rc != GPIO_OK) {
239 				/* Failures are non-fatal. */
240 				break;
241 			}
242 			rc = gpio_write(&power_gpio->latch_out, 1);
243 			gpio_close(&power_gpio->latch_out);
244 		} while(0);
245 		if (rc != GPIO_OK) {
246 			error = rc;
247 			g_print("PowerControl ERROR failed to assert latch %s rc=%d\n",
248 					power_gpio->latch_out.name, rc);
249 		} else {
250 			g_print("PowerControl asserted latch %s\n", power_gpio->latch_out.name);
251 		}
252 	}
253 
254 	rc = gpio_open(&power_gpio->power_good_in);
255 	if(rc != GPIO_OK) {
256 		return rc;
257 	}
258 	rc = gpio_read(&power_gpio->power_good_in, &pgood_state);
259 	if(rc != GPIO_OK) {
260 		return rc;
261 	}
262 	gpio_close(&power_gpio->power_good_in);
263 	control_power_set_pgood(control_power, pgood_state);
264 	control_power_set_state(control_power, pgood_state);
265 	g_print("Pgood state: %d\n", pgood_state);
266 
267 	return error;
268 }
269 
270 static void
271 on_bus_acquired(GDBusConnection *connection,
272 		const gchar *name,
273 		gpointer user_data)
274 {
275 	ObjectSkeleton *object;
276 	cmdline *cmd = user_data;
277 	if(cmd->argc < 3)
278 	{
279 		g_print("Usage: power_control.exe [poll interval] [timeout]\n");
280 		return;
281 	}
282 	manager = g_dbus_object_manager_server_new(dbus_object_path);
283 	gchar *s;
284 	s = g_strdup_printf("%s/%s",dbus_object_path,instance_name);
285 	object = object_skeleton_new(s);
286 	g_free(s);
287 
288 	ControlPower* control_power = control_power_skeleton_new();
289 	object_skeleton_set_control_power(object, control_power);
290 	g_object_unref(control_power);
291 
292 	Control* control = control_skeleton_new();
293 	object_skeleton_set_control(object, control);
294 	g_object_unref(control);
295 
296 	//define method callbacks here
297 	g_signal_connect(control_power,
298 			"handle-set-power-state",
299 			G_CALLBACK(on_set_power_state),
300 			object); /* user_data */
301 
302 	g_signal_connect(control_power,
303 			"handle-get-power-state",
304 			G_CALLBACK(on_get_power_state),
305 			NULL); /* user_data */
306 
307 	g_signal_connect(control,
308 			"handle-init",
309 			G_CALLBACK(on_init),
310 			object); /* user_data */
311 
312 
313 	/* Export the object (@manager takes its own reference to @object) */
314 	g_dbus_object_manager_server_set_connection(manager, connection);
315 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
316 	g_object_unref(object);
317 
318 	if(read_power_gpio(connection, &g_power_gpio) != TRUE) {
319 		g_print("ERROR PowerControl: could not read power GPIO configuration\n");
320 	}
321 
322 	int rc = set_up_gpio(connection, &g_power_gpio, control_power);
323 	if(rc != GPIO_OK) {
324 		g_print("ERROR PowerControl: GPIO setup (rc=%d)\n",rc);
325 	}
326 	//start poll
327 	pgood_timeout_start = 0;
328 	int poll_interval = atoi(cmd->argv[1]);
329 	int pgood_timeout = atoi(cmd->argv[2]);
330 	if(poll_interval < 1000 || pgood_timeout <5) {
331 		g_print("ERROR PowerControl: poll_interval < 1000 or pgood_timeout < 5\n");
332 	} else {
333 		control_set_poll_interval(control,poll_interval);
334 		control_power_set_pgood_timeout(control_power,pgood_timeout);
335 		g_timeout_add(poll_interval, poll_pgood, object);
336 	}
337 }
338 
339 static void
340 on_name_acquired(GDBusConnection *connection,
341 		const gchar *name,
342 		gpointer user_data)
343 {
344 }
345 
346 static void
347 on_name_lost(GDBusConnection *connection,
348 		const gchar *name,
349 		gpointer user_data)
350 {
351 	free_power_gpio(&g_power_gpio);
352 }
353 
354 /*----------------------------------------------------------------*/
355 /* Main Event Loop                                                */
356 
357 gint
358 main(gint argc, gchar *argv[])
359 {
360 	GMainLoop *loop;
361 	cmdline cmd;
362 	cmd.argc = argc;
363 	cmd.argv = argv;
364 
365 	guint id;
366 	loop = g_main_loop_new(NULL, FALSE);
367 
368 	id = g_bus_own_name(DBUS_TYPE,
369 			dbus_name,
370 			G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
371 			G_BUS_NAME_OWNER_FLAGS_REPLACE,
372 			on_bus_acquired,
373 			on_name_acquired,
374 			on_name_lost,
375 			&cmd,
376 			NULL);
377 
378 	g_main_loop_run(loop);
379 
380 	g_bus_unown_name(id);
381 	g_main_loop_unref(loop);
382 	return 0;
383 }
384