Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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