Port all olsrd 0.6.0 OS specific files and adapt them to the new interface.
[olsrd.git] / src / linux / apm.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004, Andreas Tonnesen(andreto@olsr.org)
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_logging.h"
50
51 #include <stdio.h>
52 #include <string.h>
53 #include <stdlib.h>
54
55 /* APM related stuff */
56
57 #define APM_PROC "/proc/apm"
58
59 struct linux_apm_info {
60   char driver_version[10];
61   int apm_version_major;
62   int apm_version_minor;
63   int apm_flags;
64   int ac_line_status;
65   int battery_status;
66   int battery_flags;
67   int battery_percentage;
68   int battery_time;
69   int using_minutes;
70 };
71
72 /* ACPI related stuff */
73 static const char *const acpi_info[] = {
74   "/proc/acpi/battery/0/info",
75   "/proc/acpi/battery/1/info",
76   "/proc/acpi/battery/BATA/info",
77   "/proc/acpi/battery/BAT0/info",
78   "/proc/acpi/battery/BAT1/info"
79 };
80
81 static const char *const acpi_state[] = {
82   "/proc/acpi/battery/0/status",
83   "/proc/acpi/battery/1/status",
84   "/proc/acpi/battery/BATA/state",
85   "/proc/acpi/battery/BAT0/state",
86   "/proc/acpi/battery/BAT1/state"
87 };
88
89 #define ACPI_BT_CNT  ARRAYSIZE(acpi_state)
90
91 static const char *const acpi_ac[] = {
92   "/proc/acpi/ac_adapter/0/status",
93   "/proc/acpi/ac_adapter/AC/state",
94   "/proc/acpi/ac_adapter/ACAD/state"
95 };
96
97 #define ACPI_AC_CNT  ARRAYSIZE(acpi_ac)
98
99 #define USE_APM    1
100 #define USE_ACPI   2
101
102 static int method;
103
104 static int fd_index;
105
106 static int ac_power_on;
107
108 /* Prototypes */
109
110 static int apm_read_apm(struct olsr_apm_info *);
111
112 static int apm_read_acpi(struct olsr_apm_info *);
113
114 static int acpi_probe(void);
115
116 int
117 apm_init(void)
118 {
119   struct olsr_apm_info ainfo;
120
121   method = -1;
122   OLSR_INFO(LOG_APM, "Initializing APM\n");
123
124   if ((((fd_index = acpi_probe()) >= 0) || ac_power_on) && apm_read_acpi(&ainfo))
125     method = USE_ACPI;
126   else if (apm_read_apm(&ainfo))
127     method = USE_APM;
128
129   if (method != -1)
130     apm_printinfo(&ainfo);
131
132   return method;
133 }
134
135 void
136 apm_printinfo(struct olsr_apm_info *ainfo)
137 {
138   OLSR_DEBUG(LOG_APM, "APM info:\n\tAC status %d\n\tBattery percentage %d%%\n\tBattery time left %d mins\n\n", ainfo->ac_line_status,
139               ainfo->battery_percentage, ainfo->battery_time_left);
140
141   ainfo = NULL;                 /* squelch compiler warnings */
142 }
143
144 int
145 apm_read(struct olsr_apm_info *ainfo)
146 {
147   switch (method) {
148   case USE_APM:
149     return apm_read_apm(ainfo);
150   case USE_ACPI:
151     return apm_read_acpi(ainfo);
152   default:
153     break;
154   }
155   return 0;
156 }
157
158 static int
159 apm_read_apm(struct olsr_apm_info *ainfo)
160 {
161   char buffer[100];
162   char units[10];
163   FILE *apm_procfile;
164   struct linux_apm_info lainfo;
165
166   /* Open procfile */
167   if ((apm_procfile = fopen(APM_PROC, "r")) == NULL)
168     return 0;
169
170   if (fgets(buffer, sizeof(buffer), apm_procfile) == NULL) {
171     fclose(apm_procfile);
172     /* Try re-opening the file */
173     if ((apm_procfile = fopen(APM_PROC, "r")) != NULL)
174       return 0;
175
176     if (fgets(buffer, sizeof(buffer), apm_procfile) == NULL) {
177       /* Giving up */
178       OLSR_WARN(LOG_APM, "OLSRD: Could not read APM info - setting willingness to default");
179       fclose(apm_procfile);
180       return 0;
181     }
182   }
183   fclose(apm_procfile);
184
185   //printf("READ: %s\n", buffer);
186
187   /* Get the info */
188   sscanf(buffer, "%s %d.%d %x %x %x %x %d%% %d %s\n", lainfo.driver_version, &lainfo.apm_version_major, &lainfo.apm_version_minor,
189          &lainfo.apm_flags, &lainfo.ac_line_status, &lainfo.battery_status, &lainfo.battery_flags, &lainfo.battery_percentage,
190          &lainfo.battery_time, units);
191
192   lainfo.using_minutes = strncmp(units, "min", 3) ? 0 : 1;
193
194   /*
195    * Should take care of old APM type info here
196    */
197
198   /*
199    * Fix possible percentage error
200    */
201   if (lainfo.battery_percentage > 100)
202     lainfo.battery_percentage = -1;
203
204   /* Fill the provided struct */
205
206   if (lainfo.ac_line_status)
207     ainfo->ac_line_status = OLSR_AC_POWERED;
208   else
209     ainfo->ac_line_status = OLSR_BATTERY_POWERED;
210
211   ainfo->battery_percentage = lainfo.battery_percentage;
212   ainfo->battery_time_left = lainfo.battery_time;
213
214   return 1;
215 }
216
217 static int
218 apm_read_acpi(struct olsr_apm_info *ainfo)
219 {
220   FILE *fd;
221   int bat_max = 5000;                  /* Find some sane value */
222   int bat_val = 0;
223   int result;
224
225   /* reporbe in case ac status changed */
226   fd_index = acpi_probe();
227
228   /* No battery was found */
229   if (fd_index < 0) {
230     /* but we have ac */
231     if (ac_power_on) {
232       ainfo->ac_line_status = OLSR_AC_POWERED;
233
234       ainfo->battery_percentage = -1;
235
236       return 1;
237     }
238
239     /* not enough info */
240     return 0;
241   }
242
243   /* Get maxvalue */
244   if ((fd = fopen(acpi_info[fd_index], "r")) == NULL)
245     return 0;
246
247   for (;;) {
248     char s1[32], s2[32], s3[32], s4[32], inbuff[127];
249     if (fgets(inbuff, sizeof(inbuff), fd) == NULL)
250       break;
251
252     sscanf(inbuff, "%s %s %s %s", s1, s2, s3, s4);
253     if (!strcasecmp(s2, "full"))
254       bat_max = atoi(s4);
255   }
256   fclose(fd);
257
258   if ((fd = fopen(acpi_state[fd_index], "r")) == NULL)
259     return 0;
260
261   /* Extract battery status */
262   for (;;) {
263     char s1[32], s2[32], s3[32], s4[32], inbuff[127];
264     if (fgets(inbuff, sizeof(inbuff), fd) == NULL)
265       break;
266     sscanf(inbuff, "%s %s %s %s", s1, s2, s3, s4);
267
268     /* find remaining juice */
269     if (!strcasecmp(s1, "Remaining"))
270       bat_val = atoi(s3);
271   }
272   fclose(fd);
273
274   ainfo->ac_line_status = ac_power_on ? OLSR_AC_POWERED : OLSR_BATTERY_POWERED;
275
276   result = bat_val * 100 / bat_max;
277
278   ainfo->battery_percentage = result > 100 ? 100 : result;
279
280   return 1;
281 }
282
283 static int
284 acpi_probe(void)
285 {
286   unsigned int i;
287
288   /* First check for AC power */
289   ac_power_on = 0;
290
291   for (i = 0; i < ACPI_AC_CNT; i++) {
292     char s1[32], s2[32];
293     int rc;
294     FILE *fd = fopen(acpi_ac[i], "r");
295
296     /* Try opening the info file */
297     if (fd == NULL)
298       continue;
299
300     /* Extract info */
301     rc = fscanf(fd, "%s %s", s1, s2);
302
303     /* Close info entry */
304     fclose(fd);
305
306     if (rc < 2)
307       continue;
308
309     /* Running on AC power */
310     if (!strcasecmp(s2, "on-line")) {
311
312       /* ac power enabled */
313       ac_power_on = 1;
314
315       break;
316     }
317   }
318
319   /* Only checking the first found battery entry... */
320   for (i = 0; i < ACPI_BT_CNT; i++) {
321     char s1[32], s2[32];
322     int rc;
323     FILE *fd = fopen(acpi_info[i], "r");
324
325     /* Try opening the info file */
326     if (fd == NULL)
327       continue;
328
329     /* Extract info */
330     rc = fscanf(fd, "%s %s", s1, s2);
331
332     /* Close info entry */
333     fclose(fd);
334
335     if (rc < 2)
336       continue;
337
338     /* Check if battery is present */
339     if ((!strcasecmp(s1, "present:")) && (!strcasecmp(s2, "no")))
340       continue;
341
342     /* Open the corresponding state file */
343     if ((fd = fopen(acpi_state[i], "r")) == NULL)
344       continue;
345
346     fclose(fd);
347     return i;
348   }
349
350   /* No battery found */
351   return -1;
352 }
353
354 /*
355  * Local Variables:
356  * c-basic-offset: 2
357  * indent-tabs-mode: nil
358  * End:
359  */