diff options
Diffstat (limited to 'drivers/hwmon/hp_accel.c')
| -rw-r--r-- | drivers/hwmon/hp_accel.c | 75 |
1 files changed, 72 insertions, 3 deletions
diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c index bf8d40580577..03705240000f 100644 --- a/drivers/hwmon/hp_accel.c +++ b/drivers/hwmon/hp_accel.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2007-2008 Yan Burman | 4 | * Copyright (C) 2007-2008 Yan Burman |
| 5 | * Copyright (C) 2008 Eric Piel | 5 | * Copyright (C) 2008 Eric Piel |
| 6 | * Copyright (C) 2008 Pavel Machek | 6 | * Copyright (C) 2008-2009 Pavel Machek |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 9 | * it under the terms of the GNU General Public License as published by | 9 | * it under the terms of the GNU General Public License as published by |
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/freezer.h> | 36 | #include <linux/freezer.h> |
| 37 | #include <linux/version.h> | 37 | #include <linux/version.h> |
| 38 | #include <linux/uaccess.h> | 38 | #include <linux/uaccess.h> |
| 39 | #include <linux/leds.h> | ||
| 39 | #include <acpi/acpi_drivers.h> | 40 | #include <acpi/acpi_drivers.h> |
| 40 | #include <asm/atomic.h> | 41 | #include <asm/atomic.h> |
| 41 | #include "lis3lv02d.h" | 42 | #include "lis3lv02d.h" |
| @@ -43,6 +44,36 @@ | |||
| 43 | #define DRIVER_NAME "lis3lv02d" | 44 | #define DRIVER_NAME "lis3lv02d" |
| 44 | #define ACPI_MDPS_CLASS "accelerometer" | 45 | #define ACPI_MDPS_CLASS "accelerometer" |
| 45 | 46 | ||
| 47 | /* Delayed LEDs infrastructure ------------------------------------ */ | ||
| 48 | |||
| 49 | /* Special LED class that can defer work */ | ||
| 50 | struct delayed_led_classdev { | ||
| 51 | struct led_classdev led_classdev; | ||
| 52 | struct work_struct work; | ||
| 53 | enum led_brightness new_brightness; | ||
| 54 | |||
| 55 | unsigned int led; /* For driver */ | ||
| 56 | void (*set_brightness)(struct delayed_led_classdev *data, enum led_brightness value); | ||
| 57 | }; | ||
| 58 | |||
| 59 | static inline void delayed_set_status_worker(struct work_struct *work) | ||
| 60 | { | ||
| 61 | struct delayed_led_classdev *data = | ||
| 62 | container_of(work, struct delayed_led_classdev, work); | ||
| 63 | |||
| 64 | data->set_brightness(data, data->new_brightness); | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline void delayed_sysfs_set(struct led_classdev *led_cdev, | ||
| 68 | enum led_brightness brightness) | ||
| 69 | { | ||
| 70 | struct delayed_led_classdev *data = container_of(led_cdev, | ||
| 71 | struct delayed_led_classdev, led_classdev); | ||
| 72 | data->new_brightness = brightness; | ||
| 73 | schedule_work(&data->work); | ||
| 74 | } | ||
| 75 | |||
| 76 | /* HP-specific accelerometer driver ------------------------------------ */ | ||
| 46 | 77 | ||
| 47 | /* For automatic insertion of the module */ | 78 | /* For automatic insertion of the module */ |
| 48 | static struct acpi_device_id lis3lv02d_device_ids[] = { | 79 | static struct acpi_device_id lis3lv02d_device_ids[] = { |
| @@ -154,10 +185,33 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = { | |||
| 154 | */ | 185 | */ |
| 155 | }; | 186 | }; |
| 156 | 187 | ||
| 188 | static void hpled_set(struct delayed_led_classdev *led_cdev, enum led_brightness value) | ||
| 189 | { | ||
| 190 | acpi_handle handle = adev.device->handle; | ||
| 191 | unsigned long long ret; /* Not used when writing */ | ||
| 192 | union acpi_object in_obj[1]; | ||
| 193 | struct acpi_object_list args = { 1, in_obj }; | ||
| 194 | |||
| 195 | in_obj[0].type = ACPI_TYPE_INTEGER; | ||
| 196 | in_obj[0].integer.value = !!value; | ||
| 197 | |||
| 198 | acpi_evaluate_integer(handle, "ALED", &args, &ret); | ||
| 199 | } | ||
| 200 | |||
| 201 | static struct delayed_led_classdev hpled_led = { | ||
| 202 | .led_classdev = { | ||
| 203 | .name = "hp::hddprotect", | ||
| 204 | .default_trigger = "none", | ||
| 205 | .brightness_set = delayed_sysfs_set, | ||
| 206 | .flags = LED_CORE_SUSPENDRESUME, | ||
| 207 | }, | ||
| 208 | .set_brightness = hpled_set, | ||
| 209 | }; | ||
| 157 | 210 | ||
| 158 | static int lis3lv02d_add(struct acpi_device *device) | 211 | static int lis3lv02d_add(struct acpi_device *device) |
| 159 | { | 212 | { |
| 160 | u8 val; | 213 | u8 val; |
| 214 | int ret; | ||
| 161 | 215 | ||
| 162 | if (!device) | 216 | if (!device) |
| 163 | return -EINVAL; | 217 | return -EINVAL; |
| @@ -183,7 +237,19 @@ static int lis3lv02d_add(struct acpi_device *device) | |||
| 183 | adev.ac = lis3lv02d_axis_normal; | 237 | adev.ac = lis3lv02d_axis_normal; |
| 184 | } | 238 | } |
| 185 | 239 | ||
| 186 | return lis3lv02d_init_device(&adev); | 240 | INIT_WORK(&hpled_led.work, delayed_set_status_worker); |
| 241 | ret = led_classdev_register(NULL, &hpled_led.led_classdev); | ||
| 242 | if (ret) | ||
| 243 | return ret; | ||
| 244 | |||
| 245 | ret = lis3lv02d_init_device(&adev); | ||
| 246 | if (ret) { | ||
| 247 | flush_work(&hpled_led.work); | ||
| 248 | led_classdev_unregister(&hpled_led.led_classdev); | ||
| 249 | return ret; | ||
| 250 | } | ||
| 251 | |||
| 252 | return ret; | ||
| 187 | } | 253 | } |
| 188 | 254 | ||
| 189 | static int lis3lv02d_remove(struct acpi_device *device, int type) | 255 | static int lis3lv02d_remove(struct acpi_device *device, int type) |
| @@ -194,6 +260,9 @@ static int lis3lv02d_remove(struct acpi_device *device, int type) | |||
| 194 | lis3lv02d_joystick_disable(); | 260 | lis3lv02d_joystick_disable(); |
| 195 | lis3lv02d_poweroff(device->handle); | 261 | lis3lv02d_poweroff(device->handle); |
| 196 | 262 | ||
| 263 | flush_work(&hpled_led.work); | ||
| 264 | led_classdev_unregister(&hpled_led.led_classdev); | ||
| 265 | |||
| 197 | return lis3lv02d_remove_fs(); | 266 | return lis3lv02d_remove_fs(); |
| 198 | } | 267 | } |
| 199 | 268 | ||
| @@ -256,7 +325,7 @@ static void __exit lis3lv02d_exit_module(void) | |||
| 256 | acpi_bus_unregister_driver(&lis3lv02d_driver); | 325 | acpi_bus_unregister_driver(&lis3lv02d_driver); |
| 257 | } | 326 | } |
| 258 | 327 | ||
| 259 | MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS"); | 328 | MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS and support for disk protection LED."); |
| 260 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); | 329 | MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); |
| 261 | MODULE_LICENSE("GPL"); | 330 | MODULE_LICENSE("GPL"); |
| 262 | 331 | ||
