summaryrefslogtreecommitdiffstats
path: root/hwclock/cmos.c
diff options
context:
space:
mode:
authorSami Kerola2011-07-24 17:35:43 +0200
committerSami Kerola2011-07-26 17:27:18 +0200
commitef71b8f1128b72bf072f1bd0a306b1bb06781a40 (patch)
tree14c87f9c2a58cb8f1a95e98fa7793dbb5fb2b502 /hwclock/cmos.c
parenthwclock: remove misleading information (diff)
downloadkernel-qcow2-util-linux-ef71b8f1128b72bf072f1bd0a306b1bb06781a40.tar.gz
kernel-qcow2-util-linux-ef71b8f1128b72bf072f1bd0a306b1bb06781a40.tar.xz
kernel-qcow2-util-linux-ef71b8f1128b72bf072f1bd0a306b1bb06781a40.zip
hwclock: coding style clean up
Despide amount of the change this change should be harmless. Everything is about indendation, comment restructuring etc not code changes. Signed-off-by: Sami Kerola <kerolasa@iki.fi>
Diffstat (limited to 'hwclock/cmos.c')
-rw-r--r--hwclock/cmos.c979
1 files changed, 510 insertions, 469 deletions
diff --git a/hwclock/cmos.c b/hwclock/cmos.c
index 0178ef7d3..d6216717f 100644
--- a/hwclock/cmos.c
+++ b/hwclock/cmos.c
@@ -1,47 +1,48 @@
/*
- * i386 CMOS starts out with 14 bytes clock data
- * alpha has something similar, but with details
- * depending on the machine type.
+ * i386 CMOS starts out with 14 bytes clock data alpha has something
+ * similar, but with details depending on the machine type.
*
- * byte 0: seconds (0-59)
- * byte 2: minutes (0-59)
- * byte 4: hours (0-23 in 24hr mode,
- * 1-12 in 12hr mode, with high bit unset/set if am/pm)
- * byte 6: weekday (1-7, Sunday=1)
- * byte 7: day of the month (1-31)
- * byte 8: month (1-12)
- * byte 9: year (0-99)
- * Numbers are stored in BCD/binary if bit 2 of byte 11 is unset/set
- * The clock is in 12hr/24hr mode if bit 1 of byte 11 is unset/set
- * The clock is undefined (being updated) if bit 7 of byte 10 is set.
- * The clock is frozen (to be updated) by setting bit 7 of byte 11
- * Bit 7 of byte 14 indicates whether the CMOS clock is reliable:
- * it is 1 if RTC power has been good since this bit was last read;
- * it is 0 when the battery is dead and system power has been off.
+ * byte 0: seconds 0-59
+ * byte 2: minutes 0-59
+ * byte 4: hours 0-23 in 24hr mode,
+ * 1-12 in 12hr mode, with high bit unset/set
+ * if am/pm.
+ * byte 6: weekday 1-7, Sunday=1
+ * byte 7: day of the month 1-31
+ * byte 8: month 1-12
+ * byte 9: year 0-99
*
- * Avoid setting the RTC clock within 2 seconds of the day rollover
- * that starts a new month or enters daylight saving time.
+ * Numbers are stored in BCD/binary if bit 2 of byte 11 is unset/set The
+ * clock is in 12hr/24hr mode if bit 1 of byte 11 is unset/set The clock is
+ * undefined (being updated) if bit 7 of byte 10 is set. The clock is frozen
+ * (to be updated) by setting bit 7 of byte 11 Bit 7 of byte 14 indicates
+ * whether the CMOS clock is reliable: it is 1 if RTC power has been good
+ * since this bit was last read; it is 0 when the battery is dead and system
+ * power has been off.
+ *
+ * Avoid setting the RTC clock within 2 seconds of the day rollover that
+ * starts a new month or enters daylight saving time.
*
* The century situation is messy:
- * Usually byte 50 (0x32) gives the century (in BCD, so 19 or 20 hex),
- * but IBM PS/2 has (part of) a checksum there and uses byte 55 (0x37).
- * Sometimes byte 127 (0x7f) or Bank 1, byte 0x48 gives the century.
- * The original RTC will not access any century byte; some modern
- * versions will. If a modern RTC or BIOS increments the century byte
- * it may go from 0x19 to 0x20, but in some buggy cases 0x1a is produced.
+ *
+ * Usually byte 50 (0x32) gives the century (in BCD, so 19 or 20 hex), but
+ * IBM PS/2 has (part of) a checksum there and uses byte 55 (0x37).
+ * Sometimes byte 127 (0x7f) or Bank 1, byte 0x48 gives the century. The
+ * original RTC will not access any century byte; some modern versions will.
+ * If a modern RTC or BIOS increments the century byte it may go from 0x19
+ * to 0x20, but in some buggy cases 0x1a is produced.
*/
-
/*
* A struct tm has int fields
- * tm_sec (0-59, 60 or 61 only for leap seconds)
- * tm_min (0-59)
- * tm_hour (0-23)
- * tm_mday (1-31)
- * tm_mon (0-11)
- * tm_year (number of years since 1900)
- * tm_wday (0-6, 0=Sunday)
- * tm_yday (0-365)
- * tm_isdst (>0: yes, 0: no, <0: unknown)
+ * tm_sec 0-59, 60 or 61 only for leap seconds
+ * tm_min 0-59
+ * tm_hour 0-23
+ * tm_mday 1-31
+ * tm_mon 0-11
+ * tm_year number of years since 1900
+ * tm_wday 0-6, 0=Sunday
+ * tm_yday 0-365
+ * tm_isdst >0: yes, 0: no, <0: unknown
*/
#include <unistd.h> /* for geteuid() */
@@ -50,27 +51,40 @@
#include "nls.h"
#if defined(__i386__)
-
# ifdef HAVE_SYS_IO_H
-# include <sys/io.h>
+# include <sys/io.h>
# elif defined(HAVE_ASM_IO_H)
-# include <asm/io.h> /* for inb, outb */
+# include <asm/io.h> /* for inb, outb */
# else
-/* Disable cmos access; we can no longer use asm/io.h, since
- * the kernel does not export that header. */
-# undef __i386__
-void outb(int a, int b){}
-int inb(int c){ return 0; }
-# endif
+/*
+ * Disable cmos access; we can no longer use asm/io.h, since the kernel does
+ * not export that header.
+ */
+#undef __i386__
+void outb(int a, int b)
+{
+}
+
+int inb(int c)
+{
+ return 0;
+}
+#endif /* __i386__ */
#elif defined(__alpha__)
/* <asm/io.h> fails to compile, probably because of u8 etc */
-extern unsigned int inb(unsigned long port);
-extern void outb(unsigned char b,unsigned long port);
+extern unsigned int inb(unsigned long port);
+extern void outb(unsigned char b, unsigned long port);
#else
-void outb(int a, int b){}
-int inb(int c){ return 0; }
-#endif
+void outb(int a, int b)
+{
+}
+
+int inb(int c)
+{
+ return 0;
+}
+#endif /* __alpha__ */
#include "clock.h"
@@ -80,39 +94,40 @@ int inb(int c){ return 0; }
/*
* The epoch.
*
- * Unix uses 1900 as epoch for a struct tm, and 1970 for a time_t.
- * But what was written to CMOS?
- * Digital DECstations use 1928 - this is on a mips or alpha
- * Digital Unix uses 1952, e.g. on AXPpxi33
- * Windows NT uses 1980.
- * The ARC console expects to boot Windows NT and uses 1980.
- * (But a Ruffian uses 1900, just like SRM.)
- * It is reported that ALPHA_PRE_V1_2_SRM_CONSOLE uses 1958.
+ * Unix uses 1900 as epoch for a struct tm, and 1970 for a time_t. But what
+ * was written to CMOS?
+ *
+ * Digital DECstations use 1928 - this is on a mips or alpha Digital Unix
+ * uses 1952, e.g. on AXPpxi33. Windows NT uses 1980. The ARC console
+ * expects to boot Windows NT and uses 1980. (But a Ruffian uses 1900, just
+ * like SRM.) It is reported that ALPHA_PRE_V1_2_SRM_CONSOLE uses 1958.
*/
#define TM_EPOCH 1900
int cmos_epoch = 1900;
-/* Martin Ostermann writes:
-The problem with the Jensen is twofold: First, it has the clock at a
-different address. Secondly, it has a distinction beween "local" and
-normal bus addresses. The local ones pertain to the hardware integrated
-into the chipset, like serial/parallel ports and of course, the RTC.
-Those need to be addressed differently. This is handled fine in the kernel,
-and it's not a problem, since this usually gets totally optimized by the
-compile. But the i/o routines of (g)libc lack this support so far.
-The result of this is, that the old clock program worked only on the
-Jensen when USE_DEV_PORT was defined, but not with the normal inb/outb
-functions.
+/*
+ * Martin Ostermann writes:
+ *
+ * The problem with the Jensen is twofold: First, it has the clock at a
+ * different address. Secondly, it has a distinction beween "local" and
+ * normal bus addresses. The local ones pertain to the hardware integrated
+ * into the chipset, like serial/parallel ports and of course, the RTC.
+ * Those need to be addressed differently. This is handled fine in the
+ * kernel, and it's not a problem, since this usually gets totally optimized
+ * by the compile. But the i/o routines of (g)libc lack this support so far.
+ * The result of this is, that the old clock program worked only on the
+ * Jensen when USE_DEV_PORT was defined, but not with the normal inb/outb
+ * functions.
*/
int use_dev_port = 0; /* 1 for Jensen */
int dev_port_fd;
unsigned short clock_ctl_addr = 0x70; /* 0x170 for Jensen */
-unsigned short clock_data_addr = 0x71; /* 0x171 for Jensen */
-
+unsigned short clock_data_addr = 0x71; /* 0x171 for Jensen */
int century_byte = 0; /* 0: don't access a century byte
- 50 (0x32): usual PC value
- 55 (0x37): PS/2 */
+ * 50 (0x32): usual PC value
+ * 55 (0x37): PS/2
+ */
#ifdef __alpha__
int funkyTOY = 0; /* 1 for PC164/LX164/SX164 type alpha */
@@ -120,217 +135,242 @@ int funkyTOY = 0; /* 1 for PC164/LX164/SX164 type alpha */
#ifdef __alpha
-static int
-is_in_cpuinfo(char *fmt, char *str)
+static int is_in_cpuinfo(char *fmt, char *str)
{
- FILE *cpuinfo;
- char field[256];
- char format[256];
- int found = 0;
-
- sprintf(format, "%s : %s", fmt, "%255s");
-
- if ((cpuinfo = fopen ("/proc/cpuinfo", "r")) != NULL) {
- while (!feof(cpuinfo)) {
- if (fscanf (cpuinfo, format, field) == 1) {
- if (strncmp(field, str, strlen(str)) == 0)
- found = 1;
- break;
- }
- fgets (field, 256, cpuinfo);
+ FILE *cpuinfo;
+ char field[256];
+ char format[256];
+ int found = 0;
+
+ sprintf(format, "%s : %s", fmt, "%255s");
+
+ if ((cpuinfo = fopen("/proc/cpuinfo", "r")) != NULL) {
+ while (!feof(cpuinfo)) {
+ if (fscanf(cpuinfo, format, field) == 1) {
+ if (strncmp(field, str, strlen(str)) == 0)
+ found = 1;
+ break;
+ }
+ fgets(field, 256, cpuinfo);
+ }
+ fclose(cpuinfo);
}
- fclose(cpuinfo);
- }
- return found;
+ return found;
}
-/* Set cmos_epoch, either from user options, or by asking the kernel,
- or by looking at /proc/cpu_info */
-void
-set_cmos_epoch(int ARCconsole, int SRM) {
- unsigned long epoch;
-
- /* Believe the user */
- if (epoch_option != -1) {
- cmos_epoch = epoch_option;
- return;
- }
+/*
+ * Set cmos_epoch, either from user options, or by asking the kernel, or by
+ * looking at /proc/cpu_info
+ */
+void set_cmos_epoch(int ARCconsole, int SRM)
+{
+ unsigned long epoch;
- if (ARCconsole)
- cmos_epoch = 1980;
+ /* Believe the user */
+ if (epoch_option != -1) {
+ cmos_epoch = epoch_option;
+ return;
+ }
- if (ARCconsole || SRM)
- return;
+ if (ARCconsole)
+ cmos_epoch = 1980;
+ if (ARCconsole || SRM)
+ return;
#ifdef __linux__
- /* If we can ask the kernel, we don't need guessing from /proc/cpuinfo */
- if (get_epoch_rtc(&epoch, 1) == 0) {
- cmos_epoch = epoch;
- return;
- }
+ /*
+ * If we can ask the kernel, we don't need guessing from
+ * /proc/cpuinfo
+ */
+ if (get_epoch_rtc(&epoch, 1) == 0) {
+ cmos_epoch = epoch;
+ return;
+ }
#endif
- /* The kernel source today says: read the year.
- If it is in 0-19 then the epoch is 2000.
- If it is in 20-47 then the epoch is 1980.
- If it is in 48-69 then the epoch is 1952.
- If it is in 70-99 then the epoch is 1928.
- Otherwise the epoch is 1900.
- Clearly, this must be changed before 2019. */
-
- /* See whether we are dealing with SRM or MILO, as they have
- different "epoch" ideas. */
- if (is_in_cpuinfo("system serial number", "MILO")) {
- ARCconsole = 1;
- if (debug) printf (_("booted from MILO\n"));
- }
-
- /* See whether we are dealing with a RUFFIAN aka Alpha PC-164 UX (or BX),
- as they have REALLY different TOY (TimeOfYear) format: BCD, and not
- an ARC-style epoch.
- BCD is detected dynamically, but we must NOT adjust like ARC. */
- if (ARCconsole && is_in_cpuinfo("system type", "Ruffian")) {
- ARCconsole = 0;
- if (debug) printf (_("Ruffian BCD clock\n"));
- }
-
- if (ARCconsole)
- cmos_epoch = 1980;
-}
+ /*
+ * The kernel source today says: read the year.
+ *
+ * If it is in 0-19 then the epoch is 2000.
+ * If it is in 20-47 then the epoch is 1980.
+ * If it is in 48-69 then the epoch is 1952.
+ * If it is in 70-99 then the epoch is 1928.
+ *
+ * Otherwise the epoch is 1900.
+ * TODO: Clearly, this must be changed before 2019.
+ */
+ /*
+ * See whether we are dealing with SRM or MILO, as they have
+ * different "epoch" ideas.
+ */
+ if (is_in_cpuinfo("system serial number", "MILO")) {
+ ARCconsole = 1;
+ if (debug)
+ printf(_("booted from MILO\n"));
+ }
-void
-set_cmos_access(int Jensen, int funky_toy) {
-
- /* See whether we're dealing with a Jensen---it has a weird I/O
- system. DEC was just learning how to build Alpha PCs. */
- if (Jensen || is_in_cpuinfo("system type", "Jensen")) {
- use_dev_port = 1;
- clock_ctl_addr = 0x170;
- clock_data_addr = 0x171;
- if (debug) printf (_("clockport adjusted to 0x%x\n"), clock_ctl_addr);
- }
-
- /* see whether we are dealing with PC164/LX164/SX164, as they have a TOY
- that must be accessed differently to work correctly. */
- /* Nautilus stuff reported by Neoklis Kyriazis */
- if (funky_toy ||
- is_in_cpuinfo("system variation", "PC164") ||
- is_in_cpuinfo("system variation", "LX164") ||
- is_in_cpuinfo("system variation", "SX164") ||
- is_in_cpuinfo("system type", "Nautilus")) {
- funkyTOY = 1;
- if (debug) printf (_("funky TOY!\n"));
- }
+ /*
+ * See whether we are dealing with a RUFFIAN aka Alpha PC-164 UX (or
+ * BX), as they have REALLY different TOY (TimeOfYear) format: BCD,
+ * and not an ARC-style epoch. BCD is detected dynamically, but we
+ * must NOT adjust like ARC.
+ */
+ if (ARCconsole && is_in_cpuinfo("system type", "Ruffian")) {
+ ARCconsole = 0;
+ if (debug)
+ printf(_("Ruffian BCD clock\n"));
+ }
+
+ if (ARCconsole)
+ cmos_epoch = 1980;
}
-#endif
+void set_cmos_access(int Jensen, int funky_toy)
+{
+
+ /*
+ * See whether we're dealing with a Jensen---it has a weird I/O
+ * system. DEC was just learning how to build Alpha PCs.
+ */
+ if (Jensen || is_in_cpuinfo("system type", "Jensen")) {
+ use_dev_port = 1;
+ clock_ctl_addr = 0x170;
+ clock_data_addr = 0x171;
+ if (debug)
+ printf(_("clockport adjusted to 0x%x\n"),
+ clock_ctl_addr);
+ }
+
+ /*
+ * See whether we are dealing with PC164/LX164/SX164, as they have a
+ * TOY that must be accessed differently to work correctly.
+ */
+ /* Nautilus stuff reported by Neoklis Kyriazis */
+ if (funky_toy ||
+ is_in_cpuinfo("system variation", "PC164") ||
+ is_in_cpuinfo("system variation", "LX164") ||
+ is_in_cpuinfo("system variation", "SX164") ||
+ is_in_cpuinfo("system type", "Nautilus")) {
+ funkyTOY = 1;
+ if (debug)
+ printf(_("funky TOY!\n"));
+ }
+}
+#endif /* __alpha */
#if __alpha__
/*
- * The Alpha doesn't allow user-level code to disable interrupts (for
- * good reasons). Instead, we ensure atomic operation by performing
- * the operation and checking whether the high 32 bits of the cycle
- * counter changed. If they did, a context switch must have occurred
- * and we redo the operation. As long as the operation is reasonably
- * short, it will complete atomically, eventually.
+ * The Alpha doesn't allow user-level code to disable interrupts (for good
+ * reasons). Instead, we ensure atomic operation by performing the operation
+ * and checking whether the high 32 bits of the cycle counter changed. If
+ * they did, a context switch must have occurred and we redo the operation.
+ * As long as the operation is reasonably short, it will complete
+ * atomically, eventually.
*/
-
static unsigned long
-atomic(const char *name, unsigned long (*op)(unsigned long),
- unsigned long arg)
+atomic(const char *name, unsigned long (*op) (unsigned long), unsigned long arg)
{
- unsigned long ts1, ts2, n, v;
-
- for (n = 0; n < 1000; ++n) {
- asm volatile ("rpcc %0" : "r="(ts1));
- v = (*op)(arg);
- asm volatile ("rpcc %0" : "r="(ts2));
-
- if ((ts1 ^ ts2) >> 32 == 0) {
- return v;
- }
- }
- fprintf(stderr, _("%s: atomic %s failed for 1000 iterations!"), progname, name);
- exit(1);
+ unsigned long ts1, ts2, n, v;
+
+ for (n = 0; n < 1000; ++n) {
+ asm volatile ("rpcc %0":"r=" (ts1));
+ v = (*op) (arg);
+ asm volatile ("rpcc %0":"r=" (ts2));
+
+ if ((ts1 ^ ts2) >> 32 == 0) {
+ return v;
+ }
+ }
+ fprintf(stderr, _("%s: atomic %s failed for 1000 iterations!"),
+ progname, name);
+ exit(1);
}
#else
/*
- * Hmmh, this isn't very atomic. Maybe we should force an error
- * instead?
+ * Hmmh, this isn't very atomic. Maybe we should force an error instead?
*
- * TODO: optimize the access to CMOS by mlockall(MCL_CURRENT)
- * and SCHED_FIFO
+ * TODO: optimize the access to CMOS by mlockall(MCL_CURRENT) and SCHED_FIFO
*/
static unsigned long
-atomic(const char *name, unsigned long (*op)(unsigned long),
- unsigned long arg)
+atomic(const char *name, unsigned long (*op) (unsigned long), unsigned long arg)
{
- return (*op)(arg);
+ return (*op) (arg);
}
#endif
-
-static inline
-unsigned long cmos_read(unsigned long reg)
+static inline unsigned long cmos_read(unsigned long reg)
{
- if (use_dev_port) {
- unsigned char v = reg | 0x80;
- lseek(dev_port_fd, clock_ctl_addr, 0);
- if (write(dev_port_fd, &v, 1) == -1 && debug)
- printf(_("cmos_read(): write to control address %X failed: %s\n"), clock_ctl_addr, strerror(errno));
- lseek(dev_port_fd, clock_data_addr, 0);
- if (read(dev_port_fd, &v, 1) == -1 && debug)
- printf(_("cmos_read(): read data address %X failed: %s\n"), clock_data_addr, strerror(errno));
- return v;
- } else {
- /* We only want to read CMOS data, but unfortunately
- writing to bit 7 disables (1) or enables (0) NMI;
- since this bit is read-only we have to guess the old status.
- Various docs suggest that one should disable NMI while
- reading/writing CMOS data, and enable it again afterwards.
- This would yield the sequence
- outb (reg | 0x80, 0x70);
- val = inb(0x71);
- outb (0x0d, 0x70); // 0x0d: random read-only location
- Other docs state that "any write to 0x70 should be followed
- by an action to 0x71 or the RTC wil be left in an unknown state".
- Most docs say that it doesnt matter at all what one does.
- */
- /* bit 0x80: disable NMI while reading - should we?
- Let us follow the kernel and not disable.
- Called only with 0 <= reg < 128 */
- outb (reg, clock_ctl_addr);
- return inb (clock_data_addr);
- }
+ if (use_dev_port) {
+ unsigned char v = reg | 0x80;
+ lseek(dev_port_fd, clock_ctl_addr, 0);
+ if (write(dev_port_fd, &v, 1) == -1 && debug)
+ printf(_
+ ("cmos_read(): write to control address %X failed: %s\n"),
+ clock_ctl_addr, strerror(errno));
+ lseek(dev_port_fd, clock_data_addr, 0);
+ if (read(dev_port_fd, &v, 1) == -1 && debug)
+ printf(_
+ ("cmos_read(): read data address %X failed: %s\n"),
+ clock_data_addr, strerror(errno));
+ return v;
+ } else {
+ /*
+ * We only want to read CMOS data, but unfortunately writing
+ * to bit 7 disables (1) or enables (0) NMI; since this bit
+ * is read-only we have to guess the old status. Various
+ * docs suggest that one should disable NMI while
+ * reading/writing CMOS data, and enable it again
+ * afterwards. This would yield the sequence
+ *
+ * outb (reg | 0x80, 0x70);
+ * val = inb(0x71);
+ * outb (0x0d, 0x70); // 0x0d: random read-only location
+ *
+ * Other docs state that "any write to 0x70 should be
+ * followed by an action to 0x71 or the RTC wil be left in
+ * an unknown state". Most docs say that it doesnt matter at
+ * all what one does.
+ */
+ /*
+ * bit 0x80: disable NMI while reading - should we? Let us
+ * follow the kernel and not disable. Called only with 0 <=
+ * reg < 128
+ */
+ outb(reg, clock_ctl_addr);
+ return inb(clock_data_addr);
+ }
}
-static inline
-unsigned long cmos_write(unsigned long reg, unsigned long val)
+static inline unsigned long cmos_write(unsigned long reg, unsigned long val)
{
- if (use_dev_port) {
- unsigned char v = reg | 0x80;
- lseek(dev_port_fd, clock_ctl_addr, 0);
- if (write(dev_port_fd, &v, 1) == -1 && debug)
- printf(_("cmos_write(): write to control address %X failed: %s\n"), clock_ctl_addr, strerror(errno));
- v = (val & 0xff);
- lseek(dev_port_fd, clock_data_addr, 0);
- if (write(dev_port_fd, &v, 1) == -1 && debug)
- printf(_("cmos_write(): write to data address %X failed: %s\n"), clock_data_addr, strerror(errno));
- } else {
- outb (reg, clock_ctl_addr);
- outb (val, clock_data_addr);
- }
- return 0;
+ if (use_dev_port) {
+ unsigned char v = reg | 0x80;
+ lseek(dev_port_fd, clock_ctl_addr, 0);
+ if (write(dev_port_fd, &v, 1) == -1 && debug)
+ printf(_
+ ("cmos_write(): write to control address %X failed: %s\n"),
+ clock_ctl_addr, strerror(errno));
+ v = (val & 0xff);
+ lseek(dev_port_fd, clock_data_addr, 0);
+ if (write(dev_port_fd, &v, 1) == -1 && debug)
+ printf(_
+ ("cmos_write(): write to data address %X failed: %s\n"),
+ clock_data_addr, strerror(errno));
+ } else {
+ outb(reg, clock_ctl_addr);
+ outb(val, clock_data_addr);
+ }
+ return 0;
}
static unsigned long cmos_set_time(unsigned long arg)
{
- unsigned char save_control, save_freq_select, pmbit = 0;
- struct tm tm = *(struct tm *) arg;
- unsigned int century;
+ unsigned char save_control, save_freq_select, pmbit = 0;
+ struct tm tm = *(struct tm *)arg;
+ unsigned int century;
/*
* CMOS byte 10 (clock status register A) has 3 bitfields:
@@ -349,260 +389,261 @@ static unsigned long cmos_set_time(unsigned long arg)
* 1111 500 milliseconds (maximum, 2 Hz)
* 0110 976.562 microseconds (default 1024 Hz)
*/
+ save_control = cmos_read(11); /* tell the clock it's being set */
+ cmos_write(11, (save_control | 0x80));
+ save_freq_select = cmos_read(10); /* stop and reset prescaler */
+ cmos_write(10, (save_freq_select | 0x70));
+
+ tm.tm_year += TM_EPOCH;
+ century = tm.tm_year / 100;
+ tm.tm_year -= cmos_epoch;
+ tm.tm_year %= 100;
+ tm.tm_mon += 1;
+ tm.tm_wday += 1;
+
+ if (!(save_control & 0x02)) { /* 12hr mode; the default is 24hr mode */
+ if (tm.tm_hour == 0)
+ tm.tm_hour = 24;
+ if (tm.tm_hour > 12) {
+ tm.tm_hour -= 12;
+ pmbit = 0x80;
+ }
+ }
+
+ if (!(save_control & 0x04)) { /* BCD mode - the default */
+ BIN_TO_BCD(tm.tm_sec);
+ BIN_TO_BCD(tm.tm_min);
+ BIN_TO_BCD(tm.tm_hour);
+ BIN_TO_BCD(tm.tm_wday);
+ BIN_TO_BCD(tm.tm_mday);
+ BIN_TO_BCD(tm.tm_mon);
+ BIN_TO_BCD(tm.tm_year);
+ BIN_TO_BCD(century);
+ }
- save_control = cmos_read (11); /* tell the clock it's being set */
- cmos_write (11, (save_control | 0x80));
- save_freq_select = cmos_read (10); /* stop and reset prescaler */
- cmos_write (10, (save_freq_select | 0x70));
-
- tm.tm_year += TM_EPOCH;
- century = tm.tm_year/100;
- tm.tm_year -= cmos_epoch;
- tm.tm_year %= 100;
- tm.tm_mon += 1;
- tm.tm_wday += 1;
-
- if (!(save_control & 0x02)) { /* 12hr mode; the default is 24hr mode */
- if (tm.tm_hour == 0)
- tm.tm_hour = 24;
- if (tm.tm_hour > 12) {
- tm.tm_hour -= 12;
- pmbit = 0x80;
- }
- }
-
- if (!(save_control & 0x04)) { /* BCD mode - the default */
- BIN_TO_BCD(tm.tm_sec);
- BIN_TO_BCD(tm.tm_min);
- BIN_TO_BCD(tm.tm_hour);
- BIN_TO_BCD(tm.tm_wday);
- BIN_TO_BCD(tm.tm_mday);
- BIN_TO_BCD(tm.tm_mon);
- BIN_TO_BCD(tm.tm_year);
- BIN_TO_BCD(century);
- }
-
- cmos_write (0, tm.tm_sec);
- cmos_write (2, tm.tm_min);
- cmos_write (4, tm.tm_hour | pmbit);
- cmos_write (6, tm.tm_wday);
- cmos_write (7, tm.tm_mday);
- cmos_write (8, tm.tm_mon);
- cmos_write (9, tm.tm_year);
- if (century_byte)
- cmos_write (century_byte, century);
-
-
- /* The kernel sources, linux/arch/i386/kernel/time.c, have the
- following comment:
-
- The following flags have to be released exactly in this order,
- otherwise the DS12887 (popular MC146818A clone with integrated
- battery and quartz) will not reset the oscillator and will not
- update precisely 500 ms later. You won't find this mentioned
- in the Dallas Semiconductor data sheets, but who believes data
- sheets anyway ... -- Markus Kuhn
- */
-
- cmos_write (11, save_control);
- cmos_write (10, save_freq_select);
- return 0;
+ cmos_write(0, tm.tm_sec);
+ cmos_write(2, tm.tm_min);
+ cmos_write(4, tm.tm_hour | pmbit);
+ cmos_write(6, tm.tm_wday);
+ cmos_write(7, tm.tm_mday);
+ cmos_write(8, tm.tm_mon);
+ cmos_write(9, tm.tm_year);
+ if (century_byte)
+ cmos_write(century_byte, century);
+
+ /*
+ * The kernel sources, linux/arch/i386/kernel/time.c, have the
+ * following comment:
+ *
+ * The following flags have to be released exactly in this order,
+ * otherwise the DS12887 (popular MC146818A clone with integrated
+ * battery and quartz) will not reset the oscillator and will not
+ * update precisely 500 ms later. You won't find this mentioned in
+ * the Dallas Semiconductor data sheets, but who believes data
+ * sheets anyway ... -- Markus Kuhn
+ */
+ cmos_write(11, save_control);
+ cmos_write(10, save_freq_select);
+ return 0;
}
-static int
-hclock_read(unsigned long reg) {
+static int hclock_read(unsigned long reg)
+{
return atomic("clock read", cmos_read, (reg));
}
-static void
-hclock_set_time(const struct tm *tm) {
+static void hclock_set_time(const struct tm *tm)
+{
atomic("set time", cmos_set_time, (unsigned long)(tm));
}
-static inline int
-cmos_clock_busy(void) {
+static inline int cmos_clock_busy(void)
+{
return
#ifdef __alpha__
- /* poll bit 4 (UF) of Control Register C */
+ /* poll bit 4 (UF) of Control Register C */
funkyTOY ? (hclock_read(12) & 0x10) :
#endif
- /* poll bit 7 (UIP) of Control Register A */
+ /* poll bit 7 (UIP) of Control Register A */
(hclock_read(10) & 0x80);
}
-
-static int
-synchronize_to_clock_tick_cmos(void) {
- int i;
-
- /* Wait for rise. Should be within a second, but in case something
- weird happens, we have a limit on this loop to reduce the impact
- of this failure.
- */
- for (i = 0; !cmos_clock_busy(); i++)
- if (i >= 10000000)
- return 1;
-
- /* Wait for fall. Should be within 2.228 ms. */
- for (i = 0; cmos_clock_busy(); i++)
- if (i >= 1000000)
- return 1;
- return 0;
+static int synchronize_to_clock_tick_cmos(void)
+{
+ int i;
+
+ /*
+ * Wait for rise. Should be within a second, but in case something
+ * weird happens, we have a limit on this loop to reduce the impact
+ * of this failure.
+ */
+ for (i = 0; !cmos_clock_busy(); i++)
+ if (i >= 10000000)
+ return 1;
+
+ /* Wait for fall. Should be within 2.228 ms. */
+ for (i = 0; cmos_clock_busy(); i++)
+ if (i >= 1000000)
+ return 1;
+ return 0;
}
-
-
-static int
-read_hardware_clock_cmos(struct tm *tm) {
-/*----------------------------------------------------------------------------
- Read the hardware clock and return the current time via <tm> argument.
- Assume we have an ISA machine and read the clock directly with CPU I/O
- instructions.
-
- This function is not totally reliable. It takes a finite and
- unpredictable amount of time to execute the code below. During that
- time, the clock may change and we may even read an invalid value in
- the middle of an update. We do a few checks to minimize this
- possibility, but only the kernel can actually read the clock
- properly, since it can execute code in a short and predictable
- amount of time (by turning of interrupts).
-
- In practice, the chance of this function returning the wrong time is
- extremely remote.
-
------------------------------------------------------------------------------*/
- bool got_time = FALSE;
- unsigned char status, pmbit;
-
- status = pmbit = 0; /* just for gcc */
-
- while (!got_time) {
- /* Bit 7 of Byte 10 of the Hardware Clock value is the Update In Progress
- (UIP) bit, which is on while and 244 uS before the Hardware Clock
- updates itself. It updates the counters individually, so reading
- them during an update would produce garbage. The update takes 2mS,
- so we could be spinning here that long waiting for this bit to turn
- off.
-
- Furthermore, it is pathologically possible for us to be in this
- code so long that even if the UIP bit is not on at first, the
- clock has changed while we were running. We check for that too,
- and if it happens, we start over.
- */
-
- if (!cmos_clock_busy()) {
- /* No clock update in progress, go ahead and read */
- tm->tm_sec = hclock_read(0);
- tm->tm_min = hclock_read(2);
- tm->tm_hour = hclock_read(4);
- tm->tm_wday = hclock_read(6);
- tm->tm_mday = hclock_read(7);
- tm->tm_mon = hclock_read(8);
- tm->tm_year = hclock_read(9);
- status = hclock_read(11);
+/*
+ * Read the hardware clock and return the current time via <tm> argument.
+ * Assume we have an ISA machine and read the clock directly with CPU I/O
+ * instructions.
+ *
+ * This function is not totally reliable. It takes a finite and
+ * unpredictable amount of time to execute the code below. During that time,
+ * the clock may change and we may even read an invalid value in the middle
+ * of an update. We do a few checks to minimize this possibility, but only
+ * the kernel can actually read the clock properly, since it can execute
+ * code in a short and predictable amount of time (by turning of
+ * interrupts).
+ *
+ * In practice, the chance of this function returning the wrong time is
+ * extremely remote.
+ */
+static int read_hardware_clock_cmos(struct tm *tm)
+{
+ bool got_time = FALSE;
+ unsigned char status, pmbit;
+
+ status = pmbit = 0; /* just for gcc */
+
+ while (!got_time) {
+ /*
+ * Bit 7 of Byte 10 of the Hardware Clock value is the
+ * Update In Progress (UIP) bit, which is on while and 244
+ * uS before the Hardware Clock updates itself. It updates
+ * the counters individually, so reading them during an
+ * update would produce garbage. The update takes 2mS, so we
+ * could be spinning here that long waiting for this bit to
+ * turn off.
+ *
+ * Furthermore, it is pathologically possible for us to be
+ * in this code so long that even if the UIP bit is not on
+ * at first, the clock has changed while we were running. We
+ * check for that too, and if it happens, we start over.
+ */
+ if (!cmos_clock_busy()) {
+ /* No clock update in progress, go ahead and read */
+ tm->tm_sec = hclock_read(0);
+ tm->tm_min = hclock_read(2);
+ tm->tm_hour = hclock_read(4);
+ tm->tm_wday = hclock_read(6);
+ tm->tm_mday = hclock_read(7);
+ tm->tm_mon = hclock_read(8);
+ tm->tm_year = hclock_read(9);
+ status = hclock_read(11);
#if 0
- if (century_byte)
- century = hclock_read(century_byte);
+ if (century_byte)
+ century = hclock_read(century_byte);
#endif
+ /*
+ * Unless the clock changed while we were reading,
+ * consider this a good clock read .
+ */
+ if (tm->tm_sec == hclock_read(0))
+ got_time = TRUE;
+ }
+ /*
+ * Yes, in theory we could have been running for 60 seconds
+ * and the above test wouldn't work!
+ */
+ }
- /* Unless the clock changed while we were reading, consider this
- a good clock read .
- */
- if (tm->tm_sec == hclock_read (0))
- got_time = TRUE;
- }
- /* Yes, in theory we could have been running for 60 seconds and
- the above test wouldn't work!
- */
- }
-
- if (!(status & 0x04)) { /* BCD mode - the default */
- BCD_TO_BIN(tm->tm_sec);
- BCD_TO_BIN(tm->tm_min);
- pmbit = (tm->tm_hour & 0x80);
- tm->tm_hour &= 0x7f;
- BCD_TO_BIN(tm->tm_hour);
- BCD_TO_BIN(tm->tm_wday);
- BCD_TO_BIN(tm->tm_mday);
- BCD_TO_BIN(tm->tm_mon);
- BCD_TO_BIN(tm->tm_year);
+ if (!(status & 0x04)) { /* BCD mode - the default */
+ BCD_TO_BIN(tm->tm_sec);
+ BCD_TO_BIN(tm->tm_min);
+ pmbit = (tm->tm_hour & 0x80);
+ tm->tm_hour &= 0x7f;
+ BCD_TO_BIN(tm->tm_hour);
+ BCD_TO_BIN(tm->tm_wday);
+ BCD_TO_BIN(tm->tm_mday);
+ BCD_TO_BIN(tm->tm_mon);
+ BCD_TO_BIN(tm->tm_year);
#if 0
- BCD_TO_BIN(century);
+ BCD_TO_BIN(century);
#endif
- }
-
- /* We don't use the century byte of the Hardware Clock
- since we don't know its address (usually 50 or 55).
- Here, we follow the advice of the X/Open Base Working Group:
- "if century is not specified, then values in the range [69-99]
- refer to years in the twentieth century (1969 to 1999 inclusive),
- and values in the range [00-68] refer to years in the twenty-first
- century (2000 to 2068 inclusive)."
- */
-
- tm->tm_wday -= 1;
- tm->tm_mon -= 1;
- tm->tm_year += (cmos_epoch - TM_EPOCH);
- if (tm->tm_year < 69)
- tm->tm_year += 100;
- if (pmbit) {
- tm->tm_hour += 12;
- if (tm->tm_hour == 24)
- tm->tm_hour = 0;
- }
-
- tm->tm_isdst = -1; /* don't know whether it's daylight */
- return 0;
-}
+ }
+ /*
+ * We don't use the century byte of the Hardware Clock since we
+ * don't know its address (usually 50 or 55). Here, we follow the
+ * advice of the X/Open Base Working Group: "if century is not
+ * specified, then values in the range [69-99] refer to years in the
+ * twentieth century (1969 to 1999 inclusive), and values in the
+ * range [00-68] refer to years in the twenty-first century (2000 to
+ * 2068 inclusive)."
+ */
+ tm->tm_wday -= 1;
+ tm->tm_mon -= 1;
+ tm->tm_year += (cmos_epoch - TM_EPOCH);
+ if (tm->tm_year < 69)
+ tm->tm_year += 100;
+ if (pmbit) {
+ tm->tm_hour += 12;
+ if (tm->tm_hour == 24)
+ tm->tm_hour = 0;
+ }
+ tm->tm_isdst = -1; /* don't know whether it's daylight */
+ return 0;
+}
-static int
-set_hardware_clock_cmos(const struct tm *new_broken_time) {
+static int set_hardware_clock_cmos(const struct tm *new_broken_time)
+{
- hclock_set_time(new_broken_time);
- return 0;
+ hclock_set_time(new_broken_time);
+ return 0;
}
-static int
-i386_iopl(const int level) {
+static int i386_iopl(const int level)
+{
#if defined(__i386__) || defined(__alpha__)
#if defined(HAVE_IOPL)
- extern int iopl(const int lvl);
- return iopl(level);
+ extern int iopl(const int lvl);
+ return iopl(level);
#else
- extern int ioperm(unsigned long from, unsigned long num, int turn_on);
- return ioperm(clock_ctl_addr, 2, 1);
+ extern int ioperm(unsigned long from, unsigned long num, int turn_on);
+ return ioperm(clock_ctl_addr, 2, 1);
#endif
#else
- return -2;
+ return -2;
#endif
}
-static int
-get_permissions_cmos(void) {
- int rc;
-
- if (use_dev_port) {
- if ((dev_port_fd = open("/dev/port", O_RDWR)) < 0) {
- int errsv = errno;
- fprintf(stderr, _("Cannot open /dev/port: %s"), strerror(errsv));
- rc = 1;
- } else
- rc = 0;
- } else {
- rc = i386_iopl(3);
- if (rc == -2) {
- fprintf(stderr, _("I failed to get permission because I didn't try.\n"));
- } else if (rc != 0) {
- rc = errno;
- fprintf(stderr, _("%s is unable to get I/O port access: "
- "the iopl(3) call failed.\n"), progname);
- if(rc == EPERM && geteuid())
- fprintf(stderr, _("Probably you need root privileges.\n"));
- }
- }
- return rc ? 1 : 0;
+static int get_permissions_cmos(void)
+{
+ int rc;
+
+ if (use_dev_port) {
+ if ((dev_port_fd = open("/dev/port", O_RDWR)) < 0) {
+ int errsv = errno;
+ fprintf(stderr, _("Cannot open /dev/port: %s"),
+ strerror(errsv));
+ rc = 1;
+ } else
+ rc = 0;
+ } else {
+ rc = i386_iopl(3);
+ if (rc == -2) {
+ fprintf(stderr,
+ _
+ ("I failed to get permission because I didn't try.\n"));
+ } else if (rc != 0) {
+ rc = errno;
+ fprintf(stderr,
+ _("%s is unable to get I/O port access: "
+ "the iopl(3) call failed.\n"), progname);
+ if (rc == EPERM && geteuid())
+ fprintf(stderr,
+ _
+ ("Probably you need root privileges.\n"));
+ }
+ }
+ return rc ? 1 : 0;
}
static struct clock_ops cmos = {
@@ -613,17 +654,17 @@ static struct clock_ops cmos = {
synchronize_to_clock_tick_cmos,
};
-
-/* return &cmos if cmos clock present, NULL otherwise */
-/* choose this construction to avoid gcc messages about unused variables */
-
-struct clock_ops *
-probe_for_cmos_clock(void){
- int have_cmos =
+/*
+ * return &cmos if cmos clock present, NULL otherwise choose this
+ * construction to avoid gcc messages about unused variables
+ */
+struct clock_ops *probe_for_cmos_clock(void)
+{
+ int have_cmos =
#if defined(__i386__) || defined(__alpha__)
TRUE;
#else
FALSE;
#endif
- return have_cmos ? &cmos : NULL;
+ return have_cmos ? &cmos : NULL;
}