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