When the LID switch ACPI implementation is unreliable, we might want to remove the device when we are not sure about the state. This should prevent any suspend/resume loops given that in that case, there will be no more LID switch input node. This patch prepares the dynamic creation/destruction of the input node. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@xxxxxxxxxx> --- drivers/acpi/button.c | 90 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 9ad8cdb..48bcdca 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -448,10 +448,61 @@ static int acpi_button_resume(struct device *dev) } #endif +static void acpi_button_remove_input(struct acpi_device *device) +{ + struct acpi_button *button = acpi_driver_data(device); + + input_unregister_device(button->input); + button->input = NULL; +} + +static int acpi_button_add_input(struct acpi_device *device) +{ + struct acpi_button *button = acpi_driver_data(device); + struct input_dev *input; + int error; + + button->input = input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto err; + } + + input->name = acpi_device_name(device); + input->phys = button->phys; + input->id.bustype = BUS_HOST; + input->id.product = button->type; + input->dev.parent = &device->dev; + + switch (button->type) { + case ACPI_BUTTON_TYPE_POWER: + input_set_capability(input, EV_KEY, KEY_POWER); + break; + + case ACPI_BUTTON_TYPE_SLEEP: + input_set_capability(input, EV_KEY, KEY_SLEEP); + break; + + case ACPI_BUTTON_TYPE_LID: + input_set_capability(input, EV_SW, SW_LID); + break; + } + + error = input_register_device(input); + if (error) + goto err; + + return 0; + + err: + input_free_device(input); + button->input = NULL; + return error; +} + static int acpi_button_add(struct acpi_device *device) { struct acpi_button *button; - struct input_dev *input; const char *hid = acpi_device_hid(device); char *name, *class; int error; @@ -462,12 +513,6 @@ static int acpi_button_add(struct acpi_device *device) device->driver_data = button; - button->input = input = input_allocate_device(); - if (!input) { - error = -ENOMEM; - goto err_free_button; - } - name = acpi_device_name(device); class = acpi_device_class(device); @@ -493,38 +538,19 @@ static int acpi_button_add(struct acpi_device *device) } else { printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); error = -ENODEV; - goto err_free_input; + goto err_free_button; } error = acpi_button_add_fs(device); if (error) - goto err_free_input; + goto err_free_button; snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); - input->name = name; - input->phys = button->phys; - input->id.bustype = BUS_HOST; - input->id.product = button->type; - input->dev.parent = &device->dev; - - switch (button->type) { - case ACPI_BUTTON_TYPE_POWER: - input_set_capability(input, EV_KEY, KEY_POWER); - break; - - case ACPI_BUTTON_TYPE_SLEEP: - input_set_capability(input, EV_KEY, KEY_SLEEP); - break; - - case ACPI_BUTTON_TYPE_LID: - input_set_capability(input, EV_SW, SW_LID); - break; - } - - error = input_register_device(input); + error = acpi_button_add_input(device); if (error) goto err_remove_fs; + if (button->type == ACPI_BUTTON_TYPE_LID) { acpi_lid_initialize_state(device); /* @@ -540,8 +566,6 @@ static int acpi_button_add(struct acpi_device *device) err_remove_fs: acpi_button_remove_fs(device); - err_free_input: - input_free_device(input); err_free_button: kfree(button); return error; @@ -552,7 +576,7 @@ static int acpi_button_remove(struct acpi_device *device) struct acpi_button *button = acpi_driver_data(device); acpi_button_remove_fs(device); - input_unregister_device(button->input); + acpi_button_remove_input(device); kfree(button); return 0; } -- 2.9.4 -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html