Re: [PATCH] platform/x86: thinkpad_acpi: Convert platform driver to use dev_groups

From: Hans de Goede
Date: Tue Oct 19 2021 - 05:41:39 EST


Hi Len,

On 10/3/21 11:19, Len Baker wrote:
> Platform drivers have the option of having the platform core create and
> remove any needed sysfs attribute files. So take advantage of that and
> refactor the attributes management to avoid to register them "by hand".
>
> Also, due to some attributes are optionals, refactor the code and move
> the logic inside the "is_visible" callbacks of the attribute_group
> structures.
>
> Suggested-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Len Baker <len.baker@xxxxxxx>

Thank you for the patch, this indeed results in a nice improvement.

Unfortunately I cannot take this as is (because it will trigger
a BUG_ON). See my inline remarks, if you can do a v2 with those
fixed that would be great.

> ---
> drivers/platform/x86/thinkpad_acpi.c | 536 ++++++++++++---------------
> 1 file changed, 236 insertions(+), 300 deletions(-)
>
> diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
> index 07b9710d500e..270eb4f373c9 100644
> --- a/drivers/platform/x86/thinkpad_acpi.c
> +++ b/drivers/platform/x86/thinkpad_acpi.c
> @@ -332,9 +332,7 @@ static struct {
> u32 battery_force_primary:1;
> u32 input_device_registered:1;
> u32 platform_drv_registered:1;
> - u32 platform_drv_attrs_registered:1;
> u32 sensors_pdrv_registered:1;
> - u32 sensors_pdrv_attrs_registered:1;
> u32 sensors_pdev_attrs_registered:1;
> u32 hotkey_poll_active:1;
> u32 has_adaptive_kbd:1;
> @@ -983,20 +981,6 @@ static void tpacpi_shutdown_handler(struct platform_device *pdev)
> }
> }
>
> -static struct platform_driver tpacpi_pdriver = {
> - .driver = {
> - .name = TPACPI_DRVR_NAME,
> - .pm = &tpacpi_pm,
> - },
> - .shutdown = tpacpi_shutdown_handler,
> -};
> -
> -static struct platform_driver tpacpi_hwmon_pdriver = {
> - .driver = {
> - .name = TPACPI_HWMON_DRVR_NAME,
> - },
> -};
> -
> /*************************************************************************
> * sysfs support helpers
> */
> @@ -1488,53 +1472,6 @@ static ssize_t uwb_emulstate_store(struct device_driver *drv, const char *buf,
> static DRIVER_ATTR_RW(uwb_emulstate);
> #endif
>
> -/* --------------------------------------------------------------------- */
> -
> -static struct driver_attribute *tpacpi_driver_attributes[] = {
> - &driver_attr_debug_level, &driver_attr_version,
> - &driver_attr_interface_version,
> -};
> -
> -static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
> -{
> - int i, res;
> -
> - i = 0;
> - res = 0;
> - while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {
> - res = driver_create_file(drv, tpacpi_driver_attributes[i]);
> - i++;
> - }
> -
> -#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
> - if (!res && dbg_wlswemul)
> - res = driver_create_file(drv, &driver_attr_wlsw_emulstate);
> - if (!res && dbg_bluetoothemul)
> - res = driver_create_file(drv, &driver_attr_bluetooth_emulstate);
> - if (!res && dbg_wwanemul)
> - res = driver_create_file(drv, &driver_attr_wwan_emulstate);
> - if (!res && dbg_uwbemul)
> - res = driver_create_file(drv, &driver_attr_uwb_emulstate);
> -#endif
> -
> - return res;
> -}
> -
> -static void tpacpi_remove_driver_attributes(struct device_driver *drv)
> -{
> - int i;
> -
> - for (i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)
> - driver_remove_file(drv, tpacpi_driver_attributes[i]);
> -
> -#ifdef THINKPAD_ACPI_DEBUGFACILITIES
> - driver_remove_file(drv, &driver_attr_wlsw_emulstate);
> - driver_remove_file(drv, &driver_attr_bluetooth_emulstate);
> - driver_remove_file(drv, &driver_attr_wwan_emulstate);
> - driver_remove_file(drv, &driver_attr_uwb_emulstate);
> -#endif
> -}
> -
> /*************************************************************************
> * Firmware Data
> */
> @@ -3008,7 +2945,14 @@ static struct attribute *adaptive_kbd_attributes[] = {
> NULL
> };
>
> +static umode_t hadaptive_kbd_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + return tp_features.has_adaptive_kbd ? attr->mode : 0;
> +}
> +
> static const struct attribute_group adaptive_kbd_attr_group = {
> + .is_visible = hadaptive_kbd_attr_is_visible,
> .attrs = adaptive_kbd_attributes,
> };
>
> @@ -3106,8 +3050,6 @@ static void hotkey_exit(void)
> hotkey_poll_stop_sync();
> mutex_unlock(&hotkey_mutex);
> #endif
> - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group);
> -
> dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY,
> "restoring original HKEY status and mask\n");
> /* yes, there is a bitwise or below, we want the
> @@ -3502,14 +3444,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
> */
> if (acpi_evalf(hkey_handle, &hotkey_adaptive_all_mask,
> "MHKA", "dd", 2)) {
> - if (hotkey_adaptive_all_mask != 0) {
> + if (hotkey_adaptive_all_mask != 0)
> tp_features.has_adaptive_kbd = true;
> - res = sysfs_create_group(
> - &tpacpi_pdev->dev.kobj,
> - &adaptive_kbd_attr_group);
> - if (res)
> - goto err_exit;
> - }
> } else {
> tp_features.has_adaptive_kbd = false;
> hotkey_adaptive_all_mask = 0x0U;
> @@ -3563,9 +3499,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
> }
>
> tabletsw_state = hotkey_init_tablet_mode();
> - res = sysfs_create_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group);
> - if (res)
> - goto err_exit;
>
> /* Set up key map */
> keymap_id = tpacpi_check_quirks(tpacpi_keymap_qtable,
> @@ -3662,9 +3595,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
> return 0;
>
> err_exit:
> - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &hotkey_attr_group);
> - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &adaptive_kbd_attr_group);
> -
> return (res < 0) ? res : 1;
> }
>
> @@ -4396,7 +4326,14 @@ static struct attribute *bluetooth_attributes[] = {
> NULL
> };
>
> +static umode_t bluetooth_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + return tp_features.bluetooth ? attr->mode : 0;
> +}
> +
> static const struct attribute_group bluetooth_attr_group = {
> + .is_visible = bluetooth_attr_is_visible,
> .attrs = bluetooth_attributes,
> };
>
> @@ -4418,11 +4355,7 @@ static void bluetooth_shutdown(void)
>
> static void bluetooth_exit(void)
> {
> - sysfs_remove_group(&tpacpi_pdev->dev.kobj,
> - &bluetooth_attr_group);
> -
> tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID);
> -
> bluetooth_shutdown();
> }
>
> @@ -4536,17 +4469,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
> RFKILL_TYPE_BLUETOOTH,
> TPACPI_RFK_BLUETOOTH_SW_NAME,
> true);
> - if (res)
> - return res;
> -
> - res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
> - &bluetooth_attr_group);
> - if (res) {
> - tpacpi_destroy_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID);
> - return res;
> - }
> -
> - return 0;
> + return res;
> }
>
> /* procfs -------------------------------------------------------------- */
> @@ -4653,7 +4576,14 @@ static struct attribute *wan_attributes[] = {
> NULL
> };
>
> +static umode_t wan_attr_is_visible(struct kobject *kobj, struct attribute *attr,
> + int n)
> +{
> + return tp_features.wan ? attr->mode : 0;
> +}
> +
> static const struct attribute_group wan_attr_group = {
> + .is_visible = wan_attr_is_visible,
> .attrs = wan_attributes,
> };
>
> @@ -4675,11 +4605,7 @@ static void wan_shutdown(void)
>
> static void wan_exit(void)
> {
> - sysfs_remove_group(&tpacpi_pdev->dev.kobj,
> - &wan_attr_group);
> -
> tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID);
> -
> wan_shutdown();
> }
>
> @@ -4723,18 +4649,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
> RFKILL_TYPE_WWAN,
> TPACPI_RFK_WWAN_SW_NAME,
> true);
> - if (res)
> - return res;
> -
> - res = sysfs_create_group(&tpacpi_pdev->dev.kobj,
> - &wan_attr_group);
> -
> - if (res) {
> - tpacpi_destroy_rfkill(TPACPI_RFK_WWAN_SW_ID);
> - return res;
> - }
> -
> - return 0;
> + return res;
> }
>
> /* procfs -------------------------------------------------------------- */
> @@ -5635,30 +5550,35 @@ static ssize_t cmos_command_store(struct device *dev,
>
> static DEVICE_ATTR_WO(cmos_command);
>
> +static struct attribute *cmos_attributes[] = {
> + &dev_attr_cmos_command.attr,
> + NULL
> +};
> +
> +static umode_t cmos_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + return cmos_handle ? attr->mode : 0;
> +}
> +
> +static const struct attribute_group cmos_attr_group = {
> + .is_visible = cmos_attr_is_visible,
> + .attrs = cmos_attributes,
> +};
> +
> /* --------------------------------------------------------------------- */
>
> static int __init cmos_init(struct ibm_init_struct *iibm)
> {
> - int res;
> -
> vdbg_printk(TPACPI_DBG_INIT,
> - "initializing cmos commands subdriver\n");
> + "initializing cmos commands subdriver\n");
>
> TPACPI_ACPIHANDLE_INIT(cmos);
>
> vdbg_printk(TPACPI_DBG_INIT, "cmos commands are %s\n",
> - str_supported(cmos_handle != NULL));
> -
> - res = device_create_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
> - if (res)
> - return res;
> + str_supported(cmos_handle != NULL));
>
> - return (cmos_handle) ? 0 : 1;
> -}
> -
> -static void cmos_exit(void)
> -{
> - device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command);
> + return cmos_handle ? 0 : 1;
> }
>
> static int cmos_read(struct seq_file *m)
> @@ -5699,7 +5619,6 @@ static struct ibm_struct cmos_driver_data = {
> .name = "cmos",
> .read = cmos_read,
> .write = cmos_write,
> - .exit = cmos_exit,
> };
>
> /*************************************************************************
> @@ -6210,7 +6129,6 @@ struct ibm_thermal_sensors_struct {
> };
>
> static enum thermal_access_mode thermal_read_mode;
> -static const struct attribute_group *thermal_attr_group;
> static bool thermal_use_labels;
>
> /* idx is zero-based */
> @@ -6383,12 +6301,26 @@ static struct attribute *thermal_temp_input_attr[] = {
> NULL
> };
>
> -static const struct attribute_group thermal_temp_input16_group = {
> - .attrs = thermal_temp_input_attr
> -};
> +static umode_t thermal_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + if (thermal_read_mode == TPACPI_THERMAL_NONE)
> + return 0;
> +
> + if (attr == THERMAL_ATTRS(8) || attr == THERMAL_ATTRS(9) ||
> + attr == THERMAL_ATTRS(10) || attr == THERMAL_ATTRS(11) ||
> + attr == THERMAL_ATTRS(12) || attr == THERMAL_ATTRS(13) ||
> + attr == THERMAL_ATTRS(14) || attr == THERMAL_ATTRS(15)) {
> + if (thermal_read_mode != TPACPI_THERMAL_TPEC_16)
> + return 0;
> + }
>
> -static const struct attribute_group thermal_temp_input8_group = {
> - .attrs = &thermal_temp_input_attr[8]
> + return attr->mode;
> +}
> +
> +static const struct attribute_group thermal_attr_group = {
> + .is_visible = thermal_attr_is_visible,
> + .attrs = thermal_temp_input_attr,
> };
>
> #undef THERMAL_SENSOR_ATTR_TEMP
> @@ -6412,7 +6344,14 @@ static struct attribute *temp_label_attributes[] = {
> NULL
> };
>
> +static umode_t temp_label_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + return thermal_use_labels ? attr->mode : 0;
> +}
> +
> static const struct attribute_group temp_label_attr_group = {
> + .is_visible = temp_label_attr_is_visible,
> .attrs = temp_label_attributes,
> };
>
> @@ -6423,7 +6362,6 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
> u8 t, ta1, ta2, ver = 0;
> int i;
> int acpi_tmp7;
> - int res;
>
> vdbg_printk(TPACPI_DBG_INIT, "initializing thermal subdriver\n");
>
> @@ -6498,42 +6436,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
> str_supported(thermal_read_mode != TPACPI_THERMAL_NONE),
> thermal_read_mode);
>
> - switch (thermal_read_mode) {
> - case TPACPI_THERMAL_TPEC_16:
> - thermal_attr_group = &thermal_temp_input16_group;
> - break;
> - case TPACPI_THERMAL_TPEC_8:
> - case TPACPI_THERMAL_ACPI_TMP07:
> - case TPACPI_THERMAL_ACPI_UPDT:
> - thermal_attr_group = &thermal_temp_input8_group;
> - break;
> - case TPACPI_THERMAL_NONE:
> - default:
> - return 1;
> - }
> -
> - res = sysfs_create_group(&tpacpi_hwmon->kobj, thermal_attr_group);
> - if (res)
> - return res;
> -
> - if (thermal_use_labels) {
> - res = sysfs_create_group(&tpacpi_hwmon->kobj, &temp_label_attr_group);
> - if (res) {
> - sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group);
> - return res;
> - }
> - }
> -
> - return 0;
> -}
> -
> -static void thermal_exit(void)
> -{
> - if (thermal_attr_group)
> - sysfs_remove_group(&tpacpi_hwmon->kobj, thermal_attr_group);
> -
> - if (thermal_use_labels)
> - sysfs_remove_group(&tpacpi_hwmon->kobj, &temp_label_attr_group);
> + return thermal_read_mode == TPACPI_THERMAL_NONE ? 1 : 0;
> }
>
> static int thermal_read(struct seq_file *m)
> @@ -6560,7 +6463,6 @@ static int thermal_read(struct seq_file *m)
> static struct ibm_struct thermal_driver_data = {
> .name = "thermal",
> .read = thermal_read,
> - .exit = thermal_exit,
> };
>
> /*************************************************************************
> @@ -8735,14 +8637,34 @@ static ssize_t fan_watchdog_store(struct device_driver *drv, const char *buf,
> static DRIVER_ATTR_RW(fan_watchdog);
>
> /* --------------------------------------------------------------------- */
> +
> static struct attribute *fan_attributes[] = {
> - &dev_attr_pwm1_enable.attr, &dev_attr_pwm1.attr,
> + &dev_attr_pwm1_enable.attr,
> + &dev_attr_pwm1.attr,
> &dev_attr_fan1_input.attr,
> - NULL, /* for fan2_input */
> + &dev_attr_fan2_input.attr,
> + &driver_attr_fan_watchdog.attr,
> NULL
> };
>
> +static umode_t fan_attr_is_visible(struct kobject *kobj, struct attribute *attr,
> + int n)
> +{
> + if (fan_status_access_mode != TPACPI_FAN_NONE ||
> + fan_control_access_mode != TPACPI_FAN_WR_NONE) {
> + if (attr == &dev_attr_fan2_input.attr) {
> + if (!tp_features.second_fan)
> + return 0;
> + }
> +
> + return attr->mode;
> + }


Can you refactor this one to not have nested if-s and put the
"return attr->mode;" at the end like the other is_visible
functions please ?


> +
> + return 0;
> +}
> +
> static const struct attribute_group fan_attr_group = {
> + .is_visible = fan_attr_is_visible,
> .attrs = fan_attributes,
> };
>
> @@ -8772,7 +8694,6 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
>
> static int __init fan_init(struct ibm_init_struct *iibm)
> {
> - int rc;
> unsigned long quirks;
>
> vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN,
> @@ -8869,27 +8790,10 @@ static int __init fan_init(struct ibm_init_struct *iibm)
> fan_get_status_safe(NULL);
>
> if (fan_status_access_mode != TPACPI_FAN_NONE ||
> - fan_control_access_mode != TPACPI_FAN_WR_NONE) {
> - if (tp_features.second_fan) {
> - /* attach second fan tachometer */
> - fan_attributes[ARRAY_SIZE(fan_attributes)-2] =
> - &dev_attr_fan2_input.attr;
> - }
> - rc = sysfs_create_group(&tpacpi_hwmon->kobj,
> - &fan_attr_group);
> - if (rc < 0)
> - return rc;
> -
> - rc = driver_create_file(&tpacpi_hwmon_pdriver.driver,
> - &driver_attr_fan_watchdog);
> - if (rc < 0) {
> - sysfs_remove_group(&tpacpi_hwmon->kobj,
> - &fan_attr_group);
> - return rc;
> - }
> + fan_control_access_mode != TPACPI_FAN_WR_NONE)
> return 0;
> - } else
> - return 1;
> +
> + return 1;
> }
>
> static void fan_exit(void)
> @@ -8897,11 +8801,6 @@ static void fan_exit(void)
> vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_FAN,
> "cancelling any pending fan watchdog tasks\n");
>
> - /* FIXME: can we really do this unconditionally? */
> - sysfs_remove_group(&tpacpi_hwmon->kobj, &fan_attr_group);
> - driver_remove_file(&tpacpi_hwmon_pdriver.driver,
> - &driver_attr_fan_watchdog);
> -
> cancel_delayed_work(&fan_watchdog_task);
> flush_workqueue(tpacpi_wq);
> }
> @@ -9963,6 +9862,35 @@ static ssize_t palmsensor_show(struct device *dev,
> }
> static DEVICE_ATTR_RO(palmsensor);
>
> +static struct attribute *proxsensor_attributes[] = {
> + &dev_attr_dytc_lapmode.attr,
> + &dev_attr_palmsensor.attr,
> + NULL
> +};
> +
> +static umode_t proxsensor_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + if (attr == &dev_attr_dytc_lapmode.attr) {
> + /*
> + * Platforms before DYTC version 5 claim to have a lap sensor,
> + * but it doesn't work, so we ignore them.
> + */
> + if (!has_lapsensor || dytc_version < 5)
> + return 0;
> + } else if (attr == &dev_attr_palmsensor.attr) {
> + if (!has_palmsensor)
> + return 0;
> + }
> +
> + return attr->mode;
> +}
> +
> +static const struct attribute_group proxsensor_attr_group = {
> + .is_visible = proxsensor_attr_is_visible,
> + .attrs = proxsensor_attributes,
> +};
> +
> static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm)
> {
> int palm_err, lap_err, err;
> @@ -9981,43 +9909,16 @@ static int tpacpi_proxsensor_init(struct ibm_init_struct *iibm)
> if (lap_err && (lap_err != -ENODEV))
> return lap_err;
>
> - if (has_palmsensor) {
> - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_palmsensor.attr);
> - if (err)
> - return err;
> - }
> -
> /* Check if we know the DYTC version, if we don't then get it */
> if (!dytc_version) {
> err = dytc_get_version();
> if (err)
> return err;
> }
> - /*
> - * Platforms before DYTC version 5 claim to have a lap sensor, but it doesn't work, so we
> - * ignore them
> - */
> - if (has_lapsensor && (dytc_version >= 5)) {
> - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr);
> - if (err)
> - return err;
> - }
> - return 0;
> -}
>
> -static void proxsensor_exit(void)
> -{
> - if (has_lapsensor)
> - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_dytc_lapmode.attr);
> - if (has_palmsensor)
> - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_palmsensor.attr);
> + return 0;
> }
>
> -static struct ibm_struct proxsensor_driver_data = {
> - .name = "proximity-sensor",
> - .exit = proxsensor_exit,
> -};
> -

So when I came here during the review I decided a v2 was necessary.

The way the sub-drivers inside thinkpad_acpi work is they must have a
struct ibm_struct associated with them, even if it is just for the name
field.

This is enforced rather harshly (something to fix in another patch)
by this bit of code:

```
static int __init ibm_init(struct ibm_init_struct *iibm)
{
int ret;
struct ibm_struct *ibm = iibm->data;
struct proc_dir_entry *entry;

BUG_ON(ibm == NULL);
```

The name is used in various places and the struct is also used to
store various house-keeping flags.

So for v2 please keep the proxsensor_driver_data struct here, as well
as for dprc_driver_data.


> /*************************************************************************
> * DYTC Platform Profile interface
> */
> @@ -10432,37 +10333,18 @@ static struct attribute *kbdlang_attributes[] = {
> NULL
> };
>
> -static const struct attribute_group kbdlang_attr_group = {
> - .attrs = kbdlang_attributes,
> -};
> -
> -static int tpacpi_kbdlang_init(struct ibm_init_struct *iibm)
> +static umode_t kbdlang_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> {
> int err, output;
>
> err = get_keyboard_lang(&output);
> - /*
> - * If support isn't available (ENODEV) then don't return an error
> - * just don't create the sysfs group.
> - */
> - if (err == -ENODEV)
> - return 0;
> -
> - if (err)
> - return err;
> -
> - /* Platform supports this feature - create the sysfs file */
> - return sysfs_create_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group);
> + return err ? 0 : attr->mode;
> }

get_keyboard_lang() consists of 2 not cheap ACPI calls, one of
which involves talking to the embedded-controller over some slow bus.

Please keep kbdlang_init() and make it set a flag to use inside
kbdlang_attr_is_visible().


>
> -static void kbdlang_exit(void)
> -{
> - sysfs_remove_group(&tpacpi_pdev->dev.kobj, &kbdlang_attr_group);
> -}
> -
> -static struct ibm_struct kbdlang_driver_data = {
> - .name = "kbdlang",
> - .exit = kbdlang_exit,
> +static const struct attribute_group kbdlang_attr_group = {
> + .is_visible = kbdlang_attr_is_visible,
> + .attrs = kbdlang_attributes,
> };
>
> /*************************************************************************
> @@ -10533,41 +10415,127 @@ static ssize_t wwan_antenna_type_show(struct device *dev,
> }
> static DEVICE_ATTR_RO(wwan_antenna_type);
>
> +static struct attribute *dprc_attributes[] = {
> + &dev_attr_wwan_antenna_type.attr,
> + NULL
> +};
> +
> +static umode_t dprc_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> +{
> + return has_antennatype ? attr->mode : 0;
> +}
> +
> +static const struct attribute_group dprc_attr_group = {
> + .is_visible = dprc_attr_is_visible,
> + .attrs = dprc_attributes,
> +};
> +
> static int tpacpi_dprc_init(struct ibm_init_struct *iibm)
> {
> - int wwanantenna_err, err;
> + int err = get_wwan_antenna(&wwan_antennatype);
>
> - wwanantenna_err = get_wwan_antenna(&wwan_antennatype);
> /*
> * If support isn't available (ENODEV) then quit, but don't
> * return an error.
> */
> - if (wwanantenna_err == -ENODEV)
> + if (err == -ENODEV)
> return 0;
>
> - /* if there was an error return it */
> - if (wwanantenna_err && (wwanantenna_err != -ENODEV))
> - return wwanantenna_err;
> - else if (!wwanantenna_err)
> - has_antennatype = true;
> + /* If there was an error return it */
> + if (err)
> + return err;
>
> - if (has_antennatype) {
> - err = sysfs_create_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
> - if (err)
> - return err;
> - }
> + has_antennatype = true;
> return 0;
> }
>
> -static void dprc_exit(void)
> +/* --------------------------------------------------------------------- */
> +
> +static struct attribute *tpacpi_attributes[] = {
> + &driver_attr_debug_level.attr,
> + &driver_attr_version.attr,
> + &driver_attr_interface_version.attr,
> +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
> + &driver_attr_wlsw_emulstate.attr,
> + &driver_attr_bluetooth_emulstate.attr,
> + &driver_attr_wwan_emulstate.attr,
> + &driver_attr_uwb_emulstate.attr,
> +#endif
> + NULL
> +};
> +
> +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
> +static umode_t tpacpi_attr_is_visible(struct kobject *kobj,
> + struct attribute *attr, int n)
> {
> - if (has_antennatype)
> - sysfs_remove_file(&tpacpi_pdev->dev.kobj, &dev_attr_wwan_antenna_type.attr);
> + if (attr == &driver_attr_wlsw_emulstate.attr) {
> + if (!dbg_wlswemul)
> + return 0;
> + } else if (attr == &driver_attr_bluetooth_emulstate.attr) {
> + if (!dbg_bluetoothemul)
> + return 0;
> + } else if (attr == &driver_attr_wwan_emulstate.attr) {
> + if (!dbg_wwanemul)
> + return 0;
> + } else if (attr == &driver_attr_uwb_emulstate.attr) {
> + if (!dbg_uwbemul)
> + return 0;
> + }
> +
> + return attr->mode;
> }
> +#endif
>
> -static struct ibm_struct dprc_driver_data = {
> - .name = "dprc",
> - .exit = dprc_exit,

As mentioned above this struct needs to be kept around,
with just the name set.

> +static const struct attribute_group tpacpi_attr_group = {
> +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
> + .is_visible = tpacpi_attr_is_visible,
> +#endif
> + .attrs = tpacpi_attributes,
> +};
> +
> +static const struct attribute_group *tpacpi_groups[] = {
> + &adaptive_kbd_attr_group,
> + &hotkey_attr_group,
> + &bluetooth_attr_group,
> + &wan_attr_group,
> + &proxsensor_attr_group,
> + &kbdlang_attr_group,
> + &dprc_attr_group,
> + &tpacpi_attr_group,
> + NULL,
> +};
> +
> +static const struct attribute_group *tpacpi_hwmon_groups[] = {
> + &thermal_attr_group,
> + &temp_label_attr_group,
> + &fan_attr_group,
> + &tpacpi_attr_group,
> + NULL,
> +};
> +
> +/****************************************************************************
> + ****************************************************************************
> + *
> + * Platform drivers
> + *
> + ****************************************************************************
> + ****************************************************************************/
> +
> +static struct platform_driver tpacpi_pdriver = {
> + .driver = {
> + .name = TPACPI_DRVR_NAME,
> + .pm = &tpacpi_pm,
> + .dev_groups = tpacpi_groups,
> + },
> + .shutdown = tpacpi_shutdown_handler,
> +};
> +
> +static struct platform_driver tpacpi_hwmon_pdriver = {
> + .driver = {
> + .name = TPACPI_HWMON_DRVR_NAME,
> + .dev_groups = tpacpi_hwmon_groups,
> + },
> };
>
> /****************************************************************************
> @@ -11064,19 +11032,13 @@ static struct ibm_init_struct ibms_init[] __initdata = {
> },
> {
> .init = tpacpi_proxsensor_init,
> - .data = &proxsensor_driver_data,
> },
> {
> .init = tpacpi_dytc_profile_init,
> .data = &dytc_profile_driver_data,
> },
> - {
> - .init = tpacpi_kbdlang_init,
> - .data = &kbdlang_driver_data,
> - },
> {
> .init = tpacpi_dprc_init,
> - .data = &dprc_driver_data,
> },
> };
>
> @@ -11090,8 +11052,6 @@ static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
>
> for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
> ibm = ibms_init[i].data;
> - WARN_ON(ibm == NULL);
> -
> if (!ibm || !ibm->name)
> continue;
>
> @@ -11221,26 +11181,16 @@ static void thinkpad_acpi_module_exit(void)
>
> if (tpacpi_hwmon)
> hwmon_device_unregister(tpacpi_hwmon);
> -
> if (tpacpi_sensors_pdev)
> platform_device_unregister(tpacpi_sensors_pdev);
> if (tpacpi_pdev)
> platform_device_unregister(tpacpi_pdev);
> -
> - if (tp_features.sensors_pdrv_attrs_registered)
> - tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver);
> - if (tp_features.platform_drv_attrs_registered)
> - tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
> -
> if (tp_features.sensors_pdrv_registered)
> platform_driver_unregister(&tpacpi_hwmon_pdriver);
> -
> if (tp_features.platform_drv_registered)
> platform_driver_unregister(&tpacpi_pdriver);
> -
> if (proc_dir)
> remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
> -
> if (tpacpi_wq)
> destroy_workqueue(tpacpi_wq);
>
> @@ -11308,20 +11258,6 @@ static int __init thinkpad_acpi_module_init(void)
> }
> tp_features.sensors_pdrv_registered = 1;
>
> - ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
> - if (!ret) {
> - tp_features.platform_drv_attrs_registered = 1;
> - ret = tpacpi_create_driver_attributes(
> - &tpacpi_hwmon_pdriver.driver);
> - }
> - if (ret) {
> - pr_err("unable to create sysfs driver attributes\n");
> - thinkpad_acpi_module_exit();
> - return ret;
> - }
> - tp_features.sensors_pdrv_attrs_registered = 1;
> -
> -
> /* Device initialization */
> tpacpi_pdev = platform_device_register_simple(TPACPI_DRVR_NAME, -1,
> NULL, 0);
> --
> 2.25.1
>

Regards,

Hans