1 /* rtc.c - Use /dev/rtc for clock access */
2 #include <unistd.h> /* for close() */
3 #include <fcntl.h> /* for O_RDONLY */
11 * Get defines for rtc stuff.
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.
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. */
30 /* The following is roughly equivalent */
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) */
42 #define RTCGET _IOR('p', 20, struct sparc_rtc_time)
43 #define RTCSET _IOW('p', 21, struct sparc_rtc_time)
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>
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
{
70 /* RTC_RD_TIME etc have this definition since 1.99.9 (pre2.0-9) */
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 */
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 */
84 /* ia64 uses /dev/efirtc (char 10,136) */
85 /* devfs uses /dev/misc/rtc */
87 #define RTC_DEVN "efirtc"
89 #define RTC_DEVN "rtc"
92 static char *rtc_dev_name
;
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
;
110 open_rtc_or_exit(void) {
111 int rtc_fd
= open_rtc();
114 outsyserr(_("open() of %s failed"), rtc_dev_name
);
121 do_rtc_read_ioctl(int rtc_fd
, struct tm
*tm
) {
126 /* some but not all sparcs use a different ioctl and struct */
127 struct sparc_rtc_time stm
;
129 ioctlname
= "RTCGET";
130 rc
= ioctl(rtc_fd
, RTCGET
, &stm
);
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 */
142 if (rc
== -1) { /* no sparc, or RTCGET failed */
143 ioctlname
= "RTC_RD_TIME";
144 rc
= ioctl(rtc_fd
, RTC_RD_TIME
, tm
);
148 fprintf(stderr
, _("ioctl() to %s to read the time failed.\n"),
153 tm
->tm_isdst
= -1; /* don't know whether it's dst */
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
162 -----------------------------------------------------------------------------*/
163 struct tm start_time
;
164 /* The time when we were called (and started waiting) */
166 int i
; /* local loop index */
170 printf(_("Waiting in loop for time from %s to change\n"),
173 rc
= do_rtc_read_ioctl(rtc_fd
, &start_time
);
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
182 (rc
= do_rtc_read_ioctl(rtc_fd
, &nowtime
)) == 0
183 && start_time
.tm_sec
== nowtime
.tm_sec
;
186 fprintf(stderr
, _("Timed out waiting for time change.\n"));
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 */
205 rtc_fd
= open(rtc_dev_name
, O_RDONLY
);
207 outsyserr(_("open() of %s failed"), rtc_dev_name
);
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. */
217 rc
= ioctl(rtc_fd
, RTC_UIE_ON
, 0);
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.
225 printf(_("%s does not have interrupt functions. "),
227 ret
= busywait_for_rtc_clock_tick(rtc_fd
);
228 } else if (rc
== 0) {
231 /* this blocks until the next update interrupt */
232 rc
= read(rtc_fd
, &dummy
, sizeof(dummy
));
234 outsyserr(_("read() to %s to wait for clock tick failed"),
240 /* Turn off update interrupts */
241 rc
= ioctl(rtc_fd
, RTC_UIE_OFF
, 0);
243 outsyserr(_("ioctl() to %s to turn off update interrupts failed"),
246 outsyserr(_("ioctl() to %s to turn on update interrupts "
247 "failed unexpectedly"), rtc_dev_name
);
257 read_hardware_clock_rtc(struct tm
*tm
) {
260 rtc_fd
= open_rtc_or_exit();
262 /* Read the RTC time/date, return answer via tm */
263 do_rtc_read_ioctl(rtc_fd
, tm
);
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 -------------------------------------------------------------------------*/
280 rtc_fd
= open_rtc_or_exit();
284 struct sparc_rtc_time stm
;
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;
294 ioctlname
= "RTCSET";
295 rc
= ioctl(rtc_fd
, RTCSET
, &stm
);
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
);
305 fprintf(stderr
, _("ioctl() to %s to set the time failed.\n"),
311 printf(_("ioctl(%s) was successful.\n"), ioctlname
);
319 get_permissions_rtc(void) {
323 static struct clock_ops rtc
= {
324 "/dev/" RTC_DEVN
" interface to clock",
326 read_hardware_clock_rtc
,
327 set_hardware_clock_rtc
,
328 synchronize_to_clock_tick_rtc
,
331 /* return &rtc if /dev/rtc can be opened, NULL otherwise */
333 probe_for_rtc_clock(){
334 int rtc_fd
= open_rtc();
340 outsyserr(_("Open of %s failed"), rtc_dev_name
);
347 get_epoch_rtc(unsigned long *epoch_p
, int silent
) {
348 /*----------------------------------------------------------------------------
349 Get the Hardware Clock epoch setting from the kernel.
350 ----------------------------------------------------------------------------*/
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"),
363 outsyserr(_("Unable to open %s"), rtc_dev_name
);
368 if (ioctl(rtc_fd
, RTC_EPOCH_READ
, epoch_p
) == -1) {
370 outsyserr(_("ioctl(RTC_EPOCH_READ) to %s failed"), rtc_dev_name
);
376 printf(_("we have read epoch %ld from %s "
377 "with RTC_EPOCH_READ ioctl.\n"), *epoch_p
, rtc_dev_name
);
386 set_epoch_rtc(unsigned long epoch
) {
387 /*----------------------------------------------------------------------------
388 Set the Hardware Clock epoch in the kernel.
389 ----------------------------------------------------------------------------*/
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
);
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"),
409 outsyserr(_("Unable to open %s"), rtc_dev_name
);
414 printf(_("setting epoch to %ld "
415 "with RTC_EPOCH_SET ioctl to %s.\n"), epoch
, rtc_dev_name
);
417 if (ioctl(rtc_fd
, RTC_EPOCH_SET
, epoch
) == -1) {
419 fprintf(stderr
, _("The kernel device driver for %s "
420 "does not have the RTC_EPOCH_SET ioctl.\n"), rtc_dev_name
);
422 outsyserr(_("ioctl(RTC_EPOCH_SET) to %s failed"), rtc_dev_name
);