18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <stdio.h>
38c2ecf20Sopenharmony_ci#include <stdlib.h>
48c2ecf20Sopenharmony_ci#include <unistd.h>
58c2ecf20Sopenharmony_ci#include <fcntl.h>
68c2ecf20Sopenharmony_ci#include <string.h>
78c2ecf20Sopenharmony_ci#include <memory.h>
88c2ecf20Sopenharmony_ci#include <malloc.h>
98c2ecf20Sopenharmony_ci#include <time.h>
108c2ecf20Sopenharmony_ci#include <ctype.h>
118c2ecf20Sopenharmony_ci#include <sys/types.h>
128c2ecf20Sopenharmony_ci#include <sys/wait.h>
138c2ecf20Sopenharmony_ci#include <signal.h>
148c2ecf20Sopenharmony_ci#include <errno.h>
158c2ecf20Sopenharmony_ci#include <sys/time.h>
168c2ecf20Sopenharmony_ci#include <linux/hpet.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ciextern void hpet_open_close(int, const char **);
208c2ecf20Sopenharmony_ciextern void hpet_info(int, const char **);
218c2ecf20Sopenharmony_ciextern void hpet_poll(int, const char **);
228c2ecf20Sopenharmony_ciextern void hpet_fasync(int, const char **);
238c2ecf20Sopenharmony_ciextern void hpet_read(int, const char **);
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <sys/poll.h>
268c2ecf20Sopenharmony_ci#include <sys/ioctl.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct hpet_command {
298c2ecf20Sopenharmony_ci	char		*command;
308c2ecf20Sopenharmony_ci	void		(*func)(int argc, const char ** argv);
318c2ecf20Sopenharmony_ci} hpet_command[] = {
328c2ecf20Sopenharmony_ci	{
338c2ecf20Sopenharmony_ci		"open-close",
348c2ecf20Sopenharmony_ci		hpet_open_close
358c2ecf20Sopenharmony_ci	},
368c2ecf20Sopenharmony_ci	{
378c2ecf20Sopenharmony_ci		"info",
388c2ecf20Sopenharmony_ci		hpet_info
398c2ecf20Sopenharmony_ci	},
408c2ecf20Sopenharmony_ci	{
418c2ecf20Sopenharmony_ci		"poll",
428c2ecf20Sopenharmony_ci		hpet_poll
438c2ecf20Sopenharmony_ci	},
448c2ecf20Sopenharmony_ci	{
458c2ecf20Sopenharmony_ci		"fasync",
468c2ecf20Sopenharmony_ci		hpet_fasync
478c2ecf20Sopenharmony_ci	},
488c2ecf20Sopenharmony_ci};
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciint
518c2ecf20Sopenharmony_cimain(int argc, const char ** argv)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	unsigned int	i;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	argc--;
568c2ecf20Sopenharmony_ci	argv++;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (!argc) {
598c2ecf20Sopenharmony_ci		fprintf(stderr, "-hpet: requires command\n");
608c2ecf20Sopenharmony_ci		return -1;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
658c2ecf20Sopenharmony_ci		if (!strcmp(argv[0], hpet_command[i].command)) {
668c2ecf20Sopenharmony_ci			argc--;
678c2ecf20Sopenharmony_ci			argv++;
688c2ecf20Sopenharmony_ci			fprintf(stderr, "-hpet: executing %s\n",
698c2ecf20Sopenharmony_ci				hpet_command[i].command);
708c2ecf20Sopenharmony_ci			hpet_command[i].func(argc, argv);
718c2ecf20Sopenharmony_ci			return 0;
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return -1;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_civoid
808c2ecf20Sopenharmony_cihpet_open_close(int argc, const char **argv)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	int	fd;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	if (argc != 1) {
858c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_open_close: device-name\n");
868c2ecf20Sopenharmony_ci		return;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	fd = open(argv[0], O_RDONLY);
908c2ecf20Sopenharmony_ci	if (fd < 0)
918c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_open_close: open failed\n");
928c2ecf20Sopenharmony_ci	else
938c2ecf20Sopenharmony_ci		close(fd);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_civoid
998c2ecf20Sopenharmony_cihpet_info(int argc, const char **argv)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct hpet_info	info;
1028c2ecf20Sopenharmony_ci	int			fd;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (argc != 1) {
1058c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_info: device-name\n");
1068c2ecf20Sopenharmony_ci		return;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	fd = open(argv[0], O_RDONLY);
1108c2ecf20Sopenharmony_ci	if (fd < 0) {
1118c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_info: open of %s failed\n", argv[0]);
1128c2ecf20Sopenharmony_ci		return;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_INFO, &info) < 0) {
1168c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_info: failed to get info\n");
1178c2ecf20Sopenharmony_ci		goto out;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	fprintf(stderr, "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx ",
1218c2ecf20Sopenharmony_ci		info.hi_ireqfreq, info.hi_flags);
1228c2ecf20Sopenharmony_ci	fprintf(stderr, "hi_hpet %d hi_timer %d\n",
1238c2ecf20Sopenharmony_ci		info.hi_hpet, info.hi_timer);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciout:
1268c2ecf20Sopenharmony_ci	close(fd);
1278c2ecf20Sopenharmony_ci	return;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_civoid
1318c2ecf20Sopenharmony_cihpet_poll(int argc, const char **argv)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	unsigned long		freq;
1348c2ecf20Sopenharmony_ci	int			iterations, i, fd;
1358c2ecf20Sopenharmony_ci	struct pollfd		pfd;
1368c2ecf20Sopenharmony_ci	struct hpet_info	info;
1378c2ecf20Sopenharmony_ci	struct timeval		stv, etv;
1388c2ecf20Sopenharmony_ci	struct timezone		tz;
1398c2ecf20Sopenharmony_ci	long			usec;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (argc != 3) {
1428c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_poll: device-name freq iterations\n");
1438c2ecf20Sopenharmony_ci		return;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	freq = atoi(argv[1]);
1478c2ecf20Sopenharmony_ci	iterations = atoi(argv[2]);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	fd = open(argv[0], O_RDONLY);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (fd < 0) {
1528c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
1538c2ecf20Sopenharmony_ci		return;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
1578c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
1588c2ecf20Sopenharmony_ci		goto out;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_INFO, &info) < 0) {
1628c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_poll: failed to get info\n");
1638c2ecf20Sopenharmony_ci		goto out;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
1698c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
1708c2ecf20Sopenharmony_ci		goto out;
1718c2ecf20Sopenharmony_ci	}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
1748c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
1758c2ecf20Sopenharmony_ci		goto out;
1768c2ecf20Sopenharmony_ci	}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	pfd.fd = fd;
1798c2ecf20Sopenharmony_ci	pfd.events = POLLIN;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	for (i = 0; i < iterations; i++) {
1828c2ecf20Sopenharmony_ci		pfd.revents = 0;
1838c2ecf20Sopenharmony_ci		gettimeofday(&stv, &tz);
1848c2ecf20Sopenharmony_ci		if (poll(&pfd, 1, -1) < 0)
1858c2ecf20Sopenharmony_ci			fprintf(stderr, "hpet_poll: poll failed\n");
1868c2ecf20Sopenharmony_ci		else {
1878c2ecf20Sopenharmony_ci			long 	data;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci			gettimeofday(&etv, &tz);
1908c2ecf20Sopenharmony_ci			usec = stv.tv_sec * 1000000 + stv.tv_usec;
1918c2ecf20Sopenharmony_ci			usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci			fprintf(stderr,
1948c2ecf20Sopenharmony_ci				"hpet_poll: expired time = 0x%lx\n", usec);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci			fprintf(stderr, "hpet_poll: revents = 0x%x\n",
1978c2ecf20Sopenharmony_ci				pfd.revents);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci			if (read(fd, &data, sizeof(data)) != sizeof(data)) {
2008c2ecf20Sopenharmony_ci				fprintf(stderr, "hpet_poll: read failed\n");
2018c2ecf20Sopenharmony_ci			}
2028c2ecf20Sopenharmony_ci			else
2038c2ecf20Sopenharmony_ci				fprintf(stderr, "hpet_poll: data 0x%lx\n",
2048c2ecf20Sopenharmony_ci					data);
2058c2ecf20Sopenharmony_ci		}
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ciout:
2098c2ecf20Sopenharmony_ci	close(fd);
2108c2ecf20Sopenharmony_ci	return;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int hpet_sigio_count;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic void
2168c2ecf20Sopenharmony_cihpet_sigio(int val)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	fprintf(stderr, "hpet_sigio: called\n");
2198c2ecf20Sopenharmony_ci	hpet_sigio_count++;
2208c2ecf20Sopenharmony_ci}
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_civoid
2238c2ecf20Sopenharmony_cihpet_fasync(int argc, const char **argv)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	unsigned long		freq;
2268c2ecf20Sopenharmony_ci	int			iterations, i, fd, value;
2278c2ecf20Sopenharmony_ci	sig_t			oldsig;
2288c2ecf20Sopenharmony_ci	struct hpet_info	info;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	hpet_sigio_count = 0;
2318c2ecf20Sopenharmony_ci	fd = -1;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
2348c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
2358c2ecf20Sopenharmony_ci		return;
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (argc != 3) {
2398c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
2408c2ecf20Sopenharmony_ci		goto out;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	fd = open(argv[0], O_RDONLY);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	if (fd < 0) {
2468c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
2478c2ecf20Sopenharmony_ci		return;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
2528c2ecf20Sopenharmony_ci		((value = fcntl(fd, F_GETFL)) == 1) ||
2538c2ecf20Sopenharmony_ci		(fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
2548c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: fcntl failed\n");
2558c2ecf20Sopenharmony_ci		goto out;
2568c2ecf20Sopenharmony_ci	}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	freq = atoi(argv[1]);
2598c2ecf20Sopenharmony_ci	iterations = atoi(argv[2]);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
2628c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
2638c2ecf20Sopenharmony_ci		goto out;
2648c2ecf20Sopenharmony_ci	}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_INFO, &info) < 0) {
2678c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: failed to get info\n");
2688c2ecf20Sopenharmony_ci		goto out;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
2748c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
2758c2ecf20Sopenharmony_ci		goto out;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (ioctl(fd, HPET_IE_ON, 0) < 0) {
2798c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
2808c2ecf20Sopenharmony_ci		goto out;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	for (i = 0; i < iterations; i++) {
2848c2ecf20Sopenharmony_ci		(void) pause();
2858c2ecf20Sopenharmony_ci		fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciout:
2898c2ecf20Sopenharmony_ci	signal(SIGIO, oldsig);
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (fd >= 0)
2928c2ecf20Sopenharmony_ci		close(fd);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	return;
2958c2ecf20Sopenharmony_ci}
296