- make mqueue branch HEAD
This commit is contained in:
parent
44cf601712
commit
56f18961c0
|
@ -67,6 +67,18 @@ config MISDN_HFCUSB
|
|||
Enable support for USB ISDN TAs with Cologne Chip AG's
|
||||
HFC-S USB ISDN Controller
|
||||
|
||||
config MISDN_HFCMINI
|
||||
bool "Support for 'HFC-S mini' based TAs"
|
||||
depends on PCI
|
||||
help
|
||||
Enable support for Cologne Chip AG's 'HFC-S mini' Evaluation Card
|
||||
|
||||
config MISDN_XHFC
|
||||
bool "Support for XHFC based cards"
|
||||
depends on PCI
|
||||
help
|
||||
Enable support for Cologne Chips AG's XHFC Evaluation Card
|
||||
|
||||
config MISDN_SPEEDFAX
|
||||
bool "Support for Sedlbauer Speedfax+"
|
||||
depends on PCI || ISA
|
||||
|
@ -85,12 +97,39 @@ config MISDN_DSP
|
|||
Enable support for digital audio processing capability.
|
||||
This module may be used for special applications that require
|
||||
cross connecting of bchannels, conferencing, dtmf decoding
|
||||
tone generation, and Blowfish encryption and decryption.
|
||||
echo cancelation, tone generation, and Blowfish encryption and
|
||||
decryption.
|
||||
It may use hardware features if available.
|
||||
E.g. it is required for PBX4Linux. Go to http://isdn.jolly.de
|
||||
and get more informations about this module and it's usage.
|
||||
If unsure, say 'N'.
|
||||
|
||||
config MISDN_LOOP
|
||||
bool "Loop device"
|
||||
help
|
||||
Enable support for loop device.
|
||||
This module may be used for special applications that provide
|
||||
bchannel data from user space. Applications can directly
|
||||
access bchannels, so applications can be integrated into DSP
|
||||
audio processing.
|
||||
E.g. it is required for PBX4Linux. Go to http://isdn.jolly.de
|
||||
and get more informations about this module and it's usage.
|
||||
If unsure, say 'N'.
|
||||
|
||||
config MISDN_L1OIP
|
||||
bool "ISDN over IP tunnel"
|
||||
help
|
||||
Enable support for ISDN over IP tunnel.
|
||||
|
||||
It features:
|
||||
- layer 1 control via network keepalive frames
|
||||
- dynamic IP exchange, if one or both peers have dynamic IPs
|
||||
- channel bundeling for reduced IP overhead
|
||||
- BRI (S0) and PRI (S2M) interface
|
||||
|
||||
NOTE: This protocol is called 'Layer 1 over IP' and is not
|
||||
compatible with ISDNoIP (Agfeo) or TDMoIP.
|
||||
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# EXTRA_CFLAGS += -S -g
|
||||
#
|
||||
|
||||
ifdef MINCLUDES
|
||||
CFLAGS += -I$(MINCLUDES)
|
||||
endif
|
||||
ifdef CONFIG_MISDN_MEMDEBUG
|
||||
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
|
||||
endif
|
||||
|
@ -28,8 +31,13 @@ ifdef CONFIG_MISDN_HFCUSB
|
|||
obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_HFCMINI
|
||||
obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_SPEEDFAX
|
||||
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
|
||||
# obj-$(CONFIG_MISDN_DRV) += faxl3.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_W6692
|
||||
|
@ -40,10 +48,18 @@ ifdef CONFIG_MISDN_HFCMULTI
|
|||
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_XHFC
|
||||
obj-$(CONFIG_MISDN_DRV) += xhfc.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_DSP
|
||||
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_LOOP
|
||||
obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_I4L_CAPI_LAYER
|
||||
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
|
||||
endif
|
||||
|
@ -54,11 +70,14 @@ sedlfax-objs := sedl_fax.o isar.o
|
|||
avmfritz-objs := avm_fritz.o
|
||||
hfcpci-objs := hfc_pci.o
|
||||
hfcsusb-objs := hfcs_usb.o
|
||||
hfcsmini-objs := hfcs_mini.o
|
||||
w6692pci-objs := w6692.o
|
||||
hfcmulti-objs := hfc_multi.o
|
||||
xhfc-objs := xhfc_su.o xhfc_pci2pi.o
|
||||
mISDN_isac-objs := isac.o arcofi.o
|
||||
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
|
||||
dchannel.o bchannel.o l3helper.o
|
||||
channel.o l3helper.o \
|
||||
sysfs_obj.o sysfs_inst.o sysfs_st.o
|
||||
ifdef CONFIG_MISDN_MEMDEBUG
|
||||
mISDN_core-objs += memdbg.o
|
||||
endif
|
||||
|
@ -70,8 +89,9 @@ mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.
|
|||
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
|
||||
supp_serv.o
|
||||
mISDN_dtmf-objs := dtmf.o
|
||||
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
|
||||
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
|
||||
mISDN_loop-objs := loop.o
|
||||
mISDN_x25dte-objs := x25_dte.o x25_l3.o
|
||||
I4LmISDN-objs := i4l_mISDN.o
|
||||
|
||||
include Rules.mISDN
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# EXTRA_CFLAGS += -S -g
|
||||
#
|
||||
|
||||
ifdef MINCLUDES
|
||||
CFLAGS += -I$(MINCLUDES)
|
||||
endif
|
||||
ifdef CONFIG_MISDN_MEMDEBUG
|
||||
EXTRA_CFLAGS += -DMISDN_MEMDEBUG
|
||||
endif
|
||||
|
@ -28,9 +31,13 @@ ifdef CONFIG_MISDN_HFCUSB
|
|||
obj-$(CONFIG_MISDN_DRV) += hfcsusb.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_HFCMINI
|
||||
obj-$(CONFIG_MISDN_DRV) += hfcsmini.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_SPEEDFAX
|
||||
obj-$(CONFIG_MISDN_DRV) += sedlfax.o
|
||||
obj-$(CONFIG_MISDN_DRV) += faxl3.o
|
||||
# obj-$(CONFIG_MISDN_DRV) += faxl3.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_W6692
|
||||
|
@ -41,10 +48,18 @@ ifdef CONFIG_MISDN_HFCMULTI
|
|||
obj-$(CONFIG_MISDN_DRV) += hfcmulti.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_XHFC
|
||||
obj-$(CONFIG_MISDN_DRV) += xhfc.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_DSP
|
||||
obj-$(CONFIG_MISDN_DRV) += mISDN_dsp.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_MISDN_LOOP
|
||||
obj-$(CONFIG_MISDN_DRV) += mISDN_loop.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_I4L_CAPI_LAYER
|
||||
obj-$(CONFIG_MISDN_DRV) += I4LmISDN.o
|
||||
endif
|
||||
|
@ -55,11 +70,14 @@ sedlfax-objs := sedl_fax.o isar.o
|
|||
avmfritz-objs := avm_fritz.o
|
||||
hfcpci-objs := hfc_pci.o
|
||||
hfcsusb-objs := hfcs_usb.o
|
||||
hfcsmini-objs := hfcs_mini.o
|
||||
w6692pci-objs := w6692.o
|
||||
hfcmulti-objs := hfc_multi.o
|
||||
xhfc-objs := xhfc_su.o xhfc_pci2pi.o
|
||||
mISDN_isac-objs := isac.o arcofi.o
|
||||
mISDN_core-objs := core.o stack.o udevice.o helper.o debug.o fsm.o \
|
||||
dchannel.o bchannel.o l3helper.o
|
||||
channel.o l3helper.o \
|
||||
sysfs_obj.o sysfs_inst.o sysfs_st.o
|
||||
ifdef CONFIG_MISDN_MEMDEBUG
|
||||
mISDN_core-objs += memdbg.o
|
||||
endif
|
||||
|
@ -71,6 +89,9 @@ mISDN_capi-objs := capi.o contr.o listen.o appl.o plci.o app_plci.o ncci.o asn1.
|
|||
asn1_basic_service.o asn1_address.o asn1_enc.o capi_enc.o \
|
||||
supp_serv.o
|
||||
mISDN_dtmf-objs := dtmf.o
|
||||
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o
|
||||
mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_cancel.o
|
||||
mISDN_loop-objs := loop.o
|
||||
mISDN_x25dte-objs := x25_dte.o x25_l3.o
|
||||
I4LmISDN-objs := i4l_mISDN.o
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -161,37 +161,14 @@ FacilityReq(Application_t *appl, struct sk_buff *skb)
|
|||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
__u16
|
||||
void
|
||||
ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
|
||||
{
|
||||
Plci_t *plci;
|
||||
AppPlci_t *aplci;
|
||||
Ncci_t *ncci;
|
||||
__u16 ret = CAPI_NOERROR;
|
||||
__u16 ret;
|
||||
|
||||
switch (CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data))) {
|
||||
// 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_DISCONNECT_B3_RESP:
|
||||
case CAPI_RESET_B3_REQ:
|
||||
case CAPI_RESET_B3_RESP:
|
||||
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
|
||||
if (!aplci) {
|
||||
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
|
||||
goto free;
|
||||
}
|
||||
ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT);
|
||||
if (!ncci) {
|
||||
int_error();
|
||||
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
|
||||
goto free;
|
||||
}
|
||||
ret = ncciSendMessage(ncci, skb);
|
||||
break;
|
||||
// new NCCI
|
||||
case CAPI_CONNECT_B3_REQ:
|
||||
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
|
||||
|
@ -201,6 +178,15 @@ ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
|
|||
}
|
||||
ConnectB3Request(aplci, skb);
|
||||
break;
|
||||
// maybe already down NCCI
|
||||
case CAPI_DISCONNECT_B3_RESP:
|
||||
aplci = getAppPlci4addr(appl, CAPIMSG_CONTROL(skb->data));
|
||||
if (!aplci) {
|
||||
AnswerMessage2Application(appl, skb, CapiIllContrPlciNcci);
|
||||
goto free;
|
||||
}
|
||||
DisconnectB3Request(aplci, skb);
|
||||
break;
|
||||
// for PLCI state machine
|
||||
case CAPI_INFO_REQ:
|
||||
case CAPI_ALERT_REQ:
|
||||
|
@ -215,6 +201,9 @@ ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
|
|||
goto free;
|
||||
}
|
||||
ret = AppPlciSendMessage(aplci, skb);
|
||||
if (ret) {
|
||||
int_error();
|
||||
}
|
||||
break;
|
||||
case CAPI_CONNECT_REQ:
|
||||
if (ControllerNewPlci(appl->contr, &plci, MISDN_ID_ANY)) {
|
||||
|
@ -227,11 +216,17 @@ ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
|
|||
goto free;
|
||||
}
|
||||
ret = AppPlciSendMessage(aplci, skb);
|
||||
if (ret) {
|
||||
int_error();
|
||||
}
|
||||
break;
|
||||
|
||||
// for LISTEN state machine
|
||||
case CAPI_LISTEN_REQ:
|
||||
ret = listenSendMessage(appl, skb);
|
||||
if (ret) {
|
||||
int_error();
|
||||
}
|
||||
break;
|
||||
|
||||
// other
|
||||
|
@ -248,13 +243,12 @@ ApplicationSendMessage(Application_t *appl, struct sk_buff *skb)
|
|||
default:
|
||||
applDebug(appl, CAPI_DBG_WARN, "applSendMessage: %#x %#x not handled!",
|
||||
CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
|
||||
ret = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
|
||||
break;
|
||||
}
|
||||
return(ret);
|
||||
return;
|
||||
free:
|
||||
dev_kfree_skb(skb);
|
||||
return(ret);
|
||||
return;
|
||||
}
|
||||
|
||||
AppPlci_t *
|
||||
|
|
|
@ -8,19 +8,20 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "dchannel.h"
|
||||
#include "channel.h"
|
||||
#include "layer1.h"
|
||||
#include "isac.h"
|
||||
#include "arcofi.h"
|
||||
#include "debug.h"
|
||||
#include "helper.h"
|
||||
|
||||
#define ARCOFI_TIMER_VALUE 20
|
||||
|
||||
static void
|
||||
add_arcofi_timer(dchannel_t *dch) {
|
||||
add_arcofi_timer(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
init_timer(&isac->arcofitimer);
|
||||
|
@ -29,7 +30,7 @@ add_arcofi_timer(dchannel_t *dch) {
|
|||
}
|
||||
|
||||
static void
|
||||
send_arcofi(dchannel_t *dch) {
|
||||
send_arcofi(channel_t *dch) {
|
||||
u_char val;
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
|
@ -45,15 +46,15 @@ send_arcofi(dchannel_t *dch) {
|
|||
}
|
||||
isac->mocr &= 0x0f;
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_MOSR);
|
||||
dch->write_reg(dch->inst.data, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
|
||||
isac->mocr |= 0x10;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
}
|
||||
|
||||
int
|
||||
arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
||||
arcofi_fsm(channel_t *dch, int event, void *data) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (dch->debug & L1_DEB_MONITOR) {
|
||||
|
@ -61,7 +62,7 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
}
|
||||
if (event == ARCOFI_TIMEOUT) {
|
||||
isac->arcofi_state = ARCOFI_NOP;
|
||||
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->DFlags);
|
||||
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->Flags);
|
||||
wake_up(&isac->arcofi_wait);
|
||||
return(1);
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
isac->arcofi_list->next;
|
||||
send_arcofi(dch);
|
||||
} else {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
isac->arcofi_state = ARCOFI_NOP;
|
||||
|
@ -95,13 +96,20 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
break;
|
||||
case ARCOFI_RECEIVE:
|
||||
if (event == ARCOFI_RX_END) {
|
||||
struct sk_buff *skb = data;
|
||||
|
||||
// FIXME handle message
|
||||
if (skb)
|
||||
kfree_skb(skb);
|
||||
else
|
||||
int_error();
|
||||
if (isac->arcofi_list->next) {
|
||||
isac->arcofi_list =
|
||||
isac->arcofi_list->next;
|
||||
isac->arcofi_state = ARCOFI_TRANSMIT;
|
||||
send_arcofi(dch);
|
||||
} else {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
isac->arcofi_state = ARCOFI_NOP;
|
||||
|
@ -117,21 +125,21 @@ arcofi_fsm(dchannel_t *dch, int event, void *data) {
|
|||
}
|
||||
|
||||
static void
|
||||
arcofi_timer(dchannel_t *dch) {
|
||||
arcofi_timer(channel_t *dch) {
|
||||
arcofi_fsm(dch, ARCOFI_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
clear_arcofi(dchannel_t *dch) {
|
||||
clear_arcofi(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
|
||||
del_timer(&isac->arcofitimer);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init_arcofi(dchannel_t *dch) {
|
||||
init_arcofi(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
isac->arcofitimer.function = (void *) arcofi_timer;
|
||||
|
|
|
@ -27,6 +27,6 @@ struct arcofi_msg {
|
|||
u_char msg[10];
|
||||
};
|
||||
|
||||
extern int arcofi_fsm(dchannel_t *, int, void *);
|
||||
extern void init_arcofi(dchannel_t *);
|
||||
extern void clear_arcofi(dchannel_t *);
|
||||
extern int arcofi_fsm(channel_t *, int, void *);
|
||||
extern void init_arcofi(channel_t *);
|
||||
extern void clear_arcofi(channel_t *);
|
||||
|
|
|
@ -15,6 +15,13 @@ typedef enum {
|
|||
reject = 4,
|
||||
} asn1Component;
|
||||
|
||||
typedef enum {
|
||||
GeneralP = 0,
|
||||
InvokeP = 1,
|
||||
ReturnResultP= 2,
|
||||
ReturnErrorP = 3,
|
||||
} asn1Problem;
|
||||
|
||||
struct PublicPartyNumber {
|
||||
int publicTypeOfNumber;
|
||||
char numberDigits[30];
|
||||
|
@ -88,20 +95,28 @@ struct asn1ReturnError {
|
|||
__u16 errorValue;
|
||||
};
|
||||
|
||||
struct asn1Reject {
|
||||
int invokeId;
|
||||
asn1Problem problem;
|
||||
__u16 problemValue;
|
||||
};
|
||||
|
||||
struct asn1_parm {
|
||||
asn1Component comp;
|
||||
union {
|
||||
struct asn1Invoke inv;
|
||||
struct asn1ReturnResult retResult;
|
||||
struct asn1ReturnError retError;
|
||||
struct asn1Reject reject;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
#undef ASN1_DEBUG
|
||||
// #define ASN1_DEBUG
|
||||
|
||||
#ifdef ASN1_DEBUG
|
||||
#define print_asn1msg(dummy, fmt, args...) printk(fmt, ## args)
|
||||
#define print_asn1msg(dummy, fmt, args...) printk(KERN_DEBUG fmt, ## args)
|
||||
#else
|
||||
#define print_asn1msg(dummy, fmt, args...)
|
||||
#endif
|
||||
|
@ -194,7 +209,7 @@ int ParseLen(u_char *p, u_char *end, int *len);
|
|||
} else { \
|
||||
if (!(the_tag) & ASN1_TAG_OPT) { \
|
||||
print_asn1msg(PRT_DEBUG_DECODE, " DEBUG> err 4 %s:%d\n", __FUNCTION__, __LINE__); \
|
||||
return -1; \
|
||||
return -1; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
|
|
@ -137,6 +137,68 @@ ParseReturnErrorComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dumm
|
|||
return p - beg;
|
||||
}
|
||||
|
||||
int
|
||||
ParseProblemValue(struct asn1_parm *pc, u_char *p, u_char *end, asn1Problem prob)
|
||||
{
|
||||
INIT;
|
||||
|
||||
pc->u.reject.problem = prob;
|
||||
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "ParseProblemValue: %d %d\n", prob, *p);
|
||||
pc->u.reject.problemValue = *p++;
|
||||
return p - beg;
|
||||
}
|
||||
|
||||
int
|
||||
ParseRejectProblem(struct asn1_parm *pc, u_char *p, u_char *end)
|
||||
{
|
||||
INIT;
|
||||
|
||||
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 0, GeneralP);
|
||||
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 1, InvokeP);
|
||||
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 2, ReturnResultP);
|
||||
XCHOICE_1(ParseProblemValue, ASN1_TAG_CONTEXT_SPECIFIC, 3, ReturnErrorP);
|
||||
XCHOICE_DEFAULT;
|
||||
}
|
||||
|
||||
int
|
||||
ParseRejectComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
|
||||
{
|
||||
int invokeId = -1;
|
||||
int rval;
|
||||
INIT;
|
||||
|
||||
pc->comp = reject;
|
||||
|
||||
XSEQUENCE_OPT_1(ParseInvokeId, ASN1_TAG_INTEGER, ASN1_NOT_TAGGED, &invokeId);
|
||||
XSEQUENCE_OPT(ParseNull, ASN1_TAG_NULL, ASN1_NOT_TAGGED);
|
||||
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: invokeId %d\n", invokeId);
|
||||
|
||||
pc->u.reject.invokeId = invokeId;
|
||||
|
||||
rval = ParseRejectProblem(pc, p, end);
|
||||
|
||||
print_asn1msg(PRT_DEBUG_DECODE, "ParseRejectComponent: rval %d\n", rval);
|
||||
|
||||
if (rval > 0)
|
||||
p += rval;
|
||||
else
|
||||
return(-1);
|
||||
|
||||
return p - beg;
|
||||
}
|
||||
|
||||
int
|
||||
ParseUnknownComponent(struct asn1_parm *pc, u_char *p, u_char *end, int dummy)
|
||||
{
|
||||
int invokeId;
|
||||
INIT;
|
||||
|
||||
pc->comp = tag;
|
||||
return end - beg;
|
||||
}
|
||||
|
||||
int
|
||||
ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
|
||||
{
|
||||
|
@ -145,7 +207,17 @@ ParseComponent(struct asn1_parm *pc, u_char *p, u_char *end)
|
|||
XCHOICE(ParseInvokeComponent, ASN1_TAG_SEQUENCE, 1);
|
||||
XCHOICE(ParseReturnResultComponent, ASN1_TAG_SEQUENCE, 2);
|
||||
XCHOICE(ParseReturnErrorComponent, ASN1_TAG_SEQUENCE, 3);
|
||||
// XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
|
||||
XCHOICE(ParseRejectComponent, ASN1_TAG_SEQUENCE, 4);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 5);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 6);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 7);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 8);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 9);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 10);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 11);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 12);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 13);
|
||||
XCHOICE(ParseUnknownComponent, ASN1_TAG_SEQUENCE, 14);
|
||||
XCHOICE_DEFAULT;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,14 @@ int encodeNull(__u8 *dest)
|
|||
return 2;
|
||||
}
|
||||
|
||||
int encodeBoolean(__u8 *dest, __u32 i)
|
||||
{
|
||||
dest[0] = 0x01; // BOOLEAN
|
||||
dest[1] = 1; // length 1
|
||||
dest[3] = i ? 1:0; // Value
|
||||
return 3;
|
||||
}
|
||||
|
||||
int encodeInt(__u8 *dest, __u32 i)
|
||||
{
|
||||
__u8 *p;
|
||||
|
@ -176,3 +184,18 @@ int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameter
|
|||
return p - dest;
|
||||
}
|
||||
|
||||
int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD)
|
||||
{
|
||||
__u8 *p;
|
||||
|
||||
dest[0] = 0x30; // sequence
|
||||
dest[1] = 0; // length
|
||||
p = &dest[2];
|
||||
|
||||
p += encodeAddress(p, CD->DeflectedToNumber, CD->DeflectedToSubaddress);
|
||||
p += encodeBoolean(p, CD->PresentationAllowed);
|
||||
|
||||
dest[1] = p - &dest[2];
|
||||
return p - dest;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "asn1.h"
|
||||
|
||||
int encodeNull(__u8 *dest);
|
||||
int encodeBoolean(__u8 *dest, __u32 i);
|
||||
int encodeInt(__u8 *dest, __u32 i);
|
||||
int encodeEnum(__u8 *dest, __u32 i);
|
||||
int encodeNumberDigits(__u8 *dest, __u8 *nd, __u8 len);
|
||||
|
@ -15,3 +16,4 @@ int encodeAddress(__u8 *dest, __u8 *facilityPartyNumber, __u8 *calledPartySubadd
|
|||
int encodeActivationDiversion(__u8 *dest, struct FacReqCFActivate *CFActivate);
|
||||
int encodeDeactivationDiversion(__u8 *dest,struct FacReqCFDeactivate *CFDeactivate);
|
||||
int encodeInterrogationDiversion(__u8 *dest, struct FacReqCFInterrogateParameters *params);
|
||||
int encodeInvokeDeflection(__u8 *dest, struct FacReqCDeflection *CD);
|
||||
|
|
|
@ -17,16 +17,11 @@
|
|||
#include <linux/isapnp.h>
|
||||
#endif
|
||||
#include <linux/delay.h>
|
||||
#include "dchannel.h"
|
||||
#include "bchannel.h"
|
||||
#include "channel.h"
|
||||
#include "isac.h"
|
||||
#include "layer1.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define SPIN_DEBUG
|
||||
#define LOCK_STATISTIC
|
||||
#include "hw_lock.h"
|
||||
|
||||
static const char *avm_fritz_rev = "$Revision$";
|
||||
|
||||
|
@ -131,34 +126,29 @@ typedef struct hdlc_hw {
|
|||
|
||||
typedef struct _fritzpnppci {
|
||||
struct list_head list;
|
||||
void *pdev;
|
||||
union {
|
||||
#if defined(CONFIG_PNP)
|
||||
#ifdef NEW_ISAPNP
|
||||
struct pnp_dev *pnp;
|
||||
#else
|
||||
struct pci_dev *pnp;
|
||||
#endif
|
||||
#endif
|
||||
struct pci_dev *pci;
|
||||
} dev;
|
||||
u_int type;
|
||||
u_int irq;
|
||||
u_int irqcnt;
|
||||
u_int addr;
|
||||
mISDN_HWlock_t lock;
|
||||
spinlock_t lock;
|
||||
isac_chip_t isac;
|
||||
hdlc_hw_t hdlc[2];
|
||||
dchannel_t dch;
|
||||
bchannel_t bch[2];
|
||||
channel_t dch;
|
||||
channel_t bch[2];
|
||||
u_char ctrlreg;
|
||||
} fritzpnppci;
|
||||
|
||||
|
||||
static int lock_dev(void *data, int nowait)
|
||||
{
|
||||
register mISDN_HWlock_t *lock = &((fritzpnppci *)data)->lock;
|
||||
|
||||
return(lock_HW(lock, nowait));
|
||||
}
|
||||
|
||||
static void unlock_dev(void *data)
|
||||
{
|
||||
register mISDN_HWlock_t *lock = &((fritzpnppci *)data)->lock;
|
||||
|
||||
unlock_HW(lock);
|
||||
}
|
||||
|
||||
/* Interface functions */
|
||||
|
||||
static u_char
|
||||
|
@ -244,11 +234,11 @@ fcpci2_write_isac_fifo(void *fc, unsigned char * data, int size)
|
|||
}
|
||||
|
||||
static inline
|
||||
bchannel_t *Sel_BCS(fritzpnppci *fc, int channel)
|
||||
channel_t *Sel_BCS(fritzpnppci *fc, int channel)
|
||||
{
|
||||
if (fc->bch[0].protocol && (fc->bch[0].channel == channel))
|
||||
if (test_bit(FLG_ACTIVE, &fc->bch[0].Flags) && (fc->bch[0].channel == channel))
|
||||
return(&fc->bch[0]);
|
||||
else if (fc->bch[1].protocol && (fc->bch[1].channel == channel))
|
||||
else if (test_bit(FLG_ACTIVE, &fc->bch[1].Flags) && (fc->bch[1].channel == channel))
|
||||
return(&fc->bch[1]);
|
||||
else
|
||||
return(NULL);
|
||||
|
@ -281,8 +271,8 @@ __write_ctrl_pciv2(fritzpnppci *fc, hdlc_hw_t *hdlc, int channel) {
|
|||
}
|
||||
|
||||
void
|
||||
write_ctrl(bchannel_t *bch, int which) {
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
write_ctrl(channel_t *bch, int which) {
|
||||
fritzpnppci *fc = bch->inst.privat;
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
|
||||
if (fc->dch.debug & L1_DEB_HSCX)
|
||||
|
@ -343,48 +333,64 @@ read_status(fritzpnppci *fc, int channel)
|
|||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
enable_hwirq(fritzpnppci *fc)
|
||||
{
|
||||
fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_hwirq(fritzpnppci *fc)
|
||||
{
|
||||
fc->ctrlreg &= ~((u_char)AVM_STATUS0_ENA_IRQ);
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
}
|
||||
|
||||
static int
|
||||
modehdlc(bchannel_t *bch, int bc, int protocol)
|
||||
modehdlc(channel_t *bch, int bc, int protocol)
|
||||
{
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
|
||||
if (bch->debug & L1_DEB_HSCX)
|
||||
mISDN_debugprint(&bch->inst, "hdlc %c protocol %x-->%x ch %d-->%d",
|
||||
'A' + bch->channel, bch->protocol, protocol, bch->channel, bc);
|
||||
'A' + bch->channel, bch->state, protocol, bch->channel, bc);
|
||||
if ((protocol != -1) && (bc != bch->channel))
|
||||
printk(KERN_WARNING "%s: fritzcard mismatch channel(%d/%d)\n", __FUNCTION__, bch->channel, bc);
|
||||
hdlc->ctrl.ctrl = 0;
|
||||
switch (protocol) {
|
||||
case (-1): /* used for init */
|
||||
bch->protocol = -1;
|
||||
bch->state = -1;
|
||||
bch->channel = bc;
|
||||
case (ISDN_PID_NONE):
|
||||
if (bch->protocol == ISDN_PID_NONE)
|
||||
if (bch->state == ISDN_PID_NONE)
|
||||
break;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
|
||||
write_ctrl(bch, 5);
|
||||
bch->protocol = ISDN_PID_NONE;
|
||||
bch->state = ISDN_PID_NONE;
|
||||
test_and_clear_bit(FLG_HDLC, &bch->Flags);
|
||||
test_and_clear_bit(FLG_TRANSPARENT, &bch->Flags);
|
||||
break;
|
||||
case (ISDN_PID_L1_B_64TRANS):
|
||||
bch->protocol = protocol;
|
||||
bch->state = protocol;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
|
||||
write_ctrl(bch, 5);
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
|
||||
write_ctrl(bch, 1);
|
||||
hdlc->ctrl.sr.cmd = 0;
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
test_and_set_bit(FLG_TRANSPARENT, &bch->Flags);
|
||||
break;
|
||||
case (ISDN_PID_L1_B_64HDLC):
|
||||
bch->protocol = protocol;
|
||||
bch->state = protocol;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
|
||||
write_ctrl(bch, 5);
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
|
||||
write_ctrl(bch, 1);
|
||||
hdlc->ctrl.sr.cmd = 0;
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
test_and_set_bit(FLG_HDLC, &bch->Flags);
|
||||
break;
|
||||
default:
|
||||
mISDN_debugprint(&bch->inst, "prot not known %x", protocol);
|
||||
|
@ -394,24 +400,30 @@ modehdlc(bchannel_t *bch, int bc, int protocol)
|
|||
}
|
||||
|
||||
static void
|
||||
hdlc_empty_fifo(bchannel_t *bch, int count)
|
||||
hdlc_empty_fifo(channel_t *bch, int count)
|
||||
{
|
||||
register u_int *ptr;
|
||||
u_char *p;
|
||||
u_char idx = bch->channel ? AVM_HDLC_2 : AVM_HDLC_1;
|
||||
int cnt=0;
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
fritzpnppci *fc = bch->inst.privat;
|
||||
|
||||
if ((fc->dch.debug & L1_DEB_HSCX) && !(fc->dch.debug & L1_DEB_HSCX_FIFO))
|
||||
mISDN_debugprint(&bch->inst, "hdlc_empty_fifo %d", count);
|
||||
if (bch->rx_idx + count > MAX_DATA_MEM) {
|
||||
if (fc->dch.debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&bch->inst, "hdlc_empty_fifo: incoming packet too large");
|
||||
if (!bch->rx_skb) {
|
||||
if (!(bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen))) {
|
||||
printk(KERN_WARNING "mISDN: B receive out of memory\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((bch->rx_skb->len + count) > bch->maxlen) {
|
||||
if (bch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&bch->inst, "hdlc_empty_fifo overrun %d",
|
||||
bch->rx_skb->len + count);
|
||||
return;
|
||||
}
|
||||
p = bch->rx_buf + bch->rx_idx;
|
||||
p = skb_put(bch->rx_skb, count);
|
||||
ptr = (u_int *)p;
|
||||
bch->rx_idx += count;
|
||||
if (fc->type == AVM_FRITZ_PCIV2) {
|
||||
while (cnt < count) {
|
||||
#ifdef __powerpc__
|
||||
|
@ -447,23 +459,23 @@ hdlc_empty_fifo(bchannel_t *bch, int count)
|
|||
}
|
||||
}
|
||||
if (fc->dch.debug & L1_DEB_HSCX_FIFO) {
|
||||
char *t = bch->blog;
|
||||
char *t = bch->log;
|
||||
|
||||
if (fc->type == AVM_FRITZ_PNP)
|
||||
p = (u_char *) ptr;
|
||||
t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
|
||||
bch->channel ? 'B' : 'A', count);
|
||||
mISDN_QuickHex(t, p, count);
|
||||
mISDN_debugprint(&bch->inst, bch->blog);
|
||||
mISDN_debugprint(&bch->inst, bch->log);
|
||||
}
|
||||
}
|
||||
|
||||
#define HDLC_FIFO_SIZE 32
|
||||
|
||||
static void
|
||||
hdlc_fill_fifo(bchannel_t *bch)
|
||||
hdlc_fill_fifo(channel_t *bch)
|
||||
{
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
fritzpnppci *fc = bch->inst.privat;
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
int count, cnt =0;
|
||||
u_char *p;
|
||||
|
@ -471,15 +483,17 @@ hdlc_fill_fifo(bchannel_t *bch)
|
|||
|
||||
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
|
||||
mISDN_debugprint(&bch->inst, "%s", __FUNCTION__);
|
||||
count = bch->tx_len - bch->tx_idx;
|
||||
if (!bch->tx_skb)
|
||||
return;
|
||||
count = bch->tx_skb->len - bch->tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
p = bch->tx_buf + bch->tx_idx;
|
||||
p = bch->tx_skb->data + bch->tx_idx;
|
||||
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XME;
|
||||
if (count > HDLC_FIFO_SIZE) {
|
||||
count = HDLC_FIFO_SIZE;
|
||||
} else {
|
||||
if (bch->protocol != ISDN_PID_L1_B_64TRANS)
|
||||
if (test_bit(FLG_HDLC, &bch->Flags))
|
||||
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
|
||||
}
|
||||
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
|
||||
|
@ -524,44 +538,49 @@ hdlc_fill_fifo(bchannel_t *bch)
|
|||
}
|
||||
}
|
||||
if (bch->debug & L1_DEB_HSCX_FIFO) {
|
||||
char *t = bch->blog;
|
||||
char *t = bch->log;
|
||||
|
||||
if (fc->type == AVM_FRITZ_PNP)
|
||||
p = (u_char *) ptr;
|
||||
t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
|
||||
bch->channel ? 'B' : 'A', count);
|
||||
mISDN_QuickHex(t, p, count);
|
||||
mISDN_debugprint(&bch->inst, bch->blog);
|
||||
mISDN_debugprint(&bch->inst, bch->log);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HDLC_irq_xpr(bchannel_t *bch)
|
||||
HDLC_irq_xpr(channel_t *bch)
|
||||
{
|
||||
if (bch->tx_idx < bch->tx_len)
|
||||
if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len)
|
||||
hdlc_fill_fifo(bch);
|
||||
else {
|
||||
if (bch->tx_skb)
|
||||
dev_kfree_skb(bch->tx_skb);
|
||||
bch->tx_idx = 0;
|
||||
if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) {
|
||||
if (bch->next_skb) {
|
||||
bch->tx_len = bch->next_skb->len;
|
||||
memcpy(bch->tx_buf, bch->next_skb->data, bch->tx_len);
|
||||
if (test_bit(FLG_TX_NEXT, &bch->Flags)) {
|
||||
bch->tx_skb = bch->next_skb;
|
||||
if (bch->tx_skb) {
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(bch->tx_skb);
|
||||
|
||||
bch->next_skb = NULL;
|
||||
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
|
||||
queue_ch_frame(bch, CONFIRM, hh->dinfo, NULL);
|
||||
hdlc_fill_fifo(bch);
|
||||
} else {
|
||||
bch->tx_len = 0;
|
||||
printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
test_and_clear_bit(FLG_TX_NEXT, &bch->Flags);
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
|
||||
}
|
||||
} else {
|
||||
bch->tx_len = 0;
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
bch->tx_skb = NULL;
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
|
||||
}
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
HDLC_irq(bchannel_t *bch, u_int stat)
|
||||
HDLC_irq(channel_t *bch, u_int stat)
|
||||
{
|
||||
int len;
|
||||
struct sk_buff *skb;
|
||||
|
@ -580,43 +599,58 @@ HDLC_irq(bchannel_t *bch, u_int stat)
|
|||
write_ctrl(bch, 1);
|
||||
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
|
||||
write_ctrl(bch, 1);
|
||||
bch->rx_idx = 0;
|
||||
if (bch->rx_skb)
|
||||
skb_trim(bch->rx_skb, 0);
|
||||
} else {
|
||||
if (!(len = (stat & HDLC_STAT_RML_MASK)>>8))
|
||||
len = 32;
|
||||
hdlc_empty_fifo(bch, len);
|
||||
if ((stat & HDLC_STAT_RME) || (bch->protocol == ISDN_PID_L1_B_64TRANS)) {
|
||||
if (!bch->rx_skb)
|
||||
goto handle_tx;
|
||||
if ((stat & HDLC_STAT_RME) || test_bit(FLG_TRANSPARENT, &bch->Flags)) {
|
||||
if (((stat & HDLC_STAT_CRCVFRRAB)==HDLC_STAT_CRCVFR) ||
|
||||
(bch->protocol == ISDN_PID_L1_B_64TRANS)) {
|
||||
if (!(skb = alloc_stack_skb(bch->rx_idx, bch->up_headerlen)))
|
||||
printk(KERN_WARNING "HDLC: receive out of memory\n");
|
||||
else {
|
||||
memcpy(skb_put(skb, bch->rx_idx),
|
||||
bch->rx_buf, bch->rx_idx);
|
||||
skb_queue_tail(&bch->rqueue, skb);
|
||||
test_bit(FLG_TRANSPARENT, &bch->Flags)) {
|
||||
if (bch->rx_skb->len < MISDN_COPY_SIZE) {
|
||||
skb = alloc_stack_skb(bch->rx_skb->len, bch->up_headerlen);
|
||||
if (skb) {
|
||||
memcpy(skb_put(skb, bch->rx_skb->len),
|
||||
bch->rx_skb->data, bch->rx_skb->len);
|
||||
skb_trim(bch->rx_skb, 0);
|
||||
} else {
|
||||
skb = bch->rx_skb;
|
||||
bch->rx_skb = NULL;
|
||||
}
|
||||
} else {
|
||||
skb = bch->rx_skb;
|
||||
bch->rx_skb = NULL;
|
||||
}
|
||||
bch->rx_idx = 0;
|
||||
bch_sched_event(bch, B_RCVBUFREADY);
|
||||
queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb);
|
||||
} else {
|
||||
if (bch->debug & L1_DEB_HSCX)
|
||||
mISDN_debugprint(&bch->inst, "invalid frame");
|
||||
else
|
||||
mISDN_debugprint(&bch->inst, "ch%d invalid frame %#x", bch->channel, stat);
|
||||
bch->rx_idx = 0;
|
||||
skb_trim(bch->rx_skb, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
handle_tx:
|
||||
if (stat & HDLC_INT_XDU) {
|
||||
/* Here we lost an TX interrupt, so
|
||||
* restart transmitting the whole frame on HDLC
|
||||
* in transparent mode we send the next data
|
||||
*/
|
||||
if (bch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&bch->inst, "ch%d XDU tx_len(%d) tx_idx(%d) Flag(%lx)",
|
||||
bch->channel, bch->tx_len, bch->tx_idx, bch->Flag);
|
||||
if (bch->tx_len) {
|
||||
if (bch->protocol != ISDN_PID_L1_B_64TRANS)
|
||||
if (bch->debug & L1_DEB_WARN) {
|
||||
if (bch->tx_skb)
|
||||
mISDN_debugprint(&bch->inst, "ch%d XDU tx_len(%d) tx_idx(%d) Flags(%lx)",
|
||||
bch->channel, bch->tx_skb->len, bch->tx_idx, bch->Flags);
|
||||
else
|
||||
mISDN_debugprint(&bch->inst, "ch%d XDU no tx_skb Flags(%lx)",
|
||||
bch->channel, bch->Flags);
|
||||
}
|
||||
if (bch->tx_skb && bch->tx_skb->len) {
|
||||
if (!test_bit(FLG_TRANSPARENT, &bch->Flags))
|
||||
bch->tx_idx = 0;
|
||||
}
|
||||
hdlc->ctrl.sr.xml = 0;
|
||||
|
@ -633,7 +667,7 @@ static inline void
|
|||
HDLC_irq_main(fritzpnppci *fc)
|
||||
{
|
||||
u_int stat;
|
||||
bchannel_t *bch;
|
||||
channel_t *bch;
|
||||
|
||||
stat = read_status(fc, 0);
|
||||
if (stat & HDLC_INT_MASK) {
|
||||
|
@ -657,50 +691,20 @@ static irqreturn_t
|
|||
avm_fritz_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
fritzpnppci *fc = dev_id;
|
||||
u_long flags;
|
||||
u_char val;
|
||||
u_char sval;
|
||||
|
||||
spin_lock_irqsave(&fc->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = (void *)0x2001;
|
||||
#endif
|
||||
spin_lock(&fc->lock);
|
||||
sval = inb(fc->addr + 2);
|
||||
if (fc->dch.debug & L1_DEB_INTSTAT)
|
||||
mISDN_debugprint(&fc->dch.inst, "irq stat0 %x", sval);
|
||||
if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
|
||||
/* possible a shared IRQ reqest */
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
spin_unlock(&fc->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
fc->irqcnt++;
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &fc->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n",
|
||||
__FUNCTION__, fc->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "%s: previous lock:%p\n",
|
||||
__FUNCTION__, fc->lock.busy_adr);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
fc->lock.irq_fail++;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
fc->lock.irq_ok++;
|
||||
#endif
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.busy_adr = avm_fritz_interrupt;
|
||||
#endif
|
||||
}
|
||||
|
||||
test_and_set_bit(STATE_FLAG_INIRQ, &fc->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
if (!(sval & AVM_STATUS0_IRQ_ISAC)) {
|
||||
val = ReadISAC(fc, ISAC_ISTA);
|
||||
mISDN_isac_interrupt(&fc->dch, val);
|
||||
|
@ -712,21 +716,7 @@ avm_fritz_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|||
WriteISAC(fc, ISAC_MASK, 0xFF);
|
||||
WriteISAC(fc, ISAC_MASK, 0x0);
|
||||
}
|
||||
spin_lock_irqsave(&fc->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = (void *)0x2002;
|
||||
#endif
|
||||
if (!test_and_clear_bit(STATE_FLAG_INIRQ, &fc->lock.state)) {
|
||||
}
|
||||
if (!test_and_clear_bit(STATE_FLAG_BUSY, &fc->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n",
|
||||
__FUNCTION__, fc->lock.state);
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.busy_adr = NULL;
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
spin_unlock(&fc->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -734,50 +724,20 @@ static irqreturn_t
|
|||
avm_fritzv2_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
fritzpnppci *fc = dev_id;
|
||||
u_long flags;
|
||||
u_char val;
|
||||
u_char sval;
|
||||
|
||||
spin_lock_irqsave(&fc->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = (void *)0x2001;
|
||||
#endif
|
||||
spin_lock(&fc->lock);
|
||||
sval = inb(fc->addr + 2);
|
||||
if (fc->dch.debug & L1_DEB_INTSTAT)
|
||||
mISDN_debugprint(&fc->dch.inst, "irq stat0 %x", sval);
|
||||
if (!(sval & AVM_STATUS0_IRQ_MASK)) {
|
||||
/* possible a shared IRQ reqest */
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
spin_unlock(&fc->lock);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
fc->irqcnt++;
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &fc->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n",
|
||||
__FUNCTION__, fc->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "%s: previous lock:%p\n",
|
||||
__FUNCTION__, fc->lock.busy_adr);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
fc->lock.irq_fail++;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
fc->lock.irq_ok++;
|
||||
#endif
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.busy_adr = avm_fritz_interrupt;
|
||||
#endif
|
||||
}
|
||||
|
||||
test_and_set_bit(STATE_FLAG_INIRQ, &fc->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
if (sval & AVM_STATUS0_IRQ_HDLC) {
|
||||
HDLC_irq_main(fc);
|
||||
}
|
||||
|
@ -792,86 +752,59 @@ avm_fritzv2_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|||
udelay(1);
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
}
|
||||
spin_lock_irqsave(&fc->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = (void *)0x2002;
|
||||
#endif
|
||||
if (!test_and_clear_bit(STATE_FLAG_INIRQ, &fc->lock.state)) {
|
||||
}
|
||||
if (!test_and_clear_bit(STATE_FLAG_BUSY, &fc->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n",
|
||||
__FUNCTION__, fc->lock.state);
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.busy_adr = NULL;
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
spin_unlock(&fc->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int
|
||||
hdlc_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
hdlc_down(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
bchannel_t *bch;
|
||||
int ret = -EINVAL;
|
||||
mISDN_head_t *hh;
|
||||
channel_t *bch;
|
||||
int ret = 0;
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(skb);
|
||||
u_long flags;
|
||||
|
||||
if (!hif || !skb)
|
||||
return(ret);
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
bch = hif->fdata;
|
||||
if ((hh->prim == PH_DATA_REQ) ||
|
||||
(hh->prim == (DL_DATA | REQUEST))) {
|
||||
if (bch->next_skb) {
|
||||
mISDN_debugprint(&bch->inst, " l2l1 next_skb exist this shouldn't happen");
|
||||
return(-EBUSY);
|
||||
}
|
||||
bch->inst.lock(bch->inst.data, 0);
|
||||
if (test_and_set_bit(BC_FLG_TX_BUSY, &bch->Flag)) {
|
||||
test_and_set_bit(BC_FLG_TX_NEXT, &bch->Flag);
|
||||
bch->next_skb = skb;
|
||||
bch->inst.unlock(bch->inst.data);
|
||||
return(0);
|
||||
} else {
|
||||
bch->tx_len = skb->len;
|
||||
memcpy(bch->tx_buf, skb->data, bch->tx_len);
|
||||
bch->tx_idx = 0;
|
||||
bch = container_of(inst, channel_t, inst);
|
||||
if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) {
|
||||
spin_lock_irqsave(inst->hwlock, flags);
|
||||
ret = channel_senddata(bch, hh->dinfo, skb);
|
||||
if (ret > 0) { /* direct TX */
|
||||
hdlc_fill_fifo(bch);
|
||||
bch->inst.unlock(bch->inst.data);
|
||||
skb_trim(skb, 0);
|
||||
return(if_newhead(&bch->inst.up, hh->prim | CONFIRM,
|
||||
hh->dinfo, skb));
|
||||
}
|
||||
} else if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
|
||||
(hh->prim == (DL_ESTABLISH | REQUEST))) {
|
||||
if (test_and_set_bit(BC_FLG_ACTIV, &bch->Flag))
|
||||
ret = 0;
|
||||
else {
|
||||
bch->inst.lock(bch->inst.data,0);
|
||||
}
|
||||
spin_unlock_irqrestore(inst->hwlock, flags);
|
||||
return(ret);
|
||||
}
|
||||
if ((hh->prim == (PH_ACTIVATE | REQUEST)) ||
|
||||
(hh->prim == (DL_ESTABLISH | REQUEST))) {
|
||||
if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) {
|
||||
spin_lock_irqsave(inst->hwlock, flags);
|
||||
ret = modehdlc(bch, bch->channel,
|
||||
bch->inst.pid.protocol[1]);
|
||||
bch->inst.unlock(bch->inst.data);
|
||||
spin_unlock_irqrestore(inst->hwlock, flags);
|
||||
}
|
||||
skb_trim(skb, 0);
|
||||
return(if_newhead(&bch->inst.up, hh->prim | CONFIRM, ret, skb));
|
||||
return(mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, ret, skb));
|
||||
} else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) ||
|
||||
(hh->prim == (DL_RELEASE | REQUEST)) ||
|
||||
(hh->prim == (MGR_DISCONNECT | REQUEST))) {
|
||||
bch->inst.lock(bch->inst.data,0);
|
||||
if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) {
|
||||
((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) {
|
||||
spin_lock_irqsave(inst->hwlock, flags);
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) {
|
||||
dev_kfree_skb(bch->next_skb);
|
||||
bch->next_skb = NULL;
|
||||
}
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
if (bch->tx_skb) {
|
||||
dev_kfree_skb(bch->tx_skb);
|
||||
bch->tx_skb = NULL;
|
||||
bch->tx_idx = 0;
|
||||
}
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flags);
|
||||
modehdlc(bch, bch->channel, 0);
|
||||
test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag);
|
||||
bch->inst.unlock(bch->inst.data);
|
||||
test_and_clear_bit(FLG_ACTIVE, &bch->Flags);
|
||||
spin_unlock_irqrestore(inst->hwlock, flags);
|
||||
skb_trim(skb, 0);
|
||||
if (hh->prim != (MGR_DISCONNECT | REQUEST))
|
||||
if (!if_newhead(&bch->inst.up, hh->prim | CONFIRM, 0, skb))
|
||||
return(0);
|
||||
ret = 0;
|
||||
if (hh->prim != (PH_CONTROL | REQUEST))
|
||||
ret = mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, 0, skb);
|
||||
} else {
|
||||
printk(KERN_WARNING "hdlc_down unknown prim(%x)\n", hh->prim);
|
||||
ret = -EINVAL;
|
||||
|
@ -912,18 +845,22 @@ reset_avmpcipnp(fritzpnppci *fc)
|
|||
break;
|
||||
}
|
||||
printk(KERN_INFO "AVM PCI/PnP: reset\n");
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
disable_hwirq(fc);
|
||||
mdelay(5);
|
||||
switch (fc->type) {
|
||||
case AVM_FRITZ_PNP:
|
||||
fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
|
||||
disable_hwirq(fc);
|
||||
outb(AVM_STATUS1_ENA_IOM | fc->irq, fc->addr + 3);
|
||||
break;
|
||||
case AVM_FRITZ_PCI:
|
||||
fc->ctrlreg = AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER;
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
outb(AVM_STATUS1_ENA_IOM | fc->irq, fc->addr + 3);
|
||||
disable_hwirq(fc);
|
||||
outb(AVM_STATUS1_ENA_IOM, fc->addr + 3);
|
||||
break;
|
||||
case AVM_FRITZ_PCIV2:
|
||||
fc->ctrlreg = 0;
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
disable_hwirq(fc);
|
||||
break;
|
||||
}
|
||||
mdelay(1);
|
||||
|
@ -934,44 +871,44 @@ static int init_card(fritzpnppci *fc)
|
|||
{
|
||||
int cnt = 3;
|
||||
u_int shared = SA_SHIRQ;
|
||||
u_long flags;
|
||||
u_char *id = "AVM Fritz!PCI";
|
||||
|
||||
if (fc->type == AVM_FRITZ_PNP)
|
||||
if (fc->type == AVM_FRITZ_PNP) {
|
||||
shared = 0;
|
||||
lock_dev(fc, 0);
|
||||
id = "AVM Fritz!PnP";
|
||||
}
|
||||
reset_avmpcipnp(fc); /* disable IRQ */
|
||||
if (fc->type == AVM_FRITZ_PCIV2) {
|
||||
if (request_irq(fc->irq, avm_fritzv2_interrupt, SA_SHIRQ,
|
||||
"AVM Fritz!PCI", fc)) {
|
||||
if (request_irq(fc->irq, avm_fritzv2_interrupt, shared, id, fc)) {
|
||||
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
|
||||
fc->irq);
|
||||
unlock_dev(fc);
|
||||
return(-EIO);
|
||||
}
|
||||
} else {
|
||||
if (request_irq(fc->irq, avm_fritz_interrupt, shared,
|
||||
"AVM Fritz!PCI", fc)) {
|
||||
if (request_irq(fc->irq, avm_fritz_interrupt, shared, id, fc)) {
|
||||
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
|
||||
fc->irq);
|
||||
unlock_dev(fc);
|
||||
return(-EIO);
|
||||
}
|
||||
}
|
||||
reset_avmpcipnp(fc);
|
||||
while (cnt) {
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&fc->lock, flags);
|
||||
mISDN_clear_isac(&fc->dch);
|
||||
if ((ret=mISDN_isac_init(&fc->dch))) {
|
||||
printk(KERN_WARNING "mISDN: mISDN_isac_init failed with %d\n", ret);
|
||||
spin_unlock_irqrestore(&fc->lock, flags);
|
||||
break;
|
||||
}
|
||||
clear_pending_hdlc_ints(fc);
|
||||
inithdlc(fc);
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
WriteISAC(fc, ISAC_MASK, 0);
|
||||
fc->ctrlreg |= AVM_STATUS0_ENA_IRQ;
|
||||
outb(fc->ctrlreg, fc->addr + 2);
|
||||
enable_hwirq(fc);
|
||||
/* RESET Receiver and Transmitter */
|
||||
WriteISAC(fc, ISAC_CMDR, 0x41);
|
||||
unlock_dev(fc);
|
||||
spin_unlock_irqrestore(&fc->lock, flags);
|
||||
/* Timeout 10ms */
|
||||
current->state = TASK_UNINTERRUPTIBLE;
|
||||
schedule_timeout((10*HZ)/1000);
|
||||
|
@ -990,9 +927,7 @@ static int init_card(fritzpnppci *fc)
|
|||
} else {
|
||||
return(0);
|
||||
}
|
||||
lock_dev(fc, 0);
|
||||
}
|
||||
unlock_dev(fc);
|
||||
return(-EIO);
|
||||
}
|
||||
|
||||
|
@ -1080,44 +1015,39 @@ setup_fritz(fritzpnppci *fc)
|
|||
fc->irq, fc->addr);
|
||||
|
||||
fc->dch.hw = &fc->isac;
|
||||
lock_dev(fc, 0);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "spin_lock_adr=%p now(%p)\n", &fc->lock.busy_adr, fc->lock.busy_adr);
|
||||
printk(KERN_ERR "busy_lock_adr=%p now(%p)\n", &fc->lock.busy_adr, fc->lock.busy_adr);
|
||||
#endif
|
||||
unlock_dev(fc);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void
|
||||
release_card(fritzpnppci *card)
|
||||
{
|
||||
#ifdef LOCK_STATISTIC
|
||||
printk(KERN_INFO "try_ok(%d) try_wait(%d) try_mult(%d) try_inirq(%d)\n",
|
||||
card->lock.try_ok, card->lock.try_wait, card->lock.try_mult, card->lock.try_inirq);
|
||||
printk(KERN_INFO "irq_ok(%d) irq_fail(%d)\n",
|
||||
card->lock.irq_ok, card->lock.irq_fail);
|
||||
#endif
|
||||
lock_dev(card, 0);
|
||||
outb(0, card->addr + 2);
|
||||
free_irq(card->irq, card);
|
||||
u_long flags;
|
||||
|
||||
disable_hwirq(card);
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
modehdlc(&card->bch[0], 0, ISDN_PID_NONE);
|
||||
modehdlc(&card->bch[1], 1, ISDN_PID_NONE);
|
||||
mISDN_isac_free(&card->dch);
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
free_irq(card->irq, card);
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
release_region(card->addr, 32);
|
||||
mISDN_free_bch(&card->bch[1]);
|
||||
mISDN_free_bch(&card->bch[0]);
|
||||
mISDN_free_dch(&card->dch);
|
||||
fritz.ctrl(card->dch.inst.up.peer, MGR_DISCONNECT | REQUEST, &card->dch.inst.up);
|
||||
mISDN_freechannel(&card->bch[1]);
|
||||
mISDN_freechannel(&card->bch[0]);
|
||||
mISDN_freechannel(&card->dch);
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
fritz.ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
spin_lock_irqsave(&fritz.lock, flags);
|
||||
list_del(&card->list);
|
||||
unlock_dev(card);
|
||||
spin_unlock_irqrestore(&fritz.lock, flags);
|
||||
if (card->type == AVM_FRITZ_PNP) {
|
||||
pnp_disable_dev(card->pdev);
|
||||
pnp_set_drvdata(card->pdev, NULL);
|
||||
#if defined(CONFIG_PNP)
|
||||
pnp_disable_dev(card->dev.pnp);
|
||||
pnp_set_drvdata(card->dev.pnp, NULL);
|
||||
#endif
|
||||
} else {
|
||||
pci_disable_device(card->pdev);
|
||||
pci_set_drvdata(card->pdev, NULL);
|
||||
pci_disable_device(card->dev.pci);
|
||||
pci_set_drvdata(card->dev.pci, NULL);
|
||||
}
|
||||
kfree(card);
|
||||
}
|
||||
|
@ -1127,6 +1057,7 @@ fritz_manager(void *data, u_int prim, void *arg) {
|
|||
fritzpnppci *card;
|
||||
mISDNinstance_t *inst = data;
|
||||
struct sk_buff *skb;
|
||||
u_long flags;
|
||||
int channel = -1;
|
||||
|
||||
if (debug & 0x10000)
|
||||
|
@ -1138,6 +1069,7 @@ fritz_manager(void *data, u_int prim, void *arg) {
|
|||
__FUNCTION__, prim, arg);
|
||||
return(-EINVAL);
|
||||
}
|
||||
spin_lock_irqsave(&fritz.lock, flags);
|
||||
list_for_each_entry(card, &fritz.ilist, list) {
|
||||
if (&card->dch.inst == inst) {
|
||||
channel = 2;
|
||||
|
@ -1152,6 +1084,7 @@ fritz_manager(void *data, u_int prim, void *arg) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&fritz.lock, flags);
|
||||
if (channel<0) {
|
||||
printk(KERN_WARNING "%s: no channel data %p prim %x arg %p\n",
|
||||
__FUNCTION__, data, prim, arg);
|
||||
|
@ -1161,36 +1094,31 @@ fritz_manager(void *data, u_int prim, void *arg) {
|
|||
switch(prim) {
|
||||
case MGR_REGLAYER | CONFIRM:
|
||||
if (channel == 2)
|
||||
dch_set_para(&card->dch, &inst->st->para);
|
||||
mISDN_setpara(&card->dch, &inst->st->para);
|
||||
else
|
||||
bch_set_para(&card->bch[channel], &inst->st->para);
|
||||
mISDN_setpara(&card->bch[channel], &inst->st->para);
|
||||
break;
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
if (channel == 2) {
|
||||
inst->down.fdata = &card->dch;
|
||||
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
|
||||
HW_DEACTIVATE, 0, NULL, 0))) {
|
||||
if (mISDN_ISAC_l1hw(&inst->down, skb))
|
||||
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
|
||||
HW_DEACTIVATE, 0, NULL, 0))) {
|
||||
if (channel == 2) {
|
||||
if (mISDN_ISAC_l1hw(inst, skb))
|
||||
dev_kfree_skb(skb);
|
||||
} else {
|
||||
if (hdlc_down(inst, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
} else {
|
||||
inst->down.fdata = &card->bch[channel];
|
||||
if ((skb = create_link_skb(MGR_DISCONNECT | REQUEST,
|
||||
0, 0, NULL, 0))) {
|
||||
if (hdlc_down(&inst->down, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
fritz.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
} else
|
||||
printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
|
||||
fritz.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
break;
|
||||
case MGR_CLRSTPARA | INDICATION:
|
||||
arg = NULL;
|
||||
case MGR_ADDSTPARA | INDICATION:
|
||||
if (channel == 2)
|
||||
dch_set_para(&card->dch, arg);
|
||||
mISDN_setpara(&card->dch, arg);
|
||||
else
|
||||
bch_set_para(&card->bch[channel], arg);
|
||||
mISDN_setpara(&card->bch[channel], arg);
|
||||
break;
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (channel == 2) {
|
||||
|
@ -1199,33 +1127,18 @@ fritz_manager(void *data, u_int prim, void *arg) {
|
|||
fritz.refcnt--;
|
||||
}
|
||||
break;
|
||||
case MGR_CONNECT | REQUEST:
|
||||
return(mISDN_ConnectIF(inst, arg));
|
||||
case MGR_SETIF | REQUEST:
|
||||
case MGR_SETIF | INDICATION:
|
||||
if (channel==2)
|
||||
return(mISDN_SetIF(inst, arg, prim, mISDN_ISAC_l1hw, NULL,
|
||||
&card->dch));
|
||||
else
|
||||
return(mISDN_SetIF(inst, arg, prim, hdlc_down, NULL,
|
||||
&card->bch[channel]));
|
||||
break;
|
||||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
case MGR_SETSTACK | CONFIRM:
|
||||
case MGR_SETSTACK | INDICATION:
|
||||
if ((channel!=2) && (inst->pid.global == 2)) {
|
||||
inst->down.fdata = &card->bch[channel];
|
||||
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
|
||||
0, 0, NULL, 0))) {
|
||||
if (hdlc_down(&inst->down, skb))
|
||||
if (hdlc_down(inst, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS)
|
||||
if_link(&inst->up, DL_ESTABLISH | INDICATION,
|
||||
mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
|
||||
0, 0, NULL, 0);
|
||||
else
|
||||
if_link(&inst->up, PH_ACTIVATE | INDICATION,
|
||||
mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
|
||||
0, 0, NULL, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -1243,37 +1156,52 @@ static int __devinit setup_instance(fritzpnppci *card)
|
|||
{
|
||||
int i, err;
|
||||
mISDN_pid_t pid;
|
||||
|
||||
u_long flags;
|
||||
struct device *dev;
|
||||
|
||||
if (card->type == AVM_FRITZ_PNP) {
|
||||
#if defined(CONFIG_PNP)
|
||||
dev = &card->dev.pnp->dev;
|
||||
#else
|
||||
dev = NULL;
|
||||
#endif
|
||||
} else {
|
||||
dev = &card->dev.pci->dev;
|
||||
}
|
||||
spin_lock_irqsave(&fritz.lock, flags);
|
||||
list_add_tail(&card->list, &fritz.ilist);
|
||||
spin_unlock_irqrestore(&fritz.lock, flags);
|
||||
card->dch.debug = debug;
|
||||
lock_HW_init(&card->lock);
|
||||
card->dch.inst.lock = lock_dev;
|
||||
card->dch.inst.unlock = unlock_dev;
|
||||
spin_lock_init(&card->lock);
|
||||
card->dch.inst.hwlock = &card->lock;
|
||||
card->dch.inst.class_dev.dev = dev;
|
||||
card->dch.inst.pid.layermask = ISDN_LAYER(0);
|
||||
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
|
||||
mISDN_init_instance(&card->dch.inst, &fritz, card);
|
||||
mISDN_init_instance(&card->dch.inst, &fritz, card, mISDN_ISAC_l1hw);
|
||||
sprintf(card->dch.inst.name, "Fritz%d", fritz_cnt+1);
|
||||
mISDN_set_dchannel_pid(&pid, protocol[fritz_cnt], layermask[fritz_cnt]);
|
||||
mISDN_init_dch(&card->dch);
|
||||
mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
|
||||
for (i=0; i<2; i++) {
|
||||
card->bch[i].channel = i;
|
||||
mISDN_init_instance(&card->bch[i].inst, &fritz, card);
|
||||
mISDN_init_instance(&card->bch[i].inst, &fritz, card, hdlc_down);
|
||||
card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
|
||||
card->bch[i].inst.lock = lock_dev;
|
||||
card->bch[i].inst.unlock = unlock_dev;
|
||||
card->bch[i].inst.hwlock = &card->lock;
|
||||
card->bch[i].inst.class_dev.dev = dev;
|
||||
card->bch[i].debug = debug;
|
||||
sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
|
||||
mISDN_init_bch(&card->bch[i]);
|
||||
mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
|
||||
card->bch[i].hw = &card->hdlc[i];
|
||||
}
|
||||
printk(KERN_DEBUG "fritz card %p dch %p bch1 %p bch2 %p\n",
|
||||
card, &card->dch, &card->bch[0], &card->bch[1]);
|
||||
err = setup_fritz(card);
|
||||
if (err) {
|
||||
mISDN_free_dch(&card->dch);
|
||||
mISDN_free_bch(&card->bch[1]);
|
||||
mISDN_free_bch(&card->bch[0]);
|
||||
mISDN_freechannel(&card->dch);
|
||||
mISDN_freechannel(&card->bch[1]);
|
||||
mISDN_freechannel(&card->bch[0]);
|
||||
spin_lock_irqsave(&fritz.lock, flags);
|
||||
list_del(&card->list);
|
||||
spin_unlock_irqrestore(&fritz.lock, flags);
|
||||
kfree(card);
|
||||
return(err);
|
||||
}
|
||||
|
@ -1321,7 +1249,7 @@ static int __devinit fritzpci_probe(struct pci_dev *pdev, const struct pci_devic
|
|||
card->type = AVM_FRITZ_PCIV2;
|
||||
else
|
||||
card->type = AVM_FRITZ_PCI;
|
||||
card->pdev = pdev;
|
||||
card->dev.pci = pdev;
|
||||
err = pci_enable_device(pdev);
|
||||
if (err) {
|
||||
kfree(card);
|
||||
|
@ -1359,7 +1287,7 @@ static int __devinit fritzpnp_probe(struct pci_dev *pdev, const struct isapnp_de
|
|||
}
|
||||
memset(card, 0, sizeof(fritzpnppci));
|
||||
card->type = AVM_FRITZ_PNP;
|
||||
card->pdev = pdev;
|
||||
card->dev.pnp = pdev;
|
||||
pnp_disable_dev(pdev);
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err<0) {
|
||||
|
@ -1465,6 +1393,7 @@ static int __init Fritz_init(void)
|
|||
#ifdef MODULE
|
||||
fritz.owner = THIS_MODULE;
|
||||
#endif
|
||||
spin_lock_init(&fritz.lock);
|
||||
INIT_LIST_HEAD(&fritz.ilist);
|
||||
fritz.name = FritzName;
|
||||
fritz.own_ctrl = fritz_manager;
|
||||
|
@ -1505,7 +1434,9 @@ static int __init Fritz_init(void)
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if defined(CONFIG_PNP)
|
||||
out_unregister_pci:
|
||||
#endif
|
||||
pci_unregister_driver(&fcpci_driver);
|
||||
out:
|
||||
return err;
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mISDNif.h>
|
||||
#include "layer1.h"
|
||||
#include "bchannel.h"
|
||||
#include "helper.h"
|
||||
|
||||
static void
|
||||
bchannel_bh(bchannel_t *bch)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u_int pr;
|
||||
int ret;
|
||||
mISDN_head_t *hh;
|
||||
mISDNif_t *hif;
|
||||
|
||||
if (!bch)
|
||||
return;
|
||||
if (!bch->inst.up.func) {
|
||||
printk(KERN_WARNING "%s: without up.func\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, bch->event);
|
||||
if (bch->dev)
|
||||
printk(KERN_DEBUG "%s: rpflg(%x) wpflg(%x)\n", __FUNCTION__,
|
||||
bch->dev->rport.Flag, bch->dev->wport.Flag);
|
||||
#endif
|
||||
if (test_and_clear_bit(B_XMTBUFREADY, &bch->event)) {
|
||||
skb = bch->next_skb;
|
||||
if (skb) {
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
bch->next_skb = NULL;
|
||||
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
|
||||
pr = DL_DATA | CONFIRM;
|
||||
else
|
||||
pr = PH_DATA | CONFIRM;
|
||||
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
|
||||
&& bch->dev)
|
||||
hif = &bch->dev->rport.pif;
|
||||
else
|
||||
hif = &bch->inst.up;
|
||||
if (if_newhead(hif, pr, hh->dinfo, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
if (test_and_clear_bit(B_RCVBUFREADY, &bch->event)) {
|
||||
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
|
||||
&& bch->dev)
|
||||
hif = &bch->dev->rport.pif;
|
||||
else
|
||||
hif = &bch->inst.up;
|
||||
while ((skb = skb_dequeue(&bch->rqueue))) {
|
||||
if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS)
|
||||
pr = DL_DATA | INDICATION;
|
||||
else
|
||||
pr = PH_DATA | INDICATION;
|
||||
ret = if_newhead(hif, pr, MISDN_ID_ANY, skb);
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING "%s: deliver err %d\n",
|
||||
__FUNCTION__, ret);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bch->hw_bh)
|
||||
bch->hw_bh(bch);
|
||||
}
|
||||
|
||||
int
|
||||
mISDN_init_bch(bchannel_t *bch) {
|
||||
int devtyp = mISDN_RAW_DEVICE;
|
||||
|
||||
if (!(bch->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for blog\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
if (!(bch->rx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for bchannel rx_buf\n");
|
||||
kfree(bch->blog);
|
||||
bch->blog = NULL;
|
||||
return (-ENOMEM);
|
||||
}
|
||||
if (!(bch->tx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for bchannel tx_buf\n");
|
||||
kfree(bch->blog);
|
||||
bch->blog = NULL;
|
||||
kfree(bch->rx_buf);
|
||||
bch->rx_buf = NULL;
|
||||
return (-ENOMEM);
|
||||
}
|
||||
skb_queue_head_init(&bch->rqueue);
|
||||
bch->next_skb = NULL;
|
||||
bch->Flag = 0;
|
||||
bch->event = 0;
|
||||
bch->rx_idx = 0;
|
||||
bch->tx_len = 0;
|
||||
bch->tx_idx = 0;
|
||||
INIT_WORK(&bch->work, (void *)(void *)bchannel_bh, bch);
|
||||
bch->hw_bh = NULL;
|
||||
if (!bch->dev) {
|
||||
if (bch->inst.obj->ctrl(&bch->dev, MGR_GETDEVICE | REQUEST,
|
||||
&devtyp)) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: no raw device for bchannel\n");
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
mISDN_free_bch(bchannel_t *bch) {
|
||||
#ifdef HAS_WORKQUEUE
|
||||
if (bch->work.pending)
|
||||
printk(KERN_ERR "mISDN_free_bch work:(%lx)\n", bch->work.pending);
|
||||
#else
|
||||
if (bch->work.sync)
|
||||
printk(KERN_ERR "mISDN_free_bch work:(%lx)\n", bch->work.sync);
|
||||
#endif
|
||||
discard_queue(&bch->rqueue);
|
||||
if (bch->blog) {
|
||||
kfree(bch->blog);
|
||||
bch->blog = NULL;
|
||||
}
|
||||
if (bch->rx_buf) {
|
||||
kfree(bch->rx_buf);
|
||||
bch->rx_buf = NULL;
|
||||
}
|
||||
if (bch->tx_buf) {
|
||||
kfree(bch->tx_buf);
|
||||
bch->tx_buf = NULL;
|
||||
}
|
||||
if (bch->next_skb) {
|
||||
dev_kfree_skb(bch->next_skb);
|
||||
bch->next_skb = NULL;
|
||||
}
|
||||
if (bch->inst.obj->ctrl(bch->dev, MGR_DELDEVICE | REQUEST, NULL)) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: del raw device error\n");
|
||||
} else
|
||||
bch->dev = NULL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mISDN_init_bch);
|
||||
EXPORT_SYMBOL(mISDN_free_bch);
|
|
@ -1,98 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations, defines for Bchannel hardware
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mISDNif.h>
|
||||
#ifdef HAS_WORKQUEUE
|
||||
#include <linux/workqueue.h>
|
||||
#else
|
||||
#include <linux/tqueue.h>
|
||||
#endif
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#define MAX_BLOG_SPACE 256
|
||||
|
||||
#define BC_FLG_INIT 1
|
||||
#define BC_FLG_ACTIV 2
|
||||
#define BC_FLG_TX_BUSY 3
|
||||
#define BC_FLG_NOFRAME 4
|
||||
#define BC_FLG_HALF 5
|
||||
#define BC_FLG_EMPTY 6
|
||||
#define BC_FLG_ORIG 7
|
||||
#define BC_FLG_DLEETX 8
|
||||
#define BC_FLG_LASTDLE 9
|
||||
#define BC_FLG_FIRST 10
|
||||
#define BC_FLG_LASTDATA 11
|
||||
#define BC_FLG_NMD_DATA 12
|
||||
#define BC_FLG_FTI_RUN 13
|
||||
#define BC_FLG_LL_OK 14
|
||||
#define BC_FLG_LL_CONN 15
|
||||
#define BC_FLG_TX_NEXT 16
|
||||
#define BC_FLG_DTMFSEND 17
|
||||
|
||||
typedef struct _bchannel_t {
|
||||
int channel;
|
||||
int protocol;
|
||||
u_long Flag;
|
||||
int debug;
|
||||
mISDNstack_t *st;
|
||||
mISDNinstance_t inst;
|
||||
mISDNdevice_t *dev;
|
||||
void *hw;
|
||||
u_char (*Read_Reg)(void *, int, u_char);
|
||||
void (*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 work_struct work;
|
||||
void (*hw_bh) (struct _bchannel_t *);
|
||||
u_long event;
|
||||
int maxdatasize;
|
||||
int up_headerlen;
|
||||
int err_crc;
|
||||
int err_tx;
|
||||
int err_rdo;
|
||||
int err_inv;
|
||||
} bchannel_t;
|
||||
|
||||
extern int mISDN_init_bch(bchannel_t *);
|
||||
extern int mISDN_free_bch(bchannel_t *);
|
||||
|
||||
static inline void
|
||||
bch_set_para(bchannel_t *bch, mISDN_stPara_t *stp)
|
||||
{
|
||||
if (stp) {
|
||||
bch->maxdatasize = stp->maxdatalen;
|
||||
bch->up_headerlen = stp->up_headerlen;
|
||||
} else {
|
||||
bch->maxdatasize = 0;
|
||||
bch->up_headerlen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
bch_sched_event(bchannel_t *bch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &bch->event);
|
||||
schedule_work(&bch->work);
|
||||
}
|
|
@ -311,11 +311,13 @@ capi20_manager(void *data, u_int prim, void *arg) {
|
|||
int found=0;
|
||||
PLInst_t *plink = NULL;
|
||||
Controller_t *ctrl;
|
||||
u_long flags;
|
||||
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "capi20_manager data:%p prim:%x arg:%p\n", data, prim, arg);
|
||||
if (!data)
|
||||
return(-EINVAL);
|
||||
spin_lock_irqsave(&capi_obj.lock, flags);
|
||||
list_for_each_entry(ctrl, &capi_obj.ilist, list) {
|
||||
if (&ctrl->inst == inst) {
|
||||
found++;
|
||||
|
@ -333,6 +335,7 @@ capi20_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
if (&ctrl->list == &capi_obj.ilist)
|
||||
ctrl = NULL;
|
||||
spin_unlock_irqrestore(&capi_obj.lock, flags);
|
||||
if (prim == (MGR_NEWLAYER | REQUEST)) {
|
||||
int ret = ControllerConstr(&ctrl, data, arg, &capi_obj);
|
||||
if (!ret)
|
||||
|
@ -346,8 +349,9 @@ capi20_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
switch(prim) {
|
||||
case MGR_NEWENTITY | CONFIRM:
|
||||
ctrl->entity = (int)arg;
|
||||
ctrl->entity = (u_long)arg & 0xffffffff;
|
||||
break;
|
||||
#ifdef FIXME
|
||||
case MGR_CONNECT | REQUEST:
|
||||
return(mISDN_ConnectIF(inst, arg));
|
||||
case MGR_SETIF | INDICATION:
|
||||
|
@ -359,6 +363,11 @@ capi20_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
#endif
|
||||
case MGR_SETSTACK | INDICATION:
|
||||
if (!(&ctrl->inst == inst))
|
||||
return(AppPlcimISDN_Active(inst->privat));
|
||||
return(0);
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (CAPI_DBG_INFO & debug)
|
||||
printk(KERN_DEBUG "release_capi20 id %x\n", ctrl->inst.st->id);
|
||||
|
@ -366,8 +375,7 @@ capi20_manager(void *data, u_int prim, void *arg) {
|
|||
break;
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
if (plink) {
|
||||
capi_obj.ctrl(plink->inst.down.peer, MGR_DISCONNECT | REQUEST,
|
||||
&plink->inst.down);
|
||||
plink->inst.function = NULL;
|
||||
capi_obj.ctrl(&plink->inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
}
|
||||
break;
|
||||
|
@ -397,6 +405,7 @@ int Capi20Init(void)
|
|||
capi_obj.BPROTO.protocol[4] = ISDN_PID_L4_B_CAPI20;
|
||||
capi_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_TRANS;
|
||||
capi_obj.own_ctrl = capi20_manager;
|
||||
spin_lock_init(&capi_obj.lock);
|
||||
INIT_LIST_HEAD(&capi_obj.ilist);
|
||||
if ((err = CapiNew()))
|
||||
return(err);
|
||||
|
|
|
@ -58,6 +58,7 @@ ControllerDestr(Controller_t *contr)
|
|||
}
|
||||
#endif
|
||||
contr->ctrl = NULL;
|
||||
#ifdef FIXME
|
||||
if (inst->up.peer) {
|
||||
inst->up.peer->obj->ctrl(inst->up.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
|
@ -66,13 +67,14 @@ ControllerDestr(Controller_t *contr)
|
|||
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_DELENTITY | REQUEST, (void *)((u_long)contr->entity));
|
||||
inst->obj->ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
list_del(&contr->list);
|
||||
spin_unlock_irqrestore(&contr->list_lock, flags);
|
||||
|
@ -230,15 +232,92 @@ SendMessage(struct capi_ctr *ctrl, struct sk_buff *skb)
|
|||
Controller_t *contr = ctrl->driverdata;
|
||||
Application_t *appl;
|
||||
int ApplId;
|
||||
int err;
|
||||
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;
|
||||
} else
|
||||
err = ApplicationSendMessage(appl, skb);
|
||||
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_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
|
||||
|
@ -468,21 +547,27 @@ SSProcess_t
|
|||
return(sp);
|
||||
}
|
||||
|
||||
int
|
||||
ControllerL3L4(mISDNif_t *hif, struct sk_buff *skb)
|
||||
static int
|
||||
Controller_function(mISDNinstance_t *inst, 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;
|
||||
contr = inst->privat;
|
||||
contrDebug(contr, CAPI_DBG_CONTR_INFO, "%s: prim(%x) id(%x)",
|
||||
__FUNCTION__, hh->prim, hh->dinfo);
|
||||
if (hh->prim == (CC_NEW_CR | INDICATION)) {
|
||||
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);
|
||||
|
@ -505,7 +590,7 @@ ControllerL3L4(mISDNif_t *hif, struct sk_buff *skb)
|
|||
int
|
||||
ControllerL4L3(Controller_t *contr, u_int prim, int dinfo, struct sk_buff *skb)
|
||||
{
|
||||
return(if_newhead(&contr->inst.down, prim, dinfo, skb));
|
||||
return(mISDN_queuedown_newhead(&contr->inst, 0, prim, dinfo, skb));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -522,6 +607,7 @@ ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mIS
|
|||
int retval;
|
||||
mISDNstack_t *cst;
|
||||
PLInst_t *plink;
|
||||
u_long flags;
|
||||
|
||||
if (!st)
|
||||
return(-EINVAL);
|
||||
|
@ -546,7 +632,6 @@ ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mIS
|
|||
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
|
||||
|
@ -579,10 +664,9 @@ ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mIS
|
|||
ControllerDestr(contr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
// FIXME ???
|
||||
contr->addr = st->id;
|
||||
sprintf(contr->inst.name, "CAPI %d", st->id);
|
||||
mISDN_init_instance(&contr->inst, ocapi, contr);
|
||||
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);
|
||||
|
@ -598,12 +682,14 @@ ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mIS
|
|||
memset(plink, 0, sizeof(PLInst_t));
|
||||
plink->st = cst;
|
||||
plink->inst.st = cst;
|
||||
mISDN_init_instance(&plink->inst, ocapi, plink);
|
||||
mISDN_init_instance(&plink->inst, ocapi, plink, NULL);
|
||||
plink->inst.pid.layermask |= ISDN_LAYER(4);
|
||||
plink->inst.down.stat = IF_NOACTIV;
|
||||
// plink->inst.down.stat = IF_NOACTIV;
|
||||
list_add_tail(&plink->list, &contr->linklist);
|
||||
}
|
||||
spin_lock_irqsave(&ocapi->lock, flags);
|
||||
list_add_tail(&contr->list, &ocapi->ilist);
|
||||
spin_unlock_irqrestore(&ocapi->lock, flags);
|
||||
contr->entity = MISDN_ENTITY_NONE;
|
||||
retval = ocapi->ctrl(&contr->inst, MGR_NEWENTITY | REQUEST, NULL);
|
||||
if (retval) {
|
||||
|
@ -615,14 +701,14 @@ ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mIS
|
|||
{
|
||||
char tmp[10];
|
||||
|
||||
sprintf(tmp, "mISDN%d", st->id);
|
||||
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", st->id);
|
||||
sprintf(contr->ctrl->name, "mISDN%d", contr->addr);
|
||||
contr->ctrl->driver_name = "mISDN";
|
||||
contr->ctrl->driverdata = contr;
|
||||
contr->ctrl->register_appl = RegisterApplication;
|
||||
|
@ -635,10 +721,12 @@ ControllerConstr(Controller_t **contr_p, mISDNstack_t *st, mISDN_pid_t *pid, mIS
|
|||
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->inst.up.stat = IF_DOWN;
|
||||
*contr_p = contr;
|
||||
} else {
|
||||
ControllerDestr(contr);
|
||||
|
@ -676,14 +764,11 @@ ControllerSelChannel(Controller_t *contr, u_int channel)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -22,14 +22,14 @@
|
|||
static char *mISDN_core_revision = "$Revision$";
|
||||
|
||||
LIST_HEAD(mISDN_objectlist);
|
||||
rwlock_t mISDN_objects_lock = RW_LOCK_UNLOCKED;
|
||||
static rwlock_t mISDN_objects_lock = RW_LOCK_UNLOCKED;
|
||||
|
||||
int core_debug;
|
||||
|
||||
static u_char entityarray[MISDN_MAX_ENTITY/8];
|
||||
static spinlock_t entity_lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static int debug;
|
||||
static uint debug;
|
||||
static int obj_id;
|
||||
|
||||
#ifdef MODULE
|
||||
|
@ -37,7 +37,8 @@ MODULE_AUTHOR("Karsten Keil");
|
|||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
MODULE_PARM(debug, "1i");
|
||||
module_param (debug, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC (debug, "mISDN core debug mask");
|
||||
#endif
|
||||
|
||||
typedef struct _mISDN_thread {
|
||||
|
@ -49,10 +50,10 @@ typedef struct _mISDN_thread {
|
|||
struct sk_buff_head workq;
|
||||
} mISDN_thread_t;
|
||||
|
||||
#define mISDN_TFLAGS_STARTED 1
|
||||
#define mISDN_TFLAGS_RMMOD 2
|
||||
#define mISDN_TFLAGS_ACTIV 3
|
||||
#define mISDN_TFLAGS_TEST 4
|
||||
#define mISDN_TFLAGS_STARTED 0
|
||||
#define mISDN_TFLAGS_RMMOD 1
|
||||
#define mISDN_TFLAGS_ACTIV 2
|
||||
#define mISDN_TFLAGS_TEST 3
|
||||
|
||||
static mISDN_thread_t mISDN_thread;
|
||||
|
||||
|
@ -97,7 +98,7 @@ mISDNd(void *data)
|
|||
break;
|
||||
if (hkt->notify != NULL)
|
||||
up(hkt->notify);
|
||||
interruptible_sleep_on(&hkt->waitq);
|
||||
wait_event_interruptible(hkt->waitq, ((!skb_queue_empty(&hkt->workq)) || (hkt->Flags & 0xfffffffe)));
|
||||
if (test_and_clear_bit(mISDN_TFLAGS_RMMOD, &hkt->Flags))
|
||||
break;
|
||||
while ((skb = skb_dequeue(&hkt->workq))) {
|
||||
|
@ -118,6 +119,7 @@ mISDNd(void *data)
|
|||
err--; /* to free skb */
|
||||
}
|
||||
break;
|
||||
#ifdef FIXME
|
||||
case MGR_QUEUEIF:
|
||||
err = hhe->func.iff(hhe->data[0], skb);
|
||||
if (err) {
|
||||
|
@ -125,6 +127,7 @@ mISDNd(void *data)
|
|||
hhe->addr, hhe->prim, err);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
int_error();
|
||||
printk(KERN_WARNING "mISDNd: addr(%x) prim(%x) unknown\n",
|
||||
|
@ -219,21 +222,7 @@ find_object_module(int protocol) {
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_object(mISDNobject_t *obj) {
|
||||
mISDNstack_t *st, *nst;
|
||||
mISDNlayer_t *layer, *nl;
|
||||
mISDNinstance_t *inst;
|
||||
|
||||
list_for_each_entry_safe(st, nst, &mISDN_stacklist, list) {
|
||||
list_for_each_entry_safe(layer, nl, &st->layerlist, list) {
|
||||
inst = layer->inst;
|
||||
if (inst && inst->obj == obj)
|
||||
inst->obj->own_ctrl(st, MGR_RELEASE | INDICATION, inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FIXME
|
||||
static int
|
||||
dummy_if(mISDNif_t *hif, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -251,6 +240,7 @@ dummy_if(mISDNif_t *hif, struct sk_buff *skb)
|
|||
dev_kfree_skb_any(skb);
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
mISDNinstance_t *
|
||||
get_next_instance(mISDNstack_t *st, mISDN_pid_t *pid)
|
||||
|
@ -335,6 +325,7 @@ sel_channel(mISDNstack_t *st, channel_info_t *ci)
|
|||
return(err);
|
||||
}
|
||||
|
||||
#ifdef FIXME
|
||||
static int
|
||||
disconnect_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
|
||||
int err = 0;
|
||||
|
@ -371,6 +362,7 @@ add_if(mISDNinstance_t *inst, u_int prim, mISDNif_t *hif) {
|
|||
inst->obj->own_ctrl(inst, prim, hif);
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static char tmpbuf[4096];
|
||||
static int
|
||||
|
@ -394,15 +386,18 @@ get_hdevice(mISDNdevice_t **dev, int *typ)
|
|||
return(-EINVAL);
|
||||
if (!typ)
|
||||
return(-EINVAL);
|
||||
#ifdef FIXME
|
||||
if (*typ == mISDN_RAW_DEVICE) {
|
||||
*dev = get_free_rawdevice();
|
||||
if (!(*dev))
|
||||
return(-ENODEV);
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
return(-EINVAL);
|
||||
}
|
||||
|
||||
#ifdef FIXME
|
||||
static int
|
||||
mgr_queue(void *data, u_int prim, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -414,6 +409,8 @@ mgr_queue(void *data, u_int prim, struct sk_buff *skb)
|
|||
return(0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int central_manager(void *, u_int, void *);
|
||||
|
||||
static int
|
||||
|
@ -423,6 +420,7 @@ set_stack_req(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
mISDN_headext_t *hhe;
|
||||
mISDN_pid_t *npid;
|
||||
u_char *pbuf = NULL;
|
||||
int err;
|
||||
|
||||
if (!(skb = alloc_skb(sizeof(mISDN_pid_t) + pid->maxplen, GFP_ATOMIC)))
|
||||
return(-ENOMEM);
|
||||
|
@ -431,9 +429,11 @@ set_stack_req(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
hhe->addr = MGR_FUNCTION;
|
||||
hhe->data[0] = st;
|
||||
npid = (mISDN_pid_t *)skb_put(skb, sizeof(mISDN_pid_t));
|
||||
if (pid->pbuf)
|
||||
if (pid->maxplen)
|
||||
pbuf = skb_put(skb, pid->maxplen);
|
||||
copy_pid(npid, pid, pbuf);
|
||||
err = copy_pid(npid, pid, pbuf);
|
||||
if (err) // FIXME error handling
|
||||
int_errtxt("copy_pid error %d", err);
|
||||
hhe->func.ctrl = central_manager;
|
||||
skb_queue_tail(&mISDN_thread.workq, skb);
|
||||
wake_up_interruptible(&mISDN_thread.waitq);
|
||||
|
@ -506,7 +506,7 @@ new_entity(mISDNinstance_t *inst)
|
|||
printk(KERN_WARNING "mISDN: no more entity available(max %d)\n", MISDN_MAX_ENTITY);
|
||||
return(ret);
|
||||
}
|
||||
ret = inst->obj->own_ctrl(inst, MGR_NEWENTITY | CONFIRM, (void *)entity);
|
||||
ret = inst->obj->own_ctrl(inst, MGR_NEWENTITY | CONFIRM, (void *)((u_long)entity));
|
||||
if (ret)
|
||||
mISDN_delete_entity(entity);
|
||||
return(ret);
|
||||
|
@ -524,7 +524,7 @@ static int central_manager(void *data, u_int prim, void *arg) {
|
|||
return(new_entity(data));
|
||||
case MGR_DELENTITY | REQUEST:
|
||||
case MGR_DELENTITY | INDICATION:
|
||||
return(mISDN_delete_entity((int)arg));
|
||||
return(mISDN_delete_entity((u_long)arg & 0xffffffff));
|
||||
case MGR_REGLAYER | INDICATION:
|
||||
return(register_layer(st, arg));
|
||||
case MGR_REGLAYER | REQUEST:
|
||||
|
@ -535,48 +535,62 @@ static int central_manager(void *data, u_int prim, void *arg) {
|
|||
return(-EINVAL);
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
return(unregister_instance(data));
|
||||
#ifdef FIXME
|
||||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(disconnect_if(data, prim, arg));
|
||||
#endif
|
||||
case MGR_GETDEVICE | REQUEST:
|
||||
return(get_hdevice(data, arg));
|
||||
case MGR_DELDEVICE | REQUEST:
|
||||
return(free_device(data));
|
||||
#ifdef FIXME
|
||||
case MGR_QUEUEIF | REQUEST:
|
||||
return(mgr_queue(data, MGR_QUEUEIF, arg));
|
||||
#endif
|
||||
}
|
||||
if (!data)
|
||||
return(-EINVAL);
|
||||
switch(prim) {
|
||||
case MGR_ADDLAYER | REQUEST:
|
||||
return(preregister_layer(st, arg));
|
||||
case MGR_SETSTACK | REQUEST:
|
||||
/* can sleep in case of module reload */
|
||||
return(set_stack_req(st, arg));
|
||||
case MGR_SETSTACK_NW | REQUEST:
|
||||
return(set_stack(st, arg));
|
||||
case MGR_CLEARSTACK | REQUEST:
|
||||
return(clear_stack(st));
|
||||
return(clear_stack(st, arg ? 1 : 0));
|
||||
case MGR_DELSTACK | REQUEST:
|
||||
return(release_stack(st));
|
||||
case MGR_SELCHANNEL | REQUEST:
|
||||
return(sel_channel(st, arg));
|
||||
case MGR_STOPSTACK | REQUEST:
|
||||
return(mISDN_start_stop(st, 0));
|
||||
case MGR_STARTSTACK | REQUEST:
|
||||
return(mISDN_start_stop(st, 1));
|
||||
#ifdef FIXME
|
||||
case MGR_ADDIF | REQUEST:
|
||||
return(add_if(data, prim, arg));
|
||||
#endif
|
||||
case MGR_CTRLREADY | INDICATION:
|
||||
return(queue_ctrl_ready(st, arg));
|
||||
case MGR_ADDSTPARA | REQUEST:
|
||||
case MGR_CLRSTPARA | REQUEST:
|
||||
return(change_stack_para(st, prim, arg));
|
||||
#ifdef FIXME
|
||||
case MGR_CONNECT | REQUEST:
|
||||
return(mISDN_ConnectIF(data, arg));
|
||||
#endif
|
||||
case MGR_EVALSTACK | REQUEST:
|
||||
return(evaluate_stack_pids(data, arg));
|
||||
case MGR_GLOBALOPT | REQUEST:
|
||||
case MGR_LOADFIRM | REQUEST:
|
||||
if (st->mgr && st->mgr->obj && st->mgr->obj->own_ctrl)
|
||||
return(st->mgr->obj->own_ctrl(st->mgr, prim, arg));
|
||||
break;
|
||||
break;
|
||||
case MGR_DEBUGDATA | REQUEST:
|
||||
return(debugout(data, arg));
|
||||
return(debugout(data, arg));
|
||||
default:
|
||||
if (debug)
|
||||
printk(KERN_WARNING "manager prim %x not handled\n", prim);
|
||||
|
@ -587,6 +601,7 @@ static int central_manager(void *data, u_int prim, void *arg) {
|
|||
|
||||
int mISDN_register(mISDNobject_t *obj) {
|
||||
u_long flags;
|
||||
int retval;
|
||||
|
||||
if (!obj)
|
||||
return(-EINVAL);
|
||||
|
@ -601,7 +616,14 @@ int mISDN_register(mISDNobject_t *obj) {
|
|||
obj->id);
|
||||
if (core_debug & DEBUG_CORE_FUNC)
|
||||
printk(KERN_DEBUG "mISDN_register: obj(%p)\n", obj);
|
||||
return(0);
|
||||
retval = mISDN_register_sysfs_obj(obj);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "mISDN_register class_device_register return(%d)\n", retval);
|
||||
write_lock_irqsave(&mISDN_objects_lock, flags);
|
||||
list_del(&obj->list);
|
||||
write_unlock_irqrestore(&mISDN_objects_lock, flags);
|
||||
}
|
||||
return(retval);
|
||||
}
|
||||
|
||||
int mISDN_unregister(mISDNobject_t *obj) {
|
||||
|
@ -615,13 +637,14 @@ int mISDN_unregister(mISDNobject_t *obj) {
|
|||
if (obj->DPROTO.protocol[0])
|
||||
release_stacks(obj);
|
||||
else
|
||||
remove_object(obj);
|
||||
cleanup_object(obj);
|
||||
write_lock_irqsave(&mISDN_objects_lock, flags);
|
||||
list_del(&obj->list);
|
||||
write_unlock_irqrestore(&mISDN_objects_lock, flags);
|
||||
if (core_debug & DEBUG_CORE_FUNC)
|
||||
printk(KERN_DEBUG "mISDN_unregister: mISDN_objectlist(%p<-%p->%p)\n",
|
||||
mISDN_objectlist.prev, &mISDN_objectlist, mISDN_objectlist.next);
|
||||
class_device_unregister(&obj->class_dev);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
@ -638,9 +661,14 @@ mISDNInit(void)
|
|||
if (err)
|
||||
return(err);
|
||||
#endif
|
||||
err = mISDN_sysfs_init();
|
||||
if (err)
|
||||
goto sysfs_fail;
|
||||
|
||||
err = init_mISDNdev(debug);
|
||||
if (err)
|
||||
return(err);
|
||||
goto dev_fail;
|
||||
|
||||
init_waitqueue_head(&mISDN_thread.waitq);
|
||||
skb_queue_head_init(&mISDN_thread.workq);
|
||||
mISDN_thread.notify = &sem;
|
||||
|
@ -650,27 +678,24 @@ mISDNInit(void)
|
|||
test_and_set_bit(mISDN_TFLAGS_TEST, &mISDN_thread.Flags);
|
||||
wake_up_interruptible(&mISDN_thread.waitq);
|
||||
return(err);
|
||||
|
||||
dev_fail:
|
||||
mISDN_sysfs_cleanup();
|
||||
sysfs_fail:
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
__mid_cleanup();
|
||||
#endif
|
||||
return(err);
|
||||
}
|
||||
|
||||
void mISDN_cleanup(void) {
|
||||
DECLARE_MUTEX_LOCKED(sem);
|
||||
mISDNstack_t *st, *nst;
|
||||
|
||||
free_mISDNdev();
|
||||
if (!list_empty(&mISDN_objectlist)) {
|
||||
printk(KERN_WARNING "mISDNcore mISDN_objects not empty\n");
|
||||
}
|
||||
if (!list_empty(&mISDN_stacklist)) {
|
||||
printk(KERN_WARNING "mISDNcore mISDN_stacklist not empty\n");
|
||||
list_for_each_entry_safe(st, nst, &mISDN_stacklist, list) {
|
||||
printk(KERN_WARNING "mISDNcore st %x still in list\n",
|
||||
st->id);
|
||||
if (list_empty(&st->list)) {
|
||||
printk(KERN_WARNING "mISDNcore st == next\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
check_stacklist();
|
||||
if (mISDN_thread.thread) {
|
||||
/* abort mISDNd kernel thread */
|
||||
mISDN_thread.notify = &sem;
|
||||
|
@ -682,6 +707,7 @@ void mISDN_cleanup(void) {
|
|||
#ifdef MISDN_MEMDEBUG
|
||||
__mid_cleanup();
|
||||
#endif
|
||||
mISDN_sysfs_cleanup();
|
||||
printk(KERN_DEBUG "mISDNcore unloaded\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -19,46 +19,65 @@
|
|||
|
||||
/* debugging */
|
||||
#define DEBUG_CORE_FUNC 0x0001
|
||||
#define DEBUG_DUMMY_FUNC 0x0002
|
||||
//#define DEBUG_DUMMY_FUNC 0x0002
|
||||
#define DEBUG_MSG_THREAD_ERR 0x0010
|
||||
#define DEBUG_MSG_THREAD_INFO 0x0020
|
||||
#define DEBUG_QUEUE_FUNC 0x0040
|
||||
#define DEBUG_DEV_OP 0x0100
|
||||
#define DEBUG_MGR_FUNC 0x0200
|
||||
#define DEBUG_DEV_TIMER 0x0400
|
||||
#define DEBUG_RDATA 0x1000
|
||||
#define DEBUG_WDATA 0x2000
|
||||
|
||||
/* from mISDN_dev.c */
|
||||
/* from udevice.c */
|
||||
|
||||
extern int init_mISDNdev(int);
|
||||
extern int free_mISDNdev(void);
|
||||
extern mISDNdevice_t *get_free_rawdevice(void);
|
||||
extern int free_device(mISDNdevice_t *dev);
|
||||
|
||||
/* from mISDN_stack.c */
|
||||
|
||||
extern struct list_head mISDN_stacklist;
|
||||
extern struct list_head mISDN_instlist;
|
||||
/* from stack.c */
|
||||
|
||||
extern void get_stack_info(struct sk_buff *);
|
||||
extern int get_stack_cnt(void);
|
||||
extern void check_stacklist(void);
|
||||
extern void cleanup_object(mISDNobject_t *);
|
||||
extern mISDNstack_t *get_stack4id(u_int);
|
||||
extern int mISDN_start_stack_thread(mISDNstack_t *);
|
||||
extern mISDNstack_t *new_stack(mISDNstack_t *, mISDNinstance_t *);
|
||||
extern int mISDN_start_stop(mISDNstack_t *, int);
|
||||
extern int release_stack(mISDNstack_t *);
|
||||
extern int do_for_all_layers(void *, u_int, void *);
|
||||
extern int change_stack_para(mISDNstack_t *, u_int, mISDN_stPara_t *);
|
||||
extern void release_stacks(mISDNobject_t *);
|
||||
extern int copy_pid(mISDN_pid_t *, mISDN_pid_t *, u_char *);
|
||||
extern int set_stack(mISDNstack_t *, mISDN_pid_t *);
|
||||
extern int clear_stack(mISDNstack_t *);
|
||||
extern int clear_stack(mISDNstack_t *, int);
|
||||
extern int evaluate_stack_pids(mISDNstack_t *, mISDN_pid_t *);
|
||||
extern mISDNlayer_t *getlayer4lay(mISDNstack_t *, int);
|
||||
extern mISDNinstance_t *getlayer4lay(mISDNstack_t *, int);
|
||||
extern mISDNinstance_t *get_instance(mISDNstack_t *, int, int);
|
||||
|
||||
/* from mISDN_core.c */
|
||||
/* from sysfs_obj.c */
|
||||
extern int mISDN_register_sysfs_obj(mISDNobject_t *);
|
||||
extern int mISDN_sysfs_init(void);
|
||||
extern void mISDN_sysfs_cleanup(void);
|
||||
|
||||
extern struct list_head mISDN_objectlist;
|
||||
/* from sysfs_inst.c */
|
||||
extern int mISDN_register_sysfs_inst(mISDNinstance_t *);
|
||||
extern void mISDN_unregister_sysfs_inst(mISDNinstance_t *);
|
||||
extern int mISDN_sysfs_inst_init(void);
|
||||
extern void mISDN_sysfs_inst_cleanup(void);
|
||||
|
||||
/* from sysfs_stack.c */
|
||||
extern int mISDN_register_sysfs_stack(mISDNstack_t *);
|
||||
extern void mISDN_unregister_sysfs_st(mISDNstack_t *);
|
||||
extern int mISDN_sysfs_st_init(void);
|
||||
extern void mISDN_sysfs_st_cleanup(void);
|
||||
|
||||
/* from core.c */
|
||||
extern int core_debug;
|
||||
|
||||
extern int register_layer(mISDNstack_t *, mISDNinstance_t *);
|
||||
extern int preregister_layer(mISDNstack_t *, mISDNinstance_t *);
|
||||
extern int unregister_instance(mISDNinstance_t *);
|
||||
extern mISDNinstance_t *get_next_instance(mISDNstack_t *, mISDN_pid_t *);
|
||||
extern mISDNobject_t *get_object(int);
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mISDNif.h>
|
||||
#include "layer1.h"
|
||||
#include "helper.h"
|
||||
#include "dchannel.h"
|
||||
|
||||
static void
|
||||
dchannel_bh(dchannel_t *dch)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
mISDN_head_t *hh;
|
||||
|
||||
if (!dch)
|
||||
return;
|
||||
if (dch->debug)
|
||||
printk(KERN_DEBUG "%s: event %lx\n", __FUNCTION__, dch->event);
|
||||
#if 0
|
||||
if (test_and_clear_bit(D_CLEARBUSY, &dch->event)) {
|
||||
if (dch->debug)
|
||||
mISDN_debugprint(&dch->inst, "D-Channel Busy cleared");
|
||||
stptr = dch->stlist;
|
||||
while (stptr != NULL) {
|
||||
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
|
||||
stptr = stptr->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
|
||||
if ((skb = dch->next_skb)) {
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
dch->next_skb = NULL;
|
||||
skb_trim(skb, 0);
|
||||
if (if_newhead(&dch->inst.up, PH_DATA_CNF, hh->dinfo, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (test_and_clear_bit(D_RCVBUFREADY, &dch->event)) {
|
||||
while ((skb = skb_dequeue(&dch->rqueue))) {
|
||||
err = if_newhead(&dch->inst.up, PH_DATA_IND, MISDN_ID_ANY, skb);
|
||||
if (err < 0) {
|
||||
printk(KERN_WARNING "%s: deliver err %d\n", __FUNCTION__, err);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dch->hw_bh)
|
||||
dch->hw_bh(dch);
|
||||
}
|
||||
|
||||
int
|
||||
mISDN_init_dch(dchannel_t *dch) {
|
||||
if (!(dch->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for dlog\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
if (!(dch->tx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"mISDN: No memory for dchannel tx_buf\n");
|
||||
kfree(dch->dlog);
|
||||
dch->dlog = NULL;
|
||||
return(-ENOMEM);
|
||||
}
|
||||
dch->hw = NULL;
|
||||
dch->rx_skb = NULL;
|
||||
dch->tx_idx = 0;
|
||||
dch->next_skb = NULL;
|
||||
dch->event = 0;
|
||||
INIT_WORK(&dch->work, (void *)(void *)dchannel_bh, dch);
|
||||
dch->hw_bh = NULL;
|
||||
skb_queue_head_init(&dch->rqueue);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
mISDN_free_dch(dchannel_t *dch) {
|
||||
#ifdef HAS_WORKQUEUE
|
||||
if (dch->work.pending)
|
||||
printk(KERN_ERR "mISDN_free_dch work:(%lx)\n", dch->work.pending);
|
||||
#else
|
||||
if (dch->work.sync)
|
||||
printk(KERN_ERR "mISDN_free_dch work:(%lx)\n", dch->work.sync);
|
||||
#endif
|
||||
discard_queue(&dch->rqueue);
|
||||
if (dch->rx_skb) {
|
||||
dev_kfree_skb(dch->rx_skb);
|
||||
dch->rx_skb = NULL;
|
||||
}
|
||||
if (dch->tx_buf) {
|
||||
kfree(dch->tx_buf);
|
||||
dch->tx_buf = NULL;
|
||||
}
|
||||
if (dch->next_skb) {
|
||||
dev_kfree_skb(dch->next_skb);
|
||||
dch->next_skb = NULL;
|
||||
}
|
||||
if (dch->dlog) {
|
||||
kfree(dch->dlog);
|
||||
dch->dlog = NULL;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mISDN_init_dch);
|
||||
EXPORT_SYMBOL(mISDN_free_dch);
|
|
@ -1,92 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations for dchannel HW
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mISDNif.h>
|
||||
#ifdef HAS_WORKQUEUE
|
||||
#include <linux/workqueue.h>
|
||||
#else
|
||||
#include <linux/tqueue.h>
|
||||
#endif
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#define MAX_DFRAME_LEN_L1 300
|
||||
#define MAX_MON_FRAME 32
|
||||
#define MAX_DLOG_SPACE 2048
|
||||
|
||||
#define FLG_TWO_DCHAN 4
|
||||
#define FLG_TX_BUSY 5
|
||||
#define FLG_TX_NEXT 6
|
||||
#define FLG_L1_DBUSY 7
|
||||
#define FLG_DBUSY_TIMER 8
|
||||
#define FLG_LOCK_ATOMIC 9
|
||||
#define FLG_ARCOFI_TIMER 10
|
||||
#define FLG_ARCOFI_ERROR 11
|
||||
#define FLG_HW_L1_UINT 12
|
||||
#define FLG_HW_INIT 13
|
||||
|
||||
typedef struct _dchannel_t {
|
||||
int channel;
|
||||
mISDNinstance_t inst;
|
||||
u_long DFlags;
|
||||
u_int type;
|
||||
u_int ph_state;
|
||||
u_char (*read_reg) (void *, u_char);
|
||||
void (*write_reg) (void *, u_char, u_char);
|
||||
void (*read_fifo) (void *, u_char *, int);
|
||||
void (*write_fifo) (void *, u_char *, int);
|
||||
char *dlog;
|
||||
int debug;
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff *next_skb;
|
||||
u_char *tx_buf;
|
||||
int tx_idx;
|
||||
int tx_len;
|
||||
int up_headerlen;
|
||||
int err_crc;
|
||||
int err_tx;
|
||||
int err_rx;
|
||||
void *hw;
|
||||
struct timer_list dbusytimer;
|
||||
u_long event;
|
||||
struct sk_buff_head rqueue; /* D-channel receive queue */
|
||||
struct work_struct work;
|
||||
void (*hw_bh) (struct _dchannel_t *);
|
||||
} dchannel_t;
|
||||
|
||||
#define MON0_RX 1
|
||||
#define MON1_RX 2
|
||||
#define MON0_TX 4
|
||||
#define MON1_TX 8
|
||||
|
||||
extern int mISDN_init_dch(dchannel_t *);
|
||||
extern int mISDN_free_dch(dchannel_t *);
|
||||
|
||||
static inline void
|
||||
dch_set_para(dchannel_t *dch, mISDN_stPara_t *stp)
|
||||
{
|
||||
if (stp)
|
||||
dch->up_headerlen = stp->up_headerlen;
|
||||
else
|
||||
dch->up_headerlen = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dchannel_sched_event(dchannel_t *dch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &dch->event);
|
||||
schedule_work(&dch->work);
|
||||
}
|
|
@ -5,9 +5,13 @@
|
|||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
#ifndef MISDN_DEBUG_H
|
||||
|
||||
#define MISDN_DEBUG_MANAGER 0x10000
|
||||
|
||||
extern void vmISDN_debug(int id, char *head, char *fmt, va_list args);
|
||||
extern void mISDN_debug(int id, char *head, char *fmt, ...);
|
||||
extern char * mISDN_getrev(const char *revision);
|
||||
extern void mISDN_debugprint(mISDNinstance_t *inst, char *fmt, ...);
|
||||
extern int mISDN_QuickHex(char *, u_char *, int);
|
||||
#endif
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
//#define AUTOJITTER
|
||||
|
||||
#define DEBUG_DSP_MGR 0x0001
|
||||
#define DEBUG_DSP_CORE 0x0002
|
||||
#define DEBUG_DSP_DTMF 0x0004
|
||||
|
@ -29,19 +27,31 @@
|
|||
#define DSP_OPT_ULAW (1<<0)
|
||||
#define DSP_OPT_NOHARDWARE (1<<1)
|
||||
|
||||
#ifdef HAS_WORKQUEUE
|
||||
#include <linux/workqueue.h>
|
||||
#else
|
||||
#include <linux/tqueue.h>
|
||||
#endif
|
||||
#define FEAT_STATE_INIT 1
|
||||
#define FEAT_STATE_WAIT 2
|
||||
|
||||
#include <linux/timer.h>
|
||||
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#include "dsp_ecdis.h"
|
||||
|
||||
/*
|
||||
* You are now able to choose between the Mark2 and the
|
||||
* kb1 Echo cancellor. Just comment the one and comment
|
||||
* out the other.
|
||||
*/
|
||||
|
||||
//#include "dsp_mec2.h"
|
||||
//#include "dsp_kb1ec.h"
|
||||
#include "dsp_mg2ec.h"
|
||||
|
||||
extern int dsp_options;
|
||||
extern int dsp_debug;
|
||||
extern int dsp_poll;
|
||||
extern int dsp_tics;
|
||||
|
||||
/***************
|
||||
* audio stuff *
|
||||
|
@ -67,9 +77,18 @@ extern u8 dsp_silence;
|
|||
* cmx stuff *
|
||||
*************/
|
||||
|
||||
#define CMX_BUFF_SIZE 0x4000 /* must be 2**n */
|
||||
#define CMX_BUFF_HALF 0x2000 /* CMX_BUFF_SIZE / 2 */
|
||||
#define CMX_BUFF_MASK 0x3fff /* CMX_BUFF_SIZE - 1 */
|
||||
#define MAX_POLL 256 /* maximum number of send-chunks */
|
||||
|
||||
#define CMX_BUFF_SIZE 0x8000 /* must be 2**n (0x1000 about 1/2 second) */
|
||||
#define CMX_BUFF_HALF 0x4000 /* CMX_BUFF_SIZE / 2 */
|
||||
#define CMX_BUFF_MASK 0x7fff /* CMX_BUFF_SIZE - 1 */
|
||||
|
||||
/* how many seconds will we check the lowest delay until the jitter buffer
|
||||
is reduced by that delay */
|
||||
#define MAX_SECONDS_JITTER_CHECK 5
|
||||
|
||||
extern struct timer_list dsp_spl_tl;
|
||||
extern u64 dsp_spl_jiffies;
|
||||
|
||||
/* the structure of conferences:
|
||||
*
|
||||
|
@ -93,11 +112,6 @@ typedef struct _conference {
|
|||
struct list_head mlist;
|
||||
int software; /* conf is processed by software */
|
||||
int hardware; /* conf is processed by hardware */
|
||||
//#ifndef AUTOJITTER
|
||||
int largest; /* largest frame received in conf's life. */
|
||||
//#endif
|
||||
int W_min, W_max; /* min/maximum rx-write pointer of members */
|
||||
s32 conf_buff[CMX_BUFF_SIZE];
|
||||
} conference_t;
|
||||
|
||||
extern mISDNobject_t dsp_obj;
|
||||
|
@ -109,6 +123,8 @@ extern mISDNobject_t dsp_obj;
|
|||
|
||||
#define DSP_DTMF_NPOINTS 102
|
||||
|
||||
#define ECHOCAN_BUFLEN 4*128
|
||||
|
||||
typedef struct _dtmf_t {
|
||||
int software; /* dtmf uses software decoding */
|
||||
int hardware; /* dtmf uses hardware decoding */
|
||||
|
@ -120,6 +136,12 @@ typedef struct _dtmf_t {
|
|||
} dtmf_t;
|
||||
|
||||
|
||||
/****************
|
||||
* cancel stuff *
|
||||
****************/
|
||||
|
||||
|
||||
|
||||
/***************
|
||||
* tones stuff *
|
||||
***************/
|
||||
|
@ -147,6 +169,7 @@ struct dsp_features {
|
|||
int pcm_id; /* unique id to identify the pcm bus (or -1) */
|
||||
int pcm_slots; /* number of slots on the pcm bus */
|
||||
int pcm_banks; /* number of IO banks of pcm bus */
|
||||
int has_jitter; /* data is jittered and unsorted */
|
||||
};
|
||||
|
||||
typedef struct _dsp {
|
||||
|
@ -159,8 +182,6 @@ typedef struct _dsp {
|
|||
tone_t tone;
|
||||
dtmf_t dtmf;
|
||||
int tx_volume, rx_volume;
|
||||
struct work_struct sendwork; /* event for sending data */
|
||||
int tx_pending;
|
||||
|
||||
/* conference stuff */
|
||||
u32 conf_id;
|
||||
|
@ -168,20 +189,18 @@ typedef struct _dsp {
|
|||
conf_member_t *member;
|
||||
|
||||
/* buffer stuff */
|
||||
int largest; /* largest frame received in dsp's life. */
|
||||
int R_tx, W_tx; /* pointers of transmit buffer */
|
||||
int R_rx, W_rx; /* pointers of receive buffer and conference buffer */
|
||||
int rx_W; /* current write pos for data without timestamp */
|
||||
int rx_R; /* current read pos for transmit clock */
|
||||
int tx_W; /* current write pos for transmit data */
|
||||
int tx_R; /* current read pos for transmit clock */
|
||||
int delay[MAX_SECONDS_JITTER_CHECK];
|
||||
u8 tx_buff[CMX_BUFF_SIZE];
|
||||
u8 rx_buff[CMX_BUFF_SIZE];
|
||||
#ifdef AUTOJITTER
|
||||
int tx_delay; /* used to find the delay of tx buffer */
|
||||
int tx_delay_count;
|
||||
int rx_delay; /* used to find the delay of rx buffer */
|
||||
int rx_delay_count;
|
||||
#endif
|
||||
|
||||
/* hardware stuff */
|
||||
struct dsp_features features; /* features */
|
||||
struct timer_list feature_tl;
|
||||
int feature_state;
|
||||
int pcm_slot_rx; /* current PCM slot (or -1) */
|
||||
int pcm_bank_rx;
|
||||
int pcm_slot_tx;
|
||||
|
@ -200,6 +219,25 @@ typedef struct _dsp {
|
|||
u8 bf_crypt_inring[16];
|
||||
u8 bf_data_out[9];
|
||||
int bf_sync;
|
||||
|
||||
/* echo cancellation stuff */
|
||||
int cancel_enable;
|
||||
struct echo_can_state * ec; /**< == NULL: echo cancellation disabled;
|
||||
!= NULL: echo cancellation enabled */
|
||||
|
||||
echo_can_disable_detector_state_t* ecdis_rd;
|
||||
echo_can_disable_detector_state_t* ecdis_wr;
|
||||
|
||||
uint16_t echotimer;
|
||||
uint16_t echostate;
|
||||
uint16_t echolastupdate;
|
||||
|
||||
char txbuf[ECHOCAN_BUFLEN];
|
||||
int txbuflen;
|
||||
|
||||
char rxbuf[ECHOCAN_BUFLEN];
|
||||
int rxbuflen;
|
||||
|
||||
} dsp_t;
|
||||
|
||||
/* functions */
|
||||
|
@ -211,7 +249,11 @@ extern void dsp_cmx_debug(dsp_t *dsp);
|
|||
extern void dsp_cmx_hardware(conference_t *conf, dsp_t *dsp);
|
||||
extern int dsp_cmx_conf(dsp_t *dsp, u32 conf_id);
|
||||
extern void dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb);
|
||||
#ifdef OLDCMX
|
||||
extern struct sk_buff *dsp_cmx_send(dsp_t *dsp, int len, int dinfo);
|
||||
#else
|
||||
extern void dsp_cmx_send(void *data);
|
||||
#endif
|
||||
extern void dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb);
|
||||
extern int dsp_cmx_del_conf_member(dsp_t *dsp);
|
||||
extern int dsp_cmx_del_conf(conference_t *conf);
|
||||
|
@ -228,4 +270,8 @@ extern void dsp_bf_decrypt(dsp_t *dsp, u8 *data, int len);
|
|||
extern int dsp_bf_init(dsp_t *dsp, const u8 *key, unsigned int keylen);
|
||||
extern void dsp_bf_cleanup(dsp_t *dsp);
|
||||
|
||||
extern void dsp_cancel_tx(dsp_t *dsp, u8 *data, int len);
|
||||
extern void dsp_cancel_rx(dsp_t *dsp, u8 *data, int len);
|
||||
extern int dsp_cancel_init(dsp_t *dsp, int taps, int training, int delay);
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Blowfish encryption/decryption for mISDN_dsp.
|
||||
*
|
||||
* Copyright 2002/2003 by Andreas Eversberg (jolly@jolly.de)
|
||||
* Copyright Andreas Eversberg (jolly@jolly.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
/* HOW THE CMX WORKS:
|
||||
*
|
||||
* There are 3 types of interaction: One member is alone, in this case only
|
||||
* data flow is done.
|
||||
* data flow from upper to lower layer is done.
|
||||
* Two members will also exchange their data so they are crossconnected.
|
||||
* Three or more members will be added in a conference and will hear each
|
||||
* other but will not receive their own speech (echo) if not enabled.
|
||||
|
@ -40,37 +40,24 @@
|
|||
* - Force mixing of transmit data with other crossconnect/conference members.
|
||||
* - Echo generation to benchmark the delay of audio processing.
|
||||
* - Use hardware to minimize cpu load, disable FIFO load and minimize delay.
|
||||
* - Dejittering and clock generation.
|
||||
*
|
||||
* There are 3 buffers:
|
||||
*
|
||||
* The conference buffer
|
||||
*
|
||||
* R-3 R-2 R-1 W-2 W-1 W-3
|
||||
* | | | | | |
|
||||
* --+-------+-----+------+------+---+---------------
|
||||
* | |
|
||||
* W-min W-max
|
||||
*
|
||||
* The conference buffer is a ring buffer used to mix all data from all members.
|
||||
* To compensate the echo, data of individual member will later be substracted
|
||||
* before it is sent to that member. Each conference has a W-min and a W-max
|
||||
* pointer. Each individual member has a write pointer (W-x) and a read pointer
|
||||
* (R-x). W-min shows the lowest value of all W-x. The W-max shows the highest
|
||||
* value of all W-x. Whenever data is written, it is mixed by adding to the
|
||||
* existing sample value in the buffer. If W-max would increase, the additional
|
||||
* range is cleared so old data will be erased in the ring buffer.
|
||||
* There are 2 buffers:
|
||||
*
|
||||
*
|
||||
* RX-Buffer
|
||||
* R-1 W-1
|
||||
* R W
|
||||
* | |
|
||||
* ----------------+-------------+-------------------
|
||||
*
|
||||
* The rx-buffer is a ring buffer used to store the received data for each
|
||||
* individual member. To compensate echo, this data will later be substracted
|
||||
* from the conference's data before it is sent to that member. If only two
|
||||
* members are in one conference, this data is used to get the queued data from
|
||||
* the other member.
|
||||
* individual member. This is only the case if data needs to be dejittered
|
||||
* or in case of a conference where different clocks require reclocking.
|
||||
* The transmit-clock (R) will read the buffer.
|
||||
* If the clock overruns the write-pointer, we will have a buffer underrun.
|
||||
* If the write pointer always has a certain distance from the transmit-
|
||||
* clock, we will have a delay. The delay will dynamically be increased and
|
||||
* reduced.
|
||||
*
|
||||
*
|
||||
* TX-Buffer
|
||||
|
@ -84,28 +71,25 @@
|
|||
* (some) data is dropped so that it will not overrun.
|
||||
*
|
||||
*
|
||||
* Clock:
|
||||
*
|
||||
* A Clock is not required, if the data source has exactly one clock. In this
|
||||
* case the data source is forwarded to the destination.
|
||||
*
|
||||
* A Clock is required, because the data source
|
||||
* - has multiple clocks.
|
||||
* - has no clock due to jitter (VoIP).
|
||||
* In this case the system's clock is used. The clock resolution depends on
|
||||
* the jiffie resolution.
|
||||
*
|
||||
* If a member joins a conference:
|
||||
*
|
||||
* - If a member joins, its rx_buff is set to silence.
|
||||
* - If the conference reaches three members, the conf-buffer is cleared.
|
||||
* - When a member is joined, it will set its write and read pointer to W_max.
|
||||
* - If a member joins, its rx_buff is set to silence and change read pointer
|
||||
* to transmit clock.
|
||||
*
|
||||
* The procedure of received data from card is explained in cmx_receive.
|
||||
* The procedure of received data from user space is explained in cmx_transmit.
|
||||
*
|
||||
*
|
||||
* LIMITS:
|
||||
*
|
||||
* The max_queue value is 2* the samples of largest packet ever received by any
|
||||
* conference member from her card. It also changes during life of conference.
|
||||
*
|
||||
*
|
||||
* AUDIO PROCESS:
|
||||
*
|
||||
* Writing data to conference's and member's buffer is done by adding the sample
|
||||
* value to the existing ring buffer. Writing user space data to the member's
|
||||
* buffer is done by substracting the sample value from the existing ring
|
||||
* buffer.
|
||||
* The procedure of transmit data to card is cmx_send.
|
||||
*
|
||||
*
|
||||
* Interaction with other features:
|
||||
|
@ -143,12 +127,10 @@
|
|||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
#include "dsp.h"
|
||||
#include "hw_lock.h"
|
||||
|
||||
//#define CMX_CONF_DEBUG /* debugging of multi party conference, by using conference even with two members */
|
||||
//#define CMX_DEBUG /* massive read/write pointer output */
|
||||
|
||||
extern mISDN_HWlock_t dsp_lock;
|
||||
LIST_HEAD(Conf_list);
|
||||
|
||||
/*
|
||||
|
@ -157,13 +139,12 @@ LIST_HEAD(Conf_list);
|
|||
void
|
||||
dsp_cmx_debug(dsp_t *dsp)
|
||||
{
|
||||
conference_t *conf;
|
||||
conf_member_t *member;
|
||||
dsp_t *odsp;
|
||||
conference_t *conf;
|
||||
conf_member_t *member;
|
||||
dsp_t *odsp;
|
||||
|
||||
printk(KERN_DEBUG "-----Current DSP\n");
|
||||
list_for_each_entry(odsp, &dsp_obj.ilist, list)
|
||||
{
|
||||
list_for_each_entry(odsp, &dsp_obj.ilist, list) {
|
||||
printk(KERN_DEBUG "* %s echo=%d txmix=%d", odsp->inst.name, odsp->echo, odsp->tx_mix);
|
||||
if (odsp->conf)
|
||||
printk(" (Conf %d)", odsp->conf->id);
|
||||
|
@ -171,14 +152,15 @@ dsp_cmx_debug(dsp_t *dsp)
|
|||
printk(" *this*");
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "-----Current Conf:\n");
|
||||
list_for_each_entry(conf, &Conf_list, list)
|
||||
{
|
||||
printk(KERN_DEBUG "* Conf %d (0x%x)\n", conf->id, (u32)conf);
|
||||
list_for_each_entry(member, &conf->mlist, list)
|
||||
{
|
||||
printk(KERN_DEBUG " - member = %s (slot_tx %d, bank_tx %d, slot_rx %d, bank_rx %d hfc_conf %d)%s\n", member->dsp->inst.name, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx, member->dsp->hfc_conf, (member->dsp==dsp)?" *this*":"");
|
||||
list_for_each_entry(conf, &Conf_list, list) {
|
||||
printk(KERN_DEBUG "* Conf %d (%p)\n", conf->id, conf);
|
||||
list_for_each_entry(member, &conf->mlist, list) {
|
||||
printk(KERN_DEBUG
|
||||
" - member = %s (slot_tx %d, bank_tx %d, slot_rx %d, bank_rx %d hfc_conf %d)%s\n",
|
||||
member->dsp->inst.name, member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx,
|
||||
member->dsp->pcm_slot_rx, member->dsp->pcm_bank_rx, member->dsp->hfc_conf,
|
||||
(member->dsp==dsp)?" *this*":"");
|
||||
}
|
||||
}
|
||||
printk(KERN_DEBUG "-----end\n");
|
||||
|
@ -231,26 +213,18 @@ dsp_cmx_add_conf_member(dsp_t *dsp, conference_t *conf)
|
|||
return(-EINVAL);
|
||||
}
|
||||
|
||||
unlock_HW(&dsp_lock);
|
||||
if (!(member = vmalloc(sizeof(conf_member_t)))) {
|
||||
lock_HW(&dsp_lock, 0);
|
||||
printk(KERN_ERR "vmalloc conf_member_t failed\n");
|
||||
if (!(member = kmalloc(sizeof(conf_member_t), GFP_ATOMIC))) {
|
||||
printk(KERN_ERR "kmalloc conf_member_t failed\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
lock_HW(&dsp_lock, 0);
|
||||
memset(member, 0, sizeof(conf_member_t));
|
||||
memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
|
||||
member->dsp = dsp;
|
||||
/* set initial values */
|
||||
dsp->W_rx = conf->W_max;
|
||||
dsp->R_rx = conf->W_max;
|
||||
/* clear rx buffer */
|
||||
memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
|
||||
dsp->rx_W = dsp->rx_R = -1; /* reset pointers */
|
||||
|
||||
list_add_tail(&member->list, &conf->mlist);
|
||||
|
||||
/* zero conf-buffer if we change from 2 to 3 members */
|
||||
if (3 == count_list_member(&conf->mlist))
|
||||
memset(conf->conf_buff, 0, sizeof(conf->conf_buff));
|
||||
|
||||
dsp->conf = conf;
|
||||
dsp->member = member;
|
||||
|
||||
|
@ -290,9 +264,7 @@ dsp_cmx_del_conf_member(dsp_t *dsp)
|
|||
list_del(&member->list);
|
||||
dsp->conf = NULL;
|
||||
dsp->member = NULL;
|
||||
unlock_HW(&dsp_lock);
|
||||
vfree(member);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
kfree(member);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
@ -317,13 +289,10 @@ static conference_t
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
unlock_HW(&dsp_lock);
|
||||
if (!(conf = vmalloc(sizeof(conference_t)))) {
|
||||
lock_HW(&dsp_lock, 0);
|
||||
printk(KERN_ERR "vmalloc conference_t failed\n");
|
||||
if (!(conf = kmalloc(sizeof(conference_t), GFP_ATOMIC))) {
|
||||
printk(KERN_ERR "kmalloc conference_t failed\n");
|
||||
return(NULL);
|
||||
}
|
||||
lock_HW(&dsp_lock, 0);
|
||||
memset(conf, 0, sizeof(conference_t));
|
||||
INIT_LIST_HEAD(&conf->mlist);
|
||||
conf->id = id;
|
||||
|
@ -352,9 +321,7 @@ dsp_cmx_del_conf(conference_t *conf)
|
|||
return(-EINVAL);
|
||||
}
|
||||
list_del(&conf->list);
|
||||
unlock_HW(&dsp_lock);
|
||||
vfree(conf);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
kfree(conf);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
@ -379,7 +346,7 @@ dsp_cmx_hw_message(dsp_t *dsp, u32 message, u32 param1, u32 param2, u32 param3,
|
|||
return;
|
||||
}
|
||||
/* unlocking is not required, because we don't expect a response */
|
||||
if (dsp->inst.down.func(&dsp->inst.down, nskb))
|
||||
if (mISDN_queue_down(&dsp->inst, 0, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
}
|
||||
|
||||
|
@ -395,12 +362,12 @@ dsp_cmx_hw_message(dsp_t *dsp, u32 message, u32 param1, u32 param2, u32 param3,
|
|||
void
|
||||
dsp_cmx_hardware(conference_t *conf, dsp_t *dsp)
|
||||
{
|
||||
conf_member_t *member, *nextm;
|
||||
dsp_t *finddsp;
|
||||
int memb = 0, i, ii, i1, i2;
|
||||
int freeunits[8];
|
||||
u_char freeslots[256];
|
||||
int same_hfc = -1, same_pcm = -1, current_conf = -1, all_conf = 1;
|
||||
conf_member_t *member, *nextm;
|
||||
dsp_t *finddsp;
|
||||
int memb = 0, i, ii, i1, i2;
|
||||
int freeunits[8];
|
||||
u_char freeslots[256];
|
||||
int same_hfc = -1, same_pcm = -1, current_conf = -1, all_conf = 1;
|
||||
|
||||
/* dsp gets updated (no conf) */
|
||||
//printk("-----1\n");
|
||||
|
@ -558,6 +525,12 @@ dsp_cmx_hardware(conference_t *conf, dsp_t *dsp)
|
|||
printk(KERN_DEBUG "%s dsp %s cannot form a conf, because encryption is enabled\n", __FUNCTION__, member->dsp->inst.name);
|
||||
goto conf_software;
|
||||
}
|
||||
/* check if echo cancellation is enabled */
|
||||
if (member->dsp->cancel_enable) {
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
printk(KERN_DEBUG "%s dsp %s cannot form a conf, because echo cancellation is enabled\n", __FUNCTION__, member->dsp->inst.name);
|
||||
goto conf_software;
|
||||
}
|
||||
/* check if member is on a card with PCM support */
|
||||
if (member->dsp->features.pcm_id < 0) {
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
|
@ -960,216 +933,127 @@ dsp_cmx_conf(dsp_t *dsp, u32 conf_id)
|
|||
/*
|
||||
* audio data is received from card
|
||||
*/
|
||||
|
||||
void
|
||||
dsp_cmx_receive(dsp_t *dsp, struct sk_buff *skb)
|
||||
{
|
||||
conference_t *conf = dsp->conf;
|
||||
conf_member_t *member;
|
||||
s32 *c;
|
||||
// s32 *c;
|
||||
u8 *d, *p;
|
||||
int len = skb->len;
|
||||
int w, ww, i, ii;
|
||||
int W_min, W_max;
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(skb);
|
||||
int w, i, ii;
|
||||
// int direct = 0; /* use rx data to clock tx-data */
|
||||
|
||||
/* check if we have sompen */
|
||||
if (len < 1)
|
||||
return;
|
||||
|
||||
//#ifndef AUTOJITTER
|
||||
/* -> if length*2 is greater largest */
|
||||
if (dsp->largest < (len<<1))
|
||||
dsp->largest = (len<<1);
|
||||
//#endif
|
||||
#if 0
|
||||
/* check if we can use our clock and directly forward data */
|
||||
if (!dsp->features.has_jitter) {
|
||||
if (!conf)
|
||||
direct = 1;
|
||||
else {
|
||||
if (count_list_member(&conf->mlist) <= 2)
|
||||
direct = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* half of the buffer should be 4 time larger than maximum packet size */
|
||||
if (len >= (CMX_BUFF_HALF>>2)) {
|
||||
/* half of the buffer should be larger than maximum packet size */
|
||||
if (len >= CMX_BUFF_HALF) {
|
||||
printk(KERN_ERR "%s line %d: packet from card is too large (%d bytes). please make card send smaller packets OR increase CMX_BUFF_SIZE\n", __FILE__, __LINE__, len);
|
||||
return;
|
||||
}
|
||||
|
||||
/* STEP 1: WRITE DOWN WHAT WE GOT (into the buffer(s)) */
|
||||
|
||||
/* -> new W-min & W-max is calculated:
|
||||
* W_min will be the write pointer of this dsp (after writing 'len'
|
||||
* of bytes).
|
||||
* If there are other members in a conference, W_min will be the
|
||||
* lowest of all member's writer pointers.
|
||||
* W_max respectively
|
||||
*/
|
||||
W_max = W_min = (dsp->W_rx + len) & CMX_BUFF_MASK;
|
||||
if (conf) {
|
||||
/* -> who is larger? dsp or conf */
|
||||
if (conf->largest < dsp->largest)
|
||||
conf->largest = dsp->largest;
|
||||
else if (conf->largest > dsp->largest)
|
||||
dsp->largest = conf->largest;
|
||||
|
||||
list_for_each_entry(member, &conf->mlist, list) {
|
||||
if (member != dsp->member) {
|
||||
/* if W_rx is lower */
|
||||
if (((member->dsp->W_rx - W_min) & CMX_BUFF_MASK) >= CMX_BUFF_HALF)
|
||||
W_min = member->dsp->W_rx;
|
||||
/* if W_rx is higher */
|
||||
if (((W_max - member->dsp->W_rx) & CMX_BUFF_MASK) >= CMX_BUFF_HALF)
|
||||
W_max = member->dsp->W_rx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "cmx_receive(dsp=%lx): W_rx(dsp)=%05x W_min=%05x W_max=%05x largest=%05x %s\n", dsp, dsp->W_rx, W_min, W_max, dsp->largest, dsp->inst.name);
|
||||
#endif
|
||||
|
||||
/* -> if data is not too fast (exceed maximum queue):
|
||||
* data is written if 'new W_rx' is not too far behind W_min.
|
||||
*/
|
||||
if (((dsp->W_rx + len - W_min) & CMX_BUFF_MASK) <= dsp->largest) {
|
||||
/* -> received data is written to rx-buffer */
|
||||
p = skb->data;
|
||||
d = dsp->rx_buff;
|
||||
w = dsp->W_rx;
|
||||
i = 0;
|
||||
ii = len;
|
||||
while(i < ii) {
|
||||
d[w++ & CMX_BUFF_MASK] = *p++;
|
||||
i++;
|
||||
}
|
||||
/* -> if conference has three or more members */
|
||||
if (conf) {
|
||||
#ifdef CMX_CONF_DEBUG
|
||||
#warning CMX_CONF_DEBUG is enabled, it causes performance loss with normal 2-party crossconnects
|
||||
if (2 <= count_list_member(&conf->mlist)) {
|
||||
#else
|
||||
if (3 <= count_list_member(&conf->mlist)) {
|
||||
#endif
|
||||
//printk(KERN_DEBUG "cmxing dsp:%s dsp->W_rx=%04x conf->W_max=%04x\n", dsp->inst.name, dsp->W_rx, conf->W_max);
|
||||
/* -> received data is added to conf-buffer
|
||||
* new space is overwritten */
|
||||
p = skb->data;
|
||||
c = conf->conf_buff;
|
||||
w = dsp->W_rx;
|
||||
ww = conf->W_max;
|
||||
i = 0;
|
||||
ii = len;
|
||||
/* loop until done or old W_max is reached */
|
||||
while(i<ii && w!=ww) {
|
||||
c[w] += dsp_audio_law_to_s32[*p++]; /* add to existing */
|
||||
w = (w+1) & CMX_BUFF_MASK; /* must be always masked, for loop condition */
|
||||
i++;
|
||||
}
|
||||
/* loop the rest */
|
||||
while(i < ii) {
|
||||
c[w++ & CMX_BUFF_MASK] = dsp_audio_law_to_s32[*p++]; /* write to new */
|
||||
i++;
|
||||
}
|
||||
}
|
||||
/* if W_max is lower new dsp->W_rx */
|
||||
if (((W_max - (dsp->W_rx+len)) & CMX_BUFF_MASK) >= CMX_BUFF_HALF)
|
||||
W_max = (dsp->W_rx + len) & CMX_BUFF_MASK;
|
||||
/* store for dsp_cmx_send */
|
||||
conf->W_min = W_min;
|
||||
/* -> write new W_max */
|
||||
conf->W_max = W_max;
|
||||
}
|
||||
/* -> write new W_rx */
|
||||
dsp->W_rx = (dsp->W_rx + len) & CMX_BUFF_MASK;
|
||||
/* initialize pointers if not already */
|
||||
if (dsp->rx_W < 0) {
|
||||
if (dsp->features.has_jitter)
|
||||
dsp->rx_R = dsp->rx_W = (hh->dinfo & CMX_BUFF_MASK);
|
||||
else
|
||||
dsp->rx_R = dsp->rx_W = 0;
|
||||
} else {
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
printk(KERN_DEBUG "CMX: receiving too fast (rx_buff) dsp=%x\n", (u32)dsp);
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "W_max=%x-W_min=%x = %d, largest = %d\n", W_max, W_min, (W_max - W_min) & CMX_BUFF_MASK, dsp->largest);
|
||||
#endif
|
||||
if (dsp->features.has_jitter) {
|
||||
dsp->rx_W = (hh->dinfo & CMX_BUFF_MASK);
|
||||
}
|
||||
/* if we underrun (or maybe overrun), we set our new read pointer, and write silence to buffer */
|
||||
if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) {
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
printk(KERN_DEBUG "cmx_receive(dsp=%lx): UNDERRUN (or overrun), adjusting read pointer! (inst %s)\n", (u_long)dsp, dsp->inst.name);
|
||||
dsp->rx_R = dsp->rx_W;
|
||||
memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff));
|
||||
}
|
||||
}
|
||||
|
||||
/* show where to write */
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "cmx_receive(dsp=%lx): rx_R(dsp) rx_W(dsp)=%05x len=%d %s\n", (u_long)dsp, dsp->rx_R, dsp->rx_W, len, dsp->inst.name);
|
||||
#endif
|
||||
|
||||
/* write data into rx_buffer */
|
||||
p = skb->data;
|
||||
d = dsp->rx_buff;
|
||||
w = dsp->rx_W;
|
||||
i = 0;
|
||||
ii = len;
|
||||
while(i < ii) {
|
||||
d[w++ & CMX_BUFF_MASK] = *p++;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* increase write-pointer */
|
||||
dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK);
|
||||
}
|
||||
|
||||
/*
|
||||
* send mixed audio data to card
|
||||
*/
|
||||
|
||||
struct sk_buff
|
||||
*dsp_cmx_send(dsp_t *dsp, int len, int dinfo)
|
||||
/*
|
||||
* send (mixed) audio data to card and control jitter
|
||||
*/
|
||||
static void
|
||||
dsp_cmx_send_member(dsp_t *dsp, int len, s32 *c, int members)
|
||||
{
|
||||
int dinfo = 0;
|
||||
conference_t *conf = dsp->conf;
|
||||
dsp_t *member, *other;
|
||||
register s32 sample;
|
||||
s32 *c;
|
||||
u8 *d, *o, *p, *q;
|
||||
u8 *d, *p, *q, *o_q;
|
||||
struct sk_buff *nskb;
|
||||
int r, rr, t, tt;
|
||||
int r, rr, t, tt, o_r, o_rr;
|
||||
|
||||
/* don't process if: */
|
||||
if (dsp->pcm_slot_tx >= 0 /* connected to pcm slot */
|
||||
&& dsp->tx_R == dsp->tx_W /* AND no tx-data */
|
||||
&& !(dsp->tone.tone && dsp->tone.software)) /* AND not soft tones */
|
||||
return;
|
||||
if (!dsp->b_active) /* if not active */
|
||||
return;
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "SEND members=%d dsp=%s, conf=%p, rx_R=%05x rx_W=%05x\n", members, dsp->inst.name, conf, dsp->rx_R, dsp->rx_W);
|
||||
#endif
|
||||
|
||||
/* PREPARE RESULT */
|
||||
nskb = alloc_skb(len, GFP_ATOMIC);
|
||||
if (!nskb) {
|
||||
printk(KERN_ERR "FATAL ERROR in mISDN_dsp.o: cannot alloc %d bytes\n", len);
|
||||
return(NULL);
|
||||
return;
|
||||
}
|
||||
mISDN_sethead(PH_DATA | REQUEST, dinfo, nskb);
|
||||
|
||||
/* set pointers, indexes and stuff */
|
||||
member = dsp;
|
||||
p = dsp->tx_buff; /* transmit data */
|
||||
q = dsp->rx_buff; /* received data */
|
||||
d = skb_put(nskb, len); /* result */
|
||||
t = dsp->R_tx; /* tx-pointers */
|
||||
tt = dsp->W_tx;
|
||||
r = dsp->R_rx; /* rx-pointers */
|
||||
if (conf) {
|
||||
/* special hardware access */
|
||||
if (conf->hardware) {
|
||||
if (dsp->tone.tone && dsp->tone.software) {
|
||||
/* -> copy tone */
|
||||
dsp_tone_copy(dsp, d, len);
|
||||
dsp->R_tx = dsp->W_tx = 0; /* clear tx buffer */
|
||||
return(nskb);
|
||||
}
|
||||
if (t != tt) {
|
||||
while(len && t!=tt) {
|
||||
*d++ = p[t]; /* write tx_buff */
|
||||
t = (t+1) & CMX_BUFF_MASK;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
if (len)
|
||||
memset(d, dsp_silence, len);
|
||||
dsp->R_tx = t;
|
||||
return(nskb);
|
||||
}
|
||||
/* W_min is also limit for read */
|
||||
rr = conf->W_min;
|
||||
} else
|
||||
rr = dsp->W_rx;
|
||||
t = dsp->tx_R; /* tx-pointers */
|
||||
tt = dsp->tx_W;
|
||||
r = dsp->rx_R; /* rx-pointers */
|
||||
rr = (r + len) & CMX_BUFF_MASK;
|
||||
|
||||
/* increase r, if too far behind rr
|
||||
* (this happens if interrupts get lost, so transmission is delayed) */
|
||||
if (((rr - r) & CMX_BUFF_MASK) > dsp->largest) {
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
printk(KERN_DEBUG "r=%04x is too far behind rr=%04x, correcting. (larger than %04x)\n", r, rr, dsp->largest);
|
||||
r = (rr - dsp->largest) & CMX_BUFF_MASK;
|
||||
}
|
||||
/* calculate actual r (if r+len would overrun rr) */
|
||||
if (((rr - r - len) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) {
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "r+len=%04x overruns rr=%04x\n", (r+len) & CMX_BUFF_MASK, rr);
|
||||
#endif
|
||||
/* r is set "len" bytes before W_min */
|
||||
r = (rr - len) & CMX_BUFF_MASK;
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
printk(KERN_DEBUG "CMX: sending too fast (tx_buff) dsp=%x\n", (u32)dsp);
|
||||
} else
|
||||
/* rr is set "len" bytes after R_rx */
|
||||
rr = (r + len) & CMX_BUFF_MASK;
|
||||
dsp->R_rx = rr;
|
||||
/* now: rr is exactly "len" bytes after r now */
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "CMX_SEND(dsp=%lx) %d bytes from tx:0x%05x-0x%05x rx:0x%05x-0x%05x echo=%d %s\n", dsp, len, t, tt, r, rr, dsp->echo, dsp->inst.name);
|
||||
#endif
|
||||
|
||||
/* STEP 2.0: PROCESS TONES/TX-DATA ONLY */
|
||||
/* PROCESS TONES/TX-DATA ONLY */
|
||||
if (dsp->tone.tone && dsp->tone.software) {
|
||||
/* -> copy tone */
|
||||
dsp_tone_copy(dsp, d, len);
|
||||
dsp->R_tx = dsp->W_tx = 0; /* clear tx buffer */
|
||||
return(nskb);
|
||||
dsp->tx_R = dsp->tx_W = 0; /* clear tx buffer */
|
||||
goto send_packet;
|
||||
}
|
||||
/* if we have tx-data but do not use mixing */
|
||||
if (!dsp->tx_mix && t!=tt) {
|
||||
|
@ -1180,14 +1064,13 @@ struct sk_buff
|
|||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
if(r == rr) {
|
||||
dsp->R_tx = t;
|
||||
return(nskb);
|
||||
dsp->tx_R = t;
|
||||
goto send_packet;
|
||||
}
|
||||
}
|
||||
|
||||
/* STEP 2.1: PROCESS DATA (one member / no conf) */
|
||||
if (!conf) {
|
||||
single:
|
||||
/* PROCESS DATA (one member / no conf) */
|
||||
if (!conf || members<=1) {
|
||||
/* -> if echo is NOT enabled */
|
||||
if (!dsp->echo) {
|
||||
/* -> send tx-data if available or use 0-volume */
|
||||
|
@ -1211,40 +1094,40 @@ struct sk_buff
|
|||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
}
|
||||
dsp->R_tx = t;
|
||||
return(nskb);
|
||||
dsp->tx_R = t;
|
||||
goto send_packet;
|
||||
}
|
||||
if (1 == count_list_member(&conf->mlist)) {
|
||||
goto single;
|
||||
}
|
||||
/* STEP 2.2: PROCESS DATA (two members) */
|
||||
/* PROCESS DATA (two members) */
|
||||
#ifdef CMX_CONF_DEBUG
|
||||
if (0) {
|
||||
#else
|
||||
if (2 == count_list_member(&conf->mlist)) {
|
||||
if (members == 2) {
|
||||
#endif
|
||||
/* "other" becomes other party */
|
||||
other = (list_entry(conf->mlist.next, conf_member_t, list))->dsp;
|
||||
if (other == member)
|
||||
other = (list_entry(conf->mlist.prev, conf_member_t, list))->dsp;
|
||||
o = other->rx_buff; /* received data */
|
||||
o_q = other->rx_buff; /* received data */
|
||||
o_r = other->rx_R; /* rx-pointers */
|
||||
o_rr = (o_r + len) & CMX_BUFF_MASK;
|
||||
/* -> if echo is NOT enabled */
|
||||
if (!dsp->echo) {
|
||||
//if (o_r!=o_rr) printk(KERN_DEBUG "receive data=0x%02x\n", o_q[o_r]); else printk(KERN_DEBUG "NO R!!!\n");
|
||||
/* -> copy other member's rx-data, if tx-data is available, mix */
|
||||
while(r!=rr && t!=tt) {
|
||||
*d++ = dsp_audio_mix_law[(p[t]<<8)|o[r]];
|
||||
while(o_r!=o_rr && t!=tt) {
|
||||
*d++ = dsp_audio_mix_law[(p[t]<<8)|o_q[o_r]];
|
||||
t = (t+1) & CMX_BUFF_MASK;
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
o_r = (o_r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
while(r != rr) {
|
||||
*d++ = o[r];
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
while(o_r != o_rr) {
|
||||
*d++ = o_q[o_r];
|
||||
o_r = (o_r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
/* -> if echo is enabled */
|
||||
} else {
|
||||
/* -> mix other member's rx-data with echo, if tx-data is available, mix */
|
||||
while(r!=rr && t!=tt) {
|
||||
sample = dsp_audio_law_to_s32[p[t]] + dsp_audio_law_to_s32[o[r]] + dsp_audio_law_to_s32[q[r]];
|
||||
sample = dsp_audio_law_to_s32[p[t]] + dsp_audio_law_to_s32[q[r]] + dsp_audio_law_to_s32[o_q[o_r]];
|
||||
if (sample < -32768)
|
||||
sample = -32768;
|
||||
else if (sample > 32767)
|
||||
|
@ -1252,22 +1135,23 @@ struct sk_buff
|
|||
*d++ = dsp_audio_s16_to_law[sample & 0xffff]; /* tx-data + rx_data + echo */
|
||||
t = (t+1) & CMX_BUFF_MASK;
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
o_r = (o_r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
while(r != rr) {
|
||||
*d++ = dsp_audio_mix_law[(o[r]<<8)|q[r]];
|
||||
*d++ = dsp_audio_mix_law[(q[r]<<8)|o_q[o_r]];
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
o_r = (o_r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
}
|
||||
dsp->R_tx = t;
|
||||
return(nskb);
|
||||
dsp->tx_R = t;
|
||||
goto send_packet;
|
||||
}
|
||||
/* STEP 2.3: PROCESS DATA (three or more members) */
|
||||
c = conf->conf_buff;
|
||||
/* PROCESS DATA (three or more members) */
|
||||
/* -> if echo is NOT enabled */
|
||||
if (!dsp->echo) {
|
||||
/* -> substract rx-data from conf-data, if tx-data is available, mix */
|
||||
while(r!=rr && t!=tt) {
|
||||
sample = dsp_audio_law_to_s32[p[t]] + c[r] - dsp_audio_law_to_s32[q[r]];
|
||||
sample = dsp_audio_law_to_s32[p[t]] + *c++ - dsp_audio_law_to_s32[q[r]];
|
||||
if (sample < -32768)
|
||||
sample = -32768;
|
||||
else if (sample > 32767)
|
||||
|
@ -1277,7 +1161,7 @@ struct sk_buff
|
|||
t = (t+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
while(r != rr) {
|
||||
sample = c[r] - dsp_audio_law_to_s32[q[r]];
|
||||
sample = *c++ - dsp_audio_law_to_s32[q[r]];
|
||||
if (sample < -32768)
|
||||
sample = -32768;
|
||||
else if (sample > 32767)
|
||||
|
@ -1289,7 +1173,7 @@ struct sk_buff
|
|||
} else {
|
||||
/* -> encode conf-data, if tx-data is available, mix */
|
||||
while(r!=rr && t!=tt) {
|
||||
sample = dsp_audio_law_to_s32[p[t]] + c[r];
|
||||
sample = dsp_audio_law_to_s32[p[t]] + *c++;
|
||||
if (sample < -32768)
|
||||
sample = -32768;
|
||||
else if (sample > 32767)
|
||||
|
@ -1299,7 +1183,7 @@ struct sk_buff
|
|||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
while(r != rr) {
|
||||
sample = c[r];
|
||||
sample = *c++;
|
||||
if (sample < -32768)
|
||||
sample = -32768;
|
||||
else if (sample > 32767)
|
||||
|
@ -1308,8 +1192,171 @@ struct sk_buff
|
|||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
}
|
||||
dsp->R_tx = t;
|
||||
return(nskb);
|
||||
dsp->tx_R = t;
|
||||
goto send_packet;
|
||||
|
||||
send_packet:
|
||||
/* adjust volume */
|
||||
if (dsp->tx_volume)
|
||||
dsp_change_volume(nskb, dsp->tx_volume);
|
||||
|
||||
/* cancel echo */
|
||||
if (dsp->cancel_enable)
|
||||
dsp_cancel_tx(dsp, nskb->data, nskb->len);
|
||||
|
||||
/* crypt */
|
||||
if (dsp->bf_enable)
|
||||
dsp_bf_encrypt(dsp, nskb->data, nskb->len);
|
||||
|
||||
/* send packet */
|
||||
if (mISDN_queue_down(&dsp->inst, 0, nskb)) {
|
||||
dev_kfree_skb(nskb);
|
||||
printk(KERN_ERR "%s: failed to send tx-packet\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
u32 samplecount;
|
||||
struct timer_list dsp_spl_tl;
|
||||
u64 dsp_spl_jiffies;
|
||||
|
||||
void dsp_cmx_send(void *data)
|
||||
{
|
||||
conference_t *conf;
|
||||
conf_member_t *member;
|
||||
dsp_t *dsp;
|
||||
int mustmix, members;
|
||||
s32 mixbuffer[MAX_POLL], *c;
|
||||
u8 *q;
|
||||
int r, rr;
|
||||
int jittercheck = 0, delay, i;
|
||||
u_long flags;
|
||||
|
||||
/* lock */
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
|
||||
/* check if jitter needs to be checked */
|
||||
samplecount += dsp_poll;
|
||||
if (samplecount%8000 < dsp_poll)
|
||||
jittercheck = 1;
|
||||
|
||||
/* loop all members that do not require conference mixing */
|
||||
list_for_each_entry(dsp, &dsp_obj.ilist, list) {
|
||||
conf = dsp->conf;
|
||||
mustmix = 0;
|
||||
members = 0;
|
||||
if (conf) {
|
||||
members = count_list_member(&conf->mlist);
|
||||
#ifdef CMX_CONF_DEBUG
|
||||
if (conf->software && members>1)
|
||||
#else
|
||||
if (conf->software && members>2)
|
||||
#endif
|
||||
mustmix = 1;
|
||||
}
|
||||
|
||||
/* transmission required */
|
||||
if (!mustmix)
|
||||
dsp_cmx_send_member(dsp, dsp_poll, mixbuffer, members); // unused mixbuffer is given to prevent a potential null-pointer-bug
|
||||
}
|
||||
|
||||
/* loop all members that require conference mixing */
|
||||
list_for_each_entry(conf, &Conf_list, list) {
|
||||
/* count members and check hardware */
|
||||
members = count_list_member(&conf->mlist);
|
||||
#ifdef CMX_CONF_DEBUG
|
||||
if (conf->software && members>1) {
|
||||
#else
|
||||
if (conf->software && members>2) {
|
||||
#endif
|
||||
/* mix all data */
|
||||
memset(mixbuffer, 0, dsp_poll*sizeof(s32));
|
||||
list_for_each_entry(member, &conf->mlist, list) {
|
||||
dsp = member->dsp;
|
||||
/* get range of data to mix */
|
||||
c = mixbuffer;
|
||||
q = dsp->rx_buff;
|
||||
r = dsp->rx_R;
|
||||
rr = (r + dsp_poll) & CMX_BUFF_MASK;
|
||||
/* add member's data */
|
||||
while(r != rr) {
|
||||
*c++ += dsp_audio_law_to_s32[q[r]];
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
/* process each member */
|
||||
list_for_each_entry(member, &conf->mlist, list) {
|
||||
/* transmission */
|
||||
dsp_cmx_send_member(member->dsp, dsp_poll, mixbuffer, members);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* delete rx-data, increment buffers, change pointers */
|
||||
list_for_each_entry(dsp, &dsp_obj.ilist, list) {
|
||||
q = dsp->rx_buff;
|
||||
r = dsp->rx_R;
|
||||
rr = (r + dsp_poll) & CMX_BUFF_MASK;
|
||||
/* delete rx-data */
|
||||
while(r != rr) {
|
||||
q[r] = dsp_silence;
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
/* increment rx-buffer pointer */
|
||||
dsp->rx_R = r; /* write incremented read pointer */
|
||||
|
||||
/* check current delay */
|
||||
delay = (dsp->rx_W-r) & CMX_BUFF_MASK;
|
||||
if (delay >= CMX_BUFF_HALF)
|
||||
delay = 0; /* will be the delay before next write */
|
||||
/* check for lower delay */
|
||||
if (delay < dsp->delay[0])
|
||||
dsp->delay[0] = delay;
|
||||
if (jittercheck) {
|
||||
/* find the lowest of all delays */
|
||||
delay = dsp->delay[0];
|
||||
i = 1;
|
||||
while (i < MAX_SECONDS_JITTER_CHECK) {
|
||||
if (delay > dsp->delay[i])
|
||||
delay = dsp->delay[i];
|
||||
i++;
|
||||
}
|
||||
/* remove delay */
|
||||
if (delay) {
|
||||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
printk(KERN_DEBUG "%s lowest delay of %d bytes for dsp %s are now removed.\n", __FUNCTION__, delay, dsp->inst.name);
|
||||
r = dsp->rx_R;
|
||||
rr = (r + delay) & CMX_BUFF_MASK;
|
||||
/* delete rx-data */
|
||||
while(r != rr) {
|
||||
q[r] = dsp_silence;
|
||||
r = (r+1) & CMX_BUFF_MASK;
|
||||
}
|
||||
/* increment rx-buffer pointer */
|
||||
dsp->rx_R = r; /* write incremented read pointer */
|
||||
}
|
||||
/* scroll up delays */
|
||||
i = MAX_SECONDS_JITTER_CHECK - 1;
|
||||
while (i) {
|
||||
dsp->delay[i] = dsp->delay[i-1];
|
||||
i--;
|
||||
}
|
||||
dsp->delay[0] = CMX_BUFF_HALF; /* (infinite) delay */
|
||||
}
|
||||
}
|
||||
|
||||
/* restart timer */
|
||||
// init_timer(&dsp_spl_tl);
|
||||
if (dsp_spl_jiffies + dsp_tics < jiffies) /* if next event would be in the past ... */
|
||||
dsp_spl_jiffies = jiffies;
|
||||
else
|
||||
dsp_spl_jiffies += dsp_tics;
|
||||
|
||||
dsp_spl_tl.expires = dsp_spl_jiffies;
|
||||
add_timer(&dsp_spl_tl);
|
||||
|
||||
/* unlock */
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1321,36 +1368,15 @@ dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb)
|
|||
u_int w, ww;
|
||||
u8 *d, *p;
|
||||
int space, l;
|
||||
#ifdef AUTOJITTER
|
||||
int use;
|
||||
#endif
|
||||
|
||||
/* check if we have sompen */
|
||||
l = skb->len;
|
||||
w = dsp->W_tx;
|
||||
ww = dsp->R_tx;
|
||||
if (l < 1)
|
||||
return;
|
||||
|
||||
#ifdef AUTOJITTER
|
||||
/* check the delay */
|
||||
use = w-ww;
|
||||
if (use < 0)
|
||||
use += CMX_BUFF_SIZE;
|
||||
if (!dsp->tx_delay || dsp->tx_delay>use)
|
||||
dsp->tx_delay = use;
|
||||
dsp->tx_delay_count += l;
|
||||
if (dsp->tx_delay_count >= DELAY_CHECK) {
|
||||
/* now remove the delay */
|
||||
if (dsp_debug & DEBUG_DSP_DELAY)
|
||||
printk(KERN_DEBUG "%s(dsp=0x%x) removing delay of %d bytes\n", __FUNCTION__, (u32)dsp, dsp->tx_delay);
|
||||
dsp->tx_delay_count = 0;
|
||||
dsp->R_tx = ww = (ww + dsp->tx_delay) & CMX_BUFF_MASK;
|
||||
dsp->tx_delay = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if there is enough space, and then copy */
|
||||
w = dsp->tx_W;
|
||||
ww = dsp->tx_R;
|
||||
p = dsp->tx_buff;
|
||||
d = skb->data;
|
||||
space = ww-w;
|
||||
|
@ -1363,10 +1389,11 @@ dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb)
|
|||
else
|
||||
/* write until all byte are copied */
|
||||
ww = (w + skb->len) & CMX_BUFF_MASK;
|
||||
dsp->W_tx = ww;
|
||||
dsp->tx_W = ww;
|
||||
|
||||
/* show current buffer */
|
||||
#ifdef CMX_DEBUG
|
||||
printk(KERN_DEBUG "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->inst.name);
|
||||
printk(KERN_DEBUG "cmx_transmit(dsp=%lx) %d bytes to 0x%x-0x%x. %s\n", (u_long)dsp, (ww-w)&CMX_BUFF_MASK, w, ww, dsp->inst.name);
|
||||
#endif
|
||||
|
||||
/* copy transmit data to tx-buffer */
|
||||
|
@ -1377,5 +1404,3 @@ dsp_cmx_transmit(dsp_t *dsp, struct sk_buff *skb)
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
* - (4) echo generation for delay test
|
||||
* - (5) volume control
|
||||
* - (6) disable receive data
|
||||
* - (7) encryption/decryption
|
||||
* - (7) echo cancelation
|
||||
* - (8) encryption/decryption
|
||||
*
|
||||
* Look:
|
||||
* TX RX
|
||||
|
@ -42,17 +43,11 @@
|
|||
* v |
|
||||
* +-----+-------------+-----+
|
||||
* |(3)(4) |
|
||||
* | |
|
||||
* | |
|
||||
* | CMX |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* | +-------------+
|
||||
* | | ^
|
||||
* | | |
|
||||
* | | |
|
||||
* |+---------+| +----+----+
|
||||
* ||(1) || |(5) |
|
||||
* || || | |
|
||||
|
@ -62,7 +57,6 @@
|
|||
* |+----+----+| +----+----+
|
||||
* +-----+-----+ ^
|
||||
* | |
|
||||
* | |
|
||||
* v |
|
||||
* +----+----+ +----+----+
|
||||
* |(5) | |(2) |
|
||||
|
@ -74,8 +68,18 @@
|
|||
* | ^
|
||||
* | |
|
||||
* v |
|
||||
* +----+-------------+----+
|
||||
* |(7) |
|
||||
* | |
|
||||
* | Echo Cancellation |
|
||||
* | |
|
||||
* | |
|
||||
* +----+-------------+----+
|
||||
* | ^
|
||||
* | |
|
||||
* v |
|
||||
* +----+----+ +----+----+
|
||||
* |(7) | |(7) |
|
||||
* |(8) | |(8) |
|
||||
* | | | |
|
||||
* | Encrypt | | Decrypt |
|
||||
* | | | |
|
||||
|
@ -115,6 +119,13 @@
|
|||
* data to/form upper layer may be swithed on/off individually without loosing
|
||||
* features of CMX, Tones and DTMF.
|
||||
*
|
||||
* Echo Cancellation: Sometimes we like to cancel echo from the interface.
|
||||
* Note that a VoIP call may not have echo caused by the IP phone. The echo
|
||||
* is generated by the telephone line connected to it. Because the delay
|
||||
* is high, it becomes an echo. RESULT: Echo Cachelation is required if
|
||||
* both echo AND delay is applied to an interface.
|
||||
* Remember that software CMX always generates a more or less delay.
|
||||
*
|
||||
* If all used features can be realized in hardware, and if transmit and/or
|
||||
* receive data ist disabled, the card may not send/receive any data at all.
|
||||
* Not receiving is usefull if only announcements are played. Not sending is
|
||||
|
@ -153,9 +164,6 @@ There are three things that need to transmit data to card:
|
|||
- software cmx
|
||||
- upper layer, if tx-data is written to tx-buffer
|
||||
|
||||
Whenever cmx is changed, or data is sent from upper layer, the transmission is triggered by an silence freame (if not already tx_pending==1). When the confirm is received from card, next frame is
|
||||
sent using software cmx, if tx-data is still available, or if software tone generation is used,
|
||||
or if cmx is currently using software.
|
||||
|
||||
|
||||
|
||||
|
@ -171,68 +179,27 @@ const char *dsp_revision = "$Revision$";
|
|||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
#include "dsp.h"
|
||||
#include "hw_lock.h"
|
||||
|
||||
static char DSPName[] = "DSP";
|
||||
mISDNobject_t dsp_obj;
|
||||
mISDN_HWlock_t dsp_lock;
|
||||
|
||||
static int debug = 0;
|
||||
int dsp_debug;
|
||||
static int options = 0;
|
||||
int dsp_options;
|
||||
#ifndef AUTOJITTER
|
||||
int poll = 0;
|
||||
#endif
|
||||
static int poll = 0;
|
||||
int dsp_poll, dsp_tics;
|
||||
|
||||
#ifdef MODULE
|
||||
MODULE_AUTHOR("Andreas Eversberg");
|
||||
MODULE_PARM(debug, "1i");
|
||||
MODULE_PARM(options, "1i");
|
||||
#ifndef AUTOJITTER
|
||||
MODULE_PARM(poll, "1i");
|
||||
#endif
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* sending next frame to card (triggered by PH_DATA_IND)
|
||||
*/
|
||||
static void
|
||||
sendevent(dsp_t *dsp)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
|
||||
lock_HW(&dsp_lock, 0);
|
||||
if (dsp->b_active && dsp->tx_pending) {
|
||||
/* get data from cmx */
|
||||
nskb = dsp_cmx_send(dsp, dsp->tx_pending, 0);
|
||||
dsp->tx_pending = 0;
|
||||
if (!nskb) {
|
||||
unlock_HW(&dsp_lock);
|
||||
printk(KERN_ERR "%s: failed to create tx packet\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
/* crypt if enabled */
|
||||
if (dsp->bf_enable)
|
||||
dsp_bf_encrypt(dsp, nskb->data, nskb->len);
|
||||
/* change volume if requested */
|
||||
if (dsp->tx_volume)
|
||||
dsp_change_volume(nskb, dsp->tx_volume);
|
||||
/* send subsequent requests to card */
|
||||
unlock_HW(&dsp_lock);
|
||||
if (dsp->inst.down.func(&dsp->inst.down, nskb)) {
|
||||
dev_kfree_skb(nskb);
|
||||
printk(KERN_ERR "%s: failed to send tx packet\n", __FUNCTION__);
|
||||
}
|
||||
} else {
|
||||
dsp->tx_pending = 0;
|
||||
unlock_HW(&dsp_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* special message process for DL_CONTROL | REQUEST
|
||||
|
@ -314,7 +281,7 @@ dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
|
|||
dsp_cmx_hardware(dsp->conf, dsp);
|
||||
/* reset tx buffers (user space data) */
|
||||
tone_off:
|
||||
dsp->R_tx = dsp->W_tx = 0;
|
||||
dsp->tx_R = dsp->tx_W = 0;
|
||||
break;
|
||||
case VOL_CHANGE_TX: /* change volume */
|
||||
if (len != sizeof(int)) {
|
||||
|
@ -380,6 +347,27 @@ dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
|
|||
if (dsp_debug & DEBUG_DSP_CMX)
|
||||
dsp_cmx_debug(dsp);
|
||||
break;
|
||||
case ECHOCAN_ON: /* turn echo calcellation on */
|
||||
if (len<4) {
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
int ec_arr[2];
|
||||
memcpy(&ec_arr,data,sizeof(ec_arr));
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: turn echo cancelation on (delay=%d attenuation-shift=%d\n",
|
||||
__FUNCTION__, ec_arr[0], ec_arr[1]);
|
||||
|
||||
ret = dsp_cancel_init(dsp, ec_arr[0], ec_arr[1] ,1);
|
||||
dsp_cmx_hardware(dsp->conf, dsp);
|
||||
}
|
||||
break;
|
||||
case ECHOCAN_OFF: /* turn echo calcellation off */
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: turn echo cancelation off\n", __FUNCTION__);
|
||||
|
||||
ret = dsp_cancel_init(dsp, 0,0,-1);
|
||||
dsp_cmx_hardware(dsp->conf, dsp);
|
||||
break;
|
||||
case BF_ENABLE_KEY: /* turn blowfish on */
|
||||
if (len<4 || len>56) {
|
||||
ret = -EINVAL;
|
||||
|
@ -395,12 +383,8 @@ dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
|
|||
cont = BF_REJECT;
|
||||
/* send indication if it worked to set it */
|
||||
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &cont, 0);
|
||||
unlock_HW(&dsp_lock);
|
||||
if (nskb) {
|
||||
if (dsp->inst.up.func(&dsp->inst.up, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
}
|
||||
lock_HW(&dsp_lock, 0);
|
||||
if (mISDN_queue_up(&dsp->inst, 0, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
if (!ret)
|
||||
dsp_cmx_hardware(dsp->conf, dsp);
|
||||
break;
|
||||
|
@ -415,6 +399,8 @@ dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
|
|||
printk(KERN_DEBUG "%s: ctrl req %x unhandled\n", __FUNCTION__, cont);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
if (!ret)
|
||||
dev_kfree_skb(skb);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
@ -423,68 +409,76 @@ dsp_control_req(dsp_t *dsp, mISDN_head_t *hh, struct sk_buff *skb)
|
|||
* messages from upper layers
|
||||
*/
|
||||
static int
|
||||
dsp_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dsp_from_up(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dsp_t *dsp;
|
||||
mISDN_head_t *hh;
|
||||
int ret = 0;
|
||||
u_long flags;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
if (!skb)
|
||||
return(-EINVAL);
|
||||
dsp = hif->fdata;
|
||||
if (!dsp->inst.down.func)
|
||||
return(-ENXIO);
|
||||
dsp = inst->privat;
|
||||
if (!dsp) {
|
||||
return(-EIO);
|
||||
}
|
||||
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case DL_DATA | RESPONSE:
|
||||
case PH_DATA | RESPONSE:
|
||||
/* ignore response */
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
case DL_DATA | REQUEST:
|
||||
case PH_DATA | REQUEST:
|
||||
lock_HW(&dsp_lock, 0);
|
||||
if (skb->len < 1)
|
||||
return(-EINVAL);
|
||||
|
||||
/* send data to tx-buffer (if no tone is played) */
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
if (!dsp->tone.tone)
|
||||
dsp_cmx_transmit(dsp, skb);
|
||||
unlock_HW(&dsp_lock);
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
case PH_CONTROL | REQUEST:
|
||||
lock_HW(&dsp_lock, 0);
|
||||
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
ret = dsp_control_req(dsp, hh, skb);
|
||||
unlock_HW(&dsp_lock);
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
|
||||
break;
|
||||
case DL_ESTABLISH | REQUEST:
|
||||
case PH_ACTIVATE | REQUEST:
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: activating b_channel %s\n", __FUNCTION__, dsp->inst.name);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
dsp->tx_pending = 0;
|
||||
|
||||
if (dsp->dtmf.hardware || dsp->dtmf.software)
|
||||
dsp_dtmf_goertzel_init(dsp);
|
||||
unlock_HW(&dsp_lock);
|
||||
hh->prim = PH_ACTIVATE | REQUEST;
|
||||
return(dsp->inst.down.func(&dsp->inst.down, skb));
|
||||
ret = mISDN_queue_down(&dsp->inst, 0, skb);
|
||||
|
||||
break;
|
||||
case DL_RELEASE | REQUEST:
|
||||
case PH_DEACTIVATE | REQUEST:
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: releasing b_channel %s\n", __FUNCTION__, dsp->inst.name);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
dsp->tx_pending = 0;
|
||||
|
||||
dsp->tone.tone = dsp->tone.hardware = dsp->tone.software = 0;
|
||||
if (timer_pending(&dsp->tone.tl))
|
||||
del_timer(&dsp->tone.tl);
|
||||
unlock_HW(&dsp_lock);
|
||||
hh->prim = PH_DEACTIVATE | REQUEST;
|
||||
return(dsp->inst.down.func(&dsp->inst.down, skb));
|
||||
ret = mISDN_queue_down(&dsp->inst, 0, skb);
|
||||
|
||||
break;
|
||||
default:
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: msg %x unhandled %s\n", __FUNCTION__, hh->prim, dsp->inst.name);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!ret)
|
||||
dev_kfree_skb(skb);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
@ -493,7 +487,7 @@ dsp_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
* messages from lower layers
|
||||
*/
|
||||
static int
|
||||
dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dsp_from_down(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dsp_t *dsp;
|
||||
mISDN_head_t *hh;
|
||||
|
@ -501,27 +495,35 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
u8 *digits;
|
||||
int cont;
|
||||
struct sk_buff *nskb;
|
||||
u_long flags;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
if (!skb)
|
||||
return(-EINVAL);
|
||||
dsp = hif->fdata;
|
||||
if (!dsp->inst.up.func)
|
||||
return(-ENXIO);
|
||||
dsp = inst->privat;
|
||||
if (!dsp)
|
||||
return(-EIO);
|
||||
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim)
|
||||
{
|
||||
case PH_DATA | CONFIRM:
|
||||
case DL_DATA | CONFIRM:
|
||||
/* flush response, because no relation to upper layer */
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
case PH_DATA | INDICATION:
|
||||
case DL_DATA | INDICATION:
|
||||
if (skb->len < 1)
|
||||
break;
|
||||
lock_HW(&dsp_lock, 0);
|
||||
return(-EINVAL);
|
||||
|
||||
|
||||
|
||||
/* decrypt if enabled */
|
||||
if (dsp->bf_enable)
|
||||
dsp_bf_decrypt(dsp, skb->data, skb->len);
|
||||
/* if echo cancellation is enabled */
|
||||
if (dsp->cancel_enable)
|
||||
dsp_cancel_rx(dsp, skb->data, skb->len);
|
||||
/* check if dtmf soft decoding is turned on */
|
||||
if (dsp->dtmf.software) {
|
||||
digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0);
|
||||
|
@ -530,14 +532,8 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
printk(KERN_DEBUG "%s: sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
|
||||
cont = DTMF_TONE_VAL | *digits;
|
||||
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &cont, 0);
|
||||
unlock_HW(&dsp_lock);
|
||||
if (!nskb) {
|
||||
lock_HW(&dsp_lock, 0);
|
||||
break;
|
||||
}
|
||||
if (dsp->inst.up.func(&dsp->inst.up, nskb))
|
||||
if (mISDN_queue_up(&dsp->inst, 0, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
digits++;
|
||||
}
|
||||
}
|
||||
|
@ -545,32 +541,24 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
if (dsp->rx_volume)
|
||||
dsp_change_volume(skb, dsp->rx_volume);
|
||||
/* we need to process receive data if software */
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
if (dsp->pcm_slot_tx<0 && dsp->pcm_slot_rx<0) {
|
||||
/* process data from card at cmx */
|
||||
dsp_cmx_receive(dsp, skb);
|
||||
}
|
||||
/* we send data only if software or if we have some
|
||||
* or if we cannot do tones with hardware
|
||||
*/
|
||||
if ((dsp->pcm_slot_tx<0 && !dsp->features.hfc_loops) /* software crossconnects OR software loops */
|
||||
|| dsp->R_tx != dsp->W_tx /* data in buffer */
|
||||
|| (dsp->echo==1 && dsp->pcm_slot_tx<0) /* software echo */
|
||||
|| (dsp->tone.tone && dsp->tone.software)) { /* software loops */
|
||||
/* schedule sending skb->len bytes */
|
||||
dsp->tx_pending = skb->len;
|
||||
schedule_work(&dsp->sendwork);
|
||||
}
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
if (dsp->rx_disabled) {
|
||||
/* if receive is not allowed */
|
||||
dev_kfree_skb(skb);
|
||||
unlock_HW(&dsp_lock);
|
||||
return(0);
|
||||
|
||||
break;
|
||||
}
|
||||
unlock_HW(&dsp_lock);
|
||||
hh->prim = DL_DATA | INDICATION;
|
||||
return(dsp->inst.up.func(&dsp->inst.up, skb));
|
||||
ret = mISDN_queue_up(&dsp->inst, 0, skb);
|
||||
|
||||
break;
|
||||
case PH_CONTROL | INDICATION:
|
||||
lock_HW(&dsp_lock, 0);
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
|
||||
printk(KERN_DEBUG "%s: PH_CONTROL received: %x (len %d) %s\n", __FUNCTION__, hh->dinfo, skb->len, dsp->inst.name);
|
||||
switch (hh->dinfo) {
|
||||
|
@ -578,28 +566,22 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
if (!dsp->dtmf.hardware) {
|
||||
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
|
||||
printk(KERN_DEBUG "%s: ignoring DTMF coefficients from HFC\n", __FUNCTION__);
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
if (dsp->inst.up.func) {
|
||||
digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, 2);
|
||||
if (digits) while(*digits) {
|
||||
int k;
|
||||
struct sk_buff *nskb;
|
||||
if (dsp_debug & DEBUG_DSP_DTMF)
|
||||
printk(KERN_DEBUG "%s: now sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
|
||||
k = *digits | DTMF_TONE_VAL;
|
||||
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &k, 0);
|
||||
unlock_HW(&dsp_lock);
|
||||
if (!nskb) {
|
||||
lock_HW(&dsp_lock, 0);
|
||||
break;
|
||||
}
|
||||
if (dsp->inst.up.func(&dsp->inst.up, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
digits++;
|
||||
}
|
||||
digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, 2);
|
||||
if (digits) while(*digits) {
|
||||
int k;
|
||||
struct sk_buff *nskb;
|
||||
if (dsp_debug & DEBUG_DSP_DTMF)
|
||||
printk(KERN_DEBUG "%s: now sending software decoded digit(%c) to upper layer %s\n", __FUNCTION__, *digits, dsp->inst.name);
|
||||
k = *digits | DTMF_TONE_VAL;
|
||||
nskb = create_link_skb(PH_CONTROL | INDICATION, 0, sizeof(int), &k, 0);
|
||||
if (mISDN_queue_up(&dsp->inst, 0, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
digits++;
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -607,48 +589,68 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
printk(KERN_DEBUG "%s: ctrl ind %x unhandled %s\n", __FUNCTION__, hh->dinfo, dsp->inst.name);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
unlock_HW(&dsp_lock);
|
||||
|
||||
break;
|
||||
case PH_ACTIVATE | CONFIRM:
|
||||
lock_HW(&dsp_lock, 0);
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: b_channel is now active %s\n", __FUNCTION__, dsp->inst.name);
|
||||
/* bchannel now active */
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
dsp->b_active = 1;
|
||||
dsp->W_tx = dsp->R_tx = 0; /* clear TX buffer */
|
||||
dsp->W_rx = dsp->R_rx = 0; /* clear RX buffer */
|
||||
if (dsp->conf)
|
||||
dsp->W_rx = dsp->R_rx = dsp->conf->W_max;
|
||||
dsp->tx_W = dsp->tx_R = 0; /* clear TX buffer */
|
||||
dsp->rx_W = dsp->rx_R = -1; /* reset RX buffer */
|
||||
memset(dsp->rx_buff, 0, sizeof(dsp->rx_buff));
|
||||
dsp_cmx_hardware(dsp->conf, dsp);
|
||||
// /* now trigger transmission */
|
||||
//#ifndef AUTOJITTER
|
||||
// dsp->tx_pending = 1;
|
||||
// schedule_work(&dsp->sendwork);
|
||||
//#endif
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: done with activation, sending confirm to user space. %s\n", __FUNCTION__, dsp->inst.name);
|
||||
/* send activation to upper layer */
|
||||
hh->prim = DL_ESTABLISH | CONFIRM;
|
||||
unlock_HW(&dsp_lock);
|
||||
return(dsp->inst.up.func(&dsp->inst.up, skb));
|
||||
ret = mISDN_queue_up(&dsp->inst, 0, skb);
|
||||
|
||||
break;
|
||||
case PH_DEACTIVATE | CONFIRM:
|
||||
lock_HW(&dsp_lock, 0);
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: b_channel is now inactive %s\n", __FUNCTION__, dsp->inst.name);
|
||||
/* bchannel now inactive */
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
dsp->b_active = 0;
|
||||
dsp_cmx_hardware(dsp->conf, dsp);
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
hh->prim = DL_RELEASE | CONFIRM;
|
||||
unlock_HW(&dsp_lock);
|
||||
return(dsp->inst.up.func(&dsp->inst.up, skb));
|
||||
ret = mISDN_queue_up(&dsp->inst, 0, skb);
|
||||
|
||||
break;
|
||||
default:
|
||||
if (dsp_debug & DEBUG_DSP_CORE)
|
||||
printk(KERN_DEBUG "%s: msg %x unhandled %s\n", __FUNCTION__, hh->prim, dsp->inst.name);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
if (!ret)
|
||||
dev_kfree_skb(skb);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* messages from queue
|
||||
*/
|
||||
static int
|
||||
dsp_function(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
mISDN_head_t *hh;
|
||||
int ret = -EINVAL;
|
||||
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch (hh->addr & MSG_DIR_MASK) {
|
||||
case FLG_MSG_DOWN:
|
||||
ret = dsp_from_up(inst, skb);
|
||||
break;
|
||||
case FLG_MSG_UP:
|
||||
ret = dsp_from_down(inst, skb);
|
||||
break;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
@ -660,18 +662,14 @@ static void
|
|||
release_dsp(dsp_t *dsp)
|
||||
{
|
||||
mISDNinstance_t *inst = &dsp->inst;
|
||||
conference_t *conf;
|
||||
conference_t *conf;
|
||||
u_long flags;
|
||||
|
||||
lock_HW(&dsp_lock, 0);
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
if (timer_pending(&dsp->feature_tl))
|
||||
del_timer(&dsp->feature_tl);
|
||||
if (timer_pending(&dsp->tone.tl))
|
||||
del_timer(&dsp->tone.tl);
|
||||
#ifdef HAS_WORKQUEUE
|
||||
if (dsp->sendwork.pending)
|
||||
printk(KERN_ERR "%s: pending sendwork: %lx %s\n", __FUNCTION__, dsp->sendwork.pending, dsp->inst.name);
|
||||
#else
|
||||
if (dsp->sendwork.sync)
|
||||
printk(KERN_ERR "%s: pending sendwork: %lx %s\n", __FUNCTION__, dsp->sendwork.sync, dsp->inst.name);
|
||||
#endif
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: removing conferences %s\n", __FUNCTION__, dsp->inst.name);
|
||||
conf = dsp->conf;
|
||||
|
@ -682,22 +680,11 @@ release_dsp(dsp_t *dsp)
|
|||
}
|
||||
}
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: disconnecting instances %s\n", __FUNCTION__, dsp->inst.name);
|
||||
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);
|
||||
}
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: remove & destroy object %s\n", __FUNCTION__, dsp->inst.name);
|
||||
list_del(&dsp->list);
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
dsp_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
unlock_HW(&dsp_lock);
|
||||
vfree(dsp);
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
|
@ -705,14 +692,57 @@ release_dsp(dsp_t *dsp)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* ask for hardware features
|
||||
*/
|
||||
static void
|
||||
dsp_feat(void *arg)
|
||||
{
|
||||
dsp_t *dsp = arg;
|
||||
struct sk_buff *nskb;
|
||||
void *feat;
|
||||
|
||||
switch (dsp->feature_state) {
|
||||
case FEAT_STATE_INIT:
|
||||
feat = &dsp->features;
|
||||
nskb = create_link_skb(PH_CONTROL | REQUEST, HW_FEATURES, sizeof(feat), &feat, 0);
|
||||
if (!nskb)
|
||||
break;
|
||||
if (mISDN_queue_down(&dsp->inst, 0, nskb)) {
|
||||
dev_kfree_skb(nskb);
|
||||
break;
|
||||
}
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: features will be quered now for instance %s\n", __FUNCTION__, dsp->inst.name);
|
||||
dsp->feature_state = FEAT_STATE_WAIT;
|
||||
init_timer(&dsp->feature_tl);
|
||||
dsp->feature_tl.expires = jiffies + (HZ / 100);
|
||||
add_timer(&dsp->feature_tl);
|
||||
break;
|
||||
case FEAT_STATE_WAIT:
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: features of %s are: hfc_id=%d hfc_dtmf=%d hfc_loops=%d pcm_id=%d pcm_slots=%d pcm_banks=%d\n",
|
||||
__FUNCTION__, dsp->inst.name,
|
||||
dsp->features.hfc_id,
|
||||
dsp->features.hfc_dtmf,
|
||||
dsp->features.hfc_loops,
|
||||
dsp->features.pcm_id,
|
||||
dsp->features.pcm_slots,
|
||||
dsp->features.pcm_banks);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* create new DSP instances
|
||||
*/
|
||||
static int
|
||||
new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
|
||||
{
|
||||
int err = 0;
|
||||
dsp_t *ndsp;
|
||||
int err = 0;
|
||||
dsp_t *ndsp;
|
||||
u_long flags;
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: creating new dsp instance\n", __FUNCTION__);
|
||||
|
@ -725,8 +755,7 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
}
|
||||
memset(ndsp, 0, sizeof(dsp_t));
|
||||
memcpy(&ndsp->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
ndsp->inst.obj = &dsp_obj;
|
||||
ndsp->inst.data = ndsp;
|
||||
mISDN_init_instance(&ndsp->inst, &dsp_obj, ndsp, dsp_function);
|
||||
if (!mISDN_SetHandledPID(&dsp_obj, &ndsp->inst.pid)) {
|
||||
int_error();
|
||||
err = -ENOPROTOOPT;
|
||||
|
@ -735,13 +764,8 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
return(err);
|
||||
}
|
||||
sprintf(ndsp->inst.name, "DSP_S%x/C%x",
|
||||
(st->id&0xff), (st->id&0xff00)>>8);
|
||||
ndsp->inst.up.owner = &ndsp->inst;
|
||||
ndsp->inst.down.owner = &ndsp->inst;
|
||||
//#ifndef AUTOJITTER
|
||||
(st->id&0xff00)>>8, (st->id&0xff0000)>>16);
|
||||
/* set frame size to start */
|
||||
ndsp->largest = 64 << 1;
|
||||
//#endif
|
||||
ndsp->features.hfc_id = -1; /* current PCM id */
|
||||
ndsp->features.pcm_id = -1; /* current PCM id */
|
||||
ndsp->pcm_slot_rx = -1; /* current CPM slot */
|
||||
|
@ -749,81 +773,59 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
|
|||
ndsp->pcm_bank_rx = -1;
|
||||
ndsp->pcm_bank_tx = -1;
|
||||
ndsp->hfc_conf = -1; /* current conference number */
|
||||
/* set timer */
|
||||
/* set tone timer */
|
||||
ndsp->tone.tl.function = (void *)dsp_tone_timeout;
|
||||
ndsp->tone.tl.data = (long) ndsp;
|
||||
init_timer(&ndsp->tone.tl);
|
||||
/* init send que */
|
||||
INIT_WORK(&ndsp->sendwork, (void *)(void *)sendevent, ndsp);
|
||||
lock_HW(&dsp_lock, 0);
|
||||
/* set dsp feture timer */
|
||||
ndsp->feature_tl.function = (void *)dsp_feat;
|
||||
ndsp->feature_tl.data = (long) ndsp;
|
||||
ndsp->feature_state = FEAT_STATE_INIT;
|
||||
init_timer(&ndsp->feature_tl);
|
||||
if (!(dsp_options & DSP_OPT_NOHARDWARE)) {
|
||||
ndsp->feature_tl.expires = jiffies + (HZ / 100);
|
||||
add_timer(&ndsp->feature_tl);
|
||||
}
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
/* append and register */
|
||||
list_add_tail(&ndsp->list, &dsp_obj.ilist);
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
err = dsp_obj.ctrl(st, MGR_REGLAYER | INDICATION, &ndsp->inst);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: failed to register layer %s\n", __FUNCTION__, ndsp->inst.name);
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
list_del(&ndsp->list);
|
||||
unlock_HW(&dsp_lock);
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
goto free_mem;
|
||||
}
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: dsp instance created %s\n", __FUNCTION__, ndsp->inst.name);
|
||||
unlock_HW(&dsp_lock);
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ask for hardware features
|
||||
*/
|
||||
static void
|
||||
dsp_feat(dsp_t *dsp)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
void *feat;
|
||||
|
||||
if (!(dsp_options & DSP_OPT_NOHARDWARE)) {
|
||||
feat = &dsp->features;
|
||||
nskb = create_link_skb(PH_CONTROL | REQUEST, HW_FEATURES, sizeof(feat), &feat, 0);
|
||||
if (nskb) {
|
||||
if (dsp->inst.down.func(&dsp->inst.down, nskb)) {
|
||||
dev_kfree_skb(nskb);
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: no features supported by %s\n", __FUNCTION__, dsp->inst.name);
|
||||
} else {
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: features of %s: hfc_id=%d hfc_dtmf=%d hfc_loops=%d pcm_id=%d pcm_slots=%d pcm_banks=%d\n",
|
||||
__FUNCTION__, dsp->inst.name,
|
||||
dsp->features.hfc_id,
|
||||
dsp->features.hfc_dtmf,
|
||||
dsp->features.hfc_loops,
|
||||
dsp->features.pcm_id,
|
||||
dsp->features.pcm_slots,
|
||||
dsp->features.pcm_banks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* manager for DSP instances
|
||||
*/
|
||||
static int
|
||||
dsp_manager(void *data, u_int prim, void *arg) {
|
||||
mISDNinstance_t *inst = data;
|
||||
dsp_t *dspl;
|
||||
int ret = -EINVAL;
|
||||
mISDNinstance_t *inst = data;
|
||||
dsp_t *dspl;
|
||||
int ret = -EINVAL;
|
||||
u_long flags;
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n", __FUNCTION__, data, prim, arg);
|
||||
if (!data)
|
||||
return(ret);
|
||||
spin_lock_irqsave(&dsp_obj.lock, flags);
|
||||
list_for_each_entry(dspl, &dsp_obj.ilist, list) {
|
||||
if (&dspl->inst == inst) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dsp_obj.lock, flags);
|
||||
if (ret && (prim != (MGR_NEWLAYER | REQUEST))) {
|
||||
printk(KERN_WARNING "%s: given instance(%p) not in ilist.\n", __FUNCTION__, data);
|
||||
return(ret);
|
||||
|
@ -833,9 +835,11 @@ dsp_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_NEWLAYER | REQUEST:
|
||||
ret = new_dsp(data, arg);
|
||||
break;
|
||||
case MGR_SETSTACK | INDICATION:
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CONNECT | REQUEST:
|
||||
ret = mISDN_ConnectIF(inst, arg);
|
||||
dsp_feat(dspl);
|
||||
break;
|
||||
case MGR_SETIF | REQUEST:
|
||||
case MGR_SETIF | INDICATION:
|
||||
|
@ -845,6 +849,7 @@ dsp_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | INDICATION:
|
||||
ret = mISDN_DisConnectIF(inst, arg);
|
||||
break;
|
||||
#endif
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
|
@ -873,37 +878,40 @@ static int dsp_init(void)
|
|||
dsp_debug = debug;
|
||||
|
||||
/* display revision */
|
||||
printk(KERN_INFO "mISDN_dsp: Audio DSP Rev. %s (debug=0x%x)\n", mISDN_getrev(dsp_revision), debug);
|
||||
printk(KERN_INFO "mISDN_dsp: Audio DSP Rev. %s (debug=0x%x) EchoCancellor %s\n", mISDN_getrev(dsp_revision), debug, EC_TYPE);
|
||||
|
||||
#ifndef AUTOJITTER
|
||||
/* set packet size */
|
||||
switch(poll) {
|
||||
case 8:
|
||||
break;
|
||||
case 16:
|
||||
break;
|
||||
case 32:
|
||||
break;
|
||||
case 64: case 0:
|
||||
poll = 64;
|
||||
break;
|
||||
case 128:
|
||||
break;
|
||||
case 256:
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR "%s: Wrong poll value (%d).\n", __FUNCTION__, poll);
|
||||
if (poll == 0) {
|
||||
if (HZ == 100)
|
||||
poll = 80;
|
||||
else
|
||||
poll = 64;
|
||||
}
|
||||
|
||||
if (poll > MAX_POLL) {
|
||||
printk(KERN_ERR "%s: Wrong poll value (%d), using %d.\n", __FUNCTION__, poll, MAX_POLL);
|
||||
poll = MAX_POLL;
|
||||
}
|
||||
if (poll < 8) {
|
||||
printk(KERN_ERR "%s: Wrong poll value (%d), using 8.\n", __FUNCTION__, poll);
|
||||
poll = 8;
|
||||
}
|
||||
dsp_poll = poll;
|
||||
dsp_tics = poll * HZ / 8000;
|
||||
if (dsp_tics * 8000 == poll * HZ)
|
||||
printk(KERN_INFO "mISDN_dsp: DSP clocks every %d samples. This equals %d jiffies.\n", poll, dsp_tics);
|
||||
else {
|
||||
printk(KERN_INFO "mISDN_dsp: Cannot clock ever %d samples. Use a multiple of %d (samples)\n", poll, 8000 / HZ);
|
||||
err = -EINVAL;
|
||||
return(err);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fill mISDN object (dsp_obj) */
|
||||
memset(&dsp_obj, 0, sizeof(dsp_obj));
|
||||
#ifdef MODULE
|
||||
SET_MODULE_OWNER(&dsp_obj);
|
||||
#endif
|
||||
spin_lock_init(&dsp_obj.lock);
|
||||
dsp_obj.name = DSPName;
|
||||
dsp_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_DSP;
|
||||
dsp_obj.own_ctrl = dsp_manager;
|
||||
|
@ -919,15 +927,20 @@ static int dsp_init(void)
|
|||
dsp_audio_generate_ulaw_samples();
|
||||
dsp_audio_generate_volume_changes();
|
||||
|
||||
/* init global lock */
|
||||
lock_HW_init(&dsp_lock);
|
||||
|
||||
/* register object */
|
||||
if ((err = mISDN_register(&dsp_obj))) {
|
||||
printk(KERN_ERR "mISDN_dsp: Can't register %s error(%d)\n", DSPName, err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
/* set sample timer */
|
||||
dsp_spl_tl.function = (void *)dsp_cmx_send;
|
||||
dsp_spl_tl.data = 0;
|
||||
init_timer(&dsp_spl_tl);
|
||||
dsp_spl_tl.expires = jiffies + dsp_tics + 1; /* safer */
|
||||
dsp_spl_jiffies = dsp_spl_tl.expires;
|
||||
add_timer(&dsp_spl_tl);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
@ -940,6 +953,9 @@ static void dsp_cleanup(void)
|
|||
dsp_t *dspl, *nd;
|
||||
int err;
|
||||
|
||||
if (timer_pending(&dsp_spl_tl))
|
||||
del_timer(&dsp_spl_tl);
|
||||
|
||||
if (dsp_debug & DEBUG_DSP_MGR)
|
||||
printk(KERN_DEBUG "%s: removing module\n", __FUNCTION__);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* DTMF decoder.
|
||||
*
|
||||
* Copyright 2003 by Andreas Eversberg (jolly@jolly.de)
|
||||
* Copyright by Andreas Eversberg (jolly@jolly.de)
|
||||
* based on different decoders such as ISDN4Linux
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Audio support data for ISDN4Linux.
|
||||
*
|
||||
* Copyright 2002/2003 by Andreas Eversberg (jolly@jolly.de)
|
||||
* Copyright Andreas Eversberg (jolly@jolly.de)
|
||||
*
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
|
@ -437,7 +437,7 @@ dsp_tone_hw_message(dsp_t *dsp, u8 *sample, int len)
|
|||
return;
|
||||
}
|
||||
/* unlocking is not required, because we don't expect a response */
|
||||
if (dsp->inst.down.func(&dsp->inst.down, nskb))
|
||||
if (mISDN_queue_down(&dsp->inst, 0, nskb))
|
||||
dev_kfree_skb(nskb);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#define N303 1
|
||||
#define T_CTRL 180000
|
||||
|
||||
#define THOLD 4000
|
||||
#define TRETRIEVE 4000
|
||||
|
||||
/* private TIMER events */
|
||||
#define CC_T302 0x030201
|
||||
#define CC_T303 0x030301
|
||||
|
@ -36,6 +39,8 @@
|
|||
#define CC_T318 0x031801
|
||||
#define CC_T319 0x031901
|
||||
#define CC_TCTRL 0x031f01
|
||||
#define CC_THOLD 0x03a001
|
||||
#define CC_TRETRIEVE 0x03a101
|
||||
/*
|
||||
* Message-Types
|
||||
*/
|
||||
|
@ -47,6 +52,12 @@
|
|||
#define MT_PROGRESS 0x03
|
||||
#define MT_SETUP 0x05
|
||||
#define MT_SETUP_ACKNOWLEDGE 0x0d
|
||||
#define MT_HOLD 0x24
|
||||
#define MT_HOLD_ACKNOWLEDGE 0x28
|
||||
#define MT_HOLD_REJECT 0x30
|
||||
#define MT_RETRIEVE 0x31
|
||||
#define MT_RETRIEVE_ACKNOWLEDGE 0x33
|
||||
#define MT_RETRIEVE_REJECT 0x37
|
||||
#define MT_RESUME 0x26
|
||||
#define MT_RESUME_ACKNOWLEDGE 0x2e
|
||||
#define MT_RESUME_REJECT 0x22
|
||||
|
@ -137,6 +148,16 @@
|
|||
|
||||
#define NO_CAUSE 254
|
||||
|
||||
#define AUX_IDLE 0
|
||||
#define AUX_HOLD_REQ 1
|
||||
#define AUX_CALL_HELD 2
|
||||
#define AUX_RETRIEVE_REQ 3
|
||||
#define AUX_HOLD_IND 4
|
||||
#define AUX_RETRIEVE_IND 5
|
||||
|
||||
#define VALID_HOLD_STATES_PTMP (SBIT(3) | SBIT(4) | SBIT(10))
|
||||
#define VALID_HOLD_STATES_PTP (SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10))
|
||||
|
||||
#else /* only l3dss1_process */
|
||||
|
||||
/* l3dss1 specific data in l3 process */
|
||||
|
|
|
@ -36,7 +36,7 @@ typedef struct _dtmf {
|
|||
#define FLG_DTMF_ULAW 1
|
||||
#define FLG_DTMF_ACTIV 2
|
||||
|
||||
static int debug = 0;
|
||||
static u_int debug = 0;
|
||||
|
||||
#define DEBUG_DTMF_MGR 0x001
|
||||
#define DEBUG_DTMF_TONE 0x010
|
||||
|
@ -350,7 +350,7 @@ isdn_audio_goertzel(dtmf_t *dtmf)
|
|||
if (dtmf->debug & DEBUG_DTMF_TONE)
|
||||
printk(KERN_DEBUG "DTMF: tone='%c'\n", what);
|
||||
k = what | DTMF_TONE_VAL;
|
||||
if_link(&dtmf->inst.up, PH_CONTROL | INDICATION,
|
||||
mISDN_queue_data(&dtmf->inst, FLG_MSG_UP, PH_CONTROL | INDICATION,
|
||||
0, sizeof(int), &k, 0);
|
||||
}
|
||||
dtmf->last = what;
|
||||
|
@ -397,20 +397,16 @@ dtmf_reset(dtmf_t *dtmf)
|
|||
dtmf->idx = 0;
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static int
|
||||
dtmf_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dtmf_from_up(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dtmf_t *dtmf;
|
||||
mISDN_head_t *hh;
|
||||
int *data;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
dtmf = hif->fdata;
|
||||
if (!dtmf->inst.down.func) {
|
||||
return(-ENXIO);
|
||||
}
|
||||
dtmf = inst->privat;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case (PH_CONTROL | REQUEST):
|
||||
|
@ -431,25 +427,21 @@ dtmf_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
}
|
||||
/* Fall trough in case of not handled function */
|
||||
default:
|
||||
return(dtmf->inst.down.func(&dtmf->inst.down, skb));
|
||||
return(mISDN_queue_down(inst, 0, skb));
|
||||
}
|
||||
if (!err)
|
||||
dev_kfree_skb(skb);
|
||||
return(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dtmf_function(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dtmf_t *dtmf;
|
||||
mISDN_head_t *hh;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
dtmf = hif->fdata;
|
||||
if (!dtmf->inst.up.func) {
|
||||
return(-ENXIO);
|
||||
}
|
||||
dtmf = inst->privat;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case (PH_DATA | CONFIRM):
|
||||
|
@ -461,6 +453,25 @@ dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
isdn_audio_calc_dtmf(dtmf, skb);
|
||||
hh->prim = DL_DATA_IND;
|
||||
break;
|
||||
case (PH_CONTROL | REQUEST):
|
||||
if ((hh->dinfo == 0) && (skb->len >= sizeof(int))) {
|
||||
int *data = (int *)skb->data;
|
||||
if (dtmf->debug & DEBUG_DTMF_CTRL)
|
||||
printk(KERN_DEBUG "DTMF: PH_CONTROL REQ data %04x\n",
|
||||
*data);
|
||||
if (*data == DTMF_TONE_START) {
|
||||
test_and_set_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
|
||||
dtmf_reset(dtmf);
|
||||
dev_kfree_skb(skb);
|
||||
return(0);
|
||||
} else if (*data == DTMF_TONE_STOP) {
|
||||
test_and_clear_bit(FLG_DTMF_ACTIV, &dtmf->Flags);
|
||||
dtmf_reset(dtmf);
|
||||
dev_kfree_skb(skb);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case (PH_ACTIVATE | CONFIRM):
|
||||
hh->prim = DL_ESTABLISH | CONFIRM;
|
||||
break;
|
||||
|
@ -474,30 +485,26 @@ dtmf_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
hh->prim = DL_RELEASE | INDICATION;
|
||||
break;
|
||||
}
|
||||
return(dtmf->inst.up.func(&dtmf->inst.up, skb));
|
||||
return(mISDN_queue_message(inst, hh->addr & MSG_DIR_MASK, skb));
|
||||
}
|
||||
|
||||
static void
|
||||
release_dtmf(dtmf_t *dtmf) {
|
||||
mISDNinstance_t *inst = &dtmf->inst;
|
||||
u_long flags;
|
||||
|
||||
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);
|
||||
}
|
||||
spin_lock_irqsave(&dtmf_obj.lock, flags);
|
||||
list_del(&dtmf->list);
|
||||
spin_unlock_irqrestore(&dtmf_obj.lock, flags);
|
||||
dtmf_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
kfree(dtmf);
|
||||
}
|
||||
|
||||
static int
|
||||
new_dtmf(mISDNstack_t *st, mISDN_pid_t *pid) {
|
||||
dtmf_t *n_dtmf;
|
||||
int err;
|
||||
dtmf_t *n_dtmf;
|
||||
int err;
|
||||
u_long flags;
|
||||
|
||||
if (!st || !pid)
|
||||
return(-EINVAL);
|
||||
|
@ -507,14 +514,16 @@ new_dtmf(mISDNstack_t *st, mISDN_pid_t *pid) {
|
|||
}
|
||||
memset(n_dtmf, 0, sizeof(dtmf_t));
|
||||
memcpy(&n_dtmf->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
mISDN_init_instance(&n_dtmf->inst, &dtmf_obj, n_dtmf);
|
||||
mISDN_init_instance(&n_dtmf->inst, &dtmf_obj, n_dtmf, dtmf_function);
|
||||
if (!mISDN_SetHandledPID(&dtmf_obj, &n_dtmf->inst.pid)) {
|
||||
int_error();
|
||||
kfree(n_dtmf);
|
||||
return(-ENOPROTOOPT);
|
||||
}
|
||||
n_dtmf->debug = debug;
|
||||
spin_lock_irqsave(&dtmf_obj.lock, flags);
|
||||
list_add_tail(&n_dtmf->list, &dtmf_obj.ilist);
|
||||
spin_unlock_irqrestore(&dtmf_obj.lock, flags);
|
||||
err = dtmf_obj.ctrl(st, MGR_REGLAYER | INDICATION, &n_dtmf->inst);
|
||||
if (err) {
|
||||
list_del(&n_dtmf->list);
|
||||
|
@ -550,7 +559,8 @@ static char MName[] = "DTMF";
|
|||
|
||||
#ifdef MODULE
|
||||
MODULE_AUTHOR("Karsten Keil");
|
||||
MODULE_PARM(debug, "1i");
|
||||
module_param (debug, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC (debug, "dtmf debug mask");
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
|
@ -561,17 +571,20 @@ dtmf_manager(void *data, u_int prim, void *arg) {
|
|||
mISDNinstance_t *inst = data;
|
||||
dtmf_t *dtmf_l;
|
||||
int ret = -EINVAL;
|
||||
u_long flags;
|
||||
|
||||
if (debug & DEBUG_DTMF_MGR)
|
||||
printk(KERN_DEBUG "dtmf_manager data:%p prim:%x arg:%p\n", data, prim, arg);
|
||||
if (!data)
|
||||
return(ret);
|
||||
spin_lock_irqsave(&dtmf_obj.lock, flags);
|
||||
list_for_each_entry(dtmf_l, &dtmf_obj.ilist, list) {
|
||||
if (&dtmf_l->inst == inst) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&dtmf_obj.lock, flags);
|
||||
if (prim == (MGR_NEWLAYER | REQUEST))
|
||||
return(new_dtmf(data, arg));
|
||||
if (ret) {
|
||||
|
@ -580,6 +593,8 @@ dtmf_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
switch(prim) {
|
||||
case MGR_CLRSTPARA | INDICATION:
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CLONELAYER | REQUEST:
|
||||
break;
|
||||
case MGR_CONNECT | REQUEST:
|
||||
|
@ -590,6 +605,7 @@ dtmf_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
#endif
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (debug & DEBUG_DTMF_MGR)
|
||||
|
@ -617,6 +633,7 @@ static int dtmf_init(void)
|
|||
dtmf_obj.name = MName;
|
||||
dtmf_obj.BPROTO.protocol[2] = ISDN_PID_L2_B_TRANSDTMF;
|
||||
dtmf_obj.own_ctrl = dtmf_manager;
|
||||
spin_lock_init(&dtmf_obj.lock);
|
||||
INIT_LIST_HEAD(&dtmf_obj.ilist);
|
||||
if ((err = mISDN_register(&dtmf_obj))) {
|
||||
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
|
||||
|
|
|
@ -240,6 +240,7 @@ mISDN_get_up_layer(int layermask) {
|
|||
return(uplayer);
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
int
|
||||
mISDN_SetIF(mISDNinstance_t *owner, mISDNif_t *hif, u_int prim, void *upfunc,
|
||||
void *downfunc, void *data)
|
||||
|
@ -339,9 +340,10 @@ mISDN_DisConnectIF(mISDNinstance_t *inst, mISDNif_t *hif) {
|
|||
}
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data)
|
||||
mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data, if_func_t *function)
|
||||
{
|
||||
if (!obj) {
|
||||
int_error();
|
||||
|
@ -351,16 +353,10 @@ mISDN_init_instance(mISDNinstance_t *inst, mISDNobject_t *obj, void *data)
|
|||
int_error();
|
||||
return;
|
||||
}
|
||||
INIT_LIST_HEAD(&inst->list);
|
||||
inst->obj = obj;
|
||||
inst->data = data;
|
||||
inst->up.owner = inst;
|
||||
inst->down.owner = inst;
|
||||
inst->up.clone = NULL;
|
||||
inst->up.predecessor = NULL;
|
||||
inst->down.clone = NULL;
|
||||
inst->down.predecessor = NULL;
|
||||
obj->ctrl(NULL, MGR_DISCONNECT | REQUEST, &inst->down);
|
||||
obj->ctrl(NULL, MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
inst->privat = data;
|
||||
inst->function = function;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mISDN_set_dchannel_pid);
|
||||
|
@ -373,7 +369,7 @@ EXPORT_SYMBOL(mISDN_HasProtocol);
|
|||
EXPORT_SYMBOL(mISDN_SetHandledPID);
|
||||
EXPORT_SYMBOL(mISDN_RemoveUsedPID);
|
||||
EXPORT_SYMBOL(mISDN_init_instance);
|
||||
EXPORT_SYMBOL(mISDN_SetIF);
|
||||
EXPORT_SYMBOL(mISDN_ConnectIF);
|
||||
EXPORT_SYMBOL(mISDN_DisConnectIF);
|
||||
// EXPORT_SYMBOL(mISDN_SetIF);
|
||||
// EXPORT_SYMBOL(mISDN_ConnectIF);
|
||||
// EXPORT_SYMBOL(mISDN_DisConnectIF);
|
||||
EXPORT_SYMBOL(mISDN_bprotocol2pid);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
*
|
||||
* Basic declarations, defines and prototypes
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
#ifndef _mISDN_HELPER_H
|
||||
|
@ -43,14 +43,14 @@ discard_queue(struct sk_buff_head *q)
|
|||
#ifdef MISDN_MEMDEBUG
|
||||
#define alloc_stack_skb(s, r) __mid_alloc_stack_skb(s, r, __FILE__, __LINE__)
|
||||
static inline struct sk_buff *
|
||||
__mid_alloc_stack_skb(size_t size, size_t reserve, char *fn, int line)
|
||||
__mid_alloc_stack_skb(u_int size, u_int reserve, char *fn, int line)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!(skb = __mid_alloc_skb(size + reserve, GFP_ATOMIC, fn, line)))
|
||||
#else
|
||||
static inline struct sk_buff *
|
||||
alloc_stack_skb(size_t size, size_t reserve)
|
||||
alloc_stack_skb(u_int size, u_int reserve)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
|
@ -141,7 +141,7 @@ extern void mISDN_RemoveUsedPID(mISDN_pid_t *, mISDN_pid_t *);
|
|||
*
|
||||
* initialisize the mISDNinstance_t struct <inst>
|
||||
*/
|
||||
extern void mISDN_init_instance(mISDNinstance_t *, mISDNobject_t *, void *);
|
||||
extern void mISDN_init_instance(mISDNinstance_t *, mISDNobject_t *, void *, if_func_t *);
|
||||
|
||||
/* returns the member count of a list */
|
||||
static inline int
|
||||
|
@ -176,32 +176,48 @@ mISDN_sethead(u_int prim, int dinfo, struct sk_buff *skb)
|
|||
hh->dinfo = dinfo;
|
||||
}
|
||||
|
||||
/* send the skb through this interface with new header values */
|
||||
#define mISDN_queue_up(i, a, s) mISDN_queue_message(i, a | FLG_MSG_UP, s)
|
||||
#define mISDN_queue_down(i, a, s) mISDN_queue_message(i, a | FLG_MSG_DOWN, s)
|
||||
|
||||
static inline int
|
||||
if_newhead(mISDNif_t *i, u_int prim, int dinfo, struct sk_buff *skb)
|
||||
mISDN_queueup_newhead(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, struct sk_buff *skb)
|
||||
{
|
||||
if (!i->func || !skb)
|
||||
return(-ENXIO);
|
||||
mISDN_sethead(prim, dinfo, skb);
|
||||
return(i->func(i, skb));
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(skb);
|
||||
|
||||
hh->prim = prim;
|
||||
hh->dinfo = dinfo;
|
||||
return(mISDN_queue_up(inst, aflag, skb));
|
||||
}
|
||||
|
||||
static inline int
|
||||
mISDN_queuedown_newhead(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, struct sk_buff *skb)
|
||||
{
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(skb);
|
||||
|
||||
hh->prim = prim;
|
||||
hh->dinfo = dinfo;
|
||||
return(mISDN_queue_down(inst, aflag, skb));
|
||||
}
|
||||
|
||||
|
||||
/* allocate a mISDN message SKB with enough headroom and set the header fields
|
||||
* the MEMDEBUG version is for debugging memory leaks in the mISDN stack
|
||||
*/
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#define create_link_skb(p, d, l, a, r) __mid_create_link_skb(p, d, l, a, r, __FILE__, __LINE__)
|
||||
#define create_link_skb(p, d, l, dp, r) __mid_create_link_skb(p, d, l, dp, r, __FILE__, __LINE__)
|
||||
static inline struct sk_buff *
|
||||
__mid_create_link_skb(u_int prim, int dinfo, int len, void *arg, int reserve, char *fn, int line)
|
||||
__mid_create_link_skb(u_int prim, int dinfo, u_int len, void *dp, u_int reserve, char *fn, int line)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
mISDN_head_t *hh;
|
||||
|
||||
if (!(skb = __mid_alloc_skb(len + reserve, GFP_ATOMIC, fn, line))) {
|
||||
#else
|
||||
static inline struct sk_buff *
|
||||
create_link_skb(u_int prim, int dinfo, int len, void *arg, int reserve)
|
||||
create_link_skb(u_int prim, int dinfo, u_int len, void *dp, u_int reserve)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
mISDN_head_t *hh;
|
||||
|
||||
if (!(skb = alloc_skb(len + reserve, GFP_ATOMIC))) {
|
||||
#endif
|
||||
|
@ -211,8 +227,11 @@ create_link_skb(u_int prim, int dinfo, int len, void *arg, int reserve)
|
|||
} else
|
||||
skb_reserve(skb, reserve);
|
||||
if (len)
|
||||
memcpy(skb_put(skb, len), arg, len);
|
||||
mISDN_sethead(prim, dinfo, skb);
|
||||
memcpy(skb_put(skb, len), dp, len);
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
hh->prim = prim;
|
||||
hh->dinfo = dinfo;
|
||||
hh->len = len;
|
||||
return(skb);
|
||||
}
|
||||
|
||||
|
@ -221,28 +240,25 @@ create_link_skb(u_int prim, int dinfo, int len, void *arg, int reserve)
|
|||
* the MEMDEBUG version is for debugging memory leaks in the mISDN stack
|
||||
*/
|
||||
#ifdef MISDN_MEMDEBUG
|
||||
#define if_link(i, p, d, l, a, r) __mid_if_link(i, p, d, l, a, r, __FILE__, __LINE__)
|
||||
#define mISDN_queue_data(i, a, p, d, l, dp, r) __mid_queue_data(i, a, p, d, l, dp, r, __FILE__, __LINE__)
|
||||
static inline int
|
||||
__mid_if_link(mISDNif_t *i, u_int prim, int dinfo, int len, void *arg, int reserve, char *fn, int line)
|
||||
__mid_queue_data(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, u_int len, void *dp, u_int reserve, char *fn, int line)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
if (!(skb = __mid_create_link_skb(prim, dinfo, len, arg, reserve, fn, line)))
|
||||
if (!(skb = __mid_create_link_skb(prim, dinfo, len, dp, reserve, fn, line)))
|
||||
#else
|
||||
static inline int
|
||||
if_link(mISDNif_t *i, u_int prim, int dinfo, int len, void *arg, int reserve)
|
||||
mISDN_queue_data(mISDNinstance_t *inst, u_int aflag, u_int prim, int dinfo, u_int len, void *dp, u_int reserve)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
||||
if (!(skb = create_link_skb(prim, dinfo, len, arg, reserve)))
|
||||
if (!(skb = create_link_skb(prim, dinfo, len, dp, reserve)))
|
||||
#endif
|
||||
return(-ENOMEM);
|
||||
if (!i)
|
||||
err = -ENXIO;
|
||||
else
|
||||
err = i->func(i, skb);
|
||||
err = mISDN_queue_message(inst, aflag, skb);
|
||||
if (err)
|
||||
kfree_skb(skb);
|
||||
return(err);
|
||||
|
@ -261,6 +277,8 @@ extern struct sk_buff *mISDN_alloc_l3msg(int, u_char);
|
|||
#endif
|
||||
extern void mISDN_AddvarIE(struct sk_buff *, u_char *);
|
||||
extern void mISDN_AddIE(struct sk_buff *, u_char, u_char *);
|
||||
extern ie_info_t *mISDN_get_last_repeated_ie(Q931_info_t *, ie_info_t *);
|
||||
extern int mISDN_get_free_ext_ie(Q931_info_t *);
|
||||
extern void mISDN_LogL3Msg(struct sk_buff *);
|
||||
|
||||
/* manager default handler helper macros */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,13 +3,27 @@
|
|||
* see notice in hfc_multi.c
|
||||
*/
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
// IMPORTANT!!! use CONFIG_PLX_PCI_BRIDGE only in conjunction with CONFIG_HFCMULTI_PCIMEM
|
||||
//#define CONFIG_PLX_PCI_BRIDGE // TODO should be defined in kernel config
|
||||
|
||||
#ifdef CONFIG_PLX_PCI_BRIDGE
|
||||
#undef FIFO_32BIT_ACCESS
|
||||
#ifndef CONFIG_HFCMULTI_PCIMEM
|
||||
#define CONFIG_HFCMULTI_PCIMEM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DEBUG_HFCMULTI_FIFO 0x0001
|
||||
#define DEBUG_HFCMULTI_CRC 0x0002
|
||||
#define DEBUG_HFCMULTI_INIT 0x0004
|
||||
#define DEBUG_HFCMULTI_INIT 0x0004
|
||||
#define DEBUG_HFCMULTI_MGR 0x0008
|
||||
#define DEBUG_HFCMULTI_MODE 0x0010
|
||||
#define DEBUG_HFCMULTI_MSG 0x0020
|
||||
#define DEBUG_HFCMULTI_STATE 0x0040
|
||||
#define DEBUG_HFCMULTI_STATE 0x0040
|
||||
#define DEBUG_HFCMULTI_SYNC 0x0100
|
||||
#define DEBUG_HFCMULTI_DTMF 0x0200
|
||||
#define DEBUG_HFCMULTI_LOCK 0x8000
|
||||
|
@ -21,28 +35,22 @@
|
|||
also registers are assigned differen for HFC-4s/8s and HFC-E1
|
||||
*/
|
||||
|
||||
#define MAX_FRAME_SIZE 2048
|
||||
// #define MAX_FRAME_SIZE 2048
|
||||
|
||||
struct hfc_chan {
|
||||
/* dch or bch is set, otherwhise this channel is not used */
|
||||
dchannel_t *dch; /* link if channel is a D-channel */
|
||||
bchannel_t *bch; /* link if channel is a B-channel */
|
||||
int rx_idx; /* for D-channel */
|
||||
unsigned char *rx_buf; /* for D-channel */
|
||||
int port; /* the interface port this channel is associated with */
|
||||
int nt_mode;
|
||||
channel_t *ch; /* link if channel is a D-channel */
|
||||
int port; /* the interface port this channel is associated with */
|
||||
int nt_timer; /* -1 if off, 0 if elapsed, >0 if running */
|
||||
int los, ais; /* current alarms */
|
||||
int los, ais, slip_tx, slip_rx; /* current alarms */
|
||||
int jitter;
|
||||
u_long cfg; /* port configuration */
|
||||
int sync; /* sync state (used by E1) */
|
||||
struct sk_buff_head dtmfque;
|
||||
unsigned long protocol; /* current protocol */
|
||||
u_long cfg; /* port configuration */
|
||||
int sync; /* sync state (used by E1) */
|
||||
DWORD protocol;/* current protocol */
|
||||
int slot_tx; /* current pcm slot */
|
||||
int bank_tx; /* current pcm bank */
|
||||
int slot_rx;
|
||||
int bank_rx;
|
||||
int conf; /* conference setting of TX slot */
|
||||
int conf; /* conference setting of TX slot */
|
||||
int txpending; /* if there is currently data in the FIFO 0=no, 1=yes, 2=splloop */
|
||||
int e1_state; /* keep track of last state */
|
||||
};
|
||||
|
@ -50,17 +58,17 @@ struct hfc_chan {
|
|||
typedef struct hfc_chan hfc_chan_t;
|
||||
|
||||
struct hfcmulti_hw {
|
||||
unsigned char r_ctrl;
|
||||
unsigned char r_irq_ctrl;
|
||||
unsigned char r_cirm;
|
||||
unsigned char r_ram_sz;
|
||||
unsigned char r_pcm_md0;
|
||||
unsigned char r_irqmsk_misc;
|
||||
unsigned char r_dtmf;
|
||||
unsigned char r_st_sync;
|
||||
unsigned char r_sci_msk;
|
||||
unsigned char r_tx0, r_tx1;
|
||||
unsigned char a_st_ctrl0[8];
|
||||
BYTE r_ctrl;
|
||||
BYTE r_irq_ctrl;
|
||||
BYTE r_cirm;
|
||||
BYTE r_ram_sz;
|
||||
BYTE r_pcm_md0;
|
||||
BYTE r_irqmsk_misc;
|
||||
BYTE r_dtmf;
|
||||
BYTE r_st_sync;
|
||||
BYTE r_sci_msk;
|
||||
BYTE r_tx0, r_tx1;
|
||||
BYTE a_st_ctrl0[8];
|
||||
timer_t timer;
|
||||
};
|
||||
|
||||
|
@ -76,6 +84,8 @@ typedef struct hfcmulti_hw hfcmulti_hw_t;
|
|||
#define HFC_CFG_REPORT_AIS 6 /* the card should report alarm ind. sign. */
|
||||
#define HFC_CFG_REPORT_SLIP 7 /* the card should report bit slips */
|
||||
#define HFC_CFG_DTMF 8 /* enable DTMF-detection */
|
||||
#define HFC_CFG_CRC4 9 /* disable CRC-4 Multiframe mode,
|
||||
use double frame instead. */
|
||||
|
||||
#define HFC_CHIP_EXRAM_128 0 /* external ram 128k */
|
||||
#define HFC_CHIP_EXRAM_512 1 /* external ram 256k */
|
||||
|
@ -86,10 +96,14 @@ typedef struct hfcmulti_hw hfcmulti_hw_t;
|
|||
#define HFC_CHIP_DTMF 6 /* DTMF decoding is enabled */
|
||||
#define HFC_CHIP_ULAW 7 /* ULAW mode */
|
||||
#define HFC_CHIP_CLOCK2 8 /* double clock mode */
|
||||
#define HFC_CHIP_CRYSTAL_CLOCK 9 /* autarc clocking mode */
|
||||
|
||||
struct hfc_multi {
|
||||
struct list_head list;
|
||||
#warning
|
||||
void *davor, *danach;
|
||||
char name[32];
|
||||
int idx; /* chip index for module parameters */
|
||||
int id; /* chip number starting with 1 */
|
||||
int pcm; /* id of pcm bus */
|
||||
int type;
|
||||
|
@ -98,7 +112,10 @@ struct hfc_multi {
|
|||
u_int irqcnt;
|
||||
struct pci_dev *pci_dev;
|
||||
#ifdef CONFIG_HFCMULTI_PCIMEM
|
||||
unsigned char *pci_membase;/* PCI memory (MUST BE BYTE POINTER) */
|
||||
u_long pci_origmembase, plx_origmembase, dsp_origmembase;
|
||||
u_char *pci_membase;/* PCI memory (MUST BE BYTE POINTER) */
|
||||
u_char *plx_membase;/* PCI memory (MUST BE BYTE POINTER) */
|
||||
u_char *dsp_membase;/* PCI memory (MUST BE BYTE POINTER) */
|
||||
#else
|
||||
u_int pci_iobase;/* PCI IO (MUST BE BYTE POINTER) */
|
||||
#endif
|
||||
|
@ -118,10 +135,7 @@ struct hfc_multi {
|
|||
u_int ledcount; /* used to animate leds */
|
||||
u_int activity[8]; /* if there is any action on this port (will be cleared after showing led-states) */
|
||||
|
||||
mISDN_HWlock_t lock; /* the lock */
|
||||
#ifdef SPIN_DEBUG
|
||||
void *lock_adr;
|
||||
#endif
|
||||
spinlock_t lock; /* the lock */
|
||||
|
||||
/* the channel index is counted from 0, regardless where the channel
|
||||
* is located on the hfc-channel.
|
||||
|
@ -188,6 +202,7 @@ typedef struct hfc_multi hfc_multi_t;
|
|||
#define R_TX0 0x28
|
||||
#define R_TX1 0x29
|
||||
#define R_TX_FR0 0x2C
|
||||
|
||||
#define R_TX_FR1 0x2D
|
||||
#define R_TX_FR2 0x2E
|
||||
#define R_JATT_ATT 0x2F /* undocumented */
|
||||
|
@ -537,9 +552,9 @@ typedef struct hfc_multi hfc_multi_t;
|
|||
#define V_PCM_SYNC 0x04
|
||||
#define V_NEG_CLK 0x08
|
||||
#define V_HCLK 0x10
|
||||
#define V_JATT_AUTO_DEL 0x20
|
||||
#define V_JATT_AUTO 0x40
|
||||
#define V_JATT_EN 0x80
|
||||
//#define V_JATT_AUTO_DEL 0x20
|
||||
//#define V_JATT_AUTO 0x40
|
||||
#define V_JATT_OFF 0x80
|
||||
/* R_STATE */
|
||||
#define V_E1_STA 0x01
|
||||
#define V_ALT_FR_RX 0x40
|
||||
|
@ -1083,34 +1098,51 @@ struct hfc_register_names {
|
|||
|
||||
/* ACCESS TO PCI MEMORY MAPPED REGISTERS */
|
||||
|
||||
#define ADDR_MULT 1 // can be defined to other values if there
|
||||
// is e.g. an offset in a bridge chip addressing
|
||||
|
||||
#ifdef CONFIG_HFCMULTI_PCIMEM
|
||||
|
||||
#define HFC_outl(a,b,c) (*((volatile u_long *)((a->pci_membase)+b)) = c)
|
||||
#define HFC_inl(a,b) (*((volatile u_long *)((a->pci_membase)+b)))
|
||||
#define HFC_outl(a,b,c) (*((volatile u_long *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
|
||||
#define HFC_inl(a,b) (*((volatile u_long *)((a->pci_membase)+((b)*ADDR_MULT))))
|
||||
#define HFC_outw_(a,b,c) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
|
||||
#define HFC_inw_(a,b) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))))
|
||||
/*
|
||||
// version of HFC_inw_(a,b) that makes 8bit access instead of 16bit
|
||||
// only for test purposes
|
||||
u_short HFC_inw_(hfc_multi_t *a, int b)
|
||||
{
|
||||
u_short zl,zh;
|
||||
|
||||
zl=(*((volatile u_char *)((a->pci_membase)+(b*4))));
|
||||
zh=(*((volatile u_char *)((a->pci_membase)+((b+1)*4))));
|
||||
return(zl|(zh<<8));
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
#define HFC_outb_(a,b,c) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
|
||||
#define HFC_inb_(a,b) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))))
|
||||
#define HFC_wait_(a) while((*((volatile u_char *)((a->pci_membase)+(R_STATUS*ADDR_MULT)))) & V_BUSY)
|
||||
|
||||
|
||||
/* no debug */
|
||||
#define HFC_outl_(a,b,c) (*((volatile u_long *)((a->pci_membase)+b)) = c)
|
||||
#define HFC_inl_(a,b) (*((volatile u_long *)((a->pci_membase)+b)))
|
||||
#define HFC_inw_(a,b) (*((volatile u_short *)((a->pci_membase)+b)))
|
||||
#define HFC_outb_(a,b,c) (*((volatile u_char *)((a->pci_membase)+b)) = c)
|
||||
#define HFC_inb_(a,b) (*((volatile u_char *)((a->pci_membase)+b)))
|
||||
#define HFC_wait_(a) while((*((volatile u_char *)((a->pci_membase)+R_STATUS))) & V_BUSY)
|
||||
|
||||
/* macros */
|
||||
#ifndef HFC_REGISTER_MAP
|
||||
|
||||
/* usage: HFC_outX(card,register,value); */
|
||||
#define HFC_outb(a,b,c) (*((volatile u_char *)((a->pci_membase)+b)) = c)
|
||||
#define HFC_outb(a,b,c) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
|
||||
#define HFC_outw(a,b,c) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))) = c)
|
||||
/* usage: register=HFC_inX(card,register); */
|
||||
#define HFC_inb(a,b) (*((volatile u_char *)((a->pci_membase)+b)))
|
||||
#define HFC_inw(a,b) (*((volatile u_short *)((a->pci_membase)+b)))
|
||||
#define HFC_inb(a,b) (*((volatile u_char *)((a->pci_membase)+((b)*ADDR_MULT))))
|
||||
#define HFC_inw(a,b) (*((volatile u_short *)((a->pci_membase)+((b)*ADDR_MULT))))
|
||||
/* usage: HFC_wait(card); */
|
||||
#define HFC_wait(a) while((*((volatile u_char *)((a->pci_membase)+R_STATUS))) & V_BUSY)
|
||||
#define HFC_wait(a) while((*((volatile u_char *)((a->pci_membase)+(R_STATUS*ADDR_MULT)))) & V_BUSY)
|
||||
|
||||
#else /* HFC_REGISTER_MAP */
|
||||
|
||||
#define HFC_outb(a,b,c) _HFC_outb(a, b, c, __FUNCTION__, __LINE__)
|
||||
static unsigned char _HFC_outb(hfc_multi_t *a, unsigned char b, unsigned char c, char *function, int line)
|
||||
static BYTE _HFC_outb(hfc_multi_t *a, BYTE b, BYTE c, char *function, int line)
|
||||
{
|
||||
char regname[256]="", bits[9]="xxxxxxxx";
|
||||
int i;
|
||||
|
@ -1135,10 +1167,10 @@ static unsigned char _HFC_outb(hfc_multi_t *a, unsigned char b, unsigned char c,
|
|||
return(*(((volatile u_char *)a->pci_membase)+b) = c);
|
||||
}
|
||||
#define HFC_inb(a,b) _HFC_inb(a, b, __FUNCTION__, __LINE__)
|
||||
static unsigned char _HFC_inb(hfc_multi_t *a, unsigned char b, char *function, int line)
|
||||
static BYTE _HFC_inb(hfc_multi_t *a, BYTE b, char *function, int line)
|
||||
{
|
||||
char regname[256]="", bits[9]="xxxxxxxx";
|
||||
u_char c = (*(((volatile u_char *)a->pci_membase)+b));
|
||||
u_char c = (*(((volatile u_char *)a->pci_membase)+((b)*ADDR_MULT));
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
@ -1163,10 +1195,10 @@ static unsigned char _HFC_inb(hfc_multi_t *a, unsigned char b, char *function, i
|
|||
return(c);
|
||||
}
|
||||
#define HFC_inw(a,b) _HFC_inw(a, b, __FUNCTION__, __LINE__)
|
||||
static unsigned short _HFC_inw(hfc_multi_t *a, unsigned char b, char *function, int line)
|
||||
static WORD _HFC_inw(hfc_multi_t *a, BYTE b, char *function, int line)
|
||||
{
|
||||
char regname[256]="";
|
||||
u_short c = (*(((volatile u_short *)a->pci_membase)+b));
|
||||
u_short c = (*(((volatile u_short *)a->pci_membase)+((b)*ADDR_MULT)));
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
@ -1241,10 +1273,12 @@ static inline void HFC_wait(hfc_multi_t *a)
|
|||
/* usage: HFC_putX(card,value); */
|
||||
#define HFC_putb(a,b) outb(b,a->pci_iobase)
|
||||
#define HFC_putl(a,b) outl(b,a->pci_iobase)
|
||||
#define HFC_putw(a,b) outw(b,a->pci_iobase)
|
||||
|
||||
/* usage: value=HFC_getX(card); */
|
||||
#define HFC_getb(a) inb((volatile u_int)a->pci_iobase)
|
||||
#define HFC_getl(a) inl((volatile u_int)a->pci_iobase)
|
||||
#define HFC_getw(a) inw((volatile u_int)a->pci_iobase)
|
||||
|
||||
/* no debug */
|
||||
#define HFC_outl_(a,b,c) HFC_outl(a,b,c)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -21,29 +21,23 @@
|
|||
#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */
|
||||
|
||||
/* hfcsusb Layer1 commands */
|
||||
#define HFC_L1_ACTIVATE_TE 0x01
|
||||
#define HFC_L1_DEACTIVATE_TE 0x02
|
||||
#define HFC_L1_ACTIVATE_NT 0x03
|
||||
#define HFC_L1_DEACTIVATE_NT 0x04
|
||||
#define HFC_L1_ACTIVATE_TE 0x01
|
||||
#define HFC_L1_ACTIVATE_NT 0x02
|
||||
#define HFC_L1_DEACTIVATE_NT 0x03
|
||||
#define HFC_L1_FORCE_DEACTIVATE_TE 0x04
|
||||
|
||||
/* bits in STATES */
|
||||
/* cmd FLAGS in HFCUSB_STATES register */
|
||||
#define HFCUSB_LOAD_STATE 0x10
|
||||
#define HFCUSB_ACTIVATE 0x20
|
||||
#define HFCUSB_DO_ACTION 0x40
|
||||
#define HFCUSB_NT_G2_G3 0x80
|
||||
|
||||
/* bits in hw_mode */
|
||||
#define HW_MODE_TE 0x01
|
||||
#define HW_MODE_NT 0x02
|
||||
#define PORT_MODE_TE 0x01
|
||||
#define PORT_MODE_NT 0x02
|
||||
#define NT_ACTIVATION_TIMER 0x04 /* enables NT mode activation Timer */
|
||||
#define NT_T1_COUNT 10
|
||||
|
||||
|
||||
#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */
|
||||
#define HFCUSB_L1_DRX 1 /* D-frame received */
|
||||
#define HFCUSB_L1_ERX 2 /* E-frame received */
|
||||
#define HFCUSB_L1_DTX 4 /* D-frames completed */
|
||||
|
||||
#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */
|
||||
|
||||
#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */
|
||||
|
@ -84,6 +78,15 @@
|
|||
#define HFCUSB_PCM_TX 6
|
||||
#define HFCUSB_PCM_RX 7
|
||||
|
||||
/*************/
|
||||
/* Chan idx */
|
||||
/*************/
|
||||
#define B1 0
|
||||
#define B2 1
|
||||
#define D 2
|
||||
#define PCM 3
|
||||
#define MAX_CHAN 4
|
||||
|
||||
/*
|
||||
* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
|
||||
* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
|
||||
|
@ -95,7 +98,7 @@
|
|||
#define ISOC_PACKETS_D 8
|
||||
#define ISOC_PACKETS_B 8
|
||||
#define ISO_BUFFER_SIZE 128
|
||||
|
||||
#define TRANSP_PACKET_SIZE 0
|
||||
|
||||
/* defines how much ISO packets are handled in one URB */
|
||||
static int iso_packets[8] =
|
||||
|
@ -132,7 +135,6 @@ static int iso_packets[8] =
|
|||
#define HFC_CTRL_BUFSIZE 32
|
||||
|
||||
|
||||
|
||||
/*************************************************/
|
||||
/* entry and size of output/input control buffer */
|
||||
/*************************************************/
|
||||
|
|
|
@ -1376,7 +1376,7 @@ I4Lcapi_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
case MGR_SETSTACK | CONFIRM:
|
||||
case MGR_SETSTACK | INDICATION:
|
||||
if (nr_ch >= 0) {
|
||||
if (inst->pid.protocol[2] != ISDN_PID_L2_B_TRANS)
|
||||
test_and_set_bit(I4L_FLG_LAYER1, &channel->Flags);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include "dchannel.h"
|
||||
#include "channel.h"
|
||||
#include "isac.h"
|
||||
#include "arcofi.h"
|
||||
#include "layer1.h"
|
||||
|
@ -19,8 +19,8 @@
|
|||
#endif
|
||||
|
||||
|
||||
#define DBUSY_TIMER_VALUE 80
|
||||
#define ARCOFI_USE 1
|
||||
#define DBUSY_TIMER_VALUE 80
|
||||
#define ARCOFI_USE 1
|
||||
|
||||
const char *isac_revision = "$Revision$";
|
||||
|
||||
|
@ -37,29 +37,26 @@ EXPORT_SYMBOL(mISDN_ISAC_l1hw);
|
|||
#endif
|
||||
|
||||
static inline void
|
||||
ph_command(dchannel_t *dch, unsigned int command)
|
||||
ph_command(channel_t *dch, unsigned int command)
|
||||
{
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ph_command %x", command);
|
||||
if (dch->type & ISAC_TYPE_ISACSX)
|
||||
dch->write_reg(dch->inst.data, ISACSX_CIX0, (command << 4) | 0xE);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_CIX0, (command << 4) | 0xE);
|
||||
else
|
||||
dch->write_reg(dch->inst.data, ISAC_CIX0, (command << 2) | 3);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CIX0, (command << 2) | 3);
|
||||
}
|
||||
|
||||
static void
|
||||
isac_new_ph(dchannel_t *dch)
|
||||
isac_ph_state_change(channel_t *dch)
|
||||
{
|
||||
u_int prim = PH_SIGNAL | INDICATION;
|
||||
u_int para = 0;
|
||||
mISDNif_t *upif = &dch->inst.up;
|
||||
|
||||
switch (dch->ph_state) {
|
||||
switch (dch->state) {
|
||||
case (ISAC_IND_RS):
|
||||
case (ISAC_IND_EI):
|
||||
dch->inst.lock(dch->inst.data,0);
|
||||
ph_command(dch, ISAC_CMD_DUI);
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
prim = PH_CONTROL | INDICATION;
|
||||
para = HW_RESET;
|
||||
break;
|
||||
|
@ -90,28 +87,15 @@ isac_new_ph(dchannel_t *dch)
|
|||
default:
|
||||
return;
|
||||
}
|
||||
while(upif) {
|
||||
if_link(upif, prim, para, 0, NULL, 0);
|
||||
upif = upif->clone;
|
||||
}
|
||||
mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0);
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static void
|
||||
isac_hwbh(dchannel_t *dch)
|
||||
isac_hwbh(channel_t *dch)
|
||||
{
|
||||
if (dch->debug)
|
||||
printk(KERN_DEBUG "%s: event %lx\n", __FUNCTION__, dch->event);
|
||||
#if 0
|
||||
if (test_and_clear_bit(D_CLEARBUSY, &dch->event)) {
|
||||
if (dch->debug)
|
||||
mISDN_debugprint(&dch->inst, "D-Channel Busy cleared");
|
||||
stptr = dch->stlist;
|
||||
while (stptr != NULL) {
|
||||
stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
|
||||
stptr = stptr->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (test_and_clear_bit(D_L1STATECHANGE, &dch->event))
|
||||
isac_new_ph(dch);
|
||||
#if ARCOFI_USE
|
||||
|
@ -123,9 +107,10 @@ isac_hwbh(dchannel_t *dch)
|
|||
arcofi_fsm(dch, ARCOFI_TX_END, NULL);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
isac_empty_fifo(dchannel_t *dch, int count)
|
||||
isac_empty_fifo(channel_t *dch, int count)
|
||||
{
|
||||
u_char *ptr;
|
||||
|
||||
|
@ -135,7 +120,7 @@ isac_empty_fifo(dchannel_t *dch, int count)
|
|||
if (!dch->rx_skb) {
|
||||
if (!(dch->rx_skb = alloc_stack_skb(MAX_DFRAME_LEN_L1, dch->up_headerlen))) {
|
||||
printk(KERN_WARNING "mISDN: D receive out of memory\n");
|
||||
dch->write_reg(dch->inst.data, ISAC_CMDR, 0x80);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -143,31 +128,32 @@ isac_empty_fifo(dchannel_t *dch, int count)
|
|||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "isac_empty_fifo overrun %d",
|
||||
dch->rx_skb->len + count);
|
||||
dch->write_reg(dch->inst.data, ISAC_CMDR, 0x80);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
|
||||
return;
|
||||
}
|
||||
ptr = skb_put(dch->rx_skb, count);
|
||||
dch->read_fifo(dch->inst.data, ptr, count);
|
||||
dch->write_reg(dch->inst.data, ISAC_CMDR, 0x80);
|
||||
dch->read_fifo(dch->inst.privat, ptr, count);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
|
||||
if (dch->debug & L1_DEB_ISAC_FIFO) {
|
||||
char *t = dch->dlog;
|
||||
char *t = dch->log;
|
||||
|
||||
t += sprintf(t, "isac_empty_fifo cnt %d", count);
|
||||
mISDN_QuickHex(t, ptr, count);
|
||||
mISDN_debugprint(&dch->inst, dch->dlog);
|
||||
mISDN_debugprint(&dch->inst, dch->log);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isac_fill_fifo(dchannel_t *dch)
|
||||
isac_fill_fifo(channel_t *dch)
|
||||
{
|
||||
int count, more;
|
||||
u_char *ptr;
|
||||
|
||||
if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO))
|
||||
mISDN_debugprint(&dch->inst, "isac_fill_fifo");
|
||||
|
||||
count = dch->tx_len - dch->tx_idx;
|
||||
if (!dch->tx_skb)
|
||||
return;
|
||||
count = dch->tx_skb->len - dch->tx_idx;
|
||||
if (count <= 0)
|
||||
return;
|
||||
|
||||
|
@ -176,33 +162,33 @@ isac_fill_fifo(dchannel_t *dch)
|
|||
more = !0;
|
||||
count = 32;
|
||||
}
|
||||
ptr = dch->tx_buf + dch->tx_idx;
|
||||
ptr = dch->tx_skb->data + dch->tx_idx;
|
||||
dch->tx_idx += count;
|
||||
dch->write_fifo(dch->inst.data, ptr, count);
|
||||
dch->write_reg(dch->inst.data, ISAC_CMDR, more ? 0x8 : 0xa);
|
||||
if (test_and_set_bit(FLG_DBUSY_TIMER, &dch->DFlags)) {
|
||||
dch->write_fifo(dch->inst.privat, ptr, count);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CMDR, more ? 0x8 : 0xa);
|
||||
if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) {
|
||||
mISDN_debugprint(&dch->inst, "isac_fill_fifo dbusytimer running");
|
||||
del_timer(&dch->dbusytimer);
|
||||
del_timer(&dch->timer);
|
||||
}
|
||||
init_timer(&dch->dbusytimer);
|
||||
dch->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
|
||||
add_timer(&dch->dbusytimer);
|
||||
init_timer(&dch->timer);
|
||||
dch->timer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
|
||||
add_timer(&dch->timer);
|
||||
if (dch->debug & L1_DEB_ISAC_FIFO) {
|
||||
char *t = dch->dlog;
|
||||
char *t = dch->log;
|
||||
|
||||
t += sprintf(t, "isac_fill_fifo cnt %d", count);
|
||||
mISDN_QuickHex(t, ptr, count);
|
||||
mISDN_debugprint(&dch->inst, dch->dlog);
|
||||
mISDN_debugprint(&dch->inst, dch->log);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isac_rme_irq(dchannel_t *dch)
|
||||
isac_rme_irq(channel_t *dch)
|
||||
{
|
||||
u_char val;
|
||||
u_int count;
|
||||
|
||||
val = dch->read_reg(dch->inst.data, ISAC_RSTA);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_RSTA);
|
||||
if ((val & 0x70) != 0x20) {
|
||||
if (val & 0x40) {
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
|
@ -218,86 +204,97 @@ isac_rme_irq(dchannel_t *dch)
|
|||
dch->err_crc++;
|
||||
#endif
|
||||
}
|
||||
dch->write_reg(dch->inst.data, ISAC_CMDR, 0x80);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x80);
|
||||
if (dch->rx_skb)
|
||||
dev_kfree_skb(dch->rx_skb);
|
||||
} else {
|
||||
count = dch->read_reg(dch->inst.data, ISAC_RBCL) & 0x1f;
|
||||
count = dch->read_reg(dch->inst.privat, ISAC_RBCL) & 0x1f;
|
||||
if (count == 0)
|
||||
count = 32;
|
||||
isac_empty_fifo(dch, count);
|
||||
if (dch->rx_skb) {
|
||||
skb_queue_tail(&dch->rqueue, dch->rx_skb);
|
||||
}
|
||||
if (dch->rx_skb)
|
||||
if (unlikely(mISDN_queueup_newhead(&dch->inst, 0, PH_DATA_IND, MISDN_ID_ANY, dch->rx_skb))) {
|
||||
int_error();
|
||||
dev_kfree_skb(dch->rx_skb);
|
||||
}
|
||||
}
|
||||
dch->rx_skb = NULL;
|
||||
dchannel_sched_event(dch, D_RCVBUFREADY);
|
||||
}
|
||||
|
||||
static void
|
||||
isac_xpr_irq(dchannel_t *dch)
|
||||
isac_xpr_irq(channel_t *dch)
|
||||
{
|
||||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
dchannel_sched_event(dch, D_CLEARBUSY);
|
||||
if (dch->tx_idx < dch->tx_len) {
|
||||
if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
|
||||
del_timer(&dch->timer);
|
||||
if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) {
|
||||
isac_fill_fifo(dch);
|
||||
} else {
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags)) {
|
||||
if (dch->next_skb) {
|
||||
dch->tx_len = dch->next_skb->len;
|
||||
memcpy(dch->tx_buf,
|
||||
dch->next_skb->data, dch->tx_len);
|
||||
if (dch->tx_skb)
|
||||
dev_kfree_skb(dch->tx_skb);
|
||||
if (test_bit(FLG_TX_NEXT, &dch->Flags)) {
|
||||
dch->tx_skb = dch->next_skb;
|
||||
if (dch->tx_skb) {
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(dch->tx_skb);
|
||||
|
||||
dch->next_skb = NULL;
|
||||
test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
|
||||
dch->tx_idx = 0;
|
||||
queue_ch_frame(dch, CONFIRM, hh->dinfo, NULL);
|
||||
isac_fill_fifo(dch);
|
||||
dchannel_sched_event(dch, D_XMTBUFREADY);
|
||||
} else {
|
||||
printk(KERN_WARNING "isac tx irq TX_NEXT without skb\n");
|
||||
test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags);
|
||||
test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
|
||||
test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
|
||||
}
|
||||
} else
|
||||
test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags);
|
||||
} else {
|
||||
dch->tx_skb = NULL;
|
||||
test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isac_retransmit(dchannel_t *dch)
|
||||
isac_retransmit(channel_t *dch)
|
||||
{
|
||||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
dchannel_sched_event(dch, D_CLEARBUSY);
|
||||
if (test_bit(FLG_TX_BUSY, &dch->DFlags)) {
|
||||
if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
|
||||
del_timer(&dch->timer);
|
||||
if (test_bit(FLG_TX_BUSY, &dch->Flags)) {
|
||||
/* Restart frame */
|
||||
dch->tx_idx = 0;
|
||||
isac_fill_fifo(dch);
|
||||
} else if (dch->tx_skb) { /* should not happen */
|
||||
int_error();
|
||||
test_and_set_bit(FLG_TX_BUSY, &dch->Flags);
|
||||
dch->tx_idx = 0;
|
||||
isac_fill_fifo(dch);
|
||||
} else {
|
||||
printk(KERN_WARNING "mISDN: ISAC XDU no TX_BUSY\n");
|
||||
mISDN_debugprint(&dch->inst, "ISAC XDU no TX_BUSY");
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags)) {
|
||||
if (dch->next_skb) {
|
||||
dch->tx_len = dch->next_skb->len;
|
||||
memcpy(dch->tx_buf,
|
||||
dch->next_skb->data,
|
||||
dch->tx_len);
|
||||
if (test_bit(FLG_TX_NEXT, &dch->Flags)) {
|
||||
dch->tx_skb = dch->next_skb;
|
||||
if (dch->tx_skb) {
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(dch->next_skb);
|
||||
|
||||
dch->next_skb = NULL;
|
||||
test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
|
||||
dch->tx_idx = 0;
|
||||
queue_ch_frame(dch, CONFIRM, hh->dinfo, NULL);
|
||||
isac_fill_fifo(dch);
|
||||
dchannel_sched_event(dch, D_XMTBUFREADY);
|
||||
} else {
|
||||
printk(KERN_WARNING "isac xdu irq TX_NEXT without skb\n");
|
||||
test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isac_mos_irq(dchannel_t *dch)
|
||||
isac_mos_irq(channel_t *dch)
|
||||
{
|
||||
u_char val;
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
val = dch->read_reg(dch->inst.data, ISAC_MOSR);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
|
||||
if (dch->debug & L1_DEB_MONITOR)
|
||||
mISDN_debugprint(&dch->inst, "ISAC MOSR %02x", val);
|
||||
#if ARCOFI_USE
|
||||
|
@ -308,7 +305,7 @@ isac_mos_irq(dchannel_t *dch)
|
|||
mISDN_debugprint(&dch->inst, "ISAC MON RX out of memory!");
|
||||
isac->mocr &= 0xf0;
|
||||
isac->mocr |= 0x0a;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
goto afterMONR0;
|
||||
} else
|
||||
isac->mon_rxp = 0;
|
||||
|
@ -316,18 +313,18 @@ isac_mos_irq(dchannel_t *dch)
|
|||
if (isac->mon_rxp >= MAX_MON_FRAME) {
|
||||
isac->mocr &= 0xf0;
|
||||
isac->mocr |= 0x0a;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
isac->mon_rxp = 0;
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "ISAC MON RX overflow!");
|
||||
goto afterMONR0;
|
||||
}
|
||||
isac->mon_rx[isac->mon_rxp++] = dch->read_reg(dch->inst.data, ISAC_MOR0);
|
||||
isac->mon_rx[isac->mon_rxp++] = dch->read_reg(dch->inst.privat, ISAC_MOR0);
|
||||
if (dch->debug & L1_DEB_MONITOR)
|
||||
mISDN_debugprint(&dch->inst, "ISAC MOR0 %02x", isac->mon_rx[isac->mon_rxp -1]);
|
||||
if (isac->mon_rxp == 1) {
|
||||
isac->mocr |= 0x04;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
}
|
||||
}
|
||||
afterMONR0:
|
||||
|
@ -338,7 +335,7 @@ afterMONR0:
|
|||
mISDN_debugprint(&dch->inst, "ISAC MON RX out of memory!");
|
||||
isac->mocr &= 0x0f;
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
goto afterMONR1;
|
||||
} else
|
||||
isac->mon_rxp = 0;
|
||||
|
@ -346,49 +343,53 @@ afterMONR0:
|
|||
if (isac->mon_rxp >= MAX_MON_FRAME) {
|
||||
isac->mocr &= 0x0f;
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
isac->mon_rxp = 0;
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "ISAC MON RX overflow!");
|
||||
goto afterMONR1;
|
||||
}
|
||||
isac->mon_rx[isac->mon_rxp++] = dch->read_reg(dch->inst.data, ISAC_MOR1);
|
||||
isac->mon_rx[isac->mon_rxp++] = dch->read_reg(dch->inst.privat, ISAC_MOR1);
|
||||
if (dch->debug & L1_DEB_MONITOR)
|
||||
mISDN_debugprint(&dch->inst, "ISAC MOR1 %02x", isac->mon_rx[isac->mon_rxp -1]);
|
||||
isac->mocr |= 0x40;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
}
|
||||
afterMONR1:
|
||||
if (val & 0x04) {
|
||||
isac->mocr &= 0xf0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
isac->mocr |= 0x0a;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dchannel_sched_event(dch, D_RX_MON0);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION, D_RX_MON0,
|
||||
isac->mon_rxp, isac->mon_rx, 0);
|
||||
}
|
||||
if (val & 0x40) {
|
||||
isac->mocr &= 0x0f;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dchannel_sched_event(dch, D_RX_MON1);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION, D_RX_MON1,
|
||||
isac->mon_rxp, isac->mon_rx, 0);
|
||||
}
|
||||
if (val & 0x02) {
|
||||
if ((!isac->mon_tx) || (isac->mon_txc &&
|
||||
(isac->mon_txp >= isac->mon_txc) && !(val & 0x08))) {
|
||||
isac->mocr &= 0xf0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
isac->mocr |= 0x0a;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc))
|
||||
dchannel_sched_event(dch, D_TX_MON0);
|
||||
mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
|
||||
D_TX_MON0, 0, NULL, 0);
|
||||
goto AfterMOX0;
|
||||
}
|
||||
if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
|
||||
dchannel_sched_event(dch, D_TX_MON0);
|
||||
mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
|
||||
D_TX_MON0, 0, NULL, 0);
|
||||
goto AfterMOX0;
|
||||
}
|
||||
dch->write_reg(dch->inst.data, ISAC_MOX0,
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOX0,
|
||||
isac->mon_tx[isac->mon_txp++]);
|
||||
if (dch->debug & L1_DEB_MONITOR)
|
||||
mISDN_debugprint(&dch->inst, "ISAC %02x -> MOX0", isac->mon_tx[isac->mon_txp -1]);
|
||||
|
@ -398,18 +399,20 @@ AfterMOX0:
|
|||
if ((!isac->mon_tx) || (isac->mon_txc &&
|
||||
(isac->mon_txp >= isac->mon_txc) && !(val & 0x80))) {
|
||||
isac->mocr &= 0x0f;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
|
||||
if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc))
|
||||
dchannel_sched_event(dch, D_TX_MON1);
|
||||
mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
|
||||
D_TX_MON1, 0, NULL, 0);
|
||||
goto AfterMOX1;
|
||||
}
|
||||
if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
|
||||
dchannel_sched_event(dch, D_TX_MON1);
|
||||
mISDN_queue_data(&dch->inst, 0, PH_SIGNAL | INDICATION,
|
||||
D_TX_MON1, 0, NULL, 0);
|
||||
goto AfterMOX1;
|
||||
}
|
||||
dch->write_reg(dch->inst.data, ISAC_MOX1,
|
||||
dch->write_reg(dch->inst.privat, ISAC_MOX1,
|
||||
isac->mon_tx[isac->mon_txp++]);
|
||||
if (dch->debug & L1_DEB_MONITOR)
|
||||
mISDN_debugprint(&dch->inst, "ISAC %02x -> MOX1", isac->mon_tx[isac->mon_txp -1]);
|
||||
|
@ -420,50 +423,50 @@ AfterMOX1:
|
|||
}
|
||||
|
||||
static void
|
||||
isac_cisq_irq(dchannel_t *dch) {
|
||||
isac_cisq_irq(channel_t *dch) {
|
||||
unsigned char val;
|
||||
|
||||
val = dch->read_reg(dch->inst.data, ISAC_CIR0);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_CIR0);
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ISAC CIR0 %02X", val);
|
||||
if (val & 2) {
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ph_state change %x->%x",
|
||||
dch->ph_state, (val >> 2) & 0xf);
|
||||
dch->ph_state = (val >> 2) & 0xf;
|
||||
dchannel_sched_event(dch, D_L1STATECHANGE);
|
||||
dch->state, (val >> 2) & 0xf);
|
||||
dch->state = (val >> 2) & 0xf;
|
||||
isac_ph_state_change(dch);
|
||||
}
|
||||
if (val & 1) {
|
||||
val = dch->read_reg(dch->inst.data, ISAC_CIR1);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_CIR1);
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ISAC CIR1 %02X", val );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isacsx_cic_irq(dchannel_t *dch)
|
||||
isacsx_cic_irq(channel_t *dch)
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
val = dch->read_reg(dch->inst.data, ISACSX_CIR0);
|
||||
val = dch->read_reg(dch->inst.privat, ISACSX_CIR0);
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ISACSX CIR0 %02X", val);
|
||||
if (val & ISACSX_CIR0_CIC0) {
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ph_state change %x->%x",
|
||||
dch->ph_state, val >> 4);
|
||||
dch->ph_state = val >> 4;
|
||||
dchannel_sched_event(dch, D_L1STATECHANGE);
|
||||
dch->state, val >> 4);
|
||||
dch->state = val >> 4;
|
||||
isac_ph_state_change(dch);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isacsx_rme_irq(dchannel_t *dch)
|
||||
isacsx_rme_irq(channel_t *dch)
|
||||
{
|
||||
int count;
|
||||
unsigned char val;
|
||||
|
||||
val = dch->read_reg(dch->inst.data, ISACSX_RSTAD);
|
||||
val = dch->read_reg(dch->inst.privat, ISACSX_RSTAD);
|
||||
if ((val & (ISACSX_RSTAD_VFR |
|
||||
ISACSX_RSTAD_RDO |
|
||||
ISACSX_RSTAD_CRC |
|
||||
|
@ -477,25 +480,27 @@ isacsx_rme_irq(dchannel_t *dch)
|
|||
else
|
||||
dch->err_crc++;
|
||||
#endif
|
||||
dch->write_reg(dch->inst.data, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
|
||||
if (dch->rx_skb)
|
||||
dev_kfree_skb(dch->rx_skb);
|
||||
} else {
|
||||
count = dch->read_reg(dch->inst.data, ISACSX_RBCLD) & 0x1f;
|
||||
count = dch->read_reg(dch->inst.privat, ISACSX_RBCLD) & 0x1f;
|
||||
if (count == 0)
|
||||
count = 32;
|
||||
isac_empty_fifo(dch, count);
|
||||
if (dch->rx_skb) {
|
||||
skb_trim(dch->rx_skb, dch->rx_skb->len - 1);
|
||||
skb_queue_tail(&dch->rqueue, dch->rx_skb);
|
||||
if (unlikely(mISDN_queueup_newhead(&dch->inst, 0, PH_DATA_IND, MISDN_ID_ANY, dch->rx_skb))) {
|
||||
int_error();
|
||||
dev_kfree_skb(dch->rx_skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
dch->rx_skb = NULL;
|
||||
dchannel_sched_event(dch, D_RCVBUFREADY);
|
||||
}
|
||||
|
||||
void
|
||||
mISDN_isac_interrupt(dchannel_t *dch, u_char val)
|
||||
mISDN_isac_interrupt(channel_t *dch, u_char val)
|
||||
{
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ISAC interrupt %02x", val);
|
||||
|
@ -503,7 +508,7 @@ mISDN_isac_interrupt(dchannel_t *dch, u_char val)
|
|||
if (val & ISACSX_ISTA_CIC)
|
||||
isacsx_cic_irq(dch);
|
||||
if (val & ISACSX_ISTA_ICD) {
|
||||
val = dch->read_reg(dch->inst.data, ISACSX_ISTAD);
|
||||
val = dch->read_reg(dch->inst.privat, ISACSX_ISTAD);
|
||||
if (dch->debug & L1_DEB_ISAC)
|
||||
mISDN_debugprint(&dch->inst, "ISTAD %02x", val);
|
||||
if (val & ISACSX_ISTAD_XDU) {
|
||||
|
@ -527,7 +532,7 @@ mISDN_isac_interrupt(dchannel_t *dch, u_char val)
|
|||
if (val & ISACSX_ISTAD_RFO) {
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "ISAC RFO");
|
||||
dch->write_reg(dch->inst.data, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_CMDRD, ISACSX_CMDRD_RMC);
|
||||
}
|
||||
if (val & ISACSX_ISTAD_RME)
|
||||
isacsx_rme_irq(dch);
|
||||
|
@ -550,7 +555,7 @@ mISDN_isac_interrupt(dchannel_t *dch, u_char val)
|
|||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "ISAC SIN interrupt");
|
||||
if (val & 0x01) { /* EXI */
|
||||
val = dch->read_reg(dch->inst.data, ISAC_EXIR);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_EXIR);
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "ISAC EXIR %02x", val);
|
||||
if (val & 0x80) /* XMR */
|
||||
|
@ -570,69 +575,53 @@ mISDN_isac_interrupt(dchannel_t *dch, u_char val)
|
|||
}
|
||||
|
||||
int
|
||||
mISDN_ISAC_l1hw(mISDNif_t *hif, struct sk_buff *skb)
|
||||
mISDN_ISAC_l1hw(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
dchannel_t *dch;
|
||||
int ret = -EINVAL;
|
||||
channel_t *dch;
|
||||
int ret = 0;
|
||||
mISDN_head_t *hh;
|
||||
u_long flags;
|
||||
|
||||
if (!hif || !skb)
|
||||
return(ret);
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
dch = hif->fdata;
|
||||
ret = 0;
|
||||
dch = container_of(inst, channel_t, inst);
|
||||
if (hh->prim == PH_DATA_REQ) {
|
||||
if (dch->next_skb) {
|
||||
mISDN_debugprint(&dch->inst, " l2l1 next_skb exist this shouldn't happen");
|
||||
return(-EBUSY);
|
||||
}
|
||||
dch->inst.lock(dch->inst.data,0);
|
||||
if (test_and_set_bit(FLG_TX_BUSY, &dch->DFlags)) {
|
||||
test_and_set_bit(FLG_TX_NEXT, &dch->DFlags);
|
||||
dch->next_skb = skb;
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
return(0);
|
||||
} else {
|
||||
dch->tx_len = skb->len;
|
||||
memcpy(dch->tx_buf, skb->data, dch->tx_len);
|
||||
dch->tx_idx = 0;
|
||||
spin_lock_irqsave(inst->hwlock, flags);
|
||||
ret = channel_senddata(dch, hh->dinfo, skb);
|
||||
if (ret > 0) { /* direct TX */
|
||||
isac_fill_fifo(dch);
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
return(if_newhead(&dch->inst.up, PH_DATA_CNF,
|
||||
hh->dinfo, skb));
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(inst->hwlock, flags);
|
||||
return(ret);
|
||||
} else if (hh->prim == (PH_SIGNAL | REQUEST)) {
|
||||
dch->inst.lock(dch->inst.data,0);
|
||||
spin_lock_irqsave(inst->hwlock, flags);
|
||||
if (hh->dinfo == INFO3_P8)
|
||||
ph_command(dch, ISAC_CMD_AR8);
|
||||
else if (hh->dinfo == INFO3_P10)
|
||||
ph_command(dch, ISAC_CMD_AR10);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
spin_unlock_irqrestore(inst->hwlock, flags);
|
||||
} else if (hh->prim == (PH_CONTROL | REQUEST)) {
|
||||
dch->inst.lock(dch->inst.data,0);
|
||||
spin_lock_irqsave(inst->hwlock, flags);
|
||||
if (hh->dinfo == HW_RESET) {
|
||||
if ((dch->ph_state == ISAC_IND_EI) ||
|
||||
(dch->ph_state == ISAC_IND_DR) ||
|
||||
(dch->ph_state == ISAC_IND_RS))
|
||||
if ((dch->state == ISAC_IND_EI) ||
|
||||
(dch->state == ISAC_IND_DR) ||
|
||||
(dch->state == ISAC_IND_RS))
|
||||
ph_command(dch, ISAC_CMD_TIM);
|
||||
else
|
||||
ph_command(dch, ISAC_CMD_RS);
|
||||
} else if (hh->dinfo == HW_POWERUP) {
|
||||
ph_command(dch, ISAC_CMD_TIM);
|
||||
} else if (hh->dinfo == HW_DEACTIVATE) {
|
||||
discard_queue(&dch->rqueue);
|
||||
if (dch->next_skb) {
|
||||
dev_kfree_skb(dch->next_skb);
|
||||
dch->next_skb = NULL;
|
||||
}
|
||||
test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags);
|
||||
test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags);
|
||||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
dchannel_sched_event(dch, D_CLEARBUSY);
|
||||
test_and_clear_bit(FLG_TX_NEXT, &dch->Flags);
|
||||
test_and_clear_bit(FLG_TX_BUSY, &dch->Flags);
|
||||
if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags))
|
||||
del_timer(&dch->timer);
|
||||
} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
|
||||
u_char tl;
|
||||
if (dch->type & ISAC_TYPE_ISACSX) {
|
||||
|
@ -646,19 +635,19 @@ mISDN_ISAC_l1hw(mISDNif_t *hif, struct sk_buff *skb)
|
|||
if (ISAC_TYPE_IOM1 & dch->type) {
|
||||
/* IOM 1 Mode */
|
||||
if (!tl) {
|
||||
dch->write_reg(dch->inst.data, ISAC_SPCR, 0xa);
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0x2);
|
||||
dch->write_reg(dch->inst.privat, ISAC_SPCR, 0xa);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x2);
|
||||
} else {
|
||||
dch->write_reg(dch->inst.data, ISAC_SPCR, tl);
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0xa);
|
||||
dch->write_reg(dch->inst.privat, ISAC_SPCR, tl);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF1, 0xa);
|
||||
}
|
||||
} else {
|
||||
/* IOM 2 Mode */
|
||||
dch->write_reg(dch->inst.data, ISAC_SPCR, tl);
|
||||
dch->write_reg(dch->inst.privat, ISAC_SPCR, tl);
|
||||
if (tl)
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0x8);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x8);
|
||||
else
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0x0);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -667,8 +656,21 @@ mISDN_ISAC_l1hw(mISDNif_t *hif, struct sk_buff *skb)
|
|||
hh->dinfo);
|
||||
ret = -EINVAL;
|
||||
}
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
} else {
|
||||
spin_unlock_irqrestore(inst->hwlock, flags);
|
||||
} else if (hh->prim == (PH_SIGNAL | INDICATION)) {
|
||||
#if ARCOFI_USE
|
||||
if ((ISAC_TYPE_ARCOFI & dch->type)) {
|
||||
if (hh->dinfo == D_RX_MON1) {
|
||||
arcofi_fsm(dch, ARCOFI_RX_END, skb);
|
||||
} else if (hh->dinfo == D_TX_MON1) {
|
||||
arcofi_fsm(dch, ARCOFI_TX_END, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ret = 0;
|
||||
} else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS)
|
||||
ret = -EAGAIN;
|
||||
else {
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
mISDN_debugprint(&dch->inst, "isac_l1hw unknown prim %x",
|
||||
hh->prim);
|
||||
|
@ -680,53 +682,39 @@ mISDN_ISAC_l1hw(mISDNif_t *hif, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
void
|
||||
mISDN_isac_free(dchannel_t *dch) {
|
||||
mISDN_isac_free(channel_t *dch) {
|
||||
isac_chip_t *isac = dch->hw;
|
||||
|
||||
if (dch->dbusytimer.function != NULL) {
|
||||
del_timer(&dch->dbusytimer);
|
||||
dch->dbusytimer.function = NULL;
|
||||
if (dch->timer.function != NULL) {
|
||||
del_timer(&dch->timer);
|
||||
dch->timer.function = NULL;
|
||||
}
|
||||
if (!isac)
|
||||
return;
|
||||
if (isac->mon_rx) {
|
||||
kfree(isac->mon_rx);
|
||||
isac->mon_rx = NULL;
|
||||
}
|
||||
if (isac->mon_tx) {
|
||||
kfree(isac->mon_tx);
|
||||
isac->mon_tx = NULL;
|
||||
}
|
||||
kfree(isac->mon_rx);
|
||||
isac->mon_rx = NULL;
|
||||
kfree(isac->mon_tx);
|
||||
isac->mon_tx = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
dbusy_timer_handler(dchannel_t *dch)
|
||||
dbusy_timer_handler(channel_t *dch)
|
||||
{
|
||||
int rbch, star;
|
||||
u_long flags;
|
||||
|
||||
if (test_bit(FLG_DBUSY_TIMER, &dch->DFlags)) {
|
||||
if (dch->inst.lock(dch->inst.data, 1)) {
|
||||
dch->dbusytimer.expires = jiffies + 1;
|
||||
add_timer(&dch->dbusytimer);
|
||||
return;
|
||||
}
|
||||
rbch = dch->read_reg(dch->inst.data, ISAC_RBCH);
|
||||
star = dch->read_reg(dch->inst.data, ISAC_STAR);
|
||||
if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) {
|
||||
spin_lock_irqsave(dch->inst.hwlock, flags);
|
||||
rbch = dch->read_reg(dch->inst.privat, ISAC_RBCH);
|
||||
star = dch->read_reg(dch->inst.privat, ISAC_STAR);
|
||||
if (dch->debug)
|
||||
mISDN_debugprint(&dch->inst, "D-Channel Busy RBCH %02x STAR %02x",
|
||||
rbch, star);
|
||||
if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */
|
||||
test_and_set_bit(FLG_L1_DBUSY, &dch->DFlags);
|
||||
#if 0
|
||||
stptr = dch->stlist;
|
||||
while (stptr != NULL) {
|
||||
stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
|
||||
stptr = stptr->next;
|
||||
}
|
||||
#endif
|
||||
test_and_set_bit(FLG_L1_BUSY, &dch->Flags);
|
||||
} else {
|
||||
/* discard frame; reset transceiver */
|
||||
test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags);
|
||||
test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags);
|
||||
if (dch->tx_idx) {
|
||||
dch->tx_idx = 0;
|
||||
} else {
|
||||
|
@ -734,9 +722,9 @@ dbusy_timer_handler(dchannel_t *dch)
|
|||
mISDN_debugprint(&dch->inst, "D-Channel Busy no tx_idx");
|
||||
}
|
||||
/* Transmitter reset */
|
||||
dch->write_reg(dch->inst.data, ISAC_CMDR, 0x01);
|
||||
dch->write_reg(dch->inst.privat, ISAC_CMDR, 0x01);
|
||||
}
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
spin_unlock_irqrestore(dch->inst.hwlock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,7 +733,7 @@ static char *ISACVer[] =
|
|||
"2085 V2.3"};
|
||||
|
||||
int
|
||||
mISDN_isac_init(dchannel_t *dch)
|
||||
mISDN_isac_init(channel_t *dch)
|
||||
{
|
||||
isac_chip_t *isac = dch->hw;
|
||||
u_char val;
|
||||
|
@ -753,60 +741,59 @@ mISDN_isac_init(dchannel_t *dch)
|
|||
|
||||
if (!isac)
|
||||
return(-EINVAL);
|
||||
dch->hw_bh = isac_hwbh;
|
||||
isac->mon_tx = NULL;
|
||||
isac->mon_rx = NULL;
|
||||
dch->dbusytimer.function = (void *) dbusy_timer_handler;
|
||||
dch->dbusytimer.data = (long) dch;
|
||||
init_timer(&dch->dbusytimer);
|
||||
dch->timer.function = (void *) dbusy_timer_handler;
|
||||
dch->timer.data = (long) dch;
|
||||
init_timer(&dch->timer);
|
||||
isac->mocr = 0xaa;
|
||||
if (dch->type & ISAC_TYPE_ISACSX) {
|
||||
// clear LDD
|
||||
dch->write_reg(dch->inst.data, ISACSX_TR_CONF0, 0x00);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_TR_CONF0, 0x00);
|
||||
// enable transmitter
|
||||
dch->write_reg(dch->inst.data, ISACSX_TR_CONF2, 0x00);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_TR_CONF2, 0x00);
|
||||
// transparent mode 0, RAC, stop/go
|
||||
dch->write_reg(dch->inst.data, ISACSX_MODED, 0xc9);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_MODED, 0xc9);
|
||||
// all HDLC IRQ unmasked
|
||||
dch->write_reg(dch->inst.data, ISACSX_MASKD, 0x03);
|
||||
dch->write_reg(dch->inst.privat, ISACSX_MASKD, 0x03);
|
||||
// unmask ICD, CID IRQs
|
||||
dch->write_reg(dch->inst.data, ISACSX_MASK, ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
|
||||
dch->write_reg(dch->inst.privat, ISACSX_MASK, ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC));
|
||||
printk(KERN_INFO "mISDN_isac_init: ISACSX\n");
|
||||
dchannel_sched_event(dch, D_L1STATECHANGE);
|
||||
isac_ph_state_change(dch);
|
||||
ph_command(dch, ISAC_CMD_RS);
|
||||
} else { /* old isac */
|
||||
dch->write_reg(dch->inst.data, ISAC_MASK, 0xff);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_RBCH);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MASK, 0xff);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_RBCH);
|
||||
printk(KERN_INFO "mISDN_isac_init: ISAC version (%x): %s\n", val, ISACVer[(val >> 5) & 3]);
|
||||
dch->type |= ((val >> 5) & 3);
|
||||
if (ISAC_TYPE_IOM1 & dch->type) {
|
||||
/* IOM 1 Mode */
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF2, 0x0);
|
||||
dch->write_reg(dch->inst.data, ISAC_SPCR, 0xa);
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0x2);
|
||||
dch->write_reg(dch->inst.data, ISAC_STCR, 0x70);
|
||||
dch->write_reg(dch->inst.data, ISAC_MODE, 0xc9);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF2, 0x0);
|
||||
dch->write_reg(dch->inst.privat, ISAC_SPCR, 0xa);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x2);
|
||||
dch->write_reg(dch->inst.privat, ISAC_STCR, 0x70);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MODE, 0xc9);
|
||||
} else {
|
||||
/* IOM 2 Mode */
|
||||
if (!isac->adf2)
|
||||
isac->adf2 = 0x80;
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF2, isac->adf2);
|
||||
dch->write_reg(dch->inst.data, ISAC_SQXR, 0x2f);
|
||||
dch->write_reg(dch->inst.data, ISAC_SPCR, 0x00);
|
||||
dch->write_reg(dch->inst.data, ISAC_STCR, 0x70);
|
||||
dch->write_reg(dch->inst.data, ISAC_MODE, 0xc9);
|
||||
dch->write_reg(dch->inst.data, ISAC_TIMR, 0x00);
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0x00);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF2, isac->adf2);
|
||||
dch->write_reg(dch->inst.privat, ISAC_SQXR, 0x2f);
|
||||
dch->write_reg(dch->inst.privat, ISAC_SPCR, 0x00);
|
||||
dch->write_reg(dch->inst.privat, ISAC_STCR, 0x70);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MODE, 0xc9);
|
||||
dch->write_reg(dch->inst.privat, ISAC_TIMR, 0x00);
|
||||
dch->write_reg(dch->inst.privat, ISAC_ADF1, 0x00);
|
||||
}
|
||||
dchannel_sched_event(dch, D_L1STATECHANGE);
|
||||
isac_ph_state_change(dch);
|
||||
ph_command(dch, ISAC_CMD_RS);
|
||||
dch->write_reg(dch->inst.data, ISAC_MASK, 0x0);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MASK, 0x0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
mISDN_clear_isac(dchannel_t *dch)
|
||||
mISDN_clear_isac(channel_t *dch)
|
||||
{
|
||||
isac_chip_t *isac = dch->hw;
|
||||
u_int val, eval;
|
||||
|
@ -814,22 +801,22 @@ mISDN_clear_isac(dchannel_t *dch)
|
|||
if (!isac)
|
||||
return;
|
||||
/* Disable all IRQ */
|
||||
dch->write_reg(dch->inst.data, ISAC_MASK, 0xFF);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_STAR);
|
||||
dch->write_reg(dch->inst.privat, ISAC_MASK, 0xFF);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_STAR);
|
||||
mISDN_debugprint(&dch->inst, "ISAC STAR %x", val);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_MODE);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_MODE);
|
||||
mISDN_debugprint(&dch->inst, "ISAC MODE %x", val);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_ADF2);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_ADF2);
|
||||
mISDN_debugprint(&dch->inst, "ISAC ADF2 %x", val);
|
||||
val = dch->read_reg(dch->inst.data, ISAC_ISTA);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_ISTA);
|
||||
mISDN_debugprint(&dch->inst, "ISAC ISTA %x", val);
|
||||
if (val & 0x01) {
|
||||
eval = dch->read_reg(dch->inst.data, ISAC_EXIR);
|
||||
eval = dch->read_reg(dch->inst.privat, ISAC_EXIR);
|
||||
mISDN_debugprint(&dch->inst, "ISAC EXIR %x", eval);
|
||||
}
|
||||
val = dch->read_reg(dch->inst.data, ISAC_CIR0);
|
||||
val = dch->read_reg(dch->inst.privat, ISAC_CIR0);
|
||||
mISDN_debugprint(&dch->inst, "ISAC CIR0 %x", val);
|
||||
dch->ph_state = (val >> 2) & 0xf;
|
||||
dch->state = (val >> 2) & 0xf;
|
||||
}
|
||||
|
||||
#ifdef MODULE
|
||||
|
|
|
@ -128,9 +128,9 @@ typedef struct isac_chip {
|
|||
|
||||
/* interface for the isac module */
|
||||
|
||||
extern int mISDN_isac_init(dchannel_t *);
|
||||
extern void mISDN_isac_free(dchannel_t *);
|
||||
extern int mISDN_isac_init(channel_t *);
|
||||
extern void mISDN_isac_free(channel_t *);
|
||||
|
||||
extern void mISDN_isac_interrupt(dchannel_t *, u_char);
|
||||
extern void mISDN_clear_isac(dchannel_t *);
|
||||
extern int mISDN_ISAC_l1hw(mISDNif_t *, struct sk_buff *);
|
||||
extern void mISDN_isac_interrupt(channel_t *, u_char);
|
||||
extern void mISDN_clear_isac(channel_t *);
|
||||
extern int mISDN_ISAC_l1hw(mISDNinstance_t *, struct sk_buff *);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -230,9 +230,9 @@ typedef struct _isar_hw {
|
|||
#define STFAX_ESCAPE 5
|
||||
#define STFAX_SILDET 6
|
||||
|
||||
extern int ISARVersion(bchannel_t *bch, char *s);
|
||||
extern void isar_int_main(bchannel_t *bch);
|
||||
extern int init_isar(bchannel_t *bch);
|
||||
extern void free_isar(bchannel_t *bch);
|
||||
extern int isar_down(mISDNif_t *, struct sk_buff *);
|
||||
extern int isar_load_firmware(bchannel_t *bch, u_char *buf, int size);
|
||||
extern int ISARVersion(channel_t *bch, char *s);
|
||||
extern void isar_int_main(channel_t *bch);
|
||||
extern int init_isar(channel_t *bch);
|
||||
extern void free_isar(channel_t *bch);
|
||||
extern int isar_down(mISDNinstance_t *, struct sk_buff *);
|
||||
extern int isar_load_firmware(channel_t *bch, u_char *buf, int size);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -77,10 +77,10 @@ mISDN_alloc_l3msg(int len, u_char type)
|
|||
|
||||
void mISDN_AddvarIE(struct sk_buff *skb, u_char *ie)
|
||||
{
|
||||
u_char *p, *ps;
|
||||
u16 *ies;
|
||||
int l;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
u_char *p, *ps;
|
||||
ie_info_t *ies;
|
||||
int l;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
|
||||
ies = &qi->bearer_capability;
|
||||
ps = (u_char *) qi;
|
||||
|
@ -96,6 +96,10 @@ void mISDN_AddvarIE(struct sk_buff *skb, u_char *ie)
|
|||
int_error();
|
||||
return;
|
||||
}
|
||||
if (ies->off) { /* already used, no dupes for single octett */
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
l = 1;
|
||||
} else {
|
||||
if (_mISDN_l3_ie2pos[*ie]<0) {
|
||||
|
@ -103,19 +107,34 @@ void mISDN_AddvarIE(struct sk_buff *skb, u_char *ie)
|
|||
return;
|
||||
}
|
||||
ies += _mISDN_l3_ie2pos[*ie];
|
||||
if (ies->off) {
|
||||
if (ies->repeated)
|
||||
ies = mISDN_get_last_repeated_ie(qi, ies);
|
||||
l = mISDN_get_free_ext_ie(qi);
|
||||
if (l < 0) { // overflow
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
ies->ridx = l;
|
||||
ies->repeated = 1;
|
||||
ies = &qi->ext[l].ie;
|
||||
ies->cs_flg = 0;
|
||||
qi->ext[l].v.codeset = 0;
|
||||
qi->ext[l].v.val = *ie;
|
||||
}
|
||||
l = ie[1] + 2;
|
||||
}
|
||||
p = skb_put(skb, l);
|
||||
*ies = (u16)(p - ps);
|
||||
ies->off = (u16)(p - ps);
|
||||
memcpy(p, ie, l);
|
||||
}
|
||||
|
||||
void mISDN_AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
|
||||
{
|
||||
u_char *p, *ps;
|
||||
u16 *ies;
|
||||
int l;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
u_char *p, *ps;
|
||||
ie_info_t *ies;
|
||||
int l;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
|
||||
if (ie & 0x80) { /* one octett IE */
|
||||
if (ie == IE_MORE_DATA)
|
||||
|
@ -128,6 +147,10 @@ void mISDN_AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
|
|||
int_error();
|
||||
return;
|
||||
}
|
||||
if (ies->off) { /* already used, no dupes for single octett */
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
l = 0;
|
||||
} else {
|
||||
if (!iep || !iep[0])
|
||||
|
@ -138,21 +161,55 @@ void mISDN_AddIE(struct sk_buff *skb, u_char ie, u_char *iep)
|
|||
return;
|
||||
}
|
||||
ies += _mISDN_l3_ie2pos[ie];
|
||||
if (ies->off) {
|
||||
if (ies->repeated)
|
||||
ies = mISDN_get_last_repeated_ie(qi, ies);
|
||||
l = mISDN_get_free_ext_ie(qi);
|
||||
if (l < 0) { // overflow
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
ies->ridx = l;
|
||||
ies->repeated = 1;
|
||||
ies = &qi->ext[l].ie;
|
||||
ies->cs_flg = 0;
|
||||
qi->ext[l].v.codeset = 0;
|
||||
qi->ext[l].v.val = ie;
|
||||
}
|
||||
l = iep[0] + 1;
|
||||
}
|
||||
ps = (u_char *) qi;
|
||||
ps += L3_EXTRA_SIZE;
|
||||
p = skb_put(skb, l+1);
|
||||
*ies = (u16)(p - ps);
|
||||
ies->off = (u16)(p - ps);
|
||||
*p++ = ie;
|
||||
if (l)
|
||||
memcpy(p, iep, l);
|
||||
}
|
||||
|
||||
ie_info_t *mISDN_get_last_repeated_ie(Q931_info_t *qi, ie_info_t *ie)
|
||||
{
|
||||
while(ie->repeated) {
|
||||
ie = &qi->ext[ie->ridx].ie;
|
||||
}
|
||||
return(ie);
|
||||
}
|
||||
|
||||
int mISDN_get_free_ext_ie(Q931_info_t *qi)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (qi->ext[i].ie.off == 0)
|
||||
return(i);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
void mISDN_LogL3Msg(struct sk_buff *skb)
|
||||
{
|
||||
u_char *p,*ps, *t, tmp[32];
|
||||
u16 *ies;
|
||||
u_char *p,*ps, *t, tmp[128];
|
||||
ie_info_t *ies;
|
||||
int i,j;
|
||||
Q931_info_t *qi = (Q931_info_t *)skb->data;
|
||||
mISDN_head_t *hh;
|
||||
|
@ -168,18 +225,49 @@ void mISDN_LogL3Msg(struct sk_buff *skb)
|
|||
printk(KERN_DEBUG "L3Msg type(%02x) qi(%p) ies(%p) ps(%p)\n",
|
||||
qi->type, qi, ies, ps);
|
||||
for (i=0;i<32;i++) {
|
||||
if (ies[i]) {
|
||||
p = ps + ies[i];
|
||||
if (ies[i].off) {
|
||||
p = ps + ies[i].off;
|
||||
t = tmp;
|
||||
*t = 0;
|
||||
for (j=0; j<p[1]; j++) {
|
||||
if (j>9) {
|
||||
if (j>40) {
|
||||
sprintf(t, " ...");
|
||||
break;
|
||||
}
|
||||
t += sprintf(t, " %02x", p[j+2]);
|
||||
}
|
||||
printk(KERN_DEBUG "L3Msg ies[%d] off(%d) ie(%02x/%02x) len(%d) %s\n",
|
||||
i, ies[i], _mISDN_l3_pos2ie[i], *p, p[1], tmp);
|
||||
printk(KERN_DEBUG "L3Msg ies[%d] off(%d) rep(%d) ridx(%d) ie(%02x/%02x) len(%d)%s\n",
|
||||
i, ies[i].off, ies[i].repeated, ies[i].ridx, _mISDN_l3_pos2ie[i], *p, p[1], tmp);
|
||||
}
|
||||
}
|
||||
for (i=0;i<8;i++) {
|
||||
if (qi->ext[i].ie.off) {
|
||||
p = ps + qi->ext[i].ie.off;
|
||||
t = tmp;
|
||||
*t = 0;
|
||||
if (qi->ext[i].ie.cs_flg) {
|
||||
for (j=0; j<qi->ext[i].cs.len; j++) {
|
||||
if (j>40) {
|
||||
sprintf(t, " ...");
|
||||
break;
|
||||
}
|
||||
t += sprintf(t, " %02x", p[j]);
|
||||
}
|
||||
printk(KERN_DEBUG "L3Msg ext[%d] off(%d) locked(%d) cs(%d) len(%d)%s\n",
|
||||
i, qi->ext[i].ie.off, qi->ext[i].cs.locked, qi->ext[i].cs.codeset,
|
||||
qi->ext[i].cs.len, tmp);
|
||||
} else {
|
||||
for (j=0; j<p[1]; j++) {
|
||||
if (j>40) {
|
||||
sprintf(t, " ...");
|
||||
break;
|
||||
}
|
||||
t += sprintf(t, " %02x", p[j+2]);
|
||||
}
|
||||
printk(KERN_DEBUG "L3Msg ext[%d] off(%d) rep(%d) ridx(%d) cs(%d) ie(%02x/%02x) len(%d) %s\n",
|
||||
i, qi->ext[i].ie.off, qi->ext[i].ie.repeated, qi->ext[i].ie.ridx,
|
||||
qi->ext[i].v.codeset, qi->ext[i].v.val, *p, p[1], tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,4 +282,6 @@ EXPORT_SYMBOL(mISDN_alloc_l3msg);
|
|||
#endif
|
||||
EXPORT_SYMBOL(mISDN_AddvarIE);
|
||||
EXPORT_SYMBOL(mISDN_AddIE);
|
||||
EXPORT_SYMBOL(mISDN_get_last_repeated_ie);
|
||||
EXPORT_SYMBOL(mISDN_get_free_ext_ie);
|
||||
EXPORT_SYMBOL(mISDN_LogL3Msg);
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
/* $Id$
|
||||
*
|
||||
* mISDN_l1.c common low level stuff for I.430 layer1
|
||||
* mISDN_l1.c common low level stuff for I.430 layer1 TE mode
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
* For changes and modifications please read
|
||||
* ../../../Documentation/isdn/mISDN.cert
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -46,9 +44,11 @@ static mISDNobject_t isdnl1;
|
|||
|
||||
#define TIMER3_VALUE 7000
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static
|
||||
struct Fsm l1fsm_b =
|
||||
{NULL, 0, 0, NULL, NULL};
|
||||
#endif
|
||||
|
||||
static
|
||||
struct Fsm l1fsm_s =
|
||||
|
@ -100,6 +100,7 @@ static char *strL1UState[] =
|
|||
};
|
||||
#endif
|
||||
|
||||
#ifdef OBSOLETE
|
||||
enum {
|
||||
ST_L1_NULL,
|
||||
ST_L1_WAIT_ACT,
|
||||
|
@ -116,7 +117,7 @@ static char *strL1BState[] =
|
|||
"ST_L1_WAIT_DEACT",
|
||||
"ST_L1_ACTIV",
|
||||
};
|
||||
|
||||
#endif
|
||||
enum {
|
||||
EV_PH_ACTIVATE,
|
||||
EV_PH_DEACTIVATE,
|
||||
|
@ -124,7 +125,7 @@ enum {
|
|||
EV_DEACT_CNF,
|
||||
EV_DEACT_IND,
|
||||
EV_POWER_UP,
|
||||
EV_ANYSIG_IND,
|
||||
EV_ANYSIG_IND,
|
||||
EV_INFO2_IND,
|
||||
EV_INFO4_IND,
|
||||
EV_TIMER_DEACT,
|
||||
|
@ -142,7 +143,7 @@ static char *strL1Event[] =
|
|||
"EV_DEACT_CNF",
|
||||
"EV_DEACT_IND",
|
||||
"EV_POWER_UP",
|
||||
"EV_ANYSIG_IND",
|
||||
"EV_ANYSIG_IND",
|
||||
"EV_INFO2_IND",
|
||||
"EV_INFO4_IND",
|
||||
"EV_TIMER_DEACT",
|
||||
|
@ -166,13 +167,13 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...)
|
|||
static int
|
||||
l1up(layer1_t *l1, u_int prim, int dinfo, int len, void *arg)
|
||||
{
|
||||
return(if_link(&l1->inst.up, prim, dinfo, len, arg, 0));
|
||||
return(mISDN_queue_data(&l1->inst, FLG_MSG_UP, prim, dinfo, len, arg, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
l1down(layer1_t *l1, u_int prim, int dinfo, int len, void *arg)
|
||||
{
|
||||
return(if_link(&l1->inst.down, prim, dinfo, len, arg, 0));
|
||||
return(mISDN_queue_data(&l1->inst, FLG_MSG_DOWN, prim, dinfo, len, arg, 0));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -209,8 +210,6 @@ l1_power_up_s(struct FsmInst *fi, int event, void *arg)
|
|||
if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
|
||||
mISDN_FsmChangeState(fi, ST_L1_F4);
|
||||
l1down(l1, PH_SIGNAL | REQUEST, INFO3_P8, 0, NULL);
|
||||
mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
|
||||
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
|
||||
} else
|
||||
mISDN_FsmChangeState(fi, ST_L1_F3);
|
||||
}
|
||||
|
@ -269,11 +268,14 @@ l1_timer3(struct FsmInst *fi, int event, void *arg)
|
|||
layer1_t *l1 = fi->userdata;
|
||||
u_int db = HW_D_NOBLOCKED;
|
||||
|
||||
test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags);
|
||||
test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags);
|
||||
if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) {
|
||||
if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))
|
||||
l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
|
||||
l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
|
||||
mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
#ifdef mISDN_UINTERFACE
|
||||
if (!test_bit(FLG_L1_UINT, &l1->Flags))
|
||||
|
@ -295,6 +297,9 @@ l1_timer_act(struct FsmInst *fi, int event, void *arg)
|
|||
l1up(l1, PH_ACTIVATE | CONFIRM, 0, 0, NULL);
|
||||
else
|
||||
l1up(l1, PH_ACTIVATE | INDICATION, 0, 0, NULL);
|
||||
mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_ACTIVATED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -309,6 +314,9 @@ l1_timer_deact(struct FsmInst *fi, int event, void *arg)
|
|||
l1up(l1, PH_CONTROL | INDICATION, 0, 4, &db);
|
||||
l1up(l1, PH_DEACTIVATE | INDICATION, 0, 0, NULL);
|
||||
l1down(l1, PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL);
|
||||
mISDN_queue_data(&l1->inst, l1->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L1_DEACTIVATED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -316,6 +324,8 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer1_t *l1 = fi->userdata;
|
||||
|
||||
mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
|
||||
test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);
|
||||
l1down(l1, PH_CONTROL | REQUEST, HW_RESET, 0, NULL);
|
||||
}
|
||||
|
||||
|
@ -443,7 +453,7 @@ static struct FsmNode L1UFnList[] =
|
|||
#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static void
|
||||
l1b_activate(struct FsmInst *fi, int event, void *arg)
|
||||
{
|
||||
|
@ -489,26 +499,17 @@ static struct FsmNode L1BFnList[] =
|
|||
};
|
||||
|
||||
#define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
|
||||
#endif
|
||||
|
||||
static int
|
||||
l1from_up(mISDNif_t *hif, struct sk_buff *skb)
|
||||
l1from_up(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
layer1_t *l1;
|
||||
mISDN_head_t *hh;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
l1 = hif->fdata;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
switch(hh->prim) {
|
||||
case (PH_DATA | REQUEST):
|
||||
case (PH_CONTROL | REQUEST):
|
||||
if (l1->inst.down.func)
|
||||
return(l1->inst.down.func(&l1->inst.down,
|
||||
skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
return(mISDN_queue_down(&l1->inst, 0, skb));
|
||||
break;
|
||||
case (PH_ACTIVATE | REQUEST):
|
||||
if (test_bit(FLG_L1_ACTIVATED, &l1->Flags))
|
||||
|
@ -519,10 +520,7 @@ l1from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
}
|
||||
break;
|
||||
case (MDL_FINDTEI | REQUEST):
|
||||
if (l1->inst.up.func)
|
||||
return(l1->inst.up.func(&l1->inst.up, skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
return(mISDN_queue_up(&l1->inst, 0, skb));
|
||||
break;
|
||||
default:
|
||||
if (l1->debug)
|
||||
|
@ -537,28 +535,16 @@ l1from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static int
|
||||
l1from_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
l1from_down(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
layer1_t *l1;
|
||||
mISDN_head_t *hh;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
l1 = hif->fdata;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
if (hh->prim == PH_DATA_IND) {
|
||||
if (test_bit(FLG_L1_ACTTIMER, &l1->Flags))
|
||||
mISDN_FsmEvent(&l1->l1m, EV_TIMER_ACT, NULL);
|
||||
if (l1->inst.up.func)
|
||||
return(l1->inst.up.func(&l1->inst.up, skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
return(mISDN_queue_up(&l1->inst, 0, skb));
|
||||
} else if (hh->prim == PH_DATA_CNF) {
|
||||
if (l1->inst.up.func)
|
||||
return(l1->inst.up.func(&l1->inst.up, skb));
|
||||
else
|
||||
err = -ENXIO;
|
||||
return(mISDN_queue_up(&l1->inst, 0, skb));
|
||||
} else if (hh->prim == (PH_CONTROL | INDICATION)) {
|
||||
if (hh->dinfo == HW_RESET)
|
||||
mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL);
|
||||
|
@ -570,7 +556,7 @@ l1from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
mISDN_debug(l1->inst.st->id, NULL,
|
||||
"l1from_down ctrl ind %x unhandled", hh->dinfo);
|
||||
} else if (hh->prim == (PH_CONTROL | CONFIRM)) {
|
||||
if (hh->dinfo == HW_DEACTIVATE)
|
||||
if (hh->dinfo == HW_DEACTIVATE)
|
||||
mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);
|
||||
else if (l1->debug)
|
||||
mISDN_debug(l1->inst.st->id, NULL,
|
||||
|
@ -600,11 +586,67 @@ l1from_down(mISDNif_t *hif, struct sk_buff *skb)
|
|||
return(err);
|
||||
}
|
||||
|
||||
static int
|
||||
l1_shortstatus(layer1_t *l1, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
u_int temp;
|
||||
|
||||
if (hh->prim == (MGR_SHORTSTATUS | REQUEST)) {
|
||||
temp = hh->dinfo & SSTATUS_ALL;
|
||||
if (temp == SSTATUS_ALL || temp == SSTATUS_L1) {
|
||||
skb_trim(skb, 0);
|
||||
if (hh->dinfo & SSTATUS_BROADCAST_BIT)
|
||||
temp = l1->inst.id | MSG_BROADCAST;
|
||||
else
|
||||
temp = hh->addr | FLG_MSG_TARGET;
|
||||
hh->dinfo = (l1->l1m.state == ST_L1_F7) ?
|
||||
SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED;
|
||||
hh->prim = MGR_SHORTSTATUS | CONFIRM;
|
||||
return(mISDN_queue_message(&l1->inst, temp, skb));
|
||||
}
|
||||
}
|
||||
return(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static int
|
||||
l1_function(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
layer1_t *l1 = inst->privat;
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(skb);
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (debug)
|
||||
printk(KERN_DEBUG "%s: addr(%08x) prim(%x)\n", __FUNCTION__, hh->addr, hh->prim);
|
||||
|
||||
if (unlikely((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS))
|
||||
return(l1_shortstatus(l1, skb, hh));
|
||||
|
||||
switch(hh->addr & MSG_DIR_MASK) {
|
||||
case FLG_MSG_DOWN:
|
||||
ret = l1from_up(l1, skb, hh);
|
||||
break;
|
||||
case FLG_MSG_UP:
|
||||
ret = l1from_down(l1, skb, hh);
|
||||
break;
|
||||
case MSG_TO_OWNER:
|
||||
/* FIXME: must be handled depending on type */
|
||||
int_errtxt("not implemented yet");
|
||||
break;
|
||||
default:
|
||||
/* FIXME: must be handled depending on type */
|
||||
int_errtxt("not implemented yet");
|
||||
break;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
release_l1(layer1_t *l1) {
|
||||
mISDNinstance_t *inst = &l1->inst;
|
||||
u_long flags;
|
||||
|
||||
mISDN_FsmDelTimer(&l1->timer, 0);
|
||||
#ifdef OBSOLETE
|
||||
if (inst->up.peer) {
|
||||
inst->up.peer->obj->ctrl(inst->up.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
|
@ -613,15 +655,19 @@ release_l1(layer1_t *l1) {
|
|||
inst->down.peer->obj->ctrl(inst->down.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->down);
|
||||
}
|
||||
#endif
|
||||
spin_lock_irqsave(&isdnl1.lock, flags);
|
||||
list_del(&l1->list);
|
||||
spin_unlock_irqrestore(&isdnl1.lock, flags);
|
||||
isdnl1.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
kfree(l1);
|
||||
}
|
||||
|
||||
static int
|
||||
new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
|
||||
layer1_t *nl1;
|
||||
int err;
|
||||
layer1_t *nl1;
|
||||
int err;
|
||||
u_long flags;
|
||||
|
||||
if (!st || !pid)
|
||||
return(-EINVAL);
|
||||
|
@ -631,14 +677,14 @@ new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
|
|||
}
|
||||
memset(nl1, 0, sizeof(layer1_t));
|
||||
memcpy(&nl1->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
mISDN_init_instance(&nl1->inst, &isdnl1, nl1);
|
||||
mISDN_init_instance(&nl1->inst, &isdnl1, nl1, l1_function);
|
||||
if (!mISDN_SetHandledPID(&isdnl1, &nl1->inst.pid)) {
|
||||
int_error();
|
||||
return(-ENOPROTOOPT);
|
||||
}
|
||||
switch(pid->protocol[1]) {
|
||||
case ISDN_PID_L1_TE_S0:
|
||||
sprintf(nl1->inst.name, "l1TES0 %d", st->id);
|
||||
sprintf(nl1->inst.name, "l1TES0 %x", st->id >> 8);
|
||||
nl1->l1m.fsm = &l1fsm_s;
|
||||
nl1->l1m.state = ST_L1_F3;
|
||||
nl1->Flags = 0;
|
||||
|
@ -655,7 +701,9 @@ new_l1(mISDNstack_t *st, mISDN_pid_t *pid) {
|
|||
nl1->l1m.userint = 0;
|
||||
nl1->l1m.printdebug = l1m_debug;
|
||||
mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer);
|
||||
spin_lock_irqsave(&isdnl1.lock, flags);
|
||||
list_add_tail(&nl1->list, &isdnl1.ilist);
|
||||
spin_unlock_irqrestore(&isdnl1.lock, flags);
|
||||
err = isdnl1.ctrl(st, MGR_REGLAYER | INDICATION, &nl1->inst);
|
||||
if (err) {
|
||||
mISDN_FsmDelTimer(&nl1->timer, 0);
|
||||
|
@ -701,27 +749,31 @@ l1_manager(void *data, u_int prim, void *arg) {
|
|||
mISDNinstance_t *inst = data;
|
||||
layer1_t *l1l;
|
||||
int err = -EINVAL;
|
||||
u_long flags;
|
||||
|
||||
if (debug & 0x10000)
|
||||
printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n",
|
||||
__FUNCTION__, data, prim, arg);
|
||||
if (!data)
|
||||
return(err);
|
||||
spin_lock_irqsave(&isdnl1.lock, flags);
|
||||
list_for_each_entry(l1l, &isdnl1.ilist, list) {
|
||||
if (&l1l->inst == inst) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&isdnl1.lock, flags);
|
||||
if (err && (prim != (MGR_NEWLAYER | REQUEST))) {
|
||||
printk(KERN_WARNING "l1_manager connect no instance\n");
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
||||
switch(prim) {
|
||||
case MGR_NEWLAYER | REQUEST:
|
||||
err = new_l1(data, arg);
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CONNECT | REQUEST:
|
||||
err = mISDN_ConnectIF(inst, arg);
|
||||
break;
|
||||
|
@ -733,6 +785,7 @@ l1_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | INDICATION:
|
||||
err = mISDN_DisConnectIF(inst, arg);
|
||||
break;
|
||||
#endif
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
case MGR_RELEASE | INDICATION:
|
||||
printk(KERN_DEBUG "release_l1 id %x\n", l1l->inst.st->id);
|
||||
|
@ -762,6 +815,7 @@ int Isdnl1Init(void)
|
|||
isdnl1.name = MName;
|
||||
isdnl1.DPROTO.protocol[1] = ISDN_PID_L1_TE_S0;
|
||||
isdnl1.own_ctrl = l1_manager;
|
||||
spin_lock_init(&isdnl1.lock);
|
||||
INIT_LIST_HEAD(&isdnl1.ilist);
|
||||
#ifdef mISDN_UINTERFACE
|
||||
isdnl1.DPROTO.protocol[1] |= ISDN_PID_L1_TE_U;
|
||||
|
@ -776,18 +830,22 @@ int Isdnl1Init(void)
|
|||
l1fsm_s.strEvent = strL1Event;
|
||||
l1fsm_s.strState = strL1SState;
|
||||
mISDN_FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
|
||||
#ifdef OBSOLETE
|
||||
l1fsm_b.state_count = L1B_STATE_COUNT;
|
||||
l1fsm_b.event_count = L1_EVENT_COUNT;
|
||||
l1fsm_b.strEvent = strL1Event;
|
||||
l1fsm_b.strState = strL1BState;
|
||||
mISDN_FsmNew(&l1fsm_b, L1BFnList, L1B_FN_COUNT);
|
||||
#endif
|
||||
if ((err = mISDN_register(&isdnl1))) {
|
||||
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
|
||||
#ifdef mISDN_UINTERFACE
|
||||
mISDN_FsmFree(&l1fsm_u);
|
||||
#endif
|
||||
mISDN_FsmFree(&l1fsm_s);
|
||||
#ifdef OBSOLETE
|
||||
mISDN_FsmFree(&l1fsm_b);
|
||||
#endif
|
||||
}
|
||||
return(err);
|
||||
}
|
||||
|
@ -810,6 +868,8 @@ void cleanup_module(void)
|
|||
mISDN_FsmFree(&l1fsm_u);
|
||||
#endif
|
||||
mISDN_FsmFree(&l1fsm_s);
|
||||
#ifdef OBSOLETE
|
||||
mISDN_FsmFree(&l1fsm_b);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#ifdef OBSOLETE
|
||||
#define D_RCVBUFREADY 0
|
||||
#define D_XMTBUFREADY 1
|
||||
#define D_L1STATECHANGE 2
|
||||
|
@ -32,6 +33,7 @@
|
|||
#define B_XMTBUFREADY 1
|
||||
#define B_BLOCKEDATOMIC 2
|
||||
#define B_DTMFREADY 3
|
||||
#endif
|
||||
|
||||
#define FLG_L1_ACTIVATING 1
|
||||
#define FLG_L1_ACTIVATED 2
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
* For changes and modifications please read
|
||||
* ../../../Documentation/isdn/mISDN.cert
|
||||
* This file is released under the GPLv2
|
||||
*
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
|
@ -116,14 +114,11 @@ l2addrsize(layer2_t *l2)
|
|||
static int
|
||||
l2_newid(layer2_t *l2)
|
||||
{
|
||||
u_long flags;
|
||||
int id;
|
||||
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
id = l2->next_id++;
|
||||
if (id == 0x7fff)
|
||||
l2->next_id = 1;
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
id |= (l2->entity << 16);
|
||||
return(id);
|
||||
}
|
||||
|
@ -131,22 +126,20 @@ l2_newid(layer2_t *l2)
|
|||
static int
|
||||
l2up(layer2_t *l2, u_int prim, int dinfo, struct sk_buff *skb)
|
||||
{
|
||||
return(if_newhead(&l2->inst.up, prim, dinfo, skb));
|
||||
return(mISDN_queueup_newhead(&l2->inst, 0, prim, dinfo, skb));
|
||||
}
|
||||
|
||||
static int
|
||||
l2up_create(layer2_t *l2, u_int prim, int dinfo, int len, void *arg)
|
||||
{
|
||||
return(if_link(&l2->inst.up, prim, dinfo, len, arg, 0));
|
||||
return(mISDN_queue_data(&l2->inst, FLG_MSG_UP, prim, dinfo, len, arg, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
l2down_skb(layer2_t *l2, struct sk_buff *skb) {
|
||||
mISDNif_t *down = &l2->inst.down;
|
||||
int ret = -ENXIO;
|
||||
int ret;
|
||||
|
||||
if (down->func)
|
||||
ret = down->func(down, skb);
|
||||
ret = mISDN_queue_down(&l2->inst, 0, skb);
|
||||
if (ret && l2->debug)
|
||||
printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret);
|
||||
return(ret);
|
||||
|
@ -189,18 +182,18 @@ l2down_create(layer2_t *l2, u_int prim, int dinfo, int len, void *arg)
|
|||
return(err);
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static int
|
||||
l2_chain_down(mISDNif_t *hif, struct sk_buff *skb) {
|
||||
if (!hif || !hif->fdata)
|
||||
return(-EINVAL);
|
||||
return(l2down_raw(hif->fdata, skb));
|
||||
l2_chain_down(mISDNinstance_t *inst, struct sk_buff *skb) {
|
||||
return(l2down_raw(inst->privat, skb));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ph_data_confirm(mISDNif_t *up, mISDN_head_t *hh, struct sk_buff *skb) {
|
||||
layer2_t *l2 = up->fdata;
|
||||
struct sk_buff *nskb = skb;
|
||||
mISDNif_t *next = up->clone;
|
||||
ph_data_confirm(mISDNinstance_t *inst, mISDN_head_t *hh, struct sk_buff *skb) {
|
||||
layer2_t *l2 = inst->privat;
|
||||
struct sk_buff *nskb = skb;
|
||||
// mISDNif_t *next = up->clone;
|
||||
int ret = -EAGAIN;
|
||||
|
||||
if (test_bit(FLG_L1_BUSY, &l2->flag)) {
|
||||
|
@ -213,8 +206,10 @@ ph_data_confirm(mISDNif_t *up, mISDN_head_t *hh, struct sk_buff *skb) {
|
|||
}
|
||||
} else
|
||||
l2->down_id = MISDN_ID_NONE;
|
||||
#ifdef FIXME
|
||||
if (next)
|
||||
ret = next->func(next, skb);
|
||||
#endif
|
||||
if (ret) {
|
||||
dev_kfree_skb(skb);
|
||||
ret = 0;
|
||||
|
@ -225,8 +220,10 @@ ph_data_confirm(mISDNif_t *up, mISDN_head_t *hh, struct sk_buff *skb) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef FIXME
|
||||
if (ret && next)
|
||||
ret = next->func(next, skb);
|
||||
#endif
|
||||
if (!test_and_set_bit(FLG_L1_BUSY, &l2->flag)) {
|
||||
if ((nskb = skb_dequeue(&l2->down_queue))) {
|
||||
l2->down_id = mISDN_HEAD_DINFO(nskb);
|
||||
|
@ -406,7 +403,7 @@ inline int
|
|||
IsSFrame(u_char * data, layer2_t *l2)
|
||||
{
|
||||
register u_char d = *data;
|
||||
|
||||
|
||||
if (!test_bit(FLG_MOD128, &l2->flag))
|
||||
d &= 0xf;
|
||||
return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
|
||||
|
@ -530,10 +527,8 @@ legalnr(layer2_t *l2, unsigned int nr)
|
|||
static void
|
||||
setva(layer2_t *l2, unsigned int nr)
|
||||
{
|
||||
u_long flags;
|
||||
struct sk_buff *skb;
|
||||
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
while (l2->va != nr) {
|
||||
l2->va++;
|
||||
if(test_bit(FLG_MOD128, &l2->flag))
|
||||
|
@ -547,7 +542,6 @@ setva(layer2_t *l2, unsigned int nr)
|
|||
}
|
||||
l2->sow = (l2->sow + 1) % l2->window;
|
||||
}
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
while((skb =skb_dequeue(&l2->tmp_queue))) {
|
||||
if (l2up(l2, DL_DATA | CONFIRM, mISDN_HEAD_DINFO(skb), skb))
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -658,7 +652,7 @@ l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg)
|
|||
l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'C');
|
||||
else
|
||||
l2mgr(l2, MDL_ERROR | INDICATION, (void *) 'D');
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -695,7 +689,7 @@ static void
|
|||
l2_go_st3(struct FsmInst *fi, int event, void *arg)
|
||||
{
|
||||
dev_kfree_skb((struct sk_buff *)arg);
|
||||
mISDN_FsmChangeState(fi, ST_L2_3);
|
||||
mISDN_FsmChangeState(fi, ST_L2_3);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -801,7 +795,7 @@ l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg)
|
|||
test_and_set_bit(FLG_L3_INIT, &l2->flag);
|
||||
test_and_clear_bit(FLG_PEND_REL, &l2->flag);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
l2_l3_reestablish(struct FsmInst *fi, int event, void *arg)
|
||||
|
@ -858,14 +852,11 @@ l2_start_multi(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer2_t *l2 = fi->userdata;
|
||||
struct sk_buff *skb = arg;
|
||||
u_long flags;
|
||||
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
l2->vs = 0;
|
||||
l2->va = 0;
|
||||
l2->vr = 0;
|
||||
l2->sow = 0;
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
clear_exception(l2);
|
||||
send_uframe(l2, NULL, UA | get_PollFlag(l2, skb), RSP);
|
||||
mISDN_FsmChangeState(fi, ST_L2_7);
|
||||
|
@ -873,6 +864,10 @@ l2_start_multi(struct FsmInst *fi, int event, void *arg)
|
|||
skb_trim(skb, 0);
|
||||
if (l2up(l2, DL_ESTABLISH | INDICATION, 0, skb))
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -899,7 +894,6 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg)
|
|||
layer2_t *l2 = fi->userdata;
|
||||
struct sk_buff *skb = arg;
|
||||
int est = 0;
|
||||
u_long flags;
|
||||
|
||||
send_uframe(l2, skb, UA | get_PollFlag(l2, skb), RSP);
|
||||
|
||||
|
@ -911,18 +905,20 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg)
|
|||
}
|
||||
|
||||
clear_exception(l2);
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
l2->vs = 0;
|
||||
l2->va = 0;
|
||||
l2->vr = 0;
|
||||
l2->sow = 0;
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
mISDN_FsmChangeState(fi, ST_L2_7);
|
||||
stop_t200(l2, 3);
|
||||
mISDN_FsmRestartTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 3);
|
||||
|
||||
if (est)
|
||||
if (est) {
|
||||
l2up_create(l2, DL_ESTABLISH | INDICATION, 0, 0, NULL);
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
if (skb_queue_len(&l2->i_queue) && cansend(l2))
|
||||
mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
|
||||
|
@ -942,6 +938,10 @@ l2_stop_multi(struct FsmInst *fi, int event, void *arg)
|
|||
discard_queue(&l2->i_queue);
|
||||
freewin(l2);
|
||||
lapb_dl_release_l2l3(l2, INDICATION);
|
||||
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -950,7 +950,6 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
|
|||
layer2_t *l2 = fi->userdata;
|
||||
struct sk_buff *skb = arg;
|
||||
int pr=-1;
|
||||
u_long flags;
|
||||
|
||||
if (!get_PollFlag(l2, skb)) {
|
||||
l2_mdl_error_ua(fi, event, arg);
|
||||
|
@ -966,12 +965,10 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
|
|||
pr = DL_ESTABLISH | INDICATION;
|
||||
}
|
||||
stop_t200(l2, 5);
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
l2->vr = 0;
|
||||
l2->vs = 0;
|
||||
l2->va = 0;
|
||||
l2->sow = 0;
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
mISDN_FsmChangeState(fi, ST_L2_7);
|
||||
mISDN_FsmAddTimer(&l2->t203, l2->T203, EV_L2_T203, NULL, 4);
|
||||
if (pr != -1)
|
||||
|
@ -979,6 +976,10 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
|
|||
|
||||
if (skb_queue_len(&l2->i_queue) && cansend(l2))
|
||||
mISDN_FsmEvent(fi, EV_L2_ACK_PULL, NULL);
|
||||
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_ESTABLISHED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -995,6 +996,10 @@ l2_released(struct FsmInst *fi, int event, void *arg)
|
|||
stop_t200(l2, 6);
|
||||
lapb_dl_release_l2l3(l2, CONFIRM);
|
||||
mISDN_FsmChangeState(fi, ST_L2_4);
|
||||
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1036,6 +1041,9 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
|
|||
stop_t200(l2, 8);
|
||||
lapb_dl_release_l2l3(l2, CONFIRM);
|
||||
mISDN_FsmChangeState(fi, ST_L2_4);
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
|
||||
0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1096,9 +1104,7 @@ static void
|
|||
invoke_retransmission(layer2_t *l2, unsigned int nr)
|
||||
{
|
||||
u_int p1;
|
||||
u_long flags;
|
||||
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
if (l2->vs != nr) {
|
||||
while (l2->vs != nr) {
|
||||
(l2->vs)--;
|
||||
|
@ -1116,10 +1122,8 @@ invoke_retransmission(layer2_t *l2, unsigned int nr)
|
|||
printk(KERN_WARNING "%s: windowar[%d] is NULL\n", __FUNCTION__, p1);
|
||||
l2->windowar[p1] = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL);
|
||||
} else
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1221,7 +1225,6 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
|
|||
struct sk_buff *skb = arg;
|
||||
int PollFlag, i;
|
||||
u_int ns, nr;
|
||||
u_long flags;
|
||||
|
||||
i = l2addrsize(l2);
|
||||
if (test_bit(FLG_MOD128, &l2->flag)) {
|
||||
|
@ -1238,7 +1241,6 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
|
|||
if (PollFlag)
|
||||
enquiry_response(l2);
|
||||
} else {
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
if (l2->vr == ns) {
|
||||
l2->vr++;
|
||||
if(test_bit(FLG_MOD128, &l2->flag))
|
||||
|
@ -1246,7 +1248,6 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
|
|||
else
|
||||
l2->vr %= 8;
|
||||
test_and_clear_bit(FLG_REJEXC, &l2->flag);
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
if (PollFlag)
|
||||
enquiry_response(l2);
|
||||
else
|
||||
|
@ -1256,7 +1257,6 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
|
|||
dev_kfree_skb(skb);
|
||||
} else {
|
||||
/* n(s)!=v(r) */
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
dev_kfree_skb(skb);
|
||||
if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
|
||||
if (PollFlag)
|
||||
|
@ -1410,7 +1410,6 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
|
|||
struct sk_buff *skb, *nskb, *oskb;
|
||||
u_char header[MAX_HEADER_LEN];
|
||||
u_int i, p1;
|
||||
u_long flags;
|
||||
|
||||
if (!cansend(l2))
|
||||
return;
|
||||
|
@ -1419,7 +1418,6 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&l2->lock, flags);
|
||||
if(test_bit(FLG_MOD128, &l2->flag))
|
||||
p1 = (l2->vs - l2->va) % 128;
|
||||
else
|
||||
|
@ -1440,7 +1438,6 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
|
|||
header[i++] = (l2->vr << 5) | (l2->vs << 1);
|
||||
l2->vs = (l2->vs + 1) % 8;
|
||||
}
|
||||
spin_unlock_irqrestore(&l2->lock, flags);
|
||||
|
||||
nskb = skb_clone(skb, GFP_ATOMIC);
|
||||
p1 = skb_headroom(nskb);
|
||||
|
@ -1609,6 +1606,9 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg)
|
|||
mISDN_FsmDelTimer(&l2->t203, 19);
|
||||
if (l2up(l2, DL_RELEASE | INDICATION, 0, skb))
|
||||
dev_kfree_skb(skb);
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
|
||||
0, NULL, 0);
|
||||
mISDN_FsmChangeState(fi, ST_L2_1);
|
||||
}
|
||||
|
||||
|
@ -1617,7 +1617,7 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
layer2_t *l2 = fi->userdata;
|
||||
struct sk_buff *skb = arg;
|
||||
|
||||
|
||||
discard_queue(&l2->i_queue);
|
||||
discard_queue(&l2->ui_queue);
|
||||
if (test_and_clear_bit(FLG_ESTAB_PEND, &l2->flag))
|
||||
|
@ -1667,6 +1667,9 @@ l2_persistant_da(struct FsmInst *fi, int event, void *arg)
|
|||
mISDN_FsmDelTimer(&l2->t203, 19);
|
||||
if (l2up(l2, DL_RELEASE | INDICATION, 0, skb))
|
||||
dev_kfree_skb(skb);
|
||||
mISDN_queue_data(&l2->inst, l2->inst.id | MSG_BROADCAST,
|
||||
MGR_SHORTSTATUS | INDICATION, SSTATUS_L2_RELEASED,
|
||||
0, NULL, 0);
|
||||
mISDN_FsmChangeState(fi, ST_L2_4);
|
||||
}
|
||||
|
||||
|
@ -1818,7 +1821,7 @@ ph_data_indication(layer2_t *l2, mISDN_head_t *hh, struct sk_buff *skb) {
|
|||
u_int l;
|
||||
int c = 0;
|
||||
|
||||
|
||||
|
||||
l = l2addrsize(l2);
|
||||
if (skb->len <= l) {
|
||||
mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *) 'N');
|
||||
|
@ -1833,15 +1836,24 @@ ph_data_indication(layer2_t *l2, mISDN_head_t *hh, struct sk_buff *skb) {
|
|||
}
|
||||
psapi >>= 2;
|
||||
ptei >>= 1;
|
||||
if ((psapi != l2->sapi) && (psapi != TEI_SAPI))
|
||||
return(ret);
|
||||
if ((psapi != l2->sapi) && (psapi != TEI_SAPI)) {
|
||||
/* not our bussiness */
|
||||
// printk(KERN_DEBUG "%s: sapi %d/%d sapi mismatch\n", __FUNCTION__,
|
||||
// psapi, l2->sapi);
|
||||
dev_kfree_skb(skb);
|
||||
return(0);
|
||||
}
|
||||
if (ptei == GROUP_TEI) {
|
||||
if (psapi == TEI_SAPI) {
|
||||
hh->prim = MDL_UNITDATA | INDICATION;
|
||||
return(l2_tei(l2->tm, skb));
|
||||
}
|
||||
} else if ((ptei != l2->tei) || (psapi == TEI_SAPI)) {
|
||||
return(ret);
|
||||
/* not our bussiness */
|
||||
// printk(KERN_DEBUG "%s: tei %d/%d sapi %d mismatch\n", __FUNCTION__,
|
||||
// ptei, l2->tei, psapi);
|
||||
dev_kfree_skb(skb);
|
||||
return(0);
|
||||
}
|
||||
} else
|
||||
datap += l;
|
||||
|
@ -1880,27 +1892,14 @@ ph_data_indication(layer2_t *l2, mISDN_head_t *hh, struct sk_buff *skb) {
|
|||
}
|
||||
|
||||
static int
|
||||
l2from_down(mISDNif_t *hif, struct sk_buff *askb)
|
||||
l2from_down(layer2_t *l2, struct sk_buff *askb, mISDN_head_t *hh)
|
||||
{
|
||||
layer2_t *l2;
|
||||
int ret = -EINVAL;
|
||||
struct sk_buff *cskb = askb;
|
||||
mISDNif_t *next;
|
||||
mISDN_head_t *hh, sh;
|
||||
|
||||
if (!hif || !askb)
|
||||
return(-EINVAL);
|
||||
l2 = hif->fdata;
|
||||
hh = mISDN_HEAD_P(askb);
|
||||
next = hif->clone;
|
||||
// printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim);
|
||||
if (!l2) {
|
||||
if (next && next->func)
|
||||
ret = next->func(next, askb);
|
||||
return(ret);
|
||||
}
|
||||
if (hh->prim == (PH_DATA | CONFIRM))
|
||||
return(ph_data_confirm(hif, hh, askb));
|
||||
return(ph_data_confirm(&l2->inst, hh, askb));
|
||||
if (hh->prim == (MDL_FINDTEI | REQUEST)) {
|
||||
ret = -ESRCH;
|
||||
if (test_bit(FLG_LAPD, &l2->flag)) {
|
||||
|
@ -1914,10 +1913,13 @@ l2from_down(mISDNif_t *hif, struct sk_buff *askb)
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef FIXME
|
||||
if (next && next->func)
|
||||
ret = next->func(next, askb);
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
#ifdef FIXME
|
||||
if (next) {
|
||||
if (next->func) {
|
||||
if (!(cskb = skb_clone(askb, GFP_ATOMIC)))
|
||||
|
@ -1926,6 +1928,7 @@ l2from_down(mISDNif_t *hif, struct sk_buff *askb)
|
|||
sh = *hh;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
switch (hh->prim) {
|
||||
case (PH_DATA_IND):
|
||||
ret = ph_data_indication(l2, hh, cskb);
|
||||
|
@ -1962,26 +1965,21 @@ l2from_down(mISDNif_t *hif, struct sk_buff *askb)
|
|||
dev_kfree_skb(cskb);
|
||||
ret = 0;
|
||||
}
|
||||
#ifdef FIXME
|
||||
if (next && next->func) {
|
||||
*hh = sh;
|
||||
ret = next->func(next, askb);
|
||||
}
|
||||
#endif
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
l2from_up(mISDNif_t *hif, struct sk_buff *skb) {
|
||||
layer2_t *l2;
|
||||
mISDN_head_t *hh;
|
||||
l2from_up(layer2_t *l2, struct sk_buff *skb, mISDN_head_t *hh) {
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!hif || !skb)
|
||||
return(ret);
|
||||
l2 = hif->fdata;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
// printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim);
|
||||
if (!l2)
|
||||
return(ret);
|
||||
if (hh->addr & FLG_MSG_CLONED)
|
||||
return(l2down_raw(l2, skb));
|
||||
switch (hh->prim) {
|
||||
case (DL_DATA | REQUEST):
|
||||
ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_DATA, skb);
|
||||
|
@ -2021,7 +2019,7 @@ l2from_up(mISDNif_t *hif, struct sk_buff *skb) {
|
|||
ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, skb);
|
||||
case (MDL_STATUS | REQUEST):
|
||||
l2up_create(l2, MDL_STATUS | CONFIRM, hh->dinfo, 1,
|
||||
(void *)l2->tei);
|
||||
(void *)((u_long)l2->tei));
|
||||
break;
|
||||
default:
|
||||
if (l2->debug)
|
||||
|
@ -2030,6 +2028,68 @@ l2from_up(mISDNif_t *hif, struct sk_buff *skb) {
|
|||
return(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
l2_shortstatus(layer2_t *l2, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
u_int temp;
|
||||
|
||||
if (hh->prim == (MGR_SHORTSTATUS | REQUEST)) {
|
||||
temp = hh->dinfo & SSTATUS_ALL;
|
||||
if (temp == SSTATUS_ALL || temp == SSTATUS_L2) {
|
||||
skb_trim(skb, 0);
|
||||
if (hh->dinfo & SSTATUS_BROADCAST_BIT)
|
||||
temp = l2->inst.id | MSG_BROADCAST;
|
||||
else
|
||||
temp = hh->addr | FLG_MSG_TARGET;
|
||||
switch(l2->l2m.state) {
|
||||
case ST_L2_7:
|
||||
case ST_L2_8:
|
||||
hh->dinfo = SSTATUS_L2_ESTABLISHED;
|
||||
break;
|
||||
default:
|
||||
hh->dinfo = SSTATUS_L2_RELEASED;
|
||||
}
|
||||
hh->prim = MGR_SHORTSTATUS | CONFIRM;
|
||||
return(mISDN_queue_message(&l2->inst, temp, skb));
|
||||
}
|
||||
}
|
||||
return(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static int
|
||||
l2_function(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
layer2_t *l2 = inst->privat;
|
||||
mISDN_head_t *hh = mISDN_HEAD_P(skb);
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (debug)
|
||||
printk(KERN_DEBUG "%s: addr(%08x) prim(%x)\n", __FUNCTION__, hh->addr, hh->prim);
|
||||
if (!l2)
|
||||
return(ret);
|
||||
|
||||
if (unlikely((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS))
|
||||
return(l2_shortstatus(l2, skb, hh));
|
||||
|
||||
switch(hh->addr & MSG_DIR_MASK) {
|
||||
case FLG_MSG_DOWN:
|
||||
ret = l2from_up(l2, skb, hh);
|
||||
break;
|
||||
case FLG_MSG_UP:
|
||||
ret = l2from_down(l2, skb, hh);
|
||||
break;
|
||||
case MSG_TO_OWNER:
|
||||
/* FIXME: must be handled depending on type */
|
||||
int_errtxt("not implemented yet");
|
||||
break;
|
||||
default:
|
||||
/* FIXME: broadcast must be handled depending on type */
|
||||
int_errtxt("not implemented yet");
|
||||
break;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int
|
||||
tei_l2(layer2_t *l2, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -2077,7 +2137,8 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...)
|
|||
static void
|
||||
release_l2(layer2_t *l2)
|
||||
{
|
||||
mISDNinstance_t *inst = &l2->inst;
|
||||
mISDNinstance_t *inst = &l2->inst;
|
||||
u_long flags;
|
||||
|
||||
mISDN_FsmDelTimer(&l2->t200, 21);
|
||||
mISDN_FsmDelTimer(&l2->t203, 16);
|
||||
|
@ -2087,6 +2148,7 @@ release_l2(layer2_t *l2)
|
|||
ReleaseWin(l2);
|
||||
if (test_bit(FLG_LAPD, &l2->flag))
|
||||
release_tei(l2->tm);
|
||||
#ifdef OBSOLETE
|
||||
if (inst->up.peer) {
|
||||
inst->up.peer->obj->ctrl(inst->up.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
|
@ -2108,18 +2170,22 @@ release_l2(layer2_t *l2)
|
|||
kfree(l2->cloneif);
|
||||
l2->cloneif = NULL;
|
||||
}
|
||||
#endif
|
||||
spin_lock_irqsave(&isdnl2.lock, flags);
|
||||
list_del(&l2->list);
|
||||
spin_unlock_irqrestore(&isdnl2.lock, flags);
|
||||
isdnl2.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
if (l2->entity != MISDN_ENTITY_NONE)
|
||||
isdnl2.ctrl(inst, MGR_DELENTITY | REQUEST, (void *)l2->entity);
|
||||
isdnl2.ctrl(inst, MGR_DELENTITY | REQUEST, (void *)((u_long)l2->entity));
|
||||
kfree(l2);
|
||||
}
|
||||
|
||||
static int
|
||||
new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
||||
layer2_t *nl2;
|
||||
int err;
|
||||
u_char *p;
|
||||
new_l2(mISDNstack_t *st, mISDN_pid_t *pid) {
|
||||
layer2_t *nl2;
|
||||
int err;
|
||||
u_char *p;
|
||||
u_long flags;
|
||||
|
||||
if (!st || !pid)
|
||||
return(-EINVAL);
|
||||
|
@ -2128,11 +2194,10 @@ new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
|||
return(-ENOMEM);
|
||||
}
|
||||
memset(nl2, 0, sizeof(layer2_t));
|
||||
spin_lock_init(&nl2->lock);
|
||||
nl2->debug = debug;
|
||||
nl2->next_id = 1;
|
||||
nl2->down_id = MISDN_ID_NONE;
|
||||
mISDN_init_instance(&nl2->inst, &isdnl2, nl2);
|
||||
mISDN_init_instance(&nl2->inst, &isdnl2, nl2, l2_function);
|
||||
nl2->inst.extentions = EXT_INST_CLONE;
|
||||
memcpy(&nl2->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
if (!mISDN_SetHandledPID(&isdnl2, &nl2->inst.pid)) {
|
||||
|
@ -2141,7 +2206,7 @@ new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
|||
}
|
||||
switch(pid->protocol[2] & ~ISDN_PID_FEATURE_MASK) {
|
||||
case ISDN_PID_L2_LAPD_NET:
|
||||
sprintf(nl2->inst.name, "lapdn %x", st->id);
|
||||
sprintf(nl2->inst.name, "lapdn %x", st->id>>8);
|
||||
test_and_set_bit(FLG_LAPD, &nl2->flag);
|
||||
test_and_set_bit(FLG_LAPD_NET, &nl2->flag);
|
||||
test_and_set_bit(FLG_FIXED_TEI, &nl2->flag);
|
||||
|
@ -2159,7 +2224,7 @@ new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
|||
}
|
||||
break;
|
||||
case ISDN_PID_L2_LAPD:
|
||||
sprintf(nl2->inst.name, "lapd %x", st->id);
|
||||
sprintf(nl2->inst.name, "lapd %x", st->id>>8);
|
||||
test_and_set_bit(FLG_LAPD, &nl2->flag);
|
||||
test_and_set_bit(FLG_MOD128, &nl2->flag);
|
||||
test_and_set_bit(FLG_ORIG, &nl2->flag);
|
||||
|
@ -2182,7 +2247,7 @@ new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
|||
break;
|
||||
case ISDN_PID_L2_B_X75SLP:
|
||||
test_and_set_bit(FLG_LAPB, &nl2->flag);
|
||||
sprintf(nl2->inst.name, "lapb %x", st->id);
|
||||
sprintf(nl2->inst.name, "lapb %x", st->id >> 8);
|
||||
nl2->window = 7;
|
||||
nl2->maxlen = MAX_DATA_SIZE;
|
||||
nl2->T200 = 1000;
|
||||
|
@ -2230,7 +2295,9 @@ new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
|||
|
||||
mISDN_FsmInitTimer(&nl2->l2m, &nl2->t200);
|
||||
mISDN_FsmInitTimer(&nl2->l2m, &nl2->t203);
|
||||
spin_lock_irqsave(&isdnl2.lock, flags);
|
||||
list_add_tail(&nl2->list, &isdnl2.ilist);
|
||||
spin_unlock_irqrestore(&isdnl2.lock, flags);
|
||||
err = isdnl2.ctrl(&nl2->inst, MGR_NEWENTITY | REQUEST, NULL);
|
||||
if (err) {
|
||||
printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
|
||||
|
@ -2253,16 +2320,14 @@ new_l2(mISDNstack_t *st, mISDN_pid_t *pid, layer2_t **newl2) {
|
|||
stp.down_headerlen = l2headersize(nl2, 0);
|
||||
isdnl2.ctrl(st, MGR_ADDSTPARA | REQUEST, &stp);
|
||||
}
|
||||
if (newl2)
|
||||
*newl2 = nl2;
|
||||
return(err);
|
||||
}
|
||||
|
||||
#ifdef OBSOLETE
|
||||
static int
|
||||
clone_l2(layer2_t *l2, mISDNinstance_t **new_ip) {
|
||||
int err;
|
||||
layer2_t *nl2;
|
||||
mISDNif_t *nif;
|
||||
mISDNstack_t *st;
|
||||
|
||||
if (!l2)
|
||||
|
@ -2272,19 +2337,11 @@ clone_l2(layer2_t *l2, mISDNinstance_t **new_ip) {
|
|||
st = (mISDNstack_t *)*new_ip;
|
||||
if (!st)
|
||||
return(-EINVAL);
|
||||
if (!l2->inst.down.peer)
|
||||
return(-EINVAL);
|
||||
if (!(nif = kmalloc(sizeof(mISDNif_t), GFP_ATOMIC))) {
|
||||
printk(KERN_ERR "clone l2 no if mem\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
err = new_l2(st, &l2->inst.pid, &nl2);
|
||||
if (err) {
|
||||
kfree(nif);
|
||||
printk(KERN_ERR "clone l2 failed err(%d)\n", err);
|
||||
return(err);
|
||||
}
|
||||
memset(nif, 0, sizeof(mISDNif_t));
|
||||
nl2->cloneif = nif;
|
||||
nif->func = l2from_down;
|
||||
nif->fdata = nl2;
|
||||
|
@ -2303,6 +2360,7 @@ clone_l2(layer2_t *l2, mISDNinstance_t **new_ip) {
|
|||
*new_ip = &nl2->inst;
|
||||
return(err);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
l2_status(layer2_t *l2, status_info_l2_t *si)
|
||||
|
@ -2344,7 +2402,7 @@ l2_status(layer2_t *l2, status_info_l2_t *si)
|
|||
}
|
||||
|
||||
static char MName[] = "ISDNL2";
|
||||
|
||||
|
||||
#ifdef MODULE
|
||||
MODULE_AUTHOR("Karsten Keil");
|
||||
#ifdef MODULE_LICENSE
|
||||
|
@ -2358,20 +2416,23 @@ l2_manager(void *data, u_int prim, void *arg) {
|
|||
mISDNinstance_t *inst = data;
|
||||
layer2_t *l2l;
|
||||
int err = -EINVAL;
|
||||
u_long flags;
|
||||
|
||||
if (debug & 0x1000)
|
||||
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n", __FUNCTION__,
|
||||
data, prim, arg);
|
||||
if (!data)
|
||||
return(err);
|
||||
spin_lock_irqsave(&isdnl2.lock, flags);
|
||||
list_for_each_entry(l2l, &isdnl2.ilist, list) {
|
||||
if (&l2l->inst == inst) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&isdnl2.lock, flags);
|
||||
if (prim == (MGR_NEWLAYER | REQUEST))
|
||||
return(new_l2(data, arg, NULL));
|
||||
return(new_l2(data, arg));
|
||||
if (err) {
|
||||
if (debug & 0x1)
|
||||
printk(KERN_WARNING "l2_manager prim(%x) l2 no instance\n", prim);
|
||||
|
@ -2379,13 +2440,14 @@ l2_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
switch(prim) {
|
||||
case MGR_NEWENTITY | CONFIRM:
|
||||
l2l->entity = (int)arg;
|
||||
l2l->entity = (u_long)arg & 0xffffffff;
|
||||
break;
|
||||
case MGR_ADDSTPARA | INDICATION:
|
||||
if (((mISDN_stPara_t *)arg)->maxdatalen)
|
||||
l2l->maxlen = ((mISDN_stPara_t *)arg)->maxdatalen;
|
||||
case MGR_CLRSTPARA | INDICATION:
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CLONELAYER | REQUEST:
|
||||
return(clone_l2(l2l, arg));
|
||||
case MGR_CONNECT | REQUEST:
|
||||
|
@ -2405,6 +2467,7 @@ l2_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
#endif
|
||||
case MGR_RELEASE | INDICATION:
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
release_l2(l2l);
|
||||
|
@ -2433,6 +2496,7 @@ int Isdnl2_Init(void)
|
|||
ISDN_PID_L2_DF_PTP;
|
||||
isdnl2.BPROTO.protocol[2] = ISDN_PID_L2_B_X75SLP;
|
||||
isdnl2.own_ctrl = l2_manager;
|
||||
spin_lock_init(&isdnl2.lock);
|
||||
INIT_LIST_HEAD(&isdnl2.ilist);
|
||||
l2fsm.state_count = L2_STATE_COUNT;
|
||||
l2fsm.event_count = L2_EVENT_COUNT;
|
||||
|
|
|
@ -47,7 +47,7 @@ typedef struct _layer2 {
|
|||
int T200, N200, T203;
|
||||
int debug;
|
||||
mISDNinstance_t inst;
|
||||
mISDNif_t *cloneif;
|
||||
// mISDNif_t *cloneif;
|
||||
int next_id;
|
||||
u_int down_id;
|
||||
struct sk_buff *windowar[MAX_WINDOW];
|
||||
|
@ -55,7 +55,6 @@ typedef struct _layer2 {
|
|||
struct sk_buff_head ui_queue;
|
||||
struct sk_buff_head down_queue;
|
||||
struct sk_buff_head tmp_queue;
|
||||
spinlock_t lock;
|
||||
} layer2_t;
|
||||
|
||||
/* l2 status_info */
|
||||
|
|
|
@ -88,14 +88,11 @@ l3_debug(layer3_t *l3, char *fmt, ...)
|
|||
static int
|
||||
l3_newid(layer3_t *l3)
|
||||
{
|
||||
u_long flags;
|
||||
int id;
|
||||
|
||||
spin_lock_irqsave(&l3->lock, flags);
|
||||
id = l3->next_id++;
|
||||
if (id == 0x7fff)
|
||||
l3->next_id = 1;
|
||||
spin_unlock_irqrestore(&l3->lock, flags);
|
||||
id |= (l3->entity << 16);
|
||||
return(id);
|
||||
}
|
||||
|
@ -277,7 +274,6 @@ l3_process_t
|
|||
*new_l3_process(layer3_t *l3, int cr, int n303, u_int id)
|
||||
{
|
||||
l3_process_t *p = NULL;
|
||||
u_long flags;
|
||||
|
||||
if (id == MISDN_ID_ANY) {
|
||||
if (l3->entity == MISDN_ENTITY_NONE) {
|
||||
|
@ -285,7 +281,6 @@ l3_process_t
|
|||
__FUNCTION__, l3->id);
|
||||
return (NULL);
|
||||
}
|
||||
spin_lock_irqsave(&l3->lock, flags);
|
||||
if (l3->pid_cnt == 0x7FFF)
|
||||
l3->pid_cnt = 0;
|
||||
while(l3->pid_cnt <= 0x7FFF) {
|
||||
|
@ -295,7 +290,6 @@ l3_process_t
|
|||
if (!p)
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&l3->lock, flags);
|
||||
if (p) {
|
||||
printk(KERN_WARNING "%s: no free process_id for l3(%x) entity(%x)\n",
|
||||
__FUNCTION__, l3->id, l3->entity);
|
||||
|
@ -320,6 +314,7 @@ l3_process_t
|
|||
p->callref = cr;
|
||||
p->n303 = n303;
|
||||
L3InitTimer(p, &p->timer);
|
||||
L3InitTimer(p, &p->aux_timer);
|
||||
list_add_tail(&p->list, &l3->plist);
|
||||
return (p);
|
||||
};
|
||||
|
@ -369,9 +364,9 @@ mISDN_l3up(l3_process_t *l3p, u_int prim, struct sk_buff *skb)
|
|||
return(-EINVAL);
|
||||
l3 = l3p->l3;
|
||||
if (!skb)
|
||||
err = if_link(&l3->inst.up, prim, l3p->id, 0, NULL, 0);
|
||||
err = mISDN_queue_data(&l3->inst, FLG_MSG_UP, prim, l3p->id, 0, NULL, 0);
|
||||
else
|
||||
err = if_newhead(&l3->inst.up, prim, l3p->id, skb);
|
||||
err = mISDN_queueup_newhead(&l3->inst, 0, prim, l3p->id, skb);
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
@ -380,9 +375,9 @@ l3down(layer3_t *l3, u_int prim, int dinfo, struct sk_buff *skb) {
|
|||
int err = -EINVAL;
|
||||
|
||||
if (!skb)
|
||||
err = if_link(&l3->inst.down, prim, dinfo, 0, NULL, 0);
|
||||
err = mISDN_queue_data(&l3->inst, FLG_MSG_DOWN, prim, dinfo, 0, NULL, 0);
|
||||
else
|
||||
err = if_newhead(&l3->inst.down, prim, dinfo, skb);
|
||||
err = mISDN_queuedown_newhead(&l3->inst, 0, prim, dinfo, skb);
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
@ -554,7 +549,6 @@ init_l3(layer3_t *l3)
|
|||
l3->dummy = NULL;
|
||||
l3->entity = MISDN_ENTITY_NONE;
|
||||
l3->next_id = 1;
|
||||
spin_lock_init(&l3->lock);
|
||||
skb_queue_head_init(&l3->squeue);
|
||||
l3->l3m.fsm = &l3fsm;
|
||||
l3->l3m.state = ST_L3_LC_REL;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define L3_DEB_CHARGE 0x08
|
||||
#define L3_DEB_CHECK 0x10
|
||||
#define L3_DEB_SI 0x20
|
||||
#define L3_DEB_MSG 0x80000000
|
||||
|
||||
#define FLG_L2BLOCK 1
|
||||
#define FLG_PTP 2
|
||||
|
@ -45,6 +46,8 @@ typedef struct _l3_process {
|
|||
u_int id;
|
||||
int bc;
|
||||
int err;
|
||||
int aux_state;
|
||||
L3Timer_t aux_timer;
|
||||
} l3_process_t;
|
||||
|
||||
typedef struct _layer3 {
|
||||
|
@ -64,7 +67,6 @@ typedef struct _layer3 {
|
|||
u_long Flag;
|
||||
mISDNinstance_t inst;
|
||||
struct sk_buff_head squeue;
|
||||
spinlock_t lock;
|
||||
int OrigCallRef;
|
||||
} layer3_t;
|
||||
|
||||
|
|
|
@ -182,7 +182,6 @@ struct _Controller {
|
|||
__u32 addr;
|
||||
int entity;
|
||||
int next_id;
|
||||
spinlock_t id_lock;
|
||||
u_int debug;
|
||||
int maxplci;
|
||||
Plci_t *plcis;
|
||||
|
@ -273,7 +272,6 @@ struct _Ncci {
|
|||
int savedstate;
|
||||
int window;
|
||||
u_long state;
|
||||
spinlock_t conf_lock;
|
||||
ConfQueue_t xmit_skb_handles[CAPI_MAXDATAWINDOW];
|
||||
struct sk_buff *recv_skb_handles[CAPI_MAXDATAWINDOW];
|
||||
struct sk_buff_head squeue;
|
||||
|
@ -315,7 +313,7 @@ int ControllerReleasePlci(Plci_t *);
|
|||
Application_t *getApplication4Id(Controller_t *, __u16);
|
||||
Plci_t *getPlci4Addr(Controller_t *, __u32);
|
||||
int ControllerL4L3(Controller_t *, u_int, int, struct sk_buff *);
|
||||
int ControllerL3L4(mISDNif_t *, struct sk_buff *);
|
||||
int ControllerL3L4(mISDNinstance_t *, struct sk_buff *);
|
||||
PLInst_t *ControllerSelChannel(Controller_t *, u_int);
|
||||
void ControllerAddSSProcess(Controller_t *, SSProcess_t *);
|
||||
SSProcess_t *getSSProcess4Id(Controller_t *, __u16);
|
||||
|
@ -328,7 +326,7 @@ int ControllerNextId(Controller_t *);
|
|||
int ApplicationConstr(Controller_t *, __u16, capi_register_params *);
|
||||
int ApplicationDestr(Application_t *, int);
|
||||
void ApplicationDebug(Application_t *appl, __u32 level, char *fmt, ...);
|
||||
__u16 ApplicationSendMessage(Application_t *appl, struct sk_buff *skb);
|
||||
void ApplicationSendMessage(Application_t *appl, struct sk_buff *skb);
|
||||
void SendCmsg2Application(Application_t *, _cmsg *);
|
||||
void SendCmsgAnswer2Application(Application_t *, _cmsg *, __u16);
|
||||
void AnswerMessage2Application(Application_t *, struct sk_buff *, __u16);
|
||||
|
@ -366,12 +364,15 @@ void AppPlciDelNCCI(Ncci_t *);
|
|||
void AppPlci_l3l4(AppPlci_t *, int, void *);
|
||||
__u16 AppPlciSendMessage(AppPlci_t *, struct sk_buff *);
|
||||
void AppPlciRelease(AppPlci_t *);
|
||||
int AppPlciFacHoldReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
|
||||
int AppPlciFacRetrieveReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
|
||||
int AppPlciFacSuspendReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
|
||||
int AppPlciFacResumeReq(AppPlci_t *, FacReqParm_t *, FacConfParm_t *);
|
||||
void AppPlciGetCmsg(AppPlci_t *, _cmsg *);
|
||||
Ncci_t *getNCCI4addr(AppPlci_t *, __u32, int);
|
||||
int ConnectB3Request(AppPlci_t *, struct sk_buff *);
|
||||
int AppPlcimISDN_SetIF(AppPlci_t *, u_int, void *);
|
||||
void ConnectB3Request(AppPlci_t *, struct sk_buff *);
|
||||
void DisconnectB3Request(AppPlci_t *, struct sk_buff *);
|
||||
int AppPlcimISDN_Active(AppPlci_t *);
|
||||
|
||||
#define GET_NCCI_EXACT 1
|
||||
#define GET_NCCI_ONLY_PLCI 2
|
||||
|
@ -385,7 +386,7 @@ Ncci_t *ncciConstr(AppPlci_t *);
|
|||
void ncciDestr(Ncci_t *);
|
||||
void ncciApplRelease(Ncci_t *);
|
||||
void ncciDelAppPlci(Ncci_t *);
|
||||
__u16 ncciSendMessage(Ncci_t *, struct sk_buff *);
|
||||
void ncciSendMessage(Ncci_t *, struct sk_buff *);
|
||||
int ncci_l3l4(Ncci_t *, mISDN_head_t *, struct sk_buff *);
|
||||
void ncciGetCmsg(Ncci_t *, _cmsg *);
|
||||
int ncci_l3l4_direct(Ncci_t *, mISDN_head_t *, struct sk_buff *);
|
||||
|
@ -399,30 +400,44 @@ SSProcess_t *SSProcessConstr(Application_t *, __u16, __u32);
|
|||
void SSProcessDestr(SSProcess_t *);
|
||||
int Supplementary_l3l4(Controller_t *, __u32, struct sk_buff *);
|
||||
void SupplementaryFacilityReq(Application_t *, _cmsg *);
|
||||
void SendSSNotificationEvent(AppPlci_t *, u16);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// INFOMASK defines (LISTEN commands)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define CAPI_INFOMASK_CAUSE (0x0001)
|
||||
#define CAPI_INFOMASK_DATETIME (0x0002)
|
||||
#define CAPI_INFOMASK_DISPLAY (0x0004)
|
||||
#define CAPI_INFOMASK_USERUSER (0x0008)
|
||||
#define CAPI_INFOMASK_PROGRESS (0x0010)
|
||||
#define CAPI_INFOMASK_FACILITY (0x0020)
|
||||
//#define CAPI_INFOMASK_CHARGE (0x0040)
|
||||
//#define CAPI_INFOMASK_CALLEDPN (0x0080)
|
||||
#define CAPI_INFOMASK_CHANNELID (0x0100)
|
||||
#define CAPI_INFOMASK_EARLYB3 (0x0200)
|
||||
//#define CAPI_INFOMASK_REDIRECT (0x0400)
|
||||
#define CAPI_INFOMASK_CAUSE 0x0001
|
||||
#define CAPI_INFOMASK_DATETIME 0x0002
|
||||
#define CAPI_INFOMASK_DISPLAY 0x0004
|
||||
#define CAPI_INFOMASK_USERUSER 0x0008
|
||||
#define CAPI_INFOMASK_PROGRESS 0x0010
|
||||
#define CAPI_INFOMASK_FACILITY 0x0020
|
||||
#define CAPI_INFOMASK_CHARGE 0x0040
|
||||
#define CAPI_INFOMASK_CALLEDPN 0x0080
|
||||
#define CAPI_INFOMASK_CHANNELID 0x0100
|
||||
#define CAPI_INFOMASK_EARLYB3 0x0200
|
||||
#define CAPI_INFOMASK_REDIRECT 0x0400
|
||||
/* bit 11 reserved */
|
||||
#define CAPI_INFOMASK_COMPLETE 0x1000
|
||||
/* bit 13-31 reserved */
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Supplementary Services
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#define SuppServiceHR 0x00000001
|
||||
#define SuppServiceTP 0x00000002
|
||||
#define SuppServiceECT 0x00000004
|
||||
#define SuppService3PTY 0x00000008
|
||||
#define SuppServiceCF 0x00000010
|
||||
#define mISDNSupportedServices (SuppServiceCF | SuppServiceTP)
|
||||
#define SuppServiceCD 0x00000020
|
||||
#define SuppServiceMCID 0x00000040
|
||||
#define SuppServiceCCBS 0x00000080
|
||||
|
||||
#define mISDNSupportedServices (SuppServiceCD | \
|
||||
SuppServiceCF | \
|
||||
SuppServiceTP | \
|
||||
SuppServiceHR)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// structs for Facillity requests
|
||||
|
@ -456,6 +471,12 @@ struct FacReqCFDeactivate {
|
|||
__u8 *ServedUserNumber;
|
||||
};
|
||||
|
||||
struct FacReqCDeflection {
|
||||
__u16 PresentationAllowed;
|
||||
__u8 *DeflectedToNumber;
|
||||
__u8 *DeflectedToSubaddress;
|
||||
};
|
||||
|
||||
#define FacReqCFInterrogateParameters FacReqCFDeactivate
|
||||
|
||||
struct FacReqCFInterrogateNumbers {
|
||||
|
@ -472,6 +493,7 @@ struct FacReqParm {
|
|||
struct FacReqCFDeactivate CFDeactivate;
|
||||
struct FacReqCFInterrogateParameters CFInterrogateParameters;
|
||||
struct FacReqCFInterrogateNumbers CFInterrogateNumbers;
|
||||
struct FacReqCDeflection CDeflection;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
|
|
@ -65,10 +65,8 @@ __mid_kfree(const void *p)
|
|||
_mid_item_t *mid;
|
||||
u_long flags;
|
||||
|
||||
if (!p) {
|
||||
printk(KERN_ERR "zero pointer kfree at %p", __builtin_return_address(0));
|
||||
if (!p)
|
||||
return;
|
||||
}
|
||||
mid = (_mid_item_t *)((u_char *)p - sizeof(_mid_item_t));
|
||||
spin_lock_irqsave(&memdbg_lock, flags);
|
||||
list_del(&mid->head);
|
||||
|
@ -104,10 +102,8 @@ __mid_vfree(const void *p)
|
|||
_mid_item_t *mid;
|
||||
u_long flags;
|
||||
|
||||
if (!p) {
|
||||
printk(KERN_ERR "zero pointer vfree at %p", __builtin_return_address(0));
|
||||
if (!p)
|
||||
return;
|
||||
}
|
||||
mid = (_mid_item_t *)((u_char *)p - sizeof(_mid_item_t));
|
||||
spin_lock_irqsave(&memdbg_lock, flags);
|
||||
list_del(&mid->head);
|
||||
|
|
|
@ -173,9 +173,9 @@ SKB2Application(Ncci_t *ncci, struct sk_buff *skb)
|
|||
static inline int
|
||||
SKB_l4l3(Ncci_t *ncci, struct sk_buff *skb)
|
||||
{
|
||||
if (!ncci->link || !ncci->link->inst.down.func)
|
||||
if (!ncci->link)
|
||||
return(-ENXIO);
|
||||
return(ncci->link->inst.down.func(&ncci->link->inst.down, skb));
|
||||
return(mISDN_queue_down(&ncci->link->inst, 0, skb));
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -438,15 +438,12 @@ ncci_connect_b3_active_ind(struct FsmInst *fi, int event, void *arg)
|
|||
{
|
||||
Ncci_t *ncci = fi->userdata;
|
||||
int i;
|
||||
u_long flags;
|
||||
|
||||
mISDN_FsmChangeState(fi, ST_NCCI_N_ACT);
|
||||
spin_lock_irqsave(&ncci->conf_lock, flags);
|
||||
for (i = 0; i < CAPI_MAXDATAWINDOW; i++) {
|
||||
ncci->xmit_skb_handles[i].PktId = 0;
|
||||
ncci->recv_skb_handles[i] = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
Send2Application(ncci, arg);
|
||||
}
|
||||
|
||||
|
@ -732,7 +729,7 @@ ncciD_disconnect_b3_ind(struct FsmInst *fi, int event, void *arg)
|
|||
skb_pull(skb, CAPIMSG_BASELEN);
|
||||
skb_trim(skb, 0);
|
||||
skb_put(skb, 4);
|
||||
if_newhead(&ncci->link->inst.down, CAPI_DISCONNECT_B3_RESP, 0, skb);
|
||||
mISDN_queuedown_newhead(&ncci->link->inst, 0, CAPI_DISCONNECT_B3_RESP, 0, skb);
|
||||
ncciDestr(ncci);
|
||||
} else
|
||||
SKB2Application(ncci, arg);
|
||||
|
@ -768,7 +765,7 @@ ncciD_appl_release_disc(struct FsmInst *fi, int event, void *arg)
|
|||
capimsg_setu32(parm, 0, ncci->addr);
|
||||
parm[4] = 0;
|
||||
mISDN_FsmChangeState(fi, ST_NCCI_N_4);
|
||||
if_link(&ncci->link->inst.down, CAPI_DISCONNECT_B3_REQ, 0, 5, parm, 0);
|
||||
mISDN_queue_data(&ncci->link->inst, FLG_MSG_DOWN, CAPI_DISCONNECT_B3_REQ, 0, 5, parm, 0);
|
||||
}
|
||||
|
||||
static struct FsmNode fn_ncciD_list[] =
|
||||
|
@ -831,7 +828,6 @@ ncciConstr(AppPlci_t *aplci)
|
|||
ncci->ncci_m.debug = aplci->plci->contr->debug & CAPI_DBG_NCCI_STATE;
|
||||
ncci->ncci_m.userdata = ncci;
|
||||
ncci->ncci_m.printdebug = ncci_debug;
|
||||
spin_lock_init(&ncci->conf_lock);
|
||||
/* unused NCCI */
|
||||
ncci->addr = aplci->addr;
|
||||
ncci->AppPlci = aplci;
|
||||
|
@ -862,7 +858,6 @@ void
|
|||
ncciDestr(Ncci_t *ncci)
|
||||
{
|
||||
int i;
|
||||
u_long flags;
|
||||
|
||||
capidebug(CAPI_DBG_NCCI, "ncciDestr NCCI %x", ncci->addr);
|
||||
|
||||
|
@ -871,13 +866,11 @@ ncciDestr(Ncci_t *ncci)
|
|||
ncci->contr->ctrl->free_ncci(ncci->contr->ctrl, ncci->appl->ApplId, ncci->addr);
|
||||
#endif
|
||||
/* cleanup data queues */
|
||||
spin_lock_irqsave(&ncci->conf_lock, flags);
|
||||
discard_queue(&ncci->squeue);
|
||||
for (i = 0; i < ncci->window; i++) {
|
||||
if (ncci->xmit_skb_handles[i].PktId)
|
||||
ncci->xmit_skb_handles[i].PktId = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
AppPlciDelNCCI(ncci);
|
||||
ncci_free(ncci);
|
||||
}
|
||||
|
@ -945,7 +938,7 @@ ncciDataInd(Ncci_t *ncci, int pr, struct sk_buff *skb)
|
|||
*((__u16*)(nskb->data+6)) = ncci->appl->MsgId++;
|
||||
*((__u32*)(nskb->data+8)) = ncci->addr;
|
||||
if (sizeof(nskb) == 4) {
|
||||
*((__u32*)(nskb->data+12)) = (__u32)(nskb->data + CAPI_B3_DATA_IND_HEADER_SIZE);
|
||||
*((__u32*)(nskb->data+12)) = (__u32)(((u_long)nskb->data + CAPI_B3_DATA_IND_HEADER_SIZE) & 0xffffffff);
|
||||
*((__u64*)(nskb->data+22)) = 0;
|
||||
} else {
|
||||
*((__u32*)(nskb->data+12)) = 0;
|
||||
|
@ -968,7 +961,6 @@ ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
|
|||
int i, err;
|
||||
__u16 len, capierr = 0;
|
||||
_cmsg *cmsg;
|
||||
u_long flags;
|
||||
|
||||
len = CAPIMSG_LEN(skb->data);
|
||||
if (len != 22 && len != 30) {
|
||||
|
@ -976,13 +968,11 @@ ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
|
|||
int_error();
|
||||
goto fail;
|
||||
}
|
||||
spin_lock_irqsave(&ncci->conf_lock, flags);
|
||||
for (i = 0; i < ncci->window; i++) {
|
||||
if (ncci->xmit_skb_handles[i].PktId == 0)
|
||||
break;
|
||||
}
|
||||
if (i == ncci->window) {
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
return(CAPI_SENDQUEUEFULL);
|
||||
}
|
||||
mISDN_HEAD_DINFO(skb) = ControllerNextId(ncci->contr);
|
||||
|
@ -996,7 +986,6 @@ ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
|
|||
if (test_bit(NCCI_STATE_FCTRL, &ncci->state)) {
|
||||
if (test_and_set_bit(NCCI_STATE_BUSY, &ncci->state)) {
|
||||
skb_queue_tail(&ncci->squeue, skb);
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
return(CAPI_NOERROR);
|
||||
}
|
||||
if (skb_queue_len(&ncci->squeue)) {
|
||||
|
@ -1005,7 +994,6 @@ ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
|
|||
i = -1;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
err = ncciL4L3(ncci, DL_DATA | REQUEST, mISDN_HEAD_DINFO(skb), 0, NULL, skb);
|
||||
if (!err)
|
||||
return(CAPI_NOERROR);
|
||||
|
@ -1013,7 +1001,6 @@ ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
|
|||
int_error();
|
||||
skb_push(skb, len);
|
||||
capierr = CAPI_MSGBUSY;
|
||||
spin_lock_irqsave(&ncci->conf_lock, flags);
|
||||
if (i == -1) {
|
||||
for (i = 0; i < ncci->window; i++) {
|
||||
if (ncci->xmit_skb_handles[i].PktId == mISDN_HEAD_DINFO(skb))
|
||||
|
@ -1023,10 +1010,8 @@ ncciDataReq(Ncci_t *ncci, struct sk_buff *skb)
|
|||
int_error();
|
||||
else
|
||||
ncci->xmit_skb_handles[i].PktId = 0;
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
} else {
|
||||
ncci->xmit_skb_handles[i].PktId = 0;
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
return(capierr);
|
||||
}
|
||||
fail:
|
||||
|
@ -1054,15 +1039,12 @@ ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb)
|
|||
{
|
||||
int i;
|
||||
_cmsg *cmsg;
|
||||
u_long flags;
|
||||
|
||||
spin_lock_irqsave(&ncci->conf_lock, flags);
|
||||
for (i = 0; i < ncci->window; i++) {
|
||||
if (ncci->xmit_skb_handles[i].PktId == mISDN_HEAD_DINFO(skb))
|
||||
break;
|
||||
}
|
||||
if (i == ncci->window) {
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
int_error();
|
||||
printk(KERN_DEBUG "%s: dinfo(%x)\n", __FUNCTION__, mISDN_HEAD_DINFO(skb));
|
||||
for (i = 0; i < ncci->window; i++)
|
||||
|
@ -1075,7 +1057,6 @@ ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb)
|
|||
|
||||
cmsg = cmsg_alloc();
|
||||
if (!cmsg) {
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
int_error();
|
||||
return(-ENOMEM);
|
||||
}
|
||||
|
@ -1083,14 +1064,11 @@ ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb)
|
|||
capi_cmsg_header(cmsg, ncci->AppPlci->appl->ApplId, CAPI_DATA_B3, CAPI_CONF,
|
||||
ncci->xmit_skb_handles[i].MsgId, ncci->addr);
|
||||
cmsg->DataHandle = ncci->xmit_skb_handles[i].DataHandle;
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
cmsg->Info = 0;
|
||||
Send2Application(ncci, cmsg);
|
||||
if (test_bit(NCCI_STATE_FCTRL, &ncci->state)) {
|
||||
spin_lock_irqsave(&ncci->conf_lock, flags);
|
||||
if (skb_queue_len(&ncci->squeue)) {
|
||||
skb = skb_dequeue(&ncci->squeue);
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
if (ncciL4L3(ncci, DL_DATA | REQUEST, mISDN_HEAD_DINFO(skb),
|
||||
0, NULL, skb)) {
|
||||
int_error();
|
||||
|
@ -1098,7 +1076,6 @@ ncciDataConf(Ncci_t *ncci, int pr, struct sk_buff *skb)
|
|||
}
|
||||
} else {
|
||||
test_and_clear_bit(NCCI_STATE_BUSY, &ncci->state);
|
||||
spin_unlock_irqrestore(&ncci->conf_lock, flags);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
|
@ -1224,7 +1201,7 @@ ncciGetCmsg(Ncci_t *ncci, _cmsg *cmsg)
|
|||
}
|
||||
}
|
||||
|
||||
__u16
|
||||
void
|
||||
ncciSendMessage(Ncci_t *ncci, struct sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
|
@ -1237,40 +1214,44 @@ ncciSendMessage(Ncci_t *ncci, struct sk_buff *skb)
|
|||
break;
|
||||
case -EINVAL:
|
||||
case -ENXIO:
|
||||
return(CAPI_MSGBUSY);
|
||||
int_error();
|
||||
break; /* (CAPI_MSGBUSY) */
|
||||
case -EXFULL:
|
||||
return(CAPI_SENDQUEUEFULL);
|
||||
int_error();
|
||||
break; /* (CAPI_SENDQUEUEFULL) */
|
||||
default:
|
||||
int_errtxt("ncci_l4l3_direct return(%d)", ret);
|
||||
dev_kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
return(CAPI_NOERROR);
|
||||
return;
|
||||
}
|
||||
// we're not using the cmsg for DATA_B3 for performance reasons
|
||||
switch (CAPIMSG_CMD(skb->data)) {
|
||||
case CAPI_DATA_B3_REQ:
|
||||
if (ncci->ncci_m.state == ST_NCCI_N_ACT) {
|
||||
return(ncciDataReq(ncci, skb));
|
||||
ret = ncciDataReq(ncci, skb);
|
||||
if (ret)
|
||||
int_error();
|
||||
} else {
|
||||
AnswerMessage2Application(ncci->appl, skb,
|
||||
CapiMessageNotSupportedInCurrentState);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
return(CAPI_NOERROR);
|
||||
return;
|
||||
case CAPI_DATA_B3_RESP:
|
||||
ncciDataResp(ncci, skb);
|
||||
return(CAPI_NOERROR);
|
||||
return;
|
||||
}
|
||||
cmsg = cmsg_alloc();
|
||||
if (!cmsg) {
|
||||
int_error();
|
||||
return(CAPI_MSGOSRESOURCEERR);
|
||||
return;
|
||||
}
|
||||
capi_message2cmsg(cmsg, skb->data);
|
||||
ncciGetCmsg(ncci, cmsg);
|
||||
dev_kfree_skb(skb);
|
||||
return(CAPI_NOERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -1400,10 +1381,9 @@ ncciL4L3(Ncci_t *ncci, u_int prim, int dtyp, int len, void *arg, struct sk_buff
|
|||
capidebug(CAPI_DBG_NCCI_L3, "%s: NCCI %x prim(%x) dtyp(%x) len(%d) skb(%p)",
|
||||
__FUNCTION__, ncci->addr, prim, dtyp, len, skb);
|
||||
if (skb)
|
||||
return(if_newhead(&ncci->link->inst.down, prim, dtyp, skb));
|
||||
return(mISDN_queuedown_newhead(&ncci->link->inst, 0, prim, dtyp, skb));
|
||||
else
|
||||
return(if_link(&ncci->link->inst.down, prim, dtyp,
|
||||
len, arg, 8));
|
||||
return(mISDN_queue_data(&ncci->link->inst, FLG_MSG_DOWN, prim, dtyp, len, arg, 8));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -80,8 +80,11 @@ int plci_l3l4(Plci_t *plci, int pr, struct sk_buff *skb)
|
|||
case CC_SETUP | INDICATION:
|
||||
plciHandleSetupInd(plci, pr, qi);
|
||||
break;
|
||||
/*
|
||||
// no extra treatment for CC_RELEASE_CR | INDICATION !
|
||||
case CC_RELEASE_CR | INDICATION:
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
list_for_each_safe(item, next, &plci->AppPlcis) {
|
||||
aplci = (AppPlci_t *)item;
|
||||
|
|
|
@ -36,18 +36,13 @@
|
|||
#else
|
||||
#include <linux/isapnp.h>
|
||||
#endif
|
||||
#include "dchannel.h"
|
||||
#include "bchannel.h"
|
||||
#include "channel.h"
|
||||
#include "isac.h"
|
||||
#include "isar.h"
|
||||
#include "layer1.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define SPIN_DEBUG
|
||||
#define LOCK_STATISTIC
|
||||
#include "hw_lock.h"
|
||||
|
||||
extern const char *CardType[];
|
||||
|
||||
const char *Sedlfax_revision = "$Revision$";
|
||||
|
@ -110,7 +105,16 @@ const char *Sedlbauer_Types[] =
|
|||
|
||||
typedef struct _sedl_fax {
|
||||
struct list_head list;
|
||||
void *pdev;
|
||||
union {
|
||||
#if defined(CONFIG_PNP)
|
||||
#ifdef NEW_ISAPNP
|
||||
struct pnp_dev *pnp;
|
||||
#else
|
||||
struct pci_dev *pnp;
|
||||
#endif
|
||||
#endif
|
||||
struct pci_dev *pci;
|
||||
} dev;
|
||||
u_int subtyp;
|
||||
u_int irq;
|
||||
u_int irqcnt;
|
||||
|
@ -118,28 +122,14 @@ typedef struct _sedl_fax {
|
|||
u_int addr;
|
||||
u_int isac;
|
||||
u_int isar;
|
||||
mISDN_HWlock_t lock;
|
||||
spinlock_t lock;
|
||||
isar_reg_t ir;
|
||||
isac_chip_t isac_hw;
|
||||
isar_hw_t isar_hw[2];
|
||||
dchannel_t dch;
|
||||
bchannel_t bch[2];
|
||||
channel_t dch;
|
||||
channel_t bch[2];
|
||||
} sedl_fax;
|
||||
|
||||
static int lock_dev(void *data, int nowait)
|
||||
{
|
||||
register mISDN_HWlock_t *lock = &((sedl_fax *)data)->lock;
|
||||
|
||||
return(lock_HW(lock, nowait));
|
||||
}
|
||||
|
||||
static void unlock_dev(void *data)
|
||||
{
|
||||
register mISDN_HWlock_t *lock = &((sedl_fax *)data)->lock;
|
||||
|
||||
unlock_HW(lock);
|
||||
}
|
||||
|
||||
static inline u_char
|
||||
readreg(unsigned int ale, unsigned int adr, u_char off)
|
||||
{
|
||||
|
@ -202,25 +192,27 @@ WriteISACfifo(void *p, u_char * data, int size)
|
|||
*/
|
||||
|
||||
static u_char
|
||||
ReadISAR(void *p, int mode, u_char offset)
|
||||
ReadISAR(void *p, u_char offset)
|
||||
{
|
||||
if (mode == 0)
|
||||
return (readreg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset));
|
||||
else if (mode == 1)
|
||||
byteout(((sedl_fax *)p)->addr, offset);
|
||||
return(bytein(((sedl_fax *)p)->isar));
|
||||
return (readreg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset));
|
||||
}
|
||||
|
||||
static void
|
||||
WriteISAR(void *p, int mode, u_char offset, u_char value)
|
||||
WriteISAR(void *p, u_char offset, u_char value)
|
||||
{
|
||||
if (mode == 0)
|
||||
writereg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset, value);
|
||||
else {
|
||||
if (mode == 1)
|
||||
byteout(((sedl_fax *)p)->addr, offset);
|
||||
byteout(((sedl_fax *)p)->isar, value);
|
||||
}
|
||||
writereg(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, offset, value);
|
||||
}
|
||||
|
||||
static void
|
||||
ReadISARfifo(void *p, u_char * data, int size)
|
||||
{
|
||||
readfifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, ISAR_MBOX, data, size);
|
||||
}
|
||||
|
||||
static void
|
||||
WriteISARfifo(void *p, u_char * data, int size)
|
||||
{
|
||||
writefifo(((sedl_fax *)p)->addr, ((sedl_fax *)p)->isar, ISAR_MBOX, data, size);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -266,53 +258,11 @@ static irqreturn_t
|
|||
speedfax_isa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
sedl_fax *sf = dev_id;
|
||||
u_long flags;
|
||||
|
||||
spin_lock_irqsave(&sf->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr = (void *)0x2001;
|
||||
#endif
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &sf->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n",
|
||||
__FUNCTION__, sf->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "%s: previous lock:%p\n",
|
||||
__FUNCTION__, sf->lock.busy_adr);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->lock.irq_fail++;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->lock.irq_ok++;
|
||||
#endif
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.busy_adr = speedfax_isa_interrupt;
|
||||
#endif
|
||||
}
|
||||
|
||||
test_and_set_bit(STATE_FLAG_INIRQ, &sf->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->lock.lock, flags);
|
||||
spin_lock(&sf->lock);
|
||||
sf->irqcnt++;
|
||||
do_sedl_interrupt(sf);
|
||||
spin_lock_irqsave(&sf->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr = (void *)0x2002;
|
||||
#endif
|
||||
if (!test_and_clear_bit(STATE_FLAG_INIRQ, &sf->lock.state)) {
|
||||
}
|
||||
if (!test_and_clear_bit(STATE_FLAG_BUSY, &sf->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n",
|
||||
__FUNCTION__, sf->lock.state);
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.busy_adr = NULL;
|
||||
sf->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->lock.lock, flags);
|
||||
spin_unlock(&sf->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -320,65 +270,38 @@ static irqreturn_t
|
|||
speedfax_pci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
sedl_fax *sf = dev_id;
|
||||
u_long flags;
|
||||
u_char val;
|
||||
|
||||
spin_lock_irqsave(&sf->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr = (void *)0x3001;
|
||||
#endif
|
||||
spin_lock(&sf->lock);
|
||||
val = bytein(sf->cfg + TIGER_AUX_STATUS);
|
||||
if (val & SEDL_TIGER_IRQ_BIT) { /* for us or shared ? */
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->lock.lock, flags);
|
||||
spin_unlock(&sf->lock);
|
||||
return IRQ_NONE; /* shared */
|
||||
}
|
||||
sf->irqcnt++;
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &sf->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n",
|
||||
__FUNCTION__, sf->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "%s: previous lock:%p\n",
|
||||
__FUNCTION__, sf->lock.busy_adr);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->lock.irq_fail++;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->lock.irq_ok++;
|
||||
#endif
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.busy_adr = speedfax_pci_interrupt;
|
||||
#endif
|
||||
}
|
||||
|
||||
test_and_set_bit(STATE_FLAG_INIRQ, &sf->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr= NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->lock.lock, flags);
|
||||
do_sedl_interrupt(sf);
|
||||
spin_lock_irqsave(&sf->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.spin_adr = (void *)0x3002;
|
||||
#endif
|
||||
if (!test_and_clear_bit(STATE_FLAG_INIRQ, &sf->lock.state)) {
|
||||
}
|
||||
if (!test_and_clear_bit(STATE_FLAG_BUSY, &sf->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n",
|
||||
__FUNCTION__, sf->lock.state);
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->lock.busy_adr = NULL;
|
||||
sf->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->lock.lock, flags);
|
||||
spin_unlock(&sf->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
enable_hwirq(sedl_fax *sf)
|
||||
{
|
||||
WriteISAC(sf, ISAC_MASK, 0);
|
||||
WriteISAR(sf, ISAR_IRQBIT, ISAR_IRQMSK);
|
||||
if (sf->subtyp != SEDL_SPEEDFAX_ISA)
|
||||
byteout(sf->cfg + TIGER_AUX_IRQMASK, SEDL_TIGER_IRQ_BIT);
|
||||
}
|
||||
|
||||
static void
|
||||
disable_hwirq(sedl_fax *sf)
|
||||
{
|
||||
WriteISAC(sf, ISAC_MASK, 0xFF);
|
||||
WriteISAR(sf, ISAR_IRQBIT, 0);
|
||||
if (sf->subtyp != SEDL_SPEEDFAX_ISA)
|
||||
byteout(sf->cfg + TIGER_AUX_IRQMASK, 0);
|
||||
}
|
||||
|
||||
void
|
||||
release_sedlbauer(sedl_fax *sf)
|
||||
{
|
||||
|
@ -386,8 +309,6 @@ release_sedlbauer(sedl_fax *sf)
|
|||
|
||||
if (sf->subtyp == SEDL_SPEEDFAX_ISA)
|
||||
bytecnt = 16;
|
||||
else
|
||||
byteout(sf->cfg + TIGER_AUX_IRQMASK, 0);
|
||||
if (sf->cfg)
|
||||
release_region(sf->cfg, bytecnt);
|
||||
}
|
||||
|
@ -416,6 +337,7 @@ reset_speedfax(sedl_fax *sf)
|
|||
static int init_card(sedl_fax *sf)
|
||||
{
|
||||
int cnt = 3;
|
||||
u_long flags;
|
||||
u_int shared = SA_SHIRQ;
|
||||
void *irq_func = speedfax_pci_interrupt;
|
||||
|
||||
|
@ -423,13 +345,12 @@ static int init_card(sedl_fax *sf)
|
|||
irq_func = speedfax_isa_interrupt;
|
||||
shared = 0;
|
||||
}
|
||||
lock_dev(sf, 0);
|
||||
if (request_irq(sf->irq, irq_func, shared, "speedfax", sf)) {
|
||||
printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n",
|
||||
sf->irq);
|
||||
unlock_dev(sf);
|
||||
return(-EIO);
|
||||
}
|
||||
spin_lock_irqsave(&sf->lock, flags);
|
||||
while (cnt) {
|
||||
int ret;
|
||||
|
||||
|
@ -440,13 +361,10 @@ static int init_card(sedl_fax *sf)
|
|||
}
|
||||
init_isar(&sf->bch[0]);
|
||||
init_isar(&sf->bch[1]);
|
||||
if (sf->subtyp != SEDL_SPEEDFAX_ISA)
|
||||
byteout(sf->cfg + TIGER_AUX_IRQMASK, SEDL_TIGER_IRQ_BIT);
|
||||
WriteISAC(sf, ISAC_MASK, 0);
|
||||
WriteISAR(sf, 0, ISAR_IRQBIT, ISAR_IRQMSK);
|
||||
enable_hwirq(sf);
|
||||
/* RESET Receiver and Transmitter */
|
||||
WriteISAC(sf, ISAC_CMDR, 0x41);
|
||||
unlock_dev(sf);
|
||||
spin_unlock_irqrestore(&sf->lock, flags);
|
||||
current->state = TASK_UNINTERRUPTIBLE;
|
||||
/* Timeout 10ms */
|
||||
schedule_timeout((10*HZ)/1000);
|
||||
|
@ -459,7 +377,7 @@ static int init_card(sedl_fax *sf)
|
|||
if (cnt == 1) {
|
||||
return (-EIO);
|
||||
} else {
|
||||
lock_dev(sf, 0);
|
||||
spin_lock_irqsave(&sf->lock, flags);
|
||||
reset_speedfax(sf);
|
||||
cnt--;
|
||||
}
|
||||
|
@ -467,7 +385,7 @@ static int init_card(sedl_fax *sf)
|
|||
return(0);
|
||||
}
|
||||
}
|
||||
unlock_dev(sf);
|
||||
spin_unlock_irqrestore(&sf->lock, flags);
|
||||
return(-EIO);
|
||||
}
|
||||
|
||||
|
@ -476,18 +394,28 @@ static int init_card(sedl_fax *sf)
|
|||
#define MODULE_PARM_T "1-4i"
|
||||
static int sedl_cnt;
|
||||
static mISDNobject_t speedfax;
|
||||
static int debug;
|
||||
static u_int protocol[MAX_CARDS];
|
||||
static int layermask[MAX_CARDS];
|
||||
static uint debug;
|
||||
static uint protocol_num;
|
||||
static uint layermask_num;
|
||||
static uint protocol[MAX_CARDS];
|
||||
static uint layermask[MAX_CARDS];
|
||||
|
||||
#ifdef MODULE
|
||||
MODULE_AUTHOR("Karsten Keil");
|
||||
#ifdef MODULE_LICENSE
|
||||
MODULE_LICENSE("GPL");
|
||||
#endif
|
||||
MODULE_PARM(debug, "1i");
|
||||
MODULE_PARM(protocol, MODULE_PARM_T);
|
||||
MODULE_PARM(layermask, MODULE_PARM_T);
|
||||
module_param (debug, uint, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC (debug, "sedlfax debug mask");
|
||||
#ifdef OLD_MODULE_PARAM_ARRAY
|
||||
module_param_array(protocol, uint, protocol_num, S_IRUGO | S_IWUSR);
|
||||
module_param_array(layermask, uint, layermask_num, S_IRUGO | S_IWUSR);
|
||||
#else
|
||||
module_param_array(protocol, uint, &protocol_num, S_IRUGO | S_IWUSR);
|
||||
module_param_array(layermask, uint, &layermask_num, S_IRUGO | S_IWUSR);
|
||||
#endif
|
||||
MODULE_PARM_DESC (protocol, "sedlfax protcol (DSS1 := 2)");
|
||||
MODULE_PARM_DESC(layermask, "sedlfax layer mask");
|
||||
#endif
|
||||
|
||||
static char SpeedfaxName[] = "Speedfax";
|
||||
|
@ -495,7 +423,8 @@ static char SpeedfaxName[] = "Speedfax";
|
|||
int
|
||||
setup_speedfax(sedl_fax *sf)
|
||||
{
|
||||
int bytecnt, ver;
|
||||
int bytecnt, ver;
|
||||
u_long flags;
|
||||
|
||||
bytecnt = (sf->subtyp == SEDL_SPEEDFAX_ISA) ? 16 : 256;
|
||||
if (!request_region(sf->cfg, bytecnt, (sf->subtyp == SEDL_SPEEDFAX_ISA) ? "sedl PnP" : "sedl PCI")) {
|
||||
|
@ -534,19 +463,18 @@ setup_speedfax(sedl_fax *sf)
|
|||
sf->isar_hw[1].reg = &sf->ir;
|
||||
sf->bch[0].hw = &sf->isar_hw[0];
|
||||
sf->bch[1].hw = &sf->isar_hw[1];
|
||||
sf->bch[0].Read_Reg = &ReadISAR;
|
||||
sf->bch[0].Write_Reg = &WriteISAR;
|
||||
sf->bch[1].Read_Reg = &ReadISAR;
|
||||
sf->bch[1].Write_Reg = &WriteISAR;
|
||||
lock_dev(sf, 0);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "spin_lock_adr=%p now(%p)\n", &sf->lock.spin_adr, sf->lock.spin_adr);
|
||||
printk(KERN_ERR "busy_lock_adr=%p now(%p)\n", &sf->lock.busy_adr, sf->lock.busy_adr);
|
||||
#endif
|
||||
writereg(sf->addr, sf->isar, ISAR_IRQBIT, 0);
|
||||
writereg(sf->addr, sf->isac, ISAC_MASK, 0xFF);
|
||||
sf->bch[0].read_reg = &ReadISAR;
|
||||
sf->bch[0].write_reg = &WriteISAR;
|
||||
sf->bch[0].read_fifo = &ReadISARfifo;
|
||||
sf->bch[0].write_fifo = &WriteISARfifo;
|
||||
sf->bch[1].read_reg = &ReadISAR;
|
||||
sf->bch[1].write_reg = &WriteISAR;
|
||||
sf->bch[1].read_fifo = &ReadISARfifo;
|
||||
sf->bch[1].write_fifo = &WriteISARfifo;
|
||||
spin_lock_irqsave(&sf->lock, flags);
|
||||
disable_hwirq(sf);
|
||||
ver = ISARVersion(&sf->bch[0], "Sedlbauer:");
|
||||
unlock_dev(sf);
|
||||
spin_unlock_irqrestore(&sf->lock, flags);
|
||||
if (ver < 0) {
|
||||
printk(KERN_WARNING
|
||||
"Sedlbauer: wrong ISAR version (ret = %d)\n", ver);
|
||||
|
@ -558,37 +486,33 @@ setup_speedfax(sedl_fax *sf)
|
|||
|
||||
static void
|
||||
release_card(sedl_fax *card) {
|
||||
u_long flags;
|
||||
|
||||
#ifdef LOCK_STATISTIC
|
||||
printk(KERN_INFO "try_ok(%d) try_wait(%d) try_mult(%d) try_inirq(%d)\n",
|
||||
card->lock.try_ok, card->lock.try_wait, card->lock.try_mult, card->lock.try_inirq);
|
||||
printk(KERN_INFO "irq_ok(%d) irq_fail(%d)\n",
|
||||
card->lock.irq_ok, card->lock.irq_fail);
|
||||
#endif
|
||||
lock_dev(card, 0);
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
disable_hwirq(card);
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
free_irq(card->irq, card);
|
||||
spin_lock_irqsave(&card->lock, flags);
|
||||
free_isar(&card->bch[1]);
|
||||
free_isar(&card->bch[0]);
|
||||
mISDN_isac_free(&card->dch);
|
||||
WriteISAR(card, 0, ISAR_IRQBIT, 0);
|
||||
WriteISAC(card, ISAC_MASK, 0xFF);
|
||||
reset_speedfax(card);
|
||||
WriteISAR(card, 0, ISAR_IRQBIT, 0);
|
||||
WriteISAC(card, ISAC_MASK, 0xFF);
|
||||
release_sedlbauer(card);
|
||||
mISDN_free_bch(&card->bch[1]);
|
||||
mISDN_free_bch(&card->bch[0]);
|
||||
mISDN_free_dch(&card->dch);
|
||||
speedfax.ctrl(card->dch.inst.up.peer, MGR_DISCONNECT | REQUEST, &card->dch.inst.up);
|
||||
mISDN_freechannel(&card->bch[1]);
|
||||
mISDN_freechannel(&card->bch[0]);
|
||||
mISDN_freechannel(&card->dch);
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
speedfax.ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
spin_lock_irqsave(&speedfax.lock, flags);
|
||||
list_del(&card->list);
|
||||
unlock_dev(card);
|
||||
spin_unlock_irqrestore(&speedfax.lock, flags);
|
||||
if (card->subtyp == SEDL_SPEEDFAX_ISA) {
|
||||
pnp_disable_dev(card->pdev);
|
||||
pnp_set_drvdata(card->pdev, NULL);
|
||||
#if defined(CONFIG_PNP)
|
||||
pnp_disable_dev(card->dev.pnp);
|
||||
pnp_set_drvdata(card->dev.pnp, NULL);
|
||||
#endif
|
||||
} else {
|
||||
pci_disable_device(card->pdev);
|
||||
pci_set_drvdata(card->pdev, NULL);
|
||||
pci_disable_device(card->dev.pci);
|
||||
pci_set_drvdata(card->dev.pci, NULL);
|
||||
}
|
||||
kfree(card);
|
||||
sedl_cnt--;
|
||||
|
@ -600,15 +524,18 @@ speedfax_manager(void *data, u_int prim, void *arg) {
|
|||
mISDNinstance_t *inst=data;
|
||||
int channel = -1;
|
||||
struct sk_buff *skb;
|
||||
u_long flags;
|
||||
|
||||
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
|
||||
__FUNCTION__, data, prim, arg);
|
||||
if (debug & MISDN_DEBUG_MANAGER)
|
||||
printk(KERN_DEBUG "%s: data:%p prim:%x arg:%p\n",
|
||||
__FUNCTION__, data, prim, arg);
|
||||
if (!data) {
|
||||
MGR_HASPROTOCOL_HANDLER(prim,arg,&speedfax)
|
||||
printk(KERN_ERR "speedfax_manager no data prim %x arg %p\n",
|
||||
prim, arg);
|
||||
return(-EINVAL);
|
||||
}
|
||||
spin_lock_irqsave(&speedfax.lock, flags);
|
||||
list_for_each_entry(card, &speedfax.ilist, list) {
|
||||
if (&card->dch.inst == inst) {
|
||||
channel = 2;
|
||||
|
@ -623,44 +550,42 @@ speedfax_manager(void *data, u_int prim, void *arg) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&speedfax.lock, flags);
|
||||
if (channel<0) {
|
||||
printk(KERN_ERR "speedfax_manager no channel data %p prim %x arg %p\n",
|
||||
data, prim, arg);
|
||||
return(-EINVAL);
|
||||
}
|
||||
if (debug & MISDN_DEBUG_MANAGER)
|
||||
printk(KERN_DEBUG "%s: channel %d\n", __FUNCTION__, channel);
|
||||
switch(prim) {
|
||||
case MGR_REGLAYER | CONFIRM:
|
||||
if (channel == 2)
|
||||
dch_set_para(&card->dch, &inst->st->para);
|
||||
mISDN_setpara(&card->dch, &inst->st->para);
|
||||
else
|
||||
bch_set_para(&card->bch[channel], &inst->st->para);
|
||||
mISDN_setpara(&card->bch[channel], &inst->st->para);
|
||||
break;
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
if (channel == 2) {
|
||||
inst->down.fdata = &card->dch;
|
||||
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
|
||||
HW_DEACTIVATE, 0, NULL, 0))) {
|
||||
if (mISDN_ISAC_l1hw(&inst->down, skb))
|
||||
if ((skb = create_link_skb(PH_CONTROL | REQUEST,
|
||||
HW_DEACTIVATE, 0, NULL, 0))) {
|
||||
if (channel == 2) {
|
||||
if (mISDN_ISAC_l1hw(inst, skb))
|
||||
dev_kfree_skb(skb);
|
||||
} else {
|
||||
if (isar_down(inst, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
} else {
|
||||
inst->down.fdata = &card->bch[channel];
|
||||
if ((skb = create_link_skb(MGR_DISCONNECT | REQUEST,
|
||||
0, 0, NULL, 0))) {
|
||||
if (isar_down(&inst->down, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
speedfax.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
} else
|
||||
printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__);
|
||||
speedfax.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
break;
|
||||
case MGR_CLRSTPARA | INDICATION:
|
||||
arg = NULL;
|
||||
case MGR_ADDSTPARA | INDICATION:
|
||||
if (channel == 2)
|
||||
dch_set_para(&card->dch, arg);
|
||||
mISDN_setpara(&card->dch, arg);
|
||||
else
|
||||
bch_set_para(&card->bch[channel], arg);
|
||||
mISDN_setpara(&card->bch[channel], arg);
|
||||
break;
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (channel == 2) {
|
||||
|
@ -669,6 +594,7 @@ speedfax_manager(void *data, u_int prim, void *arg) {
|
|||
speedfax.refcnt--;
|
||||
}
|
||||
break;
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CONNECT | REQUEST:
|
||||
return(mISDN_ConnectIF(inst, arg));
|
||||
case MGR_SETIF | REQUEST:
|
||||
|
@ -680,6 +606,7 @@ speedfax_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
#endif
|
||||
case MGR_LOADFIRM | REQUEST:
|
||||
{
|
||||
struct firm {
|
||||
|
@ -694,20 +621,20 @@ speedfax_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_LOADFIRM | CONFIRM:
|
||||
speedfax.ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, NULL);
|
||||
break;
|
||||
case MGR_SETSTACK | CONFIRM:
|
||||
case MGR_SETSTACK | INDICATION:
|
||||
if ((channel!=2) && (inst->pid.global == 2)) {
|
||||
inst->down.fdata = &card->bch[channel];
|
||||
// inst->down.fdata = &card->bch[channel];
|
||||
if ((skb = create_link_skb(PH_ACTIVATE | REQUEST,
|
||||
0, 0, NULL, 0))) {
|
||||
if (isar_down(&inst->down, skb))
|
||||
if (isar_down(inst, skb))
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
if ((inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS) ||
|
||||
(inst->pid.protocol[2] == ISDN_PID_L2_B_TRANSDTMF))
|
||||
if_link(&inst->up, DL_ESTABLISH | INDICATION,
|
||||
mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION,
|
||||
0, 0, NULL, 0);
|
||||
else
|
||||
if_link(&inst->up, PH_ACTIVATE | INDICATION,
|
||||
mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION,
|
||||
0, 0, NULL, 0);
|
||||
}
|
||||
break;
|
||||
|
@ -724,40 +651,55 @@ static int __devinit setup_instance(sedl_fax *card)
|
|||
{
|
||||
int i, err;
|
||||
mISDN_pid_t pid;
|
||||
struct device *dev;
|
||||
u_long flags;
|
||||
|
||||
if (sedl_cnt >= MAX_CARDS) {
|
||||
kfree(card);
|
||||
return(-EINVAL);
|
||||
}
|
||||
if (card->subtyp == SEDL_SPEEDFAX_ISA) {
|
||||
#if defined(CONFIG_PNP)
|
||||
dev = &card->dev.pnp->dev;
|
||||
#else
|
||||
dev = NULL;
|
||||
#endif
|
||||
} else {
|
||||
dev = &card->dev.pci->dev;
|
||||
}
|
||||
spin_lock_irqsave(&speedfax.lock, flags);
|
||||
list_add_tail(&card->list, &speedfax.ilist);
|
||||
spin_unlock_irqrestore(&speedfax.lock, flags);
|
||||
card->dch.debug = debug;
|
||||
lock_HW_init(&card->lock);
|
||||
card->dch.inst.lock = lock_dev;
|
||||
card->dch.inst.unlock = unlock_dev;
|
||||
spin_lock_init(&card->lock);
|
||||
card->dch.inst.hwlock = &card->lock;
|
||||
card->dch.inst.pid.layermask = ISDN_LAYER(0);
|
||||
card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0;
|
||||
mISDN_init_instance(&card->dch.inst, &speedfax, card);
|
||||
card->dch.inst.class_dev.dev = dev;
|
||||
mISDN_init_instance(&card->dch.inst, &speedfax, card, mISDN_ISAC_l1hw);
|
||||
sprintf(card->dch.inst.name, "SpeedFax%d", sedl_cnt+1);
|
||||
mISDN_set_dchannel_pid(&pid, protocol[sedl_cnt], layermask[sedl_cnt]);
|
||||
mISDN_init_dch(&card->dch);
|
||||
mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1);
|
||||
for (i=0; i<2; i++) {
|
||||
card->bch[i].channel = i;
|
||||
mISDN_init_instance(&card->bch[i].inst, &speedfax, card);
|
||||
mISDN_init_instance(&card->bch[i].inst, &speedfax, card, isar_down);
|
||||
card->bch[i].inst.pid.layermask = ISDN_LAYER(0);
|
||||
card->bch[i].inst.lock = lock_dev;
|
||||
card->bch[i].inst.unlock = unlock_dev;
|
||||
card->bch[i].inst.hwlock = &card->lock;
|
||||
card->bch[i].debug = debug;
|
||||
card->bch[i].inst.class_dev.dev = dev;
|
||||
sprintf(card->bch[i].inst.name, "%s B%d", card->dch.inst.name, i+1);
|
||||
mISDN_init_bch(&card->bch[i]);
|
||||
mISDN_initchannel(&card->bch[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM);
|
||||
}
|
||||
printk(KERN_DEBUG "sfax card %p dch %p bch1 %p bch2 %p\n",
|
||||
card, &card->dch, &card->bch[0], &card->bch[1]);
|
||||
err = setup_speedfax(card);
|
||||
if (err) {
|
||||
mISDN_free_dch(&card->dch);
|
||||
mISDN_free_bch(&card->bch[1]);
|
||||
mISDN_free_bch(&card->bch[0]);
|
||||
mISDN_freechannel(&card->dch);
|
||||
mISDN_freechannel(&card->bch[1]);
|
||||
mISDN_freechannel(&card->bch[0]);
|
||||
spin_lock_irqsave(&speedfax.lock, flags);
|
||||
list_del(&card->list);
|
||||
spin_unlock_irqrestore(&speedfax.lock, flags);
|
||||
kfree(card);
|
||||
return(err);
|
||||
}
|
||||
|
@ -767,6 +709,7 @@ static int __devinit setup_instance(sedl_fax *card)
|
|||
release_card(card);
|
||||
return(err);
|
||||
}
|
||||
speedfax.ctrl(card->dch.inst.st, MGR_STOPSTACK | REQUEST, NULL);
|
||||
for (i=0; i<2; i++) {
|
||||
err = speedfax.ctrl(card->dch.inst.st, MGR_NEWSTACK | REQUEST, &card->bch[i].inst);
|
||||
if (err) {
|
||||
|
@ -786,6 +729,7 @@ static int __devinit setup_instance(sedl_fax *card)
|
|||
speedfax.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, NULL);
|
||||
return(err);
|
||||
}
|
||||
speedfax.ctrl(card->dch.inst.st, MGR_STARTSTACK | REQUEST, NULL);
|
||||
printk(KERN_INFO "SpeedFax %d cards installed\n", sedl_cnt);
|
||||
return(0);
|
||||
}
|
||||
|
@ -800,7 +744,7 @@ static int __devinit sedlpci_probe(struct pci_dev *pdev, const struct pci_device
|
|||
return(err);
|
||||
}
|
||||
memset(card, 0, sizeof(sedl_fax));
|
||||
card->pdev = pdev;
|
||||
card->dev.pci = pdev;
|
||||
if (PCI_SUBVENDOR_SPEEDFAX_PYRAMID == pdev->subsystem_vendor)
|
||||
card->subtyp = SEDL_SPEEDFAX_PYRAMID;
|
||||
else
|
||||
|
@ -842,7 +786,7 @@ static int __devinit sedlpnp_probe(struct pci_dev *pdev, const struct isapnp_dev
|
|||
}
|
||||
memset(card, 0, sizeof(sedl_fax));
|
||||
card->subtyp = SEDL_SPEEDFAX_ISA;
|
||||
card->pdev = pdev;
|
||||
card->dev.pnp = pdev;
|
||||
pnp_disable_dev(pdev);
|
||||
err = pnp_activate_dev(pdev);
|
||||
if (err<0) {
|
||||
|
@ -945,6 +889,7 @@ static int __init Speedfax_init(void)
|
|||
#ifdef MODULE
|
||||
speedfax.owner = THIS_MODULE;
|
||||
#endif
|
||||
spin_lock_init(&speedfax.lock);
|
||||
INIT_LIST_HEAD(&speedfax.ilist);
|
||||
speedfax.name = SpeedfaxName;
|
||||
speedfax.own_ctrl = speedfax_manager;
|
||||
|
@ -989,7 +934,9 @@ static int __init Speedfax_init(void)
|
|||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#if defined(CONFIG_PNP)
|
||||
out_unregister_pci:
|
||||
#endif
|
||||
pci_unregister_driver(&sedlpci_driver);
|
||||
out:
|
||||
return err;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -175,6 +175,22 @@ static __inline__ int capiGetFacReqCFInterrogateNumbers(__u8 *p, __u8 *_end, str
|
|||
return(len + 1);
|
||||
}
|
||||
|
||||
static __inline__ int capiGetFacReqCD(__u8 *p, __u8 *_end, struct FacReqCDeflection *CD)
|
||||
{
|
||||
int len = *p++;
|
||||
int ret;
|
||||
__u8 *end = p + len;
|
||||
|
||||
if (end > _end) return -1;
|
||||
|
||||
CAPI_GET(capiGetWord, &CD->PresentationAllowed);
|
||||
CAPI_GET(capiGetStruct, &CD->DeflectedToNumber);
|
||||
CAPI_GET(capiGetStruct, &CD->DeflectedToSubaddress);
|
||||
|
||||
if (p != end) return -1;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ int capiGetFacReqParm(__u8 *p, struct FacReqParm *facReqParm)
|
||||
{
|
||||
|
@ -209,6 +225,9 @@ static __inline__ int capiGetFacReqParm(__u8 *p, struct FacReqParm *facReqParm)
|
|||
case 0x000c: // CF Interrogate Numbers
|
||||
CAPI_GET(capiGetFacReqCFInterrogateNumbers, &facReqParm->u.CFInterrogateNumbers);
|
||||
break;
|
||||
case 0x000d: // CD
|
||||
CAPI_GET(capiGetFacReqCD, &facReqParm->u.CDeflection);
|
||||
break;
|
||||
default:
|
||||
return(len + 1);
|
||||
}
|
||||
|
@ -255,7 +274,7 @@ FacCFInterrogateParameters(Application_t *appl, FacReqParm_t *facReqParm, FacCon
|
|||
|
||||
p = encodeInvokeComponentHead(sspc->buf);
|
||||
p += encodeInt(p, sspc->invokeId);
|
||||
p += encodeInt(p, 0x0b); // interrogationDiversion
|
||||
p += encodeInt(p, 11); // interrogationDiversion
|
||||
p += encodeInterrogationDiversion(p, &facReqParm->u.CFInterrogateParameters);
|
||||
encodeInvokeComponentLength(sspc->buf, p);
|
||||
mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
|
||||
|
@ -285,7 +304,7 @@ FacCFInterrogateNumbers(Application_t *appl, FacReqParm_t *facReqParm, FacConfPa
|
|||
|
||||
p = encodeInvokeComponentHead(sspc->buf);
|
||||
p += encodeInt(p, sspc->invokeId);
|
||||
p += encodeInt(p, 0x11); // InterrogateServedUserNumbers
|
||||
p += encodeInt(p, 17); // InterrogateServedUserNumbers
|
||||
encodeInvokeComponentLength(sspc->buf, p);
|
||||
mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
|
||||
SSProcess_L4L3(sspc, CC_FACILITY | REQUEST, skb);
|
||||
|
@ -311,7 +330,7 @@ FacCFActivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *facC
|
|||
}
|
||||
p = encodeInvokeComponentHead(sspc->buf);
|
||||
p += encodeInt(p, sspc->invokeId);
|
||||
p += encodeInt(p, 0x07); // activationDiversion
|
||||
p += encodeInt(p, 7); // activationDiversion
|
||||
p += encodeActivationDiversion(p, &facReqParm->u.CFActivate);
|
||||
encodeInvokeComponentLength(sspc->buf, p);
|
||||
mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
|
||||
|
@ -338,7 +357,7 @@ FacCFDeactivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *fa
|
|||
}
|
||||
p = encodeInvokeComponentHead(sspc->buf);
|
||||
p += encodeInt(p, sspc->invokeId);
|
||||
p += encodeInt(p, 0x08); // dectivationDiversion
|
||||
p += encodeInt(p, 8); // dectivationDiversion
|
||||
p += encodeDeactivationDiversion(p, &facReqParm->u.CFDeactivate);
|
||||
encodeInvokeComponentLength(sspc->buf, p);
|
||||
mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
|
||||
|
@ -350,6 +369,33 @@ FacCFDeactivate(Application_t *appl, FacReqParm_t *facReqParm, FacConfParm_t *fa
|
|||
return CapiSuccess;
|
||||
}
|
||||
|
||||
static int
|
||||
FacCDeflection(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm)
|
||||
{
|
||||
SSProcess_t *sspc;
|
||||
struct sk_buff *skb = mISDN_alloc_l3msg(260, MT_FACILITY);
|
||||
__u8 *p;
|
||||
|
||||
if (!skb)
|
||||
return CAPI_MSGOSRESOURCEERR;
|
||||
sspc = SSProcessConstr(aplci->appl, facReqParm->Function, facReqParm->u.CFActivate.Handle);
|
||||
if (!sspc) {
|
||||
kfree_skb(skb);
|
||||
return CAPI_MSGOSRESOURCEERR;
|
||||
}
|
||||
p = encodeInvokeComponentHead(sspc->buf);
|
||||
p += encodeInt(p, sspc->invokeId);
|
||||
p += encodeInt(p, 13); // Calldefection
|
||||
p += encodeInvokeDeflection(p, &facReqParm->u.CDeflection);
|
||||
encodeInvokeComponentLength(sspc->buf, p);
|
||||
mISDN_AddIE(skb, IE_FACILITY, sspc->buf);
|
||||
if (aplci->plci)
|
||||
plciL4L3(aplci->plci, CC_FACILITY | REQUEST, skb);
|
||||
SSProcessAddTimer(sspc, T_ACTIVATE);
|
||||
facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess;
|
||||
return CapiSuccess;
|
||||
}
|
||||
|
||||
void
|
||||
SupplementaryFacilityReq(Application_t *appl, _cmsg *cmsg)
|
||||
{
|
||||
|
@ -373,6 +419,22 @@ SupplementaryFacilityReq(Application_t *appl, _cmsg *cmsg)
|
|||
case 0x0001: // Listen
|
||||
Info = FacListen(appl, &facReqParm, &facConfParm);
|
||||
break;
|
||||
case 0x0002: // Hold
|
||||
aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
|
||||
if (!aplci) {
|
||||
Info = CapiIllContrPlciNcci;
|
||||
break;
|
||||
}
|
||||
Info = AppPlciFacHoldReq(aplci, &facReqParm, &facConfParm);
|
||||
break;
|
||||
case 0x0003: // Retrieve
|
||||
aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
|
||||
if (!aplci) {
|
||||
Info = CapiIllContrPlciNcci;
|
||||
break;
|
||||
}
|
||||
Info = AppPlciFacRetrieveReq(aplci, &facReqParm, &facConfParm);
|
||||
break;
|
||||
case 0x0004: // Suspend
|
||||
aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
|
||||
if (!aplci) {
|
||||
|
@ -409,6 +471,14 @@ SupplementaryFacilityReq(Application_t *appl, _cmsg *cmsg)
|
|||
case 0x000c: // CF Interrogate Numbers
|
||||
Info = FacCFInterrogateNumbers(appl, &facReqParm, &facConfParm);
|
||||
break;
|
||||
case 0x000d: // CD
|
||||
aplci = getAppPlci4addr(appl, cmsg->adr.adrPLCI);
|
||||
if (!aplci) {
|
||||
Info = CapiIllContrPlciNcci;
|
||||
break;
|
||||
}
|
||||
Info = FacCDeflection(aplci, &facReqParm, &facConfParm);
|
||||
break;
|
||||
default:
|
||||
Info = CapiSuccess;
|
||||
facConfParm.u.Info.SupplementaryServiceInfo = CapiSupplementaryServiceNotSupported;
|
||||
|
@ -457,6 +527,40 @@ SendSSFacilityInd(Application_t *appl, __u32 addr, __u8 *para)
|
|||
SendCmsg2Application(appl, cmsg);
|
||||
}
|
||||
|
||||
void
|
||||
SendSSNotificationEvent(AppPlci_t *aplci, u16 event)
|
||||
{
|
||||
__u8 tmp[4], *p;
|
||||
|
||||
if (!aplci->appl)
|
||||
return;
|
||||
switch (event) {
|
||||
case 0x8000: // user hold
|
||||
case 0x8001: // user retrieve
|
||||
if (!(aplci->appl->NotificationMask & SuppServiceHR))
|
||||
return;
|
||||
break;
|
||||
case 0x8002: // user suspended
|
||||
case 0x8003: // user resumed
|
||||
if (!(aplci->appl->NotificationMask & SuppServiceTP))
|
||||
return;
|
||||
break;
|
||||
case 0x8004: // call is diverting
|
||||
case 0x8005: // diversion activated
|
||||
if (!(aplci->appl->NotificationMask & SuppServiceCF))
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
int_errtxt("Event %x not known\n", event);
|
||||
return;
|
||||
}
|
||||
p = &tmp[1];
|
||||
p += capiEncodeWord(p, event); // Suspend/Resume Notification
|
||||
*p++ = 0; // empty struct
|
||||
tmp[0] = p - &tmp[1];
|
||||
SendSSFacilityInd(aplci->appl, aplci->addr, tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
SendSSFacilityInd2All(Controller_t *contr, __u32 nMask, __u8 *para)
|
||||
{
|
||||
|
@ -503,10 +607,10 @@ void SSProcessAddTimer(SSProcess_t *sspc, int msec)
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
#ifdef ASN1_DEBUG
|
||||
void printPublicPartyNumber(struct PublicPartyNumber *publicPartyNumber)
|
||||
{
|
||||
printk("(%d) %s\n", publicPartyNumber->publicTypeOfNumber,
|
||||
printk(KERN_DEBUG "(%d) %s\n", publicPartyNumber->publicTypeOfNumber,
|
||||
publicPartyNumber->numberDigits);
|
||||
}
|
||||
|
||||
|
@ -514,7 +618,7 @@ void printPartyNumber(struct PartyNumber *partyNumber)
|
|||
{
|
||||
switch (partyNumber->type) {
|
||||
case 0:
|
||||
printk("unknown %s\n", partyNumber->p.unknown);
|
||||
printk(KERN_DEBUG "unknown %s\n", partyNumber->p.unknown);
|
||||
break;
|
||||
case 1:
|
||||
printPublicPartyNumber(&partyNumber->p.publicPartyNumber);
|
||||
|
@ -541,63 +645,41 @@ void printAddress(struct Address *address)
|
|||
#endif
|
||||
|
||||
static void
|
||||
SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
|
||||
SSProcessSingleFacility(Controller_t *contr, struct asn1_parm *parm)
|
||||
{
|
||||
Application_t *appl;
|
||||
int ie_len;
|
||||
struct asn1_parm parm;
|
||||
SSProcess_t *sspc;
|
||||
__u8 tmp[256];
|
||||
__u8 *p, *end;
|
||||
__u8 *p, tmp[256];
|
||||
|
||||
if (!qi || !qi->facility) {
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
p = (__u8 *)qi;
|
||||
p += L3_EXTRA_SIZE + qi->facility;
|
||||
p++;
|
||||
ie_len = *p++;
|
||||
end = p + ie_len;
|
||||
// if (end > skb->data + skb->len) {
|
||||
// int_error();
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (*p++ != 0x91) { // Supplementary Service Applications
|
||||
int_error();
|
||||
return;
|
||||
}
|
||||
ParseComponent(&parm, p, end);
|
||||
switch (parm.comp) {
|
||||
switch (parm->comp) {
|
||||
case invoke:
|
||||
#if 0
|
||||
printk("invokeId %d\n", parm.u.inv.invokeId);
|
||||
printk("operationValue %d\n", parm.u.inv.operationValue);
|
||||
#ifdef ASN1_DEBUG
|
||||
printk("invokeId %d\n", parm->u.inv.invokeId);
|
||||
printk("operationValue %d\n", parm->u.inv.operationValue);
|
||||
#endif
|
||||
switch (parm.u.inv.operationValue) {
|
||||
switch (parm->u.inv.operationValue) {
|
||||
case 0x0009:
|
||||
#if 0
|
||||
printk("procedure %d basicService %d\n", parm.c.inv.o.actNot.procedure,
|
||||
parm.c.inv.o.actNot.basicService);
|
||||
printServedUserNr(&parm.c.inv.o.actNot.servedUserNr);
|
||||
printAddress(&parm.c.inv.o.actNot.address);
|
||||
#ifdef ASN1_DEBUG
|
||||
printk("procedure %d basicService %d\n", parm->u.inv.o.actNot.procedure,
|
||||
parm->u.inv.o.actNot.basicService);
|
||||
printServedUserNr(&parm->u.inv.o.actNot.servedUserNr);
|
||||
printAddress(&parm->u.inv.o.actNot.address);
|
||||
#endif
|
||||
p = &tmp[1];
|
||||
p += capiEncodeWord(p, 0x8006);
|
||||
p += capiEncodeFacIndCFNotAct(p, &parm.u.inv.o.actNot);
|
||||
p += capiEncodeFacIndCFNotAct(p, &parm->u.inv.o.actNot);
|
||||
tmp[0] = p - &tmp[1];
|
||||
SendSSFacilityInd2All(contr, SuppServiceCF, tmp);
|
||||
break;
|
||||
case 0x000a:
|
||||
#if 0
|
||||
printk("procedure %d basicService %d\n", parm.c.inv.o.deactNot.procedure,
|
||||
parm.c.inv.o.deactNot.basicService);
|
||||
printServedUserNr(&parm.c.inv.o.deactNot.servedUserNr);
|
||||
#ifdef ASN1_DEBUG
|
||||
printk("procedure %d basicService %d\n", parm->u.inv.o.deactNot.procedure,
|
||||
parm->u.inv.o.deactNot.basicService);
|
||||
printServedUserNr(&parm->u.inv.o.deactNot.servedUserNr);
|
||||
#endif
|
||||
p = &tmp[1];
|
||||
p += capiEncodeWord(p, 0x8007);
|
||||
p += capiEncodeFacIndCFNotDeact(p, &parm.u.inv.o.deactNot);
|
||||
p += capiEncodeFacIndCFNotDeact(p, &parm->u.inv.o.deactNot);
|
||||
tmp[0] = p - &tmp[1];
|
||||
SendSSFacilityInd2All(contr, SuppServiceCF, tmp);
|
||||
break;
|
||||
|
@ -606,7 +688,7 @@ SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
|
|||
}
|
||||
break;
|
||||
case returnResult:
|
||||
sspc = getSSProcess4Id(contr, parm.u.retResult.invokeId);
|
||||
sspc = getSSProcess4Id(contr, parm->u.retResult.invokeId);
|
||||
if (!sspc)
|
||||
return;
|
||||
appl = getApplication4Id(contr, sspc->ApplId);
|
||||
|
@ -623,14 +705,14 @@ SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
|
|||
break;
|
||||
case 0x000b:
|
||||
p += capiEncodeFacIndCFinterParameters(p, 0, sspc->Handle,
|
||||
&parm.u.retResult.o.resultList);
|
||||
&parm->u.retResult.o.resultList);
|
||||
break;
|
||||
case 0x000c:
|
||||
p += capiEncodeFacIndCFinterNumbers(p, 0, sspc->Handle,
|
||||
&parm.u.retResult.o.list);
|
||||
&parm->u.retResult.o.list);
|
||||
break;
|
||||
default:
|
||||
int_error();
|
||||
int_errtxt("returnResult for Function %04x", sspc->Function);
|
||||
break;
|
||||
}
|
||||
tmp[0] = p - &tmp[1];
|
||||
|
@ -638,7 +720,7 @@ SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
|
|||
SSProcessDestr(sspc);
|
||||
break;
|
||||
case returnError:
|
||||
sspc = getSSProcess4Id(contr, parm.u.retResult.invokeId);
|
||||
sspc = getSSProcess4Id(contr, parm->u.retResult.invokeId);
|
||||
if (!sspc)
|
||||
return;
|
||||
appl = getApplication4Id(contr, sspc->ApplId);
|
||||
|
@ -646,19 +728,77 @@ SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
|
|||
return;
|
||||
p = &tmp[1];
|
||||
p += capiEncodeWord(p, sspc->Function);
|
||||
p += capiEncodeFacIndCFact(p, 0x3600 | (parm.u.retError.errorValue & 0xff),
|
||||
p += capiEncodeFacIndCFact(p, 0x3600 | (parm->u.retError.errorValue & 0xff),
|
||||
sspc->Handle);
|
||||
tmp[0] = p - &tmp[1];
|
||||
SendSSFacilityInd(appl, sspc->addr, tmp);
|
||||
SSProcessDestr(sspc);
|
||||
break;
|
||||
default: {
|
||||
static char logbuf[512];
|
||||
|
||||
int_errtxt("component %x not handled", parm.comp);
|
||||
mISDN_QuickHex(logbuf, p, ie_len);
|
||||
printk(KERN_DEBUG "facIE: %s\n", logbuf);
|
||||
case reject:
|
||||
if (parm->u.reject.invokeId == -1) /* ID := NULL */
|
||||
return;
|
||||
if (parm->u.reject.problem != InvokeP) {
|
||||
int_errtxt("reject problem class %d problem %d do not match CAPI errors",
|
||||
parm->u.reject.problem, parm->u.reject.problemValue);
|
||||
/* this is not compatible, but better as ignore */
|
||||
switch (parm->u.reject.problem) {
|
||||
case GeneralP:
|
||||
parm->u.reject.problemValue |= 0x80;
|
||||
break;
|
||||
default:
|
||||
parm->u.reject.problemValue |= (parm->u.reject.problem << 4);
|
||||
}
|
||||
}
|
||||
sspc = getSSProcess4Id(contr, parm->u.reject.invokeId);
|
||||
if (!sspc)
|
||||
return;
|
||||
appl = getApplication4Id(contr, sspc->ApplId);
|
||||
if (!appl)
|
||||
return;
|
||||
p = &tmp[1];
|
||||
p += capiEncodeWord(p, sspc->Function);
|
||||
p += capiEncodeFacIndCFact(p, 0x3700 | (parm->u.reject.problemValue & 0xff),
|
||||
sspc->Handle);
|
||||
tmp[0] = p - &tmp[1];
|
||||
SendSSFacilityInd(appl, sspc->addr, tmp);
|
||||
SSProcessDestr(sspc);
|
||||
break;
|
||||
default:
|
||||
int_errtxt("component %x not handled", parm->comp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SSProcessFacility(Controller_t *contr, __u8 *p)
|
||||
{
|
||||
int ie_len, l;
|
||||
struct asn1_parm parm;
|
||||
__u8 *end;
|
||||
|
||||
ie_len = *p++;
|
||||
end = p + ie_len;
|
||||
|
||||
p++; // Supplementary Service Applications checked before
|
||||
|
||||
while (p < end) {
|
||||
parm.comp = -1;
|
||||
l = ParseComponent(&parm, p, end);
|
||||
// printk(KERN_DEBUG "ie_len (%d) l(%d) parm.comp %d\n", ie_len, l, parm.comp);
|
||||
if (parm.comp != -1) {
|
||||
SSProcessSingleFacility(contr, &parm);
|
||||
} else {
|
||||
static char logbuf[3*260];
|
||||
|
||||
int_errtxt("component %x not handled", parm.comp);
|
||||
if (ie_len > 260)
|
||||
ie_len = 260;
|
||||
mISDN_QuickHex(logbuf, p, ie_len);
|
||||
printk(KERN_DEBUG "facIE: %s\n", logbuf);
|
||||
}
|
||||
if (l>0)
|
||||
p += l;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -666,14 +806,42 @@ SSProcessFacility(Controller_t *contr, Q931_info_t *qi)
|
|||
int
|
||||
Supplementary_l3l4(Controller_t *contr, __u32 prim, struct sk_buff *skb)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int ret = -EINVAL;
|
||||
Q931_info_t *qi;
|
||||
ie_info_t *fac;
|
||||
__u8 *p, *end;
|
||||
|
||||
if (!skb)
|
||||
return(ret);
|
||||
switch (prim) {
|
||||
case CC_FACILITY | INDICATION:
|
||||
if (skb->len)
|
||||
SSProcessFacility(contr, (Q931_info_t *)skb->data);
|
||||
qi = (Q931_info_t *)skb->data;
|
||||
if (skb->len <= L3_EXTRA_SIZE) {
|
||||
int_error();
|
||||
break;
|
||||
}
|
||||
if (!qi->facility.off) {
|
||||
int_error();
|
||||
break;
|
||||
}
|
||||
fac = &qi->facility;
|
||||
while(fac && fac->off) {
|
||||
p = (__u8 *)qi;
|
||||
p += L3_EXTRA_SIZE + fac->off + 1;
|
||||
end = p + *p;
|
||||
if (end > skb->data + skb->len) {
|
||||
int_error();
|
||||
fac = NULL;
|
||||
} else if (p[1] == 0x91) { // Supplementary Service Applications
|
||||
SSProcessFacility(contr, p);
|
||||
} else {
|
||||
int_errtxt("FACILITY but not a Supplementary Service ID %x", p[1]);
|
||||
}
|
||||
if (fac->repeated)
|
||||
fac = &qi->ext[fac->ridx].ie;
|
||||
else
|
||||
fac = NULL;
|
||||
}
|
||||
dev_kfree_skb(skb);
|
||||
ret = 0;
|
||||
break;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Linux modular ISDN subsystem, mISDN
|
||||
* X.25/X.31 Layer3 for DTE mode
|
||||
* X.25/X.31 Layer3 for DTE mode
|
||||
*
|
||||
* Author Karsten Keil (kkeil@suse.de)
|
||||
*
|
||||
|
@ -370,7 +370,7 @@ static struct FsmNode PFnList[] =
|
|||
{ST_P0, EV_L3_OUTGOING_CALL, p_p0_outgoing},
|
||||
{ST_P0, EV_L3_CLEARING, p_clearing_req},
|
||||
{ST_P1, EV_L3_READY, p_ready},
|
||||
{ST_P1, EV_L3_OUTGOING_CALL, p_outgoing},
|
||||
{ST_P1, EV_L3_OUTGOING_CALL, p_outgoing},
|
||||
{ST_P1, EV_L2_INCOMING_CALL, p_incoming},
|
||||
{ST_P1, EV_L2_CLEAR, p_clear_ind},
|
||||
{ST_P1, EV_L2_CALL_CNF, p_invalid_pkt},
|
||||
|
@ -493,7 +493,7 @@ d_reset_timeout(struct FsmInst *fi, int event, void *arg)
|
|||
l3c->cause[1] = 51;
|
||||
mISDN_FsmChangeState(fi, ST_D0);
|
||||
if (test_bit(X25_STATE_PERMANENT, &l3c->state))
|
||||
X25_clear_connection(l3c, NULL, 0x3303);
|
||||
X25_clear_connection(l3c, NULL, 0x3303);
|
||||
else
|
||||
mISDN_FsmEvent(&l3c->x25p, EV_L3_CLEARING, NULL);
|
||||
}
|
||||
|
@ -660,7 +660,7 @@ dte_data_ind_d(x25_channel_t *chan, struct sk_buff *skb, u_char gfi, u_char ptyp
|
|||
mISDN_FsmEvent(&chan->x25d, EV_L3_RESETING, NULL);
|
||||
} else {
|
||||
int flag = (pr_m & 1) ? CAPI_FLAG_MOREDATA : 0;
|
||||
|
||||
|
||||
if (gfi & X25_GFI_QBIT)
|
||||
flag |= CAPI_FLAG_QUALIFIER;
|
||||
if (gfi & X25_GFI_DBIT)
|
||||
|
@ -755,7 +755,7 @@ dte_data_ind_r(x25_l3_t *l3, struct sk_buff *skb, u_char gfi, __u16 channel, u_c
|
|||
{
|
||||
int ret = X25_ERRCODE_DISCARD;
|
||||
|
||||
|
||||
|
||||
if (ptype == X25_PTYPE_NOTYPE) {
|
||||
if (channel) {
|
||||
if (l3->x25r.state == ST_R1)
|
||||
|
@ -851,19 +851,10 @@ dte_dl_data_ind(x25_l3_t *l3, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static int
|
||||
dte_from_down(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dte_from_down(x25_l3_t *l3, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
x25_l3_t *l3;
|
||||
mISDN_head_t *hh;
|
||||
int ret = -EINVAL;
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(ret);
|
||||
l3 = hif->fdata;
|
||||
if (!l3->inst.up.func) {
|
||||
return(-ENXIO);
|
||||
}
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
if (l3->debug)
|
||||
printk(KERN_DEBUG "%s: prim(%x) dinfo(%x)\n", __FUNCTION__, hh->prim, hh->dinfo);
|
||||
switch(hh->prim) {
|
||||
|
@ -917,7 +908,7 @@ dte_create_channel(x25_l3_t *l3, int typ, u_char flag, __u16 ch, int len, u_char
|
|||
x25_channel_t *l3c;
|
||||
__u16 nch = ch;
|
||||
int ret;
|
||||
|
||||
|
||||
if (typ == X25_CHANNEL_OUTGOING) {
|
||||
if (ch == 0) {
|
||||
/* first search for allready created channels in P1 state */
|
||||
|
@ -1035,38 +1026,13 @@ dte_create_channel(x25_l3_t *l3, int typ, u_char flag, __u16 ch, int len, u_char
|
|||
}
|
||||
|
||||
static int
|
||||
new_l3(mISDNstack_t *st, mISDN_pid_t *pid) {
|
||||
x25_l3_t *n_l3;
|
||||
int err;
|
||||
|
||||
err = new_x25_l3(&n_l3, st, pid, &x25dte_obj, debug);
|
||||
if (err)
|
||||
return(err);
|
||||
|
||||
n_l3->x25r.fsm = &dte_rfsm;
|
||||
n_l3->x25r.state = ST_R0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
dte_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
||||
dte_from_up(x25_l3_t *l3, struct sk_buff *skb, mISDN_head_t *hh)
|
||||
{
|
||||
x25_l3_t *l3;
|
||||
x25_channel_t *l3c;
|
||||
mISDN_head_t *hh;
|
||||
__u32 addr;
|
||||
__u16 info = 0;
|
||||
int err = 0;
|
||||
|
||||
if (!hif || !hif->fdata || !skb)
|
||||
return(-EINVAL);
|
||||
l3 = hif->fdata;
|
||||
if (!l3->inst.down.func) {
|
||||
return(-ENXIO);
|
||||
}
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
if (l3->debug)
|
||||
printk(KERN_DEBUG "%s: prim(%x) dinfo(%x) len(%d)\n", __FUNCTION__, hh->prim, hh->dinfo, skb->len);
|
||||
if (skb->len < 4) {
|
||||
printk(KERN_WARNING "%s: skb too short (%d)\n", __FUNCTION__, skb->len);
|
||||
return(-EINVAL);
|
||||
|
@ -1103,7 +1069,7 @@ dte_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
ncpi = (x25_ncpi_t *)skb->data;
|
||||
l3c = dte_create_channel(l3, X25_CHANNEL_OUTGOING, ncpi->Flags,
|
||||
(ncpi->Group<<8) | ncpi->Channel,
|
||||
ncpi->len - 3, &ncpi->Contens[0]);
|
||||
ncpi->len - 3, &ncpi->Contens[0]);
|
||||
}
|
||||
if (l3c)
|
||||
l3c->ncci = addr | (l3c->lchan << 16);
|
||||
|
@ -1166,7 +1132,7 @@ dte_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
info = 0;
|
||||
} else
|
||||
info = 0x2002;
|
||||
|
||||
|
||||
skb_trim(skb, 0);
|
||||
memcpy(skb_put(skb, 2), &info, 2);
|
||||
err = X25sendL4skb(l3c, l3, addr, CAPI_DISCONNECT_B3_CONF, hh->dinfo, skb);
|
||||
|
@ -1235,6 +1201,56 @@ dte_from_up(mISDNif_t *hif, struct sk_buff *skb)
|
|||
return(err);
|
||||
}
|
||||
|
||||
static int
|
||||
dte_function(mISDNinstance_t *inst, struct sk_buff *skb)
|
||||
{
|
||||
x25_l3_t *l3;
|
||||
mISDN_head_t *hh;
|
||||
int ret = -EINVAL;
|
||||
|
||||
l3 = inst->privat;
|
||||
hh = mISDN_HEAD_P(skb);
|
||||
if (l3->debug)
|
||||
printk(KERN_DEBUG "%s: addr(%08x) prim(%x) dinfo(%x) len(%d)\n", __FUNCTION__,
|
||||
hh->addr, hh->prim, hh->dinfo, skb->len);
|
||||
if (debug)
|
||||
printk(KERN_DEBUG "%s: addr(%08x) prim(%x)\n", __FUNCTION__, hh->addr, hh->prim);
|
||||
if (!l3)
|
||||
return(ret);
|
||||
|
||||
switch(hh->addr & MSG_DIR_MASK) {
|
||||
case FLG_MSG_DOWN:
|
||||
ret = dte_from_up(l3, skb, hh);
|
||||
break;
|
||||
case FLG_MSG_UP:
|
||||
case MSG_BROADCAST: // we define broaadcast comes from down below
|
||||
ret = dte_from_down(l3, skb, hh);
|
||||
break;
|
||||
case MSG_TO_OWNER:
|
||||
/* FIXME: must be handled depending on type */
|
||||
int_errtxt("not implemented yet");
|
||||
break;
|
||||
default:
|
||||
/* FIXME: must be handled depending on type */
|
||||
int_errtxt("not implemented yet");
|
||||
break;
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static int
|
||||
new_l3(mISDNstack_t *st, mISDN_pid_t *pid) {
|
||||
x25_l3_t *n_l3;
|
||||
int err;
|
||||
|
||||
err = new_x25_l3(&n_l3, st, pid, &x25dte_obj, debug, dte_function);
|
||||
if (err)
|
||||
return(err);
|
||||
n_l3->x25r.fsm = &dte_rfsm;
|
||||
n_l3->x25r.state = ST_R0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static char MName[] = "X25_DTE";
|
||||
|
||||
|
@ -1251,17 +1267,20 @@ dte_manager(void *data, u_int prim, void *arg) {
|
|||
mISDNinstance_t *inst = data;
|
||||
x25_l3_t *l3_l;
|
||||
int err = -EINVAL;
|
||||
u_long flags;
|
||||
|
||||
if (debug & DEBUG_L3X25_MGR)
|
||||
printk(KERN_DEBUG "l3x25_manager data:%p prim:%x arg:%p\n", data, prim, arg);
|
||||
if (!data)
|
||||
return(err);
|
||||
spin_lock_irqsave(&x25dte_obj.lock, flags);
|
||||
list_for_each_entry(l3_l, &x25dte_obj.ilist, list) {
|
||||
if (&l3_l->inst == inst) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&x25dte_obj.lock, flags);
|
||||
if (prim == (MGR_NEWLAYER | REQUEST))
|
||||
return(new_l3(data, arg));
|
||||
if (err) {
|
||||
|
@ -1270,7 +1289,7 @@ dte_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
switch(prim) {
|
||||
case MGR_NEWENTITY | CONFIRM:
|
||||
l3_l->entity = (int)arg;
|
||||
l3_l->entity = (u_long)arg & 0xffffffff;
|
||||
break;
|
||||
case MGR_ADDSTPARA | INDICATION:
|
||||
{
|
||||
|
@ -1285,6 +1304,7 @@ dte_manager(void *data, u_int prim, void *arg) {
|
|||
}
|
||||
break;
|
||||
case MGR_CLRSTPARA | INDICATION:
|
||||
#ifdef OBSOLETE
|
||||
case MGR_CLONELAYER | REQUEST:
|
||||
break;
|
||||
case MGR_CONNECT | REQUEST:
|
||||
|
@ -1295,6 +1315,7 @@ dte_manager(void *data, u_int prim, void *arg) {
|
|||
case MGR_DISCONNECT | REQUEST:
|
||||
case MGR_DISCONNECT | INDICATION:
|
||||
return(mISDN_DisConnectIF(inst, arg));
|
||||
#endif
|
||||
case MGR_UNREGLAYER | REQUEST:
|
||||
case MGR_RELEASE | INDICATION:
|
||||
if (debug & DEBUG_L3X25_MGR)
|
||||
|
@ -1323,6 +1344,7 @@ x25_dte_init(void)
|
|||
x25dte_obj.name = MName;
|
||||
x25dte_obj.BPROTO.protocol[3] = ISDN_PID_L3_B_X25DTE;
|
||||
x25dte_obj.own_ctrl = dte_manager;
|
||||
spin_lock_init(&x25dte_obj.lock);
|
||||
INIT_LIST_HEAD(&x25dte_obj.ilist);
|
||||
if ((err = mISDN_register(&x25dte_obj))) {
|
||||
printk(KERN_ERR "Can't register %s error(%d)\n", MName, err);
|
||||
|
|
|
@ -286,14 +286,11 @@ X25_restart(x25_l3_t *l3)
|
|||
int
|
||||
X25_next_id(x25_l3_t *l3)
|
||||
{
|
||||
u_long flags;
|
||||
int id;
|
||||
|
||||
spin_lock_irqsave(&l3->lock, flags);
|
||||
id = l3->next_id++;
|
||||
if (id == 0x0fff)
|
||||
l3->next_id = 1;
|
||||
spin_unlock_irqrestore(&l3->lock, flags);
|
||||
id |= (l3->entity << 16);
|
||||
return(id);
|
||||
}
|
||||
|
@ -378,7 +375,7 @@ X25_confirmed(x25_channel_t *chan)
|
|||
i = cq->MsgId;
|
||||
/* free entry */
|
||||
cq->PktId = 0;
|
||||
ret = if_newhead(&chan->l3->inst.up, CAPI_DATA_B3_CONF, i, skb);
|
||||
ret = mISDN_queueup_newhead(&chan->l3->inst, 0, CAPI_DATA_B3_CONF, i, skb);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "%s: up error %d\n", __FUNCTION__, ret);
|
||||
dev_kfree_skb(skb);
|
||||
|
@ -453,7 +450,7 @@ X25_receive_data(x25_channel_t *chan, int ps, int flag, struct sk_buff *skb)
|
|||
capimsg_setu16(nskb->data, 10, i);
|
||||
capimsg_setu16(nskb->data, 12, flag);
|
||||
|
||||
if (if_newhead(&chan->l3->inst.up, CAPI_DATA_B3_IND, 0, nskb)) {
|
||||
if (mISDN_queueup_newhead(&chan->l3->inst, 0, CAPI_DATA_B3_IND, 0, nskb)) {
|
||||
chan->recv_handles[i] = 0;
|
||||
return(X25_ERRCODE_DISCARD);
|
||||
}
|
||||
|
@ -539,8 +536,7 @@ void
|
|||
X25_release_channel(x25_channel_t *l3c)
|
||||
{
|
||||
list_del(&l3c->list);
|
||||
if (l3c->ncpi_data)
|
||||
kfree(l3c->ncpi_data);
|
||||
kfree(l3c->ncpi_data);
|
||||
l3c->ncpi_data = NULL;
|
||||
l3c->ncpi_len = 0;
|
||||
discard_queue(&l3c->dataq);
|
||||
|
@ -548,10 +544,7 @@ X25_release_channel(x25_channel_t *l3c)
|
|||
mISDN_FsmDelTimer(&l3c->TD, 2);
|
||||
discard_queue(&l3c->dataq);
|
||||
discard_confq(l3c);
|
||||
if (l3c->confq) {
|
||||
kfree(l3c->confq);
|
||||
l3c->confq = NULL;
|
||||
}
|
||||
kfree(l3c->confq);
|
||||
kfree(l3c);
|
||||
}
|
||||
|
||||
|
@ -560,6 +553,7 @@ X25_release_l3(x25_l3_t *l3) {
|
|||
mISDNinstance_t *inst = &l3->inst;
|
||||
x25_channel_t *ch, *nch;
|
||||
|
||||
#ifdef OBSOLETE
|
||||
if (inst->up.peer) {
|
||||
inst->up.peer->obj->ctrl(inst->up.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->up);
|
||||
|
@ -568,8 +562,12 @@ X25_release_l3(x25_l3_t *l3) {
|
|||
inst->down.peer->obj->ctrl(inst->down.peer,
|
||||
MGR_DISCONNECT | REQUEST, &inst->down);
|
||||
}
|
||||
#endif
|
||||
if (inst->obj) {
|
||||
u_long flags;
|
||||
spin_lock_irqsave(&inst->obj->lock, flags);
|
||||
list_del_init(&l3->list);
|
||||
spin_unlock_irqrestore(&inst->obj->lock, flags);
|
||||
}
|
||||
discard_queue(&l3->downq);
|
||||
list_for_each_entry_safe(ch, nch, &l3->channellist, list)
|
||||
|
@ -577,7 +575,8 @@ X25_release_l3(x25_l3_t *l3) {
|
|||
mISDN_FsmDelTimer(&l3->TR, 3);
|
||||
if (inst->obj) {
|
||||
if (l3->entity != MISDN_ENTITY_NONE)
|
||||
inst->obj->ctrl(inst, MGR_DELENTITY | REQUEST, (void *)l3->entity);
|
||||
inst->obj->ctrl(inst, MGR_DELENTITY | REQUEST,
|
||||
(void *)((u_long)l3->entity));
|
||||
inst->obj->ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL);
|
||||
}
|
||||
kfree(l3);
|
||||
|
@ -588,8 +587,7 @@ X25_realloc_ncpi_data(x25_channel_t *l3c, int len, u_char *data)
|
|||
{
|
||||
if (len) {
|
||||
if (len > l3c->ncpi_len) {
|
||||
if (l3c->ncpi_data)
|
||||
kfree(l3c->ncpi_data);
|
||||
kfree(l3c->ncpi_data);
|
||||
l3c->ncpi_data = kmalloc(len, GFP_ATOMIC);
|
||||
if (!l3c->ncpi_data) {
|
||||
l3c->ncpi_len = 0;
|
||||
|
@ -597,7 +595,7 @@ X25_realloc_ncpi_data(x25_channel_t *l3c, int len, u_char *data)
|
|||
}
|
||||
}
|
||||
memcpy(l3c->ncpi_data, data, len);
|
||||
} else if (l3c->ncpi_data) {
|
||||
} else {
|
||||
kfree(l3c->ncpi_data);
|
||||
l3c->ncpi_data = NULL;
|
||||
}
|
||||
|
@ -629,8 +627,7 @@ new_x25_channel(x25_l3_t *l3, x25_channel_t **ch_p, __u16 ch, int dlen, u_char *
|
|||
l3c->confq = kmalloc(l3c->lwin * sizeof(x25_ConfQueue_t), GFP_ATOMIC);
|
||||
if (!l3c->confq) {
|
||||
printk(KERN_ERR "kmalloc confq %d entries failed\n", l3c->lwin);
|
||||
if (l3c->ncpi_data)
|
||||
kfree(l3c->ncpi_data);
|
||||
kfree(l3c->ncpi_data);
|
||||
kfree(l3c);
|
||||
return(-ENOMEM);
|
||||
}
|
||||
|
@ -658,9 +655,10 @@ new_x25_channel(x25_l3_t *l3, x25_channel_t **ch_p, __u16 ch, int dlen, u_char *
|
|||
}
|
||||
|
||||
int
|
||||
new_x25_l3(x25_l3_t **l3_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *obj, int debug) {
|
||||
new_x25_l3(x25_l3_t **l3_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *obj, int debug, if_func_t *function) {
|
||||
x25_l3_t *n_l3;
|
||||
int err;
|
||||
u_long flags;
|
||||
|
||||
if (!st || !pid)
|
||||
return(-EINVAL);
|
||||
|
@ -672,9 +670,8 @@ new_x25_l3(x25_l3_t **l3_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *o
|
|||
INIT_LIST_HEAD(&n_l3->channellist);
|
||||
n_l3->entity = MISDN_ENTITY_NONE;
|
||||
n_l3->next_id = 1;
|
||||
spin_lock_init(&n_l3->lock);
|
||||
memcpy(&n_l3->inst.pid, pid, sizeof(mISDN_pid_t));
|
||||
mISDN_init_instance(&n_l3->inst, obj, n_l3);
|
||||
mISDN_init_instance(&n_l3->inst, obj, n_l3, function);
|
||||
if (!mISDN_SetHandledPID(obj, &n_l3->inst.pid)) {
|
||||
int_error();
|
||||
kfree(n_l3);
|
||||
|
@ -704,8 +701,9 @@ new_x25_l3(x25_l3_t **l3_p, mISDNstack_t *st, mISDN_pid_t *pid, mISDNobject_t *o
|
|||
n_l3->x25r.printdebug = l3m_debug;
|
||||
mISDN_FsmInitTimer(&n_l3->x25r, &n_l3->TR);
|
||||
skb_queue_head_init(&n_l3->downq);
|
||||
|
||||
spin_lock_irqsave(&obj->lock, flags);
|
||||
list_add_tail(&n_l3->list, &obj->ilist);
|
||||
spin_unlock_irqrestore(&obj->lock, flags);
|
||||
err = obj->ctrl(&n_l3->inst, MGR_NEWENTITY | REQUEST, NULL);
|
||||
if (err) {
|
||||
printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n",
|
||||
|
@ -853,9 +851,7 @@ X25sendL3frame(x25_channel_t *l3c, x25_l3_t *l3, u_char pt, int len, void *arg)
|
|||
mISDN_sethead(DL_DATA_REQ, X25_next_id(l3), skb);
|
||||
|
||||
if (l3->l2l3m.state == ST_LL_ESTAB) {
|
||||
mISDNif_t *down = &l3->inst.down;
|
||||
|
||||
ret = down->func(down, skb);
|
||||
ret = mISDN_queue_message(&l3->inst, FLG_MSG_DOWN, skb);
|
||||
if (ret) {
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
@ -869,15 +865,13 @@ X25sendL3frame(x25_channel_t *l3c, x25_l3_t *l3, u_char pt, int len, void *arg)
|
|||
int
|
||||
X25_l3down(x25_l3_t *l3, u_int prim, u_int dinfo, struct sk_buff *skb)
|
||||
{
|
||||
mISDNif_t *down = &l3->inst.down;
|
||||
int ret;
|
||||
|
||||
if (!skb) {
|
||||
if (!(skb = alloc_stack_skb(0, l3->down_headerlen)))
|
||||
return(-ENOMEM);
|
||||
}
|
||||
mISDN_sethead(prim, dinfo, skb);
|
||||
ret = down->func(down, skb);
|
||||
ret = mISDN_queuedown_newhead(&l3->inst, 0, prim, dinfo, skb);
|
||||
if (ret) {
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
@ -951,7 +945,7 @@ X25sendL4skb(x25_channel_t *l3c, x25_l3_t *l3, __u32 addr, int prim, int dinfo,
|
|||
capimsg_setu32(skb->data, 0, l3c->ncci);
|
||||
else
|
||||
capimsg_setu32(skb->data, 0, addr);
|
||||
return(if_newhead(&l3->inst.up, prim, dinfo, skb));
|
||||
return(mISDN_queueup_newhead(&l3->inst, 0, prim, dinfo, skb));
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -991,7 +985,7 @@ X25sendL4frame(x25_channel_t *l3c, x25_l3_t *l3, int prim, int flags, int len, v
|
|||
dev_kfree_skb(skb);
|
||||
return(-EINVAL);
|
||||
}
|
||||
ret = if_newhead(&l3->inst.up, prim, 0, skb);
|
||||
ret = mISDN_queueup_newhead(&l3->inst, 0, prim, 0, skb);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "%s: up error %d\n", __FUNCTION__, ret);
|
||||
dev_kfree_skb(skb);
|
||||
|
|
|
@ -64,7 +64,6 @@ struct _x25_l3 {
|
|||
x25_B3_cfg_t B3cfg;
|
||||
u_long state;
|
||||
u_int debug;
|
||||
spinlock_t lock;
|
||||
u_char cause[2];
|
||||
};
|
||||
|
||||
|
@ -84,7 +83,6 @@ struct _x25_channel {
|
|||
u_int ncpi_len;
|
||||
u_long state;
|
||||
u_int debug;
|
||||
spinlock_t lock;
|
||||
u_int pr;
|
||||
u_int ps;
|
||||
u_int rps;
|
||||
|
@ -262,7 +260,7 @@ extern void X25_release_channel(x25_channel_t *);
|
|||
extern void X25_release_l3(x25_l3_t *);
|
||||
extern int X25_realloc_ncpi_data(x25_channel_t *, int, u_char *);
|
||||
extern int new_x25_channel(x25_l3_t *, x25_channel_t **, __u16, int, u_char *);
|
||||
extern int new_x25_l3(x25_l3_t **, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *, int);
|
||||
extern int new_x25_l3(x25_l3_t **, mISDNstack_t *, mISDN_pid_t *, mISDNobject_t *, int, if_func_t *);
|
||||
extern int X25_next_id(x25_l3_t *);
|
||||
extern int X25_add_header(x25_channel_t *, x25_l3_t *, u_char , u_char *, u_char);
|
||||
extern int X25sendL3frame(x25_channel_t *, x25_l3_t *, u_char, int, void *);
|
||||
|
|
|
@ -86,10 +86,23 @@ typedef struct wait_queue *wait_queue_head_t;
|
|||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
|
||||
#define OLD_PCI_REGISTER_DRIVER 1
|
||||
#define pci_get_subsys pci_find_subsys
|
||||
#define OLD_MODULE_PARAM_ARRAY
|
||||
#else
|
||||
#undef OLD_PCI_REGISTER_DRIVER
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
|
||||
#define MODULE_MKOBJ_POINTER
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,11)
|
||||
#define CLASSDEV_HAS_DEVT
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13)
|
||||
/* udev sysfs stuff */
|
||||
#define CLASS_WITHOUT_OWNER
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_ISDN_COMPAT_H */
|
||||
|
|
|
@ -9,16 +9,6 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
/* primitives for information exchange
|
||||
* generell format
|
||||
* <8 bit reserved>
|
||||
* <4 bit flags>
|
||||
* <4 bit layer>
|
||||
* <8 bit command>
|
||||
* <8 bit subcommand>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* ABI Version 32 bit
|
||||
*
|
||||
|
@ -29,13 +19,29 @@
|
|||
* - changed if any interface is extended but backwards compatible
|
||||
*
|
||||
*/
|
||||
#define MISDN_MAJOR_VERSION 1
|
||||
#define MISDN_MAJOR_VERSION 3
|
||||
#define MISDN_MINOR_VERSION 0
|
||||
#define MISDN_VERSION ((MISDN_MAJOR_VERSION<<16) | MISDN_MINOR_VERSION)
|
||||
|
||||
#define MISDN_REVISION "$Revision$"
|
||||
#define MISDN_DATE "$Date$"
|
||||
|
||||
/* collect some statistics about the message queues */
|
||||
#define MISDN_MSG_STATS
|
||||
|
||||
/* primitives for information exchange
|
||||
* generell format
|
||||
* <8 bit reserved>
|
||||
* <4 bit flags>
|
||||
* <4 bit layer>
|
||||
* <8 bit command>
|
||||
* <8 bit subcommand>
|
||||
*
|
||||
*/
|
||||
|
||||
#define MISDN_CMD_MASK 0xffffff00
|
||||
#define MISDN_SUB_MASK 0x000000ff
|
||||
|
||||
/* SUBCOMMANDS */
|
||||
#define REQUEST 0x80
|
||||
#define CONFIRM 0x81
|
||||
|
@ -61,18 +67,22 @@
|
|||
#define MGR_SETSTACK_NW 0x0f1900
|
||||
#define MGR_ADDSTPARA 0x0f1A00
|
||||
#define MGR_CLRSTPARA 0x0f1B00
|
||||
#define MGR_ADDLAYER 0x0f1C00
|
||||
#define MGR_GETLAYER 0x0f2100
|
||||
#define MGR_GETLAYERID 0x0f2200
|
||||
#define MGR_NEWLAYER 0x0f2300
|
||||
#define MGR_DELLAYER 0x0f2400
|
||||
#define MGR_CLONELAYER 0x0f2500
|
||||
#define MGR_GETIF 0x0f3100
|
||||
#define MGR_CONNECT 0x0f3200
|
||||
#define MGR_DISCONNECT 0x0f3300
|
||||
#define MGR_SETIF 0x0f3400
|
||||
#define MGR_ADDIF 0x0f3500
|
||||
#define MGR_QUEUEIF 0x0f3600
|
||||
//#define MGR_CLONELAYER 0x0f2500
|
||||
//#define MGR_GETIF 0x0f3100
|
||||
//#define MGR_CONNECT 0x0f3200
|
||||
//#define MGR_DISCONNECT 0x0f3300
|
||||
//#define MGR_SETIF 0x0f3400
|
||||
//#define MGR_ADDIF 0x0f3500
|
||||
//#define MGR_QUEUEIF 0x0f3600
|
||||
#define MGR_CTRLREADY 0x0f4100
|
||||
#define MGR_STACKREADY 0x0f4200
|
||||
#define MGR_STOPSTACK 0x0f4300
|
||||
#define MGR_STARTSTACK 0x0f4400
|
||||
#define MGR_RELEASE 0x0f4500
|
||||
#define MGR_GETDEVICE 0x0f5100
|
||||
#define MGR_DELDEVICE 0x0f5200
|
||||
|
@ -85,9 +95,10 @@
|
|||
#define MGR_TIMER 0x0f8800
|
||||
#define MGR_CONTROL 0x0fe100
|
||||
#define MGR_STATUS 0x0fe200
|
||||
#define MGR_HASPROTOCOL 0x0fe300
|
||||
#define MGR_HASPROTOCOL 0x0fe300
|
||||
#define MGR_EVALSTACK 0x0fe400
|
||||
#define MGR_GLOBALOPT 0x0fe500
|
||||
#define MGR_SHORTSTATUS 0x0fe600
|
||||
#define MGR_LOADFIRM 0x0ff000
|
||||
#define MGR_LOGDATA 0x0ff100
|
||||
#define MGR_DEBUGDATA 0x0ff200
|
||||
|
@ -106,12 +117,16 @@
|
|||
#define INFO3_P10 0x130a
|
||||
#define INFO4_P8 0x1408
|
||||
#define INFO4_P10 0x140a
|
||||
#define D_RX_MON0 0x1800
|
||||
#define D_TX_MON0 0x1801
|
||||
#define D_RX_MON1 0x1810
|
||||
#define D_TX_MON1 0x1811
|
||||
#define LOSTFRAMING 0x1f00
|
||||
#define ANYSIGNAL 0x1f01
|
||||
|
||||
/* PH_CONTROL parameter */
|
||||
#define HW_RESET 0x0001
|
||||
#define HW_POWERDOWN 0x0100
|
||||
#define HW_RESET 0x0001
|
||||
#define HW_POWERDOWN 0x0100
|
||||
#define HW_POWERUP 0x0101
|
||||
#define HW_DEACTIVATE 0x0200
|
||||
#define HW_ACTIVATE 0x0201
|
||||
|
@ -147,8 +162,8 @@
|
|||
#define HW_FIRM_START 0xFF10
|
||||
#define HW_FIRM_DATA 0xFF11
|
||||
#define HW_FIRM_END 0xFF12
|
||||
#define HW_D_BLOCKED 0xFF20
|
||||
#define HW_D_NOBLOCKED 0xFF21
|
||||
#define HW_D_BLOCKED 0xFF20
|
||||
#define HW_D_NOBLOCKED 0xFF21
|
||||
#define HW_TESTRX_RAW 0xFF40
|
||||
#define HW_TESTRX_HDLC 0xFF41
|
||||
#define HW_TESTRX_OFF 0xFF4f
|
||||
|
@ -173,6 +188,8 @@
|
|||
#define BF_DISABLE 0x2315
|
||||
#define BF_ACCEPT 0x2316
|
||||
#define BF_REJECT 0x2317
|
||||
#define ECHOCAN_ON 0x2318
|
||||
#define ECHOCAN_OFF 0x2319
|
||||
#define HW_POTS_ON 0x1001
|
||||
#define HW_POTS_OFF 0x1002
|
||||
#define HW_POTS_SETMICVOL 0x1100
|
||||
|
@ -221,7 +238,7 @@
|
|||
#define MPH_DEACTIVATE 0x011000
|
||||
#define MPH_ACTIVATE 0x011100
|
||||
#define MPH_INFORMATION 0x012000
|
||||
|
||||
|
||||
/* layer 2 */
|
||||
#define DL_ESTABLISH 0x020100
|
||||
#define DL_RELEASE 0x020000
|
||||
|
@ -272,6 +289,8 @@
|
|||
|
||||
#define CC_B3_DATA 0x138600
|
||||
|
||||
#define CAPI_MESSAGE_REQUEST 0x040080
|
||||
|
||||
#define LAYER_MASK 0x0F0000
|
||||
#define COMMAND_MASK 0x00FF00
|
||||
#define SUBCOMMAND_MASK 0x0000FF
|
||||
|
@ -319,6 +338,9 @@
|
|||
#define ISDN_PID_L0_NT_UP2 0x00000400
|
||||
#define ISDN_PID_L0_TE_E1 0x00000008
|
||||
#define ISDN_PID_L0_NT_E1 0x00000800
|
||||
#define ISDN_PID_L0_IP_S0 0x00000010
|
||||
#define ISDN_PID_L0_IP_E1 0x00000020
|
||||
#define ISDN_PID_L0_LOOP 0x00000030
|
||||
#define ISDN_PID_L1_TE_S0 0x01000001
|
||||
#define ISDN_PID_L1_NT_S0 0x01000100
|
||||
#define ISDN_PID_L1_TE_U 0x01000002
|
||||
|
@ -327,7 +349,10 @@
|
|||
#define ISDN_PID_L1_NT_UP2 0x01000400
|
||||
#define ISDN_PID_L1_TE_E1 0x01000008
|
||||
#define ISDN_PID_L1_NT_E1 0x01000800
|
||||
#define ISDN_PID_L2_LAPD 0x02000001
|
||||
#define ISDN_PID_L2_LAPD_NET 0x02000002
|
||||
/* Bit 15-0 reserved for CAPI defined protocols */
|
||||
#define ISDN_PID_L0_B_IP 0x40000001
|
||||
#define ISDN_PID_L1_B_64HDLC 0x41000001
|
||||
#define ISDN_PID_L1_B_64TRANS 0x41000002
|
||||
#define ISDN_PID_L1_B_V110_ASYNC 0x41000004
|
||||
|
@ -338,8 +363,6 @@
|
|||
#define ISDN_PID_L1_B_MODEM_ALL 0x41000080
|
||||
#define ISDN_PID_L1_B_MODEM_ASYNC 0x41000100
|
||||
#define ISDN_PID_L1_B_MODEM_HDLC 0x41000200
|
||||
#define ISDN_PID_L2_LAPD 0x02000001
|
||||
#define ISDN_PID_L2_LAPD_NET 0x02000002
|
||||
/* Bit 15-0 reserved for CAPI defined protocols */
|
||||
#define ISDN_PID_L2_B_X75SLP 0x42000001
|
||||
#define ISDN_PID_L2_B_TRANS 0x42000002
|
||||
|
@ -382,6 +405,18 @@
|
|||
#define ISDN_PID_L3_DF_EXTCID 0x00200000
|
||||
#define ISDN_PID_L3_DF_CRLEN2 0x00400000
|
||||
|
||||
|
||||
// short message status
|
||||
#define SSTATUS_ALL 0x0fffffff
|
||||
#define SSTATUS_BROADCAST_BIT 0x10000000
|
||||
#define SSTATUS_L1 0x01ffffff
|
||||
#define SSTATUS_L2 0x02ffffff
|
||||
#define SSTATUS_L1_DEACTIVATED 0x01000000
|
||||
#define SSTATUS_L1_ACTIVATED 0x01000001
|
||||
#define SSTATUS_L2_RELEASED 0x02000000
|
||||
#define SSTATUS_L2_ESTABLISHED 0x02000001
|
||||
|
||||
|
||||
#define mISDN_CORE_DEVICE 0
|
||||
#define mISDN_RAW_DEVICE 128
|
||||
|
||||
|
@ -413,11 +448,14 @@
|
|||
#define MISDN_ID_DUMMY 0xffff0001
|
||||
#define MISDN_ID_GLOBAL 0xffff0002
|
||||
|
||||
#define MAX_LAYER_NR 7
|
||||
#define ISDN_LAYER(n) (1<<n)
|
||||
#define MAX_LAYER_NR 7
|
||||
#define ISDN_LAYER(n) (1<<n)
|
||||
#define LAYER_OUTRANGE(layer) ((layer<0) || (layer>MAX_LAYER_NR))
|
||||
#define mISDN_MAX_IDLEN 16
|
||||
|
||||
/* should be in sync with linux/kobject.h:KOBJ_NAME_LEN */
|
||||
#define mISDN_MAX_IDLEN 20
|
||||
|
||||
#ifdef OBSOLETE
|
||||
#define IF_NOACTIV 0x00000000
|
||||
#define IF_DOWN 0x01000000
|
||||
#define IF_UP 0x02000000
|
||||
|
@ -432,18 +470,53 @@
|
|||
#define IF_INSTMASK 0x400F0000
|
||||
#define IF_LAYERMASK 0x00F00000
|
||||
#define IF_TYPE(i) ((i)->stat & IF_TYPEMASK)
|
||||
#define CHILD_ID_INC 0x00000100
|
||||
#define CHILD_ID_MAX 0x1000FF00
|
||||
#define CLONE_ID_INC 0x00000100
|
||||
#define CLONE_ID_MAX 0x2000FF00
|
||||
#define INST_ID_INC 0x00010000
|
||||
#define INST_ID_MAX 0x400F0000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* general ID layout for instance and stack id's
|
||||
* 3322 2222 2222 1111 1111 1100 0000 0000
|
||||
* 1098 7654 3210 9876 5432 1098 7654 3210
|
||||
* FFFF FFFF CCCC CCCC SSSS SSSS RRRR LLLL
|
||||
*
|
||||
* L (bit 03-00) Layer ID
|
||||
* R (bit 06-04) reserved (0)
|
||||
* U (bit 07) user device id
|
||||
* S (bit 15-08) Stack ID/controller number
|
||||
* C (bit 23-16) Child/Clone ID
|
||||
* F (bit 31-24) Flags as defined below
|
||||
*
|
||||
*/
|
||||
|
||||
#define FLG_MSG_DOWN 0x01000000
|
||||
#define FLG_MSG_UP 0x02000000
|
||||
#define FLG_MSG_TARGET 0x04000000
|
||||
#define FLG_MSG_CLONED 0x08000000
|
||||
#define FLG_CHILD_STACK 0x10000000
|
||||
#define FLG_CLONE_STACK 0x20000000
|
||||
#define FLG_INSTANCE 0x40000000
|
||||
#define FLG_MSG_TAGGED 0x80000000
|
||||
#define MSG_DIR_MASK 0x03000000
|
||||
#define MSG_BROADCAST 0x03000000
|
||||
#define MSG_TO_OWNER 0x00000000
|
||||
|
||||
#define CHILD_ID_INC 0x00010000
|
||||
#define CHILD_ID_MAX 0x10FF0000
|
||||
#define CHILD_ID_MASK 0x00FF0000
|
||||
#define CLONE_ID_INC 0x00010000
|
||||
#define CLONE_ID_MAX 0x20FF0000
|
||||
#define CLONE_ID_MASK 0x00FF0000
|
||||
#define STACK_ID_INC 0x00000100
|
||||
#define STACK_ID_MAX 0x00007F00
|
||||
#define STACK_ID_MASK 0x30FFFF00
|
||||
#define MASTER_ID_MASK 0x0000FF00
|
||||
#define LAYER_ID_INC 0x00000001
|
||||
#define LAYER_ID_MAX MAX_LAYER_NR
|
||||
#define LAYER_ID_MASK 0x0000000F
|
||||
#define FLG_ID_USER 0x00000080
|
||||
#define INST_ID_MASK 0x70FFFFFF
|
||||
|
||||
#define DUMMY_CR_FLAG 0x7FFFFF00
|
||||
#define CONTROLER_MASK 0x000000FF
|
||||
// #define CONTROLER_MASK 0x0000FF
|
||||
|
||||
/* stack channel values */
|
||||
#define CHANNEL_NUMBER 0x000000FF
|
||||
|
@ -456,16 +529,35 @@
|
|||
#define CHANNEL_EXT_PCM 0x01000000
|
||||
#define CHANNEL_EXT_REV 0x02000000
|
||||
|
||||
/* interface extentions */
|
||||
/* instance/stack extentions */
|
||||
#define EXT_STACK_CLONE 0x00000001
|
||||
#define EXT_INST_CLONE 0x00000100
|
||||
#define EXT_INST_MGR 0x00000200
|
||||
#define EXT_INST_MIDDLE 0x00000400
|
||||
#define EXT_IF_CHAIN 0x00010000
|
||||
#define EXT_IF_EXCLUSIV 0x00020000
|
||||
#define EXT_IF_CREATE 0x00040000
|
||||
#define EXT_IF_SPLIT 0x00080000
|
||||
#define EXT_INST_UNUSED 0x00000800
|
||||
//#define EXT_IF_CHAIN 0x00010000
|
||||
//#define EXT_IF_EXCLUSIV 0x00020000
|
||||
//#define EXT_IF_CREATE 0x00040000
|
||||
//#define EXT_IF_SPLIT 0x00080000
|
||||
|
||||
/* stack status flag */
|
||||
#define mISDN_STACK_ACTION_MASK 0x0000ffff
|
||||
#define mISDN_STACK_COMMAND_MASK 0x000f0000
|
||||
#define mISDN_STACK_STATUS_MASK 0xfff00000
|
||||
/* action bits 0-15 */
|
||||
#define mISDN_STACK_WORK 0
|
||||
#define mISDN_STACK_SETUP 1
|
||||
#define mISDN_STACK_CLEARING 2
|
||||
#define mISDN_STACK_RESTART 3
|
||||
#define mISDN_STACK_WAKEUP 4
|
||||
#define mISDN_STACK_ABORT 15
|
||||
/* status bits 16-31 */
|
||||
#define mISDN_STACK_STOPPED 16
|
||||
#define mISDN_STACK_INIT 17
|
||||
#define mISDN_STACK_THREADSTART 18
|
||||
#define mISDN_STACK_ACTIVE 29
|
||||
#define mISDN_STACK_RUNNING 30
|
||||
#define mISDN_STACK_KILLED 31
|
||||
|
||||
/* special packet type */
|
||||
#define PACKET_NOACK 250
|
||||
|
@ -504,7 +596,7 @@ typedef struct _status_info {
|
|||
typedef struct _logdata {
|
||||
char *head;
|
||||
char *fmt;
|
||||
va_list args;
|
||||
va_list args;
|
||||
} logdata_t;
|
||||
|
||||
typedef struct _moditem {
|
||||
|
@ -533,6 +625,8 @@ typedef struct _stack_info {
|
|||
mISDN_stPara_t para;
|
||||
u_int extentions;
|
||||
u_int mgr;
|
||||
u_int master;
|
||||
u_int clone;
|
||||
int instcnt;
|
||||
int inst[MAX_LAYER_NR +1];
|
||||
int childcnt;
|
||||
|
@ -545,16 +639,19 @@ typedef struct _layer_info {
|
|||
int extentions;
|
||||
u_int id;
|
||||
u_int st;
|
||||
u_int clone;
|
||||
u_int parent;
|
||||
mISDN_pid_t pid;
|
||||
} layer_info_t;
|
||||
|
||||
|
||||
#ifdef OBSOLETE
|
||||
typedef struct _interface_info {
|
||||
int extentions;
|
||||
u_int owner;
|
||||
u_int peer;
|
||||
int stat;
|
||||
} interface_info_t;
|
||||
#endif
|
||||
|
||||
typedef struct _channel_info {
|
||||
u_int channel;
|
||||
|
@ -566,46 +663,76 @@ typedef struct _channel_info {
|
|||
|
||||
/* l3 pointer arrays */
|
||||
|
||||
typedef struct _ie_info {
|
||||
u16 off : 10,
|
||||
ridx : 3,
|
||||
res1 : 1,
|
||||
cs_flg : 1,
|
||||
repeated: 1;
|
||||
} __attribute__((packed)) ie_info_t;
|
||||
|
||||
typedef struct _ie_val {
|
||||
u16 codeset : 3,
|
||||
res1 : 5,
|
||||
val : 8;
|
||||
} __attribute__((packed)) ie_val_t;;
|
||||
|
||||
typedef struct _cs_info {
|
||||
u16 codeset : 3,
|
||||
locked : 1,
|
||||
res1 : 2,
|
||||
len : 10;
|
||||
} __attribute__((packed)) cs_info_t;
|
||||
|
||||
typedef struct _ie_info_ext {
|
||||
ie_info_t ie;
|
||||
union {
|
||||
ie_val_t v;
|
||||
cs_info_t cs;
|
||||
};
|
||||
} __attribute__((packed)) ie_info_ext_t;
|
||||
|
||||
typedef struct _Q931_info {
|
||||
u_char type __attribute__((packed));
|
||||
u_char crlen __attribute__((packed));
|
||||
u16 cr __attribute__((packed));
|
||||
u16 bearer_capability __attribute__((packed));
|
||||
u16 cause __attribute__((packed));
|
||||
u16 call_id __attribute__((packed));
|
||||
u16 call_state __attribute__((packed));
|
||||
u16 channel_id __attribute__((packed));
|
||||
u16 facility __attribute__((packed));
|
||||
u16 progress __attribute__((packed));
|
||||
u16 net_fac __attribute__((packed));
|
||||
u16 notify __attribute__((packed));
|
||||
u16 display __attribute__((packed));
|
||||
u16 date __attribute__((packed));
|
||||
u16 keypad __attribute__((packed));
|
||||
u16 signal __attribute__((packed));
|
||||
u16 info_rate __attribute__((packed));
|
||||
u16 end2end_transit __attribute__((packed));
|
||||
u16 transit_delay_sel __attribute__((packed));
|
||||
u16 pktl_bin_para __attribute__((packed));
|
||||
u16 pktl_window __attribute__((packed));
|
||||
u16 pkt_size __attribute__((packed));
|
||||
u16 closed_userg __attribute__((packed));
|
||||
u16 connected_nr __attribute__((packed));
|
||||
u16 connected_sub __attribute__((packed));
|
||||
u16 calling_nr __attribute__((packed));
|
||||
u16 calling_sub __attribute__((packed));
|
||||
u16 called_nr __attribute__((packed));
|
||||
u16 called_sub __attribute__((packed));
|
||||
u16 redirect_nr __attribute__((packed));
|
||||
u16 transit_net_sel __attribute__((packed));
|
||||
u16 restart_ind __attribute__((packed));
|
||||
u16 llc __attribute__((packed));
|
||||
u16 hlc __attribute__((packed));
|
||||
u16 useruser __attribute__((packed));
|
||||
u16 more_data __attribute__((packed));
|
||||
u16 sending_complete __attribute__((packed));
|
||||
u16 congestion_level __attribute__((packed));
|
||||
u16 fill1 __attribute__((packed));
|
||||
u_char type __attribute__((packed));
|
||||
u_char crlen __attribute__((packed));
|
||||
u16 cr __attribute__((packed));
|
||||
ie_info_t bearer_capability __attribute__((packed));
|
||||
ie_info_t cause __attribute__((packed));
|
||||
ie_info_t call_id __attribute__((packed));
|
||||
ie_info_t call_state __attribute__((packed));
|
||||
ie_info_t channel_id __attribute__((packed));
|
||||
ie_info_t facility __attribute__((packed));
|
||||
ie_info_t progress __attribute__((packed));
|
||||
ie_info_t net_fac __attribute__((packed));
|
||||
ie_info_t notify __attribute__((packed));
|
||||
ie_info_t display __attribute__((packed));
|
||||
ie_info_t date __attribute__((packed));
|
||||
ie_info_t keypad __attribute__((packed));
|
||||
ie_info_t signal __attribute__((packed));
|
||||
ie_info_t info_rate __attribute__((packed));
|
||||
ie_info_t end2end_transit __attribute__((packed));
|
||||
ie_info_t transit_delay_sel __attribute__((packed));
|
||||
ie_info_t pktl_bin_para __attribute__((packed));
|
||||
ie_info_t pktl_window __attribute__((packed));
|
||||
ie_info_t pkt_size __attribute__((packed));
|
||||
ie_info_t closed_userg __attribute__((packed));
|
||||
ie_info_t connected_nr __attribute__((packed));
|
||||
ie_info_t connected_sub __attribute__((packed));
|
||||
ie_info_t calling_nr __attribute__((packed));
|
||||
ie_info_t calling_sub __attribute__((packed));
|
||||
ie_info_t called_nr __attribute__((packed));
|
||||
ie_info_t called_sub __attribute__((packed));
|
||||
ie_info_t redirect_nr __attribute__((packed));
|
||||
ie_info_t transit_net_sel __attribute__((packed));
|
||||
ie_info_t restart_ind __attribute__((packed));
|
||||
ie_info_t llc __attribute__((packed));
|
||||
ie_info_t hlc __attribute__((packed));
|
||||
ie_info_t useruser __attribute__((packed));
|
||||
ie_info_t more_data __attribute__((packed));
|
||||
ie_info_t sending_complete __attribute__((packed));
|
||||
ie_info_t congestion_level __attribute__((packed));
|
||||
ie_info_t fill1 __attribute__((packed));
|
||||
ie_info_ext_t ext[8] __attribute__((packed));
|
||||
} Q931_info_t;
|
||||
|
||||
#define L3_EXTRA_SIZE sizeof(Q931_info_t)
|
||||
|
@ -617,15 +744,11 @@ typedef struct _Q931_info {
|
|||
|
||||
typedef struct _mISDNobject mISDNobject_t;
|
||||
typedef struct _mISDNinstance mISDNinstance_t;
|
||||
typedef struct _mISDNlayer mISDNlayer_t;
|
||||
typedef struct _mISDNstack mISDNstack_t;
|
||||
typedef struct _mISDNport mISDNport_t;
|
||||
typedef struct _mISDNdevice mISDNdevice_t;
|
||||
typedef struct _mISDNif mISDNif_t;
|
||||
typedef int (ctrl_func_t)(void *, u_int, void *);
|
||||
typedef int (if_func_t)(struct _mISDNif *, struct sk_buff *);
|
||||
typedef int (lock_func_t)(void *, int);
|
||||
typedef void (unlock_func_t)(void *);
|
||||
typedef int (if_func_t)(mISDNinstance_t *, struct sk_buff *);
|
||||
|
||||
#define mISDN_HEAD_P(s) ((mISDN_head_t *)&s->cb[0])
|
||||
#define mISDN_HEAD_PRIM(s) ((mISDN_head_t *)&s->cb[0])->prim
|
||||
|
@ -649,16 +772,19 @@ typedef struct _mISDN_headext {
|
|||
struct _mISDNobject {
|
||||
struct list_head list;
|
||||
char *name;
|
||||
int id;
|
||||
u_int id;
|
||||
int refcnt;
|
||||
mISDN_pid_t DPROTO;
|
||||
mISDN_pid_t BPROTO;
|
||||
ctrl_func_t *own_ctrl;
|
||||
ctrl_func_t *ctrl;
|
||||
struct list_head ilist;
|
||||
spinlock_t lock;
|
||||
struct module *owner;
|
||||
struct class_device class_dev;
|
||||
};
|
||||
|
||||
#ifdef OBSOLETE
|
||||
/* the interface between two mISDNinstances */
|
||||
struct _mISDNif {
|
||||
if_func_t *func;
|
||||
|
@ -671,6 +797,7 @@ struct _mISDNif {
|
|||
mISDNinstance_t *owner;
|
||||
mISDNinstance_t *peer;
|
||||
};
|
||||
#endif
|
||||
|
||||
/* a instance of a mISDNobject */
|
||||
struct _mISDNinstance {
|
||||
|
@ -678,16 +805,19 @@ struct _mISDNinstance {
|
|||
char name[mISDN_MAX_IDLEN];
|
||||
int extentions;
|
||||
u_int id;
|
||||
int regcnt;
|
||||
mISDN_pid_t pid;
|
||||
mISDNstack_t *st;
|
||||
mISDNobject_t *obj;
|
||||
void *data;
|
||||
mISDNif_t up;
|
||||
mISDNif_t down;
|
||||
lock_func_t *lock;
|
||||
unlock_func_t *unlock;
|
||||
void *privat;
|
||||
mISDNinstance_t *clone;
|
||||
mISDNinstance_t *parent;
|
||||
if_func_t *function;
|
||||
spinlock_t *hwlock;
|
||||
struct class_device class_dev;
|
||||
};
|
||||
|
||||
#ifdef OBSOLETE
|
||||
/* a list of parallel (horizontal) mISDNinstances in the same layer
|
||||
* normally here is only one instance per layer only if the information
|
||||
* will be splitted here are more instances */
|
||||
|
@ -695,7 +825,7 @@ struct _mISDNlayer {
|
|||
struct list_head list;
|
||||
mISDNinstance_t *inst;
|
||||
};
|
||||
|
||||
#endif
|
||||
/* the STACK; a (vertical) chain of layers */
|
||||
|
||||
struct _mISDNstack {
|
||||
|
@ -704,16 +834,34 @@ struct _mISDNstack {
|
|||
u_int extentions;
|
||||
mISDN_pid_t pid;
|
||||
mISDN_stPara_t para;
|
||||
struct list_head layerlist;
|
||||
u_long status;
|
||||
struct task_struct *thread;
|
||||
struct semaphore *notify;
|
||||
wait_queue_head_t workq;
|
||||
struct sk_buff_head msgq;
|
||||
#ifdef MISDN_MSG_STATS
|
||||
u_int msg_cnt;
|
||||
u_int sleep_cnt;
|
||||
u_int clone_cnt;
|
||||
u_int stopped_cnt;
|
||||
#endif
|
||||
mISDNinstance_t *i_array[MAX_LAYER_NR + 1];
|
||||
struct list_head prereg;
|
||||
mISDNinstance_t *mgr;
|
||||
mISDNstack_t *master;
|
||||
mISDNstack_t *clone;
|
||||
mISDNstack_t *parent;
|
||||
struct list_head childlist;
|
||||
struct class_device class_dev;
|
||||
/* temporary use */
|
||||
mISDN_pid_t new_pid;
|
||||
};
|
||||
|
||||
/* lowlevel read/write struct for the mISDNdevice */
|
||||
struct _mISDNport {
|
||||
wait_queue_head_t procq;
|
||||
spinlock_t lock;
|
||||
mISDNif_t pif;
|
||||
// mISDNif_t pif;
|
||||
u_long Flag;
|
||||
struct sk_buff_head queue;
|
||||
u_int maxqlen;
|
||||
|
@ -735,9 +883,11 @@ struct _mISDNdevice {
|
|||
|
||||
/* common helper functions */
|
||||
extern int mISDN_bprotocol2pid(void *, mISDN_pid_t *);
|
||||
extern int mISDN_SetIF(mISDNinstance_t *, mISDNif_t *, u_int, void *, void *, void *);
|
||||
extern int mISDN_ConnectIF(mISDNinstance_t *, mISDNinstance_t *);
|
||||
extern int mISDN_DisConnectIF(mISDNinstance_t *, mISDNif_t *);
|
||||
// extern int mISDN_SetIF(mISDNinstance_t *, mISDNif_t *, u_int, void *, void *, void *);
|
||||
// extern int mISDN_ConnectIF(mISDNinstance_t *, mISDNinstance_t *);
|
||||
// extern int mISDN_DisConnectIF(mISDNinstance_t *, mISDNif_t *);
|
||||
extern int mISDN_queue_message(mISDNinstance_t *, u_int, struct sk_buff *);
|
||||
|
||||
|
||||
/* global register/unregister functions */
|
||||
|
||||
|
|
19
std2kern
19
std2kern
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
KERNELDIR=/usr/src/linux
|
||||
KERNELDIR=/lib/modules/$(uname -r)/build
|
||||
PREPARSER="./preparser"
|
||||
UNIQUE=false
|
||||
VERBOSE=false
|
||||
|
@ -224,6 +224,23 @@ while getopts :dhk:uc:vtidr a ; do
|
|||
done
|
||||
shift `expr $OPTIND - 1`
|
||||
|
||||
echo
|
||||
echo "BE AWARE!!"
|
||||
echo
|
||||
echo "You are just attempting to overwrite your Kernel mISDN Sources"
|
||||
echo "you probably prefer to use make install."
|
||||
echo
|
||||
echo "KERNELDIR=$KERNELDIR"
|
||||
ls -ld $KERNELDIR
|
||||
echo
|
||||
echo "If you still want to patch this Kernel just answer yes:"
|
||||
read i
|
||||
|
||||
if [ ! $i == "yes" ] ; then
|
||||
echo "OK exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$VERSION" -o -z "$PATCHLEVEL" ] ; then
|
||||
if ! [ -f $KERNELDIR/Makefile ] ; then
|
||||
echo "VERSION/PATCHLEVEL not set and no Makefile to read from"
|
||||
|
|
Loading…
Reference in New Issue