chan_modem_i4l.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * ISDN4Linux TTY Driver
  5. *
  6. * Copyright (C) 2001, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <stdlib.h>
  16. #include <errno.h>
  17. #include <unistd.h>
  18. #include <sys/ioctl.h>
  19. #include <asterisk/lock.h>
  20. #include <asterisk/vmodem.h>
  21. #include <asterisk/module.h>
  22. #include <asterisk/frame.h>
  23. #include <asterisk/logger.h>
  24. #include <asterisk/options.h>
  25. #include <asterisk/dsp.h>
  26. #include <asterisk/callerid.h>
  27. #include "alaw.h"
  28. #define STATE_COMMAND 0
  29. #define STATE_VOICE 1
  30. static char *breakcmd = "\0x10\0x14\0x10\0x3";
  31. static char *desc = "ISDN4Linux Emulated Modem Driver";
  32. static int usecnt;
  33. AST_MUTEX_DEFINE_STATIC(usecnt_lock);
  34. static char *i4l_idents[] = {
  35. /* Identify ISDN4Linux Driver */
  36. "Linux ISDN",
  37. NULL
  38. };
  39. static int i4l_setdev(struct ast_modem_pvt *p, int dev)
  40. {
  41. char cmd[80];
  42. if ((dev != MODEM_DEV_TELCO) && (dev != MODEM_DEV_TELCO_SPK)) {
  43. ast_log(LOG_WARNING, "ISDN4Linux only supports telco device, not %d.\n", dev);
  44. return -1;
  45. } else /* Convert DEV to our understanding of it */
  46. dev = 2;
  47. if (ast_modem_send(p, "AT+VLS?", 0)) {
  48. ast_log(LOG_WARNING, "Unable to select current mode %d\n", dev);
  49. return -1;
  50. }
  51. if (ast_modem_read_response(p, 5)) {
  52. ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
  53. return -1;
  54. }
  55. ast_modem_trim(p->response);
  56. strncpy(cmd, p->response, sizeof(cmd)-1);
  57. if (ast_modem_expect(p, "OK", 5)) {
  58. ast_log(LOG_WARNING, "Modem did not respond properly\n");
  59. return -1;
  60. }
  61. if (dev == atoi(cmd)) {
  62. /* We're already in the right mode, don't bother changing for fear of
  63. hanging up */
  64. return 0;
  65. }
  66. snprintf(cmd, sizeof(cmd), "AT+VLS=%d", dev);
  67. if (ast_modem_send(p, cmd, 0)) {
  68. ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
  69. return -1;
  70. }
  71. if (ast_modem_read_response(p, 5)) {
  72. ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
  73. return -1;
  74. }
  75. ast_modem_trim(p->response);
  76. if (strcasecmp(p->response, "VCON") && strcasecmp(p->response, "OK")) {
  77. ast_log(LOG_WARNING, "Unexpected reply: %s\n", p->response);
  78. return -1;
  79. }
  80. return 0;
  81. }
  82. static int i4l_startrec(struct ast_modem_pvt *p)
  83. {
  84. if (ast_modem_send(p, "AT+VRX+VTX", 0) ||
  85. ast_modem_expect(p, "CONNECT", 5)) {
  86. ast_log(LOG_WARNING, "Unable to start recording\n");
  87. return -1;
  88. }
  89. p->ministate = STATE_VOICE;
  90. /* let ast dsp detect dtmf */
  91. if (p->dtmfmode & MODEM_DTMF_AST) {
  92. if (p->dsp) {
  93. ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev);
  94. } else {
  95. p->dsp = ast_dsp_new();
  96. if (p->dsp) {
  97. ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev);
  98. ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT);
  99. ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0);
  100. }
  101. }
  102. }
  103. return 0;
  104. }
  105. static int i4l_break(struct ast_modem_pvt *p)
  106. {
  107. if (ast_modem_send(p, breakcmd, 2)) {
  108. ast_log(LOG_WARNING, "Failed to break\n");
  109. return -1;
  110. }
  111. if (ast_modem_send(p, "\r\n", 2)) {
  112. ast_log(LOG_WARNING, "Failed to send enter?\n");
  113. return -1;
  114. }
  115. #if 0
  116. /* Read any outstanding junk */
  117. while(!ast_modem_read_response(p, 1));
  118. #endif
  119. if (ast_modem_send(p, "AT", 0)) {
  120. /* Modem might be stuck in some weird mode, try to get it out */
  121. ast_modem_send(p, "+++", 3);
  122. if (ast_modem_expect(p, "OK", 10)) {
  123. ast_log(LOG_WARNING, "Modem is not responding\n");
  124. return -1;
  125. }
  126. if (ast_modem_send(p, "AT", 0)) {
  127. ast_log(LOG_WARNING, "Modem is not responding\n");
  128. return -1;
  129. }
  130. }
  131. if (ast_modem_expect(p, "OK", 5)) {
  132. ast_log(LOG_WARNING, "Modem did not respond properly\n");
  133. return -1;
  134. }
  135. return 0;
  136. }
  137. static int i4l_init(struct ast_modem_pvt *p)
  138. {
  139. char cmd[256];
  140. if (option_debug)
  141. ast_log(LOG_DEBUG, "i4l_init()\n");
  142. if (i4l_break(p))
  143. return -1;
  144. /* Force into command mode */
  145. p->ministate = STATE_COMMAND;
  146. if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
  147. ast_modem_expect(p, "OK", 5)) {
  148. ast_log(LOG_WARNING, "Unable to set to voice mode\n");
  149. return -1;
  150. }
  151. if (strlen(p->msn)) {
  152. snprintf(cmd, sizeof(cmd), "AT&E%s", p->msn);
  153. if (ast_modem_send(p, cmd, 0) ||
  154. ast_modem_expect(p, "OK", 5)) {
  155. ast_log(LOG_WARNING, "Unable to set MSN to %s\n", p->msn);
  156. return -1;
  157. }
  158. }
  159. if (strlen(p->incomingmsn)) {
  160. char *q;
  161. snprintf(cmd, sizeof(cmd), "AT&L%s", p->incomingmsn);
  162. // translate , into ; since that is the seperator I4L uses, but can't be directly
  163. // put in the config file because it will interpret the rest of the line as comment.
  164. q = cmd+4;
  165. while (*q) {
  166. if (*q == ',') *q = ';';
  167. ++q;
  168. }
  169. if (ast_modem_send(p, cmd, 0) ||
  170. ast_modem_expect(p, "OK", 5)) {
  171. ast_log(LOG_WARNING, "Unable to set Listen to %s\n", p->msn);
  172. return -1;
  173. }
  174. }
  175. if (ast_modem_send(p, "AT&D2", 0) ||
  176. ast_modem_expect(p, "OK", 5)) {
  177. ast_log(LOG_WARNING, "Unable to set to DTR disconnect mode\n");
  178. return -1;
  179. }
  180. if (ast_modem_send(p, "ATS18=1", 0) ||
  181. ast_modem_expect(p, "OK", 5)) {
  182. ast_log(LOG_WARNING, "Unable to set to audio only mode\n");
  183. return -1;
  184. }
  185. if (ast_modem_send(p, "ATS13.6=1", 0) ||
  186. ast_modem_expect(p, "OK", 5)) {
  187. ast_log(LOG_WARNING, "Unable to set to RUNG indication\n");
  188. return -1;
  189. }
  190. if (ast_modem_send(p, "ATS14=4", 0) ||
  191. ast_modem_expect(p, "OK", 5)) {
  192. ast_log(LOG_WARNING, "Unable to set to transparent mode\n");
  193. return -1;
  194. }
  195. if (ast_modem_send(p, "ATS23=9", 0) ||
  196. ast_modem_expect(p, "OK", 5)) {
  197. ast_log(LOG_WARNING, "Unable to set to transparent/ringing mode\n");
  198. return -1;
  199. }
  200. if (ast_modem_send(p, "AT+VSM=5", 0) ||
  201. ast_modem_expect(p, "OK", 5)) {
  202. ast_log(LOG_WARNING, "Unable to set to aLAW mode\n");
  203. return -1;
  204. }
  205. if (ast_modem_send(p, "AT+VLS=2", 0) ||
  206. ast_modem_expect(p, "OK", 5)) {
  207. ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
  208. return -1;
  209. }
  210. p->escape = 0;
  211. return 0;
  212. }
  213. static struct ast_frame *i4l_handle_escape(struct ast_modem_pvt *p, char esc)
  214. {
  215. /* Handle escaped characters -- but sometimes we call it directly as
  216. a quick way to cause known responses */
  217. p->fr.frametype = AST_FRAME_NULL;
  218. p->fr.subclass = 0;
  219. p->fr.data = NULL;
  220. p->fr.datalen = 0;
  221. p->fr.samples = 0;
  222. p->fr.offset = 0;
  223. p->fr.mallocd = 0;
  224. p->fr.delivery.tv_sec = 0;
  225. p->fr.delivery.tv_usec = 0;
  226. if (esc && option_debug)
  227. ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
  228. switch(esc) {
  229. case 'R': /* Pseudo ring */
  230. p->fr.frametype = AST_FRAME_CONTROL;
  231. p->fr.subclass = AST_CONTROL_RING;
  232. return &p->fr;
  233. case 'I': /* Pseudo ringing */
  234. p->fr.frametype = AST_FRAME_CONTROL;
  235. p->fr.subclass = AST_CONTROL_RINGING;
  236. return &p->fr;
  237. case 'X': /* Pseudo connect */
  238. p->fr.frametype = AST_FRAME_CONTROL;
  239. p->fr.subclass = AST_CONTROL_ANSWER;
  240. if (p->owner)
  241. ast_setstate(p->owner, AST_STATE_UP);
  242. if (i4l_startrec(p))
  243. return NULL;
  244. return &p->fr;
  245. case 'b': /* Busy signal */
  246. p->fr.frametype = AST_FRAME_CONTROL;
  247. p->fr.subclass = AST_CONTROL_BUSY;
  248. return &p->fr;
  249. case 'o': /* Overrun */
  250. ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
  251. if (ast_modem_send(p, "\0x10E", 2))
  252. ast_log(LOG_WARNING, "Unable to flush buffers\n");
  253. return &p->fr;
  254. case CHAR_ETX: /* End Transmission */
  255. return NULL;
  256. case 'u': /* Underrun */
  257. ast_log(LOG_WARNING, "Data underrun\n");
  258. /* Fall Through */
  259. case 'd': /* Dialtone */
  260. case 'c': /* Calling Tone */
  261. case 'e': /* European version */
  262. case 'a': /* Answer Tone */
  263. case 'f': /* Bell Answer Tone */
  264. case 'T': /* Timing mark */
  265. case 't': /* Handset off hook */
  266. case 'h': /* Handset hungup */
  267. /* Ignore */
  268. if (option_debug)
  269. ast_log(LOG_DEBUG, "Ignoring Escaped character '%c' (%d)\n", esc, esc);
  270. return &p->fr;
  271. case '0':
  272. case '1':
  273. case '2':
  274. case '3':
  275. case '4':
  276. case '5':
  277. case '6':
  278. case '7':
  279. case '8':
  280. case '9':
  281. case '*':
  282. case '#':
  283. ast_log(LOG_DEBUG, "Detected outband DTMF digit: '%c' (%d)\n", esc, esc);
  284. p->fr.frametype=AST_FRAME_DTMF;
  285. p->fr.subclass=esc;
  286. return &p->fr;
  287. case 0: /* Pseudo signal */
  288. return &p->fr;
  289. default:
  290. ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc);
  291. }
  292. return &p->fr;
  293. }
  294. static struct ast_frame *i4l_read(struct ast_modem_pvt *p)
  295. {
  296. char result[256];
  297. short *b;
  298. struct ast_frame *f=NULL;
  299. int res;
  300. int x;
  301. if (p->ministate == STATE_COMMAND) {
  302. /* Read the first two bytes, first, in case it's a control message */
  303. res = read(p->fd, result, 2);
  304. if (res < 2) {
  305. // short read, means there was a hangup?
  306. // (or is this also possible without hangup?)
  307. // Anyway, reading from unitialized buffers is a bad idea anytime.
  308. if (errno == EAGAIN)
  309. return i4l_handle_escape(p, 0);
  310. return NULL;
  311. }
  312. if (result[0] == CHAR_DLE) {
  313. return i4l_handle_escape(p, result[1]);
  314. } else {
  315. if ((result[0] == '\n') || (result[0] == '\r'))
  316. return i4l_handle_escape(p, 0);
  317. /* Read the rest of the line */
  318. fgets(result + 2, sizeof(result) - 2, p->f);
  319. ast_modem_trim(result);
  320. if (!strcasecmp(result, "VCON")) {
  321. /* If we're in immediate mode, reply now */
  322. // if (p->mode == MODEM_MODE_IMMEDIATE)
  323. return i4l_handle_escape(p, 'X');
  324. } else
  325. if (!strcasecmp(result, "BUSY")) {
  326. /* Same as a busy signal */
  327. return i4l_handle_escape(p, 'b');
  328. } else
  329. if (!strncasecmp(result, "CALLER NUMBER: ", 15 )) {
  330. strncpy(p->cid, result + 15, sizeof(p->cid)-1);
  331. return i4l_handle_escape(p, 0);
  332. } else
  333. if (!strcasecmp(result, "RINGING")) {
  334. if (option_verbose > 2)
  335. ast_verbose(VERBOSE_PREFIX_3 "%s is ringing...\n", p->dev);
  336. return i4l_handle_escape(p, 'I');
  337. } else
  338. if (!strncasecmp(result, "RUNG", 4)) {
  339. /* PM2002: the line was hung up before we picked it up, bye bye */
  340. if (option_verbose > 2)
  341. ast_verbose(VERBOSE_PREFIX_3 "%s was hung up on before we answered\n", p->dev);
  342. return NULL;
  343. } else
  344. if (!strncasecmp(result, "RING", 4)) {
  345. if (result[4]=='/')
  346. strncpy(p->dnid, result + 5, sizeof(p->dnid)-1);
  347. return i4l_handle_escape(p, 'R');
  348. } else
  349. if (!strcasecmp(result, "NO CARRIER")) {
  350. if (option_verbose > 2)
  351. ast_verbose(VERBOSE_PREFIX_3 "%s hung up on\n", p->dev);
  352. return NULL;
  353. } else
  354. if (!strcasecmp(result, "NO DIALTONE")) {
  355. /* There's no dialtone, so the line isn't working */
  356. ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
  357. return NULL;
  358. }
  359. if (option_debug)
  360. ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
  361. return i4l_handle_escape(p, 0);
  362. }
  363. } else {
  364. /* We have to be more efficient in voice mode */
  365. b = (short *)(p->obuf + p->obuflen);
  366. while (p->obuflen/2 < 240) {
  367. /* Read ahead the full amount */
  368. res = read(p->fd, result, 240 - p->obuflen/2);
  369. if (res < 1) {
  370. /* If there's nothing there, just continue on */
  371. if (errno == EAGAIN)
  372. return i4l_handle_escape(p, 0);
  373. ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
  374. return NULL;
  375. }
  376. for (x=0;x<res;x++) {
  377. /* Process all the bytes that we've read */
  378. switch(result[x]) {
  379. case CHAR_DLE:
  380. #if 0
  381. ast_log(LOG_DEBUG, "Ooh, an escape at %d...\n", x);
  382. #endif
  383. if (!p->escape) {
  384. /* Note that next value is
  385. an escape, and continue. */
  386. p->escape++;
  387. break;
  388. } else {
  389. /* Send as is -- fallthrough */
  390. p->escape = 0;
  391. }
  392. default:
  393. if (p->escape) {
  394. ast_log(LOG_DEBUG, "Value of escape is %c (%d)...\n", result[x] < 32 ? '^' : result[x], result[x]);
  395. p->escape = 0;
  396. if (f)
  397. ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
  398. f = i4l_handle_escape(p, result[x]);
  399. /* If i4l_handle_escape says NULL, say it now, doesn't matter
  400. what else is there, the connection is dead. */
  401. if (!f)
  402. return NULL;
  403. } else {
  404. *(b++) = ALAW2INT(result[x] & 0xff);
  405. p->obuflen += 2;
  406. }
  407. }
  408. }
  409. if (f)
  410. break;
  411. }
  412. if (f) {
  413. if( ! (!(p->dtmfmode & MODEM_DTMF_I4L) && f->frametype == AST_FRAME_DTMF))
  414. return f;
  415. }
  416. /* If we get here, we have a complete voice frame */
  417. p->fr.frametype = AST_FRAME_VOICE;
  418. p->fr.subclass = AST_FORMAT_SLINEAR;
  419. p->fr.samples = 240;
  420. p->fr.data = p->obuf;
  421. p->fr.datalen = p->obuflen;
  422. p->fr.mallocd = 0;
  423. p->fr.delivery.tv_sec = 0;
  424. p->fr.delivery.tv_usec = 0;
  425. p->fr.offset = AST_FRIENDLY_OFFSET;
  426. p->fr.src = __FUNCTION__;
  427. p->obuflen = 0;
  428. /* process with dsp */
  429. if (p->dsp) {
  430. f = ast_dsp_process(p->owner, p->dsp, &p->fr);
  431. if (f && (f->frametype == AST_FRAME_DTMF)) {
  432. ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c on %s\n", f->subclass, p->dev);
  433. return f;
  434. }
  435. }
  436. return &p->fr;
  437. }
  438. return NULL;
  439. }
  440. static int i4l_write(struct ast_modem_pvt *p, struct ast_frame *f)
  441. {
  442. #define MAX_WRITE_SIZE 2048
  443. unsigned char result[MAX_WRITE_SIZE << 1];
  444. unsigned char b;
  445. int bpos=0, x;
  446. int res;
  447. if (f->datalen > MAX_WRITE_SIZE) {
  448. ast_log(LOG_WARNING, "Discarding too big frame of size %d\n", f->datalen);
  449. return -1;
  450. }
  451. if (f->frametype != AST_FRAME_VOICE) {
  452. ast_log(LOG_WARNING, "Don't know how to handle %d type frames\n", f->frametype);
  453. return -1;
  454. }
  455. if (f->subclass != AST_FORMAT_SLINEAR) {
  456. ast_log(LOG_WARNING, "Don't know how to handle anything but signed linear frames\n");
  457. return -1;
  458. }
  459. for (x=0;x<f->datalen/2;x++) {
  460. b = INT2ALAW(((short *)f->data)[x]);
  461. result[bpos++] = b;
  462. if (b == CHAR_DLE)
  463. result[bpos++]=b;
  464. }
  465. #if 0
  466. res = fwrite(result, bpos, 1, p->f);
  467. res *= bpos;
  468. #else
  469. res = write(p->fd, result, bpos);
  470. #endif
  471. if (res < 1) {
  472. if (errno != EAGAIN) {
  473. ast_log(LOG_WARNING, "Failed to write buffer\n");
  474. return -1;
  475. }
  476. }
  477. #if 0
  478. printf("Result of write is %d\n", res);
  479. #endif
  480. return 0;
  481. }
  482. static char *i4l_identify(struct ast_modem_pvt *p)
  483. {
  484. return strdup("Linux ISDN");
  485. }
  486. static void i4l_incusecnt(void)
  487. {
  488. ast_mutex_lock(&usecnt_lock);
  489. usecnt++;
  490. ast_mutex_unlock(&usecnt_lock);
  491. ast_update_use_count();
  492. }
  493. static void i4l_decusecnt(void)
  494. {
  495. ast_mutex_lock(&usecnt_lock);
  496. usecnt++;
  497. ast_mutex_unlock(&usecnt_lock);
  498. ast_update_use_count();
  499. }
  500. static int i4l_answer(struct ast_modem_pvt *p)
  501. {
  502. if (ast_modem_send(p, "ATA\r", 4) ||
  503. ast_modem_expect(p, "VCON", 10)) {
  504. ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
  505. return -1;
  506. }
  507. #if 1
  508. if (ast_modem_send(p, "AT+VDD=0,8", 0) ||
  509. ast_modem_expect(p, "OK", 5)) {
  510. ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
  511. return -1;
  512. }
  513. #endif
  514. if (ast_modem_send(p, "AT+VTX+VRX", 0) ||
  515. ast_modem_expect(p, "CONNECT", 10)) {
  516. ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
  517. return -1;
  518. }
  519. p->ministate = STATE_VOICE;
  520. /* let ast dsp detect dtmf */
  521. if (p->dtmfmode & MODEM_DTMF_AST) {
  522. if (p->dsp) {
  523. ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev);
  524. } else {
  525. p->dsp = ast_dsp_new();
  526. if (p->dsp) {
  527. ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev);
  528. ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT);
  529. ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0);
  530. }
  531. }
  532. }
  533. return 0;
  534. }
  535. static int i4l_dialdigit(struct ast_modem_pvt *p, char digit)
  536. {
  537. char c[2];
  538. if (p->ministate == STATE_VOICE) {
  539. if (p->dtmfmodegen & MODEM_DTMF_I4L) {
  540. c[0] = CHAR_DLE;
  541. c[1] = digit;
  542. write(p->fd, c, 2);
  543. ast_log(LOG_DEBUG, "Send ISDN out-of-band DTMF %c\n",digit);
  544. }
  545. if(p->dtmfmodegen & MODEM_DTMF_AST) {
  546. ast_log(LOG_DEBUG, "Generating inband DTMF\n");
  547. return -1;
  548. }
  549. } else
  550. ast_log(LOG_DEBUG, "Asked to send digit but call not up on %s\n", p->dev);
  551. return 0;
  552. }
  553. static int i4l_dial(struct ast_modem_pvt *p, char *stuff)
  554. {
  555. char cmd[80];
  556. char tmp[255];
  557. char tmpmsn[255];
  558. char *name, *num;
  559. struct ast_channel *c = p->owner;
  560. // Find callerid number first, to set the correct A number
  561. if (c && c->callerid && ! c->restrictcid) {
  562. ast_log(LOG_DEBUG, "Finding callerid from %s...\n",c->callerid);
  563. strncpy(tmp, c->callerid, sizeof(tmp) - 1);
  564. ast_callerid_parse(tmp, &name, &num);
  565. if (num) {
  566. ast_shrink_phone_number(num);
  567. snprintf(tmpmsn, sizeof(tmpmsn), ",%s,", num);
  568. if(strlen(p->outgoingmsn) && strstr(p->outgoingmsn,tmpmsn) != NULL) {
  569. // Tell ISDN4Linux to use this as A number
  570. snprintf(cmd, sizeof(cmd), "AT&E%s\n", num);
  571. if (ast_modem_send(p, cmd, strlen(cmd))) {
  572. ast_log(LOG_WARNING, "Unable to set A number to %s\n",num);
  573. }
  574. } else {
  575. ast_log(LOG_WARNING, "Outgoing MSN %s not allowed (see outgoingmsn=%s in modem.conf)\n",num,p->outgoingmsn);
  576. }
  577. }
  578. }
  579. snprintf(cmd, sizeof(cmd), "ATD%c %s\n", p->dialtype,stuff);
  580. if (ast_modem_send(p, cmd, strlen(cmd))) {
  581. ast_log(LOG_WARNING, "Unable to dial\n");
  582. return -1;
  583. }
  584. return 0;
  585. }
  586. static int i4l_hangup(struct ast_modem_pvt *p)
  587. {
  588. char dummy[50];
  589. int dtr = TIOCM_DTR;
  590. /* free the memory used by the DSP */
  591. if (p->dsp) {
  592. ast_dsp_free(p->dsp);
  593. p->dsp = NULL;
  594. }
  595. /* down DTR to hangup modem */
  596. ioctl(p->fd, TIOCMBIC, &dtr);
  597. /* Read anything outstanding */
  598. while(read(p->fd, dummy, sizeof(dummy)) > 0);
  599. /* rise DTR to re-enable line */
  600. ioctl(p->fd, TIOCMBIS, &dtr);
  601. /* Read anything outstanding */
  602. while(read(p->fd, dummy, sizeof(dummy)) > 0);
  603. /* basically we're done, just to be sure */
  604. write(p->fd, "\n\n", 2);
  605. read(p->fd, dummy, sizeof(dummy));
  606. if (ast_modem_send(p, "ATH", 0)) {
  607. ast_log(LOG_WARNING, "Unable to hang up\n");
  608. return -1;
  609. }
  610. if (ast_modem_expect(p, "OK", 5)) {
  611. ast_log(LOG_WARNING, "Final 'OK' not received\n");
  612. return -1;
  613. }
  614. return 0;
  615. }
  616. static struct ast_modem_driver i4l_driver =
  617. {
  618. "i4l",
  619. i4l_idents,
  620. AST_FORMAT_SLINEAR,
  621. 0, /* Not full duplex */
  622. i4l_incusecnt, /* incusecnt */
  623. i4l_decusecnt, /* decusecnt */
  624. i4l_identify, /* identify */
  625. i4l_init, /* init */
  626. i4l_setdev, /* setdev */
  627. i4l_read,
  628. i4l_write,
  629. i4l_dial, /* dial */
  630. i4l_answer, /* answer */
  631. i4l_hangup, /* hangup */
  632. i4l_startrec, /* start record */
  633. NULL, /* stop record */
  634. NULL, /* start playback */
  635. NULL, /* stop playback */
  636. NULL, /* set silence supression */
  637. i4l_dialdigit, /* dialdigit */
  638. };
  639. int usecount(void)
  640. {
  641. int res;
  642. ast_mutex_lock(&usecnt_lock);
  643. res = usecnt;
  644. ast_mutex_unlock(&usecnt_lock);
  645. return res;
  646. }
  647. int load_module(void)
  648. {
  649. return ast_register_modem_driver(&i4l_driver);
  650. }
  651. int unload_module(void)
  652. {
  653. return ast_unregister_modem_driver(&i4l_driver);
  654. }
  655. char *description()
  656. {
  657. return desc;
  658. }
  659. char *key()
  660. {
  661. return ASTERISK_GPL_KEY;
  662. }