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