aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRich Townsend <rhdt@bartol.udel.edu>2006-07-01 11:36:54 -0400
committerLen Brown <len.brown@intel.com>2006-07-01 16:36:14 -0400
commit3f86b83243d59bb50caf5938d284d22e10d082a4 (patch)
treeebc93aff4abae0b3f4aa96c19973782eede3411d
parent37672d4c5263d54ee4302f55242f6fd5317b0f9f (diff)
ACPI: add support for Smart Battery
Most batteries today are ACPI "Control Method" batteries, but some models ship with the older "Smart Battery" that requires this code. Rich Townsend and Bruno Ducrot were the original authors. Vladimir Lebedev updated to run on latest kernel. http://bugzilla.kernel.org/show_bug.cgi?id=3734 Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--drivers/acpi/Kconfig12
-rw-r--r--drivers/acpi/Makefile2
-rw-r--r--drivers/acpi/ac.c12
-rw-r--r--drivers/acpi/battery.c13
-rw-r--r--drivers/acpi/cm_sbs.c135
-rw-r--r--drivers/acpi/i2c_ec.c420
-rw-r--r--drivers/acpi/i2c_ec.h23
-rw-r--r--drivers/acpi/sbs.c1828
8 files changed, 2434 insertions, 11 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index bc2652d72fdc..fef7bab12244 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -352,6 +352,18 @@ config ACPI_HOTPLUG_MEMORY
352 If one selects "m," this driver can be loaded using the following 352 If one selects "m," this driver can be loaded using the following
353 command: 353 command:
354 $>modprobe acpi_memhotplug 354 $>modprobe acpi_memhotplug
355
356config ACPI_SBS
357 tristate "Smart Battery System (EXPERIMENTAL)"
358 depends on X86 && I2C
359 depends on EXPERIMENTAL
360 default y
361 help
362 This driver adds support for the Smart Battery System.
363 Depends on I2C (Device Drivers ---> I2C support)
364 A "Smart Battery" is quite old and quite rare compared
365 to today's ACPI "Control Method" battery.
366
355endif # ACPI 367endif # ACPI
356 368
357endmenu 369endmenu
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index f0a68ecf1e57..bce7ca27b429 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -58,3 +58,5 @@ obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
58obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 58obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
59obj-y += scan.o motherboard.o 59obj-y += scan.o motherboard.o
60obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o 60obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
61obj-y += cm_sbs.o
62obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 4537ae4838c4..e0a1b1541362 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -50,6 +50,9 @@ ACPI_MODULE_NAME("acpi_ac")
50MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME); 50MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
51MODULE_LICENSE("GPL"); 51MODULE_LICENSE("GPL");
52 52
53extern struct proc_dir_entry *acpi_lock_ac_dir(void);
54extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
55
53static int acpi_ac_add(struct acpi_device *device); 56static int acpi_ac_add(struct acpi_device *device);
54static int acpi_ac_remove(struct acpi_device *device, int type); 57static int acpi_ac_remove(struct acpi_device *device, int type);
55static int acpi_ac_open_fs(struct inode *inode, struct file *file); 58static int acpi_ac_open_fs(struct inode *inode, struct file *file);
@@ -278,17 +281,16 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
278 281
279static int __init acpi_ac_init(void) 282static int __init acpi_ac_init(void)
280{ 283{
281 int result = 0; 284 int result;
282 285
283 286
284 acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); 287 acpi_ac_dir = acpi_lock_ac_dir();
285 if (!acpi_ac_dir) 288 if (!acpi_ac_dir)
286 return -ENODEV; 289 return -ENODEV;
287 acpi_ac_dir->owner = THIS_MODULE;
288 290
289 result = acpi_bus_register_driver(&acpi_ac_driver); 291 result = acpi_bus_register_driver(&acpi_ac_driver);
290 if (result < 0) { 292 if (result < 0) {
291 remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); 293 acpi_unlock_ac_dir(acpi_ac_dir);
292 return -ENODEV; 294 return -ENODEV;
293 } 295 }
294 296
@@ -300,7 +302,7 @@ static void __exit acpi_ac_exit(void)
300 302
301 acpi_bus_unregister_driver(&acpi_ac_driver); 303 acpi_bus_unregister_driver(&acpi_ac_driver);
302 304
303 remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); 305 acpi_unlock_ac_dir(acpi_ac_dir);
304 306
305 return; 307 return;
306} 308}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 2b8aab560b58..3ea79decfe24 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -59,6 +59,9 @@ ACPI_MODULE_NAME("acpi_battery")
59MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME); 59MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
60MODULE_LICENSE("GPL"); 60MODULE_LICENSE("GPL");
61 61
62extern struct proc_dir_entry *acpi_lock_battery_dir(void);
63extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
64
62static int acpi_battery_add(struct acpi_device *device); 65static int acpi_battery_add(struct acpi_device *device);
63static int acpi_battery_remove(struct acpi_device *device, int type); 66static int acpi_battery_remove(struct acpi_device *device, int type);
64 67
@@ -750,17 +753,15 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
750 753
751static int __init acpi_battery_init(void) 754static int __init acpi_battery_init(void)
752{ 755{
753 int result = 0; 756 int result;
754
755 757
756 acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); 758 acpi_battery_dir = acpi_lock_battery_dir();
757 if (!acpi_battery_dir) 759 if (!acpi_battery_dir)
758 return -ENODEV; 760 return -ENODEV;
759 acpi_battery_dir->owner = THIS_MODULE;
760 761
761 result = acpi_bus_register_driver(&acpi_battery_driver); 762 result = acpi_bus_register_driver(&acpi_battery_driver);
762 if (result < 0) { 763 if (result < 0) {
763 remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); 764 acpi_unlock_battery_dir(acpi_battery_dir);
764 return -ENODEV; 765 return -ENODEV;
765 } 766 }
766 767
@@ -772,7 +773,7 @@ static void __exit acpi_battery_exit(void)
772 773
773 acpi_bus_unregister_driver(&acpi_battery_driver); 774 acpi_bus_unregister_driver(&acpi_battery_driver);
774 775
775 remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); 776 acpi_unlock_battery_dir(acpi_battery_dir);
776 777
777 return; 778 return;
778} 779}
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
new file mode 100644
index 000000000000..d11507c7b8a4
--- /dev/null
+++ b/drivers/acpi/cm_sbs.c
@@ -0,0 +1,135 @@
1/*
2 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or (at
7 * your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 *
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */
20
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/acpi.h>
25#include <linux/types.h>
26#include <linux/proc_fs.h>
27#include <linux/seq_file.h>
28#include <acpi/acpi_bus.h>
29#include <acpi/acpi_drivers.h>
30#include <acpi/acmacros.h>
31#include <acpi/actypes.h>
32#include <acpi/acutils.h>
33
34ACPI_MODULE_NAME("cm_sbs")
35#define ACPI_AC_CLASS "ac_adapter"
36#define ACPI_BATTERY_CLASS "battery"
37#define ACPI_SBS_COMPONENT 0x00080000
38#define _COMPONENT ACPI_SBS_COMPONENT
39static struct proc_dir_entry *acpi_ac_dir;
40static struct proc_dir_entry *acpi_battery_dir;
41
42static struct semaphore cm_sbs_sem;
43
44static int lock_ac_dir_cnt = 0;
45static int lock_battery_dir_cnt = 0;
46
47struct proc_dir_entry *acpi_lock_ac_dir(void)
48{
49 ACPI_FUNCTION_TRACE("acpi_lock_ac_dir");
50
51 down(&cm_sbs_sem);
52 if (!acpi_ac_dir) {
53 acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
54 }
55 if (acpi_ac_dir) {
56 lock_ac_dir_cnt++;
57 } else {
58 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
59 "Cannot create %s\n", ACPI_AC_CLASS));
60 }
61 up(&cm_sbs_sem);
62 return (acpi_ac_dir);
63}
64
65EXPORT_SYMBOL(acpi_lock_ac_dir);
66
67void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)
68{
69 ACPI_FUNCTION_TRACE("acpi_unlock_ac_dir");
70
71 down(&cm_sbs_sem);
72 if (acpi_ac_dir_param) {
73 lock_ac_dir_cnt--;
74 }
75 if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
76 remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
77 acpi_ac_dir = 0;
78 }
79 up(&cm_sbs_sem);
80}
81
82EXPORT_SYMBOL(acpi_unlock_ac_dir);
83
84struct proc_dir_entry *acpi_lock_battery_dir(void)
85{
86 ACPI_FUNCTION_TRACE("acpi_lock_battery_dir");
87
88 down(&cm_sbs_sem);
89 if (!acpi_battery_dir) {
90 acpi_battery_dir =
91 proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
92 }
93 if (acpi_battery_dir) {
94 lock_battery_dir_cnt++;
95 } else {
96 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
97 "Cannot create %s\n", ACPI_BATTERY_CLASS));
98 }
99 up(&cm_sbs_sem);
100 return (acpi_battery_dir);
101}
102
103EXPORT_SYMBOL(acpi_lock_battery_dir);
104
105void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)
106{
107 ACPI_FUNCTION_TRACE("acpi_unlock_battery_dir");
108
109 down(&cm_sbs_sem);
110 if (acpi_battery_dir_param) {
111 lock_battery_dir_cnt--;
112 }
113 if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
114 && acpi_battery_dir) {
115 remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
116 acpi_battery_dir = 0;
117 }
118 up(&cm_sbs_sem);
119}
120
121EXPORT_SYMBOL(acpi_unlock_battery_dir);
122
123static int __init acpi_cm_sbs_init(void)
124{
125 ACPI_FUNCTION_TRACE("acpi_cm_sbs_init");
126
127 if (acpi_disabled)
128 return_VALUE(0);
129
130 init_MUTEX(&cm_sbs_sem);
131
132 return_VALUE(0);
133}
134
135subsys_initcall(acpi_cm_sbs_init);
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
new file mode 100644
index 000000000000..72478a665c8c
--- /dev/null
+++ b/drivers/acpi/i2c_ec.c
@@ -0,0 +1,420 @@
1/*
2 * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)
3 *
4 * Copyright (c) 2002, 2005 Ducrot Bruno
5 * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation version 2.
10 */
11
12#include <linux/version.h>
13#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/kernel.h>
16#include <linux/stddef.h>
17#include <linux/sched.h>
18#include <linux/init.h>
19#include <linux/i2c.h>
20#include <linux/acpi.h>
21#include <linux/delay.h>
22
23#include "i2c_ec.h"
24
25#define xudelay(t) udelay(t)
26#define xmsleep(t) msleep(t)
27
28#define ACPI_EC_HC_COMPONENT 0x00080000
29#define ACPI_EC_HC_CLASS "ec_hc_smbus"
30#define ACPI_EC_HC_HID "ACPI0001"
31#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver"
32#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
33
34#define _COMPONENT ACPI_EC_HC_COMPONENT
35
36ACPI_MODULE_NAME("acpi_smbus")
37
38static int acpi_ec_hc_add(struct acpi_device *device);
39static int acpi_ec_hc_remove(struct acpi_device *device, int type);
40
41static struct acpi_driver acpi_ec_hc_driver = {
42 .name = ACPI_EC_HC_DRIVER_NAME,
43 .class = ACPI_EC_HC_CLASS,
44 .ids = ACPI_EC_HC_HID,
45 .ops = {
46 .add = acpi_ec_hc_add,
47 .remove = acpi_ec_hc_remove,
48 },
49};
50
51/* Various bit mask for EC_SC (R) */
52#define OBF 0x01
53#define IBF 0x02
54#define CMD 0x08
55#define BURST 0x10
56#define SCI_EVT 0x20
57#define SMI_EVT 0x40
58
59/* Commands for EC_SC (W) */
60#define RD_EC 0x80
61#define WR_EC 0x81
62#define BE_EC 0x82
63#define BD_EC 0x83
64#define QR_EC 0x84
65
66/*
67 * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
68 */
69
70#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
71#define ACPI_EC_SMB_STS 0x01 /* status */
72#define ACPI_EC_SMB_ADDR 0x02 /* address */
73#define ACPI_EC_SMB_CMD 0x03 /* command */
74#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
75#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
76#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */
77#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
78
79#define ACPI_EC_SMB_STS_DONE 0x80
80#define ACPI_EC_SMB_STS_ALRM 0x40
81#define ACPI_EC_SMB_STS_RES 0x20
82#define ACPI_EC_SMB_STS_STATUS 0x1f
83
84#define ACPI_EC_SMB_STATUS_OK 0x00
85#define ACPI_EC_SMB_STATUS_FAIL 0x07
86#define ACPI_EC_SMB_STATUS_DNAK 0x10
87#define ACPI_EC_SMB_STATUS_DERR 0x11
88#define ACPI_EC_SMB_STATUS_CMD_DENY 0x12
89#define ACPI_EC_SMB_STATUS_UNKNOWN 0x13
90#define ACPI_EC_SMB_STATUS_ACC_DENY 0x17
91#define ACPI_EC_SMB_STATUS_TIMEOUT 0x18
92#define ACPI_EC_SMB_STATUS_NOTSUP 0x19
93#define ACPI_EC_SMB_STATUS_BUSY 0x1A
94#define ACPI_EC_SMB_STATUS_PEC 0x1F
95
96#define ACPI_EC_SMB_PRTCL_WRITE 0x00
97#define ACPI_EC_SMB_PRTCL_READ 0x01
98#define ACPI_EC_SMB_PRTCL_QUICK 0x02
99#define ACPI_EC_SMB_PRTCL_BYTE 0x04
100#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06
101#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
102#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
103#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c
104#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
105#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
106#define ACPI_EC_SMB_PRTCL_PEC 0x80
107
108/* Length of pre/post transaction sleep (msec) */
109#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
110#define ACPI_EC_SMB_ACCESS_SLEEP1 1
111#define ACPI_EC_SMB_ACCESS_SLEEP2 10
112
113static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
114{
115 u8 val;
116 int err;
117
118 ACPI_FUNCTION_TRACE("acpi_ec_smb_read");
119
120 err = ec_read(smbus->base + address, &val);
121 if (!err) {
122 *data = val;
123 }
124 xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
125 return (err);
126}
127
128static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
129{
130 int err;
131
132 ACPI_FUNCTION_TRACE("acpi_ec_smb_write");
133
134 err = ec_write(smbus->base + address, data);
135 return (err);
136}
137
138static int
139acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
140 char read_write, u8 command, int size,
141 union i2c_smbus_data *data)
142{
143 struct acpi_ec_smbus *smbus = adap->algo_data;
144 unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
145 int i;
146
147 ACPI_FUNCTION_TRACE("acpi_ec_smb_access");
148
149 if (read_write == I2C_SMBUS_READ) {
150 protocol = ACPI_EC_SMB_PRTCL_READ;
151 } else {
152 protocol = ACPI_EC_SMB_PRTCL_WRITE;
153 }
154 pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
155
156 switch (size) {
157
158 case I2C_SMBUS_QUICK:
159 protocol |= ACPI_EC_SMB_PRTCL_QUICK;
160 read_write = I2C_SMBUS_WRITE;
161 break;
162
163 case I2C_SMBUS_BYTE:
164 if (read_write == I2C_SMBUS_WRITE) {
165 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
166 }
167 protocol |= ACPI_EC_SMB_PRTCL_BYTE;
168 break;
169
170 case I2C_SMBUS_BYTE_DATA:
171 acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
172 if (read_write == I2C_SMBUS_WRITE) {
173 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
174 }
175 protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
176 break;
177
178 case I2C_SMBUS_WORD_DATA:
179 acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
180 if (read_write == I2C_SMBUS_WRITE) {
181 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
182 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
183 data->word >> 8);
184 }
185 protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
186 break;
187
188 case I2C_SMBUS_BLOCK_DATA:
189 acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
190 if (read_write == I2C_SMBUS_WRITE) {
191 len = min_t(u8, data->block[0], 32);
192 acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
193 for (i = 0; i < len; i++)
194 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
195 data->block[i + 1]);
196 }
197 protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
198 break;
199
200 case I2C_SMBUS_I2C_BLOCK_DATA:
201 len = min_t(u8, data->block[0], 32);
202 acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
203 acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
204 if (read_write == I2C_SMBUS_WRITE) {
205 for (i = 0; i < len; i++) {
206 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
207 data->block[i + 1]);
208 }
209 }
210 protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
211 break;
212
213 case I2C_SMBUS_PROC_CALL:
214 acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
215 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
216 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
217 protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
218 read_write = I2C_SMBUS_READ;
219 break;
220
221 case I2C_SMBUS_BLOCK_PROC_CALL:
222 protocol |= pec;
223 len = min_t(u8, data->block[0], 31);
224 acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
225 acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
226 for (i = 0; i < len; i++)
227 acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
228 data->block[i + 1]);
229 protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
230 read_write = I2C_SMBUS_READ;
231 break;
232
233 default:
234 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
235 "Unsupported transaction %d\n", size));
236 return (-1);
237 }
238
239 acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
240 acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
241
242 acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
243
244 if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
245 xudelay(500);
246 acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
247 }
248 if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
249 xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
250 acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
251 }
252 if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
253 || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
254 return (-1);
255 }
256
257 if (read_write == I2C_SMBUS_WRITE) {
258 return (0);
259 }
260
261 switch (size) {
262
263 case I2C_SMBUS_BYTE:
264 case I2C_SMBUS_BYTE_DATA:
265 acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
266 break;
267
268 case I2C_SMBUS_WORD_DATA:
269 case I2C_SMBUS_PROC_CALL:
270 acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
271 acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
272 data->word = (temp[1] << 8) | temp[0];
273 break;
274
275 case I2C_SMBUS_BLOCK_DATA:
276 case I2C_SMBUS_BLOCK_PROC_CALL:
277 len = 0;
278 acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
279 len = min_t(u8, len, 32);
280 case I2C_SMBUS_I2C_BLOCK_DATA:
281 for (i = 0; i < len; i++)
282 acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
283 data->block + i + 1);
284 data->block[0] = len;
285 break;
286 }
287
288 return (0);
289}
290
291static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
292{
293 ACPI_FUNCTION_TRACE("acpi_ec_smb_func");
294
295 return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
296 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
297 I2C_FUNC_SMBUS_BLOCK_DATA |
298 I2C_FUNC_SMBUS_PROC_CALL |
299 I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
300 I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
301}
302
303static struct i2c_algorithm acpi_ec_smbus_algorithm = {
304 .smbus_xfer = acpi_ec_smb_access,
305 .functionality = acpi_ec_smb_func,
306};
307
308static int acpi_ec_hc_add(struct acpi_device *device)
309{
310 int status;
311 unsigned long val;
312 struct acpi_ec_hc *ec_hc;
313 struct acpi_ec_smbus *smbus;
314
315 ACPI_FUNCTION_TRACE("acpi_ec_hc_add");
316
317 if (!device) {
318 return_VALUE(-EINVAL);
319 }
320
321 ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
322 if (!ec_hc) {
323 return_VALUE(-ENOMEM);
324 }
325 memset(ec_hc, 0, sizeof(struct acpi_ec_hc));
326
327 smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
328 if (!smbus) {
329 kfree(ec_hc);
330 return_VALUE(-ENOMEM);
331 }
332 memset(smbus, 0, sizeof(struct acpi_ec_smbus));
333
334 ec_hc->handle = device->handle;
335 strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
336 strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
337 acpi_driver_data(device) = ec_hc;
338
339 status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
340 if (ACPI_FAILURE(status)) {
341 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
342 kfree(ec_hc->smbus);
343 kfree(smbus);
344 return_VALUE(-EIO);
345 }
346
347 smbus->ec = acpi_driver_data(device->parent);
348 smbus->base = (val & 0xff00ull) >> 8;
349 smbus->alert = val & 0xffull;
350
351 smbus->adapter.owner = THIS_MODULE;
352 smbus->adapter.algo = &acpi_ec_smbus_algorithm;
353 smbus->adapter.algo_data = smbus;
354
355 if (i2c_add_adapter(&smbus->adapter)) {
356 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
357 "EC SMBus adapter: Failed to register adapter\n"));
358 kfree(smbus);
359 kfree(ec_hc);
360 return_VALUE(-EIO);
361 }
362
363 ec_hc->smbus = smbus;
364
365 printk(KERN_INFO PREFIX "%s [%s]\n",
366 acpi_device_name(device), acpi_device_bid(device));
367
368 return_VALUE(AE_OK);
369}
370
371static int acpi_ec_hc_remove(struct acpi_device *device, int type)
372{
373 struct acpi_ec_hc *ec_hc;
374
375 ACPI_FUNCTION_TRACE("acpi_ec_hc_remove");
376
377 if (!device) {
378 return_VALUE(-EINVAL);
379 }
380 ec_hc = acpi_driver_data(device);
381
382 i2c_del_adapter(&ec_hc->smbus->adapter);
383 kfree(ec_hc->smbus);
384 kfree(ec_hc);
385
386 return_VALUE(AE_OK);
387}
388
389static int __init acpi_ec_hc_init(void)
390{
391 int result;
392
393 ACPI_FUNCTION_TRACE("acpi_ec_hc_init");
394 result = acpi_bus_register_driver(&acpi_ec_hc_driver);
395 if (result < 0) {
396 return_VALUE(-ENODEV);
397 }
398 return_VALUE(0);
399}
400
401static void __exit acpi_ec_hc_exit(void)
402{
403 ACPI_FUNCTION_TRACE("acpi_ec_hc_exit");
404 acpi_bus_unregister_driver(&acpi_ec_hc_driver);
405}
406
407struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
408{
409 ACPI_FUNCTION_TRACE("acpi_get_ec_hc");
410 return ((struct acpi_ec_hc *)acpi_driver_data(device->parent));
411}
412
413EXPORT_SYMBOL(acpi_get_ec_hc);
414
415module_init(acpi_ec_hc_init);
416module_exit(acpi_ec_hc_exit);
417
418MODULE_LICENSE("GPL");
419MODULE_AUTHOR("Ducrot Bruno");
420MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff --git a/drivers/acpi/i2c_ec.h b/drivers/acpi/i2c_ec.h
new file mode 100644
index 000000000000..7c53fb732d61
--- /dev/null
+++ b/drivers/acpi/i2c_ec.h
@@ -0,0 +1,23 @@
1/*
2 * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
3 *
4 * Copyright (c) 2002, 2005 Ducrot Bruno
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 version 2.
9 */
10
11struct acpi_ec_smbus {
12 struct i2c_adapter adapter;
13 union acpi_ec *ec;
14 int base;
15 int alert;
16};
17
18struct acpi_ec_hc {
19 acpi_handle handle;
20 struct acpi_ec_smbus *smbus;
21};
22
23struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
new file mode 100644
index 000000000000..8bebcebff5f0
--- /dev/null
+++ b/drivers/acpi/sbs.c
@@ -0,0 +1,1828 @@
1/*
2 * acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16 $)
3 *
4 * Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
23 */
24
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/kernel.h>
29#include <linux/proc_fs.h>
30#include <linux/seq_file.h>
31#include <asm/uaccess.h>
32#include <linux/acpi.h>
33#include <linux/i2c.h>
34#include <linux/delay.h>
35
36#include "i2c_ec.h"
37
38#define DEF_CAPACITY_UNIT 3
39#define MAH_CAPACITY_UNIT 1
40#define MWH_CAPACITY_UNIT 2
41#define CAPACITY_UNIT DEF_CAPACITY_UNIT
42
43#define REQUEST_UPDATE_MODE 1
44#define QUEUE_UPDATE_MODE 2
45
46#define DATA_TYPE_COMMON 0
47#define DATA_TYPE_INFO 1
48#define DATA_TYPE_STATE 2
49#define DATA_TYPE_ALARM 3
50#define DATA_TYPE_AC_STATE 4
51
52extern struct proc_dir_entry *acpi_lock_ac_dir(void);
53extern struct proc_dir_entry *acpi_lock_battery_dir(void);
54extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
55extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
56
57#define ACPI_SBS_COMPONENT 0x00080000
58#define ACPI_SBS_CLASS "sbs"
59#define ACPI_AC_CLASS "ac_adapter"
60#define ACPI_BATTERY_CLASS "battery"
61#define ACPI_SBS_HID "ACPI0002"
62#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver"
63#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
64#define ACPI_SBS_FILE_INFO "info"
65#define ACPI_SBS_FILE_STATE "state"
66#define ACPI_SBS_FILE_ALARM "alarm"
67#define ACPI_BATTERY_DIR_NAME "BAT%i"
68#define ACPI_AC_DIR_NAME "AC0"
69#define ACPI_SBC_SMBUS_ADDR 0x9
70#define ACPI_SBSM_SMBUS_ADDR 0xa
71#define ACPI_SB_SMBUS_ADDR 0xb
72#define ACPI_SBS_AC_NOTIFY_STATUS 0x80
73#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x80
74#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x81
75
76#define _COMPONENT ACPI_SBS_COMPONENT
77
78#define MAX_SBS_BAT 4
79#define MAX_SMBUS_ERR 1
80
81ACPI_MODULE_NAME("acpi_sbs");
82
83MODULE_AUTHOR("Rich Townsend");
84MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
85MODULE_LICENSE("GPL");
86
87static struct semaphore sbs_sem;
88
89#define UPDATE_MODE QUEUE_UPDATE_MODE
90/* REQUEST_UPDATE_MODE QUEUE_UPDATE_MODE */
91#define UPDATE_INFO_MODE 0
92#define UPDATE_TIME 60
93#define UPDATE_TIME2 0
94
95static int capacity_mode = CAPACITY_UNIT;
96static int update_mode = UPDATE_MODE;
97static int update_info_mode = UPDATE_INFO_MODE;
98static int update_time = UPDATE_TIME;
99static int update_time2 = UPDATE_TIME2;
100
101module_param(capacity_mode, int, CAPACITY_UNIT);
102module_param(update_mode, int, UPDATE_MODE);
103module_param(update_info_mode, int, UPDATE_INFO_MODE);
104module_param(update_time, int, UPDATE_TIME);
105module_param(update_time2, int, UPDATE_TIME2);
106
107static int acpi_sbs_add(struct acpi_device *device);
108static int acpi_sbs_remove(struct acpi_device *device, int type);
109static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
110static void acpi_sbs_update_queue(void *data);
111
112static struct acpi_driver acpi_sbs_driver = {
113 .name = ACPI_SBS_DRIVER_NAME,
114 .class = ACPI_SBS_CLASS,
115 .ids = ACPI_SBS_HID,
116 .ops = {
117 .add = acpi_sbs_add,
118 .remove = acpi_sbs_remove,
119 },
120};
121
122struct acpi_battery_info {
123 int capacity_mode;
124 s16 full_charge_capacity;
125 s16 design_capacity;
126 s16 design_voltage;
127 int vscale;
128 int ipscale;
129 s16 serial_number;
130 char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
131 char device_name[I2C_SMBUS_BLOCK_MAX + 3];
132 char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
133};
134
135struct acpi_battery_state {
136 s16 voltage;
137 s16 amperage;
138 s16 remaining_capacity;
139 s16 average_time_to_empty;
140 s16 average_time_to_full;
141 s16 battery_status;
142};
143
144struct acpi_battery_alarm {
145 s16 remaining_capacity;
146};
147
148struct acpi_battery {
149 int alive;
150 int battery_present;
151 int id;
152 int init_state;
153 struct acpi_sbs *sbs;
154 struct acpi_battery_info info;
155 struct acpi_battery_state state;
156 struct acpi_battery_alarm alarm;
157 struct proc_dir_entry *battery_entry;
158};
159
160struct acpi_sbs {
161 acpi_handle handle;
162 struct acpi_device *device;
163 struct acpi_ec_smbus *smbus;
164 int sbsm_present;
165 int sbsm_batteries_supported;
166 int ac_present;
167 struct proc_dir_entry *ac_entry;
168 struct acpi_battery battery[MAX_SBS_BAT];
169 int update_info_mode;
170 int zombie;
171 int update_time;
172 int update_time2;
173 struct timer_list update_timer;
174};
175
176static void acpi_update_delay(struct acpi_sbs *sbs);
177static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
178
179/* --------------------------------------------------------------------------
180 SMBus Communication
181 -------------------------------------------------------------------------- */
182
183static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
184{
185 union i2c_smbus_data data;
186 int result = 0;
187 char *err_str;
188 int err_number;
189
190 ACPI_FUNCTION_TRACE("acpi_battery_smbus_err_handler");
191
192 data.word = 0;
193
194 result = smbus->adapter.algo->
195 smbus_xfer(&smbus->adapter,
196 ACPI_SB_SMBUS_ADDR,
197 0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);
198
199 err_number = (data.word & 0x000f);
200
201 switch (data.word & 0x000f) {
202 case 0x0000:
203 err_str = "unexpected bus error";
204 break;
205 case 0x0001:
206 err_str = "busy";
207 break;
208 case 0x0002:
209 err_str = "reserved command";
210 break;
211 case 0x0003:
212 err_str = "unsupported command";
213 break;
214 case 0x0004:
215 err_str = "access denied";
216 break;
217 case 0x0005:
218 err_str = "overflow/underflow";
219 break;
220 case 0x0006:
221 err_str = "bad size";
222 break;
223 case 0x0007:
224 err_str = "unknown error";
225 break;
226 default:
227 err_str = "unrecognized error";
228 }
229 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
230 "%s: ret %i, err %i\n", err_str, result, err_number));
231}
232
233static int
234acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
235 u16 * word,
236 void (*err_handler) (struct acpi_ec_smbus * smbus))
237{
238 union i2c_smbus_data data;
239 int result = 0;
240 int i;
241
242 ACPI_FUNCTION_TRACE("acpi_sbs_smbus_read_word");
243
244 if (err_handler == NULL) {
245 err_handler = acpi_battery_smbus_err_handler;
246 }
247
248 for (i = 0; i < MAX_SMBUS_ERR; i++) {
249 result =
250 smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
251 I2C_SMBUS_READ, func,
252 I2C_SMBUS_WORD_DATA, &data);
253 if (result) {
254 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
255 "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
256 i));
257 if (err_handler) {
258 err_handler(smbus);
259 }
260 } else {
261 *word = data.word;
262 break;
263 }
264 }
265
266 return_VALUE(result);
267}
268
269static int
270acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
271 char *str,
272 void (*err_handler) (struct acpi_ec_smbus * smbus))
273{
274 union i2c_smbus_data data;
275 int result = 0;
276 int i;
277
278 ACPI_FUNCTION_TRACE("acpi_sbs_smbus_read_str");
279
280 if (err_handler == NULL) {
281 err_handler = acpi_battery_smbus_err_handler;
282 }
283
284 for (i = 0; i < MAX_SMBUS_ERR; i++) {
285 result =
286 smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
287 I2C_SMBUS_READ, func,
288 I2C_SMBUS_BLOCK_DATA,
289 &data);
290 if (result) {
291 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
292 "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
293 i));
294 if (err_handler) {
295 err_handler(smbus);
296 }
297 } else {
298 strncpy(str, (const char *)data.block + 1,
299 data.block[0]);
300 str[data.block[0]] = 0;
301 break;
302 }
303 }
304
305 return_VALUE(result);
306}
307
308static int
309acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
310 int word,
311 void (*err_handler) (struct acpi_ec_smbus * smbus))
312{
313 union i2c_smbus_data data;
314 int result = 0;
315 int i;
316
317 ACPI_FUNCTION_TRACE("acpi_sbs_smbus_write_word");
318
319 if (err_handler == NULL) {
320 err_handler = acpi_battery_smbus_err_handler;
321 }
322
323 data.word = word;
324
325 for (i = 0; i < MAX_SMBUS_ERR; i++) {
326 result =
327 smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
328 I2C_SMBUS_WRITE, func,
329 I2C_SMBUS_WORD_DATA, &data);
330 if (result) {
331 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
332 "try %i: smbus->adapter.algo"
333 "->smbus_xfer() failed\n", i));
334 if (err_handler) {
335 err_handler(smbus);
336 }
337 } else {
338 break;
339 }
340 }
341
342 return_VALUE(result);
343}
344
345/* --------------------------------------------------------------------------
346 Smart Battery System Management
347 -------------------------------------------------------------------------- */
348
349/* Smart Battery */
350
351static int acpi_sbs_generate_event(struct acpi_device *device,
352 int event, int state, char *bid, char *class)
353{
354 char bid_saved[5];
355 char class_saved[20];
356 int result = 0;
357
358 ACPI_FUNCTION_TRACE("acpi_sbs_generate_event");
359
360 strcpy(bid_saved, acpi_device_bid(device));
361 strcpy(class_saved, acpi_device_class(device));
362
363 strcpy(acpi_device_bid(device), bid);
364 strcpy(acpi_device_class(device), class);
365
366 result = acpi_bus_generate_event(device, event, state);
367
368 strcpy(acpi_device_bid(device), bid_saved);
369 strcpy(acpi_device_class(device), class_saved);
370
371 return_VALUE(result);
372}
373
374static int acpi_battery_get_present(struct acpi_battery *battery)
375{
376 s16 state;
377 int result = 0;
378 int is_present = 0;
379
380 ACPI_FUNCTION_TRACE("acpi_battery_get_present");
381
382 result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
383 ACPI_SBSM_SMBUS_ADDR, 0x01,
384 &state, NULL);
385 if (result) {
386 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
387 "acpi_sbs_smbus_read_word() failed"));
388 }
389 if (!result) {
390 is_present = (state & 0x000f) & (1 << battery->id);
391 }
392 battery->battery_present = is_present;
393
394 return_VALUE(result);
395}
396
397static int acpi_battery_is_present(struct acpi_battery *battery)
398{
399 return (battery->battery_present);
400}
401
402static int acpi_ac_is_present(struct acpi_sbs *sbs)
403{
404 return (sbs->ac_present);
405}
406
407static int acpi_battery_select(struct acpi_battery *battery)
408{
409 struct acpi_ec_smbus *smbus = battery->sbs->smbus;
410 int result = 0;
411 s16 state;
412 int foo;
413
414 ACPI_FUNCTION_TRACE("acpi_battery_select");
415
416 if (battery->sbs->sbsm_present) {
417
418 /* Take special care not to knobble other nibbles of
419 * state (aka selector_state), since
420 * it causes charging to halt on SBSELs */
421
422 result =
423 acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
424 &state, NULL);
425 if (result) {
426 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
427 "acpi_sbs_smbus_read_word() failed\n"));
428 goto end;
429 }
430
431 foo = (state & 0x0fff) | (1 << (battery->id + 12));
432 result =
433 acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
434 foo, NULL);
435 if (result) {
436 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
437 "acpi_sbs_smbus_write_word() failed\n"));
438 goto end;
439 }
440 }
441
442 end:
443 return_VALUE(result);
444}
445
446static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
447{
448 struct acpi_ec_smbus *smbus = sbs->smbus;
449 int result = 0;
450 s16 battery_system_info;
451
452 ACPI_FUNCTION_TRACE("acpi_sbsm_get_info");
453
454 result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
455 &battery_system_info, NULL);
456 if (result) {
457 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
458 "acpi_sbs_smbus_read_word() failed\n"));
459 goto end;
460 }
461
462 sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
463
464 end:
465
466 return_VALUE(result);
467}
468
469static int acpi_battery_get_info(struct acpi_battery *battery)
470{
471 struct acpi_ec_smbus *smbus = battery->sbs->smbus;
472 int result = 0;
473 s16 battery_mode;
474 s16 specification_info;
475
476 ACPI_FUNCTION_TRACE("acpi_battery_get_info");
477
478 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
479 &battery_mode,
480 &acpi_battery_smbus_err_handler);
481 if (result) {
482 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
483 "acpi_sbs_smbus_read_word() failed\n"));
484 goto end;
485 }
486 battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
487
488 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
489 &battery->info.full_charge_capacity,
490 &acpi_battery_smbus_err_handler);
491 if (result) {
492 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
493 "acpi_sbs_smbus_read_word() failed\n"));
494 goto end;
495 }
496
497 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
498 &battery->info.design_capacity,
499 &acpi_battery_smbus_err_handler);
500
501 if (result) {
502 goto end;
503 }
504
505 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
506 &battery->info.design_voltage,
507 &acpi_battery_smbus_err_handler);
508 if (result) {
509 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
510 "acpi_sbs_smbus_read_word() failed\n"));
511 goto end;
512 }
513
514 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
515 &specification_info,
516 &acpi_battery_smbus_err_handler);
517 if (result) {
518 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
519 "acpi_sbs_smbus_read_word() failed\n"));
520 goto end;
521 }
522
523 switch ((specification_info & 0x0f00) >> 8) {
524 case 1:
525 battery->info.vscale = 10;
526 break;
527 case 2:
528 battery->info.vscale = 100;
529 break;
530 case 3:
531 battery->info.vscale = 1000;
532 break;
533 default:
534 battery->info.vscale = 1;
535 }
536
537 switch ((specification_info & 0xf000) >> 12) {
538 case 1:
539 battery->info.ipscale = 10;
540 break;
541 case 2:
542 battery->info.ipscale = 100;
543 break;
544 case 3:
545 battery->info.ipscale = 1000;
546 break;
547 default:
548 battery->info.ipscale = 1;
549 }
550
551 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
552 &battery->info.serial_number,
553 &acpi_battery_smbus_err_handler);
554 if (result) {
555 goto end;
556 }
557
558 result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
559 battery->info.manufacturer_name,
560 &acpi_battery_smbus_err_handler);
561 if (result) {
562 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
563 "acpi_sbs_smbus_read_str() failed\n"));
564 goto end;
565 }
566
567 result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
568 battery->info.device_name,
569 &acpi_battery_smbus_err_handler);
570 if (result) {
571 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
572 "acpi_sbs_smbus_read_str() failed\n"));
573 goto end;
574 }
575
576 result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
577 battery->info.device_chemistry,
578 &acpi_battery_smbus_err_handler);
579 if (result) {
580 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
581 "acpi_sbs_smbus_read_str() failed\n"));
582 goto end;
583 }
584
585 end:
586 return_VALUE(result);
587}
588
589static void acpi_update_delay(struct acpi_sbs *sbs)
590{
591 ACPI_FUNCTION_TRACE("acpi_update_delay");
592 if (sbs->zombie) {
593 return;
594 }
595 if (sbs->update_time2 > 0) {
596 msleep(sbs->update_time2 * 1000);
597 }
598}
599
600static int acpi_battery_get_state(struct acpi_battery *battery)
601{
602 struct acpi_ec_smbus *smbus = battery->sbs->smbus;
603 int result = 0;
604
605 ACPI_FUNCTION_TRACE("acpi_battery_get_state");
606
607 acpi_update_delay(battery->sbs);
608 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
609 &battery->state.voltage,
610 &acpi_battery_smbus_err_handler);
611 if (result) {
612 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
613 "acpi_sbs_smbus_read_word() failed\n"));
614 goto end;
615 }
616
617 acpi_update_delay(battery->sbs);
618 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
619 &battery->state.amperage,
620 &acpi_battery_smbus_err_handler);
621 if (result) {
622 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
623 "acpi_sbs_smbus_read_word() failed\n"));
624 goto end;
625 }
626
627 acpi_update_delay(battery->sbs);
628 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
629 &battery->state.remaining_capacity,
630 &acpi_battery_smbus_err_handler);
631 if (result) {
632 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
633 "acpi_sbs_smbus_read_word() failed\n"));
634 goto end;
635 }
636
637 acpi_update_delay(battery->sbs);
638 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
639 &battery->state.average_time_to_empty,
640 &acpi_battery_smbus_err_handler);
641 if (result) {
642 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
643 "acpi_sbs_smbus_read_word() failed\n"));
644 goto end;
645 }
646
647 acpi_update_delay(battery->sbs);
648 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
649 &battery->state.average_time_to_full,
650 &acpi_battery_smbus_err_handler);
651 if (result) {
652 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
653 "acpi_sbs_smbus_read_word() failed\n"));
654 goto end;
655 }
656
657 acpi_update_delay(battery->sbs);
658 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
659 &battery->state.battery_status,
660 &acpi_battery_smbus_err_handler);
661 if (result) {
662 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
663 "acpi_sbs_smbus_read_word() failed\n"));
664 goto end;
665 }
666
667 acpi_update_delay(battery->sbs);
668
669 end:
670 return_VALUE(result);
671}
672
673static int acpi_battery_get_alarm(struct acpi_battery *battery)
674{
675 struct acpi_ec_smbus *smbus = battery->sbs->smbus;
676 int result = 0;
677
678 ACPI_FUNCTION_TRACE("acpi_battery_get_alarm");
679
680 result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
681 &battery->alarm.remaining_capacity,
682 &acpi_battery_smbus_err_handler);
683 if (result) {
684 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
685 "acpi_sbs_smbus_read_word() failed\n"));
686 goto end;
687 }
688
689 acpi_update_delay(battery->sbs);
690
691 end:
692
693 return_VALUE(result);
694}
695
696static int acpi_battery_set_alarm(struct acpi_battery *battery,
697 unsigned long alarm)
698{
699 struct acpi_ec_smbus *smbus = battery->sbs->smbus;
700 int result = 0;
701 s16 battery_mode;
702 int foo;
703
704 ACPI_FUNCTION_TRACE("acpi_battery_set_alarm");
705
706 result = acpi_battery_select(battery);
707 if (result) {
708 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
709 "acpi_battery_select() failed\n"));
710 goto end;
711 }
712
713 /* If necessary, enable the alarm */
714
715 if (alarm > 0) {
716 result =
717 acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
718 &battery_mode,
719 &acpi_battery_smbus_err_handler);
720 if (result) {
721 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
722 "acpi_sbs_smbus_read_word() failed\n"));
723 goto end;
724 }
725
726 result =
727 acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
728 battery_mode & 0xbfff,
729 &acpi_battery_smbus_err_handler);
730 if (result) {
731 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
732 "acpi_sbs_smbus_write_word() failed\n"));
733 goto end;
734 }
735 }
736
737 foo = alarm / (battery->info.capacity_mode ? 10 : 1);
738 result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
739 foo,
740 &acpi_battery_smbus_err_handler);
741 if (result) {
742 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
743 "acpi_sbs_smbus_write_word() failed\n"));
744 goto end;
745 }
746
747 end:
748
749 return_VALUE(result);
750}
751
752static int acpi_battery_set_mode(struct acpi_battery *battery)
753{
754 int result = 0;
755 s16 battery_mode;
756
757 ACPI_FUNCTION_TRACE("acpi_battery_set_mode");
758
759 if (capacity_mode == DEF_CAPACITY_UNIT) {
760 goto end;
761 }
762
763 result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
764 ACPI_SB_SMBUS_ADDR, 0x03,
765 &battery_mode, NULL);
766 if (result) {
767 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
768 "acpi_sbs_smbus_read_word() failed\n"));
769 goto end;
770 }
771
772 if (capacity_mode == MAH_CAPACITY_UNIT) {
773 battery_mode &= 0x7fff;
774 } else {
775 battery_mode |= 0x8000;
776 }
777 result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
778 ACPI_SB_SMBUS_ADDR, 0x03,
779 battery_mode, NULL);
780 if (result) {
781 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
782 "acpi_sbs_smbus_write_word() failed\n"));
783 goto end;
784 }
785
786 result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
787 ACPI_SB_SMBUS_ADDR, 0x03,
788 &battery_mode, NULL);
789 if (result) {
790 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
791 "acpi_sbs_smbus_read_word() failed\n"));
792 goto end;
793 }
794
795 end:
796 return_VALUE(result);
797}
798
799static int acpi_battery_init(struct acpi_battery *battery)
800{
801 int result = 0;
802
803 ACPI_FUNCTION_TRACE("acpi_battery_init");
804
805 result = acpi_battery_select(battery);
806 if (result) {
807 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
808 "acpi_battery_init() failed\n"));
809 goto end;
810 }
811
812 result = acpi_battery_set_mode(battery);
813 if (result) {
814 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
815 "acpi_battery_set_mode() failed\n"));
816 goto end;
817 }
818
819 result = acpi_battery_get_info(battery);
820 if (result) {
821 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
822 "acpi_battery_get_info() failed\n"));
823 goto end;
824 }
825
826 result = acpi_battery_get_state(battery);
827 if (result) {
828 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
829 "acpi_battery_get_state() failed\n"));
830 goto end;
831 }
832
833 result = acpi_battery_get_alarm(battery);
834 if (result) {
835 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
836 "acpi_battery_get_alarm() failed\n"));
837 goto end;
838 }
839
840 end:
841 return_VALUE(result);
842}
843
844static int acpi_ac_get_present(struct acpi_sbs *sbs)
845{
846 struct acpi_ec_smbus *smbus = sbs->smbus;
847 int result = 0;
848 s16 charger_status;
849
850 ACPI_FUNCTION_TRACE("acpi_ac_get_present");
851
852 result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
853 &charger_status, NULL);
854
855 if (result) {
856 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
857 "acpi_sbs_smbus_read_word() failed\n"));
858 goto end;
859 }
860
861 sbs->ac_present = (charger_status & 0x8000) >> 15;
862
863 end:
864
865 return_VALUE(result);
866}
867
868/* --------------------------------------------------------------------------
869 FS Interface (/proc/acpi)
870 -------------------------------------------------------------------------- */
871
872/* Generic Routines */
873
874static int
875acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
876 struct proc_dir_entry *parent_dir,
877 char *dir_name,
878 struct file_operations *info_fops,
879 struct file_operations *state_fops,
880 struct file_operations *alarm_fops, void *data)
881{
882 struct proc_dir_entry *entry = NULL;
883
884 ACPI_FUNCTION_TRACE("acpi_sbs_generic_add_fs");
885
886 if (!*dir) {
887 *dir = proc_mkdir(dir_name, parent_dir);
888 if (!*dir) {
889 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
890 "proc_mkdir() failed\n"));
891 return_VALUE(-ENODEV);
892 }
893 (*dir)->owner = THIS_MODULE;
894 }
895
896 /* 'info' [R] */
897 if (info_fops) {
898 entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
899 if (!entry) {
900 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
901 "create_proc_entry() failed\n"));
902 } else {
903 entry->proc_fops = info_fops;
904 entry->data = data;
905 entry->owner = THIS_MODULE;
906 }
907 }
908
909 /* 'state' [R] */
910 if (state_fops) {
911 entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
912 if (!entry) {
913 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
914 "create_proc_entry() failed\n"));
915 } else {
916 entry->proc_fops = state_fops;
917 entry->data = data;
918 entry->owner = THIS_MODULE;
919 }
920 }
921
922 /* 'alarm' [R/W] */
923 if (alarm_fops) {
924 entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
925 if (!entry) {
926 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
927 "create_proc_entry() failed\n"));
928 } else {
929 entry->proc_fops = alarm_fops;
930 entry->data = data;
931 entry->owner = THIS_MODULE;
932 }
933 }
934
935 return_VALUE(0);
936}
937
938static void
939acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,
940 struct proc_dir_entry *parent_dir)
941{
942 ACPI_FUNCTION_TRACE("acpi_sbs_generic_remove_fs");
943
944 if (*dir) {
945 remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
946 remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
947 remove_proc_entry(ACPI_SBS_FILE_ALARM, *dir);
948 remove_proc_entry((*dir)->name, parent_dir);
949 *dir = NULL;
950 }
951
952}
953
954/* Smart Battery Interface */
955
956static struct proc_dir_entry *acpi_battery_dir = NULL;
957
958static int acpi_battery_read_info(struct seq_file *seq, void *offset)
959{
960 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
961 int cscale;
962 int result = 0;
963
964 ACPI_FUNCTION_TRACE("acpi_battery_read_info");
965
966 if (battery->sbs->zombie) {
967 return_VALUE(-ENODEV);
968 }
969
970 down(&sbs_sem);
971
972 if (update_mode == REQUEST_UPDATE_MODE) {
973 result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);
974 if (result) {
975 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
976 "acpi_sbs_update_run() failed\n"));
977 }
978 }
979
980 if (acpi_battery_is_present(battery)) {
981 seq_printf(seq, "present: yes\n");
982 } else {
983 seq_printf(seq, "present: no\n");
984 goto end;
985 }
986
987 if (battery->info.capacity_mode) {
988 cscale = battery->info.vscale * battery->info.ipscale;
989 } else {
990 cscale = battery->info.ipscale;
991 }
992 seq_printf(seq, "design capacity: %i%s",
993 battery->info.design_capacity * cscale,
994 battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
995
996 seq_printf(seq, "last full capacity: %i%s",
997 battery->info.full_charge_capacity * cscale,
998 battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
999
1000 seq_printf(seq, "battery technology: rechargeable\n");
1001
1002 seq_printf(seq, "design voltage: %i mV\n",
1003 battery->info.design_voltage * battery->info.vscale);
1004
1005 seq_printf(seq, "design capacity warning: unknown\n");
1006 seq_printf(seq, "design capacity low: unknown\n");
1007 seq_printf(seq, "capacity granularity 1: unknown\n");
1008 seq_printf(seq, "capacity granularity 2: unknown\n");
1009
1010 seq_printf(seq, "model number: %s\n",
1011 battery->info.device_name);
1012
1013 seq_printf(seq, "serial number: %i\n",
1014 battery->info.serial_number);
1015
1016 seq_printf(seq, "battery type: %s\n",
1017 battery->info.device_chemistry);
1018
1019 seq_printf(seq, "OEM info: %s\n",
1020 battery->info.manufacturer_name);
1021
1022 end:
1023
1024 up(&sbs_sem);
1025
1026 return_VALUE(result);
1027}
1028
1029static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
1030{
1031 return single_open(file, acpi_battery_read_info, PDE(inode)->data);
1032}
1033
1034static int acpi_battery_read_state(struct seq_file *seq, void *offset)
1035{
1036 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
1037 int result = 0;
1038 int cscale;
1039 int foo;
1040
1041 ACPI_FUNCTION_TRACE("acpi_battery_read_state");
1042
1043 if (battery->sbs->zombie) {
1044 return_VALUE(-ENODEV);
1045 }
1046
1047 down(&sbs_sem);
1048
1049 if (update_mode == REQUEST_UPDATE_MODE) {
1050 result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);
1051 if (result) {
1052 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1053 "acpi_sbs_update_run() failed\n"));
1054 }
1055 }
1056
1057 if (acpi_battery_is_present(battery)) {
1058 seq_printf(seq, "present: yes\n");
1059 } else {
1060 seq_printf(seq, "present: no\n");
1061 goto end;
1062 }
1063
1064 if (battery->info.capacity_mode) {
1065 cscale = battery->info.vscale * battery->info.ipscale;
1066 } else {
1067 cscale = battery->info.ipscale;
1068 }
1069
1070 if (battery->state.battery_status & 0x0010) {
1071 seq_printf(seq, "capacity state: critical\n");
1072 } else {
1073 seq_printf(seq, "capacity state: ok\n");
1074 }
1075 if (battery->state.amperage < 0) {
1076 seq_printf(seq, "charging state: discharging\n");
1077 foo = battery->state.remaining_capacity * cscale * 60 /
1078 (battery->state.average_time_to_empty == 0 ? 1 :
1079 battery->state.average_time_to_empty);
1080 seq_printf(seq, "present rate: %i%s\n",
1081 foo, battery->info.capacity_mode ? "0 mW" : " mA");
1082 } else if (battery->state.amperage > 0) {
1083 seq_printf(seq, "charging state: charging\n");
1084 foo = (battery->info.full_charge_capacity -
1085 battery->state.remaining_capacity) * cscale * 60 /
1086 (battery->state.average_time_to_full == 0 ? 1 :
1087 battery->state.average_time_to_full);
1088 seq_printf(seq, "present rate: %i%s\n",
1089 foo, battery->info.capacity_mode ? "0 mW" : " mA");
1090 } else {
1091 seq_printf(seq, "charging state: charged\n");
1092 seq_printf(seq, "present rate: 0 %s\n",
1093 battery->info.capacity_mode ? "mW" : "mA");
1094 }
1095
1096 seq_printf(seq, "remaining capacity: %i%s",
1097 battery->state.remaining_capacity * cscale,
1098 battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
1099
1100 seq_printf(seq, "present voltage: %i mV\n",
1101 battery->state.voltage * battery->info.vscale);
1102
1103 end:
1104
1105 up(&sbs_sem);
1106
1107 return_VALUE(result);
1108}
1109
1110static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
1111{
1112 return single_open(file, acpi_battery_read_state, PDE(inode)->data);
1113}
1114
1115static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
1116{
1117 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
1118 int result = 0;
1119 int cscale;
1120
1121 ACPI_FUNCTION_TRACE("acpi_battery_read_alarm");
1122
1123 if (battery->sbs->zombie) {
1124 return_VALUE(-ENODEV);
1125 }
1126
1127 down(&sbs_sem);
1128
1129 if (update_mode == REQUEST_UPDATE_MODE) {
1130 result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);
1131 if (result) {
1132 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1133 "acpi_sbs_update_run() failed\n"));
1134 }
1135 }
1136
1137 if (!acpi_battery_is_present(battery)) {
1138 seq_printf(seq, "present: no\n");
1139 goto end;
1140 }
1141
1142 if (battery->info.capacity_mode) {
1143 cscale = battery->info.vscale * battery->info.ipscale;
1144 } else {
1145 cscale = battery->info.ipscale;
1146 }
1147
1148 seq_printf(seq, "alarm: ");
1149 if (battery->alarm.remaining_capacity) {
1150 seq_printf(seq, "%i%s",
1151 battery->alarm.remaining_capacity * cscale,
1152 battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
1153 } else {
1154 seq_printf(seq, "disabled\n");
1155 }
1156
1157 end:
1158
1159 up(&sbs_sem);
1160
1161 return_VALUE(result);
1162}
1163
1164static ssize_t
1165acpi_battery_write_alarm(struct file *file, const char __user * buffer,
1166 size_t count, loff_t * ppos)
1167{
1168 struct seq_file *seq = (struct seq_file *)file->private_data;
1169 struct acpi_battery *battery = (struct acpi_battery *)seq->private;
1170 char alarm_string[12] = { '\0' };
1171 int result, old_alarm, new_alarm;
1172
1173 ACPI_FUNCTION_TRACE("acpi_battery_write_alarm");
1174
1175 if (battery->sbs->zombie) {
1176 return_VALUE(-ENODEV);
1177 }
1178
1179 down(&sbs_sem);
1180
1181 if (!acpi_battery_is_present(battery)) {
1182 result = -ENODEV;
1183 goto end;
1184 }
1185
1186 if (count > sizeof(alarm_string) - 1) {
1187 result = -EINVAL;
1188 goto end;
1189 }
1190
1191 if (copy_from_user(alarm_string, buffer, count)) {
1192 result = -EFAULT;
1193 goto end;
1194 }
1195
1196 alarm_string[count] = 0;
1197
1198 old_alarm = battery->alarm.remaining_capacity;
1199 new_alarm = simple_strtoul(alarm_string, NULL, 0);
1200
1201 result = acpi_battery_set_alarm(battery, new_alarm);
1202 if (result) {
1203 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1204 "acpi_battery_set_alarm() failed\n"));
1205 (void)acpi_battery_set_alarm(battery, old_alarm);
1206 goto end;
1207 }
1208 result = acpi_battery_get_alarm(battery);
1209 if (result) {
1210 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1211 "acpi_battery_get_alarm() failed\n"));
1212 (void)acpi_battery_set_alarm(battery, old_alarm);
1213 goto end;
1214 }
1215
1216 end:
1217 up(&sbs_sem);
1218
1219 if (result) {
1220 return_VALUE(result);
1221 } else {
1222 return_VALUE(count);
1223 }
1224}
1225
1226static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
1227{
1228 return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
1229}
1230
1231static struct file_operations acpi_battery_info_fops = {
1232 .open = acpi_battery_info_open_fs,
1233 .read = seq_read,
1234 .llseek = seq_lseek,
1235 .release = single_release,
1236 .owner = THIS_MODULE,
1237};
1238
1239static struct file_operations acpi_battery_state_fops = {
1240 .open = acpi_battery_state_open_fs,
1241 .read = seq_read,
1242 .llseek = seq_lseek,
1243 .release = single_release,
1244 .owner = THIS_MODULE,
1245};
1246
1247static struct file_operations acpi_battery_alarm_fops = {
1248 .open = acpi_battery_alarm_open_fs,
1249 .read = seq_read,
1250 .write = acpi_battery_write_alarm,
1251 .llseek = seq_lseek,
1252 .release = single_release,
1253 .owner = THIS_MODULE,
1254};
1255
1256/* Legacy AC Adapter Interface */
1257
1258static struct proc_dir_entry *acpi_ac_dir = NULL;
1259
1260static int acpi_ac_read_state(struct seq_file *seq, void *offset)
1261{
1262 struct acpi_sbs *sbs = (struct acpi_sbs *)seq->private;
1263 int result;
1264
1265 ACPI_FUNCTION_TRACE("acpi_ac_read_state");
1266
1267 if (sbs->zombie) {
1268 return_VALUE(-ENODEV);
1269 }
1270
1271 down(&sbs_sem);
1272
1273 if (update_mode == REQUEST_UPDATE_MODE) {
1274 result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);
1275 if (result) {
1276 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1277 "acpi_sbs_update_run() failed\n"));
1278 }
1279 }
1280
1281 seq_printf(seq, "state: %s\n",
1282 sbs->ac_present ? "on-line" : "off-line");
1283
1284 up(&sbs_sem);
1285
1286 return_VALUE(0);
1287}
1288
1289static int acpi_ac_state_open_fs(struct inode *inode, struct file *file)
1290{
1291 return single_open(file, acpi_ac_read_state, PDE(inode)->data);
1292}
1293
1294static struct file_operations acpi_ac_state_fops = {
1295 .open = acpi_ac_state_open_fs,
1296 .read = seq_read,
1297 .llseek = seq_lseek,
1298 .release = single_release,
1299 .owner = THIS_MODULE,
1300};
1301
1302/* --------------------------------------------------------------------------
1303 Driver Interface
1304 -------------------------------------------------------------------------- */
1305
1306/* Smart Battery */
1307
1308static int acpi_battery_add(struct acpi_sbs *sbs, int id)
1309{
1310 int is_present;
1311 int result;
1312 char dir_name[32];
1313 struct acpi_battery *battery;
1314
1315 ACPI_FUNCTION_TRACE("acpi_battery_add");
1316
1317 battery = &sbs->battery[id];
1318
1319 battery->alive = 0;
1320
1321 battery->init_state = 0;
1322 battery->id = id;
1323 battery->sbs = sbs;
1324
1325 result = acpi_battery_select(battery);
1326 if (result) {
1327 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1328 "acpi_battery_select() failed\n"));
1329 goto end;
1330 }
1331
1332 result = acpi_battery_get_present(battery);
1333 if (result) {
1334 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1335 "acpi_battery_get_present() failed\n"));
1336 goto end;
1337 }
1338
1339 is_present = acpi_battery_is_present(battery);
1340
1341 if (is_present) {
1342 result = acpi_battery_init(battery);
1343 if (result) {
1344 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1345 "acpi_battery_init() failed\n"));
1346 goto end;
1347 }
1348 battery->init_state = 1;
1349 }
1350
1351 (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
1352
1353 result = acpi_sbs_generic_add_fs(&battery->battery_entry,
1354 acpi_battery_dir,
1355 dir_name,
1356 &acpi_battery_info_fops,
1357 &acpi_battery_state_fops,
1358 &acpi_battery_alarm_fops, battery);
1359 if (result) {
1360 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1361 "acpi_sbs_generic_add_fs() failed\n"));
1362 goto end;
1363 }
1364 battery->alive = 1;
1365
1366 end:
1367 return_VALUE(result);
1368}
1369
1370static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
1371{
1372 ACPI_FUNCTION_TRACE("acpi_battery_remove");
1373
1374 if (sbs->battery[id].battery_entry) {
1375 acpi_sbs_generic_remove_fs(&(sbs->battery[id].battery_entry),
1376 acpi_battery_dir);
1377 }
1378}
1379
1380static int acpi_ac_add(struct acpi_sbs *sbs)
1381{
1382 int result;
1383
1384 ACPI_FUNCTION_TRACE("acpi_ac_add");
1385
1386 result = acpi_ac_get_present(sbs);
1387 if (result) {
1388 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1389 "acpi_ac_get_present() failed\n"));
1390 goto end;
1391 }
1392
1393 result = acpi_sbs_generic_add_fs(&sbs->ac_entry,
1394 acpi_ac_dir,
1395 ACPI_AC_DIR_NAME,
1396 NULL, &acpi_ac_state_fops, NULL, sbs);
1397 if (result) {
1398 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1399 "acpi_sbs_generic_add_fs() failed\n"));
1400 goto end;
1401 }
1402
1403 end:
1404
1405 return_VALUE(result);
1406}
1407
1408static void acpi_ac_remove(struct acpi_sbs *sbs)
1409{
1410 ACPI_FUNCTION_TRACE("acpi_ac_remove");
1411
1412 if (sbs->ac_entry) {
1413 acpi_sbs_generic_remove_fs(&sbs->ac_entry, acpi_ac_dir);
1414 }
1415}
1416
1417static void acpi_sbs_update_queue_run(unsigned long data)
1418{
1419 ACPI_FUNCTION_TRACE("acpi_sbs_update_queue_run");
1420 acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);
1421}
1422
1423static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
1424{
1425 struct acpi_battery *battery;
1426 int result = 0;
1427 int old_ac_present;
1428 int old_battery_present;
1429 int new_ac_present;
1430 int new_battery_present;
1431 int id;
1432 char dir_name[32];
1433 int do_battery_init, do_ac_init;
1434 s16 old_remaining_capacity;
1435
1436 ACPI_FUNCTION_TRACE("acpi_sbs_update_run");
1437
1438 if (sbs->zombie) {
1439 goto end;
1440 }
1441
1442 old_ac_present = acpi_ac_is_present(sbs);
1443
1444 result = acpi_ac_get_present(sbs);
1445 if (result) {
1446 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1447 "acpi_ac_get_present() failed\n"));
1448 }
1449
1450 new_ac_present = acpi_ac_is_present(sbs);
1451
1452 do_ac_init = (old_ac_present != new_ac_present);
1453
1454 if (data_type == DATA_TYPE_AC_STATE) {
1455 goto end;
1456 }
1457
1458 for (id = 0; id < MAX_SBS_BAT; id++) {
1459 battery = &sbs->battery[id];
1460 if (battery->alive == 0) {
1461 continue;
1462 }
1463
1464 old_remaining_capacity = battery->state.remaining_capacity;
1465
1466 old_battery_present = acpi_battery_is_present(battery);
1467
1468 result = acpi_battery_select(battery);
1469 if (result) {
1470 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1471 "acpi_battery_select() failed\n"));
1472 }
1473 if (sbs->zombie) {
1474 goto end;
1475 }
1476
1477 result = acpi_battery_get_present(battery);
1478 if (result) {
1479 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1480 "acpi_battery_get_present() failed\n"));
1481 }
1482 if (sbs->zombie) {
1483 goto end;
1484 }
1485
1486 new_battery_present = acpi_battery_is_present(battery);
1487
1488 do_battery_init = ((old_battery_present != new_battery_present)
1489 && new_battery_present);
1490
1491 if (sbs->zombie) {
1492 goto end;
1493 }
1494 if (do_ac_init || do_battery_init ||
1495 update_info_mode || sbs->update_info_mode) {
1496 if (sbs->update_info_mode) {
1497 sbs->update_info_mode = 0;
1498 } else {
1499 sbs->update_info_mode = 1;
1500 }
1501 result = acpi_battery_init(battery);
1502 if (result) {
1503 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1504 "acpi_battery_init() "
1505 "failed\n"));
1506 }
1507 }
1508 if (data_type == DATA_TYPE_INFO) {
1509 continue;
1510 }
1511
1512 if (sbs->zombie) {
1513 goto end;
1514 }
1515 if (new_battery_present) {
1516 result = acpi_battery_get_alarm(battery);
1517 if (result) {
1518 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1519 "acpi_battery_get_alarm() "
1520 "failed\n"));
1521 }
1522 if (data_type == DATA_TYPE_ALARM) {
1523 continue;
1524 }
1525
1526 result = acpi_battery_get_state(battery);
1527 if (result) {
1528 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1529 "acpi_battery_get_state() "
1530 "failed\n"));
1531 }
1532 }
1533 if (sbs->zombie) {
1534 goto end;
1535 }
1536 if (data_type != DATA_TYPE_COMMON) {
1537 continue;
1538 }
1539
1540 if (old_battery_present != new_battery_present) {
1541 (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
1542 result = acpi_sbs_generate_event(sbs->device,
1543 ACPI_SBS_BATTERY_NOTIFY_STATUS,
1544 new_battery_present,
1545 dir_name,
1546 ACPI_BATTERY_CLASS);
1547 if (result) {
1548 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1549 "acpi_sbs_generate_event() "
1550 "failed\n"));
1551 }
1552 }
1553 if (old_remaining_capacity != battery->state.remaining_capacity) {
1554 (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
1555 result = acpi_sbs_generate_event(sbs->device,
1556 ACPI_SBS_BATTERY_NOTIFY_STATUS,
1557 new_battery_present,
1558 dir_name,
1559 ACPI_BATTERY_CLASS);
1560 if (result) {
1561 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1562 "acpi_sbs_generate_event() failed\n"));
1563 }
1564 }
1565
1566 }
1567 if (sbs->zombie) {
1568 goto end;
1569 }
1570 if (data_type != DATA_TYPE_COMMON) {
1571 goto end;
1572 }
1573
1574 if (old_ac_present != new_ac_present) {
1575 result = acpi_sbs_generate_event(sbs->device,
1576 ACPI_SBS_AC_NOTIFY_STATUS,
1577 new_ac_present,
1578 ACPI_AC_DIR_NAME,
1579 ACPI_AC_CLASS);
1580 if (result) {
1581 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1582 "acpi_sbs_generate_event() failed\n"));
1583 }
1584 }
1585
1586 end:
1587 return_VALUE(result);
1588}
1589
1590static void acpi_sbs_update_queue(void *data)
1591{
1592 struct acpi_sbs *sbs = data;
1593 unsigned long delay = -1;
1594 int result;
1595
1596 ACPI_FUNCTION_TRACE("acpi_sbs_update_queue");
1597
1598 if (sbs->zombie) {
1599 goto end;
1600 }
1601
1602 result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);
1603 if (result) {
1604 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1605 "acpi_sbs_update_run() failed\n"));
1606 }
1607
1608 if (sbs->zombie) {
1609 goto end;
1610 }
1611
1612 if (update_mode == REQUEST_UPDATE_MODE) {
1613 goto end;
1614 }
1615
1616 delay = jiffies + HZ * update_time;
1617 sbs->update_timer.data = (unsigned long)data;
1618 sbs->update_timer.function = acpi_sbs_update_queue_run;
1619 sbs->update_timer.expires = delay;
1620 add_timer(&sbs->update_timer);
1621 end:
1622 ;
1623}
1624
1625static int acpi_sbs_add(struct acpi_device *device)
1626{
1627 struct acpi_sbs *sbs = NULL;
1628 struct acpi_ec_hc *ec_hc = NULL;
1629 int result, remove_result = 0;
1630 unsigned long sbs_obj;
1631 int id, cnt;
1632 acpi_status status = AE_OK;
1633
1634 ACPI_FUNCTION_TRACE("acpi_sbs_add");
1635
1636 sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
1637 if (!sbs) {
1638 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
1639 return_VALUE(-ENOMEM);
1640 }
1641 memset(sbs, 0, sizeof(struct acpi_sbs));
1642
1643 cnt = 0;
1644 while (cnt < 10) {
1645 cnt++;
1646 ec_hc = acpi_get_ec_hc(device);
1647 if (ec_hc) {
1648 break;
1649 }
1650 msleep(1000);
1651 }
1652
1653 if (!ec_hc) {
1654 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1655 "acpi_get_ec_hc() failed: "
1656 "NO driver found for EC HC SMBus\n"));
1657 result = -ENODEV;
1658 goto end;
1659 }
1660
1661 sbs->device = device;
1662 sbs->smbus = ec_hc->smbus;
1663
1664 strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
1665 strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
1666 acpi_driver_data(device) = sbs;
1667
1668 sbs->update_time = 0;
1669 sbs->update_time2 = 0;
1670
1671 result = acpi_ac_add(sbs);
1672 if (result) {
1673 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));
1674 goto end;
1675 }
1676 result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
1677 if (ACPI_FAILURE(result)) {
1678 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1679 "acpi_evaluate_integer() failed\n"));
1680 result = -EIO;
1681 goto end;
1682 }
1683
1684 if (sbs_obj > 0) {
1685 result = acpi_sbsm_get_info(sbs);
1686 if (result) {
1687 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1688 "acpi_sbsm_get_info() failed\n"));
1689 goto end;
1690 }
1691 sbs->sbsm_present = 1;
1692 }
1693 if (sbs->sbsm_present == 0) {
1694 result = acpi_battery_add(sbs, 0);
1695 if (result) {
1696 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1697 "acpi_battery_add() failed\n"));
1698 goto end;
1699 }
1700 } else {
1701 for (id = 0; id < MAX_SBS_BAT; id++) {
1702 if ((sbs->sbsm_batteries_supported & (1 << id))) {
1703 result = acpi_battery_add(sbs, id);
1704 if (result) {
1705 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1706 "acpi_battery_add() "
1707 "failed\n"));
1708 goto end;
1709 }
1710 }
1711 }
1712 }
1713
1714 sbs->handle = device->handle;
1715
1716 init_timer(&sbs->update_timer);
1717 if (update_mode == QUEUE_UPDATE_MODE) {
1718 status = acpi_os_execute(OSL_GPE_HANDLER,
1719 acpi_sbs_update_queue, (void *)sbs);
1720 if (status != AE_OK) {
1721 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1722 "acpi_os_execute() failed\n"));
1723 }
1724 }
1725 sbs->update_time = update_time;
1726 sbs->update_time2 = update_time2;
1727
1728 printk(KERN_INFO PREFIX "%s [%s]\n",
1729 acpi_device_name(device), acpi_device_bid(device));
1730
1731 end:
1732 if (result) {
1733 remove_result = acpi_sbs_remove(device, 0);
1734 if (remove_result) {
1735 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1736 "acpi_sbs_remove() failed\n"));
1737 }
1738 }
1739
1740 return_VALUE(result);
1741}
1742
1743int acpi_sbs_remove(struct acpi_device *device, int type)
1744{
1745 struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
1746 int id;
1747
1748 ACPI_FUNCTION_TRACE("acpi_sbs_remove");
1749
1750 if (!device || !sbs) {
1751 return_VALUE(-EINVAL);
1752 }
1753
1754 sbs->zombie = 1;
1755 sbs->update_time = 0;
1756 sbs->update_time2 = 0;
1757 del_timer_sync(&sbs->update_timer);
1758 acpi_os_wait_events_complete(NULL);
1759 del_timer_sync(&sbs->update_timer);
1760
1761 for (id = 0; id < MAX_SBS_BAT; id++) {
1762 acpi_battery_remove(sbs, id);
1763 }
1764
1765 acpi_ac_remove(sbs);
1766
1767 kfree(sbs);
1768
1769 return_VALUE(0);
1770}
1771
1772static int __init acpi_sbs_init(void)
1773{
1774 int result = 0;
1775
1776 ACPI_FUNCTION_TRACE("acpi_sbs_init");
1777
1778 init_MUTEX(&sbs_sem);
1779
1780 if (capacity_mode != DEF_CAPACITY_UNIT
1781 && capacity_mode != MAH_CAPACITY_UNIT
1782 && capacity_mode != MWH_CAPACITY_UNIT) {
1783 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "
1784 "invalid capacity_mode = %d\n",
1785 capacity_mode));
1786 return_VALUE(-EINVAL);
1787 }
1788
1789 acpi_ac_dir = acpi_lock_ac_dir();
1790 if (!acpi_ac_dir) {
1791 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1792 "acpi_lock_ac_dir() failed\n"));
1793 return_VALUE(-ENODEV);
1794 }
1795
1796 acpi_battery_dir = acpi_lock_battery_dir();
1797 if (!acpi_battery_dir) {
1798 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1799 "acpi_lock_battery_dir() failed\n"));
1800 return_VALUE(-ENODEV);
1801 }
1802
1803 result = acpi_bus_register_driver(&acpi_sbs_driver);
1804 if (result < 0) {
1805 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
1806 "acpi_bus_register_driver() failed\n"));
1807 return_VALUE(-ENODEV);
1808 }
1809
1810 return_VALUE(0);
1811}
1812
1813static void __exit acpi_sbs_exit(void)
1814{
1815 ACPI_FUNCTION_TRACE("acpi_sbs_exit");
1816
1817 acpi_bus_unregister_driver(&acpi_sbs_driver);
1818
1819 acpi_unlock_ac_dir(acpi_ac_dir);
1820 acpi_ac_dir = NULL;
1821 acpi_unlock_battery_dir(acpi_battery_dir);
1822 acpi_battery_dir = NULL;
1823
1824 return_VOID;
1825}
1826
1827module_init(acpi_sbs_init);
1828module_exit(acpi_sbs_exit);