dahdi_dynamic_loc.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. * Dynamic Span Interface for DAHDI (Local Interface)
  3. *
  4. * Written by Nicolas Bougues <nbougues@axialys.net>
  5. *
  6. * Copyright (C) 2004, Axialys Interactive
  7. *
  8. * All rights reserved.
  9. *
  10. * Note : a DAHDI timing source must exist prior to loading this driver
  11. *
  12. * Address syntax :
  13. * <key>:<id>[:<monitor id>]
  14. *
  15. * As of now, keys and ids are single digit only
  16. *
  17. * One span may have up to one "normal" peer, and one "monitor" peer
  18. *
  19. * Example :
  20. *
  21. * Say you have two spans cross connected, a third one monitoring RX on the
  22. * first one, a fourth one monitoring RX on the second one
  23. *
  24. * 1:0
  25. * 1:1
  26. * 1:2:0
  27. * 1:3:1
  28. *
  29. * Contrary to TDMoE, no frame loss can occur.
  30. *
  31. * See bug #2021 for more details
  32. *
  33. */
  34. /*
  35. * See http://www.asterisk.org for more information about
  36. * the Asterisk project. Please do not directly contact
  37. * any of the maintainers of this project for assistance;
  38. * the project provides a web site, mailing lists and IRC
  39. * channels for your use.
  40. *
  41. * This program is free software, distributed under the terms of
  42. * the GNU General Public License Version 2 as published by the
  43. * Free Software Foundation. See the LICENSE file included with
  44. * this program for more details.
  45. */
  46. #include <linux/kernel.h>
  47. #include <linux/errno.h>
  48. #include <linux/module.h>
  49. #include <linux/init.h>
  50. #include <linux/spinlock.h>
  51. #include <linux/slab.h>
  52. #include <linux/kmod.h>
  53. #include <linux/netdevice.h>
  54. #include <linux/notifier.h>
  55. #include <dahdi/kernel.h>
  56. static DEFINE_SPINLOCK(zlock);
  57. static struct ztdlocal {
  58. unsigned short key;
  59. unsigned short id;
  60. struct ztdlocal *monitor_rx_peer; /* Indicates the peer span that monitors this span */
  61. struct ztdlocal *peer; /* Indicates the rw peer for this span */
  62. struct dahdi_span *span;
  63. struct ztdlocal *next;
  64. } *zdevs = NULL;
  65. static int ztdlocal_transmit(void *pvt, unsigned char *msg, int msglen)
  66. {
  67. struct ztdlocal *z;
  68. unsigned long flags;
  69. spin_lock_irqsave(&zlock, flags);
  70. z = pvt;
  71. if (z->peer && z->peer->span) {
  72. dahdi_dynamic_receive(z->peer->span, msg, msglen);
  73. }
  74. if (z->monitor_rx_peer && z->monitor_rx_peer->span) {
  75. dahdi_dynamic_receive(z->monitor_rx_peer->span, msg, msglen);
  76. }
  77. spin_unlock_irqrestore(&zlock, flags);
  78. return 0;
  79. }
  80. static int digit2int(char d)
  81. {
  82. switch(d) {
  83. case 'F':
  84. case 'E':
  85. case 'D':
  86. case 'C':
  87. case 'B':
  88. case 'A':
  89. return d - 'A' + 10;
  90. case 'f':
  91. case 'e':
  92. case 'd':
  93. case 'c':
  94. case 'b':
  95. case 'a':
  96. return d - 'a' + 10;
  97. case '9':
  98. case '8':
  99. case '7':
  100. case '6':
  101. case '5':
  102. case '4':
  103. case '3':
  104. case '2':
  105. case '1':
  106. case '0':
  107. return d - '0';
  108. }
  109. return -1;
  110. }
  111. static void ztdlocal_destroy(void *pvt)
  112. {
  113. struct ztdlocal *z = pvt;
  114. unsigned long flags;
  115. struct ztdlocal *prev=NULL, *cur;
  116. spin_lock_irqsave(&zlock, flags);
  117. cur = zdevs;
  118. while(cur) {
  119. if (cur->peer == z)
  120. cur->peer = NULL;
  121. if (cur->monitor_rx_peer == z)
  122. cur->monitor_rx_peer = NULL;
  123. cur = cur->next;
  124. }
  125. cur = zdevs;
  126. while(cur) {
  127. if (cur == z) {
  128. if (prev)
  129. prev->next = cur->next;
  130. else
  131. zdevs = cur->next;
  132. break;
  133. }
  134. prev = cur;
  135. cur = cur->next;
  136. }
  137. spin_unlock_irqrestore(&zlock, flags);
  138. if (cur == z) {
  139. printk(KERN_INFO "TDMoL: Removed interface for %s, key %d id %d\n", z->span->name, z->key, z->id);
  140. module_put(THIS_MODULE);
  141. kfree(z);
  142. }
  143. }
  144. static void *ztdlocal_create(struct dahdi_span *span, char *address)
  145. {
  146. struct ztdlocal *z, *l;
  147. unsigned long flags;
  148. int key = -1, id = -1, monitor = -1;
  149. if (strlen(address) >= 3) {
  150. if (address[1] != ':')
  151. goto INVALID_ADDRESS;
  152. key = digit2int(address[0]);
  153. id = digit2int(address[2]);
  154. }
  155. if (strlen (address) == 5) {
  156. if (address[3] != ':')
  157. goto INVALID_ADDRESS;
  158. monitor = digit2int(address[4]);
  159. }
  160. if (key == -1 || id == -1)
  161. goto INVALID_ADDRESS;
  162. z = kmalloc(sizeof(struct ztdlocal), GFP_KERNEL);
  163. if (z) {
  164. /* Zero it out */
  165. memset(z, 0, sizeof(struct ztdlocal));
  166. z->key = key;
  167. z->id = id;
  168. z->span = span;
  169. spin_lock_irqsave(&zlock, flags);
  170. /* Add this peer to any existing spans with same key
  171. And add them as peers to this one */
  172. for (l = zdevs; l; l = l->next)
  173. if (l->key == z->key) {
  174. if (l->id == z->id) {
  175. printk(KERN_DEBUG "TDMoL: Duplicate id (%d) for key %d\n", z->id, z->key);
  176. goto CLEAR_AND_DEL_FROM_PEERS;
  177. }
  178. if (monitor == -1) {
  179. if (l->peer) {
  180. printk(KERN_DEBUG "TDMoL: Span with key %d and id %d already has a R/W peer\n", z->key, z->id);
  181. goto CLEAR_AND_DEL_FROM_PEERS;
  182. } else {
  183. l->peer = z;
  184. z->peer = l;
  185. }
  186. }
  187. if (monitor == l->id) {
  188. if (l->monitor_rx_peer) {
  189. printk(KERN_DEBUG "TDMoL: Span with key %d and id %d already has a monitoring peer\n", z->key, z->id);
  190. goto CLEAR_AND_DEL_FROM_PEERS;
  191. } else {
  192. l->monitor_rx_peer = z;
  193. }
  194. }
  195. }
  196. z->next = zdevs;
  197. zdevs = z;
  198. spin_unlock_irqrestore(&zlock, flags);
  199. if(!try_module_get(THIS_MODULE))
  200. printk(KERN_DEBUG "TDMoL: Unable to increment module use count\n");
  201. printk(KERN_INFO "TDMoL: Added new interface for %s, key %d id %d\n", span->name, z->key, z->id);
  202. }
  203. return z;
  204. CLEAR_AND_DEL_FROM_PEERS:
  205. for (l = zdevs; l; l = l->next) {
  206. if (l->peer == z)
  207. l->peer = NULL;
  208. if (l->monitor_rx_peer == z)
  209. l->monitor_rx_peer = NULL;
  210. }
  211. kfree (z);
  212. spin_unlock_irqrestore(&zlock, flags);
  213. return NULL;
  214. INVALID_ADDRESS:
  215. printk (KERN_NOTICE "TDMoL: Invalid address %s\n", address);
  216. return NULL;
  217. }
  218. static struct dahdi_dynamic_driver ztd_local = {
  219. "loc",
  220. "Local",
  221. ztdlocal_create,
  222. ztdlocal_destroy,
  223. ztdlocal_transmit,
  224. NULL /* flush */
  225. };
  226. static int __init ztdlocal_init(void)
  227. {
  228. dahdi_dynamic_register(&ztd_local);
  229. return 0;
  230. }
  231. static void __exit ztdlocal_exit(void)
  232. {
  233. dahdi_dynamic_unregister(&ztd_local);
  234. }
  235. module_init(ztdlocal_init);
  236. module_exit(ztdlocal_exit);
  237. MODULE_LICENSE("GPL v2");