diff options
-rw-r--r-- | arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c | 1 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 38 | ||||
-rw-r--r-- | drivers/acpi/button.c | 4 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 37 | ||||
-rw-r--r-- | drivers/pnp/base.h | 5 | ||||
-rw-r--r-- | drivers/pnp/core.c | 3 | ||||
-rw-r--r-- | drivers/pnp/driver.c | 2 | ||||
-rw-r--r-- | drivers/pnp/pnpacpi/core.c | 2 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 2 |
9 files changed, 68 insertions, 26 deletions
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c index cd8da247dda1..a2baafb2fe6d 100644 --- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c +++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c @@ -701,6 +701,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) per_cpu(acfreq_data, policy->cpu) = NULL; acpi_processor_unregister_performance(data->acpi_data, policy->cpu); + kfree(data->freq_table); kfree(data); } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 7b8787b490f6..0b2707ee094b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -95,6 +95,7 @@ enum { * due to bad math. */ ACPI_BATTERY_QUIRK_SIGNED16_CURRENT, + ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, }; struct acpi_battery { @@ -405,6 +406,8 @@ static int acpi_battery_get_info(struct acpi_battery *battery) result = extract_package(battery, buffer.pointer, info_offsets, ARRAY_SIZE(info_offsets)); kfree(buffer.pointer); + if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) + battery->full_charge_capacity = battery->design_capacity; return result; } @@ -441,6 +444,10 @@ static int acpi_battery_get_state(struct acpi_battery *battery) battery->rate_now != -1) battery->rate_now = abs((s16)battery->rate_now); + if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags) + && battery->capacity_now >= 0 && battery->capacity_now <= 100) + battery->capacity_now = (battery->capacity_now * + battery->full_charge_capacity) / 100; return result; } @@ -552,6 +559,33 @@ static void acpi_battery_quirks(struct acpi_battery *battery) } } +/* + * According to the ACPI spec, some kinds of primary batteries can + * report percentage battery remaining capacity directly to OS. + * In this case, it reports the Last Full Charged Capacity == 100 + * and BatteryPresentRate == 0xFFFFFFFF. + * + * Now we found some battery reports percentage remaining capacity + * even if it's rechargeable. + * https://bugzilla.kernel.org/show_bug.cgi?id=15979 + * + * Handle this correctly so that they won't break userspace. + */ +static void acpi_battery_quirks2(struct acpi_battery *battery) +{ + if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags)) + return ; + + if (battery->full_charge_capacity == 100 && + battery->rate_now == ACPI_BATTERY_VALUE_UNKNOWN && + battery->capacity_now >=0 && battery->capacity_now <= 100) { + set_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags); + battery->full_charge_capacity = battery->design_capacity; + battery->capacity_now = (battery->capacity_now * + battery->full_charge_capacity) / 100; + } +} + static int acpi_battery_update(struct acpi_battery *battery) { int result, old_present = acpi_battery_present(battery); @@ -573,7 +607,9 @@ static int acpi_battery_update(struct acpi_battery *battery) } if (!battery->bat.dev) sysfs_add_battery(battery); - return acpi_battery_get_state(battery); + result = acpi_battery_get_state(battery); + acpi_battery_quirks2(battery); + return result; } /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 1575a9b51f1d..71ef9cd0735f 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -338,7 +338,8 @@ static int acpi_button_add(struct acpi_device *device) { struct acpi_button *button; struct input_dev *input; - char *hid, *name, *class; + const char *hid = acpi_device_hid(device); + char *name, *class; int error; button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); @@ -353,7 +354,6 @@ static int acpi_button_add(struct acpi_device *device) goto err_free_button; } - hid = acpi_device_hid(device); name = acpi_device_name(device); class = acpi_device_class(device); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b23825ecfa37..6155eeb2e89a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -26,6 +26,8 @@ extern struct acpi_device *acpi_root; #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) +static const char *dummy_hid = "device"; + static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); DEFINE_MUTEX(acpi_device_lock); @@ -49,6 +51,9 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int count; struct acpi_hardware_id *id; + if (list_empty(&acpi_dev->pnp.ids)) + return 0; + len = snprintf(modalias, size, "acpi:"); size -= len; @@ -202,13 +207,15 @@ static int acpi_device_setup_files(struct acpi_device *dev) goto end; } - result = device_create_file(&dev->dev, &dev_attr_hid); - if (result) - goto end; + if (!list_empty(&dev->pnp.ids)) { + result = device_create_file(&dev->dev, &dev_attr_hid); + if (result) + goto end; - result = device_create_file(&dev->dev, &dev_attr_modalias); - if (result) - goto end; + result = device_create_file(&dev->dev, &dev_attr_modalias); + if (result) + goto end; + } /* * If device has _EJ0, 'eject' file is created that is used to trigger @@ -316,6 +323,9 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) struct acpi_device *acpi_dev = to_acpi_device(dev); int len; + if (list_empty(&acpi_dev->pnp.ids)) + return 0; + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], @@ -1010,10 +1020,13 @@ static int acpi_dock_match(struct acpi_device *device) return acpi_get_handle(device->handle, "_DCK", &tmp); } -char *acpi_device_hid(struct acpi_device *device) +const char *acpi_device_hid(struct acpi_device *device) { struct acpi_hardware_id *hid; + if (list_empty(&device->pnp.ids)) + return dummy_hid; + hid = list_first_entry(&device->pnp.ids, struct acpi_hardware_id, list); return hid->id; } @@ -1142,16 +1155,6 @@ static void acpi_device_set_id(struct acpi_device *device) acpi_add_id(device, ACPI_BUTTON_HID_SLEEPF); break; } - - /* - * We build acpi_devices for some objects that don't have _HID or _CID, - * e.g., PCI bridges and slots. Drivers can't bind to these objects, - * but we do use them indirectly by traversing the acpi_device tree. - * This generic ID isn't useful for driver binding, but it provides - * the useful property that "every acpi_device has an ID." - */ - if (list_empty(&device->pnp.ids)) - acpi_add_id(device, "device"); } static int acpi_device_set_context(struct acpi_device *device) diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h index 0bab84ebb15d..19bc73695475 100644 --- a/drivers/pnp/base.h +++ b/drivers/pnp/base.h @@ -12,11 +12,12 @@ void pnp_unregister_protocol(struct pnp_protocol *protocol); #define PNP_EISA_ID_MASK 0x7fffffff void pnp_eisa_id_to_string(u32 id, char *str); -struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid); +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, + const char *pnpid); struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid); int pnp_add_device(struct pnp_dev *dev); -struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id); +struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id); int pnp_add_card(struct pnp_card *card); void pnp_remove_card(struct pnp_card *card); diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c index 88b3cde52596..c79ee1ded68d 100644 --- a/drivers/pnp/core.c +++ b/drivers/pnp/core.c @@ -124,7 +124,8 @@ static void pnp_release_device(struct device *dmdev) kfree(dev); } -struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid) +struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, + const char *pnpid) { struct pnp_dev *dev; struct pnp_id *dev_id; diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index cd11b113494f..d1dbb9df53fa 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -236,7 +236,7 @@ void pnp_unregister_driver(struct pnp_driver *drv) * @dev: pointer to the desired device * @id: pointer to an EISA id string */ -struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id) +struct pnp_id *pnp_add_id(struct pnp_dev *dev, const char *id) { struct pnp_id *dev_id, *ptr; diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index dc4e32e031e9..4aafcf89b03b 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -59,7 +59,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev) #define TEST_ALPHA(c) \ if (!('@' <= (c) || (c) <= 'Z')) \ return 0 -static int __init ispnpidacpi(char *id) +static int __init ispnpidacpi(const char *id) { TEST_ALPHA(id[0]); TEST_ALPHA(id[1]); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 4de84ce3a927..a47bb908ddcd 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -184,7 +184,7 @@ struct acpi_device_pnp { #define acpi_device_bid(d) ((d)->pnp.bus_id) #define acpi_device_adr(d) ((d)->pnp.bus_address) -char *acpi_device_hid(struct acpi_device *device); +const char *acpi_device_hid(struct acpi_device *device); #define acpi_device_name(d) ((d)->pnp.device_name) #define acpi_device_class(d) ((d)->pnp.device_class) |