summaryrefslogtreecommitdiffstats
path: root/clock/kd.c
diff options
context:
space:
mode:
Diffstat (limited to 'clock/kd.c')
-rw-r--r--clock/kd.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/clock/kd.c b/clock/kd.c
new file mode 100644
index 000000000..9ec91f005
--- /dev/null
+++ b/clock/kd.c
@@ -0,0 +1,149 @@
+/* kd.c - KDGHWCLK stuff, possibly m68k only */
+#include <unistd.h> /* for close() */
+#include <fcntl.h> /* for O_RDONLY */
+#include <sys/ioctl.h>
+
+#include "clock.h"
+#include "nls.h"
+
+static int con_fd = -1; /* opened by probe_for_kd_clock() */
+ /* never closed */
+
+/* Get defines for KDGHWCLK and KDSHWCLK (m68k) */
+#include <linux/kd.h>
+#ifndef KDGHWCLK
+#define KDGHWCLK 0x4B50 /* get hardware clock */
+#define KDSHWCLK 0x4B51 /* set hardware clock */
+struct hwclk_time {
+ unsigned sec; /* 0..59 */
+ unsigned min; /* 0..59 */
+ unsigned hour; /* 0..23 */
+ unsigned day; /* 1..31 */
+ unsigned mon; /* 0..11 */
+ unsigned year; /* 70... */
+ int wday; /* 0..6, 0 is Sunday, -1 means unknown/don't set */
+};
+#endif
+
+static int
+synchronize_to_clock_tick_kd(void) {
+/*----------------------------------------------------------------------------
+ Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until
+ we see it.
+-----------------------------------------------------------------------------*/
+ int i;
+
+ /* The time when we were called (and started waiting) */
+ struct hwclk_time start_time, nowtime;
+
+ if (debug)
+ printf(_("Waiting in loop for time from KDGHWCLK to change\n"));
+
+ if (ioctl(con_fd, KDGHWCLK, &start_time) == -1) {
+ outsyserr(_("KDGHWCLK ioctl to read time failed"));
+ return 3;
+ }
+
+ i = 0;
+ do {
+ if (i++ >= 1000000) {
+ fprintf(stderr, _("Timed out waiting for time change.\n"));
+ return 2;
+ }
+ if (ioctl(con_fd, KDGHWCLK, &nowtime) == -1) {
+ outsyserr(_("KDGHWCLK ioctl to read time failed in loop"));
+ return 3;
+ }
+ } while (start_time.sec == nowtime.sec);
+
+ return 0;
+}
+
+
+static int
+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.
+-----------------------------------------------------------------------------*/
+ struct hwclk_time t;
+
+ if (ioctl(con_fd, KDGHWCLK, &t) == -1) {
+ outsyserr(_("ioctl() failed to read time from /dev/tty1"));
+ exit(5);
+ }
+
+ 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;
+}
+
+
+static int
+set_hardware_clock_kd(const struct tm *new_broken_time) {
+/*----------------------------------------------------------------------------
+ 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.
+----------------------------------------------------------------------------*/
+ 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) {
+ outsyserr(_("ioctl() to open /dev/tty1 failed"));
+ exit(1);
+ }
+ 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)
+ con_fd = open("/dev/tty1", O_RDONLY);
+ if (con_fd >= 0) {
+ if (ioctl( con_fd, KDGHWCLK, &t ) == -1) {
+ if (errno != EINVAL)
+ outsyserr(_("KDGHWCLK ioctl failed"));
+ } else
+ ret = &kd;
+ } else {
+ outsyserr(_("Can't open /dev/tty1"));
+ }
+ return ret;
+}