aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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);