1 /* rtc.c - Use /dev/rtc for clock access */
2 #include <unistd.h> /* for close() */
3 #include <fcntl.h> /* for O_RDONLY */
10 * Get defines for rtc stuff.
12 * Getting the rtc defines is nontrivial.
13 * The obvious way is by including <linux/mc146818rtc.h>
14 * but that again includes <asm/io.h> which again includes ...
15 * and on sparc and alpha this gives compilation errors for
16 * many kernel versions. So, we give the defines ourselves here.
17 * Moreover, some Sparc person decided to be incompatible, and
18 * used a struct rtc_time different from that used in mc146818rtc.h.
21 /* ia64 uses /dev/efirtc (char 10,136) */
23 #define RTC_DEV "/dev/efirtc"
25 #define RTC_DEV "/dev/rtc"
28 /* On Sparcs, there is a <asm/rtc.h> that defines different ioctls
29 (that are required on my machine). However, this include file
30 does not exist on other architectures. */
36 /* The following is roughly equivalent */
39 int sec
; /* Seconds (0-59) */
40 int min
; /* Minutes (0-59) */
41 int hour
; /* Hour (0-23) */
42 int dow
; /* Day of the week (1-7) */
43 int dom
; /* Day of the month (1-31) */
44 int month
; /* Month of year (1-12) */
45 int year
; /* Year (0-99) */
48 #define RTCGET _IOR('p', 20, struct sparc_rtc_time)
49 #define RTCSET _IOW('p', 21, struct sparc_rtc_time)
54 #include <linux/version.h>
55 /* Check if the /dev/rtc interface is available in this version of
56 the system headers. 131072 is linux 2.0.0. */
57 #if LINUX_VERSION_CODE >= 131072
58 #include <linux/mc146818rtc.h>
62 /* struct rtc_time is present since 1.3.99 */
63 /* Earlier (since 1.3.89), a struct tm was used. */
64 struct linux_rtc_time
{
76 /* RTC_RD_TIME etc have this definition since 1.99.9 (pre2.0-9) */
78 #define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time)
79 #define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time)
80 #define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */
81 #define RTC_UIE_OFF _IO('p', 0x04) /* Update int. enable off */
83 /* RTC_EPOCH_READ and RTC_EPOCH_SET are present since 2.0.34 and 2.1.89 */
84 #ifndef RTC_EPOCH_READ
85 #define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */
86 #define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */
91 do_rtc_read_ioctl(int rtc_fd
, struct tm
*tm
) {
95 struct sparc_rtc_time stm
;
98 rc
= ioctl(rtc_fd
, RTCGET
, &stm
);
100 ioctlname
= "RTC_RD_TIME";
101 rc
= ioctl(rtc_fd
, RTC_RD_TIME
, tm
);
105 fprintf(stderr
, _("ioctl() to %s to read the time failed.\n"),RTC_DEV
);
109 tm
->tm_sec
= stm
.sec
;
110 tm
->tm_min
= stm
.min
;
111 tm
->tm_hour
= stm
.hour
;
112 tm
->tm_mday
= stm
.dom
;
113 tm
->tm_mon
= stm
.month
- 1;
114 tm
->tm_year
= stm
.year
- 1900;
115 tm
->tm_wday
= stm
.dow
- 1;
116 tm
->tm_yday
= -1; /* day in the year */
118 tm
->tm_isdst
= -1; /* don't know whether it's daylight */
124 busywait_for_rtc_clock_tick(const int rtc_fd
) {
125 /*----------------------------------------------------------------------------
126 Wait for the top of a clock tick by reading /dev/rtc in a busy loop until
128 -----------------------------------------------------------------------------*/
129 struct tm start_time
;
130 /* The time when we were called (and started waiting) */
132 int i
; /* local loop index */
136 printf(_("Waiting in loop for time from %s to change\n"),RTC_DEV
);
138 rc
= do_rtc_read_ioctl(rtc_fd
, &start_time
);
142 /* Wait for change. Should be within a second, but in case something
143 weird happens, we have a limit on this loop to reduce the impact
147 (rc
= do_rtc_read_ioctl(rtc_fd
, &nowtime
)) == 0
148 && start_time
.tm_sec
== nowtime
.tm_sec
;
151 fprintf(stderr
, _("Timed out waiting for time change.\n"));
163 synchronize_to_clock_tick_rtc(void) {
164 /*----------------------------------------------------------------------------
165 Same as synchronize_to_clock_tick(), but just for /dev/rtc.
166 -----------------------------------------------------------------------------*/
167 int rtc_fd
; /* File descriptor of /dev/rtc */
170 rtc_fd
= open(RTC_DEV
,O_RDONLY
);
172 outsyserr(_("open() of %s failed"),RTC_DEV
);
175 int rc
; /* Return code from ioctl */
176 /* Turn on update interrupts (one per second) */
177 #if defined(__alpha__) || defined(__sparc__)
178 /* Not all alpha kernels reject RTC_UIE_ON, but probably they should. */
182 rc
= ioctl(rtc_fd
, RTC_UIE_ON
, 0);
184 if (rc
== -1 && errno
== EINVAL
) {
185 /* This rtc device doesn't have interrupt functions. This is typical
186 on an Alpha, where the Hardware Clock interrupts are used by the
187 kernel for the system clock, so aren't at the user's disposal.
190 printf(_("%s does not have interrupt functions. "),RTC_DEV
);
191 ret
= busywait_for_rtc_clock_tick(rtc_fd
);
192 } else if (rc
== 0) {
195 /* this blocks until the next update interrupt */
196 rc
= read(rtc_fd
, &dummy
, sizeof(dummy
));
198 outsyserr(_("read() to %s to wait for clock tick failed"),RTC_DEV
);
203 /* Turn off update interrupts */
204 rc
= ioctl(rtc_fd
, RTC_UIE_OFF
, 0);
206 outsyserr(_("ioctl() to %s to turn off update interrupts "
209 outsyserr(_("ioctl() to %s to turn on update interrupts "
210 "failed unexpectedly"),RTC_DEV
);
220 read_hardware_clock_rtc(struct tm
*tm
) {
221 /*----------------------------------------------------------------------------
222 Read the hardware clock and return the current time via <tm>
223 argument. Use ioctls to "rtc" device /dev/rtc.
224 -----------------------------------------------------------------------------*/
225 int rtc_fd
; /* File descriptor of /dev/rtc */
227 rtc_fd
= open(RTC_DEV
,O_RDONLY
);
229 outsyserr(_("open() of %s failed"),RTC_DEV
);
233 /* Read the RTC time/date */
234 do_rtc_read_ioctl(rtc_fd
, tm
);
242 set_hardware_clock_rtc(const struct tm
*new_broken_time
) {
243 /*----------------------------------------------------------------------------
244 Set the Hardware Clock to the broken down time <new_broken_time>.
245 Use ioctls to "rtc" device /dev/rtc.
246 ----------------------------------------------------------------------------*/
250 rtc_fd
= open(RTC_DEV
, O_RDONLY
);
252 outsyserr(_("Unable to open %s"),RTC_DEV
);
257 struct sparc_rtc_time stm
;
259 stm
.sec
= new_broken_time
->tm_sec
;
260 stm
.min
= new_broken_time
->tm_min
;
261 stm
.hour
= new_broken_time
->tm_hour
;
262 stm
.dom
= new_broken_time
->tm_mday
;
263 stm
.month
= new_broken_time
->tm_mon
+ 1;
264 stm
.year
= new_broken_time
->tm_year
+ 1900;
265 stm
.dow
= new_broken_time
->tm_wday
+ 1;
267 ioctlname
= "RTCSET";
268 rc
= ioctl(rtc_fd
, RTCSET
, &stm
);
270 ioctlname
= "RTC_SET_TIME";
271 rc
= ioctl(rtc_fd
, RTC_SET_TIME
, new_broken_time
);
275 fprintf(stderr
, _("ioctl() to %s to set the time failed.\n"),RTC_DEV
);
279 printf(_("ioctl(%s) was successful.\n"), ioctlname
);
288 get_permissions_rtc(void) {
292 static struct clock_ops rtc
= {
293 "/dev/rtc interface to clock",
295 read_hardware_clock_rtc
,
296 set_hardware_clock_rtc
,
297 synchronize_to_clock_tick_rtc
,
300 /* return &rtc if /dev/rtc can be opened, NULL otherwise */
302 probe_for_rtc_clock(){
303 int rtc_fd
= open(RTC_DEV
, O_RDONLY
);
309 outsyserr(_("Open of %s failed"),RTC_DEV
);
316 get_epoch_rtc(unsigned long *epoch_p
, int silent
) {
317 /*----------------------------------------------------------------------------
318 Get the Hardware Clock epoch setting from the kernel.
319 ----------------------------------------------------------------------------*/
322 rtc_fd
= open(RTC_DEV
, O_RDONLY
);
327 "To manipulate the epoch value in the kernel, we must "
328 "access the Linux 'rtc' device driver via the device special "
329 "file %s. This file does not exist on this system.\n"),RTC_DEV
);
331 outsyserr(_("Unable to open %s"),RTC_DEV
);
336 if (ioctl(rtc_fd
, RTC_EPOCH_READ
, epoch_p
) == -1) {
338 outsyserr(_("ioctl(RTC_EPOCH_READ) to %s failed"),RTC_DEV
);
344 printf(_("we have read epoch %ld from %s "
345 "with RTC_EPOCH_READ ioctl.\n"), *epoch_p
,RTC_DEV
);
354 set_epoch_rtc(unsigned long epoch
) {
355 /*----------------------------------------------------------------------------
356 Set the Hardware Clock epoch in the kernel.
357 ----------------------------------------------------------------------------*/
361 /* kernel would not accept this epoch value */
362 /* Hmm - bad habit, deciding not to do what the user asks
363 just because one believes that the kernel might not like it. */
364 fprintf(stderr
, _("The epoch value may not be less than 1900. "
365 "You requested %ld\n"), epoch
);
369 rtc_fd
= open(RTC_DEV
, O_RDONLY
);
372 fprintf(stderr
, _("To manipulate the epoch value in the kernel, we must "
373 "access the Linux 'rtc' device driver via the device special "
374 "file %s. This file does not exist on this system.\n"),RTC_DEV
);
376 outsyserr(_("Unable to open %s"),RTC_DEV
);
381 printf(_("setting epoch to %ld "
382 "with RTC_EPOCH_SET ioctl to %s.\n"), epoch
, RTC_DEV
);
384 if (ioctl(rtc_fd
, RTC_EPOCH_SET
, epoch
) == -1) {
386 fprintf(stderr
, _("The kernel device driver for %s "
387 "does not have the RTC_EPOCH_SET ioctl.\n"),RTC_DEV
);
389 outsyserr(_("ioctl(RTC_EPOCH_SET) to %s failed"),RTC_DEV
);