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