diff options
author | David Brownell <david-b@pacbell.net> | 2006-11-25 14:09:26 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-11-25 16:28:33 -0500 |
commit | 7531d8faa85f8880db433027bf2b04950e49baeb (patch) | |
tree | 4271034911fcf09833f8fbeed9232521916929db /Documentation | |
parent | 4d8ebddcc525a5800dab5880946cecffe73e9dca (diff) |
[PATCH] Documentation/rtc.txt updates (for rtc class)
This updates the RTC documentation to summarize the two APIs now available:
the old PC/AT one, and the new RTC class drivers. It also updates the
included "rtctest.c" file to better meet Linux style guidelines, and to work
with the new RTC drivers.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Acked-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/rtc.txt | 463 |
1 files changed, 304 insertions, 159 deletions
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index 2a58f985795a..7cf1ec5bcdd3 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt | |||
@@ -1,12 +1,49 @@ | |||
1 | 1 | ||
2 | Real Time Clock Driver for Linux | 2 | Real Time Clock (RTC) Drivers for Linux |
3 | ================================ | 3 | ======================================= |
4 | |||
5 | When Linux developers talk about a "Real Time Clock", they usually mean | ||
6 | something that tracks wall clock time and is battery backed so that it | ||
7 | works even with system power off. Such clocks will normally not track | ||
8 | the local time zone or daylight savings time -- unless they dual boot | ||
9 | with MS-Windows -- but will instead be set to Coordinated Universal Time | ||
10 | (UTC, formerly "Greenwich Mean Time"). | ||
11 | |||
12 | The newest non-PC hardware tends to just count seconds, like the time(2) | ||
13 | system call reports, but RTCs also very commonly represent time using | ||
14 | the Gregorian calendar and 24 hour time, as reported by gmtime(3). | ||
15 | |||
16 | Linux has two largely-compatible userspace RTC API families you may | ||
17 | need to know about: | ||
18 | |||
19 | * /dev/rtc ... is the RTC provided by PC compatible systems, | ||
20 | so it's not very portable to non-x86 systems. | ||
21 | |||
22 | * /dev/rtc0, /dev/rtc1 ... are part of a framework that's | ||
23 | supported by a wide variety of RTC chips on all systems. | ||
24 | |||
25 | Programmers need to understand that the PC/AT functionality is not | ||
26 | always available, and some systems can do much more. That is, the | ||
27 | RTCs use the same API to make requests in both RTC frameworks (using | ||
28 | different filenames of course), but the hardware may not offer the | ||
29 | same functionality. For example, not every RTC is hooked up to an | ||
30 | IRQ, so they can't all issue alarms; and where standard PC RTCs can | ||
31 | only issue an alarm up to 24 hours in the future, other hardware may | ||
32 | be able to schedule one any time in the upcoming century. | ||
33 | |||
34 | |||
35 | Old PC/AT-Compatible driver: /dev/rtc | ||
36 | -------------------------------------- | ||
4 | 37 | ||
5 | All PCs (even Alpha machines) have a Real Time Clock built into them. | 38 | All PCs (even Alpha machines) have a Real Time Clock built into them. |
6 | Usually they are built into the chipset of the computer, but some may | 39 | Usually they are built into the chipset of the computer, but some may |
7 | actually have a Motorola MC146818 (or clone) on the board. This is the | 40 | actually have a Motorola MC146818 (or clone) on the board. This is the |
8 | clock that keeps the date and time while your computer is turned off. | 41 | clock that keeps the date and time while your computer is turned off. |
9 | 42 | ||
43 | ACPI has standardized that MC146818 functionality, and extended it in | ||
44 | a few ways (enabling longer alarm periods, and wake-from-hibernate). | ||
45 | That functionality is NOT exposed in the old driver. | ||
46 | |||
10 | However it can also be used to generate signals from a slow 2Hz to a | 47 | However it can also be used to generate signals from a slow 2Hz to a |
11 | relatively fast 8192Hz, in increments of powers of two. These signals | 48 | relatively fast 8192Hz, in increments of powers of two. These signals |
12 | are reported by interrupt number 8. (Oh! So *that* is what IRQ 8 is | 49 | are reported by interrupt number 8. (Oh! So *that* is what IRQ 8 is |
@@ -63,223 +100,331 @@ Rather than write 50 pages describing the ioctl() and so on, it is | |||
63 | perhaps more useful to include a small test program that demonstrates | 100 | perhaps more useful to include a small test program that demonstrates |
64 | how to use them, and demonstrates the features of the driver. This is | 101 | how to use them, and demonstrates the features of the driver. This is |
65 | probably a lot more useful to people interested in writing applications | 102 | probably a lot more useful to people interested in writing applications |
66 | that will be using this driver. | 103 | that will be using this driver. See the code at the end of this document. |
104 | |||
105 | (The original /dev/rtc driver was written by Paul Gortmaker.) | ||
106 | |||
107 | |||
108 | New portable "RTC Class" drivers: /dev/rtcN | ||
109 | -------------------------------------------- | ||
110 | |||
111 | Because Linux supports many non-ACPI and non-PC platforms, some of which | ||
112 | have more than one RTC style clock, it needed a more portable solution | ||
113 | than expecting a single battery-backed MC146818 clone on every system. | ||
114 | Accordingly, a new "RTC Class" framework has been defined. It offers | ||
115 | three different userspace interfaces: | ||
116 | |||
117 | * /dev/rtcN ... much the same as the older /dev/rtc interface | ||
118 | |||
119 | * /sys/class/rtc/rtcN ... sysfs attributes support readonly | ||
120 | access to some RTC attributes. | ||
121 | |||
122 | * /proc/driver/rtc ... the first RTC (rtc0) may expose itself | ||
123 | using a procfs interface. More information is (currently) shown | ||
124 | here than through sysfs. | ||
125 | |||
126 | The RTC Class framework supports a wide variety of RTCs, ranging from those | ||
127 | integrated into embeddable system-on-chip (SOC) processors to discrete chips | ||
128 | using I2C, SPI, or some other bus to communicate with the host CPU. There's | ||
129 | even support for PC-style RTCs ... including the features exposed on newer PCs | ||
130 | through ACPI. | ||
131 | |||
132 | The new framework also removes the "one RTC per system" restriction. For | ||
133 | example, maybe the low-power battery-backed RTC is a discrete I2C chip, but | ||
134 | a high functionality RTC is integrated into the SOC. That system might read | ||
135 | the system clock from the discrete RTC, but use the integrated one for all | ||
136 | other tasks, because of its greater functionality. | ||
137 | |||
138 | The ioctl() calls supported by /dev/rtc are also supported by the RTC class | ||
139 | framework. However, because the chips and systems are not standardized, | ||
140 | some PC/AT functionality might not be provided. And in the same way, some | ||
141 | newer features -- including those enabled by ACPI -- are exposed by the | ||
142 | RTC class framework, but can't be supported by the older driver. | ||
143 | |||
144 | * RTC_RD_TIME, RTC_SET_TIME ... every RTC supports at least reading | ||
145 | time, returning the result as a Gregorian calendar date and 24 hour | ||
146 | wall clock time. To be most useful, this time may also be updated. | ||
147 | |||
148 | * RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC | ||
149 | is connected to an IRQ line, it can often issue an alarm IRQ up to | ||
150 | 24 hours in the future. | ||
151 | |||
152 | * RTC_WKALM_SET, RTC_WKALM_READ ... RTCs that can issue alarms beyond | ||
153 | the next 24 hours use a slightly more powerful API, which supports | ||
154 | setting the longer alarm time and enabling its IRQ using a single | ||
155 | request (using the same model as EFI firmware). | ||
156 | |||
157 | * RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, it probably | ||
158 | also offers update IRQs whenever the "seconds" counter changes. | ||
159 | If needed, the RTC framework can emulate this mechanism. | ||
160 | |||
161 | * RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... another | ||
162 | feature often accessible with an IRQ line is a periodic IRQ, issued | ||
163 | at settable frequencies (usually 2^N Hz). | ||
164 | |||
165 | In many cases, the RTC alarm can be a system wake event, used to force | ||
166 | Linux out of a low power sleep state (or hibernation) back to a fully | ||
167 | operational state. For example, a system could enter a deep power saving | ||
168 | state until it's time to execute some scheduled tasks. | ||
67 | 169 | ||
68 | Paul Gortmaker | ||
69 | 170 | ||
70 | -------------------- 8< ---------------- 8< ----------------------------- | 171 | -------------------- 8< ---------------- 8< ----------------------------- |
71 | 172 | ||
72 | /* | 173 | /* |
73 | * Real Time Clock Driver Test/Example Program | 174 | * Real Time Clock Driver Test/Example Program |
74 | * | 175 | * |
75 | * Compile with: | 176 | * Compile with: |
76 | * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest | 177 | * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest |
77 | * | 178 | * |
78 | * Copyright (C) 1996, Paul Gortmaker. | 179 | * Copyright (C) 1996, Paul Gortmaker. |
79 | * | 180 | * |
80 | * Released under the GNU General Public License, version 2, | 181 | * Released under the GNU General Public License, version 2, |
81 | * included herein by reference. | 182 | * included herein by reference. |
82 | * | 183 | * |
83 | */ | 184 | */ |
84 | 185 | ||
85 | #include <stdio.h> | 186 | #include <stdio.h> |
86 | #include <stdlib.h> | ||
87 | #include <linux/rtc.h> | 187 | #include <linux/rtc.h> |
88 | #include <sys/ioctl.h> | 188 | #include <sys/ioctl.h> |
89 | #include <sys/time.h> | 189 | #include <sys/time.h> |
90 | #include <sys/types.h> | 190 | #include <sys/types.h> |
91 | #include <fcntl.h> | 191 | #include <fcntl.h> |
92 | #include <unistd.h> | 192 | #include <unistd.h> |
193 | #include <stdlib.h> | ||
93 | #include <errno.h> | 194 | #include <errno.h> |
94 | 195 | ||
95 | int main(void) { | ||
96 | |||
97 | int i, fd, retval, irqcount = 0; | ||
98 | unsigned long tmp, data; | ||
99 | struct rtc_time rtc_tm; | ||
100 | 196 | ||
101 | fd = open ("/dev/rtc", O_RDONLY); | 197 | /* |
198 | * This expects the new RTC class driver framework, working with | ||
199 | * clocks that will often not be clones of what the PC-AT had. | ||
200 | * Use the command line to specify another RTC if you need one. | ||
201 | */ | ||
202 | static const char default_rtc[] = "/dev/rtc0"; | ||
203 | |||
204 | |||
205 | int main(int argc, char **argv) | ||
206 | { | ||
207 | int i, fd, retval, irqcount = 0; | ||
208 | unsigned long tmp, data; | ||
209 | struct rtc_time rtc_tm; | ||
210 | const char *rtc = default_rtc; | ||
211 | |||
212 | switch (argc) { | ||
213 | case 2: | ||
214 | rtc = argv[1]; | ||
215 | /* FALLTHROUGH */ | ||
216 | case 1: | ||
217 | break; | ||
218 | default: | ||
219 | fprintf(stderr, "usage: rtctest [rtcdev]\n"); | ||
220 | return 1; | ||
221 | } | ||
102 | 222 | ||
103 | if (fd == -1) { | 223 | fd = open(rtc, O_RDONLY); |
104 | perror("/dev/rtc"); | ||
105 | exit(errno); | ||
106 | } | ||
107 | 224 | ||
108 | fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); | 225 | if (fd == -1) { |
226 | perror(rtc); | ||
227 | exit(errno); | ||
228 | } | ||
109 | 229 | ||
110 | /* Turn on update interrupts (one per second) */ | 230 | fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); |
111 | retval = ioctl(fd, RTC_UIE_ON, 0); | ||
112 | if (retval == -1) { | ||
113 | perror("ioctl"); | ||
114 | exit(errno); | ||
115 | } | ||
116 | 231 | ||
117 | fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading /dev/rtc:"); | 232 | /* Turn on update interrupts (one per second) */ |
118 | fflush(stderr); | 233 | retval = ioctl(fd, RTC_UIE_ON, 0); |
119 | for (i=1; i<6; i++) { | ||
120 | /* This read will block */ | ||
121 | retval = read(fd, &data, sizeof(unsigned long)); | ||
122 | if (retval == -1) { | 234 | if (retval == -1) { |
123 | perror("read"); | 235 | if (errno == ENOTTY) { |
236 | fprintf(stderr, | ||
237 | "\n...Update IRQs not supported.\n"); | ||
238 | goto test_READ; | ||
239 | } | ||
240 | perror("ioctl"); | ||
124 | exit(errno); | 241 | exit(errno); |
125 | } | 242 | } |
126 | fprintf(stderr, " %d",i); | 243 | |
244 | fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:", | ||
245 | rtc); | ||
127 | fflush(stderr); | 246 | fflush(stderr); |
128 | irqcount++; | 247 | for (i=1; i<6; i++) { |
129 | } | 248 | /* This read will block */ |
249 | retval = read(fd, &data, sizeof(unsigned long)); | ||
250 | if (retval == -1) { | ||
251 | perror("read"); | ||
252 | exit(errno); | ||
253 | } | ||
254 | fprintf(stderr, " %d",i); | ||
255 | fflush(stderr); | ||
256 | irqcount++; | ||
257 | } | ||
130 | 258 | ||
131 | fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); | 259 | fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); |
132 | fflush(stderr); | 260 | fflush(stderr); |
133 | for (i=1; i<6; i++) { | 261 | for (i=1; i<6; i++) { |
134 | struct timeval tv = {5, 0}; /* 5 second timeout on select */ | 262 | struct timeval tv = {5, 0}; /* 5 second timeout on select */ |
135 | fd_set readfds; | 263 | fd_set readfds; |
264 | |||
265 | FD_ZERO(&readfds); | ||
266 | FD_SET(fd, &readfds); | ||
267 | /* The select will wait until an RTC interrupt happens. */ | ||
268 | retval = select(fd+1, &readfds, NULL, NULL, &tv); | ||
269 | if (retval == -1) { | ||
270 | perror("select"); | ||
271 | exit(errno); | ||
272 | } | ||
273 | /* This read won't block unlike the select-less case above. */ | ||
274 | retval = read(fd, &data, sizeof(unsigned long)); | ||
275 | if (retval == -1) { | ||
276 | perror("read"); | ||
277 | exit(errno); | ||
278 | } | ||
279 | fprintf(stderr, " %d",i); | ||
280 | fflush(stderr); | ||
281 | irqcount++; | ||
282 | } | ||
136 | 283 | ||
137 | FD_ZERO(&readfds); | 284 | /* Turn off update interrupts */ |
138 | FD_SET(fd, &readfds); | 285 | retval = ioctl(fd, RTC_UIE_OFF, 0); |
139 | /* The select will wait until an RTC interrupt happens. */ | ||
140 | retval = select(fd+1, &readfds, NULL, NULL, &tv); | ||
141 | if (retval == -1) { | 286 | if (retval == -1) { |
142 | perror("select"); | 287 | perror("ioctl"); |
143 | exit(errno); | 288 | exit(errno); |
144 | } | 289 | } |
145 | /* This read won't block unlike the select-less case above. */ | 290 | |
146 | retval = read(fd, &data, sizeof(unsigned long)); | 291 | test_READ: |
292 | /* Read the RTC time/date */ | ||
293 | retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); | ||
147 | if (retval == -1) { | 294 | if (retval == -1) { |
148 | perror("read"); | 295 | perror("ioctl"); |
149 | exit(errno); | 296 | exit(errno); |
150 | } | 297 | } |
151 | fprintf(stderr, " %d",i); | ||
152 | fflush(stderr); | ||
153 | irqcount++; | ||
154 | } | ||
155 | |||
156 | /* Turn off update interrupts */ | ||
157 | retval = ioctl(fd, RTC_UIE_OFF, 0); | ||
158 | if (retval == -1) { | ||
159 | perror("ioctl"); | ||
160 | exit(errno); | ||
161 | } | ||
162 | |||
163 | /* Read the RTC time/date */ | ||
164 | retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); | ||
165 | if (retval == -1) { | ||
166 | perror("ioctl"); | ||
167 | exit(errno); | ||
168 | } | ||
169 | |||
170 | fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", | ||
171 | rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, | ||
172 | rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); | ||
173 | |||
174 | /* Set the alarm to 5 sec in the future, and check for rollover */ | ||
175 | rtc_tm.tm_sec += 5; | ||
176 | if (rtc_tm.tm_sec >= 60) { | ||
177 | rtc_tm.tm_sec %= 60; | ||
178 | rtc_tm.tm_min++; | ||
179 | } | ||
180 | if (rtc_tm.tm_min == 60) { | ||
181 | rtc_tm.tm_min = 0; | ||
182 | rtc_tm.tm_hour++; | ||
183 | } | ||
184 | if (rtc_tm.tm_hour == 24) | ||
185 | rtc_tm.tm_hour = 0; | ||
186 | |||
187 | retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); | ||
188 | if (retval == -1) { | ||
189 | perror("ioctl"); | ||
190 | exit(errno); | ||
191 | } | ||
192 | |||
193 | /* Read the current alarm settings */ | ||
194 | retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); | ||
195 | if (retval == -1) { | ||
196 | perror("ioctl"); | ||
197 | exit(errno); | ||
198 | } | ||
199 | |||
200 | fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", | ||
201 | rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); | ||
202 | 298 | ||
203 | /* Enable alarm interrupts */ | 299 | fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", |
204 | retval = ioctl(fd, RTC_AIE_ON, 0); | 300 | rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, |
205 | if (retval == -1) { | 301 | rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); |
206 | perror("ioctl"); | ||
207 | exit(errno); | ||
208 | } | ||
209 | 302 | ||
210 | fprintf(stderr, "Waiting 5 seconds for alarm..."); | 303 | /* Set the alarm to 5 sec in the future, and check for rollover */ |
211 | fflush(stderr); | 304 | rtc_tm.tm_sec += 5; |
212 | /* This blocks until the alarm ring causes an interrupt */ | 305 | if (rtc_tm.tm_sec >= 60) { |
213 | retval = read(fd, &data, sizeof(unsigned long)); | 306 | rtc_tm.tm_sec %= 60; |
214 | if (retval == -1) { | 307 | rtc_tm.tm_min++; |
215 | perror("read"); | 308 | } |
216 | exit(errno); | 309 | if (rtc_tm.tm_min == 60) { |
217 | } | 310 | rtc_tm.tm_min = 0; |
218 | irqcount++; | 311 | rtc_tm.tm_hour++; |
219 | fprintf(stderr, " okay. Alarm rang.\n"); | 312 | } |
220 | 313 | if (rtc_tm.tm_hour == 24) | |
221 | /* Disable alarm interrupts */ | 314 | rtc_tm.tm_hour = 0; |
222 | retval = ioctl(fd, RTC_AIE_OFF, 0); | ||
223 | if (retval == -1) { | ||
224 | perror("ioctl"); | ||
225 | exit(errno); | ||
226 | } | ||
227 | 315 | ||
228 | /* Read periodic IRQ rate */ | 316 | retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); |
229 | retval = ioctl(fd, RTC_IRQP_READ, &tmp); | 317 | if (retval == -1) { |
230 | if (retval == -1) { | 318 | if (errno == ENOTTY) { |
231 | perror("ioctl"); | 319 | fprintf(stderr, |
232 | exit(errno); | 320 | "\n...Alarm IRQs not supported.\n"); |
233 | } | 321 | goto test_PIE; |
234 | fprintf(stderr, "\nPeriodic IRQ rate was %ldHz.\n", tmp); | 322 | } |
323 | perror("ioctl"); | ||
324 | exit(errno); | ||
325 | } | ||
235 | 326 | ||
236 | fprintf(stderr, "Counting 20 interrupts at:"); | 327 | /* Read the current alarm settings */ |
237 | fflush(stderr); | 328 | retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); |
329 | if (retval == -1) { | ||
330 | perror("ioctl"); | ||
331 | exit(errno); | ||
332 | } | ||
238 | 333 | ||
239 | /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ | 334 | fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", |
240 | for (tmp=2; tmp<=64; tmp*=2) { | 335 | rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); |
241 | 336 | ||
242 | retval = ioctl(fd, RTC_IRQP_SET, tmp); | 337 | /* Enable alarm interrupts */ |
338 | retval = ioctl(fd, RTC_AIE_ON, 0); | ||
243 | if (retval == -1) { | 339 | if (retval == -1) { |
244 | perror("ioctl"); | 340 | perror("ioctl"); |
245 | exit(errno); | 341 | exit(errno); |
246 | } | 342 | } |
247 | 343 | ||
248 | fprintf(stderr, "\n%ldHz:\t", tmp); | 344 | fprintf(stderr, "Waiting 5 seconds for alarm..."); |
249 | fflush(stderr); | 345 | fflush(stderr); |
346 | /* This blocks until the alarm ring causes an interrupt */ | ||
347 | retval = read(fd, &data, sizeof(unsigned long)); | ||
348 | if (retval == -1) { | ||
349 | perror("read"); | ||
350 | exit(errno); | ||
351 | } | ||
352 | irqcount++; | ||
353 | fprintf(stderr, " okay. Alarm rang.\n"); | ||
250 | 354 | ||
251 | /* Enable periodic interrupts */ | 355 | /* Disable alarm interrupts */ |
252 | retval = ioctl(fd, RTC_PIE_ON, 0); | 356 | retval = ioctl(fd, RTC_AIE_OFF, 0); |
253 | if (retval == -1) { | 357 | if (retval == -1) { |
254 | perror("ioctl"); | 358 | perror("ioctl"); |
255 | exit(errno); | 359 | exit(errno); |
256 | } | 360 | } |
257 | 361 | ||
258 | for (i=1; i<21; i++) { | 362 | test_PIE: |
259 | /* This blocks */ | 363 | /* Read periodic IRQ rate */ |
260 | retval = read(fd, &data, sizeof(unsigned long)); | 364 | retval = ioctl(fd, RTC_IRQP_READ, &tmp); |
365 | if (retval == -1) { | ||
366 | /* not all RTCs support periodic IRQs */ | ||
367 | if (errno == ENOTTY) { | ||
368 | fprintf(stderr, "\nNo periodic IRQ support\n"); | ||
369 | return 0; | ||
370 | } | ||
371 | perror("ioctl"); | ||
372 | exit(errno); | ||
373 | } | ||
374 | fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); | ||
375 | |||
376 | fprintf(stderr, "Counting 20 interrupts at:"); | ||
377 | fflush(stderr); | ||
378 | |||
379 | /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ | ||
380 | for (tmp=2; tmp<=64; tmp*=2) { | ||
381 | |||
382 | retval = ioctl(fd, RTC_IRQP_SET, tmp); | ||
261 | if (retval == -1) { | 383 | if (retval == -1) { |
262 | perror("read"); | 384 | /* not all RTCs can change their periodic IRQ rate */ |
263 | exit(errno); | 385 | if (errno == ENOTTY) { |
386 | fprintf(stderr, | ||
387 | "\n...Periodic IRQ rate is fixed\n"); | ||
388 | goto done; | ||
389 | } | ||
390 | perror("ioctl"); | ||
391 | exit(errno); | ||
264 | } | 392 | } |
265 | fprintf(stderr, " %d",i); | 393 | |
394 | fprintf(stderr, "\n%ldHz:\t", tmp); | ||
266 | fflush(stderr); | 395 | fflush(stderr); |
267 | irqcount++; | ||
268 | } | ||
269 | 396 | ||
270 | /* Disable periodic interrupts */ | 397 | /* Enable periodic interrupts */ |
271 | retval = ioctl(fd, RTC_PIE_OFF, 0); | 398 | retval = ioctl(fd, RTC_PIE_ON, 0); |
272 | if (retval == -1) { | 399 | if (retval == -1) { |
273 | perror("ioctl"); | 400 | perror("ioctl"); |
274 | exit(errno); | 401 | exit(errno); |
402 | } | ||
403 | |||
404 | for (i=1; i<21; i++) { | ||
405 | /* This blocks */ | ||
406 | retval = read(fd, &data, sizeof(unsigned long)); | ||
407 | if (retval == -1) { | ||
408 | perror("read"); | ||
409 | exit(errno); | ||
410 | } | ||
411 | fprintf(stderr, " %d",i); | ||
412 | fflush(stderr); | ||
413 | irqcount++; | ||
414 | } | ||
415 | |||
416 | /* Disable periodic interrupts */ | ||
417 | retval = ioctl(fd, RTC_PIE_OFF, 0); | ||
418 | if (retval == -1) { | ||
419 | perror("ioctl"); | ||
420 | exit(errno); | ||
421 | } | ||
275 | } | 422 | } |
276 | } | ||
277 | 423 | ||
278 | fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); | 424 | done: |
279 | fprintf(stderr, "\nTyping \"cat /proc/interrupts\" will show %d more events on IRQ 8.\n\n", | 425 | fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); |
280 | irqcount); | ||
281 | 426 | ||
282 | close(fd); | 427 | close(fd); |
283 | return 0; | ||
284 | 428 | ||
285 | } /* end main */ | 429 | return 0; |
430 | } | ||