| /* |
| * 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. |
| * |
| * 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. |
| */ |
| /* |
| * 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 |
| */ |
| |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "c.h" |
| #include "nls.h" |
| #include "pathnames.h" |
| |
| /* for inb, outb */ |
| #if defined(__i386__) || defined(__x86_64__) |
| # ifdef HAVE_SYS_IO_H |
| # include <sys/io.h> |
| # elif defined(HAVE_ASM_IO_H) |
| # include <asm/io.h> |
| # else |
| # undef __i386__ |
| # undef __x86_64__ |
| # warning "disable cmos access - no sys/io.h or asm/io.h" |
| static void outb(int a __attribute__((__unused__)), |
| int b __attribute__((__unused__))) |
| { |
| } |
| |
| static int inb(int c __attribute__((__unused__))) |
| { |
| return 0; |
| } |
| # endif /* __i386__ __x86_64__ */ |
| #else |
| # warning "disable cmos access - not i386 or x86_64" |
| static void outb(int a __attribute__((__unused__)), |
| int b __attribute__((__unused__))) |
| { |
| } |
| |
| static int inb(int c __attribute__((__unused__))) |
| { |
| return 0; |
| } |
| #endif /* for inb, outb */ |
| |
| #include "hwclock.h" |
| |
| #define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) |
| #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10) |
| |
| #define IOPL_NOT_IMPLEMENTED -2 |
| |
| /* |
| * POSIX uses 1900 as epoch for a struct tm, and 1970 for a time_t. |
| */ |
| #define TM_EPOCH 1900 |
| |
| static unsigned short clock_ctl_addr = 0x70; |
| static unsigned short clock_data_addr = 0x71; |
| |
| /* |
| * 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 |
| */ |
| static unsigned long atomic(unsigned long (*op) (unsigned long), |
| unsigned long arg) |
| { |
| return (*op) (arg); |
| } |
| |
| /* |
| * 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 will be left in an unknown state". Most |
| * docs say that it doesn't 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 |
| */ |
| |
| static inline unsigned long cmos_read(unsigned long reg) |
| { |
| outb(reg, clock_ctl_addr); |
| return inb(clock_data_addr); |
| } |
| |
| static inline unsigned long cmos_write(unsigned long reg, unsigned long val) |
| { |
| 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; |
| |
| /* |
| * CMOS byte 10 (clock status register A) has 3 bitfields: |
| * bit 7: 1 if data invalid, update in progress (read-only bit) |
| * (this is raised 224 us before the actual update starts) |
| * 6-4 select base frequency |
| * 010: 32768 Hz time base (default) |
| * 111: reset |
| * all other combinations are manufacturer-dependent |
| * (e.g.: DS1287: 010 = start oscillator, anything else = stop) |
| * 3-0 rate selection bits for interrupt |
| * 0000 none (may stop RTC) |
| * 0001, 0010 give same frequency as 1000, 1001 |
| * 0011 122 microseconds (minimum, 8192 Hz) |
| * .... each increase by 1 halves the frequency, doubles the period |
| * 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 %= 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); |
| } |
| |
| 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); |
| |
| /* |
| * 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) |
| { |
| return atomic(cmos_read, reg); |
| } |
| |
| static void hclock_set_time(const struct tm *tm) |
| { |
| atomic(cmos_set_time, (unsigned long)(tm)); |
| } |
| |
| static inline int cmos_clock_busy(void) |
| { |
| return |
| /* poll bit 7 (UIP) of Control Register A */ |
| (hclock_read(10) & 0x80); |
| } |
| |
| static int synchronize_to_clock_tick_cmos(const struct hwclock_control *ctl |
| __attribute__((__unused__))) |
| { |
| 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; |
| } |
| |
| /* |
| * 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(const struct hwclock_control *ctl |
| __attribute__((__unused__)), struct tm *tm) |
| { |
| unsigned char status = 0, pmbit = 0; |
| |
| while (1) { |
| /* |
| * 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); |
| /* |
| * Unless the clock changed while we were reading, |
| * consider this a good clock read . |
| */ |
| if (tm->tm_sec == hclock_read(0)) |
| break; |
| } |
| /* |
| * 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); |
| } |
| |
| /* |
| * 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; |
| 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 hwclock_control *ctl |
| __attribute__((__unused__)), |
| const struct tm *new_broken_time) |
| { |
| hclock_set_time(new_broken_time); |
| return 0; |
| } |
| |
| #if defined(__i386__) || defined(__x86_64__) |
| # if defined(HAVE_IOPL) |
| static int i386_iopl(const int level) |
| { |
| return iopl(level); |
| } |
| # else |
| static int i386_iopl(const int level __attribute__ ((__unused__))) |
| { |
| extern int ioperm(unsigned long from, unsigned long num, int turn_on); |
| return ioperm(clock_ctl_addr, 2, 1); |
| } |
| # endif |
| #else |
| static int i386_iopl(const int level __attribute__ ((__unused__))) |
| { |
| return IOPL_NOT_IMPLEMENTED; |
| } |
| #endif |
| |
| static int get_permissions_cmos(void) |
| { |
| int rc; |
| |
| rc = i386_iopl(3); |
| if (rc == IOPL_NOT_IMPLEMENTED) { |
| warnx(_("ISA port access is not implemented")); |
| } else if (rc != 0) { |
| warn(_("iopl() port access failed")); |
| } |
| return rc; |
| } |
| |
| static const char *get_device_path(void) |
| { |
| return NULL; |
| } |
| |
| static struct clock_ops cmos_interface = { |
| N_("Using direct ISA access to the clock"), |
| get_permissions_cmos, |
| read_hardware_clock_cmos, |
| set_hardware_clock_cmos, |
| synchronize_to_clock_tick_cmos, |
| get_device_path, |
| }; |
| |
| /* |
| * return &cmos if cmos clock present, NULL otherwise. |
| */ |
| struct clock_ops *probe_for_cmos_clock(void) |
| { |
| #if defined(__i386__) || defined(__x86_64__) |
| return &cmos_interface; |
| #else |
| return NULL; |
| #endif |
| } |