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