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