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 #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 #if defined (__i386__) || defined (__mips__)
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 sti();
215 #else
216 cli();
217 *tv = xtime;
218 sti();
219 #endif
220 restore_flags(flags);
221 }
222
223 asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
224 {
225 int error;
226
227 if (tv) {
228 struct timeval ktv;
229 error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
230 if (error)
231 return error;
232 do_gettimeofday(&ktv);
233 put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
234 put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
235 }
236 if (tz) {
237 error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
238 if (error)
239 return error;
240 put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
241 put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
242 }
243 return 0;
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262 inline static void warp_clock(void)
263 {
264 cli();
265 xtime.tv_sec += sys_tz.tz_minuteswest * 60;
266 sti();
267 }
268
269
270
271
272
273
274
275
276
277
278 asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
279 {
280 static int firsttime = 1;
281 struct timeval new_tv;
282 struct timezone new_tz;
283
284 if (!suser())
285 return -EPERM;
286 if (tv) {
287 int error = verify_area(VERIFY_READ, tv, sizeof(*tv));
288 if (error)
289 return error;
290 memcpy_fromfs(&new_tv, tv, sizeof(*tv));
291 }
292 if (tz) {
293 int error = verify_area(VERIFY_READ, tz, sizeof(*tz));
294 if (error)
295 return error;
296 memcpy_fromfs(&new_tz, tz, sizeof(*tz));
297 }
298 if (tz) {
299 sys_tz = new_tz;
300 if (firsttime) {
301 firsttime = 0;
302 if (!tv)
303 warp_clock();
304 }
305 }
306 if (tv) {
307 cli();
308
309
310
311
312
313
314 new_tv.tv_usec -= do_gettimeoffset();
315
316 if (new_tv.tv_usec < 0) {
317 new_tv.tv_usec += 1000000;
318 new_tv.tv_sec--;
319 }
320
321 xtime = new_tv;
322 time_status = TIME_BAD;
323 time_maxerror = 0x70000000;
324 time_esterror = 0x70000000;
325 sti();
326 }
327 return 0;
328 }
329
330
331
332
333 asmlinkage int sys_adjtimex(struct timex *txc_p)
334 {
335 long ltemp, mtemp, save_adjust;
336 int error;
337
338
339 struct timex txc;
340
341 error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
342 if (error)
343 return error;
344
345
346
347
348
349 memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
350
351
352 if (txc.mode && !suser())
353 return -EPERM;
354
355
356
357
358 if (txc.mode != ADJ_OFFSET_SINGLESHOT && (txc.mode & ADJ_OFFSET))
359
360 if (txc.offset <= -(1 << (31 - SHIFT_UPDATE))
361 || txc.offset >= (1 << (31 - SHIFT_UPDATE)))
362 return -EINVAL;
363
364
365 if (txc.mode & ADJ_STATUS)
366 if (txc.status < TIME_OK || txc.status > TIME_BAD)
367 return -EINVAL;
368
369
370 if (txc.mode & ADJ_TICK)
371 if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
372 return -EINVAL;
373
374 cli();
375
376
377 save_adjust = time_adjust;
378
379
380 if (txc.mode)
381 {
382 if (time_status == TIME_BAD)
383 time_status = TIME_OK;
384
385 if (txc.mode & ADJ_STATUS)
386 time_status = txc.status;
387
388 if (txc.mode & ADJ_FREQUENCY)
389 time_freq = txc.frequency << (SHIFT_KF - 16);
390
391 if (txc.mode & ADJ_MAXERROR)
392 time_maxerror = txc.maxerror;
393
394 if (txc.mode & ADJ_ESTERROR)
395 time_esterror = txc.esterror;
396
397 if (txc.mode & ADJ_TIMECONST)
398 time_constant = txc.time_constant;
399
400 if (txc.mode & ADJ_OFFSET)
401 if (txc.mode == ADJ_OFFSET_SINGLESHOT)
402 {
403 time_adjust = txc.offset;
404 }
405 else
406 {
407 time_offset = txc.offset << SHIFT_UPDATE;
408 mtemp = xtime.tv_sec - time_reftime;
409 time_reftime = xtime.tv_sec;
410 if (mtemp > (MAXSEC+2) || mtemp < 0)
411 mtemp = 0;
412
413 if (txc.offset < 0)
414 time_freq -= (-txc.offset * mtemp) >>
415 (time_constant + time_constant);
416 else
417 time_freq += (txc.offset * mtemp) >>
418 (time_constant + time_constant);
419
420 ltemp = time_tolerance << SHIFT_KF;
421
422 if (time_freq > ltemp)
423 time_freq = ltemp;
424 else if (time_freq < -ltemp)
425 time_freq = -ltemp;
426 }
427 if (txc.mode & ADJ_TICK)
428 tick = txc.tick;
429
430 }
431 txc.offset = save_adjust;
432 txc.frequency = ((time_freq+1) >> (SHIFT_KF - 16));
433 txc.maxerror = time_maxerror;
434 txc.esterror = time_esterror;
435 txc.status = time_status;
436 txc.time_constant = time_constant;
437 txc.precision = time_precision;
438 txc.tolerance = time_tolerance;
439 txc.time = xtime;
440 txc.tick = tick;
441
442 sti();
443
444 memcpy_tofs(txc_p, &txc, sizeof(struct timex));
445 return time_status;
446 }
447
448 int set_rtc_mmss(unsigned long nowtime)
449 {
450 int retval = 0;
451 int real_seconds, real_minutes, cmos_minutes;
452 unsigned char save_control, save_freq_select;
453
454 save_control = CMOS_READ(RTC_CONTROL);
455 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
456
457 save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
458 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
459
460 cmos_minutes = CMOS_READ(RTC_MINUTES);
461 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
462 BCD_TO_BIN(cmos_minutes);
463
464
465
466
467
468
469 real_seconds = nowtime % 60;
470 real_minutes = nowtime / 60;
471 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
472 real_minutes += 30;
473 real_minutes %= 60;
474
475 if (abs(real_minutes - cmos_minutes) < 30)
476 {
477 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
478 {
479 BIN_TO_BCD(real_seconds);
480 BIN_TO_BCD(real_minutes);
481 }
482 CMOS_WRITE(real_seconds,RTC_SECONDS);
483 CMOS_WRITE(real_minutes,RTC_MINUTES);
484 }
485 else
486 retval = -1;
487
488 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
489 CMOS_WRITE(save_control, RTC_CONTROL);
490 return retval;
491 }