Contents of /alx-src/tags/kernel26-2.6.12-alx-r9/Documentation/hpet.txt
Parent Directory | Revision Log
Revision 630 -
(show annotations)
(download)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 6569 byte(s)
Wed Mar 4 11:03:09 2009 UTC (15 years, 6 months ago) by niro
File MIME type: text/plain
File size: 6569 byte(s)
Tag kernel26-2.6.12-alx-r9
1 | High Precision Event Timer Driver for Linux |
2 | |
3 | The High Precision Event Timer (HPET) hardware is the future replacement for the 8254 and Real |
4 | Time Clock (RTC) periodic timer functionality. Each HPET can have up two 32 timers. It is possible |
5 | to configure the first two timers as legacy replacements for 8254 and RTC periodic. A specification |
6 | done by INTEL and Microsoft can be found at http://www.intel.com/labs/platcomp/hpet/hpetspec.htm. |
7 | |
8 | The driver supports detection of HPET driver allocation and initialization of the HPET before the |
9 | driver module_init routine is called. This enables platform code which uses timer 0 or 1 as the |
10 | main timer to intercept HPET initialization. An example of this initialization can be found in |
11 | arch/i386/kernel/time_hpet.c. |
12 | |
13 | The driver provides two APIs which are very similar to the API found in the rtc.c driver. |
14 | There is a user space API and a kernel space API. An example user space program is provided |
15 | below. |
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 | |
35 | extern void hpet_open_close(int, const char **); |
36 | extern void hpet_info(int, const char **); |
37 | extern void hpet_poll(int, const char **); |
38 | extern void hpet_fasync(int, const char **); |
39 | extern void hpet_read(int, const char **); |
40 | |
41 | #include <sys/poll.h> |
42 | #include <sys/ioctl.h> |
43 | #include <signal.h> |
44 | |
45 | struct 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 | |
67 | int |
68 | main(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 | |
96 | void |
97 | hpet_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 | |
115 | void |
116 | hpet_info(int argc, const char **argv) |
117 | { |
118 | } |
119 | |
120 | void |
121 | hpet_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 | |
198 | out: |
199 | close(fd); |
200 | return; |
201 | } |
202 | |
203 | static int hpet_sigio_count; |
204 | |
205 | static void |
206 | hpet_sigio(int val) |
207 | { |
208 | fprintf(stderr, "hpet_sigio: called\n"); |
209 | hpet_sigio_count++; |
210 | } |
211 | |
212 | void |
213 | hpet_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 | |
278 | out: |
279 | signal(SIGIO, oldsig); |
280 | |
281 | if (fd >= 0) |
282 | close(fd); |
283 | |
284 | return; |
285 | } |
286 | |
287 | The 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 | |
293 | The kernel module using this interface fills in the ht_func and ht_data members of the |
294 | hpet_task structure before calling hpet_register. hpet_control simply vectors to the hpet_ioctl |
295 | routine and has the same commands and respective arguments as the user API. hpet_unregister |
296 | is used to terminate usage of the HPET timer reserved by hpet_register. |
297 | |
298 |