linux/Documentation/hpet.txt
<<
>>
Prefs
   1                High Precision Event Timer Driver for Linux
   2
   3The High Precision Event Timer (HPET) hardware is the future replacement
   4for the 8254 and Real Time Clock (RTC) periodic timer functionality.
   5Each HPET can have up to 32 timers.  It is possible to configure the
   6first two timers as legacy replacements for 8254 and RTC periodic timers.
   7A specification done by Intel and Microsoft can be found at
   8<http://www.intel.com/hardwaredesign/hpetspec.htm>.
   9
  10The driver supports detection of HPET driver allocation and initialization
  11of the HPET before the driver module_init routine is called.  This enables
  12platform code which uses timer 0 or 1 as the main timer to intercept HPET
  13initialization.  An example of this initialization can be found in
  14arch/i386/kernel/time_hpet.c.
  15
  16The driver provides two APIs which are very similar to the API found in
  17the rtc.c driver.  There is a user space API and a kernel space API.
  18An example user space program is provided below.
  19
  20#include <stdio.h>
  21#include <stdlib.h>
  22#include <unistd.h>
  23#include <fcntl.h>
  24#include <string.h>
  25#include <memory.h>
  26#include <malloc.h>
  27#include <time.h>
  28#include <ctype.h>
  29#include <sys/types.h>
  30#include <sys/wait.h>
  31#include <signal.h>
  32#include <fcntl.h>
  33#include <errno.h>
  34#include <sys/time.h>
  35#include <linux/hpet.h>
  36
  37
  38extern void hpet_open_close(int, const char **);
  39extern void hpet_info(int, const char **);
  40extern void hpet_poll(int, const char **);
  41extern void hpet_fasync(int, const char **);
  42extern void hpet_read(int, const char **);
  43
  44#include <sys/poll.h>
  45#include <sys/ioctl.h>
  46#include <signal.h>
  47
  48struct hpet_command {
  49        char            *command;
  50        void            (*func)(int argc, const char ** argv);
  51} hpet_command[] = {
  52        {
  53                "open-close",
  54                hpet_open_close
  55        },
  56        {
  57                "info",
  58                hpet_info
  59        },
  60        {
  61                "poll",
  62                hpet_poll
  63        },
  64        {
  65                "fasync",
  66                hpet_fasync
  67        },
  68};
  69
  70int
  71main(int argc, const char ** argv)
  72{
  73        int     i;
  74
  75        argc--;
  76        argv++;
  77
  78        if (!argc) {
  79                fprintf(stderr, "-hpet: requires command\n");
  80                return -1;
  81        }
  82
  83
  84        for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
  85                if (!strcmp(argv[0], hpet_command[i].command)) {
  86                        argc--;
  87                        argv++;
  88                        fprintf(stderr, "-hpet: executing %s\n",
  89                                hpet_command[i].command);
  90                        hpet_command[i].func(argc, argv);
  91                        return 0;
  92                }
  93
  94        fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
  95
  96        return -1;
  97}
  98
  99void
 100hpet_open_close(int argc, const char **argv)
 101{
 102        int     fd;
 103
 104        if (argc != 1) {
 105                fprintf(stderr, "hpet_open_close: device-name\n");
 106                return;
 107        }
 108
 109        fd = open(argv[0], O_RDONLY);
 110        if (fd < 0)
 111                fprintf(stderr, "hpet_open_close: open failed\n");
 112        else
 113                close(fd);
 114
 115        return;
 116}
 117
 118void
 119hpet_info(int argc, const char **argv)
 120{
 121}
 122
 123void
 124hpet_poll(int argc, const char **argv)
 125{
 126        unsigned long           freq;
 127        int                     iterations, i, fd;
 128        struct pollfd           pfd;
 129        struct hpet_info        info;
 130        struct timeval          stv, etv;
 131        struct timezone         tz;
 132        long                    usec;
 133
 134        if (argc != 3) {
 135                fprintf(stderr, "hpet_poll: device-name freq iterations\n");
 136                return;
 137        }
 138
 139        freq = atoi(argv[1]);
 140        iterations = atoi(argv[2]);
 141
 142        fd = open(argv[0], O_RDONLY);
 143
 144        if (fd < 0) {
 145                fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
 146                return;
 147        }
 148
 149        if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
 150                fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
 151                goto out;
 152        }
 153
 154        if (ioctl(fd, HPET_INFO, &info) < 0) {
 155                fprintf(stderr, "hpet_poll: failed to get info\n");
 156                goto out;
 157        }
 158
 159        fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
 160
 161        if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
 162                fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
 163                goto out;
 164        }
 165
 166        if (ioctl(fd, HPET_IE_ON, 0) < 0) {
 167                fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
 168                goto out;
 169        }
 170
 171        pfd.fd = fd;
 172        pfd.events = POLLIN;
 173
 174        for (i = 0; i < iterations; i++) {
 175                pfd.revents = 0;
 176                gettimeofday(&stv, &tz);
 177                if (poll(&pfd, 1, -1) < 0)
 178                        fprintf(stderr, "hpet_poll: poll failed\n");
 179                else {
 180                        long    data;
 181
 182                        gettimeofday(&etv, &tz);
 183                        usec = stv.tv_sec * 1000000 + stv.tv_usec;
 184                        usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
 185
 186                        fprintf(stderr,
 187                                "hpet_poll: expired time = 0x%lx\n", usec);
 188
 189                        fprintf(stderr, "hpet_poll: revents = 0x%x\n",
 190                                pfd.revents);
 191
 192                        if (read(fd, &data, sizeof(data)) != sizeof(data)) {
 193                                fprintf(stderr, "hpet_poll: read failed\n");
 194                        }
 195                        else
 196                                fprintf(stderr, "hpet_poll: data 0x%lx\n",
 197                                        data);
 198                }
 199        }
 200
 201out:
 202        close(fd);
 203        return;
 204}
 205
 206static int hpet_sigio_count;
 207
 208static void
 209hpet_sigio(int val)
 210{
 211        fprintf(stderr, "hpet_sigio: called\n");
 212        hpet_sigio_count++;
 213}
 214
 215void
 216hpet_fasync(int argc, const char **argv)
 217{
 218        unsigned long           freq;
 219        int                     iterations, i, fd, value;
 220        sig_t                   oldsig;
 221        struct hpet_info        info;
 222
 223        hpet_sigio_count = 0;
 224        fd = -1;
 225
 226        if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
 227                fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
 228                return;
 229        }
 230
 231        if (argc != 3) {
 232                fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
 233                goto out;
 234        }
 235
 236        fd = open(argv[0], O_RDONLY);
 237
 238        if (fd < 0) {
 239                fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
 240                return;
 241        }
 242
 243
 244        if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
 245                ((value = fcntl(fd, F_GETFL)) == 1) ||
 246                (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
 247                fprintf(stderr, "hpet_fasync: fcntl failed\n");
 248                goto out;
 249        }
 250
 251        freq = atoi(argv[1]);
 252        iterations = atoi(argv[2]);
 253
 254        if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
 255                fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
 256                goto out;
 257        }
 258
 259        if (ioctl(fd, HPET_INFO, &info) < 0) {
 260                fprintf(stderr, "hpet_fasync: failed to get info\n");
 261                goto out;
 262        }
 263
 264        fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
 265
 266        if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
 267                fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
 268                goto out;
 269        }
 270
 271        if (ioctl(fd, HPET_IE_ON, 0) < 0) {
 272                fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
 273                goto out;
 274        }
 275
 276        for (i = 0; i < iterations; i++) {
 277                (void) pause();
 278                fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
 279        }
 280
 281out:
 282        signal(SIGIO, oldsig);
 283
 284        if (fd >= 0)
 285                close(fd);
 286
 287        return;
 288}
 289
 290The kernel API has three interfaces exported from the driver:
 291
 292        hpet_register(struct hpet_task *tp, int periodic)
 293        hpet_unregister(struct hpet_task *tp)
 294        hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg)
 295
 296The kernel module using this interface fills in the ht_func and ht_data
 297members of the hpet_task structure before calling hpet_register.
 298hpet_control simply vectors to the hpet_ioctl routine and has the same
 299commands and respective arguments as the user API.  hpet_unregister
 300is used to terminate usage of the HPET timer reserved by hpet_register.
 301