All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andrey Borzenkov <arvidjaar@mail.ru>
To: cbou@mail.ru
Cc: linux-acpi@vger.kernel.org, linux-kernel@vger.kernel.org,
	dwmw2@infradead.org, Alexey Starikovskiy <aystarik@gmail.com>
Subject: [PATCH] [2.6.24-rc] ACPI: register power_supply subdevice only when battery is present
Date: Sun, 28 Oct 2007 11:37:26 +0400	[thread overview]
Message-ID: <200710281037.28098.arvidjaar@mail.ru> (raw)
In-Reply-To: <200710280950.46779.arvidjaar@mail.ru>


[-- Attachment #1.1: Type: text/plain, Size: 4496 bytes --]

On Sunday 28 October 2007, Andrey Borzenkov wrote:
> On Saturday 27 October 2007, Anton Vorontsov wrote:
> > On Sat, Oct 27, 2007 at 08:54:30PM +0400, Andrey Borzenkov wrote:
> > > 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.
>
> Well, in this case HAL behaviour makes sense (default to present == true
> if "present" attribute is missing)
>
> > 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)?

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.

[-- Attachment #1.2: fix_ACPI_battery_registration --]
[-- Type: text/x-diff, Size: 5549 bytes --]

Subject: [PATCH] [2.6.24-rc] ACPI: register power_supply subdevice only when battery is present
From: Andrey Borzenkov <arvidjaar@mail.ru>

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

Signed-off-by: Andrey Borzenkov <arvidjaar@mail.ru>

---

 drivers/acpi/battery.c |   98 ++++++++++++++++++++++++++++++------------------
 1 files changed, 61 insertions(+), 37 deletions(-)

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index d33cb49..f37e509 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -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);

[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

      reply	other threads:[~2007-10-28  7:37 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-10-27 16:54 [PATCH] 2.6.24-rc1: ensure "present" sysfs attribute even if battery is absent Andrey Borzenkov
2007-10-27 17:16 ` Alexey Starikovskiy
2007-10-27 17:50   ` Andrey Borzenkov
2007-10-27 18:18     ` Alexey Starikovskiy
2007-10-27 18:42 ` Anton Vorontsov
2007-10-27 19:32   ` David Woodhouse
2007-10-27 19:50     ` Anton Vorontsov
2007-10-28  6:50   ` Andrey Borzenkov
2007-10-28  7:37     ` Andrey Borzenkov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200710281037.28098.arvidjaar@mail.ru \
    --to=arvidjaar@mail.ru \
    --cc=aystarik@gmail.com \
    --cc=cbou@mail.ru \
    --cc=dwmw2@infradead.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.