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