1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <stdio.h> |
3 | #include <stdlib.h> |
4 | #include <unistd.h> |
5 | #include <fcntl.h> |
6 | #include <string.h> |
7 | #include <memory.h> |
8 | #include <malloc.h> |
9 | #include <time.h> |
10 | #include <ctype.h> |
11 | #include <sys/types.h> |
12 | #include <sys/wait.h> |
13 | #include <signal.h> |
14 | #include <errno.h> |
15 | #include <sys/time.h> |
16 | #include <linux/hpet.h> |
17 | |
18 | |
19 | extern void hpet_open_close(int, const char **); |
20 | extern void hpet_info(int, const char **); |
21 | extern void hpet_poll(int, const char **); |
22 | extern void hpet_fasync(int, const char **); |
23 | extern void hpet_read(int, const char **); |
24 | |
25 | #include <sys/poll.h> |
26 | #include <sys/ioctl.h> |
27 | |
28 | struct hpet_command { |
29 | char *command; |
30 | void (*func)(int argc, const char ** argv); |
31 | } hpet_command[] = { |
32 | { |
33 | "open-close" , |
34 | hpet_open_close |
35 | }, |
36 | { |
37 | "info" , |
38 | hpet_info |
39 | }, |
40 | { |
41 | "poll" , |
42 | hpet_poll |
43 | }, |
44 | { |
45 | "fasync" , |
46 | hpet_fasync |
47 | }, |
48 | }; |
49 | |
50 | int |
51 | main(int argc, const char ** argv) |
52 | { |
53 | unsigned int i; |
54 | |
55 | argc--; |
56 | argv++; |
57 | |
58 | if (!argc) { |
59 | fprintf(stderr, format: "-hpet: requires command\n" ); |
60 | return -1; |
61 | } |
62 | |
63 | |
64 | for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++) |
65 | if (!strcmp(s1: argv[0], s2: hpet_command[i].command)) { |
66 | argc--; |
67 | argv++; |
68 | fprintf(stderr, format: "-hpet: executing %s\n" , |
69 | hpet_command[i].command); |
70 | hpet_command[i].func(argc, argv); |
71 | return 0; |
72 | } |
73 | |
74 | fprintf(stderr, format: "do_hpet: command %s not implemented\n" , argv[0]); |
75 | |
76 | return -1; |
77 | } |
78 | |
79 | void |
80 | hpet_open_close(int argc, const char **argv) |
81 | { |
82 | int fd; |
83 | |
84 | if (argc != 1) { |
85 | fprintf(stderr, format: "hpet_open_close: device-name\n" ); |
86 | return; |
87 | } |
88 | |
89 | fd = open(file: argv[0], O_RDONLY); |
90 | if (fd < 0) |
91 | fprintf(stderr, format: "hpet_open_close: open failed\n" ); |
92 | else |
93 | close(fd: fd); |
94 | |
95 | return; |
96 | } |
97 | |
98 | void |
99 | hpet_info(int argc, const char **argv) |
100 | { |
101 | struct hpet_info info; |
102 | int fd; |
103 | |
104 | if (argc != 1) { |
105 | fprintf(stderr, format: "hpet_info: device-name\n" ); |
106 | return; |
107 | } |
108 | |
109 | fd = open(file: argv[0], O_RDONLY); |
110 | if (fd < 0) { |
111 | fprintf(stderr, format: "hpet_info: open of %s failed\n" , argv[0]); |
112 | return; |
113 | } |
114 | |
115 | if (ioctl(fd: fd, HPET_INFO, &info) < 0) { |
116 | fprintf(stderr, format: "hpet_info: failed to get info\n" ); |
117 | goto out; |
118 | } |
119 | |
120 | fprintf(stderr, format: "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx " , |
121 | info.hi_ireqfreq, info.hi_flags); |
122 | fprintf(stderr, format: "hi_hpet %d hi_timer %d\n" , |
123 | info.hi_hpet, info.hi_timer); |
124 | |
125 | out: |
126 | close(fd: fd); |
127 | return; |
128 | } |
129 | |
130 | void |
131 | hpet_poll(int argc, const char **argv) |
132 | { |
133 | unsigned long freq; |
134 | int iterations, i, fd; |
135 | struct pollfd pfd; |
136 | struct hpet_info info; |
137 | struct timeval stv, etv; |
138 | struct timezone tz; |
139 | long usec; |
140 | |
141 | if (argc != 3) { |
142 | fprintf(stderr, format: "hpet_poll: device-name freq iterations\n" ); |
143 | return; |
144 | } |
145 | |
146 | freq = atoi(nptr: argv[1]); |
147 | iterations = atoi(nptr: argv[2]); |
148 | |
149 | fd = open(file: argv[0], O_RDONLY); |
150 | |
151 | if (fd < 0) { |
152 | fprintf(stderr, format: "hpet_poll: open of %s failed\n" , argv[0]); |
153 | return; |
154 | } |
155 | |
156 | if (ioctl(fd: fd, HPET_IRQFREQ, freq) < 0) { |
157 | fprintf(stderr, format: "hpet_poll: HPET_IRQFREQ failed\n" ); |
158 | goto out; |
159 | } |
160 | |
161 | if (ioctl(fd: fd, HPET_INFO, &info) < 0) { |
162 | fprintf(stderr, format: "hpet_poll: failed to get info\n" ); |
163 | goto out; |
164 | } |
165 | |
166 | fprintf(stderr, format: "hpet_poll: info.hi_flags 0x%lx\n" , info.hi_flags); |
167 | |
168 | if (info.hi_flags && (ioctl(fd: fd, HPET_EPI, 0) < 0)) { |
169 | fprintf(stderr, format: "hpet_poll: HPET_EPI failed\n" ); |
170 | goto out; |
171 | } |
172 | |
173 | if (ioctl(fd: fd, HPET_IE_ON, 0) < 0) { |
174 | fprintf(stderr, format: "hpet_poll, HPET_IE_ON failed\n" ); |
175 | goto out; |
176 | } |
177 | |
178 | pfd.fd = fd; |
179 | pfd.events = POLLIN; |
180 | |
181 | for (i = 0; i < iterations; i++) { |
182 | pfd.revents = 0; |
183 | gettimeofday(tv: &stv, tz: &tz); |
184 | if (poll(fds: &pfd, nfds: 1, timeout: -1) < 0) |
185 | fprintf(stderr, format: "hpet_poll: poll failed\n" ); |
186 | else { |
187 | long data; |
188 | |
189 | gettimeofday(tv: &etv, tz: &tz); |
190 | usec = stv.tv_sec * 1000000 + stv.tv_usec; |
191 | usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec; |
192 | |
193 | fprintf(stderr, |
194 | format: "hpet_poll: expired time = 0x%lx\n" , usec); |
195 | |
196 | fprintf(stderr, format: "hpet_poll: revents = 0x%x\n" , |
197 | pfd.revents); |
198 | |
199 | if (read(fd: fd, buf: &data, nbytes: sizeof(data)) != sizeof(data)) { |
200 | fprintf(stderr, format: "hpet_poll: read failed\n" ); |
201 | } |
202 | else |
203 | fprintf(stderr, format: "hpet_poll: data 0x%lx\n" , |
204 | data); |
205 | } |
206 | } |
207 | |
208 | out: |
209 | close(fd: fd); |
210 | return; |
211 | } |
212 | |
213 | static int hpet_sigio_count; |
214 | |
215 | static void |
216 | hpet_sigio(int val) |
217 | { |
218 | fprintf(stderr, format: "hpet_sigio: called\n" ); |
219 | hpet_sigio_count++; |
220 | } |
221 | |
222 | void |
223 | hpet_fasync(int argc, const char **argv) |
224 | { |
225 | unsigned long freq; |
226 | int iterations, i, fd, value; |
227 | sig_t oldsig; |
228 | struct hpet_info info; |
229 | |
230 | hpet_sigio_count = 0; |
231 | fd = -1; |
232 | |
233 | if ((oldsig = signal(SIGIO, handler: hpet_sigio)) == SIG_ERR) { |
234 | fprintf(stderr, format: "hpet_fasync: failed to set signal handler\n" ); |
235 | return; |
236 | } |
237 | |
238 | if (argc != 3) { |
239 | fprintf(stderr, format: "hpet_fasync: device-name freq iterations\n" ); |
240 | goto out; |
241 | } |
242 | |
243 | fd = open(file: argv[0], O_RDONLY); |
244 | |
245 | if (fd < 0) { |
246 | fprintf(stderr, format: "hpet_fasync: failed to open %s\n" , argv[0]); |
247 | return; |
248 | } |
249 | |
250 | |
251 | if ((fcntl(fd: fd, F_SETOWN, getpid()) == 1) || |
252 | ((value = fcntl(fd: fd, F_GETFL)) == 1) || |
253 | (fcntl(fd: fd, F_SETFL, value | O_ASYNC) == 1)) { |
254 | fprintf(stderr, format: "hpet_fasync: fcntl failed\n" ); |
255 | goto out; |
256 | } |
257 | |
258 | freq = atoi(nptr: argv[1]); |
259 | iterations = atoi(nptr: argv[2]); |
260 | |
261 | if (ioctl(fd: fd, HPET_IRQFREQ, freq) < 0) { |
262 | fprintf(stderr, format: "hpet_fasync: HPET_IRQFREQ failed\n" ); |
263 | goto out; |
264 | } |
265 | |
266 | if (ioctl(fd: fd, HPET_INFO, &info) < 0) { |
267 | fprintf(stderr, format: "hpet_fasync: failed to get info\n" ); |
268 | goto out; |
269 | } |
270 | |
271 | fprintf(stderr, format: "hpet_fasync: info.hi_flags 0x%lx\n" , info.hi_flags); |
272 | |
273 | if (info.hi_flags && (ioctl(fd: fd, HPET_EPI, 0) < 0)) { |
274 | fprintf(stderr, format: "hpet_fasync: HPET_EPI failed\n" ); |
275 | goto out; |
276 | } |
277 | |
278 | if (ioctl(fd: fd, HPET_IE_ON, 0) < 0) { |
279 | fprintf(stderr, format: "hpet_fasync, HPET_IE_ON failed\n" ); |
280 | goto out; |
281 | } |
282 | |
283 | for (i = 0; i < iterations; i++) { |
284 | (void) pause(); |
285 | fprintf(stderr, format: "hpet_fasync: count = %d\n" , hpet_sigio_count); |
286 | } |
287 | |
288 | out: |
289 | signal(SIGIO, handler: oldsig); |
290 | |
291 | if (fd >= 0) |
292 | close(fd: fd); |
293 | |
294 | return; |
295 | } |
296 | |