]> git.ipfire.org Git - thirdparty/util-linux.git/blame - hwclock/kd.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / hwclock / kd.c
CommitLineData
7eda085c
KZ
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
eb63b9b8 6#include "../defines.h" /* for HAVE_nanosleep */
7eda085c
KZ
7#include "clock.h"
8#include "nls.h"
9
10static 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 */
18struct 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
29static int
30synchronize_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 {
eb63b9b8
KZ
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
66ee8158
KZ
58 struct timespec xsleep = { 0, 1 };
59 nanosleep( &xsleep, NULL );
eb63b9b8
KZ
60#else
61 usleep(1);
62#endif
63
7eda085c
KZ
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
78static int
79read_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
108static int
109set_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
133static int
134get_permissions_kd(void) {
135 return 0;
136}
137
138static 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 */
147struct clock_ops *
148probe_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 {
22853e4a
KZ
161 /* probably KDGHWCLK exists on m68k only */
162#ifdef __m68k__
7eda085c 163 outsyserr(_("Can't open /dev/tty1"));
22853e4a 164#endif
7eda085c
KZ
165 }
166 return ret;
167}