1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
/* kd.c - KDGHWCLK stuff, possibly m68k only - deprecated */
#ifndef __m68k__
#include "clock.h"
struct clock_ops *
probe_for_kd_clock() {
return NULL;
}
#else /* __m68k__ */
#include <unistd.h> /* for close() */
#include <fcntl.h> /* for O_RDONLY */
#include <errno.h>
#include <sysexits.h>
#include <sys/ioctl.h>
#include "../defines.h" /* for HAVE_nanosleep */
#include "clock.h"
#include "nls.h"
static int con_fd = -1; /* opened by probe_for_kd_clock() */
/* never closed */
static char *con_fd_filename; /* usually "/dev/tty1" */
/* 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 {
/* 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 nanosleep helps." */
/* Christian T. Steigies: 1 instead of 1000000 is still sufficient
to keep the machine from freezing. */
#ifdef HAVE_nanosleep
struct timespec xsleep = { 0, 1 };
nanosleep( &xsleep, NULL );
#else
usleep(1);
#endif
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 %s"), con_fd_filename);
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;
}
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 KDSHWCLK 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) { /* 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 */
outsyserr(_("Can't open /dev/tty1 or /dev/vc/1"));
} else {
if (ioctl(con_fd, KDGHWCLK, &t) == -1) {
if (errno != EINVAL)
outsyserr(_("KDGHWCLK ioctl failed"));
} else
ret = &kd;
}
return ret;
}
#endif /* __m68k__ */
|