Merge branch 'hwclock-date7-3' of github.com:jwpi/util-linux

* 'hwclock-date7-3' of github.com:jwpi/util-linux:
  hwclock: remove unused 'silent' arg
  hwclock: remove dead cmos code
  hwclock: improve cmos message strings
  hwclock: remove unused atomic arg in cmos
  hwclock: remove unused cmos ctl structs
  hwclock: remove alpha cmos
This commit is contained in:
Karel Zak 2017-04-04 14:41:50 +02:00
commit c9700fc156
5 changed files with 119 additions and 471 deletions

View File

@ -76,17 +76,8 @@ static int inb(int c __attribute__((__unused__)))
return 0; return 0;
} }
# endif /* __i386__ __x86_64__ */ # endif /* __i386__ __x86_64__ */
#elif defined(__alpha__) #else
# ifdef HAVE_SYS_IO_H # warning "disable cmos access - not i386 or x86_64"
# include <sys/io.h>
# else
/* <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 int iopl(int level);
# endif
#else /* __alpha__ */
# warning "disable cmos access - not i386, x86_64, or alpha"
static void outb(int a __attribute__((__unused__)), static void outb(int a __attribute__((__unused__)),
int b __attribute__((__unused__))) int b __attribute__((__unused__)))
{ {
@ -106,286 +97,60 @@ static int inb(int c __attribute__((__unused__)))
#define IOPL_NOT_IMPLEMENTED -2 #define IOPL_NOT_IMPLEMENTED -2
/* /*
* The epoch. * POSIX uses 1900 as epoch for a struct tm, and 1970 for a time_t.
*
* 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 #define TM_EPOCH 1900
static int cmos_epoch = 1900;
/* static unsigned short clock_ctl_addr = 0x70;
* Martin Ostermann writes: static unsigned short clock_data_addr = 0x71;
*
* The problem with the Jensen is twofold: First, it has the clock at a
* different address. Secondly, it has a distinction between "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.
*/
static int use_dev_port = 0; /* 1 for Jensen */
static int dev_port_fd;
static unsigned short clock_ctl_addr = 0x70; /* 0x170 for Jensen */
static unsigned short clock_data_addr = 0x71; /* 0x171 for Jensen */
static int century_byte = 0; /* 0: don't access a century byte
* 50 (0x32): usual PC value
* 55 (0x37): PS/2
*/
#ifdef __alpha__
static int funkyTOY = 0; /* 1 for PC164/LX164/SX164 type alpha */
#endif
#ifdef __alpha
static int is_in_cpuinfo(char *fmt, char *str)
{
FILE *cpuinfo;
char field[256];
char format[sizeof(field)];
int found = 0;
sprintf(format, "%s : %s", fmt, "%255s");
cpuinfo = fopen(_PATH_PROC_CPUINFO, "r");
if (cpuinfo) {
do {
if (fscanf(cpuinfo, format, field) == 1) {
if (strncmp(field, str, strlen(str)) == 0)
found = 1;
break;
}
} while (fgets(field, 256, cpuinfo));
fclose(cpuinfo);
}
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(const struct hwclock_control *ctl)
{
unsigned long epoch;
/* Believe the user */
if (ctl->epoch_option) {
cmos_epoch = ctl->epoch_option;
return;
}
if (ctl->ARCconsole)
cmos_epoch = 1980;
if (ctl->ARCconsole || ctl->SRM)
return;
#ifdef __linux__
/*
* If we can ask the kernel, we don't need guessing from
* /proc/cpuinfo
*/
if (get_epoch_rtc(ctl, &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.
* 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")) {
if (ctl->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 (is_in_cpuinfo("system type", "Ruffian")) {
if (debug)
printf(_("Ruffian BCD clock\n"));
return;
}
}
cmos_epoch = 1980;
}
void set_cmos_access(const struct hwclock_control *ctl)
{
/*
* 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 (ctl->Jensen || is_in_cpuinfo("system type", "Jensen")) {
use_dev_port = 1;
clock_ctl_addr = 0x170;
clock_data_addr = 0x171;
if (ctl->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 (ctl->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 (ctl->debug)
printf(_("funky TOY!\n"));
}
}
#endif /* __alpha */
#ifdef __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.
*/
static unsigned long
atomic(const char *name,
unsigned long (*op) (const struct hwclock_control *ctl, unsigned long),
const struct hwclock_control *ctl,
unsigned long arg)
{
unsigned long ts1, ts2, n, v;
for (n = 0; n < 1000; ++n) {
asm volatile ("rpcc %0":"r=" (ts1));
v = (*op) (ctl, arg);
asm volatile ("rpcc %0":"r=" (ts2));
if ((ts1 ^ ts2) >> 32 == 0) {
return v;
}
}
errx(EXIT_FAILURE, _("atomic %s failed for 1000 iterations!"),
name);
}
#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 static unsigned long atomic(unsigned long (*op) (unsigned long),
atomic(const char *name __attribute__ ((__unused__)), unsigned long arg)
unsigned long (*op) (const struct hwclock_control *ctl, unsigned long),
const struct hwclock_control *ctl,
unsigned long arg)
{ {
return (*op) (ctl, arg); return (*op) (arg);
} }
#endif /*
* 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(const struct hwclock_control *ctl, static inline unsigned long cmos_read(unsigned long reg)
unsigned long reg)
{ {
if (use_dev_port) { outb(reg, clock_ctl_addr);
unsigned char v = reg | 0x80; return inb(clock_data_addr);
lseek(dev_port_fd, clock_ctl_addr, 0);
if (write(dev_port_fd, &v, 1) == -1 && ctl->debug)
warn(_("cmos_read(): write to control address %X failed"),
clock_ctl_addr);
lseek(dev_port_fd, clock_data_addr, 0);
if (read(dev_port_fd, &v, 1) == -1 && ctl->debug)
warn(_("cmos_read(): read from data address %X failed"),
clock_data_addr);
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 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
*/
outb(reg, clock_ctl_addr);
return inb(clock_data_addr);
}
} }
static inline unsigned long cmos_write(const struct hwclock_control *ctl, static inline unsigned long cmos_write(unsigned long reg, unsigned long val)
unsigned long reg, unsigned long val)
{ {
if (use_dev_port) { outb(reg, clock_ctl_addr);
unsigned char v = reg | 0x80; outb(val, clock_data_addr);
lseek(dev_port_fd, clock_ctl_addr, 0);
if (write(dev_port_fd, &v, 1) == -1 && ctl->debug)
warn(_("cmos_write(): write to control address %X failed"),
clock_ctl_addr);
v = (val & 0xff);
lseek(dev_port_fd, clock_data_addr, 0);
if (write(dev_port_fd, &v, 1) == -1 && ctl->debug)
warn(_("cmos_write(): write to data address %X failed"),
clock_data_addr);
} else {
outb(reg, clock_ctl_addr);
outb(val, clock_data_addr);
}
return 0; return 0;
} }
static unsigned long cmos_set_time(const struct hwclock_control *ctl, static unsigned long cmos_set_time(unsigned long arg)
unsigned long arg)
{ {
unsigned char save_control, save_freq_select, pmbit = 0; unsigned char save_control, save_freq_select, pmbit = 0;
struct tm tm = *(struct tm *)arg; struct tm tm = *(struct tm *)arg;
unsigned int century;
/* /*
* CMOS byte 10 (clock status register A) has 3 bitfields: * CMOS byte 10 (clock status register A) has 3 bitfields:
@ -404,14 +169,11 @@ static unsigned long cmos_set_time(const struct hwclock_control *ctl,
* 1111 500 milliseconds (maximum, 2 Hz) * 1111 500 milliseconds (maximum, 2 Hz)
* 0110 976.562 microseconds (default 1024 Hz) * 0110 976.562 microseconds (default 1024 Hz)
*/ */
save_control = cmos_read(ctl, 11); /* tell the clock it's being set */ save_control = cmos_read(11); /* tell the clock it's being set */
cmos_write(ctl, 11, (save_control | 0x80)); cmos_write(11, (save_control | 0x80));
save_freq_select = cmos_read(ctl, 10); /* stop and reset prescaler */ save_freq_select = cmos_read(10); /* stop and reset prescaler */
cmos_write(ctl, 10, (save_freq_select | 0x70)); 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_year %= 100;
tm.tm_mon += 1; tm.tm_mon += 1;
tm.tm_wday += 1; tm.tm_wday += 1;
@ -433,18 +195,15 @@ static unsigned long cmos_set_time(const struct hwclock_control *ctl,
BIN_TO_BCD(tm.tm_mday); BIN_TO_BCD(tm.tm_mday);
BIN_TO_BCD(tm.tm_mon); BIN_TO_BCD(tm.tm_mon);
BIN_TO_BCD(tm.tm_year); BIN_TO_BCD(tm.tm_year);
BIN_TO_BCD(century);
} }
cmos_write(ctl, 0, tm.tm_sec); cmos_write(0, tm.tm_sec);
cmos_write(ctl, 2, tm.tm_min); cmos_write(2, tm.tm_min);
cmos_write(ctl, 4, tm.tm_hour | pmbit); cmos_write(4, tm.tm_hour | pmbit);
cmos_write(ctl, 6, tm.tm_wday); cmos_write(6, tm.tm_wday);
cmos_write(ctl, 7, tm.tm_mday); cmos_write(7, tm.tm_mday);
cmos_write(ctl, 8, tm.tm_mon); cmos_write(8, tm.tm_mon);
cmos_write(ctl, 9, tm.tm_year); cmos_write(9, tm.tm_year);
if (century_byte)
cmos_write(ctl, century_byte, century);
/* /*
* The kernel sources, linux/arch/i386/kernel/time.c, have the * The kernel sources, linux/arch/i386/kernel/time.c, have the
@ -457,30 +216,26 @@ static unsigned long cmos_set_time(const struct hwclock_control *ctl,
* the Dallas Semiconductor data sheets, but who believes data * the Dallas Semiconductor data sheets, but who believes data
* sheets anyway ... -- Markus Kuhn * sheets anyway ... -- Markus Kuhn
*/ */
cmos_write(ctl, 11, save_control); cmos_write(11, save_control);
cmos_write(ctl, 10, save_freq_select); cmos_write(10, save_freq_select);
return 0; return 0;
} }
static int hclock_read(const struct hwclock_control *ctl, unsigned long reg) static int hclock_read(unsigned long reg)
{ {
return atomic("clock read", cmos_read, ctl, reg); return atomic(cmos_read, reg);
} }
static void hclock_set_time(const struct hwclock_control *ctl, const struct tm *tm) static void hclock_set_time(const struct tm *tm)
{ {
atomic("set time", cmos_set_time, ctl, (unsigned long)(tm)); atomic(cmos_set_time, (unsigned long)(tm));
} }
static inline int cmos_clock_busy(const struct hwclock_control *ctl) static inline int cmos_clock_busy(void)
{ {
return return
#ifdef __alpha__
/* poll bit 4 (UF) of Control Register C */
funkyTOY ? (hclock_read(ctl, 12) & 0x10) :
#endif
/* poll bit 7 (UIP) of Control Register A */ /* poll bit 7 (UIP) of Control Register A */
(hclock_read(ctl, 10) & 0x80); (hclock_read(10) & 0x80);
} }
static int synchronize_to_clock_tick_cmos(const struct hwclock_control *ctl static int synchronize_to_clock_tick_cmos(const struct hwclock_control *ctl
@ -493,12 +248,12 @@ static int synchronize_to_clock_tick_cmos(const struct hwclock_control *ctl
* weird happens, we have a limit on this loop to reduce the impact * weird happens, we have a limit on this loop to reduce the impact
* of this failure. * of this failure.
*/ */
for (i = 0; !cmos_clock_busy(ctl); i++) for (i = 0; !cmos_clock_busy(); i++)
if (i >= 10000000) if (i >= 10000000)
return 1; return 1;
/* Wait for fall. Should be within 2.228 ms. */ /* Wait for fall. Should be within 2.228 ms. */
for (i = 0; cmos_clock_busy(ctl); i++) for (i = 0; cmos_clock_busy(); i++)
if (i >= 1000000) if (i >= 1000000)
return 1; return 1;
return 0; return 0;
@ -541,25 +296,21 @@ static int read_hardware_clock_cmos(const struct hwclock_control *ctl
* at first, the clock has changed while we were running. We * at first, the clock has changed while we were running. We
* check for that too, and if it happens, we start over. * check for that too, and if it happens, we start over.
*/ */
if (!cmos_clock_busy(ctl)) { if (!cmos_clock_busy()) {
/* No clock update in progress, go ahead and read */ /* No clock update in progress, go ahead and read */
tm->tm_sec = hclock_read(ctl, 0); tm->tm_sec = hclock_read(0);
tm->tm_min = hclock_read(ctl, 2); tm->tm_min = hclock_read(2);
tm->tm_hour = hclock_read(ctl, 4); tm->tm_hour = hclock_read(4);
tm->tm_wday = hclock_read(ctl, 6); tm->tm_wday = hclock_read(6);
tm->tm_mday = hclock_read(ctl, 7); tm->tm_mday = hclock_read(7);
tm->tm_mon = hclock_read(ctl, 8); tm->tm_mon = hclock_read(8);
tm->tm_year = hclock_read(ctl, 9); tm->tm_year = hclock_read(9);
status = hclock_read(ctl, 11); status = hclock_read(11);
#if 0
if (century_byte)
century = hclock_read(ctl, century_byte);
#endif
/* /*
* Unless the clock changed while we were reading, * Unless the clock changed while we were reading,
* consider this a good clock read . * consider this a good clock read .
*/ */
if (tm->tm_sec == hclock_read(ctl, 0)) if (tm->tm_sec == hclock_read(0))
got_time = TRUE; got_time = TRUE;
} }
/* /*
@ -578,9 +329,6 @@ static int read_hardware_clock_cmos(const struct hwclock_control *ctl
BCD_TO_BIN(tm->tm_mday); BCD_TO_BIN(tm->tm_mday);
BCD_TO_BIN(tm->tm_mon); BCD_TO_BIN(tm->tm_mon);
BCD_TO_BIN(tm->tm_year); BCD_TO_BIN(tm->tm_year);
#if 0
BCD_TO_BIN(century);
#endif
} }
/* /*
@ -594,7 +342,6 @@ static int read_hardware_clock_cmos(const struct hwclock_control *ctl
*/ */
tm->tm_wday -= 1; tm->tm_wday -= 1;
tm->tm_mon -= 1; tm->tm_mon -= 1;
tm->tm_year += (cmos_epoch - TM_EPOCH);
if (tm->tm_year < 69) if (tm->tm_year < 69)
tm->tm_year += 100; tm->tm_year += 100;
if (pmbit) { if (pmbit) {
@ -611,12 +358,11 @@ static int set_hardware_clock_cmos(const struct hwclock_control *ctl
__attribute__((__unused__)), __attribute__((__unused__)),
const struct tm *new_broken_time) const struct tm *new_broken_time)
{ {
hclock_set_time(new_broken_time);
hclock_set_time(ctl, new_broken_time);
return 0; return 0;
} }
#if defined(__i386__) || defined(__alpha__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
# if defined(HAVE_IOPL) # if defined(HAVE_IOPL)
static int i386_iopl(const int level) static int i386_iopl(const int level)
{ {
@ -640,29 +386,20 @@ static int get_permissions_cmos(void)
{ {
int rc; int rc;
if (use_dev_port) { rc = i386_iopl(3);
if ((dev_port_fd = open(_PATH_DEV_PORT, O_RDWR)) < 0) { if (rc == IOPL_NOT_IMPLEMENTED) {
warn(_("cannot open %s"), _PATH_DEV_PORT); warnx(_("ISA port access is not implemented"));
rc = 1; } else if (rc != 0) {
} else rc = errno;
rc = 0; warn(_("iopl() port access failed"));
} else { if (rc == EPERM && geteuid())
rc = i386_iopl(3); warnx(_("root privileges may be required"));
if (rc == IOPL_NOT_IMPLEMENTED) {
warnx(_("I failed to get permission because I didn't try."));
} else if (rc != 0) {
rc = errno;
warn(_("unable to get I/O port access: "
"the iopl(3) call failed"));
if (rc == EPERM && geteuid())
warnx(_("Probably you need root privileges.\n"));
}
} }
return rc ? 1 : 0; return rc ? 1 : 0;
} }
static struct clock_ops cmos_interface = { static struct clock_ops cmos_interface = {
N_("Using direct I/O instructions to ISA clock."), N_("Using direct ISA access to the clock"),
get_permissions_cmos, get_permissions_cmos,
read_hardware_clock_cmos, read_hardware_clock_cmos,
set_hardware_clock_cmos, set_hardware_clock_cmos,
@ -676,7 +413,7 @@ static struct clock_ops cmos_interface = {
struct clock_ops *probe_for_cmos_clock(void) struct clock_ops *probe_for_cmos_clock(void)
{ {
static const int have_cmos = static const int have_cmos =
#if defined(__i386__) || defined(__alpha__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
TRUE; TRUE;
#else #else
FALSE; FALSE;

View File

@ -396,27 +396,23 @@ struct clock_ops *probe_for_rtc_clock(const struct hwclock_control *ctl)
/* /*
* Get the Hardware Clock epoch setting from the kernel. * Get the Hardware Clock epoch setting from the kernel.
*/ */
int get_epoch_rtc(const struct hwclock_control *ctl, unsigned long *epoch_p, int get_epoch_rtc(const struct hwclock_control *ctl, unsigned long *epoch_p)
int silent)
{ {
int rtc_fd; int rtc_fd;
rtc_fd = open_rtc(ctl); rtc_fd = open_rtc(ctl);
if (rtc_fd < 0) { if (rtc_fd < 0) {
if (!silent) { if (errno == ENOENT)
if (errno == ENOENT) warnx(_
warnx(_ ("To manipulate the epoch value in the kernel, we must "
("To manipulate the epoch value in the kernel, we must " "access the Linux 'rtc' device driver via the device special "
"access the Linux 'rtc' device driver via the device special " "file. This file does not exist on this system."));
"file. This file does not exist on this system.")); else
else warn(_("cannot open rtc device"));
warn(_("cannot open rtc device"));
}
return 1; return 1;
} }
if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) { if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) {
if (!silent)
warn(_("ioctl(RTC_EPOCH_READ) to %s failed"), warn(_("ioctl(RTC_EPOCH_READ) to %s failed"),
rtc_dev_name); rtc_dev_name);
return 1; return 1;

View File

@ -44,22 +44,30 @@ discussion below, under
.B \-\-getepoch .B \-\-getepoch
.TQ .TQ
.B \-\-setepoch .B \-\-setepoch
These functions are for Alpha machines only. These functions are for Alpha machines only, and are only available
through the Linux kernel RTC driver.
.sp .sp
Read and set the kernel's Hardware Clock epoch value. They are used to read and set the kernel's Hardware Clock epoch value.
Epoch is the number of years into AD to which a zero year value in the Epoch is the number of years into AD to which a zero year value in the
Hardware Clock refers. For example, if you are using the convention Hardware Clock refers. For example, if the machine's BIOS sets the year
that the year counter in your Hardware Clock contains the number of counter in the Hardware Clock to contain the number of full years since
full years since 1952, then the kernel's Hardware Clock epoch value 1952, then the kernel's Hardware Clock epoch value must be 1952.
must be 1952.
.sp .sp
The \fB\%\-\-setepoch\fR function requires using the The \fB\%\-\-setepoch\fR function requires using the
.B \%\-\-epoch .B \%\-\-epoch
option to specify the year. option to specify the year. For example:
.sp .RS
.IP "" 4
.B hwclock\ \-\-setepoch\ \-\-epoch=1952
.PP
The RTC driver attempts to guess the correct epoch value, so setting it
may not be required.
.PP
This epoch value is used whenever This epoch value is used whenever
.B \%hwclock .B \%hwclock
reads or sets the Hardware Clock. reads or sets the Hardware Clock on an Alpha machine. For ISA machines
the kernel uses the fixed Hardware Clock epoch of 1900.
.RE
. .
.TP .TP
.B \-\-predict .B \-\-predict
@ -278,23 +286,27 @@ can help you understand how the program works.
. .
.TP .TP
.B \-\-directisa .B \-\-directisa
This option is meaningful for: ISA compatible machines including x86, and This option is meaningful for ISA compatible machines in the x86 and
x86_64; and Alpha (which has a similar Hardware Clock interface). For other x86_64 family. For other machines, it has no effect. This option tells
machines, it has no effect. This option tells
.B \%hwclock .B \%hwclock
to use explicit I/O instructions to access the Hardware Clock. to use explicit I/O instructions to access the Hardware Clock.
Without this option, Without this option,
.B \%hwclock .B \%hwclock
will use the rtc device, which it assumes to be driven by the RTC device will use the rtc device file, which it assumes to be driven by the Linux
driver. As of v2.26 it will no longer automatically use directisa when RTC device driver. As of v2.26 it will no longer automatically use
the rtc driver is unavailable; this was causing an unsafe condition that directisa when the rtc driver is unavailable; this was causing an unsafe
could allow two processes to access the Hardware Clock at the same time. condition that could allow two processes to access the Hardware Clock at
Direct hardware access from userspace should only be used for testing, the same time. Direct hardware access from userspace should only be
troubleshooting, and as a last resort when all other methods fail. See used for testing, troubleshooting, and as a last resort when all other
the methods fail. See the
.BR \-\-rtc " option." .BR \-\-rtc " option."
. .
.TP .TP
.BI \-\-epoch= year
This option is required when using the
.BR \%\-\-setepoch \ function.
.
.TP
.BR \-f , \ \-\-rtc=\fIfilename\fR .BR \-f , \ \-\-rtc=\fIfilename\fR
.RB "Override " \%hwclock 's .RB "Override " \%hwclock 's
default rtc device file name. Otherwise it will default rtc device file name. Otherwise it will
@ -402,55 +414,6 @@ option to be used. See the discussion below, under
.BR "The Adjust Function" . .BR "The Adjust Function" .
.RE .RE
. .
.SH OPTIONS FOR ALPHA MACHINES ONLY
.
.TP
.B \-\-arc
This option is equivalent to
.B \%\-\-epoch=1980
and is used to specify the most common epoch on Alphas
with an ARC console (although Ruffians have an epoch of 1900).
.
.TP
.BI \-\-epoch= year
Specifies the year which is the beginning of the Hardware Clock's epoch,
that is the number of years into AD to which a zero value in the
Hardware Clock's year counter refers. It is used together with the
.B \%\-\-setepoch
option to set the kernel's idea of the epoch of the Hardware Clock.
.sp
For example, on a Digital Unix machine:
.RS
.IP "" 4
.B hwclock\ \-\-setepoch\ \-\-epoch=1952
.RE
.
.TP
.B \-\-funky\-toy
.TQ
.B \-\-jensen
These two options specify what kind of Alpha machine you have. They
are invalid if you do not have an Alpha and are usually unnecessary
if you do;
.B \%hwclock
should be able to determine what it is running on when
.I \%/proc
is mounted.
.sp
.RB "The " \%\-\-jensen
option is used for Jensen models;
.B \%\-\-funky\-toy
means that the machine requires the UF bit instead of the UIP bit in
the Hardware Clock to detect a time transition. The "toy" in the option
name refers to the Time Of Year facility of the machine.
.
.TP
.B \-\-srm
This option is equivalent to
.B \%\-\-epoch=1900
and is used to specify the most common epoch on Alphas
with an SRM console.
.
.SH NOTES .SH NOTES
. .
.SS Clocks in a Linux System .SS Clocks in a Linux System
@ -566,15 +529,8 @@ reasons that userspace programs are generally not supposed to do
direct I/O and disable interrupts. direct I/O and disable interrupts.
.B \%hwclock .B \%hwclock
provides it for testing, troubleshooting, and because it may be the provides it for testing, troubleshooting, and because it may be the
only method available on ISA compatible and Alpha systems which do not only method available on ISA systems which do not have a working rtc
have a working rtc device driver. device driver.
.PP
In the case of a Jensen Alpha, there is no way for
.B \%hwclock
to execute those I/O instructions, and so it uses instead the
.I \%/dev/port
device special file, which provides almost as low-level an interface to
the I/O subsystem.
.PP .PP
On an m68k system, On an m68k system,
.B \%hwclock .B \%hwclock

View File

@ -1190,7 +1190,7 @@ manipulate_epoch(const struct hwclock_control *ctl)
if (ctl->getepoch) { if (ctl->getepoch) {
unsigned long epoch; unsigned long epoch;
if (get_epoch_rtc(ctl, &epoch, 0)) if (get_epoch_rtc(ctl, &epoch))
warnx(_ warnx(_
("Unable to get the epoch value from the kernel.")); ("Unable to get the epoch value from the kernel."));
else else
@ -1279,11 +1279,6 @@ static void usage(const struct hwclock_control *ctl, const char *fmt, ...)
" the default is %1$s\n"), _PATH_ADJTIME); " the default is %1$s\n"), _PATH_ADJTIME);
fputs(_(" --test do not update anything, just show what would happen\n" fputs(_(" --test do not update anything, just show what would happen\n"
" -D, --debug debugging mode\n" "\n"), usageto); " -D, --debug debugging mode\n" "\n"), usageto);
#ifdef __alpha__
fputs(_(" -J|--jensen, -A|--arc, -S|--srm, -F|--funky-toy\n"
" tell hwclock the type of Alpha you have (see hwclock(8))\n"
"\n"), usageto);
#endif
if (fmt) { if (fmt) {
va_start(ap, fmt); va_start(ap, fmt);
@ -1344,15 +1339,6 @@ int main(int argc, char **argv)
{ "version", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'v' },
{ "systohc", no_argument, NULL, 'w' }, { "systohc", no_argument, NULL, 'w' },
{ "debug", no_argument, NULL, 'D' }, { "debug", no_argument, NULL, 'D' },
#ifdef __alpha__
{ "ARC", no_argument, NULL, 'A' },
{ "arc", no_argument, NULL, 'A' },
{ "Jensen", no_argument, NULL, 'J' },
{ "jensen", no_argument, NULL, 'J' },
{ "SRM", no_argument, NULL, 'S' },
{ "srm", no_argument, NULL, 'S' },
{ "funky-toy", no_argument, NULL, 'F' },
#endif
{ "set", no_argument, NULL, OPT_SET }, { "set", no_argument, NULL, OPT_SET },
#ifdef __linux__ #ifdef __linux__
{ "getepoch", no_argument, NULL, OPT_GETEPOCH }, { "getepoch", no_argument, NULL, OPT_GETEPOCH },
@ -1438,20 +1424,6 @@ int main(int argc, char **argv)
case 'w': case 'w':
ctl.systohc = 1; ctl.systohc = 1;
break; break;
#ifdef __alpha__
case 'A':
ctl.ARCconsole = 1;
break;
case 'J':
ctl.Jensen = 1;
break;
case 'S':
ctl.SRM = 1;
break;
case 'F':
ctl.funky_toy = 1;
break;
#endif
case OPT_SET: case OPT_SET:
ctl.set = 1; ctl.set = 1;
break; break;
@ -1538,10 +1510,6 @@ int main(int argc, char **argv)
"either --utc or --localtime")); "either --utc or --localtime"));
hwclock_exit(&ctl, EX_USAGE); hwclock_exit(&ctl, EX_USAGE);
} }
#ifdef __alpha__
set_cmos_epoch(&ctl);
set_cmos_access(&ctl);
#endif
if (ctl.set || ctl.predict) { if (ctl.set || ctl.predict) {
if (parse_date(&when, ctl.date_opt, NULL)) if (parse_date(&when, ctl.date_opt, NULL))

View File

@ -32,12 +32,6 @@ struct hwclock_control {
hctosys:1, hctosys:1,
utc:1, utc:1,
systohc:1, systohc:1,
#ifdef __alpha__
ARCconsole:1,
Jensen:1,
SRM:1,
funky_toy:1,
#endif
#ifdef __linux__ #ifdef __linux__
getepoch:1, getepoch:1,
setepoch:1, setepoch:1,
@ -71,12 +65,9 @@ typedef int bool;
extern int debug; extern int debug;
extern unsigned long epoch_option; extern unsigned long epoch_option;
extern double time_diff(struct timeval subtrahend, struct timeval subtractor); extern double time_diff(struct timeval subtrahend, struct timeval subtractor);
/* cmos.c */
extern void set_cmos_epoch(const struct hwclock_control *ctl);
extern void set_cmos_access(const struct hwclock_control *ctl);
/* rtc.c */ /* rtc.c */
extern int get_epoch_rtc(const struct hwclock_control *ctl, unsigned long *epoch, int silent); extern int get_epoch_rtc(const struct hwclock_control *ctl, unsigned long *epoch);
extern int set_epoch_rtc(const struct hwclock_control *ctl); extern int set_epoch_rtc(const struct hwclock_control *ctl);
extern void hwclock_exit(const struct hwclock_control *ctl, int status); extern void hwclock_exit(const struct hwclock_control *ctl, int status);