1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#define RTC_VERSION "1.0"
41
42#include <linux/config.h>
43#include <linux/module.h>
44#include <linux/kernel.h>
45#include <linux/types.h>
46#include <linux/miscdevice.h>
47#include <linux/fcntl.h>
48#include <linux/init.h>
49#include <linux/poll.h>
50#include <linux/proc_fs.h>
51#include <linux/spinlock.h>
52
53#include <asm/io.h>
54#include <asm/uaccess.h>
55#include <asm/system.h>
56
57
58
59
60#if !defined(CONFIG_MIPS) || !defined(CONFIG_NEW_TIME_C)
61#error "This driver is for MIPS machines with CONFIG_NEW_TIME_C defined"
62#endif
63
64#include <asm/time.h>
65
66static unsigned long rtc_status = 0;
67
68static int rtc_read_proc(char *page, char **start, off_t off,
69 int count, int *eof, void *data);
70
71
72#define RTC_IS_OPEN 0x01
73
74static spinlock_t rtc_lock;
75
76static int
77rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
78 unsigned long arg)
79{
80 struct rtc_time rtc_tm;
81 ulong curr_time;
82
83 switch (cmd) {
84 case RTC_RD_TIME:
85 memset(&rtc_tm, 0, sizeof(struct rtc_time));
86 curr_time = rtc_get_time();
87 to_tm(curr_time, &rtc_tm);
88 rtc_tm.tm_year -= 1900;
89 return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ?
90 -EFAULT : 0;
91 case RTC_SET_TIME:
92 if (!capable(CAP_SYS_TIME))
93 return -EACCES;
94
95 if (copy_from_user(&rtc_tm,
96 (struct rtc_time *) arg,
97 sizeof(struct rtc_time)))
98 return -EFAULT;
99
100 curr_time = mktime(rtc_tm.tm_year + 1900,
101 rtc_tm.tm_mon + 1,
102 rtc_tm.tm_mday,
103 rtc_tm.tm_hour,
104 rtc_tm.tm_min,
105 rtc_tm.tm_sec);
106 return rtc_set_time(curr_time);
107 default:
108 return -EINVAL;
109 }
110}
111
112
113
114static int rtc_open(struct inode *inode, struct file *file)
115{
116 spin_lock_irq(&rtc_lock);
117
118 if (rtc_status & RTC_IS_OPEN) {
119 spin_unlock_irq(&rtc_lock);
120 return -EBUSY;
121 }
122
123 rtc_status |= RTC_IS_OPEN;
124
125 spin_unlock_irq(&rtc_lock);
126 return 0;
127}
128
129static int rtc_release(struct inode *inode, struct file *file)
130{
131 spin_lock_irq(&rtc_lock);
132 rtc_status &= ~RTC_IS_OPEN;
133 spin_unlock_irq(&rtc_lock);
134 return 0;
135}
136
137
138
139
140
141static struct file_operations rtc_fops = {
142 owner:THIS_MODULE,
143 llseek:no_llseek,
144 ioctl:rtc_ioctl,
145 open:rtc_open,
146 release:rtc_release,
147};
148
149static struct miscdevice rtc_dev = {
150 RTC_MINOR,
151 "rtc",
152 &rtc_fops
153};
154
155static int __init rtc_init(void)
156{
157
158 misc_register(&rtc_dev);
159 create_proc_read_entry("driver/rtc", 0, 0, rtc_read_proc, NULL);
160
161 printk(KERN_INFO "Generic MIPS RTC Driver v" RTC_VERSION "\n");
162
163 return 0;
164}
165
166static void __exit rtc_exit(void)
167{
168 remove_proc_entry("driver/rtc", NULL);
169 misc_deregister(&rtc_dev);
170
171}
172
173module_init(rtc_init);
174module_exit(rtc_exit);
175EXPORT_NO_SYMBOLS;
176
177
178
179
180
181static int rtc_proc_output(char *buf)
182{
183 char *p;
184 struct rtc_time tm;
185 unsigned long curr_time;
186
187 curr_time = rtc_get_time();
188 to_tm(curr_time, &tm);
189
190 p = buf;
191
192
193
194
195
196 p += sprintf(p,
197 "rtc_time\t: %02d:%02d:%02d\n"
198 "rtc_date\t: %04d-%02d-%02d\n"
199 "rtc_epoch\t: %04lu\n",
200 tm.tm_hour, tm.tm_min, tm.tm_sec,
201 tm.tm_year, tm.tm_mon + 1, tm.tm_mday, 0L);
202
203 return p - buf;
204}
205
206static int rtc_read_proc(char *page, char **start, off_t off,
207 int count, int *eof, void *data)
208{
209 int len = rtc_proc_output(page);
210 if (len <= off + count)
211 *eof = 1;
212 *start = page + off;
213 len -= off;
214 if (len > count)
215 len = count;
216 if (len < 0)
217 len = 0;
218 return len;
219}
220
221MODULE_AUTHOR("Jun Sun");
222MODULE_LICENSE("GPL");
223