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 
14 /* ------------------------------------------------------------------------- */
15 static const gchar* dbus_object_path = "/org/openbmc/control";
16 static const gchar* instance_name = "power0";
17 static const gchar* dbus_name = "org.openbmc.control.Power";
18 
19 //This object will use these GPIOs
20 GPIO power_pin    = (GPIO){ "POWER_PIN" };
21 GPIO pgood        = (GPIO){ "PGOOD" };
22 GPIO usb_reset    = (GPIO){ "USB_RESET" };
23 GPIO pcie_reset   = (GPIO){ "PCIE_RESET" };
24 
25 
26 static GDBusObjectManagerServer *manager = NULL;
27 
28 time_t pgood_timeout_start = 0;
29 
30 // TODO:  Change to interrupt driven instead of polling
31 static gboolean
32 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);
36 
37 	//send the heartbeat
38 	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 
112 static gboolean
113 on_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);
119 	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 
156 static gboolean
157 on_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 
168 static gboolean
169 on_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 
178 static void
179 on_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 
204 	//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) */
222 	g_dbus_object_manager_server_set_connection(manager, connection);
223 	g_dbus_object_manager_server_export(manager, G_DBUS_OBJECT_SKELETON(object));
224 	g_object_unref(object);
225 
226 	// 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 	}
264 }
265 
266 static void
267 on_name_acquired(GDBusConnection *connection,
268 		const gchar *name,
269 		gpointer user_data)
270 {
271 }
272 
273 static void
274 on_name_lost(GDBusConnection *connection,
275 		const gchar *name,
276 		gpointer user_data)
277 {
278 }
279 
280 /*----------------------------------------------------------------*/
281 /* Main Event Loop                                                */
282 
283 gint
284 main(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 }
310