This source file includes following definitions.
- time_init
- sys_time
- sys_stime
- do_gettimeoffset
- do_gettimeofday
- sys_gettimeofday
- warp_clock
- sys_settimeofday
- sys_adjtimex
- set_rtc_mmss
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <linux/config.h>
20 #include <linux/errno.h>
21 #include <linux/sched.h>
22 #include <linux/kernel.h>
23 #include <linux/param.h>
24 #include <linux/string.h>
25
26 #include <asm/segment.h>
27 #include <asm/io.h>
28
29 #include <linux/mc146818rtc.h>
30 #define RTC_ALWAYS_BCD 1
31
32 #include <linux/timex.h>
33 extern struct timeval xtime;
34
35 #include <linux/mktime.h>
36 extern long kernel_mktime(struct mktime * time);
37
38 void time_init(void)
39 {
40 struct mktime time;
41 int i;
42
43
44
45
46
47
48
49 for (i = 0 ; i < 1000000 ; i++)
50 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
51 break;
52 for (i = 0 ; i < 1000000 ; i++)
53 if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
54 break;
55 do {
56 time.sec = CMOS_READ(RTC_SECONDS);
57 time.min = CMOS_READ(RTC_MINUTES);
58 time.hour = CMOS_READ(RTC_HOURS);
59 time.day = CMOS_READ(RTC_DAY_OF_MONTH);
60 time.mon = CMOS_READ(RTC_MONTH);
61 time.year = CMOS_READ(RTC_YEAR);
62 } while (time.sec != CMOS_READ(RTC_SECONDS));
63 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
64 {
65 BCD_TO_BIN(time.sec);
66 BCD_TO_BIN(time.min);
67 BCD_TO_BIN(time.hour);
68 BCD_TO_BIN(time.day);
69 BCD_TO_BIN(time.mon);
70 BCD_TO_BIN(time.year);
71 }
72 time.mon--;
73 xtime.tv_sec = kernel_mktime(&time);
74 }
75
76
77
78
79 struct timezone sys_tz = { 0, 0};
80
81 asmlinkage int sys_time(long * tloc)
82 {
83 int i, error;
84
85 i = CURRENT_TIME;
86 if (tloc) {
87 error = verify_area(VERIFY_WRITE, tloc, 4);
88 if (error)
89 return error;
90 put_fs_long(i,(unsigned long *)tloc);
91 }
92 return i;
93 }
94
95 asmlinkage int sys_stime(long * tptr)
96 {
97 if (!suser())
98 return -EPERM;
99 cli();
100 xtime.tv_sec = get_fs_long((unsigned long *) tptr);
101 xtime.tv_usec = 0;
102 time_status = TIME_BAD;
103 time_maxerror = 0x70000000;
104 time_esterror = 0x70000000;
105 sti();
106 return 0;
107 }
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141 #define TICK_SIZE tick
142
143 static inline unsigned long do_gettimeoffset(void)
144 {
145 int count;
146 unsigned long offset = 0;
147
148
149 outb_p(0x00, 0x43);
150 count = inb_p(0x40);
151 count |= inb(0x40) << 8;
152
153 if (count > (LATCH - LATCH/100)) {
154
155 outb_p(0x0a, 0x20);
156 if (inb(0x20) & 1)
157 offset = TICK_SIZE;
158 }
159 count = ((LATCH-1) - count) * TICK_SIZE;
160 count = (count + LATCH/2) / LATCH;
161 return offset + count;
162 }
163
164
165
166
167 static inline void do_gettimeofday(struct timeval *tv)
168 {
169 #ifdef __i386__
170 cli();
171 *tv = xtime;
172 tv->tv_usec += do_gettimeoffset();
173 if (tv->tv_usec >= 1000000) {
174 tv->tv_usec -= 1000000;
175 tv->tv_sec++;
176 }
177 sti();
178 #else
179 cli();
180 *tv = xtime;
181 sti();
182 #endif
183 }
184
185 asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
186 {
187 int error;
188
189 if (tv) {
190 struct timeval ktv;
191 error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
192 if (error)
193 return error;
194 do_gettimeofday(&ktv);
195 put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
196 put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
197 }
198 if (tz) {
199 error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
200 if (error)
201 return error;
202 put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
203 put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
204 }
205 return 0;
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 inline static void warp_clock(void)
225 {
226 cli();
227 xtime.tv_sec += sys_tz.tz_minuteswest * 60;
228 sti();
229 }
230
231
232
233
234
235
236
237
238
239
240 asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
241 {
242 static int firsttime = 1;
243
244 if (!suser())
245 return -EPERM;
246 if (tz) {
247 sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
248 sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
249 if (firsttime) {
250 firsttime = 0;
251 if (!tv)
252 warp_clock();
253 }
254 }
255 if (tv) {
256 int sec, usec;
257
258 sec = get_fs_long((unsigned long *)tv);
259 usec = get_fs_long(((unsigned long *)tv)+1);
260
261 cli();
262
263
264
265
266
267
268 usec -= do_gettimeoffset();
269
270 if (usec < 0)
271 {
272 usec += 1000000;
273 sec--;
274 }
275 xtime.tv_sec = sec;
276 xtime.tv_usec = usec;
277 time_status = TIME_BAD;
278 time_maxerror = 0x70000000;
279 time_esterror = 0x70000000;
280 sti();
281 }
282 return 0;
283 }
284
285
286
287
288 asmlinkage int sys_adjtimex(struct timex *txc_p)
289 {
290 long ltemp, mtemp, save_adjust;
291 int error;
292
293
294 struct timex txc;
295
296 error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
297 if (error)
298 return error;
299
300
301
302
303
304 memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
305
306
307 if (txc.mode && !suser())
308 return -EPERM;
309
310
311
312
313 if (txc.mode & ADJ_OFFSET)
314
315 if (txc.offset <= -(1 << (31 - SHIFT_UPDATE))
316 || txc.offset >= (1 << (31 - SHIFT_UPDATE)))
317 return -EINVAL;
318
319
320 if (txc.mode & ADJ_STATUS)
321 if (txc.status < TIME_OK || txc.status > TIME_BAD)
322 return -EINVAL;
323
324 cli();
325
326
327 save_adjust = time_adjust;
328
329
330 if (txc.mode)
331 {
332 if (time_status == TIME_BAD)
333 time_status = TIME_OK;
334
335 if (txc.mode & ADJ_STATUS)
336 time_status = txc.status;
337
338 if (txc.mode & ADJ_FREQUENCY)
339 time_freq = txc.frequency;
340
341 if (txc.mode & ADJ_MAXERROR)
342 time_maxerror = txc.maxerror;
343
344 if (txc.mode & ADJ_ESTERROR)
345 time_esterror = txc.esterror;
346
347 if (txc.mode & ADJ_TIMECONST)
348 time_constant = txc.time_constant;
349
350 if (txc.mode & ADJ_OFFSET)
351 if (txc.mode == ADJ_OFFSET_SINGLESHOT)
352 {
353 time_adjust = txc.offset;
354 }
355 else
356 {
357 time_offset = txc.offset << SHIFT_UPDATE;
358 mtemp = xtime.tv_sec - time_reftime;
359 time_reftime = xtime.tv_sec;
360 if (mtemp > (MAXSEC+2) || mtemp < 0)
361 mtemp = 0;
362
363 if (txc.offset < 0)
364 time_freq -= (-txc.offset * mtemp) >>
365 (time_constant + time_constant);
366 else
367 time_freq += (txc.offset * mtemp) >>
368 (time_constant + time_constant);
369
370 ltemp = time_tolerance << SHIFT_KF;
371
372 if (time_freq > ltemp)
373 time_freq = ltemp;
374 else if (time_freq < -ltemp)
375 time_freq = -ltemp;
376 }
377 }
378 txc.offset = save_adjust;
379 txc.frequency = time_freq;
380 txc.maxerror = time_maxerror;
381 txc.esterror = time_esterror;
382 txc.status = time_status;
383 txc.time_constant = time_constant;
384 txc.precision = time_precision;
385 txc.tolerance = time_tolerance;
386 txc.time = xtime;
387
388 sti();
389
390 memcpy_tofs(txc_p, &txc, sizeof(struct timex));
391 return time_status;
392 }
393
394 int set_rtc_mmss(unsigned long nowtime)
395 {
396 int retval = 0;
397 short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
398 unsigned char save_control, save_freq_select, cmos_minutes;
399
400 save_control = CMOS_READ(RTC_CONTROL);
401 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
402
403 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
404 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
405
406 cmos_minutes = CMOS_READ(RTC_MINUTES);
407 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
408 BCD_TO_BIN(cmos_minutes);
409
410
411
412
413
414
415 if (((cmos_minutes < real_minutes) ?
416 (real_minutes - cmos_minutes) :
417 (cmos_minutes - real_minutes)) < 30)
418 {
419 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
420 {
421 BIN_TO_BCD(real_seconds);
422 BIN_TO_BCD(real_minutes);
423 }
424 CMOS_WRITE(real_seconds,RTC_SECONDS);
425 CMOS_WRITE(real_minutes,RTC_MINUTES);
426 }
427 else
428 retval = -1;
429
430 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
431 CMOS_WRITE(save_control, RTC_CONTROL);
432 return retval;
433 }