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