]>
Commit | Line | Data |
---|---|---|
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 | ||
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 { | |
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 | ||
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 { | |
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 | } |