dahdi_dummy.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * Dummy DAHDI Driver for DAHDI Telephony interface
  3. *
  4. * Required: kernel > 2.6.0
  5. *
  6. * Written by Robert Pleh <robert.pleh@hermes.si>
  7. * 2.6 version by Tony Hoyle
  8. * Unified by Mark Spencer <markster@digium.com>
  9. *
  10. * Converted to use HighResTimers on i386 by Jeffery Palmer <jeff@triggerinc.com>
  11. *
  12. * Copyright (C) 2002, Hermes Softlab
  13. * Copyright (C) 2004-2012, Digium, Inc.
  14. *
  15. * All rights reserved.
  16. *
  17. */
  18. /*
  19. * See http://www.asterisk.org for more information about
  20. * the Asterisk project. Please do not directly contact
  21. * any of the maintainers of this project for assistance;
  22. * the project provides a web site, mailing lists and IRC
  23. * channels for your use.
  24. *
  25. * This program is free software, distributed under the terms of
  26. * the GNU General Public License Version 2 as published by the
  27. * Free Software Foundation. See the LICENSE file included with
  28. * this program for more details.
  29. */
  30. /*
  31. * To use the high resolution timers, in your kernel CONFIG_HIGH_RES_TIMERS
  32. * needs to be enabled (Processor type and features -> High Resolution
  33. * Timer Support), and optionally HPET (Processor type and features ->
  34. * HPET Timer Support) provides a better clock source.
  35. */
  36. #include <linux/version.h>
  37. #if defined(CONFIG_HIGH_RES_TIMERS) && \
  38. LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
  39. #define USE_HIGHRESTIMER
  40. #endif
  41. #include <linux/kernel.h>
  42. #include <linux/errno.h>
  43. #include <linux/module.h>
  44. #include <linux/init.h>
  45. #include <linux/moduleparam.h>
  46. #include <linux/slab.h>
  47. #if defined(USE_HIGHRESTIMER)
  48. #include <linux/hrtimer.h>
  49. #else
  50. #include <linux/timer.h>
  51. #endif
  52. #include <dahdi/kernel.h>
  53. #ifndef HAVE_HRTIMER_ACCESSORS
  54. #if defined(USE_HIGHRESTIMER) && \
  55. (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28))
  56. /* Compatibility with new hrtimer interface */
  57. static inline ktime_t hrtimer_get_expires(const struct hrtimer *timer)
  58. {
  59. return timer->expires;
  60. }
  61. static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time)
  62. {
  63. timer->expires = time;
  64. }
  65. #endif
  66. #endif
  67. struct dahdi_dummy {
  68. struct dahdi_device *ddev;
  69. struct dahdi_span span;
  70. struct dahdi_chan _chan;
  71. struct dahdi_chan *chan;
  72. #if !defined(USE_HIGHRESTIMER)
  73. unsigned long calls_since_start;
  74. struct timespec start_interval;
  75. #endif
  76. };
  77. static struct dahdi_dummy *ztd;
  78. static int debug = 0;
  79. #ifdef USE_HIGHRESTIMER
  80. #define CLOCK_SRC "HRtimer"
  81. static struct hrtimer zaptimer;
  82. #define DAHDI_RATE 1000 /* DAHDI ticks per second */
  83. #define DAHDI_TIME (1000000 / DAHDI_RATE) /* DAHDI tick time in us */
  84. #define DAHDI_TIME_NS (DAHDI_TIME * 1000) /* DAHDI tick time in ns */
  85. #else
  86. #define CLOCK_SRC "Linux26"
  87. static struct timer_list timer;
  88. static atomic_t shutdown;
  89. #define JIFFIES_INTERVAL max(HZ/250, 1) /* 4ms is fine for dahdi_dummy */
  90. #endif
  91. /* Different bits of the debug variable: */
  92. #define DEBUG_GENERAL (1 << 0)
  93. #define DEBUG_TICKS (1 << 1)
  94. #if defined(USE_HIGHRESTIMER)
  95. static enum hrtimer_restart dahdi_dummy_hr_int(struct hrtimer *htmr)
  96. {
  97. unsigned long overrun;
  98. /* Trigger DAHDI */
  99. dahdi_receive(&ztd->span);
  100. dahdi_transmit(&ztd->span);
  101. /* Overrun should always return 1, since we are in the timer that
  102. * expired.
  103. * We should worry if overrun is 2 or more; then we really missed
  104. * a tick */
  105. overrun = hrtimer_forward(&zaptimer, hrtimer_get_expires(htmr),
  106. ktime_set(0, DAHDI_TIME_NS));
  107. if(overrun > 1) {
  108. if(printk_ratelimit())
  109. printk(KERN_NOTICE "dahdi_dummy: HRTimer missed %lu ticks\n",
  110. overrun - 1);
  111. }
  112. if(debug && DEBUG_TICKS) {
  113. static int count = 0;
  114. /* Printk every 5 seconds, good test to see if timer is
  115. * running properly */
  116. if (count++ % 5000 == 0)
  117. printk(KERN_DEBUG "dahdi_dummy: 5000 ticks from hrtimer\n");
  118. }
  119. /* Always restart the timer */
  120. return HRTIMER_RESTART;
  121. }
  122. #else
  123. static unsigned long timespec_diff_ms(struct timespec *t0, struct timespec *t1)
  124. {
  125. long nanosec, sec;
  126. unsigned long ms;
  127. sec = (t1->tv_sec - t0->tv_sec);
  128. nanosec = (t1->tv_nsec - t0->tv_nsec);
  129. while (nanosec >= NSEC_PER_SEC) {
  130. nanosec -= NSEC_PER_SEC;
  131. ++sec;
  132. }
  133. while (nanosec < 0) {
  134. nanosec += NSEC_PER_SEC;
  135. --sec;
  136. }
  137. ms = (sec * 1000) + (nanosec / 1000000L);
  138. return ms;
  139. }
  140. static void dahdi_dummy_timer(unsigned long param)
  141. {
  142. unsigned long ms_since_start;
  143. struct timespec now;
  144. const unsigned long MAX_INTERVAL = 100000L;
  145. const unsigned long MS_LIMIT = 3000;
  146. if (!atomic_read(&shutdown))
  147. mod_timer(&timer, jiffies + JIFFIES_INTERVAL);
  148. now = current_kernel_time();
  149. ms_since_start = timespec_diff_ms(&ztd->start_interval, &now);
  150. /*
  151. * If the system time has changed, it is possible for us to be far
  152. * behind. If we are more than MS_LIMIT milliseconds behind, just
  153. * reset our time base and continue so that we do not hang the system
  154. * here.
  155. *
  156. */
  157. if (unlikely((ms_since_start - ztd->calls_since_start) > MS_LIMIT)) {
  158. if (printk_ratelimit()) {
  159. printk(KERN_INFO
  160. "dahdi_dummy: Detected time shift.\n");
  161. }
  162. ztd->calls_since_start = 0;
  163. ztd->start_interval = now;
  164. return;
  165. }
  166. while (ms_since_start > ztd->calls_since_start) {
  167. ztd->calls_since_start++;
  168. dahdi_receive(&ztd->span);
  169. dahdi_transmit(&ztd->span);
  170. }
  171. if (ms_since_start > MAX_INTERVAL) {
  172. ztd->calls_since_start = 0;
  173. ztd->start_interval = now;
  174. }
  175. }
  176. #endif
  177. static const struct dahdi_span_ops dummy_ops = {
  178. .owner = THIS_MODULE,
  179. };
  180. static int dahdi_dummy_initialize(struct dahdi_dummy *ztd)
  181. {
  182. int res = 0;
  183. /* DAHDI stuff */
  184. ztd->ddev = dahdi_create_device();
  185. if (!ztd->ddev)
  186. return -ENOMEM;
  187. dev_set_name(&ztd->ddev->dev, "dahdi_dummy");
  188. ztd->chan = &ztd->_chan;
  189. sprintf(ztd->span.name, "DAHDI_DUMMY/1");
  190. snprintf(ztd->span.desc, sizeof(ztd->span.desc) - 1, "%s (source: " CLOCK_SRC ") %d", ztd->span.name, 1);
  191. sprintf(ztd->chan->name, "DAHDI_DUMMY/%d/%d", 1, 0);
  192. ztd->ddev->devicetype = "DAHDI Dummy Timing";
  193. ztd->chan->chanpos = 1;
  194. ztd->span.chans = &ztd->chan;
  195. ztd->span.channels = 0; /* no channels on our span */
  196. ztd->span.deflaw = DAHDI_LAW_MULAW;
  197. ztd->chan->pvt = ztd;
  198. ztd->span.ops = &dummy_ops;
  199. list_add_tail(&ztd->span.device_node, &ztd->ddev->spans);
  200. res = dahdi_register_device(ztd->ddev, NULL);
  201. return res;
  202. }
  203. int init_module(void)
  204. {
  205. int res;
  206. ztd = kzalloc(sizeof(*ztd), GFP_KERNEL);
  207. if (ztd == NULL) {
  208. printk(KERN_ERR "dahdi_dummy: Unable to allocate memory\n");
  209. return -ENOMEM;
  210. }
  211. res = dahdi_dummy_initialize(ztd);
  212. if (res) {
  213. printk(KERN_ERR
  214. "dahdi_dummy: Unable to intialize DAHDI driver (%d)\n",
  215. res);
  216. kfree(ztd);
  217. return res;
  218. }
  219. #if defined(USE_HIGHRESTIMER)
  220. printk(KERN_DEBUG "dahdi_dummy: Trying to load High Resolution Timer\n");
  221. hrtimer_init(&zaptimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  222. printk(KERN_DEBUG "dahdi_dummy: Initialized High Resolution Timer\n");
  223. /* Set timer callback function */
  224. zaptimer.function = dahdi_dummy_hr_int;
  225. printk(KERN_DEBUG "dahdi_dummy: Starting High Resolution Timer\n");
  226. hrtimer_start(&zaptimer, ktime_set(0, DAHDI_TIME_NS), HRTIMER_MODE_REL);
  227. printk(KERN_INFO "dahdi_dummy: High Resolution Timer started, good to go\n");
  228. #else
  229. init_timer(&timer);
  230. timer.function = dahdi_dummy_timer;
  231. ztd->start_interval = current_kernel_time();
  232. timer.expires = jiffies + JIFFIES_INTERVAL;
  233. atomic_set(&shutdown, 0);
  234. add_timer(&timer);
  235. #endif
  236. if (debug)
  237. printk(KERN_DEBUG "dahdi_dummy: init() finished\n");
  238. return 0;
  239. }
  240. void cleanup_module(void)
  241. {
  242. #if defined(USE_HIGHRESTIMER)
  243. /* Stop high resolution timer */
  244. hrtimer_cancel(&zaptimer);
  245. #else
  246. atomic_set(&shutdown, 1);
  247. del_timer_sync(&timer);
  248. #endif
  249. dahdi_unregister_device(ztd->ddev);
  250. dahdi_free_device(ztd->ddev);
  251. kfree(ztd);
  252. if (debug)
  253. printk(KERN_DEBUG "dahdi_dummy: cleanup() finished\n");
  254. }
  255. module_param(debug, int, 0600);
  256. MODULE_DESCRIPTION("Timing-Only Driver");
  257. MODULE_AUTHOR("Robert Pleh <robert.pleh@hermes.si>");
  258. MODULE_LICENSE("GPL v2");