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