2007-04-15 19:39:49 +00:00
|
|
|
/*
|
|
|
|
* An implementation of Common ISDN API 2.0 for Asterisk
|
|
|
|
*
|
2009-01-17 17:35:55 +00:00
|
|
|
* Copyright (C) 2006-2009 Cytronics & Melware
|
2007-04-15 19:39:49 +00:00
|
|
|
*
|
|
|
|
* Armin Schindler <armin@melware.de>
|
|
|
|
*
|
2007-04-19 20:24:15 +00:00
|
|
|
* capi_sendf() by Eicon Networks / Dialogic
|
|
|
|
*
|
2007-04-15 19:39:49 +00:00
|
|
|
* This program is free software and may be modified and
|
|
|
|
* distributed under the terms of the GNU Public License.
|
|
|
|
*/
|
|
|
|
|
2005-08-30 11:21:58 +00:00
|
|
|
#include <stdio.h>
|
2007-04-17 21:04:42 +00:00
|
|
|
#include <stdlib.h>
|
2007-04-29 22:28:30 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2009-07-20 11:03:49 +00:00
|
|
|
#include <string.h>
|
2011-02-04 17:18:05 +00:00
|
|
|
#include <ctype.h>
|
2007-04-29 22:28:30 +00:00
|
|
|
#include <sys/types.h>
|
2009-03-12 15:56:20 +00:00
|
|
|
#include "chan_capi_platform.h"
|
2007-04-29 22:28:30 +00:00
|
|
|
#include "xlaw.h"
|
2007-04-15 19:39:49 +00:00
|
|
|
#include "chan_capi20.h"
|
|
|
|
#include "chan_capi.h"
|
2007-04-29 22:28:30 +00:00
|
|
|
#include "chan_capi_rtp.h"
|
2007-04-15 19:39:49 +00:00
|
|
|
#include "chan_capi_utils.h"
|
2007-04-15 20:29:12 +00:00
|
|
|
#include "chan_capi_supplementary.h"
|
2010-06-30 08:33:41 +00:00
|
|
|
|
2010-04-08 22:10:54 +00:00
|
|
|
#ifdef DIVA_STREAMING
|
|
|
|
#include "platform.h"
|
|
|
|
#include "diva_streaming_result.h"
|
|
|
|
#include "diva_streaming_messages.h"
|
|
|
|
#include "diva_streaming_vector.h"
|
|
|
|
#include "diva_streaming_manager.h"
|
2010-06-30 08:33:41 +00:00
|
|
|
#include "chan_capi_divastreaming_utils.h"
|
2010-04-08 22:10:54 +00:00
|
|
|
#endif
|
2010-10-25 21:21:31 +00:00
|
|
|
#ifdef DIVA_STATUS
|
|
|
|
#include "divastatus_ifc.h"
|
|
|
|
#define CC_HW_STATE_OK(__x__) ((pbx_capi_get_controller((__x__)) == NULL) || \
|
|
|
|
(pbx_capi_get_controller((__x__))->hwState != (int)DivaStatusHardwareStateERROR))
|
|
|
|
#else
|
|
|
|
#define CC_HW_STATE_OK(__x__) (1)
|
|
|
|
#endif
|
2007-04-15 20:29:12 +00:00
|
|
|
|
|
|
|
int capidebug = 0;
|
|
|
|
char *emptyid = "\0";
|
|
|
|
|
|
|
|
AST_MUTEX_DEFINE_STATIC(verbose_lock);
|
|
|
|
AST_MUTEX_DEFINE_STATIC(messagenumber_lock);
|
|
|
|
AST_MUTEX_DEFINE_STATIC(capi_put_lock);
|
2007-04-22 10:03:52 +00:00
|
|
|
AST_MUTEX_DEFINE_STATIC(peerlink_lock);
|
2007-04-28 16:48:00 +00:00
|
|
|
AST_MUTEX_DEFINE_STATIC(nullif_lock);
|
2007-04-15 20:29:12 +00:00
|
|
|
|
|
|
|
static _cword capi_MessageNumber;
|
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
static struct capi_pvt *nulliflist = NULL;
|
2007-05-12 18:21:13 +00:00
|
|
|
static int controller_nullplcis[CAPI_MAX_CONTROLLERS];
|
2007-04-28 16:48:00 +00:00
|
|
|
|
2007-04-17 21:04:42 +00:00
|
|
|
#define CAPI_MAX_PEERLINKCHANNELS 32
|
2007-04-22 10:03:52 +00:00
|
|
|
static struct peerlink_s {
|
|
|
|
struct ast_channel *channel;
|
|
|
|
time_t age;
|
|
|
|
} peerlinkchannel[CAPI_MAX_PEERLINKCHANNELS];
|
2007-04-17 21:04:42 +00:00
|
|
|
|
2007-04-15 20:29:12 +00:00
|
|
|
/*
|
2009-03-10 22:39:04 +00:00
|
|
|
* helper for <pbx>_verbose
|
2007-04-15 20:29:12 +00:00
|
|
|
*/
|
2009-03-10 22:39:04 +00:00
|
|
|
void cc_verbose_internal(char *text, ...)
|
2007-04-15 20:29:12 +00:00
|
|
|
{
|
|
|
|
char line[4096];
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, text);
|
|
|
|
vsnprintf(line, sizeof(line), text, ap);
|
|
|
|
va_end(ap);
|
2009-03-10 22:39:04 +00:00
|
|
|
line[sizeof(line)-1]=0;
|
2007-04-15 20:29:12 +00:00
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
#if 0
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
if ((fp = fopen("/tmp/cclog", "a")) != NULL) {
|
|
|
|
fprintf(fp, "%s", line);
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-03-10 22:39:04 +00:00
|
|
|
cc_mutex_lock(&verbose_lock);
|
2010-02-17 19:01:31 +00:00
|
|
|
cc_pbx_verbose("%s", line);
|
2009-03-10 22:39:04 +00:00
|
|
|
cc_mutex_unlock(&verbose_lock);
|
2007-04-15 20:29:12 +00:00
|
|
|
}
|
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
/*
|
|
|
|
* hangup and remove null-interface
|
|
|
|
*/
|
2007-05-08 16:30:03 +00:00
|
|
|
void capi_remove_nullif(struct capi_pvt *i)
|
2007-04-28 16:48:00 +00:00
|
|
|
{
|
|
|
|
struct capi_pvt *ii;
|
|
|
|
struct capi_pvt *tmp = NULL;
|
2007-05-08 16:30:03 +00:00
|
|
|
int state;
|
2007-04-28 16:48:00 +00:00
|
|
|
|
|
|
|
if (i->channeltype != CAPI_CHANNELTYPE_NULL) {
|
2007-05-08 16:30:03 +00:00
|
|
|
return;
|
2007-04-28 16:48:00 +00:00
|
|
|
}
|
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
cc_mutex_lock(&i->lock);
|
|
|
|
if (i->line_plci != 0) {
|
|
|
|
ii = i->line_plci;
|
|
|
|
i->line_plci = 0;
|
|
|
|
capi_remove_nullif(ii);
|
|
|
|
}
|
|
|
|
cc_mutex_unlock(&i->lock);
|
|
|
|
|
2007-05-08 16:30:03 +00:00
|
|
|
if (i->PLCI != 0) {
|
|
|
|
/* if the interface is in use, hangup first */
|
|
|
|
cc_mutex_lock(&i->lock);
|
|
|
|
state = i->state;
|
|
|
|
i->state = CAPI_STATE_DISCONNECTING;
|
|
|
|
capi_activehangup(i, state);
|
|
|
|
|
|
|
|
cc_mutex_unlock(&i->lock);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2007-05-01 14:26:39 +00:00
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
cc_mutex_lock(&nullif_lock);
|
|
|
|
ii = nulliflist;
|
|
|
|
while (ii) {
|
|
|
|
if (ii == i) {
|
|
|
|
if (!tmp) {
|
|
|
|
nulliflist = ii->next;
|
|
|
|
} else {
|
|
|
|
tmp->next = ii->next;
|
|
|
|
}
|
2007-05-13 11:30:34 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: removed null-interface from controller %d.\n",
|
|
|
|
i->vname, i->controller);
|
2011-11-16 21:43:04 +00:00
|
|
|
if (i->smoother) {
|
2007-04-29 22:28:30 +00:00
|
|
|
ast_smoother_free(i->smoother);
|
2011-11-16 21:43:04 +00:00
|
|
|
i->smoother = 0;
|
|
|
|
}
|
2007-05-08 16:30:03 +00:00
|
|
|
cc_mutex_destroy(&i->lock);
|
|
|
|
ast_cond_destroy(&i->event_trigger);
|
2007-05-12 18:21:13 +00:00
|
|
|
controller_nullplcis[i->controller - 1]--;
|
2010-08-19 08:44:21 +00:00
|
|
|
ast_free(i);
|
2007-04-28 16:48:00 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
tmp = ii;
|
|
|
|
ii = ii->next;
|
|
|
|
}
|
|
|
|
cc_mutex_unlock(&nullif_lock);
|
|
|
|
}
|
|
|
|
|
2009-04-15 12:28:40 +00:00
|
|
|
int capi_verify_resource_plci(const struct capi_pvt *i) {
|
|
|
|
const struct capi_pvt *ii;
|
|
|
|
|
|
|
|
cc_mutex_lock(&nullif_lock);
|
|
|
|
for (ii = nulliflist; ii != 0 && ii != i; ii = ii->next);
|
|
|
|
cc_mutex_unlock(&nullif_lock);
|
|
|
|
|
|
|
|
return ((ii == i) ? 0 : -1);
|
|
|
|
}
|
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
/*
|
|
|
|
* create new null-interface
|
|
|
|
*/
|
2008-03-23 13:04:30 +00:00
|
|
|
struct capi_pvt *capi_mknullif(struct ast_channel *c, unsigned long long controllermask)
|
2007-04-28 16:48:00 +00:00
|
|
|
{
|
|
|
|
struct capi_pvt *tmp;
|
2007-05-12 18:21:13 +00:00
|
|
|
unsigned int controller = 1;
|
|
|
|
int contrcount;
|
|
|
|
int channelcount = 0xffff;
|
2009-03-26 21:07:28 +00:00
|
|
|
int maxcontr = (CAPI_MAX_CONTROLLERS > (sizeof(controllermask)*8)) ?
|
|
|
|
(sizeof(controllermask)*8) : CAPI_MAX_CONTROLLERS;
|
2007-05-12 18:21:13 +00:00
|
|
|
|
2008-03-22 20:08:45 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi_mknullif: find controller for mask 0x%lx\n",
|
|
|
|
controllermask);
|
2007-05-12 18:21:13 +00:00
|
|
|
/* find the next controller of mask with least plcis used */
|
2008-03-23 13:04:30 +00:00
|
|
|
for (contrcount = 0; contrcount < maxcontr; contrcount++) {
|
2010-10-25 21:21:31 +00:00
|
|
|
if (((controllermask & (1ULL << contrcount)) != 0) && CC_HW_STATE_OK(contrcount + 1)) {
|
2007-05-12 18:21:13 +00:00
|
|
|
if (controller_nullplcis[contrcount] < channelcount) {
|
|
|
|
channelcount = controller_nullplcis[contrcount];
|
|
|
|
controller = contrcount + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-04-28 16:48:00 +00:00
|
|
|
|
2010-08-19 08:44:21 +00:00
|
|
|
tmp = ast_malloc(sizeof(struct capi_pvt));
|
2007-04-28 16:48:00 +00:00
|
|
|
if (!tmp) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(tmp, 0, sizeof(struct capi_pvt));
|
|
|
|
|
|
|
|
cc_mutex_init(&tmp->lock);
|
|
|
|
ast_cond_init(&tmp->event_trigger, NULL);
|
|
|
|
|
2010-11-24 17:08:11 +00:00
|
|
|
snprintf(tmp->name, sizeof(tmp->name) - 1, "%s-NULLPLCI", (c != 0) ? c->name : "BRIDGE");
|
2007-04-28 16:48:00 +00:00
|
|
|
snprintf(tmp->vname, sizeof(tmp->vname) - 1, "%s", tmp->name);
|
|
|
|
|
|
|
|
tmp->channeltype = CAPI_CHANNELTYPE_NULL;
|
|
|
|
|
2007-04-30 15:19:28 +00:00
|
|
|
tmp->used = c;
|
|
|
|
tmp->peer = c;
|
2010-12-14 16:28:18 +00:00
|
|
|
if (c == NULL)
|
|
|
|
tmp->virtualBridgePeer = 1;
|
2007-04-29 14:00:32 +00:00
|
|
|
|
2007-05-01 14:26:39 +00:00
|
|
|
tmp->cip = CAPI_CIPI_SPEECH;
|
|
|
|
tmp->transfercapability = PRI_TRANS_CAP_SPEECH;
|
2007-04-28 16:48:00 +00:00
|
|
|
tmp->controller = controller;
|
|
|
|
tmp->doEC = 1;
|
|
|
|
tmp->doEC_global = 1;
|
|
|
|
tmp->ecOption = EC_OPTION_DISABLE_NEVER;
|
|
|
|
tmp->ecTail = EC_DEFAULT_TAIL;
|
|
|
|
tmp->isdnmode = CAPI_ISDNMODE_MSN;
|
|
|
|
tmp->ecSelector = FACILITYSELECTOR_ECHO_CANCEL;
|
2007-04-30 15:19:28 +00:00
|
|
|
tmp->capability = capi_capability;
|
2007-05-12 12:31:58 +00:00
|
|
|
|
|
|
|
tmp->rxgain = 1.0;
|
|
|
|
tmp->txgain = 1.0;
|
2007-04-30 15:19:28 +00:00
|
|
|
capi_gains(&tmp->g, 1.0, 1.0);
|
2007-04-29 22:28:30 +00:00
|
|
|
|
2010-11-24 17:08:11 +00:00
|
|
|
if (c != 0) {
|
|
|
|
if (!(capi_create_reader_writer_pipe(tmp))) {
|
|
|
|
ast_free(tmp);
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-04-29 22:28:30 +00:00
|
|
|
}
|
2007-04-30 15:19:28 +00:00
|
|
|
|
|
|
|
tmp->bproto = CC_BPROTO_TRANSPARENT;
|
|
|
|
tmp->doB3 = CAPI_B3_DONT;
|
2007-04-29 22:28:30 +00:00
|
|
|
tmp->smoother = ast_smoother_new(CAPI_MAX_B3_BLOCK_SIZE);
|
2007-04-30 15:19:28 +00:00
|
|
|
tmp->isdnstate |= CAPI_ISDN_STATE_PBX;
|
2007-04-28 16:48:00 +00:00
|
|
|
|
|
|
|
cc_mutex_lock(&nullif_lock);
|
|
|
|
tmp->next = nulliflist; /* prepend */
|
|
|
|
nulliflist = tmp;
|
2007-05-12 18:21:13 +00:00
|
|
|
controller_nullplcis[tmp->controller - 1]++;
|
2007-04-28 16:48:00 +00:00
|
|
|
cc_mutex_unlock(&nullif_lock);
|
|
|
|
|
2007-04-30 15:19:28 +00:00
|
|
|
/* connect to driver */
|
2007-04-28 16:48:00 +00:00
|
|
|
tmp->outgoing = 1;
|
|
|
|
tmp->state = CAPI_STATE_CONNECTPENDING;
|
|
|
|
tmp->MessageNumber = get_capi_MessageNumber();
|
2007-05-01 14:26:39 +00:00
|
|
|
|
2010-08-23 12:14:03 +00:00
|
|
|
#ifdef DIVA_STREAMING
|
|
|
|
tmp->diva_stream_entry = 0;
|
|
|
|
if (pbx_capi_streaming_supported (tmp) != 0) {
|
|
|
|
capi_DivaStreamingOn(tmp, 1, tmp->MessageNumber);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-11-26 16:57:43 +00:00
|
|
|
if (c == NULL) {
|
|
|
|
cc_mutex_lock(&tmp->lock);
|
|
|
|
}
|
|
|
|
capi_sendf((c != NULL) ? NULL : tmp, c == NULL, CAPI_CONNECT_REQ, controller, tmp->MessageNumber,
|
2007-04-28 16:48:00 +00:00
|
|
|
"w()()()()(www()()()())()()()((wwbbb)()()())",
|
|
|
|
0, 1,1,0, 3,0,0,0,0);
|
2010-11-26 16:57:43 +00:00
|
|
|
if (c == NULL) {
|
|
|
|
cc_mutex_unlock(&tmp->lock);
|
|
|
|
if (tmp->PLCI == 0) {
|
|
|
|
cc_log(LOG_WARNING, "%s: failed to create\n", tmp->vname);
|
|
|
|
capi_remove_nullif(tmp);
|
|
|
|
tmp = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tmp != NULL) {
|
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: created null-interface on controller %d.\n",
|
|
|
|
tmp->vname, tmp->controller);
|
|
|
|
}
|
2007-04-30 15:19:28 +00:00
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
2010-10-09 08:29:39 +00:00
|
|
|
struct capi_pvt *capi_mkresourceif(
|
|
|
|
struct ast_channel *c,
|
|
|
|
unsigned long long controllermask,
|
|
|
|
struct capi_pvt *data_plci_ifc,
|
|
|
|
cc_format_t codecs,
|
|
|
|
int all)
|
|
|
|
{
|
2009-04-10 07:23:20 +00:00
|
|
|
struct capi_pvt *data_ifc /*, *line_ifc */;
|
2009-04-09 21:14:44 +00:00
|
|
|
unsigned int controller = 1;
|
2010-09-18 23:07:38 +00:00
|
|
|
int fmt = 0;
|
2009-04-09 21:14:44 +00:00
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
if (data_plci_ifc == 0) {
|
|
|
|
int contrcount;
|
|
|
|
int channelcount = 0xffff;
|
|
|
|
int maxcontr = (CAPI_MAX_CONTROLLERS > (sizeof(controllermask)*8)) ?
|
|
|
|
(sizeof(controllermask)*8) : CAPI_MAX_CONTROLLERS;
|
|
|
|
|
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "capi_mkresourceif: find controller for mask 0x%lx\n",
|
|
|
|
controllermask);
|
|
|
|
|
|
|
|
/* find the next controller of mask with least plcis used */
|
|
|
|
for (contrcount = 0; contrcount < maxcontr; contrcount++) {
|
2010-10-25 21:21:31 +00:00
|
|
|
if (((controllermask & (1ULL << contrcount)) != 0) && CC_HW_STATE_OK(contrcount + 1)) {
|
2009-04-14 21:58:03 +00:00
|
|
|
if (controller_nullplcis[contrcount] < channelcount) {
|
|
|
|
channelcount = controller_nullplcis[contrcount];
|
|
|
|
controller = contrcount + 1;
|
|
|
|
}
|
2009-04-09 21:14:44 +00:00
|
|
|
}
|
|
|
|
}
|
2009-04-14 21:58:03 +00:00
|
|
|
} else {
|
|
|
|
controller = data_plci_ifc->controller;
|
2010-09-20 11:05:58 +00:00
|
|
|
codecs = (all != 0) ? pbx_capi_get_controller_codecs (controller) : codecs;
|
2011-10-04 08:41:28 +00:00
|
|
|
fmt = pbx_capi_get_controller_codecs (controller) & codecs & cc_get_formats_as_bits(c->nativeformats);
|
2010-09-18 23:07:38 +00:00
|
|
|
if (fmt != 0)
|
2011-10-04 08:41:28 +00:00
|
|
|
fmt = cc_get_best_codec_as_bits(fmt);
|
2009-04-09 21:14:44 +00:00
|
|
|
}
|
|
|
|
|
2010-08-19 08:44:21 +00:00
|
|
|
data_ifc = ast_malloc(sizeof(struct capi_pvt));
|
2009-04-09 21:14:44 +00:00
|
|
|
if (data_ifc == 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(data_ifc, 0, sizeof(struct capi_pvt));
|
|
|
|
|
|
|
|
cc_mutex_init(&data_ifc->lock);
|
|
|
|
ast_cond_init(&data_ifc->event_trigger, NULL);
|
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
snprintf(data_ifc->name, sizeof(data_ifc->name) - 1, "%s-%sPLCI", c->name, (data_plci_ifc == 0) ? "DATA" : "LINE");
|
2009-04-09 21:14:44 +00:00
|
|
|
snprintf(data_ifc->vname, sizeof(data_ifc->vname) - 1, "%s", data_ifc->name);
|
|
|
|
|
|
|
|
data_ifc->channeltype = CAPI_CHANNELTYPE_NULL;
|
2009-04-14 21:58:03 +00:00
|
|
|
data_ifc->resource_plci_type = (data_plci_ifc == 0) ? CAPI_RESOURCE_PLCI_DATA : CAPI_RESOURCE_PLCI_LINE;
|
2009-04-09 21:14:44 +00:00
|
|
|
|
|
|
|
data_ifc->used = c;
|
|
|
|
data_ifc->peer = c;
|
|
|
|
|
|
|
|
data_ifc->cip = CAPI_CIPI_SPEECH;
|
|
|
|
data_ifc->transfercapability = PRI_TRANS_CAP_SPEECH;
|
|
|
|
data_ifc->controller = controller;
|
|
|
|
data_ifc->doEC = 1;
|
|
|
|
data_ifc->doEC_global = 1;
|
|
|
|
data_ifc->ecOption = EC_OPTION_DISABLE_NEVER;
|
|
|
|
data_ifc->ecTail = EC_DEFAULT_TAIL;
|
|
|
|
data_ifc->isdnmode = CAPI_ISDNMODE_MSN;
|
|
|
|
data_ifc->ecSelector = FACILITYSELECTOR_ECHO_CANCEL;
|
2010-09-18 23:07:38 +00:00
|
|
|
data_ifc->capability = (fmt != 0 && data_plci_ifc != 0) ? fmt : capi_capability;
|
|
|
|
data_ifc->codec = (fmt != 0 && data_plci_ifc != 0) ? fmt : data_ifc->codec;
|
2009-04-09 21:14:44 +00:00
|
|
|
|
|
|
|
data_ifc->rxgain = 1.0;
|
|
|
|
data_ifc->txgain = 1.0;
|
|
|
|
capi_gains(&data_ifc->g, 1.0, 1.0);
|
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
if (data_plci_ifc == 0) {
|
|
|
|
if (!(capi_create_reader_writer_pipe(data_ifc))) {
|
2010-08-19 08:44:21 +00:00
|
|
|
ast_free(data_ifc);
|
2009-04-14 21:58:03 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
data_ifc->readerfd = -1;
|
|
|
|
data_ifc->writerfd = -1;
|
2009-04-09 21:14:44 +00:00
|
|
|
}
|
|
|
|
|
2010-09-18 23:07:38 +00:00
|
|
|
data_ifc->bproto = (fmt != 0 && data_plci_ifc != 0) ? CC_BPROTO_VOCODER : CC_BPROTO_TRANSPARENT;
|
2009-04-09 21:14:44 +00:00
|
|
|
data_ifc->doB3 = CAPI_B3_DONT;
|
|
|
|
data_ifc->smoother = ast_smoother_new(CAPI_MAX_B3_BLOCK_SIZE);
|
|
|
|
data_ifc->isdnstate |= CAPI_ISDN_STATE_PBX;
|
|
|
|
|
|
|
|
cc_mutex_lock(&nullif_lock);
|
|
|
|
data_ifc->next = nulliflist; /* prepend */
|
|
|
|
nulliflist = data_ifc;
|
|
|
|
controller_nullplcis[data_ifc->controller - 1]++;
|
|
|
|
cc_mutex_unlock(&nullif_lock);
|
|
|
|
|
|
|
|
/* connect to driver */
|
|
|
|
data_ifc->outgoing = 1;
|
|
|
|
data_ifc->state = CAPI_STATE_CONNECTPENDING;
|
|
|
|
data_ifc->MessageNumber = get_capi_MessageNumber();
|
|
|
|
|
2009-04-10 18:59:18 +00:00
|
|
|
cc_mutex_lock(&data_ifc->lock);
|
2010-08-23 15:21:52 +00:00
|
|
|
|
|
|
|
#ifdef DIVA_STREAMING
|
|
|
|
data_ifc->diva_stream_entry = 0;
|
|
|
|
if (data_plci_ifc == 0) {
|
|
|
|
capi_DivaStreamingStreamNotUsed(data_ifc, 1, data_ifc->MessageNumber);
|
|
|
|
} else {
|
|
|
|
if (pbx_capi_streaming_supported (data_ifc) != 0) {
|
|
|
|
capi_DivaStreamingOn(data_ifc, 1, data_ifc->MessageNumber);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-04-10 18:59:18 +00:00
|
|
|
capi_sendf(data_ifc,
|
|
|
|
1,
|
2009-04-10 07:23:20 +00:00
|
|
|
CAPI_MANUFACTURER_REQ,
|
|
|
|
controller,
|
|
|
|
data_ifc->MessageNumber,
|
2010-09-18 23:07:38 +00:00
|
|
|
"dw(wbb(wwws()()()))",
|
2009-04-10 07:23:20 +00:00
|
|
|
_DI_MANU_ID,
|
|
|
|
_DI_ASSIGN_PLCI,
|
2009-04-14 21:58:03 +00:00
|
|
|
(data_plci_ifc == 0) ? 4 : 5, /* data */
|
|
|
|
(data_plci_ifc == 0) ? 0 : (unsigned char)(data_plci_ifc->PLCI >> 8), /* bchannel */
|
2009-04-10 07:23:20 +00:00
|
|
|
1, /* connect */
|
2010-09-18 23:07:38 +00:00
|
|
|
(data_ifc->bproto == CC_BPROTO_VOCODER) ? 0x1f : 1, 1, 0,
|
|
|
|
diva_get_b1_conf(data_ifc));
|
2009-04-10 18:59:18 +00:00
|
|
|
cc_mutex_unlock(&data_ifc->lock);
|
2009-04-09 21:14:44 +00:00
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
if (data_plci_ifc != 0) {
|
|
|
|
if (data_ifc->PLCI == 0) {
|
|
|
|
cc_log(LOG_WARNING, "%s: failed to create\n", data_ifc->vname);
|
|
|
|
capi_remove_nullif(data_ifc);
|
|
|
|
data_ifc = 0;
|
|
|
|
} else {
|
|
|
|
cc_mutex_lock(&data_plci_ifc->lock);
|
|
|
|
data_plci_ifc->line_plci = data_ifc;
|
|
|
|
capi_sendf(data_plci_ifc, 1, CAPI_FACILITY_REQ, data_plci_ifc->PLCI, get_capi_MessageNumber(),
|
|
|
|
"w(w(d()))",
|
|
|
|
FACILITYSELECTOR_LINE_INTERCONNECT,
|
|
|
|
0x0001, /* CONNECT */
|
|
|
|
0x00000000 /* mask */
|
|
|
|
);
|
|
|
|
cc_mutex_unlock(&data_plci_ifc->lock);
|
|
|
|
|
|
|
|
data_ifc->data_plci = data_plci_ifc;
|
|
|
|
|
|
|
|
data_ifc->writerfd = data_plci_ifc->writerfd;
|
|
|
|
data_plci_ifc->writerfd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data_ifc != 0) {
|
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_4 "%s: created %s-resource-interface on controller %d.\n",
|
|
|
|
data_ifc->vname, (data_plci_ifc == 0) ? "data" : "line", data_ifc->controller);
|
|
|
|
}
|
2009-04-09 21:14:44 +00:00
|
|
|
|
2009-04-10 07:23:20 +00:00
|
|
|
return data_ifc;
|
2009-04-09 21:14:44 +00:00
|
|
|
}
|
|
|
|
|
2007-04-15 20:29:12 +00:00
|
|
|
/*
|
2007-04-30 15:19:28 +00:00
|
|
|
* get a new capi message number atomically
|
2007-04-15 20:29:12 +00:00
|
|
|
*/
|
|
|
|
_cword get_capi_MessageNumber(void)
|
|
|
|
{
|
|
|
|
_cword mn;
|
|
|
|
|
|
|
|
cc_mutex_lock(&messagenumber_lock);
|
|
|
|
|
|
|
|
capi_MessageNumber++;
|
|
|
|
if (capi_MessageNumber == 0) {
|
|
|
|
/* avoid zero */
|
|
|
|
capi_MessageNumber = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
mn = capi_MessageNumber;
|
|
|
|
|
|
|
|
cc_mutex_unlock(&messagenumber_lock);
|
|
|
|
|
2009-04-10 07:23:20 +00:00
|
|
|
return mn;
|
2007-04-15 20:29:12 +00:00
|
|
|
}
|
|
|
|
|
2007-04-19 20:24:15 +00:00
|
|
|
/*
|
2007-04-19 20:31:42 +00:00
|
|
|
* find the interface (pvt) the PLCI belongs to
|
|
|
|
*/
|
2007-04-29 22:28:30 +00:00
|
|
|
struct capi_pvt *capi_find_interface_by_plci(unsigned int plci)
|
2007-04-19 20:31:42 +00:00
|
|
|
{
|
|
|
|
struct capi_pvt *i;
|
|
|
|
|
2009-03-12 15:56:20 +00:00
|
|
|
if (unlikely(plci == 0))
|
2007-04-19 20:31:42 +00:00
|
|
|
return NULL;
|
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
for (i = capi_iflist; i; i = i->next) {
|
2007-04-28 16:48:00 +00:00
|
|
|
if (i->PLCI == plci)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc_mutex_lock(&nullif_lock);
|
|
|
|
for (i = nulliflist; i; i = i->next) {
|
2007-04-19 20:31:42 +00:00
|
|
|
if (i->PLCI == plci)
|
|
|
|
break;
|
|
|
|
}
|
2007-04-28 16:48:00 +00:00
|
|
|
cc_mutex_unlock(&nullif_lock);
|
2007-04-19 20:31:42 +00:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* find the interface (pvt) the messagenumber belongs to
|
|
|
|
*/
|
2007-04-29 22:28:30 +00:00
|
|
|
struct capi_pvt *capi_find_interface_by_msgnum(unsigned short msgnum)
|
2007-04-19 20:31:42 +00:00
|
|
|
{
|
|
|
|
struct capi_pvt *i;
|
|
|
|
|
|
|
|
if (msgnum == 0x0000)
|
|
|
|
return NULL;
|
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
for (i = capi_iflist; i; i = i->next) {
|
2007-04-28 16:48:00 +00:00
|
|
|
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc_mutex_lock(&nullif_lock);
|
|
|
|
for (i = nulliflist; i; i = i->next) {
|
|
|
|
if ((i->PLCI == 0) && (i->MessageNumber == msgnum))
|
2007-04-19 20:31:42 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-04-28 16:48:00 +00:00
|
|
|
cc_mutex_unlock(&nullif_lock);
|
2007-04-19 20:31:42 +00:00
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2007-04-20 08:17:29 +00:00
|
|
|
/*
|
|
|
|
* wait for a specific message
|
|
|
|
*/
|
|
|
|
MESSAGE_EXCHANGE_ERROR capi_wait_conf(struct capi_pvt *i, unsigned short wCmd)
|
|
|
|
{
|
|
|
|
MESSAGE_EXCHANGE_ERROR error = 0;
|
|
|
|
struct timespec abstime;
|
|
|
|
unsigned char command, subcommand;
|
|
|
|
|
|
|
|
subcommand = wCmd & 0xff;
|
|
|
|
command = (wCmd & 0xff00) >> 8;
|
|
|
|
i->waitevent = (unsigned int)wCmd;
|
|
|
|
abstime.tv_sec = time(NULL) + 2;
|
|
|
|
abstime.tv_nsec = 0;
|
|
|
|
cc_verbose(4, 1, "%s: wait for %s (0x%x)\n",
|
|
|
|
i->vname, capi_cmd2str(command, subcommand), i->waitevent);
|
|
|
|
if (ast_cond_timedwait(&i->event_trigger, &i->lock, &abstime) != 0) {
|
|
|
|
error = -1;
|
|
|
|
cc_log(LOG_WARNING, "%s: timed out waiting for %s\n",
|
|
|
|
i->vname, capi_cmd2str(command, subcommand));
|
|
|
|
} else {
|
|
|
|
cc_verbose(4, 1, "%s: cond signal received for %s\n",
|
|
|
|
i->vname, capi_cmd2str(command, subcommand));
|
|
|
|
}
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2007-04-19 20:31:42 +00:00
|
|
|
/*
|
2007-04-28 16:48:00 +00:00
|
|
|
* log an error in sending capi message
|
2007-04-19 20:24:15 +00:00
|
|
|
*/
|
2009-03-26 22:08:33 +00:00
|
|
|
static void log_capi_error_message(MESSAGE_EXCHANGE_ERROR err, unsigned char* msg)
|
2007-04-19 20:24:15 +00:00
|
|
|
{
|
|
|
|
if (err) {
|
2009-03-26 22:08:33 +00:00
|
|
|
_cmsg _CMSG, *CMSG = &_CMSG;
|
|
|
|
|
|
|
|
capi_message2cmsg(CMSG, msg);
|
2007-04-19 20:24:15 +00:00
|
|
|
cc_log(LOG_ERROR, "CAPI error sending %s (NCCI=%#x) (error=%#x %s)\n",
|
|
|
|
capi_cmsg2str(CMSG), (unsigned int)HEADER_CID(CMSG),
|
|
|
|
err, capi_info_string((unsigned int)err));
|
2007-04-28 16:48:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* log verbose a capi message
|
|
|
|
*/
|
|
|
|
static void log_capi_message(_cmsg *CMSG)
|
|
|
|
{
|
|
|
|
unsigned short wCmd;
|
|
|
|
|
|
|
|
wCmd = HEADER_CMD(CMSG);
|
|
|
|
if ((wCmd == CAPI_P_REQ(DATA_B3)) ||
|
|
|
|
(wCmd == CAPI_P_RESP(DATA_B3))) {
|
|
|
|
cc_verbose(7, 1, "%s\n", capi_cmsg2str(CMSG));
|
2007-04-19 20:24:15 +00:00
|
|
|
} else {
|
2007-04-28 16:48:00 +00:00
|
|
|
cc_verbose(4, 1, "%s\n", capi_cmsg2str(CMSG));
|
2007-04-19 20:24:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-15 20:29:12 +00:00
|
|
|
/*
|
|
|
|
* write a capi message to capi device
|
|
|
|
*/
|
2007-04-28 20:59:44 +00:00
|
|
|
static MESSAGE_EXCHANGE_ERROR _capi_put_msg(unsigned char *msg)
|
2007-04-19 20:24:15 +00:00
|
|
|
{
|
|
|
|
MESSAGE_EXCHANGE_ERROR error;
|
|
|
|
_cmsg CMSG;
|
|
|
|
|
|
|
|
if (cc_mutex_lock(&capi_put_lock)) {
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_log(LOG_WARNING, "Unable to lock chan_capi put!\n");
|
2007-04-19 20:24:15 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2009-03-11 09:13:03 +00:00
|
|
|
if (cc_verbose_check(4, 1) != 0) {
|
|
|
|
capi_message2cmsg(&CMSG, msg);
|
|
|
|
log_capi_message(&CMSG);
|
|
|
|
}
|
2007-04-19 20:24:15 +00:00
|
|
|
|
2007-04-23 22:18:36 +00:00
|
|
|
error = capi20_put_message(capi_ApplID, msg);
|
2007-04-19 20:24:15 +00:00
|
|
|
|
|
|
|
if (cc_mutex_unlock(&capi_put_lock)) {
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_log(LOG_WARNING, "Unable to unlock chan_capi put!\n");
|
2007-04-19 20:24:15 +00:00
|
|
|
return -1;
|
2007-04-15 20:29:12 +00:00
|
|
|
}
|
|
|
|
|
2009-03-26 22:08:33 +00:00
|
|
|
log_capi_error_message(error, msg);
|
2007-04-19 20:24:15 +00:00
|
|
|
|
2007-04-15 20:29:12 +00:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* wait some time for a new capi message
|
|
|
|
*/
|
|
|
|
MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG)
|
|
|
|
{
|
|
|
|
MESSAGE_EXCHANGE_ERROR Info;
|
|
|
|
struct timeval tv;
|
|
|
|
|
2007-04-23 18:47:49 +00:00
|
|
|
tv.tv_sec = 0;
|
2010-04-08 22:10:54 +00:00
|
|
|
#ifdef DIVA_STREAMING
|
|
|
|
tv.tv_usec = 5000;
|
|
|
|
#else
|
2007-04-23 18:47:49 +00:00
|
|
|
tv.tv_usec = 500000;
|
2010-04-08 22:10:54 +00:00
|
|
|
#endif
|
2007-04-15 20:29:12 +00:00
|
|
|
|
2007-04-23 18:47:49 +00:00
|
|
|
Info = capi20_waitformessage(capi_ApplID, &tv);
|
2007-04-15 20:29:12 +00:00
|
|
|
|
2007-04-23 18:47:49 +00:00
|
|
|
if (Info == 0x0000) {
|
2007-04-15 20:29:12 +00:00
|
|
|
|
2007-04-23 18:47:49 +00:00
|
|
|
Info = capi_get_cmsg(CMSG, capi_ApplID);
|
2007-04-15 20:29:12 +00:00
|
|
|
|
2007-04-23 18:47:49 +00:00
|
|
|
#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2)
|
2007-05-12 10:23:08 +00:00
|
|
|
if (Info == 0x0000) {
|
2007-04-23 18:47:49 +00:00
|
|
|
/*
|
|
|
|
* For BSD allow controller 0:
|
|
|
|
*/
|
|
|
|
if ((HEADER_CID(CMSG) & 0xFF) == 0) {
|
|
|
|
HEADER_CID(CMSG) += capi_num_controllers;
|
|
|
|
}
|
|
|
|
}
|
2007-05-12 10:23:08 +00:00
|
|
|
#endif
|
2007-04-15 20:29:12 +00:00
|
|
|
}
|
2007-04-23 18:47:49 +00:00
|
|
|
|
2007-04-15 20:29:12 +00:00
|
|
|
if ((Info != 0x0000) && (Info != 0x1104)) {
|
|
|
|
if (capidebug) {
|
|
|
|
cc_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Info;
|
|
|
|
}
|
2005-08-30 11:21:58 +00:00
|
|
|
|
2007-04-19 20:24:15 +00:00
|
|
|
/*
|
|
|
|
* Eicon's capi_sendf() function to create capi messages easily
|
|
|
|
* and send this message.
|
|
|
|
* Copyright by Eicon Networks / Dialogic
|
|
|
|
*/
|
|
|
|
MESSAGE_EXCHANGE_ERROR capi_sendf(
|
2007-04-20 08:17:29 +00:00
|
|
|
struct capi_pvt *capii, int waitconf,
|
2007-04-19 20:24:15 +00:00
|
|
|
_cword command, _cdword Id, _cword Number, char * format, ...)
|
|
|
|
{
|
|
|
|
MESSAGE_EXCHANGE_ERROR ret;
|
|
|
|
int i, j;
|
|
|
|
unsigned int d;
|
|
|
|
unsigned char *p, *p_length;
|
|
|
|
unsigned char *string;
|
2007-08-23 13:30:05 +00:00
|
|
|
unsigned short header_length;
|
2007-04-19 20:24:15 +00:00
|
|
|
va_list ap;
|
|
|
|
capi_prestruct_t *s;
|
|
|
|
unsigned char msg[2048];
|
|
|
|
|
|
|
|
write_capi_word(&msg[2], capi_ApplID);
|
2008-02-20 10:15:59 +00:00
|
|
|
msg[4] = (unsigned char)((command >> 8) & 0xff);
|
|
|
|
msg[5] = (unsigned char)(command & 0xff);
|
2007-04-19 20:24:15 +00:00
|
|
|
write_capi_word(&msg[6], Number);
|
|
|
|
write_capi_dword(&msg[8], Id);
|
|
|
|
|
|
|
|
p = &msg[12];
|
|
|
|
p_length = 0;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
for (i = 0; format[i]; i++) {
|
2009-03-12 15:56:20 +00:00
|
|
|
if (unlikely(((p - (&msg[0])) + 12) >= sizeof(msg))) {
|
2007-04-19 20:24:15 +00:00
|
|
|
cc_log(LOG_ERROR, "capi_sendf: message too big (%d)\n",
|
2009-02-09 18:28:16 +00:00
|
|
|
(int)(p - (&msg[0])));
|
2007-04-19 20:24:15 +00:00
|
|
|
return 0x1004;
|
|
|
|
}
|
|
|
|
switch(format[i]) {
|
|
|
|
case 'b': /* byte */
|
|
|
|
d = (unsigned char)va_arg(ap, unsigned int);
|
|
|
|
*(p++) = (unsigned char) d;
|
|
|
|
break;
|
|
|
|
case 'w': /* word (2 bytes) */
|
|
|
|
d = (unsigned short)va_arg(ap, unsigned int);
|
|
|
|
*(p++) = (unsigned char) d;
|
|
|
|
*(p++) = (unsigned char)(d >> 8);
|
|
|
|
break;
|
|
|
|
case 'd': /* double word (4 bytes) */
|
|
|
|
d = va_arg(ap, unsigned int);
|
|
|
|
*(p++) = (unsigned char) d;
|
|
|
|
*(p++) = (unsigned char)(d >> 8);
|
|
|
|
*(p++) = (unsigned char)(d >> 16);
|
|
|
|
*(p++) = (unsigned char)(d >> 24);
|
|
|
|
break;
|
|
|
|
case 's': /* struct, length is the first byte */
|
|
|
|
string = va_arg(ap, unsigned char *);
|
2007-04-24 20:21:04 +00:00
|
|
|
if (string == NULL) {
|
|
|
|
*(p++) = 0;
|
|
|
|
} else {
|
|
|
|
for (j = 0; j <= string[0]; j++)
|
|
|
|
*(p++) = string[j];
|
|
|
|
}
|
2007-04-19 20:24:15 +00:00
|
|
|
break;
|
|
|
|
case 'a': /* ascii string, NULL terminated string */
|
|
|
|
string = va_arg(ap, unsigned char *);
|
|
|
|
for (j = 0; string[j] != '\0'; j++)
|
|
|
|
*(++p) = string[j];
|
|
|
|
*((p++)-j) = (unsigned char) j;
|
|
|
|
break;
|
|
|
|
case 'c': /* predefined capi_prestruct_t */
|
|
|
|
s = va_arg(ap, capi_prestruct_t *);
|
|
|
|
if (s->wLen < 0xff) {
|
|
|
|
*(p++) = (unsigned char)(s->wLen);
|
|
|
|
} else {
|
|
|
|
*(p++) = 0xff;
|
|
|
|
*(p++) = (unsigned char)(s->wLen);
|
|
|
|
*(p++) = (unsigned char)(s->wLen >> 8);
|
|
|
|
}
|
|
|
|
for (j = 0; j < s->wLen; j++)
|
|
|
|
*(p++) = s->info[j];
|
|
|
|
break;
|
|
|
|
case '(': /* begin of a structure */
|
|
|
|
*p = (p_length) ? p - p_length : 0;
|
|
|
|
p_length = p++;
|
|
|
|
break;
|
|
|
|
case ')': /* end of structure */
|
|
|
|
if (p_length) {
|
|
|
|
j = *p_length;
|
|
|
|
*p_length = (unsigned char)((p - p_length) - 1);
|
|
|
|
p_length = (j != 0) ? p_length - j : 0;
|
|
|
|
} else {
|
|
|
|
cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n",
|
|
|
|
format);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cc_log(LOG_ERROR, "capi_sendf: unknown format \"%s\"\n",
|
|
|
|
format);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
if (p_length) {
|
|
|
|
cc_log(LOG_ERROR, "capi_sendf: inconsistent format \"%s\"\n", format);
|
|
|
|
}
|
2007-08-23 13:30:05 +00:00
|
|
|
|
|
|
|
header_length = (unsigned short)(p - (&msg[0]));
|
|
|
|
|
|
|
|
if ((sizeof(void *) > 4) && (command == CAPI_DATA_B3_REQ)) {
|
|
|
|
void* req_data;
|
|
|
|
va_start(ap, format);
|
|
|
|
req_data = va_arg(ap, void *);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
header_length += 8;
|
|
|
|
write_capi_dword(&msg[12], 0);
|
|
|
|
memcpy(&msg[22], &req_data, sizeof(void *));
|
|
|
|
}
|
|
|
|
|
|
|
|
write_capi_word(&msg[0], header_length);
|
2007-04-19 20:24:15 +00:00
|
|
|
|
|
|
|
ret = _capi_put_msg(&msg[0]);
|
2007-04-20 08:17:29 +00:00
|
|
|
if ((!(ret)) && (waitconf)) {
|
|
|
|
ret = capi_wait_conf(capii, (command & 0xff00) | CAPI_CONF);
|
|
|
|
}
|
2007-04-19 20:24:15 +00:00
|
|
|
|
2009-04-10 07:23:20 +00:00
|
|
|
return ret;
|
2007-04-19 20:24:15 +00:00
|
|
|
}
|
|
|
|
|
2005-08-30 11:21:58 +00:00
|
|
|
/*
|
|
|
|
* decode capi 2.0 info word
|
|
|
|
*/
|
|
|
|
char *capi_info_string(unsigned int info)
|
|
|
|
{
|
|
|
|
switch (info) {
|
|
|
|
/* informative values (corresponding message was processed) */
|
|
|
|
case 0x0001:
|
|
|
|
return "NCPI not supported by current protocol, NCPI ignored";
|
|
|
|
case 0x0002:
|
|
|
|
return "Flags not supported by current protocol, flags ignored";
|
|
|
|
case 0x0003:
|
|
|
|
return "Alert already sent by another application";
|
|
|
|
|
|
|
|
/* error information concerning CAPI_REGISTER */
|
|
|
|
case 0x1001:
|
|
|
|
return "Too many applications";
|
|
|
|
case 0x1002:
|
|
|
|
return "Logical block size to small, must be at least 128 Bytes";
|
|
|
|
case 0x1003:
|
|