dahdi_dynamic.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. /*
  2. * Dynamic Span Interface for DAHDI
  3. *
  4. * Written by Mark Spencer <markster@digium.com>
  5. *
  6. * Copyright (C) 2001-2008, Digium, Inc.
  7. *
  8. * All rights reserved.
  9. *
  10. */
  11. /*
  12. * See http://www.asterisk.org for more information about
  13. * the Asterisk project. Please do not directly contact
  14. * any of the maintainers of this project for assistance;
  15. * the project provides a web site, mailing lists and IRC
  16. * channels for your use.
  17. *
  18. * This program is free software, distributed under the terms of
  19. * the GNU General Public License Version 2 as published by the
  20. * Free Software Foundation. See the LICENSE file included with
  21. * this program for more details.
  22. */
  23. #include <linux/kernel.h>
  24. #include <linux/errno.h>
  25. #include <linux/module.h>
  26. #include <linux/init.h>
  27. #include <linux/spinlock.h>
  28. #include <linux/slab.h>
  29. #include <linux/kmod.h>
  30. #include <linux/sched.h>
  31. #include <linux/interrupt.h>
  32. #include <linux/moduleparam.h>
  33. #include <dahdi/kernel.h>
  34. /*
  35. * Tasklets provide better system interactive response at the cost of the
  36. * possibility of losing a frame of data at very infrequent intervals. If
  37. * you are more concerned with the performance of your machine, enable the
  38. * tasklets. If you are strict about absolutely no drops, then do not enable
  39. * tasklets.
  40. */
  41. #define ENABLE_TASKLETS
  42. /*
  43. * Dynamic spans implemented using TDM over X with standard message
  44. * types. Message format is as follows:
  45. *
  46. * Byte #: Meaning
  47. * 0 Number of samples per channel
  48. * 1 Current flags on span
  49. * Bit 0: Yellow Alarm
  50. * Bit 1: Sig bits present
  51. * Bits 2-7: reserved for future use
  52. * 2-3 16-bit counter value for detecting drops, network byte order.
  53. * 4-5 Number of channels in the message, network byte order
  54. * 6... 16-bit words, containing sig bits for each
  55. * four channels, least significant 4 bits being
  56. * the least significant channel, network byte order.
  57. * the rest data for each channel, all samples per channel
  58. before moving to the next.
  59. */
  60. /* Arbitrary limit to the max # of channels in a span */
  61. #define DAHDI_DYNAMIC_MAX_CHANS 256
  62. #define ZTD_FLAG_YELLOW_ALARM (1 << 0)
  63. #define ZTD_FLAG_SIGBITS_PRESENT (1 << 1)
  64. #define ZTD_FLAG_LOOPBACK (1 << 2)
  65. #define ERR_NSAMP (1 << 16)
  66. #define ERR_NCHAN (1 << 17)
  67. #define ERR_LEN (1 << 18)
  68. EXPORT_SYMBOL(dahdi_dynamic_register);
  69. EXPORT_SYMBOL(dahdi_dynamic_unregister);
  70. EXPORT_SYMBOL(dahdi_dynamic_receive);
  71. static int ztdynamic_init(void);
  72. static void ztdynamic_cleanup(void);
  73. #ifdef ENABLE_TASKLETS
  74. static int taskletrun;
  75. static int taskletsched;
  76. static int taskletpending;
  77. static int taskletexec;
  78. static int txerrors;
  79. static struct tasklet_struct ztd_tlet;
  80. static void ztd_tasklet(unsigned long data);
  81. #endif
  82. struct dahdi_dynamic {
  83. char addr[40];
  84. char dname[20];
  85. int err;
  86. int usecount;
  87. int dead;
  88. long rxjif;
  89. unsigned short txcnt;
  90. unsigned short rxcnt;
  91. struct dahdi_span span;
  92. struct dahdi_chan *chans[DAHDI_DYNAMIC_MAX_CHANS];
  93. struct dahdi_dynamic_driver *driver;
  94. void *pvt;
  95. int timing;
  96. int master;
  97. unsigned char *msgbuf;
  98. struct list_head list;
  99. };
  100. static DEFINE_SPINLOCK(dspan_lock);
  101. static DEFINE_SPINLOCK(driver_lock);
  102. static LIST_HEAD(dspan_list);
  103. static LIST_HEAD(driver_list);
  104. static int debug = 0;
  105. static int hasmaster = 0;
  106. static void checkmaster(void)
  107. {
  108. int newhasmaster=0;
  109. int best = 9999999;
  110. struct dahdi_dynamic *z, *master=NULL;
  111. rcu_read_lock();
  112. list_for_each_entry_rcu(z, &dspan_list, list) {
  113. if (z->timing) {
  114. z->master = 0;
  115. if (!(z->span.alarms & DAHDI_ALARM_RED) &&
  116. (z->timing < best) && !z->dead) {
  117. /* If not in alarm and they're
  118. a better timing source, use them */
  119. master = z;
  120. best = z->timing;
  121. newhasmaster = 1;
  122. }
  123. }
  124. }
  125. hasmaster = newhasmaster;
  126. /* Mark the new master if there is one */
  127. if (master)
  128. master->master = 1;
  129. rcu_read_unlock();
  130. if (master)
  131. printk(KERN_INFO "TDMoX: New master: %s\n", master->span.name);
  132. else
  133. printk(KERN_INFO "TDMoX: No master.\n");
  134. }
  135. static void ztd_sendmessage(struct dahdi_dynamic *z)
  136. {
  137. unsigned char *buf = z->msgbuf;
  138. unsigned short bits;
  139. int msglen = 0;
  140. int x;
  141. int offset;
  142. /* Byte 0: Number of samples per channel */
  143. *buf = DAHDI_CHUNKSIZE;
  144. buf++; msglen++;
  145. /* Byte 1: Flags */
  146. *buf = 0;
  147. if (z->span.alarms & DAHDI_ALARM_RED)
  148. *buf |= ZTD_FLAG_YELLOW_ALARM;
  149. *buf |= ZTD_FLAG_SIGBITS_PRESENT;
  150. buf++; msglen++;
  151. /* Bytes 2-3: Transmit counter */
  152. *((unsigned short *)buf) = htons((unsigned short)z->txcnt);
  153. z->txcnt++;
  154. buf++; msglen++;
  155. buf++; msglen++;
  156. /* Bytes 4-5: Number of channels */
  157. *((unsigned short *)buf) = htons((unsigned short)z->span.channels);
  158. buf++; msglen++;
  159. buf++; msglen++;
  160. bits = 0;
  161. offset = 0;
  162. for (x=0;x<z->span.channels;x++) {
  163. offset = x % 4;
  164. bits |= (z->chans[x]->txsig & 0xf) << (offset << 2);
  165. if (offset == 3) {
  166. /* Write the bits when we have four channels */
  167. *((unsigned short *)buf) = htons(bits);
  168. buf++; msglen++;
  169. buf++; msglen++;
  170. bits = 0;
  171. }
  172. }
  173. if (offset != 3) {
  174. /* Finish it off if it's not done already */
  175. *((unsigned short *)buf) = htons(bits);
  176. buf++; msglen++;
  177. buf++; msglen++;
  178. }
  179. for (x=0;x<z->span.channels;x++) {
  180. memcpy(buf, z->chans[x]->writechunk, DAHDI_CHUNKSIZE);
  181. buf += DAHDI_CHUNKSIZE;
  182. msglen += DAHDI_CHUNKSIZE;
  183. }
  184. z->driver->transmit(z->pvt, z->msgbuf, msglen);
  185. }
  186. static void __ztdynamic_run(void)
  187. {
  188. struct dahdi_dynamic *z;
  189. struct dahdi_dynamic_driver *drv;
  190. rcu_read_lock();
  191. list_for_each_entry_rcu(z, &dspan_list, list) {
  192. if (!z->dead) {
  193. dahdi_transmit(&z->span);
  194. /* Handle all transmissions now */
  195. ztd_sendmessage(z);
  196. }
  197. }
  198. list_for_each_entry_rcu(drv, &driver_list, list) {
  199. /* Flush any traffic still pending in the driver */
  200. if (drv->flush) {
  201. drv->flush();
  202. }
  203. }
  204. rcu_read_unlock();
  205. }
  206. #ifdef ENABLE_TASKLETS
  207. static void ztdynamic_run(void)
  208. {
  209. if (likely(!taskletpending)) {
  210. taskletpending = 1;
  211. taskletsched++;
  212. tasklet_hi_schedule(&ztd_tlet);
  213. } else {
  214. txerrors++;
  215. }
  216. }
  217. #else
  218. #define ztdynamic_run __ztdynamic_run
  219. #endif
  220. static inline struct dahdi_dynamic *dynamic_from_span(struct dahdi_span *span)
  221. {
  222. return container_of(span, struct dahdi_dynamic, span);
  223. }
  224. void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msglen)
  225. {
  226. struct dahdi_dynamic *ztd = dynamic_from_span(span);
  227. int newerr=0;
  228. int sflags;
  229. int xlen;
  230. int x, bits, sig;
  231. int nchans, master;
  232. int newalarm;
  233. unsigned short rxpos, rxcnt;
  234. rcu_read_lock();
  235. if (unlikely(msglen < 6)) {
  236. rcu_read_unlock();
  237. newerr = ERR_LEN;
  238. if (newerr != ztd->err) {
  239. printk(KERN_NOTICE "Span %s: Insufficient samples for header (only %d)\n", span->name, msglen);
  240. }
  241. ztd->err = newerr;
  242. return;
  243. }
  244. /* First, check the chunksize */
  245. if (unlikely(*msg != DAHDI_CHUNKSIZE)) {
  246. rcu_read_unlock();
  247. newerr = ERR_NSAMP | msg[0];
  248. if (newerr != ztd->err) {
  249. printk(KERN_NOTICE "Span %s: Expected %d samples, but receiving %d\n", span->name, DAHDI_CHUNKSIZE, msg[0]);
  250. }
  251. ztd->err = newerr;
  252. return;
  253. }
  254. msg++;
  255. sflags = *msg;
  256. msg++;
  257. rxpos = ntohs(*((unsigned short *)msg));
  258. msg++;
  259. msg++;
  260. nchans = ntohs(*((unsigned short *)msg));
  261. if (unlikely(nchans != span->channels)) {
  262. rcu_read_unlock();
  263. newerr = ERR_NCHAN | nchans;
  264. if (newerr != ztd->err) {
  265. printk(KERN_NOTICE "Span %s: Expected %d channels, but receiving %d\n", span->name, span->channels, nchans);
  266. }
  267. ztd->err = newerr;
  268. return;
  269. }
  270. msg++;
  271. msg++;
  272. /* Okay now we've accepted the header, lets check our message
  273. length... */
  274. /* Start with header */
  275. xlen = 6;
  276. /* Add samples of audio */
  277. xlen += nchans * DAHDI_CHUNKSIZE;
  278. /* If RBS info is there, add that */
  279. if (sflags & ZTD_FLAG_SIGBITS_PRESENT) {
  280. /* Account for sigbits -- one short per 4 channels*/
  281. xlen += ((nchans + 3) / 4) * 2;
  282. }
  283. if (unlikely(xlen != msglen)) {
  284. rcu_read_unlock();
  285. newerr = ERR_LEN | xlen;
  286. if (newerr != ztd->err) {
  287. printk(KERN_NOTICE "Span %s: Expected message size %d, but was %d instead\n", span->name, xlen, msglen);
  288. }
  289. ztd->err = newerr;
  290. return;
  291. }
  292. bits = 0;
  293. /* Record sigbits if present */
  294. if (sflags & ZTD_FLAG_SIGBITS_PRESENT) {
  295. for (x=0;x<nchans;x++) {
  296. if (!(x%4)) {
  297. /* Get new bits */
  298. bits = ntohs(*((unsigned short *)msg));
  299. msg++;
  300. msg++;
  301. }
  302. /* Pick the right bits */
  303. sig = (bits >> ((x % 4) << 2)) & 0xff;
  304. /* Update signalling if appropriate */
  305. if (sig != span->chans[x]->rxsig)
  306. dahdi_rbsbits(span->chans[x], sig);
  307. }
  308. }
  309. /* Record data for channels */
  310. for (x=0;x<nchans;x++) {
  311. memcpy(span->chans[x]->readchunk, msg, DAHDI_CHUNKSIZE);
  312. msg += DAHDI_CHUNKSIZE;
  313. }
  314. master = ztd->master;
  315. rxcnt = ztd->rxcnt;
  316. ztd->rxcnt = rxpos+1;
  317. /* Keep track of last received packet */
  318. ztd->rxjif = jiffies;
  319. rcu_read_unlock();
  320. /* Check for Yellow alarm */
  321. newalarm = span->alarms & ~(DAHDI_ALARM_YELLOW | DAHDI_ALARM_RED);
  322. if (sflags & ZTD_FLAG_YELLOW_ALARM)
  323. newalarm |= DAHDI_ALARM_YELLOW;
  324. if (newalarm != span->alarms) {
  325. span->alarms = newalarm;
  326. dahdi_alarm_notify(span);
  327. checkmaster();
  328. }
  329. /* note if we had a missing packet */
  330. if (unlikely(rxpos != rxcnt))
  331. printk(KERN_NOTICE "Span %s: Expected seq no %d, but received %d instead\n", span->name, rxcnt, rxpos);
  332. dahdi_ec_span(span);
  333. dahdi_receive(span);
  334. /* If this is our master span, then run everything */
  335. if (master)
  336. ztdynamic_run();
  337. }
  338. static void dynamic_destroy(struct dahdi_dynamic *z)
  339. {
  340. unsigned int x;
  341. /* Unregister span if appropriate */
  342. if (test_bit(DAHDI_FLAGBIT_REGISTERED, &z->span.flags))
  343. dahdi_unregister(&z->span);
  344. /* Destroy the pvt stuff if there */
  345. if (z->pvt)
  346. z->driver->destroy(z->pvt);
  347. /* Free message buffer if appropriate */
  348. if (z->msgbuf)
  349. kfree(z->msgbuf);
  350. /* Free channels */
  351. for (x = 0; x < z->span.channels; x++) {
  352. kfree(z->chans[x]);
  353. }
  354. /* Free z */
  355. kfree(z);
  356. checkmaster();
  357. }
  358. static struct dahdi_dynamic *find_dynamic(struct dahdi_dynamic_span *zds)
  359. {
  360. struct dahdi_dynamic *z = NULL, *found = NULL;
  361. rcu_read_lock();
  362. list_for_each_entry_rcu(z, &dspan_list, list) {
  363. if (!strcmp(z->dname, zds->driver) &&
  364. !strcmp(z->addr, zds->addr)) {
  365. found = z;
  366. break;
  367. }
  368. }
  369. rcu_read_unlock();
  370. return found;
  371. }
  372. static struct dahdi_dynamic_driver *find_driver(char *name)
  373. {
  374. struct dahdi_dynamic_driver *ztd, *found = NULL;
  375. rcu_read_lock();
  376. list_for_each_entry_rcu(ztd, &driver_list, list) {
  377. /* here's our driver */
  378. if (!strcmp(name, ztd->name)) {
  379. found = ztd;
  380. break;
  381. }
  382. }
  383. rcu_read_unlock();
  384. return found;
  385. }
  386. static int destroy_dynamic(struct dahdi_dynamic_span *zds)
  387. {
  388. unsigned long flags;
  389. struct dahdi_dynamic *z;
  390. z = find_dynamic(zds);
  391. if (unlikely(!z)) {
  392. return -EINVAL;
  393. }
  394. if (z->usecount) {
  395. printk(KERN_NOTICE "Attempt to destroy dynamic span while it is in use\n");
  396. return -EBUSY;
  397. }
  398. spin_lock_irqsave(&dspan_lock, flags);
  399. list_del_rcu(&z->list);
  400. spin_unlock_irqrestore(&dspan_lock, flags);
  401. synchronize_rcu();
  402. /* Destroy it */
  403. dynamic_destroy(z);
  404. return 0;
  405. }
  406. static int ztd_rbsbits(struct dahdi_chan *chan, int bits)
  407. {
  408. /* Don't have to do anything */
  409. return 0;
  410. }
  411. static int ztd_open(struct dahdi_chan *chan)
  412. {
  413. struct dahdi_dynamic *z = dynamic_from_span(chan->span);
  414. if (likely(z)) {
  415. if (unlikely(z->dead))
  416. return -ENODEV;
  417. z->usecount++;
  418. }
  419. return 0;
  420. }
  421. static int ztd_chanconfig(struct dahdi_chan *chan, int sigtype)
  422. {
  423. return 0;
  424. }
  425. static int ztd_close(struct dahdi_chan *chan)
  426. {
  427. struct dahdi_dynamic *z = dynamic_from_span(chan->span);
  428. if (z) {
  429. z->usecount--;
  430. if (z->dead && !z->usecount)
  431. dynamic_destroy(z);
  432. }
  433. return 0;
  434. }
  435. static const struct dahdi_span_ops dynamic_ops = {
  436. .owner = THIS_MODULE,
  437. .rbsbits = ztd_rbsbits,
  438. .open = ztd_open,
  439. .close = ztd_close,
  440. .chanconfig = ztd_chanconfig,
  441. };
  442. static int create_dynamic(struct dahdi_dynamic_span *zds)
  443. {
  444. struct dahdi_dynamic *z;
  445. struct dahdi_dynamic_driver *ztd;
  446. unsigned long flags;
  447. int x;
  448. int bufsize;
  449. if (zds->numchans < 1) {
  450. printk(KERN_NOTICE "Can't be less than 1 channel (%d)!\n", zds->numchans);
  451. return -EINVAL;
  452. }
  453. if (zds->numchans >= DAHDI_DYNAMIC_MAX_CHANS) {
  454. printk(KERN_NOTICE "Can't create dynamic span with greater than %d channels. See ztdynamic.c and increase DAHDI_DYNAMIC_MAX_CHANS\n", zds->numchans);
  455. return -EINVAL;
  456. }
  457. z = find_dynamic(zds);
  458. if (z)
  459. return -EEXIST;
  460. /* Allocate memory */
  461. z = (struct dahdi_dynamic *) kmalloc(sizeof(struct dahdi_dynamic), GFP_KERNEL);
  462. if (!z) {
  463. return -ENOMEM;
  464. }
  465. /* Zero it out */
  466. memset(z, 0, sizeof(*z));
  467. for (x = 0; x < zds->numchans; x++) {
  468. if (!(z->chans[x] = kmalloc(sizeof(*z->chans[x]), GFP_KERNEL))) {
  469. dynamic_destroy(z);
  470. return -ENOMEM;
  471. }
  472. memset(z->chans[x], 0, sizeof(*z->chans[x]));
  473. }
  474. /* Allocate message buffer with sample space and header space */
  475. bufsize = zds->numchans * DAHDI_CHUNKSIZE + zds->numchans / 4 + 48;
  476. z->msgbuf = kmalloc(bufsize, GFP_KERNEL);
  477. if (!z->msgbuf) {
  478. dynamic_destroy(z);
  479. return -ENOMEM;
  480. }
  481. /* Zero out -- probably not needed but why not */
  482. memset(z->msgbuf, 0, bufsize);
  483. /* Setup parameters properly assuming we're going to be okay. */
  484. dahdi_copy_string(z->dname, zds->driver, sizeof(z->dname));
  485. dahdi_copy_string(z->addr, zds->addr, sizeof(z->addr));
  486. z->timing = zds->timing;
  487. sprintf(z->span.name, "DYN/%s/%s", zds->driver, zds->addr);
  488. sprintf(z->span.desc, "Dynamic '%s' span at '%s'", zds->driver, zds->addr);
  489. z->span.channels = zds->numchans;
  490. z->span.deflaw = DAHDI_LAW_MULAW;
  491. z->span.flags |= DAHDI_FLAG_RBS;
  492. z->span.chans = z->chans;
  493. z->span.ops = &dynamic_ops;
  494. for (x=0; x < z->span.channels; x++) {
  495. sprintf(z->chans[x]->name, "DYN/%s/%s/%d", zds->driver, zds->addr, x+1);
  496. z->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR | DAHDI_SIG_FXSLS |
  497. DAHDI_SIG_FXSKS | DAHDI_SIG_FXSGS | DAHDI_SIG_FXOLS |
  498. DAHDI_SIG_FXOKS | DAHDI_SIG_FXOGS | DAHDI_SIG_SF |
  499. DAHDI_SIG_DACS_RBS | DAHDI_SIG_CAS;
  500. z->chans[x]->chanpos = x + 1;
  501. z->chans[x]->pvt = z;
  502. }
  503. ztd = find_driver(zds->driver);
  504. if (!ztd) {
  505. #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70)
  506. char fn[80];
  507. #endif
  508. #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70)
  509. request_module("dahdi_dynamic_%s", zds->driver);
  510. #else
  511. sprintf(fn, "dahdi_dynamic_%s", zds->driver);
  512. request_module(fn);
  513. #endif
  514. ztd = find_driver(zds->driver);
  515. }
  516. /* Another race -- should let the module get unloaded while we
  517. have it here */
  518. if (!ztd) {
  519. printk(KERN_NOTICE "No such driver '%s' for dynamic span\n", zds->driver);
  520. dynamic_destroy(z);
  521. return -EINVAL;
  522. }
  523. /* Create the stuff */
  524. z->pvt = ztd->create(&z->span, z->addr);
  525. if (!z->pvt) {
  526. printk(KERN_NOTICE "Driver '%s' (%s) rejected address '%s'\n", ztd->name, ztd->desc, z->addr);
  527. /* Creation failed */
  528. return -EINVAL;
  529. }
  530. /* Remember the driver */
  531. z->driver = ztd;
  532. /* Whee! We're created. Now register the span */
  533. if (dahdi_register(&z->span, 0)) {
  534. printk(KERN_NOTICE "Unable to register span '%s'\n", z->span.name);
  535. dynamic_destroy(z);
  536. return -EINVAL;
  537. }
  538. spin_lock_irqsave(&dspan_lock, flags);
  539. list_add_rcu(&z->list, &dspan_list);
  540. spin_unlock_irqrestore(&dspan_lock, flags);
  541. checkmaster();
  542. /* All done */
  543. return z->span.spanno;
  544. }
  545. #ifdef ENABLE_TASKLETS
  546. static void ztd_tasklet(unsigned long data)
  547. {
  548. taskletrun++;
  549. if (taskletpending) {
  550. taskletexec++;
  551. __ztdynamic_run();
  552. }
  553. taskletpending = 0;
  554. }
  555. #endif
  556. static int ztdynamic_ioctl(unsigned int cmd, unsigned long data)
  557. {
  558. struct dahdi_dynamic_span zds;
  559. int res;
  560. switch(cmd) {
  561. case 0:
  562. /* This is called just before rotation. If none of our
  563. spans are pulling timing, then now is the time to process
  564. them */
  565. if (!hasmaster)
  566. ztdynamic_run();
  567. return 0;
  568. case DAHDI_DYNAMIC_CREATE:
  569. if (copy_from_user(&zds, (__user const void *) data, sizeof(zds)))
  570. return -EFAULT;
  571. if (debug)
  572. printk(KERN_DEBUG "Dynamic Create\n");
  573. res = create_dynamic(&zds);
  574. if (res < 0)
  575. return res;
  576. zds.spanno = res;
  577. /* Let them know the new span number */
  578. if (copy_to_user((__user void *) data, &zds, sizeof(zds)))
  579. return -EFAULT;
  580. return 0;
  581. case DAHDI_DYNAMIC_DESTROY:
  582. if (copy_from_user(&zds, (__user const void *) data, sizeof(zds)))
  583. return -EFAULT;
  584. if (debug)
  585. printk(KERN_DEBUG "Dynamic Destroy\n");
  586. return destroy_dynamic(&zds);
  587. }
  588. return -ENOTTY;
  589. }
  590. int dahdi_dynamic_register(struct dahdi_dynamic_driver *dri)
  591. {
  592. unsigned long flags;
  593. int res = 0;
  594. if (find_driver(dri->name)) {
  595. res = -1;
  596. } else {
  597. spin_lock_irqsave(&driver_lock, flags);
  598. list_add_rcu(&dri->list, &driver_list);
  599. spin_unlock_irqrestore(&driver_lock, flags);
  600. }
  601. return res;
  602. }
  603. void dahdi_dynamic_unregister(struct dahdi_dynamic_driver *dri)
  604. {
  605. struct dahdi_dynamic *z;
  606. unsigned long flags;
  607. spin_lock_irqsave(&driver_lock, flags);
  608. list_del_rcu(&dri->list);
  609. spin_unlock_irqrestore(&driver_lock, flags);
  610. synchronize_rcu();
  611. list_for_each_entry(z, &dspan_list, list) {
  612. if (z->driver == dri) {
  613. spin_lock_irqsave(&dspan_lock, flags);
  614. list_del_rcu(&z->list);
  615. spin_unlock_irqrestore(&dspan_lock, flags);
  616. synchronize_rcu();
  617. if (!z->usecount)
  618. dynamic_destroy(z);
  619. else
  620. z->dead = 1;
  621. }
  622. }
  623. }
  624. static struct timer_list alarmcheck;
  625. static void check_for_red_alarm(unsigned long ignored)
  626. {
  627. int newalarm;
  628. int alarmchanged = 0;
  629. struct dahdi_dynamic *z;
  630. rcu_read_lock();
  631. list_for_each_entry_rcu(z, &dspan_list, list) {
  632. newalarm = z->span.alarms & ~DAHDI_ALARM_RED;
  633. /* If nothing received for a second, consider that RED ALARM */
  634. if ((jiffies - z->rxjif) > 1 * HZ) {
  635. newalarm |= DAHDI_ALARM_RED;
  636. if (z->span.alarms != newalarm) {
  637. z->span.alarms = newalarm;
  638. dahdi_alarm_notify(&z->span);
  639. alarmchanged++;
  640. }
  641. }
  642. }
  643. rcu_read_unlock();
  644. if (alarmchanged)
  645. checkmaster();
  646. /* Do the next one */
  647. mod_timer(&alarmcheck, jiffies + 1 * HZ);
  648. }
  649. static int ztdynamic_init(void)
  650. {
  651. dahdi_set_dynamic_ioctl(ztdynamic_ioctl);
  652. /* Start process to check for RED ALARM */
  653. init_timer(&alarmcheck);
  654. alarmcheck.expires = 0;
  655. alarmcheck.data = 0;
  656. alarmcheck.function = check_for_red_alarm;
  657. /* Check once per second */
  658. mod_timer(&alarmcheck, jiffies + 1 * HZ);
  659. #ifdef ENABLE_TASKLETS
  660. tasklet_init(&ztd_tlet, ztd_tasklet, 0);
  661. #endif
  662. printk(KERN_INFO "DAHDI Dynamic Span support LOADED\n");
  663. return 0;
  664. }
  665. static void ztdynamic_cleanup(void)
  666. {
  667. #ifdef ENABLE_TASKLETS
  668. if (taskletpending) {
  669. tasklet_disable(&ztd_tlet);
  670. tasklet_kill(&ztd_tlet);
  671. }
  672. #endif
  673. dahdi_set_dynamic_ioctl(NULL);
  674. del_timer(&alarmcheck);
  675. printk(KERN_INFO "DAHDI Dynamic Span support unloaded\n");
  676. }
  677. module_param(debug, int, 0600);
  678. MODULE_DESCRIPTION("DAHDI Dynamic Span Support");
  679. MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
  680. MODULE_LICENSE("GPL v2");
  681. module_init(ztdynamic_init);
  682. module_exit(ztdynamic_cleanup);