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