diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/ac.c | 20 | ||||
-rw-r--r-- | drivers/acpi/acpi_video.c | 157 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 22 | ||||
-rw-r--r-- | drivers/acpi/blacklist.c | 8 | ||||
-rw-r--r-- | drivers/acpi/utils.c | 66 |
5 files changed, 225 insertions, 48 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index f71b756b05c4..8f52483219ba 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -57,12 +57,23 @@ static int acpi_ac_add(struct acpi_device *device); static int acpi_ac_remove(struct acpi_device *device); static void acpi_ac_notify(struct acpi_device *device, u32 event); +struct acpi_ac_bl { + const char *hid; + int hrv; +}; + static const struct acpi_device_id ac_device_ids[] = { {"ACPI0003", 0}, {"", 0}, }; MODULE_DEVICE_TABLE(acpi, ac_device_ids); +/* Lists of PMIC ACPI HIDs with an (often better) native charger driver */ +static const struct acpi_ac_bl acpi_ac_blacklist[] = { + { "INT33F4", -1 }, /* X-Powers AXP288 PMIC */ + { "INT34D3", 3 }, /* Intel Cherrytrail Whiskey Cove PMIC */ +}; + #ifdef CONFIG_PM_SLEEP static int acpi_ac_resume(struct device *dev); #endif @@ -424,11 +435,20 @@ static int acpi_ac_remove(struct acpi_device *device) static int __init acpi_ac_init(void) { + unsigned int i; int result; if (acpi_disabled) return -ENODEV; + for (i = 0; i < ARRAY_SIZE(acpi_ac_blacklist); i++) + if (acpi_dev_present(acpi_ac_blacklist[i].hid, "1", + acpi_ac_blacklist[i].hrv)) { + pr_info(PREFIX "AC: found native %s PMIC, not loading\n", + acpi_ac_blacklist[i].hid); + return -ENODEV; + } + #ifdef CONFIG_ACPI_PROCFS_POWER acpi_ac_dir = acpi_lock_ac_dir(); if (!acpi_ac_dir) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index d00bc0ef87a6..e88fe3632dd6 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -73,6 +73,10 @@ module_param(report_key_events, int, 0644); MODULE_PARM_DESC(report_key_events, "0: none, 1: output changes, 2: brightness changes, 3: all"); +/* + * Whether the struct acpi_video_device_attrib::device_id_scheme bit should be + * assumed even if not actually set. + */ static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); @@ -88,6 +92,18 @@ static int acpi_video_bus_remove(struct acpi_device *device); static void acpi_video_bus_notify(struct acpi_device *device, u32 event); void acpi_video_detect_exit(void); +/* + * Indices in the _BCL method response: the first two items are special, + * the rest are all supported levels. + * + * See page 575 of the ACPI spec 3.0 + */ +enum acpi_video_level_idx { + ACPI_VIDEO_AC_LEVEL, /* level when machine has full power */ + ACPI_VIDEO_BATTERY_LEVEL, /* level when machine is on batteries */ + ACPI_VIDEO_FIRST_LEVEL, /* actual supported levels begin here */ +}; + static const struct acpi_device_id video_device_ids[] = { {ACPI_VIDEO_HID, 0}, {"", 0}, @@ -132,7 +148,15 @@ struct acpi_video_device_attrib { the VGA device. */ u32 pipe_id:3; /* For VGA multiple-head devices. */ u32 reserved:10; /* Must be 0 */ - u32 device_id_scheme:1; /* Device ID Scheme */ + + /* + * The device ID might not actually follow the scheme described by this + * struct acpi_video_device_attrib. If it does, then this bit + * device_id_scheme is set; otherwise, other fields should be ignored. + * + * (but also see the global flag device_id_scheme) + */ + u32 device_id_scheme:1; }; struct acpi_video_enumerated_device { @@ -217,20 +241,16 @@ static int acpi_video_get_brightness(struct backlight_device *bd) if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false)) return -EINVAL; - for (i = 2; i < vd->brightness->count; i++) { + for (i = ACPI_VIDEO_FIRST_LEVEL; i < vd->brightness->count; i++) { if (vd->brightness->levels[i] == cur_level) - /* - * The first two entries are special - see page 575 - * of the ACPI spec 3.0 - */ - return i - 2; + return i - ACPI_VIDEO_FIRST_LEVEL; } return 0; } static int acpi_video_set_brightness(struct backlight_device *bd) { - int request_level = bd->props.brightness + 2; + int request_level = bd->props.brightness + ACPI_VIDEO_FIRST_LEVEL; struct acpi_video_device *vd = bl_get_data(bd); cancel_delayed_work(&vd->switch_brightness_work); @@ -244,18 +264,18 @@ static const struct backlight_ops acpi_backlight_ops = { }; /* thermal cooling device callbacks */ -static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned - long *state) +static int video_get_max_state(struct thermal_cooling_device *cooling_dev, + unsigned long *state) { struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); - *state = video->brightness->count - 3; + *state = video->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; return 0; } -static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned - long *state) +static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, + unsigned long *state) { struct acpi_device *device = cooling_dev->devdata; struct acpi_video_device *video = acpi_driver_data(device); @@ -264,7 +284,8 @@ static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsig if (acpi_video_device_lcd_get_level_current(video, &level, false)) return -EINVAL; - for (offset = 2; offset < video->brightness->count; offset++) + for (offset = ACPI_VIDEO_FIRST_LEVEL; offset < video->brightness->count; + offset++) if (level == video->brightness->levels[offset]) { *state = video->brightness->count - offset - 1; return 0; @@ -280,7 +301,7 @@ video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long st struct acpi_video_device *video = acpi_driver_data(device); int level; - if (state >= video->brightness->count - 2) + if (state >= video->brightness->count - ACPI_VIDEO_FIRST_LEVEL) return -EINVAL; state = video->brightness->count - state; @@ -345,10 +366,12 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) } device->brightness->curr = level; - for (state = 2; state < device->brightness->count; state++) + for (state = ACPI_VIDEO_FIRST_LEVEL; state < device->brightness->count; + state++) if (level == device->brightness->levels[state]) { if (device->backlight) - device->backlight->props.brightness = state - 2; + device->backlight->props.brightness = + state - ACPI_VIDEO_FIRST_LEVEL; return 0; } @@ -530,14 +553,16 @@ acpi_video_bqc_value_to_level(struct acpi_video_device *device, if (device->brightness->flags._BQC_use_index) { /* - * _BQC returns an index that doesn't account for - * the first 2 items with special meaning, so we need - * to compensate for that by offsetting ourselves + * _BQC returns an index that doesn't account for the first 2 + * items with special meaning (see enum acpi_video_level_idx), + * so we need to compensate for that by offsetting ourselves */ if (device->brightness->flags._BCL_reversed) - bqc_value = device->brightness->count - 3 - bqc_value; + bqc_value = device->brightness->count - + ACPI_VIDEO_FIRST_LEVEL - 1 - bqc_value; - level = device->brightness->levels[bqc_value + 2]; + level = device->brightness->levels[bqc_value + + ACPI_VIDEO_FIRST_LEVEL]; } else { level = bqc_value; } @@ -571,7 +596,8 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device, *level = acpi_video_bqc_value_to_level(device, *level); - for (i = 2; i < device->brightness->count; i++) + for (i = ACPI_VIDEO_FIRST_LEVEL; + i < device->brightness->count; i++) if (device->brightness->levels[i] == *level) { device->brightness->curr = *level; return 0; @@ -714,9 +740,37 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, /* * Some systems always report current brightness level as maximum - * through _BQC, we need to test another value for them. + * through _BQC, we need to test another value for them. However, + * there is a subtlety: + * + * If the _BCL package ordering is descending, the first level + * (br->levels[2]) is likely to be 0, and if the number of levels + * matches the number of steps, we might confuse a returned level to + * mean the index. + * + * For example: + * + * current_level = max_level = 100 + * test_level = 0 + * returned level = 100 + * + * In this case 100 means the level, not the index, and _BCM failed. + * Still, if the _BCL package ordering is descending, the index of + * level 0 is also 100, so we assume _BQC is indexed, when it's not. + * + * This causes all _BQC calls to return bogus values causing weird + * behavior from the user's perspective. For example: + * + * xbacklight -set 10; xbacklight -set 20; + * + * would flash to 90% and then slowly down to the desired level (20). + * + * The solution is simple; test anything other than the first level + * (e.g. 1). */ - test_level = current_level == max_level ? br->levels[3] : max_level; + test_level = current_level == max_level + ? br->levels[ACPI_VIDEO_FIRST_LEVEL + 1] + : max_level; result = acpi_video_device_lcd_set_level(device, test_level); if (result) @@ -730,8 +784,8 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device, /* buggy _BQC found, need to find out if it uses index */ if (level < br->count) { if (br->flags._BCL_reversed) - level = br->count - 3 - level; - if (br->levels[level + 2] == test_level) + level = br->count - ACPI_VIDEO_FIRST_LEVEL - 1 - level; + if (br->levels[level + ACPI_VIDEO_FIRST_LEVEL] == test_level) br->flags._BQC_use_index = 1; } @@ -761,7 +815,7 @@ int acpi_video_get_levels(struct acpi_device *device, goto out; } - if (obj->package.count < 2) { + if (obj->package.count < ACPI_VIDEO_FIRST_LEVEL) { result = -EINVAL; goto out; } @@ -773,8 +827,13 @@ int acpi_video_get_levels(struct acpi_device *device, goto out; } - br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels), - GFP_KERNEL); + /* + * Note that we have to reserve 2 extra items (ACPI_VIDEO_FIRST_LEVEL), + * in order to account for buggy BIOS which don't export the first two + * special levels (see below) + */ + br->levels = kmalloc((obj->package.count + ACPI_VIDEO_FIRST_LEVEL) * + sizeof(*br->levels), GFP_KERNEL); if (!br->levels) { result = -ENOMEM; goto out_free; @@ -788,7 +847,8 @@ int acpi_video_get_levels(struct acpi_device *device, } value = (u32) o->integer.value; /* Skip duplicate entries */ - if (count > 2 && br->levels[count - 1] == value) + if (count > ACPI_VIDEO_FIRST_LEVEL + && br->levels[count - 1] == value) continue; br->levels[count] = value; @@ -804,27 +864,30 @@ int acpi_video_get_levels(struct acpi_device *device, * In this case, the first two elements in _BCL packages * are also supported brightness levels that OS should take care of. */ - for (i = 2; i < count; i++) { - if (br->levels[i] == br->levels[0]) + for (i = ACPI_VIDEO_FIRST_LEVEL; i < count; i++) { + if (br->levels[i] == br->levels[ACPI_VIDEO_AC_LEVEL]) level_ac_battery++; - if (br->levels[i] == br->levels[1]) + if (br->levels[i] == br->levels[ACPI_VIDEO_BATTERY_LEVEL]) level_ac_battery++; } - if (level_ac_battery < 2) { - level_ac_battery = 2 - level_ac_battery; + if (level_ac_battery < ACPI_VIDEO_FIRST_LEVEL) { + level_ac_battery = ACPI_VIDEO_FIRST_LEVEL - level_ac_battery; br->flags._BCL_no_ac_battery_levels = 1; - for (i = (count - 1 + level_ac_battery); i >= 2; i--) + for (i = (count - 1 + level_ac_battery); + i >= ACPI_VIDEO_FIRST_LEVEL; i--) br->levels[i] = br->levels[i - level_ac_battery]; count += level_ac_battery; - } else if (level_ac_battery > 2) + } else if (level_ac_battery > ACPI_VIDEO_FIRST_LEVEL) ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package")); /* Check if the _BCL package is in a reversed order */ - if (max_level == br->levels[2]) { + if (max_level == br->levels[ACPI_VIDEO_FIRST_LEVEL]) { br->flags._BCL_reversed = 1; - sort(&br->levels[2], count - 2, sizeof(br->levels[2]), - acpi_video_cmp_level, NULL); + sort(&br->levels[ACPI_VIDEO_FIRST_LEVEL], + count - ACPI_VIDEO_FIRST_LEVEL, + sizeof(br->levels[ACPI_VIDEO_FIRST_LEVEL]), + acpi_video_cmp_level, NULL); } else if (max_level != br->levels[count - 1]) ACPI_ERROR((AE_INFO, "Found unordered _BCL package")); @@ -894,7 +957,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) * level_old is invalid (no matter whether it's a level * or an index). Set the backlight to max_level in this case. */ - for (i = 2; i < br->count; i++) + for (i = ACPI_VIDEO_FIRST_LEVEL; i < br->count; i++) if (level == br->levels[i]) break; if (i == br->count || !level) @@ -906,7 +969,8 @@ set_level: goto out_free_levels; ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "found %d brightness levels\n", br->count - 2)); + "found %d brightness levels\n", + br->count - ACPI_VIDEO_FIRST_LEVEL)); return 0; out_free_levels: @@ -1297,7 +1361,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, max = max_below = 0; min = min_above = 255; /* Find closest level to level_current */ - for (i = 2; i < device->brightness->count; i++) { + for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (abs(l - level_current) < abs(delta)) { delta = l - level_current; @@ -1307,7 +1371,7 @@ acpi_video_get_next_level(struct acpi_video_device *device, } /* Ajust level_current to closest available level */ level_current += delta; - for (i = 2; i < device->brightness->count; i++) { + for (i = ACPI_VIDEO_FIRST_LEVEL; i < device->brightness->count; i++) { l = device->brightness->levels[i]; if (l < min) min = l; @@ -1680,7 +1744,8 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_FIRMWARE; - props.max_brightness = device->brightness->count - 3; + props.max_brightness = + device->brightness->count - ACPI_VIDEO_FIRST_LEVEL - 1; device->backlight = backlight_device_register(name, parent, device, diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 4ef1e4624b2b..d42eeef9d928 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -67,6 +67,7 @@ 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 unsigned int cache_time = 1000; @@ -93,6 +94,11 @@ static const struct acpi_device_id battery_device_ids[] = { 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, @@ -1315,8 +1321,17 @@ static struct acpi_driver acpi_battery_driver = { static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) { + unsigned int i; int result; + for (i = 0; i < ARRAY_SIZE(acpi_battery_blacklist); i++) + if (acpi_dev_present(acpi_battery_blacklist[i], "1", -1)) { + pr_info(PREFIX ACPI_BATTERY_DEVICE_NAME + ": found native %s PMIC, not loading\n", + acpi_battery_blacklist[i]); + return; + } + dmi_check_system(bat_dmi_table); #ifdef CONFIG_ACPI_PROCFS_POWER @@ -1329,6 +1344,7 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) if (result < 0) acpi_unlock_battery_dir(acpi_battery_dir); #endif + battery_driver_registered = (result == 0); } static int __init acpi_battery_init(void) @@ -1343,9 +1359,11 @@ static int __init acpi_battery_init(void) static void __exit acpi_battery_exit(void) { async_synchronize_cookie(async_cookie + 1); - acpi_bus_unregister_driver(&acpi_battery_driver); + if (battery_driver_registered) + acpi_bus_unregister_driver(&acpi_battery_driver); #ifdef CONFIG_ACPI_PROCFS_POWER - acpi_unlock_battery_dir(acpi_battery_dir); + if (acpi_battery_dir) + acpi_unlock_battery_dir(acpi_battery_dir); #endif } diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 4421f7c9981c..bb542acc0574 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -188,6 +188,14 @@ static struct dmi_system_id acpi_rev_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"), }, }, + { + .callback = dmi_enable_rev_override, + .ident = "DELL Inspiron 7537", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"), + }, + }, #endif {} }; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 22c09952e177..27d0dcfcf47d 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -736,6 +736,72 @@ bool acpi_dev_found(const char *hid) } EXPORT_SYMBOL(acpi_dev_found); +struct acpi_dev_present_info { + struct acpi_device_id hid[2]; + const char *uid; + s64 hrv; +}; + +static int acpi_dev_present_cb(struct device *dev, void *data) +{ + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_dev_present_info *match = data; + unsigned long long hrv; + acpi_status status; + + if (acpi_match_device_ids(adev, match->hid)) + return 0; + + if (match->uid && (!adev->pnp.unique_id || + strcmp(adev->pnp.unique_id, match->uid))) + return 0; + + if (match->hrv == -1) + return 1; + + status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv); + if (ACPI_FAILURE(status)) + return 0; + + return hrv == match->hrv; +} + +/** + * acpi_dev_present - Detect that a given ACPI device is present + * @hid: Hardware ID of the device. + * @uid: Unique ID of the device, pass NULL to not check _UID + * @hrv: Hardware Revision of the device, pass -1 to not check _HRV + * + * Return %true if a matching device was present at the moment of invocation. + * Note that if the device is pluggable, it may since have disappeared. + * + * Note that unlike acpi_dev_found() this function checks the status + * of the device. So for devices which are present in the dsdt, but + * which are disabled (their _STA callback returns 0) this function + * will return false. + * + * For this function to work, acpi_bus_scan() must have been executed + * which happens in the subsys_initcall() subsection. Hence, do not + * call from a subsys_initcall() or earlier (use acpi_get_devices() + * instead). Calling from module_init() is fine (which is synonymous + * with device_initcall()). + */ +bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) +{ + struct acpi_dev_present_info match = {}; + struct device *dev; + + strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); + match.uid = uid; + match.hrv = hrv; + + dev = bus_find_device(&acpi_bus_type, NULL, &match, + acpi_dev_present_cb); + + return !!dev; +} +EXPORT_SYMBOL(acpi_dev_present); + /* * acpi_backlight= handling, this is done here rather then in video_detect.c * because __setup cannot be used in modules. |