power: wakelocks: fix buffer overflow in print_wake_locks
[linux-2.6.git] / kernel / power / wakelock.c
1 /* kernel/power/wakelock.c
2  *
3  * Copyright (C) 2005-2008 Google, Inc.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/rtc.h>
19 #include <linux/suspend.h>
20 #include <linux/syscalls.h> /* sys_sync */
21 #include <linux/wakelock.h>
22 #ifdef CONFIG_WAKELOCK_STAT
23 #include <linux/proc_fs.h>
24 #endif
25 #include "power.h"
26
27 enum {
28         DEBUG_EXIT_SUSPEND = 1U << 0,
29         DEBUG_WAKEUP = 1U << 1,
30         DEBUG_SUSPEND = 1U << 2,
31         DEBUG_EXPIRE = 1U << 3,
32         DEBUG_WAKE_LOCK = 1U << 4,
33 };
34 static int debug_mask = DEBUG_EXIT_SUSPEND | DEBUG_WAKEUP;
35 module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
36
37 #define WAKE_LOCK_TYPE_MASK              (0x0f)
38 #define WAKE_LOCK_INITIALIZED            (1U << 8)
39 #define WAKE_LOCK_ACTIVE                 (1U << 9)
40 #define WAKE_LOCK_AUTO_EXPIRE            (1U << 10)
41 #define WAKE_LOCK_PREVENTING_SUSPEND     (1U << 11)
42
43 #define TOO_MAY_LOCKS_WARNING           "\n\ntoo many wakelocks!!!\n"
44
45 static DEFINE_SPINLOCK(list_lock);
46 static LIST_HEAD(inactive_locks);
47 static struct list_head active_wake_locks[WAKE_LOCK_TYPE_COUNT];
48 static int current_event_num;
49 struct workqueue_struct *suspend_work_queue;
50 struct wake_lock main_wake_lock;
51 suspend_state_t requested_suspend_state = PM_SUSPEND_MEM;
52 static struct wake_lock unknown_wakeup;
53
54 #ifdef CONFIG_WAKELOCK_STAT
55 static struct wake_lock deleted_wake_locks;
56 static ktime_t last_sleep_time_update;
57 static int wait_for_wakeup;
58
59 int get_expired_time(struct wake_lock *lock, ktime_t *expire_time)
60 {
61         struct timespec ts;
62         struct timespec kt;
63         struct timespec tomono;
64         struct timespec delta;
65         unsigned long seq;
66         long timeout;
67
68         if (!(lock->flags & WAKE_LOCK_AUTO_EXPIRE))
69                 return 0;
70         do {
71                 seq = read_seqbegin(&xtime_lock);
72                 timeout = lock->expires - jiffies;
73                 if (timeout > 0)
74                         return 0;
75                 kt = current_kernel_time();
76                 tomono = wall_to_monotonic;
77         } while (read_seqretry(&xtime_lock, seq));
78         jiffies_to_timespec(-timeout, &delta);
79         set_normalized_timespec(&ts, kt.tv_sec + tomono.tv_sec - delta.tv_sec,
80                                 kt.tv_nsec + tomono.tv_nsec - delta.tv_nsec);
81         *expire_time = timespec_to_ktime(ts);
82         return 1;
83 }
84
85
86 static int print_lock_stat(char *buf, int len, struct wake_lock *lock)
87 {
88         int lock_count = lock->stat.count;
89         int expire_count = lock->stat.expire_count;
90         ktime_t active_time = ktime_set(0, 0);
91         ktime_t total_time = lock->stat.total_time;
92         ktime_t max_time = lock->stat.max_time;
93         int n;
94
95         ktime_t prevent_suspend_time = lock->stat.prevent_suspend_time;
96         if (lock->flags & WAKE_LOCK_ACTIVE) {
97                 ktime_t now, add_time;
98                 int expired = get_expired_time(lock, &now);
99                 if (!expired)
100                         now = ktime_get();
101                 add_time = ktime_sub(now, lock->stat.last_time);
102                 lock_count++;
103                 if (!expired)
104                         active_time = add_time;
105                 else
106                         expire_count++;
107                 total_time = ktime_add(total_time, add_time);
108                 if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND)
109                         prevent_suspend_time = ktime_add(prevent_suspend_time,
110                                         ktime_sub(now, last_sleep_time_update));
111                 if (add_time.tv64 > max_time.tv64)
112                         max_time = add_time;
113         }
114
115         n = snprintf(buf, len,
116                      "\"%s\"\t%d\t%d\t%d\t%lld\t%lld\t%lld\t%lld\t%lld\n",
117                      lock->name, lock_count, expire_count,
118                      lock->stat.wakeup_count, ktime_to_ns(active_time),
119                      ktime_to_ns(total_time),
120                      ktime_to_ns(prevent_suspend_time), ktime_to_ns(max_time),
121                      ktime_to_ns(lock->stat.last_time));
122
123         return n > len ? len : n;
124 }
125
126
127 static int wakelocks_read_proc(char *page, char **start, off_t off,
128                                int count, int *eof, void *data)
129 {
130         unsigned long irqflags;
131         struct wake_lock *lock;
132         int len = 0;
133         int type;
134
135         spin_lock_irqsave(&list_lock, irqflags);
136
137         len += snprintf(page + len, count - len,
138                         "name\tcount\texpire_count\twake_count\tactive_since"
139                         "\ttotal_time\tsleep_time\tmax_time\tlast_change\n");
140         list_for_each_entry(lock, &inactive_locks, link) {
141                 len += print_lock_stat(page + len, count - len, lock);
142         }
143         for (type = 0; type < WAKE_LOCK_TYPE_COUNT; type++) {
144                 list_for_each_entry(lock, &active_wake_locks[type], link)
145                         len += print_lock_stat(page + len, count - len, lock);
146         }
147         spin_unlock_irqrestore(&list_lock, irqflags);
148
149         if (len == count)
150                 memcpy(page + len - strlen(TOO_MAY_LOCKS_WARNING),
151                        TOO_MAY_LOCKS_WARNING,
152                        strlen(TOO_MAY_LOCKS_WARNING));
153
154         *eof = 1;
155
156         return len;
157 }
158
159 static void wake_unlock_stat_locked(struct wake_lock *lock, int expired)
160 {
161         ktime_t duration;
162         ktime_t now;
163         if (!(lock->flags & WAKE_LOCK_ACTIVE))
164                 return;
165         if (get_expired_time(lock, &now))
166                 expired = 1;
167         else
168                 now = ktime_get();
169         lock->stat.count++;
170         if (expired)
171                 lock->stat.expire_count++;
172         duration = ktime_sub(now, lock->stat.last_time);
173         lock->stat.total_time = ktime_add(lock->stat.total_time, duration);
174         if (ktime_to_ns(duration) > ktime_to_ns(lock->stat.max_time))
175                 lock->stat.max_time = duration;
176         lock->stat.last_time = ktime_get();
177         if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
178                 duration = ktime_sub(now, last_sleep_time_update);
179                 lock->stat.prevent_suspend_time = ktime_add(
180                         lock->stat.prevent_suspend_time, duration);
181                 lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
182         }
183 }
184
185 static void update_sleep_wait_stats_locked(int done)
186 {
187         struct wake_lock *lock;
188         ktime_t now, etime, elapsed, add;
189         int expired;
190
191         now = ktime_get();
192         elapsed = ktime_sub(now, last_sleep_time_update);
193         list_for_each_entry(lock, &active_wake_locks[WAKE_LOCK_SUSPEND], link) {
194                 expired = get_expired_time(lock, &etime);
195                 if (lock->flags & WAKE_LOCK_PREVENTING_SUSPEND) {
196                         if (expired)
197                                 add = ktime_sub(etime, last_sleep_time_update);
198                         else
199                                 add = elapsed;
200                         lock->stat.prevent_suspend_time = ktime_add(
201                                 lock->stat.prevent_suspend_time, add);
202                 }
203                 if (done || expired)
204                         lock->flags &= ~WAKE_LOCK_PREVENTING_SUSPEND;
205                 else
206                         lock->flags |= WAKE_LOCK_PREVENTING_SUSPEND;
207         }
208         last_sleep_time_update = now;
209 }
210 #endif
211
212
213 static void expire_wake_lock(struct wake_lock *lock)
214 {
215 #ifdef CONFIG_WAKELOCK_STAT
216         wake_unlock_stat_locked(lock, 1);
217 #endif
218         lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
219         list_del(&lock->link);
220         list_add(&lock->link, &inactive_locks);
221         if (debug_mask & (DEBUG_WAKE_LOCK | DEBUG_EXPIRE))
222                 pr_info("expired wake lock %s\n", lock->name);
223 }
224
225 /* Caller must acquire the list_lock spinlock */
226 static void print_active_locks(int type)
227 {
228         unsigned long irqflags;
229         struct wake_lock *lock;
230
231         BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
232         list_for_each_entry(lock, &active_wake_locks[type], link) {
233                 if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
234                         long timeout = lock->expires - jiffies;
235                         if (timeout <= 0)
236                                 pr_info("wake lock %s, expired\n", lock->name);
237                         else
238                                 pr_info("active wake lock %s, time left %ld\n",
239                                         lock->name, timeout);
240                 } else
241                         pr_info("active wake lock %s\n", lock->name);
242         }
243 }
244
245 static long has_wake_lock_locked(int type)
246 {
247         struct wake_lock *lock, *n;
248         long max_timeout = 0;
249
250         BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
251         list_for_each_entry_safe(lock, n, &active_wake_locks[type], link) {
252                 if (lock->flags & WAKE_LOCK_AUTO_EXPIRE) {
253                         long timeout = lock->expires - jiffies;
254                         if (timeout <= 0)
255                                 expire_wake_lock(lock);
256                         else if (timeout > max_timeout)
257                                 max_timeout = timeout;
258                 } else
259                         return -1;
260         }
261         return max_timeout;
262 }
263
264 long has_wake_lock(int type)
265 {
266         long ret;
267         unsigned long irqflags;
268         spin_lock_irqsave(&list_lock, irqflags);
269         ret = has_wake_lock_locked(type);
270         spin_unlock_irqrestore(&list_lock, irqflags);
271         return ret;
272 }
273
274 static void suspend(struct work_struct *work)
275 {
276         int ret;
277         int entry_event_num;
278
279         if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
280                 if (debug_mask & DEBUG_SUSPEND)
281                         pr_info("suspend: abort suspend\n");
282                 return;
283         }
284
285         entry_event_num = current_event_num;
286         sys_sync();
287         if (debug_mask & DEBUG_SUSPEND)
288                 pr_info("suspend: enter suspend\n");
289         ret = pm_suspend(requested_suspend_state);
290         if (debug_mask & DEBUG_EXIT_SUSPEND) {
291                 struct timespec ts;
292                 struct rtc_time tm;
293                 getnstimeofday(&ts);
294                 rtc_time_to_tm(ts.tv_sec, &tm);
295                 pr_info("suspend: exit suspend, ret = %d "
296                         "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
297                         tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
298                         tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
299         }
300         if (current_event_num == entry_event_num) {
301                 if (debug_mask & DEBUG_SUSPEND)
302                         pr_info("suspend: pm_suspend returned with no event\n");
303                 wake_lock_timeout(&unknown_wakeup, HZ / 2);
304         }
305 }
306 static DECLARE_WORK(suspend_work, suspend);
307
308 static void expire_wake_locks(unsigned long data)
309 {
310         long has_lock;
311         unsigned long irqflags;
312         if (debug_mask & DEBUG_EXPIRE)
313                 pr_info("expire_wake_locks: start\n");
314         spin_lock_irqsave(&list_lock, irqflags);
315         if (debug_mask & DEBUG_SUSPEND)
316                 print_active_locks(WAKE_LOCK_SUSPEND);
317         has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
318         if (debug_mask & DEBUG_EXPIRE)
319                 pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
320         if (has_lock == 0)
321                 queue_work(suspend_work_queue, &suspend_work);
322         spin_unlock_irqrestore(&list_lock, irqflags);
323 }
324 static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
325
326 static int power_suspend_late(struct device *dev)
327 {
328         int ret = has_wake_lock(WAKE_LOCK_SUSPEND) ? -EAGAIN : 0;
329 #ifdef CONFIG_WAKELOCK_STAT
330         wait_for_wakeup = 1;
331 #endif
332         if (debug_mask & DEBUG_SUSPEND)
333                 pr_info("power_suspend_late return %d\n", ret);
334         return ret;
335 }
336
337 static struct dev_pm_ops power_driver_pm_ops = {
338         .suspend_noirq = power_suspend_late,
339 };
340
341 static struct platform_driver power_driver = {
342         .driver.name = "power",
343         .driver.pm = &power_driver_pm_ops,
344 };
345 static struct platform_device power_device = {
346         .name = "power",
347 };
348
349 void wake_lock_init(struct wake_lock *lock, int type, const char *name)
350 {
351         unsigned long irqflags = 0;
352
353         if (name)
354                 lock->name = name;
355         BUG_ON(!lock->name);
356
357         if (debug_mask & DEBUG_WAKE_LOCK)
358                 pr_info("wake_lock_init name=%s\n", lock->name);
359 #ifdef CONFIG_WAKELOCK_STAT
360         lock->stat.count = 0;
361         lock->stat.expire_count = 0;
362         lock->stat.wakeup_count = 0;
363         lock->stat.total_time = ktime_set(0, 0);
364         lock->stat.prevent_suspend_time = ktime_set(0, 0);
365         lock->stat.max_time = ktime_set(0, 0);
366         lock->stat.last_time = ktime_set(0, 0);
367 #endif
368         lock->flags = (type & WAKE_LOCK_TYPE_MASK) | WAKE_LOCK_INITIALIZED;
369
370         INIT_LIST_HEAD(&lock->link);
371         spin_lock_irqsave(&list_lock, irqflags);
372         list_add(&lock->link, &inactive_locks);
373         spin_unlock_irqrestore(&list_lock, irqflags);
374 }
375 EXPORT_SYMBOL(wake_lock_init);
376
377 void wake_lock_destroy(struct wake_lock *lock)
378 {
379         unsigned long irqflags;
380         if (debug_mask & DEBUG_WAKE_LOCK)
381                 pr_info("wake_lock_destroy name=%s\n", lock->name);
382         spin_lock_irqsave(&list_lock, irqflags);
383         lock->flags &= ~WAKE_LOCK_INITIALIZED;
384 #ifdef CONFIG_WAKELOCK_STAT
385         if (lock->stat.count) {
386                 deleted_wake_locks.stat.count += lock->stat.count;
387                 deleted_wake_locks.stat.expire_count += lock->stat.expire_count;
388                 deleted_wake_locks.stat.total_time =
389                         ktime_add(deleted_wake_locks.stat.total_time,
390                                   lock->stat.total_time);
391                 deleted_wake_locks.stat.prevent_suspend_time =
392                         ktime_add(deleted_wake_locks.stat.prevent_suspend_time,
393                                   lock->stat.prevent_suspend_time);
394                 deleted_wake_locks.stat.max_time =
395                         ktime_add(deleted_wake_locks.stat.max_time,
396                                   lock->stat.max_time);
397         }
398 #endif
399         list_del(&lock->link);
400         spin_unlock_irqrestore(&list_lock, irqflags);
401 }
402 EXPORT_SYMBOL(wake_lock_destroy);
403
404 static void wake_lock_internal(
405         struct wake_lock *lock, long timeout, int has_timeout)
406 {
407         int type;
408         unsigned long irqflags;
409         long expire_in;
410
411         spin_lock_irqsave(&list_lock, irqflags);
412         type = lock->flags & WAKE_LOCK_TYPE_MASK;
413         BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
414         BUG_ON(!(lock->flags & WAKE_LOCK_INITIALIZED));
415 #ifdef CONFIG_WAKELOCK_STAT
416         if (type == WAKE_LOCK_SUSPEND && wait_for_wakeup) {
417                 if (debug_mask & DEBUG_WAKEUP)
418                         pr_info("wakeup wake lock: %s\n", lock->name);
419                 wait_for_wakeup = 0;
420                 lock->stat.wakeup_count++;
421         }
422         if ((lock->flags & WAKE_LOCK_AUTO_EXPIRE) &&
423             (long)(lock->expires - jiffies) <= 0) {
424                 wake_unlock_stat_locked(lock, 0);
425                 lock->stat.last_time = ktime_get();
426         }
427 #endif
428         if (!(lock->flags & WAKE_LOCK_ACTIVE)) {
429                 lock->flags |= WAKE_LOCK_ACTIVE;
430 #ifdef CONFIG_WAKELOCK_STAT
431                 lock->stat.last_time = ktime_get();
432 #endif
433         }
434         list_del(&lock->link);
435         if (has_timeout) {
436                 if (debug_mask & DEBUG_WAKE_LOCK)
437                         pr_info("wake_lock: %s, type %d, timeout %ld.%03lu\n",
438                                 lock->name, type, timeout / HZ,
439                                 (timeout % HZ) * MSEC_PER_SEC / HZ);
440                 lock->expires = jiffies + timeout;
441                 lock->flags |= WAKE_LOCK_AUTO_EXPIRE;
442                 list_add_tail(&lock->link, &active_wake_locks[type]);
443         } else {
444                 if (debug_mask & DEBUG_WAKE_LOCK)
445                         pr_info("wake_lock: %s, type %d\n", lock->name, type);
446                 lock->expires = LONG_MAX;
447                 lock->flags &= ~WAKE_LOCK_AUTO_EXPIRE;
448                 list_add(&lock->link, &active_wake_locks[type]);
449         }
450         if (type == WAKE_LOCK_SUSPEND) {
451                 current_event_num++;
452 #ifdef CONFIG_WAKELOCK_STAT
453                 if (lock == &main_wake_lock)
454                         update_sleep_wait_stats_locked(1);
455                 else if (!wake_lock_active(&main_wake_lock))
456                         update_sleep_wait_stats_locked(0);
457 #endif
458                 if (has_timeout)
459                         expire_in = has_wake_lock_locked(type);
460                 else
461                         expire_in = -1;
462                 if (expire_in > 0) {
463                         if (debug_mask & DEBUG_EXPIRE)
464                                 pr_info("wake_lock: %s, start expire timer, "
465                                         "%ld\n", lock->name, expire_in);
466                         mod_timer(&expire_timer, jiffies + expire_in);
467                 } else {
468                         if (del_timer(&expire_timer))
469                                 if (debug_mask & DEBUG_EXPIRE)
470                                         pr_info("wake_lock: %s, stop expire timer\n",
471                                                 lock->name);
472                         if (expire_in == 0)
473                                 queue_work(suspend_work_queue, &suspend_work);
474                 }
475         }
476         spin_unlock_irqrestore(&list_lock, irqflags);
477 }
478
479 void wake_lock(struct wake_lock *lock)
480 {
481         wake_lock_internal(lock, 0, 0);
482 }
483 EXPORT_SYMBOL(wake_lock);
484
485 void wake_lock_timeout(struct wake_lock *lock, long timeout)
486 {
487         wake_lock_internal(lock, timeout, 1);
488 }
489 EXPORT_SYMBOL(wake_lock_timeout);
490
491 void wake_unlock(struct wake_lock *lock)
492 {
493         int type;
494         unsigned long irqflags;
495         spin_lock_irqsave(&list_lock, irqflags);
496         type = lock->flags & WAKE_LOCK_TYPE_MASK;
497 #ifdef CONFIG_WAKELOCK_STAT
498         wake_unlock_stat_locked(lock, 0);
499 #endif
500         if (debug_mask & DEBUG_WAKE_LOCK)
501                 pr_info("wake_unlock: %s\n", lock->name);
502         lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
503         list_del(&lock->link);
504         list_add(&lock->link, &inactive_locks);
505         if (type == WAKE_LOCK_SUSPEND) {
506                 long has_lock = has_wake_lock_locked(type);
507                 if (has_lock > 0) {
508                         if (debug_mask & DEBUG_EXPIRE)
509                                 pr_info("wake_unlock: %s, start expire timer, "
510                                         "%ld\n", lock->name, has_lock);
511                         mod_timer(&expire_timer, jiffies + has_lock);
512                 } else {
513                         if (del_timer(&expire_timer))
514                                 if (debug_mask & DEBUG_EXPIRE)
515                                         pr_info("wake_unlock: %s, stop expire "
516                                                 "timer\n", lock->name);
517                         if (has_lock == 0)
518                                 queue_work(suspend_work_queue, &suspend_work);
519                 }
520                 if (lock == &main_wake_lock) {
521                         if (debug_mask & DEBUG_SUSPEND)
522                                 print_active_locks(WAKE_LOCK_SUSPEND);
523 #ifdef CONFIG_WAKELOCK_STAT
524                         update_sleep_wait_stats_locked(0);
525 #endif
526                 }
527         }
528         spin_unlock_irqrestore(&list_lock, irqflags);
529 }
530 EXPORT_SYMBOL(wake_unlock);
531
532 int wake_lock_active(struct wake_lock *lock)
533 {
534         return !!(lock->flags & WAKE_LOCK_ACTIVE);
535 }
536 EXPORT_SYMBOL(wake_lock_active);
537
538 static int __init wakelocks_init(void)
539 {
540         int ret;
541         int i;
542
543         for (i = 0; i < ARRAY_SIZE(active_wake_locks); i++)
544                 INIT_LIST_HEAD(&active_wake_locks[i]);
545
546 #ifdef CONFIG_WAKELOCK_STAT
547         wake_lock_init(&deleted_wake_locks, WAKE_LOCK_SUSPEND,
548                         "deleted_wake_locks");
549 #endif
550         wake_lock_init(&main_wake_lock, WAKE_LOCK_SUSPEND, "main");
551         wake_lock(&main_wake_lock);
552         wake_lock_init(&unknown_wakeup, WAKE_LOCK_SUSPEND, "unknown_wakeups");
553
554         ret = platform_device_register(&power_device);
555         if (ret) {
556                 pr_err("wakelocks_init: platform_device_register failed\n");
557                 goto err_platform_device_register;
558         }
559         ret = platform_driver_register(&power_driver);
560         if (ret) {
561                 pr_err("wakelocks_init: platform_driver_register failed\n");
562                 goto err_platform_driver_register;
563         }
564
565         suspend_work_queue = create_singlethread_workqueue("suspend");
566         if (suspend_work_queue == NULL) {
567                 ret = -ENOMEM;
568                 goto err_suspend_work_queue;
569         }
570
571 #ifdef CONFIG_WAKELOCK_STAT
572         create_proc_read_entry("wakelocks", S_IRUGO, NULL,
573                                 wakelocks_read_proc, NULL);
574 #endif
575
576         return 0;
577
578 err_suspend_work_queue:
579         platform_driver_unregister(&power_driver);
580 err_platform_driver_register:
581         platform_device_unregister(&power_device);
582 err_platform_device_register:
583         wake_lock_destroy(&unknown_wakeup);
584         wake_lock_destroy(&main_wake_lock);
585 #ifdef CONFIG_WAKELOCK_STAT
586         wake_lock_destroy(&deleted_wake_locks);
587 #endif
588         return ret;
589 }
590
591 static void  __exit wakelocks_exit(void)
592 {
593 #ifdef CONFIG_WAKELOCK_STAT
594         remove_proc_entry("wakelocks", NULL);
595 #endif
596         destroy_workqueue(suspend_work_queue);
597         platform_driver_unregister(&power_driver);
598         platform_device_unregister(&power_device);
599         wake_lock_destroy(&unknown_wakeup);
600         wake_lock_destroy(&main_wake_lock);
601 #ifdef CONFIG_WAKELOCK_STAT
602         wake_lock_destroy(&deleted_wake_locks);
603 #endif
604 }
605
606 core_initcall(wakelocks_init);
607 module_exit(wakelocks_exit);