mISDN/drivers/isdn/hardware/mISDN/contr.c

788 lines
20 KiB
C

/* $Id$
*
*/
#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include "m_capi.h"
#include "helper.h"
#include "debug.h"
#define contrDebug(contr, lev, fmt, args...) \
if (contr->debug & lev) capidebug(lev, fmt, ## args)
void
ControllerDestr(Controller_t *contr)
{
mISDNinstance_t *inst = &contr->inst;
struct list_head *item, *next;
u_long flags;
spin_lock_irqsave(&contr->list_lock, flags);
list_for_each_safe(item, next, &contr->Applications) {
ApplicationDestr(list_entry(item, Application_t, head), 3);
}
if (contr->plcis) {
Plci_t *plci = contr->plcis;
int i;
for (i = 0; i < contr->maxplci; i++) {
AppPlci_t *aplci;
if (test_bit(PLCI_STATE_ACTIV, &plci->state)) {
if (plci->nAppl) {
printk(KERN_ERR "%s: PLCI(%x) still busy (%d)\n",
__FUNCTION__, plci->addr, plci->nAppl);
list_for_each_safe(item, next, &plci->AppPlcis) {
aplci = (AppPlci_t *)item;
aplci->contr = NULL;
plciDetachAppPlci(plci, aplci);
AppPlciDestr(aplci);
}
}
}
plci++;
}
kfree(contr->plcis);
contr->plcis = NULL;
}
list_for_each_safe(item, next, &contr->SSProcesse) {
SSProcessDestr(list_entry(item, SSProcess_t, head));
}
#ifdef OLDCAPI_DRIVER_INTERFACE
if (contr->ctrl)
cdrv_if->detach_ctr(contr->ctrl);
#else
if (contr->ctrl) {
detach_capi_ctr(contr->ctrl);
kfree(contr->ctrl);
}
#endif
contr->ctrl = NULL;
#ifdef FIXME
if (inst->up.peer) {
inst->up.peer->obj->ctrl(inst->up.peer,
MGR_DISCONNECT | REQUEST, &inst->up);
}
if (inst->down.peer) {
inst->down.peer->obj->ctrl(inst->down.peer,
MGR_DISCONNECT | REQUEST, &inst->down);
}
#endif
list_for_each_safe(item, next, &contr->linklist) {
PLInst_t *plink = list_entry(item, PLInst_t, list);
list_del(&plink->list);
kfree(plink);
}
if (contr->entity != MISDN_ENTITY_NONE)
inst->obj->ctrl(inst, MGR_DELENTITY | REQUEST, (void *)contr->entity);
inst->obj->ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
list_del(&contr->list);
spin_unlock_irqrestore(&contr->list_lock, flags);
kfree(contr);
}
void
ControllerRun(Controller_t *contr)
{
PLInst_t *plink;
int ret;
if (contr->inst.st && contr->inst.st->mgr)
sprintf(contr->ctrl->manu, "mISDN CAPI controller %s", contr->inst.st->mgr->name);
else
sprintf(contr->ctrl->manu, "mISDN CAPI");
strncpy(contr->ctrl->serial, "0002", CAPI_SERIAL_LEN);
contr->ctrl->version.majorversion = 2;
contr->ctrl->version.minorversion = 0;
contr->ctrl->version.majormanuversion = 1;
contr->ctrl->version.minormanuversion = 0;
memset(&contr->ctrl->profile, 0, sizeof(struct capi_profile));
contr->ctrl->profile.ncontroller = 1;
contr->ctrl->profile.nbchannel = contr->nr_bc;
contrDebug(contr, CAPI_DBG_INFO, "%s: %s version(%s)",
__FUNCTION__, contr->ctrl->manu, contr->ctrl->serial);
// FIXME
ret = contr->inst.obj->ctrl(contr->inst.st, MGR_GLOBALOPT | REQUEST, &contr->ctrl->profile.goptions);
if (ret) {
/* Fallback on error, minimum set */
contr->ctrl->profile.goptions = GLOBALOPT_INTERNAL_CTRL;
}
/* add options we allways know about FIXME: DTMF */
contr->ctrl->profile.goptions |= GLOBALOPT_DTMF |
GLOBALOPT_SUPPLEMENTARY_SERVICE;
if (contr->nr_bc) {
mISDN_pid_t pidmask;
memset(&pidmask, 0, sizeof(mISDN_pid_t));
pidmask.protocol[1] = 0x03ff;
pidmask.protocol[2] = 0x1fff;
pidmask.protocol[3] = 0x00ff;
if (list_empty(&contr->linklist)) {
int_error();
ret = -EINVAL;
} else {
plink = list_entry(contr->linklist.next, PLInst_t, list);
ret = plink->inst.obj->ctrl(plink->st, MGR_EVALSTACK | REQUEST, &pidmask);
}
if (ret) {
/* Fallback on error, minimum set */
int_error();
contr->ctrl->profile.support1 = 3; // HDLC, TRANS
contr->ctrl->profile.support2 = 3; // X75SLP, TRANS
contr->ctrl->profile.support3 = 1; // TRANS
} else {
contr->ctrl->profile.support1 = pidmask.protocol[1];
contr->ctrl->profile.support2 = pidmask.protocol[2];
contr->ctrl->profile.support3 = pidmask.protocol[3];
}
}
contrDebug(contr, CAPI_DBG_INFO, "%s: GLOBAL(%08X) B1(%08X) B2(%08X) B3(%08X)",
__FUNCTION__, contr->ctrl->profile.goptions, contr->ctrl->profile.support1,
contr->ctrl->profile.support2, contr->ctrl->profile.support2);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->ready(contr->ctrl);
#else
capi_ctr_ready(contr->ctrl);
#endif
}
Application_t
*getApplication4Id(Controller_t *contr, __u16 ApplId)
{
struct list_head *item;
Application_t *ap = NULL;
list_for_each(item, &contr->Applications) {
ap = (Application_t *)item;
if (ap->ApplId == ApplId)
break;
ap = NULL;
}
return(ap);
}
Plci_t
*getPlci4Addr(Controller_t *contr, __u32 addr)
{
int i = (addr >> 8) & 0xff;
if ((i < 1) || (i > contr->maxplci)) {
int_error();
return(NULL);
}
return(&contr->plcis[i - 1]);
}
static void
RegisterApplication(struct capi_ctr *ctrl, __u16 ApplId, capi_register_params *rp)
{
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
u_long flags;
int ret;
contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x)", __FUNCTION__, ApplId);
appl = getApplication4Id(contr, ApplId);
if (appl) {
int_error();
return;
}
spin_lock_irqsave(&contr->list_lock, flags);
ret = ApplicationConstr(contr, ApplId, rp);
spin_unlock_irqrestore(&contr->list_lock, flags);
if (ret) {
int_error();
return;
}
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->appl_registered(contr->ctrl, ApplId);
#endif
}
static void
ReleaseApplication(struct capi_ctr *ctrl, __u16 ApplId)
{
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
u_long flags;
contrDebug(contr, CAPI_DBG_APPL, "%s: ApplId(%x) caller:%lx", __FUNCTION__, ApplId, __builtin_return_address(0));
spin_lock_irqsave(&contr->list_lock, flags);
appl = getApplication4Id(contr, ApplId);
if (!appl) {
spin_unlock_irqrestore(&contr->list_lock, flags);
int_error();
return;
}
ApplicationDestr(appl, 1);
spin_unlock_irqrestore(&contr->list_lock, flags);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->appl_released(contr->ctrl, ApplId);
#endif
}
#ifdef OLDCAPI_DRIVER_INTERFACE
static void
#else
static u16
#endif
SendMessage(struct capi_ctr *ctrl, struct sk_buff *skb)
{
Controller_t *contr = ctrl->driverdata;
Application_t *appl;
int ApplId;
int err = CAPI_NOERROR;
u16 cmd;
AppPlci_t *aplci;
Ncci_t *ncci;
mISDN_head_t *hh = mISDN_HEAD_P(skb);
ApplId = CAPIMSG_APPID(skb->data);
appl = getApplication4Id(contr, ApplId);
if (!appl) {
int_error();
err = CAPI_ILLAPPNR;
goto end;
}
hh->prim = CAPI_MESSAGE_REQUEST;
hh->dinfo = ApplId;
cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
contrDebug(contr, CAPI_DBG_CONTR_MSG, "SendMessage: %s caddr(%x)",
capi_cmd2str(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data)),
CAPIMSG_CONTROL(skb->data));
switch (cmd) {
// for NCCI state machine
case CAPI_DATA_B3_REQ:
case CAPI_DATA_B3_RESP:
case CAPI_CONNECT_B3_RESP:
case CAPI_CONNECT_B3_ACTIVE_RESP:
case CAPI_DISCONNECT_B3_REQ:
case CAPI_RESET_B3_REQ:
case CAPI_RESET_B3_RESP:
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
if (!aplci) {
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
dev_kfree_skb(skb);
break;
}
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
if ((!ncci) || (!ncci->link)) {
int_error();
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
dev_kfree_skb(skb);
break;
}
err = mISDN_queue_message(&ncci->link->inst, 0, skb);
if (err) {
int_errtxt("mISDN_queue_message return(%d)", err);
err = CAPI_MSGBUSY;
}
break;
// new NCCI
case CAPI_CONNECT_B3_REQ:
// maybe already down NCCI
case CAPI_DISCONNECT_B3_RESP:
// for PLCI state machine
case CAPI_INFO_REQ:
case CAPI_ALERT_REQ:
case CAPI_CONNECT_RESP:
case CAPI_CONNECT_ACTIVE_RESP:
case CAPI_DISCONNECT_REQ:
case CAPI_DISCONNECT_RESP:
case CAPI_SELECT_B_PROTOCOL_REQ:
// for LISTEN state machine
case CAPI_LISTEN_REQ:
// other
case CAPI_FACILITY_REQ:
case CAPI_MANUFACTURER_REQ:
case CAPI_INFO_RESP:
err = mISDN_queue_message(&contr->inst, 0, skb);
if (err) {
int_errtxt("mISDN_queue_message return(%d)", err);
err = CAPI_MSGBUSY;
}
break;
/* need not further action currently, so it can be released here too avoid
* overlap with a release application
*/
case CAPI_FACILITY_RESP:
dev_kfree_skb(skb);
break;
default:
contrDebug(contr, CAPI_DBG_WARN, "SendMessage: %#x %#x not handled!",
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
err = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
break;
}
end:
#ifndef OLDCAPI_DRIVER_INTERFACE
return(err);
#endif
}
static int
LoadFirmware(struct capi_ctr *ctrl, capiloaddata *data)
{
Controller_t *contr = ctrl->driverdata;
struct firm {
int len;
void *data;
} firm;
int retval;
firm.len = data->firmware.len;
if (data->firmware.user) {
firm.data = vmalloc(data->firmware.len);
if (!firm.data)
return(-ENOMEM);
retval = copy_from_user(firm.data, data->firmware.data, data->firmware.len);
if (retval) {
vfree(firm.data);
return(retval);
}
} else
firm.data = data;
contr->inst.obj->ctrl(contr->inst.st, MGR_LOADFIRM | REQUEST, &firm);
if (data->firmware.user)
vfree(firm.data);
return(0);
}
static char *
procinfo(struct capi_ctr *ctrl)
{
Controller_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & contr->debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
if (!contr)
return "";
sprintf(contr->infobuf, "-");
return contr->infobuf;
}
static int
read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
{
int len = 0;
len += sprintf(page+len, "mISDN_read_proc\n");
if (off+count >= len)
*eof = 1;
if (len < off)
return 0;
*start = page + off;
return ((count < len-off) ? count : len-off);
};
static void
ResetController(struct capi_ctr *ctrl)
{
Controller_t *contr = ctrl->driverdata;
struct list_head *item, *next;
u_long flags;
spin_lock_irqsave(&contr->list_lock, flags);
list_for_each_safe(item, next, &contr->Applications) {
ApplicationDestr((Application_t *)item, 2);
}
list_for_each_safe(item, next, &contr->SSProcesse) {
SSProcessDestr((SSProcess_t *)item);
}
spin_unlock_irqrestore(&contr->list_lock, flags);
#ifdef OLDCAPI_DRIVER_INTERFACE
contr->ctrl->reseted(contr->ctrl);
#else
capi_ctr_reseted(contr->ctrl);
#endif
}
#ifdef OLDCAPI_DRIVER_INTERFACE
static void
Remove_Controller(struct capi_ctr *ctrl)
{
Controller_t *contr = ctrl->driverdata;
if (CAPI_DBG_INFO & contr->debug)
printk(KERN_DEBUG "%s\n", __FUNCTION__);
}
struct capi_driver mISDN_driver = {
"mISDN",
"0.01",
LoadFirmware,
ResetController,
Remove_Controller,
RegisterApplication,
ReleaseApplication,
SendMessage,
procinfo,
read_proc,
0,
0,
};
#endif
void
ControllerD2Trace(Controller_t *contr, u_char *buf, int len)
{
struct list_head *item;
list_for_each(item, &contr->Applications) {
applD2Trace((Application_t *)item, buf, len);
}
}
static __inline__ Plci_t *
getPlci4L3id(Controller_t *contr, u_int l3id)
{
Plci_t *plci = contr->plcis;
int i;
for (i = 0; i < contr->maxplci; i++) {
if (test_bit(PLCI_STATE_ACTIV, &plci->state) &&
(plci->l3id == l3id))
return(plci);
plci++;
}
return(NULL);
}
int
ControllerNewPlci(Controller_t *contr, Plci_t **plci_p, u_int l3id)
{
int i;
Plci_t *plci = contr->plcis;
for (i = 0; i < contr->maxplci; i++) {
if (!test_and_set_bit(PLCI_STATE_ACTIV, &plci->state))
break;
plci++;
}
if (i == contr->maxplci) {
contrDebug(contr, CAPI_DBG_PLCI, "%s: no free PLCI",
__FUNCTION__);
return(-EBUSY); //FIXME
}
*plci_p = plci;
if (l3id == MISDN_ID_ANY) {
if (contr->entity == MISDN_ENTITY_NONE) {
printk(KERN_ERR "mISDN %s: no ENTITY id\n",
__FUNCTION__);
test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state);
return(-EINVAL); //FIXME
}
plci->l3id = (contr->entity << 16) | plci->addr;
} else {
plci = getPlci4L3id(contr, l3id);
if (plci) {
printk(KERN_WARNING "mISDN %s: PLCI(%x) allready has l3id(%x)\n",
__FUNCTION__, plci->addr, l3id);
test_and_clear_bit(PLCI_STATE_ACTIV, &(*plci_p)->state);
return(-EBUSY);
}
plci = *plci_p;
plci->l3id = l3id;
}
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p,%d) id(%x)",
__FUNCTION__, plci->addr, plci, sizeof(*plci), plci->l3id);
return(0);
}
int
ControllerReleasePlci(Plci_t *plci)
{
if (!plci->contr) {
int_error();
return(-EINVAL);
}
if (plci->nAppl) {
contrDebug(plci->contr, CAPI_DBG_PLCI, "%s: PLCI(%x) still has %d Applications",
__FUNCTION__, plci->addr, plci->nAppl);
return(-EBUSY);
}
if (!list_empty(&plci->AppPlcis)) {
int_errtxt("PLCI(%x) AppPlcis list not empty", plci->addr);
return(-EBUSY);
}
test_and_clear_bit(PLCI_STATE_ALERTING, &plci->state);
test_and_clear_bit(PLCI_STATE_OUTGOING, &plci->state);
plci->l3id = MISDN_ID_NONE;
if (!test_and_clear_bit(PLCI_STATE_ACTIV, &plci->state))
int_errtxt("PLCI(%x) was not activ", plci->addr);
return(0);
}
void
ControllerAddSSProcess(Controller_t *contr, SSProcess_t *sp)
{
u_long flags;
INIT_LIST_HEAD(&sp->head);
sp->contr = contr;
sp->addr = contr->addr;
spin_lock_irqsave(&contr->list_lock, flags);
contr->LastInvokeId++;
sp->invokeId = contr->LastInvokeId;
list_add(&sp->head, &contr->SSProcesse);
spin_unlock_irqrestore(&contr->list_lock, flags);
}
SSProcess_t
*getSSProcess4Id(Controller_t *contr, __u16 id)
{
struct list_head *item;
SSProcess_t *sp = NULL;
list_for_each(item, &contr->SSProcesse) {
sp = (SSProcess_t *)item;
if (sp->invokeId == id)
break;
sp = NULL;
}
return(sp);
}
static int
Controller_function(mISDNinstance_t *inst, struct sk_buff *skb)
{
Controller_t *contr;
Plci_t *plci;
int ret = -EINVAL;
mISDN_head_t *hh;
hh = mISDN_HEAD_P(skb);
contr = inst->privat;
contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: prim(%x) id(%x)",
__FUNCTION__, hh->prim, hh->dinfo);
if (hh->prim == CAPI_MESSAGE_REQUEST) {
Application_t *appl = getApplication4Id(contr, hh->dinfo);
if (!appl) {
int_error();
return(ret);
}
ApplicationSendMessage(appl, skb);
return(0);
} else if (hh->prim == (CC_NEW_CR | INDICATION)) {
ret = ControllerNewPlci(contr, &plci, hh->dinfo);
if(!ret)
dev_kfree_skb(skb);
} else if (hh->dinfo == MISDN_ID_DUMMY) {
ret = Supplementary_l3l4(contr, hh->prim, skb);
} else {
if (!(plci = getPlci4L3id(contr, hh->dinfo))) {
contrDebug(contr, CAPI_DBG_WARN, "%s: unknown plci prim(%x) id(%x)",
__FUNCTION__, hh->prim, hh->dinfo);
return(-ENODEV);
}
contrDebug(contr, CAPI_DBG_PLCI, "%s: PLCI(%x) plci(%p)", __FUNCTION__, plci->addr, plci);
ret = plci_l3l4(plci, hh->prim, skb);
}
return(ret);
}
int
ControllerL4L3(Controller_t *contr, u_int prim, int dinfo, struct sk_buff *skb)
{
return(mISDN_queuedown_newhead(&contr->inst, 0, prim, dinfo, skb));
}
void
ControllerPutStatus(Controller_t *contr, char *msg)
{
contrDebug(contr, CAPI_DBG_CONTR, "%s: %s", __FUNCTION__, msg);
}
int
ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *ocapi)
{
struct list_head *head;
Controller_t *contr;
int retval;
mISDNstack_t *cst;
PLInst_t *plink;
if (!st)
return(-EINVAL);
if (list_empty(&st->childlist)) {
if ((st->id & FLG_CLONE_STACK) &&
(st->childlist.prev != &st->childlist)) {
head = st->childlist.prev;
} else {
printk(KERN_ERR "%s: invalid empty childlist (no clone) stid(%x) childlist(%p<-%p->%p)\n",
__FUNCTION__, st->id, st->childlist.prev, &st->childlist, st->childlist.next);
return(-EINVAL);
}
} else
head = &st->childlist;
if (!pid)
return(-EINVAL);
contr = kmalloc(sizeof(Controller_t), GFP_KERNEL);
if (!contr)
return(-ENOMEM);
memset(contr, 0, sizeof(Controller_t));
INIT_LIST_HEAD(&contr->Applications);
INIT_LIST_HEAD(&contr->SSProcesse);
INIT_LIST_HEAD(&contr->linklist);
spin_lock_init(&contr->list_lock);
spin_lock_init(&contr->id_lock);
contr->next_id = 1;
memcpy(&contr->inst.pid, pid, sizeof(mISDN_pid_t));
#ifndef OLDCAPI_DRIVER_INTERFACE
if (!(contr->ctrl = kmalloc(sizeof(struct capi_ctr), GFP_KERNEL))) {
printk(KERN_ERR "no mem for contr->ctrl\n");
int_error();
ControllerDestr(contr);
return -ENOMEM;
}
memset(contr->ctrl, 0, sizeof(struct capi_ctr));
#endif
list_for_each_entry(cst, head, list)
contr->nr_bc++;
if (!contr->nr_bc) {
printk(KERN_ERR "no bchannels\n");
ControllerDestr(contr);
return(-EINVAL); // FIXME
}
if (contr->nr_bc <= 2)
contr->maxplci = CAPI_MAXPLCI_BRI;
else if (contr->nr_bc <= 8)
contr->maxplci = contr->nr_bc * 2 + 4;
else
contr->maxplci = CAPI_MAXPLCI_PRI;
contr->plcis = kmalloc(contr->maxplci*sizeof(Plci_t), GFP_KERNEL);
if (!contr->plcis) {
printk(KERN_ERR "no mem for contr->plcis\n");
int_error();
contr->maxplci = 0;
ControllerDestr(contr);
return -ENOMEM;
}
contr->addr = (st->id >> 8) & 0xff;
sprintf(contr->inst.name, "CAPI %d", contr->addr);
mISDN_init_instance(&contr->inst, ocapi, contr, Controller_function);
if (!mISDN_SetHandledPID(ocapi, &contr->inst.pid)) {
int_error();
ControllerDestr(contr);
return(-ENOPROTOOPT);
}
list_for_each_entry(cst, head, list) {
if (!(plink = kmalloc(sizeof(PLInst_t), GFP_KERNEL))) {
printk(KERN_ERR "no mem for PLinst\n");
int_error();
ControllerDestr(contr);
return -ENOMEM;
}
memset(plink, 0, sizeof(PLInst_t));
plink->st = cst;
plink->inst.st = cst;
mISDN_init_instance(&plink->inst, ocapi, plink, NULL);
plink->inst.pid.layermask |= ISDN_LAYER(4);
// plink->inst.down.stat = IF_NOACTIV;
list_add_tail(&plink->list, &contr->linklist);
}
list_add_tail(&contr->list, &ocapi->ilist);
contr->entity = MISDN_ENTITY_NONE;
retval = ocapi->ctrl(&contr->inst, MGR_NEWENTITY | REQUEST, NULL);
if (retval) {
printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
__FUNCTION__, retval);
}
retval = 0;
#ifdef OLDCAPI_DRIVER_INTERFACE
{
char tmp[10];
sprintf(tmp, "mISDN%d", (st->id >> 8) & 0xff);
contr->ctrl = cdrv_if->attach_ctr(&mISDN_driver, tmp, contr);
if (!contr->ctrl)
retval = -ENODEV;
}
#else
contr->ctrl->owner = THIS_MODULE;
sprintf(contr->ctrl->name, "mISDN%d", contr->addr);
contr->ctrl->driver_name = "mISDN";
contr->ctrl->driverdata = contr;
contr->ctrl->register_appl = RegisterApplication;
contr->ctrl->release_appl = ReleaseApplication;
contr->ctrl->send_message = SendMessage;
contr->ctrl->load_firmware = LoadFirmware;
contr->ctrl->reset_ctr = ResetController;
contr->ctrl->procinfo = procinfo;
contr->ctrl->ctr_read_proc = read_proc;
retval = attach_capi_ctr(contr->ctrl);
#endif
if (!retval) {
printk(KERN_DEBUG "contr->addr(%02x) cnr(%02x) st(%08x)\n",
contr->addr, contr->ctrl->cnr, st->id);
contr->addr = contr->ctrl->cnr;
plciInit(contr);
ocapi->ctrl(st, MGR_REGLAYER | INDICATION, &contr->inst);
// contr->inst.up.stat = IF_DOWN;
*contr_p = contr;
} else {
ControllerDestr(contr);
}
return retval;
}
PLInst_t *
ControllerSelChannel(Controller_t *contr, u_int channel)
{
mISDNstack_t *cst;
PLInst_t *plink;
channel_info_t ci;
int ret;
if (list_empty(&contr->linklist)) {
int_errtxt("no linklist for controller(%x)", contr->addr);
return(NULL);
}
ci.channel = channel;
ci.st.p = NULL;
ret = contr->inst.obj->ctrl(contr->inst.st, MGR_SELCHANNEL | REQUEST, &ci);
if (ret) {
int_errtxt("MGR_SELCHANNEL ret(%d)", ret);
return(NULL);
}
cst = ci.st.p;
list_for_each_entry(plink, &contr->linklist, list) {
if (cst == plink->st)
return(plink);
}
return(NULL);
}
int
ControllerNextId(Controller_t *contr)
{
u_long flags;
int id;
spin_lock_irqsave(&contr->id_lock, flags);
id = contr->next_id++;
if (id == 0x7fff)
contr->next_id = 1;
spin_unlock_irqrestore(&contr->id_lock, flags);
id |= (contr->entity << 16);
return(id);
}
#if 0
static void
d2_listener(struct IsdnCardState *cs, u_char *buf, int len)
{
Controller_t *contr = cs->contr;
if (!contr) {
int_error();
return;
}
ControllerD2Trace(contr, buf, len);
}
#endif