diff options
Diffstat (limited to 'drivers/acpi/battery.c')
| -rw-r--r-- | drivers/acpi/battery.c | 337 |
1 files changed, 178 insertions, 159 deletions
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index dae91f906cea..34181fa52e93 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -10,7 +10,6 @@ #define pr_fmt(fmt) "ACPI: battery: " fmt -#include <linux/async.h> #include <linux/delay.h> #include <linux/dmi.h> #include <linux/jiffies.h> @@ -22,7 +21,7 @@ #include <linux/suspend.h> #include <linux/types.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/power_supply.h> @@ -38,37 +37,36 @@ /* Battery power unit: 0 means mW, 1 means mA */ #define ACPI_BATTERY_POWER_UNIT_MA 1 -#define ACPI_BATTERY_STATE_DISCHARGING 0x1 -#define ACPI_BATTERY_STATE_CHARGING 0x2 -#define ACPI_BATTERY_STATE_CRITICAL 0x4 +#define ACPI_BATTERY_STATE_DISCHARGING 0x1 +#define ACPI_BATTERY_STATE_CHARGING 0x2 +#define ACPI_BATTERY_STATE_CRITICAL 0x4 +#define ACPI_BATTERY_STATE_CHARGE_LIMITING 0x8 + +#define MAX_STRING_LENGTH 64 MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); -static async_cookie_t async_cookie; -static bool battery_driver_registered; static int battery_bix_broken_package; static int battery_notification_delay_ms; static int battery_ac_is_broken; -static int battery_check_pmic = 1; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); static const struct acpi_device_id battery_device_ids[] = { {"PNP0C0A", 0}, + + /* Microsoft Surface Go 3 */ + {"MSHW0146", 0}, + {"", 0}, }; MODULE_DEVICE_TABLE(acpi, battery_device_ids); -/* Lists of PMIC ACPI HIDs with an (often better) native battery driver */ -static const char * const acpi_battery_blacklist[] = { - "INT33F4", /* X-Powers AXP288 PMIC */ -}; - enum { ACPI_BATTERY_ALARM_PRESENT, ACPI_BATTERY_XINFO_PRESENT, @@ -93,8 +91,7 @@ enum { }; struct acpi_battery { - struct mutex lock; - struct mutex sysfs_lock; + struct mutex update_lock; struct power_supply *bat; struct power_supply_desc bat_desc; struct acpi_device *device; @@ -120,10 +117,10 @@ struct acpi_battery { int capacity_granularity_1; int capacity_granularity_2; int alarm; - char model_number[32]; - char serial_number[32]; - char type[32]; - char oem_info[32]; + char model_number[MAX_STRING_LENGTH]; + char serial_number[MAX_STRING_LENGTH]; + char type[MAX_STRING_LENGTH]; + char oem_info[MAX_STRING_LENGTH]; int state; int power_unit; unsigned long flags; @@ -155,7 +152,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery); static int acpi_battery_is_charged(struct acpi_battery *battery) { - /* charging, discharging or critical low */ + /* charging, discharging, critical low or charge limited */ if (battery->state != 0) return 0; @@ -169,7 +166,7 @@ static int acpi_battery_is_charged(struct acpi_battery *battery) return 1; /* fallback to using design values for broken batteries */ - if (battery->design_capacity == battery->capacity_now) + if (battery->design_capacity <= battery->capacity_now) return 1; /* we don't do any sort of metric based on percentages */ @@ -215,10 +212,12 @@ static int acpi_battery_get_property(struct power_supply *psy, val->intval = acpi_battery_handle_discharging(battery); else if (battery->state & ACPI_BATTERY_STATE_CHARGING) val->intval = POWER_SUPPLY_STATUS_CHARGING; + else if (battery->state & ACPI_BATTERY_STATE_CHARGE_LIMITING) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; else if (acpi_battery_is_charged(battery)) val->intval = POWER_SUPPLY_STATUS_FULL; else - val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; break; case POWER_SUPPLY_PROP_PRESENT: val->intval = acpi_battery_present(battery); @@ -279,8 +278,8 @@ static int acpi_battery_get_property(struct power_supply *psy, full_capacity == ACPI_BATTERY_VALUE_UNKNOWN) ret = -ENODEV; else - val->intval = battery->capacity_now * 100/ - full_capacity; + val->intval = DIV_ROUND_CLOSEST_ULL(battery->capacity_now * 100ULL, + full_capacity); break; case POWER_SUPPLY_PROP_CAPACITY_LEVEL: if (battery->state & ACPI_BATTERY_STATE_CRITICAL) @@ -308,7 +307,7 @@ static int acpi_battery_get_property(struct power_supply *psy, return ret; } -static enum power_supply_property charge_battery_props[] = { +static const enum power_supply_property charge_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, @@ -326,7 +325,7 @@ static enum power_supply_property charge_battery_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; -static enum power_supply_property charge_battery_full_cap_broken_props[] = { +static const enum power_supply_property charge_battery_full_cap_broken_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, @@ -340,7 +339,7 @@ static enum power_supply_property charge_battery_full_cap_broken_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; -static enum power_supply_property energy_battery_props[] = { +static const enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, @@ -358,7 +357,7 @@ static enum power_supply_property energy_battery_props[] = { POWER_SUPPLY_PROP_SERIAL_NUMBER, }; -static enum power_supply_property energy_battery_full_cap_broken_props[] = { +static const enum power_supply_property energy_battery_full_cap_broken_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_TECHNOLOGY, @@ -439,16 +438,25 @@ static int extract_package(struct acpi_battery *battery, element = &package->package.elements[i]; if (offsets[i].mode) { u8 *ptr = (u8 *)battery + offsets[i].offset; + u32 len = MAX_STRING_LENGTH; + + switch (element->type) { + case ACPI_TYPE_BUFFER: + if (len > element->buffer.length + 1) + len = element->buffer.length + 1; + + fallthrough; + case ACPI_TYPE_STRING: + strscpy(ptr, element->string.pointer, len); - 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(u64)); - ptr[sizeof(u64)] = 0; - } else + break; + case ACPI_TYPE_INTEGER: + strscpy(ptr, (u8 *)&element->integer.value, sizeof(u64) + 1); + + break; + default: *ptr = 0; /* don't have value */ + } } else { int *x = (int *)((u8 *)battery + offsets[i].offset); *x = (element->type == ACPI_TYPE_INTEGER) ? @@ -526,11 +534,9 @@ static int acpi_battery_get_info(struct acpi_battery *battery) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_status status = AE_ERROR; - mutex_lock(&battery->lock); status = acpi_evaluate_object(battery->device->handle, use_bix ? "_BIX":"_BIF", NULL, &buffer); - mutex_unlock(&battery->lock); if (ACPI_FAILURE(status)) { acpi_handle_info(battery->device->handle, @@ -567,11 +573,8 @@ static int acpi_battery_get_state(struct acpi_battery *battery) msecs_to_jiffies(cache_time))) return 0; - mutex_lock(&battery->lock); status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer); - mutex_unlock(&battery->lock); - if (ACPI_FAILURE(status)) { acpi_handle_info(battery->device->handle, "_BST evaluation failed: %s", @@ -619,11 +622,8 @@ static int acpi_battery_set_alarm(struct acpi_battery *battery) !test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags)) return -ENODEV; - mutex_lock(&battery->lock); status = acpi_execute_simple_method(battery->device->handle, "_BTP", battery->alarm); - mutex_unlock(&battery->lock); - if (ACPI_FAILURE(status)) return -ENODEV; @@ -652,7 +652,7 @@ static ssize_t acpi_battery_alarm_show(struct device *dev, { struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - return sprintf(buf, "%d\n", battery->alarm * 1000); + return sysfs_emit(buf, "%d\n", battery->alarm * 1000); } static ssize_t acpi_battery_alarm_store(struct device *dev, @@ -669,12 +669,18 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, return count; } -static const struct device_attribute alarm_attr = { +static struct device_attribute alarm_attr = { .attr = {.name = "alarm", .mode = 0644}, .show = acpi_battery_alarm_show, .store = acpi_battery_alarm_store, }; +static struct attribute *acpi_battery_attrs[] = { + &alarm_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(acpi_battery); + /* * The Battery Hooking API * @@ -688,27 +694,35 @@ static LIST_HEAD(acpi_battery_list); static LIST_HEAD(battery_hook_list); static DEFINE_MUTEX(hook_mutex); -static void __battery_hook_unregister(struct acpi_battery_hook *hook, int lock) +static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook) { struct acpi_battery *battery; + /* * In order to remove a hook, we first need to * de-register all the batteries that are registered. */ - if (lock) - mutex_lock(&hook_mutex); list_for_each_entry(battery, &acpi_battery_list, list) { - hook->remove_battery(battery->bat); + if (!hook->remove_battery(battery->bat, hook)) + power_supply_changed(battery->bat); } - list_del(&hook->list); - if (lock) - mutex_unlock(&hook_mutex); - pr_info("extension unregistered: %s\n", hook->name); + list_del_init(&hook->list); + + pr_info("hook unregistered: %s\n", hook->name); } void battery_hook_unregister(struct acpi_battery_hook *hook) { - __battery_hook_unregister(hook, 1); + mutex_lock(&hook_mutex); + /* + * Ignore already unregistered battery hooks. This might happen + * if a battery hook was previously unloaded due to an error when + * adding a new battery. + */ + if (!list_empty(&hook->list)) + battery_hook_unregister_unlocked(hook); + + mutex_unlock(&hook_mutex); } EXPORT_SYMBOL_GPL(battery_hook_unregister); @@ -717,7 +731,6 @@ void battery_hook_register(struct acpi_battery_hook *hook) struct acpi_battery *battery; mutex_lock(&hook_mutex); - INIT_LIST_HEAD(&hook->list); list_add(&hook->list, &battery_hook_list); /* * Now that the driver is registered, we need @@ -726,24 +739,41 @@ void battery_hook_register(struct acpi_battery_hook *hook) * its attributes. */ list_for_each_entry(battery, &acpi_battery_list, list) { - if (hook->add_battery(battery->bat)) { + if (hook->add_battery(battery->bat, hook)) { /* * If a add-battery returns non-zero, - * the registration of the extension has failed, + * the registration of the hook has failed, * and we will not add it to the list of loaded * hooks. */ - pr_err("extension failed to load: %s", hook->name); - __battery_hook_unregister(hook, 0); + pr_err("hook failed to load: %s", hook->name); + battery_hook_unregister_unlocked(hook); goto end; } + + power_supply_changed(battery->bat); } - pr_info("new extension: %s\n", hook->name); + pr_info("new hook: %s\n", hook->name); end: mutex_unlock(&hook_mutex); } EXPORT_SYMBOL_GPL(battery_hook_register); +static void devm_battery_hook_unregister(void *data) +{ + struct acpi_battery_hook *hook = data; + + battery_hook_unregister(hook); +} + +int devm_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook) +{ + battery_hook_register(hook); + + return devm_add_action_or_reset(dev, devm_battery_hook_unregister, hook); +} +EXPORT_SYMBOL_GPL(devm_battery_hook_register); + /* * This function gets called right after the battery sysfs * attributes have been added, so that the drivers that @@ -764,14 +794,14 @@ static void battery_hook_add_battery(struct acpi_battery *battery) * during the battery module initialization. */ list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) { - if (hook_node->add_battery(battery->bat)) { + if (hook_node->add_battery(battery->bat, hook_node)) { /* - * The notification of the extensions has failed, to - * prevent further errors we will unload the extension. + * The notification of the hook has failed, to + * prevent further errors we will unload the hook. */ - pr_err("error in extension, unloading: %s", + pr_err("error in hook, unloading: %s", hook_node->name); - __battery_hook_unregister(hook_node, 0); + battery_hook_unregister_unlocked(hook_node); } } mutex_unlock(&hook_mutex); @@ -787,7 +817,7 @@ static void battery_hook_remove_battery(struct acpi_battery *battery) * custom attributes from the battery. */ list_for_each_entry(hook, &battery_hook_list, list) { - hook->remove_battery(battery->bat); + hook->remove_battery(battery->bat, hook); } /* Then, just remove the battery from the list */ list_del(&battery->list); @@ -804,14 +834,18 @@ static void __exit battery_hook_exit(void) * need to remove the hooks. */ list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) { - __battery_hook_unregister(hook, 1); + battery_hook_unregister(hook); } mutex_destroy(&hook_mutex); } static int sysfs_add_battery(struct acpi_battery *battery) { - struct power_supply_config psy_cfg = { .drv_data = battery, }; + struct power_supply_config psy_cfg = { + .drv_data = battery, + .attr_grp = acpi_battery_groups, + .no_wakeup_source = true, + }; bool full_cap_broken = false; if (!ACPI_BATTERY_CAPACITY_VALID(battery->full_charge_capacity) && @@ -846,7 +880,7 @@ static int sysfs_add_battery(struct acpi_battery *battery) battery->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY; battery->bat_desc.get_property = acpi_battery_get_property; - battery->bat = power_supply_register_no_ws(&battery->device->dev, + battery->bat = power_supply_register(&battery->device->dev, &battery->bat_desc, &psy_cfg); if (IS_ERR(battery->bat)) { @@ -856,21 +890,17 @@ static int sysfs_add_battery(struct acpi_battery *battery) return result; } battery_hook_add_battery(battery); - return device_create_file(&battery->bat->dev, &alarm_attr); + return 0; } static void sysfs_remove_battery(struct acpi_battery *battery) { - mutex_lock(&battery->sysfs_lock); - if (!battery->bat) { - mutex_unlock(&battery->sysfs_lock); + if (!battery->bat) return; - } + battery_hook_remove_battery(battery); - device_remove_file(&battery->bat->dev, &alarm_attr); power_supply_unregister(battery->bat); battery->bat = NULL; - mutex_unlock(&battery->sysfs_lock); } static void find_battery(const struct dmi_header *dm, void *private) @@ -1022,13 +1052,17 @@ static void acpi_battery_refresh(struct acpi_battery *battery) } /* Driver Interface */ -static void acpi_battery_notify(struct acpi_device *device, u32 event) +static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; struct acpi_battery *battery = acpi_driver_data(device); struct power_supply *old; if (!battery) return; + + guard(mutex)(&battery->update_lock); + old = battery->bat; /* * On Acer Aspire V5-573G notifications are sometimes triggered too @@ -1051,21 +1085,22 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) } static int battery_notify(struct notifier_block *nb, - unsigned long mode, void *_unused) + unsigned long mode, void *_unused) { struct acpi_battery *battery = container_of(nb, struct acpi_battery, pm_nb); - int result; - switch (mode) { - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: + if (mode == PM_POST_SUSPEND || mode == PM_POST_HIBERNATION) { + guard(mutex)(&battery->update_lock); + if (!acpi_battery_present(battery)) return 0; if (battery->bat) { acpi_battery_refresh(battery); } else { + int result; + result = acpi_battery_get_info(battery); if (result) return result; @@ -1077,7 +1112,6 @@ static int battery_notify(struct notifier_block *nb, acpi_battery_init_alarm(battery); acpi_battery_get_state(battery); - break; } return 0; @@ -1104,13 +1138,6 @@ battery_ac_is_broken_quirk(const struct dmi_system_id *d) return 0; } -static int __init -battery_do_not_check_pmic_quirk(const struct dmi_system_id *d) -{ - battery_check_pmic = 0; - return 0; -} - static const struct dmi_system_id bat_dmi_table[] __initconst = { { /* NEC LZ750/LS */ @@ -1140,19 +1167,11 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = { }, }, { - /* ECS EF20EA, AXP288 PMIC but uses separate fuel-gauge */ - .callback = battery_do_not_check_pmic_quirk, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "EF20EA"), - }, - }, - { - /* Lenovo Ideapad Miix 320, AXP288 PMIC, separate fuel-gauge */ - .callback = battery_do_not_check_pmic_quirk, + /* Microsoft Surface Go 3 */ + .callback = battery_notification_delay_quirk, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "80XF"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo MIIX 320-10ICR"), + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"), }, }, {}, @@ -1170,6 +1189,8 @@ static int acpi_battery_update_retry(struct acpi_battery *battery) { int retry, ret; + guard(mutex)(&battery->update_lock); + for (retry = 5; retry; retry--) { ret = acpi_battery_update(battery, false); if (!ret) @@ -1180,10 +1201,17 @@ static int acpi_battery_update_retry(struct acpi_battery *battery) return ret; } +static void sysfs_battery_cleanup(struct acpi_battery *battery) +{ + guard(mutex)(&battery->update_lock); + + sysfs_remove_battery(battery); +} + static int acpi_battery_add(struct acpi_device *device) { int result = 0; - struct acpi_battery *battery = NULL; + struct acpi_battery *battery; if (!device) return -EINVAL; @@ -1191,15 +1219,18 @@ static int acpi_battery_add(struct acpi_device *device) if (device->dep_unmet) return -EPROBE_DEFER; - battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); + battery = devm_kzalloc(&device->dev, sizeof(*battery), GFP_KERNEL); if (!battery) return -ENOMEM; battery->device = device; - strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); + strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); + strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS); device->driver_data = battery; - mutex_init(&battery->lock); - mutex_init(&battery->sysfs_lock); + + result = devm_mutex_init(&device->dev, &battery->update_lock); + if (result) + return result; + if (acpi_has_method(battery->device->handle, "_BIX")) set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags); @@ -1211,37 +1242,48 @@ static int acpi_battery_add(struct acpi_device *device) device->status.battery_present ? "present" : "absent"); battery->pm_nb.notifier_call = battery_notify; - register_pm_notifier(&battery->pm_nb); + result = register_pm_notifier(&battery->pm_nb); + if (result) + goto fail; device_init_wakeup(&device->dev, 1); - return result; + result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_battery_notify, device); + if (result) + goto fail_pm; + + return 0; +fail_pm: + device_init_wakeup(&device->dev, 0); + unregister_pm_notifier(&battery->pm_nb); fail: - sysfs_remove_battery(battery); - mutex_destroy(&battery->lock); - mutex_destroy(&battery->sysfs_lock); - kfree(battery); + sysfs_battery_cleanup(battery); + return result; } -static int acpi_battery_remove(struct acpi_device *device) +static void acpi_battery_remove(struct acpi_device *device) { - struct acpi_battery *battery = NULL; + struct acpi_battery *battery; if (!device || !acpi_driver_data(device)) - return -EINVAL; - device_init_wakeup(&device->dev, 0); + return; + battery = acpi_driver_data(device); + + acpi_dev_remove_notify_handler(device, ACPI_ALL_NOTIFY, + acpi_battery_notify); + + device_init_wakeup(&device->dev, 0); unregister_pm_notifier(&battery->pm_nb); + + guard(mutex)(&battery->update_lock); + sysfs_remove_battery(battery); - mutex_destroy(&battery->lock); - mutex_destroy(&battery->sysfs_lock); - kfree(battery); - return 0; } -#ifdef CONFIG_PM_SLEEP /* this is needed to learn about changes made in suspended state */ static int acpi_battery_resume(struct device *dev) { @@ -1255,64 +1297,41 @@ static int acpi_battery_resume(struct device *dev) return -EINVAL; battery->update_time = 0; + + guard(mutex)(&battery->update_lock); + acpi_battery_update(battery, true); return 0; } -#else -#define acpi_battery_resume NULL -#endif -static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); static struct acpi_driver acpi_battery_driver = { .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = battery_device_ids, - .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, .ops = { .add = acpi_battery_add, .remove = acpi_battery_remove, - .notify = acpi_battery_notify, }, - .drv.pm = &acpi_battery_pm, + .drv.pm = pm_sleep_ptr(&acpi_battery_pm), + .drv.probe_type = PROBE_PREFER_ASYNCHRONOUS, }; -static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) -{ - unsigned int i; - int result; - - dmi_check_system(bat_dmi_table); - - if (battery_check_pmic) { - for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) - if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { - pr_info("found native %s PMIC, not loading\n", - acpi_battery_blacklist[i]); - return; - } - } - - result = acpi_bus_register_driver(&acpi_battery_driver); - battery_driver_registered = (result == 0); -} - static int __init acpi_battery_init(void) { - if (acpi_disabled) + if (acpi_disabled || acpi_quirk_skip_acpi_ac_and_battery()) return -ENODEV; - async_cookie = async_schedule(acpi_battery_init_async, NULL); - return 0; + dmi_check_system(bat_dmi_table); + + return acpi_bus_register_driver(&acpi_battery_driver); } static void __exit acpi_battery_exit(void) { - async_synchronize_cookie(async_cookie + 1); - if (battery_driver_registered) { - acpi_bus_unregister_driver(&acpi_battery_driver); - battery_hook_exit(); - } + acpi_bus_unregister_driver(&acpi_battery_driver); + battery_hook_exit(); } module_init(acpi_battery_init); |
