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