Prex Home / Browse Source - Prex Version: 0.9.0

root/usr/server/pow/pow.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pow_noop
  2. pow_set_power
  3. pow_get_policy
  4. pow_set_policy
  5. pow_get_sustmr
  6. pow_set_sustmr
  7. pow_get_dimtmr
  8. pow_set_dimtmr
  9. pow_battery_lvl
  10. set_power_state
  11. exception_handler
  12. power_thread
  13. run_thread
  14. pow_init
  15. register_process
  16. wait_server
  17. shutdown_server
  18. pow_debug
  19. main

   1 /*-
   2  * Copyright (c) 2009, Kohsuke Ohtani
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the author nor the names of any co-contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * pow.c - power server
  32  */
  33 
  34 #include <sys/prex.h>
  35 #include <sys/mount.h>
  36 #include <sys/ioctl.h>
  37 #include <ipc/proc.h>
  38 #include <ipc/pow.h>
  39 #include <ipc/exec.h>
  40 #include <ipc/ipc.h>
  41 
  42 #include <unistd.h>
  43 #include <string.h>
  44 #include <stdlib.h>
  45 #include <stdio.h>
  46 #include <signal.h>
  47 #include <errno.h>
  48 
  49 /* #define DEBUG_POW 1 */
  50 
  51 #ifdef DEBUG_POW
  52 #define DPRINTF(a) dprintf a
  53 #else
  54 #define DPRINTF(a)
  55 #endif
  56 
  57 /*
  58  * Action for each power event.
  59  */
  60 struct power_action {
  61         int     pwrbtn;         /* state for power button press */
  62         int     slpbtn;         /* state for sleep button press */
  63         int     lcdclose;       /* state for LCD close */
  64         int     lowbatt;        /* state for low battery */
  65 };
  66 
  67 static int pow_noop(struct msg *);
  68 static int pow_set_power(struct msg *);
  69 static int pow_get_policy(struct msg *);
  70 static int pow_set_policy(struct msg *);
  71 static int pow_get_sustmr(struct msg *);
  72 static int pow_set_sustmr(struct msg *);
  73 static int pow_get_dimtmr(struct msg *);
  74 static int pow_set_dimtmr(struct msg *);
  75 static int pow_battery_lvl(struct msg *);
  76 static int pow_debug(struct msg *);
  77 
  78 static void set_power_state(int);
  79 static void shutdown_server(const char *);
  80 
  81 /*
  82  * Message mapping
  83  */
  84 struct msg_map {
  85         int     code;
  86         int     (*func)(struct msg *);
  87 };
  88 
  89 static const struct msg_map powermsg_map[] = {
  90         {POW_SET_POWER, pow_set_power},
  91         {POW_GET_POLICY,        pow_get_policy},
  92         {POW_SET_POLICY,        pow_set_policy},
  93         {POW_GET_SUSTMR,        pow_get_sustmr},
  94         {POW_SET_SUSTMR,        pow_set_sustmr},
  95         {POW_GET_DIMTMR,        pow_get_dimtmr},
  96         {POW_SET_DIMTMR,        pow_set_dimtmr},
  97         {POW_BATTERY_LVL,       pow_battery_lvl},
  98         {STD_DEBUG,             pow_debug},
  99         {0,                     pow_noop},
 100 };
 101 
 102 static struct power_action pmact;
 103 static device_t pmdev;
 104 
 105 static int
 106 pow_noop(struct msg *msg)
 107 {
 108         return 0;
 109 }
 110 
 111 static int
 112 pow_set_power(struct msg *msg)
 113 {
 114         int state;
 115 
 116         state = msg->data[0];
 117         set_power_state(state);
 118         return 0;
 119 }
 120 
 121 static int
 122 pow_get_policy(struct msg *msg)
 123 {
 124         int policy;
 125 
 126         device_ioctl(pmdev, PMIOC_GET_POLICY, &policy);
 127         msg->data[0] = policy;
 128         return 0;
 129 }
 130 
 131 static int
 132 pow_set_policy(struct msg *msg)
 133 {
 134         int policy;
 135 
 136         policy = msg->data[0];
 137         device_ioctl(pmdev, PMIOC_SET_POLICY, &policy);
 138         return 0;
 139 }
 140 
 141 static int
 142 pow_get_sustmr(struct msg *msg)
 143 {
 144         int timeout;
 145 
 146         device_ioctl(pmdev, PMIOC_GET_SUSTMR, &timeout);
 147         msg->data[0] = timeout;
 148         return 0;
 149 }
 150 
 151 static int
 152 pow_set_sustmr(struct msg *msg)
 153 {
 154         int timeout;
 155 
 156         timeout = msg->data[0];
 157         device_ioctl(pmdev, PMIOC_SET_SUSTMR, &timeout);
 158         return 0;
 159 }
 160 
 161 static int
 162 pow_get_dimtmr(struct msg *msg)
 163 {
 164         int timeout;
 165 
 166         device_ioctl(pmdev, PMIOC_GET_DIMTMR, &timeout);
 167         msg->data[0] = timeout;
 168         return 0;
 169 }
 170 
 171 static int
 172 pow_set_dimtmr(struct msg *msg)
 173 {
 174         int timeout;
 175 
 176         timeout = msg->data[0];
 177         device_ioctl(pmdev, PMIOC_SET_DIMTMR, &timeout);
 178         return 0;
 179 }
 180 
 181 static int
 182 pow_battery_lvl(struct msg *msg)
 183 {
 184         /* TODO: Get current battery level from battery driver. */
 185         return 0;
 186 }
 187 
 188 static void
 189 set_power_state(int state)
 190 {
 191 
 192         if (pmdev != NODEV) {
 193                 DPRINTF(("set_power_state: state=%d\n", state));
 194 
 195                 sync();
 196                 if (state == PWR_OFF || state == PWR_REBOOT) {
 197                         kill(-1, SIGTERM);
 198                         shutdown_server("!exec");
 199                         shutdown_server("!fs");
 200                         shutdown_server("!proc");
 201                 }
 202                 device_ioctl(pmdev, PMIOC_SET_POWER, &state);
 203         }
 204 }
 205 
 206 static void
 207 exception_handler(int sig)
 208 {
 209 
 210         if (sig == SIGPWR) {
 211                 DPRINTF(("SIGPWR!\n"));
 212         }
 213         exception_return();
 214 }
 215 
 216 static void
 217 power_thread(void)
 218 {
 219         int sig, event, state;
 220 
 221         DPRINTF(("power_thread: start\n"));
 222 
 223         for (;;) {
 224                 /*
 225                  * Wait signals from PM driver.
 226                  */
 227                 exception_wait(&sig);
 228                 DPRINTF(("power_thread: sig=%d\n", sig));
 229 
 230                 if (sig == SIGPWR) {
 231                         /*
 232                          * Query PM events.
 233                          */
 234                         device_ioctl(pmdev, PMIOC_QUERY_EVENT, &event);
 235                         DPRINTF(("power_thread: event=%d\n", event));
 236 
 237                         /*
 238                          * Do action for current power settings.
 239                          */
 240                         state = PWR_ON;
 241                         switch (event) {
 242                         case PME_PWRBTN_PRESS:
 243                                 state = pmact.pwrbtn;
 244                                 break;
 245                         case PME_LOW_BATTERY:
 246                                 state = pmact.lowbatt;
 247                                 break;
 248                         case PME_SLPBTN_PRESS:
 249                                 state = pmact.slpbtn;
 250                                 break;
 251                         case PME_LCD_CLOSE:
 252                                 state = pmact.lcdclose;
 253                                 break;
 254                         }
 255                         if (state != PWR_ON)
 256                                 set_power_state(state);
 257 
 258                 }
 259         }
 260 }
 261 
 262 /*
 263  * Run specified routine as a thread.
 264  */
 265 static int
 266 run_thread(void (*entry)(void))
 267 {
 268         task_t self;
 269         thread_t t;
 270         void *stack, *sp;
 271         int error;
 272 
 273         self = task_self();
 274         if ((error = thread_create(self, &t)) != 0)
 275                 return error;
 276         if ((error = vm_allocate(self, &stack, DFLSTKSZ, 1)) != 0)
 277                 return error;
 278 
 279         sp = (void *)((u_long)stack + DFLSTKSZ - sizeof(u_long) * 3);
 280         if ((error = thread_load(t, entry, sp)) != 0)
 281                 return error;
 282 
 283         return thread_resume(t);
 284 }
 285 
 286 static void
 287 pow_init(void)
 288 {
 289         task_t self;
 290 
 291         /*
 292          * Set default power actions
 293          */
 294         pmact.pwrbtn = PWR_OFF;
 295         pmact.slpbtn = PWR_SUSPEND;
 296         pmact.lcdclose = PWR_SUSPEND;
 297         pmact.lowbatt = PWR_OFF;
 298 
 299         /*
 300          * Connect to the pm driver to get all power events.
 301          */
 302         if (device_open("pm", 0, &pmdev) != 0) {
 303                 /*
 304                  * Bad config...
 305                  */
 306                 sys_panic("pow: no pm driver");
 307         }
 308         self = task_self();
 309         device_ioctl(pmdev, PMIOC_CONNECT, &self);
 310 
 311         /*
 312          * Setup exception to receive signals from pm driver.
 313          */
 314         exception_setup(exception_handler);
 315 
 316         /*
 317          * Start power thread.
 318          */
 319         if (run_thread(power_thread))
 320                 sys_panic("pow_init");
 321 }
 322 
 323 static void
 324 register_process(void)
 325 {
 326         struct msg m;
 327         object_t obj;
 328         int error;
 329 
 330         error = object_lookup("!proc", &obj);
 331         if (error)
 332                 sys_panic("pow: no proc found");
 333 
 334         m.hdr.code = PS_REGISTER;
 335         msg_send(obj, &m, sizeof(m));
 336 }
 337 
 338 /*
 339  * Wait until specified server starts.
 340  */
 341 static void
 342 wait_server(const char *name, object_t *pobj)
 343 {
 344         int i, error = 0;
 345 
 346         /* Give chance to run other servers. */
 347         thread_yield();
 348 
 349         /*
 350          * Wait for server loading. timeout is 1 sec.
 351          */
 352         for (i = 0; i < 100; i++) {
 353                 error = object_lookup((char *)name, pobj);
 354                 if (error == 0)
 355                         break;
 356 
 357                 /* Wait 10msec */
 358                 timer_sleep(10, 0);
 359                 thread_yield();
 360         }
 361         if (error)
 362                 sys_panic("pow: server not found");
 363 }
 364 
 365 static void
 366 shutdown_server(const char *name)
 367 {
 368         struct msg m;
 369         object_t obj;
 370         int error;
 371 
 372         DPRINTF(("pow: shutdown %s\n", name));
 373         error = object_lookup((char *)name, &obj);
 374         if (error != 0)
 375                 return;
 376 
 377         m.hdr.code = STD_SHUTDOWN;
 378         error = msg_send(obj, &m, sizeof(m));
 379         if (error)
 380                 sys_panic("pow: shutdown error");
 381 }
 382 
 383 static int
 384 pow_debug(struct msg *msg)
 385 {
 386         return 0;
 387 }
 388 
 389 /*
 390  * Main routine for power server.
 391  */
 392 int
 393 main(int argc, char *argv[])
 394 {
 395         static struct msg msg;
 396         const struct msg_map *map;
 397         object_t obj;
 398         struct bind_msg bm;
 399         object_t execobj, procobj;
 400         int error;
 401 
 402         sys_log("Starting power server\n");
 403 
 404         /* Boost thread priority. */
 405         thread_setpri(thread_self(), PRI_POW);
 406 
 407         /*
 408          * Wait until all required system servers
 409          * become available.
 410          */
 411         wait_server("!proc", &procobj);
 412         wait_server("!exec", &execobj);
 413 
 414         /*
 415          * Request to bind a new capabilities for us.
 416          */
 417         bm.hdr.code = EXEC_BINDCAP;
 418         strlcpy(bm.path, "/boot/pow", sizeof(bm.path));
 419         msg_send(execobj, &bm, sizeof(bm));
 420 
 421         /*
 422          * Register to process server
 423          */
 424         register_process();
 425 
 426         /*
 427          * Initialize power service.
 428          */
 429         pow_init();
 430 
 431         /*
 432          * Create an object to expose our service.
 433          */
 434         error = object_create("!pow", &obj);
 435         if (error)
 436                 sys_panic("fail to create object");
 437 
 438         /*
 439          * Message loop
 440          */
 441         for (;;) {
 442                 /*
 443                  * Wait for an incoming request.
 444                  */
 445                 error = msg_receive(obj, &msg, sizeof(msg));
 446                 if (error)
 447                         continue;
 448 
 449                 DPRINTF(("pow: msg code=%x task=%x\n",
 450                          msg.hdr.code, msg.hdr.task));
 451 
 452 
 453                 /* Check client's capability. */
 454                 if (task_chkcap(msg.hdr.task, CAP_POWERMGMT) != 0) {
 455                         map = NULL;
 456                         error = EPERM;
 457                 } else {
 458                         error = EINVAL;
 459                         map = &powermsg_map[0];
 460                         while (map->code != 0) {
 461                                 if (map->code == msg.hdr.code) {
 462                                         error = (*map->func)(&msg);
 463                                         break;
 464                                 }
 465                                 map++;
 466                         }
 467                 }
 468                 /*
 469                  * Reply to the client.
 470                  */
 471                 msg.hdr.status = error;
 472                 msg_reply(obj, &msg, sizeof(msg));
 473 #ifdef DEBUG_POWER
 474                 if (map != NULL && error != 0)
 475                         DPRINTF(("pow: msg code=%x error=%d\n",
 476                                  map->code, error));
 477 #endif
 478         }
 479 }

/* [<][>][^][v][top][bottom][index][help] */