Based on kernel version 2.6.27. Page generated on 2008-10-13 09:53 EST.
1 High Precision Event Timer Driver for Linux 2 3 The High Precision Event Timer (HPET) hardware is the future replacement 4 for the 8254 and Real Time Clock (RTC) periodic timer functionality. 5 Each HPET can have up to 32 timers. It is possible to configure the 6 first two timers as legacy replacements for 8254 and RTC periodic timers. 7 A specification done by Intel and Microsoft can be found at 8 <http://www.intel.com/technology/architecture/hpetspec.htm>. 9 10 The driver supports detection of HPET driver allocation and initialization 11 of the HPET before the driver module_init routine is called. This enables 12 platform code which uses timer 0 or 1 as the main timer to intercept HPET 13 initialization. An example of this initialization can be found in 14 arch/i386/kernel/time_hpet.c. 15 16 The driver provides two APIs which are very similar to the API found in 17 the rtc.c driver. There is a user space API and a kernel space API. 18 An example user space program is provided below. 19 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <unistd.h> 23 #include <fcntl.h> 24 #include <string.h> 25 #include <memory.h> 26 #include <malloc.h> 27 #include <time.h> 28 #include <ctype.h> 29 #include <sys/types.h> 30 #include <sys/wait.h> 31 #include <signal.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <sys/time.h> 35 #include <linux/hpet.h> 36 37 38 extern void hpet_open_close(int, const char **); 39 extern void hpet_info(int, const char **); 40 extern void hpet_poll(int, const char **); 41 extern void hpet_fasync(int, const char **); 42 extern void hpet_read(int, const char **); 43 44 #include <sys/poll.h> 45 #include <sys/ioctl.h> 46 #include <signal.h> 47 48 struct hpet_command { 49 char *command; 50 void (*func)(int argc, const char ** argv); 51 } hpet_command[] = { 52 { 53 "open-close", 54 hpet_open_close 55 }, 56 { 57 "info", 58 hpet_info 59 }, 60 { 61 "poll", 62 hpet_poll 63 }, 64 { 65 "fasync", 66 hpet_fasync 67 }, 68 }; 69 70 int 71 main(int argc, const char ** argv) 72 { 73 int i; 74 75 argc--; 76 argv++; 77 78 if (!argc) { 79 fprintf(stderr, "-hpet: requires command\n"); 80 return -1; 81 } 82 83 84 for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++) 85 if (!strcmp(argv[0], hpet_command[i].command)) { 86 argc--; 87 argv++; 88 fprintf(stderr, "-hpet: executing %s\n", 89 hpet_command[i].command); 90 hpet_command[i].func(argc, argv); 91 return 0; 92 } 93 94 fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]); 95 96 return -1; 97 } 98 99 void 100 hpet_open_close(int argc, const char **argv) 101 { 102 int fd; 103 104 if (argc != 1) { 105 fprintf(stderr, "hpet_open_close: device-name\n"); 106 return; 107 } 108 109 fd = open(argv[0], O_RDONLY); 110 if (fd < 0) 111 fprintf(stderr, "hpet_open_close: open failed\n"); 112 else 113 close(fd); 114 115 return; 116 } 117 118 void 119 hpet_info(int argc, const char **argv) 120 { 121 } 122 123 void 124 hpet_poll(int argc, const char **argv) 125 { 126 unsigned long freq; 127 int iterations, i, fd; 128 struct pollfd pfd; 129 struct hpet_info info; 130 struct timeval stv, etv; 131 struct timezone tz; 132 long usec; 133 134 if (argc != 3) { 135 fprintf(stderr, "hpet_poll: device-name freq iterations\n"); 136 return; 137 } 138 139 freq = atoi(argv[1]); 140 iterations = atoi(argv[2]); 141 142 fd = open(argv[0], O_RDONLY); 143 144 if (fd < 0) { 145 fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]); 146 return; 147 } 148 149 if (ioctl(fd, HPET_IRQFREQ, freq) < 0) { 150 fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n"); 151 goto out; 152 } 153 154 if (ioctl(fd, HPET_INFO, &info) < 0) { 155 fprintf(stderr, "hpet_poll: failed to get info\n"); 156 goto out; 157 } 158 159 fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags); 160 161 if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) { 162 fprintf(stderr, "hpet_poll: HPET_EPI failed\n"); 163 goto out; 164 } 165 166 if (ioctl(fd, HPET_IE_ON, 0) < 0) { 167 fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n"); 168 goto out; 169 } 170 171 pfd.fd = fd; 172 pfd.events = POLLIN; 173 174 for (i = 0; i < iterations; i++) { 175 pfd.revents = 0; 176 gettimeofday(&stv, &tz); 177 if (poll(&pfd, 1, -1) < 0) 178 fprintf(stderr, "hpet_poll: poll failed\n"); 179 else { 180 long data; 181 182 gettimeofday(&etv, &tz); 183 usec = stv.tv_sec * 1000000 + stv.tv_usec; 184 usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec; 185 186 fprintf(stderr, 187 "hpet_poll: expired time = 0x%lx\n", usec); 188 189 fprintf(stderr, "hpet_poll: revents = 0x%x\n", 190 pfd.revents); 191 192 if (read(fd, &data, sizeof(data)) != sizeof(data)) { 193 fprintf(stderr, "hpet_poll: read failed\n"); 194 } 195 else 196 fprintf(stderr, "hpet_poll: data 0x%lx\n", 197 data); 198 } 199 } 200 201 out: 202 close(fd); 203 return; 204 } 205 206 static int hpet_sigio_count; 207 208 static void 209 hpet_sigio(int val) 210 { 211 fprintf(stderr, "hpet_sigio: called\n"); 212 hpet_sigio_count++; 213 } 214 215 void 216 hpet_fasync(int argc, const char **argv) 217 { 218 unsigned long freq; 219 int iterations, i, fd, value; 220 sig_t oldsig; 221 struct hpet_info info; 222 223 hpet_sigio_count = 0; 224 fd = -1; 225 226 if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) { 227 fprintf(stderr, "hpet_fasync: failed to set signal handler\n"); 228 return; 229 } 230 231 if (argc != 3) { 232 fprintf(stderr, "hpet_fasync: device-name freq iterations\n"); 233 goto out; 234 } 235 236 fd = open(argv[0], O_RDONLY); 237 238 if (fd < 0) { 239 fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]); 240 return; 241 } 242 243 244 if ((fcntl(fd, F_SETOWN, getpid()) == 1) || 245 ((value = fcntl(fd, F_GETFL)) == 1) || 246 (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) { 247 fprintf(stderr, "hpet_fasync: fcntl failed\n"); 248 goto out; 249 } 250 251 freq = atoi(argv[1]); 252 iterations = atoi(argv[2]); 253 254 if (ioctl(fd, HPET_IRQFREQ, freq) < 0) { 255 fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n"); 256 goto out; 257 } 258 259 if (ioctl(fd, HPET_INFO, &info) < 0) { 260 fprintf(stderr, "hpet_fasync: failed to get info\n"); 261 goto out; 262 } 263 264 fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags); 265 266 if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) { 267 fprintf(stderr, "hpet_fasync: HPET_EPI failed\n"); 268 goto out; 269 } 270 271 if (ioctl(fd, HPET_IE_ON, 0) < 0) { 272 fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n"); 273 goto out; 274 } 275 276 for (i = 0; i < iterations; i++) { 277 (void) pause(); 278 fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count); 279 } 280 281 out: 282 signal(SIGIO, oldsig); 283 284 if (fd >= 0) 285 close(fd); 286 287 return; 288 } 289 290 The kernel API has three interfaces exported from the driver: 291 292 hpet_register(struct hpet_task *tp, int periodic) 293 hpet_unregister(struct hpet_task *tp) 294 hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) 295 296 The kernel module using this interface fills in the ht_func and ht_data 297 members of the hpet_task structure before calling hpet_register. 298 hpet_control simply vectors to the hpet_ioctl routine and has the same 299 commands and respective arguments as the user API. hpet_unregister 300 is used to terminate usage of the HPET timer reserved by hpet_register.