]> git.ipfire.org Git - thirdparty/util-linux.git/blob - hwclock/rtc.c
Imported from util-linux-2.11y tarball.
[thirdparty/util-linux.git] / hwclock / rtc.c
1 /* rtc.c - Use /dev/rtc for clock access */
2 #include <unistd.h> /* for close() */
3 #include <fcntl.h> /* for O_RDONLY */
4 #include <sysexits.h>
5 #include <sys/ioctl.h>
6
7 #include "clock.h"
8 #include "nls.h"
9
10 /*
11 * Get defines for rtc stuff.
12 *
13 * Getting the rtc defines is nontrivial.
14 * The obvious way is by including <linux/mc146818rtc.h>
15 * but that again includes <asm/io.h> which again includes ...
16 * and on sparc and alpha this gives compilation errors for
17 * many kernel versions. So, we give the defines ourselves here.
18 * Moreover, some Sparc person decided to be incompatible, and
19 * used a struct rtc_time different from that used in mc146818rtc.h.
20 */
21
22 /* On Sparcs, there is a <asm/rtc.h> that defines different ioctls
23 (that are required on my machine). However, this include file
24 does not exist on other architectures. */
25 /* One might do:
26 #ifdef __sparc__
27 #include <asm/rtc.h>
28 #endif
29 */
30 /* The following is roughly equivalent */
31 struct sparc_rtc_time
32 {
33 int sec; /* Seconds (0-59) */
34 int min; /* Minutes (0-59) */
35 int hour; /* Hour (0-23) */
36 int dow; /* Day of the week (1-7) */
37 int dom; /* Day of the month (1-31) */
38 int month; /* Month of year (1-12) */
39 int year; /* Year (0-99) */
40 };
41
42 #define RTCGET _IOR('p', 20, struct sparc_rtc_time)
43 #define RTCSET _IOW('p', 21, struct sparc_rtc_time)
44
45
46 /* non-sparc stuff */
47 #if 0
48 #include <linux/version.h>
49 /* Check if the /dev/rtc interface is available in this version of
50 the system headers. 131072 is linux 2.0.0. */
51 #if LINUX_VERSION_CODE >= 131072
52 #include <linux/mc146818rtc.h>
53 #endif
54 #endif
55
56 /* struct rtc_time is present since 1.3.99 */
57 /* Earlier (since 1.3.89), a struct tm was used. */
58 struct linux_rtc_time {
59 int tm_sec;
60 int tm_min;
61 int tm_hour;
62 int tm_mday;
63 int tm_mon;
64 int tm_year;
65 int tm_wday;
66 int tm_yday;
67 int tm_isdst;
68 };
69
70 /* RTC_RD_TIME etc have this definition since 1.99.9 (pre2.0-9) */
71 #ifndef RTC_RD_TIME
72 #define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time)
73 #define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time)
74 #define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
75 #define RTC_UIE_OFF _IO('p', 0x04) /* Update int. enable off */
76 #endif
77 /* RTC_EPOCH_READ and RTC_EPOCH_SET are present since 2.0.34 and 2.1.89 */
78 #ifndef RTC_EPOCH_READ
79 #define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
80 #define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
81 #endif
82
83
84 /* ia64 uses /dev/efirtc (char 10,136) */
85 /* devfs uses /dev/misc/rtc */
86 #if __ia64__
87 #define RTC_DEVN "efirtc"
88 #else
89 #define RTC_DEVN "rtc"
90 #endif
91
92 static char *rtc_dev_name;
93
94 static int
95 open_rtc(void) {
96 int rtc_fd;
97
98 rtc_dev_name = "/dev/" RTC_DEVN;
99 rtc_fd = open(rtc_dev_name, O_RDONLY);
100 if (rtc_fd < 0 && errno == ENOENT) {
101 rtc_dev_name = "/dev/misc/" RTC_DEVN;
102 rtc_fd = open(rtc_dev_name, O_RDONLY);
103 if (rtc_fd < 0 && errno == ENOENT)
104 rtc_dev_name = "/dev/" RTC_DEVN;
105 }
106 return rtc_fd;
107 }
108
109 static int
110 open_rtc_or_exit(void) {
111 int rtc_fd = open_rtc();
112
113 if (rtc_fd < 0) {
114 outsyserr(_("open() of %s failed"), rtc_dev_name);
115 exit(EX_OSFILE);
116 }
117 return rtc_fd;
118 }
119
120 static int
121 do_rtc_read_ioctl(int rtc_fd, struct tm *tm) {
122 int rc = -1;
123 char *ioctlname;
124
125 #ifdef __sparc__
126 /* some but not all sparcs use a different ioctl and struct */
127 struct sparc_rtc_time stm;
128
129 ioctlname = "RTCGET";
130 rc = ioctl(rtc_fd, RTCGET, &stm);
131 if (rc == 0) {
132 tm->tm_sec = stm.sec;
133 tm->tm_min = stm.min;
134 tm->tm_hour = stm.hour;
135 tm->tm_mday = stm.dom;
136 tm->tm_mon = stm.month - 1;
137 tm->tm_year = stm.year - 1900;
138 tm->tm_wday = stm.dow - 1;
139 tm->tm_yday = -1; /* day in the year */
140 }
141 #endif
142 if (rc == -1) { /* no sparc, or RTCGET failed */
143 ioctlname = "RTC_RD_TIME";
144 rc = ioctl(rtc_fd, RTC_RD_TIME, tm);
145 }
146 if (rc == -1) {
147 perror(ioctlname);
148 fprintf(stderr, _("ioctl() to %s to read the time failed.\n"),
149 rtc_dev_name);
150 exit(EX_IOERR);
151 }
152
153 tm->tm_isdst = -1; /* don't know whether it's dst */
154 return 0;
155 }
156
157 static int
158 busywait_for_rtc_clock_tick(const int rtc_fd) {
159 /*----------------------------------------------------------------------------
160 Wait for the top of a clock tick by reading /dev/rtc in a busy loop until
161 we see it.
162 -----------------------------------------------------------------------------*/
163 struct tm start_time;
164 /* The time when we were called (and started waiting) */
165 struct tm nowtime;
166 int i; /* local loop index */
167 int rc;
168
169 if (debug)
170 printf(_("Waiting in loop for time from %s to change\n"),
171 rtc_dev_name);
172
173 rc = do_rtc_read_ioctl(rtc_fd, &start_time);
174 if (rc)
175 return 1;
176
177 /* Wait for change. Should be within a second, but in case something
178 weird happens, we have a limit on this loop to reduce the impact
179 of this failure.
180 */
181 for (i = 0;
182 (rc = do_rtc_read_ioctl(rtc_fd, &nowtime)) == 0
183 && start_time.tm_sec == nowtime.tm_sec;
184 i++)
185 if (i >= 1000000) {
186 fprintf(stderr, _("Timed out waiting for time change.\n"));
187 return 2;
188 }
189
190 if (rc)
191 return 3;
192 return 0;
193 }
194
195
196
197 static int
198 synchronize_to_clock_tick_rtc(void) {
199 /*----------------------------------------------------------------------------
200 Same as synchronize_to_clock_tick(), but just for /dev/rtc.
201 -----------------------------------------------------------------------------*/
202 int rtc_fd; /* File descriptor of /dev/rtc */
203 int ret;
204
205 rtc_fd = open(rtc_dev_name, O_RDONLY);
206 if (rtc_fd == -1) {
207 outsyserr(_("open() of %s failed"), rtc_dev_name);
208 ret = 1;
209 } else {
210 int rc; /* Return code from ioctl */
211 /* Turn on update interrupts (one per second) */
212 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
213 /* Not all alpha kernels reject RTC_UIE_ON, but probably they should. */
214 rc = -1;
215 errno = EINVAL;
216 #else
217 rc = ioctl(rtc_fd, RTC_UIE_ON, 0);
218 #endif
219 if (rc == -1 && (errno == ENOTTY || errno == EINVAL)) {
220 /* This rtc device doesn't have interrupt functions. This is typical
221 on an Alpha, where the Hardware Clock interrupts are used by the
222 kernel for the system clock, so aren't at the user's disposal.
223 */
224 if (debug)
225 printf(_("%s does not have interrupt functions. "),
226 rtc_dev_name);
227 ret = busywait_for_rtc_clock_tick(rtc_fd);
228 } else if (rc == 0) {
229 unsigned long dummy;
230
231 /* this blocks until the next update interrupt */
232 rc = read(rtc_fd, &dummy, sizeof(dummy));
233 if (rc == -1) {
234 outsyserr(_("read() to %s to wait for clock tick failed"),
235 rtc_dev_name);
236 ret = 1;
237 } else {
238 ret = 0;
239 }
240 /* Turn off update interrupts */
241 rc = ioctl(rtc_fd, RTC_UIE_OFF, 0);
242 if (rc == -1)
243 outsyserr(_("ioctl() to %s to turn off update interrupts failed"),
244 rtc_dev_name);
245 } else {
246 outsyserr(_("ioctl() to %s to turn on update interrupts "
247 "failed unexpectedly"), rtc_dev_name);
248 ret = 1;
249 }
250 close(rtc_fd);
251 }
252 return ret;
253 }
254
255
256 static int
257 read_hardware_clock_rtc(struct tm *tm) {
258 int rtc_fd;
259
260 rtc_fd = open_rtc_or_exit();
261
262 /* Read the RTC time/date, return answer via tm */
263 do_rtc_read_ioctl(rtc_fd, tm);
264
265 close(rtc_fd);
266 return 0;
267 }
268
269
270 static int
271 set_hardware_clock_rtc(const struct tm *new_broken_time) {
272 /*-------------------------------------------------------------------------
273 Set the Hardware Clock to the broken down time <new_broken_time>.
274 Use ioctls to "rtc" device /dev/rtc.
275 -------------------------------------------------------------------------*/
276 int rc = -1;
277 int rtc_fd;
278 char *ioctlname;
279
280 rtc_fd = open_rtc_or_exit();
281
282 #ifdef __sparc__
283 {
284 struct sparc_rtc_time stm;
285
286 stm.sec = new_broken_time->tm_sec;
287 stm.min = new_broken_time->tm_min;
288 stm.hour = new_broken_time->tm_hour;
289 stm.dom = new_broken_time->tm_mday;
290 stm.month = new_broken_time->tm_mon + 1;
291 stm.year = new_broken_time->tm_year + 1900;
292 stm.dow = new_broken_time->tm_wday + 1;
293
294 ioctlname = "RTCSET";
295 rc = ioctl(rtc_fd, RTCSET, &stm);
296 }
297 #endif
298 if (rc == -1) { /* no sparc, or RTCSET failed */
299 ioctlname = "RTC_SET_TIME";
300 rc = ioctl(rtc_fd, RTC_SET_TIME, new_broken_time);
301 }
302
303 if (rc == -1) {
304 perror(ioctlname);
305 fprintf(stderr, _("ioctl() to %s to set the time failed.\n"),
306 rtc_dev_name);
307 exit(EX_IOERR);
308 }
309
310 if (debug)
311 printf(_("ioctl(%s) was successful.\n"), ioctlname);
312
313 close(rtc_fd);
314 return 0;
315 }
316
317
318 static int
319 get_permissions_rtc(void) {
320 return 0;
321 }
322
323 static struct clock_ops rtc = {
324 "/dev/" RTC_DEVN " interface to clock",
325 get_permissions_rtc,
326 read_hardware_clock_rtc,
327 set_hardware_clock_rtc,
328 synchronize_to_clock_tick_rtc,
329 };
330
331 /* return &rtc if /dev/rtc can be opened, NULL otherwise */
332 struct clock_ops *
333 probe_for_rtc_clock(){
334 int rtc_fd = open_rtc();
335 if (rtc_fd > 0) {
336 close(rtc_fd);
337 return &rtc;
338 }
339 if (debug)
340 outsyserr(_("Open of %s failed"), rtc_dev_name);
341 return NULL;
342 }
343
344
345
346 int
347 get_epoch_rtc(unsigned long *epoch_p, int silent) {
348 /*----------------------------------------------------------------------------
349 Get the Hardware Clock epoch setting from the kernel.
350 ----------------------------------------------------------------------------*/
351 int rtc_fd;
352
353 rtc_fd = open_rtc();
354 if (rtc_fd < 0) {
355 if (!silent) {
356 if (errno == ENOENT)
357 fprintf(stderr, _(
358 "To manipulate the epoch value in the kernel, we must "
359 "access the Linux 'rtc' device driver via the device special "
360 "file %s. This file does not exist on this system.\n"),
361 rtc_dev_name);
362 else
363 outsyserr(_("Unable to open %s"), rtc_dev_name);
364 }
365 return 1;
366 }
367
368 if (ioctl(rtc_fd, RTC_EPOCH_READ, epoch_p) == -1) {
369 if (!silent)
370 outsyserr(_("ioctl(RTC_EPOCH_READ) to %s failed"), rtc_dev_name);
371 close(rtc_fd);
372 return 1;
373 }
374
375 if (debug)
376 printf(_("we have read epoch %ld from %s "
377 "with RTC_EPOCH_READ ioctl.\n"), *epoch_p, rtc_dev_name);
378
379 close(rtc_fd);
380 return 0;
381 }
382
383
384
385 int
386 set_epoch_rtc(unsigned long epoch) {
387 /*----------------------------------------------------------------------------
388 Set the Hardware Clock epoch in the kernel.
389 ----------------------------------------------------------------------------*/
390 int rtc_fd;
391
392 if (epoch < 1900) {
393 /* kernel would not accept this epoch value */
394 /* Hmm - bad habit, deciding not to do what the user asks
395 just because one believes that the kernel might not like it. */
396 fprintf(stderr, _("The epoch value may not be less than 1900. "
397 "You requested %ld\n"), epoch);
398 return 1;
399 }
400
401 rtc_fd = open_rtc();
402 if (rtc_fd < 0) {
403 if (errno == ENOENT)
404 fprintf(stderr, _("To manipulate the epoch value in the kernel, we must "
405 "access the Linux 'rtc' device driver via the device special "
406 "file %s. This file does not exist on this system.\n"),
407 rtc_dev_name);
408 else
409 outsyserr(_("Unable to open %s"), rtc_dev_name);
410 return 1;
411 }
412
413 if (debug)
414 printf(_("setting epoch to %ld "
415 "with RTC_EPOCH_SET ioctl to %s.\n"), epoch, rtc_dev_name);
416
417 if (ioctl(rtc_fd, RTC_EPOCH_SET, epoch) == -1) {
418 if (errno == EINVAL)
419 fprintf(stderr, _("The kernel device driver for %s "
420 "does not have the RTC_EPOCH_SET ioctl.\n"), rtc_dev_name);
421 else
422 outsyserr(_("ioctl(RTC_EPOCH_SET) to %s failed"), rtc_dev_name);
423 close(rtc_fd);
424 return 1;
425 }
426
427 close(rtc_fd);
428 return 0;
429 }