diff options
| -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 | } | ||
