summaryrefslogtreecommitdiffstats
path: root/sys-utils/hwclock-kd.c
diff options
context:
space:
mode:
authorKarel Zak2012-05-31 11:15:07 +0200
committerKarel Zak2012-06-26 20:48:23 +0200
commitc7f753901f45bffdf39506e4f19bba4c37659ccc (patch)
tree88fc1be2f3f104144b4a45737a070ebf76801106 /sys-utils/hwclock-kd.c
parentbuild-sys: convert sys-utils/ to module (diff)
downloadkernel-qcow2-util-linux-c7f753901f45bffdf39506e4f19bba4c37659ccc.tar.gz
kernel-qcow2-util-linux-c7f753901f45bffdf39506e4f19bba4c37659ccc.tar.xz
kernel-qcow2-util-linux-c7f753901f45bffdf39506e4f19bba4c37659ccc.zip
build-sys: move hwclock to sys-utils/
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/hwclock-kd.c')
-rw-r--r--sys-utils/hwclock-kd.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/sys-utils/hwclock-kd.c b/sys-utils/hwclock-kd.c
new file mode 100644
index 000000000..ec98f45ba
--- /dev/null
+++ b/sys-utils/hwclock-kd.c
@@ -0,0 +1,183 @@
+/*
+ * kd.c - KDGHWCLK stuff, possibly m68k only, likely to be deprecated
+ */
+
+
+#ifdef __m68k__
+
+# include <fcntl.h>
+# include <sysexits.h>
+# include <sys/ioctl.h>
+# include <unistd.h>
+
+# include "nls.h"
+# include "usleep.h"
+
+# include "hwclock.h"
+
+/* Get defines for KDGHWCLK and KDSHWCLK (m68k) */
+# include <linux/kd.h>
+
+/* Even on m68k, if KDGHWCLK (antique) is not defined, don't build this */
+
+#endif
+
+#if !defined(__m68k__) || !defined(KDGHWCLK)
+
+#include <stddef.h>
+struct clock_ops *probe_for_kd_clock(void)
+{
+ return NULL;
+}
+
+#else /* __m68k__ && KDGHWCLK */
+
+/* Opened by probe_for_kd_clock(), and never closed. */
+static int con_fd = -1;
+static char *con_fd_filename; /* usually "/dev/tty1" */
+
+/*
+ * Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until
+ * we see it.
+ */
+static int synchronize_to_clock_tick_kd(void)
+{
+ /* The time when we were called (and started waiting) */
+ struct hwclk_time start_time, nowtime;
+ struct timeval begin, now;
+
+ if (debug)
+ printf(_("Waiting in loop for time from KDGHWCLK to change\n"));
+
+ if (ioctl(con_fd, KDGHWCLK, &start_time) == -1) {
+ warn(_("KDGHWCLK ioctl to read time failed"));
+ return 3;
+ }
+
+ /*
+ * Wait for change. Should be within a second, but in case something
+ * weird happens, we have a time limit (1.5s) on this loop to reduce
+ * the impact of this failure.
+ */
+ gettimeofday(&begin, NULL);
+ do {
+ /*
+ * Added by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * "The culprit is the fast loop with KDGHWCLK ioctls. It
+ * seems the kernel gets confused by those on Amigas with
+ * A2000 RTCs and simply hangs after some time. Inserting a
+ * sleep helps."
+ */
+ usleep(1);
+
+ if (ioctl(con_fd, KDGHWCLK, &nowtime) == -1) {
+ warn(_("KDGHWCLK ioctl to read time failed in loop"));
+ return 3;
+ }
+ if (start_time.tm_sec != nowtime.tm_sec)
+ break;
+ gettimeofday(&now, NULL);
+ if (time_diff(now, begin) > 1.5) {
+ warnx(_("Timed out waiting for time change."));
+ return 2;
+ }
+ } while (1);
+
+ return 0;
+}
+
+/*
+ * 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.
+ */
+static int read_hardware_clock_kd(struct tm *tm)
+{
+ struct hwclk_time t;
+
+ if (ioctl(con_fd, KDGHWCLK, &t) == -1) {
+ warn(_("ioctl() failed to read time from %s"),
+ con_fd_filename);
+ hwclock_exit(EX_IOERR);
+ }
+
+ 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 */
+
+ return 0;
+}
+
+/*
+ * 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.
+ */
+static int set_hardware_clock_kd(const struct tm *new_broken_time)
+{
+ struct hwclk_time t;
+
+ 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 (ioctl(con_fd, KDSHWCLK, &t) == -1) {
+ warn(_("ioctl KDSHWCLK failed"));
+ hwclock_exit(EX_IOERR);
+ }
+ return 0;
+}
+
+static int get_permissions_kd(void)
+{
+ return 0;
+}
+
+static struct clock_ops kd = {
+ "KDGHWCLK interface to m68k clock",
+ get_permissions_kd,
+ read_hardware_clock_kd,
+ set_hardware_clock_kd,
+ synchronize_to_clock_tick_kd,
+};
+
+/* return &kd if KDGHWCLK works, NULL otherwise */
+struct clock_ops *probe_for_kd_clock()
+{
+ struct clock_ops *ret = NULL;
+ struct hwclk_time t;
+
+ if (con_fd < 0) { /* first time here */
+ con_fd_filename = "/dev/tty1";
+ con_fd = open(con_fd_filename, O_RDONLY);
+ }
+ if (con_fd < 0) {
+ /* perhaps they are using devfs? */
+ con_fd_filename = "/dev/vc/1";
+ con_fd = open(con_fd_filename, O_RDONLY);
+ }
+ if (con_fd < 0) {
+ /* probably KDGHWCLK exists on m68k only */
+ warn(_("Can't open /dev/tty1 or /dev/vc/1"));
+ } else {
+ if (ioctl(con_fd, KDGHWCLK, &t) == -1) {
+ if (errno != EINVAL)
+ warn(_("KDGHWCLK ioctl failed"));
+ } else
+ ret = &kd;
+ }
+ return ret;
+}
+#endif /* __m68k__ && KDGHWCLK */