162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <stdio.h> 362306a36Sopenharmony_ci#include <stdlib.h> 462306a36Sopenharmony_ci#include <unistd.h> 562306a36Sopenharmony_ci#include <fcntl.h> 662306a36Sopenharmony_ci#include <string.h> 762306a36Sopenharmony_ci#include <memory.h> 862306a36Sopenharmony_ci#include <malloc.h> 962306a36Sopenharmony_ci#include <time.h> 1062306a36Sopenharmony_ci#include <ctype.h> 1162306a36Sopenharmony_ci#include <sys/types.h> 1262306a36Sopenharmony_ci#include <sys/wait.h> 1362306a36Sopenharmony_ci#include <signal.h> 1462306a36Sopenharmony_ci#include <errno.h> 1562306a36Sopenharmony_ci#include <sys/time.h> 1662306a36Sopenharmony_ci#include <linux/hpet.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciextern void hpet_open_close(int, const char **); 2062306a36Sopenharmony_ciextern void hpet_info(int, const char **); 2162306a36Sopenharmony_ciextern void hpet_poll(int, const char **); 2262306a36Sopenharmony_ciextern void hpet_fasync(int, const char **); 2362306a36Sopenharmony_ciextern void hpet_read(int, const char **); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <sys/poll.h> 2662306a36Sopenharmony_ci#include <sys/ioctl.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct hpet_command { 2962306a36Sopenharmony_ci char *command; 3062306a36Sopenharmony_ci void (*func)(int argc, const char ** argv); 3162306a36Sopenharmony_ci} hpet_command[] = { 3262306a36Sopenharmony_ci { 3362306a36Sopenharmony_ci "open-close", 3462306a36Sopenharmony_ci hpet_open_close 3562306a36Sopenharmony_ci }, 3662306a36Sopenharmony_ci { 3762306a36Sopenharmony_ci "info", 3862306a36Sopenharmony_ci hpet_info 3962306a36Sopenharmony_ci }, 4062306a36Sopenharmony_ci { 4162306a36Sopenharmony_ci "poll", 4262306a36Sopenharmony_ci hpet_poll 4362306a36Sopenharmony_ci }, 4462306a36Sopenharmony_ci { 4562306a36Sopenharmony_ci "fasync", 4662306a36Sopenharmony_ci hpet_fasync 4762306a36Sopenharmony_ci }, 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ciint 5162306a36Sopenharmony_cimain(int argc, const char ** argv) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned int i; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci argc--; 5662306a36Sopenharmony_ci argv++; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (!argc) { 5962306a36Sopenharmony_ci fprintf(stderr, "-hpet: requires command\n"); 6062306a36Sopenharmony_ci return -1; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++) 6562306a36Sopenharmony_ci if (!strcmp(argv[0], hpet_command[i].command)) { 6662306a36Sopenharmony_ci argc--; 6762306a36Sopenharmony_ci argv++; 6862306a36Sopenharmony_ci fprintf(stderr, "-hpet: executing %s\n", 6962306a36Sopenharmony_ci hpet_command[i].command); 7062306a36Sopenharmony_ci hpet_command[i].func(argc, argv); 7162306a36Sopenharmony_ci return 0; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return -1; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid 8062306a36Sopenharmony_cihpet_open_close(int argc, const char **argv) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci int fd; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (argc != 1) { 8562306a36Sopenharmony_ci fprintf(stderr, "hpet_open_close: device-name\n"); 8662306a36Sopenharmony_ci return; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci fd = open(argv[0], O_RDONLY); 9062306a36Sopenharmony_ci if (fd < 0) 9162306a36Sopenharmony_ci fprintf(stderr, "hpet_open_close: open failed\n"); 9262306a36Sopenharmony_ci else 9362306a36Sopenharmony_ci close(fd); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid 9962306a36Sopenharmony_cihpet_info(int argc, const char **argv) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct hpet_info info; 10262306a36Sopenharmony_ci int fd; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (argc != 1) { 10562306a36Sopenharmony_ci fprintf(stderr, "hpet_info: device-name\n"); 10662306a36Sopenharmony_ci return; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci fd = open(argv[0], O_RDONLY); 11062306a36Sopenharmony_ci if (fd < 0) { 11162306a36Sopenharmony_ci fprintf(stderr, "hpet_info: open of %s failed\n", argv[0]); 11262306a36Sopenharmony_ci return; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (ioctl(fd, HPET_INFO, &info) < 0) { 11662306a36Sopenharmony_ci fprintf(stderr, "hpet_info: failed to get info\n"); 11762306a36Sopenharmony_ci goto out; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci fprintf(stderr, "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx ", 12162306a36Sopenharmony_ci info.hi_ireqfreq, info.hi_flags); 12262306a36Sopenharmony_ci fprintf(stderr, "hi_hpet %d hi_timer %d\n", 12362306a36Sopenharmony_ci info.hi_hpet, info.hi_timer); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ciout: 12662306a36Sopenharmony_ci close(fd); 12762306a36Sopenharmony_ci return; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_civoid 13162306a36Sopenharmony_cihpet_poll(int argc, const char **argv) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci unsigned long freq; 13462306a36Sopenharmony_ci int iterations, i, fd; 13562306a36Sopenharmony_ci struct pollfd pfd; 13662306a36Sopenharmony_ci struct hpet_info info; 13762306a36Sopenharmony_ci struct timeval stv, etv; 13862306a36Sopenharmony_ci struct timezone tz; 13962306a36Sopenharmony_ci long usec; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (argc != 3) { 14262306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: device-name freq iterations\n"); 14362306a36Sopenharmony_ci return; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci freq = atoi(argv[1]); 14762306a36Sopenharmony_ci iterations = atoi(argv[2]); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci fd = open(argv[0], O_RDONLY); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (fd < 0) { 15262306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]); 15362306a36Sopenharmony_ci return; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (ioctl(fd, HPET_IRQFREQ, freq) < 0) { 15762306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n"); 15862306a36Sopenharmony_ci goto out; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (ioctl(fd, HPET_INFO, &info) < 0) { 16262306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: failed to get info\n"); 16362306a36Sopenharmony_ci goto out; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) { 16962306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: HPET_EPI failed\n"); 17062306a36Sopenharmony_ci goto out; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (ioctl(fd, HPET_IE_ON, 0) < 0) { 17462306a36Sopenharmony_ci fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n"); 17562306a36Sopenharmony_ci goto out; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci pfd.fd = fd; 17962306a36Sopenharmony_ci pfd.events = POLLIN; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci for (i = 0; i < iterations; i++) { 18262306a36Sopenharmony_ci pfd.revents = 0; 18362306a36Sopenharmony_ci gettimeofday(&stv, &tz); 18462306a36Sopenharmony_ci if (poll(&pfd, 1, -1) < 0) 18562306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: poll failed\n"); 18662306a36Sopenharmony_ci else { 18762306a36Sopenharmony_ci long data; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci gettimeofday(&etv, &tz); 19062306a36Sopenharmony_ci usec = stv.tv_sec * 1000000 + stv.tv_usec; 19162306a36Sopenharmony_ci usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci fprintf(stderr, 19462306a36Sopenharmony_ci "hpet_poll: expired time = 0x%lx\n", usec); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: revents = 0x%x\n", 19762306a36Sopenharmony_ci pfd.revents); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (read(fd, &data, sizeof(data)) != sizeof(data)) { 20062306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: read failed\n"); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci else 20362306a36Sopenharmony_ci fprintf(stderr, "hpet_poll: data 0x%lx\n", 20462306a36Sopenharmony_ci data); 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciout: 20962306a36Sopenharmony_ci close(fd); 21062306a36Sopenharmony_ci return; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic int hpet_sigio_count; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic void 21662306a36Sopenharmony_cihpet_sigio(int val) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci fprintf(stderr, "hpet_sigio: called\n"); 21962306a36Sopenharmony_ci hpet_sigio_count++; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_civoid 22362306a36Sopenharmony_cihpet_fasync(int argc, const char **argv) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci unsigned long freq; 22662306a36Sopenharmony_ci int iterations, i, fd, value; 22762306a36Sopenharmony_ci sig_t oldsig; 22862306a36Sopenharmony_ci struct hpet_info info; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci hpet_sigio_count = 0; 23162306a36Sopenharmony_ci fd = -1; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) { 23462306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: failed to set signal handler\n"); 23562306a36Sopenharmony_ci return; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (argc != 3) { 23962306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: device-name freq iterations\n"); 24062306a36Sopenharmony_ci goto out; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci fd = open(argv[0], O_RDONLY); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (fd < 0) { 24662306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]); 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if ((fcntl(fd, F_SETOWN, getpid()) == 1) || 25262306a36Sopenharmony_ci ((value = fcntl(fd, F_GETFL)) == 1) || 25362306a36Sopenharmony_ci (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) { 25462306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: fcntl failed\n"); 25562306a36Sopenharmony_ci goto out; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci freq = atoi(argv[1]); 25962306a36Sopenharmony_ci iterations = atoi(argv[2]); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (ioctl(fd, HPET_IRQFREQ, freq) < 0) { 26262306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n"); 26362306a36Sopenharmony_ci goto out; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (ioctl(fd, HPET_INFO, &info) < 0) { 26762306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: failed to get info\n"); 26862306a36Sopenharmony_ci goto out; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) { 27462306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: HPET_EPI failed\n"); 27562306a36Sopenharmony_ci goto out; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (ioctl(fd, HPET_IE_ON, 0) < 0) { 27962306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n"); 28062306a36Sopenharmony_ci goto out; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci for (i = 0; i < iterations; i++) { 28462306a36Sopenharmony_ci (void) pause(); 28562306a36Sopenharmony_ci fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ciout: 28962306a36Sopenharmony_ci signal(SIGIO, oldsig); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (fd >= 0) 29262306a36Sopenharmony_ci close(fd); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return; 29562306a36Sopenharmony_ci} 296