Store the supported features in the driver private data, and modify the is_visible() callback to use it, and create ideapad_check_features() to populate it. Signed-off-by: Barnabás Pőcze <pobrn@xxxxxxxxxxxxxx> diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index c8ab660cdacc..77a8e19441ed 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -115,9 +115,15 @@ struct ideapad_private { struct ideapad_dytc_priv *dytc; struct dentry *debug; unsigned long cfg; - bool has_hw_rfkill_switch; - bool has_touchpad_switch; const char *fnesc_guid; + struct { + bool conservation_mode : 1; + bool dytc : 1; + bool fan_mode : 1; + bool fn_lock : 1; + bool hw_rfkill_switch : 1; + bool touchpad_ctrl_via_ec : 1; + } features; }; static bool no_bt_rfkill; @@ -563,24 +569,18 @@ static umode_t ideapad_is_visible(struct kobject *kobj, { struct device *dev = kobj_to_dev(kobj); struct ideapad_private *priv = dev_get_drvdata(dev); - bool supported; + bool supported = true; if (attr == &dev_attr_camera_power.attr) supported = test_bit(CFG_CAP_CAM_BIT, &priv->cfg); - else if (attr == &dev_attr_fan_mode.attr) { - unsigned long value; - supported = !read_ec_data(priv->adev->handle, VPCCMD_R_FAN, - &value); - } else if (attr == &dev_attr_conservation_mode.attr) { - supported = acpi_has_method(priv->adev->handle, "GBMD") && - acpi_has_method(priv->adev->handle, "SBMC"); - } else if (attr == &dev_attr_fn_lock.attr) { - supported = acpi_has_method(priv->adev->handle, "HALS") && - acpi_has_method(priv->adev->handle, "SALS"); - } else if (attr == &dev_attr_touchpad.attr) - supported = priv->has_touchpad_switch; - else - supported = true; + else if (attr == &dev_attr_conservation_mode.attr) + supported = priv->features.conservation_mode; + else if (attr == &dev_attr_fan_mode.attr) + supported = priv->features.fan_mode; + else if (attr == &dev_attr_fn_lock.attr) + supported = priv->features.fn_lock; + else if (attr == &dev_attr_touchpad.attr) + supported = priv->features.touchpad_ctrl_via_ec; return supported ? attr->mode : 0; } @@ -784,6 +784,9 @@ static int ideapad_dytc_profile_init(struct ideapad_private *priv) int err, dytc_version; unsigned long output; + if (!priv->features.dytc) + return -ENODEV; + err = eval_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output); /* For all other errors we can flag the failure */ if (err) @@ -873,7 +876,7 @@ static void ideapad_sync_rfk_state(struct ideapad_private *priv) unsigned long hw_blocked = 0; int i; - if (priv->has_hw_rfkill_switch) { + if (priv->features.hw_rfkill_switch) { if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked)) return; hw_blocked = !hw_blocked; @@ -1167,7 +1170,7 @@ static void ideapad_sync_touchpad_state(struct ideapad_private *priv) { unsigned long value; - if (!priv->has_touchpad_switch) + if (!priv->features.touchpad_ctrl_via_ec) return; /* Without reading from EC touchpad LED doesn't switch state */ @@ -1271,6 +1274,29 @@ static const struct dmi_system_id hw_rfkill_list[] = { {} }; +static void ideapad_check_features(struct ideapad_private *priv) +{ + acpi_handle handle = priv->adev->handle; + unsigned long val; + + priv->features.hw_rfkill_switch = dmi_check_system(hw_rfkill_list); + + /* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */ + priv->features.touchpad_ctrl_via_ec = !acpi_dev_present("ELAN0634", NULL, -1); + + if (!read_ec_data(handle, VPCCMD_R_FAN, &val)) + priv->features.fan_mode = true; + + if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) + priv->features.conservation_mode = true; + + if (acpi_has_method(handle, "DYTC")) + priv->features.dytc = true; + + if (acpi_has_method(handle, "HALS") && acpi_has_method(handle, "SALS")) + priv->features.fn_lock = true; +} + static int ideapad_acpi_add(struct platform_device *pdev) { int ret, i; @@ -1294,10 +1320,8 @@ static int ideapad_acpi_add(struct platform_device *pdev) priv->cfg = cfg; priv->adev = adev; priv->platform_device = pdev; - priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list); - /* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */ - priv->has_touchpad_switch = !acpi_dev_present("ELAN0634", NULL, -1); + ideapad_check_features(priv); ret = ideapad_sysfs_init(priv); if (ret) @@ -1313,11 +1337,11 @@ static int ideapad_acpi_add(struct platform_device *pdev) * On some models without a hw-switch (the yoga 2 13 at least) * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work. */ - if (!priv->has_hw_rfkill_switch) + if (!priv->features.hw_rfkill_switch) write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1); /* The same for Touchpad */ - if (!priv->has_touchpad_switch) + if (!priv->features.touchpad_ctrl_via_ec) write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1); for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) @@ -1327,7 +1351,13 @@ static int ideapad_acpi_add(struct platform_device *pdev) ideapad_sync_rfk_state(priv); ideapad_sync_touchpad_state(priv); - ideapad_dytc_profile_init(priv); + ret = ideapad_dytc_profile_init(priv); + if (ret) { + if (ret != -ENODEV) + dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", ret); + else + dev_info(&pdev->dev, "DYTC interface is not available\n"); + } if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { ret = ideapad_backlight_init(priv); -- 2.30.0