clock.c 5.6 KB

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