From 2b2ae7c7f8e25043793042eb9df88aa875b4cff8 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 1 Oct 2010 10:53:59 +0200 Subject: ACPI: Do not export hid/modalias sysfs file for ACPI objects without a HID Boot and compile tested. The fact that pnp.ids can now be empty needs testing on some further machines, though. This should handle a "modprobe is wrongly called by udev" issue: https://bugzilla.kernel.org/show_bug.cgi?id=19162 Modaliase files in /sys/devices/LNXSYSTM:00/ went down from 113 to 71 on my tested system. This is a sysfs change, but userspace must already be able to handle it. Also do not fill up pnp.ids list with a "struct hid" entry. This comment: * This generic ID isn't useful for driver binding, but it provides * the useful property that "every acpi_device has an ID." is still half way true: Best you never touch pnp.ids list directly or make sure it can be empty, instead use: char *acpi_device_hid() which always returns a value ("device" as a dummy if the object has no hid). Signed-off-by: Thomas Renninger CC: Zhang Rui CC: kay.sievers@vrfy.org CC: Bjorn Helgaas Signed-off-by: Len Brown --- drivers/acpi/scan.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b23825ecfa37..81aec8d66fd0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -26,6 +26,9 @@ extern struct acpi_device *acpi_root; #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) +/* Should be const */ +static char* dummy_hid = "device"; + static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); DEFINE_MUTEX(acpi_device_lock); @@ -49,6 +52,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 +208,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 +324,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], @@ -1014,6 +1025,9 @@ 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 +1156,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) -- cgit v1.2.3 From 620e112cfe1c9281c176de8ad1a7691c4eb4950d Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Fri, 1 Oct 2010 10:54:00 +0200 Subject: ACPI/PNP: A HID value of an object never changes -> make it const Signed-off-by: Thomas Renninger Signed-off-by: Len Brown --- drivers/acpi/button.c | 4 ++-- drivers/acpi/scan.c | 5 ++--- drivers/pnp/base.h | 5 +++-- drivers/pnp/core.c | 3 ++- drivers/pnp/driver.c | 2 +- drivers/pnp/pnpacpi/core.c | 2 +- include/acpi/acpi_bus.h | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/acpi') 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 81aec8d66fd0..6155eeb2e89a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -26,8 +26,7 @@ extern struct acpi_device *acpi_root; #define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) -/* Should be const */ -static char* dummy_hid = "device"; +static const char *dummy_hid = "device"; static LIST_HEAD(acpi_device_list); static LIST_HEAD(acpi_bus_id_list); @@ -1021,7 +1020,7 @@ 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; 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) -- cgit v1.2.3 From 557d58687dcdee6bc00c1a8f1fd4e0eac8fefce9 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Fri, 22 Oct 2010 10:02:06 +0800 Subject: ACPI battery: support percentage battery remaining capacity According to the ACPI spec, some kinds of primary battery can report percentage battery remaining capacity directly to OS. In this case, it reports the LastFullChargedCapacity == 100, BatteryPresentRate = 0xFFFFFFFF, and BatteryRemaingCapacity a percentage value, which actually means RemainingBatteryPercentage. Now we found some battery follows this rule even if it's a rechargeable. https://bugzilla.kernel.org/show_bug.cgi?id=15979 Handle these batteries correctly in ACPI battery driver so that they won't break userspace. Signed-off-by: Zhang Rui Tested-by: Sitsofe Wheeler Signed-off-by: Len Brown --- drivers/acpi/battery.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') 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; } /* -------------------------------------------------------------------------- -- cgit v1.2.3