|
@@ -92,18 +92,116 @@ static void devalarm_cancel(struct devalarm *alrm)
|
|
|
hrtimer_cancel(&alrm->u.hrt);
|
|
|
}
|
|
|
|
|
|
+static void alarm_clear(enum android_alarm_type alarm_type)
|
|
|
+{
|
|
|
+ uint32_t alarm_type_mask = 1U << alarm_type;
|
|
|
+ unsigned long flags;
|
|
|
|
|
|
-static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
+ spin_lock_irqsave(&alarm_slock, flags);
|
|
|
+ alarm_dbg(IO, "alarm %d clear\n", alarm_type);
|
|
|
+ devalarm_try_to_cancel(&alarms[alarm_type]);
|
|
|
+ if (alarm_pending) {
|
|
|
+ alarm_pending &= ~alarm_type_mask;
|
|
|
+ if (!alarm_pending && !wait_pending)
|
|
|
+ __pm_relax(&alarm_wake_lock);
|
|
|
+ }
|
|
|
+ alarm_enabled &= ~alarm_type_mask;
|
|
|
+ spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static void alarm_set(enum android_alarm_type alarm_type,
|
|
|
+ struct timespec *ts)
|
|
|
+{
|
|
|
+ uint32_t alarm_type_mask = 1U << alarm_type;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&alarm_slock, flags);
|
|
|
+ alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
|
|
|
+ alarm_type, ts->tv_sec, ts->tv_nsec);
|
|
|
+ alarm_enabled |= alarm_type_mask;
|
|
|
+ devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
|
|
|
+ spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+static int alarm_wait(void)
|
|
|
{
|
|
|
- int rv = 0;
|
|
|
unsigned long flags;
|
|
|
- struct timespec new_alarm_time;
|
|
|
- struct timespec new_rtc_time;
|
|
|
- struct timespec tmp_time;
|
|
|
+ int rv = 0;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&alarm_slock, flags);
|
|
|
+ alarm_dbg(IO, "alarm wait\n");
|
|
|
+ if (!alarm_pending && wait_pending) {
|
|
|
+ __pm_relax(&alarm_wake_lock);
|
|
|
+ wait_pending = 0;
|
|
|
+ }
|
|
|
+ spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
+
|
|
|
+ rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
|
|
|
+ if (rv)
|
|
|
+ return rv;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&alarm_slock, flags);
|
|
|
+ rv = alarm_pending;
|
|
|
+ wait_pending = 1;
|
|
|
+ alarm_pending = 0;
|
|
|
+ spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+static int alarm_set_rtc(struct timespec *ts)
|
|
|
+{
|
|
|
struct rtc_time new_rtc_tm;
|
|
|
struct rtc_device *rtc_dev;
|
|
|
+ unsigned long flags;
|
|
|
+ int rv = 0;
|
|
|
+
|
|
|
+ rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
|
|
|
+ rtc_dev = alarmtimer_get_rtcdev();
|
|
|
+ rv = do_settimeofday(ts);
|
|
|
+ if (rv < 0)
|
|
|
+ return rv;
|
|
|
+ if (rtc_dev)
|
|
|
+ rv = rtc_set_time(rtc_dev, &new_rtc_tm);
|
|
|
+
|
|
|
+ spin_lock_irqsave(&alarm_slock, flags);
|
|
|
+ alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
|
|
|
+ wake_up(&alarm_wait_queue);
|
|
|
+ spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
+
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+static int alarm_get_time(enum android_alarm_type alarm_type,
|
|
|
+ struct timespec *ts)
|
|
|
+{
|
|
|
+ int rv = 0;
|
|
|
+
|
|
|
+ switch (alarm_type) {
|
|
|
+ case ANDROID_ALARM_RTC_WAKEUP:
|
|
|
+ case ANDROID_ALARM_RTC:
|
|
|
+ getnstimeofday(ts);
|
|
|
+ break;
|
|
|
+ case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
|
|
|
+ case ANDROID_ALARM_ELAPSED_REALTIME:
|
|
|
+ get_monotonic_boottime(ts);
|
|
|
+ break;
|
|
|
+ case ANDROID_ALARM_SYSTEMTIME:
|
|
|
+ ktime_get_ts(ts);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ rv = -EINVAL;
|
|
|
+ }
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+static long alarm_do_ioctl(struct file *file, unsigned int cmd,
|
|
|
+ struct timespec *ts)
|
|
|
+{
|
|
|
+ int rv = 0;
|
|
|
+ unsigned long flags;
|
|
|
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;
|
|
@@ -126,102 +224,54 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
|
|
|
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
|
|
case ANDROID_ALARM_CLEAR(0):
|
|
|
- spin_lock_irqsave(&alarm_slock, flags);
|
|
|
- alarm_dbg(IO, "alarm %d clear\n", alarm_type);
|
|
|
- devalarm_try_to_cancel(&alarms[alarm_type]);
|
|
|
- if (alarm_pending) {
|
|
|
- alarm_pending &= ~alarm_type_mask;
|
|
|
- if (!alarm_pending && !wait_pending)
|
|
|
- __pm_relax(&alarm_wake_lock);
|
|
|
- }
|
|
|
- alarm_enabled &= ~alarm_type_mask;
|
|
|
- spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
+ alarm_clear(alarm_type);
|
|
|
break;
|
|
|
-
|
|
|
- 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;
|
|
|
- }
|
|
|
- spin_lock_irqsave(&alarm_slock, flags);
|
|
|
- alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
|
|
|
- alarm_type,
|
|
|
- new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
|
|
|
- alarm_enabled |= alarm_type_mask;
|
|
|
- devalarm_start(&alarms[alarm_type],
|
|
|
- timespec_to_ktime(new_alarm_time));
|
|
|
- spin_unlock_irqrestore(&alarm_slock, flags);
|
|
|
- if (ANDROID_ALARM_BASE_CMD(cmd) !=
|
|
|
- ANDROID_ALARM_SET_AND_WAIT(0))
|
|
|
- break;
|
|
|
+ alarm_set(alarm_type, ts);
|
|
|
+ break;
|
|
|
+ case ANDROID_ALARM_SET_AND_WAIT(0):
|
|
|
+ alarm_set(alarm_type, ts);
|
|
|
/* fall though */
|
|
|
case ANDROID_ALARM_WAIT:
|
|
|
- spin_lock_irqsave(&alarm_slock, flags);
|
|
|
- alarm_dbg(IO, "alarm wait\n");
|
|
|
- if (!alarm_pending && wait_pending) {
|
|
|
- __pm_relax(&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);
|
|
|
+ rv = alarm_wait();
|
|
|
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, &new_rtc_tm);
|
|
|
- rtc_dev = alarmtimer_get_rtcdev();
|
|
|
- rv = do_settimeofday(&new_rtc_time);
|
|
|
- if (rv < 0)
|
|
|
- goto err1;
|
|
|
- if (rtc_dev)
|
|
|
- rv = rtc_set_time(rtc_dev, &new_rtc_tm);
|
|
|
- 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;
|
|
|
+ rv = alarm_set_rtc(ts);
|
|
|
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:
|
|
|
- get_monotonic_boottime(&tmp_time);
|
|
|
- break;
|
|
|
- case ANDROID_ALARM_SYSTEMTIME:
|
|
|
- ktime_get_ts(&tmp_time);
|
|
|
- break;
|
|
|
- default:
|
|
|
- rv = -EINVAL;
|
|
|
- goto err1;
|
|
|
- }
|
|
|
- if (copy_to_user((void __user *)arg, &tmp_time,
|
|
|
- sizeof(tmp_time))) {
|
|
|
- rv = -EFAULT;
|
|
|
- goto err1;
|
|
|
- }
|
|
|
+ rv = alarm_get_time(alarm_type, ts);
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
rv = -EINVAL;
|
|
|
}
|
|
|
-err1:
|
|
|
+ return rv;
|
|
|
+}
|
|
|
+
|
|
|
+static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|
|
+{
|
|
|
+
|
|
|
+ struct timespec ts;
|
|
|
+ int rv;
|
|
|
+
|
|
|
+ switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
|
|
+ case ANDROID_ALARM_SET_AND_WAIT(0):
|
|
|
+ case ANDROID_ALARM_SET(0):
|
|
|
+ case ANDROID_ALARM_SET_RTC:
|
|
|
+ if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
|
|
|
+ return -EFAULT;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ rv = alarm_do_ioctl(file, cmd, &ts);
|
|
|
+
|
|
|
+ switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
|
|
+ case ANDROID_ALARM_GET_TIME(0):
|
|
|
+ if (copy_to_user((void __user *)arg, &ts, sizeof(ts)))
|
|
|
+ return -EFAULT;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
return rv;
|
|
|
}
|
|
|
|