- make mqueue branch HEAD

This commit is contained in:
Karsten Keil 2006-03-06 12:52:08 +00:00
parent 44cf601712
commit 56f18961c0
65 changed files with 9732 additions and 8148 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 *

View File

@ -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;

View File

@ -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 *);

View File

@ -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)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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;
}

View File

@ -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__);

View File

@ -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

View File

@ -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);
}

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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 */
/*************************************************/

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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 *);

View File

@ -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 */

View File

@ -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 */

View File

@ -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"

View File

@ -1,6 +1,6 @@
#!/bin/sh
KERNELDIR=/usr/src/linux
KERNELDIR=/lib/modules/$(uname -r)/build
KERNFIRST=false
PREPARSER="./preparser"
DODIFF=dodiff