hpet.txt 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. High Precision Event Timer Driver for Linux
  2. The High Precision Event Timer (HPET) hardware follows a specification
  3. by Intel and Microsoft which can be found at
  4. http://www.intel.com/technology/architecture/hpetspec.htm
  5. Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision")
  6. and up to 32 comparators. Normally three or more comparators are provided,
  7. each of which can generate oneshot interrupts and at least one of which has
  8. additional hardware to support periodic interrupts. The comparators are
  9. also called "timers", which can be misleading since usually timers are
  10. independent of each other ... these share a counter, complicating resets.
  11. HPET devices can support two interrupt routing modes. In one mode, the
  12. comparators are additional interrupt sources with no particular system
  13. role. Many x86 BIOS writers don't route HPET interrupts at all, which
  14. prevents use of that mode. They support the other "legacy replacement"
  15. mode where the first two comparators block interrupts from 8254 timers
  16. and from the RTC.
  17. The driver supports detection of HPET driver allocation and initialization
  18. of the HPET before the driver module_init routine is called. This enables
  19. platform code which uses timer 0 or 1 as the main timer to intercept HPET
  20. initialization. An example of this initialization can be found in
  21. arch/x86/kernel/hpet.c.
  22. The driver provides a userspace API which resembles the API found in the
  23. RTC driver framework. An example user space program is provided below.
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <fcntl.h>
  28. #include <string.h>
  29. #include <memory.h>
  30. #include <malloc.h>
  31. #include <time.h>
  32. #include <ctype.h>
  33. #include <sys/types.h>
  34. #include <sys/wait.h>
  35. #include <signal.h>
  36. #include <fcntl.h>
  37. #include <errno.h>
  38. #include <sys/time.h>
  39. #include <linux/hpet.h>
  40. extern void hpet_open_close(int, const char **);
  41. extern void hpet_info(int, const char **);
  42. extern void hpet_poll(int, const char **);
  43. extern void hpet_fasync(int, const char **);
  44. extern void hpet_read(int, const char **);
  45. #include <sys/poll.h>
  46. #include <sys/ioctl.h>
  47. #include <signal.h>
  48. struct 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. int
  70. main(int argc, const char ** argv)
  71. {
  72. int i;
  73. argc--;
  74. argv++;
  75. if (!argc) {
  76. fprintf(stderr, "-hpet: requires command\n");
  77. return -1;
  78. }
  79. for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
  80. if (!strcmp(argv[0], hpet_command[i].command)) {
  81. argc--;
  82. argv++;
  83. fprintf(stderr, "-hpet: executing %s\n",
  84. hpet_command[i].command);
  85. hpet_command[i].func(argc, argv);
  86. return 0;
  87. }
  88. fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
  89. return -1;
  90. }
  91. void
  92. hpet_open_close(int argc, const char **argv)
  93. {
  94. int fd;
  95. if (argc != 1) {
  96. fprintf(stderr, "hpet_open_close: device-name\n");
  97. return;
  98. }
  99. fd = open(argv[0], O_RDONLY);
  100. if (fd < 0)
  101. fprintf(stderr, "hpet_open_close: open failed\n");
  102. else
  103. close(fd);
  104. return;
  105. }
  106. void
  107. hpet_info(int argc, const char **argv)
  108. {
  109. }
  110. void
  111. hpet_poll(int argc, const char **argv)
  112. {
  113. unsigned long freq;
  114. int iterations, i, fd;
  115. struct pollfd pfd;
  116. struct hpet_info info;
  117. struct timeval stv, etv;
  118. struct timezone tz;
  119. long usec;
  120. if (argc != 3) {
  121. fprintf(stderr, "hpet_poll: device-name freq iterations\n");
  122. return;
  123. }
  124. freq = atoi(argv[1]);
  125. iterations = atoi(argv[2]);
  126. fd = open(argv[0], O_RDONLY);
  127. if (fd < 0) {
  128. fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
  129. return;
  130. }
  131. if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
  132. fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
  133. goto out;
  134. }
  135. if (ioctl(fd, HPET_INFO, &info) < 0) {
  136. fprintf(stderr, "hpet_poll: failed to get info\n");
  137. goto out;
  138. }
  139. fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
  140. if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
  141. fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
  142. goto out;
  143. }
  144. if (ioctl(fd, HPET_IE_ON, 0) < 0) {
  145. fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
  146. goto out;
  147. }
  148. pfd.fd = fd;
  149. pfd.events = POLLIN;
  150. for (i = 0; i < iterations; i++) {
  151. pfd.revents = 0;
  152. gettimeofday(&stv, &tz);
  153. if (poll(&pfd, 1, -1) < 0)
  154. fprintf(stderr, "hpet_poll: poll failed\n");
  155. else {
  156. long data;
  157. gettimeofday(&etv, &tz);
  158. usec = stv.tv_sec * 1000000 + stv.tv_usec;
  159. usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
  160. fprintf(stderr,
  161. "hpet_poll: expired time = 0x%lx\n", usec);
  162. fprintf(stderr, "hpet_poll: revents = 0x%x\n",
  163. pfd.revents);
  164. if (read(fd, &data, sizeof(data)) != sizeof(data)) {
  165. fprintf(stderr, "hpet_poll: read failed\n");
  166. }
  167. else
  168. fprintf(stderr, "hpet_poll: data 0x%lx\n",
  169. data);
  170. }
  171. }
  172. out:
  173. close(fd);
  174. return;
  175. }
  176. static int hpet_sigio_count;
  177. static void
  178. hpet_sigio(int val)
  179. {
  180. fprintf(stderr, "hpet_sigio: called\n");
  181. hpet_sigio_count++;
  182. }
  183. void
  184. hpet_fasync(int argc, const char **argv)
  185. {
  186. unsigned long freq;
  187. int iterations, i, fd, value;
  188. sig_t oldsig;
  189. struct hpet_info info;
  190. hpet_sigio_count = 0;
  191. fd = -1;
  192. if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
  193. fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
  194. return;
  195. }
  196. if (argc != 3) {
  197. fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
  198. goto out;
  199. }
  200. fd = open(argv[0], O_RDONLY);
  201. if (fd < 0) {
  202. fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
  203. return;
  204. }
  205. if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
  206. ((value = fcntl(fd, F_GETFL)) == 1) ||
  207. (fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
  208. fprintf(stderr, "hpet_fasync: fcntl failed\n");
  209. goto out;
  210. }
  211. freq = atoi(argv[1]);
  212. iterations = atoi(argv[2]);
  213. if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
  214. fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
  215. goto out;
  216. }
  217. if (ioctl(fd, HPET_INFO, &info) < 0) {
  218. fprintf(stderr, "hpet_fasync: failed to get info\n");
  219. goto out;
  220. }
  221. fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
  222. if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
  223. fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
  224. goto out;
  225. }
  226. if (ioctl(fd, HPET_IE_ON, 0) < 0) {
  227. fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
  228. goto out;
  229. }
  230. for (i = 0; i < iterations; i++) {
  231. (void) pause();
  232. fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
  233. }
  234. out:
  235. signal(SIGIO, oldsig);
  236. if (fd >= 0)
  237. close(fd);
  238. return;
  239. }