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