Linux Audio

Check our new training course

Linux kernel drivers training

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