clock.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * Quick API description:
  14. *
  15. * A clock source registers using mISDN_register_clock:
  16. * name = text string to name clock source
  17. * priority = value to priorize clock sources (0 = default)
  18. * ctl = callback function to enable/disable clock source
  19. * priv = private pointer of clock source
  20. * return = pointer to clock source structure;
  21. *
  22. * Note: Callback 'ctl' can be called before mISDN_register_clock returns!
  23. * Also it can be called during mISDN_unregister_clock.
  24. *
  25. * A clock source calls mISDN_clock_update with given samples elapsed, if
  26. * enabled. If function call is delayed, tv must be set with the timestamp
  27. * of the actual event.
  28. *
  29. * A clock source unregisters using mISDN_unregister_clock.
  30. *
  31. * To get current clock, call mISDN_clock_get. The signed short value
  32. * counts the number of samples since. Time since last clock event is added.
  33. *
  34. */
  35. #include <linux/slab.h>
  36. #include <linux/types.h>
  37. #include <linux/stddef.h>
  38. #include <linux/spinlock.h>
  39. #include <linux/mISDNif.h>
  40. #include <linux/export.h>
  41. #include "core.h"
  42. static u_int *debug;
  43. static LIST_HEAD(iclock_list);
  44. static DEFINE_RWLOCK(iclock_lock);
  45. static u16 iclock_count; /* counter of last clock */
  46. static struct timeval iclock_tv; /* time stamp of last clock */
  47. static int iclock_tv_valid; /* already received one timestamp */
  48. static struct mISDNclock *iclock_current;
  49. void
  50. mISDN_init_clock(u_int *dp)
  51. {
  52. debug = dp;
  53. do_gettimeofday(&iclock_tv);
  54. }
  55. static void
  56. select_iclock(void)
  57. {
  58. struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL;
  59. int pri = -128;
  60. list_for_each_entry(iclock, &iclock_list, list) {
  61. if (iclock->pri > pri) {
  62. pri = iclock->pri;
  63. bestclock = iclock;
  64. }
  65. if (iclock_current == iclock)
  66. lastclock = iclock;
  67. }
  68. if (lastclock && bestclock != lastclock) {
  69. /* last used clock source still exists but changes, disable */
  70. if (*debug & DEBUG_CLOCK)
  71. printk(KERN_DEBUG "Old clock source '%s' disable.\n",
  72. lastclock->name);
  73. lastclock->ctl(lastclock->priv, 0);
  74. }
  75. if (bestclock && bestclock != iclock_current) {
  76. /* new clock source selected, enable */
  77. if (*debug & DEBUG_CLOCK)
  78. printk(KERN_DEBUG "New clock source '%s' enable.\n",
  79. bestclock->name);
  80. bestclock->ctl(bestclock->priv, 1);
  81. }
  82. if (bestclock != iclock_current) {
  83. /* no clock received yet */
  84. iclock_tv_valid = 0;
  85. }
  86. iclock_current = bestclock;
  87. }
  88. struct mISDNclock
  89. *mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv)
  90. {
  91. u_long flags;
  92. struct mISDNclock *iclock;
  93. if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
  94. printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri);
  95. iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC);
  96. if (!iclock) {
  97. printk(KERN_ERR "%s: No memory for clock entry.\n", __func__);
  98. return NULL;
  99. }
  100. strncpy(iclock->name, name, sizeof(iclock->name) - 1);
  101. iclock->pri = pri;
  102. iclock->priv = priv;
  103. iclock->ctl = ctl;
  104. write_lock_irqsave(&iclock_lock, flags);
  105. list_add_tail(&iclock->list, &iclock_list);
  106. select_iclock();
  107. write_unlock_irqrestore(&iclock_lock, flags);
  108. return iclock;
  109. }
  110. EXPORT_SYMBOL(mISDN_register_clock);
  111. void
  112. mISDN_unregister_clock(struct mISDNclock *iclock)
  113. {
  114. u_long flags;
  115. if (*debug & (DEBUG_CORE | DEBUG_CLOCK))
  116. printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name,
  117. iclock->pri);
  118. write_lock_irqsave(&iclock_lock, flags);
  119. if (iclock_current == iclock) {
  120. if (*debug & DEBUG_CLOCK)
  121. printk(KERN_DEBUG
  122. "Current clock source '%s' unregisters.\n",
  123. iclock->name);
  124. iclock->ctl(iclock->priv, 0);
  125. }
  126. list_del(&iclock->list);
  127. select_iclock();
  128. write_unlock_irqrestore(&iclock_lock, flags);
  129. }
  130. EXPORT_SYMBOL(mISDN_unregister_clock);
  131. void
  132. mISDN_clock_update(struct mISDNclock *iclock, int samples, struct timeval *tv)
  133. {
  134. u_long flags;
  135. struct timeval tv_now;
  136. time_t elapsed_sec;
  137. int elapsed_8000th;
  138. write_lock_irqsave(&iclock_lock, flags);
  139. if (iclock_current != iclock) {
  140. printk(KERN_ERR "%s: '%s' sends us clock updates, but we do "
  141. "listen to '%s'. This is a bug!\n", __func__,
  142. iclock->name,
  143. iclock_current ? iclock_current->name : "nothing");
  144. iclock->ctl(iclock->priv, 0);
  145. write_unlock_irqrestore(&iclock_lock, flags);
  146. return;
  147. }
  148. if (iclock_tv_valid) {
  149. /* increment sample counter by given samples */
  150. iclock_count += samples;
  151. if (tv) { /* tv must be set, if function call is delayed */
  152. iclock_tv.tv_sec = tv->tv_sec;
  153. iclock_tv.tv_usec = tv->tv_usec;
  154. } else
  155. do_gettimeofday(&iclock_tv);
  156. } else {
  157. /* calc elapsed time by system clock */
  158. if (tv) { /* tv must be set, if function call is delayed */
  159. tv_now.tv_sec = tv->tv_sec;
  160. tv_now.tv_usec = tv->tv_usec;
  161. } else
  162. do_gettimeofday(&tv_now);
  163. elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec;
  164. elapsed_8000th = (tv_now.tv_usec / 125)
  165. - (iclock_tv.tv_usec / 125);
  166. if (elapsed_8000th < 0) {
  167. elapsed_sec -= 1;
  168. elapsed_8000th += 8000;
  169. }
  170. /* add elapsed time to counter and set new timestamp */
  171. iclock_count += elapsed_sec * 8000 + elapsed_8000th;
  172. iclock_tv.tv_sec = tv_now.tv_sec;
  173. iclock_tv.tv_usec = tv_now.tv_usec;
  174. iclock_tv_valid = 1;
  175. if (*debug & DEBUG_CLOCK)
  176. printk("Received first clock from source '%s'.\n",
  177. iclock_current ? iclock_current->name : "nothing");
  178. }
  179. write_unlock_irqrestore(&iclock_lock, flags);
  180. }
  181. EXPORT_SYMBOL(mISDN_clock_update);
  182. unsigned short
  183. mISDN_clock_get(void)
  184. {
  185. u_long flags;
  186. struct timeval tv_now;
  187. time_t elapsed_sec;
  188. int elapsed_8000th;
  189. u16 count;
  190. read_lock_irqsave(&iclock_lock, flags);
  191. /* calc elapsed time by system clock */
  192. do_gettimeofday(&tv_now);
  193. elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec;
  194. elapsed_8000th = (tv_now.tv_usec / 125) - (iclock_tv.tv_usec / 125);
  195. if (elapsed_8000th < 0) {
  196. elapsed_sec -= 1;
  197. elapsed_8000th += 8000;
  198. }
  199. /* add elapsed time to counter */
  200. count = iclock_count + elapsed_sec * 8000 + elapsed_8000th;
  201. read_unlock_irqrestore(&iclock_lock, flags);
  202. return count;
  203. }
  204. EXPORT_SYMBOL(mISDN_clock_get);