~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/acpi/cmbatt.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  cmbatt.c - Control Method Battery driver
  3  *
  4  *  Copyright (C) 2000 Andrew Grover
  5  *
  6  *  This program is free software; you can redistribute it and/or modify
  7  *  it under the terms of the GNU General Public License as published by
  8  *  the Free Software Foundation; either version 2 of the License, or
  9  *  (at your option) any later version.
 10  *
 11  *  This program is distributed in the hope that it will be useful,
 12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  *  GNU General Public License for more details.
 15  *
 16  *  You should have received a copy of the GNU General Public License
 17  *  along with this program; if not, write to the Free Software
 18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 19  */
 20 /*
 21  * Changes:
 22  * Brendan Burns <bburns@wso.williams.edu> 2000-11-15
 23  * - added proc battery interface
 24  * - parse returned data from _BST and _BIF
 25  * Andy Grover <andrew.grover@intel.com> 2000-12-8
 26  * - improved proc interface
 27  */
 28 
 29 #include <linux/kernel.h>
 30 #include <linux/types.h>
 31 #include <linux/proc_fs.h>
 32 #include "acpi.h"
 33 #include "driver.h"
 34 
 35 #define _COMPONENT      OS_DEPENDENT
 36         MODULE_NAME     ("cmbatt")
 37 
 38 /* ACPI-specific defines */
 39 #define ACPI_CMBATT_HID         "PNP0C0A"
 40 #define ACPI_BATT_PRESENT       0x10
 41 #define ACPI_BATT_UNKNOWN       0xFFFFFFFF
 42 
 43 /* driver-specific defines */
 44 #define MAX_CM_BATTERIES        0x8
 45 #define MAX_BATT_STRLEN         0x20
 46 
 47 struct cmbatt_info
 48 {
 49         u32  power_unit;
 50         u32  design_capacity;
 51         u32  last_full_capacity;
 52         u32  battery_technology;
 53         u32  design_voltage;
 54         u32  design_capacity_warning;
 55         u32  design_capacity_low;
 56         u32  battery_capacity_granularity_1;
 57         u32  battery_capacity_granularity_2;
 58 
 59         char model_number[MAX_BATT_STRLEN];
 60         char serial_number[MAX_BATT_STRLEN];
 61         char battery_type[MAX_BATT_STRLEN];
 62         char oem_info[MAX_BATT_STRLEN];
 63 };
 64 
 65 struct cmbatt_context
 66 {
 67         u32                     is_present;
 68         ACPI_HANDLE             handle;
 69         char                    UID[9];
 70         char                    *power_unit;
 71         struct cmbatt_info      info;
 72 };
 73 
 74 struct cmbatt_status
 75 {
 76         u32                     state;
 77         u32                     present_rate;
 78         u32                     remaining_capacity;
 79         u32                     present_voltage;
 80 };
 81 
 82 static u32 batt_count = 0;
 83 
 84 static struct cmbatt_context batt_list[MAX_CM_BATTERIES];
 85 
 86 static ACPI_STATUS
 87 acpi_get_battery_status(ACPI_HANDLE handle, struct cmbatt_status *result)
 88 {
 89         ACPI_OBJECT       *obj;
 90         ACPI_OBJECT       *objs;
 91         ACPI_BUFFER       buf;
 92 
 93         buf.length = 0;
 94         buf.pointer = NULL;             
 95 
 96         /* determine buffer length needed */
 97         if (acpi_evaluate_object(handle, "_BST", NULL, &buf) != AE_BUFFER_OVERFLOW) {
 98                 printk(KERN_ERR "Cmbatt: Could not get battery status struct length\n");
 99                 return AE_NOT_FOUND;
100         }
101 
102         buf.pointer = kmalloc(buf.length, GFP_KERNEL);
103         if (!buf.pointer)
104                 return AE_NO_MEMORY;
105 
106         /* get the data */
107         if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_BST", NULL, &buf))) {
108                 printk(KERN_ERR "Cmbatt: Could not get battery status\n");
109                 kfree (buf.pointer);
110                 return AE_NOT_FOUND;
111         }
112 
113         obj = (ACPI_OBJECT *) buf.pointer;
114         objs = obj->package.elements;
115 
116         result->state = objs[0].number.value;
117         result->present_rate = objs[1].number.value;
118         result->remaining_capacity = objs[2].number.value;
119         result->present_voltage = objs[3].number.value;
120 
121         kfree(buf.pointer);
122 
123         return AE_OK;
124 }
125 
126 static ACPI_STATUS
127 acpi_get_battery_info(ACPI_HANDLE handle, struct cmbatt_info *result)
128 {
129         ACPI_OBJECT       *obj;
130         ACPI_OBJECT       *objs;
131         ACPI_BUFFER       buf;
132 
133         buf.length = 0;
134         buf.pointer = NULL;
135 
136         /* determine the length of the data */
137         if (acpi_evaluate_object(handle, "_BIF", NULL, &buf) != AE_BUFFER_OVERFLOW) {
138                 printk(KERN_ERR "Cmbatt: Could not get battery info struct length\n");
139                 return AE_NOT_FOUND;
140         }
141 
142         buf.pointer = kmalloc(buf.length, GFP_KERNEL);
143         if (!buf.pointer)
144                 return AE_NO_MEMORY;
145 
146         /* get the data */
147         if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_BIF", NULL, &buf))) {
148                 printk(KERN_ERR "Cmbatt: Could not get battery info\n");
149                 kfree (buf.pointer);
150                 return AE_NOT_FOUND;
151         }
152         
153         obj = (ACPI_OBJECT *) buf.pointer;
154         objs = obj->package.elements;
155         
156         result->power_unit=objs[0].number.value;
157         result->design_capacity=objs[1].number.value;
158         result->last_full_capacity=objs[2].number.value;
159         result->battery_technology=objs[3].number.value;
160         result->design_voltage=objs[4].number.value;
161         result->design_capacity_warning=objs[5].number.value;
162         result->design_capacity_low=objs[6].number.value;
163         result->battery_capacity_granularity_1=objs[7].number.value;
164         result->battery_capacity_granularity_2=objs[8].number.value;
165 
166         /* BUG: trailing NULL issue */
167         strncpy(result->model_number, objs[9].string.pointer, MAX_BATT_STRLEN-1);
168         strncpy(result->serial_number, objs[10].string.pointer, MAX_BATT_STRLEN-1);
169         strncpy(result->battery_type, objs[11].string.pointer, MAX_BATT_STRLEN-1);
170         strncpy(result->oem_info, objs[12].string.pointer, MAX_BATT_STRLEN-1);
171         
172         kfree(buf.pointer);
173 
174         return AE_OK;
175 }
176 
177 /*
178  * We found a device with the correct HID
179  */
180 static ACPI_STATUS
181 acpi_found_cmbatt(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
182 {
183         ACPI_DEVICE_INFO        info;
184 
185         if (batt_count >= MAX_CM_BATTERIES) {
186                 printk(KERN_ERR "Cmbatt: MAX_CM_BATTERIES exceeded\n");
187                 return AE_OK;
188         }
189 
190         if (!ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
191                 printk(KERN_ERR "Cmbatt: Could not get battery object info\n");
192                 return (AE_OK);
193         }
194 
195         if (info.valid & ACPI_VALID_UID) {
196                 strncpy(batt_list[batt_count].UID, info.unique_id, 9);
197         }
198         else if (batt_count > 1) {
199                 printk(KERN_WARNING "Cmbatt: No UID but more than 1 battery\n");
200         }
201         
202         if (!(info.valid & ACPI_VALID_STA)) {
203                 printk(KERN_ERR "Cmbatt: Battery _STA invalid\n");
204                 return AE_OK;
205         }
206 
207         if (!(info.current_status & ACPI_BATT_PRESENT)) {
208                 printk(KERN_INFO "Cmbatt: Battery socket %d empty\n", batt_count);
209                 batt_list[batt_count].is_present = FALSE;
210         }
211         else {
212                 printk(KERN_INFO "Cmbatt: Battery socket %d occupied\n", batt_count);
213                 batt_list[batt_count].is_present = TRUE;
214                 if (acpi_get_battery_info(handle, &batt_list[batt_count].info) != AE_OK) {
215                         printk(KERN_ERR "acpi_get_battery_info failed\n");
216                         return AE_OK;
217                 }
218 
219                 batt_list[batt_count].power_unit = (batt_list[batt_count].info.power_unit) ? "mA" : "mW";
220         }
221         
222         batt_list[batt_count].handle = handle;
223 
224         batt_count++;
225 
226         return AE_OK;
227 }
228 
229 static int
230 proc_read_batt_info(char *page, char **start, off_t off,
231                         int count, int *eof, void *data)
232 {
233         struct cmbatt_info *info;
234         u32 batt_num = (u32) data;
235         char *p = page;
236         int len;
237 
238         info = &batt_list[batt_num].info;
239 
240         /* don't get info more than once for a single proc read */
241         if (off != 0)
242                 goto end;
243 
244         if (!batt_list[batt_num].is_present) {
245                 p += sprintf(p, "battery %d not present\n", batt_num);
246                 goto end;
247         }
248 
249         if (info->last_full_capacity == ACPI_BATT_UNKNOWN)
250                 p += sprintf(p, "Unknown last full capacity\n");
251         else
252                 p += sprintf(p, "Last Full Capacity %x %s /hr\n", 
253                      info->last_full_capacity, batt_list[batt_num].power_unit);
254 
255         if (info->design_capacity == ACPI_BATT_UNKNOWN)
256                 p += sprintf(p, "Unknown Design Capacity\n");
257         else
258                 p += sprintf(p, "Design Capacity %x %s /hr\n", 
259                      info->design_capacity, batt_list[batt_num].power_unit);
260         
261         if (info->battery_technology)
262                 p += sprintf(p, "Secondary Battery Technology\n");
263         else
264                 p += sprintf(p, "Primary Battery Technology\n");
265         
266         if (info->design_voltage == ACPI_BATT_UNKNOWN)
267                 p += sprintf(p, "Unknown Design Voltage\n");
268         else
269                 p += sprintf(p, "Design Voltage %x mV\n", 
270                      info->design_voltage);
271         
272         p += sprintf(p, "Design Capacity Warning %d\n",
273                 info->design_capacity_warning);
274         p += sprintf(p, "Design Capacity Low %d\n",
275                 info->design_capacity_low);
276         p += sprintf(p, "Battery Capacity Granularity 1 %d\n",
277                 info->battery_capacity_granularity_1);
278         p += sprintf(p, "Battery Capacity Granularity 2 %d\n",
279                 info->battery_capacity_granularity_2);
280         p += sprintf(p, "model number %s\nserial number %s\nbattery type %s\nOEM info %s\n",
281                 info->model_number,info->serial_number,
282                 info->battery_type,info->oem_info);
283 end:
284         len = (p - page);
285         if (len <= off+count) *eof = 1;
286         *start = page + off;
287         len -= off;
288         if (len>count) len = count;
289         if (len<0) len = 0;
290         return len;
291 }
292 
293 static int
294 proc_read_batt_status(char *page, char **start, off_t off,
295                         int count, int *eof, void *data)
296 {
297         struct cmbatt_status status;
298         u32 batt_num = (u32) data;
299         char *p = page;
300         int len;
301 
302         /* don't get status more than once for a single proc read */
303         if (off != 0)
304                 goto end;
305 
306         if (!batt_list[batt_num].is_present) {
307                 p += sprintf(p, "battery %d not present\n", batt_num);
308                 goto end;
309         }
310 
311         printk("getting batt status\n");
312 
313         if (acpi_get_battery_status(batt_list[batt_num].handle, &status) != AE_OK) {
314                 printk(KERN_ERR "Cmbatt: acpi_get_battery_status failed\n");
315                 goto end;
316         }
317 
318         p += sprintf(p, "Remaining Capacity: %x\n", status.remaining_capacity);
319 
320         if (status.state & 0x1)
321                 p += sprintf(p, "Battery discharging\n");
322         if (status.state & 0x2)
323                 p += sprintf(p, "Battery charging\n");
324         if (status.state & 0x4)
325                 p += sprintf(p, "Battery critically low\n");
326 
327         if (status.present_rate == ACPI_BATT_UNKNOWN)
328                 p += sprintf(p, "Battery rate unknown\n");
329         else
330                 p += sprintf(p, "Battery rate %x\n",
331                         status.present_rate);
332 
333         if (status.remaining_capacity == ACPI_BATT_UNKNOWN)
334                 p += sprintf(p, "Battery capacity unknown\n");
335         else
336                 p += sprintf(p, "Battery capacity %x %s\n",
337                         status.remaining_capacity, batt_list[batt_num].power_unit);
338 
339         if (status.present_voltage == ACPI_BATT_UNKNOWN)
340                 p += sprintf(p, "Battery voltage unknown\n");
341         else
342                 p += sprintf(p, "Battery voltage %x volts\n",
343                         status.present_voltage);
344 
345 end:
346 
347         len = (p - page);
348         if (len <= off+count) *eof = 1;
349         *start = page + off;
350         len -= off;
351         if (len>count) len = count;
352         if (len<0) len = 0;
353         return len;
354 }
355 
356 
357 
358 int
359 acpi_cmbatt_init(void)
360 {
361         int i;
362 
363         acpi_get_devices(ACPI_CMBATT_HID, 
364                         acpi_found_cmbatt,
365                         NULL,
366                         NULL);
367 
368         for (i = 0; i < batt_count; i++) {
369 
370                 char batt_name[20];
371 
372                 sprintf(batt_name, "power/batt%d_info", i);
373                 create_proc_read_entry(batt_name, 0, NULL,
374                         proc_read_batt_info, (void *) i);
375 
376                 sprintf(batt_name, "power/batt%d_status", i);
377                 create_proc_read_entry(batt_name, 0, NULL,
378                         proc_read_batt_status, (void *) i);
379 
380         }
381 
382         return 0;
383 }
384 
385 int
386 acpi_cmbatt_terminate(void)
387 {
388         int i;
389 
390         for (i = 0; i < batt_count; i++) {
391 
392                 char batt_name[20];
393 
394                 sprintf(batt_name, "power/batt%d_info", i);
395                 remove_proc_entry(batt_name, NULL);
396 
397                 sprintf(batt_name, "power/batt%d_status", i);
398                 remove_proc_entry(batt_name, NULL);
399         }
400 
401         return 0;
402 }
403 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.