1/*
2 *  linux/arch/arm/common/rtctime.c
3 *
4 *  Copyright (C) 2003 Deep Blue Solutions Ltd.
5 *  Based on sa1100-rtc.c, Nils Faerber, CIH, Nicolas Pitre.
6 *  Based on rtc.c by Paul Gortmaker
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/time.h>
15#include <linux/rtc.h>
16#include <linux/poll.h>
17#include <linux/proc_fs.h>
18#include <linux/miscdevice.h>
19#include <linux/spinlock.h>
20#include <linux/capability.h>
21#include <linux/device.h>
22#include <linux/mutex.h>
23#include <linux/rtc.h>
24
25#include <asm/rtc.h>
26#include <asm/semaphore.h>
27
28static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
29static struct fasync_struct *rtc_async_queue;
30
31/*
32 * rtc_lock protects rtc_irq_data
33 */
34static DEFINE_SPINLOCK(rtc_lock);
35static unsigned long rtc_irq_data;
36
37/*
38 * rtc_sem protects rtc_inuse and rtc_ops
39 */
40static DEFINE_MUTEX(rtc_mutex);
41static unsigned long rtc_inuse;
42static struct rtc_ops *rtc_ops;
43
44#define rtc_epoch 1900UL
45
46/*
47 * Calculate the next alarm time given the requested alarm time mask
48 * and the current time.
49 */
50void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
51{
52	unsigned long next_time;
53	unsigned long now_time;
54
55	next->tm_year = now->tm_year;
56	next->tm_mon = now->tm_mon;
57	next->tm_mday = now->tm_mday;
58	next->tm_hour = alrm->tm_hour;
59	next->tm_min = alrm->tm_min;
60	next->tm_sec = alrm->tm_sec;
61
62	rtc_tm_to_time(now, &now_time);
63	rtc_tm_to_time(next, &next_time);
64
65	if (next_time < now_time) {
66		/* Advance one day */
67		next_time += 60 * 60 * 24;
68		rtc_time_to_tm(next_time, next);
69	}
70}
71EXPORT_SYMBOL(rtc_next_alarm_time);
72
73static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm)
74{
75	memset(tm, 0, sizeof(struct rtc_time));
76	return ops->read_time(tm);
77}
78
79static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm)
80{
81	int ret;
82
83	ret = rtc_valid_tm(tm);
84	if (ret == 0)
85		ret = ops->set_time(tm);
86
87	return ret;
88}
89
90static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
91{
92	int ret = -EINVAL;
93	if (ops->read_alarm) {
94		memset(alrm, 0, sizeof(struct rtc_wkalrm));
95		ret = ops->read_alarm(alrm);
96	}
97	return ret;
98}
99
100static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
101{
102	int ret = -EINVAL;
103	if (ops->set_alarm)
104		ret = ops->set_alarm(alrm);
105	return ret;
106}
107
108void rtc_update(unsigned long num, unsigned long events)
109{
110	spin_lock(&rtc_lock);
111	rtc_irq_data = (rtc_irq_data + (num << 8)) | events;
112	spin_unlock(&rtc_lock);
113
114	wake_up_interruptible(&rtc_wait);
115	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
116}
117EXPORT_SYMBOL(rtc_update);
118
119
120static ssize_t
121rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
122{
123	DECLARE_WAITQUEUE(wait, current);
124	unsigned long data;
125	ssize_t ret;
126
127	if (count < sizeof(unsigned long))
128		return -EINVAL;
129
130	add_wait_queue(&rtc_wait, &wait);
131	do {
132		__set_current_state(TASK_INTERRUPTIBLE);
133
134		spin_lock_irq(&rtc_lock);
135		data = rtc_irq_data;
136		rtc_irq_data = 0;
137		spin_unlock_irq(&rtc_lock);
138
139		if (data != 0) {
140			ret = 0;
141			break;
142		}
143		if (file->f_flags & O_NONBLOCK) {
144			ret = -EAGAIN;
145			break;
146		}
147		if (signal_pending(current)) {
148			ret = -ERESTARTSYS;
149			break;
150		}
151		schedule();
152	} while (1);
153	set_current_state(TASK_RUNNING);
154	remove_wait_queue(&rtc_wait, &wait);
155
156	if (ret == 0) {
157		ret = put_user(data, (unsigned long __user *)buf);
158		if (ret == 0)
159			ret = sizeof(unsigned long);
160	}
161	return ret;
162}
163
164static unsigned int rtc_poll(struct file *file, poll_table *wait)
165{
166	unsigned long data;
167
168	poll_wait(file, &rtc_wait, wait);
169
170	spin_lock_irq(&rtc_lock);
171	data = rtc_irq_data;
172	spin_unlock_irq(&rtc_lock);
173
174	return data != 0 ? POLLIN | POLLRDNORM : 0;
175}
176
177static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
178		     unsigned long arg)
179{
180	struct rtc_ops *ops = file->private_data;
181	struct rtc_time tm;
182	struct rtc_wkalrm alrm;
183	void __user *uarg = (void __user *)arg;
184	int ret = -EINVAL;
185
186	switch (cmd) {
187	case RTC_ALM_READ:
188		ret = rtc_arm_read_alarm(ops, &alrm);
189		if (ret)
190			break;
191		ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
192		if (ret)
193			ret = -EFAULT;
194		break;
195
196	case RTC_ALM_SET:
197		ret = copy_from_user(&alrm.time, uarg, sizeof(tm));
198		if (ret) {
199			ret = -EFAULT;
200			break;
201		}
202		alrm.enabled = 0;
203		alrm.pending = 0;
204		alrm.time.tm_mday = -1;
205		alrm.time.tm_mon = -1;
206		alrm.time.tm_year = -1;
207		alrm.time.tm_wday = -1;
208		alrm.time.tm_yday = -1;
209		alrm.time.tm_isdst = -1;
210		ret = rtc_arm_set_alarm(ops, &alrm);
211		break;
212
213	case RTC_RD_TIME:
214		ret = rtc_arm_read_time(ops, &tm);
215		if (ret)
216			break;
217		ret = copy_to_user(uarg, &tm, sizeof(tm));
218		if (ret)
219			ret = -EFAULT;
220		break;
221
222	case RTC_SET_TIME:
223		if (!capable(CAP_SYS_TIME)) {
224			ret = -EACCES;
225			break;
226		}
227		ret = copy_from_user(&tm, uarg, sizeof(tm));
228		if (ret) {
229			ret = -EFAULT;
230			break;
231		}
232		ret = rtc_arm_set_time(ops, &tm);
233		break;
234
235	case RTC_EPOCH_SET:
236#ifndef rtc_epoch
237		/*
238		 * There were no RTC clocks before 1900.
239		 */
240		if (arg < 1900) {
241			ret = -EINVAL;
242			break;
243		}
244		if (!capable(CAP_SYS_TIME)) {
245			ret = -EACCES;
246			break;
247		}
248		rtc_epoch = arg;
249		ret = 0;
250#endif
251		break;
252
253	case RTC_EPOCH_READ:
254		ret = put_user(rtc_epoch, (unsigned long __user *)uarg);
255		break;
256
257	case RTC_WKALM_SET:
258		ret = copy_from_user(&alrm, uarg, sizeof(alrm));
259		if (ret) {
260			ret = -EFAULT;
261			break;
262		}
263		ret = rtc_arm_set_alarm(ops, &alrm);
264		break;
265
266	case RTC_WKALM_RD:
267		ret = rtc_arm_read_alarm(ops, &alrm);
268		if (ret)
269			break;
270		ret = copy_to_user(uarg, &alrm, sizeof(alrm));
271		if (ret)
272			ret = -EFAULT;
273		break;
274
275	default:
276		if (ops->ioctl)
277			ret = ops->ioctl(cmd, arg);
278		break;
279	}
280	return ret;
281}
282
283static int rtc_open(struct inode *inode, struct file *file)
284{
285	int ret;
286
287	mutex_lock(&rtc_mutex);
288
289	if (rtc_inuse) {
290		ret = -EBUSY;
291	} else if (!rtc_ops || !try_module_get(rtc_ops->owner)) {
292		ret = -ENODEV;
293	} else {
294		file->private_data = rtc_ops;
295
296		ret = rtc_ops->open ? rtc_ops->open() : 0;
297		if (ret == 0) {
298			spin_lock_irq(&rtc_lock);
299			rtc_irq_data = 0;
300			spin_unlock_irq(&rtc_lock);
301
302			rtc_inuse = 1;
303		}
304	}
305	mutex_unlock(&rtc_mutex);
306
307	return ret;
308}
309
310static int rtc_release(struct inode *inode, struct file *file)
311{
312	struct rtc_ops *ops = file->private_data;
313
314	if (ops->release)
315		ops->release();
316
317	spin_lock_irq(&rtc_lock);
318	rtc_irq_data = 0;
319	spin_unlock_irq(&rtc_lock);
320
321	module_put(rtc_ops->owner);
322	rtc_inuse = 0;
323
324	return 0;
325}
326
327static int rtc_fasync(int fd, struct file *file, int on)
328{
329	return fasync_helper(fd, file, on, &rtc_async_queue);
330}
331
332static const struct file_operations rtc_fops = {
333	.owner		= THIS_MODULE,
334	.llseek		= no_llseek,
335	.read		= rtc_read,
336	.poll		= rtc_poll,
337	.ioctl		= rtc_ioctl,
338	.open		= rtc_open,
339	.release	= rtc_release,
340	.fasync		= rtc_fasync,
341};
342
343static struct miscdevice rtc_miscdev = {
344	.minor		= RTC_MINOR,
345	.name		= "rtc",
346	.fops		= &rtc_fops,
347};
348
349
350static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
351{
352	struct rtc_ops *ops = data;
353	struct rtc_wkalrm alrm;
354	struct rtc_time tm;
355	char *p = page;
356
357	if (rtc_arm_read_time(ops, &tm) == 0) {
358		p += sprintf(p,
359			"rtc_time\t: %02d:%02d:%02d\n"
360			"rtc_date\t: %04d-%02d-%02d\n"
361			"rtc_epoch\t: %04lu\n",
362			tm.tm_hour, tm.tm_min, tm.tm_sec,
363			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
364			rtc_epoch);
365	}
366
367	if (rtc_arm_read_alarm(ops, &alrm) == 0) {
368		p += sprintf(p, "alrm_time\t: ");
369		if ((unsigned int)alrm.time.tm_hour <= 24)
370			p += sprintf(p, "%02d:", alrm.time.tm_hour);
371		else
372			p += sprintf(p, "**:");
373		if ((unsigned int)alrm.time.tm_min <= 59)
374			p += sprintf(p, "%02d:", alrm.time.tm_min);
375		else
376			p += sprintf(p, "**:");
377		if ((unsigned int)alrm.time.tm_sec <= 59)
378			p += sprintf(p, "%02d\n", alrm.time.tm_sec);
379		else
380			p += sprintf(p, "**\n");
381
382		p += sprintf(p, "alrm_date\t: ");
383		if ((unsigned int)alrm.time.tm_year <= 200)
384			p += sprintf(p, "%04d-", alrm.time.tm_year + 1900);
385		else
386			p += sprintf(p, "****-");
387		if ((unsigned int)alrm.time.tm_mon <= 11)
388			p += sprintf(p, "%02d-", alrm.time.tm_mon + 1);
389		else
390			p += sprintf(p, "**-");
391		if ((unsigned int)alrm.time.tm_mday <= 31)
392			p += sprintf(p, "%02d\n", alrm.time.tm_mday);
393		else
394			p += sprintf(p, "**\n");
395		p += sprintf(p, "alrm_wakeup\t: %s\n",
396			     alrm.enabled ? "yes" : "no");
397		p += sprintf(p, "alrm_pending\t: %s\n",
398			     alrm.pending ? "yes" : "no");
399	}
400
401	if (ops->proc)
402		p += ops->proc(p);
403
404	return p - page;
405}
406
407int register_rtc(struct rtc_ops *ops)
408{
409	int ret = -EBUSY;
410
411	mutex_lock(&rtc_mutex);
412	if (rtc_ops == NULL) {
413		rtc_ops = ops;
414
415		ret = misc_register(&rtc_miscdev);
416		if (ret == 0)
417			create_proc_read_entry("driver/rtc", 0, NULL,
418					       rtc_read_proc, ops);
419	}
420	mutex_unlock(&rtc_mutex);
421
422	return ret;
423}
424EXPORT_SYMBOL(register_rtc);
425
426void unregister_rtc(struct rtc_ops *rtc)
427{
428	mutex_lock(&rtc_mutex);
429	if (rtc == rtc_ops) {
430		remove_proc_entry("driver/rtc", NULL);
431		misc_deregister(&rtc_miscdev);
432		rtc_ops = NULL;
433	}
434	mutex_unlock(&rtc_mutex);
435}
436EXPORT_SYMBOL(unregister_rtc);
437