diff options
author | Alexey Starikovskiy <astarikovskiy@suse.de> | 2007-09-26 11:43:48 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-09-27 15:50:22 -0400 |
commit | 94f6c0860139da9219255b8ff45ad42117dda859 (patch) | |
tree | bc61aa08e89467d3b9b22b5f1d640425491a65d5 /drivers/acpi/sbs.c | |
parent | db1c291af7ad748777371f25b9ff92e3e5aba38e (diff) |
ACPI: SBS: Add support for power_supply class (and sysfs)
Add support for power_supply class and sysfs interface of it.
Refer to Documentation/power_supply_class.txt for interface description.
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/sbs.c')
-rw-r--r-- | drivers/acpi/sbs.c | 314 |
1 files changed, 233 insertions, 81 deletions
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 3351dea11ff0..c4f9641147c4 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c | |||
@@ -28,17 +28,20 @@ | |||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | |||
31 | #include <linux/proc_fs.h> | 32 | #include <linux/proc_fs.h> |
32 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
35 | |||
34 | #include <linux/acpi.h> | 36 | #include <linux/acpi.h> |
35 | #include <linux/timer.h> | 37 | #include <linux/timer.h> |
36 | #include <linux/jiffies.h> | 38 | #include <linux/jiffies.h> |
37 | #include <linux/delay.h> | 39 | #include <linux/delay.h> |
38 | 40 | ||
41 | #include <linux/power_supply.h> | ||
42 | |||
39 | #include "sbshc.h" | 43 | #include "sbshc.h" |
40 | 44 | ||
41 | #define ACPI_SBS_COMPONENT 0x00080000 | ||
42 | #define ACPI_SBS_CLASS "sbs" | 45 | #define ACPI_SBS_CLASS "sbs" |
43 | #define ACPI_AC_CLASS "ac_adapter" | 46 | #define ACPI_AC_CLASS "ac_adapter" |
44 | #define ACPI_BATTERY_CLASS "battery" | 47 | #define ACPI_BATTERY_CLASS "battery" |
@@ -58,8 +61,6 @@ enum acpi_sbs_device_addr { | |||
58 | #define ACPI_SBS_NOTIFY_STATUS 0x80 | 61 | #define ACPI_SBS_NOTIFY_STATUS 0x80 |
59 | #define ACPI_SBS_NOTIFY_INFO 0x81 | 62 | #define ACPI_SBS_NOTIFY_INFO 0x81 |
60 | 63 | ||
61 | ACPI_MODULE_NAME("sbs"); | ||
62 | |||
63 | MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); | 64 | MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); |
64 | MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); | 65 | MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); |
65 | MODULE_LICENSE("GPL"); | 66 | MODULE_LICENSE("GPL"); |
@@ -76,28 +77,14 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | |||
76 | #define MAX_SBS_BAT 4 | 77 | #define MAX_SBS_BAT 4 |
77 | #define ACPI_SBS_BLOCK_MAX 32 | 78 | #define ACPI_SBS_BLOCK_MAX 32 |
78 | 79 | ||
79 | static int acpi_sbs_add(struct acpi_device *device); | ||
80 | static int acpi_sbs_remove(struct acpi_device *device, int type); | ||
81 | static int acpi_sbs_resume(struct acpi_device *device); | ||
82 | |||
83 | static const struct acpi_device_id sbs_device_ids[] = { | 80 | static const struct acpi_device_id sbs_device_ids[] = { |
84 | {"ACPI0002", 0}, | 81 | {"ACPI0002", 0}, |
85 | {"", 0}, | 82 | {"", 0}, |
86 | }; | 83 | }; |
87 | MODULE_DEVICE_TABLE(acpi, sbs_device_ids); | 84 | MODULE_DEVICE_TABLE(acpi, sbs_device_ids); |
88 | 85 | ||
89 | static struct acpi_driver acpi_sbs_driver = { | ||
90 | .name = "sbs", | ||
91 | .class = ACPI_SBS_CLASS, | ||
92 | .ids = sbs_device_ids, | ||
93 | .ops = { | ||
94 | .add = acpi_sbs_add, | ||
95 | .remove = acpi_sbs_remove, | ||
96 | .resume = acpi_sbs_resume, | ||
97 | }, | ||
98 | }; | ||
99 | |||
100 | struct acpi_battery { | 86 | struct acpi_battery { |
87 | struct power_supply bat; | ||
101 | struct acpi_sbs *sbs; | 88 | struct acpi_sbs *sbs; |
102 | struct proc_dir_entry *proc_entry; | 89 | struct proc_dir_entry *proc_entry; |
103 | unsigned long update_time; | 90 | unsigned long update_time; |
@@ -105,7 +92,7 @@ struct acpi_battery { | |||
105 | char manufacturer_name[ACPI_SBS_BLOCK_MAX]; | 92 | char manufacturer_name[ACPI_SBS_BLOCK_MAX]; |
106 | char device_name[ACPI_SBS_BLOCK_MAX]; | 93 | char device_name[ACPI_SBS_BLOCK_MAX]; |
107 | char device_chemistry[ACPI_SBS_BLOCK_MAX]; | 94 | char device_chemistry[ACPI_SBS_BLOCK_MAX]; |
108 | u32 alarm_capacity; | 95 | u16 alarm_capacity; |
109 | u16 full_charge_capacity; | 96 | u16 full_charge_capacity; |
110 | u16 design_capacity; | 97 | u16 design_capacity; |
111 | u16 design_voltage; | 98 | u16 design_voltage; |
@@ -124,7 +111,10 @@ struct acpi_battery { | |||
124 | u8 present:1; | 111 | u8 present:1; |
125 | }; | 112 | }; |
126 | 113 | ||
114 | #define to_acpi_battery(x) container_of(x, struct acpi_battery, bat); | ||
115 | |||
127 | struct acpi_sbs { | 116 | struct acpi_sbs { |
117 | struct power_supply charger; | ||
128 | struct acpi_device *device; | 118 | struct acpi_device *device; |
129 | struct acpi_smb_hc *hc; | 119 | struct acpi_smb_hc *hc; |
130 | struct mutex lock; | 120 | struct mutex lock; |
@@ -135,6 +125,8 @@ struct acpi_sbs { | |||
135 | u8 charger_present:1; | 125 | u8 charger_present:1; |
136 | }; | 126 | }; |
137 | 127 | ||
128 | #define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger) | ||
129 | |||
138 | static inline int battery_scale(int log) | 130 | static inline int battery_scale(int log) |
139 | { | 131 | { |
140 | int scale = 1; | 132 | int scale = 1; |
@@ -164,6 +156,144 @@ static inline int acpi_battery_scale(struct acpi_battery *battery) | |||
164 | acpi_battery_ipscale(battery); | 156 | acpi_battery_ipscale(battery); |
165 | } | 157 | } |
166 | 158 | ||
159 | static int sbs_get_ac_property(struct power_supply *psy, | ||
160 | enum power_supply_property psp, | ||
161 | union power_supply_propval *val) | ||
162 | { | ||
163 | struct acpi_sbs *sbs = to_acpi_sbs(psy); | ||
164 | switch (psp) { | ||
165 | case POWER_SUPPLY_PROP_ONLINE: | ||
166 | val->intval = sbs->charger_present; | ||
167 | break; | ||
168 | default: | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int acpi_battery_technology(struct acpi_battery *battery) | ||
175 | { | ||
176 | if (!strcasecmp("NiCd", battery->device_chemistry)) | ||
177 | return POWER_SUPPLY_TECHNOLOGY_NiCd; | ||
178 | if (!strcasecmp("NiMH", battery->device_chemistry)) | ||
179 | return POWER_SUPPLY_TECHNOLOGY_NiMH; | ||
180 | if (!strcasecmp("LION", battery->device_chemistry)) | ||
181 | return POWER_SUPPLY_TECHNOLOGY_LION; | ||
182 | if (!strcasecmp("LiP", battery->device_chemistry)) | ||
183 | return POWER_SUPPLY_TECHNOLOGY_LIPO; | ||
184 | return POWER_SUPPLY_TECHNOLOGY_UNKNOWN; | ||
185 | } | ||
186 | |||
187 | static int acpi_sbs_battery_get_property(struct power_supply *psy, | ||
188 | enum power_supply_property psp, | ||
189 | union power_supply_propval *val) | ||
190 | { | ||
191 | struct acpi_battery *battery = to_acpi_battery(psy); | ||
192 | |||
193 | if ((!battery->present) && psp != POWER_SUPPLY_PROP_PRESENT) | ||
194 | return -ENODEV; | ||
195 | switch (psp) { | ||
196 | case POWER_SUPPLY_PROP_STATUS: | ||
197 | if (battery->current_now < 0) | ||
198 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
199 | else if (battery->current_now > 0) | ||
200 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
201 | else | ||
202 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
203 | break; | ||
204 | case POWER_SUPPLY_PROP_PRESENT: | ||
205 | val->intval = battery->present; | ||
206 | break; | ||
207 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
208 | val->intval = acpi_battery_technology(battery); | ||
209 | break; | ||
210 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
211 | val->intval = battery->design_voltage * | ||
212 | acpi_battery_vscale(battery) * 1000; | ||
213 | break; | ||
214 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
215 | val->intval = battery->voltage_now * | ||
216 | acpi_battery_vscale(battery) * 1000; | ||
217 | break; | ||
218 | case POWER_SUPPLY_PROP_CURRENT_NOW: | ||
219 | val->intval = abs(battery->current_now) * | ||
220 | acpi_battery_ipscale(battery) * 1000; | ||
221 | break; | ||
222 | case POWER_SUPPLY_PROP_CURRENT_AVG: | ||
223 | val->intval = abs(battery->current_avg) * | ||
224 | acpi_battery_ipscale(battery) * 1000; | ||
225 | break; | ||
226 | case POWER_SUPPLY_PROP_CAPACITY: | ||
227 | val->intval = battery->state_of_charge; | ||
228 | break; | ||
229 | case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: | ||
230 | case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: | ||
231 | val->intval = battery->design_capacity * | ||
232 | acpi_battery_scale(battery) * 1000; | ||
233 | break; | ||
234 | case POWER_SUPPLY_PROP_CHARGE_FULL: | ||
235 | case POWER_SUPPLY_PROP_ENERGY_FULL: | ||
236 | val->intval = battery->full_charge_capacity * | ||
237 | acpi_battery_scale(battery) * 1000; | ||
238 | break; | ||
239 | case POWER_SUPPLY_PROP_CHARGE_NOW: | ||
240 | case POWER_SUPPLY_PROP_ENERGY_NOW: | ||
241 | val->intval = battery->capacity_now * | ||
242 | acpi_battery_scale(battery) * 1000; | ||
243 | break; | ||
244 | case POWER_SUPPLY_PROP_TEMP: | ||
245 | val->intval = battery->temp_now - 2730; // dK -> dC | ||
246 | break; | ||
247 | case POWER_SUPPLY_PROP_MODEL_NAME: | ||
248 | val->strval = battery->device_name; | ||
249 | break; | ||
250 | case POWER_SUPPLY_PROP_MANUFACTURER: | ||
251 | val->strval = battery->manufacturer_name; | ||
252 | break; | ||
253 | default: | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static enum power_supply_property sbs_ac_props[] = { | ||
260 | POWER_SUPPLY_PROP_ONLINE, | ||
261 | }; | ||
262 | |||
263 | static enum power_supply_property sbs_charge_battery_props[] = { | ||
264 | POWER_SUPPLY_PROP_STATUS, | ||
265 | POWER_SUPPLY_PROP_PRESENT, | ||
266 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
267 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | ||
268 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
269 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
270 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
271 | POWER_SUPPLY_PROP_CAPACITY, | ||
272 | POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, | ||
273 | POWER_SUPPLY_PROP_CHARGE_FULL, | ||
274 | POWER_SUPPLY_PROP_CHARGE_NOW, | ||
275 | POWER_SUPPLY_PROP_TEMP, | ||
276 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
277 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
278 | }; | ||
279 | |||
280 | static enum power_supply_property sbs_energy_battery_props[] = { | ||
281 | POWER_SUPPLY_PROP_STATUS, | ||
282 | POWER_SUPPLY_PROP_PRESENT, | ||
283 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
284 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | ||
285 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
286 | POWER_SUPPLY_PROP_CURRENT_NOW, | ||
287 | POWER_SUPPLY_PROP_CURRENT_AVG, | ||
288 | POWER_SUPPLY_PROP_CAPACITY, | ||
289 | POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, | ||
290 | POWER_SUPPLY_PROP_ENERGY_FULL, | ||
291 | POWER_SUPPLY_PROP_ENERGY_NOW, | ||
292 | POWER_SUPPLY_PROP_TEMP, | ||
293 | POWER_SUPPLY_PROP_MODEL_NAME, | ||
294 | POWER_SUPPLY_PROP_MANUFACTURER, | ||
295 | }; | ||
296 | |||
167 | /* -------------------------------------------------------------------------- | 297 | /* -------------------------------------------------------------------------- |
168 | Smart Battery System Management | 298 | Smart Battery System Management |
169 | -------------------------------------------------------------------------- */ | 299 | -------------------------------------------------------------------------- */ |
@@ -204,7 +334,7 @@ static int acpi_manager_get_info(struct acpi_sbs *sbs) | |||
204 | u16 battery_system_info; | 334 | u16 battery_system_info; |
205 | 335 | ||
206 | result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, | 336 | result = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, |
207 | 0x04, (u8 *) & battery_system_info); | 337 | 0x04, (u8 *)&battery_system_info); |
208 | if (!result) | 338 | if (!result) |
209 | sbs->batteries_supported = battery_system_info & 0x000f; | 339 | sbs->batteries_supported = battery_system_info & 0x000f; |
210 | return result; | 340 | return result; |
@@ -215,9 +345,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery) | |||
215 | int i, result = 0; | 345 | int i, result = 0; |
216 | 346 | ||
217 | for (i = 0; i < ARRAY_SIZE(info_readers); ++i) { | 347 | for (i = 0; i < ARRAY_SIZE(info_readers); ++i) { |
218 | result = acpi_smbus_read(battery->sbs->hc, info_readers[i].mode, | 348 | result = acpi_smbus_read(battery->sbs->hc, |
219 | ACPI_SBS_BATTERY, info_readers[i].command, | 349 | info_readers[i].mode, |
220 | (u8 *) battery + info_readers[i].offset); | 350 | ACPI_SBS_BATTERY, |
351 | info_readers[i].command, | ||
352 | (u8 *) battery + | ||
353 | info_readers[i].offset); | ||
221 | if (result) | 354 | if (result) |
222 | break; | 355 | break; |
223 | } | 356 | } |
@@ -228,7 +361,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery) | |||
228 | { | 361 | { |
229 | int i, result = 0; | 362 | int i, result = 0; |
230 | 363 | ||
231 | if (time_before(jiffies, battery->update_time + | 364 | if (battery->update_time && |
365 | time_before(jiffies, battery->update_time + | ||
232 | msecs_to_jiffies(cache_time))) | 366 | msecs_to_jiffies(cache_time))) |
233 | return 0; | 367 | return 0; |
234 | for (i = 0; i < ARRAY_SIZE(state_readers); ++i) { | 368 | for (i = 0; i < ARRAY_SIZE(state_readers); ++i) { |
@@ -250,26 +384,36 @@ static int acpi_battery_get_alarm(struct acpi_battery *battery) | |||
250 | { | 384 | { |
251 | return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, | 385 | return acpi_smbus_read(battery->sbs->hc, SMBUS_READ_WORD, |
252 | ACPI_SBS_BATTERY, 0x01, | 386 | ACPI_SBS_BATTERY, 0x01, |
253 | (u8 *) & battery->alarm_capacity); | 387 | (u8 *)&battery->alarm_capacity); |
254 | } | 388 | } |
255 | 389 | ||
256 | static int acpi_battery_set_alarm(struct acpi_battery *battery) | 390 | static int acpi_battery_set_alarm(struct acpi_battery *battery) |
257 | { | 391 | { |
258 | struct acpi_sbs *sbs = battery->sbs; | 392 | struct acpi_sbs *sbs = battery->sbs; |
259 | u16 value; | 393 | u16 value, sel = 1 << (battery->id + 12); |
260 | return 0; | 394 | |
395 | int ret; | ||
396 | |||
261 | 397 | ||
262 | if (sbs->manager_present) { | 398 | if (sbs->manager_present) { |
263 | acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, | 399 | ret = acpi_smbus_read(sbs->hc, SMBUS_READ_WORD, ACPI_SBS_MANAGER, |
264 | 0x01, (u8 *)&value); | 400 | 0x01, (u8 *)&value); |
265 | value &= 0x0fff; | 401 | if (ret) |
266 | value |= 1 << (battery->id + 12); | 402 | goto end; |
267 | acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_MANAGER, | 403 | if ((value & 0xf000) != sel) { |
268 | 0x01, (u8 *)&value, 2); | 404 | value &= 0x0fff; |
405 | value |= sel; | ||
406 | ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, | ||
407 | ACPI_SBS_MANAGER, | ||
408 | 0x01, (u8 *)&value, 2); | ||
409 | if (ret) | ||
410 | goto end; | ||
411 | } | ||
269 | } | 412 | } |
270 | value = battery->alarm_capacity / (acpi_battery_mode(battery) ? 10 : 1); | 413 | ret = acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, |
271 | return acpi_smbus_write(sbs->hc, SMBUS_WRITE_WORD, ACPI_SBS_BATTERY, | 414 | 0x01, (u8 *)&battery->alarm_capacity, 2); |
272 | 0x01, (u8 *)&value, 2); | 415 | end: |
416 | return ret; | ||
273 | } | 417 | } |
274 | 418 | ||
275 | static int acpi_ac_get_present(struct acpi_sbs *sbs) | 419 | static int acpi_ac_get_present(struct acpi_sbs *sbs) |
@@ -289,22 +433,19 @@ static int acpi_ac_get_present(struct acpi_sbs *sbs) | |||
289 | -------------------------------------------------------------------------- */ | 433 | -------------------------------------------------------------------------- */ |
290 | 434 | ||
291 | /* Generic Routines */ | 435 | /* Generic Routines */ |
292 | |||
293 | static int | 436 | static int |
294 | acpi_sbs_add_fs(struct proc_dir_entry **dir, | 437 | acpi_sbs_add_fs(struct proc_dir_entry **dir, |
295 | struct proc_dir_entry *parent_dir, | 438 | struct proc_dir_entry *parent_dir, |
296 | char *dir_name, | 439 | char *dir_name, |
297 | struct file_operations *info_fops, | 440 | struct file_operations *info_fops, |
298 | struct file_operations *state_fops, | 441 | struct file_operations *state_fops, |
299 | struct file_operations *alarm_fops, void *data) | 442 | struct file_operations *alarm_fops, void *data) |
300 | { | 443 | { |
301 | struct proc_dir_entry *entry = NULL; | 444 | struct proc_dir_entry *entry = NULL; |
302 | 445 | ||
303 | if (!*dir) { | 446 | if (!*dir) { |
304 | *dir = proc_mkdir(dir_name, parent_dir); | 447 | *dir = proc_mkdir(dir_name, parent_dir); |
305 | if (!*dir) { | 448 | if (!*dir) { |
306 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
307 | "proc_mkdir() failed")); | ||
308 | return -ENODEV; | 449 | return -ENODEV; |
309 | } | 450 | } |
310 | (*dir)->owner = THIS_MODULE; | 451 | (*dir)->owner = THIS_MODULE; |
@@ -313,10 +454,7 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, | |||
313 | /* 'info' [R] */ | 454 | /* 'info' [R] */ |
314 | if (info_fops) { | 455 | if (info_fops) { |
315 | entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); | 456 | entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); |
316 | if (!entry) { | 457 | if (entry) { |
317 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
318 | "create_proc_entry() failed")); | ||
319 | } else { | ||
320 | entry->proc_fops = info_fops; | 458 | entry->proc_fops = info_fops; |
321 | entry->data = data; | 459 | entry->data = data; |
322 | entry->owner = THIS_MODULE; | 460 | entry->owner = THIS_MODULE; |
@@ -326,10 +464,7 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, | |||
326 | /* 'state' [R] */ | 464 | /* 'state' [R] */ |
327 | if (state_fops) { | 465 | if (state_fops) { |
328 | entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); | 466 | entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); |
329 | if (!entry) { | 467 | if (entry) { |
330 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
331 | "create_proc_entry() failed")); | ||
332 | } else { | ||
333 | entry->proc_fops = state_fops; | 468 | entry->proc_fops = state_fops; |
334 | entry->data = data; | 469 | entry->data = data; |
335 | entry->owner = THIS_MODULE; | 470 | entry->owner = THIS_MODULE; |
@@ -339,16 +474,12 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, | |||
339 | /* 'alarm' [R/W] */ | 474 | /* 'alarm' [R/W] */ |
340 | if (alarm_fops) { | 475 | if (alarm_fops) { |
341 | entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); | 476 | entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); |
342 | if (!entry) { | 477 | if (entry) { |
343 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
344 | "create_proc_entry() failed")); | ||
345 | } else { | ||
346 | entry->proc_fops = alarm_fops; | 478 | entry->proc_fops = alarm_fops; |
347 | entry->data = data; | 479 | entry->data = data; |
348 | entry->owner = THIS_MODULE; | 480 | entry->owner = THIS_MODULE; |
349 | } | 481 | } |
350 | } | 482 | } |
351 | |||
352 | return 0; | 483 | return 0; |
353 | } | 484 | } |
354 | 485 | ||
@@ -356,7 +487,6 @@ static void | |||
356 | acpi_sbs_remove_fs(struct proc_dir_entry **dir, | 487 | acpi_sbs_remove_fs(struct proc_dir_entry **dir, |
357 | struct proc_dir_entry *parent_dir) | 488 | struct proc_dir_entry *parent_dir) |
358 | { | 489 | { |
359 | |||
360 | if (*dir) { | 490 | if (*dir) { |
361 | remove_proc_entry(ACPI_SBS_FILE_INFO, *dir); | 491 | remove_proc_entry(ACPI_SBS_FILE_INFO, *dir); |
362 | remove_proc_entry(ACPI_SBS_FILE_STATE, *dir); | 492 | remove_proc_entry(ACPI_SBS_FILE_STATE, *dir); |
@@ -364,11 +494,9 @@ acpi_sbs_remove_fs(struct proc_dir_entry **dir, | |||
364 | remove_proc_entry((*dir)->name, parent_dir); | 494 | remove_proc_entry((*dir)->name, parent_dir); |
365 | *dir = NULL; | 495 | *dir = NULL; |
366 | } | 496 | } |
367 | |||
368 | } | 497 | } |
369 | 498 | ||
370 | /* Smart Battery Interface */ | 499 | /* Smart Battery Interface */ |
371 | |||
372 | static struct proc_dir_entry *acpi_battery_dir = NULL; | 500 | static struct proc_dir_entry *acpi_battery_dir = NULL; |
373 | 501 | ||
374 | static inline char *acpi_battery_units(struct acpi_battery *battery) | 502 | static inline char *acpi_battery_units(struct acpi_battery *battery) |
@@ -506,7 +634,8 @@ acpi_battery_write_alarm(struct file *file, const char __user * buffer, | |||
506 | goto end; | 634 | goto end; |
507 | } | 635 | } |
508 | alarm_string[count] = 0; | 636 | alarm_string[count] = 0; |
509 | battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0); | 637 | battery->alarm_capacity = simple_strtoul(alarm_string, NULL, 0) / |
638 | acpi_battery_scale(battery); | ||
510 | acpi_battery_set_alarm(battery); | 639 | acpi_battery_set_alarm(battery); |
511 | end: | 640 | end: |
512 | mutex_unlock(&sbs->lock); | 641 | mutex_unlock(&sbs->lock); |
@@ -579,9 +708,6 @@ static struct file_operations acpi_ac_state_fops = { | |||
579 | /* -------------------------------------------------------------------------- | 708 | /* -------------------------------------------------------------------------- |
580 | Driver Interface | 709 | Driver Interface |
581 | -------------------------------------------------------------------------- */ | 710 | -------------------------------------------------------------------------- */ |
582 | |||
583 | /* Smart Battery */ | ||
584 | |||
585 | static int acpi_battery_read(struct acpi_battery *battery) | 711 | static int acpi_battery_read(struct acpi_battery *battery) |
586 | { | 712 | { |
587 | int result = 0, saved_present = battery->present; | 713 | int result = 0, saved_present = battery->present; |
@@ -611,13 +737,14 @@ static int acpi_battery_read(struct acpi_battery *battery) | |||
611 | return result; | 737 | return result; |
612 | } | 738 | } |
613 | 739 | ||
740 | /* Smart Battery */ | ||
614 | static int acpi_battery_add(struct acpi_sbs *sbs, int id) | 741 | static int acpi_battery_add(struct acpi_sbs *sbs, int id) |
615 | { | 742 | { |
616 | int result; | ||
617 | struct acpi_battery *battery = &sbs->battery[id]; | 743 | struct acpi_battery *battery = &sbs->battery[id]; |
744 | int result; | ||
745 | |||
618 | battery->id = id; | 746 | battery->id = id; |
619 | battery->sbs = sbs; | 747 | battery->sbs = sbs; |
620 | battery->update_time = 0; | ||
621 | result = acpi_battery_read(battery); | 748 | result = acpi_battery_read(battery); |
622 | if (result) | 749 | if (result) |
623 | return result; | 750 | return result; |
@@ -627,6 +754,19 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) | |||
627 | battery->name, &acpi_battery_info_fops, | 754 | battery->name, &acpi_battery_info_fops, |
628 | &acpi_battery_state_fops, &acpi_battery_alarm_fops, | 755 | &acpi_battery_state_fops, &acpi_battery_alarm_fops, |
629 | battery); | 756 | battery); |
757 | battery->bat.name = battery->name; | ||
758 | battery->bat.type = POWER_SUPPLY_TYPE_BATTERY; | ||
759 | if (!acpi_battery_mode(battery)) { | ||
760 | battery->bat.properties = sbs_charge_battery_props; | ||
761 | battery->bat.num_properties = | ||
762 | ARRAY_SIZE(sbs_charge_battery_props); | ||
763 | } else { | ||
764 | battery->bat.properties = sbs_energy_battery_props; | ||
765 | battery->bat.num_properties = | ||
766 | ARRAY_SIZE(sbs_energy_battery_props); | ||
767 | } | ||
768 | battery->bat.get_property = acpi_sbs_battery_get_property; | ||
769 | result = power_supply_register(&sbs->device->dev, &battery->bat); | ||
630 | printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", | 770 | printk(KERN_INFO PREFIX "%s [%s]: Battery Slot [%s] (battery %s)\n", |
631 | ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), | 771 | ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), |
632 | battery->name, sbs->battery->present ? "present" : "absent"); | 772 | battery->name, sbs->battery->present ? "present" : "absent"); |
@@ -635,7 +775,8 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id) | |||
635 | 775 | ||
636 | static void acpi_battery_remove(struct acpi_sbs *sbs, int id) | 776 | static void acpi_battery_remove(struct acpi_sbs *sbs, int id) |
637 | { | 777 | { |
638 | 778 | if (sbs->battery[id].bat.dev) | |
779 | power_supply_unregister(&sbs->battery[id].bat); | ||
639 | if (sbs->battery[id].proc_entry) { | 780 | if (sbs->battery[id].proc_entry) { |
640 | acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), | 781 | acpi_sbs_remove_fs(&(sbs->battery[id].proc_entry), |
641 | acpi_battery_dir); | 782 | acpi_battery_dir); |
@@ -654,6 +795,12 @@ static int acpi_charger_add(struct acpi_sbs *sbs) | |||
654 | &acpi_ac_state_fops, NULL, sbs); | 795 | &acpi_ac_state_fops, NULL, sbs); |
655 | if (result) | 796 | if (result) |
656 | goto end; | 797 | goto end; |
798 | sbs->charger.name = "sbs-charger"; | ||
799 | sbs->charger.type = POWER_SUPPLY_TYPE_MAINS; | ||
800 | sbs->charger.properties = sbs_ac_props; | ||
801 | sbs->charger.num_properties = ARRAY_SIZE(sbs_ac_props); | ||
802 | sbs->charger.get_property = sbs_get_ac_property; | ||
803 | power_supply_register(&sbs->device->dev, &sbs->charger); | ||
657 | printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", | 804 | printk(KERN_INFO PREFIX "%s [%s]: AC Adapter [%s] (%s)\n", |
658 | ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), | 805 | ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device), |
659 | ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); | 806 | ACPI_AC_DIR_NAME, sbs->charger_present ? "on-line" : "off-line"); |
@@ -663,7 +810,8 @@ static int acpi_charger_add(struct acpi_sbs *sbs) | |||
663 | 810 | ||
664 | static void acpi_charger_remove(struct acpi_sbs *sbs) | 811 | static void acpi_charger_remove(struct acpi_sbs *sbs) |
665 | { | 812 | { |
666 | 813 | if (sbs->charger.dev) | |
814 | power_supply_unregister(&sbs->charger); | ||
667 | if (sbs->charger_entry) | 815 | if (sbs->charger_entry) |
668 | acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); | 816 | acpi_sbs_remove_fs(&sbs->charger_entry, acpi_ac_dir); |
669 | } | 817 | } |
@@ -677,9 +825,12 @@ void acpi_sbs_callback(void *context) | |||
677 | u8 saved_battery_state; | 825 | u8 saved_battery_state; |
678 | acpi_ac_get_present(sbs); | 826 | acpi_ac_get_present(sbs); |
679 | if (sbs->charger_present != saved_charger_state) { | 827 | if (sbs->charger_present != saved_charger_state) { |
828 | #ifdef CONFIG_ACPI_PROC_EVENT | ||
680 | acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, | 829 | acpi_bus_generate_proc_event4(ACPI_AC_CLASS, ACPI_AC_DIR_NAME, |
681 | ACPI_SBS_NOTIFY_STATUS, | 830 | ACPI_SBS_NOTIFY_STATUS, |
682 | sbs->charger_present); | 831 | sbs->charger_present); |
832 | #endif | ||
833 | kobject_uevent(&sbs->charger.dev->kobj, KOBJ_CHANGE); | ||
683 | } | 834 | } |
684 | if (sbs->manager_present) { | 835 | if (sbs->manager_present) { |
685 | for (id = 0; id < MAX_SBS_BAT; ++id) { | 836 | for (id = 0; id < MAX_SBS_BAT; ++id) { |
@@ -690,10 +841,13 @@ void acpi_sbs_callback(void *context) | |||
690 | acpi_battery_read(bat); | 841 | acpi_battery_read(bat); |
691 | if (saved_battery_state == bat->present) | 842 | if (saved_battery_state == bat->present) |
692 | continue; | 843 | continue; |
844 | #ifdef CONFIG_ACPI_PROC_EVENT | ||
693 | acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, | 845 | acpi_bus_generate_proc_event4(ACPI_BATTERY_CLASS, |
694 | bat->name, | 846 | bat->name, |
695 | ACPI_SBS_NOTIFY_STATUS, | 847 | ACPI_SBS_NOTIFY_STATUS, |
696 | bat->present); | 848 | bat->present); |
849 | #endif | ||
850 | kobject_uevent(&bat->bat.dev->kobj, KOBJ_CHANGE); | ||
697 | } | 851 | } |
698 | } | 852 | } |
699 | } | 853 | } |
@@ -782,45 +936,43 @@ static int acpi_sbs_resume(struct acpi_device *device) | |||
782 | return 0; | 936 | return 0; |
783 | } | 937 | } |
784 | 938 | ||
939 | static struct acpi_driver acpi_sbs_driver = { | ||
940 | .name = "sbs", | ||
941 | .class = ACPI_SBS_CLASS, | ||
942 | .ids = sbs_device_ids, | ||
943 | .ops = { | ||
944 | .add = acpi_sbs_add, | ||
945 | .remove = acpi_sbs_remove, | ||
946 | .resume = acpi_sbs_resume, | ||
947 | }, | ||
948 | }; | ||
949 | |||
785 | static int __init acpi_sbs_init(void) | 950 | static int __init acpi_sbs_init(void) |
786 | { | 951 | { |
787 | int result = 0; | 952 | int result = 0; |
788 | 953 | ||
789 | if (acpi_disabled) | 954 | if (acpi_disabled) |
790 | return -ENODEV; | 955 | return -ENODEV; |
791 | |||
792 | acpi_ac_dir = acpi_lock_ac_dir(); | 956 | acpi_ac_dir = acpi_lock_ac_dir(); |
793 | if (!acpi_ac_dir) { | 957 | if (!acpi_ac_dir) |
794 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
795 | "acpi_lock_ac_dir() failed")); | ||
796 | return -ENODEV; | 958 | return -ENODEV; |
797 | } | ||
798 | |||
799 | acpi_battery_dir = acpi_lock_battery_dir(); | 959 | acpi_battery_dir = acpi_lock_battery_dir(); |
800 | if (!acpi_battery_dir) { | 960 | if (!acpi_battery_dir) { |
801 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
802 | "acpi_lock_battery_dir() failed")); | ||
803 | acpi_sbs_rmdirs(); | 961 | acpi_sbs_rmdirs(); |
804 | return -ENODEV; | 962 | return -ENODEV; |
805 | } | 963 | } |
806 | |||
807 | result = acpi_bus_register_driver(&acpi_sbs_driver); | 964 | result = acpi_bus_register_driver(&acpi_sbs_driver); |
808 | if (result < 0) { | 965 | if (result < 0) { |
809 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
810 | "acpi_bus_register_driver() failed")); | ||
811 | acpi_sbs_rmdirs(); | 966 | acpi_sbs_rmdirs(); |
812 | return -ENODEV; | 967 | return -ENODEV; |
813 | } | 968 | } |
814 | |||
815 | return 0; | 969 | return 0; |
816 | } | 970 | } |
817 | 971 | ||
818 | static void __exit acpi_sbs_exit(void) | 972 | static void __exit acpi_sbs_exit(void) |
819 | { | 973 | { |
820 | acpi_bus_unregister_driver(&acpi_sbs_driver); | 974 | acpi_bus_unregister_driver(&acpi_sbs_driver); |
821 | |||
822 | acpi_sbs_rmdirs(); | 975 | acpi_sbs_rmdirs(); |
823 | |||
824 | return; | 976 | return; |
825 | } | 977 | } |
826 | 978 | ||