676 lines
16 KiB
C
676 lines
16 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((Application_t *)item, 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((SSProcess_t *)item);
|
|
}
|
|
#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;
|
|
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);
|
|
}
|
|
while (contr->binst) {
|
|
BInst_t *binst = contr->binst;
|
|
REMOVE_FROM_LISTBASE(binst, contr->binst);
|
|
kfree(binst);
|
|
}
|
|
if (contr->entity != MISDN_ENTITY_NONE)
|
|
inst->obj->ctrl(inst, MGR_DELENTITY | REQUEST, (void *)contr->entity);
|
|
inst->obj->ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
|
REMOVE_FROM_LISTBASE(contr, ((Controller_t *)inst->obj->ilist));
|
|
spin_unlock_irqrestore(&contr->list_lock, flags);
|
|
kfree(contr);
|
|
}
|
|
|
|
void
|
|
ControllerRun(Controller_t *contr)
|
|
{
|
|
BInst_t *binst;
|
|
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;
|
|
binst = contr->binst;
|
|
ret = binst->inst.obj->ctrl(binst->bst, 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;
|
|
|
|
ApplId = CAPIMSG_APPID(skb->data);
|
|
appl = getApplication4Id(contr, ApplId);
|
|
if (!appl) {
|
|
int_error();
|
|
err = CAPI_ILLAPPNR;
|
|
} else
|
|
ApplicationSendMessage(appl, skb);
|
|
#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);
|
|
}
|
|
|
|
int
|
|
ControllerL3L4(mISDNif_t *hif, struct sk_buff *skb)
|
|
{
|
|
Controller_t *contr;
|
|
Plci_t *plci;
|
|
int ret = -EINVAL;
|
|
mISDN_head_t *hh;
|
|
|
|
if (!hif || !skb)
|
|
return(ret);
|
|
hh = mISDN_HEAD_P(skb);
|
|
contr = hif->fdata;
|
|
contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: prim(%x) id(%x)",
|
|
__FUNCTION__, hh->prim, hh->dinfo);
|
|
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(if_newhead(&contr->inst.down, 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)
|
|
{
|
|
Controller_t *contr;
|
|
int retval;
|
|
mISDNstack_t *cst;
|
|
BInst_t *binst;
|
|
|
|
if (!st)
|
|
return(-EINVAL);
|
|
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);
|
|
spin_lock_init(&contr->list_lock);
|
|
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
|
|
cst = st->child;
|
|
while(cst) {
|
|
contr->nr_bc++;
|
|
cst = cst->next;
|
|
}
|
|
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;
|
|
}
|
|
// FIXME ???
|
|
contr->addr = st->id;
|
|
sprintf(contr->inst.name, "CAPI %d", st->id);
|
|
init_mISDNinstance(&contr->inst, ocapi, contr);
|
|
if (!SetHandledPID(ocapi, &contr->inst.pid)) {
|
|
int_error();
|
|
ControllerDestr(contr);
|
|
return(-ENOPROTOOPT);
|
|
}
|
|
cst = st->child;
|
|
while(cst) {
|
|
if (!(binst = kmalloc(sizeof(BInst_t), GFP_KERNEL))) {
|
|
printk(KERN_ERR "no mem for Binst\n");
|
|
int_error();
|
|
ControllerDestr(contr);
|
|
return -ENOMEM;
|
|
}
|
|
memset(binst, 0, sizeof(BInst_t));
|
|
binst->bst = cst;
|
|
binst->inst.st = cst;
|
|
init_mISDNinstance(&binst->inst, ocapi, binst);
|
|
binst->inst.pid.layermask |= ISDN_LAYER(4);
|
|
binst->inst.down.stat = IF_NOACTIV;
|
|
APPEND_TO_LIST(binst, contr->binst);
|
|
cst = cst->next;
|
|
}
|
|
APPEND_TO_LIST(contr, 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(%x)\n",
|
|
__FUNCTION__, retval);
|
|
}
|
|
retval = 0;
|
|
#ifdef OLDCAPI_DRIVER_INTERFACE
|
|
{
|
|
char tmp[10];
|
|
|
|
sprintf(tmp, "mISDN%d", st->id);
|
|
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", st->id);
|
|
contr->ctrl->driver_name = "mISDN";
|
|
contr->ctrl->driverdata = contr;
|
|
contr->ctrl->register_appl = RegisterAppl;
|
|
contr->ctrl->release_appl = ReleaseAppl;
|
|
contr->ctrl->send_message = SendMessage;
|
|
contr->ctrl->load_firmware = LoadFirmware;
|
|
contr->ctrl->reset_ctr = ResetContr;
|
|
contr->ctrl->procinfo = procinfo;
|
|
contr->ctrl->ctr_read_proc = read_proc;
|
|
retval = attach_capi_ctr(contr->ctrl);
|
|
#endif
|
|
if (!retval) {
|
|
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;
|
|
}
|
|
|
|
BInst_t *
|
|
ControllerSelChannel(Controller_t *contr, u_int channel)
|
|
{
|
|
mISDNstack_t *cst;
|
|
BInst_t *binst;
|
|
channel_info_t ci;
|
|
int ret;
|
|
|
|
if (!contr->binst) {
|
|
int_errtxt("no binst 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;
|
|
binst = contr->binst;
|
|
while(binst) {
|
|
if (cst == binst->bst)
|
|
break;
|
|
binst = binst->next;
|
|
}
|
|
return(binst);
|
|
}
|
|
|
|
#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
|