Revert "staging: Remove the Android alarm-dev driver" 84/78084/2
authorInki Dae <inki.dae@samsung.com>
Mon, 4 Jul 2016 07:52:24 +0000 (16:52 +0900)
committerInki Dae <inki.dae@samsung.com>
Tue, 5 Jul 2016 04:16:51 +0000 (21:16 -0700)
This reverts commit 5da41e925656649fd970f0c205eee5fda887dc24.

Linux mainline removed Android logger driver with alarm-dev driver.
As Tizen common platform decided to use Android logger driver and
dlog as its backend. So to revive Android logger driver,
this patch reverts relevant patches in same other as mainline.

Change-Id: Ibc07aba62879794fd468a1c0e71ce60da8d0b631
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/staging/android/Kconfig
drivers/staging/android/alarm-dev.c [new file with mode: 0644]
drivers/staging/android/android_alarm.h [new file with mode: 0644]
drivers/staging/android/uapi/android_alarm.h [new file with mode: 0644]

index 8feb9048e62ffa45cf601b5deeb392c5be4486e3..e543376a22d343099cc6dc20a4d026a5825734b5 100644 (file)
@@ -28,6 +28,15 @@ config ANDROID_LOW_MEMORY_KILLER
        ---help---
          Registers processes to be killed when memory is low
 
+config ANDROID_INTF_ALARM_DEV
+       tristate "Android alarm driver"
+       depends on RTC_CLASS
+       default n
+       ---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 exports the alarm interface to user-space.
+
 config SYNC
        bool "Synchronization framework"
        default n
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
new file mode 100644 (file)
index 0000000..ff4b3e8
--- /dev/null
@@ -0,0 +1,446 @@
+/* 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 <linux/time.h>
+#include <linux/module.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/uaccess.h>
+#include <linux/alarmtimer.h>
+#include "android_alarm.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 alarm_dbg(debug_level_mask, fmt, ...)                          \
+do {                                                                   \
+       if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask)        \
+               pr_info(fmt, ##__VA_ARGS__);                            \
+} while (0)
+
+#define ANDROID_ALARM_WAKEUP_MASK ( \
+       ANDROID_ALARM_RTC_WAKEUP_MASK | \
+       ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
+
+static int alarm_opened;
+static DEFINE_SPINLOCK(alarm_slock);
+static struct wakeup_source 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;
+
+struct devalarm {
+       union {
+               struct hrtimer hrt;
+               struct alarm alrm;
+       } u;
+       enum android_alarm_type type;
+};
+
+static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
+
+/**
+ * is_wakeup() - Checks to see if this alarm can wake the device
+ * @type:       The type of alarm being checked
+ *
+ * Return: 1 if this is a wakeup alarm, otherwise 0
+ */
+static int is_wakeup(enum android_alarm_type type)
+{
+       return type == ANDROID_ALARM_RTC_WAKEUP ||
+               type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP;
+}
+
+static void devalarm_start(struct devalarm *alrm, ktime_t exp)
+{
+       if (is_wakeup(alrm->type))
+               alarm_start(&alrm->u.alrm, exp);
+       else
+               hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
+}
+
+static int devalarm_try_to_cancel(struct devalarm *alrm)
+{
+       if (is_wakeup(alrm->type))
+               return alarm_try_to_cancel(&alrm->u.alrm);
+       return hrtimer_try_to_cancel(&alrm->u.hrt);
+}
+
+static void devalarm_cancel(struct devalarm *alrm)
+{
+       if (is_wakeup(alrm->type))
+               alarm_cancel(&alrm->u.alrm);
+       else
+               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;
+
+       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)
+{
+       unsigned long flags;
+       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);
+
+       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):
+               alarm_clear(alarm_type);
+               break;
+       case ANDROID_ALARM_SET(0):
+               alarm_set(alarm_type, ts);
+               break;
+       case ANDROID_ALARM_SET_AND_WAIT(0):
+               alarm_set(alarm_type, ts);
+               /* fall though */
+       case ANDROID_ALARM_WAIT:
+               rv = alarm_wait();
+               break;
+       case ANDROID_ALARM_SET_RTC:
+               rv = alarm_set_rtc(ts);
+               break;
+       case ANDROID_ALARM_GET_TIME(0):
+               rv = alarm_get_time(alarm_type, ts);
+               break;
+
+       default:
+               rv = -EINVAL;
+       }
+       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);
+       if (rv)
+               return rv;
+
+       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 0;
+}
+
+#ifdef CONFIG_COMPAT
+static long alarm_compat_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_COMPAT(0):
+       case ANDROID_ALARM_SET_COMPAT(0):
+       case ANDROID_ALARM_SET_RTC_COMPAT:
+               if (compat_get_timespec(&ts, (void __user *)arg))
+                       return -EFAULT;
+               /* fall through */
+       case ANDROID_ALARM_GET_TIME_COMPAT(0):
+               cmd = ANDROID_ALARM_COMPAT_TO_NORM(cmd);
+               break;
+       }
+
+       rv = alarm_do_ioctl(file, cmd, &ts);
+       if (rv)
+               return rv;
+
+       switch (ANDROID_ALARM_BASE_CMD(cmd)) {
+       case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
+               if (compat_put_timespec(&ts, (void __user *)arg))
+                       return -EFAULT;
+               break;
+       }
+
+       return 0;
+}
+#endif
+
+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) {
+               for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+                       uint32_t alarm_type_mask = 1U << i;
+
+                       if (alarm_enabled & alarm_type_mask) {
+                               alarm_dbg(INFO,
+                                         "%s: clear alarm, pending %d\n",
+                                         __func__,
+                                         !!(alarm_pending & alarm_type_mask));
+                               alarm_enabled &= ~alarm_type_mask;
+                       }
+                       spin_unlock_irqrestore(&alarm_slock, flags);
+                       devalarm_cancel(&alarms[i]);
+                       spin_lock_irqsave(&alarm_slock, flags);
+               }
+               if (alarm_pending | wait_pending) {
+                       if (alarm_pending)
+                               alarm_dbg(INFO, "%s: clear pending alarms %x\n",
+                                         __func__, alarm_pending);
+                       __pm_relax(&alarm_wake_lock);
+                       wait_pending = 0;
+                       alarm_pending = 0;
+               }
+               alarm_opened = 0;
+       }
+       spin_unlock_irqrestore(&alarm_slock, flags);
+       return 0;
+}
+
+static void devalarm_triggered(struct devalarm *alarm)
+{
+       unsigned long flags;
+       uint32_t alarm_type_mask = 1U << alarm->type;
+
+       alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
+       spin_lock_irqsave(&alarm_slock, flags);
+       if (alarm_enabled & alarm_type_mask) {
+               __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
+               alarm_enabled &= ~alarm_type_mask;
+               alarm_pending |= alarm_type_mask;
+               wake_up(&alarm_wait_queue);
+       }
+       spin_unlock_irqrestore(&alarm_slock, flags);
+}
+
+static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
+{
+       struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
+
+       devalarm_triggered(devalrm);
+       return HRTIMER_NORESTART;
+}
+
+static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
+                                                       ktime_t now)
+{
+       struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
+
+       devalarm_triggered(devalrm);
+       return ALARMTIMER_NORESTART;
+}
+
+
+static const struct file_operations alarm_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = alarm_ioctl,
+       .open = alarm_open,
+       .release = alarm_release,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = alarm_compat_ioctl,
+#endif
+};
+
+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;
+
+       alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
+                       ALARM_REALTIME, devalarm_alarmhandler);
+       hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
+                       CLOCK_REALTIME, HRTIMER_MODE_ABS);
+       alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
+                       ALARM_BOOTTIME, devalarm_alarmhandler);
+       hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
+                       CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
+       hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
+                       CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+
+       for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+               alarms[i].type = i;
+               if (!is_wakeup(i))
+                       alarms[i].u.hrt.function = devalarm_hrthandler;
+       }
+
+       wakeup_source_init(&alarm_wake_lock, "alarm");
+       return 0;
+}
+
+static void  __exit alarm_dev_exit(void)
+{
+       misc_deregister(&alarm_device);
+       wakeup_source_trash(&alarm_wake_lock);
+}
+
+module_init(alarm_dev_init);
+module_exit(alarm_dev_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
new file mode 100644 (file)
index 0000000..495b20c
--- /dev/null
@@ -0,0 +1,41 @@
+/* include/linux/android_alarm.h
+ *
+ * Copyright (C) 2006-2007 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.
+ *
+ */
+
+#ifndef _LINUX_ANDROID_ALARM_H
+#define _LINUX_ANDROID_ALARM_H
+
+#include <linux/compat.h>
+#include <linux/ioctl.h>
+
+#include "uapi/android_alarm.h"
+
+#ifdef CONFIG_COMPAT
+#define ANDROID_ALARM_SET_COMPAT(type)         ALARM_IOW(2, type, \
+                                                       struct compat_timespec)
+#define ANDROID_ALARM_SET_AND_WAIT_COMPAT(type)        ALARM_IOW(3, type, \
+                                                       struct compat_timespec)
+#define ANDROID_ALARM_GET_TIME_COMPAT(type)    ALARM_IOW(4, type, \
+                                                       struct compat_timespec)
+#define ANDROID_ALARM_SET_RTC_COMPAT           _IOW('a', 5, \
+                                                       struct compat_timespec)
+#define ANDROID_ALARM_IOCTL_NR(cmd)            (_IOC_NR(cmd) & ((1<<4)-1))
+#define ANDROID_ALARM_COMPAT_TO_NORM(cmd)  \
+                               ALARM_IOW(ANDROID_ALARM_IOCTL_NR(cmd), \
+                                       ANDROID_ALARM_IOCTL_TO_TYPE(cmd), \
+                                       struct timespec)
+
+#endif
+
+#endif
diff --git a/drivers/staging/android/uapi/android_alarm.h b/drivers/staging/android/uapi/android_alarm.h
new file mode 100644 (file)
index 0000000..aa013f6
--- /dev/null
@@ -0,0 +1,62 @@
+/* drivers/staging/android/uapi/android_alarm.h
+ *
+ * Copyright (C) 2006-2007 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.
+ *
+ */
+
+#ifndef _UAPI_LINUX_ANDROID_ALARM_H
+#define _UAPI_LINUX_ANDROID_ALARM_H
+
+#include <linux/ioctl.h>
+#include <linux/time.h>
+
+enum android_alarm_type {
+       /* return code bit numbers or set alarm arg */
+       ANDROID_ALARM_RTC_WAKEUP,
+       ANDROID_ALARM_RTC,
+       ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+       ANDROID_ALARM_ELAPSED_REALTIME,
+       ANDROID_ALARM_SYSTEMTIME,
+
+       ANDROID_ALARM_TYPE_COUNT,
+
+       /* return code bit numbers */
+       /* ANDROID_ALARM_TIME_CHANGE = 16 */
+};
+
+enum android_alarm_return_flags {
+       ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
+       ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
+       ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
+                               1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
+       ANDROID_ALARM_ELAPSED_REALTIME_MASK =
+                               1U << ANDROID_ALARM_ELAPSED_REALTIME,
+       ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
+       ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
+};
+
+/* Disable alarm */
+#define ANDROID_ALARM_CLEAR(type)           _IO('a', 0 | ((type) << 4))
+
+/* Ack last alarm and wait for next */
+#define ANDROID_ALARM_WAIT                  _IO('a', 1)
+
+#define ALARM_IOW(c, type, size)            _IOW('a', (c) | ((type) << 4), size)
+/* Set alarm */
+#define ANDROID_ALARM_SET(type)             ALARM_IOW(2, type, struct timespec)
+#define ANDROID_ALARM_SET_AND_WAIT(type)    ALARM_IOW(3, type, struct timespec)
+#define ANDROID_ALARM_GET_TIME(type)        ALARM_IOW(4, type, struct timespec)
+#define ANDROID_ALARM_SET_RTC               _IOW('a', 5, struct timespec)
+#define ANDROID_ALARM_BASE_CMD(cmd)         (cmd & ~(_IOC(0, 0, 0xf0, 0)))
+#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd)    (_IOC_NR(cmd) >> 4)
+
+#endif