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 static inline void do_gettimeofday(struct timeval *tv)
202 {
203 #ifdef __i386__
204 cli();
205 *tv = xtime;
206 tv->tv_usec += do_gettimeoffset();
207 if (tv->tv_usec >= 1000000) {
208 tv->tv_usec -= 1000000;
209 tv->tv_sec++;
210 }
211 sti();
212 #else
213 cli();
214 *tv = xtime;
215 sti();
216 #endif
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 }