Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | #ifdef pr_fmt |
2 | #undef pr_fmt | |
3 | #endif | |
4 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
5 | ||
6 | #include <linux/version.h> | |
7 | #include <linux/kernel.h> | |
8 | #include <linux/module.h> | |
9 | #include <linux/printk.h> | |
10 | #include <linux/types.h> | |
11 | #include <linux/kobject.h> | |
12 | #include "mach/mtk_thermal_monitor.h" | |
13 | ||
14 | #define MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN 3 | |
15 | ||
16 | /* #define MTK_COOLER_SHUTDOWN_UEVENT */ | |
17 | #define MTK_COOLER_SHUTDOWN_SIGNAL | |
18 | ||
19 | #if defined(MTK_COOLER_SHUTDOWN_SIGNAL) | |
20 | #include <linux/version.h> | |
21 | #include <linux/proc_fs.h> | |
22 | #include <linux/seq_file.h> | |
23 | #include <asm/uaccess.h> | |
24 | #include <linux/pid.h> | |
25 | #include <linux/signal.h> | |
26 | #include <linux/sched.h> | |
27 | ||
28 | #define MAX_LEN 256 | |
29 | #endif | |
30 | ||
31 | #if 1 | |
32 | #define mtk_cooler_shutdown_dprintk(fmt, args...) \ | |
33 | do { pr_debug("thermal/cooler/shutdown " fmt, ##args); } while (0) | |
34 | #else | |
35 | #define mtk_cooler_shutdown_dprintk(fmt, args...) | |
36 | #endif | |
37 | ||
38 | extern struct proc_dir_entry * mtk_thermal_get_proc_drv_therm_dir_entry(void); | |
39 | ||
40 | typedef struct _sd_state { | |
41 | unsigned long state; | |
42 | int sd_cnt; | |
43 | } sd_state; | |
44 | ||
45 | static struct thermal_cooling_device *cl_shutdown_dev[MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN] = { 0 }; | |
46 | //static unsigned long cl_shutdown_state[MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN] = { 0 }; | |
47 | static sd_state cl_sd_state[MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN]; | |
48 | ||
49 | #if defined(MTK_COOLER_SHUTDOWN_SIGNAL) | |
50 | ||
51 | static unsigned int tm_pid; | |
52 | static unsigned int tm_input_pid; | |
53 | static unsigned int mtk_cl_sd_rst; | |
54 | static struct task_struct g_task; | |
55 | static struct task_struct *pg_task = &g_task; | |
56 | ||
57 | static int sd_debouncet = 1; | |
58 | //static int sd_cnt = 0; | |
59 | static int sd_happened = 0; | |
60 | ||
61 | static ssize_t _mtk_cl_sd_rst_write(struct file *filp, const char __user *buf, size_t len, | |
62 | loff_t *data) | |
63 | { | |
64 | int ret = 0; | |
65 | char tmp[MAX_LEN] = { 0 }; | |
66 | ||
4b9e9796 | 67 | len = (len < (MAX_LEN-1)) ? len : (MAX_LEN-1); |
6fa3eb70 S |
68 | /* write data to the buffer */ |
69 | if (copy_from_user(tmp, buf, len)) { | |
70 | return -EFAULT; | |
71 | } | |
72 | ||
73 | ret = kstrtouint(tmp, 10, &mtk_cl_sd_rst); | |
74 | if (ret) | |
75 | WARN_ON(1); | |
76 | ||
77 | ||
78 | if (1 == mtk_cl_sd_rst) { | |
79 | int i; | |
80 | for (i = MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN; i-- > 0;) { | |
81 | cl_sd_state[i].state = 0; | |
82 | cl_sd_state[i].sd_cnt = 0; | |
83 | } | |
84 | mtk_cl_sd_rst = 0; | |
85 | sd_happened = 0; | |
86 | //sd_cnt = 0; | |
87 | } | |
88 | mtk_cooler_shutdown_dprintk("%s %s = %d\n", __func__, tmp, mtk_cl_sd_rst); | |
89 | ||
90 | return len; | |
91 | } | |
92 | ||
93 | int _mtk_cl_sd_rst_read(struct seq_file *m, void *v) | |
94 | { | |
95 | return 0; | |
96 | } | |
97 | ||
98 | static int _mtk_cl_sd_rst_open(struct inode *inode, struct file *file) | |
99 | { | |
100 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
101 | return single_open(file, _mtk_cl_sd_rst_read, PDE_DATA(inode)); | |
102 | #else | |
103 | return single_open(file, _mtk_cl_sd_rst_read, PDE(inode)->data); | |
104 | #endif | |
105 | } | |
106 | ||
107 | static const struct file_operations _cl_sd_rst_fops = { | |
108 | .owner = THIS_MODULE, | |
109 | .open = _mtk_cl_sd_rst_open, | |
110 | .read = seq_read, | |
111 | .llseek = seq_lseek, | |
112 | .write = _mtk_cl_sd_rst_write, | |
113 | .release = single_release, | |
114 | }; | |
115 | ||
116 | static ssize_t _mtk_cl_sd_pid_write(struct file *filp, const char __user *buf, size_t len, | |
117 | loff_t *data) | |
118 | { | |
119 | int ret = 0; | |
120 | char tmp[MAX_LEN] = { 0 }; | |
121 | ||
4b9e9796 | 122 | len = (len < (MAX_LEN-1)) ? len : (MAX_LEN-1); |
6fa3eb70 S |
123 | /* write data to the buffer */ |
124 | if (copy_from_user(tmp, buf, len)) { | |
125 | return -EFAULT; | |
126 | } | |
127 | ||
128 | ret = kstrtouint(tmp, 10, &tm_input_pid); | |
129 | if (ret) | |
130 | WARN_ON(1); | |
131 | ||
132 | mtk_cooler_shutdown_dprintk("%s %s = %d\n", __func__, tmp, tm_input_pid); | |
133 | ||
134 | return len; | |
135 | } | |
136 | ||
137 | static int _mtk_cl_sd_pid_read(struct seq_file *m, void *v) | |
138 | { | |
139 | seq_printf(m, "%d\n", tm_input_pid); | |
140 | mtk_cooler_shutdown_dprintk("%s %d\n", __func__, tm_input_pid); | |
141 | ||
142 | return 0; | |
143 | } | |
144 | ||
145 | static int _mtk_cl_sd_pid_open(struct inode *inode, struct file *file) | |
146 | { | |
147 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
148 | return single_open(file, _mtk_cl_sd_pid_read, PDE_DATA(inode)); | |
149 | #else | |
150 | return single_open(file, _mtk_cl_sd_pid_read, PDE(inode)->data); | |
151 | #endif | |
152 | } | |
153 | ||
154 | static const struct file_operations _cl_sd_pid_fops = { | |
155 | .owner = THIS_MODULE, | |
156 | .open = _mtk_cl_sd_pid_open, | |
157 | .read = seq_read, | |
158 | .llseek = seq_lseek, | |
159 | .write = _mtk_cl_sd_pid_write, | |
160 | .release = single_release, | |
161 | }; | |
162 | ||
163 | static ssize_t _mtk_cl_sd_debouncet_write(struct file *filp, const char __user *buf, size_t len, loff_t *data) | |
164 | { | |
165 | char desc[MAX_LEN] = {0}; | |
166 | int tmp_dbt = -1; | |
167 | ||
4b9e9796 | 168 | len = (len < (MAX_LEN-1)) ? len : (MAX_LEN-1); |
6fa3eb70 S |
169 | /* write data to the buffer */ |
170 | if (copy_from_user(desc, buf, len)) { | |
171 | return -EFAULT; | |
172 | } | |
173 | ||
174 | if(sscanf(desc, "%d", &tmp_dbt) == 1) | |
175 | { | |
176 | if (tmp_dbt >= 0 && tmp_dbt <= 5) | |
177 | sd_debouncet = tmp_dbt; | |
178 | else | |
179 | mtk_cooler_shutdown_dprintk("[%s] oo range %s = %d\n", __func__, desc, sd_debouncet); | |
180 | } | |
181 | else | |
182 | mtk_cooler_shutdown_dprintk("[%s] bad arg %s = %d\n", __func__, desc, sd_debouncet); | |
183 | ||
184 | mtk_cooler_shutdown_dprintk("[%s] %s = %d\n", __func__, desc, sd_debouncet); | |
185 | ||
186 | return len; | |
187 | } | |
188 | ||
189 | static int _mtk_cl_sd_debouncet_read(struct seq_file *m, void *v) | |
190 | { | |
191 | seq_printf(m, "%d\n", sd_debouncet); | |
192 | mtk_cooler_shutdown_dprintk("[%s] %d\n", __func__, sd_debouncet); | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | static int _mtk_cl_sd_debouncet_open(struct inode *inode, struct file *file) | |
198 | { | |
199 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
200 | return single_open(file, _mtk_cl_sd_debouncet_read, PDE_DATA(inode)); | |
201 | #else | |
202 | return single_open(file, _mtk_cl_sd_debouncet_read, PDE(inode)->data); | |
203 | #endif | |
204 | } | |
205 | ||
206 | static const struct file_operations _cl_sd_debouncet_fops = { | |
207 | .owner = THIS_MODULE, | |
208 | .open = _mtk_cl_sd_debouncet_open, | |
209 | .read = seq_read, | |
210 | .llseek = seq_lseek, | |
211 | .write = _mtk_cl_sd_debouncet_write, | |
212 | .release = single_release, | |
213 | }; | |
214 | ||
215 | static int _mtk_cl_sd_send_signal(void) | |
216 | { | |
217 | int ret = 0; | |
218 | ||
219 | if (tm_input_pid == 0) { | |
220 | mtk_cooler_shutdown_dprintk("%s pid is empty\n", __func__); | |
221 | ret = -1; | |
222 | } | |
223 | ||
224 | mtk_cooler_shutdown_dprintk("%s pid is %d, %d\n", __func__, tm_pid, tm_input_pid); | |
225 | ||
226 | if (ret == 0 && tm_input_pid != tm_pid) { | |
227 | tm_pid = tm_input_pid; | |
228 | pg_task = get_pid_task(find_vpid(tm_pid), PIDTYPE_PID); | |
229 | } | |
230 | ||
231 | if (ret == 0 && pg_task) { | |
232 | siginfo_t info; | |
233 | info.si_signo = SIGIO; | |
234 | info.si_errno = 0; | |
235 | info.si_code = 1; | |
236 | info.si_addr = NULL; | |
237 | ret = send_sig_info(SIGIO, &info, pg_task); | |
238 | } | |
239 | ||
240 | if (ret != 0) | |
241 | mtk_cooler_shutdown_dprintk("%s ret=%d\n", __func__, ret); | |
242 | ||
243 | return ret; | |
244 | } | |
245 | ||
246 | #endif | |
247 | ||
248 | static int mtk_cl_shutdown_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) | |
249 | { | |
250 | *state = 1; | |
251 | /* mtk_cooler_shutdown_dprintk("mtk_cl_shutdown_get_max_state() %s %d\n", cdev->type, *state); */ | |
252 | return 0; | |
253 | } | |
254 | ||
255 | static int mtk_cl_shutdown_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *state) | |
256 | { | |
257 | //*state = *((unsigned long *)cdev->devdata); | |
258 | sd_state *cl_state = (sd_state *) cdev->devdata; | |
259 | if (state) | |
260 | *state = cl_state->state; | |
261 | /* mtk_cooler_shutdown_dprintk("mtk_cl_shutdown_get_cur_state() %s %d\n", cdev->type, *state); */ | |
262 | return 0; | |
263 | } | |
264 | ||
265 | static int mtk_cl_shutdown_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) | |
266 | { | |
267 | sd_state *cl_state = (sd_state *) cdev->devdata; | |
268 | #if defined(MTK_COOLER_SHUTDOWN_SIGNAL) | |
269 | volatile unsigned long original_state; | |
270 | #endif | |
271 | /* mtk_cooler_shutdown_dprintk("mtk_cl_shutdown_set_cur_state() %s %d\n", cdev->type, state); */ | |
272 | if (!cl_state) | |
273 | return -1; | |
274 | ||
275 | #if defined(MTK_COOLER_SHUTDOWN_SIGNAL) | |
276 | original_state = cl_state->state; | |
277 | #endif | |
278 | ||
279 | cl_state->state = state; | |
280 | ||
281 | if (0 == state) | |
282 | { | |
283 | if (cl_state->sd_cnt > 0) | |
284 | cl_state->sd_cnt--; | |
285 | else | |
286 | ; | |
287 | } | |
288 | else if (1 == state) | |
289 | { | |
290 | cl_state->sd_cnt++; | |
291 | } | |
292 | ||
293 | if (sd_debouncet == cl_state->sd_cnt) { | |
294 | #if defined(MTK_COOLER_SHUTDOWN_UEVENT) | |
295 | { | |
296 | /* send uevent to notify current call must be dropped */ | |
297 | char event[] = "SHUTDOWN=1"; | |
298 | char *envp[] = { event, NULL }; | |
299 | ||
300 | kobject_uevent_env(&(cdev->device.kobj), KOBJ_CHANGE, envp); | |
301 | } | |
302 | #endif | |
303 | ||
304 | #if defined(MTK_COOLER_SHUTDOWN_SIGNAL) | |
305 | if (0 == sd_happened) /* make this an edge trigger instead of level trigger */ | |
306 | { | |
307 | /* send signal to target process */ | |
308 | _mtk_cl_sd_send_signal(); | |
309 | sd_happened = 1; | |
310 | } | |
311 | #endif | |
312 | } | |
313 | ||
314 | return 0; | |
315 | } | |
316 | ||
317 | /* bind fan callbacks to fan device */ | |
318 | static struct thermal_cooling_device_ops mtk_cl_shutdown_ops = { | |
319 | .get_max_state = mtk_cl_shutdown_get_max_state, | |
320 | .get_cur_state = mtk_cl_shutdown_get_cur_state, | |
321 | .set_cur_state = mtk_cl_shutdown_set_cur_state, | |
322 | }; | |
323 | ||
324 | static int mtk_cooler_shutdown_register_ltf(void) | |
325 | { | |
326 | int i; | |
327 | mtk_cooler_shutdown_dprintk("register ltf\n"); | |
328 | ||
329 | for (i = MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN; i-- > 0;) { | |
330 | char temp[20] = { 0 }; | |
331 | sprintf(temp, "mtk-cl-shutdown%02d", i); | |
332 | cl_shutdown_dev[i] = mtk_thermal_cooling_device_register(temp, | |
333 | (void *) | |
334 | &cl_sd_state[i], | |
335 | &mtk_cl_shutdown_ops); | |
336 | } | |
337 | ||
338 | return 0; | |
339 | } | |
340 | ||
341 | static void mtk_cooler_shutdown_unregister_ltf(void) | |
342 | { | |
343 | int i; | |
344 | mtk_cooler_shutdown_dprintk("unregister ltf\n"); | |
345 | ||
346 | for (i = MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN; i-- > 0;) { | |
347 | if (cl_shutdown_dev[i]) { | |
348 | mtk_thermal_cooling_device_unregister(cl_shutdown_dev[i]); | |
349 | cl_shutdown_dev[i] = NULL; | |
350 | cl_sd_state[i].state = 0; | |
351 | cl_sd_state[i].sd_cnt = 0; | |
352 | } | |
353 | } | |
354 | } | |
355 | ||
356 | ||
357 | static int __init mtk_cooler_shutdown_init(void) | |
358 | { | |
359 | int err = 0; | |
360 | int i; | |
361 | ||
362 | for (i = MAX_NUM_INSTANCE_MTK_COOLER_SHUTDOWN; i-- > 0;) { | |
363 | cl_shutdown_dev[i] = NULL; | |
364 | cl_sd_state[i].state = 0; | |
365 | cl_sd_state[i].sd_cnt = 0; | |
366 | } | |
367 | ||
368 | mtk_cooler_shutdown_dprintk("init\n"); | |
369 | ||
370 | #if defined(MTK_COOLER_SHUTDOWN_SIGNAL) | |
371 | { | |
372 | struct proc_dir_entry *entry = NULL; | |
373 | struct proc_dir_entry *dir_entry = mtk_thermal_get_proc_drv_therm_dir_entry(); | |
374 | ||
375 | if (!dir_entry) { | |
376 | mtk_cooler_shutdown_dprintk("%s mkdir /proc/driver/thermal failed\n", __func__); | |
377 | return 0; | |
378 | } | |
379 | ||
380 | entry = | |
381 | proc_create("clsd_pid", S_IRUGO | S_IWUSR | S_IWGRP, dir_entry, | |
382 | &_cl_sd_pid_fops); | |
383 | if (!entry) { | |
384 | mtk_cooler_shutdown_dprintk("%s clsd_pid creation failed\n", | |
385 | __func__); | |
386 | } else { | |
387 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
388 | proc_set_user(entry, 0, 1000); | |
389 | #else | |
390 | entry->gid = 1000; | |
391 | #endif | |
392 | } | |
393 | ||
394 | entry = | |
395 | proc_create("clsd_rst", S_IRUGO | S_IWUSR | S_IWGRP, dir_entry, | |
396 | &_cl_sd_rst_fops); | |
397 | if (!entry) { | |
398 | mtk_cooler_shutdown_dprintk("%s clsd_rst creation failed\n", | |
399 | __func__); | |
400 | } else { | |
401 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
402 | proc_set_user(entry, 0, 1000); | |
403 | #else | |
404 | entry->gid = 1000; | |
405 | #endif | |
406 | } | |
407 | ||
408 | entry = | |
409 | proc_create("clsd_dbt", S_IRUGO | S_IWUSR | S_IWGRP, dir_entry, | |
410 | &_cl_sd_debouncet_fops); | |
411 | if (!entry) { | |
412 | mtk_cooler_shutdown_dprintk("%s clsd_dbt creation failed\n", | |
413 | __func__); | |
414 | } else { | |
415 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
416 | proc_set_user(entry, 0, 1000); | |
417 | #else | |
418 | entry->gid = 1000; | |
419 | #endif | |
420 | } | |
421 | } | |
422 | #endif | |
423 | ||
424 | err = mtk_cooler_shutdown_register_ltf(); | |
425 | if (err) | |
426 | goto err_unreg; | |
427 | ||
428 | return 0; | |
429 | ||
430 | err_unreg: | |
431 | mtk_cooler_shutdown_unregister_ltf(); | |
432 | return err; | |
433 | } | |
434 | ||
435 | static void __exit mtk_cooler_shutdown_exit(void) | |
436 | { | |
437 | mtk_cooler_shutdown_dprintk("exit\n"); | |
438 | mtk_cooler_shutdown_unregister_ltf(); | |
439 | } | |
440 | module_init(mtk_cooler_shutdown_init); | |
441 | module_exit(mtk_cooler_shutdown_exit); |