• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1		High Precision Event Timer Driver for Linux
2
3The High Precision Event Timer (HPET) hardware follows a specification
4by Intel and Microsoft which can be found at
5
6	http://www.intel.com/technology/architecture/hpetspec.htm
7
8Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
9and up to 32 comparators.  Normally three or more comparators are provided,
10each of which can generate oneshot interupts and at least one of which has
11additional hardware to support periodic interrupts.  The comparators are
12also called "timers", which can be misleading since usually timers are
13independent of each other ... these share a counter, complicating resets.
14
15HPET devices can support two interrupt routing modes.  In one mode, the
16comparators are additional interrupt sources with no particular system
17role.  Many x86 BIOS writers don't route HPET interrupts at all, which
18prevents use of that mode.  They support the other "legacy replacement"
19mode where the first two comparators block interrupts from 8254 timers
20and from the RTC.
21
22The driver supports detection of HPET driver allocation and initialization
23of the HPET before the driver module_init routine is called.  This enables
24platform code which uses timer 0 or 1 as the main timer to intercept HPET
25initialization.  An example of this initialization can be found in
26arch/x86/kernel/hpet.c.
27
28The driver provides a userspace API which resembles the API found in the
29RTC 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
49extern void hpet_open_close(int, const char **);
50extern void hpet_info(int, const char **);
51extern void hpet_poll(int, const char **);
52extern void hpet_fasync(int, const char **);
53extern void hpet_read(int, const char **);
54
55#include <sys/poll.h>
56#include <sys/ioctl.h>
57#include <signal.h>
58
59struct 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
81int
82main(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
110void
111hpet_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
129void
130hpet_info(int argc, const char **argv)
131{
132}
133
134void
135hpet_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
212out:
213	close(fd);
214	return;
215}
216
217static int hpet_sigio_count;
218
219static void
220hpet_sigio(int val)
221{
222	fprintf(stderr, "hpet_sigio: called\n");
223	hpet_sigio_count++;
224}
225
226void
227hpet_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
292out:
293	signal(SIGIO, oldsig);
294
295	if (fd >= 0)
296		close(fd);
297
298	return;
299}
300