dahdi_dynamic.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. * Dynamic Span Interface for DAHDI
  3. *
  4. * Written by Mark Spencer <markster@digium.com>
  5. *
  6. * Copyright (C) 2001-2012, 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. #ifndef DAHDI_SYNC_TICK
  35. #error "Dynamic support depends on DAHDI_SYNC_TICK being enabled."
  36. #endif
  37. /*
  38. * Tasklets provide better system interactive response at the cost of the
  39. * possibility of losing a frame of data at very infrequent intervals. If
  40. * you are more concerned with the performance of your machine, enable the
  41. * tasklets. If you are strict about absolutely no drops, then do not enable
  42. * tasklets.
  43. */
  44. #undef ENABLE_TASKLETS
  45. /*
  46. * Dynamic spans implemented using TDM over X with standard message
  47. * types. Message format is as follows:
  48. *
  49. * Byte #: Meaning
  50. * 0 Number of samples per channel
  51. * 1 Current flags on span
  52. * Bit 0: Yellow Alarm
  53. * Bit 1: Sig bits present
  54. * Bits 2-7: reserved for future use
  55. * 2-3 16-bit counter value for detecting drops, network byte order.
  56. * 4-5 Number of channels in the message, network byte order
  57. * 6... 16-bit words, containing sig bits for each
  58. * four channels, least significant 4 bits being
  59. * the least significant channel, network byte order.
  60. * the rest data for each channel, all samples per channel
  61. before moving to the next.
  62. */
  63. #define DAHDI_DYNAMIC_FLAG_YELLOW_ALARM (1 << 0)
  64. #define DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT (1 << 1)
  65. #define DAHDI_DYNAMIC_FLAG_LOOPBACK (1 << 2)
  66. #define ERR_NSAMP (1 << 16)
  67. #define ERR_NCHAN (1 << 17)
  68. #define ERR_LEN (1 << 18)
  69. static int dahdi_dynamic_init(void);
  70. static void dahdi_dynamic_cleanup(void);
  71. #ifdef ENABLE_TASKLETS
  72. static int taskletrun;
  73. static int taskletsched;
  74. static int taskletpending;
  75. static int taskletexec;
  76. static int txerrors;
  77. static struct tasklet_struct dahdi_dynamic_tlet;
  78. static void dahdi_dynamic_tasklet(unsigned long data);
  79. #else
  80. static struct tasklet_struct dahdi_dynamic_flush_tlet;
  81. #endif
  82. static DEFINE_MUTEX(dspan_mutex);
  83. static DEFINE_SPINLOCK(dspan_lock);
  84. static DEFINE_SPINLOCK(driver_lock);
  85. static LIST_HEAD(dspan_list);
  86. static LIST_HEAD(driver_list);
  87. static int debug = 0;
  88. static int hasmaster = 0;
  89. static void checkmaster(void)
  90. {
  91. int newhasmaster=0;
  92. int best = 9999999;
  93. struct dahdi_dynamic *d, *master = NULL;
  94. rcu_read_lock();
  95. list_for_each_entry_rcu(d, &dspan_list, list) {
  96. if (d->timing) {
  97. d->master = 0;
  98. if (!(d->span.alarms & DAHDI_ALARM_RED) &&
  99. (d->timing < best)) {
  100. /* If not in alarm and they're
  101. a better timing source, use them */
  102. master = d;
  103. best = d->timing;
  104. newhasmaster = 1;
  105. }
  106. }
  107. }
  108. hasmaster = newhasmaster;
  109. /* Mark the new master if there is one */
  110. if (master)
  111. master->master = 1;
  112. rcu_read_unlock();
  113. if (master)
  114. printk(KERN_INFO "TDMoX: New master: %s\n", master->span.name);
  115. else
  116. printk(KERN_INFO "TDMoX: No master.\n");
  117. }
  118. static void dahdi_dynamic_sendmessage(struct dahdi_dynamic *d)
  119. {
  120. unsigned char *buf = d->msgbuf;
  121. unsigned short bits;
  122. int msglen = 0;
  123. int x;
  124. int offset;
  125. /* Byte 0: Number of samples per channel */
  126. *buf = DAHDI_CHUNKSIZE;
  127. buf++; msglen++;
  128. /* Byte 1: Flags */
  129. *buf = 0;
  130. if (d->span.alarms & DAHDI_ALARM_RED)
  131. *buf |= DAHDI_DYNAMIC_FLAG_YELLOW_ALARM;
  132. *buf |= DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT;
  133. buf++; msglen++;
  134. /* Bytes 2-3: Transmit counter */
  135. *((unsigned short *)buf) = htons((unsigned short)d->txcnt);
  136. d->txcnt++;
  137. buf++; msglen++;
  138. buf++; msglen++;
  139. /* Bytes 4-5: Number of channels */
  140. *((unsigned short *)buf) = htons((unsigned short)d->span.channels);
  141. buf++; msglen++;
  142. buf++; msglen++;
  143. bits = 0;
  144. offset = 0;
  145. for (x = 0; x < d->span.channels; x++) {
  146. offset = x % 4;
  147. bits |= (d->chans[x]->txsig & 0xf) << (offset << 2);
  148. if (offset == 3) {
  149. /* Write the bits when we have four channels */
  150. *((unsigned short *)buf) = htons(bits);
  151. buf++; msglen++;
  152. buf++; msglen++;
  153. bits = 0;
  154. }
  155. }
  156. if (offset != 3) {
  157. /* Finish it off if it's not done already */
  158. *((unsigned short *)buf) = htons(bits);
  159. buf++; msglen++;
  160. buf++; msglen++;
  161. }
  162. for (x = 0; x < d->span.channels; x++) {
  163. memcpy(buf, d->chans[x]->writechunk, DAHDI_CHUNKSIZE);
  164. buf += DAHDI_CHUNKSIZE;
  165. msglen += DAHDI_CHUNKSIZE;
  166. }
  167. d->driver->transmit(d, d->msgbuf, msglen);
  168. }
  169. static void __dahdi_dynamic_run(void)
  170. {
  171. struct dahdi_dynamic *d;
  172. #ifdef ENABLE_TASKLETS
  173. struct dahdi_dynamic_driver *drv;
  174. #endif
  175. rcu_read_lock();
  176. list_for_each_entry_rcu(d, &dspan_list, list) {
  177. dahdi_transmit(&d->span);
  178. /* Handle all transmissions now */
  179. dahdi_dynamic_sendmessage(d);
  180. }
  181. #ifdef ENABLE_TASKLETS
  182. list_for_each_entry_rcu(drv, &driver_list, list) {
  183. /* Flush any traffic still pending in the driver */
  184. if (drv->flush) {
  185. drv->flush();
  186. }
  187. }
  188. #else
  189. /* If tasklets are not enabled, the above section will be called in
  190. * interrupt context and the flushing of each driver will be called in a
  191. * separate tasklet that only handles that. This is necessary since some
  192. * of the dynamic spans need to call functions that require interrupts
  193. * to be enabled but dahdi_transmit / ...sendmessage needs to be called
  194. * each time the masterspan is processed which happens with interrupts
  195. * disabled.
  196. *
  197. */
  198. tasklet_hi_schedule(&dahdi_dynamic_flush_tlet);
  199. #endif
  200. rcu_read_unlock();
  201. }
  202. #ifdef ENABLE_TASKLETS
  203. static void dahdi_dynamic_run(void)
  204. {
  205. if (likely(!taskletpending)) {
  206. taskletpending = 1;
  207. taskletsched++;
  208. tasklet_hi_schedule(&dahdi_dynamic_tlet);
  209. } else {
  210. txerrors++;
  211. }
  212. }
  213. #else
  214. #define dahdi_dynamic_run __dahdi_dynamic_run
  215. #endif
  216. static inline struct dahdi_dynamic *dynamic_from_span(struct dahdi_span *span)
  217. {
  218. return container_of(span, struct dahdi_dynamic, span);
  219. }
  220. void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msglen)
  221. {
  222. struct dahdi_dynamic *dtd = dynamic_from_span(span);
  223. int newerr=0;
  224. int sflags;
  225. int xlen;
  226. int x, bits, sig;
  227. int nchans, master;
  228. int newalarm;
  229. unsigned short rxpos, rxcnt;
  230. rcu_read_lock();
  231. if (unlikely(msglen < 6)) {
  232. rcu_read_unlock();
  233. newerr = ERR_LEN;
  234. if (newerr != dtd->err)
  235. printk(KERN_NOTICE "Span %s: Insufficient samples for header (only %d)\n", span->name, msglen);
  236. dtd->err = newerr;
  237. return;
  238. }
  239. /* First, check the chunksize */
  240. if (unlikely(*msg != DAHDI_CHUNKSIZE)) {
  241. rcu_read_unlock();
  242. newerr = ERR_NSAMP | msg[0];
  243. if (newerr != dtd->err)
  244. printk(KERN_NOTICE "Span %s: Expected %d samples, but receiving %d\n", span->name, DAHDI_CHUNKSIZE, msg[0]);
  245. dtd->err = newerr;
  246. return;
  247. }
  248. msg++;
  249. sflags = *msg;
  250. msg++;
  251. rxpos = ntohs(*((unsigned short *)msg));
  252. msg++;
  253. msg++;
  254. nchans = ntohs(*((unsigned short *)msg));
  255. if (unlikely(nchans != span->channels)) {
  256. rcu_read_unlock();
  257. newerr = ERR_NCHAN | nchans;
  258. if (newerr != dtd->err)
  259. printk(KERN_NOTICE "Span %s: Expected %d channels, but receiving %d\n", span->name, span->channels, nchans);
  260. dtd->err = newerr;
  261. return;
  262. }
  263. msg++;
  264. msg++;
  265. /* Okay now we've accepted the header, lets check our message
  266. length... */
  267. /* Start with header */
  268. xlen = 6;
  269. /* Add samples of audio */
  270. xlen += nchans * DAHDI_CHUNKSIZE;
  271. /* If RBS info is there, add that */
  272. if (sflags & DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT) {
  273. /* Account for sigbits -- one short per 4 channels*/
  274. xlen += ((nchans + 3) / 4) * 2;
  275. }
  276. if (unlikely(xlen != msglen)) {
  277. rcu_read_unlock();
  278. newerr = ERR_LEN | xlen;
  279. if (newerr != dtd->err)
  280. printk(KERN_NOTICE "Span %s: Expected message size %d, but was %d instead\n", span->name, xlen, msglen);
  281. dtd->err = newerr;
  282. return;
  283. }
  284. bits = 0;
  285. /* Record sigbits if present */
  286. if (sflags & DAHDI_DYNAMIC_FLAG_SIGBITS_PRESENT) {
  287. for (x=0;x<nchans;x++) {
  288. if (!(x%4)) {
  289. /* Get new bits */
  290. bits = ntohs(*((unsigned short *)msg));
  291. msg++;
  292. msg++;
  293. }
  294. /* Pick the right bits */
  295. sig = (bits >> ((x % 4) << 2)) & 0xff;
  296. /* Update signalling if appropriate */
  297. if (sig != span->chans[x]->rxsig)
  298. dahdi_rbsbits(span->chans[x], sig);
  299. }
  300. }
  301. /* Record data for channels */
  302. for (x=0;x<nchans;x++) {
  303. memcpy(span->chans[x]->readchunk, msg, DAHDI_CHUNKSIZE);
  304. msg += DAHDI_CHUNKSIZE;
  305. }
  306. master = dtd->master;
  307. rxcnt = dtd->rxcnt;
  308. dtd->rxcnt = rxpos+1;
  309. /* Keep track of last received packet */
  310. dtd->rxjif = jiffies;
  311. rcu_read_unlock();
  312. /* Check for Yellow alarm */
  313. newalarm = span->alarms & ~(DAHDI_ALARM_YELLOW | DAHDI_ALARM_RED);
  314. if (sflags & DAHDI_DYNAMIC_FLAG_YELLOW_ALARM)
  315. newalarm |= DAHDI_ALARM_YELLOW;
  316. if (newalarm != span->alarms) {
  317. span->alarms = newalarm;
  318. dahdi_alarm_notify(span);
  319. checkmaster();
  320. }
  321. /* note if we had a missing packet */
  322. if (unlikely(rxpos != rxcnt))
  323. printk(KERN_NOTICE "Span %s: Expected seq no %d, but received %d instead\n", span->name, rxcnt, rxpos);
  324. dahdi_ec_span(span);
  325. dahdi_receive(span);
  326. /* If this is our master span, then run everything */
  327. if (master)
  328. dahdi_dynamic_run();
  329. }
  330. EXPORT_SYMBOL(dahdi_dynamic_receive);
  331. /**
  332. * dahdi_dynamic_release() - Free the memory associated with the dahdi_dynamic.
  333. * @kref: Pointer to kref embedded in dahdi_dynamic structure.
  334. *
  335. */
  336. static void dahdi_dynamic_release(struct kref *kref)
  337. {
  338. struct dahdi_dynamic *d = container_of(kref, struct dahdi_dynamic,
  339. kref);
  340. unsigned int x;
  341. WARN_ON(test_bit(DAHDI_FLAGBIT_REGISTERED, &d->span.flags));
  342. kfree(d->msgbuf);
  343. for (x = 0; x < d->span.channels; x++)
  344. kfree(d->chans[x]);
  345. dahdi_free_device(d->ddev);
  346. kfree(d);
  347. }
  348. static inline int dynamic_put(struct dahdi_dynamic *d)
  349. {
  350. return kref_put(&d->kref, dahdi_dynamic_release);
  351. }
  352. static inline void dynamic_get(struct dahdi_dynamic *d)
  353. {
  354. kref_get(&d->kref);
  355. }
  356. static struct dahdi_dynamic *find_dynamic(struct dahdi_dynamic_span *dds)
  357. {
  358. struct dahdi_dynamic *d = NULL, *found = NULL;
  359. rcu_read_lock();
  360. list_for_each_entry_rcu(d, &dspan_list, list) {
  361. if (!strcmp(d->dname, dds->driver) &&
  362. !strcmp(d->addr, dds->addr)) {
  363. dynamic_get(d);
  364. found = d;
  365. break;
  366. }
  367. }
  368. rcu_read_unlock();
  369. return found;
  370. }
  371. static struct dahdi_dynamic_driver *find_driver(const char *name)
  372. {
  373. struct dahdi_dynamic_driver *dtd, *found = NULL;
  374. rcu_read_lock();
  375. list_for_each_entry_rcu(dtd, &driver_list, list) {
  376. /* here's our driver */
  377. if (!strcmp(name, dtd->name)) {
  378. found = dtd;
  379. break;
  380. }
  381. }
  382. rcu_read_unlock();
  383. return found;
  384. }
  385. static int _destroy_dynamic(struct dahdi_dynamic_span *dds)
  386. {
  387. unsigned long flags;
  388. struct dahdi_dynamic *d;
  389. d = find_dynamic(dds);
  390. if (unlikely(!d))
  391. return -EINVAL;
  392. /* We shouldn't have more than the two references at this point. If
  393. * we do, there are probably channels that are still opened. */
  394. if (atomic_read(&d->kref.refcount) > 2) {
  395. dynamic_put(d);
  396. return -EBUSY;
  397. }
  398. if (d->pvt) {
  399. if (d->driver && d->driver->destroy) {
  400. if (!try_module_get(d->driver->owner)) {
  401. /* The driver for this device is in the
  402. * process of unloading. Leave this dynamic on
  403. * the list so it's cleaned up when the driver
  404. * unregisters. */
  405. dynamic_put(d);
  406. return -ENXIO;
  407. }
  408. d->driver->destroy(d);
  409. module_put(d->driver->owner);
  410. } else {
  411. WARN_ON(1);
  412. }
  413. d->pvt = NULL;
  414. }
  415. dahdi_unregister_device(d->ddev);
  416. spin_lock_irqsave(&dspan_lock, flags);
  417. list_del_rcu(&d->list);
  418. spin_unlock_irqrestore(&dspan_lock, flags);
  419. synchronize_rcu();
  420. /* One since we've removed the item from the list... */
  421. dynamic_put(d);
  422. /* ...and one for find_dynamic. */
  423. dynamic_put(d);
  424. return 0;
  425. }
  426. static int destroy_dynamic(struct dahdi_dynamic_span *dds)
  427. {
  428. int ret;
  429. mutex_lock(&dspan_mutex);
  430. ret = _destroy_dynamic(dds);
  431. mutex_unlock(&dspan_mutex);
  432. return ret;
  433. }
  434. static int dahdi_dynamic_rbsbits(struct dahdi_chan *chan, int bits)
  435. {
  436. /* Don't have to do anything */
  437. return 0;
  438. }
  439. static int dahdi_dynamic_open(struct dahdi_chan *chan)
  440. {
  441. struct dahdi_dynamic *d = dynamic_from_span(chan->span);
  442. if (!try_module_get(d->driver->owner))
  443. return -ENODEV;
  444. dynamic_get(d);
  445. return 0;
  446. }
  447. static int dahdi_dynamic_chanconfig(struct file *file,
  448. struct dahdi_chan *chan, int sigtype)
  449. {
  450. return 0;
  451. }
  452. static int dahdi_dynamic_close(struct dahdi_chan *chan)
  453. {
  454. struct dahdi_dynamic *d = dynamic_from_span(chan->span);
  455. struct module *owner = d->driver->owner;
  456. dynamic_put(d);
  457. module_put(owner);
  458. return 0;
  459. }
  460. static void dahdi_dynamic_sync_tick(struct dahdi_span *span, int is_master)
  461. {
  462. struct dahdi_dynamic *head;
  463. struct dahdi_dynamic *d = dynamic_from_span(span);
  464. if (hasmaster)
  465. return;
  466. rcu_read_lock();
  467. head = list_entry(dspan_list.next, struct dahdi_dynamic, list);
  468. rcu_read_unlock();
  469. if (d == head)
  470. dahdi_dynamic_run();
  471. return;
  472. }
  473. static const struct dahdi_span_ops dynamic_ops = {
  474. .owner = THIS_MODULE,
  475. .rbsbits = dahdi_dynamic_rbsbits,
  476. .open = dahdi_dynamic_open,
  477. .close = dahdi_dynamic_close,
  478. .chanconfig = dahdi_dynamic_chanconfig,
  479. .sync_tick = dahdi_dynamic_sync_tick,
  480. };
  481. static int _create_dynamic(struct dahdi_dynamic_span *dds)
  482. {
  483. int res = 0;
  484. struct dahdi_dynamic *d;
  485. struct dahdi_dynamic_driver *dtd;
  486. unsigned long flags;
  487. int x;
  488. int bufsize;
  489. if (dds->numchans < 1) {
  490. printk(KERN_NOTICE "Can't be less than 1 channel (%d)!\n",
  491. dds->numchans);
  492. return -EINVAL;
  493. }
  494. if (dds->numchans >= ARRAY_SIZE(d->chans)) {
  495. printk(KERN_NOTICE "Can't create dynamic span with greater "
  496. "than %d channels. See dahdi_dynamic.c and increase "
  497. "DAHDI_DYNAMIC_MAX_CHANS\n", dds->numchans);
  498. return -EINVAL;
  499. }
  500. d = find_dynamic(dds);
  501. if (d) {
  502. dynamic_put(d);
  503. return -EEXIST;
  504. }
  505. d = kzalloc(sizeof(*d), GFP_KERNEL);
  506. if (!d)
  507. return -ENOMEM;
  508. kref_init(&d->kref);
  509. d->ddev = dahdi_create_device();
  510. for (x = 0; x < dds->numchans; x++) {
  511. d->chans[x] = kzalloc(sizeof(*d->chans[x]), GFP_KERNEL);
  512. if (!d->chans[x]) {
  513. dynamic_put(d);
  514. return -ENOMEM;
  515. }
  516. d->span.channels++;
  517. }
  518. /* Allocate message buffer with sample space and header space */
  519. bufsize = dds->numchans * DAHDI_CHUNKSIZE + dds->numchans / 4 + 48;
  520. d->msgbuf = kzalloc(bufsize, GFP_KERNEL);
  521. if (!d->msgbuf) {
  522. dynamic_put(d);
  523. return -ENOMEM;
  524. }
  525. /* Setup parameters properly assuming we're going to be okay. */
  526. strlcpy(d->dname, dds->driver, sizeof(d->dname));
  527. strlcpy(d->addr, dds->addr, sizeof(d->addr));
  528. d->timing = dds->timing;
  529. snprintf(d->span.name, sizeof(d->span.name), "DYN/%s/%s",
  530. dds->driver, dds->addr);
  531. snprintf(d->span.desc, sizeof(d->span.desc),
  532. "Dynamic '%s' span at '%s'", dds->driver, dds->addr);
  533. d->span.deflaw = DAHDI_LAW_MULAW;
  534. d->span.flags |= DAHDI_FLAG_RBS;
  535. d->span.chans = d->chans;
  536. d->span.spantype = SPANTYPE_DIGITAL_DYNAMIC;
  537. d->span.linecompat = DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF |
  538. DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_CCS |
  539. DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CRC4 | DAHDI_CONFIG_NOTOPEN;
  540. d->span.ops = &dynamic_ops;
  541. for (x = 0; x < d->span.channels; x++) {
  542. sprintf(d->chans[x]->name, "DYN/%s/%s/%d",
  543. dds->driver, dds->addr, x+1);
  544. d->chans[x]->sigcap = DAHDI_SIG_EM | DAHDI_SIG_CLEAR |
  545. DAHDI_SIG_FXSLS | DAHDI_SIG_FXSKS |
  546. DAHDI_SIG_FXSGS | DAHDI_SIG_FXOLS |
  547. DAHDI_SIG_FXOKS | DAHDI_SIG_FXOGS |
  548. DAHDI_SIG_SF | DAHDI_SIG_DACS_RBS |
  549. DAHDI_SIG_CAS;
  550. d->chans[x]->chanpos = x + 1;
  551. d->chans[x]->pvt = d;
  552. }
  553. dtd = find_driver(dds->driver);
  554. if (!dtd) {
  555. request_module("dahdi_dynamic_%s", dds->driver);
  556. dtd = find_driver(dds->driver);
  557. }
  558. if (!dtd) {
  559. printk(KERN_NOTICE "No such driver '%s' for dynamic span\n",
  560. dds->driver);
  561. dynamic_put(d);
  562. return -EINVAL;
  563. }
  564. if (!try_module_get(dtd->owner)) {
  565. dynamic_put(d);
  566. return -ENODEV;
  567. }
  568. /* Remember the driver. We also give our reference to the driver to
  569. * the dahdi_dyanmic here. Do not access dtd directly now. */
  570. d->driver = dtd;
  571. /* Create the stuff */
  572. res = dtd->create(d, d->addr);
  573. if (res) {
  574. printk(KERN_NOTICE "Driver '%s' (%s) rejected address '%s'\n",
  575. dtd->name, dtd->desc, d->addr);
  576. dynamic_put(d);
  577. module_put(dtd->owner);
  578. return res;
  579. }
  580. d->ddev->devicetype = d->span.name;
  581. d->ddev->hardware_id = d->span.name;
  582. dev_set_name(&d->ddev->dev, "dynamic:%s:%d", dds->driver, dtd->id++);
  583. list_add_tail(&d->span.device_node, &d->ddev->spans);
  584. /* Whee! We're created. Now register the span */
  585. if (dahdi_register_device(d->ddev, d->dev)) {
  586. printk(KERN_NOTICE "Unable to register span '%s'\n",
  587. d->span.name);
  588. dynamic_put(d);
  589. module_put(dtd->owner);
  590. return -EINVAL;
  591. }
  592. x = d->span.spanno;
  593. /* Transfer our reference to the dspan_list. Do not touch d after
  594. * this point. It also must remain on the list while registered. */
  595. spin_lock_irqsave(&dspan_lock, flags);
  596. list_add_rcu(&d->list, &dspan_list);
  597. spin_unlock_irqrestore(&dspan_lock, flags);
  598. checkmaster();
  599. module_put(dtd->owner);
  600. return x;
  601. }
  602. static int create_dynamic(struct dahdi_dynamic_span *dds)
  603. {
  604. int ret;
  605. mutex_lock(&dspan_mutex);
  606. ret = _create_dynamic(dds);
  607. mutex_unlock(&dspan_mutex);
  608. return ret;
  609. }
  610. #ifdef ENABLE_TASKLETS
  611. static void dahdi_dynamic_tasklet(unsigned long data)
  612. {
  613. taskletrun++;
  614. if (taskletpending) {
  615. taskletexec++;
  616. __dahdi_dynamic_run();
  617. }
  618. taskletpending = 0;
  619. }
  620. #else
  621. static void dahdi_dynamic_flush_tasklet(unsigned long data)
  622. {
  623. struct dahdi_dynamic_driver *drv;
  624. rcu_read_lock();
  625. list_for_each_entry_rcu(drv, &driver_list, list) {
  626. /* Flush any traffic still pending in the driver */
  627. if (drv->flush) {
  628. drv->flush();
  629. }
  630. }
  631. rcu_read_unlock();
  632. }
  633. #endif
  634. static int dahdi_dynamic_ioctl(unsigned int cmd, unsigned long data)
  635. {
  636. struct dahdi_dynamic_span dds;
  637. int res;
  638. switch(cmd) {
  639. case DAHDI_DYNAMIC_CREATE:
  640. if (copy_from_user(&dds, (__user const void *)data,
  641. sizeof(dds)))
  642. return -EFAULT;
  643. if (debug)
  644. printk(KERN_DEBUG "Dynamic Create\n");
  645. res = create_dynamic(&dds);
  646. if (res < 0)
  647. return res;
  648. dds.spanno = res;
  649. /* Let them know the new span number */
  650. if (copy_to_user((__user void *) data, &dds, sizeof(dds)))
  651. return -EFAULT;
  652. return 0;
  653. case DAHDI_DYNAMIC_DESTROY:
  654. if (copy_from_user(&dds, (__user const void *)data,
  655. sizeof(dds)))
  656. return -EFAULT;
  657. if (debug)
  658. printk(KERN_DEBUG "Dynamic Destroy\n");
  659. return destroy_dynamic(&dds);
  660. }
  661. return -ENOTTY;
  662. }
  663. int dahdi_dynamic_register_driver(struct dahdi_dynamic_driver *dri)
  664. {
  665. unsigned long flags;
  666. int res = 0;
  667. if (!dri->owner)
  668. return -EINVAL;
  669. if (find_driver(dri->name)) {
  670. res = -1;
  671. } else {
  672. spin_lock_irqsave(&driver_lock, flags);
  673. list_add_rcu(&dri->list, &driver_list);
  674. spin_unlock_irqrestore(&driver_lock, flags);
  675. }
  676. return res;
  677. }
  678. EXPORT_SYMBOL(dahdi_dynamic_register_driver);
  679. void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *dri)
  680. {
  681. struct dahdi_dynamic *d, *n;
  682. unsigned long flags;
  683. mutex_lock(&dspan_mutex);
  684. list_for_each_entry_safe(d, n, &dspan_list, list) {
  685. if (d->driver == dri) {
  686. if (d->pvt) {
  687. if (d->driver && d->driver->destroy)
  688. d->driver->destroy(d);
  689. else
  690. WARN_ON(1);
  691. }
  692. dahdi_unregister_device(d->ddev);
  693. spin_lock_irqsave(&dspan_lock, flags);
  694. list_del_rcu(&d->list);
  695. spin_unlock_irqrestore(&dspan_lock, flags);
  696. synchronize_rcu();
  697. d->driver = NULL;
  698. dynamic_put(d);
  699. }
  700. }
  701. spin_lock_irqsave(&driver_lock, flags);
  702. list_del_rcu(&dri->list);
  703. spin_unlock_irqrestore(&driver_lock, flags);
  704. synchronize_rcu();
  705. mutex_unlock(&dspan_mutex);
  706. }
  707. EXPORT_SYMBOL(dahdi_dynamic_unregister_driver);
  708. static struct timer_list alarmcheck;
  709. static void check_for_red_alarm(unsigned long ignored)
  710. {
  711. int newalarm;
  712. int alarmchanged = 0;
  713. struct dahdi_dynamic *d;
  714. rcu_read_lock();
  715. list_for_each_entry_rcu(d, &dspan_list, list) {
  716. newalarm = d->span.alarms & ~DAHDI_ALARM_RED;
  717. /* If nothing received for a second, consider that RED ALARM */
  718. if ((jiffies - d->rxjif) > 1 * HZ) {
  719. newalarm |= DAHDI_ALARM_RED;
  720. if (d->span.alarms != newalarm) {
  721. d->span.alarms = newalarm;
  722. dahdi_alarm_notify(&d->span);
  723. alarmchanged++;
  724. }
  725. }
  726. }
  727. rcu_read_unlock();
  728. if (alarmchanged)
  729. checkmaster();
  730. /* Do the next one */
  731. mod_timer(&alarmcheck, jiffies + 1 * HZ);
  732. }
  733. static const struct dahdi_dynamic_ops dahdi_dynamic_ops = {
  734. .owner = THIS_MODULE,
  735. .ioctl = dahdi_dynamic_ioctl,
  736. };
  737. static int dahdi_dynamic_init(void)
  738. {
  739. /* Start process to check for RED ALARM */
  740. init_timer(&alarmcheck);
  741. alarmcheck.expires = 0;
  742. alarmcheck.data = 0;
  743. alarmcheck.function = check_for_red_alarm;
  744. /* Check once per second */
  745. mod_timer(&alarmcheck, jiffies + 1 * HZ);
  746. #ifdef ENABLE_TASKLETS
  747. tasklet_init(&dahdi_dynamic_tlet, dahdi_dynamic_tasklet, 0);
  748. #else
  749. tasklet_init(&dahdi_dynamic_flush_tlet, dahdi_dynamic_flush_tasklet, 0);
  750. #endif
  751. dahdi_set_dynamic_ops(&dahdi_dynamic_ops);
  752. printk(KERN_INFO "DAHDI Dynamic Span support LOADED\n");
  753. return 0;
  754. }
  755. static void dahdi_dynamic_cleanup(void)
  756. {
  757. dahdi_set_dynamic_ops(NULL);
  758. #ifdef ENABLE_TASKLETS
  759. if (taskletpending) {
  760. tasklet_disable(&dahdi_dynamic_tlet);
  761. tasklet_kill(&dahdi_dynamic_tlet);
  762. }
  763. #else
  764. tasklet_disable(&dahdi_dynamic_flush_tlet);
  765. tasklet_kill(&dahdi_dynamic_flush_tlet);
  766. #endif
  767. del_timer_sync(&alarmcheck);
  768. /* Must call again in case it was running before and rescheduled
  769. * itself. */
  770. del_timer(&alarmcheck);
  771. printk(KERN_INFO "DAHDI Dynamic Span support unloaded\n");
  772. }
  773. module_param(debug, int, 0600);
  774. MODULE_DESCRIPTION("DAHDI Dynamic Span Support");
  775. MODULE_AUTHOR("Mark Spencer <markster@digium.com>");
  776. MODULE_LICENSE("GPL v2");
  777. module_init(dahdi_dynamic_init);
  778. module_exit(dahdi_dynamic_cleanup);