This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / arm / common / rtctime.c
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/device.h>
21
22 #include <asm/rtc.h>
23 #include <asm/semaphore.h>
24
25 static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
26 static struct fasync_struct *rtc_async_queue;
27
28 /*
29  * rtc_lock protects rtc_irq_data
30  */
31 static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
32 static unsigned long rtc_irq_data;
33
34 /*
35  * rtc_sem protects rtc_inuse and rtc_ops
36  */
37 static DECLARE_MUTEX(rtc_sem);
38 static unsigned long rtc_inuse;
39 static struct rtc_ops *rtc_ops;
40
41 #define rtc_epoch 1900UL
42
43 static const unsigned char days_in_month[] = {
44         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
45 };
46
47 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
48 #define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
49
50 static int month_days(unsigned int month, unsigned int year)
51 {
52         return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
53 }
54
55 /*
56  * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
57  */
58 void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
59 {
60         int days, month, year;
61
62         days = time / 86400;
63         time -= days * 86400;
64
65         tm->tm_wday = (days + 4) % 7;
66
67         year = 1970 + days / 365;
68         days -= (year - 1970) * 365
69                 + LEAPS_THRU_END_OF(year - 1)
70                 - LEAPS_THRU_END_OF(1970 - 1);
71         if (days < 0) {
72                 year -= 1;
73                 days += 365 + LEAP_YEAR(year);
74         }
75         tm->tm_year = year - 1900;
76         tm->tm_yday = days + 1;
77
78         for (month = 0; month < 11; month++) {
79                 int newdays;
80
81                 newdays = days - month_days(month, year);
82                 if (newdays < 0)
83                         break;
84                 days = newdays;
85         }
86         tm->tm_mon = month;
87         tm->tm_mday = days + 1;
88
89         tm->tm_hour = time / 3600;
90         time -= tm->tm_hour * 3600;
91         tm->tm_min = time / 60;
92         tm->tm_sec = time - tm->tm_min * 60;
93 }
94 EXPORT_SYMBOL(rtc_time_to_tm);
95
96 /*
97  * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
98  */
99 int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
100 {
101         unsigned int yrs = tm->tm_year + 1900;
102
103         *time = 0;
104
105         if (yrs < 1970 ||
106             tm->tm_mon >= 12 ||
107             tm->tm_mday < 1 ||
108             tm->tm_mday > month_days(tm->tm_mon, yrs) ||
109             tm->tm_hour >= 24 ||
110             tm->tm_min >= 60 ||
111             tm->tm_sec >= 60)
112                 return -EINVAL;
113
114         *time = mktime(yrs, tm->tm_mon + 1, tm->tm_mday,
115                        tm->tm_hour, tm->tm_min, tm->tm_sec);
116
117         return 0;
118 }
119 EXPORT_SYMBOL(rtc_tm_to_time);
120
121 /*
122  * Calculate the next alarm time given the requested alarm time mask
123  * and the current time.
124  *
125  * FIXME: for now, we just copy the alarm time because we're lazy (and
126  * is therefore buggy - setting a 10am alarm at 8pm will not result in
127  * the alarm triggering.)
128  */
129 void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
130 {
131         next->tm_year = now->tm_year;
132         next->tm_mon = now->tm_mon;
133         next->tm_mday = now->tm_mday;
134         next->tm_hour = alrm->tm_hour;
135         next->tm_min = alrm->tm_min;
136         next->tm_sec = alrm->tm_sec;
137 }
138
139 static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
140 {
141         memset(tm, 0, sizeof(struct rtc_time));
142         ops->read_time(tm);
143 }
144
145 static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
146 {
147         return ops->set_time(tm);
148 }
149
150 static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
151 {
152         int ret = -EINVAL;
153         if (ops->read_alarm) {
154                 memset(alrm, 0, sizeof(struct rtc_wkalrm));
155                 ops->read_alarm(alrm);
156                 ret = 0;
157         }
158         return ret;
159 }
160
161 static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
162 {
163         int ret = -EINVAL;
164         if (ops->set_alarm)
165                 ret = ops->set_alarm(alrm);
166         return ret;
167 }
168
169 void rtc_update(unsigned long num, unsigned long events)
170 {
171         spin_lock(&rtc_lock);
172         rtc_irq_data = (rtc_irq_data + (num << 8)) | events;
173         spin_unlock(&rtc_lock);
174
175         wake_up_interruptible(&rtc_wait);
176         kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
177 }
178 EXPORT_SYMBOL(rtc_update);
179
180
181 static ssize_t
182 rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
183 {
184         DECLARE_WAITQUEUE(wait, current);
185         unsigned long data;
186         ssize_t ret;
187
188         if (count < sizeof(unsigned long))
189                 return -EINVAL;
190
191         add_wait_queue(&rtc_wait, &wait);
192         do {
193                 __set_current_state(TASK_INTERRUPTIBLE);
194
195                 spin_lock_irq(&rtc_lock);
196                 data = rtc_irq_data;
197                 rtc_irq_data = 0;
198                 spin_unlock_irq(&rtc_lock);
199
200                 if (data != 0) {
201                         ret = 0;
202                         break;
203                 }
204                 if (file->f_flags & O_NONBLOCK) {
205                         ret = -EAGAIN;
206                         break;
207                 }
208                 if (signal_pending(current)) {
209                         ret = -ERESTARTSYS;
210                         break;
211                 }
212                 schedule();
213         } while (1);
214         set_current_state(TASK_RUNNING);
215         remove_wait_queue(&rtc_wait, &wait);
216
217         if (ret == 0) {
218                 ret = put_user(data, (unsigned long __user *)buf);
219                 if (ret == 0)
220                         ret = sizeof(unsigned long);
221         }
222         return ret;
223 }
224
225 static unsigned int rtc_poll(struct file *file, poll_table *wait)
226 {
227         unsigned long data;
228
229         poll_wait(file, &rtc_wait, wait);
230
231         spin_lock_irq(&rtc_lock);
232         data = rtc_irq_data;
233         spin_unlock_irq(&rtc_lock);
234
235         return data != 0 ? POLLIN | POLLRDNORM : 0;
236 }
237
238 static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
239                      unsigned long arg)
240 {
241         struct rtc_ops *ops = file->private_data;
242         struct rtc_time tm;
243         struct rtc_wkalrm alrm;
244         void __user *uarg = (void __user *)arg;
245         int ret = -EINVAL;
246
247         switch (cmd) {
248         case RTC_ALM_READ:
249                 ret = rtc_read_alarm(ops, &alrm);
250                 if (ret)
251                         break;
252                 ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
253                 if (ret)
254                         ret = -EFAULT;
255                 break;
256
257         case RTC_ALM_SET:
258                 ret = copy_from_user(&alrm.time, uarg, sizeof(tm));
259                 if (ret) {
260                         ret = -EFAULT;
261                         break;
262                 }
263                 alrm.enabled = 0;
264                 alrm.pending = 0;
265                 alrm.time.tm_mday = -1;
266                 alrm.time.tm_mon = -1;
267                 alrm.time.tm_year = -1;
268                 alrm.time.tm_wday = -1;
269                 alrm.time.tm_yday = -1;
270                 alrm.time.tm_isdst = -1;
271                 ret = rtc_set_alarm(ops, &alrm);
272                 break;
273
274         case RTC_RD_TIME:
275                 rtc_read_time(ops, &tm);
276                 ret = copy_to_user(uarg, &tm, sizeof(tm));
277                 if (ret)
278                         ret = -EFAULT;
279                 break;
280
281         case RTC_SET_TIME:
282                 if (!capable(CAP_SYS_TIME)) {
283                         ret = -EACCES;
284                         break;
285                 }
286                 ret = copy_from_user(&tm, uarg, sizeof(tm));
287                 if (ret) {
288                         ret = -EFAULT;
289                         break;
290                 }
291                 ret = rtc_set_time(ops, &tm);
292                 break;
293
294         case RTC_EPOCH_SET:
295 #ifndef rtc_epoch
296                 /*
297                  * There were no RTC clocks before 1900.
298                  */
299                 if (arg < 1900) {
300                         ret = -EINVAL;
301                         break;
302                 }
303                 if (!capable(CAP_SYS_TIME)) {
304                         ret = -EACCES;
305                         break;
306                 }
307                 rtc_epoch = arg;
308                 ret = 0;
309 #endif
310                 break;
311
312         case RTC_EPOCH_READ:
313                 ret = put_user(rtc_epoch, (unsigned long __user *)uarg);
314                 break;
315
316         case RTC_WKALM_SET:
317                 ret = copy_from_user(&alrm, uarg, sizeof(alrm));
318                 if (ret) {
319                         ret = -EFAULT;
320                         break;
321                 }
322                 ret = rtc_set_alarm(ops, &alrm);
323                 break;
324
325         case RTC_WKALM_RD:
326                 ret = rtc_read_alarm(ops, &alrm);
327                 if (ret)
328                         break;
329                 ret = copy_to_user(uarg, &alrm, sizeof(alrm));
330                 if (ret)
331                         ret = -EFAULT;
332                 break;
333
334         default:
335                 if (ops->ioctl)
336                         ret = ops->ioctl(cmd, arg);
337                 break;
338         }
339         return ret;
340 }
341
342 static int rtc_open(struct inode *inode, struct file *file)
343 {
344         int ret;
345
346         down(&rtc_sem);
347
348         if (rtc_inuse) {
349                 ret = -EBUSY;
350         } else if (!rtc_ops || !try_module_get(rtc_ops->owner)) {
351                 ret = -ENODEV;
352         } else {
353                 file->private_data = rtc_ops;
354
355                 ret = rtc_ops->open ? rtc_ops->open() : 0;
356                 if (ret == 0) {
357                         spin_lock_irq(&rtc_lock);
358                         rtc_irq_data = 0;
359                         spin_unlock_irq(&rtc_lock);
360
361                         rtc_inuse = 1;
362                 }
363         }
364         up(&rtc_sem);
365
366         return ret;
367 }
368
369 static int rtc_release(struct inode *inode, struct file *file)
370 {
371         struct rtc_ops *ops = file->private_data;
372
373         if (ops->release)
374                 ops->release();
375
376         spin_lock_irq(&rtc_lock);
377         rtc_irq_data = 0;
378         spin_unlock_irq(&rtc_lock);
379
380         module_put(rtc_ops->owner);
381         rtc_inuse = 0;
382
383         return 0;
384 }
385
386 static int rtc_fasync(int fd, struct file *file, int on)
387 {
388         return fasync_helper(fd, file, on, &rtc_async_queue);
389 }
390
391 static struct file_operations rtc_fops = {
392         .owner          = THIS_MODULE,
393         .llseek         = no_llseek,
394         .read           = rtc_read,
395         .poll           = rtc_poll,
396         .ioctl          = rtc_ioctl,
397         .open           = rtc_open,
398         .release        = rtc_release,
399         .fasync         = rtc_fasync,
400 };
401
402 static struct miscdevice rtc_miscdev = {
403         .minor          = RTC_MINOR,
404         .name           = "rtc",
405         .fops           = &rtc_fops,
406 };
407
408
409 static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
410 {
411         struct rtc_ops *ops = data;
412         struct rtc_wkalrm alrm;
413         struct rtc_time tm;
414         char *p = page;
415         int len;
416
417         rtc_read_time(ops, &tm);
418
419         p += sprintf(p,
420                 "rtc_time\t: %02d:%02d:%02d\n"
421                 "rtc_date\t: %04d-%02d-%02d\n"
422                 "rtc_epoch\t: %04lu\n",
423                 tm.tm_hour, tm.tm_min, tm.tm_sec,
424                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
425                 rtc_epoch);
426
427         if (rtc_read_alarm(ops, &alrm) == 0) {
428                 p += sprintf(p, "alrm_time\t: ");
429                 if ((unsigned int)alrm.time.tm_hour <= 24)
430                         p += sprintf(p, "%02d:", alrm.time.tm_hour);
431                 else
432                         p += sprintf(p, "**:");
433                 if ((unsigned int)alrm.time.tm_min <= 59)
434                         p += sprintf(p, "%02d:", alrm.time.tm_min);
435                 else
436                         p += sprintf(p, "**:");
437                 if ((unsigned int)alrm.time.tm_sec <= 59)
438                         p += sprintf(p, "%02d\n", alrm.time.tm_sec);
439                 else
440                         p += sprintf(p, "**\n");
441
442                 p += sprintf(p, "alrm_date\t: ");
443                 if ((unsigned int)alrm.time.tm_year <= 200)
444                         p += sprintf(p, "%04d-", alrm.time.tm_year + 1900);
445                 else
446                         p += sprintf(p, "****-");
447                 if ((unsigned int)alrm.time.tm_mon <= 11)
448                         p += sprintf(p, "%02d-", alrm.time.tm_mon + 1);
449                 else
450                         p += sprintf(p, "**-");
451                 if ((unsigned int)alrm.time.tm_mday <= 31)
452                         p += sprintf(p, "%02d\n", alrm.time.tm_mday);
453                 else
454                         p += sprintf(p, "**\n");
455                 p += sprintf(p, "alrm_wakeup\t: %s\n",
456                              alrm.enabled ? "yes" : "no");
457                 p += sprintf(p, "alrm_pending\t: %s\n",
458                              alrm.pending ? "yes" : "no");
459         }
460
461         if (ops->proc)
462                 p += ops->proc(p);
463
464         len = (p - page) - off;
465         if (len < 0)
466                 len = 0;
467         *eof = len <= count;
468         *start = page + off;
469
470         return len;
471 }
472
473 int register_rtc(struct rtc_ops *ops)
474 {
475         int ret = -EBUSY;
476
477         down(&rtc_sem);
478         if (rtc_ops == NULL) {
479                 rtc_ops = ops;
480
481                 ret = misc_register(&rtc_miscdev);
482                 if (ret == 0)
483                         create_proc_read_entry("driver/rtc", 0, NULL,
484                                                rtc_read_proc, ops);
485         }
486         up(&rtc_sem);
487
488         return ret;
489 }
490 EXPORT_SYMBOL(register_rtc);
491
492 void unregister_rtc(struct rtc_ops *rtc)
493 {
494         down(&rtc_sem);
495         if (rtc == rtc_ops) {
496                 remove_proc_entry("driver/rtc", NULL);
497                 misc_deregister(&rtc_miscdev);
498                 rtc_ops = NULL;
499         }
500         up(&rtc_sem);
501 }
502 EXPORT_SYMBOL(unregister_rtc);