More Makefile cleanups, otherwise mainly noticeable are the netfilter fix
[davej-history.git] / drivers / acpi / cmbatt.c
blobc45aa810c12ed142f80102cdd50beaa03893f860
1 /*
2 * cmbatt.c - Control Method Battery driver
4 * Copyright (C) 2000 Andrew Grover
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.
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.
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
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
29 #include <linux/kernel.h>
30 #include <linux/types.h>
31 #include <linux/proc_fs.h>
32 #include "acpi.h"
33 #include "driver.h"
35 #define _COMPONENT OS_DEPENDENT
36 MODULE_NAME ("cmbatt")
38 /* ACPI-specific defines */
39 #define ACPI_CMBATT_HID "PNP0C0A"
40 #define ACPI_BATT_PRESENT 0x10
41 #define ACPI_BATT_UNKNOWN 0xFFFFFFFF
43 /* driver-specific defines */
44 #define MAX_CM_BATTERIES 0x8
45 #define MAX_BATT_STRLEN 0x20
47 struct cmbatt_info
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;
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];
65 struct cmbatt_context
67 u32 is_present;
68 ACPI_HANDLE handle;
69 char UID[9];
70 char *power_unit;
71 struct cmbatt_info info;
74 struct cmbatt_status
76 u32 state;
77 u32 present_rate;
78 u32 remaining_capacity;
79 u32 present_voltage;
82 static u32 batt_count = 0;
84 static struct cmbatt_context batt_list[MAX_CM_BATTERIES];
86 static ACPI_STATUS
87 acpi_get_battery_status(ACPI_HANDLE handle, struct cmbatt_status *result)
89 ACPI_OBJECT *obj;
90 ACPI_OBJECT *objs;
91 ACPI_BUFFER buf;
93 buf.length = 0;
94 buf.pointer = NULL;
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;
102 buf.pointer = kmalloc(buf.length, GFP_KERNEL);
103 if (!buf.pointer)
104 return AE_NO_MEMORY;
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;
113 obj = (ACPI_OBJECT *) buf.pointer;
114 objs = obj->package.elements;
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;
121 kfree(buf.pointer);
123 return AE_OK;
126 static ACPI_STATUS
127 acpi_get_battery_info(ACPI_HANDLE handle, struct cmbatt_info *result)
129 ACPI_OBJECT *obj;
130 ACPI_OBJECT *objs;
131 ACPI_BUFFER buf;
133 buf.length = 0;
134 buf.pointer = NULL;
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;
142 buf.pointer = kmalloc(buf.length, GFP_KERNEL);
143 if (!buf.pointer)
144 return AE_NO_MEMORY;
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;
153 obj = (ACPI_OBJECT *) buf.pointer;
154 objs = obj->package.elements;
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;
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);
172 kfree(buf.pointer);
174 return AE_OK;
178 * We found a device with the correct HID
180 static ACPI_STATUS
181 acpi_found_cmbatt(ACPI_HANDLE handle, u32 level, void *ctx, void **value)
183 ACPI_DEVICE_INFO info;
185 if (batt_count >= MAX_CM_BATTERIES) {
186 printk(KERN_ERR "Cmbatt: MAX_CM_BATTERIES exceeded\n");
187 return AE_OK;
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);
195 if (info.valid & ACPI_VALID_UID) {
196 strncpy(batt_list[batt_count].UID, info.unique_id, 9);
198 else if (batt_count > 1) {
199 printk(KERN_WARNING "Cmbatt: No UID but more than 1 battery\n");
202 if (!(info.valid & ACPI_VALID_STA)) {
203 printk(KERN_ERR "Cmbatt: Battery _STA invalid\n");
204 return AE_OK;
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;
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;
219 batt_list[batt_count].power_unit = (batt_list[batt_count].info.power_unit) ? "mA" : "mW";
222 batt_list[batt_count].handle = handle;
224 batt_count++;
226 return AE_OK;
229 static int
230 proc_read_batt_info(char *page, char **start, off_t off,
231 int count, int *eof, void *data)
233 struct cmbatt_info *info;
234 u32 batt_num = (u32) data;
235 char *p = page;
236 int len;
238 info = &batt_list[batt_num].info;
240 /* don't get info more than once for a single proc read */
241 if (off != 0)
242 goto end;
244 if (!batt_list[batt_num].is_present) {
245 p += sprintf(p, "battery %d not present\n", batt_num);
246 goto end;
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);
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);
261 if (info->battery_technology)
262 p += sprintf(p, "Secondary Battery Technology\n");
263 else
264 p += sprintf(p, "Primary Battery Technology\n");
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);
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;
293 static int
294 proc_read_batt_status(char *page, char **start, off_t off,
295 int count, int *eof, void *data)
297 struct cmbatt_status status;
298 u32 batt_num = (u32) data;
299 char *p = page;
300 int len;
302 /* don't get status more than once for a single proc read */
303 if (off != 0)
304 goto end;
306 if (!batt_list[batt_num].is_present) {
307 p += sprintf(p, "battery %d not present\n", batt_num);
308 goto end;
311 printk("getting batt status\n");
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;
318 p += sprintf(p, "Remaining Capacity: %x\n", status.remaining_capacity);
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");
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);
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);
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);
345 end:
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;
359 acpi_cmbatt_init(void)
361 int i;
363 acpi_get_devices(ACPI_CMBATT_HID,
364 acpi_found_cmbatt,
365 NULL,
366 NULL);
368 for (i = 0; i < batt_count; i++) {
370 char batt_name[20];
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);
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);
382 return 0;
386 acpi_cmbatt_terminate(void)
388 int i;
390 for (i = 0; i < batt_count; i++) {
392 char batt_name[20];
394 sprintf(batt_name, "power/batt%d_info", i);
395 remove_proc_entry(batt_name, NULL);
397 sprintf(batt_name, "power/batt%d_status", i);
398 remove_proc_entry(batt_name, NULL);
401 return 0;