]> git.ipfire.org Git - thirdparty/util-linux.git/blob - hwclock/kd.c
Imported from util-linux-2.10m tarball.
[thirdparty/util-linux.git] / hwclock / kd.c
1 /* kd.c - KDGHWCLK stuff, possibly m68k only */
2 #include <unistd.h> /* for close() */
3 #include <fcntl.h> /* for O_RDONLY */
4 #include <sys/ioctl.h>
5
6 #include "../defines.h" /* for HAVE_nanosleep */
7 #include "clock.h"
8 #include "nls.h"
9
10 static int con_fd = -1; /* opened by probe_for_kd_clock() */
11 /* never closed */
12
13 /* Get defines for KDGHWCLK and KDSHWCLK (m68k) */
14 #include <linux/kd.h>
15 #ifndef KDGHWCLK
16 #define KDGHWCLK 0x4B50 /* get hardware clock */
17 #define KDSHWCLK 0x4B51 /* set hardware clock */
18 struct hwclk_time {
19 unsigned sec; /* 0..59 */
20 unsigned min; /* 0..59 */
21 unsigned hour; /* 0..23 */
22 unsigned day; /* 1..31 */
23 unsigned mon; /* 0..11 */
24 unsigned year; /* 70... */
25 int wday; /* 0..6, 0 is Sunday, -1 means unknown/don't set */
26 };
27 #endif
28
29 static int
30 synchronize_to_clock_tick_kd(void) {
31 /*----------------------------------------------------------------------------
32 Wait for the top of a clock tick by calling KDGHWCLK in a busy loop until
33 we see it.
34 -----------------------------------------------------------------------------*/
35 int i;
36
37 /* The time when we were called (and started waiting) */
38 struct hwclk_time start_time, nowtime;
39
40 if (debug)
41 printf(_("Waiting in loop for time from KDGHWCLK to change\n"));
42
43 if (ioctl(con_fd, KDGHWCLK, &start_time) == -1) {
44 outsyserr(_("KDGHWCLK ioctl to read time failed"));
45 return 3;
46 }
47
48 i = 0;
49 do {
50 /* Added by Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> */
51 /* "The culprit is the fast loop with KDGHWCLK ioctls. It seems
52 the kernel gets confused by those on Amigas with A2000 RTCs
53 and simply hangs after some time. Inserting a nanosleep helps." */
54 /* Christian T. Steigies: 1 instead of 1000000 is still sufficient
55 to keep the machine from freezing. */
56
57 #ifdef HAVE_nanosleep
58 struct timespec xsleep = { 0, 1 };
59 nanosleep( &xsleep, NULL );
60 #else
61 usleep(1);
62 #endif
63
64 if (i++ >= 1000000) {
65 fprintf(stderr, _("Timed out waiting for time change.\n"));
66 return 2;
67 }
68 if (ioctl(con_fd, KDGHWCLK, &nowtime) == -1) {
69 outsyserr(_("KDGHWCLK ioctl to read time failed in loop"));
70 return 3;
71 }
72 } while (start_time.sec == nowtime.sec);
73
74 return 0;
75 }
76
77
78 static int
79 read_hardware_clock_kd(struct tm *tm) {
80 /*----------------------------------------------------------------------------
81 Read the hardware clock and return the current time via <tm>
82 argument. Use ioctls to /dev/tty1 on what we assume is an m68k
83 machine.
84
85 Note that we don't use /dev/console here. That might be a serial
86 console.
87 -----------------------------------------------------------------------------*/
88 struct hwclk_time t;
89
90 if (ioctl(con_fd, KDGHWCLK, &t) == -1) {
91 outsyserr(_("ioctl() failed to read time from /dev/tty1"));
92 exit(5);
93 }
94
95 tm->tm_sec = t.sec;
96 tm->tm_min = t.min;
97 tm->tm_hour = t.hour;
98 tm->tm_mday = t.day;
99 tm->tm_mon = t.mon;
100 tm->tm_year = t.year;
101 tm->tm_wday = t.wday;
102 tm->tm_isdst = -1; /* Don't know if it's Daylight Savings Time */
103
104 return 0;
105 }
106
107
108 static int
109 set_hardware_clock_kd(const struct tm *new_broken_time) {
110 /*----------------------------------------------------------------------------
111 Set the Hardware Clock to the time <new_broken_time>. Use ioctls to
112 /dev/tty1 on what we assume is an m68k machine.
113
114 Note that we don't use /dev/console here. That might be a serial console.
115 ----------------------------------------------------------------------------*/
116 struct hwclk_time t;
117
118 t.sec = new_broken_time->tm_sec;
119 t.min = new_broken_time->tm_min;
120 t.hour = new_broken_time->tm_hour;
121 t.day = new_broken_time->tm_mday;
122 t.mon = new_broken_time->tm_mon;
123 t.year = new_broken_time->tm_year;
124 t.wday = new_broken_time->tm_wday;
125
126 if (ioctl(con_fd, KDSHWCLK, &t ) == -1) {
127 outsyserr(_("ioctl() to open /dev/tty1 failed"));
128 exit(1);
129 }
130 return 0;
131 }
132
133 static int
134 get_permissions_kd(void) {
135 return 0;
136 }
137
138 static struct clock_ops kd = {
139 "KDGHWCLK interface to m68k clock",
140 get_permissions_kd,
141 read_hardware_clock_kd,
142 set_hardware_clock_kd,
143 synchronize_to_clock_tick_kd,
144 };
145
146 /* return &kd if KDGHWCLK works, NULL otherwise */
147 struct clock_ops *
148 probe_for_kd_clock() {
149 struct clock_ops *ret = NULL;
150 struct hwclk_time t;
151
152 if (con_fd < 0)
153 con_fd = open("/dev/tty1", O_RDONLY);
154 if (con_fd >= 0) {
155 if (ioctl( con_fd, KDGHWCLK, &t ) == -1) {
156 if (errno != EINVAL)
157 outsyserr(_("KDGHWCLK ioctl failed"));
158 } else
159 ret = &kd;
160 } else {
161 /* probably KDGHWCLK exists on m68k only */
162 #ifdef __m68k__
163 outsyserr(_("Can't open /dev/tty1"));
164 #endif
165 }
166 return ret;
167 }