]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/acpi/battery.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
[linux-2.6-omap-h63xx.git] / drivers / acpi / battery.c
index 681e26b56b11c2b37a3e242db63ee9ef1dc6444a..8f7505d304b58790c077e4bc257380eccf523117 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/types.h>
 #include <linux/jiffies.h>
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <asm/uaccess.h>
@@ -63,7 +63,7 @@ static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 extern struct proc_dir_entry *acpi_lock_battery_dir(void);
 extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
@@ -125,19 +125,25 @@ static int acpi_battery_technology(struct acpi_battery *battery)
                return POWER_SUPPLY_TECHNOLOGY_NiMH;
        if (!strcasecmp("LION", battery->type))
                return POWER_SUPPLY_TECHNOLOGY_LION;
+       if (!strncasecmp("LI-ION", battery->type, 6))
+               return POWER_SUPPLY_TECHNOLOGY_LION;
        if (!strcasecmp("LiP", battery->type))
                return POWER_SUPPLY_TECHNOLOGY_LIPO;
        return POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
 }
 
+static int acpi_battery_get_state(struct acpi_battery *battery);
+
 static int acpi_battery_get_property(struct power_supply *psy,
                                     enum power_supply_property psp,
                                     union power_supply_propval *val)
 {
        struct acpi_battery *battery = to_acpi_battery(psy);
 
-       if ((!acpi_battery_present(battery)) &&
-            psp != POWER_SUPPLY_PROP_PRESENT)
+       if (acpi_battery_present(battery)) {
+               /* run battery update only if it is present */
+               acpi_battery_get_state(battery);
+       } else if (psp != POWER_SUPPLY_PROP_PRESENT)
                return -ENODEV;
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
@@ -147,6 +153,8 @@ static int acpi_battery_get_property(struct power_supply *psy,
                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
                else if (battery->state == 0)
                        val->intval = POWER_SUPPLY_STATUS_FULL;
+               else
+                       val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
                break;
        case POWER_SUPPLY_PROP_PRESENT:
                val->intval = acpi_battery_present(battery);
@@ -215,7 +223,7 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_MANUFACTURER,
 };
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 inline char *acpi_battery_units(struct acpi_battery *battery)
 {
        return (battery->power_unit)?"mA":"mW";
@@ -257,7 +265,7 @@ static int extract_package(struct acpi_battery *battery,
                           union acpi_object *package,
                           struct acpi_offsets *offsets, int num)
 {
-       int i, *x;
+       int i;
        union acpi_object *element;
        if (package->type != ACPI_TYPE_PACKAGE)
                return -EFAULT;
@@ -266,16 +274,21 @@ static int extract_package(struct acpi_battery *battery,
                        return -EFAULT;
                element = &package->package.elements[i];
                if (offsets[i].mode) {
-                       if (element->type != ACPI_TYPE_STRING &&
-                           element->type != ACPI_TYPE_BUFFER)
-                               return -EFAULT;
-                       strncpy((u8 *)battery + offsets[i].offset,
-                               element->string.pointer, 32);
+                       u8 *ptr = (u8 *)battery + offsets[i].offset;
+                       if (element->type == ACPI_TYPE_STRING ||
+                           element->type == ACPI_TYPE_BUFFER)
+                               strncpy(ptr, element->string.pointer, 32);
+                       else if (element->type == ACPI_TYPE_INTEGER) {
+                               strncpy(ptr, (u8 *)&element->integer.value,
+                                       sizeof(acpi_integer));
+                               ptr[sizeof(acpi_integer)] = 0;
+                       } else return -EFAULT;
                } else {
-                       if (element->type != ACPI_TYPE_INTEGER)
-                               return -EFAULT;
-                       x = (int *)((u8 *)battery + offsets[i].offset);
-                       *x = element->integer.value;
+                       if (element->type == ACPI_TYPE_INTEGER) {
+                               int *x = (int *)((u8 *)battery +
+                                               offsets[i].offset);
+                               *x = element->integer.value;
+                       } else return -EFAULT;
                }
        }
        return 0;
@@ -385,29 +398,82 @@ 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);
+       battery->bat.dev = NULL;
+}
+
 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);
 }
 
@@ -415,7 +481,7 @@ static int acpi_battery_update(struct acpi_battery *battery)
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
 static struct proc_dir_entry *acpi_battery_dir;
 
 static int acpi_battery_print_info(struct seq_file *seq, int result)
@@ -554,10 +620,6 @@ static ssize_t acpi_battery_write_alarm(struct file *file,
 
        if (!battery || (count > sizeof(alarm_string) - 1))
                return -EINVAL;
-       if (result) {
-               result = -ENODEV;
-               goto end;
-       }
        if (!acpi_battery_present(battery)) {
                result = -ENODEV;
                goto end;
@@ -688,33 +750,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
    -------------------------------------------------------------------------- */
@@ -732,7 +767,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)
@@ -751,16 +788,11 @@ static int acpi_battery_add(struct acpi_device *device)
        acpi_driver_data(device) = battery;
        mutex_init(&battery->lock);
        acpi_battery_update(battery);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
        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);
@@ -774,7 +806,7 @@ static int acpi_battery_add(struct acpi_device *device)
               device->status.battery_present ? "present" : "absent");
       end:
        if (result) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
                acpi_battery_remove_fs(device);
 #endif
                kfree(battery);
@@ -793,13 +825,10 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
        status = acpi_remove_notify_handler(device->handle,
                                            ACPI_ALL_NOTIFY,
                                            acpi_battery_notify);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
        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;
@@ -813,6 +842,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;
 }
 
@@ -831,13 +861,13 @@ static int __init acpi_battery_init(void)
 {
        if (acpi_disabled)
                return -ENODEV;
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_dir = acpi_lock_battery_dir();
        if (!acpi_battery_dir)
                return -ENODEV;
 #endif
        if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
                acpi_unlock_battery_dir(acpi_battery_dir);
 #endif
                return -ENODEV;
@@ -848,7 +878,7 @@ static int __init acpi_battery_init(void)
 static void __exit acpi_battery_exit(void)
 {
        acpi_bus_unregister_driver(&acpi_battery_driver);
-#ifdef CONFIG_ACPI_PROCFS
+#ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_unlock_battery_dir(acpi_battery_dir);
 #endif
 }