linux/drivers/staging/android/alarm-dev.c
<<
>>
Prefs
   1/* drivers/rtc/alarm-dev.c
   2 *
   3 * Copyright (C) 2007-2009 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/time.h>
  17#include <linux/module.h>
  18#include <linux/device.h>
  19#include <linux/miscdevice.h>
  20#include <linux/fs.h>
  21#include <linux/platform_device.h>
  22#include <linux/sched.h>
  23#include <linux/spinlock.h>
  24#include <linux/uaccess.h>
  25#include <linux/alarmtimer.h>
  26#include "android_alarm.h"
  27
  28#define ANDROID_ALARM_PRINT_INFO (1U << 0)
  29#define ANDROID_ALARM_PRINT_IO (1U << 1)
  30#define ANDROID_ALARM_PRINT_INT (1U << 2)
  31
  32static int debug_mask = ANDROID_ALARM_PRINT_INFO;
  33module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
  34
  35#define alarm_dbg(debug_level_mask, fmt, ...)                           \
  36do {                                                                    \
  37        if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask)        \
  38                pr_info(fmt, ##__VA_ARGS__);                            \
  39} while (0)
  40
  41#define ANDROID_ALARM_WAKEUP_MASK ( \
  42        ANDROID_ALARM_RTC_WAKEUP_MASK | \
  43        ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
  44
  45static int alarm_opened;
  46static DEFINE_SPINLOCK(alarm_slock);
  47static struct wakeup_source alarm_wake_lock;
  48static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
  49static uint32_t alarm_pending;
  50static uint32_t alarm_enabled;
  51static uint32_t wait_pending;
  52
  53struct devalarm {
  54        union {
  55                struct hrtimer hrt;
  56                struct alarm alrm;
  57        } u;
  58        enum android_alarm_type type;
  59};
  60
  61static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
  62
  63
  64static int is_wakeup(enum android_alarm_type type)
  65{
  66        return (type == ANDROID_ALARM_RTC_WAKEUP ||
  67                type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP);
  68}
  69
  70
  71static void devalarm_start(struct devalarm *alrm, ktime_t exp)
  72{
  73        if (is_wakeup(alrm->type))
  74                alarm_start(&alrm->u.alrm, exp);
  75        else
  76                hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
  77}
  78
  79
  80static int devalarm_try_to_cancel(struct devalarm *alrm)
  81{
  82        if (is_wakeup(alrm->type))
  83                return alarm_try_to_cancel(&alrm->u.alrm);
  84        return hrtimer_try_to_cancel(&alrm->u.hrt);
  85}
  86
  87static void devalarm_cancel(struct devalarm *alrm)
  88{
  89        if (is_wakeup(alrm->type))
  90                alarm_cancel(&alrm->u.alrm);
  91        else
  92                hrtimer_cancel(&alrm->u.hrt);
  93}
  94
  95static void alarm_clear(enum android_alarm_type alarm_type)
  96{
  97        uint32_t alarm_type_mask = 1U << alarm_type;
  98        unsigned long flags;
  99
 100        spin_lock_irqsave(&alarm_slock, flags);
 101        alarm_dbg(IO, "alarm %d clear\n", alarm_type);
 102        devalarm_try_to_cancel(&alarms[alarm_type]);
 103        if (alarm_pending) {
 104                alarm_pending &= ~alarm_type_mask;
 105                if (!alarm_pending && !wait_pending)
 106                        __pm_relax(&alarm_wake_lock);
 107        }
 108        alarm_enabled &= ~alarm_type_mask;
 109        spin_unlock_irqrestore(&alarm_slock, flags);
 110
 111}
 112
 113static void alarm_set(enum android_alarm_type alarm_type,
 114                                                        struct timespec *ts)
 115{
 116        uint32_t alarm_type_mask = 1U << alarm_type;
 117        unsigned long flags;
 118
 119        spin_lock_irqsave(&alarm_slock, flags);
 120        alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
 121                        alarm_type, ts->tv_sec, ts->tv_nsec);
 122        alarm_enabled |= alarm_type_mask;
 123        devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
 124        spin_unlock_irqrestore(&alarm_slock, flags);
 125}
 126
 127static int alarm_wait(void)
 128{
 129        unsigned long flags;
 130        int rv = 0;
 131
 132        spin_lock_irqsave(&alarm_slock, flags);
 133        alarm_dbg(IO, "alarm wait\n");
 134        if (!alarm_pending && wait_pending) {
 135                __pm_relax(&alarm_wake_lock);
 136                wait_pending = 0;
 137        }
 138        spin_unlock_irqrestore(&alarm_slock, flags);
 139
 140        rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
 141        if (rv)
 142                return rv;
 143
 144        spin_lock_irqsave(&alarm_slock, flags);
 145        rv = alarm_pending;
 146        wait_pending = 1;
 147        alarm_pending = 0;
 148        spin_unlock_irqrestore(&alarm_slock, flags);
 149
 150        return rv;
 151}
 152
 153static int alarm_set_rtc(struct timespec *ts)
 154{
 155        struct rtc_time new_rtc_tm;
 156        struct rtc_device *rtc_dev;
 157        unsigned long flags;
 158        int rv = 0;
 159
 160        rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
 161        rtc_dev = alarmtimer_get_rtcdev();
 162        rv = do_settimeofday(ts);
 163        if (rv < 0)
 164                return rv;
 165        if (rtc_dev)
 166                rv = rtc_set_time(rtc_dev, &new_rtc_tm);
 167
 168        spin_lock_irqsave(&alarm_slock, flags);
 169        alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
 170        wake_up(&alarm_wait_queue);
 171        spin_unlock_irqrestore(&alarm_slock, flags);
 172
 173        return rv;
 174}
 175
 176static int alarm_get_time(enum android_alarm_type alarm_type,
 177                                                        struct timespec *ts)
 178{
 179        int rv = 0;
 180
 181        switch (alarm_type) {
 182        case ANDROID_ALARM_RTC_WAKEUP:
 183        case ANDROID_ALARM_RTC:
 184                getnstimeofday(ts);
 185                break;
 186        case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
 187        case ANDROID_ALARM_ELAPSED_REALTIME:
 188                get_monotonic_boottime(ts);
 189                break;
 190        case ANDROID_ALARM_SYSTEMTIME:
 191                ktime_get_ts(ts);
 192                break;
 193        default:
 194                rv = -EINVAL;
 195        }
 196        return rv;
 197}
 198
 199static long alarm_do_ioctl(struct file *file, unsigned int cmd,
 200                                                        struct timespec *ts)
 201{
 202        int rv = 0;
 203        unsigned long flags;
 204        enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
 205
 206        if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
 207                return -EINVAL;
 208
 209        if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
 210                if ((file->f_flags & O_ACCMODE) == O_RDONLY)
 211                        return -EPERM;
 212                if (file->private_data == NULL &&
 213                    cmd != ANDROID_ALARM_SET_RTC) {
 214                        spin_lock_irqsave(&alarm_slock, flags);
 215                        if (alarm_opened) {
 216                                spin_unlock_irqrestore(&alarm_slock, flags);
 217                                return -EBUSY;
 218                        }
 219                        alarm_opened = 1;
 220                        file->private_data = (void *)1;
 221                        spin_unlock_irqrestore(&alarm_slock, flags);
 222                }
 223        }
 224
 225        switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 226        case ANDROID_ALARM_CLEAR(0):
 227                alarm_clear(alarm_type);
 228                break;
 229        case ANDROID_ALARM_SET(0):
 230                alarm_set(alarm_type, ts);
 231                break;
 232        case ANDROID_ALARM_SET_AND_WAIT(0):
 233                alarm_set(alarm_type, ts);
 234                /* fall though */
 235        case ANDROID_ALARM_WAIT:
 236                rv = alarm_wait();
 237                break;
 238        case ANDROID_ALARM_SET_RTC:
 239                rv = alarm_set_rtc(ts);
 240                break;
 241        case ANDROID_ALARM_GET_TIME(0):
 242                rv = alarm_get_time(alarm_type, ts);
 243                break;
 244
 245        default:
 246                rv = -EINVAL;
 247        }
 248        return rv;
 249}
 250
 251static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 252{
 253
 254        struct timespec ts;
 255        int rv;
 256
 257        switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 258        case ANDROID_ALARM_SET_AND_WAIT(0):
 259        case ANDROID_ALARM_SET(0):
 260        case ANDROID_ALARM_SET_RTC:
 261                if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
 262                        return -EFAULT;
 263                break;
 264        }
 265
 266        rv = alarm_do_ioctl(file, cmd, &ts);
 267        if (rv)
 268                return rv;
 269
 270        switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 271        case ANDROID_ALARM_GET_TIME(0):
 272                if (copy_to_user((void __user *)arg, &ts, sizeof(ts)))
 273                        return -EFAULT;
 274                break;
 275        }
 276
 277        return 0;
 278}
 279#ifdef CONFIG_COMPAT
 280static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
 281                                                        unsigned long arg)
 282{
 283
 284        struct timespec ts;
 285        int rv;
 286
 287        switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 288        case ANDROID_ALARM_SET_AND_WAIT_COMPAT(0):
 289        case ANDROID_ALARM_SET_COMPAT(0):
 290        case ANDROID_ALARM_SET_RTC_COMPAT:
 291                if (compat_get_timespec(&ts, (void __user *)arg))
 292                        return -EFAULT;
 293                /* fall through */
 294        case ANDROID_ALARM_GET_TIME_COMPAT(0):
 295                cmd = ANDROID_ALARM_COMPAT_TO_NORM(cmd);
 296                break;
 297        }
 298
 299        rv = alarm_do_ioctl(file, cmd, &ts);
 300        if (rv)
 301                return rv;
 302
 303        switch (ANDROID_ALARM_BASE_CMD(cmd)) {
 304        case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
 305                if (compat_put_timespec(&ts, (void __user *)arg))
 306                        return -EFAULT;
 307                break;
 308        }
 309
 310        return 0;
 311}
 312#endif
 313
 314static int alarm_open(struct inode *inode, struct file *file)
 315{
 316        file->private_data = NULL;
 317        return 0;
 318}
 319
 320static int alarm_release(struct inode *inode, struct file *file)
 321{
 322        int i;
 323        unsigned long flags;
 324
 325        spin_lock_irqsave(&alarm_slock, flags);
 326        if (file->private_data) {
 327                for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
 328                        uint32_t alarm_type_mask = 1U << i;
 329                        if (alarm_enabled & alarm_type_mask) {
 330                                alarm_dbg(INFO,
 331                                          "%s: clear alarm, pending %d\n",
 332                                          __func__,
 333                                          !!(alarm_pending & alarm_type_mask));
 334                                alarm_enabled &= ~alarm_type_mask;
 335                        }
 336                        spin_unlock_irqrestore(&alarm_slock, flags);
 337                        devalarm_cancel(&alarms[i]);
 338                        spin_lock_irqsave(&alarm_slock, flags);
 339                }
 340                if (alarm_pending | wait_pending) {
 341                        if (alarm_pending)
 342                                alarm_dbg(INFO, "%s: clear pending alarms %x\n",
 343                                          __func__, alarm_pending);
 344                        __pm_relax(&alarm_wake_lock);
 345                        wait_pending = 0;
 346                        alarm_pending = 0;
 347                }
 348                alarm_opened = 0;
 349        }
 350        spin_unlock_irqrestore(&alarm_slock, flags);
 351        return 0;
 352}
 353
 354static void devalarm_triggered(struct devalarm *alarm)
 355{
 356        unsigned long flags;
 357        uint32_t alarm_type_mask = 1U << alarm->type;
 358
 359        alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
 360        spin_lock_irqsave(&alarm_slock, flags);
 361        if (alarm_enabled & alarm_type_mask) {
 362                __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
 363                alarm_enabled &= ~alarm_type_mask;
 364                alarm_pending |= alarm_type_mask;
 365                wake_up(&alarm_wait_queue);
 366        }
 367        spin_unlock_irqrestore(&alarm_slock, flags);
 368}
 369
 370
 371static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
 372{
 373        struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
 374
 375        devalarm_triggered(devalrm);
 376        return HRTIMER_NORESTART;
 377}
 378
 379static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
 380                                                        ktime_t now)
 381{
 382        struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
 383
 384        devalarm_triggered(devalrm);
 385        return ALARMTIMER_NORESTART;
 386}
 387
 388
 389static const struct file_operations alarm_fops = {
 390        .owner = THIS_MODULE,
 391        .unlocked_ioctl = alarm_ioctl,
 392        .open = alarm_open,
 393        .release = alarm_release,
 394#ifdef CONFIG_COMPAT
 395        .compat_ioctl = alarm_compat_ioctl,
 396#endif
 397};
 398
 399static struct miscdevice alarm_device = {
 400        .minor = MISC_DYNAMIC_MINOR,
 401        .name = "alarm",
 402        .fops = &alarm_fops,
 403};
 404
 405static int __init alarm_dev_init(void)
 406{
 407        int err;
 408        int i;
 409
 410        err = misc_register(&alarm_device);
 411        if (err)
 412                return err;
 413
 414        alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
 415                        ALARM_REALTIME, devalarm_alarmhandler);
 416        hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
 417                        CLOCK_REALTIME, HRTIMER_MODE_ABS);
 418        alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
 419                        ALARM_BOOTTIME, devalarm_alarmhandler);
 420        hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
 421                        CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
 422        hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
 423                        CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
 424
 425        for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
 426                alarms[i].type = i;
 427                if (!is_wakeup(i))
 428                        alarms[i].u.hrt.function = devalarm_hrthandler;
 429        }
 430
 431        wakeup_source_init(&alarm_wake_lock, "alarm");
 432        return 0;
 433}
 434
 435static void  __exit alarm_dev_exit(void)
 436{
 437        misc_deregister(&alarm_device);
 438        wakeup_source_trash(&alarm_wake_lock);
 439}
 440
 441module_init(alarm_dev_init);
 442module_exit(alarm_dev_exit);
 443
 444