Skip to contentSkip to conversation

2.6.24-rc1: ensure "present" sysfs attribute even if battery is absent

PATCH In review Andrey Borzenkov 5 participants 10 messages Oct 27, 2007 – Oct 28, 2007 ACPI

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 2.6.24-rc1: ensure "present" sysfs attribute even if battery is absent

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Subject: [PATCH] 2.6.24-rc1: ensure "present" sysfs attribute even if battery is absent
From: Andrey Borzenkov <[email protected]>

Ensure that we always have "present" attribute in sysfs. This is compatible with procfs case where we had "present: no" if battery was not available.

This fixes HAL battery detection where it does pretend battery is present but canot provide any value for it.

---

 drivers/acpi/battery.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)
drivers/acpi/battery.c +10 -1
index 681e26b..6e67fcd 100644
@@ -187,6 +187,10 @@ static int acpi_battery_get_property(struct power_supply *psy,
 	return 0;
 }
 
+static enum power_supply_property missing_battery_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+};
+
 static enum power_supply_property charge_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
@@ -389,8 +393,13 @@ static int acpi_battery_update(struct acpi_battery *battery)
 {
 	int saved_present = acpi_battery_present(battery);
 	int result = acpi_battery_get_status(battery);
-	if (result || !acpi_battery_present(battery))
+	if (result)
 		return result;
+	if (!acpi_battery_present(battery)) {
+		battery->bat.properties = missing_battery_props;
+		battery->bat.num_properties = ARRAY_SIZE(missing_battery_props);
+		return result;
+	}
 	if (saved_present != acpi_battery_present(battery) ||
 	    !battery->update_time) {
 		battery->update_time = 0;
#1 lore raw
Quoted 5 lines · Andrey Borzenkov

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Hm, do you need separate set of properties for that? You could register either of existing two, and read function will not allow read of anything but "present". IMHO, this is what other modules do (/drivers/power)
One remaining trick here, you need to call unregister/register for power_supply if you change attributes -- so please check if your patched driver survives insertion of the battery.

Regards,
Alex.

#2 lore raw
Quoted 8 lines · Alexey Starikovskiy
Quoted 3 lines · Andrey Borzenkov

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Hm, do you need separate set of properties for that? You could register either of existing two, and read function will not allow read of anything but "present". IMHO, this is what other modules do (/drivers/power)

Do they have different set of properties depending on underlying hardware that you can't query unless hardware is present? I'd rather avoid adding fake attributes; but I do not actually care so which one do you prefer? :)

Quoted 4 lines

One remaining trick here, you need to call unregister/register for power_supply if you change attributes -- so please check if your patched driver survives insertion of the battery.

Neither does your code (nor kpowersave :) ) Remove battery and set of attributes is "stuck" instead of being reset to only fixed set of power device attributes (basically "info"). The only call to power_supply_register is in acpi_battery_add and as far as I can tell this is executed on adding *slot* not when content of this slot changes.

#3 lore raw
Quoted 5 lines · Andrey Borzenkov
Quoted 4 lines · Alexey Starikovskiy
Quoted 3 lines · Andrey Borzenkov

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Quoted 7 lines
Quoted 3 lines

Hm, do you need separate set of properties for that? You could register either of existing two, and read function will not allow read of anything but "present". IMHO, this is what other modules do (/drivers/power)

Do they have different set of properties depending on underlying hardware that you can't query unless hardware is present? I'd rather avoid adding fake attributes; but I do not actually care so which one do you prefer? :)

I prefer less code :)

Quoted 7 lines
Quoted 5 lines

One remaining trick here, you need to call unregister/register for power_supply if you change attributes -- so please check if your patched driver survives insertion of the battery.

Quoted 5 lines

Neither does your code (nor kpowersave :) ) Remove battery and set of attributes is "stuck" instead of being reset to only fixed set of power device attributes (basically "info"). The only call to power_supply_register is in acpi_battery_add and as far as I can tell this is executed on adding *slot* not when content of this slot changes.

Point is -- it does not break :) If you start to play with shorter length of attributes table and don't call unregister/register, power_supply may go past the end of table.

#4 lore raw
In reply to Andrey Borzenkov
Quoted 3 lines · Andrey Borzenkov

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Well, PROP_PRESENT wasn't my idea, currently it's used by pmu and olpc drivers becuase it's not trivial to register/unregister their batteries on physical insertion/removal. I have some plans to teach at least pmu batteries to not use PROP_PRESENT. I don't have any OLPC, thus I can't convert it.

To sum this: the good way to handle "missing" batteries is to unregister them, so they'll not show up in the /sys/class/power_supply. Is that possible with the ACPI?

The good example is ds2760 batteries:

drivers/power/ds2760_battery.c - is platform device drivers/w1/slaves/w1_ds2760.c - is w1 slave, which registers/unregisters pdevs on the detection/removal.

Quoted 1 line

Subject: [PATCH] 2.6.24-rc1: ensure "present" sysfs attribute even if battery is absent

Bad idea. Don't use present attribute, if possible.

Quoted 45 lines

From: Andrey Borzenkov <[email protected]>

Ensure that we always have "present" attribute in sysfs. This is compatible with procfs case where we had "present: no" if battery was not available.

This fixes HAL battery detection where it does pretend battery is present but canot provide any value for it.

---

 drivers/acpi/battery.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)
drivers/acpi/battery.c +10 -1
index 681e26b..6e67fcd 100644
@@ -187,6 +187,10 @@ static int acpi_battery_get_property(struct power_supply *psy,
 	return 0;
 }
 
+static enum power_supply_property missing_battery_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+};
+
 static enum power_supply_property charge_battery_props[] = {
 	POWER_SUPPLY_PROP_STATUS,
 	POWER_SUPPLY_PROP_PRESENT,
@@ -389,8 +393,13 @@ static int acpi_battery_update(struct acpi_battery *battery)
 {
 	int saved_present = acpi_battery_present(battery);
 	int result = acpi_battery_get_status(battery);
-	if (result || !acpi_battery_present(battery))
+	if (result)
 		return result;
+	if (!acpi_battery_present(battery)) {
+		battery->bat.properties = missing_battery_props;
+		battery->bat.num_properties = ARRAY_SIZE(missing_battery_props);
+		return result;
+	}
 	if (saved_present != acpi_battery_present(battery) ||
 	    !battery->update_time) {
 		battery->update_time = 0;
Signature · 4 lines
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2
#5 lore raw
Quoted 5 lines · Anton Vorontsov

Well, PROP_PRESENT wasn't my idea, currently it's used by pmu and olpc drivers becuase it's not trivial to register/unregister their batteries on physical insertion/removal. I have some plans to teach at least pmu batteries to not use PROP_PRESENT. I don't have any OLPC, thus I can't convert it.

Actually it's not hard to do that. It was done this way in response to a request from the userspace side. IIRC.

Signature · 1 line
dwmw2
#6 lore raw
Quoted 8 lines · David Woodhouse
Quoted 5 lines · Anton Vorontsov

Well, PROP_PRESENT wasn't my idea, currently it's used by pmu and olpc drivers becuase it's not trivial to register/unregister their batteries on physical insertion/removal. I have some plans to teach at least pmu batteries to not use PROP_PRESENT. I don't have any OLPC, thus I can't convert it.

Actually it's not hard to do that.

I didn't say it's hard. But we don't have any interrupts for the battery events, thus we have to implement polling.

Quoted 2 lines

It was done this way in response to a
request from the userspace side. IIRC.

Oh. Userspace tried to do something weird then, I think. Generally it's just sane to unregister absent hardware.

Signature · 4 lines
Anton Vorontsov
email: [email protected]
backup email: [email protected]
irc://irc.freenode.net/bd2
#7 lore raw
In reply to Anton Vorontsov
Quoted 5 lines · Anton Vorontsov
Quoted 3 lines · Andrey Borzenkov

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Quoted 8 lines

Well, PROP_PRESENT wasn't my idea, currently it's used by pmu and olpc drivers becuase it's not trivial to register/unregister their batteries on physical insertion/removal. I have some plans to teach at least pmu batteries to not use PROP_PRESENT. I don't have any OLPC, thus I can't convert it.

To sum this: the good way to handle "missing" batteries is to unregister them, so they'll not show up in the /sys/class/power_supply.

Well, in this case HAL behaviour makes sense (default to present == true if "present" attribute is missing)

Quoted 2 lines

Is that possible with the ACPI?

At least looking in ACPI specs, this looks possible. What currently is presented as battery object is actually battery bay according to ACPI spec:

Unlike most other devices, when a battery is inserted or removed from the system, the device itself (the
battery bay) is still considered to be present in the system.

When battery is inserted/removed, ACPI notifies us and we can check whether battery is actually present and update registration accordingly. From the sysfs structure POV probably nothing has to be changed; just when and how power_supply is registered
under /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:0n

Alexey, does it make sense (or doable)?

#8 lore raw

PATCH 1/1 ACPI: register power_supply subdevice only when battery is present

Quoted 27 lines · Andrey Borzenkov
Quoted 5 lines · Anton Vorontsov
Quoted 3 lines · Andrey Borzenkov

I am not exactly sure about this one ... what other power_supply class drivers do? Should I fix HAL instead (but then, I do not know whether HAL is the only application that is using this interface).

Quoted 8 lines

Well, PROP_PRESENT wasn't my idea, currently it's used by pmu and olpc drivers becuase it's not trivial to register/unregister their batteries on physical insertion/removal. I have some plans to teach at least pmu batteries to not use PROP_PRESENT. I don't have any OLPC, thus I can't convert it.

To sum this: the good way to handle "missing" batteries is to unregister them, so they'll not show up in the /sys/class/power_supply.

Well, in this case HAL behaviour makes sense (default to present == true if "present" attribute is missing)

Quoted 1 line

Is that possible with the ACPI?

At least looking in ACPI specs, this looks possible. What currently is presented as battery object is actually battery bay according to ACPI spec:

Unlike most other devices, when a battery is inserted or removed from the system, the device itself (the
battery bay) is still considered to be present in the system.

Quoted 7 lines

When battery is inserted/removed, ACPI notifies us and we can check whether battery is actually present and update registration accordingly. From the sysfs structure POV probably nothing has to be changed; just when and how power_supply is registered
under /sys/devices/LNXSYSTM:00/device:00/PNP0C0A:0n

Alexey, does it make sense (or doable)?

or would you take attached patch as prototype? :) This works on my system and does not crash it immediately. Here is event sequence I get:

UEVENT[1193556388.161539] add /module/battery (module)
ACTION=add
DEVPATH=/module/battery
SUBSYSTEM=module
SEQNUM=3243

UEVENT[1193556388.177069] add /bus/acpi/drivers/battery (drivers)
ACTION=add
DEVPATH=/bus/acpi/drivers/battery
SUBSYSTEM=drivers
SEQNUM=3244

UEVENT[1193556388.212721]
add /devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1
(power_supply)
ACTION=add DEVPATH=/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1 SUBSYSTEM=power_supply
SEQNUM=3245

UEVENT[1193556388.223113]
change /devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1
(power_supply)
ACTION=change DEVPATH=/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1 SUBSYSTEM=power_supply
POWER_SUPPLY_NAME=BAT1
POWER_SUPPLY_TYPE=Battery
POWER_SUPPLY_STATUS=Full
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_TECHNOLOGY=Unknown POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000 POWER_SUPPLY_VOLTAGE_NOW=0
POWER_SUPPLY_CURRENT_NOW=0 POWER_SUPPLY_ENERGY_FULL_DESIGN=38880000 POWER_SUPPLY_ENERGY_FULL=37530000 POWER_SUPPLY_ENERGY_NOW=0 POWER_SUPPLY_MODEL_NAME=XM2038P04 POWER_SUPPLY_MANUFACTURER=
SEQNUM=3246

physically remove battery

UEVENT[1193556483.326303]
remove /devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1
(power_supply)
ACTION=remove DEVPATH=/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1 SUBSYSTEM=power_supply
POWER_SUPPLY_NAME=BAT1
POWER_SUPPLY_TYPE=Battery
POWER_SUPPLY_PRESENT=0
SEQNUM=3252

battery back

UEVENT[1193556510.339045]
add /devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1
(power_supply)
ACTION=add DEVPATH=/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1 SUBSYSTEM=power_supply
SEQNUM=3253

UEVENT[1193556510.339387]
change /devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1
(power_supply)
ACTION=change DEVPATH=/devices/LNXSYSTM:00/device:00/PNP0C0A:00/power_supply/BAT1 SUBSYSTEM=power_supply
POWER_SUPPLY_NAME=BAT1
POWER_SUPPLY_TYPE=Battery
POWER_SUPPLY_STATUS=Charging
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_TECHNOLOGY=Unknown POWER_SUPPLY_VOLTAGE_MIN_DESIGN=10800000 POWER_SUPPLY_VOLTAGE_NOW=11340000 POWER_SUPPLY_CURRENT_NOW=13197000 POWER_SUPPLY_ENERGY_FULL_DESIGN=38880000 POWER_SUPPLY_ENERGY_FULL=37530000 POWER_SUPPLY_ENERGY_NOW=37519000 POWER_SUPPLY_MODEL_NAME=XM2038P04 POWER_SUPPLY_MANUFACTURER=
SEQNUM=3254

We'll probably need to teach user space to distinguish between battery and battery bay (and not to crash when battery is removed :) ) but that is all doable once we settle on kernel implementation.

Subject: [PATCH] [2.6.24-rc] ACPI: register power_supply subdevice only when battery is present
From: Andrey Borzenkov <[email protected]>

Make sure no power_supply object is present unless we actualy detect presence of battery. This fixes ghost batteries detected by HAL

---

 drivers/acpi/battery.c |   98 ++++++++++++++++++++++++++++++------------------
 1 files changed, 61 insertions(+), 37 deletions(-)
drivers/acpi/battery.c +61 -37
index d33cb49..f37e509 100644
@@ -390,14 +390,64 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
 	return acpi_battery_set_alarm(battery);
 }
 
+static ssize_t acpi_battery_alarm_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+	return sprintf(buf, "%d\n", battery->alarm * 1000);
+}
+
+static ssize_t acpi_battery_alarm_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	unsigned long x;
+	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+	if (sscanf(buf, "%ld\n", &x) == 1)
+		battery->alarm = x/1000;
+	if (acpi_battery_present(battery))
+		acpi_battery_set_alarm(battery);
+	return count;
+}
+
+static struct device_attribute alarm_attr = {
+	.attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
+	.show = acpi_battery_alarm_show,
+	.store = acpi_battery_alarm_store,
+};
+
+static int sysfs_add_battery(struct acpi_battery *battery)
+{
+	int result = 0;
+
+	result = power_supply_register(&battery->device->dev, &battery->bat);
+	result = device_create_file(battery->bat.dev, &alarm_attr);
+
+	return result;
+}
+
+static int sysfs_remove_battery(struct acpi_battery *battery)
+{
+	if (battery->bat.dev) {
+		device_remove_file(battery->bat.dev, &alarm_attr);
+		power_supply_unregister(&battery->bat);
+		battery->bat.dev = NULL;
+	}
+
+	return 0;
+}
+
 static int acpi_battery_update(struct acpi_battery *battery)
 {
-	int saved_present = acpi_battery_present(battery);
 	int result = acpi_battery_get_status(battery);
-	if (result || !acpi_battery_present(battery))
+	if (result)
 		return result;
-	if (saved_present != acpi_battery_present(battery) ||
-	    !battery->update_time) {
+	if (!acpi_battery_present(battery)) {
+		sysfs_remove_battery(battery);
+		return 0;
+	}
+	if (!battery->bat.dev) {
 		battery->update_time = 0;
 		result = acpi_battery_get_info(battery);
 		if (result)
@@ -411,6 +461,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
 			battery->bat.num_properties =
 				ARRAY_SIZE(energy_battery_props);
 		}
+		sysfs_add_battery(battery);
 		acpi_battery_init_alarm(battery);
 	}
 	return acpi_battery_get_state(battery);
@@ -693,33 +744,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
 
 #endif
 
-static ssize_t acpi_battery_alarm_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
-	return sprintf(buf, "%d\n", battery->alarm * 1000);
-}
-
-static ssize_t acpi_battery_alarm_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	unsigned long x;
-	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
-	if (sscanf(buf, "%ld\n", &x) == 1)
-		battery->alarm = x/1000;
-	if (acpi_battery_present(battery))
-		acpi_battery_set_alarm(battery);
-	return count;
-}
-
-static struct device_attribute alarm_attr = {
-	.attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
-	.show = acpi_battery_alarm_show,
-	.store = acpi_battery_alarm_store,
-};
-
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -737,7 +761,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
 	acpi_bus_generate_netlink_event(device->pnp.device_class,
 					device->dev.bus_id, event,
 					acpi_battery_present(battery));
-	kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
+	/* acpi_batter_update could remove power_supply object */
+	if (battery->bat.dev)
+		kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
 }
 
 static int acpi_battery_add(struct acpi_device *device)
@@ -755,17 +781,15 @@ static int acpi_battery_add(struct acpi_device *device)
 	strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
 	acpi_driver_data(device) = battery;
 	mutex_init(&battery->lock);
+	battery->bat.name = acpi_device_bid(device);
+	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+	battery->bat.get_property = acpi_battery_get_property;
 	acpi_battery_update(battery);
 #ifdef CONFIG_ACPI_PROCFS
 	result = acpi_battery_add_fs(device);
 	if (result)
 		goto end;
 #endif
-	battery->bat.name = acpi_device_bid(device);
-	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
-	battery->bat.get_property = acpi_battery_get_property;
-	result = power_supply_register(&battery->device->dev, &battery->bat);
-	result = device_create_file(battery->bat.dev, &alarm_attr);
 	status = acpi_install_notify_handler(device->handle,
 					     ACPI_ALL_NOTIFY,
 					     acpi_battery_notify, battery);
#9 lore raw

PATCH 1/1 ACPI: battery: register power_supply subdevice only when battery is present

In reply to Andrey Borzenkov

From: Andrey Borzenkov <[email protected]>

Make sure no power_supply object is present unless we actualy detect presence of battery. This fixes ghost batteries detected by HAL

---

 drivers/acpi/battery.c |  130 ++++++++++++++++++++++++++++--------------------
 1 files changed, 75 insertions(+), 55 deletions(-)
drivers/acpi/battery.c +75 -55
index 6c06879..e3133bc 100644
@@ -393,29 +393,81 @@ static int acpi_battery_init_alarm(struct acpi_battery *battery)
 	return acpi_battery_set_alarm(battery);
 }
 
+static ssize_t acpi_battery_alarm_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+	return sprintf(buf, "%d\n", battery->alarm * 1000);
+}
+
+static ssize_t acpi_battery_alarm_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	unsigned long x;
+	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
+	if (sscanf(buf, "%ld\n", &x) == 1)
+		battery->alarm = x/1000;
+	if (acpi_battery_present(battery))
+		acpi_battery_set_alarm(battery);
+	return count;
+}
+
+static struct device_attribute alarm_attr = {
+	.attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
+	.show = acpi_battery_alarm_show,
+	.store = acpi_battery_alarm_store,
+};
+
+static int sysfs_add_battery(struct acpi_battery *battery)
+{
+	int result;
+
+	battery->update_time = 0;
+	result = acpi_battery_get_info(battery);
+	acpi_battery_init_alarm(battery);
+	if (result)
+		return result;
+	if (battery->power_unit) {
+		battery->bat.properties = charge_battery_props;
+		battery->bat.num_properties =
+			ARRAY_SIZE(charge_battery_props);
+	} else {
+		battery->bat.properties = energy_battery_props;
+		battery->bat.num_properties =
+			ARRAY_SIZE(energy_battery_props);
+	}
+
+	battery->bat.name = acpi_device_bid(battery->device);
+	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+	battery->bat.get_property = acpi_battery_get_property;
+
+	result = power_supply_register(&battery->device->dev, &battery->bat);
+	if (result)
+		return result;
+	return device_create_file(battery->bat.dev, &alarm_attr);
+}
+
+static void sysfs_remove_battery(struct acpi_battery *battery)
+{
+	if (!battery->bat.dev)
+		return;
+	device_remove_file(battery->bat.dev, &alarm_attr);
+	power_supply_unregister(&battery->bat);
+}
+
 static int acpi_battery_update(struct acpi_battery *battery)
 {
-	int saved_present = acpi_battery_present(battery);
 	int result = acpi_battery_get_status(battery);
-	if (result || !acpi_battery_present(battery))
+	if (result)
 		return result;
-	if (saved_present != acpi_battery_present(battery) ||
-	    !battery->update_time) {
-		battery->update_time = 0;
-		result = acpi_battery_get_info(battery);
-		if (result)
-			return result;
-		if (battery->power_unit) {
-			battery->bat.properties = charge_battery_props;
-			battery->bat.num_properties =
-				ARRAY_SIZE(charge_battery_props);
-		} else {
-			battery->bat.properties = energy_battery_props;
-			battery->bat.num_properties =
-				ARRAY_SIZE(energy_battery_props);
-		}
-		acpi_battery_init_alarm(battery);
+	if (!acpi_battery_present(battery)) {
+		sysfs_remove_battery(battery);
+		return 0;
 	}
+	if (!battery->bat.dev)
+		sysfs_add_battery(battery);
 	return acpi_battery_get_state(battery);
 }
 
@@ -696,33 +748,6 @@ static void acpi_battery_remove_fs(struct acpi_device *device)
 
 #endif
 
-static ssize_t acpi_battery_alarm_show(struct device *dev,
-					struct device_attribute *attr,
-					char *buf)
-{
-	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
-	return sprintf(buf, "%d\n", battery->alarm * 1000);
-}
-
-static ssize_t acpi_battery_alarm_store(struct device *dev,
-					struct device_attribute *attr,
-					const char *buf, size_t count)
-{
-	unsigned long x;
-	struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev));
-	if (sscanf(buf, "%ld\n", &x) == 1)
-		battery->alarm = x/1000;
-	if (acpi_battery_present(battery))
-		acpi_battery_set_alarm(battery);
-	return count;
-}
-
-static struct device_attribute alarm_attr = {
-	.attr = {.name = "alarm", .mode = 0644, .owner = THIS_MODULE},
-	.show = acpi_battery_alarm_show,
-	.store = acpi_battery_alarm_store,
-};
-
 /* --------------------------------------------------------------------------
                                  Driver Interface
    -------------------------------------------------------------------------- */
@@ -740,7 +765,9 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
 	acpi_bus_generate_netlink_event(device->pnp.device_class,
 					device->dev.bus_id, event,
 					acpi_battery_present(battery));
-	kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
+	/* acpi_batter_update could remove power_supply object */
+	if (battery->bat.dev)
+		kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
 }
 
 static int acpi_battery_add(struct acpi_device *device)
@@ -764,11 +791,6 @@ static int acpi_battery_add(struct acpi_device *device)
 	if (result)
 		goto end;
 #endif
-	battery->bat.name = acpi_device_bid(device);
-	battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
-	battery->bat.get_property = acpi_battery_get_property;
-	result = power_supply_register(&battery->device->dev, &battery->bat);
-	result = device_create_file(battery->bat.dev, &alarm_attr);
 	status = acpi_install_notify_handler(device->handle,
 					     ACPI_ALL_NOTIFY,
 					     acpi_battery_notify, battery);
@@ -804,10 +826,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 #ifdef CONFIG_ACPI_PROCFS
 	acpi_battery_remove_fs(device);
 #endif
-	if (battery->bat.dev) {
-		device_remove_file(battery->bat.dev, &alarm_attr);
-		power_supply_unregister(&battery->bat);
-	}
+	sysfs_remove_battery(battery);
 	mutex_destroy(&battery->lock);
 	kfree(battery);
 	return 0;
@@ -821,6 +840,7 @@ static int acpi_battery_resume(struct acpi_device *device)
 		return -EINVAL;
 	battery = acpi_driver_data(device);
 	battery->update_time = 0;
+	acpi_battery_update(battery);
 	return 0;
 }