rtc: alarm: Add in-kernel alarm interface

Drivers can now create alarms that will use an hrtimer while the
system is running and the rtc to wake up from suspend.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
This commit is contained in:
Arve Hjønnevåg 2009-05-04 14:09:15 -07:00 committed by Colin Cross
parent b54b33d0b9
commit fa56540eb5
5 changed files with 685 additions and 328 deletions

View File

@ -113,9 +113,17 @@ config RTC_INTF_ALARM
help
Provides non-wakeup and rtc backed wakeup alarms based on rtc or
elapsed realtime, and a non-wakeup alarm on the monotonic clock.
Also provides an ioctl to set the wall time which must be used
Also provides an interface to set the wall time which must be used
for elapsed realtime to work.
config RTC_INTF_ALARM_DEV
bool "Android alarm device"
depends on RTC_INTF_ALARM
default y
help
Exports the alarm interface to user-space.
config RTC_DRV_TEST
tristate "Test driver/device"
help

View File

@ -9,7 +9,8 @@ obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o
rtc-core-$(CONFIG_RTC_INTF_ALARM) += alarm.o
obj-$(CONFIG_RTC_INTF_ALARM) += alarm.o
obj-$(CONFIG_RTC_INTF_ALARM_DEV) += alarm-dev.o
rtc-core-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o

286
drivers/rtc/alarm-dev.c Normal file
View File

@ -0,0 +1,286 @@
/* drivers/rtc/alarm-dev.c
*
* Copyright (C) 2007-2009 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <asm/mach/time.h>
#include <linux/android_alarm.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/sysdev.h>
#include <linux/uaccess.h>
#include <linux/wakelock.h>
#define ANDROID_ALARM_PRINT_INFO (1U << 0)
#define ANDROID_ALARM_PRINT_IO (1U << 1)
#define ANDROID_ALARM_PRINT_INT (1U << 2)
static int debug_mask = ANDROID_ALARM_PRINT_INFO;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
#define pr_alarm(debug_level_mask, args...) \
do { \
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
pr_info(args); \
} \
} while (0)
#define ANDROID_ALARM_WAKEUP_MASK ( \
ANDROID_ALARM_RTC_WAKEUP_MASK | \
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
/* support old usespace code */
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
static int alarm_opened;
static DEFINE_SPINLOCK(alarm_slock);
static struct wake_lock alarm_wake_lock;
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
static uint32_t alarm_pending;
static uint32_t alarm_enabled;
static uint32_t wait_pending;
static struct alarm alarms[ANDROID_ALARM_TYPE_COUNT];
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int rv = 0;
unsigned long flags;
struct timespec new_alarm_time;
struct timespec new_rtc_time;
struct timespec tmp_time;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
uint32_t alarm_type_mask = 1U << alarm_type;
if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
return -EINVAL;
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EPERM;
if (file->private_data == NULL &&
cmd != ANDROID_ALARM_SET_RTC) {
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_opened) {
spin_unlock_irqrestore(&alarm_slock, flags);
return -EBUSY;
}
alarm_opened = 1;
file->private_data = (void *)1;
spin_unlock_irqrestore(&alarm_slock, flags);
}
}
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_CLEAR(0):
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d clear\n", alarm_type);
alarm_try_to_cancel(&alarms[alarm_type]);
if (alarm_pending) {
alarm_pending &= ~alarm_type_mask;
if (!alarm_pending && !wait_pending)
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
spin_unlock_irqrestore(&alarm_slock, flags);
break;
case ANDROID_ALARM_SET_OLD:
case ANDROID_ALARM_SET_AND_WAIT_OLD:
if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) {
rv = -EFAULT;
goto err1;
}
new_alarm_time.tv_nsec = 0;
goto from_old_alarm_set;
case ANDROID_ALARM_SET_AND_WAIT(0):
case ANDROID_ALARM_SET(0):
if (copy_from_user(&new_alarm_time, (void __user *)arg,
sizeof(new_alarm_time))) {
rv = -EFAULT;
goto err1;
}
from_old_alarm_set:
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
alarm_enabled |= alarm_type_mask;
alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
break;
/* fall though */
case ANDROID_ALARM_WAIT:
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm wait\n");
if (!alarm_pending && wait_pending) {
wake_unlock(&alarm_wake_lock);
wait_pending = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
if (rv)
goto err1;
spin_lock_irqsave(&alarm_slock, flags);
rv = alarm_pending;
wait_pending = 1;
alarm_pending = 0;
spin_unlock_irqrestore(&alarm_slock, flags);
break;
case ANDROID_ALARM_SET_RTC:
if (copy_from_user(&new_rtc_time, (void __user *)arg,
sizeof(new_rtc_time))) {
rv = -EFAULT;
goto err1;
}
rv = alarm_set_rtc(new_rtc_time);
spin_lock_irqsave(&alarm_slock, flags);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
spin_unlock_irqrestore(&alarm_slock, flags);
if (rv < 0)
goto err1;
break;
case ANDROID_ALARM_GET_TIME(0):
switch (alarm_type) {
case ANDROID_ALARM_RTC_WAKEUP:
case ANDROID_ALARM_RTC:
getnstimeofday(&tmp_time);
break;
case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
case ANDROID_ALARM_ELAPSED_REALTIME:
tmp_time =
ktime_to_timespec(alarm_get_elapsed_realtime());
break;
case ANDROID_ALARM_TYPE_COUNT:
case ANDROID_ALARM_SYSTEMTIME:
ktime_get_ts(&tmp_time);
break;
}
if (copy_to_user((void __user *)arg, &tmp_time,
sizeof(tmp_time))) {
rv = -EFAULT;
goto err1;
}
break;
default:
rv = -EINVAL;
goto err1;
}
err1:
return rv;
}
static int alarm_open(struct inode *inode, struct file *file)
{
file->private_data = NULL;
return 0;
}
static int alarm_release(struct inode *inode, struct file *file)
{
int i;
unsigned long flags;
spin_lock_irqsave(&alarm_slock, flags);
if (file->private_data != 0) {
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
uint32_t alarm_type_mask = 1U << i;
if (alarm_enabled & alarm_type_mask) {
pr_alarm(INFO, "alarm_release: clear alarm, "
"pending %d\n",
!!(alarm_pending & alarm_type_mask));
alarm_enabled &= ~alarm_type_mask;
}
spin_unlock_irqrestore(&alarm_slock, flags);
alarm_cancel(&alarms[i]);
spin_lock_irqsave(&alarm_slock, flags);
}
if (alarm_pending | wait_pending) {
if (alarm_pending)
pr_alarm(INFO, "alarm_release: clear "
"pending alarms %x\n", alarm_pending);
wake_unlock(&alarm_wake_lock);
wait_pending = 0;
alarm_pending = 0;
}
alarm_opened = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
}
static void alarm_triggered(struct alarm *alarm)
{
unsigned long flags;
uint32_t alarm_type_mask = 1U << alarm->type;
pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_enabled & alarm_type_mask) {
wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
alarm_enabled &= ~alarm_type_mask;
alarm_pending |= alarm_type_mask;
wake_up(&alarm_wait_queue);
}
spin_unlock_irqrestore(&alarm_slock, flags);
}
static const struct file_operations alarm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = alarm_ioctl,
.open = alarm_open,
.release = alarm_release,
};
static struct miscdevice alarm_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "alarm",
.fops = &alarm_fops,
};
static int __init alarm_dev_init(void)
{
int err;
int i;
err = misc_register(&alarm_device);
if (err)
return err;
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
alarm_init(&alarms[i], i, alarm_triggered);
wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
return 0;
}
static void __exit alarm_dev_exit(void)
{
misc_deregister(&alarm_device);
wake_lock_destroy(&alarm_wake_lock);
}
module_init(alarm_dev_init);
module_exit(alarm_dev_exit);

View File

@ -1,6 +1,6 @@
/* drivers/rtc/alarm.c
*
* Copyright (C) 2007 Google, Inc.
* Copyright (C) 2007-2009 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@ -24,24 +24,24 @@
#include <linux/sysdev.h>
#include <linux/wakelock.h>
#define ANDROID_ALARM_PRINT_ERRORS (1U << 0)
#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
#define ANDROID_ALARM_PRINT_INFO (1U << 2)
#define ANDROID_ALARM_PRINT_IO (1U << 3)
#define ANDROID_ALARM_PRINT_INT (1U << 4)
#define ANDROID_ALARM_PRINT_FLOW (1U << 5)
#define ANDROID_ALARM_PRINT_TSET (1U << 2)
#define ANDROID_ALARM_PRINT_CALL (1U << 3)
#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
#define ANDROID_ALARM_PRINT_INT (1U << 5)
#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
#if 0
#define ANDROID_ALARM_DPRINTF_MASK (~0)
#define ANDROID_ALARM_DPRINTF(debug_level_mask, args...) \
static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
ANDROID_ALARM_PRINT_INIT_STATUS;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
#define pr_alarm(debug_level_mask, args...) \
do { \
if (ANDROID_ALARM_DPRINTF_MASK & debug_level_mask) { \
printk(args); \
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
pr_info(args); \
} \
} while (0)
#else
#define ANDROID_ALARM_DPRINTF(args...)
#endif
#define ANDROID_ALARM_WAKEUP_MASK ( \
ANDROID_ALARM_RTC_WAKEUP_MASK | \
@ -51,264 +51,307 @@
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
struct alarm_queue {
struct rb_root alarms;
struct rb_node *first;
struct hrtimer timer;
ktime_t delta;
bool stopped;
ktime_t stopped_time;
};
static struct rtc_device *alarm_rtc_dev;
static int alarm_opened;
static DEFINE_SPINLOCK(alarm_slock);
static DEFINE_MUTEX(alarm_setrtc_mutex);
static struct wake_lock alarm_wake_lock;
static struct wake_lock alarm_rtc_wake_lock;
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
static uint32_t alarm_pending;
static uint32_t alarm_enabled;
static uint32_t wait_pending;
static struct platform_device *alarm_platform_dev;
static struct hrtimer alarm_timer[ANDROID_ALARM_TYPE_COUNT];
static struct timespec alarm_time[ANDROID_ALARM_TYPE_COUNT];
static struct timespec elapsed_rtc_delta;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
static void alarm_start_hrtimer(enum android_alarm_type alarm_type)
static void update_timer_locked(struct alarm_queue *base, bool head_removed)
{
struct timespec hr_alarm_time;
if (!(alarm_enabled & (1U << alarm_type)))
struct alarm *alarm;
bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
if (base->stopped) {
pr_alarm(FLOW, "changed alarm while setting the wall time\n");
return;
hr_alarm_time = alarm_time[alarm_type];
if (alarm_type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP ||
alarm_type == ANDROID_ALARM_ELAPSED_REALTIME)
set_normalized_timespec(&hr_alarm_time,
hr_alarm_time.tv_sec + elapsed_rtc_delta.tv_sec,
hr_alarm_time.tv_nsec + elapsed_rtc_delta.tv_nsec);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW,
"alarm start hrtimer %d at %ld.%09ld\n",
alarm_type, hr_alarm_time.tv_sec, hr_alarm_time.tv_nsec);
hrtimer_start(&alarm_timer[alarm_type],
timespec_to_ktime(hr_alarm_time), HRTIMER_MODE_ABS);
}
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int rv = 0;
unsigned long flags;
int i;
struct timespec new_alarm_time;
struct timespec new_rtc_time;
struct timespec tmp_time;
struct rtc_time rtc_new_rtc_time;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
uint32_t alarm_type_mask = 1U << alarm_type;
if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
return -EINVAL;
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EPERM;
if (file->private_data == NULL &&
cmd != ANDROID_ALARM_SET_RTC) {
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_opened) {
spin_unlock_irqrestore(&alarm_slock, flags);
return -EBUSY;
}
alarm_opened = 1;
file->private_data = (void *)1;
spin_unlock_irqrestore(&alarm_slock, flags);
}
}
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_CLEAR(0):
spin_lock_irqsave(&alarm_slock, flags);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO,
"alarm %d clear\n", alarm_type);
hrtimer_try_to_cancel(&alarm_timer[alarm_type]);
if (alarm_pending) {
alarm_pending &= ~alarm_type_mask;
if (!alarm_pending && !wait_pending)
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
spin_unlock_irqrestore(&alarm_slock, flags);
break;
if (is_wakeup && !suspended && head_removed)
wake_unlock(&alarm_rtc_wake_lock);
case ANDROID_ALARM_SET_OLD:
case ANDROID_ALARM_SET_AND_WAIT_OLD:
if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) {
rv = -EFAULT;
goto err1;
}
new_alarm_time.tv_nsec = 0;
goto from_old_alarm_set;
if (!base->first)
return;
case ANDROID_ALARM_SET_AND_WAIT(0):
case ANDROID_ALARM_SET(0):
if (copy_from_user(&new_alarm_time, (void __user *)arg,
sizeof(new_alarm_time))) {
rv = -EFAULT;
goto err1;
}
from_old_alarm_set:
spin_lock_irqsave(&alarm_slock, flags);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO,
"alarm %d set %ld.%09ld\n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
alarm_time[alarm_type] = new_alarm_time;
alarm_enabled |= alarm_type_mask;
alarm_start_hrtimer(alarm_type);
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
break;
/* fall though */
case ANDROID_ALARM_WAIT:
spin_lock_irqsave(&alarm_slock, flags);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO, "alarm wait\n");
if (!alarm_pending && wait_pending) {
wake_unlock(&alarm_wake_lock);
wait_pending = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
if (rv)
goto err1;
spin_lock_irqsave(&alarm_slock, flags);
rv = alarm_pending;
wait_pending = 1;
alarm_pending = 0;
if (rv & ANDROID_ALARM_WAKEUP_MASK)
wake_unlock(&alarm_rtc_wake_lock);
spin_unlock_irqrestore(&alarm_slock, flags);
break;
case ANDROID_ALARM_SET_RTC:
if (copy_from_user(&new_rtc_time, (void __user *)arg,
sizeof(new_rtc_time))) {
rv = -EFAULT;
goto err1;
}
rtc_time_to_tm(new_rtc_time.tv_sec, &rtc_new_rtc_time);
alarm = container_of(base->first, struct alarm, node);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO,
"set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
new_rtc_time.tv_sec, new_rtc_time.tv_nsec,
rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
rtc_new_rtc_time.tm_mday,
rtc_new_rtc_time.tm_year + 1900);
pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
mutex_lock(&alarm_setrtc_mutex);
spin_lock_irqsave(&alarm_slock, flags);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++)
hrtimer_try_to_cancel(&alarm_timer[i]);
getnstimeofday(&tmp_time);
elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta,
timespec_sub(tmp_time, new_rtc_time));
spin_unlock_irqrestore(&alarm_slock, flags);
rv = do_settimeofday(&new_rtc_time);
spin_lock_irqsave(&alarm_slock, flags);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++)
alarm_start_hrtimer(i);
spin_unlock_irqrestore(&alarm_slock, flags);
if (rv < 0) {
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_ERRORS,
"Failed to set time\n");
mutex_unlock(&alarm_setrtc_mutex);
goto err1;
}
rv = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
spin_lock_irqsave(&alarm_slock, flags);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
spin_unlock_irqrestore(&alarm_slock, flags);
mutex_unlock(&alarm_setrtc_mutex);
if (rv < 0) {
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_ERRORS,
"Failed to set RTC, time will be lost on reboot\n");
goto err1;
}
break;
case ANDROID_ALARM_GET_TIME(0):
mutex_lock(&alarm_setrtc_mutex);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_type != ANDROID_ALARM_SYSTEMTIME) {
getnstimeofday(&tmp_time);
if (alarm_type >= ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP)
tmp_time = timespec_sub(tmp_time,
elapsed_rtc_delta);
} else
ktime_get_ts(&tmp_time);
spin_unlock_irqrestore(&alarm_slock, flags);
mutex_unlock(&alarm_setrtc_mutex);
if (copy_to_user((void __user *)arg, &tmp_time,
sizeof(tmp_time))) {
rv = -EFAULT;
goto err1;
}
break;
default:
rv = -EINVAL;
goto err1;
if (is_wakeup && suspended) {
pr_alarm(FLOW, "changed alarm while suspened\n");
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
return;
}
err1:
return rv;
hrtimer_try_to_cancel(&base->timer);
base->timer.node.expires = ktime_add(base->delta, alarm->expires);
base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
}
static int alarm_open(struct inode *inode, struct file *file)
static void alarm_enqueue_locked(struct alarm *alarm)
{
file->private_data = NULL;
return 0;
struct alarm_queue *base = &alarms[alarm->type];
struct rb_node **link = &base->alarms.rb_node;
struct rb_node *parent = NULL;
struct alarm *entry;
int leftmost = 1;
pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
if (base->first == &alarm->node)
base->first = rb_next(&alarm->node);
if (!RB_EMPTY_NODE(&alarm->node)) {
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
}
while (*link) {
parent = *link;
entry = rb_entry(parent, struct alarm, node);
/*
* We dont care about collisions. Nodes with
* the same expiry time stay together.
*/
if (alarm->expires.tv64 < entry->expires.tv64) {
link = &(*link)->rb_left;
} else {
link = &(*link)->rb_right;
leftmost = 0;
}
}
if (leftmost) {
base->first = &alarm->node;
update_timer_locked(base, false);
}
rb_link_node(&alarm->node, parent, link);
rb_insert_color(&alarm->node, &base->alarms);
}
static int alarm_release(struct inode *inode, struct file *file)
/**
* alarm_init - initialize an alarm
* @alarm: the alarm to be initialized
* @type: the alarm type to be used
* @function: alarm callback function
*/
void alarm_init(struct alarm *alarm,
enum android_alarm_type type, void (*function)(struct alarm *))
{
RB_CLEAR_NODE(&alarm->node);
alarm->type = type;
alarm->function = function;
pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
}
/**
* alarm_start_range - (re)start an alarm
* @alarm: the alarm to be added
* @start: earliest expiry time
* @end: expiry time
*/
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end)
{
int i;
unsigned long flags;
spin_lock_irqsave(&alarm_slock, flags);
if (file->private_data != 0) {
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
uint32_t alarm_type_mask = 1U << i;
if (alarm_enabled & alarm_type_mask) {
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
"alarm_release: clear alarm, "
"pending %d\n",
!!(alarm_pending & alarm_type_mask));
alarm_enabled &= ~alarm_type_mask;
}
spin_unlock_irqrestore(&alarm_slock, flags);
hrtimer_cancel(&alarm_timer[i]);
spin_lock_irqsave(&alarm_slock, flags);
alarm->softexpires = start;
alarm->expires = end;
alarm_enqueue_locked(alarm);
spin_unlock_irqrestore(&alarm_slock, flags);
}
/**
* alarm_try_to_cancel - try to deactivate an alarm
* @alarm: alarm to stop
*
* Returns:
* 0 when the alarm was not active
* 1 when the alarm was active
* -1 when the alarm may currently be excuting the callback function and
* cannot be stopped (it may also be inactive)
*/
int alarm_try_to_cancel(struct alarm *alarm)
{
struct alarm_queue *base = &alarms[alarm->type];
unsigned long flags;
bool first = false;
int ret = 0;
spin_lock_irqsave(&alarm_slock, flags);
if (!RB_EMPTY_NODE(&alarm->node)) {
pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function,
ktime_to_ns(alarm->expires));
ret = 1;
if (base->first == &alarm->node) {
base->first = rb_next(&alarm->node);
first = true;
}
if (alarm_pending | wait_pending) {
if (alarm_pending)
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
"alarm_release: clear pending alarms "
"%x\n", alarm_pending);
wake_unlock(&alarm_wake_lock);
wait_pending = 0;
alarm_pending = 0;
}
alarm_opened = 0;
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
if (first)
update_timer_locked(base, true);
} else
pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
alarm->type, alarm->function);
spin_unlock_irqrestore(&alarm_slock, flags);
if (!ret && hrtimer_callback_running(&base->timer))
ret = -1;
return ret;
}
/**
* alarm_cancel - cancel an alarm and wait for the handler to finish.
* @alarm: the alarm to be cancelled
*
* Returns:
* 0 when the alarm was not active
* 1 when the alarm was active
*/
int alarm_cancel(struct alarm *alarm)
{
for (;;) {
int ret = alarm_try_to_cancel(alarm);
if (ret >= 0)
return ret;
cpu_relax();
}
}
/**
* alarm_set_rtc - set the kernel and rtc walltime
* @new_time: timespec value containing the new time
*/
int alarm_set_rtc(struct timespec new_time)
{
int i;
int ret;
unsigned long flags;
struct rtc_time rtc_new_rtc_time;
struct timespec tmp_time;
rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
new_time.tv_sec, new_time.tv_nsec,
rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
rtc_new_rtc_time.tm_mday,
rtc_new_rtc_time.tm_year + 1900);
mutex_lock(&alarm_setrtc_mutex);
spin_lock_irqsave(&alarm_slock, flags);
wake_lock(&alarm_rtc_wake_lock);
getnstimeofday(&tmp_time);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
hrtimer_try_to_cancel(&alarms[i].timer);
alarms[i].stopped = true;
alarms[i].stopped_time = timespec_to_ktime(tmp_time);
}
alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
timespec_to_ktime(timespec_sub(tmp_time, new_time)));
spin_unlock_irqrestore(&alarm_slock, flags);
ret = do_settimeofday(&new_time);
spin_lock_irqsave(&alarm_slock, flags);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
alarms[i].stopped = false;
update_timer_locked(&alarms[i], false);
}
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
if (ret < 0) {
pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
goto err;
}
if (!alarm_rtc_dev) {
pr_alarm(ERROR,
"alarm_set_rtc: no RTC, time will be lost on reboot\n");
goto err;
}
ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
if (ret < 0)
pr_alarm(ERROR, "alarm_set_rtc: "
"Failed to set RTC, time will be lost on reboot\n");
err:
wake_unlock(&alarm_rtc_wake_lock);
mutex_unlock(&alarm_setrtc_mutex);
return ret;
}
/**
* alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
*
* returns the time in ktime_t format
*/
ktime_t alarm_get_elapsed_realtime(void)
{
ktime_t now;
unsigned long flags;
struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
spin_lock_irqsave(&alarm_slock, flags);
now = base->stopped ? base->stopped_time : ktime_get_real();
now = ktime_sub(now, base->delta);
spin_unlock_irqrestore(&alarm_slock, flags);
return now;
}
static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
{
struct alarm_queue *base;
struct alarm *alarm;
unsigned long flags;
enum android_alarm_type alarm_type = (timer - alarm_timer);
uint32_t alarm_type_mask = 1U << alarm_type;
ktime_t now;
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INT,
"alarm_timer_triggered type %d\n", alarm_type);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_enabled & alarm_type_mask) {
wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
alarm_enabled &= ~alarm_type_mask;
alarm_pending |= alarm_type_mask;
wake_up(&alarm_wait_queue);
base = container_of(timer, struct alarm_queue, timer);
now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
now = ktime_sub(now, base->delta);
pr_alarm(INT, "alarm_timer_triggered type %d at %lld\n",
base - alarms, ktime_to_ns(now));
while (base->first) {
alarm = container_of(base->first, struct alarm, node);
if (alarm->softexpires.tv64 > now.tv64) {
pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
alarm->function, ktime_to_ns(alarm->expires),
ktime_to_ns(alarm->softexpires));
break;
}
base->first = rb_next(&alarm->node);
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
alarm->type, alarm->function,
ktime_to_ns(alarm->expires),
ktime_to_ns(alarm->softexpires));
spin_unlock_irqrestore(&alarm_slock, flags);
alarm->function(alarm);
spin_lock_irqsave(&alarm_slock, flags);
}
if (!base->first)
pr_alarm(FLOW, "no more alarms of type %d\n", base - alarms);
update_timer_locked(base, true);
spin_unlock_irqrestore(&alarm_slock, flags);
return HRTIMER_NORESTART;
}
@ -318,11 +361,11 @@ static void alarm_triggered_func(void *p)
struct rtc_device *rtc = alarm_rtc_dev;
if (!(rtc->irq_data & RTC_AF))
return;
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INT, "rtc alarm triggered\n");
pr_alarm(INT, "rtc alarm triggered\n");
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
}
int alarm_suspend(struct platform_device *pdev, pm_message_t state)
static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
{
int err = 0;
unsigned long flags;
@ -332,89 +375,85 @@ int alarm_suspend(struct platform_device *pdev, pm_message_t state)
unsigned long rtc_alarm_time;
struct timespec rtc_current_timespec;
struct timespec rtc_delta;
struct timespec elapsed_realtime_alarm_time;
struct alarm_queue *wakeup_queue = NULL;
struct alarm_queue *tmp_queue = NULL;
pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW,
"alarm_suspend(%p, %d)\n", pdev, state.event);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_pending && !wake_lock_active(&alarm_wake_lock)) {
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
"alarm pending\n");
err = -EBUSY;
goto err1;
}
if (alarm_enabled & ANDROID_ALARM_WAKEUP_MASK) {
spin_unlock_irqrestore(&alarm_slock, flags);
if (alarm_enabled & ANDROID_ALARM_RTC_WAKEUP_MASK)
hrtimer_cancel(&alarm_timer[ANDROID_ALARM_RTC_WAKEUP]);
if (alarm_enabled & ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
hrtimer_cancel(&alarm_timer[
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]);
suspended = true;
spin_unlock_irqrestore(&alarm_slock, flags);
hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
hrtimer_cancel(&alarms[
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK].timer);
tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
if (tmp_queue->first)
wakeup_queue = tmp_queue;
tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
if (tmp_queue->first && (!wakeup_queue ||
hrtimer_get_expires(&tmp_queue->timer).tv64 <
hrtimer_get_expires(&wakeup_queue->timer).tv64))
wakeup_queue = tmp_queue;
if (wakeup_queue) {
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
rtc_current_timespec.tv_nsec = 0;
rtc_tm_to_time(&rtc_current_rtc_time,
&rtc_current_timespec.tv_sec);
save_time_delta(&rtc_delta, &rtc_current_timespec);
set_normalized_timespec(&elapsed_realtime_alarm_time,
alarm_time[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]
.tv_sec + elapsed_rtc_delta.tv_sec,
alarm_time[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP]
.tv_nsec + elapsed_rtc_delta.tv_nsec);
if ((alarm_enabled & ANDROID_ALARM_RTC_WAKEUP_MASK) &&
(!(alarm_enabled &
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK) ||
timespec_compare(&alarm_time[ANDROID_ALARM_RTC_WAKEUP],
&elapsed_realtime_alarm_time) < 0))
rtc_alarm_time = timespec_sub(
alarm_time[ANDROID_ALARM_RTC_WAKEUP],
rtc_delta).tv_sec;
else
rtc_alarm_time = timespec_sub(
elapsed_realtime_alarm_time, rtc_delta).tv_sec;
rtc_alarm_time = timespec_sub(ktime_to_timespec(
hrtimer_get_expires(&wakeup_queue->timer)),
rtc_delta).tv_sec;
rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
rtc_alarm.enabled = 1;
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
pr_alarm(SUSPEND,
"rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
rtc_alarm_time, rtc_current_time,
rtc_delta.tv_sec, rtc_delta.tv_nsec);
if (rtc_current_time + 1 >= rtc_alarm_time) {
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
"alarm about to go off\n");
pr_alarm(SUSPEND, "alarm about to go off\n");
memset(&rtc_alarm, 0, sizeof(rtc_alarm));
rtc_alarm.enabled = 0;
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
spin_lock_irqsave(&alarm_slock, flags);
suspended = false;
wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
alarm_start_hrtimer(ANDROID_ALARM_RTC_WAKEUP);
alarm_start_hrtimer(
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP);
update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
false);
update_timer_locked(&alarms[
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
err = -EBUSY;
spin_unlock_irqrestore(&alarm_slock, flags);
}
} else {
err1:
spin_unlock_irqrestore(&alarm_slock, flags);
}
return err;
}
int alarm_resume(struct platform_device *pdev)
static int alarm_resume(struct platform_device *pdev)
{
struct rtc_wkalrm alarm;
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_FLOW,
"alarm_resume(%p)\n", pdev);
if (alarm_enabled & ANDROID_ALARM_WAKEUP_MASK) {
memset(&alarm, 0, sizeof(alarm));
alarm.enabled = 0;
rtc_set_alarm(alarm_rtc_dev, &alarm);
alarm_start_hrtimer(ANDROID_ALARM_RTC_WAKEUP);
alarm_start_hrtimer(ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP);
}
unsigned long flags;
pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
memset(&alarm, 0, sizeof(alarm));
alarm.enabled = 0;
rtc_set_alarm(alarm_rtc_dev, &alarm);
spin_lock_irqsave(&alarm_slock, flags);
suspended = false;
update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
false);
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
}
@ -422,19 +461,6 @@ static struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
static struct file_operations alarm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = alarm_ioctl,
.open = alarm_open,
.release = alarm_release,
};
static struct miscdevice alarm_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "alarm",
.fops = &alarm_fops,
};
static int rtc_alarm_add_device(struct device *dev,
struct class_interface *class_intf)
{
@ -448,9 +474,6 @@ static int rtc_alarm_add_device(struct device *dev,
goto err1;
}
err = misc_register(&alarm_device);
if (err)
goto err1;
alarm_platform_dev =
platform_device_register_simple("alarm", -1, NULL, 0);
if (IS_ERR(alarm_platform_dev)) {
@ -461,16 +484,14 @@ static int rtc_alarm_add_device(struct device *dev,
if (err)
goto err3;
alarm_rtc_dev = rtc;
pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
mutex_unlock(&alarm_setrtc_mutex);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO, "alarm: parent %p\n",
alarm_platform_dev->dev.power.pm_parent);
return 0;
err3:
platform_device_unregister(alarm_platform_dev);
err2:
misc_deregister(&alarm_device);
err1:
mutex_unlock(&alarm_setrtc_mutex);
return err;
@ -480,9 +501,9 @@ static void rtc_alarm_remove_device(struct device *dev,
struct class_interface *class_intf)
{
if (dev == &alarm_rtc_dev->dev) {
pr_alarm(INIT_STATUS, "lost rtc device for alarms");
rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
platform_device_unregister(alarm_platform_dev);
misc_deregister(&alarm_device);
alarm_rtc_dev = NULL;
}
}
@ -503,7 +524,7 @@ static struct platform_driver alarm_driver = {
static int __init alarm_late_init(void)
{
unsigned long flags;
struct timespec system_time;
struct timespec tmp_time, system_time;
/* this needs to run after the rtc is read at boot */
spin_lock_irqsave(&alarm_slock, flags);
@ -511,33 +532,32 @@ static int __init alarm_late_init(void)
* elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
* (rtc - (boot_rtc - boot_systemtime))
*/
getnstimeofday(&elapsed_rtc_delta);
getnstimeofday(&tmp_time);
ktime_get_ts(&system_time);
elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta, system_time);
spin_unlock_irqrestore(&alarm_slock, flags);
alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
timespec_to_ktime(timespec_sub(tmp_time, system_time));
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_INFO,
"alarm_late_init: rtc to elapsed realtime delta %ld.%09ld\n",
elapsed_rtc_delta.tv_sec, elapsed_rtc_delta.tv_nsec);
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
}
static int __init alarm_init(void)
static int __init alarm_driver_init(void)
{
int err;
int i;
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
hrtimer_init(&alarm_timer[i], CLOCK_REALTIME, HRTIMER_MODE_ABS);
alarm_timer[i].function = alarm_timer_triggered;
hrtimer_init(&alarms[i].timer,
CLOCK_REALTIME, HRTIMER_MODE_ABS);
alarms[i].timer.function = alarm_timer_triggered;
}
hrtimer_init(&alarm_timer[ANDROID_ALARM_SYSTEMTIME],
hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
alarm_timer[ANDROID_ALARM_SYSTEMTIME].function = alarm_timer_triggered;
alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
err = platform_driver_register(&alarm_driver);
if (err < 0)
goto err1;
wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
rtc_alarm_interface.class = rtc_class;
err = class_interface_register(&rtc_alarm_interface);
@ -548,7 +568,6 @@ static int __init alarm_init(void)
err2:
wake_lock_destroy(&alarm_rtc_wake_lock);
wake_lock_destroy(&alarm_wake_lock);
platform_driver_unregister(&alarm_driver);
err1:
return err;
@ -558,11 +577,10 @@ static void __exit alarm_exit(void)
{
class_interface_unregister(&rtc_alarm_interface);
wake_lock_destroy(&alarm_rtc_wake_lock);
wake_lock_destroy(&alarm_wake_lock);
platform_driver_unregister(&alarm_driver);
}
late_initcall(alarm_late_init);
module_init(alarm_init);
module_init(alarm_driver_init);
module_exit(alarm_exit);

View File

@ -33,6 +33,50 @@ enum android_alarm_type {
/* ANDROID_ALARM_TIME_CHANGE = 16 */
};
#ifdef __KERNEL__
#include <linux/ktime.h>
#include <linux/rbtree.h>
/*
* The alarm interface is similar to the hrtimer interface but adds support
* for wakeup from suspend. It also adds an elapsed realtime clock that can
* be used for periodic timers that need to keep runing while the system is
* suspended and not be disrupted when the wall time is set.
*/
/**
* struct alarm - the basic alarm structure
* @node: red black tree node for time ordered insertion
* @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
* @softexpires: the absolute earliest expiry time of the alarm.
* @expires: the absolute expiry time.
* @function: alarm expiry callback function
*
* The alarm structure must be initialized by alarm_init()
*
*/
struct alarm {
struct rb_node node;
enum android_alarm_type type;
ktime_t softexpires;
ktime_t expires;
void (*function)(struct alarm *);
};
void alarm_init(struct alarm *alarm,
enum android_alarm_type type, void (*function)(struct alarm *));
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end);
int alarm_try_to_cancel(struct alarm *alarm);
int alarm_cancel(struct alarm *alarm);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
int alarm_set_rtc(const struct timespec ts);
#endif
enum android_alarm_return_flags {
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,