Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / usr / server / pow / pow.c @ 03e9c04a

History | View | Annotate | Download (9.25 KB)

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
}