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