blob: 68287cb545da7b2c53f77a2e9e540099d86c8734 [file] [log] [blame]
/**************************************************************************
This is a component of the hwclock program.
This file contains the code for accessing the hardware clock via
the KDHWCLK facility of M68k machines.
****************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include "hwclock.h"
#if defined(KDGHWCLK)
const bool got_kdghwclk = TRUE;
static const int kdghwclk_ioctl = KDGHWCLK;
static const int kdshwclk_ioctl = KDSHWCLK;
#else
const bool got_kdghwclk = FALSE;
static const int kdghwclk_ioctl; /* Never used; just to make compile work */
struct hwclk_time {int sec;};
/* Never used; just to make compile work */
#endif
void
synchronize_to_clock_tick_KD(int *retcode_p) {
/*----------------------------------------------------------------------------
Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until
we see it.
-----------------------------------------------------------------------------*/
int con_fd;
if (debug)
printf("Waiting in loop for time from KDGHWCLK to change\n");
con_fd = open("/dev/tty1", O_RDONLY);
if (con_fd < 0) {
fprintf(stderr, "%s: open() failed to open /dev/tty1, errno = %s (%d).\n",
MYNAME, strerror(errno), errno);
*retcode_p = 1;
} else {
int rc; /* return code from ioctl() */
int i; /* local loop index */
/* The time when we were called (and started waiting) */
struct hwclk_time start_time, nowtime;
rc = ioctl(con_fd, kdghwclk_ioctl, &start_time);
if (rc == -1) {
fprintf(stderr, "%s: KDGHWCLK to read time failed, "
"errno = %s (%d).\n", MYNAME, strerror(errno), errno);
*retcode_p = 3;
}
for (i = 0;
(rc = ioctl(con_fd, kdghwclk_ioctl, &nowtime)) != -1
&& start_time.sec == nowtime.sec && i < 1000000;
i++);
if (i >= 1000000) {
fprintf(stderr, "%s: Timed out waiting for time change.\n", MYNAME);
*retcode_p = 2;
} else if (rc == -1) {
fprintf(stderr, "%s: KDGHWCLK to read time failed, "
"errno = %s (%d).\n", MYNAME, strerror(errno), errno);
*retcode_p = 3;
} else *retcode_p = 0;
close(con_fd);
}
}
void
read_hardware_clock_kd(struct tm *tm) {
/*----------------------------------------------------------------------------
Read the hardware clock and return the current time via <tm>
argument. Use ioctls to /dev/tty1 on what we assume is an m68k
machine.
Note that we don't use /dev/console here. That might be a serial
console.
-----------------------------------------------------------------------------*/
#ifdef KDGHWCLK
int con_fd;
struct hwclk_time t;
con_fd = open("/dev/tty1", O_RDONLY);
if (con_fd < 0) {
fprintf(stderr, "%s: open() failed to open /dev/tty1, errno = %s (%d).\n",
MYNAME, strerror(errno), errno);
exit(5);
} else {
int rc; /* return code from ioctl() */
rc = ioctl(con_fd, kdghwclk_ioctl, &t);
if (rc == -1) {
fprintf(stderr, "%s: ioctl() failed to read time from /dev/tty1, "
"errno = %s (%d).\n",
MYNAME, strerror(errno), errno);
exit(5);
}
close(con_fd);
}
tm->tm_sec = t.sec;
tm->tm_min = t.min;
tm->tm_hour = t.hour;
tm->tm_mday = t.day;
tm->tm_mon = t.mon;
tm->tm_year = t.year;
tm->tm_wday = t.wday;
tm->tm_isdst = -1; /* Don't know if it's Daylight Savings Time */
#else
/* This routine should never be invoked. It is here just to make the
program compile.
*/
#endif
}
void
set_hardware_clock_kd(const struct tm new_broken_time,
const bool testing) {
/*----------------------------------------------------------------------------
Set the Hardware Clock to the time <new_broken_time>. Use ioctls to
/dev/tty1 on what we assume is an m68k machine.
Note that we don't use /dev/console here. That might be a serial console.
----------------------------------------------------------------------------*/
#ifdef KDGHWCLK
int con_fd; /* File descriptor of /dev/tty1 */
struct hwclk_time t;
con_fd = open("/dev/tty1", O_RDONLY);
if (con_fd < 0) {
fprintf(stderr, "%s: Error opening /dev/tty1. Errno: %s (%d)\n",
MYNAME, strerror(errno), errno);
exit(1);
} else {
int rc; /* locally used return code */
t.sec = new_broken_time.tm_sec;
t.min = new_broken_time.tm_min;
t.hour = new_broken_time.tm_hour;
t.day = new_broken_time.tm_mday;
t.mon = new_broken_time.tm_mon;
t.year = new_broken_time.tm_year;
t.wday = new_broken_time.tm_wday;
if (testing)
printf("Not setting Hardware Clock because running in test mode.\n");
else {
rc = ioctl(con_fd, kdshwclk_ioctl, &t );
if (rc < 0) {
fprintf(stderr, "%s: ioctl() to open /dev/tty1 failed. "
"Errno: %s (%d)\n",
MYNAME, strerror(errno), errno);
exit(1);
}
}
close(con_fd);
}
#else
/* This function should never be invoked. It is here just to make the
program compile.
*/
#endif
}
void
see_if_kdghwclk_works(bool * const kdghwclk_works_p) {
/*----------------------------------------------------------------------------
Find out if we are capable of accessing the Hardware Clock via the
KDHWCLK facility (ioctl to /dev/tty1).
-----------------------------------------------------------------------------*/
if (got_kdghwclk) {
int con_fd;
struct hwclk_time t;
con_fd = open("/dev/tty1", O_RDONLY);
if (con_fd >= 0) {
if (ioctl( con_fd, kdghwclk_ioctl, &t ) >= 0)
*kdghwclk_works_p = TRUE;
else {
if (errno == EINVAL) {
/* KDGHWCLK not implemented in this kernel... */
*kdghwclk_works_p = FALSE;
if (debug)
printf(MYNAME "was built with KDGHWCLK capability, but the "
"ioctl does not exist in the kernel. The ioctl (to "
"/dev/tty1) failed with errno EINVAL.\n");
} else {
*kdghwclk_works_p = FALSE;
fprintf(stderr,
"%s: KDGHWCLK ioctl failed, errno = %s (%d).\n",
MYNAME, strerror(errno), errno);
}
}
} else {
*kdghwclk_works_p = FALSE;
fprintf(stderr,
"%s: Can't open /dev/tty1. open() errno = %s (%d).\n",
MYNAME, strerror(errno), errno);
}
close(con_fd);
} else *kdghwclk_works_p = FALSE;
}