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