diff options
-rw-r--r-- | drivers/acpi/fan.c | 90 |
1 files changed, 83 insertions, 7 deletions
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index a6e149d692cb..f6e8165c32e8 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/proc_fs.h> | 30 | #include <linux/proc_fs.h> |
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
33 | 33 | #include <linux/thermal.h> | |
34 | #include <acpi/acpi_bus.h> | 34 | #include <acpi/acpi_bus.h> |
35 | #include <acpi/acpi_drivers.h> | 35 | #include <acpi/acpi_drivers.h> |
36 | 36 | ||
@@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = { | |||
68 | }, | 68 | }, |
69 | }; | 69 | }; |
70 | 70 | ||
71 | /* thermal cooling device callbacks */ | ||
72 | static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf) | ||
73 | { | ||
74 | /* ACPI fan device only support two states: ON/OFF */ | ||
75 | return sprintf(buf, "1\n"); | ||
76 | } | ||
77 | |||
78 | static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf) | ||
79 | { | ||
80 | struct acpi_device *device = cdev->devdata; | ||
81 | int state; | ||
82 | int result; | ||
83 | |||
84 | if (!device) | ||
85 | return -EINVAL; | ||
86 | |||
87 | result = acpi_bus_get_power(device->handle, &state); | ||
88 | if (result) | ||
89 | return result; | ||
90 | |||
91 | return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" : | ||
92 | (state == ACPI_STATE_D0 ? "1" : "unknown")); | ||
93 | } | ||
94 | |||
95 | static int | ||
96 | fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state) | ||
97 | { | ||
98 | struct acpi_device *device = cdev->devdata; | ||
99 | int result; | ||
100 | |||
101 | if (!device || (state != 0 && state != 1)) | ||
102 | return -EINVAL; | ||
103 | |||
104 | result = acpi_bus_set_power(device->handle, | ||
105 | state ? ACPI_STATE_D0 : ACPI_STATE_D3); | ||
106 | |||
107 | return result; | ||
108 | } | ||
109 | |||
110 | static struct thermal_cooling_device_ops fan_cooling_ops = { | ||
111 | .get_max_state = fan_get_max_state, | ||
112 | .get_cur_state = fan_get_cur_state, | ||
113 | .set_cur_state = fan_set_cur_state, | ||
114 | }; | ||
115 | |||
71 | /* -------------------------------------------------------------------------- | 116 | /* -------------------------------------------------------------------------- |
72 | FS Interface (/proc) | 117 | FS Interface (/proc) |
73 | -------------------------------------------------------------------------- */ | 118 | -------------------------------------------------------------------------- */ |
119 | #ifdef CONFIG_ACPI_PROCFS | ||
74 | 120 | ||
75 | static struct proc_dir_entry *acpi_fan_dir; | 121 | static struct proc_dir_entry *acpi_fan_dir; |
76 | 122 | ||
@@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device) | |||
171 | 217 | ||
172 | return 0; | 218 | return 0; |
173 | } | 219 | } |
220 | #else | ||
221 | static int acpi_fan_add_fs(struct acpi_device *device) | ||
222 | { | ||
223 | return 0; | ||
224 | } | ||
174 | 225 | ||
226 | static int acpi_fan_remove_fs(struct acpi_device *device) | ||
227 | { | ||
228 | return 0; | ||
229 | } | ||
230 | #endif | ||
175 | /* -------------------------------------------------------------------------- | 231 | /* -------------------------------------------------------------------------- |
176 | Driver Interface | 232 | Driver Interface |
177 | -------------------------------------------------------------------------- */ | 233 | -------------------------------------------------------------------------- */ |
@@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device) | |||
179 | static int acpi_fan_add(struct acpi_device *device) | 235 | static int acpi_fan_add(struct acpi_device *device) |
180 | { | 236 | { |
181 | int result = 0; | 237 | int result = 0; |
182 | struct acpi_fan *fan = NULL; | ||
183 | int state = 0; | 238 | int state = 0; |
184 | 239 | struct thermal_cooling_device *cdev; | |
185 | 240 | ||
186 | if (!device) | 241 | if (!device) |
187 | return -EINVAL; | 242 | return -EINVAL; |
@@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device) | |||
199 | acpi_bus_set_power(device->handle, state); | 254 | acpi_bus_set_power(device->handle, state); |
200 | device->flags.force_power_state = 0; | 255 | device->flags.force_power_state = 0; |
201 | 256 | ||
257 | cdev = thermal_cooling_device_register("Fan", device, | ||
258 | &fan_cooling_ops); | ||
259 | if (cdev) | ||
260 | printk(KERN_INFO PREFIX | ||
261 | "%s is registered as cooling_device%d\n", | ||
262 | device->dev.bus_id, cdev->id); | ||
263 | else | ||
264 | goto end; | ||
265 | acpi_driver_data(device) = cdev; | ||
266 | result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj, | ||
267 | "thermal_cooling"); | ||
268 | if (result) | ||
269 | return result; | ||
270 | |||
271 | result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj, | ||
272 | "device"); | ||
273 | if (result) | ||
274 | return result; | ||
275 | |||
202 | result = acpi_fan_add_fs(device); | 276 | result = acpi_fan_add_fs(device); |
203 | if (result) | 277 | if (result) |
204 | goto end; | 278 | goto end; |
@@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device) | |||
208 | !device->power.state ? "on" : "off"); | 282 | !device->power.state ? "on" : "off"); |
209 | 283 | ||
210 | end: | 284 | end: |
211 | if (result) | ||
212 | kfree(fan); | ||
213 | |||
214 | return result; | 285 | return result; |
215 | } | 286 | } |
216 | 287 | ||
217 | static int acpi_fan_remove(struct acpi_device *device, int type) | 288 | static int acpi_fan_remove(struct acpi_device *device, int type) |
218 | { | 289 | { |
219 | if (!device || !acpi_driver_data(device)) | 290 | struct thermal_cooling_device *cdev = acpi_driver_data(device); |
291 | |||
292 | if (!device || !cdev) | ||
220 | return -EINVAL; | 293 | return -EINVAL; |
221 | 294 | ||
222 | acpi_fan_remove_fs(device); | 295 | acpi_fan_remove_fs(device); |
296 | sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); | ||
297 | sysfs_remove_link(&cdev->device.kobj, "device"); | ||
298 | thermal_cooling_device_unregister(cdev); | ||
223 | 299 | ||
224 | return 0; | 300 | return 0; |
225 | } | 301 | } |