]>
Commit | Line | Data |
---|---|---|
7eda085c KZ |
1 | /* |
2 | * i386 CMOS starts out with 14 bytes clock data | |
3 | * alpha has something similar, but with details | |
4 | * depending on the machine type. | |
5 | * | |
6 | * byte 0: seconds (0-59) | |
7 | * byte 2: minutes (0-59) | |
8 | * byte 4: hours (0-23 in 24hr mode, | |
9 | * 1-12 in 12hr mode, with high bit unset/set if am/pm) | |
10 | * byte 6: weekday (1-7, Sunday=1) | |
11 | * byte 7: day of the month (1-31) | |
12 | * byte 8: month (1-12) | |
13 | * byte 9: year (0-99) | |
14 | * Numbers are stored in BCD/binary if bit 2 of byte 11 is unset/set | |
15 | * The clock is in 12hr/24hr mode if bit 1 of byte 11 is unset/set | |
16 | * The clock is undefined (being updated) if bit 7 of byte 10 is set. | |
17 | * The clock is frozen (to be updated) by setting bit 7 of byte 11 | |
18 | * Bit 7 of byte 14 indicates whether the CMOS clock is reliable: | |
19 | * it is 1 if RTC power has been good since this bit was last read; | |
20 | * it is 0 when the battery is dead and system power has been off. | |
21 | * | |
22 | * Avoid setting the RTC clock within 2 seconds of the day rollover | |
23 | * that starts a new month or enters daylight saving time. | |
24 | * | |
25 | * The century situation is messy: | |
26 | * Usually byte 50 (0x32) gives the century (in BCD, so 19 or 20 hex), | |
27 | * but IBM PS/2 has (part of) a checksum there and uses byte 55 (0x37). | |
28 | * Sometimes byte 127 (0x7f) or Bank 1, byte 0x48 gives the century. | |
29 | * The original RTC will not access any century byte; some modern | |
30 | * versions will. If a modern RTC or BIOS increments the century byte | |
31 | * it may go from 0x19 to 0x20, but in some buggy cases 0x1a is produced. | |
32 | */ | |
33 | ||
34 | /* | |
35 | * A struct tm has int fields | |
36 | * tm_sec (0-59, 60 or 61 only for leap seconds) | |
37 | * tm_min (0-59) | |
38 | * tm_hour (0-23) | |
39 | * tm_mday (1-31) | |
40 | * tm_mon (0-11) | |
41 | * tm_year (number of years since 1900) | |
42 | * tm_wday (0-6, 0=Sunday) | |
43 | * tm_yday (0-365) | |
44 | * tm_isdst (>0: yes, 0: no, <0: unknown) | |
45 | */ | |
46 | ||
47 | #include <unistd.h> /* for geteuid() */ | |
48 | #include <fcntl.h> /* for O_RDWR */ | |
49 | ||
50 | #include "nls.h" | |
51 | ||
52 | #if defined(__i386__) || defined(__alpha__) | |
53 | #include <asm/io.h> /* for inb, outb */ | |
54 | #else | |
55 | void outb(int a, int b){} | |
56 | int inb(int c){ return 0; } | |
57 | #endif | |
58 | ||
59 | #include "clock.h" | |
60 | ||
61 | #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) | |
62 | #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) | |
63 | ||
64 | #define TM_EPOCH 1900 | |
65 | int cmos_epoch = 1900; /* 1980 for an alpha in ARC console time */ | |
22853e4a | 66 | /* One also sees 1952 (Digital Unix) |
7eda085c KZ |
67 | and 1958 (ALPHA_PRE_V1_2_SRM_CONSOLE) */ |
68 | ||
69 | /* Martin Ostermann writes: | |
70 | The problem with the Jensen is twofold: First, it has the clock at a | |
71 | different address. Secondly, it has a distinction beween "local" and | |
72 | normal bus addresses. The local ones pertain to the hardware integrated | |
73 | into the chipset, like serial/parallel ports and of course, the RTC. | |
74 | Those need to be addressed differently. This is handled fine in the kernel, | |
75 | and it's not a problem, since this usually gets totally optimized by the | |
76 | compile. But the i/o routines of (g)libc lack this support so far. | |
77 | The result of this is, that the old clock program worked only on the | |
78 | Jensen when USE_DEV_PORT was defined, but not with the normal inb/outb | |
79 | functions. | |
80 | */ | |
81 | int use_dev_port = 0; /* 1 for Jensen */ | |
82 | int dev_port_fd; | |
83 | unsigned short clock_ctl_addr = 0x70; /* 0x170 for Jensen */ | |
84 | unsigned short clock_data_addr = 0x71; /* 0x171 for Jensen */ | |
85 | ||
86 | ||
87 | int century_byte = 0; /* 0: don't access a century byte | |
88 | 50 (0x32): usual PC value | |
89 | 55 (0x37): PS/2 */ | |
90 | ||
91 | #ifdef __alpha__ | |
92 | int funkyTOY = 0; /* 1 for PC164/LX164/SX164 type alpha */ | |
93 | #endif | |
94 | ||
95 | #ifdef __alpha | |
96 | ||
97 | static int | |
98 | is_in_cpuinfo(char *fmt, char *str) | |
99 | { | |
100 | FILE *cpuinfo; | |
101 | char field[256]; | |
102 | char format[256]; | |
103 | int found = 0; | |
104 | ||
105 | sprintf(format, "%s : %s", fmt, "%255s"); | |
106 | ||
107 | if ((cpuinfo = fopen ("/proc/cpuinfo", "r")) != NULL) { | |
108 | while (!feof(cpuinfo)) { | |
109 | if (fscanf (cpuinfo, format, field) == 1) { | |
110 | if (strncmp(field, str, strlen(str)) == 0) | |
111 | found = 1; | |
112 | break; | |
113 | } | |
114 | fgets (field, 256, cpuinfo); | |
115 | } | |
116 | fclose(cpuinfo); | |
117 | } | |
118 | return found; | |
119 | } | |
120 | ||
121 | /* Set cmos_epoch, either from user options, or by asking the kernel, | |
122 | or by looking at /proc/cpu_info */ | |
123 | void | |
124 | set_cmos_epoch(int ARCconsole, int SRM) { | |
125 | unsigned long epoch; | |
126 | ||
127 | /* Believe the user */ | |
22853e4a KZ |
128 | if (epoch_option != -1) { |
129 | cmos_epoch = epoch_option; | |
130 | return; | |
131 | } | |
132 | ||
7eda085c KZ |
133 | if (ARCconsole) |
134 | cmos_epoch = 1980; | |
135 | ||
136 | if (ARCconsole || SRM) | |
137 | return; | |
138 | ||
139 | ||
140 | /* If we can ask the kernel, we don't need guessing from /proc/cpuinfo */ | |
141 | if (get_epoch_rtc(&epoch, 1) == 0) { | |
142 | cmos_epoch = epoch; | |
143 | return; | |
144 | } | |
145 | ||
22853e4a KZ |
146 | /* The kernel source today says: read the year. If it is |
147 | in 11-43 then the epoch is 1980 (this covers 1991-2023). | |
148 | Otherwise, if it is less than 96 then the epoch is 1952 | |
149 | (this covers 1952-1962 and 1996-2047). Otherwise, the epoch | |
150 | is 1900 (this covers 1996-1999, or rather 1996-2155). */ | |
151 | ||
7eda085c KZ |
152 | |
153 | /* See whether we are dealing with SRM or MILO, as they have | |
154 | different "epoch" ideas. */ | |
155 | if (is_in_cpuinfo("system serial number", "MILO")) { | |
156 | ARCconsole = 1; | |
157 | if (debug) printf (_("booted from MILO\n")); | |
158 | } | |
159 | ||
eb63b9b8 KZ |
160 | /* See whether we are dealing with a RUFFIAN aka Alpha PC-164 UX (or BX), |
161 | as they have REALLY different TOY (TimeOfYear) format: BCD, and not | |
162 | an ARC-style epoch. | |
7eda085c KZ |
163 | BCD is detected dynamically, but we must NOT adjust like ARC. */ |
164 | if (ARCconsole && is_in_cpuinfo("system type", "Ruffian")) { | |
165 | ARCconsole = 0; | |
166 | if (debug) printf (_("Ruffian BCD clock\n")); | |
167 | } | |
168 | ||
169 | if (ARCconsole) | |
170 | cmos_epoch = 1980; | |
171 | } | |
172 | ||
173 | void | |
174 | set_cmos_access(int Jensen, int funky_toy) { | |
175 | ||
176 | /* See whether we're dealing with a Jensen---it has a weird I/O | |
177 | system. DEC was just learning how to build Alpha PCs. */ | |
178 | if (Jensen || is_in_cpuinfo("system type", "Jensen")) { | |
179 | use_dev_port = 1; | |
180 | clock_ctl_addr = 0x170; | |
181 | clock_data_addr = 0x171; | |
182 | if (debug) printf (_("clockport adjusted to 0x%x\n"), clock_ctl_addr); | |
183 | } | |
184 | ||
185 | /* see whether we are dealing with PC164/LX164/SX164, as they have a TOY | |
186 | that must be accessed differently to work correctly. */ | |
66ee8158 | 187 | /* Nautilus stuff reported by Neoklis Kyriazis */ |
7eda085c KZ |
188 | if (funky_toy || |
189 | is_in_cpuinfo("system variation", "PC164") || | |
190 | is_in_cpuinfo("system variation", "LX164") || | |
66ee8158 KZ |
191 | is_in_cpuinfo("system variation", "SX164") || |
192 | is_in_cpuinfo("system type", "Nautilus")) { | |
7eda085c KZ |
193 | funkyTOY = 1; |
194 | if (debug) printf (_("funky TOY!\n")); | |
195 | } | |
196 | } | |
197 | #endif | |
198 | ||
199 | ||
200 | ||
201 | ||
202 | #ifdef __i386__ | |
203 | ||
204 | /* | |
205 | * Try to do CMOS access atomically, so that no other processes | |
206 | * can get a time slice while we are reading or setting the clock. | |
207 | * (Also, if the kernel time is synchronized with an external source, | |
208 | * the kernel itself will fiddle with the RTC every 11 minutes.) | |
209 | */ | |
210 | ||
211 | static unsigned long | |
212 | atomic(const char *name, unsigned long (*op)(unsigned long), | |
213 | unsigned long arg) | |
214 | { | |
215 | unsigned long v; | |
216 | __asm__ volatile ("cli"); | |
217 | v = (*op)(arg); | |
218 | __asm__ volatile ("sti"); | |
219 | return v; | |
220 | } | |
221 | ||
222 | #elif __alpha__ | |
223 | ||
224 | /* | |
225 | * The Alpha doesn't allow user-level code to disable interrupts (for | |
226 | * good reasons). Instead, we ensure atomic operation by performing | |
227 | * the operation and checking whether the high 32 bits of the cycle | |
228 | * counter changed. If they did, a context switch must have occurred | |
229 | * and we redo the operation. As long as the operation is reasonably | |
230 | * short, it will complete atomically, eventually. | |
231 | */ | |
232 | ||
233 | static unsigned long | |
234 | atomic(const char *name, unsigned long (*op)(unsigned long), | |
235 | unsigned long arg) | |
236 | { | |
237 | unsigned long ts1, ts2, n, v; | |
238 | ||
239 | for (n = 0; n < 1000; ++n) { | |
240 | asm volatile ("rpcc %0" : "r="(ts1)); | |
241 | v = (*op)(arg); | |
242 | asm volatile ("rpcc %0" : "r="(ts2)); | |
243 | ||
244 | if ((ts1 ^ ts2) >> 32 == 0) { | |
245 | return v; | |
246 | } | |
247 | } | |
248 | fprintf(stderr, _("%s: atomic %s failed for 1000 iterations!"), progname, name); | |
249 | exit(1); | |
250 | } | |
251 | ||
252 | #else | |
253 | ||
254 | /* | |
255 | * Hmmh, this isn't very atomic. Maybe we should force an error | |
256 | * instead? | |
257 | */ | |
258 | static unsigned long | |
259 | atomic(const char *name, unsigned long (*op)(unsigned long), | |
260 | unsigned long arg) | |
261 | { | |
262 | return (*op)(arg); | |
263 | } | |
264 | ||
265 | #endif | |
266 | ||
267 | ||
268 | static inline | |
269 | unsigned long cmos_read(unsigned long reg) | |
270 | { | |
271 | if (use_dev_port) { | |
272 | unsigned char v = reg | 0x80; | |
273 | lseek(dev_port_fd, clock_ctl_addr, 0); | |
274 | write(dev_port_fd, &v, 1); | |
275 | lseek(dev_port_fd, clock_data_addr, 0); | |
276 | read(dev_port_fd, &v, 1); | |
277 | return v; | |
278 | } else { | |
279 | /* We only want to read CMOS data, but unfortunately | |
280 | writing to bit 7 disables (1) or enables (0) NMI; | |
281 | since this bit is read-only we have to guess the old status. | |
282 | Various docs suggest that one should disable NMI while | |
283 | reading/writing CMOS data, and enable it again afterwards. | |
284 | This would yield the sequence | |
285 | outb (reg | 0x80, 0x70); | |
286 | val = inb(0x71); | |
287 | outb (0x0d, 0x70); // 0x0d: random read-only location | |
288 | Other docs state that "any write to 0x70 should be followed | |
289 | by an action to 0x71 or the RTC wil be left in an unknown state". | |
290 | Most docs say that it doesnt matter at all what one does. | |
291 | */ | |
292 | /* bit 0x80: disable NMI while reading - should we? | |
293 | Let us follow the kernel and not disable. | |
294 | Called only with 0 <= reg < 128 */ | |
295 | outb (reg, clock_ctl_addr); | |
296 | return inb (clock_data_addr); | |
297 | } | |
298 | } | |
299 | ||
300 | static inline | |
301 | unsigned long cmos_write(unsigned long reg, unsigned long val) | |
302 | { | |
303 | if (use_dev_port) { | |
304 | unsigned char v = reg | 0x80; | |
305 | lseek(dev_port_fd, clock_ctl_addr, 0); | |
306 | write(dev_port_fd, &v, 1); | |
307 | v = (val & 0xff); | |
308 | lseek(dev_port_fd, clock_data_addr, 0); | |
309 | write(dev_port_fd, &v, 1); | |
310 | } else { | |
311 | outb (reg, clock_ctl_addr); | |
312 | outb (val, clock_data_addr); | |
313 | } | |
314 | return 0; | |
315 | } | |
316 | ||
317 | unsigned long cmos_set_time(unsigned long arg) | |
318 | { | |
319 | unsigned char save_control, save_freq_select, pmbit = 0; | |
320 | struct tm tm = *(struct tm *) arg; | |
321 | unsigned int century; | |
322 | ||
323 | /* | |
324 | * CMOS byte 10 (clock status register A) has 3 bitfields: | |
325 | * bit 7: 1 if data invalid, update in progress (read-only bit) | |
326 | * (this is raised 224 us before the actual update starts) | |
327 | * 6-4 select base frequency | |
328 | * 010: 32768 Hz time base (default) | |
329 | * 111: reset | |
330 | * all other combinations are manufacturer-dependent | |
331 | * (e.g.: DS1287: 010 = start oscillator, anything else = stop) | |
332 | * 3-0 rate selection bits for interrupt | |
333 | * 0000 none (may stop RTC) | |
334 | * 0001, 0010 give same frequency as 1000, 1001 | |
335 | * 0011 122 microseconds (minimum, 8192 Hz) | |
336 | * .... each increase by 1 halves the frequency, doubles the period | |
337 | * 1111 500 milliseconds (maximum, 2 Hz) | |
338 | * 0110 976.562 microseconds (default 1024 Hz) | |
339 | */ | |
340 | ||
341 | save_control = cmos_read (11); /* tell the clock it's being set */ | |
342 | cmos_write (11, (save_control | 0x80)); | |
343 | save_freq_select = cmos_read (10); /* stop and reset prescaler */ | |
344 | cmos_write (10, (save_freq_select | 0x70)); | |
345 | ||
346 | tm.tm_year += TM_EPOCH; | |
347 | century = tm.tm_year/100; | |
348 | tm.tm_year -= cmos_epoch; | |
349 | tm.tm_year %= 100; | |
350 | tm.tm_mon += 1; | |
351 | tm.tm_wday += 1; | |
352 | ||
353 | if (!(save_control & 0x02)) { /* 12hr mode; the default is 24hr mode */ | |
354 | if (tm.tm_hour == 0) | |
355 | tm.tm_hour = 24; | |
356 | if (tm.tm_hour > 12) { | |
357 | tm.tm_hour -= 12; | |
358 | pmbit = 0x80; | |
359 | } | |
360 | } | |
361 | ||
362 | if (!(save_control & 0x04)) { /* BCD mode - the default */ | |
363 | BIN_TO_BCD(tm.tm_sec); | |
364 | BIN_TO_BCD(tm.tm_min); | |
365 | BIN_TO_BCD(tm.tm_hour); | |
366 | BIN_TO_BCD(tm.tm_wday); | |
367 | BIN_TO_BCD(tm.tm_mday); | |
368 | BIN_TO_BCD(tm.tm_mon); | |
369 | BIN_TO_BCD(tm.tm_year); | |
370 | BIN_TO_BCD(century); | |
371 | } | |
372 | ||
373 | cmos_write (0, tm.tm_sec); | |
374 | cmos_write (2, tm.tm_min); | |
375 | cmos_write (4, tm.tm_hour | pmbit); | |
376 | cmos_write (6, tm.tm_wday); | |
377 | cmos_write (7, tm.tm_mday); | |
378 | cmos_write (8, tm.tm_mon); | |
379 | cmos_write (9, tm.tm_year); | |
380 | if (century_byte) | |
381 | cmos_write (century_byte, century); | |
382 | ||
383 | ||
384 | /* The kernel sources, linux/arch/i386/kernel/time.c, have the | |
385 | following comment: | |
386 | ||
387 | The following flags have to be released exactly in this order, | |
388 | otherwise the DS12887 (popular MC146818A clone with integrated | |
389 | battery and quartz) will not reset the oscillator and will not | |
390 | update precisely 500 ms later. You won't find this mentioned | |
391 | in the Dallas Semiconductor data sheets, but who believes data | |
392 | sheets anyway ... -- Markus Kuhn | |
393 | */ | |
394 | ||
395 | cmos_write (11, save_control); | |
396 | cmos_write (10, save_freq_select); | |
397 | return 0; | |
398 | } | |
399 | ||
400 | static int | |
401 | hclock_read(unsigned long reg) { | |
402 | return atomic("clock read", cmos_read, (reg)); | |
403 | } | |
404 | ||
405 | static void | |
406 | hclock_set_time(const struct tm *tm) { | |
407 | atomic("set time", cmos_set_time, (unsigned long)(tm)); | |
408 | } | |
409 | ||
410 | static inline int | |
22853e4a | 411 | cmos_clock_busy(void) { |
7eda085c KZ |
412 | return |
413 | #ifdef __alpha__ | |
414 | /* poll bit 4 (UF) of Control Register C */ | |
415 | funkyTOY ? (hclock_read(12) & 0x10) : | |
416 | #endif | |
417 | /* poll bit 7 (UIP) of Control Register A */ | |
418 | (hclock_read(10) & 0x80); | |
419 | } | |
420 | ||
421 | ||
422 | static int | |
423 | synchronize_to_clock_tick_cmos(void) { | |
424 | int i; | |
425 | ||
426 | /* Wait for rise. Should be within a second, but in case something | |
427 | weird happens, we have a limit on this loop to reduce the impact | |
428 | of this failure. | |
429 | */ | |
430 | for (i = 0; !cmos_clock_busy(); i++) | |
431 | if (i >= 10000000) | |
432 | return 1; | |
433 | ||
434 | /* Wait for fall. Should be within 2.228 ms. */ | |
435 | for (i = 0; cmos_clock_busy(); i++) | |
436 | if (i >= 1000000) | |
437 | return 1; | |
438 | return 0; | |
439 | } | |
440 | ||
441 | ||
442 | ||
443 | static int | |
444 | read_hardware_clock_cmos(struct tm *tm) { | |
445 | /*---------------------------------------------------------------------------- | |
446 | Read the hardware clock and return the current time via <tm> argument. | |
447 | Assume we have an ISA machine and read the clock directly with CPU I/O | |
448 | instructions. | |
449 | ||
450 | This function is not totally reliable. It takes a finite and | |
451 | unpredictable amount of time to execute the code below. During that | |
452 | time, the clock may change and we may even read an invalid value in | |
453 | the middle of an update. We do a few checks to minimize this | |
454 | possibility, but only the kernel can actually read the clock | |
455 | properly, since it can execute code in a short and predictable | |
456 | amount of time (by turning of interrupts). | |
457 | ||
458 | In practice, the chance of this function returning the wrong time is | |
459 | extremely remote. | |
460 | ||
461 | -----------------------------------------------------------------------------*/ | |
462 | bool got_time = FALSE; | |
463 | unsigned char status, pmbit; | |
464 | ||
465 | status = pmbit = 0; /* just for gcc */ | |
466 | ||
467 | while (!got_time) { | |
468 | /* Bit 7 of Byte 10 of the Hardware Clock value is the Update In Progress | |
469 | (UIP) bit, which is on while and 244 uS before the Hardware Clock | |
470 | updates itself. It updates the counters individually, so reading | |
471 | them during an update would produce garbage. The update takes 2mS, | |
472 | so we could be spinning here that long waiting for this bit to turn | |
473 | off. | |
474 | ||
475 | Furthermore, it is pathologically possible for us to be in this | |
476 | code so long that even if the UIP bit is not on at first, the | |
477 | clock has changed while we were running. We check for that too, | |
478 | and if it happens, we start over. | |
479 | */ | |
480 | ||
481 | if (!cmos_clock_busy()) { | |
482 | /* No clock update in progress, go ahead and read */ | |
483 | tm->tm_sec = hclock_read(0); | |
484 | tm->tm_min = hclock_read(2); | |
485 | tm->tm_hour = hclock_read(4); | |
486 | tm->tm_wday = hclock_read(6); | |
487 | tm->tm_mday = hclock_read(7); | |
488 | tm->tm_mon = hclock_read(8); | |
489 | tm->tm_year = hclock_read(9); | |
490 | status = hclock_read(11); | |
491 | #if 0 | |
492 | if (century_byte) | |
493 | century = hclock_read(century_byte); | |
494 | #endif | |
495 | ||
496 | /* Unless the clock changed while we were reading, consider this | |
497 | a good clock read . | |
498 | */ | |
499 | if (tm->tm_sec == hclock_read (0)) | |
500 | got_time = TRUE; | |
501 | } | |
502 | /* Yes, in theory we could have been running for 60 seconds and | |
503 | the above test wouldn't work! | |
504 | */ | |
505 | } | |
506 | ||
507 | if (!(status & 0x04)) { /* BCD mode - the default */ | |
508 | BCD_TO_BIN(tm->tm_sec); | |
509 | BCD_TO_BIN(tm->tm_min); | |
510 | pmbit = (tm->tm_hour & 0x80); | |
511 | tm->tm_hour &= 0x7f; | |
512 | BCD_TO_BIN(tm->tm_hour); | |
513 | BCD_TO_BIN(tm->tm_wday); | |
514 | BCD_TO_BIN(tm->tm_mday); | |
515 | BCD_TO_BIN(tm->tm_mon); | |
516 | BCD_TO_BIN(tm->tm_year); | |
517 | #if 0 | |
518 | BCD_TO_BIN(century); | |
519 | #endif | |
520 | } | |
521 | ||
522 | /* We don't use the century byte of the Hardware Clock | |
523 | since we don't know its address (usually 50 or 55). | |
524 | Here, we follow the advice of the X/Open Base Working Group: | |
525 | "if century is not specified, then values in the range [69-99] | |
526 | refer to years in the twentieth century (1969 to 1999 inclusive), | |
527 | and values in the range [00-68] refer to years in the twenty-first | |
528 | century (2000 to 2068 inclusive)." | |
529 | */ | |
530 | ||
531 | tm->tm_wday -= 1; | |
532 | tm->tm_mon -= 1; | |
533 | tm->tm_year += (cmos_epoch - TM_EPOCH); | |
534 | if (tm->tm_year < 69) | |
535 | tm->tm_year += 100; | |
536 | if (pmbit) { | |
537 | tm->tm_hour += 12; | |
538 | if (tm->tm_hour == 24) | |
539 | tm->tm_hour = 0; | |
540 | } | |
541 | ||
542 | tm->tm_isdst = -1; /* don't know whether it's daylight */ | |
543 | return 0; | |
544 | } | |
545 | ||
546 | ||
547 | ||
548 | static int | |
549 | set_hardware_clock_cmos(const struct tm *new_broken_time) { | |
550 | ||
551 | hclock_set_time(new_broken_time); | |
552 | return 0; | |
553 | } | |
554 | ||
555 | static int | |
556 | i386_iopl(const int level) { | |
557 | #if defined(__i386__) || defined(__alpha__) | |
66ee8158 | 558 | extern int iopl(const int lvl); |
7eda085c KZ |
559 | return iopl(level); |
560 | #else | |
561 | return -2; | |
562 | #endif | |
563 | } | |
564 | ||
565 | static int | |
566 | get_permissions_cmos(void) { | |
567 | int rc; | |
568 | ||
569 | if (use_dev_port) { | |
570 | if ((dev_port_fd = open("/dev/port", O_RDWR)) < 0) { | |
571 | int errsv = errno; | |
572 | fprintf(stderr, _("Cannot open /dev/port: %s"), strerror(errsv)); | |
573 | rc = 1; | |
574 | } else | |
575 | rc = 0; | |
576 | } else { | |
577 | rc = i386_iopl(3); | |
578 | if (rc == -2) { | |
579 | fprintf(stderr, _("I failed to get permission because I didnt try.\n")); | |
580 | } else if (rc != 0) { | |
581 | rc = errno; | |
582 | fprintf(stderr, _("%s is unable to get I/O port access: " | |
583 | "the iopl(3) call failed.\n"), progname); | |
584 | if(rc == EPERM && geteuid()) | |
585 | fprintf(stderr, _("Probably you need root privileges.\n")); | |
586 | } | |
587 | } | |
588 | return rc ? 1 : 0; | |
589 | } | |
590 | ||
591 | static struct clock_ops cmos = { | |
592 | "direct I/O instructions to ISA clock", | |
593 | get_permissions_cmos, | |
594 | read_hardware_clock_cmos, | |
595 | set_hardware_clock_cmos, | |
596 | synchronize_to_clock_tick_cmos, | |
597 | }; | |
598 | ||
599 | ||
600 | /* return &cmos if cmos clock present, NULL otherwise */ | |
601 | /* choose this construction to avoid gcc messages about unused variables */ | |
602 | ||
603 | struct clock_ops * | |
604 | probe_for_cmos_clock(void){ | |
605 | int have_cmos = | |
606 | #if defined(__i386__) || defined(__alpha__) | |
607 | TRUE; | |
608 | #else | |
609 | FALSE; | |
610 | #endif | |
611 | return have_cmos ? &cmos : NULL; | |
612 | } |