implement PCM mode

This commit is contained in:
Karsten Keil 2001-11-14 10:41:26 +00:00
parent fe89662fca
commit 845651c9ec
15 changed files with 628 additions and 305 deletions

View File

@ -19,6 +19,7 @@ Rules.make: $(KDIR)/Rules.make Rules.make.ext
.config: $(KDIR)/.config
cp -pf $(KDIR)/.config .
cat add.config >> .config
arch: $(KDIR)/arch
rm -f arch

View File

@ -44,16 +44,16 @@ endif
# endif
#endif
obj-$(CONFIG_ISDN_DRV_HISAX) :=
obj-$(CONFIG_ISDN_DRV_HISAX) += hisaxcore.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) :=
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += hisaxcore.o
obj-$(CONFIG_ISDN_DRV_HISAX) += fritzpci.o
obj-$(CONFIG_ISDN_DRV_HISAX) += sedlfax.o
obj-$(CONFIG_ISDN_DRV_HISAX) += hfcpci.o
obj-$(CONFIG_ISDN_DRV_HISAX) += hisaxl1.o
obj-$(CONFIG_ISDN_DRV_HISAX) += hisaxl2.o
obj-$(CONFIG_ISDN_DRV_HISAX) += l3udss1.o
obj-$(CONFIG_ISDN_DRV_HISAX) += hisaxcapi.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += fritzpci.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += sedlfax.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += hfcpci.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += hisaxl1.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += hisaxl2.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += l3udss1.o
obj-$(CONFIG_ISDN_DRV_NEWHISAX) += hisaxcapi.o
M_OBJS := $(obj-m)

View File

@ -186,7 +186,7 @@ DummyProcess_t *contrNewDummyPc(Contr_t *contr);
DummyProcess_t *contrId2DummyPc(Contr_t *contr, __u16 invokeId);
int contrL4L3(Contr_t *, u_int, int, struct sk_buff *);
int contrL3L4(hisaxif_t *, struct sk_buff *);
BInst_t *contrSelChannel(Contr_t *, int);
BInst_t *contrSelChannel(Contr_t *, u_int);
// ---------------------------------------------------------------------------
// struct Listen
@ -295,7 +295,7 @@ typedef struct _Cplci {
u_char cause[4]; // we may get a cause from l3 DISCONNECT message
// which we'll need send in DISCONNECT_IND caused by
// l3 RELEASE message
int bchannel;
u_int bchannel;
struct Bprotocol Bprotocol;
} Cplci_t;

View File

@ -11,9 +11,9 @@
int contrConstr(Contr_t *contr, hisaxstack_t *st, hisax_pid_t *pid, hisaxobject_t *ocapi)
{
char tmp[10];
hisaxstack_t *cst = st->child;
BInst_t *binst;
char tmp[10];
hisaxstack_t *cst = st->child;
BInst_t *binst;
memset(contr, 0, sizeof(Contr_t));
memcpy(&contr->inst.pid, pid, sizeof(hisax_pid_t));
@ -99,9 +99,16 @@ void contrDestr(Contr_t *contr)
void contrRun(Contr_t *contr)
{
struct capi_ctr *ctrl = contr->ctrl;
struct capi_ctr *ctrl = contr->ctrl;
BInst_t *binst;
int nb;
nb = 0;
binst = contr->binst;
while(binst) {
nb++;
binst = binst->next;
}
strncpy(ctrl->manu, "ISDN4Linux, (C) Kai Germaschewski", CAPI_MANUFACTURER_LEN);
strncpy(ctrl->serial, "0002", CAPI_SERIAL_LEN);
ctrl->version.majorversion = 2;
@ -110,7 +117,7 @@ void contrRun(Contr_t *contr)
ctrl->version.minormanuversion = 1;
memset(&ctrl->profile, 0, sizeof(struct capi_profile));
ctrl->profile.ncontroller = 1;
ctrl->profile.nbchannel = 2;
ctrl->profile.nbchannel = nb;
ctrl->profile.goptions = 0x11; // internal controller, supplementary services
ctrl->profile.support1 = 3; // HDLC, TRANS
ctrl->profile.support2 = 3; // X75SLP, TRANS
@ -384,10 +391,12 @@ Contr_t *newContr(hisaxobject_t *ocapi, hisaxstack_t *st, hisax_pid_t *pid)
return contr;
}
BInst_t *contrSelChannel(Contr_t *contr, int channr)
BInst_t *contrSelChannel(Contr_t *contr, u_int channel)
{
hisaxstack_t *cst;
BInst_t *binst;
hisaxstack_t *cst;
BInst_t *binst;
channel_info_t ci;
int ret;
if (!contr->binst) {
cst = contr->inst.st->child;
@ -410,11 +419,21 @@ BInst_t *contrSelChannel(Contr_t *contr, int channr)
cst = cst->next;
}
}
binst = NULL;
if (channr == 1)
binst = contr->binst;
else if (channr == 2)
binst = contr->binst->next;
ci.channel = channel;
ci.st.p = NULL;
ret = contr->inst.obj->ctrl(contr->inst.st, MGR_SELCHANNEL | REQUEST,
&ci);
if (ret) {
int_errtxt("ret(%d)", ret);
return(NULL);
}
cst = ci.st.p;
binst = contr->binst;
while(binst) {
if (cst == binst->bst)
break;
binst = binst->next;
}
return(binst);
}

View File

@ -164,6 +164,47 @@ get_next_instance(hisaxstack_t *st, hisax_pid_t *pid)
return(next);
}
static int
sel_channel(hisaxstack_t *st, channel_info_t *ci)
{
int err = -EINVAL;
if (!ci)
return(err);
printk(KERN_DEBUG __FUNCTION__": st(%p) st->mgr(%p)\n",
st, st->mgr);
if (st->mgr) {
if (st->mgr->obj && st->mgr->obj->own_ctrl) {
err = st->mgr->obj->own_ctrl(st->mgr,
MGR_SELCHANNEL | REQUEST, ci);
printk(KERN_DEBUG __FUNCTION__": MGR_SELCHANNEL(%d)\n",
err);
} else
int_error();
} else {
printk(KERN_WARNING __FUNCTION__": no mgr st(%p)\n", st);
}
if (err) {
hisaxstack_t *cst = st->child;
int nr = 0;
ci->st.p = NULL;
if (!(ci->channel & (~CHANNEL_NUMBER))) {
/* only number is set */
while(cst) {
nr++;
if (nr == (ci->channel & 3)) {
ci->st.p = cst;
err = 0;
break;
}
cst = cst->next;
}
}
}
return(err);
}
static int
disconnect_if(hisaxinstance_t *inst, u_int prim, hisaxif_t *hif) {
int err = 0;
@ -264,6 +305,8 @@ static int central_manager(void *data, u_int prim, void *arg) {
return(clear_stack(st));
case MGR_DELSTACK | REQUEST:
return(release_stack(st));
case MGR_SELCHANNEL | REQUEST:
return(sel_channel(st, arg));
case MGR_ADDIF | REQUEST:
return(add_if(data, prim, arg));
case MGR_CONNECT | REQUEST:

View File

@ -55,6 +55,25 @@ __u16 q931CIPValue(SETUP_t *setup)
return CIPValue;
}
u_int plci_parse_channel_id(u_char *p)
{
u_int cid = -1;
int l;
if (p) {
printk(KERN_DEBUG __FUNCTION__": l(%d) %x\n",p[0],p[1]);
l = *p++;
if (l == 1) {
cid = *p;
} else if (l == 3) {
cid = *p++ << 16;
cid |= *p++ << 8;
cid |= *p;
}
}
return(cid);
}
__u16 CIPValue2setup(__u16 CIPValue, SETUP_t *setup)
{
switch (CIPValue) {
@ -195,6 +214,7 @@ enum {
EV_PLCI_SUSPEND_CONF,
EV_PLCI_RESUME_REQ,
EV_PLCI_RESUME_CONF,
EV_PLCI_CHANNEL_ERR,
EV_PLCI_CC_SETUP_IND,
EV_PLCI_CC_SETUP_CONF_ERR,
EV_PLCI_CC_SETUP_CONF,
@ -231,6 +251,7 @@ static char* str_ev_plci[] = {
"EV_PLCI_SUSPEND_CONF",
"EV_PLCI_RESUME_REQ",
"EV_PLCI_RESUME_CONF",
"EV_PLCI_CHANNEL_ERR",
"EV_PLCI_CC_SETUP_IND",
"EV_PLCI_CC_SETUP_CONF_ERR",
"EV_PLCI_CC_SETUP_CONF",
@ -511,7 +532,10 @@ static void plci_cc_setup_conf(struct FsmInst *fi, int event, void *arg)
_cmsg cmsg;
CONNECT_t *conn = arg;
memset(&cmsg, 0, sizeof(_cmsg));
if (cplci->bchannel == -1) {/* no valid channel set */
FsmEvent(fi, EV_PLCI_CHANNEL_ERR, NULL);
return;
}
cplciCmsgHeader(cplci, &cmsg, CAPI_CONNECT_ACTIVE, CAPI_IND);
if (arg) {
cmsg.ConnectedNumber = conn->CONNECT_PN;
@ -533,13 +557,37 @@ static void plci_cc_setup_conf_err(struct FsmInst *fi, int event, void *arg)
cplciRecvCmsg(cplci, &cmsg);
}
static void plci_channel_err(struct FsmInst *fi, int event, void *arg)
{
Cplci_t *cplci = fi->userdata;
Plci_t *plci = cplci->plci;
_cmsg cmsg;
RELEASE_COMPLETE_t relc;
unsigned char cause[4];
if (!plci) {
int_error();
return;
}
memset(&relc, 0, sizeof(RELEASE_COMPLETE_t));
cause[0] = 2;
cause[1] = 0x80;
cause[2] = 0x86; /* channel unacceptable */
relc.CAUSE = cause;
plciL4L3(plci, CC_RELEASE_COMPLETE | REQUEST, sizeof(RELEASE_COMPLETE_t),
&relc);
cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND);
cmsg.Reason = CapiProtocolErrorLayer3;
FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg);
cplciRecvCmsg(cplci, &cmsg);
}
static void plci_cc_setup_ind(struct FsmInst *fi, int event, void *arg)
{
Cplci_t *cplci = fi->userdata;
SETUP_t *setup = arg;
_cmsg cmsg;
memset(&cmsg, 0, sizeof(_cmsg));
cplciCmsgHeader(cplci, &cmsg, CAPI_CONNECT, CAPI_IND);
// FIXME: CW
@ -590,7 +638,6 @@ static void plci_cc_release_ind(struct FsmInst *fi, int event, void *arg)
plciDetachCplci(cplci->plci, cplci);
cplciLinkDown(cplci);
cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND);
if (rel) {
if (rel->CAUSE) {
@ -682,7 +729,6 @@ static void plci_cc_suspend_conf(struct FsmInst *fi, int event, void *arg)
plci_suspend_reply(cplci, CapiSuccess);
plciDetachCplci(cplci->plci, cplci);
cplciCmsgHeader(cplci, &cmsg, CAPI_DISCONNECT, CAPI_IND);
FsmEvent(&cplci->plci_m, EV_PLCI_DISCONNECT_IND, &cmsg);
cplciRecvCmsg(cplci, &cmsg);
@ -719,7 +765,7 @@ static void plci_cc_resume_conf(struct FsmInst *fi, int event, void *arg)
int_error();
return;
}
cplci->bchannel = ack->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(ack->CHANNEL_ID);
cplciCmsgHeader(cplci, &cmsg, CAPI_FACILITY, CAPI_IND);
p = &tmp[1];
p += capiEncodeWord(p, 0x0005); // Suspend
@ -778,60 +824,62 @@ static void plci_info_req(struct FsmInst *fi, int event, void *arg)
static struct FsmNode fn_plci_list[] =
{
{ST_PLCI_P_0, EV_PLCI_CONNECT_REQ, plci_connect_req},
{ST_PLCI_P_0, EV_PLCI_CONNECT_IND, plci_connect_ind},
{ST_PLCI_P_0, EV_PLCI_RESUME_REQ, plci_resume_req},
{ST_PLCI_P_0, EV_PLCI_CC_SETUP_IND, plci_cc_setup_ind},
{ST_PLCI_P_0, EV_PLCI_CONNECT_REQ, plci_connect_req},
{ST_PLCI_P_0, EV_PLCI_CONNECT_IND, plci_connect_ind},
{ST_PLCI_P_0, EV_PLCI_RESUME_REQ, plci_resume_req},
{ST_PLCI_P_0, EV_PLCI_CC_SETUP_IND, plci_cc_setup_ind},
{ST_PLCI_P_0_1, EV_PLCI_CONNECT_CONF, plci_connect_conf},
{ST_PLCI_P_0_1, EV_PLCI_CONNECT_CONF, plci_connect_conf},
{ST_PLCI_P_1, EV_PLCI_CONNECT_ACTIVE_IND, plci_connect_active_ind},
{ST_PLCI_P_1, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_1, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_1, EV_PLCI_INFO_REQ, plci_info_req_overlap},
{ST_PLCI_P_1, EV_PLCI_CC_SETUP_CONF, plci_cc_setup_conf},
{ST_PLCI_P_1, EV_PLCI_CC_SETUP_CONF_ERR, plci_cc_setup_conf_err},
{ST_PLCI_P_1, EV_PLCI_CC_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_1, EV_PLCI_CC_RELEASE_PROC_IND, plci_cc_setup_conf_err},
{ST_PLCI_P_1, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_1, EV_PLCI_CC_REJECT_IND, plci_cc_release_ind},
{ST_PLCI_P_1, EV_PLCI_CONNECT_ACTIVE_IND, plci_connect_active_ind},
{ST_PLCI_P_1, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_1, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_1, EV_PLCI_INFO_REQ, plci_info_req_overlap},
{ST_PLCI_P_1, EV_PLCI_CC_SETUP_CONF, plci_cc_setup_conf},
{ST_PLCI_P_1, EV_PLCI_CC_SETUP_CONF_ERR, plci_cc_setup_conf_err},
{ST_PLCI_P_1, EV_PLCI_CC_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_1, EV_PLCI_CC_RELEASE_PROC_IND, plci_cc_setup_conf_err},
{ST_PLCI_P_1, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_1, EV_PLCI_CC_REJECT_IND, plci_cc_release_ind},
{ST_PLCI_P_1, EV_PLCI_CHANNEL_ERR, plci_channel_err},
{ST_PLCI_P_2, EV_PLCI_ALERT_REQ, plci_alert_req},
{ST_PLCI_P_2, EV_PLCI_CONNECT_RESP, plci_connect_resp},
{ST_PLCI_P_2, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_2, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_2, EV_PLCI_INFO_REQ, plci_info_req},
{ST_PLCI_P_2, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_2, EV_PLCI_ALERT_REQ, plci_alert_req},
{ST_PLCI_P_2, EV_PLCI_CONNECT_RESP, plci_connect_resp},
{ST_PLCI_P_2, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_2, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_2, EV_PLCI_INFO_REQ, plci_info_req},
{ST_PLCI_P_2, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_4, EV_PLCI_CONNECT_ACTIVE_IND, plci_connect_active_ind},
{ST_PLCI_P_4, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_4, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_4, EV_PLCI_INFO_REQ, plci_info_req},
{ST_PLCI_P_4, EV_PLCI_CC_SETUP_COMPL_IND, plci_cc_setup_compl_ind},
{ST_PLCI_P_4, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_4, EV_PLCI_CONNECT_ACTIVE_IND, plci_connect_active_ind},
{ST_PLCI_P_4, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_4, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_4, EV_PLCI_INFO_REQ, plci_info_req},
{ST_PLCI_P_4, EV_PLCI_CC_SETUP_COMPL_IND, plci_cc_setup_compl_ind},
{ST_PLCI_P_4, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_4, EV_PLCI_CHANNEL_ERR, plci_channel_err},
{ST_PLCI_P_ACT, EV_PLCI_CONNECT_ACTIVE_RESP, plci_connect_active_resp},
{ST_PLCI_P_ACT, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_ACT, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_ACT, EV_PLCI_INFO_REQ, plci_info_req},
{ST_PLCI_P_ACT, EV_PLCI_SELECT_B_PROTOCOL_REQ, plci_select_b_protocol_req},
{ST_PLCI_P_ACT, EV_PLCI_SUSPEND_REQ, plci_suspend_req},
{ST_PLCI_P_ACT, EV_PLCI_SUSPEND_CONF, plci_suspend_conf},
{ST_PLCI_P_ACT, EV_PLCI_CC_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_ACT, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_ACT, EV_PLCI_CC_NOTIFY_IND, plci_cc_notify_ind},
{ST_PLCI_P_ACT, EV_PLCI_CC_SUSPEND_ERR, plci_cc_suspend_err},
{ST_PLCI_P_ACT, EV_PLCI_CC_SUSPEND_CONF, plci_cc_suspend_conf},
{ST_PLCI_P_ACT, EV_PLCI_CONNECT_ACTIVE_RESP, plci_connect_active_resp},
{ST_PLCI_P_ACT, EV_PLCI_DISCONNECT_REQ, plci_disconnect_req},
{ST_PLCI_P_ACT, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_ACT, EV_PLCI_INFO_REQ, plci_info_req},
{ST_PLCI_P_ACT, EV_PLCI_SELECT_B_PROTOCOL_REQ, plci_select_b_protocol_req},
{ST_PLCI_P_ACT, EV_PLCI_SUSPEND_REQ, plci_suspend_req},
{ST_PLCI_P_ACT, EV_PLCI_SUSPEND_CONF, plci_suspend_conf},
{ST_PLCI_P_ACT, EV_PLCI_CC_DISCONNECT_IND, plci_cc_disconnect_ind},
{ST_PLCI_P_ACT, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_ACT, EV_PLCI_CC_NOTIFY_IND, plci_cc_notify_ind},
{ST_PLCI_P_ACT, EV_PLCI_CC_SUSPEND_ERR, plci_cc_suspend_err},
{ST_PLCI_P_ACT, EV_PLCI_CC_SUSPEND_CONF, plci_cc_suspend_conf},
{ST_PLCI_P_5, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_5, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_5, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_5, EV_PLCI_CC_RELEASE_IND, plci_cc_release_ind},
{ST_PLCI_P_6, EV_PLCI_DISCONNECT_RESP, plci_disconnect_resp},
{ST_PLCI_P_6, EV_PLCI_DISCONNECT_RESP, plci_disconnect_resp},
{ST_PLCI_P_RES, EV_PLCI_RESUME_CONF, plci_resume_conf},
{ST_PLCI_P_RES, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_RES, EV_PLCI_CC_RESUME_ERR, plci_cc_resume_err},
{ST_PLCI_P_RES, EV_PLCI_CC_RESUME_CONF, plci_cc_resume_conf},
{ST_PLCI_P_RES, EV_PLCI_RESUME_CONF, plci_resume_conf},
{ST_PLCI_P_RES, EV_PLCI_DISCONNECT_IND, plci_disconnect_ind},
{ST_PLCI_P_RES, EV_PLCI_CC_RESUME_ERR, plci_cc_resume_err},
{ST_PLCI_P_RES, EV_PLCI_CC_RESUME_CONF, plci_cc_resume_conf},
#if 0
{ST_PLCI_P_0, EV_PLCI_FACILITY_IND, plci_facility_ind_p_0_off_hook},
@ -917,7 +965,7 @@ void cplci_l3l4(Cplci_t *cplci, int pr, void *arg)
cplciInfoIndIE(cplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID,
p.setup->CHANNEL_ID);
if (p.setup->CHANNEL_ID)
cplci->bchannel = p.setup->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(p.setup->CHANNEL_ID);
FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_IND, arg);
break;
case CC_TIMEOUT | INDICATION:
@ -938,7 +986,7 @@ void cplci_l3l4(Cplci_t *cplci, int pr, void *arg)
cplciInfoIndIE(cplci, IE_CHANNEL_ID,
CAPI_INFOMASK_CHANNELID, p.conn->CHANNEL_ID);
if (p.conn->CHANNEL_ID)
cplci->bchannel = p.conn->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(p.conn->CHANNEL_ID);
}
FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_CONF, arg);
break;
@ -949,7 +997,7 @@ void cplci_l3l4(Cplci_t *cplci, int pr, void *arg)
cplciInfoIndIE(cplci, IE_CHANNEL_ID,
CAPI_INFOMASK_CHANNELID, p.c_ack->CHANNEL_ID);
if (p.c_ack->CHANNEL_ID)
cplci->bchannel = p.c_ack->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(p.c_ack->CHANNEL_ID);
}
FsmEvent(&cplci->plci_m, EV_PLCI_CC_SETUP_COMPL_IND, arg);
break;
@ -1010,7 +1058,7 @@ void cplci_l3l4(Cplci_t *cplci, int pr, void *arg)
cplciInfoIndIE(cplci, IE_CHANNEL_ID,
CAPI_INFOMASK_CHANNELID, p.s_ack->CHANNEL_ID);
if (p.s_ack->CHANNEL_ID)
cplci->bchannel = p.s_ack->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(p.s_ack->CHANNEL_ID);
}
break;
case CC_PROCEEDING | INDICATION:
@ -1025,7 +1073,7 @@ void cplci_l3l4(Cplci_t *cplci, int pr, void *arg)
cplciInfoIndIE(cplci, IE_CHANNEL_ID,
CAPI_INFOMASK_CHANNELID, p.proc->CHANNEL_ID);
if (p.proc->CHANNEL_ID)
cplci->bchannel = p.proc->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(p.proc->CHANNEL_ID);
}
break;
case CC_ALERTING | INDICATION:
@ -1044,7 +1092,7 @@ void cplci_l3l4(Cplci_t *cplci, int pr, void *arg)
cplciInfoIndIE(cplci, IE_CHANNEL_ID,
CAPI_INFOMASK_CHANNELID, p.alert->CHANNEL_ID);
if (p.alert->CHANNEL_ID)
cplci->bchannel = p.alert->CHANNEL_ID[1];
cplci->bchannel = plci_parse_channel_id(p.alert->CHANNEL_ID);
}
break;
case CC_PROGRESS | INDICATION:
@ -1137,12 +1185,6 @@ void cplciLinkUp(Cplci_t *cplci)
return;
}
if (!(cplci->bchannel & 3) || ((cplci->bchannel & 3) == 3)) {
// at the moment only B-channel 1 or B-channel 2 allowed
int_error();
return;
}
cplci->ncci = kmalloc(sizeof(Ncci_t), GFP_ATOMIC);
if (!cplci->ncci) {
int_error();
@ -1214,7 +1256,6 @@ void cplciClearOtherApps(Cplci_t *cplci)
cp = plci->cplcis[applId - 1];
if (cp && (cp != cplci)) {
plciDetachCplci(plci, cp);
cplciCmsgHeader(cp, &cm, CAPI_DISCONNECT, CAPI_IND);
cm.Reason = 0x3304; // other application got the call
FsmEvent(&cp->plci_m, EV_PLCI_DISCONNECT_IND, &cm);
@ -1248,7 +1289,6 @@ void cplciInfoIndIE(Cplci_t *cplci, unsigned char ie, __u32 mask, u_char *iep)
cplciLinkUp(cplci);
}
}
cplciCmsgHeader(cplci, &cmsg, CAPI_INFO, CAPI_IND);
cmsg.InfoNumber = ie;
cmsg.InfoElement = iep;

View File

@ -1,13 +1,13 @@
/* $Id$
* hfc_pci.c low level driver for CCD´s hfc-pci based cards
* hfc_pci.c low level driver for CCD's hfc-pci based cards
*
* Author Werner Cornelius (werner@isdn4linux.de)
* based on existing driver for CCD hfc ISA cards
* type approval valid for HFC-S PCI A based card
*
* Copyright 1999 by Werner Cornelius (werner@isdn-development.de)
* Copyright 1999 by Karsten Keil (keil@isdn4linux.de)
* Copyright 2001 by Karsten Keil (keil@isdn4linux.de)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -115,51 +115,59 @@ static const PCI_ENTRY id_list[] =
struct hfcPCI_hw {
unsigned char cirm;
unsigned char ctmt;
unsigned char clkdel;
unsigned char states;
unsigned char conn;
unsigned char mst_m;
unsigned char int_m1;
unsigned char int_m2;
unsigned char int_s1;
unsigned char sctrl;
unsigned char sctrl_r;
unsigned char sctrl_e;
unsigned char trm;
unsigned char stat;
unsigned char fifo;
unsigned char fifo_en;
unsigned char bswapped;
unsigned char nt_mode;
int nt_timer;
unsigned char pci_bus;
unsigned char pci_device_fn;
unsigned char *pci_io; /* start of PCI IO memory */
void *share_start; /* shared memory for Fifos start */
void *fifos; /* FIFO memory */
int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
struct timer_list timer;
unsigned char cirm;
unsigned char ctmt;
unsigned char clkdel;
unsigned char states;
unsigned char conn;
unsigned char mst_m;
unsigned char int_m1;
unsigned char int_m2;
unsigned char int_s1;
unsigned char sctrl;
unsigned char sctrl_r;
unsigned char sctrl_e;
unsigned char trm;
unsigned char stat;
unsigned char fifo;
unsigned char fifo_en;
unsigned char bswapped;
unsigned char nt_mode;
int nt_timer;
unsigned char pci_bus;
unsigned char pci_device_fn;
unsigned char *pci_io; /* start of PCI IO memory */
void *share_start; /* shared memory for Fifos start */
void *fifos; /* FIFO memory */
int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */
timer_t timer;
};
typedef struct hfcPCI_hw hfcPCI_hw_t;
#define SPIN_DEBUG
#define HFC_CFG_MASTER 1
#define HFC_CFG_SLAVE 2
#define HFC_CFG_PCM 3
#define HFC_CFG_2HFC 4
#define HFC_CFG_SLAVEHFC 5
typedef struct _hfc_pci {
struct _hfc_pci *prev;
struct _hfc_pci *next;
u_char subtyp;
u_char chanlimit;
u_int irq;
u_int addr;
struct hfcPCI_hw hw;
spinlock_t devlock;
u_long flags;
struct _hfc_pci *prev;
struct _hfc_pci *next;
u_char subtyp;
u_char chanlimit;
u_int cfg;
u_int irq;
u_int addr;
hfcPCI_hw_t hw;
spinlock_t devlock;
u_long flags;
#ifdef SPIN_DEBUG
void *lock_adr;
void *lock_adr;
#endif
dchannel_t dch;
bchannel_t bch[2];
dchannel_t dch;
bchannel_t bch[2];
} hfc_pci_t;
@ -255,7 +263,8 @@ reset_hfcpci(hfc_pci_t *hc)
hc->hw.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */
hc->hw.sctrl_r = 0;
hc->hw.sctrl_e = HFCPCI_AUTO_AWAKE; /* S/T Auto awake */
hc->hw.mst_m = HFCPCI_MASTER; /* HFC Master Mode */
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m = HFCPCI_MASTER; /* HFC Master Mode */
if (hc->hw.nt_mode) {
hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */
hc->hw.sctrl |= SCTRL_MODE_NT; /* NT-MODE */
@ -349,9 +358,9 @@ static
bchannel_t *
Sel_BCS(hfc_pci_t *hc, int channel)
{
if (hc->bch[0].protocol && (hc->bch[0].channel == channel))
if (hc->bch[0].protocol && (hc->bch[0].channel & channel))
return (&hc->bch[0]);
else if (hc->bch[1].protocol && (hc->bch[1].channel == channel))
else if (hc->bch[1].protocol && (hc->bch[1].channel & channel))
return (&hc->bch[1]);
else
return (NULL);
@ -621,7 +630,7 @@ main_rec_hfcpci(bchannel_t *bch)
z_type *zp;
if ((bch->channel) && (!hc->hw.bswapped)) {
if ((bch->channel & 2) && (!hc->hw.bswapped)) {
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b2;
real_fifo = 1;
@ -636,13 +645,13 @@ main_rec_hfcpci(bchannel_t *bch)
cli();
if (test_and_set_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags)) {
restore_flags(flags);
debugprint(&bch->inst, "rec_data %d blocked", bch->channel);
debugprint(&bch->inst, "rec_data ch(%x) blocked", bch->channel);
return;
}
restore_flags(flags);
if (bz->f1 != bz->f2) {
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci rec %d f1(%d) f2(%d)",
debugprint(&bch->inst, "hfcpci rec ch(%x) f1(%d) f2(%d)",
bch->channel, bz->f1, bz->f2);
zp = &bz->za[bz->f2];
@ -651,7 +660,7 @@ main_rec_hfcpci(bchannel_t *bch)
rcnt += B_FIFO_SIZE;
rcnt++;
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)",
debugprint(&bch->inst, "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)",
bch->channel, zp->z1, zp->z2, rcnt);
if ((skb = hfcpci_empty_fifo(bch, bz, bdata, rcnt))) {
skb_queue_tail(&bch->rqueue, skb);
@ -796,7 +805,7 @@ hfcpci_fill_fifo(bchannel_t *bch)
if (bch->tx_len <= 0)
return;
if ((bch->channel) && (!hc->hw.bswapped)) {
if ((bch->channel & 2) && (!hc->hw.bswapped)) {
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b2;
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b2;
} else {
@ -808,7 +817,7 @@ hfcpci_fill_fifo(bchannel_t *bch)
z1t = &bz->za[MAX_B_FRAMES].z1;
z2t = z1t + 1;
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci_fill_fifo_trans%d cnt(%d) z1(%x) z2(%x)",
debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) cnt(%d) z1(%x) z2(%x)",
bch->channel, count, *z1t, *z2t);
fcnt = *z2t - *z1t;
if (fcnt <= 0)
@ -841,7 +850,7 @@ next_t_frame:
fcnt += bch->tx_len;
*z1t = new_z1; /* now send data */
} else if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci_fill_fifo_trans %d frame length %d discarded",
debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) frame length %d discarded",
bch->channel, bch->tx_len);
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flag)) {
if (bch->next_skb) {
@ -861,7 +870,7 @@ next_t_frame:
return;
}
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, __FUNCTION__": %d f1(%d) f2(%d) z1(f1)(%x)",
debugprint(&bch->inst, __FUNCTION__": ch(%x) f1(%d) f2(%d) z1(f1)(%x)",
bch->channel, bz->f1, bz->f2, bz->za[bz->f1].z1);
fcnt = bz->f1 - bz->f2; /* frame count actually buffered */
if (fcnt < 0)
@ -877,7 +886,7 @@ next_t_frame:
maxlen += B_FIFO_SIZE; /* count now contains available bytes */
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "hfcpci_fill_fifo %d count(%ld/%d),%lx",
debugprint(&bch->inst, "hfcpci_fill_fifo ch(%x) count(%ld/%d),%lx",
bch->channel, count,
maxlen, current->state);
@ -926,7 +935,7 @@ hfcpci_send_data(bchannel_t *bch)
hfcpci_fill_fifo(bch);
test_and_clear_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags);
} else {
debugprint(&bch->inst, "send_data %d blocked", bch->channel);
debugprint(&bch->inst, "send_data ch(%x) blocked", bch->channel);
hfcpci_sched_event(bch, B_BLOCKEDATOMIC);
}
}
@ -1201,7 +1210,7 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
hc->hw.int_s1 = exval;
}
if (val & 0x08) {
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 0))) {
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x08 IRQ");
} else
@ -1211,14 +1220,14 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
// if (hc->logecho)
// receive_emsg(hc);
// else
if (!(bch = Sel_BCS(hc, 1))) {
if (!(bch = Sel_BCS(hc, 2))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x10 IRQ");
} else
main_rec_hfcpci(bch);
}
if (val & 0x01) {
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 0))) {
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x01 IRQ");
} else {
@ -1248,7 +1257,7 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
}
if (val & 0x02) {
if (!(bch = Sel_BCS(hc, 1))) {
if (!(bch = Sel_BCS(hc, 2))) {
if (hc->dch.debug)
debugprint(&hc->dch.inst, "hfcpci spurious 0x02 IRQ");
} else {
@ -1368,7 +1377,8 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
} else if (hh->prim == (PH_SIGNAL | REQUEST)) {
dch->inst.lock(dch->inst.data);
if ((hh->dinfo == INFO3_P8) || (hh->dinfo == INFO3_P10)) {
hc->hw.mst_m |= HFCPCI_MASTER;
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER;
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
} else
ret = -EINVAL;
@ -1379,7 +1389,8 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */
udelay(6);
Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */
hc->hw.mst_m |= HFCPCI_MASTER;
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER;
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION);
// l1_msg(hc, HW_POWERUP | CONFIRM, NULL);
@ -1440,7 +1451,8 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
udelay(6);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* G1 */
udelay(6);
hc->hw.mst_m |= HFCPCI_MASTER;
if (test_bit(HFC_CFG_MASTER, &hc->cfg))
hc->hw.mst_m |= HFCPCI_MASTER;
Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m);
udelay(6);
Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION | 1);
@ -1492,19 +1504,26 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
hfc_pci_t *hc = bch->inst.data;
long flags;
int fifo2;
u_char rx_slot = 0, tx_slot = 0, pcm_mode;
if (bch->debug & L1_DEB_HSCX)
debugprint(&bch->inst, "HFCPCI bchannel%d protocol %x-->%x ch %d-->%d",
bch->channel, bch->protocol, protocol, bch->channel, bc);
debugprint(&bch->inst, "HFCPCI bchannel protocol %x-->%x ch %x-->%x",
bch->protocol, protocol, bch->channel, bc);
fifo2 = bc;
pcm_mode = (bc>>24) & 0xff;
if (pcm_mode) { /* PCM SLOT USE */
rx_slot = (bc>>8) & 0xff;
tx_slot = (bc>>16) & 0xff;
bc = bc & 0xff;
}
save_flags(flags);
cli();
if (hc->chanlimit > 1) {
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
hc->hw.sctrl_e &= ~0x80;
} else {
if (bc) {
if (bc & 2) {
if (protocol != ISDN_PID_NONE) {
hc->hw.bswapped = 1; /* B1 and B2 exchanged */
hc->hw.sctrl_e |= 0x80;
@ -1512,7 +1531,7 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
hc->hw.sctrl_e &= ~0x80;
}
fifo2 = 0;
fifo2 = 1;
} else {
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
hc->hw.sctrl_e &= ~0x80;
@ -1527,21 +1546,21 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
restore_flags(flags);
return(0);
}
if (bc) {
if (bc & 2) {
hc->hw.sctrl &= ~SCTRL_B2_ENA;
hc->hw.sctrl_r &= ~SCTRL_B2_ENA;
} else {
hc->hw.sctrl &= ~SCTRL_B1_ENA;
hc->hw.sctrl_r &= ~SCTRL_B1_ENA;
}
if (fifo2) {
if (fifo2 & 2) {
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2;
hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
} else {
hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1;
hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
}
if (bch->channel)
if (bch->channel & 2)
hc->hw.cirm &= 0x7f;
else
hc->hw.cirm &= 0xbf;
@ -1553,7 +1572,7 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
bch->channel = bc;
hfcpci_clear_fifo_rx(hc, fifo2);
hfcpci_clear_fifo_tx(hc, fifo2);
if (bc) {
if (bc & 2) {
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
hc->hw.cirm |= 0x80;
@ -1562,7 +1581,7 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
hc->hw.sctrl_r |= SCTRL_B1_ENA;
hc->hw.cirm |= 0x40;
}
if (fifo2) {
if (fifo2 & 2) {
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
hc->hw.ctmt |= 2;
@ -1579,14 +1598,14 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
bch->channel = bc;
hfcpci_clear_fifo_rx(hc, fifo2);
hfcpci_clear_fifo_tx(hc, fifo2);
if (bc) {
if (bc & 2) {
hc->hw.sctrl |= SCTRL_B2_ENA;
hc->hw.sctrl_r |= SCTRL_B2_ENA;
} else {
hc->hw.sctrl |= SCTRL_B1_ENA;
hc->hw.sctrl_r |= SCTRL_B1_ENA;
}
if (fifo2) {
if (fifo2 & 2) {
hc->hw.last_bfifo_cnt[1] = 0;
hc->hw.fifo_en |= HFCPCI_FIFOEN_B2;
hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
@ -1622,6 +1641,26 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
restore_flags(flags);
return(-ENOPROTOOPT);
}
if (pcm_mode) {
if (protocol == ISDN_PID_NONE) {
rx_slot = 0;
tx_slot = 0;
} else {
rx_slot |= 0x80;
tx_slot |= 0x80;
}
if (bc & 2) {
hc->hw.conn &= 0xc7;
hc->hw.conn |= 0x08;
Write_hfc(hc, HFCPCI_B2_SSL, tx_slot);
Write_hfc(hc, HFCPCI_B2_RSL, rx_slot);
} else {
hc->hw.conn &= 0xf8;
hc->hw.conn |= 0x01;
Write_hfc(hc, HFCPCI_B1_SSL, tx_slot);
Write_hfc(hc, HFCPCI_B1_RSL, rx_slot);
}
}
Write_hfc(hc, HFCPCI_SCTRL_E, hc->hw.sctrl_e);
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en);
@ -1942,8 +1981,8 @@ inithfcpci(hfc_pci_t *hc)
hc->dch.dbusytimer.data = (long) &hc->dch;
init_timer(&hc->dch.dbusytimer);
hc->chanlimit = 2;
mode_hfcpci(&hc->bch[0], 0, -1);
mode_hfcpci(&hc->bch[1], 1, -1);
mode_hfcpci(&hc->bch[0], 1, -1);
mode_hfcpci(&hc->bch[1], 2, -1);
}
#if 0
@ -2030,8 +2069,58 @@ static int init_card(hfc_pci_t *hc)
return(-EIO);
}
#define MAX_CARDS 4
#define MODULE_PARM_T "1-4i"
static int
SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci)
{
bchannel_t *bch;
hfc_pci_t *hfc;
hisaxstack_t *bst;
int cnr;
if (!ci)
return(-EINVAL);
ci->st.p = NULL;
bst = hc->dch.inst.st->child;
cnr=0;
while(bst) {
if(!bst->mgr) {
int_errtxt("no mgr st(%p)", bst);
return(-EINVAL);
}
hfc = bst->mgr->data;
if (!hfc) {
int_errtxt("no mgr->data st(%p)", bst);
return(-EINVAL);
}
bch = &hfc->bch[cnr & 1];
if (!(ci->channel & (~CHANNEL_NUMBER))) {
/* only number is set */
if ((ci->channel & CHANNEL_NUMBER) == (cnr + 1)) {
if (bch->protocol != ISDN_PID_NONE)
return(-EBUSY);
bch->channel = (cnr & 1) ? 2 : 1;
ci->st.p = bst;
return(0);
}
} else if ((ci->channel & (~CHANNEL_NUMBER)) == 0x00a18300) {
if (bch->protocol == ISDN_PID_NONE) {
ci->st.p = bst;
bch->channel = (cnr & 1) ? 2 : 1;
bch->channel |= CHANNEL_EXT_PCM;
bch->channel |= (ci->channel & 0x1f) << 16;
bch->channel |= (ci->channel & 0x1f) << 8;
ci->st.p = bst;
return(0);
}
}
cnr++;
bst = bst->next;
}
return(-EBUSY);
}
#define MAX_CARDS 8
#define MODULE_PARM_T "1-8i"
static int HFC_cnt;
static u_int protocol[MAX_CARDS];
static int layermask[MAX_CARDS];
@ -2142,8 +2231,8 @@ release_card(hfc_pci_t *hc) {
lock_dev(hc);
free_irq(hc->irq, hc);
mode_hfcpci(&hc->bch[0], 0, ISDN_PID_NONE);
mode_hfcpci(&hc->bch[1], 1, ISDN_PID_NONE);
mode_hfcpci(&hc->bch[0], 1, ISDN_PID_NONE);
mode_hfcpci(&hc->bch[1], 2, ISDN_PID_NONE);
if (hc->dch.dbusytimer.function != NULL) {
del_timer(&hc->dch.dbusytimer);
hc->dch.dbusytimer.function = NULL;
@ -2264,11 +2353,19 @@ HFC_manager(void *data, u_int prim, void *arg) {
}
return(DisConnectIF(inst, arg));
break;
case MGR_SELCHANNEL | REQUEST:
if (channel != 2) {
printk(KERN_WARNING __FUNCTION__": selchannel not dinst\n");
return(-EINVAL);
}
return(SelFreeBChannel(card, arg));
break;
case MGR_SETSTACK | CONFIRM:
if (!card) {
printk(KERN_WARNING __FUNCTION__": setstack failed\n");
return(-ENODEV);
}
if ((channel!=2) && (inst->pid.global == 2)) {
inst->down.fdata = &card->bch[channel];
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
@ -2294,9 +2391,10 @@ HFC_manager(void *data, u_int prim, void *arg) {
int
HFC_init(void)
{
int err,i;
hfc_pci_t *card;
hisax_pid_t pid;
int err,i;
hfc_pci_t *card, *prev;
hisax_pid_t pid;
hisaxstack_t *dst;
HFC_obj.name = HFCName;
HFC_obj.own_ctrl = HFC_manager;
@ -2328,22 +2426,6 @@ HFC_init(void)
card->dch.inst.unlock = unlock_dev;
card->dch.inst.data = card;
card->dch.inst.pid.layermask = ISDN_LAYER(0);
set_dchannel_pid(&pid, protocol[HFC_cnt] &0xf,
layermask[HFC_cnt]);
if (protocol[HFC_cnt] & 0x10) {
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
card->dch.inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
pid.protocol[0] = ISDN_PID_L0_NT_S0;
pid.protocol[1] = ISDN_PID_L1_NT_S0;
card->dch.inst.pid.layermask |= ISDN_LAYER(1);
pid.layermask |= ISDN_LAYER(1);
if (layermask[HFC_cnt] & ISDN_LAYER(2))
pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
card->hw.nt_mode = 1;
} else {
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
card->hw.nt_mode = 0;
}
card->dch.inst.up.owner = &card->dch.inst;
card->dch.inst.down.owner = &card->dch.inst;
HFC_obj.ctrl(NULL, MGR_DISCONNECT | REQUEST,
@ -2353,7 +2435,7 @@ HFC_init(void)
sprintf(card->dch.inst.name, "HFC%d", HFC_cnt+1);
init_dchannel(&card->dch);
for (i=0; i<2; i++) {
card->bch[i].channel = i;
card->bch[i].channel = i + 1;
card->bch[i].inst.obj = &HFC_obj;
card->bch[i].inst.data = card;
card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
@ -2374,6 +2456,56 @@ HFC_init(void)
&card->bch[i];
}
}
if (protocol[HFC_cnt] == 0x100) {
prev = card->prev;
if (!prev) {
int_errtxt("card(%d) no previous HFC",
HFC_cnt);
if (!HFC_cnt)
HiSax_unregister(&HFC_obj);
else
err = 0;
return(err);
}
i = HFC_cnt - 1;
test_and_set_bit(HFC_CFG_2HFC, &prev->cfg);
test_and_set_bit(HFC_CFG_2HFC, &card->cfg);
test_and_set_bit(HFC_CFG_SLAVEHFC, &card->cfg);
} else {
prev = NULL;
i = HFC_cnt;
}
set_dchannel_pid(&pid, protocol[i] & 0xf,
layermask[i]);
test_and_set_bit(HFC_CFG_MASTER, &card->cfg);
if (protocol[i] & 0x10) {
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_NT_S0;
card->dch.inst.pid.protocol[1] = ISDN_PID_L1_NT_S0;
pid.protocol[0] = ISDN_PID_L0_NT_S0;
pid.protocol[1] = ISDN_PID_L1_NT_S0;
card->dch.inst.pid.layermask |= ISDN_LAYER(1);
pid.layermask |= ISDN_LAYER(1);
if (layermask[i] & ISDN_LAYER(2))
pid.protocol[2] = ISDN_PID_L2_LAPD_NET;
card->hw.nt_mode = 1;
} else {
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
card->hw.nt_mode = 0;
}
if (protocol[i] & 0x20) {
if (pid.layermask & ISDN_LAYER(2))
pid.protocol[2] |= ISDN_PID_L2_DF_PTP;
if (pid.layermask & ISDN_LAYER(3))
pid.protocol[3] |= ISDN_PID_L3_DF_PTP;
}
if (protocol[i] & 0x40) {
if (pid.layermask & ISDN_LAYER(3))
pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID;
test_and_set_bit(HFC_CFG_PCM, &card->cfg);
test_and_set_bit(HFC_CFG_SLAVE, &card->cfg);
test_and_clear_bit(HFC_CFG_MASTER, &card->cfg);
}
printk(KERN_DEBUG "HFC card %p dch %p bch1 %p bch2 %p\n",
card, &card->dch, &card->bch[0], &card->bch[1]);
if (setup_hfcpci(card)) {
@ -2392,27 +2524,24 @@ HFC_init(void)
return(err);
}
HFC_cnt++;
if ((err = HFC_obj.ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->dch.inst))) {
printk(KERN_ERR "MGR_ADDSTACK REQUEST dch err(%d)\n", err);
release_card(card);
if (!HFC_cnt)
HiSax_unregister(&HFC_obj);
else
err = 0;
return(err);
if (prev) {
dst = prev->dch.inst.st;
} else {
if ((err = HFC_obj.ctrl(NULL, MGR_NEWSTACK | REQUEST,
&card->dch.inst))) {
printk(KERN_ERR "MGR_ADDSTACK REQUEST dch err(%d)\n", err);
release_card(card);
if (!HFC_cnt)
HiSax_unregister(&HFC_obj);
else
err = 0;
return(err);
}
dst = card->dch.inst.st;
}
if ((err = HFC_obj.ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, &pid))) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err);
HFC_obj.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
if (!HFC_cnt)
HiSax_unregister(&HFC_obj);
else
err = 0;
return(err);
}
for (i=0; i<2; i++) {
if ((err = HFC_obj.ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST,
&card->bch[i].inst))) {
for (i = 0; i < 2; i++) {
if ((err = HFC_obj.ctrl(dst,
MGR_NEWSTACK | REQUEST, &card->bch[i].inst))) {
printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err);
HFC_obj.ctrl(card->dch.inst.st,
MGR_DELSTACK | REQUEST, NULL);
@ -2422,9 +2551,23 @@ HFC_init(void)
err = 0;
return(err);
}
card->bch[i].st = card->bch[i].inst.st;
}
if (protocol[HFC_cnt] != 0x100) { /* next not second HFC */
if ((err = HFC_obj.ctrl(dst, MGR_SETSTACK | REQUEST,
&pid))) {
printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n",
err);
HFC_obj.ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
if (!HFC_cnt)
HiSax_unregister(&HFC_obj);
else
err = 0;
return(err);
}
}
if ((err = init_card(card))) {
HFC_obj.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
HFC_obj.ctrl(dst, MGR_DELSTACK | REQUEST, NULL);
if (!HFC_cnt)
HiSax_unregister(&HFC_obj);
else

View File

@ -93,78 +93,79 @@ struct hfcB_hw {
#define BC_FLG_LL_CONN 15
typedef struct _bchannel_t {
int channel;
int protocol;
int Flag;
int debug;
hisaxinstance_t inst;
hisaxdevice_t *dev;
u_char (*BC_Read_Reg)(void *, int, u_char);
void (*BC_Write_Reg)(void *, int, u_char, u_char);
struct sk_buff *next_skb;
u_char *tx_buf;
int tx_idx;
int tx_len;
u_char *rx_buf;
int rx_idx;
struct sk_buff_head rqueue; /* B-Channel receive Queue */
u_char *blog;
u_char *conmsg;
struct timer_list transbusy;
struct tq_struct tqueue;
int event;
int err_crc;
int err_tx;
int err_rdo;
int err_inv;
int channel;
int protocol;
int Flag;
int debug;
hisaxstack_t *st;
hisaxinstance_t inst;
hisaxdevice_t *dev;
u_char (*BC_Read_Reg)(void *, int, u_char);
void (*BC_Write_Reg)(void *, int, u_char, u_char);
struct sk_buff *next_skb;
u_char *tx_buf;
int tx_idx;
int tx_len;
u_char *rx_buf;
int rx_idx;
struct sk_buff_head rqueue; /* B-Channel receive Queue */
u_char *blog;
u_char *conmsg;
struct timer_list transbusy;
struct tq_struct tqueue;
int event;
int err_crc;
int err_tx;
int err_rdo;
int err_inv;
union {
struct hdlc_hw hdlc;
struct isar_hw isar;
} hw;
struct hdlc_hw hdlc;
struct isar_hw isar;
} hw;
} bchannel_t;
struct avm_hw {
unsigned int cfg_reg;
unsigned int isac;
unsigned int hscx[2];
unsigned int isacfifo;
unsigned int hscxfifo[2];
unsigned int counter;
unsigned int cfg_reg;
unsigned int isac;
unsigned int hscx[2];
unsigned int isacfifo;
unsigned int hscxfifo[2];
unsigned int counter;
};
struct sedl_hw {
unsigned int cfg_reg;
unsigned int adr;
unsigned int isac;
unsigned int hscx;
unsigned int reset_on;
unsigned int reset_off;
struct isar_reg isar;
unsigned int chip;
unsigned int bus;
unsigned intcfg_reg;
unsigned int adr;
unsigned int isac;
unsigned int hscx;
unsigned int reset_on;
unsigned int reset_off;
struct isar_reg isar;
unsigned int chip;
unsigned int bus;
};
struct arcofi_msg {
struct arcofi_msg *next;
u_char receive;
u_char len;
u_char msg[10];
struct arcofi_msg *next;
u_char receive;
u_char len;
u_char msg[10];
};
struct isac_chip {
int ph_state;
u_char *mon_tx;
u_char *mon_rx;
int mon_txp;
int mon_txc;
int mon_rxp;
struct arcofi_msg *arcofi_list;
struct timer_list arcofitimer;
wait_queue_head_t arcofi_wait;
u_char arcofi_bc;
u_char arcofi_state;
u_char mocr;
u_char adf2;
int ph_state;
u_char *mon_tx;
u_char *mon_rx;
int mon_txp;
int mon_txc;
int mon_rxp;
struct arcofi_msg *arcofi_list;
struct timer_list arcofitimer;
wait_queue_head_t arcofi_wait;
u_char arcofi_bc;
u_char arcofi_state;
u_char mocr;
u_char adf2;
};
struct hfcpci_chip {
@ -187,31 +188,31 @@ struct hfcpci_chip {
#define FLG_HW_INIT 13
typedef struct _dchannel_t {
hisaxinstance_t inst;
u_int DFlags;
u_char (*readisac) (void *, u_char);
void (*writeisac) (void *, u_char, u_char);
void (*readisacfifo) (void *, u_char *, int);
void (*writeisacfifo) (void *, u_char *, int);
char *dlog;
int debug;
u_char *rx_buf;
int rx_idx;
struct sk_buff *next_skb;
u_char *tx_buf;
int tx_idx;
int tx_len;
int event;
int err_crc;
int err_tx;
int err_rx;
hisaxinstance_t inst;
u_int DFlags;
u_char (*readisac) (void *, u_char);
void (*writeisac) (void *, u_char, u_char);
void (*readisacfifo) (void *, u_char *, int);
void (*writeisacfifo) (void *, u_char *, int);
char *dlog;
int debug;
u_char *rx_buf;
int rx_idx;
struct sk_buff *next_skb;
u_char *tx_buf;
int tx_idx;
int tx_len;
int event;
int err_crc;
int err_tx;
int err_rx;
union {
struct isac_chip isac;
struct hfcpci_chip hfcpci;
} hw;
struct sk_buff_head rqueue; /* D-channel receive queue */
struct tq_struct tqueue;
struct timer_list dbusytimer;
struct isac_chip isac;
struct hfcpci_chip hfcpci;
} hw;
struct sk_buff_head rqueue; /* D-channel receive queue */
struct tq_struct tqueue;
struct timer_list dbusytimer;
} dchannel_t;
#define MON0_RX 1

View File

@ -403,6 +403,12 @@ l3dss1_get_channel_id(l3_process_t *pc, struct sk_buff *skb) {
u_char *sp, *p;
if ((sp = p = findie(skb->data, skb->len, IE_CHANNEL_ID, 0))) {
if (test_bit(FLG_EXTCID, &pc->l3->Flag)) {
if (*p != 1) {
pc->bc = 1;
return (sp);
}
}
if (*p != 1) { /* len for BRI = 1 */
if (pc->l3->debug & L3_DEB_WARN)
l3_debug(pc->l3, "wrong chid len %d", *p);
@ -768,6 +774,8 @@ l3dss1_alerting(l3_process_t *pc, u_char pr, void *arg)
}
L3DelTimer(&pc->timer); /* T304 */
newl3state(pc, 4);
pc->para.ALERTING.CHANNEL_ID =
l3dss1_get_channel_id(pc, skb);
pc->para.ALERTING.BEARER =
findie(skb->data, skb->len, IE_BEARER, 0);
pc->para.ALERTING.FACILITY =
@ -851,6 +859,8 @@ l3dss1_connect(l3_process_t *pc, u_char pr, void *arg)
}
L3DelTimer(&pc->timer); /* T310 */
newl3state(pc, 10);
pc->para.CONNECT.CHANNEL_ID =
l3dss1_get_channel_id(pc, skb);
pc->para.CONNECT.BEARER =
findie(skb->data, skb->len, IE_BEARER, 0);
pc->para.CONNECT.FACILITY =
@ -2243,13 +2253,17 @@ new_udss1(hisaxstack_t *st, hisax_pid_t *pid)
int_error();
return(-ENOPROTOOPT);
}
if (pid->protocol[3] != ISDN_PID_L3_DSS1USER) {
if ((pid->protocol[3] & ~ISDN_PID_FEATURE_MASK) != ISDN_PID_L3_DSS1USER) {
printk(KERN_ERR "udss1 create failed prt %x\n",
pid->protocol[3]);
kfree(nl3);
return(-ENOPROTOOPT);
}
init_l3(nl3);
if (pid->protocol[3] & ISDN_PID_L3_DF_PTP)
test_and_set_bit(FLG_PTP, &nl3->Flag);
if (pid->protocol[3] & ISDN_PID_L3_DF_EXTCID)
test_and_set_bit(FLG_EXTCID, &nl3->Flag);
if (!(nl3->global = kmalloc(sizeof(l3_process_t), GFP_ATOMIC))) {
printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n");
release_l3(nl3);
@ -2360,7 +2374,9 @@ int UDSS1Init(void)
strcpy(tmp, dss1_revision);
printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp));
u_dss1.name = MName;
u_dss1.DPROTO.protocol[3] = ISDN_PID_L3_DSS1USER;
u_dss1.DPROTO.protocol[3] = ISDN_PID_L3_DSS1USER |
ISDN_PID_L3_DF_PTP |
ISDN_PID_L3_DF_EXTCID;
u_dss1.own_ctrl = udss1_manager;
u_dss1.prev = NULL;
u_dss1.next = NULL;

View File

@ -2096,7 +2096,7 @@ new_l2(hisaxstack_t *st, hisax_pid_t *pid, layer2_t **newl2) {
int_error();
return(-ENOPROTOOPT);
}
switch(pid->protocol[2]) {
switch(pid->protocol[2] & ~ISDN_PID_FEATURE_MASK) {
case ISDN_PID_L2_LAPD_NET:
sprintf(nl2->inst.name, "lapdn %x", st->id);
test_and_set_bit(FLG_LAPD, &nl2->flag);
@ -2122,6 +2122,11 @@ new_l2(hisaxstack_t *st, hisax_pid_t *pid, layer2_t **newl2) {
test_and_set_bit(FLG_ORIG, &nl2->flag);
nl2->sapi = 0;
nl2->tei = -1;
if (pid->protocol[2] & ISDN_PID_L2_DF_PTP) {
test_and_set_bit(FLG_PTP, &nl2->flag);
test_and_set_bit(FLG_FIXED_TEI, &nl2->flag);
nl2->tei = 0;
}
nl2->maxlen = MAX_DFRAME_LEN;
nl2->window = 1;
nl2->T200 = 1000;
@ -2367,7 +2372,9 @@ int Isdnl2Init(void)
int err;
isdnl2.name = MName;
isdnl2.DPROTO.protocol[2] = ISDN_PID_L2_LAPD | ISDN_PID_L2_LAPD_NET;
isdnl2.DPROTO.protocol[2] = ISDN_PID_L2_LAPD |
ISDN_PID_L2_LAPD_NET |
ISDN_PID_L2_DF_PTP;
isdnl2.BPROTO.protocol[2] = ISDN_PID_L2_B_X75SLP;
isdnl2.own_ctrl = l2_manager;
isdnl2.prev = NULL;

View File

@ -25,6 +25,7 @@
#define FLG_L2BLOCK 1
#define FLG_PTP 2
#define FLG_EXTCID 3
typedef struct _L3Timer {
struct _l3_process *pc;

View File

@ -367,16 +367,12 @@ void ncciInitSt(Ncci_t *ncci)
printk(KERN_DEBUG "ncciInitSt ch(%d) cplci->contr->binst(%p)\n",
cplci->bchannel & 3, cplci->contr->binst);
pid.protocol[4] = ISDN_PID_L4_B_CAPI20;
if ((cplci->bchannel & 0xf4) == 0x80) {
ncci->binst = contrSelChannel(cplci->contr, cplci->bchannel & 3);
} else {
printk(KERN_WARNING "ncciInitSt channel %x not supported\n",
cplci->bchannel);
}
ncci->binst = contrSelChannel(cplci->contr, cplci->bchannel);
if (!ncci->binst) {
int_error();
return;
}
}
printk(KERN_DEBUG "ncciInitSt ncci->binst(%p)\n", ncci->binst);
memset(&ncci->binst->inst.pid, 0, sizeof(hisax_pid_t));
ncci->binst->inst.data = ncci;
ncci->binst->inst.pid.layermask = ISDN_LAYER(4);

View File

@ -477,7 +477,8 @@ unregister_instance(hisaxinstance_t *inst) {
printk(KERN_WARNING __FUNCTION__": no layer found\n");
err = -ENODEV;
}
inst->st = NULL;
if (inst->st && (inst->st->mgr != inst))
inst->st = NULL;
}
REMOVE_FROM_LISTBASE(inst, hisax_instlist);
inst->prev = inst->next = NULL;

View File

@ -1,6 +1,7 @@
/* $Id$
*
* Copyright 2000 by Karsten Keil <kkeil@isdn4linux.de>
*
*/
#include <linux/types.h>
@ -160,8 +161,8 @@ next_frame_len(hisaxport_t *port)
} else {
len = IFRAME_HEAD_SIZE + *lp;
}
if (len < port->cnt) {
int_errtxt("size mismatch %d/%d", len, port->cnt);
if (len > port->cnt) {
int_errtxt("size mismatch %d/%d/%d", *lp, len, port->cnt);
return(0);
}
return(len);
@ -360,6 +361,22 @@ new_devstack(hisaxdevice_t *dev, stack_info_t *si)
return(inst.st->id);
}
static hisaxstack_t *
sel_channel(u_int addr, u_int channel)
{
hisaxstack_t *st;
channel_info_t ci;
st = get_stack4id(addr);
if (!st)
return(NULL);
ci.channel = channel;
ci.st.p = NULL;
if (udev_obj.ctrl(st, MGR_SELCHANNEL | REQUEST, &ci))
return(NULL);
return(ci.st.p);
}
static int
create_layer(hisaxdevice_t *dev, layer_info_t *linfo, int *adr)
{
@ -1099,6 +1116,20 @@ hisax_wdata_if(hisaxdevice_t *dev, iframe_t *iff, int len) {
off.len = -ENODEV;
hisax_rdata(dev, &off, 1);
break;
case (MGR_SELCHANNEL | REQUEST):
used = head;
off.addr = iff->addr;
off.prim = MGR_SELCHANNEL | CONFIRM;
st = sel_channel(iff->addr, iff->dinfo);
if (st) {
off.len = 0;
off.dinfo = st->id;
} else {
off.dinfo = 0;
off.len = -ENODEV;
}
hisax_rdata(dev, &off, 1);
break;
case (MGR_GETLAYERID | REQUEST):
used = head;
off.addr = iff->addr;

View File

@ -37,6 +37,7 @@
#define MGR_CLEARSTACK 0x0f1500
#define MGR_REGLAYER 0x0f1600
#define MGR_UNREGLAYER 0x0f1700
#define MGR_SELCHANNEL 0x0f1800
#define MGR_GETLAYER 0x0f2100
#define MGR_GETLAYERID 0x0f2200
#define MGR_NEWLAYER 0x0f2300
@ -225,6 +226,12 @@
#define ISDN_PID_BCHANNEL_BIT 0x40000000
#define ISDN_PID_LAYER_MASK 0x0f000000
#define ISDN_PID_LAYER(n) (n<<24)
#define ISDN_PID_FEATURE_MASK 0x00F00000
#define ISDN_PID_L2_DF_PTP 0x00100000
#define ISDN_PID_L2_DF_MULT_TEI 0x00200000
#define ISDN_PID_L3_DF_PTP 0x00100000
#define ISDN_PID_L3_DF_EXTCID 0x00200000
#define HISAX_CORE_DEVICE 0
#define HISAX_RAW_DEVICE 128
@ -269,6 +276,16 @@
#define DUMMY_CR_FLAG 0x7FFFFF00
#define CONTROLER_MASK 0x000000FF
/* stack channel values */
#define CHANNEL_NUMBER 0x000000FF
#define CHANNEL_RXSLOT 0x0000FF00
#define CHANNEL_TXSLOT 0x00FF0000
#define CHANNEL_EXTINFO 0xFF000000
#define CHANNEL_NR_D 0x00000000
#define CHANNEL_NR_B1 0x00000001
#define CHANNEL_NR_B2 0x00000002
#define CHANNEL_EXT_PCM 0x01000000
#define CHANNEL_EXT_REV 0x02000000
/* interface extentions */
#define EXT_STACK_CLONE 0x00000001
@ -365,6 +382,13 @@ typedef struct _interface_info {
int stat;
} interface_info_t;
typedef struct _channel_info {
u_int channel;
union {
u_int id;
void *p;
} st;
} channel_info_t;
/* l3 pointer arrays */