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