a7c579adb285efa791e3f5183b6b0f5251283d9e
[olsrd.git] / src / linux / apm.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /*
43  * Much of the ACPI code is taken from Florian Schaefers
44  * Acpi-Power Enlightenment epplet
45  */
46
47 #include "apm.h"
48 #include "defs.h"
49 #include "olsr_cfg.h"
50 #include "olsr_logging.h"
51
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55
56 /* APM related stuff */
57
58 #define APM_PROC "/proc/apm"
59
60 struct linux_apm_info {
61   char driver_version[10];
62   int apm_version_major;
63   int apm_version_minor;
64   int apm_flags;
65   int ac_line_status;
66   int battery_status;
67   int battery_flags;
68   int battery_percentage;
69   int battery_time;
70   int using_minutes;
71 };
72
73
74 /* ACPI related stuff */
75 static const char *const acpi_info[] = {
76   "/proc/acpi/battery/0/info",
77   "/proc/acpi/battery/1/info",
78   "/proc/acpi/battery/BATA/info",
79   "/proc/acpi/battery/BAT0/info",
80   "/proc/acpi/battery/BAT1/info"
81 };
82
83 static const char *const acpi_state[] = {
84   "/proc/acpi/battery/0/status",
85   "/proc/acpi/battery/1/status",
86   "/proc/acpi/battery/BATA/state",
87   "/proc/acpi/battery/BAT0/state",
88   "/proc/acpi/battery/BAT1/state"
89 };
90
91
92 #define ACPI_BT_CNT  ARRAYSIZE(acpi_state)
93
94
95 static const char *const acpi_ac[] = {
96   "/proc/acpi/ac_adapter/0/status",
97   "/proc/acpi/ac_adapter/AC/state",
98   "/proc/acpi/ac_adapter/ACAD/state"
99 };
100
101 #define ACPI_AC_CNT  ARRAYSIZE(acpi_ac)
102
103
104 #define USE_APM    1
105 #define USE_ACPI   2
106
107 static int method;
108
109 static int fd_index;
110
111 static int ac_power_on;
112
113 /* Prototypes */
114
115 static int
116   apm_read_apm(struct olsr_apm_info *);
117
118 static int
119   apm_read_acpi(struct olsr_apm_info *);
120
121 static int
122   acpi_probe(void);
123
124
125 int
126 apm_init(void)
127 {
128   struct olsr_apm_info ainfo;
129
130   method = -1;
131   OLSR_INFO(LOG_MAIN, "Initializing APM\n");
132
133   if ((((fd_index = acpi_probe()) >= 0) || ac_power_on) && apm_read_acpi(&ainfo))
134     method = USE_ACPI;
135   else if (apm_read_apm(&ainfo))
136     method = USE_APM;
137
138   if (method != -1)
139     apm_printinfo(&ainfo);
140
141   return method;
142 }
143
144
145 void
146 apm_printinfo(struct olsr_apm_info *ainfo)
147 {
148   OLSR_INFO(LOG_MAIN, "APM info:\n\tAC status %d\n\tBattery percentage %d%%\n\tBattery time left %d mins\n\n",
149             ainfo->ac_line_status, ainfo->battery_percentage, ainfo->battery_time_left);
150
151   ainfo = NULL;                 /* squelch compiler warnings */
152 }
153
154
155 int
156 apm_read(struct olsr_apm_info *ainfo)
157 {
158   switch (method) {
159   case USE_APM:
160     return apm_read_apm(ainfo);
161   case USE_ACPI:
162     return apm_read_acpi(ainfo);
163   default:
164     break;
165   }
166   return 0;
167 }
168
169
170 static int
171 apm_read_apm(struct olsr_apm_info *ainfo)
172 {
173   char buffer[100];
174   char units[10];
175   FILE *apm_procfile;
176   struct linux_apm_info lainfo;
177
178   /* Open procfile */
179   if ((apm_procfile = fopen(APM_PROC, "r")) == NULL)
180     return 0;
181
182   if (fgets(buffer, sizeof(buffer), apm_procfile) == NULL) {
183     fclose(apm_procfile);
184     /* Try re-opening the file */
185     if ((apm_procfile = fopen(APM_PROC, "r")) != NULL)
186       return 0;
187
188     if (fgets(buffer, sizeof(buffer), apm_procfile) == NULL) {
189       /* Giving up */
190       OLSR_WARN(LOG_MAIN, "OLSRD: Could not read APM info - setting willingness to default\n");
191       fclose(apm_procfile);
192       return 0;
193     }
194   }
195   fclose(apm_procfile);
196
197
198   //printf("READ: %s\n", buffer);
199
200   /* Get the info */
201   sscanf(buffer, "%s %d.%d %x %x %x %x %d%% %d %s\n",
202          lainfo.driver_version,
203          &lainfo.apm_version_major,
204          &lainfo.apm_version_minor,
205          &lainfo.apm_flags,
206          &lainfo.ac_line_status,
207          &lainfo.battery_status, &lainfo.battery_flags, &lainfo.battery_percentage, &lainfo.battery_time, units);
208
209   lainfo.using_minutes = strncmp(units, "min", 3) ? 0 : 1;
210
211   /*
212    * Should take care of old APM type info here
213    */
214
215   /*
216    * Fix possible percentage error
217    */
218   if (lainfo.battery_percentage > 100)
219     lainfo.battery_percentage = -1;
220
221   /* Fill the provided struct */
222
223   if (lainfo.ac_line_status)
224     ainfo->ac_line_status = OLSR_AC_POWERED;
225   else
226     ainfo->ac_line_status = OLSR_BATTERY_POWERED;
227
228   ainfo->battery_percentage = lainfo.battery_percentage;
229   ainfo->battery_time_left = lainfo.battery_time;
230
231   return 1;
232 }
233
234
235 static int
236 apm_read_acpi(struct olsr_apm_info *ainfo)
237 {
238   FILE *fd;
239   int bat_max = 5000;                  /* Find some sane value */
240   int bat_val = 0;
241   int result;
242
243   /* reporbe in case ac status changed */
244   fd_index = acpi_probe();
245
246   /* No battery was found */
247   if (fd_index < 0) {
248     /* but we have ac */
249     if (ac_power_on) {
250       ainfo->ac_line_status = OLSR_AC_POWERED;
251
252       ainfo->battery_percentage = -1;
253
254       return 1;
255     }
256
257     /* not enough info */
258     return 0;
259   }
260
261   /* Get maxvalue */
262   if ((fd = fopen(acpi_info[fd_index], "r")) == NULL)
263     return 0;
264
265   for (;;) {
266     char s1[32], s2[32], s3[32], s4[32], inbuff[127];
267     if (fgets(inbuff, sizeof(inbuff), fd) == NULL)
268       break;
269
270     sscanf(inbuff, "%s %s %s %s", s1, s2, s3, s4);
271     if (!strcasecmp(s2, "full"))
272       bat_max = atoi(s4);
273   }
274   fclose(fd);
275
276
277   if ((fd = fopen(acpi_state[fd_index], "r")) == NULL)
278     return 0;
279
280   /* Extract battery status */
281   for (;;) {
282     char s1[32], s2[32], s3[32], s4[32], inbuff[127];
283     if (fgets(inbuff, sizeof(inbuff), fd) == NULL)
284       break;
285     sscanf(inbuff, "%s %s %s %s", s1, s2, s3, s4);
286
287     /* find remaining juice */
288     if (!strcasecmp(s1, "Remaining"))
289       bat_val = atoi(s3);
290   }
291   fclose(fd);
292
293   ainfo->ac_line_status = ac_power_on ? OLSR_AC_POWERED : OLSR_BATTERY_POWERED;
294
295   result = bat_val * 100 / bat_max;
296
297   ainfo->battery_percentage = result > 100 ? 100 : result;
298
299   return 1;
300 }
301
302
303 static int
304 acpi_probe(void)
305 {
306   unsigned int i;
307
308   /* First check for AC power */
309   ac_power_on = 0;
310
311   for (i = 0; i < ACPI_AC_CNT; i++) {
312     char s1[32], s2[32];
313     int rc;
314     FILE *fd = fopen(acpi_ac[i], "r");
315
316     /* Try opening the info file */
317     if (fd == NULL)
318       continue;
319
320     /* Extract info */
321     rc = fscanf(fd, "%s %s", s1, s2);
322
323     /* Close info entry */
324     fclose(fd);
325
326     if (rc < 2)
327       continue;
328
329     /* Running on AC power */
330     if (!strcasecmp(s2, "on-line")) {
331
332       /* ac power enabled */
333       ac_power_on = 1;
334
335       break;
336     }
337   }
338
339   /* Only checking the first found battery entry... */
340   for (i = 0; i < ACPI_BT_CNT; i++) {
341     char s1[32], s2[32];
342     int rc;
343     FILE *fd = fopen(acpi_info[i], "r");
344
345     /* Try opening the info file */
346     if (fd == NULL)
347       continue;
348
349     /* Extract info */
350     rc = fscanf(fd, "%s %s", s1, s2);
351
352     /* Close info entry */
353     fclose(fd);
354
355     if (rc < 2)
356       continue;
357
358     /* Check if battery is present */
359     if ((!strcasecmp(s1, "present:")) && (!strcasecmp(s2, "no")))
360       continue;
361
362     /* Open the corresponding state file */
363     if ((fd = fopen(acpi_state[i], "r")) == NULL)
364       continue;
365
366     fclose(fd);
367     return i;
368   }
369
370   /* No battery found */
371   return -1;
372 }
373
374 /*
375  * Local Variables:
376  * c-basic-offset: 2
377  * indent-tabs-mode: nil
378  * End:
379  */