From 56f18961c0adf1e4dd425ce3dafdd2a80b1b7b70 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Mon, 6 Mar 2006 12:52:08 +0000 Subject: [PATCH] - make mqueue branch HEAD --- drivers/isdn/hardware/mISDN/Kconfig.v2.6 | 41 +- drivers/isdn/hardware/mISDN/Makefile | 26 +- drivers/isdn/hardware/mISDN/Makefile.v2.6 | 27 +- drivers/isdn/hardware/mISDN/app_plci.c | 795 +++- drivers/isdn/hardware/mISDN/appl.c | 50 +- drivers/isdn/hardware/mISDN/arcofi.c | 40 +- drivers/isdn/hardware/mISDN/arcofi.h | 6 +- drivers/isdn/hardware/mISDN/asn1.h | 19 +- drivers/isdn/hardware/mISDN/asn1_comp.c | 74 +- drivers/isdn/hardware/mISDN/asn1_enc.c | 23 + drivers/isdn/hardware/mISDN/asn1_enc.h | 2 + drivers/isdn/hardware/mISDN/avm_fritz.c | 569 ++- drivers/isdn/hardware/mISDN/bchannel.c | 156 - drivers/isdn/hardware/mISDN/bchannel.h | 98 - drivers/isdn/hardware/mISDN/capi.c | 15 +- drivers/isdn/hardware/mISDN/contr.c | 133 +- drivers/isdn/hardware/mISDN/core.c | 116 +- drivers/isdn/hardware/mISDN/core.h | 41 +- drivers/isdn/hardware/mISDN/dchannel.c | 116 - drivers/isdn/hardware/mISDN/dchannel.h | 92 - drivers/isdn/hardware/mISDN/debug.h | 4 + drivers/isdn/hardware/mISDN/dsp.h | 98 +- drivers/isdn/hardware/mISDN/dsp_blowfish.c | 2 +- drivers/isdn/hardware/mISDN/dsp_cmx.c | 651 ++-- drivers/isdn/hardware/mISDN/dsp_core.c | 506 +-- drivers/isdn/hardware/mISDN/dsp_dtmf.c | 2 +- drivers/isdn/hardware/mISDN/dsp_tones.c | 4 +- drivers/isdn/hardware/mISDN/dss1.h | 21 + drivers/isdn/hardware/mISDN/dtmf.c | 77 +- drivers/isdn/hardware/mISDN/helper.c | 22 +- drivers/isdn/hardware/mISDN/helper.h | 66 +- drivers/isdn/hardware/mISDN/hfc_multi.c | 3975 ++++++++++---------- drivers/isdn/hardware/mISDN/hfc_multi.h | 140 +- drivers/isdn/hardware/mISDN/hfc_pci.c | 1571 ++++---- drivers/isdn/hardware/mISDN/hfcs_usb.c | 1854 ++++----- drivers/isdn/hardware/mISDN/hfcs_usb.h | 32 +- drivers/isdn/hardware/mISDN/i4l_mISDN.c | 2 +- drivers/isdn/hardware/mISDN/isac.c | 475 ++- drivers/isdn/hardware/mISDN/isac.h | 10 +- drivers/isdn/hardware/mISDN/isar.c | 703 ++-- drivers/isdn/hardware/mISDN/isar.h | 12 +- drivers/isdn/hardware/mISDN/l3_udss1.c | 819 +++- drivers/isdn/hardware/mISDN/l3helper.c | 124 +- drivers/isdn/hardware/mISDN/layer1.c | 160 +- drivers/isdn/hardware/mISDN/layer1.h | 2 + drivers/isdn/hardware/mISDN/layer2.c | 274 +- drivers/isdn/hardware/mISDN/layer2.h | 3 +- drivers/isdn/hardware/mISDN/layer3.c | 16 +- drivers/isdn/hardware/mISDN/layer3.h | 4 +- drivers/isdn/hardware/mISDN/m_capi.h | 60 +- drivers/isdn/hardware/mISDN/memdbg.c | 8 +- drivers/isdn/hardware/mISDN/ncci.c | 60 +- drivers/isdn/hardware/mISDN/plci.c | 3 + drivers/isdn/hardware/mISDN/sedl_fax.c | 387 +- drivers/isdn/hardware/mISDN/stack.c | 1005 ++++- drivers/isdn/hardware/mISDN/supp_serv.c | 292 +- drivers/isdn/hardware/mISDN/udevice.c | 616 +-- drivers/isdn/hardware/mISDN/w6692.c | 827 ++-- drivers/isdn/hardware/mISDN/x25_dte.c | 114 +- drivers/isdn/hardware/mISDN/x25_l3.c | 52 +- drivers/isdn/hardware/mISDN/x25_l3.h | 4 +- include/linux/isdn_compat.h | 15 +- include/linux/mISDNif.h | 348 +- std2kern | 19 +- stddiff | 2 +- 65 files changed, 9732 insertions(+), 8148 deletions(-) delete mode 100644 drivers/isdn/hardware/mISDN/bchannel.c delete mode 100644 drivers/isdn/hardware/mISDN/bchannel.h delete mode 100644 drivers/isdn/hardware/mISDN/dchannel.c delete mode 100644 drivers/isdn/hardware/mISDN/dchannel.h diff --git a/drivers/isdn/hardware/mISDN/Kconfig.v2.6 b/drivers/isdn/hardware/mISDN/Kconfig.v2.6 index 3b07d2d..80ed484 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig.v2.6 +++ b/drivers/isdn/hardware/mISDN/Kconfig.v2.6 @@ -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 diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 8d6ab37..143f439 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -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 + diff --git a/drivers/isdn/hardware/mISDN/Makefile.v2.6 b/drivers/isdn/hardware/mISDN/Makefile.v2.6 index 5ea97d0..143f439 100644 --- a/drivers/isdn/hardware/mISDN/Makefile.v2.6 +++ b/drivers/isdn/hardware/mISDN/Makefile.v2.6 @@ -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 + + diff --git a/drivers/isdn/hardware/mISDN/app_plci.c b/drivers/isdn/hardware/mISDN/app_plci.c index 1469337..7c2174b 100644 --- a/drivers/isdn/hardware/mISDN/app_plci.c +++ b/drivers/isdn/hardware/mISDN/app_plci.c @@ -32,10 +32,10 @@ __u16 q931CIPValue(Q931_info_t *qi) if (!qi) return 0; - if (!qi->bearer_capability) + if (!qi->bearer_capability.off) return 0; p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->bearer_capability; + p += L3_EXTRA_SIZE + qi->bearer_capability.off; if (memcmp(p, BEARER_SPEECH_64K_ALAW, 5) == 0 || memcmp(p, BEARER_SPEECH_64K_ULAW, 5) == 0) { CIPValue = 1; @@ -50,11 +50,12 @@ __u16 q931CIPValue(Q931_info_t *qi) CIPValue = 0; } - if (!qi->hlc) + // FIXME: handle duplicated IE's + if (!qi->hlc.off) return CIPValue; p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->hlc; + p += L3_EXTRA_SIZE + qi->hlc.off; if ((CIPValue == 1) || (CIPValue == 4)) { if (memcmp(p, HLC_TELEPHONY, 4) == 0) { CIPValue = 16; @@ -206,6 +207,7 @@ enum { ST_PLCI_P_3, ST_PLCI_P_4, ST_PLCI_P_ACT, + ST_PLCI_P_HELD, ST_PLCI_P_5, ST_PLCI_P_6, ST_PLCI_P_RES, @@ -221,6 +223,7 @@ static char *str_st_plci[] = { "ST_PLCI_P_3", "ST_PLCI_P_4", "ST_PLCI_P_ACT", + "ST_PLCI_P_HELD", "ST_PLCI_P_5", "ST_PLCI_P_6", "ST_PLCI_P_RES", @@ -241,6 +244,10 @@ enum { EV_AP_DISCONNECT_REQ, EV_PI_DISCONNECT_IND, EV_AP_DISCONNECT_RESP, + EV_AP_HOLD_REQ, + EV_AP_RETRIEVE_REQ, + EV_PI_HOLD_CONF, + EV_PI_RETRIEVE_CONF, EV_AP_SUSPEND_REQ, EV_PI_SUSPEND_CONF, EV_AP_RESUME_REQ, @@ -254,6 +261,12 @@ enum { EV_L3_RELEASE_IND, EV_L3_RELEASE_PROC_IND, EV_L3_NOTIFY_IND, + EV_L3_HOLD_IND, + EV_L3_HOLD_ACKNOWLEDGE, + EV_L3_HOLD_REJECT, + EV_L3_RETRIEVE_IND, + EV_L3_RETRIEVE_ACKNOWLEDGE, + EV_L3_RETRIEVE_REJECT, EV_L3_SUSPEND_ERR, EV_L3_SUSPEND_CONF, EV_L3_RESUME_ERR, @@ -280,6 +293,10 @@ static char* str_ev_plci[] = { "EV_AP_DISCONNECT_REQ", "EV_PI_DISCONNECT_IND", "EV_AP_DISCONNECT_RESP", + "EV_AP_HOLD_REQ", + "EV_AP_RETRIEVE_REQ", + "EV_PI_HOLD_CONF", + "EV_PI_RETRIEVE_CONF", "EV_AP_SUSPEND_REQ", "EV_PI_SUSPEND_CONF", "EV_AP_RESUME_REQ", @@ -293,6 +310,12 @@ static char* str_ev_plci[] = { "EV_L3_RELEASE_IND", "EV_L3_RELEASE_PROC_IND", "EV_L3_NOTIFY_IND", + "EV_L3_HOLD_IND", + "EV_L3_HOLD_ACKNOWLEDGE", + "EV_L3_HOLD_REJECT", + "EV_L3_RETRIEVE_IND", + "EV_L3_RETRIEVE_ACKNOWLEDGE", + "EV_L3_RETRIEVE_REJECT", "EV_L3_SUSPEND_ERR", "EV_L3_SUSPEND_CONF", "EV_L3_RESUME_ERR", @@ -447,6 +470,22 @@ plci_connect_ind(struct FsmInst *fi, int event, void *arg) Send2Application(fi->userdata, arg); } +static void plci_hold_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + + plciL4L3(plci, CC_HOLD | REQUEST, arg); +} + +static void plci_retrieve_req(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Plci_t *plci = aplci->plci; + + plciL4L3(plci, CC_RETRIEVE | REQUEST, arg); +} + static void plci_suspend_req(struct FsmInst *fi, int event, void *arg) { AppPlci_t *aplci = fi->userdata; @@ -706,12 +745,12 @@ plci_cc_setup_conf(struct FsmInst *fi, int event, void *arg) if (qi) { p = (u_char *)qi; p += L3_EXTRA_SIZE; - if (qi->connected_nr) - cmsg->ConnectedNumber = &p[qi->connected_nr + 1]; - if (qi->connected_sub) - cmsg->ConnectedSubaddress = &p[qi->connected_sub + 1]; - if (qi->llc) - cmsg->LLC = &p[qi->llc + 1]; + if (qi->connected_nr.off) + cmsg->ConnectedNumber = &p[qi->connected_nr.off + 1]; + if (qi->connected_sub.off) + cmsg->ConnectedSubaddress = &p[qi->connected_sub.off + 1]; + if (qi->llc.off) + cmsg->LLC = &p[qi->llc.off + 1]; } if (mISDN_FsmEvent(fi, EV_PI_CONNECT_ACTIVE_IND, cmsg)) cmsg_free(cmsg); @@ -770,20 +809,29 @@ plci_cc_setup_ind(struct FsmInst *fi, int event, void *arg) p = (u_char *)qi; p += L3_EXTRA_SIZE; cmsg->CIPValue = q931CIPValue(qi); - if (qi->called_nr) - cmsg->CalledPartyNumber = &p[qi->called_nr + 1]; - if (qi->called_sub) - cmsg->CalledPartySubaddress = &p[qi->called_sub + 1]; - if (qi->calling_nr) - cmsg->CallingPartyNumber = &p[qi->calling_nr + 1]; - if (qi->calling_sub) - cmsg->CallingPartySubaddress = &p[qi->calling_sub + 1]; - if (qi->bearer_capability) - cmsg->BC = &p[qi->bearer_capability + 1]; - if (qi->llc) - cmsg->LLC = &p[qi->llc + 1]; - if (qi->hlc) - cmsg->HLC = &p[qi->hlc + 1]; + if (qi->called_nr.off) + cmsg->CalledPartyNumber = &p[qi->called_nr.off + 1]; + if (qi->called_sub.off) + cmsg->CalledPartySubaddress = &p[qi->called_sub.off + 1]; + if (qi->calling_nr.off) + cmsg->CallingPartyNumber = &p[qi->calling_nr.off + 1]; + if (qi->calling_sub.off) + cmsg->CallingPartySubaddress = &p[qi->calling_sub.off + 1]; + if (qi->bearer_capability.off) + cmsg->BC = &p[qi->bearer_capability.off + 1]; + if (qi->llc.off) + cmsg->LLC = &p[qi->llc.off + 1]; + if (qi->hlc.off) + cmsg->HLC = &p[qi->hlc.off + 1]; +#if CAPIUTIL_VERSION > 1 + /* ETS 300 092 Annex B */ + if (qi->calling_nr.repeated) { + if (qi->ext[qi->calling_nr.ridx].ie.off) + cmsg->CallingPartyNumber2 = &p[qi->ext[qi->calling_nr.ridx].ie.off + 1]; + else + int_error(); + } +#endif // all else set to default } if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_CONNECT_IND, cmsg)) @@ -812,13 +860,13 @@ plci_cc_disconnect_ind(struct FsmInst *fi, int event, void *arg) if (qi) { p = (u_char *)qi; p += L3_EXTRA_SIZE; - if (qi->cause) - memcpy(aplci->cause, &p[qi->cause + 1], 3); + if (qi->cause.off) + memcpy(aplci->cause, &p[qi->cause.off + 1], 3); } if (aplci->appl->InfoMask & CAPI_INFOMASK_EARLYB3) return; - AppPlciLinkDown(aplci); +// AppPlciLinkDown(aplci); plciL4L3(aplci->plci, CC_RELEASE | REQUEST, NULL); } @@ -836,8 +884,8 @@ plci_cc_release_ind(struct FsmInst *fi, int event, void *arg) if (qi) { p = (u_char *)qi; p += L3_EXTRA_SIZE; - if (qi->cause) - cmsg->Reason = 0x3400 | p[qi->cause + 3]; + if (qi->cause.off) + cmsg->Reason = 0x3400 | p[qi->cause.off + 3]; else if (aplci->cause[0]) // cause from CC_DISCONNECT IND cmsg->Reason = 0x3400 | aplci->cause[2]; else @@ -854,32 +902,193 @@ plci_cc_notify_ind(struct FsmInst *fi, int event, void *arg) { AppPlci_t *aplci = fi->userdata; Q931_info_t *qi = arg; - _cmsg *cmsg; - __u8 tmp[10], *p, *nf; + __u8 *nf; - if (!qi || !qi->notify) + if (!qi || !qi->notify.off) return; nf = (u_char *)qi; - nf += L3_EXTRA_SIZE + qi->notify + 1; + nf += L3_EXTRA_SIZE + qi->notify.off + 1; if (nf[0] != 1) // len != 1 return; switch (nf[1]) { - case 0x80: // user suspended - case 0x81: // user resumed - if (!aplci->appl) - break; - if (!(aplci->appl->NotificationMask & SuppServiceTP)) - break; - CMSG_ALLOC(cmsg); - AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); - p = &tmp[1]; - p += capiEncodeWord(p, 0x8002 + (nf[1] & 1)); // Suspend/Resume Notification - *p++ = 0; // empty struct - tmp[0] = p - &tmp[1]; - cmsg->FacilitySelector = 0x0003; - cmsg->FacilityIndicationParameter = tmp; - Send2Application(aplci, cmsg); + case 0xF9: // user hold + SendSSNotificationEvent(aplci, 0x8000); break; + case 0xFA: // user retrieve + SendSSNotificationEvent(aplci, 0x8001); + break; + case 0x80: // user suspended + SendSSNotificationEvent(aplci, 0x8002); + break; + case 0x81: // user resumed + SendSSNotificationEvent(aplci, 0x8003); + break; + case 0xFB: // call is diverting + SendSSNotificationEvent(aplci, 0x8004); + break; + case 0xE8: // diversion activated + SendSSNotificationEvent(aplci, 0x8005); + break; + default: + int_errtxt("unhandled notification %x", nf[1]); + } +} + +static void plci_hold_conf(struct FsmInst *fi, int event, void *arg) +{ + mISDN_FsmChangeState(fi, ST_PLCI_P_HELD); +} + +static void +AppPlci_hold_reply(AppPlci_t *aplci, __u16 SuppServiceReason) +{ + _cmsg *cmsg; + __u8 tmp[10], *p; + + if (aplci->appl) { + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); + p = &tmp[1]; + p += capiEncodeWord(p, 0x0002); // Hold + p += capiEncodeFacIndSuspend(p, SuppServiceReason); + tmp[0] = p - &tmp[1]; + cmsg->FacilitySelector = 0x0003; + cmsg->FacilityIndicationParameter = tmp; + Send2Application(aplci, cmsg); + } + if (SuppServiceReason == CapiSuccess) + mISDN_FsmEvent(&aplci->plci_m, EV_PI_HOLD_CONF, NULL); +} + +static void +plci_cc_hold_rej(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *p; + __u16 SuppServiceReason; + + if (qi) { // reject from network + if (qi->cause.off) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->cause.off; + SuppServiceReason = 0x3400 | p[3]; + } else + SuppServiceReason = CapiProtocolErrorLayer3; + } else { // timeout + SuppServiceReason = CapiTimeOut; + } + AppPlci_hold_reply(aplci, SuppServiceReason); +} + +static void +plci_cc_hold_ack(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + + AppPlci_hold_reply(aplci, CapiSuccess); + AppPlciLinkDown(aplci); +} + +static void +plci_cc_hold_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + + AppPlci_hold_reply(aplci, CapiSuccess); + AppPlciLinkDown(aplci); + plciL4L3(aplci->plci, CC_HOLD_ACKNOWLEDGE| REQUEST, NULL); +} + +static void plci_retrieve_conf(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + + mISDN_FsmChangeState(fi, ST_PLCI_P_ACT); + AppPlciLinkUp(aplci); + if (test_bit(PLCI_STATE_STACKREADY, &aplci->plci->state)) + Send2Application(aplci, arg); + else + Send2ApplicationDelayed(aplci, arg); +} + +static void +AppPlci_retrieve_reply(AppPlci_t *aplci, __u16 SuppServiceReason) +{ + _cmsg *cmsg; + __u8 tmp[10], *p; + + if (aplci->appl) { + CMSG_ALLOC(cmsg); + AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); + p = &tmp[1]; + p += capiEncodeWord(p, 0x0003); // Retrieve + p += capiEncodeFacIndSuspend(p, SuppServiceReason); + tmp[0] = p - &tmp[1]; + cmsg->FacilitySelector = 0x0003; + cmsg->FacilityIndicationParameter = tmp; + + if (SuppServiceReason != CapiSuccess) + Send2Application(aplci, cmsg); + else + if (mISDN_FsmEvent(&aplci->plci_m, EV_PI_RETRIEVE_CONF, cmsg)) + cmsg_free(cmsg); + } +} + +static void +plci_cc_retrieve_rej(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *p; + __u16 SuppServiceReason; + + if (qi) { // reject from network + if (qi->cause.off) { + p = (u_char *)qi; + p += L3_EXTRA_SIZE + qi->cause.off; + SuppServiceReason = 0x3400 | p[3]; + } else + SuppServiceReason = CapiProtocolErrorLayer3; + } else { // timeout + SuppServiceReason = CapiTimeOut; + } + AppPlci_retrieve_reply(aplci, SuppServiceReason); +} + +static void +plci_cc_retrieve_ack(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *ie; + + if (qi->channel_id.off) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id.off; + aplci->channel = plci_parse_channel_id(ie); + AppPlci_retrieve_reply(aplci, CapiSuccess); + } else + AppPlci_retrieve_reply(aplci, 0x3711); /* resource Error */ +} + +static void +plci_cc_retrieve_ind(struct FsmInst *fi, int event, void *arg) +{ + AppPlci_t *aplci = fi->userdata; + Q931_info_t *qi = arg; + u_char *ie; + + if (qi->channel_id.off) { + ie = (u_char *)qi; + ie += L3_EXTRA_SIZE + qi->channel_id.off; + aplci->channel = plci_parse_channel_id(ie); + AppPlci_retrieve_reply(aplci, CapiSuccess); + plciL4L3(aplci->plci, CC_RETRIEVE_ACKNOWLEDGE | REQUEST, NULL); + } else { + AppPlci_retrieve_reply(aplci, 0x3711); /* resource Error */ + plciL4L3(aplci->plci, CC_RETRIEVE_REJECT | REQUEST, NULL); } } @@ -913,9 +1122,9 @@ plci_cc_suspend_err(struct FsmInst *fi, int event, void *arg) __u16 SuppServiceReason; if (qi) { // reject from network - if (qi->cause) { + if (qi->cause.off) { p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->cause; + p += L3_EXTRA_SIZE + qi->cause.off; SuppServiceReason = 0x3400 | p[3]; } else SuppServiceReason = CapiProtocolErrorLayer3; @@ -952,9 +1161,9 @@ plci_cc_resume_err(struct FsmInst *fi, int event, void *arg) CMSG_ALLOC(cmsg); AppPlciCmsgHeader(aplci, cmsg, CAPI_DISCONNECT, CAPI_IND); if (qi) { // reject from network - if (qi->cause) { + if (qi->cause.off) { p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->cause; + p += L3_EXTRA_SIZE + qi->cause.off; cmsg->Reason = 0x3400 | p[3]; } else cmsg->Reason = 0; @@ -973,12 +1182,12 @@ plci_cc_resume_conf(struct FsmInst *fi, int event, void *arg) _cmsg *cmsg; __u8 tmp[10], *p; - if (!qi || !qi->channel_id) { + if (!qi || !qi->channel_id.off) { int_error(); return; } p = (u_char *)qi; - p += L3_EXTRA_SIZE + qi->channel_id; + p += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(p); CMSG_ALLOC(cmsg); AppPlciCmsgHeader(aplci, cmsg, CAPI_FACILITY, CAPI_IND); @@ -1006,12 +1215,12 @@ plci_select_b_protocol_req(struct FsmInst *fi, int event, void *arg) ret = AppPlciLinkDown(aplci); if (ret) { - Info = 0x2001; + Info = CapiMessageNotSupportedInCurrentState; goto answer; } ret = AppPlciLinkUp(aplci); if (ret < 0) - Info = 0x2001; + Info = CapiMessageNotSupportedInCurrentState; else Info = ret; answer: @@ -1104,6 +1313,7 @@ static struct FsmNode fn_plci_list[] = {ST_PLCI_P_2, EV_AP_CONNECT_RESP, plci_connect_resp}, {ST_PLCI_P_2, EV_AP_DISCONNECT_REQ, plci_disconnect_req}, {ST_PLCI_P_2, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_2, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind}, {ST_PLCI_P_2, EV_AP_INFO_REQ, plci_info_req}, {ST_PLCI_P_2, EV_L3_RELEASE_IND, plci_cc_release_ind}, {ST_PLCI_P_2, EV_AP_RELEASE, plci_appl_release_disc}, @@ -1114,6 +1324,7 @@ static struct FsmNode fn_plci_list[] = {ST_PLCI_P_4, EV_AP_INFO_REQ, plci_info_req}, {ST_PLCI_P_4, EV_L3_SETUP_COMPL_IND, plci_cc_setup_compl_ind}, {ST_PLCI_P_4, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_4, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind}, {ST_PLCI_P_4, EV_PI_CHANNEL_ERR, plci_channel_err}, {ST_PLCI_P_4, EV_AP_RELEASE, plci_appl_release_disc}, @@ -1122,18 +1333,40 @@ static struct FsmNode fn_plci_list[] = {ST_PLCI_P_ACT, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, {ST_PLCI_P_ACT, EV_AP_INFO_REQ, plci_info_req}, {ST_PLCI_P_ACT, EV_AP_SELECT_B_PROTOCOL_REQ, plci_select_b_protocol_req}, + {ST_PLCI_P_ACT, EV_AP_HOLD_REQ, plci_hold_req}, {ST_PLCI_P_ACT, EV_AP_SUSPEND_REQ, plci_suspend_req}, {ST_PLCI_P_ACT, EV_PI_SUSPEND_CONF, plci_suspend_conf}, {ST_PLCI_P_ACT, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind}, {ST_PLCI_P_ACT, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_ACT, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind}, {ST_PLCI_P_ACT, EV_L3_NOTIFY_IND, plci_cc_notify_ind}, + {ST_PLCI_P_ACT, EV_L3_HOLD_IND, plci_cc_hold_ind}, + {ST_PLCI_P_ACT, EV_L3_HOLD_ACKNOWLEDGE, plci_cc_hold_ack}, + {ST_PLCI_P_ACT, EV_L3_HOLD_REJECT, plci_cc_hold_rej}, + {ST_PLCI_P_ACT, EV_PI_HOLD_CONF, plci_hold_conf}, {ST_PLCI_P_ACT, EV_L3_SUSPEND_ERR, plci_cc_suspend_err}, {ST_PLCI_P_ACT, EV_L3_SUSPEND_CONF, plci_cc_suspend_conf}, {ST_PLCI_P_ACT, EV_PH_CONTROL_IND, plci_cc_ph_control_ind}, {ST_PLCI_P_ACT, EV_AP_RELEASE, plci_appl_release_disc}, + {ST_PLCI_P_HELD, EV_AP_RETRIEVE_REQ, plci_retrieve_req}, + {ST_PLCI_P_HELD, EV_L3_RETRIEVE_ACKNOWLEDGE, plci_cc_retrieve_ack}, + {ST_PLCI_P_HELD, EV_L3_RETRIEVE_REJECT, plci_cc_retrieve_rej}, + {ST_PLCI_P_HELD, EV_PI_RETRIEVE_CONF, plci_retrieve_conf}, + {ST_PLCI_P_HELD, EV_AP_DISCONNECT_REQ, plci_disconnect_req}, + {ST_PLCI_P_HELD, EV_AP_INFO_REQ, plci_info_req}, + {ST_PLCI_P_HELD, EV_L3_RETRIEVE_IND, plci_cc_retrieve_ind}, + {ST_PLCI_P_HELD, EV_L3_DISCONNECT_IND, plci_cc_disconnect_ind}, + {ST_PLCI_P_HELD, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_HELD, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind}, + {ST_PLCI_P_HELD, EV_L3_NOTIFY_IND, plci_cc_notify_ind}, + {ST_PLCI_P_HELD, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, + {ST_PLCI_P_HELD, EV_AP_RELEASE, plci_appl_release_disc}, + {ST_PLCI_P_5, EV_PI_DISCONNECT_IND, plci_disconnect_ind}, {ST_PLCI_P_5, EV_L3_RELEASE_IND, plci_cc_release_ind}, + {ST_PLCI_P_5, EV_L3_RELEASE_PROC_IND, plci_cc_release_ind}, + {ST_PLCI_P_5, EV_AP_RELEASE, plci_appl_release}, {ST_PLCI_P_6, EV_AP_DISCONNECT_RESP, plci_disconnect_resp}, {ST_PLCI_P_6, EV_AP_RELEASE, plci_disconnect_resp}, @@ -1210,6 +1443,119 @@ AppPlciRelease(AppPlci_t *aplci) mISDN_FsmEvent(&aplci->plci_m, EV_AP_RELEASE, NULL); } +static __inline__ Ncci_t * +get_single_NCCI(AppPlci_t *aplci) +{ + struct list_head *item = aplci->Nccis.next; + + if (item == &aplci->Nccis) + return(NULL); + if (item->next != &aplci->Nccis) + return(NULL); // more as one NCCI + return((Ncci_t *)item); +} + +static int +PL_l3l4(mISDNinstance_t *inst, struct sk_buff *skb) +{ + AppPlci_t *aplci; + Ncci_t *ncci; + mISDN_head_t *hh; + + hh = mISDN_HEAD_P(skb); + aplci = inst->privat; + if (!aplci) + return(-EINVAL); + ncci = get_single_NCCI(aplci); + capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb(%p) APLCI(%x) ncci(%p)", + __FUNCTION__, hh->prim, hh->dinfo, skb, aplci->addr, ncci); + if (hh->prim == CAPI_MESSAGE_REQUEST) { + if (!ncci) { + int_error(); + return(-EINVAL); + } + ncciSendMessage(ncci, skb); + return(0); + } + if (!ncci) { + if ((hh->prim != (DL_ESTABLISH | INDICATION)) && (hh->prim != (DL_ESTABLISH | CONFIRM))) { + int_error(); + return(-ENODEV); + } + ncci = ncciConstr(aplci); + if (!ncci) { + int_error(); + return(-ENOMEM); + } + } + return(ncci_l3l4(ncci, hh, skb)); +} + +static int +PL_l3l4mux(mISDNinstance_t *inst, struct sk_buff *skb) +{ + AppPlci_t *aplci; + Ncci_t *ncci; + mISDN_head_t *hh; + __u32 addr; + + hh = mISDN_HEAD_P(skb); + aplci = inst->privat; + if (!aplci) + return(-EINVAL); + + capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb->len(%d)", + __FUNCTION__, hh->prim, hh->dinfo, skb->len); + if (skb->len < 4) { + int_error(); + return(-EINVAL); + } + if (hh->prim == CAPI_MESSAGE_REQUEST) { + ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT); + if (!ncci) { + int_error(); + return(-EINVAL); + } + ncciSendMessage(ncci, skb); + return(0); + } + addr = CAPIMSG_U32(skb->data, 0); + ncci = getNCCI4addr(aplci, addr, GET_NCCI_ONLY_PLCI); + if (hh->prim == CAPI_CONNECT_B3_IND) { + if (ncci) { + int_error(); + return(-EBUSY); + } + ncci = ncciConstr(aplci); + if (!ncci) { + int_error(); + return(-ENOMEM); + } + addr &= 0xffff0000; + addr |= aplci->addr; + ncci->addr = addr; + capimsg_setu32(skb->data, 0, addr); +#ifdef OLDCAPI_DRIVER_INTERFACE + ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window); +#endif + } else if (hh->prim == CAPI_CONNECT_B3_CONF) { + if (ncci && ((addr & 0xffff0000) != 0)) { + if (ncci->addr != addr) { + ncci->addr = addr; +#ifdef OLDCAPI_DRIVER_INTERFACE + ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window); +#endif + } else + int_error(); + } + } + if (!ncci) { + int_error(); + return(-ENODEV); + } + return(ncci_l3l4_direct(ncci, hh, skb)); +} + static int AppPlciLinkUp(AppPlci_t *aplci) { @@ -1234,16 +1580,20 @@ AppPlciLinkUp(AppPlci_t *aplci) } pid.protocol[1] = (1 << aplci->Bprotocol.B1) | ISDN_PID_LAYER(1) | ISDN_PID_BCHANNEL_BIT; - if (aplci->Bprotocol.B1cfg[0]) + if (aplci->Bprotocol.B1cfg[0]) { pid.param[1] = &aplci->Bprotocol.B1cfg[0]; + pid.maxplen += aplci->Bprotocol.B1cfg[0]; + } if (aplci->Bprotocol.B2 > 23) { int_errtxt("wrong B2 prot %x", aplci->Bprotocol.B2); return(0x3002); } pid.protocol[2] = (1 << aplci->Bprotocol.B2) | ISDN_PID_LAYER(2) | ISDN_PID_BCHANNEL_BIT; - if (aplci->Bprotocol.B2cfg[0]) + if (aplci->Bprotocol.B2cfg[0]) { pid.param[2] = &aplci->Bprotocol.B2cfg[0]; + pid.maxplen += aplci->Bprotocol.B2cfg[0]; + } /* handle DTMF TODO */ if ((pid.protocol[2] == ISDN_PID_L2_B_TRANS) && (pid.protocol[1] == ISDN_PID_L1_B_64TRANS)) @@ -1254,8 +1604,10 @@ AppPlciLinkUp(AppPlci_t *aplci) } pid.protocol[3] = (1 << aplci->Bprotocol.B3) | ISDN_PID_LAYER(3) | ISDN_PID_BCHANNEL_BIT; - if (aplci->Bprotocol.B3cfg[0]) + if (aplci->Bprotocol.B3cfg[0]) { pid.param[3] = &aplci->Bprotocol.B3cfg[0]; + pid.maxplen += aplci->Bprotocol.B3cfg[0]; + } capidebug(CAPI_DBG_PLCI, "AppPlciLinkUp B1(%x) B2(%x) B3(%x) global(%d) ch(%x)", pid.protocol[1], pid.protocol[2], pid.protocol[3], pid.global, aplci->channel); @@ -1269,17 +1621,23 @@ AppPlciLinkUp(AppPlci_t *aplci) } capidebug(CAPI_DBG_NCCI, "AppPlciLinkUp aplci->link(%p)", aplci->link); memset(&aplci->link->inst.pid, 0, sizeof(mISDN_pid_t)); - aplci->link->inst.data = aplci; + aplci->link->inst.privat = aplci; aplci->link->inst.pid.layermask = ISDN_LAYER(4); aplci->link->inst.pid.protocol[4] = ISDN_PID_L4_B_CAPI20; if (pid.protocol[3] == ISDN_PID_L3_B_TRANS) { aplci->link->inst.pid.protocol[3] = ISDN_PID_L3_B_TRANS; aplci->link->inst.pid.layermask |= ISDN_LAYER(3); } + if (aplci->link->inst.function) + int_errtxt("id(%08x) overwrite function (%p)", aplci->link->inst.id, aplci->link->inst.function); + if (aplci->Bprotocol.B3 == 0) // transparent + aplci->link->inst.function = PL_l3l4; + else + aplci->link->inst.function = PL_l3l4mux; retval = aplci->link->inst.obj->ctrl(aplci->link->st, - MGR_REGLAYER | INDICATION, &aplci->link->inst); + MGR_ADDLAYER | REQUEST, &aplci->link->inst); if (retval) { - printk(KERN_WARNING "%s MGR_REGLAYER | INDICATION ret(%d)\n", + printk(KERN_WARNING "%s MGR_ADDLAYER | REQUEST ret(%d)\n", __FUNCTION__, retval); return(retval); } @@ -1327,7 +1685,7 @@ ReleaseLink(AppPlci_t *aplci) Ncci_t * getNCCI4addr(AppPlci_t *aplci, __u32 addr, int mode) { - Ncci_t *ncci; + Ncci_t *ncci = NULL; struct list_head *item; int cnt = 0; @@ -1357,120 +1715,13 @@ AppPlciDelNCCI(Ncci_t *ncci) { list_del_init(&ncci->head); } -static __inline__ Ncci_t * -get_single_NCCI(AppPlci_t *aplci) -{ - struct list_head *item = aplci->Nccis.next; - - if (item == &aplci->Nccis) - return(NULL); - if (item->next != &aplci->Nccis) - return(NULL); // more as one NCCI - return((Ncci_t *)item); -} - -static int -PL_l3l4(mISDNif_t *hif, struct sk_buff *skb) -{ - AppPlci_t *aplci; - Ncci_t *ncci; - int ret = -EINVAL; - mISDN_head_t *hh; - - if (!hif || !skb) - return(ret); - hh = mISDN_HEAD_P(skb); - aplci = hif->fdata; - if (!aplci) - return(-EINVAL); - ncci = get_single_NCCI(aplci); - capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb(%p) APLCI(%x) ncci(%p)", - __FUNCTION__, hh->prim, hh->dinfo, skb, aplci->addr, ncci); - if (!ncci) { - if ((hh->prim != (DL_ESTABLISH | INDICATION)) && (hh->prim != (DL_ESTABLISH | CONFIRM))) { - int_error(); - return(-ENODEV); - } - ncci = ncciConstr(aplci); - if (!ncci) { - int_error(); - return(-ENOMEM); - } - } - return(ncci_l3l4(ncci, hh, skb)); -} - -static int -PL_l3l4mux(mISDNif_t *hif, struct sk_buff *skb) -{ - AppPlci_t *aplci; - Ncci_t *ncci; - int ret = -EINVAL; - mISDN_head_t *hh; - __u32 addr; - - if (!hif || !skb) - return(ret); - hh = mISDN_HEAD_P(skb); - aplci = hif->fdata; - if (!aplci) - return(-EINVAL); - - capidebug(CAPI_DBG_NCCI_L3, "%s: prim(%x) dinfo (%x) skb->len(%d)", - __FUNCTION__, hh->prim, hh->dinfo, skb->len); - if (skb->len < 4) { - int_error(); - return(-EINVAL); - } - addr = CAPIMSG_U32(skb->data, 0); - ncci = getNCCI4addr(aplci, addr, GET_NCCI_ONLY_PLCI); - if (hh->prim == CAPI_CONNECT_B3_IND) { - if (ncci) { - int_error(); - return(-EBUSY); - } - ncci = ncciConstr(aplci); - if (!ncci) { - int_error(); - return(-ENOMEM); - } - addr &= 0xffff0000; - addr |= aplci->addr; - ncci->addr = addr; - capimsg_setu32(skb->data, 0, addr); -#ifdef OLDCAPI_DRIVER_INTERFACE - ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window); -#endif - } else if (hh->prim == CAPI_CONNECT_B3_CONF) { - if (ncci && ((addr & 0xffff0000) != 0)) { - if (ncci->addr != addr) { - ncci->addr = addr; -#ifdef OLDCAPI_DRIVER_INTERFACE - ncci->contr->ctrl->new_ncci(ncci->contr->ctrl, ncci->appl->ApplId, addr, ncci->window); -#endif - } else - int_error(); - } - } - if (!ncci) { - int_error(); - return(-ENODEV); - } - return(ncci_l3l4_direct(ncci, hh, skb)); -} - int -AppPlcimISDN_SetIF(AppPlci_t *aplci, u_int prim, void *arg) +AppPlcimISDN_Active(AppPlci_t *aplci) { - int ret; - - if (aplci->Bprotocol.B3 == 0) // transparent - ret = mISDN_SetIF(&aplci->link->inst, arg, prim, NULL, PL_l3l4, aplci); - else - ret = mISDN_SetIF(&aplci->link->inst, arg, prim, NULL, PL_l3l4mux, aplci); - if (ret) - return(ret); - + if (!aplci) { + int_error(); + return(-EINVAL); + } if (!test_and_set_bit(PLCI_STATE_SENDDELAYED, &aplci->plci->state)) { test_and_set_bit(PLCI_STATE_STACKREADY, &aplci->plci->state); SendingDelayedMsg(aplci); @@ -1491,17 +1742,21 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) case CC_SETUP | INDICATION: if (!qi) return; - AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); - AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); - AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); - AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); - AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { + if (qi->channel_id.off) { ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; + ie += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(ie); } - mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_IND, arg); + mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_IND, arg); + if (qi) { + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_USER_USER, CAPI_INFOMASK_USERUSER, qi); + AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); + AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + AppPlciInfoIndIE(aplci, IE_CALLED_PN, CAPI_INFOMASK_CALLEDPN, qi); + AppPlciInfoIndIE(aplci, IE_COMPLETE, CAPI_INFOMASK_COMPLETE, qi); + } break; case CC_TIMEOUT | INDICATION: mISDN_FsmEvent(&aplci->plci_m, EV_L3_SETUP_CONF_ERR, arg); @@ -1514,9 +1769,9 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS, qi); AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { + if (qi->channel_id.off) { ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; + ie += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(ie); } } @@ -1526,9 +1781,9 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) if (qi) { AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { + if (qi->channel_id.off) { ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; + ie += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(ie); } } @@ -1573,9 +1828,9 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { + if (qi->channel_id.off) { ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; + ie += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(ie); } } @@ -1587,9 +1842,9 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) AppPlciInfoIndIE(aplci, IE_PROGRESS, CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { + if (qi->channel_id.off) { ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; + ie += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(ie); } } @@ -1603,9 +1858,9 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); AppPlciInfoIndIE(aplci, IE_FACILITY, CAPI_INFOMASK_FACILITY, qi); AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); - if (qi->channel_id) { + if (qi->channel_id.off) { ie = (u_char *)qi; - ie += L3_EXTRA_SIZE + qi->channel_id; + ie += L3_EXTRA_SIZE + qi->channel_id.off; aplci->channel = plci_parse_channel_id(ie); } } @@ -1620,6 +1875,50 @@ AppPlci_l3l4(AppPlci_t *aplci, int pr, void *arg) CAPI_INFOMASK_PROGRESS | CAPI_INFOMASK_EARLYB3, qi); } break; + case CC_HOLD | INDICATION: + if (qi) + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + if (mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_IND, arg)) { + /* no routine reject L3 */ + plciL4L3(aplci->plci, CC_HOLD_REJECT | REQUEST, NULL); + } + break; + case CC_HOLD_ACKNOWLEDGE | INDICATION: + if (qi) + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_ACKNOWLEDGE, arg); + break; + case CC_HOLD_REJECT | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + } + mISDN_FsmEvent(&aplci->plci_m, EV_L3_HOLD_REJECT, arg); + break; + case CC_RETRIEVE | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + } + if (mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_IND, arg)) { + /* no routine reject L3 */ + plciL4L3(aplci->plci, CC_RETRIEVE_REJECT | REQUEST, NULL); + } + break; + case CC_RETRIEVE_ACKNOWLEDGE | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + AppPlciInfoIndIE(aplci, IE_CHANNEL_ID, CAPI_INFOMASK_CHANNELID, qi); + } + mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_ACKNOWLEDGE, arg); + break; + case CC_RETRIEVE_REJECT | INDICATION: + if (qi) { + AppPlciInfoIndIE(aplci, IE_CAUSE, CAPI_INFOMASK_CAUSE, qi); + AppPlciInfoIndIE(aplci, IE_DISPLAY, CAPI_INFOMASK_DISPLAY, qi); + } + mISDN_FsmEvent(&aplci->plci_m, EV_L3_RETRIEVE_REJECT, arg); + break; case CC_SUSPEND_ACKNOWLEDGE | INDICATION: mISDN_FsmEvent(&aplci->plci_m, EV_L3_SUSPEND_CONF, arg); break; @@ -1709,17 +2008,53 @@ AppPlciSendMessage(AppPlci_t *aplci, struct sk_buff *skb) return(ret); } -int +void ConnectB3Request(AppPlci_t *aplci, struct sk_buff *skb) { Ncci_t *ncci = ncciConstr(aplci); + int err; if (!ncci) { int_error(); - return(-ENOMEM); + dev_kfree_skb(skb); + return; + } + if (!ncci->link) { + int_error(); + dev_kfree_skb(skb); + return; + } + err = mISDN_queue_message(&ncci->link->inst, 0, skb); + if (err) { + int_errtxt("mISDN_queue_message return(%d)", err); + dev_kfree_skb(skb); + } +} + +void +DisconnectB3Request(AppPlci_t *aplci, struct sk_buff *skb) +{ + Ncci_t *ncci; + int err; + + ncci = getNCCI4addr(aplci, CAPIMSG_NCCI(skb->data), GET_NCCI_EXACT); + if ((!ncci) || (!ncci->link)) { + int_error(); + if (aplci->appl) + AnswerMessage2Application(aplci->appl, skb, CapiIllContrPlciNcci); + dev_kfree_skb(skb); + return; + } + if (ncci->link->inst.id == 0) { + /* stack is already cleared and so we cannot handle this via the stack */ + ncciSendMessage(ncci, skb); + return; + } + err = mISDN_queue_message(&ncci->link->inst, 0, skb); + if (err) { + int_errtxt("mISDN_queue_message return(%d)", err); + dev_kfree_skb(skb); } - ncciSendMessage(ncci, skb); - return(0); } static int @@ -1734,6 +2069,52 @@ AppPlciLinkDown(AppPlci_t *aplci) return(0); } +int +AppPlciFacHoldReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm) +{ + struct sk_buff *skb; + + skb = mISDN_alloc_l3msg(20, MT_HOLD); + if (!skb) { + int_error(); + return CapiIllMessageParmCoding; + } + + if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_HOLD_REQ, skb)) { + // no routine + facConfParm->u.Info.SupplementaryServiceInfo = + CapiRequestNotAllowedInThisState; + dev_kfree_skb(skb); + return CapiMessageNotSupportedInCurrentState; + } else { + facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; + } + return CapiSuccess; +} + +int +AppPlciFacRetrieveReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm) +{ + struct sk_buff *skb; + + skb = mISDN_alloc_l3msg(20, MT_RETRIEVE); + if (!skb) { + int_error(); + return CapiIllMessageParmCoding; + } + + if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_RETRIEVE_REQ, skb)) { + // no routine + facConfParm->u.Info.SupplementaryServiceInfo = + CapiRequestNotAllowedInThisState; + dev_kfree_skb(skb); + return CapiMessageNotSupportedInCurrentState; + } else { + facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; + } + return CapiSuccess; +} + int AppPlciFacSuspendReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *facConfParm) { @@ -1755,7 +2136,8 @@ AppPlciFacSuspendReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t * // no routine facConfParm->u.Info.SupplementaryServiceInfo = CapiRequestNotAllowedInThisState; - kfree(skb); + dev_kfree_skb(skb); + return CapiMessageNotSupportedInCurrentState; } else { facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; } @@ -1782,7 +2164,7 @@ AppPlciFacResumeReq(AppPlci_t *aplci, FacReqParm_t *facReqParm, FacConfParm_t *f if (CallIdentity && CallIdentity[0]) mISDN_AddIE(skb, IE_CALL_ID, CallIdentity); if (mISDN_FsmEvent(&aplci->plci_m, EV_AP_RESUME_REQ, skb)) - kfree(skb); + dev_kfree_skb(skb); facConfParm->u.Info.SupplementaryServiceInfo = CapiSuccess; return CapiSuccess; @@ -1829,7 +2211,7 @@ AppPlciInfoIndIE(AppPlci_t *aplci, unsigned char ie, __u32 mask, Q931_info_t *qi { _cmsg *cmsg; u_char *iep = NULL; - u16 *ies; + ie_info_t *ies; if ((!aplci->appl) || (!(aplci->appl->InfoMask & mask))) @@ -1838,16 +2220,21 @@ AppPlciInfoIndIE(AppPlci_t *aplci, unsigned char ie, __u32 mask, Q931_info_t *qi return; ies = &qi->bearer_capability; if (ie & 0x80) { /* single octett */ - int_error(); - return; + if (ie == IE_COMPLETE) { + if (!qi->sending_complete.off) + return; + } else { + int_error(); + return; + } } else { if (mISDN_l3_ie2pos(ie) < 0) return; ies += mISDN_l3_ie2pos(ie); - if (!*ies) + if (!ies->off) return; iep = (u_char *)qi; - iep += L3_EXTRA_SIZE + *ies +1; + iep += L3_EXTRA_SIZE + ies->off +1; } CMSG_ALLOC(cmsg); AppPlciCmsgHeader(aplci, cmsg, CAPI_INFO, CAPI_IND); diff --git a/drivers/isdn/hardware/mISDN/appl.c b/drivers/isdn/hardware/mISDN/appl.c index e912254..ce0b670 100644 --- a/drivers/isdn/hardware/mISDN/appl.c +++ b/drivers/isdn/hardware/mISDN/appl.c @@ -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 * diff --git a/drivers/isdn/hardware/mISDN/arcofi.c b/drivers/isdn/hardware/mISDN/arcofi.c index 422e132..f56581f 100644 --- a/drivers/isdn/hardware/mISDN/arcofi.c +++ b/drivers/isdn/hardware/mISDN/arcofi.c @@ -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; diff --git a/drivers/isdn/hardware/mISDN/arcofi.h b/drivers/isdn/hardware/mISDN/arcofi.h index 6269838..df82739 100644 --- a/drivers/isdn/hardware/mISDN/arcofi.h +++ b/drivers/isdn/hardware/mISDN/arcofi.h @@ -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 *); diff --git a/drivers/isdn/hardware/mISDN/asn1.h b/drivers/isdn/hardware/mISDN/asn1.h index dafcc58..fd545c6 100644 --- a/drivers/isdn/hardware/mISDN/asn1.h +++ b/drivers/isdn/hardware/mISDN/asn1.h @@ -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) diff --git a/drivers/isdn/hardware/mISDN/asn1_comp.c b/drivers/isdn/hardware/mISDN/asn1_comp.c index 18a956a..d32f974 100644 --- a/drivers/isdn/hardware/mISDN/asn1_comp.c +++ b/drivers/isdn/hardware/mISDN/asn1_comp.c @@ -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; } diff --git a/drivers/isdn/hardware/mISDN/asn1_enc.c b/drivers/isdn/hardware/mISDN/asn1_enc.c index 8346577..776d9e7 100644 --- a/drivers/isdn/hardware/mISDN/asn1_enc.c +++ b/drivers/isdn/hardware/mISDN/asn1_enc.c @@ -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; +} + diff --git a/drivers/isdn/hardware/mISDN/asn1_enc.h b/drivers/isdn/hardware/mISDN/asn1_enc.h index 4fb29b4..32965cc 100644 --- a/drivers/isdn/hardware/mISDN/asn1_enc.h +++ b/drivers/isdn/hardware/mISDN/asn1_enc.h @@ -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); diff --git a/drivers/isdn/hardware/mISDN/avm_fritz.c b/drivers/isdn/hardware/mISDN/avm_fritz.c index 0d635b1..fd97df8 100644 --- a/drivers/isdn/hardware/mISDN/avm_fritz.c +++ b/drivers/isdn/hardware/mISDN/avm_fritz.c @@ -17,16 +17,11 @@ #include #endif #include -#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; diff --git a/drivers/isdn/hardware/mISDN/bchannel.c b/drivers/isdn/hardware/mISDN/bchannel.c deleted file mode 100644 index 56730f4..0000000 --- a/drivers/isdn/hardware/mISDN/bchannel.c +++ /dev/null @@ -1,156 +0,0 @@ -/* $Id$ - * - * Author Karsten Keil (keil@isdn4linux.de) - * - * This file is (c) under GNU PUBLIC LICENSE - * - */ - -#include -#include -#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); diff --git a/drivers/isdn/hardware/mISDN/bchannel.h b/drivers/isdn/hardware/mISDN/bchannel.h deleted file mode 100644 index 123dd11..0000000 --- a/drivers/isdn/hardware/mISDN/bchannel.h +++ /dev/null @@ -1,98 +0,0 @@ -/* $Id$ - * - * Basic declarations, defines for Bchannel hardware - * - * This file is (c) under GNU PUBLIC LICENSE - * - */ - -#include -#ifdef HAS_WORKQUEUE -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#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); -} diff --git a/drivers/isdn/hardware/mISDN/capi.c b/drivers/isdn/hardware/mISDN/capi.c index 9bcddf7..44864f5 100644 --- a/drivers/isdn/hardware/mISDN/capi.c +++ b/drivers/isdn/hardware/mISDN/capi.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/contr.c b/drivers/isdn/hardware/mISDN/contr.c index 2bf1dba..b88a434 100644 --- a/drivers/isdn/hardware/mISDN/contr.c +++ b/drivers/isdn/hardware/mISDN/contr.c @@ -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); } diff --git a/drivers/isdn/hardware/mISDN/core.c b/drivers/isdn/hardware/mISDN/core.c index 9a39a12..1293b23 100644 --- a/drivers/isdn/hardware/mISDN/core.c +++ b/drivers/isdn/hardware/mISDN/core.c @@ -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"); } diff --git a/drivers/isdn/hardware/mISDN/core.h b/drivers/isdn/hardware/mISDN/core.h index 9cb4999..9349c8d 100644 --- a/drivers/isdn/hardware/mISDN/core.h +++ b/drivers/isdn/hardware/mISDN/core.h @@ -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); diff --git a/drivers/isdn/hardware/mISDN/dchannel.c b/drivers/isdn/hardware/mISDN/dchannel.c deleted file mode 100644 index 865be67..0000000 --- a/drivers/isdn/hardware/mISDN/dchannel.c +++ /dev/null @@ -1,116 +0,0 @@ -/* $Id$ - * - * Author Karsten Keil (keil@isdn4linux.de) - * - * This file is (c) under GNU PUBLIC LICENSE - * - */ - -#include -#include -#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); diff --git a/drivers/isdn/hardware/mISDN/dchannel.h b/drivers/isdn/hardware/mISDN/dchannel.h deleted file mode 100644 index 57f9847..0000000 --- a/drivers/isdn/hardware/mISDN/dchannel.h +++ /dev/null @@ -1,92 +0,0 @@ -/* $Id$ - * - * Basic declarations for dchannel HW - * - * This file is (c) under GNU PUBLIC LICENSE - * - */ - -#include -#ifdef HAS_WORKQUEUE -#include -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#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); -} diff --git a/drivers/isdn/hardware/mISDN/debug.h b/drivers/isdn/hardware/mISDN/debug.h index 4bc155e..59342b2 100644 --- a/drivers/isdn/hardware/mISDN/debug.h +++ b/drivers/isdn/hardware/mISDN/debug.h @@ -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 diff --git a/drivers/isdn/hardware/mISDN/dsp.h b/drivers/isdn/hardware/mISDN/dsp.h index 8a23717..85d35de 100644 --- a/drivers/isdn/hardware/mISDN/dsp.h +++ b/drivers/isdn/hardware/mISDN/dsp.h @@ -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 -#else -#include -#endif +#define FEAT_STATE_INIT 1 +#define FEAT_STATE_WAIT 2 + #include #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); + diff --git a/drivers/isdn/hardware/mISDN/dsp_blowfish.c b/drivers/isdn/hardware/mISDN/dsp_blowfish.c index 016efe9..ac840b5 100644 --- a/drivers/isdn/hardware/mISDN/dsp_blowfish.c +++ b/drivers/isdn/hardware/mISDN/dsp_blowfish.c @@ -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. diff --git a/drivers/isdn/hardware/mISDN/dsp_cmx.c b/drivers/isdn/hardware/mISDN/dsp_cmx.c index b14cb59..904541b 100644 --- a/drivers/isdn/hardware/mISDN/dsp_cmx.c +++ b/drivers/isdn/hardware/mISDN/dsp_cmx.c @@ -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(iW_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; } - - diff --git a/drivers/isdn/hardware/mISDN/dsp_core.c b/drivers/isdn/hardware/mISDN/dsp_core.c index 30db2f6..88aae42 100644 --- a/drivers/isdn/hardware/mISDN/dsp_core.c +++ b/drivers/isdn/hardware/mISDN/dsp_core.c @@ -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__); diff --git a/drivers/isdn/hardware/mISDN/dsp_dtmf.c b/drivers/isdn/hardware/mISDN/dsp_dtmf.c index 96c8332..e77ef96 100644 --- a/drivers/isdn/hardware/mISDN/dsp_dtmf.c +++ b/drivers/isdn/hardware/mISDN/dsp_dtmf.c @@ -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 diff --git a/drivers/isdn/hardware/mISDN/dsp_tones.c b/drivers/isdn/hardware/mISDN/dsp_tones.c index 92def6a..37ad1e2 100644 --- a/drivers/isdn/hardware/mISDN/dsp_tones.c +++ b/drivers/isdn/hardware/mISDN/dsp_tones.c @@ -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); } diff --git a/drivers/isdn/hardware/mISDN/dss1.h b/drivers/isdn/hardware/mISDN/dss1.h index 4921d6b..a57d1b8 100644 --- a/drivers/isdn/hardware/mISDN/dss1.h +++ b/drivers/isdn/hardware/mISDN/dss1.h @@ -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 */ diff --git a/drivers/isdn/hardware/mISDN/dtmf.c b/drivers/isdn/hardware/mISDN/dtmf.c index e20d85e..5a11ad5 100644 --- a/drivers/isdn/hardware/mISDN/dtmf.c +++ b/drivers/isdn/hardware/mISDN/dtmf.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/helper.c b/drivers/isdn/hardware/mISDN/helper.c index daf8470..ce06f5a 100644 --- a/drivers/isdn/hardware/mISDN/helper.c +++ b/drivers/isdn/hardware/mISDN/helper.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/helper.h b/drivers/isdn/hardware/mISDN/helper.h index 05cac69..d66992f 100644 --- a/drivers/isdn/hardware/mISDN/helper.h +++ b/drivers/isdn/hardware/mISDN/helper.h @@ -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 */ -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 */ diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.c b/drivers/isdn/hardware/mISDN/hfc_multi.c index 2d18a86..e8a3473 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.c +++ b/drivers/isdn/hardware/mISDN/hfc_multi.c @@ -1,8 +1,9 @@ -/* - +/* * hfc_multi.c low level driver for hfc-4s/hfc-8s/hfc-e1 based cards * - * Author Andreas Eversberg (jolly@jolly.de) + * Author Andreas Eversberg (jolly@jolly.de) + * ported to mqueue mechanism: + * Peter Sprenger (sprengermoving-bytes.de) * * inspired by existing hfc-pci driver: * Copyright 1999 by Werner Cornelius (werner@isdn-development.de) @@ -23,7 +24,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * - * Thanx to Cologne Chip AG for this great controller! + * Thanks to Cologne Chip AG for this great controller! */ /* module parameters: @@ -33,7 +34,7 @@ Value 8 = HFC-8S (8 ports) 0x08 Bit 8 = uLaw (instead of aLaw) Bit 9 = Enable DTMF detection on all B-channels - Bit 10 = spare + Bit 10 = spare Bit 11 = Set PCM bus into slave mode. Bit 12 = Ignore missing frame clock on PCM bus. Bit 13 = Use direct RX clock for PCM sync rather than PLL. (E1 only) @@ -41,6 +42,7 @@ Bit 15 = Use external ram (512K) Bit 16 = Use 64 timeslots instead of 32 Bit 17 = Use 128 timeslots instead of anything else + Bit 18 = Use crystal clock for PCM and E1, for autarc clocking. * protocol: NOTE: Must be given for all ports, not for the number of cards. @@ -53,7 +55,6 @@ Bit 16 = Use master clock for this S/T interface (ony once per chip). Bit 17 = transmitter line setup (non capacitive mode) DONT CARE! Bit 18 = Disable E-channel. (No E-channel processing) - Bit 19 = Register E-channel as D-stack (TE-mode only) HFC-E1 only bits: Bit 16 = interface: 0=copper, 1=optical @@ -62,6 +63,7 @@ Bit 19 = Report AIS Bit 20 = Report SLIP Bit 21-22 = elastic jitter buffer (1-3), Use 0 for default. + Bit 23 = Turn off CRC-4 Multiframe Mode, use double frame mode instead. (all other bits are reserved and shall be 0) * layermask: @@ -95,24 +97,35 @@ #include #include -#include "dchannel.h" -#include "bchannel.h" +#include "channel.h" #include "layer1.h" #include "dsp.h" -#include "helper.h" #include "debug.h" #include -#define SPIN_DEBUG -#define LOCK_STATISTIC -#include "hw_lock.h" +#warning + +//#define IRQCOUNT_DEBUG #include "hfc_multi.h" +#warning +#define bugtest {} +#if 0 +#define bugtest \ + if (hc->irq) free_irq(hc->irq, hc); \ + hc->irq = 0; \ + if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, SA_SHIRQ, "HFC-multi", hc)) { \ + printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", hc->pci_dev->irq); \ + hc->irq = hc->pci_dev->irq; } +#endif + +static void ph_state_change(channel_t *ch); + extern const char *CardType[]; static const char *hfcmulti_revision = "$Revision$"; -static int HFC_cnt; +static int HFC_cnt, HFC_idx; static mISDNobject_t HFCM_obj; @@ -139,38 +152,50 @@ static int nt_t1_count[] = { 480, 240, 120, 60, 30, 15, 8, 4 }; static u_char silence = 0xff; /* silence by LAW */ /* enable 32 bit fifo access (PC usage) */ -#define FIFO_32BIT_ACCESS +//#define FIFO_32BIT_ACCESS #define VENDOR_CCD "Cologne Chip AG" +#define CCAG_VID 0x1397 // Cologne Chip Vendor ID +#define HFC4S_ID 0x08B4 +#define HFC8S_ID 0x16B8 +#define HFCE1_ID 0x30B1 static const PCI_ENTRY id_list[] = { - {0x1397, 0x1397, 0x08B4, 0x08B4, VENDOR_CCD, - "HFC-4S Eval", 4, 0, 0}, - {0x1397, 0x1397, 0x16B8, 0x16B8, VENDOR_CCD, - "HFC-8S Eval", 8, 0, 0}, - {0x1397, 0x1397, 0x30B1, 0x30B1, VENDOR_CCD, - "HFC-E1 Eval", 1, 0, 0}, - {0x1397, 0x1397, 0x08B4, 0xB520, VENDOR_CCD, + {CCAG_VID, 0xffffffff, HFC4S_ID, 0xffffffff, VENDOR_CCD, + "HFC-4S CCAG Eval", 4, 1, 2}, + {CCAG_VID, 0xffffffff, HFC8S_ID, 0xffffffff, VENDOR_CCD, + "HFC-8S CCAG Eval", 8, 1, 0}, + {CCAG_VID, 0xffffffff, HFCE1_ID, 0xffffffff, VENDOR_CCD, + "HFC-E1 CCAG Eval", 1, 0, 1}, /* E1 only supports single clock */ + {CCAG_VID, CCAG_VID, HFC4S_ID, 0x08B4, VENDOR_CCD, + "HFC-4S CCAG Eval (old)", 4, 0, 0}, + {CCAG_VID, CCAG_VID, HFC8S_ID, 0x16B8, VENDOR_CCD, + "HFC-8S CCAG Eval (old)", 8, 0, 0}, + {CCAG_VID, CCAG_VID, HFCE1_ID, 0x30B1, VENDOR_CCD, + "HFC-E1 CCAG Eval (old)", 1, 0, 0}, + {CCAG_VID, CCAG_VID, HFC4S_ID, 0xB520, VENDOR_CCD, "HFC-4S IOB4ST", 4, 1, 2}, - {0x1397, 0x1397, 0x08B4, 0xB620, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFC4S_ID, 0xB620, VENDOR_CCD, "HFC-4S", 4, 1, 2}, - {0x1397, 0x1397, 0x08B4, 0xB560, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFC4S_ID, 0xB560, VENDOR_CCD, "HFC-4S Beronet Card", 4, 1, 2}, - {0x1397, 0x1397, 0x16B8, 0xB521, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFC8S_ID, 0xB521, VENDOR_CCD, "HFC-8S IOB4ST Recording", 8, 1, 0}, - {0x1397, 0x1397, 0x16B8, 0xB522, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFC8S_ID, 0xB522, VENDOR_CCD, "HFC-8S IOB8ST", 8, 1, 0}, - {0x1397, 0x1397, 0x16B8, 0xB622, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFC8S_ID, 0xB622, VENDOR_CCD, "HFC-8S", 8, 1, 0}, - {0x1397, 0x1397, 0x16B8, 0xB562, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFC8S_ID, 0xB562, VENDOR_CCD, "HFC-8S Beronet Card", 8, 1, 0}, - {0x1397, 0x1397, 0x30B1, 0xB523, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFCE1_ID, 0xB523, VENDOR_CCD, "HFC-E1 IOB1E1", 1, 0, 1}, /* E1 only supports single clock */ - {0x1397, 0x1397, 0x30B1, 0xC523, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFCE1_ID, 0xC523, VENDOR_CCD, "HFC-E1", 1, 0, 1}, /* E1 only supports single clock */ - {0x1397, 0x1397, 0x30B1, 0xB563, VENDOR_CCD, + {CCAG_VID, CCAG_VID, HFCE1_ID, 0xB563, VENDOR_CCD, "HFC-E1 Beronet Card", 1, 0, 1}, /* E1 only supports single clock */ + {0x10B5, CCAG_VID, 0x9030, 0x3136, VENDOR_CCD, + "HFC-4S PCIBridgeEval", 4, 0, 0}, // PLX PCI-Bridge {0, 0, 0, 0, NULL, NULL, 0, 0, 0}, }; @@ -185,6 +210,7 @@ static const PCI_ENTRY id_list[] = #define MODULE_CARDS_T "1-16i" #define MODULE_PORTS_T "1-128i" /* 16 cards can have 128 ports */ static u_int type[MAX_CARDS]; +static BYTE allocated[MAX_CARDS]; // remember if card is found static int pcm[MAX_PORTS]; static u_int protocol[MAX_PORTS]; static int layermask[MAX_PORTS]; @@ -204,26 +230,18 @@ MODULE_PARM(protocol, MODULE_PORTS_T); MODULE_PARM(layermask, MODULE_PORTS_T); #endif - -/*************************/ -/* lock and unlock stuff */ -/*************************/ - -static int -lock_dev(void *data, int nowait) -{ - register mISDN_HWlock_t *lock = &((hfc_multi_t *)data)->lock; - if (debug & DEBUG_HFCMULTI_LOCK) - printk(KERN_DEBUG "%s\n", __FUNCTION__); - return(lock_HW(lock, nowait)); -} static void -unlock_dev(void *data) +enable_hwirq(hfc_multi_t *hc) { - register mISDN_HWlock_t *lock = &((hfc_multi_t *)data)->lock; - if (debug & DEBUG_HFCMULTI_LOCK) - printk(KERN_DEBUG "%s\n", __FUNCTION__); - unlock_HW(lock); + hc->hw.r_irq_ctrl |= V_GLOB_IRQ_EN; + HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); +} + +static void +disable_hwirq(hfc_multi_t *hc) +{ + hc->hw.r_irq_ctrl &= ~((u_char)V_GLOB_IRQ_EN); + HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); } /******************************************/ @@ -236,27 +254,29 @@ release_io_hfcmulti(hfc_multi_t *hc) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __FUNCTION__); - /* irq off */ - HFC_outb(hc, R_IRQ_CTRL, 0); - - /* soft reset */ + /* soft reset also masks all interrupts */ hc->hw.r_cirm |= V_SRES; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(10); + udelay(1000); hc->hw.r_cirm &= ~V_SRES; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(10); /* instead of 'wait' that may cause locking */ + udelay(1000); /* instead of 'wait' that may cause locking */ /* disable memory mapped ports / io ports */ pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); #ifdef CONFIG_HFCMULTI_PCIMEM - if (hc->pci_membase) - iounmap((void *)hc->pci_membase); + if (hc->pci_membase) iounmap((void *)hc->pci_membase); + if (hc->plx_membase) iounmap((void *)hc->plx_membase); #else if (hc->pci_iobase) release_region(hc->pci_iobase, 8); #endif + if (hc->pci_dev) { + pci_disable_device(hc->pci_dev); + pci_set_drvdata(hc->pci_dev, NULL); + } + if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: done\n", __FUNCTION__); } @@ -269,20 +289,27 @@ release_io_hfcmulti(hfc_multi_t *hc) static int init_chip(hfc_multi_t *hc) { - u_long val, val2 = 0, rev; - int cnt = 0; - int i; - u_char r_conf_en; + u_long flags, val, val2 = 0, rev; + int cnt = 0; + int i, err = 0; + u_char r_conf_en, rval; + spin_lock_irqsave(&hc->lock, flags); /* reset all registers */ memset(&hc->hw, 0, sizeof(hfcmulti_hw_t)); /* revision check */ if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __FUNCTION__); - val = HFC_inb(hc, R_CHIP_ID); + val = HFC_inb(hc, R_CHIP_ID)>>4; + if(val!=0x8 && val!=0xc && val!=0xe) + { + printk(KERN_INFO "HFC_multi: unknown CHIP_ID:%x\n",(u_int)val); + err = -EIO; + goto out; + } rev = HFC_inb(hc, R_CHIP_RV); - printk(KERN_INFO "HFC_multi: resetting HFC with chip ID=0x%lx revision=%ld%s\n", val>>4, rev, (rev==0)?" (old FIFO handling)":""); + printk(KERN_INFO "HFC_multi: resetting HFC with chip ID=0x%lx revision=%ld%s\n", val, rev, (rev==0)?" (old FIFO handling)":""); if (rev == 0) { test_and_set_bit(HFC_CHIP_REVISION0, &hc->chip); printk(KERN_WARNING "HFC_multi: NOTE: Your chip is revision 0, ask Cologne Chip for update. Newer chips have a better FIFO handling. Old chips still work but may have slightly lower HDLC transmit performance.\n"); @@ -327,21 +354,50 @@ init_chip(hfc_multi_t *hc) HFC_outb(hc, R_FIFO_MD, 0); hc->hw.r_cirm = V_SRES | V_HFCRES | V_PCMRES | V_STRES | V_RLD_EPR; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(10); + udelay(100); hc->hw.r_cirm = 0; HFC_outb(hc, R_CIRM, hc->hw.r_cirm); - udelay(10); + udelay(100); HFC_outb(hc, R_RAM_SZ, hc->hw.r_ram_sz); + /* set pcm mode & reset */ if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: setting PCM into slave mode\n", __FUNCTION__); + if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: setting PCM into slave mode\n", __FUNCTION__); } else { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: setting PCM into master mode\n", __FUNCTION__); + if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: setting PCM into master mode\n", __FUNCTION__); hc->hw.r_pcm_md0 |= V_PCM_MD; } + + // RAM access test + HFC_outb(hc, R_RAM_ADDR0, 0); + HFC_outb(hc, R_RAM_ADDR1, 0); + HFC_outb(hc, R_RAM_ADDR2, 0); + + for(i=0;i<256;i++) { + HFC_outb(hc, R_RAM_ADDR0,i); + HFC_outb(hc, R_RAM_DATA,((i*3)&0xff)); + //udelay(5); + //HFC_outb(hc, R_RAM_DATA,((i*3)&0xff)); + } + + for(i=0;i<256;i++) { + HFC_outb(hc, R_RAM_ADDR0,i); + HFC_inb(hc, R_RAM_DATA); + rval=HFC_inb(hc, R_INT_DATA); + if(rval!=((i*3)&0xff)) + { + printk(KERN_DEBUG "addr:%x val:%x should:%x\n",i,rval,(i*3)&0xff); + err++; + } + } + + if (err) { + printk(KERN_DEBUG "aborting.1 - %d RAM access errors\n",err); + err = -EIO; + goto out; + } + i = 0; HFC_outb(hc, R_PCM_MD0, hc->hw.r_pcm_md0 | 0x90); if (hc->slots == 32) @@ -373,17 +429,17 @@ init_chip(hfc_multi_t *hc) val += HFC_inb(hc, R_F0_CNTH) << 8; if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "HFC_multi F0_CNT %ld after status ok\n", val); - unlock_dev(hc); set_current_state(TASK_UNINTERRUPTIBLE); while (cnt < 50) { /* max 50 ms */ + spin_unlock_irqrestore(&hc->lock, flags); schedule_timeout((HZ*10)/1000); /* Timeout 10ms */ + spin_lock_irqsave(&hc->lock, flags); cnt+=10; val2 = HFC_inb(hc, R_F0_CNTL); val2 += HFC_inb(hc, R_F0_CNTH) << 8; if (val2 >= val+4) /* wait 4 pulses */ break; } - lock_dev(hc, 0); if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "HFC_multi F0_CNT %ld after %dms\n", val2, cnt); if (val2 < val+4) { @@ -391,8 +447,10 @@ init_chip(hfc_multi_t *hc) if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { printk(KERN_ERR "HFC_multi This happens in PCM slave mode without connected master.\n"); } - if (!test_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip)) - return(-EIO); + if (!test_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip)) { + err = -EIO; + goto out; + } } /* set up timer */ @@ -446,10 +504,14 @@ init_chip(hfc_multi_t *hc) /* setting misc irq */ HFC_outb(hc, R_IRQMSK_MISC, hc->hw.r_irqmsk_misc); + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "r_irqmsk_misc.2: 0x%x\n", hc->hw.r_irqmsk_misc); if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: done\n", __FUNCTION__); - return(0); +out: + spin_unlock_irqrestore(&hc->lock, flags); + return(err); } @@ -460,7 +522,7 @@ static void hfcmulti_leds(hfc_multi_t *hc) { int i, state, active; - dchannel_t *dch; + channel_t *dch; int led[4]; hc->ledcount += poll; @@ -522,9 +584,9 @@ hfcmulti_leds(hfc_multi_t *hc) } state = 0; active = 1; - if ((dch = hc->chan[16].dch)) { - state = dch->ph_state; - } + dch = hc->chan[16].ch; + if (dch && test_bit(FLG_DCHANNEL, &dch->Flags)) + state = dch->state; if (state == active) { led[2] = 1; /* left green */ if (hc->activity[0]) { @@ -532,13 +594,13 @@ hfcmulti_leds(hfc_multi_t *hc) hc->activity[0] = 0; } else led[3] = 0; /* no right green */ - + } else led[2] = led[3] = 0; /* no green */ } HFC_outb(hc, R_GPIO_OUT1, (led[0] | (led[1]<<2) | (led[2]<<1) | (led[3]<<3))^0xf); /* leds are inverted */ - + break; case 2: /* HFC-4S OEM */ @@ -550,8 +612,9 @@ hfcmulti_leds(hfc_multi_t *hc) while(i < 4) { state = 0; active = -1; - if ((dch = hc->chan[(i<<2)|2].dch)) { - state = dch->ph_state; + dch = hc->chan[(i<<2)|2].ch; + if (dch && test_bit(FLG_DCHANNEL, &dch->Flags)) { + state = dch->state; active = test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)?3:7; } if (state) { @@ -587,21 +650,22 @@ static void hfcmulti_dtmf(hfc_multi_t *hc) { signed long coeff[16]; - unsigned long mantissa; + DWORD mantissa; int co, ch; - bchannel_t *bch = NULL; - unsigned char exponent; + channel_t *bch = NULL; + BYTE exponent; int dtmf = 0; int addr; - unsigned short w_float; + WORD w_float; struct sk_buff *skb; if (debug & DEBUG_HFCMULTI_DTMF) printk(KERN_DEBUG "%s: dtmf detection irq\n", __FUNCTION__); ch = 0; while(ch < 32) { - /* only process enabled B-channels */ - if (!(bch = hc->chan[ch].bch)) { + // only process enabled B-channels + bch = hc->chan[ch].ch; + if ((!bch) || !test_bit(FLG_BCHANNEL, &bch->Flags)) { ch++; continue; } @@ -609,7 +673,7 @@ hfcmulti_dtmf(hfc_multi_t *hc) ch++; continue; } - if (bch->protocol != ISDN_PID_L1_B_64TRANS) { + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) { ch++; continue; } @@ -618,7 +682,7 @@ hfcmulti_dtmf(hfc_multi_t *hc) dtmf = 1; co = 0; while(co < 8) { - /* read W(n-1) coefficient */ + // read W(n-1) coefficient addr = hc->DTMFbase + ((co<<7) | (ch<<2)); HFC_outb_(hc, R_RAM_ADDR0, addr); HFC_outb_(hc, R_RAM_ADDR1, addr>>8); @@ -632,7 +696,7 @@ hfcmulti_dtmf(hfc_multi_t *hc) if (debug & DEBUG_HFCMULTI_DTMF) printk(" %04x", w_float); - /* decode float (see chip doc) */ + // decode float (see chip doc) mantissa = w_float & 0x0fff; if (w_float & 0x8000) mantissa |= 0xfffff000; @@ -642,10 +706,10 @@ hfcmulti_dtmf(hfc_multi_t *hc) mantissa <<= (exponent-1); } - /* store coefficient */ + // store coefficient coeff[co<<1] = mantissa; - /* read W(n) coefficient */ + // read W(n) coefficient w_float = HFC_inb_(hc, R_RAM_DATA); #ifdef CONFIG_HFCMULTI_PCIMEM w_float |= (HFC_inb_(hc, R_RAM_DATA) << 8); @@ -655,7 +719,7 @@ hfcmulti_dtmf(hfc_multi_t *hc) if (debug & DEBUG_HFCMULTI_DTMF) printk(" %04x", w_float); - /* decode float (see chip doc) */ + // decode float (see chip doc) mantissa = w_float & 0x0fff; if (w_float & 0x8000) mantissa |= 0xfffff000; @@ -665,67 +729,132 @@ hfcmulti_dtmf(hfc_multi_t *hc) mantissa <<= (exponent-1); } - /* store coefficient */ + // store coefficient coeff[(co<<1)|1] = mantissa; co++; } - if (debug & DEBUG_HFCMULTI_DTMF) - printk("\n"); skb = create_link_skb(PH_CONTROL | INDICATION, HW_HFC_COEFF, sizeof(coeff), coeff, 0); if (!skb) { printk(KERN_WARNING "%s: No memory for skb\n", __FUNCTION__); ch++; continue; } - skb_queue_tail(&hc->chan[ch].dtmfque, skb); - bch_sched_event(bch, B_DTMFREADY); + if (debug & DEBUG_HFCMULTI_DTMF) { + printk("\n"); + printk("%s: DTMF ready %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx len=%d\n", __FUNCTION__, + coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7], skb->len); + } + +#ifdef FIXME // TODO changed + if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) && bch->dev) + hif = &bch->dev->rport.pif; + else + hif = &bch->inst.up; +#endif + if (mISDN_queue_up(&bch->inst, 0, skb)) + dev_kfree_skb(skb); + ch++; } - /* restart DTMF processing */ + // restart DTMF processing hc->dtmf = dtmf; if (dtmf) HFC_outb_(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); } +#ifdef CONFIG_HFCMULTI_PCIMEM +/*******************/ +/* write fifo data */ +/*******************/ +void write_fifo_data(hfc_multi_t *hc,BYTE *dest,int len) +{ + int i, remain; + + remain = len; + +#ifdef FIFO_32BIT_ACCESS + for (i = 0; i < len/4; i++) { + HFC_outl_(hc, A_FIFO_DATA0, *((DWORD *)dest)); + remain -= 4; + dest += 4; + } +#endif + +#ifdef FIFO_16BIT_ACCESS + for (i = 0; i < len/2; i++) { + HFC_outw_(hc, A_FIFO_DATA0, *((WORD *)dest)); + remain -= 2; + dest += 2; + } +#endif + + for (i = 0; i < remain; i++) + HFC_outb_(hc, A_FIFO_DATA0, *dest++); + +} +#endif + +#ifndef CONFIG_HFCMULTI_PCIMEM +/*******************/ +/* write fifo data */ +/*******************/ +void +write_fifo_data(hfc_multi_t *hc, BYTE *dest, int len) +{ + int i, remain; + + remain = len; + HFC_set(hc, A_FIFO_DATA0); + +#ifdef FIFO_32BIT_ACCESS + for (i = 0; i < len/4; i++) { + HFC_putl(hc, *((DWORD *)dest)); + remain -= 4; + dest += 4; + } +#endif + +#ifdef FIFO_16BIT_ACCESS + for(i = 0; i < len/2; i++) { + HFC_putw(hc, *((WORD *)dest)); + remain -= 2; + dest += 2; + } +#endif + + for (i = 0; i < remain; i++) + HFC_putb(hc, *dest++); +} +#endif /*********************************/ /* fill fifo as much as possible */ /*********************************/ static void -hfcmulti_tx(hfc_multi_t *hc, int ch, dchannel_t *dch, bchannel_t *bch) +hfcmulti_tx(hfc_multi_t *hc, int ch, channel_t *chan) { - int i, ii, temp; + int i, ii, temp, len; int Zspace, z1, z2; int Fspace, f1, f2; - unsigned char *d, *dd, *buf = NULL; - int *len = NULL, *idx = NULL; /* = NULL, to make GCC happy */ + BYTE *d; int txpending, slot_tx; - int hdlc = 0; + f1 = HFC_inb_(hc, A_F1); + f2 = HFC_inb_(hc, A_F2); + //printk(KERN_DEBUG "txf12:%x %x\n",f1,f2); /* get skb, fifo & mode */ - if (dch) { - buf = dch->tx_buf; - len = &dch->tx_len; - idx = &dch->tx_idx; - hdlc = 1; - } - if (bch) { - buf = bch->tx_buf; - len = &bch->tx_len; - idx = &bch->tx_idx; - if (bch->protocol == ISDN_PID_L1_B_64HDLC) - hdlc = 1; - } + txpending = hc->chan[ch].txpending; slot_tx = hc->chan[ch].slot_tx; - if ((!(*len)) && txpending!=1) + len = chan->tx_skb ? chan->tx_skb->len : 0; + if ((!len) && txpending != 1) return; /* no data */ -//printk("debug: data: len = %d, txpending = %d!!!!\n", *len, txpending); + //printk("debug: data: len = %d, txpending = %d!!!!\n", *len, txpending); /* lets see how much data we will have left in buffer */ - HFC_outb_(hc, R_FIFO, ch<<1); + HFC_outb_(hc, R_FIFO, ch << 1); HFC_wait_(hc); if (txpending == 2) { /* reset fifo */ @@ -735,15 +864,16 @@ hfcmulti_tx(hfc_multi_t *hc, int ch, dchannel_t *dch, bchannel_t *bch) txpending = 1; } next_frame: - if (hdlc) { + if (test_bit(FLG_HDLC, &chan->Flags)) { f1 = HFC_inb_(hc, A_F1); f2 = HFC_inb_(hc, A_F2); - while (f2 != (temp=HFC_inb_(hc, A_F2))) { + while (f2 != (temp = HFC_inb_(hc, A_F2))) { if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s: reread f2 because %d!=%d\n", __FUNCTION__, temp, f2); + printk(KERN_DEBUG "%s: reread f2 because %d!=%d\n", + __FUNCTION__, temp, f2); f2 = temp; /* repeat until F2 is equal */ } - Fspace = f2-f1-1; + Fspace = f2 - f1 - 1; if (Fspace < 0) Fspace += hc->Flen; /* Old FIFO handling doesn't give us the current Z2 read @@ -758,7 +888,7 @@ next_frame: Fspace = 1; } /* one frame only for ST D-channels, to allow resending */ - if (hc->type!=1 && dch) { + if (hc->type != 1 && test_bit(FLG_DCHANNEL, &chan->Flags)) { if (f1 != f2) Fspace = 0; } @@ -768,12 +898,13 @@ next_frame: } z1 = HFC_inw_(hc, A_Z1) - hc->Zmin; z2 = HFC_inw_(hc, A_Z2) - hc->Zmin; - while(z2 != (temp=(HFC_inw_(hc, A_Z2) - hc->Zmin))) { + while (z2 != (temp = (HFC_inw_(hc, A_Z2) - hc->Zmin))) { if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s: reread z2 because %d!=%d\n", __FUNCTION__, temp, z2); + printk(KERN_DEBUG "%s: reread z2 because %d!=%d\n", + __FUNCTION__, temp, z2); z2 = temp; /* repeat unti Z2 is equal */ } - Zspace = z2-z1-1; + Zspace = z2 - z1 - 1; if (Zspace < 0) Zspace += hc->Zlen; /* buffer too full, there must be at least one more byte for 0-volume */ @@ -781,13 +912,13 @@ next_frame: return; /* if no data */ - if (!(*len)) { + if (!len) { if (z1 == z2) { /* empty */ /* if done with FIFO audio data during PCM connection */ - if (!hdlc && txpending && slot_tx>=0) { + if (!test_bit(FLG_HDLC, &chan->Flags) && txpending && slot_tx >= 0) { if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: reconnecting PCM due to no more FIFO data: channel %d slot_tx %d\n", __FUNCTION__, ch, slot_tx); - + printk(KERN_DEBUG "%s: reconnecting PCM due to no more FIFO data: channel %d slot_tx %d\n", + __FUNCTION__, ch, slot_tx); /* connect slot */ HFC_outb(hc, A_CON_HDLC, 0xc0 | 0x00 | V_HDLC_TRP | V_IFF); HFC_outb_(hc, R_FIFO, ch<<1 | 1); @@ -802,9 +933,10 @@ next_frame: } /* if audio data */ - if (!hdlc && !txpending && slot_tx>=0) { + if (!test_bit(FLG_HDLC, &chan->Flags) && !txpending && slot_tx >= 0) { if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: disconnecting PCM due to FIFO data: channel %d slot_tx %d\n", __FUNCTION__, ch, slot_tx); + printk(KERN_DEBUG "%s: disconnecting PCM due to FIFO data: channel %d slot_tx %d\n", + __FUNCTION__, ch, slot_tx); /* disconnect slot */ HFC_outb(hc, A_CON_HDLC, 0x80 | 0x00 | V_HDLC_TRP | V_IFF); HFC_outb_(hc, R_FIFO, ch<<1 | 1); @@ -819,298 +951,263 @@ next_frame: hc->activity[hc->chan[ch].port] = 1; /* fill fifo to what we have left */ - i = *idx; - ii = *len; - d = buf + i; - if (ii-i > Zspace) - ii = Zspace+i; - if (debug & DEBUG_HFCMULTI_FIFO) { + i = chan->tx_idx; + ii = len; + d = chan->tx_skb->data + i; + if (ii - i > Zspace) + ii = Zspace + i; + if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: fifo(%d) has %d bytes space left (z1=%04x, z2=%04x) sending %d of %d bytes %s\n", - __FUNCTION__, ch, Zspace, z1, z2, ii-i, (*len)-i, hdlc?"HDLC":"TRANS"); - } -#ifdef FIFO_32BIT_ACCESS -#ifndef CONFIG_HFCMULTI_PCIMEM - HFC_set(hc, A_FIFO_DATA0); -#endif - dd = d + ((ii-i)&0xfffc); - i += (ii-i) & 0xfffc; - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - HFC_outl_(hc, A_FIFO_DATA0, *((unsigned long *)d)); -#else - HFC_putl(hc, *((unsigned long *)d)); -#endif -// if (debug & DEBUG_HFCMULTI_FIFO) -// printk("%02x %02x %02x %02x ", d[0], d[1], d[2], d[3]); - d+=4; - } -#endif - dd = d + (ii-i); - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - HFC_outb_(hc, A_FIFO_DATA0, *d); -#else - HFC_putb(hc, *d); -#endif -// if (debug & DEBUG_HFCMULTI_FIFO) -// printk("%02x ", d[0]); - d++; - } -// if (debug & DEBUG_HFCMULTI_FIFO) -// printk("\n"); - *idx = ii; + __FUNCTION__, ch, Zspace, z1, z2, ii-i, len-i, + test_bit(FLG_HDLC, &chan->Flags) ? "HDLC":"TRANS"); + + write_fifo_data(hc, d, ii - i); + chan->tx_idx = ii; /* if not all data has been written */ - if (ii != *len) { + if (ii != len) { /* NOTE: fifo is started by the calling function */ return; } /* if all data has been written */ - if (hdlc) { + if (test_bit(FLG_HDLC, &chan->Flags)) { /* increment f-counter */ HFC_outb_(hc, R_INC_RES_FIFO, V_INC_F); HFC_wait_(hc); } - if (dch) { - /* check for next frame */ - if (test_and_clear_bit(FLG_TX_NEXT, &dch->DFlags)) { - if (dch->next_skb) { - dch->tx_idx = 0; - dch->tx_len = dch->next_skb->len; - memcpy(dch->tx_buf, dch->next_skb->data, dch->tx_len); - dchannel_sched_event(dch, D_XMTBUFREADY); - goto next_frame; - } else - printk(KERN_WARNING "%s: tx irq TX_NEXT without skb (dch ch=%d)\n", __FUNCTION__, ch); + // check for next frame + if (chan->tx_skb) + dev_kfree_skb(chan->tx_skb); + if (test_bit(FLG_TX_NEXT, &chan->Flags)) { + chan->tx_skb = chan->next_skb; + if (chan->tx_skb) { + mISDN_head_t *hh = mISDN_HEAD_P(chan->tx_skb); + chan->next_skb = NULL; + test_and_clear_bit(FLG_TX_NEXT, &chan->Flags); + chan->tx_idx = 0; + len = chan->tx_skb->len; + queue_ch_frame(chan, CONFIRM, hh->dinfo, NULL); + goto next_frame; + } else { + test_and_clear_bit(FLG_TX_NEXT, &chan->Flags); + printk(KERN_WARNING "%s: tx irq TX_NEXT without skb (dch ch=%d)\n", + __FUNCTION__, ch); } - test_and_clear_bit(FLG_TX_BUSY, &dch->DFlags); - dch->tx_idx = dch->tx_len = 0; - } - if (bch) { - /* check for next frame */ - if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) { - if (bch->next_skb) { - bch->tx_idx = 0; - bch->tx_len = bch->next_skb->len; - memcpy(bch->tx_buf, bch->next_skb->data, bch->tx_len); - bch_sched_event(bch, B_XMTBUFREADY); - goto next_frame; - } else - printk(KERN_WARNING "%s: tx irq TX_NEXT without skb (bch ch=%d)\n", __FUNCTION__, ch); - } - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch->tx_idx = bch->tx_len = 0; - } + } else + chan->tx_skb = NULL; + test_and_clear_bit(FLG_TX_BUSY, &chan->Flags); + chan->tx_idx = 0; /* now we have no more data, so in case of transparent, * we set the last byte in fifo to 'silence' in case we will get * no more data at all. this prevents sending an undefined value. */ - if (!hdlc) + if (!test_bit(FLG_HDLC, &chan->Flags)) HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); } -/**************/ -/* empty fifo */ -/**************/ +#ifdef CONFIG_HFCMULTI_PCIMEM +/******************/ +/* read fifo data */ +/******************/ +void read_fifo_data(hfc_multi_t *hc, BYTE *dest, int len) +{ + int i, remain; + + remain = len; + +#ifdef FIFO_32BIT_ACCESS + for(i = 0; i < len/4; i++) { + *((DWORD *)dest) = HFC_inl_(hc, A_FIFO_DATA0); + remain -= 4; + dest += 4; + } +#endif + +#ifdef FIFO_16BIT_ACCESS + for(i = 0; i < len/2; i++) { + *((WORD *)dest) = HFC_inw_(hc, A_FIFO_DATA0); + remain -= 2; + dest += 2; + } +#endif + + for(i = 0; i < remain; i++) + *dest++ = HFC_inb_(hc, A_FIFO_DATA0); + +} +#endif + +#ifndef CONFIG_HFCMULTI_PCIMEM +/******************/ +/* read fifo data */ +/******************/ +void read_fifo_data(hfc_multi_t *hc, BYTE *dest, int len) +{ + int i, remain; + + remain = len; + HFC_set(hc, A_FIFO_DATA0); + +#ifdef FIFO_32BIT_ACCESS + for(i = 0; i < len/4; i++) { + *((DWORD *)dest) = HFC_getl(hc); + remain -= 4; + dest += 4; + } +#endif + +#ifdef FIFO_16BIT_ACCESS + for(i = 0; i < len/2; i++) { + *((WORD *)dest) = HFC_getw(hc); + remain -= 2; + dest += 2; + } +#endif + + for(i = 0;i < remain; i++) + *dest++ = HFC_getb(hc); +} +#endif + static void -hfcmulti_rx(hfc_multi_t *hc, int ch, dchannel_t *dch, bchannel_t *bch) +hfcmulti_rx(hfc_multi_t *hc, int ch, channel_t *chan) { - int ii, temp; + int temp; int Zsize, z1, z2 = 0; /* = 0, to make GCC happy */ int f1 = 0, f2 = 0; /* = 0, to make GCC happy */ - unsigned char *d, *dd, *buf = NULL; - int *idx = NULL, max = 0; /* = 0, to make GCC happy */ - int hdlc = 0; struct sk_buff *skb; - /* get skb, fifo & mode */ - if (dch) { - buf = hc->chan[ch].rx_buf; - idx = &hc->chan[ch].rx_idx; - max = MAX_DFRAME_LEN_L1; - hdlc = 1; - } - if (bch) { - buf = bch->rx_buf; - idx = &bch->rx_idx; - max = MAX_DATA_MEM; - if (bch->protocol == ISDN_PID_L1_B_64HDLC) - hdlc = 1; - } - /* lets see how much data we received */ HFC_outb_(hc, R_FIFO, (ch<<1)|1); HFC_wait_(hc); next_frame: -#if 0 - /* set Z2(F1) */ - HFC_outb_(hc, R_RAM_SZ, hc->hw.r_ram_sz & ~V_FZ_MD); -#endif - if (hdlc) { + if (test_bit(FLG_HDLC, &chan->Flags)) { f1 = HFC_inb_(hc, A_F1); - while (f1 != (temp=HFC_inb_(hc, A_F1))) { + while (f1 != (temp = HFC_inb_(hc, A_F1))) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: reread f1 because %d!=%d\n", __FUNCTION__, temp, f1); f1 = temp; /* repeat until F1 is equal */ } f2 = HFC_inb_(hc, A_F2); } + //if(f1!=f2) printk(KERN_DEBUG "got a chan:%d framef12:%x %x!!!!\n",ch,f1,f2); + //printk(KERN_DEBUG "got a chan:%d framef12:%x %x!!!!\n",ch,f1,f2); z1 = HFC_inw_(hc, A_Z1) - hc->Zmin; - while(z1 != (temp=(HFC_inw_(hc, A_Z1) - hc->Zmin))) { + while(z1 != (temp = (HFC_inw_(hc, A_Z1) - hc->Zmin))) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: reread z2 because %d!=%d\n", __FUNCTION__, temp, z2); - z1 = temp; /* repeat unti Z1 is equal */ + z1 = temp; /* repeat until Z1 is equal */ } z2 = HFC_inw_(hc, A_Z2) - hc->Zmin; - Zsize = z1-z2; - if (hdlc && f1!=f2) /* complete hdlc frame */ + Zsize = z1 - z2; + if (test_bit(FLG_HDLC, &chan->Flags) && f1 != f2) /* complete hdlc frame */ Zsize++; if (Zsize < 0) Zsize += hc->Zlen; /* if buffer is empty */ if (Zsize <= 0) return; - + + if (!chan->rx_skb) { + chan->rx_skb = alloc_stack_skb(chan->maxlen + 3, chan->up_headerlen); + if (!chan->rx_skb) { + printk(KERN_DEBUG "%s: No mem for rx_skb\n", __FUNCTION__); + return; + } + } /* show activity */ hc->activity[hc->chan[ch].port] = 1; /* empty fifo with what we have */ - if (hdlc) { + if (test_bit(FLG_HDLC, &chan->Flags)) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: fifo(%d) reading %d bytes (z1=%04x, z2=%04x) HDLC %s (f1=%d, f2=%d) got=%d\n", - __FUNCTION__, ch, Zsize, z1, z2, (f1==f2)?"fragment":"COMPLETE", f1, f2, Zsize+*idx); + __FUNCTION__, ch, Zsize, z1, z2, + (f1 == f2) ? "fragment" : "COMPLETE", + f1, f2, Zsize + chan->rx_skb->len); /* HDLC */ - ii = Zsize; - if ((ii + *idx) > max) { + if ((Zsize + chan->rx_skb->len) > (chan->maxlen + 3)) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: hdlc-frame too large.\n", __FUNCTION__); - *idx = 0; + skb_trim(chan->rx_skb, 0); HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait_(hc); return; } - d = buf + *idx; -#ifdef FIFO_32BIT_ACCESS -#ifndef CONFIG_HFCMULTI_PCIMEM - HFC_set(hc, A_FIFO_DATA0); -#endif - dd = d + (ii&0xfffc); - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - *((unsigned long *)d) = HFC_inl_(hc, A_FIFO_DATA0); -#else - *((unsigned long *)d) = HFC_getl(hc); -#endif - d+=4; - } - dd = d + (ii&0x0003); -#else - dd = d + ii; -#endif - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - *d++ = HFC_inb_(hc, A_FIFO_DATA0); -#else - *d++ = HFC_getb(hc); -#endif - } - *idx += ii; + + read_fifo_data(hc, skb_put(chan->rx_skb, Zsize), Zsize); + if (f1 != f2) { /* increment Z2,F2-counter */ HFC_outb_(hc, R_INC_RES_FIFO, V_INC_F); HFC_wait_(hc); /* check size */ - if (*idx < 4) { + if (chan->rx_skb->len < 4) { if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: Frame below minimum size\n", __FUNCTION__); - return; + skb_trim(chan->rx_skb, 0); + goto next_frame; } /* there is at least one complete frame, check crc */ - if (buf[(*idx)-1]) { + if (chan->rx_skb->data[chan->rx_skb->len - 1]) { if (debug & DEBUG_HFCMULTI_CRC) printk(KERN_DEBUG "%s: CRC-error\n", __FUNCTION__); - return; - } - /* only send dchannel if in active state */ - if (dch && hc->type==1 && hc->chan[ch].e1_state!=1) - return; - if (!(skb = alloc_stack_skb((*idx)-3, (bch)?bch->up_headerlen:dch->up_headerlen))) { - printk(KERN_DEBUG "%s: No mem for skb\n", __FUNCTION__); - return; + skb_trim(chan->rx_skb, 0); + goto next_frame; + } + /* only send dchannel if in active state */ + if (test_bit(FLG_DCHANNEL, &chan->Flags) && + hc->type == 1 && hc->chan[ch].e1_state != 1) { + skb_trim(chan->rx_skb, 0); + goto next_frame; + } + skb_trim(chan->rx_skb, chan->rx_skb->len - 3); + if (chan->rx_skb->len < MISDN_COPY_SIZE) { + skb = alloc_stack_skb(chan->rx_skb->len, chan->up_headerlen); + if (skb) { + memcpy(skb_put(skb, chan->rx_skb->len), + chan->rx_skb->data, chan->rx_skb->len); + skb_trim(chan->rx_skb, 0); + } else { + skb = chan->rx_skb; + chan->rx_skb = NULL; + } + } else { + skb = chan->rx_skb; + chan->rx_skb = NULL; } - memcpy(skb_put(skb, (*idx)-3), buf, (*idx)-3); if (debug & DEBUG_HFCMULTI_FIFO) { temp = 0; - while(temp < (*idx)-3) + while(temp < skb->len) printk("%02x ", skb->data[temp++]); printk("\n"); } - if (dch) { - if (debug & DEBUG_HFCMULTI_FIFO) - printk(KERN_DEBUG "%s: sending D-channel frame to user space.\n", __FUNCTION__); - /* schedule D-channel event */ - skb_queue_tail(&dch->rqueue, skb); - dchannel_sched_event(dch, D_RCVBUFREADY); - } - if (bch) { - /* schedule B-channel event */ - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - } - *idx = 0; + queue_ch_frame(chan, INDICATION, MISDN_ID_ANY, skb); goto next_frame; } /* there is an incomplete frame */ } else { /* transparent */ - ii = Zsize; - if (ii > MAX_DATA_MEM) - ii = MAX_DATA_MEM; - if (!(skb = alloc_stack_skb(ii, bch->up_headerlen))) { - printk(KERN_DEBUG "%s: No mem for skb\n", __FUNCTION__); - HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait_(hc); - return; + if (Zsize > skb_tailroom(chan->rx_skb)) + Zsize = skb_tailroom(chan->rx_skb); + if (Zsize < MISDN_COPY_SIZE) { + skb = alloc_stack_skb(Zsize, chan->up_headerlen); + if (!skb) { + skb = chan->rx_skb; + chan->rx_skb = NULL; + } + } else { + skb = chan->rx_skb; + chan->rx_skb = NULL; } if (debug & DEBUG_HFCMULTI_FIFO) printk(KERN_DEBUG "%s: fifo(%d) reading %d bytes (z1=%04x, z2=%04x) TRANS\n", - __FUNCTION__, ch, ii, z1, z2); - d = skb_put(skb, ii); -#ifdef FIFO_32BIT_ACCESS -#ifndef CONFIG_HFCMULTI_PCIMEM - HFC_set(hc, A_FIFO_DATA0); -#endif - dd = d + (ii&0xfffc); - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - *((unsigned long *)d) = HFC_inl_(hc, A_FIFO_DATA0); -#else - *((unsigned long *)d) = HFC_getl(hc); -#endif - d+=4; - } -#endif - dd = d + (ii&0x0003); - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - *d++ = HFC_inb_(hc, A_FIFO_DATA0); -#else - *d++ = HFC_getb(hc); -#endif - } - if (dch) { - /* schedule D-channel event */ - skb_queue_tail(&dch->rqueue, skb); - dchannel_sched_event(dch, D_RCVBUFREADY); - } - if (bch) { - /* schedule B-channel event */ - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - } + __FUNCTION__, ch, Zsize, z1, z2); + read_fifo_data(hc, skb_put(skb, Zsize), Zsize); + queue_ch_frame(chan, INDICATION, MISDN_ID_ANY, skb); } } @@ -1119,84 +1216,228 @@ next_frame: /* Interrupt handler */ /*********************/ +static void signal_state_up(channel_t *dch, int dinfo, char *msg) +{ + struct sk_buff *skb; + + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: %s\n", __FUNCTION__,msg); + + skb = create_link_skb(PH_CONTROL | INDICATION, dinfo, 0, NULL, 0); + if(!skb) return; + + if (mISDN_queue_up(&dch->inst, 0, skb)) + dev_kfree_skb(skb); +} + +static inline void +handle_timer_irq(hfc_multi_t *hc) +{ + int ch, temp; + channel_t *chan; + + ch = 0; + while(ch < 32) { + chan = hc->chan[ch].ch; + if (chan && hc->created[hc->chan[ch].port]) { + hfcmulti_tx(hc, ch, chan); + /* fifo is started when switching to rx-fifo */ + hfcmulti_rx(hc, ch, chan); + if (test_bit(FLG_DCHANNEL, &chan->Flags) && + hc->chan[ch].nt_timer > -1) { + if (!(--hc->chan[ch].nt_timer)) { + ph_state_change(chan); + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: nt_timer at state %x\n", + __FUNCTION__, chan->state); + } + } + } + ch++; + } + if (hc->type == 1 && hc->created[0]) { + chan = hc->chan[16].ch; + if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[16].cfg)) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 got LOS\n", + __FUNCTION__, hc->id); + /* LOS */ + temp = HFC_inb_(hc, R_RX_STA0) & V_SIG_LOS; + if (!temp && hc->chan[16].los) + signal_state_up(chan, HW_LOS, "LOS detected"); + if (temp && !hc->chan[16].los) + signal_state_up(chan, HW_LOS_OFF, "LOS gone"); + hc->chan[16].los = temp; + } + if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[16].cfg)) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 got AIS\n", + __FUNCTION__, hc->id); + /* AIS */ + temp = HFC_inb_(hc, R_RX_STA0) & V_AIS; + if (!temp && hc->chan[16].ais) + signal_state_up(chan, HW_AIS, "AIS detected"); + if (temp && !hc->chan[16].ais) + signal_state_up(chan, HW_AIS_OFF, "AIS gone"); + hc->chan[16].ais = temp; + } + if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[16].cfg)) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 got SLIP (RX)\n", + __FUNCTION__, hc->id); + /* SLIP */ + temp = HFC_inb_(hc, R_SLIP) & V_FOSLIP_RX; + if (!temp && hc->chan[16].slip_rx) + signal_state_up(chan, HW_SLIP_RX, " bit SLIP detected RX"); + hc->chan[16].slip_rx = temp; + temp = HFC_inb_(hc, R_SLIP) & V_FOSLIP_TX; + if (!temp && hc->chan[16].slip_tx) + signal_state_up(chan, HW_SLIP_TX, " bit SLIP detected TX"); + hc->chan[16].slip_tx = temp; + } + temp = HFC_inb_(hc, R_JATT_DIR); + switch(hc->chan[16].sync) { + case 0: + if ((temp & 0x60) == 0x60) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 now in clock sync\n", + __FUNCTION__, hc->id); + HFC_outb(hc, R_RX_OFF, hc->chan[16].jitter | V_RX_INIT); + HFC_outb(hc, R_TX_OFF, hc->chan[16].jitter | V_RX_INIT); + hc->chan[16].sync = 1; + goto check_framesync; + } + break; + case 1: + if ((temp & 0x60) != 0x60) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 lost clock sync\n", + __FUNCTION__, hc->id); + hc->chan[16].sync = 0; + break; + } + check_framesync: + temp = HFC_inb_(hc, R_RX_STA0); + if (temp == 0x27) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 now in frame sync\n", + __FUNCTION__, hc->id); + hc->chan[16].sync = 2; + } + break; + case 2: + if ((temp & 0x60) != 0x60) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 lost clock & frame sync\n", + __FUNCTION__, hc->id); + hc->chan[16].sync = 0; + break; + } + temp = HFC_inb_(hc, R_RX_STA0); + if (temp != 0x27) { + if (debug & DEBUG_HFCMULTI_SYNC) + printk(KERN_DEBUG "%s: (id=%d) E1 lost frame sync\n", + __FUNCTION__, hc->id); + hc->chan[16].sync = 1; + } + break; + } + } + if (hc->leds) + hfcmulti_leds(hc); +} + static irqreturn_t hfcmulti_interrupt(int intno, void *dev_id, struct pt_regs *regs) { - hfc_multi_t *hc = dev_id; - bchannel_t *bch; - dchannel_t *dch; - u_long flags; - u_char r_irq_statech, status, r_irq_misc, r_irq_oview, r_irq_fifo_bl; - int ch; - int i, j; - int temp; - - spin_lock_irqsave(&hc->lock.lock, flags); -#ifdef SPIN_DEBUG - hc->lock.spin_adr = (void *)0x3001; +#ifdef IRQCOUNT_DEBUG + static int iq1=0,iq2=0,iq3=0,iq4=0,iq5=0,iq6=0,iqcnt=0; #endif + hfc_multi_t *hc = dev_id; + channel_t *chan; + u_char r_irq_statech, status, r_irq_misc, r_irq_oview, r_irq_fifo_bl; + //u_char bl1,bl2; +#ifdef CONFIG_PLX_PCI_BRIDGE + u_short *plx_acc,wval; +#endif + int ch,i,j; + +#ifdef CONFIG_PLX_PCI_BRIDGE + plx_acc=(u_short*)(hc->plx_membase+0x4c); + wval=*plx_acc; + if(!(wval&0x04)) + { + if(wval&0x20) + { + //printk(KERN_WARNING "NO irq LINTI1:%x\n",wval); + printk(KERN_WARNING "got irq LINTI2\n"); + } + return(IRQ_NONE); + } +#endif + + spin_lock(&hc->lock); if (!hc) { printk(KERN_WARNING "HFC-multi: Spurious interrupt!\n"); irq_notforus: -#ifdef SPIN_DEBUG - hc->lock.spin_adr = NULL; + +#ifdef CONFIG_PLX_PCI_BRIDGE + //plx_acc=(u_short*)(hc->plx_membase+0x4c); + //*plx_acc=0xc00; // clear LINTI1 & LINTI2 + //*plx_acc=0xc41; #endif - spin_unlock_irqrestore(&hc->lock.lock, flags); + spin_unlock(&hc->lock); return(IRQ_NONE); } - status = HFC_inb_(hc, R_STATUS); r_irq_statech = HFC_inb_(hc, R_IRQ_STATECH); +#ifdef IRQCOUNT_DEBUG + if (r_irq_statech) + iq1++; + if (status&V_DTMF_STA) + iq2++; + if (status&V_LOST_STA) + iq3++; + if (status&V_EXT_IRQSTA) + iq4++; + if (status&V_MISC_IRQSTA) + iq5++; + if (status&V_FR_IRQSTA) + iq6++; + if (iqcnt++ > 5000) { + printk(KERN_ERR "iq1:%x iq2:%x iq3:%x iq4:%x iq5:%x iq6:%x\n",iq1,iq2,iq3,iq4,iq5,iq6); + iqcnt=0; + } +#endif if (!r_irq_statech && !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | V_MISC_IRQSTA | V_FR_IRQSTA))) { /* irq is not for us */ + //if(status) printk(KERN_WARNING "nofus:%x\n",status); goto irq_notforus; } hc->irqcnt++; - if (test_and_set_bit(STATE_FLAG_BUSY, &hc->lock.state)) { - printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n", - __FUNCTION__, hc->lock.state); -#ifdef SPIN_DEBUG - printk(KERN_ERR "%s: previous lock:%p\n", - __FUNCTION__, hc->lock.busy_adr); -#endif -#ifdef LOCK_STATISTIC - hc->lock.irq_fail++; -#endif - } else { -#ifdef LOCK_STATISTIC - hc->lock.irq_ok++; -#endif -#ifdef SPIN_DEBUG - hc->lock.busy_adr = hfcmulti_interrupt; -#endif - } - - test_and_set_bit(STATE_FLAG_INIRQ, &hc->lock.state); -#ifdef SPIN_DEBUG - hc->lock.spin_adr= NULL; -#endif - spin_unlock_irqrestore(&hc->lock.lock, flags); - if (r_irq_statech) { if (hc->type != 1) { /* state machine */ ch = 0; while(ch < 32) { - if ((dch = hc->chan[ch].dch)) { + chan = hc->chan[ch].ch; + if (chan && test_bit(FLG_DCHANNEL, &chan->Flags)) { if (r_irq_statech & 1) { HFC_outb_(hc, R_ST_SEL, hc->chan[ch].port); - dch->ph_state = HFC_inb(hc, A_ST_RD_STATE) & 0x0f; - if (dch->ph_state == (test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)?3:7)) { - HFC_outb_(hc, R_FIFO, (ch<<1)|1); + chan->state = HFC_inb(hc, A_ST_RD_STATE) & 0x0f; + if (chan->state == (test_bit(HFC_CFG_NTMODE, + &hc->chan[chan->channel].cfg) ? 3: 7)) { + HFC_outb_(hc, R_FIFO, (ch<<1) | 1); HFC_wait_(hc); HFC_outb_(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait_(hc); + chan->tx_idx=0; } - - dchannel_sched_event(dch, D_L1STATECHANGE); + ph_state_change(chan); if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: S/T newstate %x port %d\n", __FUNCTION__, dch->ph_state, hc->chan[ch].port); + printk(KERN_DEBUG "%s: S/T newstate %x port %d\n", + __FUNCTION__, chan->state, hc->chan[ch].port); } r_irq_statech >>= 1; } @@ -1217,141 +1458,17 @@ hfcmulti_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (r_irq_misc & V_STA_IRQ) { if (hc->type == 1) { /* state machine */ - dch = hc->chan[16].dch; - dch->ph_state = HFC_inb_(hc, R_E1_RD_STA) & 0x7; - dchannel_sched_event(dch, D_L1STATECHANGE); + chan = hc->chan[16].ch; + chan->state = HFC_inb_(hc, R_E1_RD_STA) & 0x7; + ph_state_change(chan); if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: E1 newstate %x\n", __FUNCTION__, dch->ph_state); + printk(KERN_DEBUG "%s: E1 newstate %x\n", + __FUNCTION__, chan->state); } } - if (r_irq_misc & V_TI_IRQ) { - /* -> timer IRQ */ - ch = 0; - while(ch < 32) { - if ((dch = hc->chan[ch].dch)) - if (hc->created[hc->chan[ch].port]) { - hfcmulti_tx(hc, ch, dch, NULL); - /* fifo is started when switching to rx-fifo */ - hfcmulti_rx(hc, ch, dch, NULL); - if (hc->chan[ch].nt_timer > -1) { - if (!(--hc->chan[ch].nt_timer)) { - dchannel_sched_event(dch, D_L1STATECHANGE); - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: nt_timer at state %x\n", __FUNCTION__, dch->ph_state); - } - } - } - if ((bch = hc->chan[ch].bch)) - if (hc->created[hc->chan[ch].port]) { - if (bch->protocol != ISDN_PID_NONE) { - hfcmulti_tx(hc, ch, NULL, bch); - /* fifo is started when switching to rx-fifo */ - hfcmulti_rx(hc, ch, NULL, bch); - } - } - ch++; - } - if (hc->type == 1) - if (hc->created[0]) { - if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[16].cfg)) { - /* LOS */ - temp = HFC_inb_(hc, R_RX_STA0) & V_SIG_LOS; - if (!temp && hc->chan[16].los) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 got LOS\n", __FUNCTION__, hc->id); - if ((dch = hc->chan[16].dch)) - dchannel_sched_event(dch, D_LOS); - } - if (temp && !hc->chan[16].los) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 LOS cleared\n", __FUNCTION__, hc->id); - if ((dch = hc->chan[16].dch)) - dchannel_sched_event(dch, D_LOS_OFF); - } - hc->chan[16].los = temp; - } - if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[16].cfg)) { - /* AIS */ - temp = HFC_inb_(hc, R_RX_STA0) & V_AIS; - if (!temp && hc->chan[16].ais) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 got AIS\n", __FUNCTION__, hc->id); - if ((dch = hc->chan[16].dch)) - dchannel_sched_event(dch, D_AIS); - } - if (temp && !hc->chan[16].ais) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 AIS cleared\n", __FUNCTION__, hc->id); - if ((dch = hc->chan[16].dch)) - dchannel_sched_event(dch, D_AIS_OFF); - } - hc->chan[16].ais = temp; - } - if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[16].cfg)) { - /* SLIP */ - temp = HFC_inb_(hc, R_SLIP) & V_FOSLIP_RX; - if (temp) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 got SLIP (RX)\n", __FUNCTION__, hc->id); - if ((dch = hc->chan[16].dch)) - dchannel_sched_event(dch, D_SLIP_RX); - } - temp = HFC_inb_(hc, R_SLIP) & V_FOSLIP_TX; - if (temp) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 got SLIP (TX)\n", __FUNCTION__, hc->id); - if ((dch = hc->chan[16].dch)) - dchannel_sched_event(dch, D_SLIP_TX); - } - } - temp = HFC_inb_(hc, R_JATT_DIR); - switch(hc->chan[16].sync) { - case 0: - if ((temp&0x60) == 0x60) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 now in clock sync\n", __FUNCTION__, hc->id); - HFC_outb(hc, R_RX_OFF, hc->chan[16].jitter | V_RX_INIT); - HFC_outb(hc, R_TX_OFF, hc->chan[16].jitter | V_RX_INIT); - hc->chan[16].sync = 1; - goto check_framesync; - } - break; + if (r_irq_misc & V_TI_IRQ) + handle_timer_irq(hc); - case 1: - if ((temp&0x60) != 0x60) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 lost clock sync\n", __FUNCTION__, hc->id); - hc->chan[16].sync = 0; - break; - } - check_framesync: - temp = HFC_inb_(hc, R_RX_STA0); - if (temp == 0x27) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 now in frame sync\n", __FUNCTION__, hc->id); - hc->chan[16].sync = 2; - } - break; - - case 2: - if ((temp&0x60) != 0x60) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 lost clock & frame sync\n", __FUNCTION__, hc->id); - hc->chan[16].sync = 0; - break; - } - temp = HFC_inb_(hc, R_RX_STA0); - if (temp != 0x27) { - if (debug & DEBUG_HFCMULTI_SYNC) - printk(KERN_DEBUG "%s: (id=%d) E1 lost frame sync\n", __FUNCTION__, hc->id); - hc->chan[16].sync = 1; - } - break; - } - } - if (hc->leds) - hfcmulti_leds(hc); - } if (r_irq_misc & V_DTMF_IRQ) { /* -> DTMF IRQ */ hfcmulti_dtmf(hc); @@ -1360,42 +1477,37 @@ hfcmulti_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (status & V_FR_IRQSTA) { /* FIFO IRQ */ r_irq_oview = HFC_inb_(hc, R_IRQ_OVIEW); + //if(r_irq_oview) printk(KERN_DEBUG "OV:%x\n",r_irq_oview); i = 0; while(i < 8) { if (r_irq_oview & (1 << i)) { + r_irq_fifo_bl = HFC_inb_(hc, R_IRQ_FIFO_BL0 + i); + //r_irq_fifo_bl = HFC_inb_(hc, R_INT_DATA); + //if(r_irq_fifo_bl) printk(KERN_DEBUG "BL%d:%x\n",i,r_irq_fifo_bl); + //bl1 = HFC_inb_(hc, R_IRQ_FIFO_BL0); + //bl2 = HFC_inb_(hc, R_IRQ_FIFO_BL0); + //printk(KERN_DEBUG "zero:%x :%x\n",bl1,bl2); r_irq_fifo_bl = HFC_inb_(hc, R_IRQ_FIFO_BL0 + i); j = 0; while(j < 8) { ch = (i<<2) + (j>>1); + chan = hc->chan[ch].ch; if (r_irq_fifo_bl & (1 << j)) { - if ((dch = hc->chan[ch].dch)) - if (hc->created[hc->chan[ch].port]) { - hfcmulti_tx(hc, ch, dch, NULL); + if (chan && hc->created[hc->chan[ch].port] && + test_bit(FLG_ACTIVE, &chan->Flags)) { + //printk(KERN_DEBUG "txchan:%d\n",ch); + hfcmulti_tx(hc, ch, chan); /* start fifo */ HFC_outb_(hc, R_FIFO, 0); HFC_wait_(hc); } - if ((bch = hc->chan[ch].bch)) - if (hc->created[hc->chan[ch].port]) { - if (bch->protocol != ISDN_PID_NONE) { - hfcmulti_tx(hc, ch, NULL, bch); - /* start fifo */ - HFC_outb_(hc, R_FIFO, 0); - HFC_wait_(hc); - } - } } j++; if (r_irq_fifo_bl & (1 << j)) { - if ((dch = hc->chan[ch].dch)) - if (hc->created[hc->chan[ch].port]) { - hfcmulti_rx(hc, ch, dch, NULL); - } - if ((bch = hc->chan[ch].bch)) - if (hc->created[hc->chan[ch].port]) { - if (bch->protocol != ISDN_PID_NONE) { - hfcmulti_rx(hc, ch, NULL, bch); - } + if (chan && hc->created[hc->chan[ch].port] && + test_bit(FLG_ACTIVE, &chan->Flags)) { + hfcmulti_rx(hc, ch, chan); + //printk(KERN_DEBUG "rxchan:%d\n",ch); } } j++; @@ -1405,22 +1517,13 @@ hfcmulti_interrupt(int intno, void *dev_id, struct pt_regs *regs) } } - spin_lock_irqsave(&hc->lock.lock, flags); -#ifdef SPIN_DEBUG - hc->lock.spin_adr = (void *)0x3002; +#ifdef CONFIG_PLX_PCI_BRIDGE + //plx_acc=(u_short*)(hc->plx_membase+0x4c); + //*plx_acc=0xc00; // clear LINTI1 & LINTI2 + //*plx_acc=0xc41; #endif - if (!test_and_clear_bit(STATE_FLAG_INIRQ, &hc->lock.state)) { - } - if (!test_and_clear_bit(STATE_FLAG_BUSY, &hc->lock.state)) { - printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n", - __FUNCTION__, hc->lock.state); - } -#ifdef SPIN_DEBUG - hc->lock.busy_adr = NULL; - hc->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&hc->lock.lock, flags); - return IRQ_HANDLED; + spin_unlock(&hc->lock); + return(IRQ_HANDLED); } @@ -1442,7 +1545,7 @@ hfcmulti_dbusy_timer(hfc_multi_t *hc) * ch eqals to the HFC-channel (0-31) * ch is the number of channel (0-4,4-7,8-11,12-15,16-19,20-23,24-27,28-31 for S/T, 1-31 for E1) * the hdlc interrupts will be set/unset - * + * */ static int mode_hfcmulti(hfc_multi_t *hc, int ch, int protocol, int slot_tx, int bank_tx, int slot_rx, int bank_rx) @@ -1453,7 +1556,8 @@ mode_hfcmulti(hfc_multi_t *hc, int ch, int protocol, int slot_tx, int bank_tx, i int conf = hc->chan[ch].conf; if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: channel %d protocol %x slot %d bank %d (TX) slot %d bank %d (RX)\n", __FUNCTION__, ch, protocol, slot_tx, bank_tx, slot_rx, bank_rx); + printk(KERN_DEBUG "%s: channel %d protocol %x slot %d bank %d (TX) slot %d bank %d (RX)\n", + __FUNCTION__, ch, protocol, slot_tx, bank_tx, slot_rx, bank_rx); if (oslot_tx>=0 && slot_tx!=oslot_tx) { /* remove from slot */ @@ -1521,119 +1625,126 @@ mode_hfcmulti(hfc_multi_t *hc, int ch, int protocol, int slot_tx, int bank_tx, i flow_rx = 0xc0; /* ST->(FIFO,PCM) */ /* put on slot */ routing = bank_rx?0x80:0xc0; /* reversed */ - if (conf>=0 || bank_rx>1) + if (conf >= 0 || bank_rx > 1) routing = 0x40; /* loop */ if (debug & DEBUG_HFCMULTI_MODE) - printk(KERN_DEBUG "%s: put to slot %d bank %d flow %02x routing %02x conf %d (RX)\n", __FUNCTION__, slot_rx, bank_rx, flow_rx, routing, conf); + printk(KERN_DEBUG "%s: put to slot %d bank %d flow %02x routing %02x conf %d (RX)\n", + __FUNCTION__, slot_rx, bank_rx, flow_rx, routing, conf); HFC_outb(hc, R_SLOT, (slot_rx<<1) | V_SL_DIR); HFC_outb(hc, A_SL_CFG, (ch<<1) | V_CH_DIR | routing); hc->slot_owner[(slot_rx<<1)|1] = ch; hc->chan[ch].slot_rx = slot_rx; hc->chan[ch].bank_rx = bank_rx; } - + switch (protocol) { case (ISDN_PID_NONE): - /* disable TX fifo */ - HFC_outb(hc, R_FIFO, ch<<1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - /* disable RX fifo */ - HFC_outb(hc, R_FIFO, (ch<<1)|1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - if (hc->type == 1) { - } else if ((ch&0x3)<2) { - hc->hw.a_st_ctrl0[hc->chan[ch].port] &= ((ch&0x3)==0)?~V_B1_EN:~V_B2_EN; - HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); - HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[hc->chan[ch].port]); - } - break; - + /* disable TX fifo */ + HFC_outb(hc, R_FIFO, ch << 1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_IFF); + HFC_outb(hc, A_SUBCH_CFG, 0); + HFC_outb(hc, A_IRQ_MSK, 0); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + /* disable RX fifo */ + HFC_outb(hc, R_FIFO, (ch<<1)|1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00); + HFC_outb(hc, A_SUBCH_CFG, 0); + HFC_outb(hc, A_IRQ_MSK, 0); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + if (hc->type == 1) { + } else if ((ch & 0x3) < 2) { + hc->hw.a_st_ctrl0[hc->chan[ch].port] &= ((ch & 0x3) == 0)? ~V_B1_EN: ~V_B2_EN; + HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); + HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[hc->chan[ch].port]); + } + if (test_bit(FLG_BCHANNEL, &hc->chan[ch].ch->Flags)) { + test_and_clear_bit(FLG_HDLC, &hc->chan[ch].ch->Flags); + test_and_clear_bit(FLG_TRANSPARENT, &hc->chan[ch].ch->Flags); + } + break; case (ISDN_PID_L1_B_64TRANS): /* B-channel */ - /* enable TX fifo */ - HFC_outb(hc, R_FIFO, ch<<1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_HDLC_TRP | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); /* tx silence */ - /* enable RX fifo */ - HFC_outb(hc, R_FIFO, (ch<<1)|1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, 0); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - if (hc->type != 1) { - hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3)==0)?V_B1_EN:V_B2_EN; - HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); - HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[hc->chan[ch].port]); - } - break; - + /* enable TX fifo */ + HFC_outb(hc, R_FIFO, ch<<1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x00 | V_HDLC_TRP | V_IFF); + HFC_outb(hc, A_SUBCH_CFG, 0); + HFC_outb(hc, A_IRQ_MSK, 0); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + HFC_outb_(hc, A_FIFO_DATA0_NOINC, silence); /* tx silence */ + /* enable RX fifo */ + HFC_outb(hc, R_FIFO, (ch<<1)|1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x00 | V_HDLC_TRP); + HFC_outb(hc, A_SUBCH_CFG, 0); + HFC_outb(hc, A_IRQ_MSK, 0); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + if (hc->type != 1) { + hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3)==0)?V_B1_EN:V_B2_EN; + HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); + HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[hc->chan[ch].port]); + } + if (test_bit(FLG_BCHANNEL, &hc->chan[ch].ch->Flags)) + test_and_set_bit(FLG_TRANSPARENT, &hc->chan[ch].ch->Flags); + break; case (ISDN_PID_L1_B_64HDLC): /* B-channel */ case (ISDN_PID_L1_TE_E1): /* D-channel E1 */ case (ISDN_PID_L1_NT_E1): - /* enable TX fifo */ - HFC_outb(hc, R_FIFO, ch<<1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, V_IRQ); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - /* enable RX fifo */ - HFC_outb(hc, R_FIFO, (ch<<1)|1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); - HFC_outb(hc, A_SUBCH_CFG, 0); - HFC_outb(hc, A_IRQ_MSK, V_IRQ); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - if (hc->type == 1) { - } else { - hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3)==0)?V_B1_EN:V_B2_EN; - HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); - HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[hc->chan[ch].port]); - } - break; + /* enable TX fifo */ + HFC_outb(hc, R_FIFO, ch<<1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04); + HFC_outb(hc, A_SUBCH_CFG, 0); + HFC_outb(hc, A_IRQ_MSK, V_IRQ); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + /* enable RX fifo */ + HFC_outb(hc, R_FIFO, (ch<<1)|1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); + HFC_outb(hc, A_SUBCH_CFG, 0); + HFC_outb(hc, A_IRQ_MSK, V_IRQ); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + if (hc->type == 1) { + } else { + hc->hw.a_st_ctrl0[hc->chan[ch].port] |= ((ch&0x3)==0)?V_B1_EN:V_B2_EN; + HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); + HFC_outb(hc, A_ST_CTRL0, hc->hw.a_st_ctrl0[hc->chan[ch].port]); + } + if (test_bit(FLG_BCHANNEL, &hc->chan[ch].ch->Flags)) + test_and_set_bit(FLG_HDLC, &hc->chan[ch].ch->Flags); + break; case (ISDN_PID_L1_TE_S0): /* D-channel S0 */ case (ISDN_PID_L1_NT_S0): - /* enable TX fifo */ - HFC_outb(hc, R_FIFO, ch<<1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); - HFC_outb(hc, A_SUBCH_CFG, 2); - HFC_outb(hc, A_IRQ_MSK, V_IRQ); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - /* enable RX fifo */ - HFC_outb(hc, R_FIFO, (ch<<1)|1); - HFC_wait(hc); - HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); - HFC_outb(hc, A_SUBCH_CFG, 2); - HFC_outb(hc, A_IRQ_MSK, V_IRQ); - HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); - HFC_wait(hc); - break; + /* enable TX fifo */ + HFC_outb(hc, R_FIFO, ch<<1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_tx | 0x04 | V_IFF); + HFC_outb(hc, A_SUBCH_CFG, 2); + HFC_outb(hc, A_IRQ_MSK, V_IRQ); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + /* enable RX fifo */ + HFC_outb(hc, R_FIFO, (ch<<1)|1); + HFC_wait(hc); + HFC_outb(hc, A_CON_HDLC, flow_rx | 0x04); + HFC_outb(hc, A_SUBCH_CFG, 2); + HFC_outb(hc, A_IRQ_MSK, V_IRQ); + HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); + HFC_wait(hc); + break; default: - printk(KERN_DEBUG "%s: protocol not known %x\n", __FUNCTION__, protocol); - hc->chan[ch].protocol = ISDN_PID_NONE; - return(-ENOPROTOOPT); + printk(KERN_DEBUG "%s: protocol not known %x\n", __FUNCTION__, protocol); + hc->chan[ch].protocol = ISDN_PID_NONE; + return(-ENOPROTOOPT); } hc->chan[ch].protocol = protocol; return(0); @@ -1654,7 +1765,8 @@ hfcmulti_pcm(hfc_multi_t *hc, int ch, int slot_tx, int bank_tx, int slot_rx, int } /* enable pcm */ - mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, slot_rx, bank_rx); + mode_hfcmulti(hc, ch, hc->chan[ch].protocol, slot_tx, bank_tx, + slot_rx, bank_rx); } @@ -1669,7 +1781,8 @@ hfcmulti_conf(hfc_multi_t *hc, int ch, int num) hc->chan[ch].conf = num; else hc->chan[ch].conf = -1; - mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, hc->chan[ch].bank_rx); + mode_hfcmulti(hc, ch, hc->chan[ch].protocol, hc->chan[ch].slot_tx, + hc->chan[ch].bank_tx, hc->chan[ch].slot_rx, hc->chan[ch].bank_rx); } @@ -1680,16 +1793,15 @@ hfcmulti_conf(hfc_multi_t *hc, int ch, int num) static void hfcmulti_splloop(hfc_multi_t *hc, int ch, u_char *data, int len) { - u_char *d, *dd; - bchannel_t *bch = hc->chan[ch].bch; + channel_t *bch = hc->chan[ch].ch; /* flush pending TX data */ if (bch->next_skb) { - test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag); + test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); dev_kfree_skb(bch->next_skb); bch->next_skb = NULL; } - bch->tx_idx = bch->tx_len = bch->rx_idx = 0; + bch->tx_idx = 0; /* prevent overflow */ if (len > hc->Zlen-1) @@ -1729,33 +1841,7 @@ hfcmulti_splloop(hfc_multi_t *hc, int ch, u_char *data, int len) //printk("len=%d %02x %02x %02x\n", len, data[0], data[1], data[2]); /* write loop data */ - d = data; -#ifdef FIFO_32BIT_ACCESS -#ifndef CONFIG_HFCMULTI_PCIMEM - HFC_set(hc, A_FIFO_DATA0); -#endif - dd = d + (len & 0xfffc); - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - HFC_outl_(hc, A_FIFO_DATA0, *((unsigned long *)d)); -#else - HFC_putl(hc, *((unsigned long *)d)); -#endif - d+=4; - - } - dd = d + (len & 0x0003); -#else - dd = d + len; -#endif - while(d != dd) { -#ifdef CONFIG_HFCMULTI_PCIMEM - HFC_outb_(hc, A_FIFO_DATA0, *d); -#else - HFC_putb(hc, *d); -#endif - d++; - } + write_fifo_data(hc,data,len); udelay(500); HFC_outb(hc, A_SUBCH_CFG, V_LOOP_FIFO); @@ -1780,450 +1866,416 @@ hfcmulti_splloop(hfc_multi_t *hc, int ch, u_char *data, int len) //udelay(300); } - -/*************************************/ -/* Layer 1 D-channel hardware access */ -/*************************************/ - -/* message transfer from layer 1 to hardware. - */ -static int -hfcmulti_l1hw(mISDNif_t *hif, struct sk_buff *skb) -{ - dchannel_t *dch; - int slot_tx, slot_rx, bank_tx, bank_rx; - hfc_multi_t *hc; - int ret = -EINVAL; - mISDN_head_t *hh; - - if (!hif || !skb) - return(ret); - hh = mISDN_HEAD_P(skb); - dch = hif->fdata; - hc = dch->inst.data; - ret = 0; - if (hh->prim == PH_DATA_REQ) { - /* check oversize */ - if (skb->len == 0) { - printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__); - return(-EINVAL); - } - if (skb->len > MAX_DFRAME_LEN_L1) { - printk(KERN_WARNING "%s: skb too large\n", __FUNCTION__); - return(-EINVAL); - } - /* check for pending next_skb */ - if (dch->next_skb) { - printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", __FUNCTION__, skb->len, dch->next_skb->len); - return(-EBUSY); - } - /* if we have currently a pending tx skb */ - dch->inst.lock(hc, 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(hc); - return(0); - } - /* write to fifo */ - dch->tx_len = skb->len; - memcpy(dch->tx_buf, skb->data, dch->tx_len); -// if (debug & DEBUG_HFCMULTI_FIFO) { -// printk(KERN_DEBUG "%s:from user space:\n", __FUNCTION__); -// i = 0; -// while(i < dch->tx_len) -// printk(" %02x", dch->tx_buf[i++]); -// printk("\n"); -// } - dch->tx_idx = 0; - hfcmulti_tx(hc, dch->channel, dch, NULL); - /* start fifo */ - HFC_outb(hc, R_FIFO, 0); - HFC_wait(hc); - dch->inst.unlock(hc); - skb_trim(skb, 0); - return(if_newhead(&dch->inst.up, PH_DATA_CNF, - hh->dinfo, skb)); - } else - if (hh->prim == (PH_SIGNAL | REQUEST)) { - dch->inst.lock(hc, 0); - switch (hh->dinfo) { -#if 0 - case INFO3_P8: - case INFO3_P10: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: INFO3_P%d\n", __FUNCTION__, (hh->dinfo==INFO3_P8)?8:10); - if (test_bit(HFC_CHIP_MASTER, &hc->chip)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - break; -#endif - default: - printk(KERN_DEBUG "%s: unknown PH_SIGNAL info %x\n", __FUNCTION__, hh->dinfo); - ret = -EINVAL; - } - dch->inst.unlock(hc); - } else - if (hh->prim == (PH_CONTROL | REQUEST)) { - dch->inst.lock(hc, 0); - switch (hh->dinfo) { - case HW_RESET: - /* start activation */ - if (hc->type == 1) { - HFC_outb(hc, R_E1_WR_STA, V_E1_LD_STA | 0); - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, R_E1_WR_STA, 0); - } else { - HFC_outb(hc, R_ST_SEL, hc->chan[dch->channel].port); - HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* G1 */ - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, 3); - HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT*3)); /* activate */ - } - break; - - case HW_DEACTIVATE: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_DEACTIVATE\n", __FUNCTION__); - goto hw_deactivate; /* after lock */ - - /* connect interface to pcm timeslot (0..N) */ - case HW_PCM_CONN: - if (skb->len < 4*sizeof(u_long)) { - printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n", __FUNCTION__); - break; - } - slot_tx = ((int *)skb->data)[0]; - bank_tx = ((int *)skb->data)[1]; - slot_rx = ((int *)skb->data)[2]; - bank_rx = ((int *)skb->data)[3]; - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n", __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); - if (slot_tx<=hc->slots && bank_tx<=2 && slot_rx<=hc->slots && bank_rx<=2) - hfcmulti_pcm(hc, dch->channel, slot_tx, bank_tx, slot_rx, bank_rx); - else - printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n", __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); - break; - - /* release interface from pcm timeslot */ - case HW_PCM_DISC: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_PCM_DISC\n", __FUNCTION__); - hfcmulti_pcm(hc, dch->channel, -1, -1, -1, -1); - break; - - default: - printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", __FUNCTION__, hh->dinfo); - ret = -EINVAL; - } - dch->inst.unlock(hc); - } else - if (hh->prim == (PH_ACTIVATE | REQUEST)) { - if (test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_ACTIVATE port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->type-1); - dch->inst.lock(hc, 0); - /* start activation */ - if (hc->type == 1) { - dchannel_sched_event(dch, D_L1STATECHANGE); - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: E1 report state %x \n", __FUNCTION__, dch->ph_state); - } else { - HFC_outb(hc, R_ST_SEL, hc->chan[dch->channel].port); - HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); /* G1 */ - udelay(6); /* wait at least 5,21us */ - HFC_outb(hc, A_ST_WR_STATE, 1); - HFC_outb(hc, A_ST_WR_STATE, 1 | (V_ST_ACT*3)); /* activate */ - dch->ph_state = 1; - } - dch->inst.unlock(hc); - } else { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_ACTIVATE no NT-mode port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->type-1); - ret = -EINVAL; - } - } else - if (hh->prim == (PH_DEACTIVATE | REQUEST)) { - if (test_bit(HFC_CFG_NTMODE, &hc->chan[dch->channel].cfg)) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_DEACTIVATE port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->type-1); - dch->inst.lock(hc, 0); - hw_deactivate: /* after lock */ - dch->ph_state = 0; - /* start deactivation */ - if (hc->type == 1) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_DEACTIVATE no BRI\n", __FUNCTION__); - } else { - HFC_outb(hc, R_ST_SEL, hc->chan[dch->channel].port); - HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); /* deactivate */ - } - discard_queue(&dch->rqueue); - if (dch->next_skb) { - dev_kfree_skb(dch->next_skb); - dch->next_skb = NULL; - } - dch->tx_idx = dch->tx_len = hc->chan[dch->channel].rx_idx = 0; - 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); - dch->inst.unlock(hc); - } else { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_DEACTIVATE no NT-mode port %d (0..%d)\n", __FUNCTION__, hc->chan[dch->channel].port, hc->type-1); - ret = -EINVAL; - } - } else { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: unknown prim %x\n", __FUNCTION__, hh->prim); - ret = -EINVAL; - } - if (!ret) { -// printk("1\n"); - dev_kfree_skb(skb); -// printk("2\n"); - } - return(ret); -} - - /******************************/ /* Layer2 -> Layer 1 Transfer */ /******************************/ -/* messages from layer 2 to layer 1 are processed here. - */ static int -hfcmulti_l2l1(mISDNif_t *hif, struct sk_buff *skb) +handle_dmsg(channel_t *ch, struct sk_buff *skb) { - u_long num; + + mISDN_head_t *hh = mISDN_HEAD_P(skb); + hfc_multi_t *hc = ch->inst.privat; int slot_tx, slot_rx, bank_tx, bank_rx; - bchannel_t *bch; - int ret = -EINVAL; - mISDN_head_t *hh; - hfc_multi_t *hc; - struct dsp_features *features; + int ret = -EAGAIN; + u_long flags; - if (!hif || !skb) - return(ret); - hh = mISDN_HEAD_P(skb); - bch = hif->fdata; - hc = bch->inst.data; - - if ((hh->prim == PH_DATA_REQ) - || (hh->prim == (DL_DATA | REQUEST))) { - if (skb->len == 0) { - printk(KERN_WARNING "%s: skb too small\n", __FUNCTION__); - return(-EINVAL); - } - if (skb->len > MAX_DATA_MEM) { - printk(KERN_WARNING "%s: skb too large\n", __FUNCTION__); - return(-EINVAL); - } - /* check for pending next_skb */ - if (bch->next_skb) { - printk(KERN_WARNING "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", __FUNCTION__, skb->len, bch->next_skb->len); - return(-EBUSY); - } - /* if we have currently a pending tx skb */ - bch->inst.lock(hc, 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(hc); - return(0); - } - /* write to fifo */ - bch->tx_len = skb->len; - memcpy(bch->tx_buf, skb->data, bch->tx_len); - bch->tx_idx = 0; - hfcmulti_tx(hc, bch->channel, NULL, bch); - /* start fifo */ - HFC_outb_(hc, R_FIFO, 0); - HFC_wait_(hc); - bch->inst.unlock(hc); - if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - && bch->dev) - hif = &bch->dev->rport.pif; - else - hif = &bch->inst.up; - skb_trim(skb, 0); - return(if_newhead(hif, hh->prim | CONFIRM, - hh->dinfo, skb)); - } else - if ((hh->prim == (PH_ACTIVATE | REQUEST)) - || (hh->prim == (DL_ESTABLISH | REQUEST))) { - /* activate B-channel if not already activated */ - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", __FUNCTION__, bch->channel); - if (test_and_set_bit(BC_FLG_ACTIV, &bch->Flag)) - ret = 0; - else { - bch->inst.lock(hc, 0); - ret = mode_hfcmulti(hc, bch->channel, bch->inst.pid.protocol[1], hc->chan[bch->channel].slot_tx, hc->chan[bch->channel].bank_tx, hc->chan[bch->channel].slot_rx, hc->chan[bch->channel].bank_rx); - if (!ret) { - bch->protocol = bch->inst.pid.protocol[1]; - if (bch->protocol) - bch_sched_event(bch, B_XMTBUFREADY); - if (bch->protocol==ISDN_PID_L1_B_64TRANS && !hc->dtmf) { - /* start decoder */ - hc->dtmf = 1; - if (debug & DEBUG_HFCMULTI_DTMF) - printk(KERN_DEBUG "%s: start dtmf decoder\n", __FUNCTION__); - HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); - } - } - bch->inst.unlock(hc); - } - if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - if (bch->dev) - if_link(&bch->dev->rport.pif, hh->prim | CONFIRM, 0, 0, NULL, 0); - skb_trim(skb, 0); - return(if_newhead(&bch->inst.up, hh->prim | CONFIRM, ret, skb)); - } else - if ((hh->prim == (PH_DEACTIVATE | REQUEST)) - || (hh->prim == (DL_RELEASE | REQUEST)) - || (hh->prim == (MGR_DISCONNECT | REQUEST))) { - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: PH_DEACTIVATE ch %d (0..32)\n", __FUNCTION__, bch->channel); - /* deactivate B-channel if not already deactivated */ - bch->inst.lock(hc, 0); - if (bch->next_skb) { - test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag); - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - bch->tx_idx = bch->tx_len = bch->rx_idx = 0; - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - hc->chan[bch->channel].slot_tx = -1; - hc->chan[bch->channel].slot_rx = -1; - hc->chan[bch->channel].conf = -1; - mode_hfcmulti(hc, bch->channel, ISDN_PID_NONE, hc->chan[bch->channel].slot_tx, hc->chan[bch->channel].bank_tx, hc->chan[bch->channel].slot_rx, hc->chan[bch->channel].bank_rx); - bch->protocol = ISDN_PID_NONE; - test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag); - bch->inst.unlock(hc); - skb_trim(skb, 0); -//printk("5\n"); - if (hh->prim != (MGR_DISCONNECT | REQUEST)) { - if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - if (bch->dev) - if_link(&bch->dev->rport.pif, hh->prim | CONFIRM, 0, 0, NULL, 0); - if (!if_newhead(&bch->inst.up, hh->prim | CONFIRM, 0, skb)) - return(0); -//printk("6\n"); - } -//printk("7\n"); - ret = 0; - } else - if (hh->prim == (PH_CONTROL | REQUEST)) { - bch->inst.lock(hc, 0); + if (hh->prim == (PH_SIGNAL | REQUEST)) { + spin_lock_irqsave(ch->inst.hwlock, flags); switch (hh->dinfo) { - /* fill features structure */ - case HW_FEATURES: - if (skb->len != sizeof(void *)) { - printk(KERN_WARNING "%s: HW_FEATURES lacks parameters\n", __FUNCTION__); + case INFO3_P8: + case INFO3_P10: break; - } - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_FEATURE request\n", __FUNCTION__); - features = *((struct dsp_features **)skb->data); - features->hfc_id = hc->id; - if (test_bit(HFC_CHIP_DTMF, &hc->chip)) - features->hfc_dtmf = 1; - features->hfc_loops = 0; - features->pcm_id = hc->pcm; - features->pcm_slots = hc->slots; - features->pcm_banks = 2; - ret = 0; - break; - - /* connect interface to pcm timeslot (0..N) */ - case HW_PCM_CONN: - if (skb->len < 4*sizeof(u_long)) { - printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n", __FUNCTION__); - break; - } - slot_tx = ((int *)skb->data)[0]; - bank_tx = ((int *)skb->data)[1]; - slot_rx = ((int *)skb->data)[2]; - bank_rx = ((int *)skb->data)[3]; - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n", __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); - if (slot_tx<=hc->slots && bank_tx<=2 && slot_rx<=hc->slots && bank_rx<=2) - hfcmulti_pcm(hc, bch->channel, slot_tx, bank_tx, slot_rx, bank_rx); - else - printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n", __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); - ret = 0; - break; - - /* release interface from pcm timeslot */ - case HW_PCM_DISC: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_PCM_DISC\n", __FUNCTION__); - hfcmulti_pcm(hc, bch->channel, -1, -1, -1, -1); - ret = 0; - break; - - /* join conference (0..7) */ - case HW_CONF_JOIN: - if (skb->len < sizeof(u_long)) { - printk(KERN_WARNING "%s: HW_CONF_JOIN lacks parameters\n", __FUNCTION__); - break; - } - num = ((u_long *)skb->data)[0]; - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_CONF_JOIN conf %ld\n", __FUNCTION__, num); - if (num <= 7) { - hfcmulti_conf(hc, bch->channel, num); - ret = 0; - } else - printk(KERN_WARNING "%s: HW_CONF_JOIN conf %ld out of range\n", __FUNCTION__, num); - break; - - /* split conference */ - case HW_CONF_SPLIT: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_CONF_SPLIT\n", __FUNCTION__); - hfcmulti_conf(hc, bch->channel, -1); - ret = 0; - break; - - /* set sample loop */ - case HW_SPL_LOOP_ON: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_SPL_LOOP_ON (len = %d)\n", __FUNCTION__, skb->len); - hfcmulti_splloop(hc, bch->channel, skb->data, skb->len); - ret = 0; - break; - - /* set silence */ - case HW_SPL_LOOP_OFF: - if (debug & DEBUG_HFCMULTI_MSG) - printk(KERN_DEBUG "%s: HW_SPL_LOOP_OFF\n", __FUNCTION__); - hfcmulti_splloop(hc, bch->channel, NULL, 0); - ret = 0; - break; - default: - printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", __FUNCTION__, hh->dinfo); + printk(KERN_DEBUG "%s: unknown PH_SIGNAL info %x\n", + __FUNCTION__, hh->dinfo); + ret = -EINVAL; + } + spin_unlock_irqrestore(ch->inst.hwlock, flags); + } else if (hh->prim == (PH_CONTROL | REQUEST)) { + spin_lock_irqsave(ch->inst.hwlock, flags); + ret = 0; + switch (hh->dinfo) { + case HW_RESET: + /* start activation */ + if (hc->type == 1) { + HFC_outb(hc, R_E1_WR_STA, V_E1_LD_STA | 0); + udelay(6); /* wait at least 5,21us */ + HFC_outb(hc, R_E1_WR_STA, 0); + } else { + HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port); + HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 3); /* G1 */ + udelay(6); /* wait at least 5,21us */ + HFC_outb(hc, A_ST_WR_STATE, 3); + HFC_outb(hc, A_ST_WR_STATE, 3 | (V_ST_ACT*3)); /* activate */ + } + spin_unlock_irqrestore(ch->inst.hwlock, flags); + skb_trim(skb, 0); + return(mISDN_queueup_newhead(&ch->inst, 0, PH_CONTROL | INDICATION,HW_POWERUP, skb)); + case HW_DEACTIVATE: + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_DEACTIVATE\n", + __FUNCTION__); + goto hw_deactivate; /* after lock */ + case HW_PCM_CONN: /* connect interface to pcm timeslot (0..N) */ + if (skb->len < 4*sizeof(u_long)) { + printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n", + __FUNCTION__); + break; + } + slot_tx = ((int *)skb->data)[0]; + bank_tx = ((int *)skb->data)[1]; + slot_rx = ((int *)skb->data)[2]; + bank_rx = ((int *)skb->data)[3]; + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n", + __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); + if (slot_tx <= hc->slots && bank_tx <=2 && + slot_rx <= hc->slots && bank_rx <= 2) + hfcmulti_pcm(hc, ch->channel, slot_tx, + bank_tx, slot_rx, bank_rx); + else + printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n", + __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); + break; + case HW_PCM_DISC: /* release interface from pcm timeslot */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_PCM_DISC\n", + __FUNCTION__); + hfcmulti_pcm(hc, ch->channel, -1, -1, -1, -1); + break; + case HW_POWERUP: + printk(KERN_INFO "HW_POWERUP\n"); + HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port); + HFC_outb(hc, A_ST_WR_STATE, 3 | 0x10); /* activate */ + udelay(6); /* wait at least 5,21us */ + HFC_outb(hc, A_ST_WR_STATE, 3); /* activate */ + break; + default: + printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", + __FUNCTION__, hh->dinfo); + ret = -EINVAL; + } + spin_unlock_irqrestore(ch->inst.hwlock, flags); + } else if (hh->prim == (PH_ACTIVATE | REQUEST)) { + if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch->channel].cfg)) { + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_ACTIVATE port %d (0..%d)\n", + __FUNCTION__, hc->chan[ch->channel].port, hc->type-1); + spin_lock_irqsave(ch->inst.hwlock, flags); + /* start activation */ + if (hc->type == 1) { + //chanannel_sched_event(chan, D_L1STATECHANGE); + ph_state_change(ch); + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: E1 report state %x \n", + __FUNCTION__, ch->state); + } else { + HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port); + HFC_outb(hc, A_ST_WR_STATE, V_ST_LD_STA | 1); /* G1 */ + udelay(6); /* wait at least 5,21us */ + HFC_outb(hc, A_ST_WR_STATE, 1); + HFC_outb(hc, A_ST_WR_STATE, 1 | (V_ST_ACT*3)); /* activate */ + ch->state = 1; + } + spin_unlock_irqrestore(ch->inst.hwlock, flags); + ret = 0; + } else { + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_ACTIVATE no NT-mode port %d (0..%d)\n", + __FUNCTION__, hc->chan[ch->channel].port, hc->type-1); ret = -EINVAL; } - bch->inst.unlock(hc); - } else { - printk(KERN_WARNING "%s: unknown prim(%x)\n", __FUNCTION__, hh->prim); - ret = -EINVAL; + } else if (hh->prim == (PH_DEACTIVATE | REQUEST)) { + if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch->channel].cfg)) { + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_DEACTIVATE port %d (0..%d)\n", + __FUNCTION__, hc->chan[ch->channel].port, hc->type-1); + spin_lock_irqsave(ch->inst.hwlock, flags); +hw_deactivate: + ch->state = 0; + /* start deactivation */ + if (hc->type == 1) { + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_DEACTIVATE no BRI\n", + __FUNCTION__); + } else { + HFC_outb(hc, R_ST_SEL, hc->chan[ch->channel].port); + HFC_outb(hc, A_ST_WR_STATE, V_ST_ACT*2); /* deactivate */ + } + if (ch->next_skb) { + dev_kfree_skb(ch->next_skb); + ch->next_skb = NULL; + } + if (ch->rx_skb) { + dev_kfree_skb(ch->rx_skb); + ch->rx_skb = NULL; + } + ch->tx_idx = 0; + if (ch->tx_skb) { + dev_kfree_skb(ch->tx_skb); + ch->tx_skb = NULL; + } + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); + test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); + if (test_and_clear_bit(FLG_BUSY_TIMER, &ch->Flags)) + del_timer(&ch->timer); + spin_unlock_irqrestore(ch->inst.hwlock, flags); + ret = 0; + } else { + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_DEACTIVATE no NT-mode port %d (0..%d)\n", + __FUNCTION__, hc->chan[ch->channel].port, hc->type-1); + ret = -EINVAL; + } + } else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) { + u_int temp = hh->dinfo & SSTATUS_ALL; // remove SSTATUS_BROADCAST_BIT + if (((hc->type == 1) || test_bit(HFC_CFG_NTMODE, + &hc->chan[ch->channel].cfg)) && + (temp == SSTATUS_ALL || temp == SSTATUS_L1)) { + if (hh->dinfo & SSTATUS_BROADCAST_BIT) + temp = ch->inst.id | MSG_BROADCAST; + else + temp = hh->addr | FLG_MSG_TARGET; + skb_trim(skb, 0); + hh->dinfo = test_bit(FLG_ACTIVE, &ch->Flags) ? + SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED; + hh->prim = MGR_SHORTSTATUS | CONFIRM; + return(mISDN_queue_message(&ch->inst, temp, skb)); + } + ret = -EOPNOTSUPP; } - if (!ret) { -// printk("3\n"); + if (!ret) dev_kfree_skb(skb); -// printk("4\n"); - } return(ret); } +static int +handle_bmsg(channel_t *ch, struct sk_buff *skb) +{ + mISDN_head_t *hh = mISDN_HEAD_P(skb); + hfc_multi_t *hc = ch->inst.privat; + u_long flags, num; + int slot_tx, slot_rx, bank_tx, bank_rx; + int ret = -EAGAIN; + struct dsp_features *features; + + if ((hh->prim == (PH_ACTIVATE | REQUEST)) || + (hh->prim == (DL_ESTABLISH | REQUEST))) { + /* activate B-channel if not already activated */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_ACTIVATE ch %d (0..32)\n", + __FUNCTION__, ch->channel); + if (!test_and_set_bit(FLG_ACTIVE, &ch->Flags)) { + spin_lock_irqsave(ch->inst.hwlock, flags); + if (ch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS) + test_and_set_bit(FLG_L2DATA, &ch->Flags); + ret = mode_hfcmulti(hc, ch->channel, + ch->inst.pid.protocol[1], + hc->chan[ch->channel].slot_tx, + hc->chan[ch->channel].bank_tx, + hc->chan[ch->channel].slot_rx, + hc->chan[ch->channel].bank_rx); + if (!ret) { + if (ch->inst.pid.protocol[1] == + ISDN_PID_L1_B_64TRANS && !hc->dtmf) { + /* start decoder */ + hc->dtmf = 1; + if (debug & DEBUG_HFCMULTI_DTMF) + printk(KERN_DEBUG "%s: start dtmf decoder\n", + __FUNCTION__); + HFC_outb(hc, R_DTMF, hc->hw.r_dtmf | V_RST_DTMF); + } + } + spin_unlock_irqrestore(ch->inst.hwlock, flags); + } else + ret = 0; + skb_trim(skb, 0); + return(mISDN_queueup_newhead(&ch->inst, 0, hh->prim | CONFIRM, ret, skb)); + } + if ((hh->prim == (PH_DEACTIVATE | REQUEST)) || + (hh->prim == (DL_RELEASE | REQUEST)) || + ((hh->prim == (PH_CONTROL | REQUEST) && + (hh->dinfo == HW_DEACTIVATE)))) { + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: PH_DEACTIVATE ch %d (0..32)\n", + __FUNCTION__, ch->channel); + /* deactivate B-channel if not already deactivated */ + spin_lock_irqsave(ch->inst.hwlock, flags); + if (ch->next_skb) { + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); + dev_kfree_skb(ch->next_skb); + ch->next_skb = NULL; + } + if (ch->tx_skb) { + dev_kfree_skb(ch->tx_skb); + ch->tx_skb = NULL; + } + ch->tx_idx = 0; + if (ch->rx_skb) { + dev_kfree_skb(ch->rx_skb); + ch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); + hc->chan[ch->channel].slot_tx = -1; + hc->chan[ch->channel].slot_rx = -1; + hc->chan[ch->channel].conf = -1; + mode_hfcmulti(hc, ch->channel, ISDN_PID_NONE, + hc->chan[ch->channel].slot_tx, + hc->chan[ch->channel].bank_tx, + hc->chan[ch->channel].slot_rx, + hc->chan[ch->channel].bank_rx); + test_and_clear_bit(FLG_L2DATA, &ch->Flags); + test_and_clear_bit(FLG_ACTIVE, &ch->Flags); + spin_unlock_irqrestore(ch->inst.hwlock, flags); + skb_trim(skb, 0); + ret = 0; + if (hh->prim != (PH_CONTROL | REQUEST)) + return(mISDN_queueup_newhead(&ch->inst, 0, + hh->prim | CONFIRM, ret, skb)); + } else if (hh->prim == (PH_CONTROL | REQUEST)) { + spin_lock_irqsave(ch->inst.hwlock, flags); + switch (hh->dinfo) { + case HW_FEATURES: /* fill features structure */ + #warning this is dangerous, the skb should never used to transfer a pointer please use a message + if (skb->len != sizeof(void *)) { + printk(KERN_WARNING "%s: HW_FEATURES lacks parameters\n", + __FUNCTION__); + break; + } + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_FEATURE request\n", + __FUNCTION__); + features = *((struct dsp_features **)skb->data); + features->hfc_id = hc->id; + if (test_bit(HFC_CHIP_DTMF, &hc->chip)) + features->hfc_dtmf = 1; + features->hfc_loops = 0; + features->pcm_id = hc->pcm; + features->pcm_slots = hc->slots; + features->pcm_banks = 2; + ret = 0; + break; + case HW_PCM_CONN: /* connect interface to pcm timeslot (0..N) */ + if (skb->len < 4*sizeof(s32)) { + printk(KERN_WARNING "%s: HW_PCM_CONN lacks parameters\n", + __FUNCTION__); + break; + } + slot_tx = ((s32 *)skb->data)[0]; + bank_tx = ((s32 *)skb->data)[1]; + slot_rx = ((s32 *)skb->data)[2]; + bank_rx = ((s32 *)skb->data)[3]; + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX)\n", + __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); + if (slot_tx <= hc->slots && bank_tx <= 2 && + slot_rx <= hc->slots && bank_rx <= 2) + hfcmulti_pcm(hc, ch->channel, slot_tx, bank_tx, slot_rx, bank_rx); + else + printk(KERN_WARNING "%s: HW_PCM_CONN slot %d bank %d (TX) slot %d bank %d (RX) out of range\n", + __FUNCTION__, slot_tx, bank_tx, slot_rx, bank_rx); + ret = 0; + break; + case HW_PCM_DISC: /* release interface from pcm timeslot */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_PCM_DISC\n", + __FUNCTION__); + hfcmulti_pcm(hc, ch->channel, -1, -1, -1, -1); + ret = 0; + break; + case HW_CONF_JOIN: /* join conference (0..7) */ + if (skb->len < sizeof(u32)) { + printk(KERN_WARNING "%s: HW_CONF_JOIN lacks parameters\n", __FUNCTION__); + break; + } + num = ((u32 *)skb->data)[0]; + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_CONF_JOIN conf %ld\n", + __FUNCTION__, num); + if (num <= 7) { + hfcmulti_conf(hc, ch->channel, num); + ret = 0; + } else + printk(KERN_WARNING "%s: HW_CONF_JOIN conf %ld out of range\n", + __FUNCTION__, num); + break; + case HW_CONF_SPLIT: /* split conference */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_CONF_SPLIT\n", + __FUNCTION__); + hfcmulti_conf(hc, ch->channel, -1); + ret = 0; + break; + case HW_SPL_LOOP_ON: /* set sample loop */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_SPL_LOOP_ON (len = %d)\n", + __FUNCTION__, skb->len); + hfcmulti_splloop(hc, ch->channel, skb->data, skb->len); + ret = 0; + break; + case HW_SPL_LOOP_OFF: /* set silence */ + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: HW_SPL_LOOP_OFF\n", + __FUNCTION__); + hfcmulti_splloop(hc, ch->channel, NULL, 0); + ret = 0; + break; + + default: + printk(KERN_DEBUG "%s: unknown PH_CONTROL info %x\n", + __FUNCTION__, hh->dinfo); + ret = -EINVAL; + } + spin_unlock_irqrestore(ch->inst.hwlock, flags); + } + if (!ret) + dev_kfree_skb(skb); + return(ret); +} + +/* + * message transfer from layer 1 to hardware. + */ +static int +hfcmulti_l2l1(mISDNinstance_t *inst, struct sk_buff *skb) +{ + channel_t *chan = container_of(inst, channel_t, inst); + hfc_multi_t *hc; + int ret = 0; + mISDN_head_t *hh = mISDN_HEAD_P(skb); + u_long flags; + + hc = chan->inst.privat; + if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) { + spin_lock_irqsave(inst->hwlock, flags); + ret = channel_senddata(chan, hh->dinfo, skb); + if (ret > 0) { /* direct TX */ + hfcmulti_tx(hc, chan->channel, chan); + /* start fifo */ + HFC_outb(hc, R_FIFO, 0); + HFC_wait(hc); + ret = 0; + } + spin_unlock_irqrestore(inst->hwlock, flags); + return(ret); + } + if (test_bit(FLG_DCHANNEL, &chan->Flags)) { + ret = handle_dmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; + } + if (test_bit(FLG_BCHANNEL, &chan->Flags)) { + ret = handle_bmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return(ret); +} /***************************/ /* handle D-channel events */ @@ -2231,16 +2283,12 @@ hfcmulti_l2l1(mISDNif_t *hif, struct sk_buff *skb) /* handle state change event */ -static void -hfcmulti_dch_bh(dchannel_t *dch) +static void ph_state_change(channel_t *dch) { - hfc_multi_t *hc = dch->inst.data; + hfc_multi_t *hc = dch->inst.privat; u_int prim = PH_SIGNAL | INDICATION; u_int para = 0; - mISDNif_t *upif = &dch->inst.up; - mISDN_head_t *hh; int ch; - struct sk_buff *skb; if (!dch) { printk(KERN_WARNING "%s: ERROR given dch is NULL\n", __FUNCTION__); @@ -2248,221 +2296,112 @@ hfcmulti_dch_bh(dchannel_t *dch) } ch = dch->channel; - /* Loss Of Signal */ - if (test_and_clear_bit(D_LOS, &dch->event)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: LOS detected\n", __FUNCTION__); - skb = create_link_skb(PH_CONTROL | INDICATION, HW_LOS, 0, NULL, 0); - if (skb) { - hh = mISDN_HEAD_P(skb); - if (if_newhead(upif, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); + if (hc->type == 1) { + if (!test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) { + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: E1 TE newstate %x\n", __FUNCTION__, dch->state); + } else { + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: E1 NT newstate %x\n", __FUNCTION__, dch->state); } - } - /* Loss Of Signal OFF */ - if (test_and_clear_bit(D_LOS_OFF, &dch->event)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: LOS gone\n", __FUNCTION__); - skb = create_link_skb(PH_CONTROL | INDICATION, HW_LOS_OFF, 0, NULL, 0); - if (skb) { - hh = mISDN_HEAD_P(skb); - if (if_newhead(upif, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); - } - } - /* Alarm Indication Signal */ - if (test_and_clear_bit(D_AIS, &dch->event)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: AIS detected\n", __FUNCTION__); - skb = create_link_skb(PH_CONTROL | INDICATION, HW_AIS, 0, NULL, 0); - if (skb) { - hh = mISDN_HEAD_P(skb); - if (if_newhead(upif, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); - } - } - /* Alarm Indication Signal OFF */ - if (test_and_clear_bit(D_AIS_OFF, &dch->event)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: AIS gone\n", __FUNCTION__); - skb = create_link_skb(PH_CONTROL | INDICATION, HW_AIS_OFF, 0, NULL, 0); - if (skb) { - hh = mISDN_HEAD_P(skb); - if (if_newhead(upif, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); - } - } - /* SLIP detected */ - if (test_and_clear_bit(D_SLIP_TX, &dch->event)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: bit SLIP detected TX\n", __FUNCTION__); - skb = create_link_skb(PH_CONTROL | INDICATION, HW_SLIP_TX, 0, NULL, 0); - if (skb) { - hh = mISDN_HEAD_P(skb); - if (if_newhead(upif, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); - } - } - if (test_and_clear_bit(D_SLIP_RX, &dch->event)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: bit SLIP detected RX\n", __FUNCTION__); - skb = create_link_skb(PH_CONTROL | INDICATION, HW_SLIP_RX, 0, NULL, 0); - if (skb) { - hh = mISDN_HEAD_P(skb); - if (if_newhead(upif, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); - } - } - - if (test_and_clear_bit(D_L1STATECHANGE, &dch->event)) { - if (hc->type == 1) { - if (!test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: E1 TE newstate %x\n", __FUNCTION__, dch->ph_state); - } else { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: E1 NT newstate %x\n", __FUNCTION__, dch->ph_state); - } - switch (dch->ph_state) { - case (1): + switch (dch->state) { + case (1): prim = PH_ACTIVATE | INDICATION; para = 0; + test_and_set_bit(FLG_ACTIVE, &dch->Flags); break; - default: + default: if (hc->chan[ch].e1_state != 1) return; prim = PH_DEACTIVATE | INDICATION; para = 0; - } - hc->chan[ch].e1_state = dch->ph_state; - } else { - if (!test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: S/T TE newstate %x\n", __FUNCTION__, dch->ph_state); - switch (dch->ph_state) { - case (0): + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + } + hc->chan[ch].e1_state = dch->state; + } else { + if (!test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) { + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: S/T TE newstate %x\n", __FUNCTION__, dch->state); + switch (dch->state) { + case (0): prim = PH_CONTROL | INDICATION; para = HW_RESET; break; - case (3): + case (3): prim = PH_CONTROL | INDICATION; para = HW_DEACTIVATE; break; - case (5): - case (8): + case (5): + case (8): para = ANYSIGNAL; break; - case (6): + case (6): para = INFO2; break; - case (7): + case (7): para = INFO4_P8; break; - default: + default: return; - } - } else { - if (debug & DEBUG_HFCMULTI_STATE) - printk(KERN_DEBUG "%s: S/T NT newstate %x\n", __FUNCTION__, dch->ph_state); - dch->inst.lock(hc, 0); - switch (dch->ph_state) { - case (2): + } + } else { + if (debug & DEBUG_HFCMULTI_STATE) + printk(KERN_DEBUG "%s: S/T NT newstate %x\n", __FUNCTION__, dch->state); + switch (dch->state) { + case (2): if (hc->chan[ch].nt_timer == 0) { hc->chan[ch].nt_timer = -1; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); HFC_outb(hc, A_ST_WR_STATE, 4 | V_ST_LD_STA); /* G4 */ udelay(6); /* wait at least 5,21us */ HFC_outb(hc, A_ST_WR_STATE, 4); - dch->ph_state = 4; + dch->state = 4; } else { /* one extra count for the next event */ hc->chan[ch].nt_timer = nt_t1_count[poll_timer] + 1; HFC_outb(hc, R_ST_SEL, hc->chan[ch].port); HFC_outb(hc, A_ST_WR_STATE, 2 | V_SET_G2_G3); /* allow G2 -> G3 transition */ } - upif = NULL; - break; + return; - case (1): + case (1): prim = PH_DEACTIVATE | INDICATION; para = 0; hc->chan[ch].nt_timer = -1; + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); break; - case (4): + case (4): hc->chan[ch].nt_timer = -1; - upif = NULL; - break; + return; - case (3): + case (3): prim = PH_ACTIVATE | INDICATION; para = 0; hc->chan[ch].nt_timer = -1; + test_and_set_bit(FLG_ACTIVE, &dch->Flags); break; - default: - break; - } - dch->inst.unlock(hc); - } - } - /* transmit new state to upper layer if available */ - if (hc->created[hc->chan[ch].port]) { - while(upif) { - if_link(upif, prim, para, 0, NULL, 0); - upif = upif->clone; + default: + return; } } } + + mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0); + if ((hc->type == 1) || test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) + mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST, + MGR_SHORTSTATUS | INDICATION, test_bit(FLG_ACTIVE, &dch->Flags) ? + SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED, + 0, NULL, 0); } -/***************************/ -/* handle D-channel events */ -/***************************/ - -/* handle DTMF event - */ -static void -hfcmulti_bch_bh(bchannel_t *bch) -{ - hfc_multi_t *hc = bch->inst.data; - struct sk_buff *skb; - mISDN_head_t *hh; - mISDNif_t *hif = 0; /* make gcc happy */ - u_long *coeff; - - if (!bch) { - printk(KERN_WARNING "%s: ERROR given bch is NULL\n", __FUNCTION__); - return; - } - - /* DTMF event */ - if (test_and_clear_bit(B_DTMFREADY, &bch->event)) { - while ((skb = skb_dequeue(&hc->chan[bch->channel].dtmfque))) { - if (debug & DEBUG_HFCMULTI_DTMF) { - coeff = (u_long *)skb->data; - printk("%s: DTMF ready %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx len=%d\n", __FUNCTION__, - coeff[0], coeff[1], coeff[2], coeff[3], coeff[4], coeff[5], coeff[6], coeff[7], skb->len); - } - hh = mISDN_HEAD_P(skb); - 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, hh->prim, hh->dinfo, skb)) - dev_kfree_skb(skb); - } - } - -} - - /*************************************/ /* called for card mode init message */ /*************************************/ @@ -2470,35 +2409,33 @@ hfcmulti_bch_bh(bchannel_t *bch) static void hfcmulti_initmode(hfc_multi_t *hc) { - int nt_mode; - unsigned char r_sci_msk, a_st_wr_state, r_e1_wr_sta; - int i, port; - dchannel_t *dch; + int nt_mode; + BYTE r_sci_msk, a_st_wr_state, r_e1_wr_sta; + int i, port; + channel_t *dch; + u_long flags; if (debug & DEBUG_HFCMULTI_INIT) printk("%s: entered\n", __FUNCTION__); - lock_dev(hc, 0); - +#warning KARSTEN: this causes a crash on UP and SMP with multiple cards +// spin_lock_irqsave(&hc->lock, flags); if (hc->type == 1) { nt_mode = test_bit(HFC_CFG_NTMODE, &hc->chan[16].cfg); hc->chan[16].slot_tx = -1; hc->chan[16].slot_rx = -1; hc->chan[16].conf = -1; mode_hfcmulti(hc, 16, nt_mode?ISDN_PID_L1_NT_E1:ISDN_PID_L1_TE_E1, -1, 0, -1, 0); - hc->chan[16].dch->hw_bh = hfcmulti_dch_bh; - hc->chan[16].dch->dbusytimer.function = (void *) hfcmulti_dbusy_timer; - hc->chan[16].dch->dbusytimer.data = (long) &hc->chan[16].dch; - init_timer(&hc->chan[16].dch->dbusytimer); + hc->chan[16].ch->timer.function = (void *) hfcmulti_dbusy_timer; + hc->chan[16].ch->timer.data = (long) &hc->chan[16].ch; + init_timer(&hc->chan[16].ch->timer); i = 0; while (i < 30) { hc->chan[i+1+(i>=15)].slot_tx = -1; hc->chan[i+1+(i>=15)].slot_rx = -1; hc->chan[i+1+(i>=15)].conf = -1; - hc->chan[i+1+(i>=15)].bch->hw_bh = hfcmulti_bch_bh; mode_hfcmulti(hc, i+1+(i>=15), ISDN_PID_NONE, -1, 0, -1, 0); - hc->chan[i+1+(i>=15)].bch->protocol = ISDN_PID_NONE; i++; } } else { @@ -2509,23 +2446,18 @@ hfcmulti_initmode(hfc_multi_t *hc) hc->chan[(i<<2)+2].slot_rx = -1; hc->chan[(i<<2)+2].conf = -1; mode_hfcmulti(hc, (i<<2)+2, nt_mode?ISDN_PID_L1_NT_S0:ISDN_PID_L1_TE_S0, -1, 0, -1, 0); - hc->chan[(i<<2)+2].dch->hw_bh = hfcmulti_dch_bh; - hc->chan[(i<<2)+2].dch->dbusytimer.function = (void *) hfcmulti_dbusy_timer; - hc->chan[(i<<2)+2].dch->dbusytimer.data = (long) &hc->chan[(i<<2)+2].dch; - init_timer(&hc->chan[(i<<2)+2].dch->dbusytimer); - - hc->chan[i<<2].bch->hw_bh = hfcmulti_bch_bh; + hc->chan[(i<<2)+2].ch->timer.function = (void *) hfcmulti_dbusy_timer; + hc->chan[(i<<2)+2].ch->timer.data = (long) &hc->chan[(i<<2)+2].ch; + init_timer(&hc->chan[(i<<2)+2].ch->timer); + hc->chan[i<<2].slot_tx = -1; hc->chan[i<<2].slot_rx = -1; hc->chan[i<<2].conf = -1; mode_hfcmulti(hc, i<<2, ISDN_PID_NONE, -1, 0, -1, 0); - hc->chan[i<<2].bch->protocol = ISDN_PID_NONE; - hc->chan[(i<<2)+1].bch->hw_bh = hfcmulti_bch_bh; hc->chan[(i<<2)+1].slot_tx = -1; hc->chan[(i<<2)+1].slot_rx = -1; hc->chan[(i<<2)+1].conf = -1; mode_hfcmulti(hc, (i<<2)+1, ISDN_PID_NONE, -1, 0, -1, 0); - hc->chan[(i<<2)+1].bch->protocol = ISDN_PID_NONE; i++; } } @@ -2536,7 +2468,8 @@ hfcmulti_initmode(hfc_multi_t *hc) r_sci_msk = 0; i = 0; while(i < 32) { - if (!(dch = hc->chan[i].dch)) { + dch = hc->chan[i].ch; + if (!dch || !test_bit(FLG_DCHANNEL, &dch->Flags)) { i++; continue; } @@ -2596,20 +2529,32 @@ hfcmulti_initmode(hfc_multi_t *hc) HFC_outb(hc, R_TX1, hc->hw.r_tx1); HFC_outb(hc, R_TX_FR0, 0x00); HFC_outb(hc, R_TX_FR1, 0xf8); - HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); + + if (test_bit(HFC_CFG_CRC4, &hc->chan[16].cfg)) + HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E); + HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0); - HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); + + if (test_bit(HFC_CFG_CRC4, &hc->chan[16].cfg)) + HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC); + if (test_bit(HFC_CHIP_PCM_SLAVE, &hc->chip)) { /* SLAVE (clock master) */ if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: E1 port is clock master\n", __FUNCTION__); -// HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS | V_PCM_SYNC); + printk(KERN_DEBUG "%s: E1 port is clock master (clock from PCM)\n", __FUNCTION__); HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC); } else { - /* MASTER (clock slave) */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: E1 port is clock slave\n", __FUNCTION__); - HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); + if (test_bit(HFC_CHIP_CRYSTAL_CLOCK, &hc->chip)) { + /* MASTER (clock master) */ + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: E1 port is clock master (clock from crystal)\n", __FUNCTION__); + HFC_outb(hc, R_SYNC_CTRL, V_EXT_CLK_SYNC | V_PCM_SYNC | V_JATT_OFF); + } else { + /* MASTER (clock slave) */ + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: E1 port is clock slave (clock to PCM)\n", __FUNCTION__); + HFC_outb(hc, R_SYNC_CTRL, V_SYNC_OFFS); + } } if (test_bit(HFC_CFG_NTMODE, &hc->chan[(i<<2)+2].cfg)) { if (debug & DEBUG_HFCMULTI_INIT) @@ -2633,14 +2578,10 @@ hfcmulti_initmode(hfc_multi_t *hc) HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta | V_E1_LD_STA); udelay(6); /* wait at least 5,21us */ HFC_outb(hc, R_E1_WR_STA, r_e1_wr_sta); - + } - - /* set interrupts & global interrupt */ - hc->hw.r_irq_ctrl = V_FIFO_IRQ | V_GLOB_IRQ_EN; - - unlock_dev(hc); - +#warning KARSTEN: this causes a crash on UP and SMP with multiple cards +// spin_unlock_irqrestore(&hc->lock, flags); if (debug & DEBUG_HFCMULTI_INIT) printk("%s: done\n", __FUNCTION__); } @@ -2656,35 +2597,51 @@ hfcmulti_initmode(hfc_multi_t *hc) static int init_card(hfc_multi_t *hc) { - int cnt = 1; /* as long as there is no trouble */ - int err = -EIO; + int cnt = 1; /* as long as there is no trouble */ + int err = -EIO; + u_long flags; +#ifdef CONFIG_PLX_PCI_BRIDGE + u_short *plx_acc; +#endif if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __FUNCTION__); - lock_dev(hc, 0); + spin_lock_irqsave(&hc->lock, flags); + /* set interrupts but let global interrupt disabled*/ + hc->hw.r_irq_ctrl = V_FIFO_IRQ; + disable_hwirq(hc); + spin_unlock_irqrestore(&hc->lock, flags); if (request_irq(hc->pci_dev->irq, hfcmulti_interrupt, SA_SHIRQ, "HFC-multi", hc)) { printk(KERN_WARNING "mISDN: Could not get interrupt %d.\n", hc->pci_dev->irq); - unlock_dev(hc); return(-EIO); } hc->irq = hc->pci_dev->irq; +#ifdef CONFIG_PLX_PCI_BRIDGE + plx_acc=(u_short*)(hc->plx_membase+0x4c); + *plx_acc=0x41; // enable PCI & LINT1 irq +#endif if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: IRQ %d count %d\n", __FUNCTION__, hc->irq, hc->irqcnt); while (cnt) { - if ((err = init_chip(hc))) + if ((err = init_chip(hc))) { goto error; - /* Finally enable IRQ output + } + /* Finally enable IRQ output * this is only allowed, if an IRQ routine is allready * established for this HFC, so don't do that earlier */ - unlock_dev(hc); - HFC_outb(hc, R_IRQ_CTRL, V_GLOB_IRQ_EN); + spin_lock_irqsave(&hc->lock, flags); + enable_hwirq(hc); + spin_unlock_irqrestore(&hc->lock, flags); + //printk(KERN_DEBUG "no master irq set!!!\n"); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout((100*HZ)/1000); /* Timeout 100ms */ /* turn IRQ off until chip is completely initialized */ - HFC_outb(hc, R_IRQ_CTRL, 0); + spin_lock_irqsave(&hc->lock, flags); + disable_hwirq(hc); + spin_unlock_irqrestore(&hc->lock, flags); if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: IRQ %d count %d\n", __FUNCTION__, hc->irq, hc->irqcnt); if (hc->irqcnt) { @@ -2692,8 +2649,11 @@ init_card(hfc_multi_t *hc) printk(KERN_DEBUG "%s: done\n", __FUNCTION__); return(0); } - lock_dev(hc, 0); printk(KERN_WARNING "HFC PCI: IRQ(%d) getting no interrupts during init (try %d)\n", hc->irq, cnt); +#ifdef CONFIG_PLX_PCI_BRIDGE + plx_acc=(u_short*)(hc->plx_membase+0x4c); + *plx_acc=0x00; // disable PCI & LINT1 irq +#endif cnt--; err = -EIO; } @@ -2701,9 +2661,10 @@ init_card(hfc_multi_t *hc) error: if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_WARNING "%s: free irq %d\n", __FUNCTION__, hc->irq); - free_irq(hc->irq, hc); - hc->irq = 0; - unlock_dev(hc); + if (hc->irq) { + free_irq(hc->irq, hc); + hc->irq = 0; + } if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: done (err=%d)\n", __FUNCTION__, err); @@ -2718,23 +2679,23 @@ init_card(hfc_multi_t *hc) static int SelFreeBChannel(hfc_multi_t *hc, int ch, channel_info_t *ci) { - bchannel_t *bch; + channel_t *bch; hfc_multi_t *hfc; mISDNstack_t *bst; struct list_head *head; int cnr; int port = hc->chan[ch].port; - if (port < 0 || port>=hc->type) { + if (port < 0 || port >= hc->type) { printk(KERN_WARNING "%s: port(%d) out of range", __FUNCTION__, port); return(-EINVAL); } - + if (!ci) return(-EINVAL); ci->st.p = NULL; cnr=0; - bst = hc->chan[ch].dch->inst.st; + bst = hc->chan[ch].ch->inst.st; if (list_empty(&bst->childlist)) { if ((bst->id & FLG_CLONE_STACK) && (bst->childlist.prev != &bst->childlist)) { @@ -2747,7 +2708,7 @@ SelFreeBChannel(hfc_multi_t *hc, int ch, channel_info_t *ci) } else head = &bst->childlist; list_for_each_entry(bst, head, list) { - if (cnr == ((hc->type==1)?30:2)) /* 30 or 2 B-channels */ { + if (cnr == ((hc->type == 1) ? 30: 2)) /* 30 or 2 B-channels */ { printk(KERN_WARNING "%s: fatal error: more b-stacks than ports", __FUNCTION__); return(-EINVAL); } @@ -2755,26 +2716,26 @@ SelFreeBChannel(hfc_multi_t *hc, int ch, channel_info_t *ci) int_errtxt("no mgr st(%p)", bst); return(-EINVAL); } - hfc = bst->mgr->data; + hfc = bst->mgr->privat; if (!hfc) { int_errtxt("no mgr->data st(%p)", bst); return(-EINVAL); } - if (hc->type==1) - bch = hc->chan[cnr + 1 + (cnr>=15)].bch; + if (hc->type == 1) + bch = hc->chan[cnr + 1 + (cnr>=15)].ch; else - bch = hc->chan[(port<<2) + cnr].bch; + bch = hc->chan[(port<<2) + cnr].ch; if (!(ci->channel & (~CHANNEL_NUMBER))) { /* only number is set */ if ((ci->channel & 0x3) == (cnr + 1)) { - if (bch->protocol != ISDN_PID_NONE) + if (test_bit(FLG_ACTIVE, &bch->Flags)) return(-EBUSY); ci->st.p = bst; return(0); } } if ((ci->channel & (~CHANNEL_NUMBER)) == 0x00a18300) { - if (bch->protocol == ISDN_PID_NONE) { + if (!test_bit(FLG_ACTIVE, &bch->Flags)) { ci->st.p = bst; return(0); } @@ -2790,54 +2751,20 @@ SelFreeBChannel(hfc_multi_t *hc, int ch, channel_info_t *ci) /*********************************/ static int -setup_pci(hfc_multi_t *hc) +setup_pci(hfc_multi_t *hc, struct pci_dev *pdev, int id_idx) { int i; - struct pci_dev *tmp_dev = NULL; - hfc_multi_t *hc_tmp, *next; + + printk(KERN_INFO "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", id_list[id_idx].vendor_name, id_list[id_idx].card_name, (id_list[id_idx].clock2)?"double":"normal"); /* go into 0-state (we might already be due to zero-filled-object */ - i = 0; - while(i < 32) { - if (hc->chan[i].dch) - hc->chan[i].dch->ph_state = 0; - i++; + for (i = 0; i < 32; i++) { + if (hc->chan[i].ch && test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags)) + hc->chan[i].ch->state = 0; } - /* loop all card ids */ - i = 0; - while (id_list[i].vendor_id) { - /* only the given type is searched */ - if (id_list[i].type != hc->type) { - i++; - continue; - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "setup_pci(): investigating card entry %d (looking for type %d)\n", i, hc->type); - inuse: - tmp_dev = pci_get_subsys(id_list[i].vendor_id, id_list[i].device_id, id_list[i].vendor_sub, id_list[i].device_sub, tmp_dev); - if (tmp_dev) { - /* skip if already in use */ - list_for_each_entry_safe(hc_tmp, next, &HFCM_obj.ilist, list) { - if (hc_tmp->pci_dev == tmp_dev) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_INFO "setup_pci(): found a pci card: '%s' card name: '%s', but already in use, so we skip.\n", id_list[i].vendor_name, id_list[i].card_name); - goto inuse; - } - } - break; - } - i++; - } - if (!tmp_dev) { - printk(KERN_WARNING "HFC-multi: No PCI card found\n"); - return (-ENODEV); - } - - /* found a card */ - printk(KERN_INFO "HFC-multi: card manufacturer: '%s' card name: '%s' clock: %s\n", id_list[i].vendor_name, id_list[i].card_name, (id_list[i].clock2)?"double":"normal"); - hc->pci_dev = tmp_dev; - if (id_list[i].clock2) + hc->pci_dev = pdev; + if (id_list[id_idx].clock2) test_and_set_bit(HFC_CHIP_CLOCK2, &hc->chip); if (hc->pci_dev->irq <= 0) { printk(KERN_WARNING "HFC-multi: No IRQ for PCI card found.\n"); @@ -2847,30 +2774,72 @@ setup_pci(hfc_multi_t *hc) printk(KERN_WARNING "HFC-multi: Error enabling PCI card.\n"); return (-EIO); } - hc->leds = id_list[i].leds; + hc->leds = id_list[id_idx].leds; #ifdef CONFIG_HFCMULTI_PCIMEM - hc->pci_membase = (char *) get_pcibase(hc->pci_dev, 1); - if (!hc->pci_membase) { - printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI card found\n"); + hc->pci_membase = NULL; + hc->plx_membase = NULL; + +#ifdef CONFIG_PLX_PCI_BRIDGE + hc->plx_origmembase = get_pcibase(hc->pci_dev, 0); // MEMBASE 1 is PLX PCI Bridge + + if (!hc->plx_origmembase) { + printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI PLX bridge found\n"); + pci_disable_device(hc->pci_dev); return (-EIO); } - if (!(hc->pci_membase = ioremap((ulong) hc->pci_membase, 256))) { - printk(KERN_WARNING "HFC-multi: failed to remap io address space. (internal error)\n"); - hc->pci_membase = NULL; + if (!(hc->plx_membase = ioremap(hc->plx_origmembase, 128))) { + printk(KERN_WARNING "HFC-multi: failed to remap plx address space. (internal error)\n"); + hc->plx_membase = NULL; + pci_disable_device(hc->pci_dev); return (-EIO); } - printk(KERN_INFO "%s: defined at MEMBASE %#x IRQ %d HZ %d leds-type %d\n", hc->name, (u_int) hc->pci_membase, hc->pci_dev->irq, HZ, hc->leds); + printk(KERN_WARNING "HFC-multi: plx_membase:%#x plx_origmembase:%#x\n",(u_int) hc->plx_membase, (u_int)hc->plx_origmembase); + + hc->pci_origmembase = get_pcibase(hc->pci_dev, 2); // MEMBASE 1 is PLX PCI Bridge + if (!hc->pci_origmembase) { + printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI card found\n"); + pci_disable_device(hc->pci_dev); + return (-EIO); + } + + if (!(hc->pci_membase = ioremap(hc->pci_origmembase, 0x400))) { + printk(KERN_WARNING "HFC-multi: failed to remap io address space. (internal error)\n"); + hc->pci_membase = NULL; + pci_disable_device(hc->pci_dev); + return (-EIO); + } + + printk(KERN_INFO "%s: defined at MEMBASE %#x (%#x) IRQ %d HZ %d leds-type %d\n", hc->name, (u_int) hc->pci_membase, (u_int) hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); +#else // CONFIG_PLX_PCI_BRIDGE + hc->pci_origmembase = get_pcibase(hc->pci_dev, 1); + if (!hc->pci_origmembase) { + printk(KERN_WARNING "HFC-multi: No IO-Memory for PCI card found\n"); + pci_disable_device(hc->pci_dev); + return (-EIO); + } + + if (!(hc->pci_membase = ioremap(hc->pci_origmembase, 256))) { + printk(KERN_WARNING "HFC-multi: failed to remap io address space. (internal error)\n"); + hc->pci_membase = NULL; + pci_disable_device(hc->pci_dev); + return (-EIO); + } + printk(KERN_INFO "%s: defined at MEMBASE %#x (%#x) IRQ %d HZ %d leds-type %d\n", hc->name, (u_int) hc->pci_membase, (u_int) hc->pci_origmembase, hc->pci_dev->irq, HZ, hc->leds); + pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_MEMIO); +#endif // CONFIG_PLX_PCI_BRIDGE #else hc->pci_iobase = (u_int) get_pcibase(hc->pci_dev, 0); if (!hc->pci_iobase) { printk(KERN_WARNING "HFC-multi: No IO for PCI card found\n"); + pci_disable_device(hc->pci_dev); return (-EIO); } if (!request_region(hc->pci_iobase, 8, "hfcmulti")) { printk(KERN_WARNING "HFC-multi: failed to rquest address space at 0x%04x (internal error)\n", hc->pci_iobase); hc->pci_iobase = 0; + pci_disable_device(hc->pci_dev); return (-EIO); } @@ -2878,14 +2847,10 @@ setup_pci(hfc_multi_t *hc) pci_write_config_word(hc->pci_dev, PCI_COMMAND, PCI_ENA_REGIO); #endif + pci_set_drvdata(hc->pci_dev, hc); + /* At this point the needed PCI config is done */ /* fifos are still not enabled */ - lock_dev(hc, 0); -#ifdef SPIN_DEBUG - printk(KERN_ERR "spin_lock_adr=%p now(%p)\n", &hc->lock.spin_adr, hc->lock.spin_adr); - printk(KERN_ERR "busy_lock_adr=%p now(%p)\n", &hc->lock.busy_adr, hc->lock.busy_adr); -#endif - unlock_dev(hc); return (0); } @@ -2897,29 +2862,20 @@ setup_pci(hfc_multi_t *hc) static void release_port(hfc_multi_t *hc, int port) { - int i = 0; - int all = 1, any = 0; + int i = 0; + int all = 1, any = 0; + u_long flags; if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: entered\n", __FUNCTION__); -#ifdef LOCK_STATISTIC - printk(KERN_INFO "try_ok(%d) try_wait(%d) try_mult(%d) try_inirq(%d)\n", hc->lock.try_ok, hc->lock.try_wait, hc->lock.try_mult, hc->lock.try_inirq); - printk(KERN_INFO "irq_ok(%d) irq_fail(%d)\n", - hc->lock.irq_ok, hc->lock.irq_fail); -#endif - if (port >= hc->type) { printk(KERN_WARNING "%s: ERROR port out of range (%d).\n", __FUNCTION__, port); return; } -// if (debug & DEBUG_HFCMULTI_INIT) -// printk(KERN_DEBUG "%s: before lock_dev\n", __FUNCTION__); - lock_dev(hc, 0); -// if (debug & DEBUG_HFCMULTI_INIT) -// printk(KERN_DEBUG "%s: after lock_dev\n", __FUNCTION__); - + spin_lock_irqsave(&hc->lock, flags); + disable_hwirq(hc); if (port > -1) { i = 0; while(i < hc->type) { @@ -2931,7 +2887,7 @@ release_port(hfc_multi_t *hc, int port) } if (!any) { printk(KERN_WARNING "%s: ERROR card has no used stacks anymore.\n", __FUNCTION__); - unlock_dev(hc); + spin_unlock_irqrestore(&hc->lock, flags); return; } } @@ -2940,21 +2896,10 @@ release_port(hfc_multi_t *hc, int port) if (port>-1 && !hc->created[port]) { printk(KERN_WARNING "%s: ERROR given stack is not used by card (port=%d).\n", __FUNCTION__, port); - unlock_dev(hc); + spin_unlock_irqrestore(&hc->lock, flags); return; } - if (all) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: card has no more used stacks, so we release hardware.\n", __FUNCTION__); - if (hc->irq) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_WARNING "%s: free irq %d\n", __FUNCTION__, hc->irq); - free_irq(hc->irq, hc); - hc->irq = 0; - } - } - /* disable D-channels & B-channels */ if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: disable all channels (d and b)\n", __FUNCTION__); @@ -2995,11 +2940,12 @@ release_port(hfc_multi_t *hc, int port) i = 0; while(i < 32) { - if (hc->chan[i].dch) - if (hc->created[hc->chan[i].port]) - if (hc->chan[i].dch->dbusytimer.function != NULL && (all || port==i)) { - del_timer(&hc->chan[i].dch->dbusytimer); - hc->chan[i].dch->dbusytimer.function = NULL; + if (hc->chan[i].ch && test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags) && + hc->created[hc->chan[i].port] && + hc->chan[i].ch->timer.function != NULL && + (all || port==i)) { + del_timer(&hc->chan[i].ch->timer); + hc->chan[i].ch->timer.function = NULL; } i++; } @@ -3007,28 +2953,18 @@ release_port(hfc_multi_t *hc, int port) /* free channels */ i = 0; while(i < 32) { - if (hc->created[hc->chan[i].port]) - if (hc->chan[i].port==port || all) { - if (hc->chan[i].dch) { + if ((hc->created[hc->chan[i].port]) && + (hc->chan[i].port == port || all)) { + if (hc->chan[i].ch) { if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free port %d D-channel %d (1..32)\n", __FUNCTION__, hc->chan[i].port, i); - mISDN_free_dch(hc->chan[i].dch); - HFCM_obj.ctrl(hc->chan[i].dch->inst.up.peer, MGR_DISCONNECT | REQUEST, &hc->chan[i].dch->inst.up); - HFCM_obj.ctrl(&hc->chan[i].dch->inst, MGR_UNREGLAYER | REQUEST, NULL); - kfree(hc->chan[i].dch); - hc->chan[i].dch = NULL; - } - if (hc->chan[i].rx_buf) { - kfree(hc->chan[i].rx_buf); - hc->chan[i].rx_buf = NULL; - } - if (hc->chan[i].bch) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free port %d B-channel %d (1..32)\n", __FUNCTION__, hc->chan[i].port, i); - discard_queue(&hc->chan[i].dtmfque); - mISDN_free_bch(hc->chan[i].bch); - kfree(hc->chan[i].bch); - hc->chan[i].bch = NULL; + printk(KERN_DEBUG "%s: free port %d %c-channel %d (1..32)\n", + __FUNCTION__, hc->chan[i].port, + test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags) ? + 'D' : 'B', i); + mISDN_freechannel(hc->chan[i].ch); + HFCM_obj.ctrl(&hc->chan[i].ch->inst, MGR_UNREGLAYER | REQUEST, NULL); + kfree(hc->chan[i].ch); + hc->chan[i].ch = NULL; } } i++; @@ -3046,29 +2982,50 @@ release_port(hfc_multi_t *hc, int port) /* release IO & remove card */ if (all) { + /* release hardware */ if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: do release_io_hfcmulti\n", __FUNCTION__); + printk(KERN_WARNING "%s: card has no more used stacks, so we release hardware.\n", __FUNCTION__); release_io_hfcmulti(hc); + spin_unlock_irqrestore(&hc->lock, flags); + /* release irq */ + if (hc->irq) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_WARNING "%s: free irq %d\n", __FUNCTION__, hc->irq); + free_irq(hc->irq, hc); + hc->irq = 0; + } + /* remove us from list and delete */ if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: removing object from listbase\n", __FUNCTION__); + printk(KERN_WARNING "%s: remove instance from list\n", __FUNCTION__); + spin_lock_irqsave(&HFCM_obj.lock, flags); list_del(&hc->list); - unlock_dev(hc); + spin_unlock_irqrestore(&HFCM_obj.lock, flags); + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_WARNING "%s: delete instance\n", __FUNCTION__); +//#warning +// kfree(hc->davor); +// kfree(hc->danach); kfree(hc); - } else - unlock_dev(hc); + HFC_cnt--; + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_WARNING "%s: card successfully removed\n", __FUNCTION__); + } else { + enable_hwirq(hc); + spin_unlock_irqrestore(&hc->lock, flags); + } } static int HFC_manager(void *data, u_int prim, void *arg) { - hfc_multi_t *hc; - mISDNinstance_t *inst = data; - struct sk_buff *skb; - dchannel_t *dch = NULL; - bchannel_t *bch = NULL; - int ch = -1; - int i; + hfc_multi_t *hc; + mISDNinstance_t *inst = data; + struct sk_buff *skb; + channel_t *chan = NULL; + int ch = -1; + int i; + u_long flags; if (!data) { MGR_HASPROTOCOL_HANDLER(prim,arg,&HFCM_obj) @@ -3077,20 +3034,15 @@ HFC_manager(void *data, u_int prim, void *arg) } /* find channel and card */ + spin_lock_irqsave(&HFCM_obj.lock, flags); list_for_each_entry(hc, &HFCM_obj.ilist, list) { i = 0; while(i < 32) { //printk(KERN_DEBUG "comparing (D-channel) card=%08x inst=%08x with inst=%08x\n", hc, &hc->dch[i].inst, inst); - if (hc->chan[i].dch) - if (&hc->chan[i].dch->inst == inst) { + if ((hc->chan[i].ch) && + (&hc->chan[i].ch->inst == inst)) { ch = i; - dch = hc->chan[i].dch; - break; - } - if (hc->chan[i].bch) - if (&hc->chan[i].bch->inst == inst) { - ch = i; - bch = hc->chan[i].bch; + chan = hc->chan[i].ch; break; } i++; @@ -3098,6 +3050,7 @@ HFC_manager(void *data, u_int prim, void *arg) if (ch >= 0) break; } + spin_unlock_irqrestore(&HFCM_obj.lock, flags); if (ch < 0) { printk(KERN_ERR "%s: no card/channel found data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg); return(-EINVAL); @@ -3107,33 +3060,24 @@ HFC_manager(void *data, u_int prim, void *arg) switch(prim) { case MGR_REGLAYER | CONFIRM: +bugtest if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_REGLAYER\n", __FUNCTION__); - if (dch) - dch_set_para(dch, &inst->st->para); - if (bch) - bch_set_para(bch, &inst->st->para); + mISDN_setpara(chan, &inst->st->para); +bugtest break; case MGR_UNREGLAYER | REQUEST: +bugtest if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_UNREGLAYER\n", __FUNCTION__); - if (dch) { - inst->down.fdata = dch; - if ((skb = create_link_skb(PH_CONTROL | REQUEST, HW_DEACTIVATE, 0, NULL, 0))) { - if (hfcmulti_l1hw(&inst->down, skb)) - dev_kfree_skb(skb); - } - } else - if (bch) { - inst->down.fdata = bch; - if ((skb = create_link_skb(MGR_DISCONNECT | REQUEST, 0, 0, NULL, 0))) { - if (hfcmulti_l2l1(&inst->down, skb)) - dev_kfree_skb(skb); - } + i = test_bit(FLG_DCHANNEL, &chan->Flags) ? HW_DEACTIVATE : 0; + if ((skb = create_link_skb(PH_CONTROL | REQUEST, i, 0, NULL, 0))) { + if (hfcmulti_l2l1(inst, skb)) + dev_kfree_skb(skb); } - HFCM_obj.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up); HFCM_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL); +bugtest break; case MGR_CLRSTPARA | INDICATION: @@ -3142,28 +3086,20 @@ HFC_manager(void *data, u_int prim, void *arg) case MGR_ADDSTPARA | INDICATION: if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_***STPARA\n", __FUNCTION__); - if (dch) - dch_set_para(dch, arg); - if (bch) - bch_set_para(bch, arg); + mISDN_setpara(chan, arg); break; case MGR_RELEASE | INDICATION: if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_RELEASE = remove port from mISDN\n", __FUNCTION__); - if (dch) { - release_port(hc, hc->chan[ch].port); - HFCM_obj.refcnt--; - } - if (bch) - HFCM_obj.refcnt--; + if (test_bit(FLG_DCHANNEL, &chan->Flags)) + release_port(hc, hc->chan[ch].port); /* hc is free */ break; - +#ifdef FIXME case MGR_CONNECT | REQUEST: if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_CONNECT\n", __FUNCTION__); return(mISDN_ConnectIF(inst, arg)); - //break; case MGR_SETIF | REQUEST: case MGR_SETIF | INDICATION: @@ -3173,39 +3109,38 @@ HFC_manager(void *data, u_int prim, void *arg) return(mISDN_SetIF(inst, arg, prim, hfcmulti_l1hw, NULL, dch)); if (bch) return(mISDN_SetIF(inst, arg, prim, hfcmulti_l2l1, NULL, bch)); - //break; + break; case MGR_DISCONNECT | REQUEST: case MGR_DISCONNECT | INDICATION: if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_DISCONNECT\n", __FUNCTION__); return(mISDN_DisConnectIF(inst, arg)); - //break; - +#endif case MGR_SELCHANNEL | REQUEST: if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_SELCHANNEL\n", __FUNCTION__); - if (!dch) { + if (!test_bit(FLG_DCHANNEL, &chan->Flags)) { printk(KERN_WARNING "%s(MGR_SELCHANNEL|REQUEST): selchannel not dinst\n", __FUNCTION__); return(-EINVAL); } return(SelFreeBChannel(hc, ch, arg)); - //break; - case MGR_SETSTACK | CONFIRM: + case MGR_SETSTACK | INDICATION: +bugtest if (debug & DEBUG_HFCMULTI_MGR) printk(KERN_DEBUG "%s: MGR_SETSTACK\n", __FUNCTION__); - if (bch && inst->pid.global==2) { - inst->down.fdata = bch; + if (test_bit(FLG_BCHANNEL, &chan->Flags) && inst->pid.global==2) { if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) { - if (hfcmulti_l2l1(&inst->down, skb)) + if (hfcmulti_l2l1(inst, skb)) dev_kfree_skb(skb); } if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS) - if_link(&inst->up, DL_ESTABLISH | INDICATION, 0, 0, NULL, 0); + mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION, 0, 0, NULL, 0); else - if_link(&inst->up, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0); + mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, 0, 0, NULL, 0); } +bugtest break; PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION); @@ -3217,31 +3152,584 @@ HFC_manager(void *data, u_int prim, void *arg) return(0); } +static void find_type_entry(int hfc_type, int *card, int *port) +{ + int i, j = 0; + + for(i=0;ivendor,ent->subvendor,ent->device,ent->subdevice); + if (id_idx == -1) { + if (ent->vendor == CCAG_VID) + if (ent->device == HFC4S_ID + || ent->device == HFC8S_ID + || ent->device == HFCE1_ID) + printk( KERN_ERR "unknown HFC multiport controller (vendor:%x device:%x subvendor:%x subdevice:%x) Please contact the driver maintainer for support.\n", + ent->vendor,ent->device,ent->subvendor,ent->subdevice); + return (-ENODEV); + } + + hfc_type=id_list[id_idx].type; + find_type_entry(hfc_type, &HFC_idx, &port_idx); + if(HFC_idx == -1) { + printk( KERN_ERR "HFC-MULTI: Card '%s' found, but not given by module's options, ignoring...\n", + id_list[id_idx].card_name); + return (-ENODEV); + } + + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Registering chip type %d (0x%x)\n", + __FUNCTION__, type[HFC_idx] & 0xff, type[HFC_idx]); + + /* check card type */ + switch (type[HFC_idx] & 0xff) { + case 1: + bchperport = 30; + break; + + case 4: + bchperport = 2; + break; + + case 8: + bchperport = 2; + break; + + default: + printk(KERN_ERR "Card type(%d) not supported.\n", type[HFC_idx] & 0xff); + ret_err = -EINVAL; + goto free_object; + } + + + /* allocate card+fifo structure */ +//#warning +//void *davor=kmalloc(8, GFP_ATOMIC); + if (!(hc = kmalloc(sizeof(hfc_multi_t), GFP_ATOMIC))) { + printk(KERN_ERR "No kmem for HFC-Multi card\n"); + ret_err = -ENOMEM; + goto free_object; + } +//void *danach=kmalloc(8, GFP_ATOMIC); + memset(hc, 0, sizeof(hfc_multi_t)); +//hc->davor=davor; +//hc->danach=danach; + hc->idx = HFC_idx; + hc->id = HFC_idx + 1; + hc->pcm = pcm[HFC_idx]; + + /* set chip specific features */ + hc->masterclk = -1; + hc->type = type[HFC_idx] & 0xff; + if (type[HFC_idx] & 0x100) { + test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); + silence = 0xff; /* ulaw silence */ + } else + silence = 0x2a; /* alaw silence */ + if (type[HFC_idx] & 0x200) + test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); +// if ((type[HFC_idx]&0x400) && hc->type==4) +// test_and_set_bit(HFC_CHIP_LEDS, &hc->chip); + if (type[HFC_idx] & 0x800) + test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); + if (type[HFC_idx] & 0x1000) + test_and_set_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip); + if (type[HFC_idx] & 0x2000) + test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); + if (type[HFC_idx] & 0x4000) + test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); + if (type[HFC_idx] & 0x8000) + test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); + hc->slots = 32; + if (type[HFC_idx] & 0x10000) + hc->slots = 64; + if (type[HFC_idx] & 0x20000) + hc->slots = 128; + if (type[HFC_idx] & 0x40000) + test_and_set_bit(HFC_CHIP_CRYSTAL_CLOCK, &hc->chip); + if (hc->type == 1) + sprintf(hc->name, "HFC-E1#%d", HFC_idx+1); + else + sprintf(hc->name, "HFC-%dS#%d", hc->type, HFC_idx+1); + + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__); + + spin_lock_irqsave(&HFCM_obj.lock, flags); + list_add_tail(&hc->list, &HFCM_obj.ilist); + spin_unlock_irqrestore(&HFCM_obj.lock, flags); + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__); + + spin_lock_init(&hc->lock); + + pt = 0; + while (pt < hc->type) { + if (port_idx >= MAX_PORTS) { + printk(KERN_ERR "Invalid HFC type.\n"); + ret_err = -EINVAL; + goto free_channels; + } + if (protocol[port_idx] == 0) { + printk(KERN_ERR "Not enough 'protocol' values given.\n"); + ret_err = -EINVAL; + goto free_channels; + } + if (hc->type == 1) + ch = 16; + else + ch = (pt<<2)+2; + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Registering D-channel, card(%d) ch(%d) port(%d) protocol(%x)\n", __FUNCTION__, HFC_idx+1, ch, pt+1, protocol[port_idx]); + hc->chan[ch].port = pt; + hc->chan[ch].nt_timer = -1; + chan = kmalloc(sizeof(channel_t), GFP_ATOMIC); + if (!chan) { + ret_err = -ENOMEM; + goto free_channels; + } + memset(chan, 0, sizeof(channel_t)); + chan->channel = ch; + //chan->debug = debug; + chan->inst.obj = &HFCM_obj; + chan->inst.hwlock = &hc->lock; + chan->inst.class_dev.dev = &pdev->dev; + mISDN_init_instance(&chan->inst, &HFCM_obj, hc, hfcmulti_l2l1); + chan->inst.pid.layermask = ISDN_LAYER(0); + sprintf(chan->inst.name, "HFCm%d/%d", HFC_idx+1, pt+1); + ret_err = mISDN_initchannel(chan, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1); + if (ret_err) + goto free_channels; + hc->chan[ch].ch = chan; + + i=0; + while(i < bchperport) { + if (hc->type == 1) + ch2 = i + 1 + (i>=15); + else + ch2 = (pt<<2)+i; + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Registering B-channel, card(%d) ch(%d) port(%d) channel(%d)\n", __FUNCTION__, HFC_idx+1, ch2, pt+1, i); + hc->chan[ch2].port = pt; + chan = kmalloc(sizeof(channel_t), GFP_ATOMIC); + if (!chan) { + ret_err = -ENOMEM; + goto free_channels; + } + memset(chan, 0, sizeof(channel_t)); + chan->channel = ch2; + mISDN_init_instance(&chan->inst, &HFCM_obj, hc, hfcmulti_l2l1); + chan->inst.pid.layermask = ISDN_LAYER(0); + chan->inst.hwlock = &hc->lock; + chan->inst.class_dev.dev = &pdev->dev; + //bch->debug = debug; + sprintf(chan->inst.name, "%s B%d", + hc->chan[ch].ch->inst.name, i+1); + ret_err = mISDN_initchannel(chan, MSK_INIT_BCHANNEL, MAX_DATA_MEM); + if (ret_err) { + kfree(chan); + goto free_channels; + } + hc->chan[ch2].ch = chan; +#ifdef FIXME // TODO + if (chan->dev) { + chan->dev->wport.pif.func = hfcmulti_l2l1; + chan->dev->wport.pif.fdata = chan; + } +#endif + i++; + } + chan = hc->chan[ch].ch; + + /* set D-channel */ + mISDN_set_dchannel_pid(&pid, protocol[port_idx], layermask[port_idx]); + + /* set PRI */ + if (hc->type == 1) { + if (layermask[port_idx] & ISDN_LAYER(2)) { + pid.protocol[2] |= ISDN_PID_L2_DF_PTP; + } + if (layermask[port_idx] & ISDN_LAYER(3)) { + pid.protocol[3] |= ISDN_PID_L3_DF_PTP; + pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID; + pid.protocol[3] |= ISDN_PID_L3_DF_CRLEN2; + } + } + + /* set protocol type */ + if (protocol[port_idx] & 0x10) { + /* NT-mode */ + chan->inst.pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_NT_E1:ISDN_PID_L0_NT_S0; + chan->inst.pid.protocol[1] = (hc->type==1)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0; + pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_NT_E1:ISDN_PID_L0_NT_S0; + pid.protocol[1] = (hc->type==1)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0; + chan->inst.pid.layermask |= ISDN_LAYER(1); + pid.layermask |= ISDN_LAYER(1); + if (layermask[port_idx] & ISDN_LAYER(2)) + pid.protocol[2] = ISDN_PID_L2_LAPD_NET; + test_and_set_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg); + } else { + /* TE-mode */ + chan->inst.pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_TE_E1:ISDN_PID_L0_TE_S0; + pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_TE_E1:ISDN_PID_L0_TE_S0; + if (hc->type == 1) { + /* own E1 for E1 */ + chan->inst.pid.protocol[1] = ISDN_PID_L1_TE_E1; + pid.protocol[1] = ISDN_PID_L1_TE_E1; + chan->inst.pid.layermask |= ISDN_LAYER(1); + pid.layermask |= ISDN_LAYER(1); + } + } + + + if (hc->type != 1) { + /* S/T */ + /* set master clock */ + if (protocol[port_idx] & 0x10000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set master clock: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) { + printk(KERN_ERR "Error: Master clock for port(%d) of card(%d) is only possible with TE-mode\n", pt+1, HFC_idx+1); + ret_err = -EINVAL; + goto free_channels; + } + if (hc->masterclk >= 0) { + printk(KERN_ERR "Error: Master clock for port(%d) of card(%d) already defined for port(%d)\n", pt+1, HFC_idx+1, hc->masterclk+1); + ret_err = -EINVAL; + goto free_channels; + } + hc->masterclk = pt; + } + + /* set transmitter line to non capacitive */ + if (protocol[port_idx] & 0x20000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set non capacitive transmitter: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_NONCAP_TX, &hc->chan[ch].cfg); + } + + /* disable E-channel */ + if (protocol[port_idx] & 0x40000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL disable E-channel: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[ch].cfg); + } + /* register E-channel */ + if (protocol[port_idx] & 0x80000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL register E-channel: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_REG_ECHANNEL, &hc->chan[ch].cfg); + } + } else { + /* E1 */ + /* set optical line type */ + if (protocol[port_idx] & 0x10000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set optical interfacs: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_OPTICAL, &hc->chan[ch].cfg); + } + + /* set LOS report */ + if (protocol[port_idx] & 0x40000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set LOS report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_REPORT_LOS, &hc->chan[ch].cfg); + } + + /* set AIS report */ + if (protocol[port_idx] & 0x80000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set AIS report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_REPORT_AIS, &hc->chan[ch].cfg); + } + + /* set SLIP report */ + if (protocol[port_idx] & 0x100000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set SLIP report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_REPORT_SLIP, &hc->chan[ch].cfg); + } + + /* set elastic jitter buffer */ + if (protocol[port_idx] & 0x600000) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL set elastic buffer to %d: card(%d) port(%d)\n", __FUNCTION__, hc->chan[ch].jitter, HFC_idx+1, pt); + hc->chan[ch].jitter = (protocol[port_idx]>>21) & 0x3; + } else + hc->chan[ch].jitter = 2; /* default */ + + + /* set CRC-4 Mode */ + if (! (protocol[port_idx] & 0x800000)) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: PROTOCOL turn on CRC4 report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + test_and_set_bit(HFC_CFG_CRC4, &hc->chan[ch].cfg); + + printk(KERN_DEBUG "%s: PROTOCOL turn on CRC4 report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + } else { + printk(KERN_DEBUG "%s: PROTOCOL turn off CRC4 report: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt); + } + + } + + memcpy(&pids[pt], &pid, sizeof(pid)); + + pt++; + port_idx++; + } + + /* run card setup */ + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Setting up card(%d)\n", __FUNCTION__, HFC_idx+1); + if ((ret_err = setup_pci(hc,pdev,id_idx))) { + goto free_channels; + } + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Initializing card(%d)\n", __FUNCTION__, HFC_idx+1); + if ((ret_err = init_card(hc))) { + if (debug & DEBUG_HFCMULTI_INIT) { + printk(KERN_DEBUG "%s: do release_io_hfcmulti\n", __FUNCTION__); + release_io_hfcmulti(hc); + } + goto free_channels; + } + + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Init modes card(%d)\n", __FUNCTION__, HFC_idx+1); + hfcmulti_initmode(hc); + + /* add stacks */ + pt = 0; + while(pt < hc->type) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Adding d-stack: card(%d) port(%d)\n", __FUNCTION__, HFC_idx+1, pt+1); + if (hc->type == 1) + chan = hc->chan[16].ch; + else + chan = hc->chan[(pt<<2)+2].ch; + if ((ret_err = HFCM_obj.ctrl(NULL, MGR_NEWSTACK | REQUEST, &chan->inst))) { + printk(KERN_ERR "MGR_ADDSTACK REQUEST dch err(%d)\n", ret_err); +free_release: + release_port(hc, -1); /* all ports, hc is free */ + goto free_object; + } + /* indicate that this stack is created */ + hc->created[pt] = 1; + + dst = chan->inst.st; + + i = 0; + while(i < bchperport) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: Adding b-stack: card(%d) port(%d) B-channel(%d)\n", __FUNCTION__, HFC_idx+1, pt+1, i+1); + if (hc->type == 1) + chan = hc->chan[i + 1 + (i>=15)].ch; + else + chan = hc->chan[(pt<<2) + i].ch; + if ((ret_err = HFCM_obj.ctrl(dst, MGR_NEWSTACK | REQUEST, &chan->inst))) { + printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", ret_err); +free_delstack: + HFCM_obj.ctrl(dst, MGR_DELSTACK | REQUEST, NULL); + goto free_release; + } + i++; + } + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: (before MGR_SETSTACK REQUEST) layermask=0x%x\n", __FUNCTION__, pids[pt].layermask); + + if ((ret_err = HFCM_obj.ctrl(dst, MGR_SETSTACK | REQUEST, &pids[pt]))) { + printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", ret_err); + goto free_delstack; + } + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: (after MGR_SETSTACK REQUEST)\n", __FUNCTION__); + + /* delay some time */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((100*HZ)/1000); /* Timeout 100ms */ + + /* tell stack, that we are ready */ + HFCM_obj.ctrl(dst, MGR_CTRLREADY | INDICATION, NULL); + + pt++; + } + + /* now turning on irq */ + spin_lock_irqsave(&hc->lock, flags); + enable_hwirq(hc); + /* we are on air! */ + allocated[HFC_idx] = 1; + HFC_cnt++; + spin_unlock_irqrestore(&hc->lock, flags); + return(0); + + /* if an error ocurred */ + free_channels: + i = 0; + while(i < 32) { + if (hc->chan[i].ch) { + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: free %c-channel %d (1..32)\n", + __FUNCTION__, test_bit(FLG_DCHANNEL, &hc->chan[i].ch->Flags) ? + 'D' : 'B', i); + mISDN_freechannel(hc->chan[i].ch); + kfree(hc->chan[i].ch); + hc->chan[i].ch = NULL; + } + i++; + } + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: before REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); + spin_lock_irqsave(&HFCM_obj.lock, flags); + list_del(&hc->list); + spin_unlock_irqrestore(&HFCM_obj.lock, flags); + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: after REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); + kfree(hc); + + free_object: + return(ret_err); +} + +static void __devexit hfc_remove_pci(struct pci_dev *pdev) +{ + int i,ch; + hfc_multi_t *card = pci_get_drvdata(pdev); + + printk( KERN_INFO "removing hfc_multi card vendor:%x device:%x subvendor:%x subdevice:%x\n", + pdev->vendor,pdev->device,pdev->subsystem_vendor,pdev->subsystem_device); + if (card) { + for(i=0;itype;i++) { // type is also number of d-channel + if(card->created[i]) { + if (card->type == 1) + ch = 16; + else + ch = (i*4)+2; + // if created elete stack + if (card->chan[ch].ch && + test_bit(FLG_DCHANNEL, &card->chan[ch].ch->Flags)) + HFCM_obj.ctrl(card->chan[ch].ch->inst.st, + MGR_DELSTACK | REQUEST, NULL); + } + } + // relase all ports + allocated[card->idx] = 0; + release_port(card, -1); // card is free ... */ + printk(KERN_DEBUG "test\n"); + } + else printk(KERN_WARNING "%s: drvdata allready removed\n", __FUNCTION__); +} + +static struct pci_device_id hfmultipci_ids[] __devinitdata = { + { CCAG_VID, 0x08B4 , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { CCAG_VID, 0x16B8 , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { CCAG_VID, 0x30B1 , PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0x10B5, 0x9030 , CCAG_VID, 0x3136 , 0, 0, 0 }, // PLX PCI Bridge + { 0x10B5, 0x9030 , PCI_ANY_ID, PCI_ANY_ID , 0, 0, 0 }, // PLX PCI Bridge + {0, } +}; +MODULE_DEVICE_TABLE(pci, hfmultipci_ids); + +static struct pci_driver hfcmultipci_driver = { + name: "hfc_multi", + probe: hfcpci_probe, + remove: __devexit_p(hfc_remove_pci), + id_table: hfmultipci_ids, +}; + +static void __exit +HFCmulti_cleanup(void) +{ + hfc_multi_t *hc,*next; + int err; + + /* unregister mISDN object */ + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: entered (refcnt = %d HFC_cnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt, HFC_cnt); + if ((err = mISDN_unregister(&HFCM_obj))) { + printk(KERN_ERR "Can't unregister HFC-Multi cards error(%d)\n", err); + } + + /* remove remaining devices, but this should never happen */ + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: now checking ilist (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); + + list_for_each_entry_safe(hc, next, &HFCM_obj.ilist, list) { + printk(KERN_ERR "HFC PCI card struct not empty refs %d\n", HFCM_obj.refcnt); + release_port(hc, -1); /* all ports, hc is free */ + } + if (debug & DEBUG_HFCMULTI_INIT) + printk(KERN_DEBUG "%s: done (refcnt = %d HFC_cnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt, HFC_cnt); + + /* get rid of all devices of this driver */ + pci_unregister_driver(&hfcmultipci_driver); + +} static int __init HFCmulti_init(void) { - int err, err2, i; - hfc_multi_t *hc,*next; - mISDN_pid_t pid, pids[MAX_CARDS]; - mISDNstack_t *dst = NULL; /* make gcc happy */ - int port_cnt; - int bchperport, pt; - int ch, ch2; - dchannel_t *dch; - bchannel_t *bch; - char tmp[64]; + int err, i; + char tmpstr[64]; +#if !defined(CONFIG_HOTPLUG) || !defined(MODULE) +#error "CONFIG_HOTPLUG and MODULE are not defined." +#endif if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: init entered\n", __FUNCTION__); #ifdef __BIG_ENDIAN #error "not running on big endian machines now" #endif - strcpy(tmp, hfcmulti_revision); - printk(KERN_INFO "mISDN: HFC-multi driver Rev. %s\n", mISDN_getrev(tmp)); + strcpy(tmpstr, hfcmulti_revision); + printk(KERN_INFO "mISDN: HFC-multi driver Rev. %s\n", mISDN_getrev(tmpstr)); switch(poll) { + case 0: + poll_timer = 6; + poll = 128; + break; /* wenn dieses break nochmal verschwindet, gibt es heisse ohren :-) */ case 8: poll_timer = 2; break; @@ -3254,9 +3742,8 @@ HFCmulti_init(void) case 64: poll_timer = 5; break; - case 128: case 0: + case 128: poll_timer = 6; - poll = 128; break; case 256: poll_timer = 7; @@ -3265,13 +3752,14 @@ HFCmulti_init(void) printk(KERN_ERR "%s: Wrong poll value (%d).\n", __FUNCTION__, poll); err = -EINVAL; return(err); - + } memset(&HFCM_obj, 0, sizeof(HFCM_obj)); #ifdef MODULE HFCM_obj.owner = THIS_MODULE; #endif + spin_lock_init(&HFCM_obj.lock); INIT_LIST_HEAD(&HFCM_obj.ilist); HFCM_obj.name = HFCName; HFCM_obj.own_ctrl = HFC_manager; @@ -3291,454 +3779,23 @@ HFCmulti_init(void) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: new mISDN object (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - /* Note: ALL ports are one "card" object */ + for(i=0;i 0) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Registering chip type %d (0x%x)\n", __FUNCTION__, type[HFC_cnt] & 0xff, type[HFC_cnt]); - - /* check card type */ - switch (type[HFC_cnt] & 0xff) { - case 1: - bchperport = 30; - break; - - case 4: - bchperport = 2; - break; - - case 8: - bchperport = 2; - break; - - default: - printk(KERN_ERR "Card type(%d) not supported.\n", type[HFC_cnt] & 0xff); - err = -EINVAL; - goto free_object; - } - - - /* allocate card+fifo structure */ - if (!(hc = kmalloc(sizeof(hfc_multi_t), GFP_ATOMIC))) { - printk(KERN_ERR "No kmem for HFC-Multi card\n"); - err = -ENOMEM; - goto free_object; - } - memset(hc, 0, sizeof(hfc_multi_t)); - hc->id = HFC_cnt + 1; - hc->pcm = pcm[HFC_cnt]; - - /* set chip specific features */ - hc->masterclk = -1; - hc->type = type[HFC_cnt] & 0xff; - if (type[HFC_cnt] & 0x100) { - test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); - silence = 0xff; /* ulaw silence */ - } else - silence = 0x2a; /* alaw silence */ - if (type[HFC_cnt] & 0x200) - test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); -// if ((type[HFC_cnt]&0x400) && hc->type==4) -// test_and_set_bit(HFC_CHIP_LEDS, &hc->chip); - if (type[HFC_cnt] & 0x800) - test_and_set_bit(HFC_CHIP_PCM_SLAVE, &hc->chip); - if (type[HFC_cnt] & 0x1000) - test_and_set_bit(HFC_CHIP_CLOCK_IGNORE, &hc->chip); - if (type[HFC_cnt] & 0x2000) - test_and_set_bit(HFC_CHIP_RX_SYNC, &hc->chip); - if (type[HFC_cnt] & 0x4000) - test_and_set_bit(HFC_CHIP_EXRAM_128, &hc->chip); - if (type[HFC_cnt] & 0x8000) - test_and_set_bit(HFC_CHIP_EXRAM_512, &hc->chip); - hc->slots = 32; - if (type[HFC_cnt] & 0x10000) - hc->slots = 64; - if (type[HFC_cnt] & 0x20000) - hc->slots = 128; - if (hc->type == 1) - sprintf(hc->name, "HFC-E1#%d", HFC_cnt+1); - else - sprintf(hc->name, "HFC-%dS#%d", hc->type, HFC_cnt+1); - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__); - list_add_tail(&hc->list, &HFCM_obj.ilist); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: (after APPEND_TO_LIST)\n", __FUNCTION__); - - lock_HW_init(&hc->lock); - - pt = 0; - while (pt < hc->type) { - if (protocol[port_cnt] == 0) { - printk(KERN_ERR "Not enough 'protocol' values given.\n"); - err = -EINVAL; - goto free_channels; - } - if (hc->type == 1) - ch = 16; - else - ch = (pt<<2)+2; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Registering D-channel, card(%d) ch(%d) port(%d) protocol(%x)\n", __FUNCTION__, HFC_cnt+1, ch, pt+1, protocol[port_cnt]); - hc->chan[ch].port = pt; - hc->chan[ch].nt_timer = -1; - dch = kmalloc(sizeof(dchannel_t), GFP_ATOMIC); - if (!dch) { - err = -ENOMEM; - goto free_channels; - } - memset(dch, 0, sizeof(dchannel_t)); - dch->channel = ch; - //dch->debug = debug; - dch->inst.obj = &HFCM_obj; - dch->inst.lock = lock_dev; - dch->inst.unlock = unlock_dev; - mISDN_init_instance(&dch->inst, &HFCM_obj, hc); - dch->inst.pid.layermask = ISDN_LAYER(0); - sprintf(dch->inst.name, "HFCm%d/%d", HFC_cnt+1, pt+1); - if (!(hc->chan[ch].rx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { - err = -ENOMEM; - goto free_channels; - } - if (mISDN_init_dch(dch)) { - err = -ENOMEM; - goto free_channels; - } - hc->chan[ch].dch = dch; - - i=0; - while(i < bchperport) { - if (hc->type == 1) - ch2 = i + 1 + (i>=15); - else - ch2 = (pt<<2)+i; - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Registering B-channel, card(%d) ch(%d) port(%d) channel(%d)\n", __FUNCTION__, HFC_cnt+1, ch2, pt+1, i); - hc->chan[ch2].port = pt; - bch = kmalloc(sizeof(bchannel_t), GFP_ATOMIC); - if (!bch) { - err = -ENOMEM; - goto free_channels; - } - memset(bch, 0, sizeof(bchannel_t)); - bch->channel = ch2; - mISDN_init_instance(&bch->inst, &HFCM_obj, hc); - bch->inst.pid.layermask = ISDN_LAYER(0); - bch->inst.lock = lock_dev; - bch->inst.unlock = unlock_dev; - //bch->debug = debug; - sprintf(bch->inst.name, "%s B%d", - dch->inst.name, i+1); - if (mISDN_init_bch(bch)) { - kfree(bch); - err = -ENOMEM; - goto free_channels; - } - skb_queue_head_init(&hc->chan[ch2].dtmfque); - hc->chan[ch2].bch = bch; - if (bch->dev) { - bch->dev->wport.pif.func = - hfcmulti_l2l1; - bch->dev->wport.pif.fdata = - bch; - } - i++; - } - - /* set D-channel */ - mISDN_set_dchannel_pid(&pid, protocol[port_cnt], layermask[port_cnt]); - - /* set PRI */ - if (hc->type == 1) { - if (layermask[port_cnt] & ISDN_LAYER(2)) { - pid.protocol[2] |= ISDN_PID_L2_DF_PTP; - } - if (layermask[port_cnt] & ISDN_LAYER(3)) { - pid.protocol[3] |= ISDN_PID_L3_DF_PTP; - pid.protocol[3] |= ISDN_PID_L3_DF_EXTCID; - pid.protocol[3] |= ISDN_PID_L3_DF_CRLEN2; - } - } - - /* set protocol type */ - if (protocol[port_cnt] & 0x10) { - /* NT-mode */ - dch->inst.pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_NT_E1:ISDN_PID_L0_NT_S0; - dch->inst.pid.protocol[1] = (hc->type==1)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0; - pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_NT_E1:ISDN_PID_L0_NT_S0; - pid.protocol[1] = (hc->type==1)?ISDN_PID_L1_NT_E1:ISDN_PID_L1_NT_S0; - dch->inst.pid.layermask |= ISDN_LAYER(1); - pid.layermask |= ISDN_LAYER(1); - if (layermask[port_cnt] & ISDN_LAYER(2)) - pid.protocol[2] = ISDN_PID_L2_LAPD_NET; - test_and_set_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg); - } else { - /* TE-mode */ - dch->inst.pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_TE_E1:ISDN_PID_L0_TE_S0; - pid.protocol[0] = (hc->type==1)?ISDN_PID_L0_TE_E1:ISDN_PID_L0_TE_S0; - if (hc->type == 1) { - /* own E1 for E1 */ - dch->inst.pid.protocol[1] = ISDN_PID_L1_TE_E1; - pid.protocol[1] = ISDN_PID_L1_TE_E1; - dch->inst.pid.layermask |= ISDN_LAYER(1); - pid.layermask |= ISDN_LAYER(1); - } - } - - - if (hc->type != 1) { - /* S/T */ - /* set master clock */ - if (protocol[port_cnt] & 0x10000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set master clock: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - if (test_bit(HFC_CFG_NTMODE, &hc->chan[ch].cfg)) { - printk(KERN_ERR "Error: Master clock for port(%d) of card(%d) is only possible with TE-mode\n", pt+1, HFC_cnt+1); - err = -EINVAL; - goto free_channels; - } - if (hc->masterclk >= 0) { - printk(KERN_ERR "Error: Master clock for port(%d) of card(%d) already defined for port(%d)\n", pt+1, HFC_cnt+1, hc->masterclk+1); - err = -EINVAL; - goto free_channels; - } - hc->masterclk = pt; - } - - /* set transmitter line to non capacitive */ - if (protocol[port_cnt] & 0x20000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set non capacitive transmitter: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_NONCAP_TX, &hc->chan[ch].cfg); - } - - /* disable E-channel */ - if (protocol[port_cnt] & 0x40000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL disable E-channel: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[ch].cfg); - } - /* register E-channel */ - if (protocol[port_cnt] & 0x80000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL register E-channel: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_REG_ECHANNEL, &hc->chan[ch].cfg); - } - } else { - /* E1 */ - /* set optical line type */ - if (protocol[port_cnt] & 0x10000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set optical interfacs: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_OPTICAL, &hc->chan[ch].cfg); - } - - /* set LOS report */ - if (protocol[port_cnt] & 0x40000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set LOS report: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_REPORT_LOS, &hc->chan[ch].cfg); - } - - /* set AIS report */ - if (protocol[port_cnt] & 0x80000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set AIS report: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_REPORT_AIS, &hc->chan[ch].cfg); - } - - /* set SLIP report */ - if (protocol[port_cnt] & 0x100000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set SLIP report: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt); - test_and_set_bit(HFC_CFG_REPORT_SLIP, &hc->chan[ch].cfg); - } - - /* set elastic jitter buffer */ - if (protocol[port_cnt] & 0x600000) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: PROTOCOL set elastic buffer to %d: card(%d) port(%d)\n", __FUNCTION__, hc->chan[ch].jitter, HFC_cnt+1, pt); - hc->chan[ch].jitter = (protocol[port_cnt]>>21) & 0x3; - } else - hc->chan[ch].jitter = 2; /* default */ - } - - memcpy(&pids[pt], &pid, sizeof(pid)); - - pt++; - port_cnt++; - } - - /* run card setup */ - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Setting up card(%d)\n", __FUNCTION__, HFC_cnt+1); - if ((err = setup_pci(hc))) { - goto free_channels; - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Initializing card(%d)\n", __FUNCTION__, HFC_cnt+1); - if ((err = init_card(hc))) { - if (debug & DEBUG_HFCMULTI_INIT) { - printk(KERN_DEBUG "%s: do release_io_hfcmulti\n", __FUNCTION__); - release_io_hfcmulti(hc); - } - goto free_channels; - } - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Init modes card(%d)\n", __FUNCTION__, HFC_cnt+1); - hfcmulti_initmode(hc); - - /* add stacks */ - pt = 0; - while(pt < hc->type) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Adding d-stack: card(%d) port(%d)\n", __FUNCTION__, HFC_cnt+1, pt+1); - if (hc->type == 1) - dch = hc->chan[16].dch; - else - dch = hc->chan[(pt<<2)+2].dch; - if ((err = HFCM_obj.ctrl(NULL, MGR_NEWSTACK | REQUEST, &dch->inst))) { - printk(KERN_ERR "MGR_ADDSTACK REQUEST dch err(%d)\n", err); - free_release: - release_port(hc, -1); /* all ports */ - goto free_object; - } - /* indicate that this stack is created */ - hc->created[pt] = 1; - - dst = dch->inst.st; - - i = 0; - while(i < bchperport) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: Adding b-stack: card(%d) port(%d) B-channel(%d)\n", __FUNCTION__, HFC_cnt+1, pt+1, i+1); - if (hc->type == 1) - bch = hc->chan[i + 1 + (i>=15)].bch; - else - bch = hc->chan[(pt<<2) + i].bch; - if ((err = HFCM_obj.ctrl(dst, MGR_NEWSTACK | REQUEST, &bch->inst))) { - printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err); - free_delstack: - HFCM_obj.ctrl(dst, MGR_DELSTACK | REQUEST, NULL); - goto free_release; - } - bch->st = bch->inst.st; - i++; - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: (before MGR_SETSTACK REQUEST) layermask=0x%x\n", __FUNCTION__, pids[pt].layermask); - - if ((err = HFCM_obj.ctrl(dst, MGR_SETSTACK | REQUEST, &pids[pt]))) { - printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err); - goto free_delstack; - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: (after MGR_SETSTACK REQUEST)\n", __FUNCTION__); - - /* delay some time */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((100*HZ)/1000); /* Timeout 100ms */ - - /* tell stack, that we are ready */ - HFCM_obj.ctrl(dst, MGR_CTRLREADY | INDICATION, NULL); - - pt++; - } - - /* now turning on irq */ - HFC_outb(hc, R_IRQ_CTRL, hc->hw.r_irq_ctrl); - - HFC_cnt++; + err = pci_register_driver(&hfcmultipci_driver); + if (err < 0) + { + printk(KERN_ERR "error registering pci driver:%x\n",err); + HFCmulti_cleanup(); + return(err); } + printk(KERN_INFO "%d devices registered\n", HFC_cnt); - if (HFC_cnt == 0) { - printk(KERN_INFO "hfc_multi: No cards defined, read the documentation.\n"); - err = -EINVAL; - goto free_object; - } - - printk(KERN_INFO "hfc_multi driver: %d cards with total of %d ports installed.\n", HFC_cnt, port_cnt); return(0); - - /* DONE */ - - /* if an error ocurred */ - free_channels: - i = 0; - while(i < 32) { - if (hc->chan[i].dch) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free D-channel %d (1..32)\n", __FUNCTION__, i); - mISDN_free_dch(hc->chan[i].dch); - kfree(hc->chan[i].dch); - hc->chan[i].dch = NULL; - } - if (hc->chan[i].rx_buf) { - kfree(hc->chan[i].rx_buf); - hc->chan[i].rx_buf = NULL; - } - if (hc->chan[i].bch) { - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: free B-channel %d (1..32)\n", __FUNCTION__, i); - discard_queue(&hc->chan[i].dtmfque); - mISDN_free_bch(hc->chan[i].bch); - kfree(hc->chan[i].bch); - hc->chan[i].bch = NULL; - } - i++; - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: before REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - list_del(&hc->list); - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: after REMOVE_FROM_LIST (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - kfree(hc); - - free_object: - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: brefore mISDN_unregister (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - if ((err2 = mISDN_unregister(&HFCM_obj))) { - printk(KERN_ERR "Can't unregister HFC-Multi cards error(%d)\n", err); - } - list_for_each_entry_safe(hc, next, &HFCM_obj.ilist, list) { - printk(KERN_ERR "HFC PCI card struct not empty refs %d\n", HFCM_obj.refcnt); - release_port(hc, -1); /* all ports */ - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: after mISDN_unregister (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: exitting with error %d\n", __FUNCTION__, err); - return(err); } #ifdef MODULE -static void __exit -HFCmulti_cleanup(void) -{ - hfc_multi_t *hc,*next; - int err; - - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: entered (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - if ((err = mISDN_unregister(&HFCM_obj))) { - printk(KERN_ERR "Can't unregister HFC-Multi cards error(%d)\n", err); - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: now checking ilist (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - - list_for_each_entry_safe(hc, next, &HFCM_obj.ilist, list) { - printk(KERN_ERR "HFC PCI card struct not empty refs %d\n", HFCM_obj.refcnt); - release_port(hc, -1); /* all ports */ - } - if (debug & DEBUG_HFCMULTI_INIT) - printk(KERN_DEBUG "%s: done (refcnt = %d)\n", __FUNCTION__, HFCM_obj.refcnt); - return; -} module_init(HFCmulti_init); module_exit(HFCmulti_cleanup); #endif diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index d72e763..9a254fa 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -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) diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.c b/drivers/isdn/hardware/mISDN/hfc_pci.c index 58e76cd..6c04588 100644 --- a/drivers/isdn/hardware/mISDN/hfc_pci.c +++ b/drivers/isdn/hardware/mISDN/hfc_pci.c @@ -30,18 +30,12 @@ #include #include -#include "dchannel.h" -#include "bchannel.h" +#include "channel.h" #include "hfc_pci.h" #include "layer1.h" -#include "helper.h" #include "debug.h" #include -#define SPIN_DEBUG -#define LOCK_STATISTIC -#include "hw_lock.h" - #define HFC_INFO(txt) printk(KERN_DEBUG txt) extern const char *CardType[]; @@ -100,6 +94,15 @@ typedef struct { #define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069 #endif +/* new device IDs, obsolete when include/linux/pci_ids.h will be updated */ +#ifndef PCI_DEVICE_ID_CCD_B700 +#define PCI_DEVICE_ID_CCD_B700 0xb700 +#endif +#ifndef PCI_DEVICE_ID_CCD_B701 +#define PCI_DEVICE_ID_CCD_B701 0xb701 +#endif + + static const PCI_ENTRY id_list[] = { {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"}, @@ -112,6 +115,8 @@ static const PCI_ENTRY id_list[] = {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"}, {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"}, {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, "Primux II S0", "B700"}, + {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, "Primux II S0 NT", "B701"}, {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"}, {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"}, {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"}, @@ -171,27 +176,25 @@ typedef struct _hfc_pci { u_int irq; u_int irqcnt; hfcPCI_hw_t hw; - mISDN_HWlock_t lock; - dchannel_t dch; - bchannel_t bch[2]; + spinlock_t lock; + channel_t dch; + channel_t bch[2]; } hfc_pci_t; - -static int lock_dev(void *data, int nowait) +/* Interface functions */ +static void +enable_hwirq(hfc_pci_t *hc) { - register mISDN_HWlock_t *lock = &((hfc_pci_t *)data)->lock; - - return(lock_HW(lock, nowait)); -} - -static void unlock_dev(void *data) -{ - register mISDN_HWlock_t *lock = &((hfc_pci_t *)data)->lock; - - unlock_HW(lock); + hc->hw.int_m2 |= HFCPCI_IRQ_ENABLE; + Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); } -/* Interface functions */ +static void +disable_hwirq(hfc_pci_t *hc) +{ + hc->hw.int_m2 &= ~((u_char)HFCPCI_IRQ_ENABLE); + Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); +} /******************************************/ /* free hardware resources used by driver */ @@ -199,8 +202,8 @@ static void unlock_dev(void *data) void release_io_hfcpci(hfc_pci_t *hc) { - hc->hw.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); + hc->hw.int_m2 = 0; /* interrupt output off ! */ + disable_hwirq(hc); Write_hfc(hc, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ mdelay(10); /* Timeout 10ms */ hc->hw.cirm = 0; /* Reset Off */ @@ -226,8 +229,7 @@ reset_hfcpci(hfc_pci_t *hc) val = Read_hfc(hc, HFCPCI_CHIP_ID); printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val); pci_write_config_word(hc->hw.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ - hc->hw.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); + disable_hwirq(hc); pci_write_config_word(hc->hw.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ val = Read_hfc(hc, HFCPCI_STATUS); printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val); @@ -335,13 +337,14 @@ hfcpci_Timer(hfc_pci_t *hc) /************************************************/ /* select a b-channel entry matching and active */ /************************************************/ -static -bchannel_t * +static channel_t * Sel_BCS(hfc_pci_t *hc, int channel) { - if (hc->bch[0].protocol && (hc->bch[0].channel & channel)) + if (test_bit(FLG_ACTIVE, &hc->bch[0].Flags) && + (hc->bch[0].channel & channel)) return (&hc->bch[0]); - else if (hc->bch[1].protocol && (hc->bch[1].channel & channel)) + else if (test_bit(FLG_ACTIVE, &hc->bch[1].Flags) && + (hc->bch[1].channel & channel)) return (&hc->bch[1]); else return (NULL); @@ -416,12 +419,10 @@ static void hfcpci_clear_fifo_tx(hfc_pci_t *hc, int fifo) /*********************************************/ /* read a complete B-frame out of the buffer */ /*********************************************/ -static struct sk_buff -* -hfcpci_empty_fifo(bchannel_t *bch, bzfifo_type * bz, u_char * bdata, int count) +static void +hfcpci_empty_fifo(channel_t *bch, bzfifo_type * bz, u_char * bdata, int count) { u_char *ptr, *ptr1, new_f2; - struct sk_buff *skb; int total, maxlen, new_z2; z_type *zp; @@ -441,13 +442,12 @@ hfcpci_empty_fifo(bchannel_t *bch, bzfifo_type * bz, u_char * bdata, int count) #endif bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->f2 = new_f2; /* next buffer */ - skb = NULL; - } else if (!(skb = alloc_stack_skb(count - 3, bch->up_headerlen))) + } else if (!(bch->rx_skb = alloc_stack_skb(count - 3, bch->up_headerlen))) printk(KERN_WARNING "HFCPCI: receive out of memory\n"); else { total = count; count -= 3; - ptr = skb_put(skb, count); + ptr = skb_put(bch->rx_skb, count); if (le16_to_cpu(zp->z2) + count <= B_FIFO_SIZE + B_SUB_VAL) maxlen = count; /* complete transfer */ @@ -465,9 +465,9 @@ hfcpci_empty_fifo(bchannel_t *bch, bzfifo_type * bz, u_char * bdata, int count) } bz->za[new_f2].z2 = cpu_to_le16(new_z2); bz->f2 = new_f2; /* next buffer */ - + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb); + bch->rx_skb = NULL; } - return (skb); } /*******************************/ @@ -477,8 +477,7 @@ static int receive_dmsg(hfc_pci_t *hc) { - struct sk_buff *skb; - dchannel_t *dch = &hc->dch; + channel_t *dch = &hc->dch; int maxlen; int rcnt, total; int count = 5; @@ -511,11 +510,11 @@ receive_dmsg(hfc_pci_t *hc) cs->err_rx++; #endif df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + rcnt) & (D_FIFO_SIZE - 1)); - } else if ((skb = alloc_stack_skb(rcnt - 3, dch->up_headerlen))) { + df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((zp->z2 + rcnt) & (D_FIFO_SIZE - 1)); + } else if ((dch->rx_skb = alloc_stack_skb(rcnt - 3, dch->up_headerlen))) { total = rcnt; rcnt -= 3; - ptr = skb_put(skb, rcnt); + ptr = skb_put(dch->rx_skb, rcnt); if (le16_to_cpu(zp->z2) + rcnt <= D_FIFO_SIZE) maxlen = rcnt; /* complete transfer */ @@ -535,16 +534,16 @@ receive_dmsg(hfc_pci_t *hc) df->za[df->f2 & D_FREG_MASK].z2 = cpu_to_le16((le16_to_cpu(zp->z2) + total) & (D_FIFO_SIZE - 1)); if (dch->debug & L1_DEB_ISAC_FIFO) { - char *t = dch->dlog; + char *t = dch->log; - count = skb->len; - ptr = skb->data; + count = dch->rx_skb->len; + ptr = dch->rx_skb->data; t += sprintf(t, "hfcD_empty_fifo cnt %d", count); mISDN_QuickHex(t, ptr, count); - mISDN_debugprint(&dch->inst, dch->dlog); + mISDN_debugprint(&dch->inst, dch->log); } - skb_queue_tail(&dch->rqueue, skb); - dchannel_sched_event(dch, D_RCVBUFREADY); + mISDN_queueup_newhead(&dch->inst, 0, PH_DATA_IND, MISDN_ID_ANY, dch->rx_skb); + dch->rx_skb = NULL; } else printk(KERN_WARNING "HFC-PCI: D receive out of memory\n"); } @@ -555,11 +554,10 @@ receive_dmsg(hfc_pci_t *hc) /* check for transparent receive data and read max one threshold size if avail */ /*******************************************************************************/ int -hfcpci_empty_fifo_trans(bchannel_t *bch, bzfifo_type * bz, u_char * bdata) +hfcpci_empty_fifo_trans(channel_t *bch, bzfifo_type * bz, u_char * bdata) { unsigned short *z1r, *z2r; int new_z2, fcnt, maxlen; - struct sk_buff *skb; u_char *ptr, *ptr1; z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ @@ -577,10 +575,10 @@ hfcpci_empty_fifo_trans(bchannel_t *bch, bzfifo_type * bz, u_char * bdata) if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - if (!(skb = alloc_stack_skb(fcnt, bch->up_headerlen))) + if (!(bch->rx_skb = alloc_stack_skb(fcnt, bch->up_headerlen))) printk(KERN_WARNING "HFCPCI: receive out of memory\n"); else { - ptr = skb_put(skb, fcnt); + ptr = skb_put(bch->rx_skb, fcnt); if (le16_to_cpu(*z2r) + fcnt <= B_FIFO_SIZE + B_SUB_VAL) maxlen = fcnt; /* complete transfer */ else @@ -595,8 +593,8 @@ hfcpci_empty_fifo_trans(bchannel_t *bch, bzfifo_type * bz, u_char * bdata) ptr1 = bdata; /* start of buffer */ memcpy(ptr, ptr1, fcnt); /* rest */ } - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb); + bch->rx_skb = NULL; } *z2r = cpu_to_le16(new_z2); /* new position */ @@ -607,12 +605,11 @@ hfcpci_empty_fifo_trans(bchannel_t *bch, bzfifo_type * bz, u_char * bdata) /* B-channel main receive routine */ /**********************************/ void -main_rec_hfcpci(bchannel_t *bch) +main_rec_hfcpci(channel_t *bch) { - hfc_pci_t *hc = bch->inst.data; + hfc_pci_t *hc = bch->hw; int rcnt, real_fifo; int receive, count = 5; - struct sk_buff *skb; bzfifo_type *bz; u_char *bdata; z_type *zp; @@ -642,10 +639,7 @@ main_rec_hfcpci(bchannel_t *bch) if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "hfcpci rec ch(%x) z1(%x) z2(%x) cnt(%d)", bch->channel, le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); - if ((skb = hfcpci_empty_fifo(bch, bz, bdata, rcnt))) { - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - } + hfcpci_empty_fifo(bch, bz, bdata, rcnt); rcnt = bz->f1 - bz->f2; if (rcnt < 0) rcnt += MAX_B_FRAMES + 1; @@ -658,7 +652,7 @@ main_rec_hfcpci(bchannel_t *bch) receive = 1; else receive = 0; - } else if (bch->protocol == ISDN_PID_L1_B_64TRANS) + } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) receive = hfcpci_empty_fifo_trans(bch, bz, bdata); else receive = 0; @@ -673,7 +667,7 @@ main_rec_hfcpci(bchannel_t *bch) static void hfcpci_fill_dfifo(hfc_pci_t *hc) { - dchannel_t *dch = &hc->dch; + channel_t *dch = &hc->dch; int fcnt; int count, new_z1, maxlen; dfifo_type *df; @@ -682,7 +676,9 @@ hfcpci_fill_dfifo(hfc_pci_t *hc) if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO)) mISDN_debugprint(&dch->inst, "hfcpci_fill_dfifo"); - count = dch->tx_len - dch->tx_idx; + if (!dch->tx_skb) + return; + count = dch->tx_skb->len - dch->tx_idx; if (count <= 0) return; df = &((fifo_area *) (hc->hw.fifos))->d_chan.d_tx; @@ -717,7 +713,7 @@ hfcpci_fill_dfifo(hfc_pci_t *hc) } new_z1 = (le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1) + count) & (D_FIFO_SIZE - 1); new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); - src = dch->tx_buf + dch->tx_idx; /* source pointer */ + src = dch->tx_skb->data + dch->tx_idx; /* source pointer */ dst = df->data + le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); maxlen = D_FIFO_SIZE - le16_to_cpu(df->za[df->f1 & D_FREG_MASK].z1); /* end fifo */ if (maxlen > count) @@ -734,15 +730,15 @@ hfcpci_fill_dfifo(hfc_pci_t *hc) df->za[df->f1 & D_FREG_MASK].z1 = cpu_to_le16(new_z1); /* new pos actual buffer */ df->f1 = new_f1; /* next frame */ if (dch->debug & L1_DEB_ISAC_FIFO) { - char *t = dch->dlog; + char *t = dch->log; - count = dch->tx_len - dch->tx_idx; - src = dch->tx_buf + dch->tx_idx; + count = dch->tx_skb->len - dch->tx_idx; + src = dch->tx_skb->data + dch->tx_idx; t += sprintf(t, "hfcD_fill_fifo cnt %d", count); mISDN_QuickHex(t, src, count); - mISDN_debugprint(&dch->inst, dch->dlog); + mISDN_debugprint(&dch->inst, dch->log); } - dch->tx_idx = dch->tx_len; + dch->tx_idx = dch->tx_skb->len; return; } @@ -750,9 +746,9 @@ hfcpci_fill_dfifo(hfc_pci_t *hc) /* B-channel send routine */ /**************************/ static void -hfcpci_fill_fifo(bchannel_t *bch) +hfcpci_fill_fifo(channel_t *bch) { - hfc_pci_t *hc = bch->inst.data; + hfc_pci_t *hc = bch->hw; int maxlen, fcnt; int count, new_z1; bzfifo_type *bz; @@ -762,10 +758,9 @@ hfcpci_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_len <= 0) + if ((!bch->tx_skb) || bch->tx_skb->len <= 0) return; - + count = bch->tx_skb->len - bch->tx_idx; if ((bch->channel & 2) && (!hc->hw.bswapped)) { bz = &((fifo_area *) (hc->hw.fifos))->b_chans.txbz_b2; bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b2; @@ -774,7 +769,7 @@ hfcpci_fill_fifo(bchannel_t *bch) bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.txdat_b1; } - if (bch->protocol == ISDN_PID_L1_B_64TRANS) { + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { z1t = &bz->za[MAX_B_FRAMES].z1; z2t = z1t + 1; if (bch->debug & L1_DEB_HSCX) @@ -786,48 +781,52 @@ hfcpci_fill_fifo(bchannel_t *bch) fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */ next_t_frame: if (fcnt < (2 * HFCPCI_BTRANS_THRESHOLD)) { - count = bch->tx_len - bch->tx_idx; - if (count < B_FIFO_SIZE - fcnt) { - /* data is suitable for fifo */ - new_z1 = le16_to_cpu(*z1t) + count; /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - src = bch->tx_buf; /* source pointer */ - dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); /* end of fifo */ - if (bch->debug & L1_DEB_HSCX_FIFO) - mISDN_debugprint(&bch->inst, "hfcpci_FFt fcnt(%d) maxl(%d) nz1(%x) dst(%p)", - fcnt, maxlen, new_z1, dst); - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - fcnt += bch->tx_len; - *z1t = cpu_to_le16(new_z1); /* now send data */ - } else if (bch->debug & L1_DEB_HSCX) - mISDN_debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) frame length %d discarded", - bch->channel, bch->tx_len); - if (test_and_clear_bit(BC_FLG_TX_NEXT, &bch->Flag)) { - if (bch->next_skb) { - bch->tx_idx = 0; - bch->tx_len = bch->next_skb->len; - memcpy(bch->tx_buf, - bch->next_skb->data, - bch->tx_len); - bch_sched_event(bch, B_XMTBUFREADY); - goto next_t_frame; - } else - printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n"); + count = bch->tx_skb->len - bch->tx_idx; + if (count >= B_FIFO_SIZE - fcnt) + count = B_FIFO_SIZE - fcnt -1; + if (count <= 0) + return; + /* data is suitable for fifo */ + new_z1 = le16_to_cpu(*z1t) + count; /* new buffer Position */ + if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z1 -= B_FIFO_SIZE; /* buffer wrap */ + src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ + dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); /* end of fifo */ + if (bch->debug & L1_DEB_HSCX_FIFO) + mISDN_debugprint(&bch->inst, "hfcpci_FFt fcnt(%d) maxl(%d) nz1(%x) dst(%p)", + fcnt, maxlen, new_z1, dst); + fcnt += count; + bch->tx_idx += count; + if (maxlen > count) + maxlen = count; /* limit size */ + memcpy(dst, src, maxlen); /* first copy */ + count -= maxlen; /* remaining bytes */ + if (count) { + dst = bdata; /* start of buffer */ + src += maxlen; /* new position */ + memcpy(dst, src, count); } - bch->tx_len = 0; - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch->tx_idx = bch->tx_len; + *z1t = cpu_to_le16(new_z1); /* now send data */ + if (bch->tx_idx < bch->tx_skb->len) + return; + dev_kfree_skb(bch->tx_skb); + bch->tx_idx = 0; + 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); + goto next_t_frame; + } else { + test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); + printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n"); + } + } + bch->tx_skb = NULL; + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); } return; } @@ -862,7 +861,7 @@ next_t_frame: new_z1 -= B_FIFO_SIZE; /* buffer wrap */ new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); - src = bch->tx_buf + bch->tx_idx; /* source pointer */ + src = bch->tx_skb->data + bch->tx_idx; /* source pointer */ dst = bdata + (le16_to_cpu(bz->za[bz->f1].z1) - B_SUB_VAL); maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(bz->za[bz->f1].z1); /* end fifo */ if (maxlen > count) @@ -877,222 +876,174 @@ next_t_frame: } bz->za[new_f1].z1 = cpu_to_le16(new_z1); /* for next buffer */ bz->f1 = new_f1; /* next frame */ - bch->tx_idx = bch->tx_len; - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - return; -} - - -#if 0 -/**********************************************/ -/* D-channel l1 state call for leased NT-mode */ -/**********************************************/ -static void -dch_nt_l2l1(struct PStack *st, int pr, void *arg) -{ - hfc_pci_t *hc = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(hc, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(hc, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(hc, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (hc->debug) - debugl1(hc, "dch_nt_l2l1 msg %04X unhandled", pr); - break; - } -} - - - -/***********************/ -/* set/reset echo mode */ -/***********************/ -static int -hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic) -{ - int i = *(unsigned int *) ic->parm.num; - - if ((ic->arg == 98) && - (!(hc->hw.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { - hc->hw.clkdel = CLKDEL_NT; /* ST-Bit delay for NT-Mode */ - Write_hfc(hc, HFCPCI_CLKDEL, hc->hw.clkdel); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ - udelay(10); - hc->hw.sctrl |= SCTRL_MODE_NT; - Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); /* set NT-mode */ - udelay(10); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* HFC ST G1 */ - udelay(10); - Write_hfc(hc, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); - cs->dc.hfcpci.ph_state = 1; - hc->hw.nt_mode = 1; - hc->hw.nt_timer = 0; - cs->stlist->l2.l2l1 = dch_nt_l2l1; - debugl1(hc, "NT mode activated"); - return (0); - } - if ((hc->chanlimit > 1) || (hc->hw.bswapped) || - (hc->hw.nt_mode) || (ic->arg != 12)) - return (-EINVAL); - - if (i) { - cs->logecho = 1; - hc->hw.trm |= 0x20; /* enable echo chan */ - hc->hw.int_m1 |= HFCPCI_INTS_B2REC; - hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; - } else { - cs->logecho = 0; - hc->hw.trm &= ~0x20; /* disable echo chan */ - hc->hw.int_m1 &= ~HFCPCI_INTS_B2REC; - hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2RX; - } - hc->hw.sctrl_r &= ~SCTRL_B2_ENA; - hc->hw.sctrl &= ~SCTRL_B2_ENA; - hc->hw.conn |= 0x10; /* B2-IOM -> B2-ST */ - hc->hw.ctmt &= ~2; - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt); - Write_hfc(hc, HFCPCI_SCTRL_R, hc->hw.sctrl_r); - Write_hfc(hc, HFCPCI_SCTRL, hc->hw.sctrl); - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); - Write_hfc(hc, HFCPCI_FIFO_EN, hc->hw.fifo_en); - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - return (0); -} /* hfcpci_auxcmd */ - -/*****************************/ -/* E-channel receive routine */ -/*****************************/ -static void -receive_emsg(hfc_pci_t *hc) -{ - int rcnt; - int receive, count = 5; - bzfifo_type *bz; - u_char *bdata; - z_type *zp; - u_char *ptr, *ptr1, new_f2; - int total, maxlen, new_z2; - u_char e_buffer[256]; - - bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2; - bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b2; - Begin: - count--; - if (bz->f1 != bz->f2) { - if (hc->debug & L1_DEB_ISAC) - debugl1(hc, "hfcpci e_rec f1(%d) f2(%d)", - bz->f1, bz->f2); - zp = &bz->za[bz->f2]; - - rcnt = le16_to_cpu(zp->z1) - le16_to_cpu(zp->z2); - if (rcnt < 0) - rcnt += B_FIFO_SIZE; - rcnt++; - if (hc->debug & L1_DEB_ISAC) - debugl1(hc, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)", - le16_to_cpu(zp->z1), le16_to_cpu(zp->z2), rcnt); - new_z2 = le16_to_cpu(zp->z2) + rcnt; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; - if ((rcnt > 256 + 3) || (count < 4) || - (*(bdata + (le16_to_cpu(zp->z1) - B_SUB_VAL)))) { - if (hc->debug & L1_DEB_WARN) - debugl1(hc, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt); - bz->za[new_f2].z2 = cpu_to_le16(new_z2); - bz->f2 = new_f2; /* next buffer */ + dev_kfree_skb(bch->tx_skb); + bch->tx_idx = 0; + 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); } else { - total = rcnt; - rcnt -= 3; - ptr = e_buffer; - - if (le16_to_cpu(zp->z2) <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = rcnt; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - le16_to_cpu(zp->z2); /* maximum */ - - ptr1 = bdata + (le16_to_cpu(zp->z2) - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - rcnt -= maxlen; - - if (rcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, rcnt); /* rest */ - } - bz->za[new_f2].z2 = cpu_to_le16(new_z2); - bz->f2 = new_f2; /* next buffer */ - if (hc->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += mISDN_QuickHex(ptr, e_buffer, total - 3); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - mISDN_putstatus(hc, NULL, cs->dlog); - } else - mISDN_putstatus(hc, "LogEcho: ", "warning Frame too big (%d)", total - 3); - } + test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n"); } + } else { + bch->tx_skb = NULL; + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + } +} - rcnt = bz->f1 - bz->f2; - if (rcnt < 0) - rcnt += MAX_B_FRAMES + 1; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else - receive = 0; - if (count && receive) - goto Begin; - return; -} /* receive_emsg */ -#endif + +/***************************/ +/* handle L1 state changes */ +/***************************/ + +static void +ph_state_change(channel_t *dch) +{ + hfc_pci_t *hc = dch->inst.privat; + u_int prim = PH_SIGNAL | INDICATION; + u_int para = 0; + + if (!hc->hw.nt_mode) { + if (dch->debug) + printk(KERN_DEBUG "%s: TE newstate %x\n", + __FUNCTION__, dch->state); + switch (dch->state) { + case (0): + prim = PH_CONTROL | INDICATION; + para = HW_RESET; + break; + case (3): + prim = PH_CONTROL | INDICATION; + para = HW_DEACTIVATE; + break; + case (5): + case (8): + para = ANYSIGNAL; + break; + case (6): + para = INFO2; + break; + case (7): + para = INFO4_P8; + break; + default: + return; + } + } else { + if (dch->debug) + printk(KERN_DEBUG "%s: NT newstate %x\n", + __FUNCTION__, dch->state); + switch (dch->state) { + case (2): + if (hc->hw.nt_timer < 0) { + hc->hw.nt_timer = 0; + hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; + Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); + /* Clear already pending ints */ + if (Read_hfc(hc, HFCPCI_INT_S1)); + + Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); + udelay(10); + Write_hfc(hc, HFCPCI_STATES, 4); + dch->state = 4; + } else { + hc->hw.int_m1 |= HFCPCI_INTS_TIMER; + Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); + hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; + hc->hw.ctmt |= HFCPCI_TIM3_125; + Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); + Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); + hc->hw.nt_timer = NT_T1_COUNT; + Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */ + } + return; + case (1): + prim = PH_DEACTIVATE | INDICATION; + para = 0; + hc->hw.nt_timer = 0; + hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; + Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + break; + case (4): + hc->hw.nt_timer = 0; + hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; + Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); + return; + case (3): + prim = PH_ACTIVATE | INDICATION; + para = 0; + hc->hw.nt_timer = 0; + hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; + Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + break; + default: + return; + } + mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST, + MGR_SHORTSTATUS | INDICATION, test_bit(FLG_ACTIVE, &dch->Flags) ? + SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED, + 0, NULL, 0); + } + mISDN_queue_data(&dch->inst, FLG_MSG_UP, prim, para, 0, NULL, 0); +} /*********************/ /* Interrupt handler */ /*********************/ +static inline void +tx_irq(channel_t *chan) +{ + if (chan->tx_skb && chan->tx_idx < chan->tx_skb->len) { + if (test_bit(FLG_DCHANNEL, &chan->Flags)) + hfcpci_fill_dfifo(chan->hw); + if (test_bit(FLG_BCHANNEL, &chan->Flags)) + hfcpci_fill_fifo(chan); + } else { + if (chan->tx_skb) + dev_kfree_skb(chan->tx_skb); + chan->tx_idx = 0; + if (test_bit(FLG_TX_NEXT, &chan->Flags)) { + chan->tx_skb = chan->next_skb; + if (chan->tx_skb) { + mISDN_head_t *hh = mISDN_HEAD_P(chan->tx_skb); + chan->next_skb = NULL; + test_and_clear_bit(FLG_TX_NEXT, &chan->Flags); + queue_ch_frame(chan, CONFIRM, hh->dinfo, NULL); + if (test_bit(FLG_DCHANNEL, &chan->Flags)) + hfcpci_fill_dfifo(chan->hw); + if (test_bit(FLG_BCHANNEL, &chan->Flags)) + hfcpci_fill_fifo(chan); + } else { + printk(KERN_WARNING "hfc tx irq TX_NEXT without skb\n"); + test_and_clear_bit(FLG_TX_NEXT, &chan->Flags); + test_and_clear_bit(FLG_TX_BUSY, &chan->Flags); + } + } else { + test_and_clear_bit(FLG_TX_BUSY, &chan->Flags); + chan->tx_skb = NULL; + } + } +} + static irqreturn_t hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) { hfc_pci_t *hc = dev_id; u_char exval; - bchannel_t *bch; - u_long flags; + channel_t *bch; u_char val, stat; - spin_lock_irqsave(&hc->lock.lock, flags); -#ifdef SPIN_DEBUG - hc->lock.spin_adr = (void *)0x3001; -#endif + spin_lock(&hc->lock); if (!(hc->hw.int_m2 & 0x08)) { -#ifdef SPIN_DEBUG - hc->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&hc->lock.lock, flags); + spin_unlock(&hc->lock); return IRQ_NONE; /* not initialised */ } @@ -1103,37 +1054,10 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) stat, val); } else { /* shared */ -#ifdef SPIN_DEBUG - hc->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&hc->lock.lock, flags); + spin_unlock(&hc->lock); return IRQ_NONE; } hc->irqcnt++; - if (test_and_set_bit(STATE_FLAG_BUSY, &hc->lock.state)) { - printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n", - __FUNCTION__, hc->lock.state); -#ifdef SPIN_DEBUG - printk(KERN_ERR "%s: previous lock:%p\n", - __FUNCTION__, hc->lock.busy_adr); -#endif -#ifdef LOCK_STATISTIC - hc->lock.irq_fail++; -#endif - } else { -#ifdef LOCK_STATISTIC - hc->lock.irq_ok++; -#endif -#ifdef SPIN_DEBUG - hc->lock.busy_adr = hfcpci_interrupt; -#endif - } - - test_and_set_bit(STATE_FLAG_INIRQ, &hc->lock.state); -#ifdef SPIN_DEBUG - hc->lock.spin_adr= NULL; -#endif - spin_unlock_irqrestore(&hc->lock.lock, flags); if (hc->dch.debug & L1_DEB_ISAC) mISDN_debugprint(&hc->dch.inst, "HFC-PCI irq %x", val); @@ -1142,15 +1066,15 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) exval = Read_hfc(hc, HFCPCI_STATES) & 0xf; if (hc->dch.debug & L1_DEB_ISAC) mISDN_debugprint(&hc->dch.inst, "ph_state chg %d->%d", - hc->dch.ph_state, exval); - hc->dch.ph_state = exval; - dchannel_sched_event(&hc->dch, D_L1STATECHANGE); + hc->dch.state, exval); + hc->dch.state = exval; + ph_state_change(&hc->dch); val &= ~0x40; } if (val & 0x80) { /* timer irq */ if (hc->hw.nt_mode) { if ((--hc->hw.nt_timer) < 0) - dchannel_sched_event(&hc->dch, D_L1STATECHANGE); + ph_state_change(&hc->dch); } val &= ~0x80; Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); @@ -1176,105 +1100,25 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) { if (hc->dch.debug) mISDN_debugprint(&hc->dch.inst, "hfcpci spurious 0x01 IRQ"); - } else { - if (bch->tx_idx < bch->tx_len) { - hfcpci_fill_fifo(bch); - } else { - 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); - hfcpci_fill_fifo(bch); - bch_sched_event(bch, B_XMTBUFREADY); - } else { - printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n"); - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch->tx_len = 0; - } - } else { - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch_sched_event(bch, B_XMTBUFREADY); - bch->tx_len = 0; - } - } - } + } else + tx_irq(bch); } if (val & 0x02) { if (!(bch = Sel_BCS(hc, 2))) { if (hc->dch.debug) mISDN_debugprint(&hc->dch.inst, "hfcpci spurious 0x02 IRQ"); - } else { - if (bch->tx_idx < bch->tx_len) { - hfcpci_fill_fifo(bch); - } else { - 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); - hfcpci_fill_fifo(bch); - bch_sched_event(bch, B_XMTBUFREADY); - } else { - printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n"); - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch->tx_len = 0; - } - } else { - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch_sched_event(bch, B_XMTBUFREADY); - bch->tx_len = 0; - } - } - } + } else + tx_irq(bch); } if (val & 0x20) { /* receive dframe */ receive_dmsg(hc); } if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &hc->dch.DFlags)) - del_timer(&hc->dch.dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &hc->dch.DFlags)) - dchannel_sched_event(&hc->dch, D_CLEARBUSY); - if (hc->dch.tx_idx < hc->dch.tx_len) { - hfcpci_fill_dfifo(hc); - } else { - if (test_and_clear_bit(FLG_TX_NEXT, &hc->dch.DFlags)) { - if (hc->dch.next_skb) { - hc->dch.tx_len = hc->dch.next_skb->len; - memcpy(hc->dch.tx_buf, - hc->dch.next_skb->data, - hc->dch.tx_len); - hc->dch.tx_idx = 0; - hfcpci_fill_dfifo(hc); - dchannel_sched_event(&hc->dch, D_XMTBUFREADY); - } else { - printk(KERN_WARNING "hfcd tx irq TX_NEXT without skb\n"); - test_and_clear_bit(FLG_TX_BUSY, &hc->dch.DFlags); - } - } else - test_and_clear_bit(FLG_TX_BUSY, &hc->dch.DFlags); - } + if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) + del_timer(&hc->dch.timer); + tx_irq(&hc->dch); } - spin_lock_irqsave(&hc->lock.lock, flags); -#ifdef SPIN_DEBUG - hc->lock.spin_adr = (void *)0x3002; -#endif - if (!test_and_clear_bit(STATE_FLAG_INIRQ, &hc->lock.state)) { - } - if (!test_and_clear_bit(STATE_FLAG_BUSY, &hc->lock.state)) { - printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n", - __FUNCTION__, hc->lock.state); - } -#ifdef SPIN_DEBUG - hc->lock.busy_adr = NULL; - hc->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&hc->lock.lock, flags); + spin_unlock(&hc->lock); return IRQ_HANDLED; } @@ -1286,184 +1130,19 @@ hfcpci_dbusy_timer(hfc_pci_t *hc) { } -/*************************************/ -/* Layer 1 D-channel hardware access */ -/*************************************/ -static int -HFCD_l1hw(mISDNif_t *hif, struct sk_buff *skb) -{ - dchannel_t *dch; - hfc_pci_t *hc; - int ret = -EINVAL; - mISDN_head_t *hh; - - if (!hif || !skb) - return(ret); - hh = mISDN_HEAD_P(skb); - dch = hif->fdata; - hc = dch->inst.data; - ret = 0; - if (hh->prim == PH_DATA_REQ) { - if (dch->next_skb) { - printk(KERN_WARNING "%s: next_skb exist ERROR\n", __FUNCTION__); - 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; - hfcpci_fill_dfifo(dch->inst.data); - dch->inst.unlock(dch->inst.data); - skb_trim(skb, 0); - return(if_newhead(&dch->inst.up, PH_DATA_CNF, - hh->dinfo, skb)); - } - } else if (hh->prim == (PH_SIGNAL | REQUEST)) { - dch->inst.lock(dch->inst.data, 0); - if ((hh->dinfo == INFO3_P8) || (hh->dinfo == INFO3_P10)) { - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - } else - ret = -EINVAL; - dch->inst.unlock(dch->inst.data); - } else if (hh->prim == (PH_CONTROL | REQUEST)) { - dch->inst.lock(dch->inst.data, 0); - if (hh->dinfo == HW_RESET) { - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); -// l1_msg(hc, HW_POWERUP | CONFIRM, NULL); - } else if (hh->dinfo == HW_DEACTIVATE) { - hc->hw.mst_m &= ~HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - 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(&hc->dch, D_CLEARBUSY); - } else if (hh->dinfo == HW_POWERUP) { - Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); - } else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) { - u_char slot; - if (1 & hh->dinfo) { - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) - slot = 0xC0; - else - slot = 0x80; - printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", - __FUNCTION__, slot); - Write_hfc(hc, HFCPCI_B1_SSL, slot); - Write_hfc(hc, HFCPCI_B1_RSL, slot); - hc->hw.conn = (hc->hw.conn & ~7) | 1; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - } - if (2 & hh->dinfo) { - if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) - slot = 0xC1; - else - slot = 0x81; - printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", - __FUNCTION__, slot); - Write_hfc(hc, HFCPCI_B2_SSL, slot); - Write_hfc(hc, HFCPCI_B2_RSL, slot); - hc->hw.conn = (hc->hw.conn & ~0x38) | 0x08; - Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); - } - if (3 & hh->dinfo) - hc->hw.trm |= 0x80; /* enable IOM-loop */ - else - hc->hw.trm &= 0x7f; /* disable IOM-loop */ - Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); - } else { - if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "%s: unknown ctrl %x", - __FUNCTION__, hh->dinfo); - ret = -EINVAL; - } - dch->inst.unlock(dch->inst.data); - } else if (hh->prim == (PH_ACTIVATE | REQUEST)) { - if (hc->hw.nt_mode) { - dch->inst.lock(dch->inst.data, 0); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* G0 */ - udelay(6); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* G1 */ - udelay(6); - if (test_bit(HFC_CFG_MASTER, &hc->cfg)) - hc->hw.mst_m |= HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - udelay(6); - Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION | 1); - dch->inst.unlock(dch->inst.data); - } else { - if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "%s: PH_ACTIVATE none NT mode", - __FUNCTION__); - ret = -EINVAL; - } - } else if (hh->prim == (PH_DEACTIVATE | REQUEST)) { - if (hc->hw.nt_mode) { - dch->inst.lock(dch->inst.data, 0); - hc->hw.mst_m &= ~HFCPCI_MASTER; - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - 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(&hc->dch, D_CLEARBUSY); - dch->inst.unlock(dch->inst.data); - } else { - if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "%s: PH_DEACTIVATE none NT mode", - __FUNCTION__); - ret = -EINVAL; - } - } else { - if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "%s: unknown prim %x", - __FUNCTION__, hh->prim); - ret = -EINVAL; - } - if (!ret) - dev_kfree_skb(skb); - return(ret); -} - /***************************************************************/ /* activate/deactivate hardware for selected channels and mode */ /***************************************************************/ static int -mode_hfcpci(bchannel_t *bch, int bc, int protocol) +mode_hfcpci(channel_t *bch, int bc, int protocol) { - hfc_pci_t *hc = bch->inst.data; + hfc_pci_t *hc = bch->hw; int fifo2; u_char rx_slot = 0, tx_slot = 0, pcm_mode; if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "HFCPCI bchannel protocol %x-->%x ch %x-->%x", - bch->protocol, protocol, bch->channel, bc); + bch->state, protocol, bch->channel, bc); fifo2 = bc; pcm_mode = (bc>>24) & 0xff; @@ -1497,10 +1176,10 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol) } 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) { return(0); } if (bc & 2) { @@ -1523,11 +1202,13 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol) else hc->hw.cirm &= 0xbf; #endif - bch->protocol = ISDN_PID_NONE; + bch->state = ISDN_PID_NONE; bch->channel = bc; + 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; bch->channel = bc; hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); @@ -1555,9 +1236,10 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol) hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; } + test_and_set_bit(FLG_TRANSPARENT, &bch->Flags); break; case (ISDN_PID_L1_B_64HDLC): - bch->protocol = protocol; + bch->state = protocol; bch->channel = bc; hfcpci_clear_fifo_rx(hc, (fifo2 & 2)?1:0); hfcpci_clear_fifo_tx(hc, (fifo2 & 2)?1:0); @@ -1581,24 +1263,8 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol) hc->hw.ctmt &= ~1; hc->hw.conn &= ~0x03; } + test_and_set_bit(FLG_HDLC, &bch->Flags); break; -#if 0 - case (L1_MODE_EXTRN): - if (bc) { - hc->hw.conn |= 0x10; - hc->hw.sctrl |= SCTRL_B2_ENA; - hc->hw.sctrl_r |= SCTRL_B2_ENA; - hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B2; - hc->hw.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - } else { - hc->hw.conn |= 0x02; - hc->hw.sctrl |= SCTRL_B1_ENA; - hc->hw.sctrl_r |= SCTRL_B1_ENA; - hc->hw.fifo_en &= ~HFCPCI_FIFOEN_B1; - hc->hw.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - } - break; -#endif default: mISDN_debugprint(&bch->inst, "prot not known %x", protocol); return(-ENOPROTOOPT); @@ -1647,15 +1313,13 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol) #ifdef REVERSE_BITORDER Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm); #endif - if (bch->protocol) - bch_sched_event(bch, B_XMTBUFREADY); return(0); } static int -set_hfcpci_rxtest(bchannel_t *bch, int protocol, struct sk_buff *skb) +set_hfcpci_rxtest(channel_t *bch, int protocol, struct sk_buff *skb) { - hfc_pci_t *hc = bch->inst.data; + hfc_pci_t *hc = bch->hw; int *chan = (int *)skb->data; if (skb->len <4) { @@ -1664,7 +1328,7 @@ set_hfcpci_rxtest(bchannel_t *bch, int protocol, struct sk_buff *skb) } if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "HFCPCI bchannel test rx protocol %x-->%x ch %x-->%x", - bch->protocol, protocol, bch->channel, *chan); + bch->state, protocol, bch->channel, *chan); if (bch->channel != *chan) { mISDN_debugprint(&bch->inst, "HFCPCI rxtest wrong channel parameter %x/%x", bch->channel, *chan); @@ -1672,7 +1336,7 @@ set_hfcpci_rxtest(bchannel_t *bch, int protocol, struct sk_buff *skb) } switch (protocol) { case (ISDN_PID_L1_B_64TRANS): - bch->protocol = protocol; + bch->state = protocol; hfcpci_clear_fifo_rx(hc, (*chan & 2)?1:0); if (*chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; @@ -1695,7 +1359,7 @@ set_hfcpci_rxtest(bchannel_t *bch, int protocol, struct sk_buff *skb) } break; case (ISDN_PID_L1_B_64HDLC): - bch->protocol = protocol; + bch->state = protocol; hfcpci_clear_fifo_rx(hc, (*chan & 2)?1:0); if (*chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; @@ -1728,89 +1392,213 @@ set_hfcpci_rxtest(bchannel_t *bch, int protocol, struct sk_buff *skb) return(0); } -/******************************/ -/* Layer2 -> Layer 1 Transfer */ -/******************************/ +/*************************************/ +/* Layer 1 D-channel hardware access */ +/*************************************/ static int -hfcpci_l2l1(mISDNif_t *hif, struct sk_buff *skb) +hfc_dmsg(channel_t *dch, struct sk_buff *skb) { - bchannel_t *bch; - int ret = -EINVAL; - mISDN_head_t *hh; + hfc_pci_t *hc = dch->hw; + 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))) { -#warning TODO: hier muss abgefragt werden, ob skb->len <= 0 ist, und ggf. ein -EINVAL zurückliefern, sonst wird zwar einmal confirmed, aber es regt sich nichts mehr. dies bitte auch für den d-kanal überdenken, sowie für alle andere kartentreiber. - if (bch->next_skb) { - printk(KERN_WARNING "%s: next_skb exist ERROR\n", - __FUNCTION__); - 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; - hfcpci_fill_fifo(bch); - bch->inst.unlock(bch->inst.data); - if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - && bch->dev) - hif = &bch->dev->rport.pif; - else - hif = &bch->inst.up; + if (hh->prim == (PH_SIGNAL | REQUEST)) { + spin_lock_irqsave(dch->inst.hwlock, flags); + if ((hh->dinfo == INFO3_P8) || (hh->dinfo == INFO3_P10)) { + if (test_bit(HFC_CFG_MASTER, &hc->cfg)) + hc->hw.mst_m |= HFCPCI_MASTER; + Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); + } else + ret = -EINVAL; + spin_unlock_irqrestore(dch->inst.hwlock, flags); + } else if (hh->prim == (PH_CONTROL | REQUEST)) { + spin_lock_irqsave(dch->inst.hwlock, flags); + if (hh->dinfo == HW_RESET) { + Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */ + udelay(6); + Write_hfc(hc, HFCPCI_STATES, 3); /* HFC ST 2 */ + if (test_bit(HFC_CFG_MASTER, &hc->cfg)) + hc->hw.mst_m |= HFCPCI_MASTER; + Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); + Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); + spin_unlock_irqrestore(dch->inst.hwlock, flags); skb_trim(skb, 0); - return(if_newhead(hif, hh->prim | CONFIRM, - hh->dinfo, skb)); + return(mISDN_queueup_newhead(&dch->inst, 0, PH_CONTROL | INDICATION, + HW_POWERUP, skb)); +// l1_msg(hc, HW_POWERUP | CONFIRM, NULL); + } else if (hh->dinfo == HW_DEACTIVATE) { + hc->hw.mst_m &= ~HFCPCI_MASTER; + Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); + if (dch->next_skb) { + dev_kfree_skb(dch->next_skb); + dch->next_skb = NULL; + } + 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_POWERUP) { + Write_hfc(hc, HFCPCI_STATES, HFCPCI_DO_ACTION); + } else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) { + u_char slot; + if (1 & hh->dinfo) { + if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) + slot = 0xC0; + else + slot = 0x80; + printk(KERN_DEBUG "%s: Write_hfc: B1_SSL/RSL 0x%x\n", + __FUNCTION__, slot); + Write_hfc(hc, HFCPCI_B1_SSL, slot); + Write_hfc(hc, HFCPCI_B1_RSL, slot); + hc->hw.conn = (hc->hw.conn & ~7) | 1; + Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); + } + if (2 & hh->dinfo) { + if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg)) + slot = 0xC1; + else + slot = 0x81; + printk(KERN_DEBUG "%s: Write_hfc: B2_SSL/RSL 0x%x\n", + __FUNCTION__, slot); + Write_hfc(hc, HFCPCI_B2_SSL, slot); + Write_hfc(hc, HFCPCI_B2_RSL, slot); + hc->hw.conn = (hc->hw.conn & ~0x38) | 0x08; + Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn); + } + if (3 & hh->dinfo) + hc->hw.trm |= 0x80; /* enable IOM-loop */ + else + hc->hw.trm &= 0x7f; /* disable IOM-loop */ + Write_hfc(hc, HFCPCI_TRM, hc->hw.trm); + } else { + if (dch->debug & L1_DEB_WARN) + mISDN_debugprint(&dch->inst, "%s: unknown ctrl %x", + __FUNCTION__, hh->dinfo); + ret = -EINVAL; } - } else if ((hh->prim == (PH_ACTIVATE | REQUEST)) || + spin_unlock_irqrestore(dch->inst.hwlock, flags); + } else if (hh->prim == (PH_ACTIVATE | REQUEST)) { + if (hc->hw.nt_mode) { + spin_lock_irqsave(dch->inst.hwlock, flags); + Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* G0 */ + udelay(6); + Write_hfc(hc, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* G1 */ + udelay(6); + if (test_bit(HFC_CFG_MASTER, &hc->cfg)) + hc->hw.mst_m |= HFCPCI_MASTER; + Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); + udelay(6); + Write_hfc(hc, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION | 1); + spin_unlock_irqrestore(dch->inst.hwlock, flags); + } else { + if (dch->debug & L1_DEB_WARN) + mISDN_debugprint(&dch->inst, "%s: PH_ACTIVATE none NT mode", + __FUNCTION__); + ret = -EINVAL; + } + } else if (hh->prim == (PH_DEACTIVATE | REQUEST)) { + if (hc->hw.nt_mode) { + spin_lock_irqsave(dch->inst.hwlock, flags); + hc->hw.mst_m &= ~HFCPCI_MASTER; + Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); + if (dch->next_skb) { + dev_kfree_skb(dch->next_skb); + dch->next_skb = NULL; + } + 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); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) + dchannel_sched_event(&hc->dch, D_CLEARBUSY); +#endif + spin_unlock_irqrestore(dch->inst.hwlock, flags); + } else { + if (dch->debug & L1_DEB_WARN) + mISDN_debugprint(&dch->inst, "%s: PH_DEACTIVATE none NT mode", + __FUNCTION__); + ret = -EINVAL; + } + } else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) { + u_int temp = hh->dinfo & SSTATUS_ALL; + if (hc->hw.nt_mode && /* if TE mode ignore */ + (temp == SSTATUS_ALL || temp == SSTATUS_L1)) { + if (hh->dinfo & SSTATUS_BROADCAST_BIT) + temp = dch->inst.id | MSG_BROADCAST; + else + temp = hh->addr | FLG_MSG_TARGET; + skb_trim(skb, 0); + hh->dinfo = test_bit(FLG_ACTIVE, &dch->Flags) ? + SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED; + hh->prim = MGR_SHORTSTATUS | CONFIRM; + return(mISDN_queue_message(&dch->inst, temp, skb)); + } + ret = -EOPNOTSUPP; + } else { + if (dch->debug & L1_DEB_WARN) + mISDN_debugprint(&dch->inst, "%s: unknown prim %x", + __FUNCTION__, hh->prim); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return(ret); +} + +/*************************************/ +/* Layer 1 B-channel hardware access */ +/*************************************/ +static int +hfc_bmsg(channel_t *bch, struct sk_buff *skb) +{ + mISDN_head_t *hh = mISDN_HEAD_P(skb); + int ret = -EINVAL; + u_long flags; + + 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); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(bch->inst.hwlock, flags); ret = mode_hfcpci(bch, bch->channel, bch->inst.pid.protocol[1]); - bch->inst.unlock(bch->inst.data); - } - if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - if (bch->dev) - if_link(&bch->dev->rport.pif, - hh->prim | CONFIRM, 0, 0, NULL, 0); + if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS) + test_and_set_bit(FLG_L2DATA, &bch->Flags); + spin_unlock_irqrestore(bch->inst.hwlock, flags); + } else + ret = 0; skb_trim(skb, 0); - return(if_newhead(&bch->inst.up, hh->prim | CONFIRM, ret, skb)); + return(mISDN_queueup_newhead(&bch->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(bch->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); - mode_hfcpci(bch, bch->channel, ISDN_PID_NONE); - test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag); - bch->inst.unlock(bch->inst.data); - skb_trim(skb, 0); - if (hh->prim != (MGR_DISCONNECT | REQUEST)) { - if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - if (bch->dev) - if_link(&bch->dev->rport.pif, - hh->prim | CONFIRM, 0, 0, NULL, 0); - if (!if_newhead(&bch->inst.up, hh->prim | CONFIRM, 0, skb)) - return(0); + if (bch->tx_skb) { + dev_kfree_skb(bch->tx_skb); + bch->tx_skb = NULL; } + bch->tx_idx = 0; + if (bch->rx_skb) { + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + mode_hfcpci(bch, bch->channel, ISDN_PID_NONE); + test_and_clear_bit(FLG_L2DATA, &bch->Flags); + test_and_clear_bit(FLG_ACTIVE, &bch->Flags); + spin_unlock_irqrestore(bch->inst.hwlock, flags); + skb_trim(skb, 0); + if (hh->prim != (PH_CONTROL | REQUEST)) + if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, 0, skb)) + return(0); ret = 0; } else if (hh->prim == (PH_CONTROL | REQUEST)) { - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); if (hh->dinfo == HW_TESTRX_RAW) { ret = set_hfcpci_rxtest(bch, ISDN_PID_L1_B_64TRANS, skb); } else if (hh->dinfo == HW_TESTRX_HDLC) { @@ -1820,121 +1608,61 @@ hfcpci_l2l1(mISDNif_t *hif, struct sk_buff *skb) ret = 0; } else ret = -EINVAL; - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); if (!ret) { skb_trim(skb, 0); - if (!if_newhead(&bch->inst.up, hh->prim | CONFIRM, hh->dinfo, skb)) + if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, hh->dinfo, skb)) return(0); } } else { printk(KERN_WARNING "%s: unknown prim(%x)\n", __FUNCTION__, hh->prim); - ret = -EINVAL; + ret = -EAGAIN; } if (!ret) dev_kfree_skb(skb); return(ret); } - -/***************************/ -/* handle L1 state changes */ -/***************************/ - -static void -HW_hfcD_bh(dchannel_t *dch) +/******************************/ +/* Layer2 -> Layer 1 Transfer */ +/******************************/ +static int +hfcpci_l2l1(mISDNinstance_t *inst, struct sk_buff *skb) { - hfc_pci_t *hc = dch->inst.data; - u_int prim = PH_SIGNAL | INDICATION; - u_int para = 0; - mISDNif_t *upif = &dch->inst.up; + channel_t *chan = container_of(inst, channel_t, inst); + int ret = -EINVAL; + mISDN_head_t *hh = mISDN_HEAD_P(skb); + u_long flags; - if (test_and_clear_bit(D_L1STATECHANGE, &dch->event)) { - if (!hc->hw.nt_mode) { - if (dch->debug) - printk(KERN_DEBUG "%s: TE newstate %x\n", - __FUNCTION__, dch->ph_state); - switch (dch->ph_state) { - case (0): - prim = PH_CONTROL | INDICATION; - para = HW_RESET; - break; - case (3): - prim = PH_CONTROL | INDICATION; - para = HW_DEACTIVATE; - break; - case (5): - case (8): - para = ANYSIGNAL; - break; - case (6): - para = INFO2; - break; - case (7): - para = INFO4_P8; - break; - default: - return; - } - } else { - if (dch->debug) - printk(KERN_DEBUG "%s: NT newstate %x\n", - __FUNCTION__, dch->ph_state); - dch->inst.lock(dch->inst.data, 0); - switch (dch->ph_state) { - case (2): - if (hc->hw.nt_timer < 0) { - hc->hw.nt_timer = 0; - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - /* Clear already pending ints */ - if (Read_hfc(hc, HFCPCI_INT_S1)); - - Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); - udelay(10); - Write_hfc(hc, HFCPCI_STATES, 4); - dch->ph_state = 4; - } else { - hc->hw.int_m1 |= HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - hc->hw.ctmt &= ~HFCPCI_AUTO_TIMER; - hc->hw.ctmt |= HFCPCI_TIM3_125; - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); - Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); - hc->hw.nt_timer = NT_T1_COUNT; - Write_hfc(hc, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */ - } - upif = NULL; - break; - case (1): - prim = PH_DEACTIVATE | INDICATION; - para = 0; - hc->hw.nt_timer = 0; - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - break; - case (4): - hc->hw.nt_timer = 0; - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - upif = NULL; - break; - case (3): - prim = PH_ACTIVATE | INDICATION; - para = 0; - hc->hw.nt_timer = 0; - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - break; - default: - break; - } - dch->inst.unlock(dch->inst.data); - } - while(upif) { - if_link(upif, prim, para, 0, NULL, 0); - upif = upif->clone; + if ((hh->prim == PH_DATA_REQ) || + (hh->prim == (DL_DATA | REQUEST))) { + spin_lock_irqsave(inst->hwlock, flags); + ret = channel_senddata(chan, hh->dinfo, skb); + if (ret > 0) { /* direct TX */ + if (test_bit(FLG_DCHANNEL, &chan->Flags)) + hfcpci_fill_dfifo(chan->hw); + if (test_bit(FLG_BCHANNEL, &chan->Flags)) + hfcpci_fill_fifo(chan); + ret = 0; } + spin_unlock_irqrestore(inst->hwlock, flags); + return(ret); } + if (test_bit(FLG_DCHANNEL, &chan->Flags)) { + ret = hfc_dmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; + } + if (test_bit(FLG_BCHANNEL, &chan->Flags)) { + ret = hfc_bmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; + } + if (!ret) + dev_kfree_skb(skb); + return(ret); } /********************************/ @@ -1945,86 +1673,46 @@ void inithfcpci(hfc_pci_t *hc) { HFC_INFO("inithfcpci: entered\n"); - hc->dch.hw_bh = HW_hfcD_bh; - hc->dch.dbusytimer.function = (void *) hfcpci_dbusy_timer; - hc->dch.dbusytimer.data = (long) &hc->dch; - init_timer(&hc->dch.dbusytimer); + hc->dch.timer.function = (void *) hfcpci_dbusy_timer; + hc->dch.timer.data = (long) &hc->dch; + init_timer(&hc->dch.timer); hc->chanlimit = 2; mode_hfcpci(&hc->bch[0], 1, -1); mode_hfcpci(&hc->bch[1], 2, -1); } -#if 0 -/*******************************************/ -/* handle card messages from control layer */ -/*******************************************/ -static int -hfcpci_card_msg(hfc_pci_t *hc, int mt, void *arg) -{ - long flags; - - if (hc->debug & L1_DEB_ISAC) - debugl1(hc, "HFCPCI: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - HFC_INFO("hfcpci_card_msg: CARD_RESET\n"); - reset_hfcpci(hc); - return (0); - case CARD_RELEASE: - HFC_INFO("hfcpci_card_msg: CARD_RELEASE\n"); - release_io_hfcpci(hc); - return (0); - case CARD_INIT: - HFC_INFO("hfcpci_card_msg: CARD_INIT\n"); - inithfcpci(hc); - save_flags(flags); - sti(); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ - /* now switch timer interrupt off */ - hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); - /* reinit mode reg */ - Write_hfc(hc, HFCPCI_MST_MODE, hc->hw.mst_m); - restore_flags(flags); - return (0); - case CARD_TEST: - HFC_INFO("hfcpci_card_msg: CARD_TEST\n"); - return (0); - } - return (0); -} - -#endif static int init_card(hfc_pci_t *hc) { int cnt = 3; + u_long flags; HFC_INFO("init_card: entered\n"); - lock_dev(hc, 0); + + spin_lock_irqsave(&hc->lock, flags); + disable_hwirq(hc); + spin_unlock_irqrestore(&hc->lock, flags); if (request_irq(hc->irq, hfcpci_interrupt, SA_SHIRQ, "HFC PCI", hc)) { - printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", - hc->irq); - unlock_dev(hc); + printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", hc->irq); return(-EIO); } + spin_lock_irqsave(&hc->lock, flags); while (cnt) { inithfcpci(hc); - unlock_dev(hc); /* Finally enable IRQ output * this is only allowed, if an IRQ routine is allready * established for this HFC, so don't do that earlier */ - hc->hw.int_m2 = HFCPCI_IRQ_ENABLE; - Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); + enable_hwirq(hc); + spin_unlock_irqrestore(&hc->lock, flags); /* Timeout 80ms */ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout((80*HZ)/1000); printk(KERN_INFO "HFC PCI: IRQ %d count %d\n", hc->irq, hc->irqcnt); /* now switch timer interrupt off */ + spin_lock_irqsave(&hc->lock, flags); hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* reinit mode reg */ @@ -2034,24 +1722,25 @@ static int init_card(hfc_pci_t *hc) "HFC PCI: IRQ(%d) getting no interrupts during init %d\n", hc->irq, 4 - cnt); if (cnt == 1) { + spin_unlock_irqrestore(&hc->lock, flags); return (-EIO); } else { reset_hfcpci(hc); cnt--; } } else { + spin_unlock_irqrestore(&hc->lock, flags); return(0); } - lock_dev(hc, 0); } - unlock_dev(hc); + spin_unlock_irqrestore(&hc->lock, flags); return(-EIO); } static int SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci) { - bchannel_t *bch; + channel_t *bch; hfc_pci_t *hfc; mISDNstack_t *bst; u_int cnr; @@ -2074,11 +1763,12 @@ SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci) } else head = &bst->childlist; list_for_each_entry(bst, head, list) { - if(!bst->mgr) { + if (!bst->mgr) { int_errtxt("no mgr st(%p)", bst); return(-EINVAL); } - hfc = bst->mgr->data; + bch = container_of(bst->mgr, channel_t, inst); + hfc = bst->mgr->privat; if (!hfc) { int_errtxt("no mgr->data st(%p)", bst); return(-EINVAL); @@ -2087,14 +1777,14 @@ SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci) if (!(ci->channel & (~CHANNEL_NUMBER))) { /* only number is set */ if ((ci->channel & 0x3) == (cnr + 1)) { - if (bch->protocol != ISDN_PID_NONE) + if (test_bit(FLG_ACTIVE, &bch->Flags)) return(-EBUSY); bch->channel = (cnr & 1) ? 2 : 1; ci->st.p = bst; return(0); } } else if ((ci->channel & (~CHANNEL_NUMBER)) == 0x00a18300) { - if (bch->protocol == ISDN_PID_NONE) { + if (!test_bit(FLG_ACTIVE, &bch->Flags)) { ci->st.p = bst; bch->channel = (cnr & 1) ? 2 : 1; bch->channel |= CHANNEL_EXT_PCM; @@ -2112,19 +1802,26 @@ SelFreeBChannel(hfc_pci_t *hc, channel_info_t *ci) #define MAX_CARDS 8 #define MODULE_PARM_T "1-8i" static int HFC_cnt; -static u_int protocol[MAX_CARDS]; -static int layermask[MAX_CARDS]; +static uint protocol[MAX_CARDS]; +static uint layermask[MAX_CARDS]; +static uint debug; static mISDNobject_t HFC_obj; -static int debug; #ifdef MODULE MODULE_AUTHOR("Karsten Keil"); #ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); #endif -MODULE_PARM(debug, "1i"); -MODULE_PARM(protocol, MODULE_PARM_T); +module_param (debug, uint, 0); +MODULE_PARM_DESC (debug, "hfcpci debug mask"); +#ifdef OLD_MODULE_PARAM_ARRAY +static int protocol_cnt; +module_param_array(protocol, uint, protocol_cnt, 0); +#else +module_param_array(protocol, uint, NULL, 0); +#endif +MODULE_PARM_DESC (protocol, "hfcpci protcol (DSS1 := 2)"); /* short description of protocol * protocol=[,p2,p3...] @@ -2149,8 +1846,13 @@ MODULE_PARM(protocol, MODULE_PARM_T); * bit 9 0x0200 switch DD/DU interface * bit 10 - 15 reserved */ - -MODULE_PARM(layermask, MODULE_PARM_T); +#ifdef OLD_MODULE_PARAM_ARRAY +static int layermask_cnt; +module_param_array(layermask, uint, layermask_cnt, 0); +#else +module_param_array(layermask, uint, NULL, 0); +#endif +MODULE_PARM_DESC(layermask, "hfcpci layer mask"); #endif static char HFCName[] = "HFC_PCI"; @@ -2170,7 +1872,7 @@ setup_hfcpci(hfc_pci_t *hc) strcpy(tmp, hfcpci_revision); printk(KERN_INFO "mISDN: HFC-PCI driver Rev. %s\n", mISDN_getrev(tmp)); hc->hw.cirm = 0; - hc->dch.ph_state = 0; + hc->dch.state = 0; while (id_list[i].vendor_id) { tmp_hfcpci = pci_find_device(id_list[i].vendor_id, id_list[i].device_id, dev_hfcpci); @@ -2214,13 +1916,13 @@ setup_hfcpci(hfc_pci_t *hc) pci_write_config_dword(hc->hw.dev, 0x80, (u_int) cpu_to_le32((unsigned int)virt_to_bus(hc->hw.fifos))); hc->hw.pci_io = ioremap((ulong) hc->hw.pci_io, 256); printk(KERN_INFO - "HFC-PCI: defined at mem %#x fifo %#x(%#x) IRQ %d HZ %d\n", - (u_int) hc->hw.pci_io, (u_int) hc->hw.fifos, - (u_int) virt_to_bus(hc->hw.fifos), + "HFC-PCI: defined at mem %#lx fifo %#lx(%#lx) IRQ %d HZ %d\n", + (u_long) hc->hw.pci_io, (u_long) hc->hw.fifos, + (u_long) virt_to_bus(hc->hw.fifos), hc->irq, HZ); pci_write_config_word(hc->hw.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ - hc->hw.int_m2 = 0; /* disable alle interrupts */ - Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2); + hc->hw.int_m2 = 0; + disable_hwirq(hc); hc->hw.int_m1 = 0; Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1); /* At this point the needed PCI config is done */ @@ -2228,41 +1930,31 @@ setup_hfcpci(hfc_pci_t *hc) hc->hw.timer.function = (void *) hfcpci_Timer; hc->hw.timer.data = (long) hc; init_timer(&hc->hw.timer); - lock_dev(hc, 0); -#ifdef SPIN_DEBUG - printk(KERN_ERR "spin_lock_adr=%p now(%p)\n", &hc->lock.spin_adr, hc->lock.spin_adr); - printk(KERN_ERR "busy_lock_adr=%p now(%p)\n", &hc->lock.busy_adr, hc->lock.busy_adr); -#endif - unlock_dev(hc); reset_hfcpci(hc); return (0); } static void release_card(hfc_pci_t *hc) { + u_long flags; -#ifdef LOCK_STATISTIC - printk(KERN_INFO "try_ok(%d) try_wait(%d) try_mult(%d) try_inirq(%d)\n", - hc->lock.try_ok, hc->lock.try_wait, hc->lock.try_mult, hc->lock.try_inirq); - printk(KERN_INFO "irq_ok(%d) irq_fail(%d)\n", - hc->lock.irq_ok, hc->lock.irq_fail); -#endif - lock_dev(hc, 0); free_irq(hc->irq, hc); + spin_lock_irqsave(&hc->lock, flags); mode_hfcpci(&hc->bch[0], 1, ISDN_PID_NONE); mode_hfcpci(&hc->bch[1], 2, ISDN_PID_NONE); - if (hc->dch.dbusytimer.function != NULL) { - del_timer(&hc->dch.dbusytimer); - hc->dch.dbusytimer.function = NULL; + if (hc->dch.timer.function != NULL) { + del_timer(&hc->dch.timer); + hc->dch.timer.function = NULL; } release_io_hfcpci(hc); - mISDN_free_bch(&hc->bch[1]); - mISDN_free_bch(&hc->bch[0]); - mISDN_free_dch(&hc->dch); - HFC_obj.ctrl(hc->dch.inst.up.peer, MGR_DISCONNECT | REQUEST, &hc->dch.inst.up); + mISDN_freechannel(&hc->bch[1]); + mISDN_freechannel(&hc->bch[0]); + mISDN_freechannel(&hc->dch); + spin_unlock_irqrestore(&hc->lock, flags); HFC_obj.ctrl(&hc->dch.inst, MGR_UNREGLAYER | REQUEST, NULL); + spin_lock_irqsave(&HFC_obj.lock, flags); list_del(&hc->list); - unlock_dev(hc); + spin_unlock_irqrestore(&HFC_obj.lock, flags); kfree(hc); } @@ -2272,6 +1964,7 @@ HFC_manager(void *data, u_int prim, void *arg) { mISDNinstance_t *inst = data; struct sk_buff *skb; int channel = -1; + u_long flags; if (!data) { MGR_HASPROTOCOL_HANDLER(prim,arg,&HFC_obj) @@ -2279,6 +1972,7 @@ HFC_manager(void *data, u_int prim, void *arg) { __FUNCTION__, prim, arg); return(-EINVAL); } + spin_lock_irqsave(&HFC_obj.lock, flags); list_for_each_entry(card, &HFC_obj.ilist, list) { if (&card->dch.inst == inst) { channel = 2; @@ -2294,6 +1988,7 @@ HFC_manager(void *data, u_int prim, void *arg) { break; } } + spin_unlock_irqrestore(&HFC_obj.lock, flags); if (channel<0) { printk(KERN_ERR "%s: no channel data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg); @@ -2303,36 +1998,25 @@ HFC_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 (HFCD_l1hw(&inst->down, 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 (hfcpci_l2l1(&inst->down, skb)) - dev_kfree_skb(skb); - } + if ((skb = create_link_skb(PH_CONTROL | REQUEST, + HW_DEACTIVATE, 0, NULL, 0))) { + if (hfcpci_l2l1(inst, skb)) + dev_kfree_skb(skb); } - HFC_obj.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up); HFC_obj.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) { @@ -2341,6 +2025,7 @@ HFC_manager(void *data, u_int prim, void *arg) { HFC_obj.refcnt--; } break; +#ifdef FIXME case MGR_CONNECT | REQUEST: return(mISDN_ConnectIF(inst, arg)); case MGR_SETIF | REQUEST: @@ -2354,6 +2039,7 @@ HFC_manager(void *data, u_int prim, void *arg) { case MGR_DISCONNECT | REQUEST: case MGR_DISCONNECT | INDICATION: return(mISDN_DisConnectIF(inst, arg)); +#endif case MGR_SELCHANNEL | REQUEST: if (channel != 2) { printk(KERN_WARNING "%s: selchannel not dinst\n", @@ -2361,19 +2047,17 @@ HFC_manager(void *data, u_int prim, void *arg) { return(-EINVAL); } return(SelFreeBChannel(card, 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 (hfcpci_l2l1(&inst->down, skb)) + if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, 0, 0, NULL, 0))) { + if (hfcpci_l2l1(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; @@ -2393,10 +2077,12 @@ static int __init HFC_init(void) hfc_pci_t *card, *prev; mISDN_pid_t pid; mISDNstack_t *dst; + u_long flags; #ifdef MODULE HFC_obj.owner = THIS_MODULE; #endif + spin_lock_init(&HFC_obj.lock); INIT_LIST_HEAD(&HFC_obj.ilist); HFC_obj.name = HFCName; HFC_obj.own_ctrl = HFC_manager; @@ -2418,31 +2104,39 @@ static int __init HFC_init(void) return(-ENOMEM); } memset(card, 0, sizeof(hfc_pci_t)); + spin_lock_irqsave(&HFC_obj.lock, flags); list_add_tail(&card->list, &HFC_obj.ilist); + spin_unlock_irqrestore(&HFC_obj.lock, flags); card->dch.debug = debug; - lock_HW_init(&card->lock); - card->dch.inst.lock = lock_dev; - card->dch.inst.unlock = unlock_dev; - mISDN_init_instance(&card->dch.inst, &HFC_obj, card); + spin_lock_init(&card->lock); + card->dch.inst.hwlock = &card->lock; + mISDN_init_instance(&card->dch.inst, &HFC_obj, card, hfcpci_l2l1); card->dch.inst.pid.layermask = ISDN_LAYER(0); sprintf(card->dch.inst.name, "HFC%d", HFC_cnt+1); - mISDN_init_dch(&card->dch); + err = mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1); + card->dch.hw = card; + if (err) { + mISDN_unregister(&HFC_obj); + return(err); + } for (i=0; i<2; i++) { card->bch[i].channel = i + 1; - mISDN_init_instance(&card->bch[i].inst, &HFC_obj, card); + mISDN_init_instance(&card->bch[i].inst, &HFC_obj, card, hfcpci_l2l1); 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; 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; +#ifdef FIXME if (card->bch[i].dev) { card->bch[i].dev->wport.pif.func = hfcpci_l2l1; card->bch[i].dev->wport.pif.fdata = &card->bch[i]; } +#endif } if (protocol[HFC_cnt] == 0x100) { if (card->list.prev == &HFC_obj.ilist) @@ -2500,10 +2194,12 @@ static int __init HFC_init(void) card, &card->dch, &card->bch[0], &card->bch[1]); if (setup_hfcpci(card)) { err = 0; - 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(&HFC_obj.lock, flags); list_del(&card->list); + spin_unlock_irqrestore(&HFC_obj.lock, flags); kfree(card); if (!HFC_cnt) { mISDN_unregister(&HFC_obj); @@ -2513,6 +2209,7 @@ static int __init HFC_init(void) HFC_cnt); return(err); } + card->dch.inst.class_dev.dev = &card->hw.dev->dev; HFC_cnt++; if (prev) { dst = prev->dch.inst.st; @@ -2529,7 +2226,9 @@ static int __init HFC_init(void) } dst = card->dch.inst.st; } + HFC_obj.ctrl(dst, MGR_STOPSTACK | REQUEST, NULL); for (i = 0; i < 2; i++) { + card->bch[i].inst.class_dev.dev = &card->hw.dev->dev; if ((err = HFC_obj.ctrl(dst, MGR_NEWSTACK | REQUEST, &card->bch[i].inst))) { printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err); @@ -2541,7 +2240,6 @@ static int __init HFC_init(void) err = 0; return(err); } - card->bch[i].st = card->bch[i].inst.st; } if (protocol[HFC_cnt] != 0x100) { /* next not second HFC */ if ((err = HFC_obj.ctrl(dst, MGR_SETSTACK | REQUEST, @@ -2564,6 +2262,7 @@ static int __init HFC_init(void) err = 0; return(err); } + HFC_obj.ctrl(dst, MGR_STARTSTACK | REQUEST, NULL); HFC_obj.ctrl(dst, MGR_CTRLREADY | INDICATION, NULL); } printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); diff --git a/drivers/isdn/hardware/mISDN/hfcs_usb.c b/drivers/isdn/hardware/mISDN/hfcs_usb.c index 8b63fb8..b521029 100644 --- a/drivers/isdn/hardware/mISDN/hfcs_usb.c +++ b/drivers/isdn/hardware/mISDN/hfcs_usb.c @@ -20,32 +20,24 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * DISCLAIMER - * This driver is for ISDN USB TAs with HFC-S USB chips only. - * Please verify your TA's Vendor/Product IDs in the usb_device_id - * list below to make sure your hardware is supported by this driver. - * You might possibly have a device with the same device name - * but different IDs which are not supported by this driver due to a - * different chipset. - * * TODO * - hotplug disconnect the USB TA does not unregister mISDN Controller * /proc/capi/controller is still "ready"... * --> use rmmod before disconnecting the TA + * - E channel features + * */ #include #include #include #include -#include "dchannel.h" -#include "bchannel.h" +#include "channel.h" #include "layer1.h" -#include "helper.h" #include "debug.h" -#include "hw_lock.h" #include "hfcs_usb.h" + #define DRIVER_NAME "mISDN_hfcsusb" const char *hfcsusb_rev = "$Revision$"; @@ -76,7 +68,7 @@ struct _hfcsusb_t; /* forward definition */ struct usb_fifo; /* forward definition */ typedef struct iso_urb_struct { struct urb *purb; - __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */ + __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing USB URB data */ struct usb_fifo *owner_fifo; /* pointer to owner fifo */ } iso_urb_struct; @@ -88,56 +80,52 @@ typedef struct usb_fifo { __u8 usb_packet_maxlen; /* maximum length for usb transfer */ unsigned int max_size; /* maximum size of receive/send packet */ __u8 intervall; /* interrupt interval */ - struct sk_buff *skbuff; /* actual used buffer */ struct urb *urb; /* transfer structure for usb routines */ - __u8 buffer[128]; /* buffer incoming/outgoing data */ + __u8 buffer[128]; /* buffer USB INT OUT URB data */ int bit_line; /* how much bits are in the fifo? */ volatile __u8 usb_transfer_mode; /* switched between ISO and INT */ iso_urb_struct iso[2]; /* need two urbs to have one always for pending */ - __u8 bch_idx; /* link BChannel Fifos to bch[bch_idx] */ - int delete_flg; /* only delete skbuff once */ + __u8 ch_idx; /* link BChannel Fifos to chan[ch_idx] */ int last_urblen; /* remember length of last packet */ } usb_fifo; typedef struct _hfcsusb_t { - struct list_head list; - mISDN_HWlock_t lock; - dchannel_t dch; - bchannel_t bch[2]; + struct list_head list; + channel_t chan[4]; // B1,B2,D,(PCM) - struct usb_device *dev; /* our device */ - int if_used; /* used interface number */ - int alt_used; /* used alternate config */ - int cfg_used; /* configuration index used */ - int vend_idx; /* index in hfcsusb_idtab */ - int packet_size; - int iso_packet_size; - int disc_flag; /* 1 if device was disonnected to avoid some USB actions */ - - usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */ + struct usb_device *dev; /* our device */ + struct usb_interface *intf; /* used interface */ + int if_used; /* used interface number */ + int alt_used; /* used alternate config */ + int cfg_used; /* configuration index used */ + int vend_idx; /* index in hfcsusb_idtab */ + int packet_size; + int iso_packet_size; + int disc_flag; /* 1 if device was disonnected to avoid some USB actions */ + usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */ /* control pipe background handling */ - ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */ - volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */ - struct urb *ctrl_urb; /* transfer structure for control channel */ - struct usb_ctrlrequest ctrl_write; /* buffer for control write request */ - struct usb_ctrlrequest ctrl_read; /* same for read request */ - int ctrl_paksize; /* control pipe packet size */ - int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */ + ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */ + volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */ + struct urb *ctrl_urb; /* transfer structure for control channel */ + struct usb_ctrlrequest ctrl_write; /* buffer for control write request */ + struct usb_ctrlrequest ctrl_read; /* same for read request */ + int ctrl_paksize; /* control pipe packet size */ + int ctrl_in_pipe, ctrl_out_pipe; /* handles for control pipe */ - volatile __u8 threshold_mask; /* threshold in fifo flow control */ - __u8 old_led_state, led_state; + volatile __u8 threshold_mask; /* threshold in fifo flow control */ + __u8 old_led_state, led_state; - __u8 hw_mode; /* TE ?, NT ?, NT Timer runnning? */ - int nt_timer; + __u8 portmode; /* TE ?, NT ?, NT Timer runnning? */ + int nt_timer; } hfcsusb_t; /* private vendor specific data */ typedef struct { - __u8 led_scheme; // led display scheme - signed short led_bits[8]; // array of 8 possible LED bitmask settings - char *vend_name; // device name + __u8 led_scheme; // led display scheme + signed short led_bits[8]; // array of 8 possible LED bitmask settings + char *vend_name; // device name } hfcsusb_vdata; /****************************************/ @@ -208,10 +196,10 @@ static struct usb_device_id hfcsusb_idtab[] = { }; /* some function prototypes */ -static int hfcsusb_l1hwD(mISDNif_t * hif, struct sk_buff *skb); -static int hfcsusb_l2l1B(mISDNif_t * hif, struct sk_buff *skb); -static int mode_bchannel(bchannel_t * bch, int bc, int protocol); -static void hfcsusb_ph_command(hfcsusb_t * card, u_char command); +static int hfcsusb_l2l1(mISDNinstance_t *inst, struct sk_buff *skb); +static int setup_bchannel(channel_t * bch, int protocol); +static void hfcsusb_ph_command(hfcsusb_t * card, u_char command); +static void release_card(hfcsusb_t * card); /******************************************************/ @@ -227,9 +215,9 @@ ctrl_start_transfer(hfcsusb_t * card) card->ctrl_urb->transfer_buffer = NULL; card->ctrl_urb->transfer_buffer_length = 0; card->ctrl_write.wIndex = - card->ctrl_buff[card->ctrl_out_idx].hfcs_reg; + cpu_to_le16(card->ctrl_buff[card->ctrl_out_idx].hfcs_reg); card->ctrl_write.wValue = - card->ctrl_buff[card->ctrl_out_idx].reg_val; + cpu_to_le16(card->ctrl_buff[card->ctrl_out_idx].reg_val); usb_submit_urb(card->ctrl_urb, GFP_ATOMIC); /* start transfer */ } @@ -356,197 +344,24 @@ handle_led(hfcsusb_t * card, int event) write_led(card, card->led_state); } -/* HW lock/unlock functions */ -static int -lock_dev(void *data, int nowait) -{ - register mISDN_HWlock_t *lock = &((hfcsusb_t *) data)->lock; - return (lock_HW(lock, nowait)); -} - -static void -unlock_dev(void *data) -{ - register mISDN_HWlock_t *lock = &((hfcsusb_t *) data)->lock; - unlock_HW(lock); -} - - -static int -hfcsusb_manager(void *data, u_int prim, void *arg) -{ - hfcsusb_t *card; - mISDNinstance_t *inst = data; - struct sk_buff *skb; - int channel = -1; - - if (debug & 0x10000) - printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n", - __FUNCTION__, data, prim, arg); - - if (!data) { - MGR_HASPROTOCOL_HANDLER(prim, arg, &hw_mISDNObj) - printk(KERN_ERR "%s: no data prim %x arg %p\n", - __FUNCTION__, prim, arg); - return (-EINVAL); - } - list_for_each_entry(card, &hw_mISDNObj.ilist, list) { - if (&card->dch.inst == inst) { - channel = 2; - break; - } - if (&card->bch[0].inst == inst) { - channel = 0; - break; - } - if (&card->bch[1].inst == inst) { - channel = 1; - break; - } - } - if (channel < 0) { - printk(KERN_WARNING - "%s: no channel data %p prim %x arg %p\n", - __FUNCTION__, data, prim, arg); - return (-EINVAL); - } - - switch (prim) { - case MGR_REGLAYER | CONFIRM: - if (channel == 2) - dch_set_para(&card->dch, &inst->st->para); - else - bch_set_para(&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 (hfcsusb_l1hwD - (&inst->down, 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 (hfcsusb_l2l1B - (&inst->down, skb)) - dev_kfree_skb(skb); - } - } - hw_mISDNObj.ctrl(inst->up.peer, - MGR_DISCONNECT | REQUEST, - &inst->up); - hw_mISDNObj.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); - else - bch_set_para(&card->bch[channel], arg); - break; - case MGR_RELEASE | INDICATION: - if (debug & 0x10000) - printk(KERN_DEBUG - "%s : ignoring MGR_RELEASE | INDICATION\n", - __FUNCTION__); - /* card get released later at usb disconnect or module removal ... - if (channel == 2) { - release_card(card); - } else { - hfcsusb.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, hfcsusb_l1hwD, - NULL, &card->dch)); - else - return (mISDN_SetIF - (inst, arg, prim, hfcsusb_l2l1B, - NULL, &card->bch[channel])); - break; - case MGR_DISCONNECT | REQUEST: - case MGR_DISCONNECT | INDICATION: - return (mISDN_DisConnectIF(inst, arg)); - case MGR_SETSTACK | CONFIRM: - 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 (hfcsusb_l2l1B - (&inst->down, skb)) - dev_kfree_skb(skb); - } - if (inst->pid.protocol[2] == - ISDN_PID_L2_B_TRANS) - if_link(&inst->up, - DL_ESTABLISH | INDICATION, - 0, 0, NULL, 0); - else - if_link(&inst->up, - PH_ACTIVATE | INDICATION, - 0, 0, NULL, 0); - } - break; - case MGR_GLOBALOPT | REQUEST: - if (arg) { - /* FIXME: detect cards with HEADSET */ - u_int *gopt = arg; - *gopt = GLOBALOPT_INTERNAL_CTRL | - GLOBALOPT_EXTERNAL_EQUIPMENT | - GLOBALOPT_HANDSET; - } else - return (-EINVAL); - break; - case MGR_SELCHANNEL | REQUEST: - return (-EINVAL); - PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION); - default: - printk(KERN_WARNING "%s: prim %x not handled\n", - __FUNCTION__, prim); - return (-EINVAL); - } - return (0); -} /*********************************/ /* S0 state change event handler */ /*********************************/ static void -S0_new_state(dchannel_t * dch) +S0_new_state(channel_t * dch) { - u_int prim = PH_SIGNAL | INDICATION; - u_int para = 0; - mISDNif_t *upif = &dch->inst.up; - hfcsusb_t *card = dch->hw; + u_int prim = PH_SIGNAL | INDICATION; + u_int para = 0; + hfcsusb_t *card = dch->inst.privat; - if (!test_and_clear_bit(D_L1STATECHANGE, &dch->event)) - return; - - if (card->hw_mode & HW_MODE_TE) { + if (card->portmode & PORT_MODE_TE) { if (dch->debug) - mISDN_debugprint(&card->dch.inst, + mISDN_debugprint(&card->chan[D].inst, "%s: TE %d", - __FUNCTION__, dch->ph_state); + __FUNCTION__, dch->state); - switch (dch->ph_state) { + switch (dch->state) { case (0): prim = PH_CONTROL | INDICATION; para = HW_RESET; @@ -570,17 +385,22 @@ S0_new_state(dchannel_t * dch) default: return; } + if (dch->state== 7) + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + else + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + } else { if (dch->debug) - mISDN_debugprint(&card->dch.inst, + mISDN_debugprint(&card->chan[D].inst, "%s: NT %d", - __FUNCTION__, dch->ph_state); + __FUNCTION__, dch->state); - dch->inst.lock(dch->inst.data, 0); - switch (dch->ph_state) { + switch (dch->state) { case (1): + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); card->nt_timer = 0; - card->hw_mode &= ~NT_ACTIVATION_TIMER; + card->portmode &= ~NT_ACTIVATION_TIMER; prim = PH_DEACTIVATE | INDICATION; para = 0; handle_led(card, LED_S0_OFF); @@ -589,38 +409,36 @@ S0_new_state(dchannel_t * dch) case (2): if (card->nt_timer < 0) { card->nt_timer = 0; - card->hw_mode &= ~NT_ACTIVATION_TIMER; + card->portmode &= ~NT_ACTIVATION_TIMER; hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT); } else { - card->hw_mode |= NT_ACTIVATION_TIMER; + card->portmode |= NT_ACTIVATION_TIMER; card->nt_timer = NT_T1_COUNT; /* allow G2 -> G3 transition */ queued_Write_hfc(card, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3); } - upif = NULL; - break; + return; case (3): + test_and_set_bit(FLG_ACTIVE, &dch->Flags); card->nt_timer = 0; - card->hw_mode &= ~NT_ACTIVATION_TIMER; + card->portmode &= ~NT_ACTIVATION_TIMER; prim = PH_ACTIVATE | INDICATION; para = 0; handle_led(card, LED_S0_ON); break; case (4): card->nt_timer = 0; - card->hw_mode &= ~NT_ACTIVATION_TIMER; - upif = NULL; - break; + card->portmode &= ~NT_ACTIVATION_TIMER; + return; default: break; } - dch->inst.unlock(dch->inst.data); + mISDN_queue_data(&dch->inst, dch->inst.id | MSG_BROADCAST, + MGR_SHORTSTATUS | INDICATION, test_bit(FLG_ACTIVE, &dch->Flags) ? + SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED, + 0, NULL, 0); } - - 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); } /******************************/ @@ -629,12 +447,12 @@ S0_new_state(dchannel_t * dch) static void state_handler(hfcsusb_t * card, __u8 new_l1_state) { - if (new_l1_state == card->dch.ph_state + if (new_l1_state == card->chan[D].state || new_l1_state < 1 || new_l1_state > 8) return; - card->dch.ph_state = new_l1_state; - dchannel_sched_event(&card->dch, D_L1STATECHANGE); + card->chan[D].state = new_l1_state; + S0_new_state(&card->chan[D]); } /* @@ -651,17 +469,17 @@ state_handler(hfcsusb_t * card, __u8 new_l1_state) * if the hardware supports more protocols, they should be handled too */ static int -mode_bchannel(bchannel_t * bch, int bc, int protocol) +setup_bchannel(channel_t * bch, int protocol) { __u8 conhdlc, sctrl, sctrl_r; /* conatainer for new register vals */ - hfcsusb_t *card = bch->inst.data; + hfcsusb_t *card = bch->inst.privat; if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, - "protocol %x-->%x ch %d-->%d", - bch->protocol, protocol, - bch->channel, bc); + "protocol %x-->%x channel(%d)", + bch->state, protocol, + bch->channel); /* setup val for CON_HDLC */ conhdlc = 0; @@ -670,20 +488,23 @@ mode_bchannel(bchannel_t * bch, int bc, int protocol) switch (protocol) { case (-1): /* used for init */ - bch->protocol = -1; - bch->channel = bc; + bch->state = -1; /* fall trough */ case (ISDN_PID_NONE): - if (bch->protocol == ISDN_PID_NONE) + if (bch->state == ISDN_PID_NONE) return (0); /* already in idle state */ - 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): conhdlc |= 2; - bch->protocol = protocol; + bch->state = protocol; + set_bit(FLG_TRANSPARENT, &bch->Flags); break; case (ISDN_PID_L1_B_64HDLC): - bch->protocol = protocol; + bch->state = protocol; + set_bit(FLG_HDLC, &bch->Flags); break; default: mISDN_debugprint(&bch->inst, "prot not known %x", @@ -704,37 +525,28 @@ mode_bchannel(bchannel_t * bch, int bc, int protocol) queued_Write_hfc(card, HFCUSB_FIFO, ((bch->channel)?3:1)); queued_Write_hfc(card, HFCUSB_CON_HDLC, conhdlc); - + /* reset fifo */ queued_Write_hfc(card, HFCUSB_INC_RES_F, 2); - sctrl = 0x40 + ((card->hw_mode & HW_MODE_TE)?0x00:0x04); + sctrl = 0x40 + ((card->portmode & PORT_MODE_TE)?0x00:0x04); sctrl_r = 0x0; - - if (card->bch[0].protocol) { - sctrl |= ((card->bch[0].channel)?2:1); - sctrl_r |= ((card->bch[0].channel)?2:1); + + if (card->chan[B1].state) { + sctrl |= ((card->chan[B1].channel)?2:1); + sctrl_r |= ((card->chan[B1].channel)?2:1); } - - if (card->bch[1].protocol) { - sctrl |= ((card->bch[1].channel)?2:1); - sctrl_r |= ((card->bch[1].channel)?2:1); + + if (card->chan[B2].state) { + sctrl |= ((card->chan[B2].channel)?2:1); + sctrl_r |= ((card->chan[B2].channel)?2:1); } - card->fifos[HFCUSB_B1_RX].bch_idx = 0; /* bch[0] linked to B1 */ - card->fifos[HFCUSB_B1_TX].bch_idx = 0; - card->fifos[HFCUSB_B2_RX].bch_idx = 1; /* bch[1] linked to B2 */ - card->fifos[HFCUSB_B2_TX].bch_idx = 1; - queued_Write_hfc(card, HFCUSB_SCTRL, sctrl); queued_Write_hfc(card, HFCUSB_SCTRL_R, sctrl_r); if (protocol > ISDN_PID_NONE) { handle_led(card, ((bch->channel)?LED_B2_ON:LED_B1_ON)); - - /* signal the channel has space for transmit data */ - bch_sched_event(bch, B_XMTBUFREADY); - } else { handle_led(card, ((bch->channel)?LED_B2_OFF:LED_B1_OFF)); } @@ -745,43 +557,33 @@ mode_bchannel(bchannel_t * bch, int bc, int protocol) static void hfcsusb_ph_command(hfcsusb_t * card, u_char command) { - if (card->dch.debug & L1_DEB_ISAC) - mISDN_debugprint(&card->dch.inst, "hfcsusb_ph_command %x", + if (card->chan[D].debug & L1_DEB_ISAC) + mISDN_debugprint(&card->chan[D].inst, "hfcsusb_ph_command %x", command); switch (command) { case HFC_L1_ACTIVATE_TE: /* force sending sending INFO1 */ - queued_Write_hfc(card, - HFCUSB_STATES, 0x14); - - schedule_timeout((1 * HZ) / 1000); /* sleep 1ms */ - + queued_Write_hfc(card, HFCUSB_STATES, 0x14); /* start l1 activation */ - queued_Write_hfc(card, - HFCUSB_STATES, 0x04); + queued_Write_hfc(card, HFCUSB_STATES, 0x04); break; - case HFC_L1_DEACTIVATE_TE: - queued_Write_hfc(card, - HFCUSB_STATES, 0x10); - - queued_Write_hfc(card, - HFCUSB_STATES, 0x03); + case HFC_L1_FORCE_DEACTIVATE_TE: + queued_Write_hfc(card, HFCUSB_STATES, 0x10); + queued_Write_hfc(card, HFCUSB_STATES, 0x03); break; case HFC_L1_ACTIVATE_NT: - queued_Write_hfc(card, - HFCUSB_STATES, - HFCUSB_ACTIVATE - | HFCUSB_DO_ACTION - | HFCUSB_NT_G2_G3); + queued_Write_hfc(card, HFCUSB_STATES, + HFCUSB_ACTIVATE + | HFCUSB_DO_ACTION + | HFCUSB_NT_G2_G3); break; case HFC_L1_DEACTIVATE_NT: - queued_Write_hfc(card, - HFCUSB_STATES, - HFCUSB_DO_ACTION); + queued_Write_hfc(card, HFCUSB_STATES, + HFCUSB_DO_ACTION); break; } } @@ -790,114 +592,162 @@ hfcsusb_ph_command(hfcsusb_t * card, u_char command) /* Layer 1 D-channel hardware access */ /*************************************/ static int -hfcsusb_l1hwD(mISDNif_t * hif, struct sk_buff *skb) +handle_dmsg(channel_t *dch, struct sk_buff *skb) { - dchannel_t *dch;; - int ret = -EINVAL; - mISDN_head_t *hh; - hfcsusb_t *card; - - if (!hif || !skb) - return (ret); - hh = mISDN_HEAD_P(skb); - dch = hif->fdata; - mISDNif_t *upif = &dch->inst.up; - card = dch->hw; - ret = 0; - - if (hh->prim == PH_DATA_REQ) { - if (dch->next_skb) { - mISDN_debugprint(&dch->inst, - "hfcsusb 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 { - /* prepare buffer, which is transmitted by - tx_iso completions later */ - dch->tx_len = skb->len; - memcpy(dch->tx_buf, skb->data, dch->tx_len); - dch->tx_idx = 0; - dch->inst.unlock(dch->inst.data); - skb_trim(skb, 0); - return (if_newhead(&dch->inst.up, PH_DATA_CNF, - hh->dinfo, skb)); - } - } else if (hh->prim == (PH_SIGNAL | REQUEST)) { - /* do not handle INFO3_P8 and INFO3_P10 */ + int ret = 0; + mISDN_head_t *hh = mISDN_HEAD_P(skb); + hfcsusb_t *hw = dch->hw; + + if (hh->prim == (PH_SIGNAL | REQUEST)) { ret = -EINVAL; } else if (hh->prim == (PH_CONTROL | REQUEST)) { - dch->inst.lock(dch->inst.data, 0); if (hh->dinfo == HW_RESET) { - if (dch->ph_state != 0) - hfcsusb_ph_command(dch->hw, - HFC_L1_ACTIVATE_TE); - while (upif) { - if_link(upif, PH_CONTROL | INDICATION, - HW_POWERUP, 0, NULL, 0); - upif = upif->clone; - } - } else if (hh->dinfo == HW_POWERUP) { - hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_TE); + if (dch->state != 0) + hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE); + skb_trim(skb, 0); + return(mISDN_queueup_newhead(&dch->inst, 0, PH_CONTROL | INDICATION,HW_POWERUP, skb)); } 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_L1_DBUSY, &dch->DFlags)) + test_and_clear_bit(FLG_TX_NEXT, &dch->Flags); + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_DBUSY, &dch->Flags)) dchannel_sched_event(dch, D_CLEARBUSY); - } else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) { - u_char val = 0; - - if (1 & hh->dinfo) - val |= 0x0c; - if (2 & hh->dinfo) - val |= 0x3; - /* !!! not implemented yet */ +#endif + } else if (hh->dinfo == HW_POWERUP) { + hfcsusb_ph_command(hw, HFC_L1_FORCE_DEACTIVATE_TE); } else { if (dch->debug & L1_DEB_WARN) mISDN_debugprint(&dch->inst, - "hfcsusb_l1hw unknown ctrl %x", - hh->dinfo); + "hfcsusb_l1hw unknown ctrl %x", + hh->dinfo); ret = -EINVAL; } - dch->inst.unlock(dch->inst.data); } else if (hh->prim == (PH_ACTIVATE | REQUEST)) { - dch->inst.lock(dch->inst.data, 0); - if (card->hw_mode & HW_MODE_NT) { - hfcsusb_ph_command(dch->hw, HFC_L1_ACTIVATE_NT); + if (hw->portmode & PORT_MODE_NT) { + hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_NT); } else { if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "%s: PH_ACTIVATE none NT mode", + mISDN_debugprint(&dch->inst, + "%s: PH_ACTIVATE none NT mode", __FUNCTION__); - ret = -EINVAL; + ret = -EINVAL; } - dch->inst.unlock(dch->inst.data); } else if (hh->prim == (PH_DEACTIVATE | REQUEST)) { - dch->inst.lock(dch->inst.data, 0); - if (card->hw_mode & HW_MODE_NT) { - hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT); + if (hw->portmode & PORT_MODE_NT) { + hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT); + if (test_and_clear_bit(FLG_TX_NEXT, &dch->Flags)) { + dev_kfree_skb(dch->next_skb); + dch->next_skb = NULL; + } + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); } else { if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "%s: PH_DEACTIVATE none NT mode", + mISDN_debugprint(&dch->inst, + "%s: PH_DEACTIVATE none NT mode", __FUNCTION__); - ret = -EINVAL; + ret = -EINVAL; } - dch->inst.unlock(dch->inst.data); + } else if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) { + u_int temp = hh->dinfo & SSTATUS_ALL; // remove SSTATUS_BROADCAST_BIT + if ((hw->portmode & PORT_MODE_NT) && + (temp == SSTATUS_ALL || temp == SSTATUS_L1)) { + if (hh->dinfo & SSTATUS_BROADCAST_BIT) + temp = dch->inst.id | MSG_BROADCAST; + else + temp = hh->addr | FLG_MSG_TARGET; + skb_trim(skb, 0); + hh->dinfo = test_bit(FLG_ACTIVE, &dch->Flags) ? + SSTATUS_L1_ACTIVATED : SSTATUS_L1_DEACTIVATED; + hh->prim = MGR_SHORTSTATUS | CONFIRM; + return(mISDN_queue_message(&dch->inst, temp, skb)); + } + ret = -EOPNOTSUPP; } else { - if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, - "hfcsusb_l1hw unknown prim %x", - hh->prim); - ret = -EINVAL; + printk(KERN_WARNING "%s %s: unknown prim(%x)\n", + dch->inst.name, __FUNCTION__, hh->prim); + ret = -EAGAIN; + } + if (!ret) + dev_kfree_skb(skb); + return (ret); +} + +/*************************************/ +/* Layer 1 B-channel hardware access */ +/*************************************/ +static int +handle_bmsg(channel_t *bch, struct sk_buff *skb) +{ + int ret = 0; + mISDN_head_t *hh = mISDN_HEAD_P(skb); + + if ((hh->prim == (PH_ACTIVATE | REQUEST)) || + (hh->prim == (DL_ESTABLISH | REQUEST))) { + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { + ret = setup_bchannel(bch, bch->inst.pid.protocol[1]); + if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANS) + test_and_set_bit(FLG_L2DATA, &bch->Flags); + } +#ifdef FIXME + if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) + if (bch->dev) + if_link(&bch->dev->rport.pif, + hh->prim | CONFIRM, 0, 0, NULL, 0); +#endif + skb_trim(skb, 0); + return(mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, ret, skb)); + } else if ((hh->prim == (PH_DEACTIVATE | REQUEST)) || + (hh->prim == (DL_RELEASE | REQUEST)) || + ((hh->prim == (PH_CONTROL | REQUEST) && (hh->dinfo == HW_DEACTIVATE)))) { + + if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { + dev_kfree_skb(bch->next_skb); + bch->next_skb = NULL; + } + if (bch->tx_skb) { + dev_kfree_skb(bch->tx_skb); + bch->tx_skb = NULL; + } + bch->tx_idx = 0; + if (bch->rx_skb) { + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } + test_and_clear_bit(FLG_L2DATA, &bch->Flags); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + setup_bchannel(bch, ISDN_PID_NONE); + test_and_clear_bit(FLG_ACTIVE, &bch->Flags); + skb_trim(skb, 0); + if (hh->prim != (PH_CONTROL | REQUEST)) { +#ifdef FIXME + if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) + if (bch->dev) + if_link(&bch->dev->rport.pif, + hh->prim | CONFIRM, 0, 0, NULL, 0); +#endif + if (!mISDN_queueup_newhead(&bch->inst, 0, hh->prim | CONFIRM, 0, skb)) + return(0); + } + } else if (hh->prim == (PH_CONTROL | REQUEST)) { + // do not handle PH_CONTROL | REQUEST ?? + } else { + printk(KERN_WARNING "%s %s: unknown prim(%x)\n", + bch->inst.name, __FUNCTION__, hh->prim); + ret = -EAGAIN; } if (!ret) dev_kfree_skb(skb); @@ -908,274 +758,204 @@ hfcsusb_l1hwD(mISDNif_t * hif, struct sk_buff *skb) /* Layer2 -> Layer 1 Transfer */ /******************************/ static int -hfcsusb_l2l1B(mISDNif_t * hif, struct sk_buff *skb) +hfcsusb_l2l1(mISDNinstance_t *inst, struct sk_buff *skb) { - bchannel_t *bch; - int ret = -EINVAL; - mISDN_head_t *hh; - - hfcsusb_t *card; + channel_t *chan = container_of(inst, channel_t, inst); + int ret = 0; + mISDN_head_t *hh = mISDN_HEAD_P(skb); - if (!hif || !skb) - return (ret); - hh = mISDN_HEAD_P(skb); - bch = hif->fdata; - - card = bch->hw; - - if ((hh->prim == PH_DATA_REQ) || (hh->prim == (DL_DATA | REQUEST))) { - if (bch->next_skb) { - printk(KERN_WARNING "%s: next_skb exist ERROR\n", - __FUNCTION__); - 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 { - /* prepare buffer, wich is transmitted by - tx_iso completions later */ - bch->tx_len = skb->len; - memcpy(bch->tx_buf, skb->data, bch->tx_len); - bch->tx_idx = 0; - bch->inst.unlock(bch->inst.data); - if ((bch->inst.pid.protocol[2] == - ISDN_PID_L2_B_RAWDEV) - && bch->dev) - hif = &bch->dev->rport.pif; - else - hif = &bch->inst.up; - skb_trim(skb, 0); - return (if_newhead(hif, 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)) + if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) { + ret = channel_senddata(chan, hh->dinfo, skb); + if (ret > 0) { + /* data gets transmitted later in USB ISO OUT traffic */ ret = 0; - else { - bch->inst.lock(bch->inst.data, 0); - ret = - mode_bchannel(bch, bch->channel, - bch->inst.pid.protocol[1]); - bch->inst.unlock(bch->inst.data); } - if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - if (bch->dev) - if_link(&bch->dev->rport.pif, - hh->prim | CONFIRM, 0, 0, NULL, 0); - skb_trim(skb, 0); - return (if_newhead - (&bch->inst.up, 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)) { - dev_kfree_skb(bch->next_skb); - bch->next_skb = NULL; - } - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - mode_bchannel(bch, bch->channel, ISDN_PID_NONE); - test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag); - bch->inst.unlock(bch->inst.data); - skb_trim(skb, 0); - if (hh->prim != (MGR_DISCONNECT | REQUEST)) { - if (bch->inst.pid.protocol[2] == - ISDN_PID_L2_B_RAWDEV) - if (bch->dev) - if_link(&bch->dev->rport.pif, - hh->prim | CONFIRM, 0, 0, - NULL, 0); - if (!if_newhead - (&bch->inst.up, hh->prim | CONFIRM, 0, skb)) - return (0); - } - - ret = 0; - } else if (hh->prim == (PH_CONTROL | REQUEST)) { - // do not handle PH_CONTROL | REQUEST ?? - } else { - printk(KERN_WARNING "%s: unknown prim(%x)\n", - __FUNCTION__, hh->prim); + return(ret); + } + if (test_bit(FLG_DCHANNEL, &chan->Flags)) { + ret = handle_dmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; + } + if (test_bit(FLG_BCHANNEL, &chan->Flags)) { + ret = handle_bmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; } if (!ret) dev_kfree_skb(skb); - return (ret); + return(ret); } -/*****************************************************/ -/* collect data from interrupt or isochron in */ -/*****************************************************/ -static void -collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish) + +static int +hfcsusb_manager(void *data, u_int prim, void *arg) { - hfcsusb_t *card = fifo->card; + hfcsusb_t *hw = NULL; + mISDNinstance_t *inst = data; struct sk_buff *skb; - u_char *ptr; - int fifon; + int channel = -1; int i; + channel_t *chan = NULL; + u_long flags; - fifon = fifo->fifonum; - - if (!fifo->skbuff) { - fifo->skbuff = dev_alloc_skb(fifo->max_size + 3); - if (!fifo->skbuff) { - printk(KERN_INFO - "HFC-S USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n", - fifon); - return; - } + if (!data) { + MGR_HASPROTOCOL_HANDLER(prim, arg, &hw_mISDNObj) + printk(KERN_ERR "%s %s: no data prim %x arg %p\n", + hw->chan[D].inst.name, __FUNCTION__, prim, arg); + return (-EINVAL); } - if (len) { - if (fifo->skbuff->len + len < fifo->max_size) { - memcpy(skb_put(fifo->skbuff, len), data, len); - } else { + + spin_lock_irqsave(&hw_mISDNObj.lock, flags); - if (debug & 0x10000) { - printk(KERN_INFO "HFC-S USB: "); - for (i = 0; i < 15; i++) - printk("%.2x ", - fifo->skbuff->data[fifo-> - skbuff-> - len - - 15 + i]); - printk("\n"); + /* find channel and card */ + list_for_each_entry(hw, &hw_mISDNObj.ilist, list) { + i = 0; + while (i < MAX_CHAN) { + if (hw->chan[i].Flags && + &hw->chan[i].inst == inst) { + channel = i; + chan = &hw->chan[i]; + break; } - - printk(KERN_INFO - "HCF-USB: got frame exceeded fifo->max_size:%d on fifo:%d\n", - fifo->max_size, fifon); + i++; } + if (channel >= 0) + break; + } + spin_unlock_irqrestore(&hw_mISDNObj.lock, flags); + + if (channel < 0) { + printk(KERN_ERR + "%s: no card/channel found data %p prim %x arg %p\n", + __FUNCTION__, data, prim, arg); + return (-EINVAL); } - /* Transparent mode data to upper layer */ - if ((fifon == HFCUSB_B1_RX) || (fifon == HFCUSB_B2_RX)) { - if (card->bch[fifo->bch_idx].protocol == ISDN_PID_L1_B_64TRANS) { - if (fifo->skbuff->len >= 128) { - if (!(skb = alloc_stack_skb(fifo->skbuff->len, - card->bch->up_headerlen))) - printk(KERN_WARNING "HFC-S USB: receive out of memory\n"); - else { - ptr = - skb_put(skb, - fifo->skbuff-> - len); - memcpy(ptr, fifo->skbuff->data, - fifo->skbuff->len); - dev_kfree_skb(fifo->skbuff); - fifo->skbuff=NULL; - - skb_queue_tail(&card->bch[fifo->bch_idx]. - rqueue, - skb); - - bch_sched_event(&card->bch[fifo->bch_idx], B_RCVBUFREADY); - } - } - return; - } - } - - /* we have a complete hdlc packet */ - if (finish) { - if ((!fifo->skbuff->data[fifo->skbuff->len - 1]) - && (fifo->skbuff->len > 3)) { - /* remove CRC & status */ - skb_trim(fifo->skbuff, fifo->skbuff->len - 3); - - switch (fifon) { - case HFCUSB_D_RX: - if ((skb = - alloc_stack_skb(fifo->skbuff-> - len, - card->dch. - up_headerlen))) - { - ptr = - skb_put(skb, - fifo->skbuff-> - len); - memcpy(ptr, fifo->skbuff->data, fifo->skbuff->len); - dev_kfree_skb(fifo->skbuff); - fifo->skbuff=NULL; - - skb_queue_tail(&card->dch. - rqueue, - skb); - - dchannel_sched_event - (&card->dch, - D_RCVBUFREADY); - - } else { - printk(KERN_WARNING - "HFC-S USB: D receive out of memory\n"); - } - break; - case HFCUSB_B1_RX: - case HFCUSB_B2_RX: - if (card->bch[fifo->bch_idx].protocol > ISDN_PID_NONE) { - if ((skb = - alloc_stack_skb(fifo->skbuff-> - len, - card-> - bch[fifo->bch_idx]. - up_headerlen))) - { - ptr = - skb_put(skb, - fifo->skbuff-> - len); - memcpy(ptr, fifo->skbuff->data, fifo->skbuff->len); - dev_kfree_skb(fifo->skbuff); - fifo->skbuff=NULL; - - skb_queue_tail(&card-> - bch - [fifo->bch_idx]. - rqueue, - skb); - bch_sched_event(&card-> - bch - [fifo->bch_idx], - B_RCVBUFREADY); - } else { - printk(KERN_WARNING - "HFC-S USB: B%i receive out of memory\n", - fifo->bch_idx); - } - } - break; - default: - printk(KERN_WARNING - "HFC-S USB: FIFO UNKWON!\n"); - } - - } else { - if (fifo->skbuff->len > 3) { - printk(KERN_INFO - "HFC-S USB: got frame %d bytes but CRC ERROR on fifo:%d!!!\n", - fifo->skbuff->len, fifon); - if (debug & 0x10000) { - printk(KERN_INFO "HFC-S USB: "); - for (i = 0; i < 15; i++) - printk("%.2x ", - fifo->skbuff-> - data[fifo->skbuff-> - len - 15 + i]); - printk("\n"); - } + switch (prim) { + case MGR_REGLAYER | CONFIRM: + mISDN_setpara(chan, &inst->st->para); + break; + case MGR_UNREGLAYER | REQUEST: + if ((skb = create_link_skb(PH_CONTROL | REQUEST, + HW_DEACTIVATE, 0, NULL, 0))) { + if (hfcsusb_l2l1(inst, skb)) + dev_kfree_skb(skb); + } else + printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__); + hw_mISDNObj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL); + break; + case MGR_CLRSTPARA | INDICATION: + arg = NULL; + case MGR_ADDSTPARA | INDICATION: + mISDN_setpara(chan, arg); + break; + case MGR_RELEASE | INDICATION: + if (channel == 2) { + release_card(hw); } else { - printk(KERN_INFO - "HFC-S USB: frame to small (%d bytes)!!!\n", - fifo->skbuff->len); + hw_mISDNObj.refcnt--; } - skb_trim(fifo->skbuff, 0); + break; + case MGR_SETSTACK | INDICATION: + if ((channel != 2) && (inst->pid.global == 2)) { + if ((skb = create_link_skb(PH_ACTIVATE | REQUEST, + 0, 0, NULL, 0))) { + if (hfcsusb_l2l1(inst, skb)) + dev_kfree_skb(skb); + } + if (inst->pid.protocol[2] == ISDN_PID_L2_B_TRANS) + mISDN_queue_data(inst, FLG_MSG_UP, DL_ESTABLISH | INDICATION, + 0, 0, NULL, 0); + else + mISDN_queue_data(inst, FLG_MSG_UP, PH_ACTIVATE | INDICATION, + 0, 0, NULL, 0); + } + break; + case MGR_GLOBALOPT | REQUEST: + if (arg) { + // FIXME: detect cards with HEADSET + u_int *gopt = arg; + *gopt = GLOBALOPT_INTERNAL_CTRL | + GLOBALOPT_EXTERNAL_EQUIPMENT | + GLOBALOPT_HANDSET; + } else + return (-EINVAL); + break; + case MGR_SELCHANNEL | REQUEST: + // no special procedure + return (-EINVAL); + PRIM_NOT_HANDLED(MGR_CTRLREADY | INDICATION); + default: + printk(KERN_WARNING "%s %s: prim %x not handled\n", + hw->chan[D].inst.name, __FUNCTION__, prim); + return (-EINVAL); + } + return (0); +} + + +/***********************************************/ +/* collect data from interrupt or isochron in */ +/***********************************************/ +static void +collect_rx_frame(usb_fifo * fifo, __u8 * data, unsigned int len, int finish) +{ + hfcsusb_t *card = fifo->card; + channel_t *ch = &card->chan[fifo->ch_idx]; + struct sk_buff *skb; /* data buffer for upper layer */ + int fifon; + + if (!len) + return; + + fifon = fifo->fifonum; + + if (!ch->rx_skb) { + ch->rx_skb = alloc_stack_skb(ch->maxlen + 3, ch->up_headerlen); + if (!ch->rx_skb) { + printk(KERN_DEBUG "%s: No mem for rx_skb\n", __FUNCTION__); + return; + } + } + memcpy(skb_put(ch->rx_skb, len), data, len); + + if (test_bit(FLG_HDLC, &ch->Flags)) { + /* we have a complete hdlc packet */ + if (finish) { + if ((ch->rx_skb->len > 3) && + (!(ch->rx_skb->data[ch->rx_skb->len - 1]))) { + + /* remove CRC & status */ + skb_trim(ch->rx_skb, ch->rx_skb->len - 3); + + if (ch->rx_skb->len < MISDN_COPY_SIZE) { + skb = alloc_stack_skb(ch->rx_skb->len, ch->up_headerlen); + if (skb) { + memcpy(skb_put(skb, ch->rx_skb->len), + ch->rx_skb->data, ch->rx_skb->len); + skb_trim(ch->rx_skb, 0); + } else { + skb = ch->rx_skb; + ch->rx_skb = NULL; + } + } else { + skb = ch->rx_skb; + ch->rx_skb = NULL; + } + queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, skb); + + } else { + printk ("HFC-S USB: CRC or minlen ERROR\n"); + } + } + } else { + if (ch->rx_skb->len >= TRANSP_PACKET_SIZE) { + /* deliver transparent data to layer2 */ + queue_ch_frame(ch, INDICATION, MISDN_ID_ANY, ch->rx_skb); + ch->rx_skb = NULL; } } } @@ -1243,7 +1023,7 @@ rx_iso_complete(struct urb *urb, struct pt_regs *regs) /* care for L1 state only for D-Channel to avoid overlapped iso completions */ - if (fifon == 5) { + if (fifon == HFCUSB_D_RX) { /* the S0 state is in the upper half of the 1st status byte */ state_handler(card, buf[0] >> 4); @@ -1253,9 +1033,7 @@ rx_iso_complete(struct urb *urb, struct pt_regs *regs) if (len > 2) collect_rx_frame(fifo, buf + 2, len - 2, - (len < - maxlen) ? - eof[fifon] : 0); + (len < maxlen) ? eof[fifon] : 0); } else { collect_rx_frame(fifo, buf, len, (len < @@ -1308,16 +1086,12 @@ rx_int_complete(struct urb *urb, struct pt_regs *regs) urb->status); fifo->urb->interval = 0; /* cancel automatic rescheduling */ - if (fifo->skbuff) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - } return; } len = urb->actual_length; buf = fifo->buffer; maxlen = fifo->usb_packet_maxlen; - + if (fifo->last_urblen != fifo->usb_packet_maxlen) { /* the threshold mask is in the 2nd status byte */ card->threshold_mask = buf[1]; @@ -1336,6 +1110,7 @@ rx_int_complete(struct urb *urb, struct pt_regs *regs) (len < maxlen) ? eof[fifon] : 0); } fifo->last_urblen = urb->actual_length; + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { printk(KERN_INFO @@ -1344,44 +1119,38 @@ rx_int_complete(struct urb *urb, struct pt_regs *regs) } /* rx_int_complete */ -void -next_d_tx_frame(hfcsusb_t * card) +/***********************************/ +/* check if new buffer for channel */ +/* is waitinng is transmitt queue */ +/***********************************/ +int +next_tx_frame(hfcsusb_t * hw, __u8 channel) { - if (test_and_clear_bit(FLG_TX_NEXT, &card->dch.DFlags)) { - if (card->dch.next_skb) { - card->dch.tx_len = card->dch.next_skb->len; - memcpy(card->dch.tx_buf, - card->dch.next_skb->data, card->dch.tx_len); - card->dch.tx_idx = 0; - dchannel_sched_event(&card->dch, D_XMTBUFREADY); + channel_t *ch = &hw->chan[channel]; + + if (ch->tx_skb) + dev_kfree_skb(ch->tx_skb); + if (test_and_clear_bit(FLG_TX_NEXT, &ch->Flags)) { + ch->tx_skb = ch->next_skb; + if (ch->tx_skb) { + mISDN_head_t *hh = mISDN_HEAD_P(ch->tx_skb); + ch->next_skb = NULL; + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); + ch->tx_idx = 0; + queue_ch_frame(ch, CONFIRM, hh->dinfo, NULL); + return (1); } else { printk(KERN_WARNING - "hfcd tx irq TX_NEXT without skb\n"); - test_and_clear_bit(FLG_TX_BUSY, &card->dch.DFlags); + "%s channel(%i) TX_NEXT without skb\n", + ch->inst.name, channel); + test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); } } else - test_and_clear_bit(FLG_TX_BUSY, &card->dch.DFlags); + ch->tx_skb = NULL; + test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); + return (0); } -void -next_b_tx_frame(hfcsusb_t * card, __u8 bch_idx) -{ - if (test_and_clear_bit(BC_FLG_TX_NEXT, &card->bch[bch_idx].Flag)) { - if (card->bch[bch_idx].next_skb) { - card->bch[bch_idx].tx_idx = 0; - card->bch[bch_idx].tx_len = - card->bch[bch_idx].next_skb->len; - memcpy(card->bch[bch_idx].tx_buf, - card->bch[bch_idx].next_skb->data, - card->bch[bch_idx].tx_len); - bch_sched_event(&card->bch[bch_idx], - B_XMTBUFREADY); - } else - printk(KERN_WARNING - "hfc B%i tx irq TX_NEXT without skb\n", - bch_idx); - } -} /*****************************************************/ /* transmit completion routine for all ISO tx fifos */ @@ -1392,11 +1161,10 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; usb_fifo *fifo = context_iso_urb->owner_fifo; hfcsusb_t *card = fifo->card; - int k, tx_offset, num_isoc_packets, sink, len, current_len, + channel_t *ch = &card->chan[fifo->ch_idx]; + int k, tx_offset, num_isoc_packets, sink, remain, current_len, errcode; - int *tx_len, *tx_idx; - u_char *tx_buf; - int frame_complete, transp_mode=0, fifon, status; + int frame_complete, fifon, status; __u8 threshbit; __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 }; @@ -1404,7 +1172,7 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) status = urb->status; tx_offset = 0; - + if (fifo->active && !status) { /* is FifoFull-threshold set for our channel? */ threshbit = threshtable[fifon] & card->threshold_mask; @@ -1424,49 +1192,31 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) sizeof(context_iso_urb->buffer)); frame_complete = 0; - switch (fifon) { - case HFCUSB_D_TX: - tx_buf = card->dch.tx_buf; - tx_len = &card->dch.tx_len; - tx_idx = &card->dch.tx_idx; - break; - case HFCUSB_B1_TX: - case HFCUSB_B2_TX: - tx_buf = card->bch[fifo->bch_idx].tx_buf; - tx_len = &card->bch[fifo->bch_idx].tx_len; - tx_idx = &card->bch[fifo->bch_idx].tx_idx; - transp_mode = card->bch[fifo->bch_idx].protocol == ISDN_PID_L1_B_64TRANS; - break; - default: - /* should never happen ... */ - tx_buf = NULL; - tx_len = 0; - tx_idx = 0; - } - /* Generate next Iso Packets */ for (k = 0; k < num_isoc_packets; ++k) { - len = (*tx_len - *tx_idx); - if (len) { + if (ch->tx_skb) { + remain = ch->tx_skb->len - ch->tx_idx; + } else { + remain = 0; + } + if (remain>0) { /* we lower data margin every msec */ fifo->bit_line -= sink; current_len = (0 - fifo->bit_line) / 8; + /* maximum 15 byte for every ISO packet makes our life easier */ if (current_len > 14) current_len = 14; - current_len = - (len <= - current_len) ? len : current_len; + current_len = (remain <= current_len) ? remain : current_len; /* how much bit do we put on the line? */ fifo->bit_line += current_len * 8; context_iso_urb->buffer[tx_offset] = 0; - if (current_len == len) { - if (!transp_mode) { + if (current_len == remain) { + if (test_bit(FLG_HDLC, &ch->Flags)) { /* here frame completion */ - context_iso_urb-> - buffer[tx_offset] = 1; + context_iso_urb->buffer[tx_offset] = 1; /* add 2 byte flags and 16bit CRC at end of ISDN frame */ fifo->bit_line += 32; } @@ -1474,20 +1224,17 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) } /* copy tx data to iso-urb buffer */ - memcpy(context_iso_urb->buffer + - tx_offset + 1, - (tx_buf + *tx_idx), current_len); - *tx_idx += current_len; + memcpy(context_iso_urb->buffer + tx_offset + 1, + (ch->tx_skb->data + ch->tx_idx), current_len); + ch->tx_idx += current_len; /* define packet delimeters within the URB buffer */ urb->iso_frame_desc[k].offset = tx_offset; - urb->iso_frame_desc[k].length = - current_len + 1; + urb->iso_frame_desc[k].length = current_len + 1; tx_offset += (current_len + 1); } else { - urb->iso_frame_desc[k].offset = - tx_offset++; + urb->iso_frame_desc[k].offset = tx_offset++; urb->iso_frame_desc[k].length = 1; fifo->bit_line -= sink; /* we lower data margin every msec */ @@ -1497,41 +1244,9 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) } } - if (frame_complete) { - fifo->delete_flg = 1; + if (frame_complete) + next_tx_frame(card, fifo->ch_idx); - /* check for next tx data in queue */ - switch (fifon) { - case HFCUSB_D_TX: - next_d_tx_frame(card); - if (fifo->skbuff - && fifo->delete_flg) { - dev_kfree_skb_any - (fifo->skbuff); - fifo->skbuff = - NULL; - fifo->delete_flg = - 0; - } - frame_complete = 0; - break; - - case HFCUSB_B1_TX: - case HFCUSB_B2_TX: - next_b_tx_frame(card, fifo->bch_idx); - - card->bch[fifo->bch_idx].tx_len = - 0; - test_and_clear_bit - (BC_FLG_TX_BUSY, - &card->bch[fifo->bch_idx]. - Flag); - card->bch[fifo->bch_idx].tx_idx = - card->bch[fifo->bch_idx]. - tx_len; - break; - } - } } errcode = usb_submit_urb(urb, GFP_ATOMIC); if (errcode < 0) { @@ -1544,10 +1259,10 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs) abuse DChannel tx iso completion to trigger NT mode state changes tx_iso_complete is assumed to be called every fifo->intervall ms */ - if ((fifon == HFCUSB_D_TX) && (card->hw_mode & HW_MODE_NT) - && (card->hw_mode & NT_ACTIVATION_TIMER)) { + if ((fifon == HFCUSB_D_TX) && (card->portmode & PORT_MODE_NT) + && (card->portmode & NT_ACTIVATION_TIMER)) { if ((--card->nt_timer) < 0) - dchannel_sched_event(&card->dch, D_L1STATECHANGE); + S0_new_state(&card->chan[D]); } } else { @@ -1673,27 +1388,9 @@ start_int_fifo(usb_fifo * fifo) "HFC-S USB: submit URB error(start_int_info): status:%i\n", errcode); fifo->active = 0; - fifo->skbuff = NULL; } } -/* - * hardware init function, called after the basic - * struct's and stack's were setuped - * - */ -void -hw_init(hfcsusb_t * card) -{ - /* setup basic function pointers */ - card->dch.hw_bh = S0_new_state; - - /* init bchannel mode */ - mode_bchannel(&card->bch[0], 0, -1); - mode_bchannel(&card->bch[1], 1, -1); - card->dch.ph_state = 0; -} - /* Hardware Initialization */ int setup_hfcsusb(hfcsusb_t * card) @@ -1740,7 +1437,6 @@ setup_hfcsusb(hfcsusb_t * card) fifo = card->fifos; for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { write_usb(card, HFCUSB_FIFO, i); /* select the desired fifo */ - fifo[i].skbuff = NULL; /* init buffer pointer */ fifo[i].max_size = (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; fifo[i].last_urblen = 0; @@ -1753,7 +1449,7 @@ setup_hfcsusb(hfcsusb_t * card) write_usb(card, HFCUSB_INC_RES_F, 2); /* reset the fifo */ } - if (card->hw_mode & HW_MODE_NT) { + if (card->portmode & PORT_MODE_NT) { write_usb(card, HFCUSB_SCTRL, 0x44); /* disable B transmitters + capacitive mode, enable NT mode */ write_usb(card, HFCUSB_CLKDEL, CLKDEL_NT); /* clock delay value */ write_usb(card, HFCUSB_STATES, 1 | 0x10); /* set deactivated mode */ @@ -1774,7 +1470,7 @@ setup_hfcsusb(hfcsusb_t * card) /* init the background machinery for control requests */ card->ctrl_read.bRequestType = 0xc0; card->ctrl_read.bRequest = 1; - card->ctrl_read.wLength = 1; + card->ctrl_read.wLength = cpu_to_le16(1); card->ctrl_write.bRequestType = 0x40; card->ctrl_write.bRequest = 0; card->ctrl_write.wLength = 0; @@ -1791,15 +1487,16 @@ setup_hfcsusb(hfcsusb_t * card) card->fifos[i].active = 0; } - /* 3 (+1) INT IN + 3 ISO OUT */ if (card->cfg_used == CNF_3INT3ISO || card->cfg_used == CNF_4INT3ISO) { + start_int_fifo(card->fifos + HFCUSB_D_RX); /* if (card->fifos[HFCUSB_PCM_RX].pipe) start_int_fifo(card->fifos + HFCUSB_PCM_RX); */ + start_int_fifo(card->fifos + HFCUSB_B1_RX); start_int_fifo(card->fifos + HFCUSB_B2_RX); } @@ -1823,6 +1520,7 @@ setup_hfcsusb(hfcsusb_t * card) ISOC_PACKETS_B, rx_iso_complete, 16); } + start_isoc_chain(card->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, tx_iso_complete, 1); start_isoc_chain(card->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, @@ -1838,31 +1536,22 @@ setup_hfcsusb(hfcsusb_t * card) static void release_card(hfcsusb_t * card) { - int i; + int i; + 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 if (debug & 0x10000) printk(KERN_DEBUG "%s\n", __FUNCTION__); - lock_dev(card, 0); - mode_bchannel(&card->bch[0], 0, ISDN_PID_NONE); - mode_bchannel(&card->bch[1], 1, ISDN_PID_NONE); - mISDN_free_bch(&card->bch[1]); - mISDN_free_bch(&card->bch[0]); - mISDN_free_dch(&card->dch); - hw_mISDNObj.ctrl(card->dch.inst.up.peer, MGR_DISCONNECT | REQUEST, - &card->dch.inst.up); - hw_mISDNObj.ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL); + setup_bchannel(&card->chan[B1], ISDN_PID_NONE); + setup_bchannel(&card->chan[B2], ISDN_PID_NONE); + mISDN_freechannel(&card->chan[B1]); + mISDN_freechannel(&card->chan[B2]); + mISDN_freechannel(&card->chan[D]); + hw_mISDNObj.ctrl(&card->chan[D].inst, MGR_UNREGLAYER | REQUEST, NULL); + + spin_lock_irqsave(&hw_mISDNObj.lock, flags); list_del(&card->list); - unlock_dev(card); - + spin_unlock_irqrestore(&hw_mISDNObj.lock, flags); schedule_timeout((80 * HZ) / 1000); /* Timeout 80ms */ /* tell all fifos to terminate */ @@ -1884,126 +1573,138 @@ release_card(hfcsusb_t * card) card->fifos[i].active = 0; } - /* wait for all URBS to terminate */ if (card->ctrl_urb) { usb_kill_urb(card->ctrl_urb); usb_free_urb(card->ctrl_urb); card->ctrl_urb = NULL; } - hfcsusb_cnt--; + if (card->intf) + usb_set_intfdata(card->intf, NULL); kfree(card); } static int setup_instance(hfcsusb_t * card) { - int i, err; - mISDN_pid_t pid; - - list_add_tail(&card->list, &hw_mISDNObj.ilist); - card->dch.debug = debug; - lock_HW_init(&card->lock); - card->dch.inst.lock = lock_dev; - card->dch.inst.unlock = unlock_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, &hw_mISDNObj, card); - sprintf(card->dch.inst.name, "hfcsusb_%d", hfcsusb_cnt + 1); - mISDN_set_dchannel_pid(&pid, protocol[hfcsusb_cnt], - layermask[hfcsusb_cnt]); - mISDN_init_dch(&card->dch); - card->dch.hw = card; - card->hw_mode = 0; + int i, err; + mISDN_pid_t pid; + u_long flags; - for (i = 0; i < 2; i++) { - card->bch[i].channel = i; - mISDN_init_instance(&card->bch[i].inst, &hw_mISDNObj, - card); - 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].debug = debug; - sprintf(card->bch[i].inst.name, "%s B%d", - card->dch.inst.name, i + 1); - mISDN_init_bch(&card->bch[i]); - card->bch[i].hw = card; - if (card->bch[i].dev) { - card->bch[i].dev->wport.pif.func = hfcsusb_l2l1B; - card->bch[i].dev->wport.pif.fdata = &card->bch[i]; + spin_lock_irqsave(&hw_mISDNObj.lock, flags); + + list_add_tail(&card->list, &hw_mISDNObj.ilist); + spin_unlock_irqrestore(&hw_mISDNObj.lock, flags); + card->chan[D].debug = debug; + + /* link card->fifos[] to card->chan[] */ + card->fifos[HFCUSB_D_RX].ch_idx = D; + card->fifos[HFCUSB_D_TX].ch_idx = D; + card->fifos[HFCUSB_B1_RX].ch_idx = B1; + card->fifos[HFCUSB_B1_TX].ch_idx = B1; + card->fifos[HFCUSB_B2_RX].ch_idx = B2; + card->fifos[HFCUSB_B2_TX].ch_idx = B2; + card->fifos[HFCUSB_PCM_RX].ch_idx = PCM; + card->fifos[HFCUSB_PCM_TX].ch_idx = PCM; + + card->chan[D].channel = D; + card->chan[D].state = 0; + card->chan[D].inst.hwlock = NULL; + card->chan[D].inst.pid.layermask = ISDN_LAYER(0); + card->chan[D].inst.pid.protocol[0] = ISDN_PID_L0_TE_S0; + card->chan[D].inst.class_dev.dev = &card->dev->dev; + mISDN_init_instance(&card->chan[D].inst, &hw_mISDNObj, card, hfcsusb_l2l1); + sprintf(card->chan[D].inst.name, "hfcsusb_%d", hfcsusb_cnt + 1); + mISDN_set_dchannel_pid(&pid, protocol[hfcsusb_cnt], layermask[hfcsusb_cnt]); + mISDN_initchannel(&card->chan[D], MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1); + card->chan[D].hw = card; + card->portmode = 0; + + for (i = B1; i <= B2; i++) { + card->chan[i].channel = i; + mISDN_init_instance(&card->chan[i].inst, &hw_mISDNObj, card, hfcsusb_l2l1); + card->chan[i].inst.pid.layermask = ISDN_LAYER(0); + card->chan[i].inst.hwlock = NULL; + card->chan[i].inst.class_dev.dev = &card->dev->dev; + card->chan[i].debug = debug; + sprintf(card->chan[i].inst.name, "%s B%d", + card->chan[D].inst.name, i + 1); + mISDN_initchannel(&card->chan[i], MSK_INIT_BCHANNEL, MAX_DATA_MEM); + card->chan[i].hw = card; +#ifdef FIXME + if (card->chan[i].dev) { + card->chan[i].dev->wport.pif.func = hfcsusb_l2l1; + card->chan[i].dev->wport.pif.fdata = &card->chan[i]; } +#endif } + + card->chan[PCM].channel = PCM; if (protocol[hfcsusb_cnt] & 0x10) { // NT Mode - printk (KERN_INFO "%s wants NT Mode\n", card->dch.inst.name); - card->dch.inst.pid.protocol[0] = ISDN_PID_L0_NT_S0; - card->dch.inst.pid.protocol[1] = ISDN_PID_L1_NT_S0; + printk (KERN_INFO "%s wants NT Mode\n", card->chan[D].inst.name); + card->chan[D].inst.pid.protocol[0] = ISDN_PID_L0_NT_S0; + card->chan[D].inst.pid.protocol[1] = ISDN_PID_L1_NT_S0; pid.protocol[0] = ISDN_PID_L0_NT_S0; pid.protocol[1] = ISDN_PID_L1_NT_S0; - card->dch.inst.pid.layermask |= ISDN_LAYER(1); + card->chan[D].inst.pid.layermask |= ISDN_LAYER(1); pid.layermask |= ISDN_LAYER(1); if (layermask[i] & ISDN_LAYER(2)) pid.protocol[2] = ISDN_PID_L2_LAPD_NET; /* select NT mode with activated NT Timer (T1) */ - card->hw_mode |= (HW_MODE_NT | NT_ACTIVATION_TIMER); + card->portmode |= (PORT_MODE_NT | NT_ACTIVATION_TIMER); } else { - printk (KERN_INFO "%s wants TE Mode\n", card->dch.inst.name); + printk (KERN_INFO "%s wants TE Mode\n", card->chan[D].inst.name); // TE Mode - card->dch.inst.pid.protocol[0] = ISDN_PID_L0_TE_S0; - card->hw_mode |= HW_MODE_TE; + card->chan[D].inst.pid.protocol[0] = ISDN_PID_L0_TE_S0; + card->portmode |= PORT_MODE_TE; } if (debug) printk(KERN_DEBUG "hfcsusb card %p dch %p bch1 %p bch2 %p\n", card, - &card->dch, &card->bch[0], &card->bch[1]); + &card->chan[D], &card->chan[B1], &card->chan[B2]); err = setup_hfcsusb(card); if (err) { - mISDN_free_dch(&card->dch); - mISDN_free_bch(&card->bch[1]); - mISDN_free_bch(&card->bch[0]); + mISDN_freechannel(&card->chan[D]); + mISDN_freechannel(&card->chan[B2]); + mISDN_freechannel(&card->chan[B1]); + spin_lock_irqsave(&hw_mISDNObj.lock, flags); list_del(&card->list); + spin_unlock_irqrestore(&hw_mISDNObj.lock, flags); kfree(card); return (err); } hfcsusb_cnt++; - err = - hw_mISDNObj.ctrl(NULL, MGR_NEWSTACK | REQUEST, - &card->dch.inst); + err = hw_mISDNObj.ctrl(NULL, MGR_NEWSTACK | REQUEST, &card->chan[D].inst); if (err) { release_card(card); return (err); } - for (i = 0; i < 2; i++) { - err = - hw_mISDNObj.ctrl(card->dch.inst.st, - MGR_NEWSTACK | REQUEST, - &card->bch[i].inst); + for (i = B1; i <= B2; i++) { + err = hw_mISDNObj.ctrl(card->chan[D].inst.st, + MGR_NEWSTACK | REQUEST, &card->chan[i].inst); if (err) { - printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", - err); - hw_mISDNObj.ctrl(card->dch.inst.st, - MGR_DELSTACK | REQUEST, NULL); + printk(KERN_ERR "MGR_ADDSTACK bchan error %d\n", err); + hw_mISDNObj.ctrl(card->chan[D].inst.st, MGR_DELSTACK | REQUEST, NULL); return (err); } + setup_bchannel(&card->chan[i], -1); } - err = - hw_mISDNObj.ctrl(card->dch.inst.st, MGR_SETSTACK | REQUEST, - &pid); + if (debug) + printk(KERN_DEBUG "%s lm %x\n", __FUNCTION__, pid.layermask); + err = hw_mISDNObj.ctrl(card->chan[D].inst.st, MGR_SETSTACK | REQUEST, &pid); if (err) { printk(KERN_ERR "MGR_SETSTACK REQUEST dch err(%d)\n", err); - hw_mISDNObj.ctrl(card->dch.inst.st, MGR_DELSTACK | REQUEST, - NULL); + hw_mISDNObj.ctrl(card->chan[D].inst.st, MGR_DELSTACK | REQUEST, NULL); return (err); } - hw_init(card); - hw_mISDNObj.ctrl(card->dch.inst.st, MGR_CTRLREADY | INDICATION, - NULL); - + hw_mISDNObj.ctrl(card->chan[D].inst.st, MGR_CTRLREADY | INDICATION, NULL); + usb_set_intfdata(card->intf, card); return (0); } @@ -2011,298 +1712,220 @@ setup_instance(hfcsusb_t * card) /*************************************************/ /* function called to probe a new plugged device */ /*************************************************/ + static int hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { - struct usb_device *dev = interface_to_usbdev(intf); - hfcsusb_t *card; - struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_host_interface *iface_used = NULL; - struct usb_host_endpoint *ep; - int ifnum = iface->desc.bInterfaceNumber; - int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, - attr, cfg_found, cidx, ep_addr; - int cmptbl[16], small_match, iso_packet_size, packet_size, - alt_used = 0; - - hfcsusb_vdata *driver_info; + struct usb_device *dev = interface_to_usbdev(intf); + hfcsusb_t *card; + struct usb_host_interface *iface = intf->cur_altsetting; + struct usb_host_interface *iface_used = NULL; + struct usb_host_endpoint *ep; + int ifnum = iface->desc.bInterfaceNumber; + int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, + attr, cfg_found, ep_addr; + int cmptbl[16], small_match, iso_packet_size, packet_size, alt_used = 0; + hfcsusb_vdata *driver_info; vend_idx = 0xffff; for (i = 0; hfcsusb_idtab[i].idVendor; i++) { - if (dev->descriptor.idVendor == hfcsusb_idtab[i].idVendor - && dev->descriptor.idProduct == - hfcsusb_idtab[i].idProduct) { + if ((le16_to_cpu(dev->descriptor.idVendor) == hfcsusb_idtab[i].idVendor) + && (le16_to_cpu(dev->descriptor.idProduct) == hfcsusb_idtab[i].idProduct)) { vend_idx = i; continue; } } printk(KERN_INFO - "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n", - ifnum, iface->desc.bAlternateSetting, intf->minor); + "HFC-S USB: probing interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n", + ifnum, iface->desc.bAlternateSetting, intf->minor, vend_idx); - if (vend_idx != 0xffff) { - /* if vendor and product ID is OK, start probing alternate settings */ - alt_idx = 0; - small_match = 0xffff; + if (vend_idx == 0xffff) { + printk(KERN_WARNING + "HFC-S USB: no valid vendor found in USB descriptor\n"); + return (-EIO); + } + /* if vendor and product ID is OK, start probing alternate settings */ + alt_idx = 0; + small_match = 0xffff; - /* default settings */ - iso_packet_size = 16; - packet_size = 64; + /* default settings */ + iso_packet_size = 16; + packet_size = 64; - while (alt_idx < intf->num_altsetting) { - iface = intf->altsetting + alt_idx; - probe_alt_setting = iface->desc.bAlternateSetting; - cfg_used = 0; - - /* check for config EOL element */ - while (validconf[cfg_used][0]) { - cfg_found = 1; - vcf = validconf[cfg_used]; - /* first endpoint descriptor */ - ep = iface->endpoint; - memcpy(cmptbl, vcf, 16 * sizeof(int)); - - /* check for all endpoints in this alternate setting */ - for (i = 0; i < iface->desc.bNumEndpoints; - i++) { - ep_addr = - ep->desc.bEndpointAddress; - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (ep_addr & 0x80) - idx++; - attr = ep->desc.bmAttributes; - if (cmptbl[idx] == EP_NUL) { - cfg_found = 0; - } - if (attr == USB_ENDPOINT_XFER_INT - && cmptbl[idx] == EP_INT) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_BULK - && cmptbl[idx] == EP_BLK) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_ISOC - && cmptbl[idx] == EP_ISO) - cmptbl[idx] = EP_NUL; - - /* check if all INT endpoints match minimum interval */ - if (attr == USB_ENDPOINT_XFER_INT - && ep->desc.bInterval < - vcf[17]) { - cfg_found = 0; - } - ep++; - } - for (i = 0; i < 16; i++) { - /* all entries must be EP_NOP or EP_NUL for a valid config */ - if (cmptbl[i] != EP_NOP - && cmptbl[i] != EP_NUL) - cfg_found = 0; - } - if (cfg_found) { - if (cfg_used < small_match) { - small_match = cfg_used; - alt_used = - probe_alt_setting; - iface_used = iface; - } - } - cfg_used++; - } - alt_idx++; - } /* (alt_idx < intf->num_altsetting) */ - - /* found a valid USB Ta Endpint config */ - if (small_match != 0xffff) { - iface = iface_used; - if (! - (card = - kmalloc(sizeof(hfcsusb_t), GFP_KERNEL))) - return (-ENOMEM); /* got no mem */ - memset(card, 0, sizeof(hfcsusb_t)); + while (alt_idx < intf->num_altsetting) { + iface = intf->altsetting + alt_idx; + probe_alt_setting = iface->desc.bAlternateSetting; + cfg_used = 0; + /* check for config EOL element */ + while (validconf[cfg_used][0]) { + cfg_found = 1; + vcf = validconf[cfg_used]; + /* first endpoint descriptor */ ep = iface->endpoint; - vcf = validconf[small_match]; + memcpy(cmptbl, vcf, 16 * sizeof(int)); + /* check for all endpoints in this alternate setting */ for (i = 0; i < iface->desc.bNumEndpoints; i++) { ep_addr = ep->desc.bEndpointAddress; /* get endpoint base */ idx = ((ep_addr & 0x7f) - 1) * 2; if (ep_addr & 0x80) idx++; - cidx = idx & 7; attr = ep->desc.bmAttributes; + if (cmptbl[idx] == EP_NUL) { + cfg_found = 0; + } + if (attr == USB_ENDPOINT_XFER_INT + && cmptbl[idx] == EP_INT) + cmptbl[idx] = EP_NUL; + if (attr == USB_ENDPOINT_XFER_BULK + && cmptbl[idx] == EP_BLK) + cmptbl[idx] = EP_NUL; + if (attr == USB_ENDPOINT_XFER_ISOC + && cmptbl[idx] == EP_ISO) + cmptbl[idx] = EP_NUL; - /* init Endpoints */ - if (vcf[idx] != EP_NOP - && vcf[idx] != EP_NUL) { - switch (attr) { - case USB_ENDPOINT_XFER_INT: - card-> - fifos[cidx]. - pipe = - usb_rcvintpipe - (dev, - ep->desc. - bEndpointAddress); - card-> - fifos[cidx]. - usb_transfer_mode - = USB_INT; - packet_size = - ep->desc. - wMaxPacketSize; - break; - case USB_ENDPOINT_XFER_BULK: - if (ep_addr & 0x80) - card-> - fifos - [cidx]. - pipe = - usb_rcvbulkpipe - (dev, - ep-> - desc. - bEndpointAddress); - else - card-> - fifos - [cidx]. - pipe = - usb_sndbulkpipe - (dev, - ep-> - desc. - bEndpointAddress); - card-> - fifos[cidx]. - usb_transfer_mode - = USB_BULK; - packet_size = - ep->desc. - wMaxPacketSize; - break; - case USB_ENDPOINT_XFER_ISOC: - if (ep_addr & 0x80) - card-> - fifos - [cidx]. - pipe = - usb_rcvisocpipe - (dev, - ep-> - desc. - bEndpointAddress); - else - card-> - fifos - [cidx]. - pipe = - usb_sndisocpipe - (dev, - ep-> - desc. - bEndpointAddress); - card-> - fifos[cidx]. - usb_transfer_mode - = USB_ISOC; - iso_packet_size = - ep->desc. - wMaxPacketSize; - break; - default: - card-> - fifos[cidx]. - pipe = 0; - } /* switch attribute */ - - if (card->fifos[cidx].pipe) { - card->fifos[cidx]. - fifonum = cidx; - card->fifos[cidx].card = - card; - card->fifos[cidx]. - usb_packet_maxlen = - ep->desc. - wMaxPacketSize; - card->fifos[cidx]. - intervall = - ep->desc.bInterval; - card->fifos[cidx]. - skbuff = NULL; - } + /* check if all INT endpoints match minimum interval */ + if (attr == USB_ENDPOINT_XFER_INT && + ep->desc.bInterval < vcf[17]) { + cfg_found = 0; } ep++; } - card->dev = dev; /* save device */ - card->if_used = ifnum; /* save used interface */ - card->alt_used = alt_used; /* and alternate config */ - card->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ - card->cfg_used = vcf[16]; /* store used config */ - card->vend_idx = vend_idx; /* store found vendor */ - card->packet_size = packet_size; - card->iso_packet_size = iso_packet_size; - - /* create the control pipes needed for register access */ - card->ctrl_in_pipe = usb_rcvctrlpipe(card->dev, 0); - card->ctrl_out_pipe = - usb_sndctrlpipe(card->dev, 0); - card->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - - - driver_info = - (hfcsusb_vdata *) hfcsusb_idtab[vend_idx]. - driver_info; - printk(KERN_INFO "HFC-S USB: detected \"%s\"\n", - driver_info->vend_name); - printk(KERN_INFO - "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n", - conf_str[small_match], ifnum, alt_used); - - if (setup_instance(card)) { - if (card->ctrl_urb) { - usb_kill_urb(card->ctrl_urb); - usb_free_urb(card->ctrl_urb); - card->ctrl_urb = NULL; - } - kfree(card); - return (-EIO); + for (i = 0; i < 16; i++) { + /* all entries must be EP_NOP or EP_NUL for a valid config */ + if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL) + cfg_found = 0; } - usb_set_intfdata(intf, card); - - return (0); + if (cfg_found) { + if (cfg_used < small_match) { + small_match = cfg_used; + alt_used = probe_alt_setting; + iface_used = iface; + } + } + cfg_used++; } - } else { - printk(KERN_INFO - "HFC-S USB: no valid vendor found in USB descriptor\n"); + alt_idx++; + } /* (alt_idx < intf->num_altsetting) */ + + /* not found a valid USB Ta Endpoint config */ + if (small_match == 0xffff) { + printk(KERN_WARNING + "HFC-S USB: no valid endpoint found in USB descriptor\n"); + return (-EIO); } - return (-EIO); + iface = iface_used; + card = kmalloc(sizeof(hfcsusb_t), GFP_KERNEL); + if (!card) + return (-ENOMEM); /* got no mem */ + memset(card, 0, sizeof(hfcsusb_t)); + + ep = iface->endpoint; + vcf = validconf[small_match]; + + for (i = 0; i < iface->desc.bNumEndpoints; i++) { + usb_fifo *f; + + ep_addr = ep->desc.bEndpointAddress; + /* get endpoint base */ + idx = ((ep_addr & 0x7f) - 1) * 2; + if (ep_addr & 0x80) + idx++; + f = &card->fifos[idx & 7]; + + /* init Endpoints */ + if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) { + ep++; + continue; + } + switch (ep->desc.bmAttributes) { + case USB_ENDPOINT_XFER_INT: + f->pipe = usb_rcvintpipe(dev, + ep->desc.bEndpointAddress); + f->usb_transfer_mode = USB_INT; + packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + break; + case USB_ENDPOINT_XFER_BULK: + if (ep_addr & 0x80) + f->pipe = usb_rcvbulkpipe(dev, + ep->desc.bEndpointAddress); + else + f->pipe = usb_sndbulkpipe(dev, + ep->desc.bEndpointAddress); + f->usb_transfer_mode = USB_BULK; + packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + break; + case USB_ENDPOINT_XFER_ISOC: + if (ep_addr & 0x80) + f->pipe = usb_rcvisocpipe(dev, + ep->desc.bEndpointAddress); + else + f->pipe = usb_sndisocpipe(dev, + ep->desc.bEndpointAddress); + f->usb_transfer_mode = USB_ISOC; + iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + break; + default: + f->pipe = 0; + } /* switch attribute */ + + if (f->pipe) { + f->fifonum = idx & 7; + f->card = card; + f->usb_packet_maxlen = le16_to_cpu(ep->desc.wMaxPacketSize); + f->intervall = ep->desc.bInterval; + } + ep++; + } + card->dev = dev; /* save device */ + card->if_used = ifnum; /* save used interface */ + card->alt_used = alt_used; /* and alternate config */ + card->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ + card->cfg_used = vcf[16]; /* store used config */ + card->vend_idx = vend_idx; /* store found vendor */ + card->packet_size = packet_size; + card->iso_packet_size = iso_packet_size; + + /* create the control pipes needed for register access */ + card->ctrl_in_pipe = usb_rcvctrlpipe(card->dev, 0); + card->ctrl_out_pipe = usb_sndctrlpipe(card->dev, 0); + card->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); + + driver_info = (hfcsusb_vdata *) hfcsusb_idtab[vend_idx].driver_info; + printk(KERN_INFO "HFC-S USB: detected \"%s\"\n", + driver_info->vend_name); + printk(KERN_INFO "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n", + conf_str[small_match], ifnum, alt_used); + + card->intf = intf; + if (setup_instance(card)) { + return (-EIO); + } + return (0); } /****************************************************/ /* function called when an active device is removed */ /****************************************************/ static void -hfcsusb_disconnect(struct usb_interface - *intf) +hfcsusb_disconnect(struct usb_interface *intf) { hfcsusb_t *card = usb_get_intfdata(intf); + printk(KERN_INFO "HFC-S USB: device disconnect\n"); - card->disc_flag = 1; - - if (debug & 0x10000) - printk(KERN_DEBUG "%s\n", __FUNCTION__); - if (!card) { if (debug & 0x10000) - printk(KERN_DEBUG "%s : NO CONTEXT!\n", - __FUNCTION__); + printk(KERN_DEBUG "%s : NO CONTEXT!\n", __FUNCTION__); return; } - - release_card(card); + if (debug & 0x10000) + printk(KERN_DEBUG "%s\n", __FUNCTION__); + card->disc_flag = 1; + hw_mISDNObj.ctrl(card->chan[D].inst.st, MGR_DELSTACK | REQUEST, NULL); +// release_card(card); usb_set_intfdata(intf, NULL); } /* hfcsusb_disconnect */ @@ -2330,6 +1953,7 @@ hfcsusb_init(void) #ifdef MODULE hw_mISDNObj.owner = THIS_MODULE; #endif + spin_lock_init(&hw_mISDNObj.lock); INIT_LIST_HEAD(&hw_mISDNObj.ilist); hw_mISDNObj.name = DRIVER_NAME; hw_mISDNObj.own_ctrl = hfcsusb_manager; @@ -2367,15 +1991,13 @@ hfcsusb_cleanup(void) if (debug & 0x10000) printk(KERN_DEBUG "%s\n", __FUNCTION__); + list_for_each_entry_safe(card, next, &hw_mISDNObj.ilist, list) { + handle_led(card, LED_POWER_OFF); + } if ((err = mISDN_unregister(&hw_mISDNObj))) { printk(KERN_ERR "Can't unregister hfcsusb error(%d)\n", err); } - - list_for_each_entry_safe(card, next, &hw_mISDNObj.ilist, list) { - handle_led(card, LED_POWER_OFF); - } - /* unregister Hardware */ usb_deregister(&hfcsusb_drv); /* release our driver */ } diff --git a/drivers/isdn/hardware/mISDN/hfcs_usb.h b/drivers/isdn/hardware/mISDN/hfcs_usb.h index c9c0647..b5c04b6 100644 --- a/drivers/isdn/hardware/mISDN/hfcs_usb.h +++ b/drivers/isdn/hardware/mISDN/hfcs_usb.h @@ -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 */ /*************************************************/ diff --git a/drivers/isdn/hardware/mISDN/i4l_mISDN.c b/drivers/isdn/hardware/mISDN/i4l_mISDN.c index c217992..24f185f 100644 --- a/drivers/isdn/hardware/mISDN/i4l_mISDN.c +++ b/drivers/isdn/hardware/mISDN/i4l_mISDN.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/isac.c b/drivers/isdn/hardware/mISDN/isac.c index d0424ae..f824a02 100644 --- a/drivers/isdn/hardware/mISDN/isac.c +++ b/drivers/isdn/hardware/mISDN/isac.c @@ -8,7 +8,7 @@ */ #include -#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 diff --git a/drivers/isdn/hardware/mISDN/isac.h b/drivers/isdn/hardware/mISDN/isac.h index 08b861a..233413a 100644 --- a/drivers/isdn/hardware/mISDN/isac.h +++ b/drivers/isdn/hardware/mISDN/isac.h @@ -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 *); diff --git a/drivers/isdn/hardware/mISDN/isar.c b/drivers/isdn/hardware/mISDN/isar.c index 4d788c4..ba553cd 100644 --- a/drivers/isdn/hardware/mISDN/isar.c +++ b/drivers/isdn/hardware/mISDN/isar.c @@ -9,9 +9,9 @@ */ #include +#include #include "layer1.h" -#include "helper.h" -#include "bchannel.h" +#include "channel.h" #include "isar.h" #include "debug.h" @@ -26,18 +26,18 @@ const u_char faxmodulation_s[] = "3,24,48,72,73,74,96,97,98,121,122,145,146"; const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146}; #define FAXMODCNT 13 -void isar_setup(bchannel_t *); -static void isar_pump_cmd(bchannel_t *, int, u_char); +void isar_setup(channel_t *); +static void isar_pump_cmd(channel_t *, int, u_char); static int firmwaresize = 0; static u_char *firmware; static u_char *fw_p; static inline int -waitforHIA(bchannel_t *bch, int timeout) +waitforHIA(channel_t *bch, int timeout) { - while ((bch->Read_Reg(bch->inst.data, 0, ISAR_HIA) & 1) && timeout) { + while ((bch->read_reg(bch->inst.privat, ISAR_HIA) & 1) && timeout) { udelay(1); timeout--; } @@ -48,7 +48,7 @@ waitforHIA(bchannel_t *bch, int timeout) int -sendmsg(bchannel_t *bch, u_char his, u_char creg, u_char len, +sendmsg(channel_t *bch, u_char his, u_char creg, u_char len, u_char *msg) { int i; @@ -59,69 +59,65 @@ sendmsg(bchannel_t *bch, u_char his, u_char creg, u_char len, if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "sendmsg(%02x,%02x,%d)", his, creg, len); #endif - bch->Write_Reg(bch->inst.data, 0, ISAR_CTRL_H, creg); - bch->Write_Reg(bch->inst.data, 0, ISAR_CTRL_L, len); - bch->Write_Reg(bch->inst.data, 0, ISAR_WADR, 0); + bch->write_reg(bch->inst.privat, ISAR_CTRL_H, creg); + bch->write_reg(bch->inst.privat, ISAR_CTRL_L, len); + bch->write_reg(bch->inst.privat, ISAR_WADR, 0); if (msg && len) { - bch->Write_Reg(bch->inst.data, 1, ISAR_MBOX, msg[0]); - for (i=1; iWrite_Reg(bch->inst.data, 2, ISAR_MBOX, msg[i]); + bch->write_fifo(bch->inst.privat, msg, len); #if DUMP_MBOXFRAME>1 if (bch->debug & L1_DEB_HSCX_FIFO) { char *t; i = len; while (i>0) { - t = bch->blog; + t = bch->log; t += sprintf(t, "sendmbox cnt %d", len); mISDN_QuickHex(t, &msg[len-i], (i>64) ? 64:i); - mISDN_debugprint(&bch->inst, bch->blog); + mISDN_debugprint(&bch->inst, bch->log); i -= 64; } } #endif } - bch->Write_Reg(bch->inst.data, 1, ISAR_HIS, his); + bch->write_reg(bch->inst.privat, ISAR_HIS, his); waitforHIA(bch, 10000); return(1); } /* Call only with IRQ disabled !!! */ inline void -rcv_mbox(bchannel_t *bch, isar_reg_t *ireg, u_char *msg) +rcv_mbox(channel_t *bch, isar_reg_t *ireg, u_char *msg) { int i; - bch->Write_Reg(bch->inst.data, 1, ISAR_RADR, 0); + bch->write_reg(bch->inst.privat, ISAR_RADR, 0); if (msg && ireg->clsb) { - msg[0] = bch->Read_Reg(bch->inst.data, 1, ISAR_MBOX); - for (i=1; i < ireg->clsb; i++) - msg[i] = bch->Read_Reg(bch->inst.data, 2, ISAR_MBOX); + bch->read_fifo(bch->inst.privat, msg, ireg->clsb); #if DUMP_MBOXFRAME>1 if (bch->debug & L1_DEB_HSCX_FIFO) { char *t; i = ireg->clsb; while (i>0) { - t = bch->blog; + t = bch->log; t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb); mISDN_QuickHex(t, &msg[ireg->clsb-i], (i>64) ? 64:i); - mISDN_debugprint(&bch->inst, bch->blog); + mISDN_debugprint(&bch->inst, bch->log); i -= 64; } } #endif } - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); } /* Call only with IRQ disabled !!! */ inline void -get_irq_infos(bchannel_t *bch, isar_reg_t *ireg) +get_irq_infos(channel_t *bch, isar_reg_t *ireg) { - ireg->iis = bch->Read_Reg(bch->inst.data, 1, ISAR_IIS); - ireg->cmsb = bch->Read_Reg(bch->inst.data, 1, ISAR_CTRL_H); - ireg->clsb = bch->Read_Reg(bch->inst.data, 1, ISAR_CTRL_L); + ireg->iis = bch->read_reg(bch->inst.privat, ISAR_IIS); + ireg->cmsb = bch->read_reg(bch->inst.privat, ISAR_CTRL_H); + ireg->clsb = bch->read_reg(bch->inst.privat, ISAR_CTRL_L); #if DUMP_MBOXFRAME if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "rcv_mbox(%02x,%02x,%d)", ireg->iis, ireg->cmsb, @@ -130,14 +126,14 @@ get_irq_infos(bchannel_t *bch, isar_reg_t *ireg) } int -waitrecmsg(bchannel_t *bch, u_char *len, +waitrecmsg(channel_t *bch, u_char *len, u_char *msg, int maxdelay) { int timeout = 0; isar_hw_t *ih = bch->hw; - while((!(bch->Read_Reg(bch->inst.data, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && + while((!(bch->read_reg(bch->inst.privat, ISAR_IRQBIT) & ISAR_IRQSTA)) && (timeout++ < maxdelay)) udelay(1); if (timeout >= maxdelay) { @@ -151,7 +147,7 @@ waitrecmsg(bchannel_t *bch, u_char *len, } int -ISARVersion(bchannel_t *bch, char *s) +ISARVersion(channel_t *bch, char *s) { int ver; u_char msg[] = ISAR_MSG_HWVER; @@ -160,9 +156,9 @@ ISARVersion(bchannel_t *bch, char *s) isar_hw_t *ih = bch->hw; int debug; -// bch->cardmsg(bch->inst.data, CARD_RESET, NULL); +// bch->cardmsg(bch->inst.privat, CARD_RESET, NULL); /* disable ISAR IRQ */ - bch->Write_Reg(bch->inst.data, 0, ISAR_IRQBIT, 0); + bch->write_reg(bch->inst.privat, ISAR_IRQBIT, 0); debug = bch->debug; bch->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); if (!sendmsg(bch, ISAR_HIS_VNR, 0, 3, msg)) @@ -182,25 +178,26 @@ ISARVersion(bchannel_t *bch, char *s) } int -isar_load_firmware(bchannel_t *bch, u_char *buf, int size) +isar_load_firmware(channel_t *bch, u_char *buf, int size) { - int ret, cnt, debug; - u_char len, nom, noc; - u_short sadr, left, *sp; - u_char *p = buf; - u_char *msg, *tmpmsg, *mp, tmp[64]; - isar_hw_t *ih = bch->hw; + int ret, cnt, debug; + u_char len, nom, noc; + u_short sadr, left, *sp; + u_char *p = buf; + u_char *msg, *tmpmsg, *mp, tmp[64]; + isar_hw_t *ih = bch->hw; + u_long flags; struct {u_short sadr; u_short len; u_short d_key; } *blk_head; - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); #define BLK_HEAD_SIZE 6 if (1 != (ret = ISARVersion(bch, "Testing"))) { printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret); - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); return(1); } debug = bch->debug; @@ -211,10 +208,10 @@ isar_load_firmware(bchannel_t *bch, u_char *buf, int size) printk(KERN_DEBUG"isar_load_firmware size: %d\n", size); cnt = 0; /* disable ISAR IRQ */ - bch->Write_Reg(bch->inst.data, 0, ISAR_IRQBIT, 0); + bch->write_reg(bch->inst.privat, ISAR_IRQBIT, 0); if (!(msg = kmalloc(256, GFP_ATOMIC))) { printk(KERN_ERR"isar_load_firmware no buffer\n"); - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); return (1); } while (cnt < size) { @@ -320,8 +317,8 @@ isar_load_firmware(bchannel_t *bch, u_char *buf, int size) printk(KERN_DEBUG"isar start dsp success\n"); /* NORMAL mode entered */ /* Enable IRQs of ISAR */ - bch->Write_Reg(bch->inst.data, 0, ISAR_IRQBIT, ISAR_IRQSTA); - bch->inst.unlock(bch->inst.data); + bch->write_reg(bch->inst.privat, ISAR_IRQBIT, ISAR_IRQSTA); + spin_unlock_irqrestore(bch->inst.hwlock, flags); cnt = 1000; /* max 1s */ while ((!ih->reg->bstat) && cnt) { mdelay(1); @@ -340,12 +337,12 @@ isar_load_firmware(bchannel_t *bch, u_char *buf, int size) while (cnt--) mdelay(1); ih->reg->iis = 0; - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); if (!sendmsg(bch, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { printk(KERN_ERR"isar sendmsg self tst failed\n"); ret = 1;goto reterror; } - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); cnt = 10000; /* max 100 ms */ while ((ih->reg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); @@ -364,13 +361,13 @@ isar_load_firmware(bchannel_t *bch, u_char *buf, int size) ih->reg->cmsb, ih->reg->clsb, ih->reg->par[0]); ret = 1;goto reterrflg; } - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); ih->reg->iis = 0; if (!sendmsg(bch, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { printk(KERN_ERR"isar RQST SVN failed\n"); ret = 1;goto reterror; } - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); cnt = 30000; /* max 300 ms */ while ((ih->reg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); @@ -392,40 +389,43 @@ isar_load_firmware(bchannel_t *bch, u_char *buf, int size) } } bch->debug = debug; - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); isar_setup(bch); - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); bch->inst.obj->own_ctrl(&bch->inst, MGR_LOADFIRM | CONFIRM, NULL); ret = 0; reterrflg: - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); reterror: bch->debug = debug; if (ret) /* disable ISAR IRQ */ - bch->Write_Reg(bch->inst.data, 0, ISAR_IRQBIT, 0); - bch->inst.unlock(bch->inst.data); + bch->write_reg(bch->inst.privat, ISAR_IRQBIT, 0); + spin_unlock_irqrestore(bch->inst.hwlock, flags); kfree(msg); return(ret); } +#ifdef OBSOLETE #define B_LL_READY 8 #define B_LL_NOCARRIER 9 #define B_LL_CONNECT 10 #define B_LL_OK 11 #define B_LL_FCERROR 12 #define B_TOUCH_TONE 13 +#endif static inline void -deliver_status(bchannel_t *bch, int status) +deliver_status(channel_t *bch, int status) { if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "HL->LL FAXIND %x", status); - if_link(&bch->inst.up, PH_STATUS | INDICATION, status, 0, NULL, 0); + mISDN_queue_data(&bch->inst, FLG_MSG_UP, PH_STATUS | INDICATION, status, 0, NULL, 0); } +#ifdef OBSOLETE static void -isar_bh(bchannel_t *bch) +isar_bh(channel_t *bch) { int tt; @@ -448,13 +448,14 @@ isar_bh(bchannel_t *bch) else if (tt > '9') tt += 7; tt |= DTMF_TONE_VAL; - if_link(&bch->inst.up, PH_CONTROL | INDICATION, + mISDN_queue_data(&bch->inst, FLG_MSG_UP, PH_CONTROL | INDICATION, 0, sizeof(int), &tt, 0); } } +#endif static inline void -isar_rcv_frame(bchannel_t *bch) +isar_rcv_frame(channel_t *bch) { u_char *ptr; struct sk_buff *skb; @@ -462,36 +463,49 @@ isar_rcv_frame(bchannel_t *bch) if (!ih->reg->clsb) { mISDN_debugprint(&bch->inst, "isar zero len frame"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); return; } - switch (bch->protocol) { + switch (bch->state) { case ISDN_PID_NONE: mISDN_debugprint(&bch->inst, "isar protocol 0 spurious IIS_RDATA %x/%x/%x", ih->reg->iis, ih->reg->cmsb, ih->reg->clsb); printk(KERN_WARNING"isar protocol 0 spurious IIS_RDATA %x/%x/%x\n", ih->reg->iis, ih->reg->cmsb, ih->reg->clsb); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); break; case ISDN_PID_L1_B_64TRANS: case ISDN_PID_L2_B_TRANSDTMF: case ISDN_PID_L1_B_MODEM_ASYNC: - if ((skb = alloc_stack_skb(ih->reg->clsb, bch->up_headerlen))) { - rcv_mbox(bch, ih->reg, (u_char *)skb_put(skb, ih->reg->clsb)); - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - } else { - printk(KERN_WARNING "mISDN: skb out of memory\n"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + if (!bch->rx_skb) { + bch->rx_skb = alloc_stack_skb(ih->reg->clsb, bch->up_headerlen); + if (unlikely(!bch->rx_skb)) { + printk(KERN_WARNING "mISDN: skb out of memory\n"); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + break; + } } + rcv_mbox(bch, ih->reg, (u_char *)skb_put(bch->rx_skb, ih->reg->clsb)); + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb); + bch->rx_skb = NULL; break; case ISDN_PID_L1_B_64HDLC: - if ((bch->rx_idx + ih->reg->clsb) > MAX_DATA_MEM) { + if (!bch->rx_skb) { + bch->rx_skb = alloc_stack_skb(bch->maxlen + 2, bch->up_headerlen); + if (unlikely(!bch->rx_skb)) { + printk(KERN_WARNING "mISDN: skb out of memory\n"); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + break; + } + } + if ((bch->rx_skb->len + ih->reg->clsb) > (bch->maxlen + 2)) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar_rcv_frame: incoming packet too large"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - bch->rx_idx = 0; - } else if (ih->reg->cmsb & HDLC_ERROR) { + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + skb_trim(bch->rx_skb, 0); + break; + } + if (ih->reg->cmsb & HDLC_ERROR) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar frame error %x len %d", ih->reg->cmsb, ih->reg->clsb); @@ -501,131 +515,160 @@ isar_rcv_frame(bchannel_t *bch) if (ih->reg->cmsb & HDLC_ERR_CER) bch->err_crc++; #endif - bch->rx_idx = 0; - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - } else { - if (ih->reg->cmsb & HDLC_FSD) - bch->rx_idx = 0; - ptr = bch->rx_buf + bch->rx_idx; - bch->rx_idx += ih->reg->clsb; - rcv_mbox(bch, ih->reg, ptr); - if (ih->reg->cmsb & HDLC_FED) { - if (bch->rx_idx < 3) { /* last 2 bytes are the FCS */ - if (bch->debug & L1_DEB_WARN) - mISDN_debugprint(&bch->inst, "isar frame to short %d", - bch->rx_idx); - } else if (!(skb = alloc_stack_skb(bch->rx_idx-2, bch->up_headerlen))) { - printk(KERN_WARNING "ISAR: receive out of memory\n"); - } else { - memcpy(skb_put(skb, bch->rx_idx-2), - bch->rx_buf, bch->rx_idx-2); - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - } - bch->rx_idx = 0; + skb_trim(bch->rx_skb, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + break; + } + if (ih->reg->cmsb & HDLC_FSD) + skb_trim(bch->rx_skb, 0); + ptr = skb_put(bch->rx_skb, ih->reg->clsb); + rcv_mbox(bch, ih->reg, ptr); + if (ih->reg->cmsb & HDLC_FED) { + if (bch->rx_skb->len < 3) { /* last 2 bytes are the FCS */ + if (bch->debug & L1_DEB_WARN) + mISDN_debugprint(&bch->inst, "isar frame to short %d", + bch->rx_skb->len); + skb_trim(bch->rx_skb, 0); + break; } + skb_trim(bch->rx_skb, bch->rx_skb->len - 2); + 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; + } + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb); } break; case ISDN_PID_L1_B_T30FAX: if (ih->state != STFAX_ACTIV) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar_rcv_frame: not ACTIV"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - bch->rx_idx = 0; + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); break; } if (ih->cmd == PCTRL_CMD_FRM) { - rcv_mbox(bch, ih->reg, bch->rx_buf); - bch->rx_idx = ih->reg->clsb; - if (bch->debug & L1_DEB_HSCX) - mISDN_debugprint(&bch->inst, "isar_rcv_frame: %d", bch->rx_idx); - if ((skb = alloc_stack_skb(bch->rx_idx, bch->up_headerlen))) { - memcpy(skb_put(skb, bch->rx_idx), bch->rx_buf, bch->rx_idx); - if (ih->reg->cmsb & SART_NMD) { /* ABORT */ - if (bch->debug & L1_DEB_WARN) - mISDN_debugprint(&bch->inst, "isar_rcv_frame: no more data"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - bch->rx_idx = 0; - sendmsg(bch, SET_DPS(ih->dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, - 0, NULL); - ih->state = STFAX_ESCAPE; -// set_skb_flag(skb, DF_NOMOREDATA); + if (!bch->rx_skb) { + bch->rx_skb = alloc_stack_skb(ih->reg->clsb, bch->up_headerlen); + if (unlikely(!bch->rx_skb)) { + printk(KERN_WARNING "mISDN: skb out of memory\n"); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + break; } - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - if (ih->reg->cmsb & SART_NMD) - bch_sched_event(bch, B_LL_NOCARRIER); - } else { - printk(KERN_WARNING "mISDN: skb out of memory\n"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); } + rcv_mbox(bch, ih->reg, skb_put(bch->rx_skb, ih->reg->clsb)); + if (bch->debug & L1_DEB_HSCX) + mISDN_debugprint(&bch->inst, "isar_rcv_frame: %d", + bch->rx_skb->len); + if (ih->reg->cmsb & SART_NMD) { /* ABORT */ + if (bch->debug & L1_DEB_WARN) + mISDN_debugprint(&bch->inst, "isar_rcv_frame: no more data"); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + sendmsg(bch, SET_DPS(ih->dpath) | + ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, + 0, NULL); + ih->state = STFAX_ESCAPE; +// set_skb_flag(skb, DF_NOMOREDATA); + } + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb); + bch->rx_skb = NULL; + if (ih->reg->cmsb & SART_NMD) + deliver_status(bch, HW_MOD_NOCARR); break; } if (ih->cmd != PCTRL_CMD_FRH) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar_rcv_frame: unknown fax mode %x", ih->cmd); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - bch->rx_idx = 0; + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); break; } /* PCTRL_CMD_FRH */ - if ((bch->rx_idx + ih->reg->clsb) > MAX_DATA_MEM) { + if (!bch->rx_skb) { + bch->rx_skb = alloc_stack_skb(bch->maxlen + 2, bch->up_headerlen); + if (unlikely(!bch->rx_skb)) { + printk(KERN_WARNING "mISDN: skb out of memory\n"); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + break; + } + } + if ((bch->rx_skb->len + ih->reg->clsb) > (bch->maxlen + 2)) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar_rcv_frame: incoming packet too large"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - bch->rx_idx = 0; - } else if (ih->reg->cmsb & HDLC_ERROR) { + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + skb_trim(bch->rx_skb, 0); + break; + } else if (ih->reg->cmsb & HDLC_ERROR) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar frame error %x len %d", ih->reg->cmsb, ih->reg->clsb); - bch->rx_idx = 0; - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - } else { - if (ih->reg->cmsb & HDLC_FSD) - bch->rx_idx = 0; - ptr = bch->rx_buf + bch->rx_idx; - bch->rx_idx += ih->reg->clsb; - rcv_mbox(bch, ih->reg, ptr); - if (ih->reg->cmsb & HDLC_FED) { - if (bch->rx_idx < 3) { /* last 2 bytes are the FCS */ - if (bch->debug & L1_DEB_WARN) - mISDN_debugprint(&bch->inst, "isar frame to short %d", - bch->rx_idx); - } else if (!(skb = alloc_stack_skb(bch->rx_idx, bch->up_headerlen))) { - printk(KERN_WARNING "ISAR: receive out of memory\n"); - } else { - memcpy(skb_put(skb, bch->rx_idx-2), bch->rx_buf, bch->rx_idx-2); -// if (ih->reg->cmsb & SART_NMD) - /* ABORT */ -// set_skb_flag(skb, DF_NOMOREDATA); - skb_queue_tail(&bch->rqueue, skb); - bch_sched_event(bch, B_RCVBUFREADY); - } - bch->rx_idx = 0; + skb_trim(bch->rx_skb, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + break; + } + if (ih->reg->cmsb & HDLC_FSD) + skb_trim(bch->rx_skb, 0); + ptr = skb_put(bch->rx_skb, ih->reg->clsb); + rcv_mbox(bch, ih->reg, ptr); + if (ih->reg->cmsb & HDLC_FED) { + if (bch->rx_skb->len < 3) { /* last 2 bytes are the FCS */ + if (bch->debug & L1_DEB_WARN) + mISDN_debugprint(&bch->inst, "isar frame to short %d", + bch->rx_skb->len); + skb_trim(bch->rx_skb, 0); + break; } + skb_trim(bch->rx_skb, bch->rx_skb->len - 2); + 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; + } + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb); } if (ih->reg->cmsb & SART_NMD) { /* ABORT */ if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar_rcv_frame: no more data"); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); - bch->rx_idx = 0; - sendmsg(bch, SET_DPS(ih->dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); + sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_PUMPCTRL, + PCTRL_CMD_ESC, 0, NULL); ih->state = STFAX_ESCAPE; - bch_sched_event(bch, B_LL_NOCARRIER); + deliver_status(bch, HW_MOD_NOCARR); } break; default: - printk(KERN_ERR"isar_rcv_frame protocol (%x)error\n", bch->protocol); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + printk(KERN_ERR"isar_rcv_frame protocol (%x)error\n", bch->state); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); break; } } void -isar_fill_fifo(bchannel_t *bch) +isar_fill_fifo(channel_t *bch) { isar_hw_t *ih = bch->hw; int count; @@ -634,7 +677,9 @@ isar_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; if (!(ih->reg->bstat & @@ -646,27 +691,27 @@ isar_fill_fifo(bchannel_t *bch) } else { msb = HDLC_FED; } - ptr = bch->tx_buf + bch->tx_idx; + ptr = bch->tx_skb->data + bch->tx_idx; if (!bch->tx_idx) { if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "frame start"); - if ((bch->protocol == ISDN_PID_L1_B_T30FAX) && + if ((bch->state == ISDN_PID_L1_B_T30FAX) && (ih->cmd == PCTRL_CMD_FTH)) { if (count > 1) { if ((ptr[0]== 0xff) && (ptr[1] == 0x13)) { /* last frame */ - test_and_set_bit(BC_FLG_LASTDATA, &bch->Flag); + test_and_set_bit(FLG_LASTDATA, &bch->Flags); if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "set LASTDATA"); if (msb == HDLC_FED) - test_and_set_bit(BC_FLG_DLEETX, &bch->Flag); + test_and_set_bit(FLG_DLEETX, &bch->Flags); } } } msb |= HDLC_FST; } bch->tx_idx += count; - switch (bch->protocol) { + switch (bch->state) { case ISDN_PID_NONE: printk(KERN_ERR "%s: wrong protocol 0\n", __FUNCTION__); break; @@ -700,15 +745,15 @@ isar_fill_fifo(bchannel_t *bch) default: if (bch->debug) mISDN_debugprint(&bch->inst, "%s: protocol(%x) error", - __FUNCTION__, bch->protocol); + __FUNCTION__, bch->state); printk(KERN_ERR "%s: protocol(%x) error\n", - __FUNCTION__, bch->protocol); + __FUNCTION__, bch->state); break; } } inline -bchannel_t *sel_bch_isar(bchannel_t *bch, u_char dpath) +channel_t *sel_bch_isar(channel_t *bch, u_char dpath) { if ((!dpath) || (dpath == 3)) @@ -722,74 +767,78 @@ bchannel_t *sel_bch_isar(bchannel_t *bch, u_char dpath) } inline void -send_frames(bchannel_t *bch) +send_frames(channel_t *bch) { isar_hw_t *ih = bch->hw; - if (bch->tx_len - bch->tx_idx) { + if (bch->tx_skb && (bch->tx_skb->len > bch->tx_idx)) { isar_fill_fifo(bch); } else { - bch->tx_idx = 0; - if (bch->protocol == ISDN_PID_L1_B_T30FAX) { + if (bch->state == ISDN_PID_L1_B_T30FAX) { if (ih->cmd == PCTRL_CMD_FTH) { - if (test_bit(BC_FLG_LASTDATA, &bch->Flag)) { + if (test_bit(FLG_LASTDATA, &bch->Flags)) { printk(KERN_WARNING "set NMD_DATA\n"); - test_and_set_bit(BC_FLG_NMD_DATA, &bch->Flag); + test_and_set_bit(FLG_NMD_DATA, &bch->Flags); } } else if (ih->cmd == PCTRL_CMD_FTM) { - if (test_bit(BC_FLG_DLEETX, &bch->Flag)) { - test_and_set_bit(BC_FLG_LASTDATA, &bch->Flag); - test_and_set_bit(BC_FLG_NMD_DATA, &bch->Flag); + if (test_bit(FLG_DLEETX, &bch->Flags)) { + test_and_set_bit(FLG_LASTDATA, &bch->Flags); + test_and_set_bit(FLG_NMD_DATA, &bch->Flags); } } } - 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 (bch->tx_skb) + dev_kfree_skb(bch->tx_skb); + bch->tx_idx = 0; + 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); isar_fill_fifo(bch); - bch_sched_event(bch, B_XMTBUFREADY); } else { - bch->tx_len = 0; - printk(KERN_WARNING "isar tx irq TX_NEXT without skb\n"); - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); + printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n"); + test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); } } else { - bch->tx_len = 0; - if (test_and_clear_bit(BC_FLG_DLEETX, &bch->Flag)) { - if (test_and_clear_bit(BC_FLG_LASTDATA, &bch->Flag)) { - if (test_and_clear_bit(BC_FLG_NMD_DATA, &bch->Flag)) { + bch->tx_skb = NULL; + if (test_and_clear_bit(FLG_DLEETX, &bch->Flags)) { + if (test_and_clear_bit(FLG_LASTDATA, &bch->Flags)) { + if (test_and_clear_bit(FLG_NMD_DATA, &bch->Flags)) { u_char dummy = 0; sendmsg(bch, SET_DPS(ih->dpath) | ISAR_HIS_SDATA, 0x01, 1, &dummy); } - test_and_set_bit(BC_FLG_LL_OK, &bch->Flag); + test_and_set_bit(FLG_LL_OK, &bch->Flags); } else { - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); } } - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); - bch_sched_event(bch, B_XMTBUFREADY); + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); +// bch_sched_event(bch, B_XMTBUFREADY); } } } inline void -check_send(bchannel_t *bch, u_char rdm) +check_send(channel_t *bch, u_char rdm) { - bchannel_t *bc; + channel_t *bc; if (rdm & BSTAT_RDM1) { if ((bc = sel_bch_isar(bch, 1))) { - if (bc->protocol) { + if (test_bit(FLG_ACTIVE, &bc->Flags)) { send_frames(bc); } } } if (rdm & BSTAT_RDM2) { if ((bc = sel_bch_isar(bch, 2))) { - if (bc->protocol) { + if (test_bit(FLG_ACTIVE, &bc->Flags)) { send_frames(bc); } } @@ -804,7 +853,7 @@ const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"}; static void -isar_pump_status_rsp(bchannel_t *bch, isar_reg_t *ireg) { +isar_pump_status_rsp(channel_t *bch, isar_reg_t *ireg) { isar_hw_t *ih = bch->hw; u_char ril = ireg->par[0]; u_char rim; @@ -852,13 +901,12 @@ isar_pump_status_rsp(bchannel_t *bch, isar_reg_t *ireg) { break; } sprintf(ih->conmsg,"%s %s", dmril[ril], dmrim[rim]); - bch->conmsg = ih->conmsg; if (bch->debug & L1_DEB_HSCX) - mISDN_debugprint(&bch->inst, "pump strsp %s", bch->conmsg); + mISDN_debugprint(&bch->inst, "pump strsp %s %s", ih->conmsg); } static void -isar_pump_statev_modem(bchannel_t *bch, u_char devt) { +isar_pump_statev_modem(channel_t *bch, u_char devt) { isar_hw_t *ih = bch->hw; u_char dps = SET_DPS(ih->dpath); @@ -870,13 +918,13 @@ isar_pump_statev_modem(bchannel_t *bch, u_char devt) { case PSEV_CON_ON: if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "pump stev CONNECT"); - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); break; case PSEV_CON_OFF: if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "pump stev NO CONNECT"); sendmsg(bch, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - bch_sched_event(bch, B_LL_NOCARRIER); + deliver_status(bch, HW_MOD_NOCARR); break; case PSEV_V24_OFF: if (bch->debug & L1_DEB_HSCX) @@ -928,7 +976,7 @@ isar_pump_statev_modem(bchannel_t *bch, u_char devt) { } static void -isar_pump_statev_fax(bchannel_t *bch, u_char devt) { +isar_pump_statev_fax(channel_t *bch, u_char devt) { isar_hw_t *ih = bch->hw; u_char dps = SET_DPS(ih->dpath); u_char p1; @@ -942,8 +990,8 @@ isar_pump_statev_fax(bchannel_t *bch, u_char devt) { if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "pump stev RSP_READY"); ih->state = STFAX_READY; - bch_sched_event(bch, B_LL_READY); -// if (test_bit(BC_FLG_ORIG, &bch->Flag)) { + deliver_status(bch, HW_MOD_READY); +// if (test_bit(BC_FLG_ORIG, &bch->Flags)) { // isar_pump_cmd(bch, HW_MOD_FRH, 3); // } else { // isar_pump_cmd(bch, HW_MOD_FTH, 3); @@ -1007,15 +1055,15 @@ isar_pump_statev_fax(bchannel_t *bch, u_char devt) { if (ih->cmd == PCTRL_CMD_FTH) { int delay = (ih->mod == 3) ? 1000 : 200; /* 1s (200 ms) Flags before data */ - if (test_and_set_bit(BC_FLG_FTI_RUN, &bch->Flag)) + if (test_and_set_bit(FLG_FTI_RUN, &bch->Flags)) del_timer(&ih->ftimer); ih->ftimer.expires = jiffies + ((delay * HZ)/1000); - test_and_set_bit(BC_FLG_LL_CONN, - &bch->Flag); + test_and_set_bit(FLG_LL_CONN, + &bch->Flags); add_timer(&ih->ftimer); } else { - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); } } else { if (bch->debug & L1_DEB_WARN) @@ -1060,17 +1108,17 @@ isar_pump_statev_fax(bchannel_t *bch, u_char devt) { break; } } else if (ih->state == STFAX_ACTIV) { - if (test_and_clear_bit(BC_FLG_LL_OK, &bch->Flag)) { - bch_sched_event(bch, B_LL_OK); + if (test_and_clear_bit(FLG_LL_OK, &bch->Flags)) { + deliver_status(bch, HW_MOD_OK); } else if (ih->cmd == PCTRL_CMD_FRM) { - bch_sched_event(bch, B_LL_NOCARRIER); + deliver_status(bch, HW_MOD_NOCARR); } else { - bch_sched_event(bch, B_LL_FCERROR); + deliver_status(bch, HW_MOD_FCERROR); } ih->state = STFAX_READY; } else if (ih->state != STFAX_SILDET) { // ignore in STFAX_SILDET ih->state = STFAX_READY; - bch_sched_event(bch, B_LL_FCERROR); + deliver_status(bch, HW_MOD_FCERROR); } break; case PSEV_RSP_SILDET: @@ -1107,7 +1155,7 @@ isar_pump_statev_fax(bchannel_t *bch, u_char devt) { mISDN_debugprint(&bch->inst, "pump stev RSP_FCERR"); ih->state = STFAX_ESCAPE; sendmsg(bch, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); - bch_sched_event(bch, B_LL_FCERROR); + deliver_status(bch, HW_MOD_FCERROR); break; default: break; @@ -1117,10 +1165,10 @@ isar_pump_statev_fax(bchannel_t *bch, u_char devt) { static char debbuf[128]; void -isar_int_main(bchannel_t *bch) +isar_int_main(channel_t *bch) { isar_hw_t *ih = bch->hw; - bchannel_t *bc; + channel_t *bc; get_irq_infos(bch, ih->reg); switch (ih->reg->iis & ISAR_IIS_MSCMSD) { @@ -1130,11 +1178,11 @@ isar_int_main(bchannel_t *bch) } else { mISDN_debugprint(&bch->inst, "isar spurious IIS_RDATA %x/%x/%x", ih->reg->iis, ih->reg->cmsb, ih->reg->clsb); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); } break; case ISAR_IIS_GSTEV: - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); ih->reg->bstat |= ih->reg->cmsb; check_send(bch, ih->reg->cmsb); break; @@ -1150,28 +1198,36 @@ isar_int_main(bchannel_t *bch) if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "Buffer STEV dpath%d msb(%x)", ih->reg->iis>>6, ih->reg->cmsb); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); break; case ISAR_IIS_PSTEV: if ((bc = sel_bch_isar(bch, ih->reg->iis >> 6))) { rcv_mbox(bc, ih->reg, (u_char *)ih->reg->par); - if (bc->protocol == ISDN_PID_L1_B_MODEM_ASYNC) { + if (bc->state == ISDN_PID_L1_B_MODEM_ASYNC) { isar_pump_statev_modem(bc, ih->reg->cmsb); - } else if (bc->protocol == ISDN_PID_L1_B_T30FAX) { + } else if (bc->state == ISDN_PID_L1_B_T30FAX) { isar_pump_statev_fax(bc, ih->reg->cmsb); - } else if (bc->protocol == ISDN_PID_L2_B_TRANSDTMF) { - ih->conmsg[0] = ih->reg->cmsb; - bch->conmsg = ih->conmsg; - bch_sched_event(bc, B_TOUCH_TONE); + } else if (bc->state == ISDN_PID_L2_B_TRANSDTMF) { + int tt; + tt = ih->reg->cmsb | 0x30; + if (tt == 0x3e) + tt = '*'; + else if (tt == 0x3f) + tt = '#'; + else if (tt > '9') + tt += 7; + tt |= DTMF_TONE_VAL; + mISDN_queue_data(&bch->inst, FLG_MSG_UP, PH_CONTROL | INDICATION, + 0, sizeof(int), &tt, 0); } else { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "isar IIS_PSTEV pmode %d stat %x", - bc->protocol, ih->reg->cmsb); + bc->state, ih->reg->cmsb); } } else { mISDN_debugprint(&bch->inst, "isar spurious IIS_PSTEV %x/%x/%x", ih->reg->iis, ih->reg->cmsb, ih->reg->clsb); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); } break; case ISAR_IIS_PSTRSP: @@ -1181,7 +1237,7 @@ isar_int_main(bchannel_t *bch) } else { mISDN_debugprint(&bch->inst, "isar spurious IIS_PSTRSP %x/%x/%x", ih->reg->iis, ih->reg->cmsb, ih->reg->clsb); - bch->Write_Reg(bch->inst.data, 1, ISAR_IIA, 0); + bch->write_reg(bch->inst.privat, ISAR_IIA, 0); } break; case ISAR_IIS_DIAG: @@ -1214,30 +1270,30 @@ isar_int_main(bchannel_t *bch) } static void -ftimer_handler(bchannel_t *bch) { +ftimer_handler(channel_t *bch) { if (bch->debug) mISDN_debugprint(&bch->inst, "ftimer flags %04x", - bch->Flag); - test_and_clear_bit(BC_FLG_FTI_RUN, &bch->Flag); - if (test_and_clear_bit(BC_FLG_LL_CONN, &bch->Flag)) { - bch_sched_event(bch, B_LL_CONNECT); + bch->Flags); + test_and_clear_bit(FLG_FTI_RUN, &bch->Flags); + if (test_and_clear_bit(FLG_LL_CONN, &bch->Flags)) { + deliver_status(bch, HW_MOD_CONNECT); } } static void -setup_pump(bchannel_t *bch) { +setup_pump(channel_t *bch) { isar_hw_t *ih = bch->hw; u_char dps = SET_DPS(ih->dpath); u_char ctrl, param[6]; - switch (bch->protocol) { + switch (bch->state) { case ISDN_PID_NONE: case ISDN_PID_L1_B_64TRANS: case ISDN_PID_L1_B_64HDLC: sendmsg(bch, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); break; case ISDN_PID_L2_B_TRANSDTMF: - if (test_bit(BC_FLG_DTMFSEND, &bch->Flag)) { + if (test_bit(FLG_DTMFSEND, &bch->Flags)) { param[0] = 5; /* TOA 5 db */ sendmsg(bch, dps | ISAR_HIS_PUMPCFG, PMOD_DTMF_TRANS, 1, param); } else { @@ -1246,7 +1302,7 @@ setup_pump(bchannel_t *bch) { } case ISDN_PID_L1_B_MODEM_ASYNC: ctrl = PMOD_DATAMODEM; - if (test_bit(BC_FLG_ORIG, &bch->Flag)) { + if (test_bit(FLG_ORIGIN, &bch->Flags)) { ctrl |= PCTRL_ORIG; param[5] = PV32P6_CTN; } else { @@ -1262,7 +1318,7 @@ setup_pump(bchannel_t *bch) { break; case ISDN_PID_L1_B_T30FAX: ctrl = PMOD_FAX; - if (test_bit(BC_FLG_ORIG, &bch->Flag)) { + if (test_bit(FLG_ORIGIN, &bch->Flags)) { ctrl |= PCTRL_ORIG; param[1] = PFAXP2_CTN; } else { @@ -1273,7 +1329,7 @@ setup_pump(bchannel_t *bch) { ih->state = STFAX_NULL; ih->newcmd = 0; ih->newmod = 0; - test_and_set_bit(BC_FLG_FTI_RUN, &bch->Flag); + test_and_set_bit(FLG_FTI_RUN, &bch->Flags); break; } udelay(1000); @@ -1282,12 +1338,12 @@ setup_pump(bchannel_t *bch) { } static void -setup_sart(bchannel_t *bch) { +setup_sart(channel_t *bch) { isar_hw_t *ih = bch->hw; u_char dps = SET_DPS(ih->dpath); u_char ctrl, param[2]; - switch (bch->protocol) { + switch (bch->state) { case ISDN_PID_NONE: sendmsg(bch, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, NULL); @@ -1317,14 +1373,14 @@ setup_sart(bchannel_t *bch) { } static void -setup_iom2(bchannel_t *bch) { +setup_iom2(channel_t *bch) { isar_hw_t *ih = bch->hw; u_char dps = SET_DPS(ih->dpath); u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD,0,0,0,0}; if (bch->channel) msg[1] = msg[3] = 1; - switch (bch->protocol) { + switch (bch->state) { case ISDN_PID_NONE: cmsb = 0; /* dummy slot */ @@ -1337,7 +1393,7 @@ setup_iom2(bchannel_t *bch) { case ISDN_PID_L1_B_T30FAX: cmsb |= IOM_CTRL_RCV; case ISDN_PID_L2_B_TRANSDTMF: - if (test_bit(BC_FLG_DTMFSEND, &bch->Flag)) + if (test_bit(FLG_DTMFSEND, &bch->Flags)) cmsb |= IOM_CTRL_RCV; cmsb |= IOM_CTRL_ALAW; break; @@ -1349,12 +1405,12 @@ setup_iom2(bchannel_t *bch) { } static int -modeisar(bchannel_t *bch, int channel, u_int bprotocol, u_char *param) +modeisar(channel_t *bch, int channel, u_int bprotocol, u_char *param) { isar_hw_t *ih = bch->hw; /* Here we are selecting the best datapath for requested protocol */ - if(bch->protocol == ISDN_PID_NONE) { /* New Setup */ + if(bch->state == ISDN_PID_NONE) { /* New Setup */ bch->channel = channel; switch (bprotocol) { case ISDN_PID_NONE: /* init */ @@ -1392,12 +1448,12 @@ modeisar(bchannel_t *bch, int channel, u_int bprotocol, u_char *param) } if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "isar dp%d protocol %x->%x ichan %d", - ih->dpath, bch->protocol, bprotocol, channel); - bch->protocol = bprotocol; + ih->dpath, bch->state, bprotocol, channel); + bch->state = bprotocol; setup_pump(bch); setup_iom2(bch); setup_sart(bch); - if (bch->protocol == ISDN_PID_NONE) { + if (bch->state == ISDN_PID_NONE) { /* Clear resources */ if (ih->dpath == 1) test_and_clear_bit(ISAR_DP1_USE, &ih->reg->Flags); @@ -1409,7 +1465,7 @@ modeisar(bchannel_t *bch, int channel, u_int bprotocol, u_char *param) } static void -isar_pump_cmd(bchannel_t *bch, int cmd, u_char para) +isar_pump_cmd(channel_t *bch, int cmd, u_char para) { isar_hw_t *ih = bch->hw; u_char dps = SET_DPS(ih->dpath); @@ -1433,7 +1489,7 @@ isar_pump_cmd(bchannel_t *bch, int cmd, u_char para) } else if ((ih->state == STFAX_ACTIV) && (ih->cmd == PCTRL_CMD_FTM) && (ih->mod == para)) { - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); } else { ih->newmod = para; ih->newcmd = PCTRL_CMD_FTM; @@ -1456,7 +1512,7 @@ isar_pump_cmd(bchannel_t *bch, int cmd, u_char para) } else if ((ih->state == STFAX_ACTIV) && (ih->cmd == PCTRL_CMD_FTH) && (ih->mod == para)) { - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); } else { ih->newmod = para; ih->newcmd = PCTRL_CMD_FTH; @@ -1479,7 +1535,7 @@ isar_pump_cmd(bchannel_t *bch, int cmd, u_char para) } else if ((ih->state == STFAX_ACTIV) && (ih->cmd == PCTRL_CMD_FRM) && (ih->mod == para)) { - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); } else { ih->newmod = para; ih->newcmd = PCTRL_CMD_FRM; @@ -1502,7 +1558,7 @@ isar_pump_cmd(bchannel_t *bch, int cmd, u_char para) } else if ((ih->state == STFAX_ACTIV) && (ih->cmd == PCTRL_CMD_FRH) && (ih->mod == para)) { - bch_sched_event(bch, B_LL_CONNECT); + deliver_status(bch, HW_MOD_CONNECT); } else { ih->newmod = para; ih->newcmd = PCTRL_CMD_FRH; @@ -1522,7 +1578,7 @@ isar_pump_cmd(bchannel_t *bch, int cmd, u_char para) } void -isar_setup(bchannel_t *bch) +isar_setup(channel_t *bch) { u_char msg; int i; @@ -1535,80 +1591,72 @@ isar_setup(bchannel_t *bch) sendmsg(bch, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | ISAR_HIS_P12CFG, 4, 1, &msg); ih->mml = msg; - bch[i].protocol = 0; + bch[i].state = 0; ih->dpath = i + 1; modeisar(&bch[i], i, 0, NULL); } } int -isar_down(mISDNif_t *hif, struct sk_buff *skb) +isar_down(mISDNinstance_t *inst, struct sk_buff *skb) { - bchannel_t *bch; - int ret = -EINVAL; - mISDN_head_t *hh; + channel_t *bch = container_of(inst, channel_t, inst); + 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; - ret = 0; 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; + spin_lock_irqsave(inst->hwlock, flags); + ret = channel_senddata(bch, hh->dinfo, skb); + if (ret > 0) { /* direct TX */ isar_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 { + } + 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)) { u_int bp = bch->inst.pid.protocol[1]; if (bch->inst.pid.global == 1) - test_and_set_bit(BC_FLG_ORIG, &bch->Flag); + test_and_set_bit(FLG_ORIGIN, &bch->Flags); if ((bp == ISDN_PID_L1_B_64TRANS) && (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_TRANSDTMF)) bp = ISDN_PID_L2_B_TRANSDTMF; - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(inst->hwlock, flags); ret = modeisar(bch, bch->channel, bp, NULL); - 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; + if (bch->rx_skb) { + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); + test_and_clear_bit(FLG_L2DATA, &bch->Flags); modeisar(bch, bch->channel, 0, NULL); - 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); + if (hh->prim != (PH_CONTROL | REQUEST)) + ret = mISDN_queueup_newhead(inst, 0, hh->prim | CONFIRM, 0, skb); } else if (hh->prim == (PH_CONTROL | REQUEST)) { int *val; int len; @@ -1618,7 +1666,7 @@ isar_down(mISDNif_t *hif, struct sk_buff *skb) mISDN_debugprint(&bch->inst, "PH_CONTROL | REQUEST %x/%x", hh->dinfo, *val); if ((hh->dinfo == 0) && ((*val & ~DTMF_TONE_MASK) == DTMF_TONE_VAL)) { - if (bch->protocol == ISDN_PID_L2_B_TRANSDTMF) { + if (bch->state == ISDN_PID_L2_B_TRANSDTMF) { char tt = *val & DTMF_TONE_MASK; if (tt == '*') @@ -1628,16 +1676,15 @@ isar_down(mISDNif_t *hif, struct sk_buff *skb) else if (tt > '9') tt -= 7; tt &= 0x1f; - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(inst->hwlock, flags); isar_pump_cmd(bch, PCTRL_CMD_TDTMF, tt); - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(inst->hwlock, flags); skb_trim(skb, 0); - if (!if_newhead(&bch->inst.up, PH_CONTROL | - CONFIRM, 0, skb)) + if (!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb)) return(0); } else { printk(KERN_WARNING "isar_down TOUCH_TONE_SEND wrong protocol %x\n", - bch->protocol); + bch->state); return(-EINVAL); } } else if ((hh->dinfo == HW_MOD_FRM) || (hh->dinfo == HW_MOD_FRH) || @@ -1647,7 +1694,7 @@ isar_down(mISDNif_t *hif, struct sk_buff *skb) for (i=0; i i) && test_bit(BC_FLG_INIT, &bch->Flag)) { + if ((FAXMODCNT > i) && test_bit(FLG_INITIALIZED, &bch->Flags)) { printk(KERN_WARNING "isar: new mod\n"); isar_pump_cmd(bch, hh->dinfo, *val); ret = 0; @@ -1655,9 +1702,10 @@ isar_down(mISDNif_t *hif, struct sk_buff *skb) int_errtxt("wrong modulation"); /* wrong modulation or not activ */ // TODO + ret = -EINVAL; } } else if (hh->dinfo == HW_MOD_LASTDATA) { - test_and_set_bit(BC_FLG_DLEETX, &bch->Flag); + test_and_set_bit(FLG_DLEETX, &bch->Flags); } else if (hh->dinfo == HW_FIRM_START) { firmwaresize = *val; if (!(firmware = vmalloc(firmwaresize))) { @@ -1666,32 +1714,38 @@ isar_down(mISDNif_t *hif, struct sk_buff *skb) } fw_p = firmware; skb_trim(skb, 0); - if(!if_newhead(&bch->inst.up, PH_CONTROL | CONFIRM, - 0, skb)) + if(!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb)) return(0); } else if (hh->dinfo == HW_FIRM_DATA) { len = *val++; + if (!fw_p) + return(-EINVAL); memcpy(fw_p, val, len); fw_p += len; skb_trim(skb, 0); - if(!if_newhead(&bch->inst.up, PH_CONTROL | CONFIRM, - 0, skb)) + if(!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb)) return(0); } else if (hh->dinfo == HW_FIRM_END) { - if ((fw_p - firmware) == firmwaresize) + if (!fw_p) + return(-EINVAL); + len = (fw_p - firmware) & 0xffffffff; + if (len == firmwaresize) ret = isar_load_firmware(bch, firmware, firmwaresize); else { printk(KERN_WARNING "wrong firmware size %d/%d\n", - fw_p - firmware, firmwaresize); + len, firmwaresize); ret = -EINVAL; } vfree(firmware); fw_p = firmware = NULL; firmwaresize = 0; skb_trim(skb, 0); - if(!if_newhead(&bch->inst.up, PH_CONTROL | CONFIRM, - 0, skb)) + if(!mISDN_queueup_newhead(inst, 0, PH_CONTROL | CONFIRM, 0, skb)) return(0); + } else { + printk(KERN_WARNING "isar_down unknown (PH_CONTROL | REQUEST) %x\n", + hh->dinfo); + ret = -EINVAL; } } else { printk(KERN_WARNING "isar_down unknown prim(%x)\n", hh->prim); @@ -1703,25 +1757,24 @@ isar_down(mISDNif_t *hif, struct sk_buff *skb) } void -free_isar(bchannel_t *bch) +free_isar(channel_t *bch) { isar_hw_t *ih = bch->hw; modeisar(bch, bch->channel, 0, NULL); del_timer(&ih->ftimer); - test_and_clear_bit(BC_FLG_INIT, &bch->Flag); + test_and_clear_bit(FLG_INITIALIZED, &bch->Flags); } -int init_isar(bchannel_t *bch) +int init_isar(channel_t *bch) { isar_hw_t *ih = bch->hw; printk(KERN_INFO "mISDN: ISAR driver Rev. %s\n", mISDN_getrev(ISAR_revision)); - bch->hw_bh = isar_bh; ih->ftimer.function = (void *) ftimer_handler; ih->ftimer.data = (long) bch; init_timer(&ih->ftimer); - test_and_set_bit(BC_FLG_INIT, &bch->Flag); + test_and_set_bit(FLG_INITIALIZED, &bch->Flags); return (0); } diff --git a/drivers/isdn/hardware/mISDN/isar.h b/drivers/isdn/hardware/mISDN/isar.h index 65c7bc7..10f7995 100644 --- a/drivers/isdn/hardware/mISDN/isar.h +++ b/drivers/isdn/hardware/mISDN/isar.h @@ -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); diff --git a/drivers/isdn/hardware/mISDN/l3_udss1.c b/drivers/isdn/hardware/mISDN/l3_udss1.c index 55f919d..61ba1a0 100644 --- a/drivers/isdn/hardware/mISDN/l3_udss1.c +++ b/drivers/isdn/hardware/mISDN/l3_udss1.c @@ -4,7 +4,7 @@ * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is (c) under GNU PUBLIC LICENSE * For changes and modifications please read * ../../../Documentation/isdn/mISDN.cert * @@ -32,8 +32,9 @@ static int parseQ931(struct sk_buff *skb) { Q931_info_t *qi; int l, codeset, maincodeset; - int len, iep, pos = 0, cnt = 0; - u16 *ie, cr; + int len, iep, pos = 0, cnt = 0, eidx = -1; + u16 cr; + ie_info_t *ie, *old; u_char t, *p = skb->data; if (skb->len < 3) @@ -79,57 +80,125 @@ parseQ931(struct sk_buff *skb) { codeset = p[pos] & 0x07; if (!(p[pos] & 0x08)) maincodeset = codeset; + if (eidx >= 0) { + qi->ext[eidx].cs.len = pos - qi->ext[eidx].ie.off; + eidx = -1; + } pos++; continue; } if (codeset == 0) { if (p[pos] & 0x80) { /* single octett IE */ if (p[pos] == IE_MORE_DATA) - qi->more_data = pos; + qi->more_data.off = pos; else if (p[pos] == IE_COMPLETE) - qi->sending_complete = pos; + qi->sending_complete.off = pos; else if ((p[pos] & 0xf0) == IE_CONGESTION) - qi->congestion_level = pos; + qi->congestion_level.off = pos; cnt++; pos++; } else { - iep = mISDN_l3_ie2pos(p[pos]); + t = p[pos]; + iep = mISDN_l3_ie2pos(t); if ((pos+1) >= len) return(-4); l = p[pos+1]; if ((pos+l+1) >= len) return(-5); if (iep>=0) { - if (!ie[iep]) - ie[iep] = pos; + if (!ie[iep].off) { /* IE not detected before */ + ie[iep].off = pos; + } else { /* IE is repeated */ + old = &ie[iep]; + if (old->repeated) + old = mISDN_get_last_repeated_ie(qi, old); + if (!old) { + int_error(); + return(-6); + } + eidx = mISDN_get_free_ext_ie(qi); + if (eidx < 0) { + int_error(); + return(-7); + } + old->ridx = eidx; + old->repeated = 1; + qi->ext[eidx].ie.off = pos; + qi->ext[eidx].v.codeset = 0; + qi->ext[eidx].v.val = t; + eidx = -1; + } } pos += l + 2; cnt++; } + } else { /* codeset != 0 */ + if (eidx < 0) { + eidx = mISDN_get_free_ext_ie(qi); + if (eidx < 0) { + int_error(); + return(-8); + } + qi->ext[eidx].cs.codeset = codeset; + qi->ext[eidx].ie.off = pos; + qi->ext[eidx].ie.cs_flg = 1; + if (codeset == maincodeset) { /* locked shift */ + qi->ext[eidx].cs.locked = 1; + } + } + if (p[pos] & 0x80) { /* single octett IE */ + cnt++; + pos++; + } else { + if ((pos+1) >= len) + return(-4); + l = p[pos+1]; + if ((pos+l+1) >= len) + return(-5); + pos += l + 2; + cnt++; + } + if (qi->ext[eidx].cs.locked == 0) {/* single IE codeset shift */ + qi->ext[eidx].cs.len = pos - qi->ext[eidx].ie.off; + eidx = -1; + } } codeset = maincodeset; } + if (eidx >= 0) + qi->ext[eidx].cs.len = pos - qi->ext[eidx].ie.off; return(cnt); } static int calc_msg_len(Q931_info_t *qi) { - int i, cnt = 0; - u_char *buf = (u_char *)qi; - u16 *v_ie; + int i, cnt = 0; + u_char *buf = (u_char *)qi; + ie_info_t *ie; buf += L3_EXTRA_SIZE; - if (qi->more_data) + if (qi->more_data.off) cnt++; - if (qi->sending_complete) + if (qi->sending_complete.off) cnt++; - if (qi->congestion_level) + if (qi->congestion_level.off) cnt++; - v_ie = &qi->bearer_capability; - for (i=0; i<32; i++) { - if (v_ie[i]) - cnt += buf[v_ie[i] + 1] + 2; + ie = &qi->bearer_capability; + while (ie <= &qi->fill1) { + if (ie->off) + cnt += buf[ie->off + 1] + 2; + ie++; + } + for (i = 0; i < 8; i++) { + if (qi->ext[i].ie.off) { + if (qi->ext[i].ie.cs_flg == 1) { /* other codset info chunk */ + cnt++; /* codeset shift IE */ + cnt += qi->ext[i].cs.len; + } else { /* repeated IE */ + cnt += buf[qi->ext[i].ie.off + 1] + 2; + } + } } return(cnt); } @@ -137,31 +206,58 @@ calc_msg_len(Q931_info_t *qi) static int compose_msg(struct sk_buff *skb, Q931_info_t *qi) { - int i, l; - u_char *p, *buf = (u_char *)qi; - u16 *v_ie; + int i, l, ri; + u_char *p, *buf = (u_char *)qi; + ie_info_t *ie; buf += L3_EXTRA_SIZE; - - if (qi->more_data) { + + if (qi->more_data.off) { p = skb_put(skb, 1); - *p = buf[qi->more_data]; + *p = buf[qi->more_data.off]; } - if (qi->sending_complete) { + if (qi->sending_complete.off) { p = skb_put(skb, 1); - *p = buf[qi->sending_complete]; + *p = buf[qi->sending_complete.off]; } - if (qi->congestion_level) { + if (qi->congestion_level.off) { p = skb_put(skb, 1); - *p = buf[qi->congestion_level]; + *p = buf[qi->congestion_level.off]; } - v_ie = &qi->bearer_capability; + ie = &qi->bearer_capability; for (i=0; i<32; i++) { - if (v_ie[i]) { - l = buf[v_ie[i] + 1] +1; + if (ie[i].off) { + l = buf[ie[i].off + 1] +1; p = skb_put(skb, l + 1); *p++ = mISDN_l3_pos2ie(i); - memcpy(p, &buf[v_ie[i] + 1], l); + memcpy(p, &buf[ie[i].off + 1], l); + if (ie[i].repeated) { + ri = ie[i].ridx; + while(ri >= 0) { + l = buf[qi->ext[ri].ie.off + 1] +1; + p = skb_put(skb, l + 1); + if (mISDN_l3_pos2ie(i) != qi->ext[ri].v.val) + int_error(); + *p++ = qi->ext[ri].v.val; + memcpy(p, &buf[qi->ext[ri].ie.off + 1], l); + if (qi->ext[ri].ie.repeated) + ri = qi->ext[ri].ie.ridx; + else + ri = -1; + } + } + } + } + for (i=0; i<8; i++) { + /* handle other codeset elements */ + if (qi->ext[i].ie.cs_flg == 1) { + p = skb_put(skb, 1); /* shift codeset IE */ + if (qi->ext[i].cs.locked == 1) + *p = 0x90 | qi->ext[i].cs.codeset; + else /* non-locking shift */ + *p = 0x98 | qi->ext[i].cs.codeset; + p = skb_put(skb, qi->ext[i].cs.len); + memcpy(p, &buf[qi->ext[i].ie.off], qi->ext[i].cs.len); } } return(0); @@ -302,7 +398,7 @@ static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, IE_USER_USER, -1}; static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; -static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, +static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; @@ -315,7 +411,7 @@ static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -/* a RELEASE_COMPLETE with errors don't require special actions +/* a RELEASE_COMPLETE with errors don't require special actions static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; */ @@ -334,7 +430,13 @@ static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_FACILITY, IE_DISPLAY, -1}; static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -/* not used +static int ie_HOLD[] = {IE_DISPLAY, -1}; +static int ie_HOLD_ACKNOWLEDGE[] = {IE_DISPLAY, -1}; +static int ie_HOLD_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_RETRIEVE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_RETRIEVE_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_DISPLAY, -1}; +static int ie_RETRIEVE_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; +/* not used * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; @@ -421,16 +523,16 @@ check_infoelements(l3_process_t *pc, struct sk_buff *skb, int *checklist) Q931_info_t *qi = (Q931_info_t *)skb->data; int *cl = checklist; u_char *p, ie; - u16 *iep; + ie_info_t *iep; int i, l, newpos, oldpos; int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - + p = skb->data; p += L3_EXTRA_SIZE; iep = &qi->bearer_capability; oldpos = -1; for (i=0; i<32; i++) { - if (iep[i]) { + if (iep[i].off) { ie = mISDN_l3_pos2ie(i); if ((newpos = ie_in_set(pc, ie, cl))) { if (newpos > 0) { @@ -445,7 +547,7 @@ check_infoelements(l3_process_t *pc, struct sk_buff *skb, int *checklist) else err_ureg++; } - l = p[iep[i] +1]; + l = p[iep[i].off +1]; if (l > getmax_ie_len(ie)) err_len++; } @@ -462,7 +564,7 @@ check_infoelements(l3_process_t *pc, struct sk_buff *skb, int *checklist) return(ERR_IE_LENGTH); if (err_seq) return(ERR_IE_SEQUENCE); - } + } return(0); } @@ -494,6 +596,12 @@ l3dss1_check_messagetype_validity(l3_process_t *pc, int mt, void *arg) case MT_CONGESTION_CONTROL: case MT_STATUS: case MT_STATUS_ENQUIRY: + case MT_HOLD: + case MT_HOLD_ACKNOWLEDGE: + case MT_HOLD_REJECT: + case MT_RETRIEVE: + case MT_RETRIEVE_ACKNOWLEDGE: + case MT_RETRIEVE_REJECT: if (pc->l3->debug & L3_DEB_CHECK) l3_debug(pc->l3, "l3dss1_check_messagetype_validity mt(%x) OK", mt); break; @@ -514,7 +622,7 @@ l3dss1_std_ie_err(l3_process_t *pc, int ret) { if (pc->l3->debug & L3_DEB_CHECK) l3_debug(pc->l3, "check_infoelements ret %d", ret); switch(ret) { - case 0: + case 0: break; case ERR_IE_COMPREHENSION: l3dss1_status_send(pc, CAUSE_MANDATORY_IE_MISS); @@ -536,9 +644,9 @@ l3dss1_get_channel_id(l3_process_t *pc, struct sk_buff *skb) { Q931_info_t *qi = (Q931_info_t *)skb->data; u_char *p; - if (qi->channel_id) { + if (qi->channel_id.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->channel_id; + p += L3_EXTRA_SIZE + qi->channel_id.off; p++; if (test_bit(FLG_EXTCID, &pc->l3->Flag)) { if (*p != 1) { @@ -569,9 +677,9 @@ l3dss1_get_cause(l3_process_t *pc, struct sk_buff *skb) { u_char l; u_char *p; - if (qi->cause) { + if (qi->cause.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->cause; + p += L3_EXTRA_SIZE + qi->cause.off; p++; l = *p++; if (l>30) { @@ -636,8 +744,8 @@ l3dss1_disconnect_req(l3_process_t *pc, u_char pr, void *arg) StopAllL3Timer(pc); if (arg) { qi = (Q931_info_t *)skb->data; - if (!qi->cause) { - qi->cause = skb->len - L3_EXTRA_SIZE; + if (!qi->cause.off) { + qi->cause.off = skb->len - L3_EXTRA_SIZE; p = skb_put(skb, 4); *p++ = IE_CAUSE; *p++ = 2; @@ -935,7 +1043,7 @@ l3dss1_disconnect(l3_process_t *pc, u_char pr, void *arg) cause = CAUSE_MANDATORY_IE_MISS; else cause = CAUSE_INVALID_CONTENTS; - } + } ret = check_infoelements(pc, skb, ie_DISCONNECT); if (ERR_IE_COMPREHENSION == ret) cause = CAUSE_MANDATORY_IE_MISS; @@ -1020,8 +1128,8 @@ l3dss1_setup(l3_process_t *pc, u_char pr, void *arg) */ /* only the first occurence 'll be detected ! */ p = skb->data; - if (qi->bearer_capability) { - p += L3_EXTRA_SIZE + qi->bearer_capability; + if (qi->bearer_capability.off) { + p += L3_EXTRA_SIZE + qi->bearer_capability.off; p++; if ((p[0] < 2) || (p[0] > 11)) err = 1; @@ -1033,7 +1141,7 @@ l3dss1_setup(l3_process_t *pc, u_char pr, void *arg) case 0x08: /* Unrestricted digital information */ case 0x09: /* Restricted digital information */ case 0x11: - /* Unrestr. digital information with + /* Unrestr. digital information with * tones/announcements ( or 7 kHz audio */ case 0x18: /* Video */ @@ -1062,7 +1170,7 @@ l3dss1_setup(l3_process_t *pc, u_char pr, void *arg) l3dss1_msg_without_setup(pc, CAUSE_INVALID_CONTENTS); dev_kfree_skb(skb); return; - } + } } else { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "setup without bearer capabilities"); @@ -1090,7 +1198,7 @@ l3dss1_setup(l3_process_t *pc, u_char pr, void *arg) if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "setup without bchannel, call waiting"); bcfound++; - } + } } else { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "setup with wrong chid ret %d", err); @@ -1163,9 +1271,9 @@ l3dss1_progress(l3_process_t *pc, u_char pr, void *arg) { int err = 0; u_char *p, cause = CAUSE_INVALID_CONTENTS; - if (qi->progress) { + if (qi->progress.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->progress; + p += L3_EXTRA_SIZE + qi->progress.off; p++; if (p[0] != 2) { err = 1; @@ -1199,7 +1307,7 @@ l3dss1_progress(l3_process_t *pc, u_char pr, void *arg) { cause = CAUSE_MANDATORY_IE_MISS; err = 4; } - if (err) { + if (err) { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "progress error %d", err); l3dss1_status_send(pc, cause); @@ -1210,6 +1318,16 @@ l3dss1_progress(l3_process_t *pc, u_char pr, void *arg) { err = check_infoelements(pc, skb, ie_PROGRESS); if (err) l3dss1_std_ie_err(pc, err); + /* + * clear T310 if running (should be cleared by a Progress + * Message, according to ETSI). + * + */ + L3DelTimer(&pc->timer); + if (pc->t303skb) { + dev_kfree_skb(pc->t303skb); + pc->t303skb = NULL; + } if (ERR_IE_COMPREHENSION != err) { if (mISDN_l3up(pc, CC_PROGRESS | INDICATION, skb)) dev_kfree_skb(skb); @@ -1223,10 +1341,10 @@ l3dss1_notify(l3_process_t *pc, u_char pr, void *arg) { Q931_info_t *qi = (Q931_info_t *)skb->data; int err = 0; u_char *p, cause = CAUSE_INVALID_CONTENTS; - - if (qi->notify) { + + if (qi->notify.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->notify; + p += L3_EXTRA_SIZE + qi->notify.off; p++; if (p[0] != 1) { err = 1; @@ -1247,7 +1365,7 @@ l3dss1_notify(l3_process_t *pc, u_char pr, void *arg) { cause = CAUSE_MANDATORY_IE_MISS; err = 3; } - if (err) { + if (err) { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "notify error %d", err); l3dss1_status_send(pc, cause); @@ -1301,9 +1419,9 @@ l3dss1_release_ind(l3_process_t *pc, u_char pr, void *arg) int err, callState = -1; Q931_info_t *qi = (Q931_info_t *)skb->data; - if (qi->call_state) { + if (qi->call_state.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->call_state; + p += L3_EXTRA_SIZE + qi->call_state.off; p++; if (1 == *p++) callState = *p; @@ -1325,6 +1443,7 @@ l3dss1_release_ind(l3_process_t *pc, u_char pr, void *arg) static void l3dss1_restart(l3_process_t *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; + L3DelTimer(&pc->timer); mISDN_l3up(pc, CC_RELEASE | INDICATION, NULL); release_l3_process(pc); @@ -1336,9 +1455,9 @@ static void l3dss1_status(l3_process_t *pc, u_char pr, void *arg) { struct sk_buff *skb = arg; Q931_info_t *qi = (Q931_info_t *)skb->data; - int ret = 0; + int ret = 0; u_char *p, cause = 0, callState = 0xff; - + if ((ret = l3dss1_get_cause(pc, skb))) { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "STATUS get_cause ret(%d)", ret); @@ -1347,9 +1466,9 @@ l3dss1_status(l3_process_t *pc, u_char pr, void *arg) { else cause = CAUSE_INVALID_CONTENTS; } - if (qi->call_state) { + if (qi->call_state.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->call_state; + p += L3_EXTRA_SIZE + qi->call_state.off; p++; if (1 == *p++) { callState = *p; @@ -1375,7 +1494,7 @@ l3dss1_status(l3_process_t *pc, u_char pr, void *arg) { return; } } - if (qi->cause) + if (qi->cause.off) cause = pc->err & 0x7f; if ((cause == CAUSE_PROTOCOL_ERROR) && (callState == 0)) { /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... @@ -1397,15 +1516,15 @@ l3dss1_facility(l3_process_t *pc, u_char pr, void *arg) struct sk_buff *skb = arg; Q931_info_t *qi = (Q931_info_t *)skb->data; int ret; - + ret = check_infoelements(pc, skb, ie_FACILITY); l3dss1_std_ie_err(pc, ret); - if (!qi->facility) { + if (!qi->facility.off) { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "FACILITY without IE_FACILITY"); dev_kfree_skb(skb); return; - } + } if (mISDN_l3up(pc, CC_FACILITY | INDICATION, skb)) dev_kfree_skb(skb); } @@ -1436,7 +1555,7 @@ l3dss1_suspend_rej(l3_process_t *pc, u_char pr, void *arg) if ((ret = l3dss1_get_cause(pc, skb))) { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "SUSP_REJ get_cause err(%d)", ret); - if (ret == -1) + if (ret == -1) cause = CAUSE_MANDATORY_IE_MISS; else cause = CAUSE_INVALID_CONTENTS; @@ -1505,7 +1624,7 @@ l3dss1_resume_rej(l3_process_t *pc, u_char pr, void *arg) if ((ret = l3dss1_get_cause(pc, skb))) { if (pc->l3->debug & L3_DEB_WARN) l3_debug(pc->l3, "RES_REJ get_cause err(%d)", ret); - if (ret == -1) + if (ret == -1) cause = CAUSE_MANDATORY_IE_MISS; else cause = CAUSE_INVALID_CONTENTS; @@ -1538,9 +1657,9 @@ l3dss1_global_restart(l3_process_t *pc, u_char pr, void *arg) // newl3state(pc, 2); L3DelTimer(&pc->timer); - if (qi->restart_ind) { + if (qi->restart_ind.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->restart_ind; + p += L3_EXTRA_SIZE + qi->restart_ind.off; p++; ri = p[1]; l3_debug(pc->l3, "Restart %x", ri); @@ -1548,9 +1667,9 @@ l3dss1_global_restart(l3_process_t *pc, u_char pr, void *arg) l3_debug(pc->l3, "Restart without restart IE"); ri = 0x86; } - if (qi->channel_id) { + if (qi->channel_id.off) { p = skb->data; - p += L3_EXTRA_SIZE + qi->channel_id; + p += L3_EXTRA_SIZE + qi->channel_id.off; p++; chan = p[1] & 3; ch = p[1]; @@ -1583,6 +1702,394 @@ l3dss1_dummy(l3_process_t *pc, u_char pr, void *arg) { } +static void +l3dss1_hold_req(l3_process_t *pc, u_char pr, void *arg) +{ + if (!test_bit(FLG_PTP, &pc->l3->Flag)) { + if ((pc->state & VALID_HOLD_STATES_PTMP) == 0) { /* not a valid HOLD state for PtMP */ + return; + } + } + switch(pc->aux_state) { + case AUX_IDLE: + break; + default: + int_errtxt("RETRIEVE_REQ in wrong aux state %d\n", pc->aux_state); + case AUX_HOLD_IND: /* maybe collition, ignored */ + return; + } + if (arg) + SendMsg(pc, arg, -1); + else + l3dss1_message(pc, MT_HOLD); + pc->aux_state = AUX_HOLD_REQ; + L3AddTimer(&pc->aux_timer, THOLD, CC_THOLD); +} + +static void +l3dss1_hold_ack_req(l3_process_t *pc, u_char pr, void *arg) +{ + switch(pc->aux_state) { + case AUX_HOLD_IND: + break; + default: + int_errtxt("HOLD_ACK in wrong aux state %d\n", pc->aux_state); + return; + } + if (arg) + SendMsg(pc, arg, -1); + else + l3dss1_message(pc, MT_HOLD_ACKNOWLEDGE); + pc->aux_state = AUX_CALL_HELD; +} + +static void +l3dss1_hold_rej_req(l3_process_t *pc, u_char pr, void *arg) +{ + switch(pc->aux_state) { + case AUX_HOLD_IND: + break; + default: + int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state); + return; + } + if (arg) + SendMsg(pc, arg, -1); + else + l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_RESOURCES_UNAVAIL); // FIXME + pc->aux_state = AUX_IDLE; +} + +static void +l3dss1_hold_ind(l3_process_t *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_HOLD); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + dev_kfree_skb(skb); + return; + } + if (test_bit(FLG_PTP, &pc->l3->Flag)) { + if ((pc->state & VALID_HOLD_STATES_PTP) == 0) { /* not a valid HOLD state for PtP */ + l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE); + dev_kfree_skb(skb); + return; + } + } else { + if ((pc->state & VALID_HOLD_STATES_PTMP) == 0) { /* not a valid HOLD state for PtMP */ + l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE); + dev_kfree_skb(skb); + return; + } + } + switch(pc->aux_state) { + case AUX_HOLD_REQ: + L3DelTimer(&pc->aux_timer); + case AUX_IDLE: + if (mISDN_l3up(pc, CC_HOLD | INDICATION, skb)) + dev_kfree_skb(skb); + else { + pc->aux_state = AUX_HOLD_IND; + } + break; + default: + l3dss1_message_cause(pc, MT_HOLD_REJECT, CAUSE_NOTCOMPAT_STATE); + dev_kfree_skb(skb); + return; + } + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); +} + +static void +l3dss1_hold_rej(l3_process_t *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + u_char cause; + + if ((ret = l3dss1_get_cause(pc, skb))) { + if (pc->l3->debug & L3_DEB_WARN) + l3_debug(pc->l3, "HOLD_REJ get_cause err(%d)", ret); + if (ret == -1) + cause = CAUSE_MANDATORY_IE_MISS; + else + cause = CAUSE_INVALID_CONTENTS; + l3dss1_status_send(pc, cause); + dev_kfree_skb(skb); + return; + } + ret = check_infoelements(pc, skb, ie_HOLD_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + dev_kfree_skb(skb); + return; + } + switch(pc->aux_state) { + case AUX_HOLD_REQ: + L3DelTimer(&pc->aux_timer); + break; + default: + int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state); + } + pc->aux_state = AUX_IDLE; + if (mISDN_l3up(pc, CC_HOLD_REJECT | INDICATION, skb)) + dev_kfree_skb(skb); +} + +static void +l3dss1_hold_ignore(l3_process_t *pc, u_char pr, void *arg) +{ + dev_kfree_skb(arg); +} + +static void +l3dss1_hold_req_ignore(l3_process_t *pc, u_char pr, void *arg) +{ +} + +static void +l3dss1_hold_ack(l3_process_t *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_HOLD_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + dev_kfree_skb(skb); + return; + } + switch(pc->aux_state) { + case AUX_HOLD_REQ: + L3DelTimer(&pc->aux_timer); + if (mISDN_l3up(pc, CC_HOLD_ACKNOWLEDGE | INDICATION, skb)) + dev_kfree_skb(skb); + pc->aux_state = AUX_CALL_HELD; + break; + default: + int_errtxt("HOLD_ACK in wrong aux state %d\n", pc->aux_state); + dev_kfree_skb(skb); + } + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); +} + +static void +l3dss1_retrieve_req(l3_process_t *pc, u_char pr, void *arg) +{ + if (!test_bit(FLG_PTP, &pc->l3->Flag)) { + if ((pc->state & (VALID_HOLD_STATES_PTMP | SBIT(12))) == 0) { /* not a valid RETRIEVE state for PtMP */ + return; + } + } + switch(pc->aux_state) { + case AUX_CALL_HELD: + break; + default: + int_errtxt("RETRIEVE_REQ in wrong aux state %d\n", pc->aux_state); + case AUX_RETRIEVE_IND: /* maybe collition, ignored */ + return; + } + if (arg) { + SendMsg(pc, arg, -1); + } else { + newl3state(pc, -1); + l3dss1_message(pc, MT_RETRIEVE); + } + pc->aux_state = AUX_RETRIEVE_REQ; + L3AddTimer(&pc->aux_timer, TRETRIEVE, CC_TRETRIEVE); +} + +static void +l3dss1_retrieve_ack_req(l3_process_t *pc, u_char pr, void *arg) +{ + switch(pc->aux_state) { + case AUX_RETRIEVE_IND: + break; + default: + int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state); + return; + } + if (arg) + SendMsg(pc, arg, -1); + else + l3dss1_message(pc, MT_RETRIEVE_ACKNOWLEDGE); + pc->aux_state = AUX_IDLE; +} + +static void +l3dss1_retrieve_rej_req(l3_process_t *pc, u_char pr, void *arg) +{ + switch(pc->aux_state) { + case AUX_RETRIEVE_IND: + break; + default: + int_errtxt("HOLD_REJ in wrong aux state %d\n", pc->aux_state); + return; + } + if (arg) + SendMsg(pc, arg, -1); + else + l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_RESOURCES_UNAVAIL); // FIXME + pc->aux_state = AUX_CALL_HELD; +} + + +static void +l3dss1_retrieve_ind(l3_process_t *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + if (test_bit(FLG_PTP, &pc->l3->Flag)) { + if ((pc->state & (VALID_HOLD_STATES_PTP | SBIT(12))) == 0) { /* not a valid RETRIEVE state for PtP */ + l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE); + dev_kfree_skb(skb); + return; + } + } else { + if ((pc->state & (VALID_HOLD_STATES_PTMP | SBIT(12))) == 0) { /* not a valid RETRIEVE state for PtMP */ + l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE); + dev_kfree_skb(skb); + return; + } + } + ret = check_infoelements(pc, skb, ie_RETRIEVE); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + dev_kfree_skb(skb); + return; + } + switch(pc->aux_state) { + case AUX_RETRIEVE_REQ: + L3DelTimer(&pc->aux_timer); + case AUX_CALL_HELD: + if (!(ret = l3dss1_get_channel_id(pc, skb))) { + if ((0 == pc->bc) || (3 == pc->bc)) { + if (pc->l3->debug & L3_DEB_WARN) + l3_debug(pc->l3, "RETRIEVE with wrong chid %x", + pc->bc); + l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_INVALID_CONTENTS); + dev_kfree_skb(skb); + return; + } + } + if (mISDN_l3up(pc, CC_RETRIEVE | INDICATION, skb)) + dev_kfree_skb(skb); + else { + pc->aux_state = AUX_RETRIEVE_IND; + } + break; + default: + l3dss1_message_cause(pc, MT_RETRIEVE_REJECT, CAUSE_NOTCOMPAT_STATE); + dev_kfree_skb(skb); + return; + } + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); +} + +static void +l3dss1_retrieve_ack(l3_process_t *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + + ret = check_infoelements(pc, skb, ie_RETRIEVE_ACKNOWLEDGE); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + dev_kfree_skb(skb); + return; + } + switch(pc->aux_state) { + case AUX_RETRIEVE_REQ: + L3DelTimer(&pc->aux_timer); + if (!(ret = l3dss1_get_channel_id(pc, skb))) { + if ((0 == pc->bc) || (3 == pc->bc)) { + if (pc->l3->debug & L3_DEB_WARN) + l3_debug(pc->l3, "RETRIEVE ACK with wrong chid %x", + pc->bc); + l3dss1_status_send(pc, CAUSE_INVALID_CONTENTS); + dev_kfree_skb(skb); + return; + } + } + if (mISDN_l3up(pc, CC_RETRIEVE_ACKNOWLEDGE | INDICATION, skb)) + dev_kfree_skb(skb); + pc->aux_state = AUX_IDLE; + break; + default: + int_errtxt("RETRIEVE_ACK in wrong aux state %d\n", pc->aux_state); + } + if (ret) /* STATUS for none mandatory IE errors after actions are taken */ + l3dss1_std_ie_err(pc, ret); +} + +static void +l3dss1_retrieve_rej(l3_process_t *pc, u_char pr, void *arg) +{ + struct sk_buff *skb = arg; + int ret; + u_char cause; + + if ((ret = l3dss1_get_cause(pc, skb))) { + if (pc->l3->debug & L3_DEB_WARN) + l3_debug(pc->l3, "RETRIEVE_REJ get_cause err(%d)", ret); + if (ret == -1) + cause = CAUSE_MANDATORY_IE_MISS; + else + cause = CAUSE_INVALID_CONTENTS; + l3dss1_status_send(pc, cause); + dev_kfree_skb(skb); + return; + } + ret = check_infoelements(pc, skb, ie_RETRIEVE_REJECT); + if (ERR_IE_COMPREHENSION == ret) { + l3dss1_std_ie_err(pc, ret); + dev_kfree_skb(skb); + return; + } + switch(pc->aux_state) { + case AUX_RETRIEVE_REQ: + L3DelTimer(&pc->aux_timer); + pc->aux_state = AUX_CALL_HELD; + break; + default: + int_errtxt("RETRIEVE_REJ in wrong aux state %d\n", pc->aux_state); + } + pc->aux_state = AUX_IDLE; + if (mISDN_l3up(pc, CC_RETRIEVE_REJECT | INDICATION, skb)) + dev_kfree_skb(skb); +} + +static void +l3dss1_thold(l3_process_t *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->aux_timer); +#if 0 + pc->cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ +#endif + mISDN_l3up(pc, CC_HOLD_REJECT | INDICATION, NULL); + pc->aux_state = AUX_IDLE; +} + +static void +l3dss1_tretrieve(l3_process_t *pc, u_char pr, void *arg) +{ + L3DelTimer(&pc->aux_timer); +#if 0 + pc->cause = 102; /* Timer expiry */ + pc->para.loc = 0; /* local */ +#endif + mISDN_l3up(pc, CC_RETRIEVE_REJECT | INDICATION, NULL); + pc->aux_state = AUX_CALL_HELD; +} + static void l3dss1_t302(l3_process_t *pc, u_char pr, void *arg) { @@ -1715,7 +2222,7 @@ l3dss1_dl_reset(l3_process_t *pc, u_char pr, void *arg) qi = (Q931_info_t *)skb_put(skb, L3_EXTRA_SIZE); mISDN_initQ931_info(qi); qi->type = MT_DISCONNECT; - qi->cause = 1; + qi->cause.off = 1; p = skb_put(skb, 5); p++; *p++ = IE_CAUSE; @@ -1748,7 +2255,7 @@ l3dss1_dl_reestablish(l3_process_t *pc, u_char pr, void *arg) L3AddTimer(&pc->timer, T309, CC_T309); l3_msg(pc->l3, DL_ESTABLISH | REQUEST, 0, 0, NULL); } - + static void l3dss1_dl_reest_status(l3_process_t *pc, u_char pr, void *arg) { @@ -1794,6 +2301,26 @@ static struct stateentry downstatelist[] = CC_CONNECT | REQUEST, l3dss1_connect_req}, {SBIT(10), CC_SUSPEND | REQUEST, l3dss1_suspend_req}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + CC_HOLD | REQUEST, l3dss1_hold_req}, + {ALL_STATES, + CC_HOLD | REQUEST, l3dss1_hold_req_ignore}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + CC_HOLD_ACKNOWLEDGE | REQUEST, l3dss1_hold_ack_req}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + CC_HOLD_REJECT | REQUEST, l3dss1_hold_rej_req}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12), + CC_RETRIEVE | REQUEST, l3dss1_retrieve_req}, + {ALL_STATES, + CC_RETRIEVE| REQUEST, l3dss1_hold_req_ignore}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12), + CC_RETRIEVE_ACKNOWLEDGE | REQUEST, l3dss1_retrieve_ack_req}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12), + CC_RETRIEVE_REJECT | REQUEST, l3dss1_retrieve_rej_req}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + CC_HOLD | REQUEST, l3dss1_hold_req}, + {ALL_STATES, + CC_FACILITY | REQUEST, l3dss1_facility_req}, {ALL_STATES, CC_STATUS_ENQUIRY | REQUEST, l3dss1_status_enq_req}, }; @@ -1851,6 +2378,20 @@ static struct stateentry datastatelist[] = MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack}, {SBIT(17), MT_RESUME_REJECT, l3dss1_resume_rej}, + {SBIT(12) | SBIT(19), + MT_HOLD, l3dss1_hold_ignore}, + {ALL_STATES, + MT_HOLD, l3dss1_hold_ind}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + MT_HOLD_REJECT, l3dss1_hold_rej}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10), + MT_HOLD_ACKNOWLEDGE, l3dss1_hold_ack}, + {ALL_STATES, + MT_RETRIEVE, l3dss1_retrieve_ind}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12), + MT_RETRIEVE_REJECT, l3dss1_retrieve_rej}, + {SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(12), + MT_RETRIEVE_ACKNOWLEDGE, l3dss1_retrieve_ack}, }; #define DATASLLEN \ @@ -1903,6 +2444,10 @@ static struct stateentry manstatelist[] = CC_T309, l3dss1_dl_release}, {SBIT(6), CC_TCTRL, l3dss1_reset}, + {ALL_STATES, + CC_THOLD, l3dss1_thold}, + {ALL_STATES, + CC_TRETRIEVE, l3dss1_tretrieve}, {ALL_STATES, CC_RESTART | REQUEST, l3dss1_restart}, }; @@ -1940,25 +2485,14 @@ global_handler(layer3_t *l3, u_int mt, struct sk_buff *skb) } static int -dss1_fromdown(mISDNif_t *hif, struct sk_buff *skb) +dss1_fromdown(layer3_t *l3, struct sk_buff *skb, mISDN_head_t *hh) { - layer3_t *l3; u_int i; int cause, callState, ret = -EINVAL; char *ptr; l3_process_t *proc; - mISDN_head_t *hh; Q931_info_t *qi; - - if (!hif || !skb) - return(ret); - l3 = hif->fdata; - hh = mISDN_HEAD_P(skb); - if (debug) - printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim); - if (!l3) - return(ret); switch (hh->prim) { case (DL_DATA | INDICATION): case (DL_UNITDATA | INDICATION): @@ -1977,8 +2511,8 @@ dss1_fromdown(mISDNif_t *hif, struct sk_buff *skb) return(0); break; default: - printk(KERN_WARNING "%s: unknown pr=%04x\n", - __FUNCTION__, hh->prim); + printk(KERN_WARNING "%s: unknown pr=%04x dinfo=%x\n", + __FUNCTION__, hh->prim, hh->dinfo); return(-EINVAL); } if (skb->len < 3) { @@ -2003,6 +2537,8 @@ dss1_fromdown(mISDNif_t *hif, struct sk_buff *skb) dev_kfree_skb(skb); return(0); } + if (l3->debug & L3_DEB_MSG) + mISDN_LogL3Msg(skb); qi = (Q931_info_t *)skb->data; ptr = skb->data; ptr += L3_EXTRA_SIZE; @@ -2053,15 +2589,15 @@ dss1_fromdown(mISDNif_t *hif, struct sk_buff *skb) } } else if (qi->type == MT_STATUS) { cause = 0; - if (qi->cause) { - if (ptr[qi->cause +1] >= 2) - cause = ptr[qi->cause + 3] & 0x7f; + if (qi->cause.off) { + if (ptr[qi->cause.off +1] >= 2) + cause = ptr[qi->cause.off + 3] & 0x7f; else - cause = ptr[qi->cause + 2] & 0x7f; + cause = ptr[qi->cause.off + 2] & 0x7f; } callState = 0; - if (qi->call_state) { - callState = ptr[qi->cause + 2]; + if (qi->call_state.off) { + callState = ptr[qi->call_state.off + 2]; } /* ETS 300-104 part 2.4.1 * if setup has not been made and a message type @@ -2127,22 +2663,12 @@ dss1_fromdown(mISDNif_t *hif, struct sk_buff *skb) } static int -dss1_fromup(mISDNif_t *hif, struct sk_buff *skb) +dss1_fromup(layer3_t *l3, struct sk_buff *skb, mISDN_head_t *hh) { - layer3_t *l3; u_int i; int cr, ret = -EINVAL; l3_process_t *proc; - mISDN_head_t *hh; - if (!hif || !skb) - return(ret); - l3 = hif->fdata; - hh = mISDN_HEAD_P(skb); - if (debug) - printk(KERN_DEBUG "%s: prim(%x)\n", __FUNCTION__, hh->prim); - if (!l3) - return(ret); if ((DL_ESTABLISH | REQUEST) == hh->prim) { l3_msg(l3, hh->prim, 0, 0, NULL); dev_kfree_skb(skb); @@ -2164,7 +2690,9 @@ dss1_fromup(mISDNif_t *hif, struct sk_buff *skb) } } return(ret); - } + } + if ((l3->debug & L3_DEB_MSG) && skb->len) + mISDN_LogL3Msg(skb); if (!proc && hh->dinfo == MISDN_ID_DUMMY) { if (hh->prim == (CC_FACILITY | REQUEST)) { l3dss1_facility_req(l3->dummy, hh->prim, skb->len ? skb : NULL); @@ -2206,7 +2734,7 @@ static int dss1man(l3_process_t *proc, u_int pr, void *arg) { u_int i; - + if (!proc) { printk(KERN_ERR "mISDN dss1man without proc pr=%04x\n", pr); return(-EINVAL); @@ -2230,14 +2758,53 @@ dss1man(l3_process_t *proc, u_int pr, void *arg) return(0); } +static int +dss1_function(mISDNinstance_t *inst, struct sk_buff *skb) +{ + layer3_t *l3; + int ret = -EINVAL; + mISDN_head_t *hh; + + l3 = inst->privat; + hh = mISDN_HEAD_P(skb); + 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 = dss1_fromup(l3, skb, hh); + break; + case FLG_MSG_UP: + ret = dss1_fromdown(l3, 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 */ + if ((hh->prim & MISDN_CMD_MASK) == MGR_SHORTSTATUS) { + ret = -EOPNOTSUPP; + break; + } + int_errtxt("not implemented yet"); + break; + } + return(ret); +} + static void release_udss1(layer3_t *l3) { mISDNinstance_t *inst = &l3->inst; + u_long flags; printk(KERN_DEBUG "release_udss1 refcnt %d l3(%p) inst(%p)\n", u_dss1.refcnt, l3, inst); release_l3(l3); +#ifdef FIXME if (inst->up.peer) { inst->up.peer->obj->ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up); @@ -2246,10 +2813,13 @@ release_udss1(layer3_t *l3) inst->down.peer->obj->ctrl(inst->down.peer, MGR_DISCONNECT | REQUEST, &inst->down); } +#endif + spin_lock_irqsave(&u_dss1.lock, flags); list_del(&l3->list); + spin_unlock_irqrestore(&u_dss1.lock, flags); u_dss1.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL); if (l3->entity != MISDN_ENTITY_NONE) - u_dss1.ctrl(inst, MGR_DELENTITY | REQUEST, (void *)l3->entity); + u_dss1.ctrl(inst, MGR_DELENTITY | REQUEST, (void *)((u_long)l3->entity)); kfree(l3); } @@ -2258,6 +2828,7 @@ new_udss1(mISDNstack_t *st, mISDN_pid_t *pid) { layer3_t *nl3; int err; + u_long flags; if (!st || !pid) return(-EINVAL); @@ -2268,7 +2839,7 @@ new_udss1(mISDNstack_t *st, mISDN_pid_t *pid) memset(nl3, 0, sizeof(layer3_t)); memcpy(&nl3->inst.pid, pid, sizeof(mISDN_pid_t)); nl3->debug = debug; - mISDN_init_instance(&nl3->inst, &u_dss1, nl3); + mISDN_init_instance(&nl3->inst, &u_dss1, nl3, dss1_function); if (!mISDN_SetHandledPID(&u_dss1, &nl3->inst.pid)) { int_error(); return(-ENOPROTOOPT); @@ -2300,6 +2871,7 @@ new_udss1(mISDNstack_t *st, mISDN_pid_t *pid) nl3->global->l3 = nl3; nl3->global->t303skb = NULL; L3InitTimer(nl3->global, &nl3->global->timer); + L3InitTimer(nl3->global, &nl3->global->aux_timer); if (!(nl3->dummy = kmalloc(sizeof(l3_process_t), GFP_ATOMIC))) { printk(KERN_ERR "mISDN can't get memory for dss1 dummy CR\n"); release_l3(nl3); @@ -2314,9 +2886,12 @@ new_udss1(mISDNstack_t *st, mISDN_pid_t *pid) nl3->dummy->l3 = nl3; nl3->dummy->t303skb = NULL; L3InitTimer(nl3->dummy, &nl3->dummy->timer); - sprintf(nl3->inst.name, "DSS1 %d", st->id); + L3InitTimer(nl3->dummy, &nl3->dummy->aux_timer); + sprintf(nl3->inst.name, "DSS1 %x", st->id >> 8); nl3->p_mgr = dss1man; + spin_lock_irqsave(&u_dss1.lock, flags); list_add_tail(&nl3->list, &u_dss1.ilist); + spin_unlock_irqrestore(&u_dss1.lock, flags); err = u_dss1.ctrl(&nl3->inst, MGR_NEWENTITY | REQUEST, NULL); if (err) { printk(KERN_WARNING "mISDN %s: MGR_NEWENTITY REQUEST failed err(%d)\n", @@ -2353,18 +2928,21 @@ MODULE_PARM(debug, "1i"); static int udss1_manager(void *data, u_int prim, void *arg) { mISDNinstance_t *inst = data; - layer3_t *l3l; + layer3_t *l3l; + u_long flags; - if (debug & 0x1000) + if (debug & MISDN_DEBUG_MANAGER) printk(KERN_DEBUG "udss1_manager data:%p prim:%x arg:%p\n", data, prim, arg); if (!data) return(-EINVAL); + spin_lock_irqsave(&u_dss1.lock, flags); list_for_each_entry(l3l, &u_dss1.ilist, list) { if (&l3l->inst == inst) break; } if (&l3l->list == &u_dss1.ilist) l3l = NULL; + spin_unlock_irqrestore(&u_dss1.lock, flags); if (prim == (MGR_NEWLAYER | REQUEST)) return(new_udss1(data, arg)); if (!l3l) { @@ -2374,12 +2952,13 @@ udss1_manager(void *data, u_int prim, void *arg) { } switch(prim) { case MGR_NEWENTITY | CONFIRM: - l3l->entity = (int)arg; + l3l->entity = (u_long)arg & 0xffffffff; break; case MGR_ADDSTPARA | INDICATION: l3l->down_headerlen = ((mISDN_stPara_t *)arg)->down_headerlen; case MGR_CLRSTPARA | INDICATION: break; +#ifdef FIXME case MGR_CONNECT | REQUEST: return(mISDN_ConnectIF(inst, arg)); case MGR_SETIF | REQUEST: @@ -2388,9 +2967,10 @@ udss1_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: - if (debug & 0x1000) + if (debug & MISDN_DEBUG_MANAGER) printk(KERN_DEBUG "release_udss1 id %x\n", l3l->inst.st->id); release_udss1(l3l); break; @@ -2413,6 +2993,7 @@ int UDSS1Init(void) #ifdef MODULE u_dss1.owner = THIS_MODULE; #endif + spin_lock_init(&u_dss1.lock); INIT_LIST_HEAD(&u_dss1.ilist); u_dss1.name = MName; u_dss1.DPROTO.protocol[3] = ISDN_PID_L3_DSS1USER | diff --git a/drivers/isdn/hardware/mISDN/l3helper.c b/drivers/isdn/hardware/mISDN/l3helper.c index e72c7b5..e2371f3 100644 --- a/drivers/isdn/hardware/mISDN/l3helper.c +++ b/drivers/isdn/hardware/mISDN/l3helper.c @@ -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; j9) { + 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; jext[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; j40) { + 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); diff --git a/drivers/isdn/hardware/mISDN/layer1.c b/drivers/isdn/hardware/mISDN/layer1.c index 6780032..a51e636 100644 --- a/drivers/isdn/hardware/mISDN/layer1.c +++ b/drivers/isdn/hardware/mISDN/layer1.c @@ -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 diff --git a/drivers/isdn/hardware/mISDN/layer1.h b/drivers/isdn/hardware/mISDN/layer1.h index a0adf56..5c2c730 100644 --- a/drivers/isdn/hardware/mISDN/layer1.h +++ b/drivers/isdn/hardware/mISDN/layer1.h @@ -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 diff --git a/drivers/isdn/hardware/mISDN/layer2.c b/drivers/isdn/hardware/mISDN/layer2.c index 6e3b62b..d80f46a 100644 --- a/drivers/isdn/hardware/mISDN/layer2.c +++ b/drivers/isdn/hardware/mISDN/layer2.c @@ -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 @@ -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; diff --git a/drivers/isdn/hardware/mISDN/layer2.h b/drivers/isdn/hardware/mISDN/layer2.h index 9b87395..ed0b9c8 100644 --- a/drivers/isdn/hardware/mISDN/layer2.h +++ b/drivers/isdn/hardware/mISDN/layer2.h @@ -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 */ diff --git a/drivers/isdn/hardware/mISDN/layer3.c b/drivers/isdn/hardware/mISDN/layer3.c index 9924433..33533f9 100644 --- a/drivers/isdn/hardware/mISDN/layer3.c +++ b/drivers/isdn/hardware/mISDN/layer3.c @@ -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; diff --git a/drivers/isdn/hardware/mISDN/layer3.h b/drivers/isdn/hardware/mISDN/layer3.h index 9d74394..fd018d5 100644 --- a/drivers/isdn/hardware/mISDN/layer3.h +++ b/drivers/isdn/hardware/mISDN/layer3.h @@ -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; diff --git a/drivers/isdn/hardware/mISDN/m_capi.h b/drivers/isdn/hardware/mISDN/m_capi.h index 8bd4261..1cdf871 100755 --- a/drivers/isdn/hardware/mISDN/m_capi.h +++ b/drivers/isdn/hardware/mISDN/m_capi.h @@ -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; }; diff --git a/drivers/isdn/hardware/mISDN/memdbg.c b/drivers/isdn/hardware/mISDN/memdbg.c index 6670a5e..6f06fa9 100644 --- a/drivers/isdn/hardware/mISDN/memdbg.c +++ b/drivers/isdn/hardware/mISDN/memdbg.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/ncci.c b/drivers/isdn/hardware/mISDN/ncci.c index 870e253..f576cea 100644 --- a/drivers/isdn/hardware/mISDN/ncci.c +++ b/drivers/isdn/hardware/mISDN/ncci.c @@ -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 diff --git a/drivers/isdn/hardware/mISDN/plci.c b/drivers/isdn/hardware/mISDN/plci.c index 944eb8a..8183cc8 100644 --- a/drivers/isdn/hardware/mISDN/plci.c +++ b/drivers/isdn/hardware/mISDN/plci.c @@ -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; diff --git a/drivers/isdn/hardware/mISDN/sedl_fax.c b/drivers/isdn/hardware/mISDN/sedl_fax.c index 63e2ca0..d840015 100644 --- a/drivers/isdn/hardware/mISDN/sedl_fax.c +++ b/drivers/isdn/hardware/mISDN/sedl_fax.c @@ -36,18 +36,13 @@ #else #include #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; diff --git a/drivers/isdn/hardware/mISDN/stack.c b/drivers/isdn/hardware/mISDN/stack.c index 1e6e1d4..10796a1 100644 --- a/drivers/isdn/hardware/mISDN/stack.c +++ b/drivers/isdn/hardware/mISDN/stack.c @@ -2,14 +2,16 @@ * * Author Karsten Keil (keil@isdn4linux.de) * - * This file is (c) under GNU PUBLIC LICENSE + * This file is released under the GPLv2 * */ #include "core.h" -LIST_HEAD(mISDN_stacklist); -LIST_HEAD(mISDN_instlist); +static LIST_HEAD(mISDN_stacklist); +static rwlock_t stacklist_lock = RW_LOCK_UNLOCKED; +static LIST_HEAD(mISDN_instlist); +static rwlock_t instlist_lock = RW_LOCK_UNLOCKED; int get_stack_cnt(void) @@ -17,8 +19,10 @@ get_stack_cnt(void) int cnt = 0; mISDNstack_t *st; + read_lock(&stacklist_lock); list_for_each_entry(st, &mISDN_stacklist, list) cnt++; + read_unlock(&stacklist_lock); return(cnt); } @@ -28,13 +32,32 @@ get_stack_info(struct sk_buff *skb) mISDN_head_t *hp; mISDNstack_t *cst, *st; stack_info_t *si; - mISDNlayer_t *lay; + int i; hp = mISDN_HEAD_P(skb); - st = get_stack4id(hp->addr); - if (!st) + if (hp->addr == 0) { + hp->dinfo = get_stack_cnt(); hp->len = 0; - else { + return; + } else if (hp->addr <= 127 && hp->addr <= get_stack_cnt()) { + /* stack nr */ + i = 1; + read_lock(&stacklist_lock); + list_for_each_entry(st, &mISDN_stacklist, list) { + if (i == hp->addr) + break; + i++; + } + read_unlock(&stacklist_lock); + } else + st = get_stack4id(hp->addr); + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "%s: addr(%08x) st(%p) id(%08x)\n", __FUNCTION__, hp->addr, st, + st ? st->id : 0); + if (!st) { + hp->len = -ENODEV; + return; + } else { si = (stack_info_t *)skb->data; memset(si, 0, sizeof(stack_info_t)); si->id = st->id; @@ -45,10 +68,18 @@ get_stack_info(struct sk_buff *skb) si->mgr = 0; memcpy(&si->pid, &st->pid, sizeof(mISDN_pid_t)); memcpy(&si->para, &st->para, sizeof(mISDN_stPara_t)); + if (st->clone) + si->clone = st->clone->id; + else + si->clone = 0; + if (st->master) + si->master = st->master->id; + else + si->master = 0; si->instcnt = 0; - list_for_each_entry(lay, &st->layerlist, list) { - if (lay->inst) { - si->inst[si->instcnt] = lay->inst->id; + for (i = 0; i <= MAX_LAYER_NR; i++) { + if (st->i_array[i]) { + si->inst[si->instcnt] = st->i_array[i]->id; si->instcnt++; } } @@ -65,22 +96,24 @@ get_stack_info(struct sk_buff *skb) } static int -get_free_stackid(mISDNstack_t *mst, int flag) { - u_int id=1, found; +get_free_stackid(mISDNstack_t *mst, int flag) +{ + u_int id = 0, found; mISDNstack_t *st; if (!mst) { - while(id<127) { + while(id < STACK_ID_MAX) { found = 0; + id += STACK_ID_INC; + read_lock(&stacklist_lock); list_for_each_entry(st, &mISDN_stacklist, list) { if (st->id == id) { found++; break; } } - if (found) - id++; - else + read_unlock(&stacklist_lock); + if (!found) return(id); } } else if (flag & FLG_CLONE_STACK) { @@ -88,11 +121,13 @@ get_free_stackid(mISDNstack_t *mst, int flag) { while(id < CLONE_ID_MAX) { found = 0; id += CLONE_ID_INC; - list_for_each_entry(st, &mISDN_stacklist, list) { + st = mst->clone; + while (st) { if (st->id == id) { found++; break; } + st = st->clone; } if (!found) return(id); @@ -124,71 +159,133 @@ get_stack4id(u_int id) printk(KERN_DEBUG "get_stack4id(%x)\n", id); if (!id) /* 0 isn't a valid id */ return(NULL); - list_for_each_entry(st, &mISDN_stacklist, list) { - if (id == st->id) + read_lock(&stacklist_lock); + list_for_each_entry(st, &mISDN_stacklist, list) { + if (id == st->id) { + read_unlock(&stacklist_lock); return(st); - list_for_each_entry(cst, &st->childlist, list) { - if (cst->id == id) - return(cst); + } + if ((id & FLG_CHILD_STACK) && ((id & MASTER_ID_MASK) == st->id)) { + list_for_each_entry(cst, &st->childlist, list) { + if (cst->id == id) { + read_unlock(&stacklist_lock); + return(cst); + } + } + } + if ((id & FLG_CLONE_STACK) && ((id & MASTER_ID_MASK) == st->id)) { + cst = st->clone; + while (cst) { + if (cst->id == id) { + read_unlock(&stacklist_lock); + return(cst); + } + cst = cst->clone; + } } } + read_unlock(&stacklist_lock); return(NULL); } -mISDNlayer_t * +mISDNinstance_t * getlayer4lay(mISDNstack_t *st, int layermask) { - mISDNlayer_t *layer; - mISDNinstance_t *inst; + int i; if (!st) { int_error(); return(NULL); } - list_for_each_entry(layer, &st->layerlist, list) { - inst = layer->inst; - if(inst && (inst->pid.layermask & layermask)) - return(layer); + for (i = 0; i <= MAX_LAYER_NR; i++) { + if (st->i_array[i] && (st->i_array[i]->pid.layermask & layermask)) + return(st->i_array[i]); } return(NULL); } +static mISDNinstance_t * +get_nextlayer(mISDNstack_t *st, u_int addr) +{ + mISDNinstance_t *inst=NULL; + int layer = addr & LAYER_ID_MASK; + + if (!(addr & FLG_MSG_TARGET)) { + switch(addr & MSG_DIR_MASK) { + case FLG_MSG_DOWN: + if (addr & FLG_MSG_CLONED) { + /* OK */ + } else + layer -= LAYER_ID_INC; + break; + case FLG_MSG_UP: + if (addr & FLG_MSG_CLONED) { + /* OK */ + } else + layer += LAYER_ID_INC; + break; + case MSG_TO_OWNER: + break; + default: /* broadcast */ + int_errtxt("st(%08x) addr(%08x) wrong address", st->id, addr); + return(NULL); + } + } + if ((layer < 0) || (layer > MAX_LAYER_NR)) { + int_errtxt("st(%08x) addr(%08x) layer %d out of range", st->id, addr, layer); + return(NULL); + } + inst = st->i_array[layer]; + if (core_debug & DEBUG_QUEUE_FUNC) + printk(KERN_DEBUG "%s: st(%08x) addr(%08x) -> inst(%08x)\n", + __FUNCTION__, st->id, addr, inst ? inst->id : 0); + return(inst); +} + mISDNinstance_t * get_instance(mISDNstack_t *st, int layer_nr, int protocol) { - mISDNlayer_t *layer; mISDNinstance_t *inst=NULL; + int i; - if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "get_instance st(%p) lnr(%d) prot(%x)\n", - st, layer_nr, protocol); if (!st) { int_error(); return(NULL); } - if ((layer_nr<0) || (layer_nr>MAX_LAYER_NR)) { + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "get_instance st(%08x) lnr(%d) prot(%x)\n", + st->id, layer_nr, protocol); + if ((layer_nr < 0) || (layer_nr > MAX_LAYER_NR)) { int_errtxt("lnr %d", layer_nr); return(NULL); } - list_for_each_entry(layer, &st->layerlist, list) { - inst = layer->inst; - if (inst) { + list_for_each_entry(inst, &st->prereg, list) { + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "get_instance prereg(%p, %x) lm %x/%x prot %x/%x\n", + inst, inst->id, inst->pid.layermask, ISDN_LAYER(layer_nr), + inst->pid.protocol[layer_nr], protocol); + if ((inst->pid.layermask & ISDN_LAYER(layer_nr)) && + (inst->pid.protocol[layer_nr] == protocol)) { + i = register_layer(st, inst); + if (i) { + int_errtxt("error(%d) register preregistered inst(%08x) on st(%08x)", i, inst->id, st->id); + return(NULL); + } + return(inst); + } + } + for (i = 0; i <= MAX_LAYER_NR; i++) { + if ((inst = st->i_array[i])) { if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "get_instance inst(%p, %x) lm %x/%x prot %x/%x\n", - inst, inst->id, inst->pid.layermask, ISDN_LAYER(layer_nr), + printk(KERN_DEBUG "get_instance inst%d(%p, %x) lm %x/%x prot %x/%x\n", + i,inst, inst->id, inst->pid.layermask, ISDN_LAYER(layer_nr), inst->pid.protocol[layer_nr], protocol); if ((inst->pid.layermask & ISDN_LAYER(layer_nr)) && (inst->pid.protocol[layer_nr] == protocol)) - goto out; - inst = NULL; - } - if (list_empty(&layer->list)) { - int_errtxt("deadloop layer %p", layer); - return(NULL); + return(inst); } } -out: - return(inst); + return(NULL); } mISDNinstance_t * @@ -196,12 +293,17 @@ get_instance4id(u_int id) { mISDNinstance_t *inst; + read_lock(&instlist_lock); list_for_each_entry(inst, &mISDN_instlist, list) - if (inst->id == id) + if (inst->id == id) { + read_unlock(&instlist_lock); return(inst); + } + read_unlock(&instlist_lock); return(NULL); } +#ifdef OBSOLETE int get_layermask(mISDNlayer_t *layer) { @@ -216,10 +318,10 @@ int insertlayer(mISDNstack_t *st, mISDNlayer_t *layer, int layermask) { mISDNlayer_t *item; - + if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s(%p, %p, %x)\n", - __FUNCTION__, st, layer, layermask); + __FUNCTION__, st, layer, layermask); if (!st || !layer) { int_error(); return(-EINVAL); @@ -229,7 +331,7 @@ insertlayer(mISDNstack_t *st, mISDNlayer_t *layer, int layermask) } else { list_for_each_entry(item, &st->layerlist, list) { if (layermask < get_layermask(item)) { - list_add_tail(&layer->list, &item->list); + list_add_tail(&layer->list, &item->list); return(0); } } @@ -237,11 +339,321 @@ insertlayer(mISDNstack_t *st, mISDNlayer_t *layer, int layermask) } return(0); } +#endif + +inline void +_queue_message(mISDNstack_t *st, struct sk_buff *skb) +{ + skb_queue_tail(&st->msgq, skb); + if (likely(!test_bit(mISDN_STACK_STOPPED, &st->status))) { + test_and_set_bit(mISDN_STACK_WORK, &st->status); + wake_up_interruptible(&st->workq); + } +} + +int +mISDN_queue_message(mISDNinstance_t *inst, u_int aflag, struct sk_buff *skb) +{ + mISDN_head_t *hh = mISDN_HEAD_P(skb); + mISDNstack_t *st = inst->st; + u_int id; + + if (core_debug & DEBUG_QUEUE_FUNC) + printk(KERN_DEBUG "%s(%08x, %x, prim(%x))\n", __FUNCTION__, + inst->id, aflag, hh->prim); + if (aflag & FLG_MSG_TARGET) { + id = aflag; + } else { + id = (inst->id & INST_ID_MASK) | aflag; + } + if ((aflag & MSG_DIR_MASK) == FLG_MSG_DOWN) { + if (inst->parent) { + inst = inst->parent; + st = inst->st; + id = (inst->id & INST_ID_MASK) | FLG_MSG_TARGET | FLG_MSG_CLONED | FLG_MSG_DOWN; + } + } + if (!st) + return(-EINVAL); + if (st->id == 0 || test_bit(mISDN_STACK_ABORT, &st->status)) + return(-EBUSY); + if (inst->id == 0) { /* instance is not initialised */ + if (!(aflag & FLG_MSG_TARGET)) { + id &= INST_ID_MASK; + id |= (st->id & INST_ID_MASK) | aflag | FLG_INSTANCE; + } + } + if (test_bit(mISDN_STACK_KILLED, &st->status)) + return(-EBUSY); + if ((st->id & STACK_ID_MASK) != (id & STACK_ID_MASK)) { + int_errtxt("stack id not match st(%08x) id(%08x) inst(%08x) aflag(%08x) prim(%x)", + st->id, id, inst->id, aflag, hh->prim); + } + hh->addr = id; + _queue_message(st, skb); + return(0); +} + +static void +do_broadcast(mISDNstack_t *st, struct sk_buff *skb) +{ + mISDN_head_t *hh = mISDN_HEAD_P(skb); + mISDNinstance_t *inst = NULL; + struct sk_buff *c_skb = NULL; + int i, err; + + for(i=0; i<=MAX_LAYER_NR; i++) { + if (i == (hh->addr & LAYER_ID_MASK)) + continue; // skip own layer + inst = st->i_array[i]; + if (!inst) + continue; // maybe we have a gap + if (!c_skb) + c_skb = skb_copy(skb, GFP_KERNEL); // we need a new private copy + if (!c_skb) + break; // stop here when copy not possible + + if (core_debug & DEBUG_MSG_THREAD_INFO) + printk(KERN_DEBUG "%s: inst(%08x) msg call addr(%08x) prim(%x)\n", + __FUNCTION__, inst->id, hh->addr, hh->prim); + + if (inst->function) { + err = inst->function(inst, c_skb); + if (!err) + c_skb = NULL; /* function consumed the skb */ + if (core_debug & DEBUG_MSG_THREAD_INFO) + printk(KERN_DEBUG "%s: inst(%08x) msg call return %d\n", + __FUNCTION__, inst->id, err); + + } else { + if (core_debug & DEBUG_MSG_THREAD_ERR) + printk(KERN_DEBUG "%s: instance(%08x) no function\n", + __FUNCTION__, inst->id); + } + } + if (c_skb) + dev_kfree_skb(c_skb); + dev_kfree_skb(skb); +} + +static void +release_layers(mISDNstack_t *st, u_int prim) +{ + int i; + + for (i = 0; i <= MAX_LAYER_NR; i++) { + if (st->i_array[i]) { + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "%s: st(%p) inst%d(%p):%x %s lm(%x)\n", + __FUNCTION__, st, i, st->i_array[i], st->i_array[i]->id, + st->i_array[i]->name, st->i_array[i]->pid.layermask); + st->i_array[i]->obj->own_ctrl(st->i_array[i], prim, NULL); + } + } +} + +static void +do_clear_stack(mISDNstack_t *st) { + + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "%s: st(%08x)\n", __FUNCTION__, st->id); + kfree(st->pid.pbuf); + memset(&st->pid, 0, sizeof(mISDN_pid_t)); + memset(&st->para, 0, sizeof(mISDN_stPara_t)); + release_layers(st, MGR_UNREGLAYER | REQUEST); +} + +static int +mISDNStackd(void *data) +{ + mISDNstack_t *st = data; + int err = 0; + +#ifdef CONFIG_SMP + lock_kernel(); +#endif + MAKEDAEMON("mISDNStackd"); + sigfillset(¤t->blocked); + st->thread = current; +#ifdef CONFIG_SMP + unlock_kernel(); +#endif + printk(KERN_DEBUG "mISDNStackd started for id(%08x)\n", st->id); + for (;;) { + struct sk_buff *skb, *c_skb; + mISDN_head_t *hh; + + if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { + test_and_clear_bit(mISDN_STACK_WORK, &st->status); + test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); + } else + test_and_set_bit(mISDN_STACK_RUNNING, &st->status); + while (test_bit(mISDN_STACK_WORK, &st->status)) { + mISDNinstance_t *inst; + + skb = skb_dequeue(&st->msgq); + if (!skb) { + test_and_clear_bit(mISDN_STACK_WORK, &st->status); + /* test if a race happens */ + if (!(skb = skb_dequeue(&st->msgq))) + continue; + test_and_set_bit(mISDN_STACK_WORK, &st->status); + } +#ifdef MISDN_MSG_STATS + st->msg_cnt++; +#endif + hh = mISDN_HEAD_P(skb); + if (hh->prim == (MGR_CLEARSTACK | REQUEST)) { + mISDN_headext_t *hhe = (mISDN_headext_t *)hh; + + if (test_and_set_bit(mISDN_STACK_CLEARING, &st->status)) { + int_errtxt("double clearing"); + } + if (hhe->data[0]) { + if (st->notify) { + int_errtxt("notify already set"); + up(st->notify); + } + st->notify = hhe->data[0]; + } + dev_kfree_skb(skb); + continue; + } + if ((hh->addr & MSG_DIR_MASK) == MSG_BROADCAST) { + do_broadcast(st, skb); + continue; + } + inst = get_nextlayer(st, hh->addr); + if (!inst) { + if (core_debug & DEBUG_MSG_THREAD_ERR) + printk(KERN_DEBUG "%s: st(%08x) no instance for addr(%08x) prim(%x) dinfo(%x)\n", + __FUNCTION__, st->id, hh->addr, hh->prim, hh->dinfo); + dev_kfree_skb(skb); + continue; + } + if (inst->clone && ((hh->addr & MSG_DIR_MASK) == FLG_MSG_UP)) { + u_int id = (inst->clone->id & INST_ID_MASK) | FLG_MSG_TARGET | FLG_MSG_CLONED | FLG_MSG_UP; + +#ifdef MISDN_MSG_STATS + st->clone_cnt++; +#endif + c_skb = skb_copy(skb, GFP_KERNEL); + if (c_skb) { + if (core_debug & DEBUG_MSG_THREAD_INFO) + printk(KERN_DEBUG "%s: inst(%08x) msg clone msg to(%08x) caddr(%08x) prim(%x)\n", + __FUNCTION__, inst->id, inst->clone->id, id, hh->prim); + err = mISDN_queue_message(inst->clone, id, c_skb); + if (err) { + if (core_debug & DEBUG_MSG_THREAD_ERR) + printk(KERN_DEBUG "%s: clone instance(%08x) cannot queue msg(%08x) err(%d)\n", + __FUNCTION__, inst->clone->id, id, err); + dev_kfree_skb(c_skb); + } + } else { + printk(KERN_WARNING "%s OOM on msg cloning inst(%08x) caddr(%08x) prim(%x) len(%d)\n", + __FUNCTION__, inst->id, id, hh->prim, skb->len); + } + } + if (core_debug & DEBUG_MSG_THREAD_INFO) + printk(KERN_DEBUG "%s: inst(%08x) msg call addr(%08x) prim(%x)\n", + __FUNCTION__, inst->id, hh->addr, hh->prim); + if (!inst->function) { + if (core_debug & DEBUG_MSG_THREAD_ERR) + printk(KERN_DEBUG "%s: instance(%08x) no function\n", + __FUNCTION__, inst->id); + dev_kfree_skb(skb); + continue; + } + err = inst->function(inst, skb); + if (err) { + if (core_debug & DEBUG_MSG_THREAD_ERR) + printk(KERN_DEBUG "%s: instance(%08x)->function return(%d)\n", + __FUNCTION__, inst->id, err); + dev_kfree_skb(skb); + continue; + } + if (unlikely(test_bit(mISDN_STACK_STOPPED, &st->status))) { + test_and_clear_bit(mISDN_STACK_WORK, &st->status); + test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); + break; + } + } + if (test_bit(mISDN_STACK_CLEARING, &st->status)) { + test_and_set_bit(mISDN_STACK_STOPPED, &st->status); + test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); + do_clear_stack(st); + test_and_clear_bit(mISDN_STACK_CLEARING, &st->status); + test_and_set_bit(mISDN_STACK_RESTART, &st->status); + } + if (test_and_clear_bit(mISDN_STACK_RESTART, &st->status)) { + test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); + test_and_set_bit(mISDN_STACK_RUNNING, &st->status); + if (!skb_queue_empty(&st->msgq)) + test_and_set_bit(mISDN_STACK_WORK, &st->status); + } + if (test_bit(mISDN_STACK_ABORT, &st->status)) + break; + if (st->notify != NULL) { + up(st->notify); + st->notify = NULL; + } +#ifdef MISDN_MSG_STATS + st->sleep_cnt++; +#endif + test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); + wait_event_interruptible(st->workq, (st->status & mISDN_STACK_ACTION_MASK)); + if (core_debug & DEBUG_MSG_THREAD_INFO) + printk(KERN_DEBUG "%s: %08x wake status %08lx\n", __FUNCTION__, st->id, st->status); + test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); + + test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); + + if (test_bit(mISDN_STACK_STOPPED, &st->status)) { + test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); +#ifdef MISDN_MSG_STATS + st->stopped_cnt++; +#endif + } + } +#ifdef MISDN_MSG_STATS + printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) proceed %d msg %d clone %d sleep %d stopped\n", + st->id, st->msg_cnt, st->clone_cnt, st->sleep_cnt, st->stopped_cnt); + printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) utime(%ld) stime(%ld)\n", st->id, st->thread->utime, st->thread->stime); + printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) nvcsw(%ld) nivcsw(%ld)\n", st->id, st->thread->nvcsw, st->thread->nivcsw); +#endif + printk(KERN_DEBUG "mISDNStackd daemon for id(%08x) killed now\n", st->id); + test_and_set_bit(mISDN_STACK_KILLED, &st->status); + test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); + test_and_clear_bit(mISDN_STACK_ACTIVE, &st->status); + test_and_clear_bit(mISDN_STACK_ABORT, &st->status); + discard_queue(&st->msgq); + st->thread = NULL; + if (st->notify != NULL) { + up(st->notify); + st->notify = NULL; + } + return(0); +} + +int +mISDN_start_stack_thread(mISDNstack_t *st) +{ + int err = 0; + + if (st->thread == NULL && test_bit(mISDN_STACK_KILLED, &st->status)) { + test_and_clear_bit(mISDN_STACK_KILLED, &st->status); + kernel_thread(mISDNStackd, (void *)st, 0); + } else + err = -EBUSY; + return(err); +} mISDNstack_t * new_stack(mISDNstack_t *master, mISDNinstance_t *inst) { - mISDNstack_t *newst; + mISDNstack_t *newst; + int err; + u_long flags; if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "create %s stack inst(%p)\n", @@ -251,11 +663,20 @@ new_stack(mISDNstack_t *master, mISDNinstance_t *inst) return(NULL); } memset(newst, 0, sizeof(mISDNstack_t)); - INIT_LIST_HEAD(&newst->layerlist); + INIT_LIST_HEAD(&newst->list); INIT_LIST_HEAD(&newst->childlist); + INIT_LIST_HEAD(&newst->prereg); + init_waitqueue_head(&newst->workq); + skb_queue_head_init(&newst->msgq); if (!master) { if (inst && inst->st) { + master = inst->st; + while(master->clone) + master = master->clone; newst->id = get_free_stackid(inst->st, FLG_CLONE_STACK); + newst->master = master; + master->clone = newst; + master = NULL; } else { newst->id = get_free_stackid(NULL, 0); } @@ -265,66 +686,59 @@ new_stack(mISDNstack_t *master, mISDNinstance_t *inst) newst->mgr = inst; if (master) { list_add_tail(&newst->list, &master->childlist); - } else { + newst->parent = master; + } else if (!(newst->id & FLG_CLONE_STACK)) { + write_lock_irqsave(&stacklist_lock, flags); list_add_tail(&newst->list, &mISDN_stacklist); + write_unlock_irqrestore(&stacklist_lock, flags); + } + if (inst) { + inst->st = newst; + } + err = mISDN_register_sysfs_stack(newst); + if (err) { + // FIXME error handling + printk(KERN_ERR "Stack id %x not registered in sysfs\n", newst->id); } if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "Stack id %x added\n", newst->id); - if (inst) - inst->st = newst; + kernel_thread(mISDNStackd, (void *)newst, 0); return(newst); } - -static int -release_layers(mISDNstack_t *st, u_int prim) +int +mISDN_start_stop(mISDNstack_t *st, int start) { - mISDNinstance_t *inst; - mISDNlayer_t *layer, *nl; - int cnt = 0; + int ret; - list_for_each_entry_safe(layer, nl, &st->layerlist, list) { - inst = layer->inst; - if (inst) { - if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%p) inst(%p):%x %s lm(%x)\n", - __FUNCTION__, st, inst, inst->id, - inst->name, inst->pid.layermask); - inst->obj->own_ctrl(inst, prim, NULL); - } - list_del(&layer->list); - kfree(layer); - if (cnt++ > 1000) { - int_errtxt("release_layers endless loop st(%p)", st); - return(-EINVAL); - } - } - return(0); + if (start) { + ret = test_and_clear_bit(mISDN_STACK_STOPPED, &st->status); + test_and_set_bit(mISDN_STACK_WAKEUP, &st->status); + if (!skb_queue_empty(&st->msgq)) + test_and_set_bit(mISDN_STACK_WORK, &st->status); + wake_up_interruptible(&st->workq); + } else + ret = test_and_set_bit(mISDN_STACK_STOPPED, &st->status); + return(ret); } int do_for_all_layers(void *data, u_int prim, void *arg) { mISDNstack_t *st = data; - mISDNinstance_t *inst; - mISDNlayer_t *layer, *nl; - int cnt = 0; + int i; if (!st) { int_error(); return(-EINVAL); } - list_for_each_entry_safe(layer, nl, &st->layerlist, list) { - inst = layer->inst; - if (inst) { + for (i = 0; i <= MAX_LAYER_NR; i++) { + if (st->i_array[i]) { if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%p) inst(%p):%x %s prim(%x) arg(%p)\n", - __FUNCTION__, st, inst, inst->id, inst->name, prim, arg); - inst->obj->own_ctrl(inst, prim, arg); - } - if (cnt++ > 1000) { - int_errtxt("do_for_all_layers endless loop st(%p)", st); - return(-EINVAL); + printk(KERN_DEBUG "%s: st(%p) inst%d(%p):%x %s prim(%x) arg(%p)\n", + __FUNCTION__, st, i, st->i_array[i], st->i_array[i]->id, + st->i_array[i]->name, prim, arg); + st->i_array[i]->obj->own_ctrl(st->i_array[i], prim, arg); } } return(0); @@ -367,6 +781,47 @@ change_stack_para(mISDNstack_t *st, u_int prim, mISDN_stPara_t *stpara) return(do_for_all_layers(st, prim, stpara)); } +static int +delete_stack(mISDNstack_t *st) +{ + DECLARE_MUTEX_LOCKED(sem); + u_long flags; + + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "%s: st(%p:%08x)\n", __FUNCTION__, st, st->id); + mISDN_unregister_sysfs_st(st); + if (st->parent) + st->parent = NULL; + if (!list_empty(&st->prereg)) { + mISDNinstance_t *inst, *ni; + + int_errtxt("st(%08x)->prereg not empty\n", st->id); + list_for_each_entry_safe(inst, ni, &st->prereg, list) { + int_errtxt("inst(%p:%08x) preregistered", inst, inst->id); + list_del(&inst->list); + } + } + if (st->thread) { + if (st->thread != current) { + if (st->notify) { + int_error(); + up(st->notify); + } + st->notify = &sem; + } + test_and_set_bit(mISDN_STACK_ABORT, &st->status); + mISDN_start_stop(st, 1); + if (st->thread != current) /* we cannot wait for us */ + down(&sem); + } + release_layers(st, MGR_RELEASE | INDICATION); + write_lock_irqsave(&stacklist_lock, flags); + list_del(&st->list); + write_unlock_irqrestore(&stacklist_lock, flags); + kfree(st); + return(0); +} + int release_stack(mISDNstack_t *st) { int err; @@ -374,22 +829,24 @@ release_stack(mISDNstack_t *st) { if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%p)\n", __FUNCTION__, st); + list_for_each_entry_safe(cst, nst, &st->childlist, list) { - if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: cst(%p)\n", __FUNCTION__, cst); - if ((err = release_layers(cst, MGR_RELEASE | INDICATION))) { - printk(KERN_WARNING "release_stack child err(%d)\n", err); + if ((err = delete_stack(cst))) { return(err); } - list_del(&cst->list); - kfree(cst); } - if ((err = release_layers(st, MGR_RELEASE | INDICATION))) { - printk(KERN_WARNING "release_stack err(%d)\n", err); + if (st->clone) { + st->clone->master = st->master; + } + if (st->master) { + st->master->clone = st->clone; + } else if (st->clone) { /* no master left -> delete clone too */ + delete_stack(st->clone); + st->clone = NULL; + } + if ((err = delete_stack(st))) return(err); - } - list_del(&st->list); - kfree(st); + if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: mISDN_stacklist(%p<-%p->%p)\n", __FUNCTION__, mISDN_stacklist.prev, &mISDN_stacklist, mISDN_stacklist.next); @@ -397,35 +854,79 @@ release_stack(mISDNstack_t *st) { } void -release_stacks(mISDNobject_t *obj) { - mISDNstack_t *st, *tmp; - mISDNlayer_t *layer, *ltmp; - int rel; +cleanup_object(mISDNobject_t *obj) +{ + mISDNstack_t *st, *nst; + mISDNinstance_t *inst; + int i; + + read_lock(&stacklist_lock); + list_for_each_entry_safe(st, nst, &mISDN_stacklist, list) { + for (i = 0; i < MAX_LAYER_NR; i++) { + inst = st->i_array[i]; + if (inst && inst->obj == obj) { + read_unlock(&stacklist_lock); + inst->obj->own_ctrl(st, MGR_RELEASE | INDICATION, inst); + read_lock(&stacklist_lock); + } + } + } + read_unlock(&stacklist_lock); +} + +void +check_stacklist(void) +{ + mISDNstack_t *st, *nst; + + read_lock(&stacklist_lock); + 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; + } + } + } + read_unlock(&stacklist_lock); +} + +void +release_stacks(mISDNobject_t *obj) +{ + mISDNstack_t *st, *tmp; + int rel, i; if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: obj(%p) %s\n", - __FUNCTION__, obj, obj->name); + printk(KERN_DEBUG "%s: obj(%p) %s\n", __FUNCTION__, obj, obj->name); + read_lock(&stacklist_lock); list_for_each_entry_safe(st, tmp, &mISDN_stacklist, list) { rel = 0; if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%p)\n", - __FUNCTION__, st); - list_for_each_entry_safe(layer, ltmp, &st->layerlist, list) { + printk(KERN_DEBUG "%s: st(%p)\n", __FUNCTION__, st); + for (i = 0; i <= MAX_LAYER_NR; i++) { + if (!st->i_array[i]) + continue; if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: layer(%p) inst(%p)\n", - __FUNCTION__, layer, layer->inst); - if (layer->inst && layer->inst->obj == obj) + printk(KERN_DEBUG "%s: inst%d(%p)\n", __FUNCTION__, i, st->i_array[i]); + if (st->i_array[i]->obj == obj) rel++; - } - if (rel) + } + if (rel) { + read_unlock(&stacklist_lock); release_stack(st); + read_lock(&stacklist_lock); + } } + read_unlock(&stacklist_lock); if (obj->refcnt) printk(KERN_WARNING "release_stacks obj %s refcnt is %d\n", obj->name, obj->refcnt); } - +#ifdef OBSOLETE static void get_free_instid(mISDNstack_t *st, mISDNinstance_t *inst) { mISDNinstance_t *il; @@ -441,93 +942,153 @@ get_free_instid(mISDNstack_t *st, mISDNinstance_t *inst) { inst->id = 0; return; } - inst->id += INST_ID_INC; + inst->id += LAYER_ID_INC; il = list_entry(mISDN_instlist.next, mISDNinstance_t, list); } } } } +#endif int -register_layer(mISDNstack_t *st, mISDNinstance_t *inst) { - mISDNlayer_t *layer = NULL; - int refinc = 0; +register_layer(mISDNstack_t *st, mISDNinstance_t *inst) +{ + int idx, err; + mISDNinstance_t *dup; + u_long flags; - if (!inst) + if (!inst || !st) return(-EINVAL); if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s:st(%p) inst(%p/%p) lmask(%x) id(%x)\n", __FUNCTION__, st, inst, inst->obj, inst->pid.layermask, inst->id); - if (inst->id) { /* allready registered */ - if (inst->st || !st) { + if (inst->id) { /* already registered */ + // if (inst->st || !st) { int_errtxt("register duplicate %08x %p %p", inst->id, inst->st, st); return(-EBUSY); - } + //} } - if (st) { - if ((layer = getlayer4lay(st, inst->pid.layermask))) { - if (layer->inst) { - int_errtxt("stack %08x has layer %08x", - st->id, layer->inst->id); - return(-EBUSY); - } - } else if (!(layer = kmalloc(sizeof(mISDNlayer_t), GFP_ATOMIC))) { - int_errtxt("no mem for layer %x", inst->pid.layermask); - return(-ENOMEM); + /* + * To simplify registration we assume that our stacks are + * always build with monoton increasing layernumbers from + * bottom (HW,L0) to highest number + */ +// if (st) { + for (idx = 0; idx <= MAX_LAYER_NR; idx++) + if (!st->i_array[idx]) + break; + if (idx > MAX_LAYER_NR) { + int_errtxt("stack %08x overflow", st->id); + return(-EXFULL); } - memset(layer, 0, sizeof(mISDNlayer_t)); - insertlayer(st, layer, inst->pid.layermask); - layer->inst = inst; - } - if (!inst->id) - refinc++; - get_free_instid(st, inst); + inst->regcnt++; + st->i_array[idx] = inst; + inst->id = st->id | FLG_INSTANCE | idx; + dup = get_instance4id(inst->id); + if (dup) { + int_errtxt("register duplicate %08x i1(%p) i2(%p) i1->st(%p) i2->st(%p) st(%p)", + inst->id, inst, dup, inst->st, dup->st, st); + inst->regcnt--; + st->i_array[idx] = NULL; + inst->id = 0; + return(-EBUSY); + } +// } + if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: inst(%p/%p) id(%x)%s\n", __FUNCTION__, - inst, inst->obj, inst->id, refinc ? " changed" : ""); - if (!inst->id) { - int_errtxt("no free inst->id for layer %x", inst->pid.layermask); - if (st && layer) { - list_del(&layer->list); - kfree(layer); - } - return(-EINVAL); + printk(KERN_DEBUG "%s: inst(%p/%p) id(%x)\n", __FUNCTION__, + inst, inst->obj, inst->id); + + if (!list_empty(&inst->list)) { + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "%s: register preregistered instance st(%p/%p)", + __FUNCTION__, st, inst->st); + list_del_init(&inst->list); } inst->st = st; - if (refinc) - inst->obj->refcnt++; + write_lock_irqsave(&instlist_lock, flags); list_add_tail(&inst->list, &mISDN_instlist); + write_unlock_irqrestore(&instlist_lock, flags); + err = mISDN_register_sysfs_inst(inst); + if (err) { + // FIXME error handling + printk(KERN_ERR "%s: register_sysfs failed %d st(%08x) inst(%08x)\n", + __FUNCTION__, err, st->id, inst->id); + } + return(0); +} + +int +preregister_layer(mISDNstack_t *st, mISDNinstance_t *inst) +{ + if (!inst || !st) + return(-EINVAL); + if (core_debug & DEBUG_CORE_FUNC) + printk(KERN_DEBUG "%s:st(%08x) inst(%p:%08x) lmask(%x)\n", + __FUNCTION__, st->id, inst, inst->id, inst->pid.layermask); + if (inst->id) { + /* already registered */ + int_errtxt("register duplicate %08x %p %p", + inst->id, inst->st, st); + return(-EBUSY); + } + inst->st = st; + list_add_tail(&inst->list, &st->prereg); return(0); } int unregister_instance(mISDNinstance_t *inst) { - mISDNlayer_t *layer; - int err = 0; + int i; + u_long flags; if (!inst) return(-EINVAL); if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%p) inst(%p):%x lay(%x)\n", __FUNCTION__, inst->st, inst, inst->id, inst->pid.layermask); - if (inst->st) { - if ((layer = getlayer4lay(inst->st, inst->pid.layermask))) { - if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: layer(%p)->inst(%p)\n", - __FUNCTION__, layer, layer->inst); - layer->inst = NULL; - } else { - printk(KERN_WARNING "%s: no layer found\n", __FUNCTION__); - err = -ENODEV; + mISDN_unregister_sysfs_inst(inst); + if (inst->st && inst->id) { + i = inst->id & LAYER_ID_MASK; + if (i > MAX_LAYER_NR) { + int_errtxt("unregister %08x st(%08x) wrong layer", inst->id, inst->st->id); + return(-EINVAL); } + if (inst->st->i_array[i] == inst) { + inst->regcnt--; + inst->st->i_array[i] = NULL; + } else if (inst->st->i_array[i]) { + int_errtxt("unregister %08x st(%08x) wrong instance %08x", + inst->id, inst->st->id, inst->st->i_array[i]->id); + return(-EINVAL); + } else + printk(KERN_WARNING "unregister %08x st(%08x) not in stack", + inst->id, inst->st->id); if (inst->st && (inst->st->mgr != inst)) inst->st = NULL; } - list_del_init(&inst->list); + if (inst->parent) { /*we are cloned */ + inst->parent->clone = inst->clone; + if (inst->clone) + inst->clone->parent = inst->parent; + inst->clone = NULL; + inst->parent = NULL; + } else if (inst->clone) { + /* deleting the top level master of a clone */ + /* FIXME: should be handled somehow, maybe unregister the clone */ + int_errtxt("removed master(%08x) of clone(%08x)", inst->id, inst->clone->id); + inst->clone->parent = NULL; + inst->clone = NULL; + } + write_lock_irqsave(&instlist_lock, flags); + if (inst->list.prev && inst->list.next) + list_del_init(&inst->list); + else + int_errtxt("uninitialized list inst(%08x)", inst->id); inst->id = 0; - inst->obj->refcnt--; + write_unlock_irqrestore(&instlist_lock, flags); if (core_debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: mISDN_instlist(%p<-%p->%p)\n", __FUNCTION__, mISDN_instlist.prev, &mISDN_instlist, mISDN_instlist.next); @@ -540,7 +1101,7 @@ copy_pid(mISDN_pid_t *dpid, mISDN_pid_t *spid, u_char *pbuf) u_int i, off; memcpy(dpid, spid, sizeof(mISDN_pid_t)); - if (spid->pbuf) { + if (spid->pbuf && spid->maxplen) { if (!pbuf) { int_error(); return(-ENOMEM); @@ -553,6 +1114,33 @@ copy_pid(mISDN_pid_t *dpid, mISDN_pid_t *spid, u_char *pbuf) dpid->param[i] = dpid->pbuf + off; } } + } else if (spid->maxplen) { + off = 0; + for (i = 0; i <= MAX_LAYER_NR; i++) + if (spid->param[i]) + off += *spid->param[i]; + if (off == 0) { + int_error(); /* we ignore this */ + dpid->maxplen = 0; + return(0); + } + if (off > spid->maxplen) { + int_errtxt("overflow"); + dpid->maxplen = 0; + return(-EINVAL); + } + if (!pbuf) { + int_error(); + return(-ENOMEM); + } + for (i = 0; i <= MAX_LAYER_NR; i++) { + if (spid->param[i]) { + dpid->param[i] = pbuf; + off = *dpid->param[i] +1; + memcpy(pbuf, dpid->param[i], off); + pbuf += off; + } + } } return(0); } @@ -560,10 +1148,10 @@ copy_pid(mISDN_pid_t *dpid, mISDN_pid_t *spid, u_char *pbuf) int set_stack(mISDNstack_t *st, mISDN_pid_t *pid) { - int err; + int err, i; u_char *pbuf = NULL; mISDNinstance_t *inst; - mISDNlayer_t *hl, *hln; +// mISDNlayer_t *hl, *hln; if (!st || !pid) { int_error(); @@ -594,46 +1182,62 @@ set_stack(mISDNstack_t *st, mISDN_pid_t *pid) inst = get_next_instance(st, pid); if (!inst) { int_error(); - st->mgr->obj->ctrl(st, MGR_CLEARSTACK| REQUEST, NULL); + st->mgr->obj->ctrl(st, MGR_CLEARSTACK| REQUEST, (void *)1); return(-ENOPROTOOPT); } mISDN_RemoveUsedPID(pid, &inst->pid); } - - list_for_each_entry_safe(hl, hln, &st->layerlist, list) { - if (hl->list.next == &st->layerlist) + if (!list_empty(&st->prereg)) + int_errtxt("st(%08x)->prereg not empty\n", st->id); + + for (i = 0; i <= MAX_LAYER_NR; i++) { + inst = st->i_array[i]; + if (!inst) break; - if (!hl->inst) { + if (!inst->obj) { int_error(); - return(-EINVAL); + continue; } - if (!hl->inst->obj) { + if (!inst->obj->own_ctrl) { int_error(); - return(-EINVAL); + continue; } - if (!hl->inst->obj->own_ctrl) { - int_error(); - return(-EINVAL); - } - hl->inst->obj->own_ctrl(hl->inst, MGR_CONNECT | REQUEST, - hln->inst); + inst->obj->own_ctrl(inst, MGR_SETSTACK | INDICATION, NULL); } - st->mgr->obj->own_ctrl(st->mgr, MGR_SETSTACK |CONFIRM, NULL); return(0); } int -clear_stack(mISDNstack_t *st) { +clear_stack(mISDNstack_t *st, int wait) { + struct sk_buff *skb; + mISDN_headext_t *hhe; if (!st) return(-EINVAL); if (core_debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%p)\n", __FUNCTION__, st); - if (st->pid.pbuf) - kfree(st->pid.pbuf); - memset(&st->pid, 0, sizeof(mISDN_pid_t)); - memset(&st->para, 0, sizeof(mISDN_stPara_t)); - return(release_layers(st, MGR_UNREGLAYER | REQUEST)); + printk(KERN_DEBUG "%s: st(%08x)\n", __FUNCTION__, st->id); + + if (!(skb = alloc_skb(8, GFP_ATOMIC))) + return(-ENOMEM); + hhe = mISDN_HEADEXT_P(skb); + hhe->prim = MGR_CLEARSTACK | REQUEST; + hhe->addr = st->id; + + if (wait) { + DECLARE_MUTEX_LOCKED(sem); + + hhe->data[0] = &sem; + _queue_message(st, skb); + if (st->thread == current) {/* we cannot wait for us */ + int_error(); + return(-EBUSY); + } + down(&sem); + } else { + hhe->data[0] = NULL; + _queue_message(st, skb); + } + return(0); } static int @@ -642,15 +1246,15 @@ test_stack_protocol(mISDNstack_t *st, u_int l1prot, u_int l2prot, u_int l3prot) int cnt = MAX_LAYER_NR + 1, ret = 1; mISDN_pid_t pid; mISDNinstance_t *inst; - - clear_stack(st); + + clear_stack(st,1); memset(&pid, 0, sizeof(mISDN_pid_t)); pid.layermask = ISDN_LAYER(1); if (!(((l2prot == 2) || (l2prot == 0x40)) && (l3prot == 1))) pid.layermask |= ISDN_LAYER(2); if (!(l3prot == 1)) pid.layermask |= ISDN_LAYER(3); - + pid.protocol[1] = l1prot | ISDN_PID_LAYER(1) | ISDN_PID_BCHANNEL_BIT; if (pid.layermask & ISDN_LAYER(2)) pid.protocol[2] = l2prot | ISDN_PID_LAYER(2) | ISDN_PID_BCHANNEL_BIT; @@ -670,20 +1274,20 @@ test_stack_protocol(mISDNstack_t *st, u_int l1prot, u_int l2prot, u_int l3prot) } ret = st->mgr->obj->ctrl(st, MGR_REGLAYER | REQUEST, st->mgr); if (ret) { - clear_stack(st); + clear_stack(st, 1); return(ret); } while (pid.layermask && cnt--) { inst = get_next_instance(st, &pid); if (!inst) { - st->mgr->obj->ctrl(st, MGR_CLEARSTACK| REQUEST, NULL); - return(-ENOPROTOOPT); + ret = -ENOPROTOOPT; + break; } mISDN_RemoveUsedPID(&pid, &inst->pid); } if (!cnt) ret = -ENOPROTOOPT; - clear_stack(st); + clear_stack(st, 1); return(ret); } @@ -759,5 +1363,8 @@ evaluate_stack_pids(mISDNstack_t *st, mISDN_pid_t *pid) } } } + clear_stack(st, 1); return(0); } + +EXPORT_SYMBOL(mISDN_queue_message); diff --git a/drivers/isdn/hardware/mISDN/supp_serv.c b/drivers/isdn/hardware/mISDN/supp_serv.c index b5fb1d2..49a7288 100644 --- a/drivers/isdn/hardware/mISDN/supp_serv.c +++ b/drivers/isdn/hardware/mISDN/supp_serv.c @@ -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; diff --git a/drivers/isdn/hardware/mISDN/udevice.c b/drivers/isdn/hardware/mISDN/udevice.c index a07d6c3..1fdfb25 100644 --- a/drivers/isdn/hardware/mISDN/udevice.c +++ b/drivers/isdn/hardware/mISDN/udevice.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "core.h" #define MAX_HEADER_LEN 4 @@ -20,16 +21,17 @@ #define FLG_MGR_TIMER_INIT 1 #define FLG_MGR_TIMER_RUNING 2 +#define MAX_USERDEVICE_ID MAX_LAYER_NR typedef struct _devicelayer { struct list_head list; mISDNdevice_t *dev; mISDNinstance_t inst; mISDNinstance_t *slave; - mISDNif_t s_up; - mISDNif_t s_down; - int iaddr; - int lm_st; +// mISDNif_t s_up; +// mISDNif_t s_down; + u_int id; + u_int lm_st; u_long Flags; } devicelayer_t; @@ -44,7 +46,7 @@ typedef struct _mISDNtimer { struct list_head list; struct _mISDNdevice *dev; struct timer_list tl; - int id; + u_int id; u_long Flags; } mISDNtimer_t; @@ -61,7 +63,7 @@ static char MName[] = "UserDevice"; static int device_debug = 0; -static int from_up_down(mISDNif_t *, struct sk_buff *); +static int from_up_down(mISDNinstance_t *, struct sk_buff *); // static int from_peer(mISDNif_t *, u_int, int, int, void *); // static int to_peer(mISDNif_t *, u_int, int, int, void *); @@ -83,16 +85,15 @@ get_mISDNdevice4minor(int minor) return(NULL); } +#ifdef FIXME static int -mISDN_rdata_raw(mISDNif_t *hif, struct sk_buff *skb) { +mISDN_rdata_raw(mISDNinstance_t *inst, struct sk_buff *skb) { mISDNdevice_t *dev; mISDN_head_t *hh; u_long flags; int retval = 0; - if (!hif || !hif->fdata || !skb) - return(-EINVAL); - dev = hif->fdata; + dev = inst->priv; hh = mISDN_HEAD_P(skb); if (hh->prim == (PH_DATA | INDICATION)) { if (test_bit(FLG_mISDNPORT_OPEN, &dev->rport.Flag)) { @@ -164,6 +165,7 @@ mISDN_rdata_raw(mISDNif_t *hif, struct sk_buff *skb) { dev_kfree_skb_any(skb); return(retval); } +#endif static int mISDN_rdata(mISDNdevice_t *dev, struct sk_buff *skb) @@ -180,8 +182,9 @@ mISDN_rdata(mISDNdevice_t *dev, struct sk_buff *skb) spin_lock_irqsave(&dev->rport.lock, flags); if (skb_queue_len(&dev->rport.queue) >= dev->rport.maxqlen) { spin_unlock_irqrestore(&dev->rport.lock, flags); - printk(KERN_WARNING "%s: rport queue overflow %d/%d\n", - __FUNCTION__, skb_queue_len(&dev->rport.queue), dev->rport.maxqlen); + printk(KERN_WARNING "%s: rport queue overflow %d/%d [addr:%x prim:%x dinfo:%x]\n", + __FUNCTION__, skb_queue_len(&dev->rport.queue), dev->rport.maxqlen, + hp->addr, hp->prim, hp->dinfo); return(-ENOSPC); } skb_queue_tail(&dev->rport.queue, skb); @@ -201,21 +204,45 @@ error_answer(mISDNdevice_t *dev, struct sk_buff *skb, int err) } static devicelayer_t -*get_devlayer(mISDNdevice_t *dev, int addr) { +*get_devlayer(mISDNdevice_t *dev, u_int addr) +{ devicelayer_t *dl; if (device_debug & DEBUG_MGR_FUNC) printk(KERN_DEBUG "%s: addr:%x\n", __FUNCTION__, addr); list_for_each_entry(dl, &dev->layerlist, list) { // if (device_debug & DEBUG_MGR_FUNC) -// printk(KERN_DEBUG "%s: dl(%p) iaddr:%x\n", -// __FUNCTION__, dl, dl->iaddr); - if ((u_int)dl->iaddr == (IF_IADDRMASK & addr)) +// printk(KERN_DEBUG "%s: dl(%p) id:%x\n", +// __FUNCTION__, dl, dl->id); + if (dl->id == (INST_ID_MASK & addr)) + return(dl); + if (dl->inst.id == (INST_ID_MASK & addr)) + return(dl); + if (dl->slave && (dl->slave->id == (INST_ID_MASK & addr))) return(dl); } return(NULL); } +static u_int +get_new_devicelayer_id(mISDNdevice_t *dev, u_int addr) +{ + devicelayer_t *dl; + u_int i, found; + + addr |= (FLG_INSTANCE | FLG_ID_USER); + for (i=0; i<= MAX_USERDEVICE_ID; i++) { + found = 0; + list_for_each_entry(dl, &dev->layerlist, list) { + if (dl->id == (addr | i)) + found++; + } + if (!found) + return(addr | i); + } + return(0); +} + static devicestack_t *get_devstack(mISDNdevice_t *dev, int addr) { @@ -323,22 +350,40 @@ sel_channel(u_int addr, u_int channel) return(ci.st.p); } +static int +from_up_down(mISDNinstance_t *inst, struct sk_buff *skb) { + + devicelayer_t *dl; + mISDN_head_t *hh; + int retval = -EINVAL; + + dl = inst->privat; + hh = mISDN_HEAD_P(skb); + hh->len = skb->len; +// hh->addr = dl->iaddr; + if (device_debug & DEBUG_RDATA) + printk(KERN_DEBUG "from_up_down: %x(%x) dinfo:%x len:%d\n", + hh->prim, hh->addr, hh->dinfo, hh->len); + retval = mISDN_rdata(dl->dev, skb); + return(retval); +} + static int create_layer(mISDNdevice_t *dev, struct sk_buff *skb) { layer_info_t *linfo; - mISDNlayer_t *layer; mISDNstack_t *st; int i, ret; devicelayer_t *nl; mISDNobject_t *obj; mISDNinstance_t *inst = NULL; - mISDN_head_t *hp; + mISDN_head_t *hp; hp = mISDN_HEAD_P(skb); linfo = (layer_info_t *)skb->data; if (!(st = get_stack4id(linfo->st))) { - int_error(); + /* should be changed */ + printk(KERN_WARNING "%s: no stack found for id(%08x)\n", __FUNCTION__, linfo->st); return(-ENODEV); } if (linfo->object_id != -1) { @@ -354,104 +399,130 @@ create_layer(mISDNdevice_t *dev, struct sk_buff *skb) __FUNCTION__, ret); return(ret); } - layer = getlayer4lay(st, linfo->pid.layermask); - if (!layer) { - printk(KERN_WARNING "%s: no layer for lm(%x)\n", - __FUNCTION__, linfo->pid.layermask); - return(-EINVAL); - } - inst = layer->inst; + inst = getlayer4lay(st, linfo->pid.layermask); if (!inst) { - printk(KERN_WARNING "%s: no inst in layer(%p)\n", - __FUNCTION__, layer); + printk(KERN_WARNING "%s: no inst found\n", __FUNCTION__); return(-EINVAL); } - } else if ((layer = getlayer4lay(st, linfo->pid.layermask))) { + } else if (linfo->extentions & EXT_INST_CLONE) { + mISDN_pid_t *pid; + + inst = get_instance4id(linfo->parent); + if (!inst) { + printk(KERN_WARNING "%s: no parent inst found\n", __FUNCTION__); + return(-EINVAL); + } + if (!(inst->extentions & EXT_INST_CLONE)) { + printk(KERN_WARNING "%s: inst(%08x) ext(%x) is not cloneable\n", + __FUNCTION__, inst->id, inst->extentions); + return(-ENOSYS); + } + for(i=0; i<=MAX_LAYER_NR; i++) + if (!st->i_array[i]) + break; + if (i > MAX_LAYER_NR) { + printk(KERN_WARNING "%s: no free instance slot in stack id(%08x)\n", + __FUNCTION__, st->id); + return(-EBUSY); + } + pid = kmalloc(sizeof(mISDN_pid_t), GFP_ATOMIC); + if (!pid) { + printk(KERN_ERR "kmalloc pid failed\n"); + return(-ENOMEM); + } + memset(pid, 0, sizeof(mISDN_pid_t)); + if (inst->pid.pbuf && inst->pid.maxplen) { + pid->pbuf = kmalloc(inst->pid.maxplen, GFP_ATOMIC); + if (!pid->pbuf) { + kfree(pid); + printk(KERN_ERR "kmalloc pid->pbuf failed\n"); + return(-ENOMEM); + } + memset(pid->pbuf, 0, inst->pid.maxplen); + } + copy_pid(pid, &inst->pid, pid->pbuf); + ret = inst->obj->own_ctrl(st, MGR_NEWLAYER | REQUEST, pid); + kfree(pid->pbuf); + kfree(pid); + if (ret) { + printk(KERN_WARNING "%s: MGR_NEWLAYER | REQUEST for clone returns %d\n", __FUNCTION__, ret); + return(ret); + } + if (!st->i_array[i]) { + int_error(); + return(-EINVAL); + } else { + while (inst->clone) + inst = inst->clone; + inst->clone = st->i_array[i]; + st->i_array[i]->parent = inst; + inst = st->i_array[i]; + } + } +#if 0 + else if ((inst = getlayer4lay(st, linfo->pid.layermask))) { if (!(linfo->extentions & EXT_INST_MIDDLE)) { printk(KERN_WARNING - "mISDN create_layer st(%x) LM(%x) inst not empty(%p)\n", - st->id, linfo->pid.layermask, layer); + "mISDN create_layer st(%x) LM(%x) inst not empty(%08x)\n", + st->id, linfo->pid.layermask, inst->id); return(-EBUSY); } } +#endif if (!(nl = kmalloc(sizeof(devicelayer_t), GFP_ATOMIC))) { printk(KERN_ERR "kmalloc devicelayer failed\n"); return(-ENOMEM); } memset(nl, 0, sizeof(devicelayer_t)); + if (inst) + nl->id = get_new_devicelayer_id(dev, inst->id); + else if (st) + nl->id = get_new_devicelayer_id(dev, st->id); + else + nl->id = get_new_devicelayer_id(dev, 0); + if (!nl->id) { + int_errtxt("overflow devicelayer ids"); + kfree(nl); + return(-EBUSY); + } if (device_debug & DEBUG_MGR_FUNC) printk(KERN_DEBUG - "mISDN create_layer LM(%x) nl(%p) nl inst(%p)\n", - linfo->pid.layermask, nl, &nl->inst); + "mISDN create_layer LM(%x) nl(%p:%08x) nl->inst(%p) inst(%p)\n", + linfo->pid.layermask, nl, nl->id, &nl->inst, inst); nl->dev = dev; - memcpy(&nl->inst.pid, &linfo->pid, sizeof(mISDN_pid_t)); - strcpy(nl->inst.name, linfo->name); - nl->inst.extentions = linfo->extentions; - for (i=0; i<= MAX_LAYER_NR; i++) { - if (linfo->pid.layermask & ISDN_LAYER(i)) { - if (st && (st->pid.protocol[i] == ISDN_PID_NONE)) { - st->pid.protocol[i] = linfo->pid.protocol[i]; - nl->lm_st |= ISDN_LAYER(i); + list_add_tail(&nl->list, &dev->layerlist); + if (!inst) { + mISDN_init_instance(&nl->inst, &udev_obj, nl, from_up_down); + memcpy(&nl->inst.pid, &linfo->pid, sizeof(mISDN_pid_t)); + strcpy(nl->inst.name, linfo->name); + nl->inst.extentions = linfo->extentions; + for (i=0; i<= MAX_LAYER_NR; i++) { + if (linfo->pid.layermask & ISDN_LAYER(i)) { + if (st && (st->pid.protocol[i] == ISDN_PID_NONE)) { + st->pid.protocol[i] = linfo->pid.protocol[i]; + nl->lm_st |= ISDN_LAYER(i); + } } } - } - if (st && (linfo->extentions & EXT_INST_MGR)) { - st->mgr = &nl->inst; - test_and_set_bit(FLG_MGR_OWNSTACK, &nl->Flags); - } - nl->inst.down.owner = &nl->inst; - nl->inst.up.owner = &nl->inst; - nl->inst.obj = &udev_obj; - nl->inst.data = nl; - list_add_tail(&nl->list, &dev->layerlist); - nl->inst.obj->ctrl(st, MGR_REGLAYER | INDICATION, &nl->inst); - nl->iaddr = nl->inst.id; - skb_trim(skb, 0); - memcpy(skb_put(skb, sizeof(nl->iaddr)), &nl->iaddr, sizeof(nl->iaddr)); - if (inst) { + if (st && (linfo->extentions & EXT_INST_MGR)) { + st->mgr = &nl->inst; + test_and_set_bit(FLG_MGR_OWNSTACK, &nl->Flags); + } + if (st) + nl->inst.obj->ctrl(st, MGR_ADDLAYER | REQUEST, &nl->inst); + } else { nl->slave = inst; + nl->inst.extentions |= EXT_INST_UNUSED; + } + skb_trim(skb, 0); + memcpy(skb_put(skb, sizeof(nl->id)), &nl->id, sizeof(nl->id)); + if (inst) memcpy(skb_put(skb, sizeof(inst->id)), &inst->id, sizeof(inst->id)); - } else { - memset(skb_put(skb, sizeof(nl->iaddr)), 0, sizeof(nl->iaddr)); - } + else + memset(skb_put(skb, sizeof(nl->id)), 0, sizeof(nl->id)); return(8); } -static int -remove_if(devicelayer_t *dl, int stat) { - mISDNif_t *hif,*phif,*shif; - int err; - - if (device_debug & DEBUG_MGR_FUNC) - printk(KERN_DEBUG "%s: dl(%p) stat(%x)\n", __FUNCTION__, - dl, stat); - phif = NULL; - if (stat & IF_UP) { - hif = &dl->inst.up; - shif = &dl->s_up; - if (shif->owner) - phif = &shif->owner->down; - } else if (stat & IF_DOWN) { - hif = &dl->inst.down; - shif = &dl->s_down; - if (shif->owner) - phif = &shif->owner->up; - } else { - printk(KERN_WARNING "%s: stat not UP/DOWN\n", __FUNCTION__); - return(-EINVAL); - } - err = udev_obj.ctrl(hif->peer, MGR_DISCONNECT | REQUEST, hif); - if (phif) { - memcpy(phif, shif, sizeof(mISDNif_t)); - memset(shif, 0, sizeof(mISDNif_t)); - } - if (hif->predecessor) - hif->predecessor->clone = hif->clone; - if (hif->clone) - hif->clone->predecessor = hif->predecessor; - return(err); -} - static int del_stack(devicestack_t *ds) { @@ -488,11 +559,9 @@ del_layer(devicelayer_t *dl) if (device_debug & DEBUG_MGR_FUNC) { printk(KERN_DEBUG "%s: dl(%p) inst(%p) LM(%x) dev(%p)\n", __FUNCTION__, dl, inst, inst->pid.layermask, dev); - printk(KERN_DEBUG "%s: iaddr %x inst %s slave %p\n", - __FUNCTION__, dl->iaddr, inst->name, dl->slave); + printk(KERN_DEBUG "%s: iaddr %x inst(%08x) %s slave %p\n", + __FUNCTION__, dl->id, inst->id, inst->name, dl->slave); } - remove_if(dl, IF_UP); - remove_if(dl, IF_DOWN); if (dl->slave) { if (dl->slave->obj) dl->slave->obj->own_ctrl(dl->slave, @@ -514,17 +583,11 @@ del_layer(devicelayer_t *dl) inst->st->id); udev_obj.ctrl(inst->st, MGR_CLEARSTACK | REQUEST, NULL); } - if (inst->up.peer) { - inst->up.peer->obj->ctrl(inst->up.peer, - MGR_DISCONNECT | REQUEST, &inst->up); - } - if (inst->down.peer) { - inst->down.peer->obj->ctrl(inst->down.peer, - MGR_DISCONNECT | REQUEST, &inst->down); - } - dl->iaddr = 0; + dl->id = 0; list_del(&dl->list); - udev_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL); + if (!(inst->extentions & EXT_INST_UNUSED)) { + udev_obj.ctrl(inst, MGR_UNREGLAYER | REQUEST, NULL); + } if (test_and_clear_bit(FLG_MGR_OWNSTACK, &dl->Flags)) { if (dl->inst.st) { del_stack(get_devstack(dev, dl->inst.st->id)); @@ -534,6 +597,7 @@ del_layer(devicelayer_t *dl) return(0); } +#ifdef OBSOLETE static mISDNinstance_t * clone_instance(devicelayer_t *dl, mISDNstack_t *st, mISDNinstance_t *peer) { @@ -559,6 +623,41 @@ clone_instance(devicelayer_t *dl, mISDNstack_t *st, mISDNinstance_t *peer) return(dl->slave); } +static int +remove_if(devicelayer_t *dl, int stat) { + mISDNif_t *hif,*phif,*shif; + int err; + + if (device_debug & DEBUG_MGR_FUNC) + printk(KERN_DEBUG "%s: dl(%p) stat(%x)\n", __FUNCTION__, + dl, stat); + phif = NULL; + if (stat & IF_UP) { + hif = &dl->inst.up; + shif = &dl->s_up; + if (shif->owner) + phif = &shif->owner->down; + } else if (stat & IF_DOWN) { + hif = &dl->inst.down; + shif = &dl->s_down; + if (shif->owner) + phif = &shif->owner->up; + } else { + printk(KERN_WARNING "%s: stat not UP/DOWN\n", __FUNCTION__); + return(-EINVAL); + } + err = udev_obj.ctrl(hif->peer, MGR_DISCONNECT | REQUEST, hif); + if (phif) { + memcpy(phif, shif, sizeof(mISDNif_t)); + memset(shif, 0, sizeof(mISDNif_t)); + } + if (hif->predecessor) + hif->predecessor->clone = hif->clone; + if (hif->clone) + hif->clone->predecessor = hif->predecessor; + return(err); +} + static int connect_if_req(mISDNdevice_t *dev, struct sk_buff *skb) { @@ -765,6 +864,43 @@ del_if_req(mISDNdevice_t *dev, u_int addr) return(remove_if(dl, addr)); } +static void +get_if_info(struct sk_buff *skb) +{ + mISDN_head_t *hp; + mISDNinstance_t *inst; + mISDNif_t *hif; + interface_info_t *ii = (interface_info_t *)skb->data; + + hp = mISDN_HEAD_P(skb); + if (!(inst = get_instance4id(hp->addr & IF_ADDRMASK))) { + printk(KERN_WARNING "%s: no instance\n", __FUNCTION__); + hp->len = -ENODEV; + return; + } + if (hp->dinfo == IF_DOWN) + hif = &inst->down; + else if (hp->dinfo == IF_UP) + hif = &inst->up; + else { + printk(KERN_WARNING "%s: wrong interface %x\n", + __FUNCTION__, hp->dinfo); + hp->len = -EINVAL; + return; + } + hp->dinfo = 0; + memset(ii, 0, sizeof(interface_info_t)); + if (hif->owner) + ii->owner = hif->owner->id; + if (hif->peer) + ii->peer = hif->peer->id; + ii->extentions = hif->extentions; + ii->stat = hif->stat; + hp->len = sizeof(interface_info_t); + skb_put(skb, hp->len); +} +#endif + static int new_entity_req(mISDNdevice_t *dev, int *entity) { @@ -846,8 +982,9 @@ dev_init_timer(mISDNdevice_t *dev, u_int id) } else if (device_debug & DEBUG_DEV_TIMER) printk(KERN_DEBUG "%s: old(%x)\n", __FUNCTION__, ht->id); if (timer_pending(&ht->tl)) { - printk(KERN_WARNING "%s: timer(%x) pending\n", __FUNCTION__, - ht->id); + if (device_debug & DEBUG_DEV_TIMER) + printk(KERN_WARNING "%s: timer(%x) pending\n", + __FUNCTION__, ht->id); del_timer(&ht->tl); } init_timer(&ht->tl); @@ -901,9 +1038,11 @@ dev_del_timer(mISDNdevice_t *dev, u_int id) printk(KERN_DEBUG "%s: timer(%x)\n", __FUNCTION__, ht->id); del_timer(&ht->tl); - if (!test_and_clear_bit(FLG_MGR_TIMER_RUNING, &ht->Flags)) - printk(KERN_WARNING "%s: timer(%x) not running\n", - __FUNCTION__, ht->id); + if (!test_and_clear_bit(FLG_MGR_TIMER_RUNING, &ht->Flags)) { + if (device_debug & DEBUG_DEV_TIMER) + printk(KERN_WARNING "%s: timer(%x) not running\n", + __FUNCTION__, ht->id); + } return(0); } @@ -940,7 +1079,7 @@ get_status(struct sk_buff *skb) int err; hp = mISDN_HEAD_P(skb); - if (!(inst = get_instance4id(hp->addr & IF_ADDRMASK))) { + if (!(inst = get_instance4id(hp->addr & INST_ID_MASK))) { printk(KERN_WARNING "%s: no instance\n", __FUNCTION__); err = -ENODEV; } else { @@ -963,7 +1102,7 @@ get_layer_info(struct sk_buff *skb) layer_info_t *li = (layer_info_t *)skb->data; hp = mISDN_HEAD_P(skb); - if (!(inst = get_instance4id(hp->addr & IF_ADDRMASK))) { + if (!(inst = get_instance4id(hp->addr & INST_ID_MASK))) { printk(KERN_WARNING "%s: no instance\n", __FUNCTION__); hp->len = -ENODEV; return; @@ -976,52 +1115,19 @@ get_layer_info(struct sk_buff *skb) li->id = inst->id; if (inst->st) li->st = inst->st->id; + if (inst->parent) + li->parent = inst->parent->id; + if (inst->clone) + li->clone = inst->clone->id; memcpy(&li->pid, &inst->pid, sizeof(mISDN_pid_t)); hp->len = sizeof(layer_info_t); skb_put(skb, hp->len); } -static void -get_if_info(struct sk_buff *skb) -{ - mISDN_head_t *hp; - mISDNinstance_t *inst; - mISDNif_t *hif; - interface_info_t *ii = (interface_info_t *)skb->data; - - hp = mISDN_HEAD_P(skb); - if (!(inst = get_instance4id(hp->addr & IF_ADDRMASK))) { - printk(KERN_WARNING "%s: no instance\n", __FUNCTION__); - hp->len = -ENODEV; - return; - } - if (hp->dinfo == IF_DOWN) - hif = &inst->down; - else if (hp->dinfo == IF_UP) - hif = &inst->up; - else { - printk(KERN_WARNING "%s: wrong interface %x\n", - __FUNCTION__, hp->dinfo); - hp->len = -EINVAL; - return; - } - hp->dinfo = 0; - memset(ii, 0, sizeof(interface_info_t)); - if (hif->owner) - ii->owner = hif->owner->id; - if (hif->peer) - ii->peer = hif->peer->id; - ii->extentions = hif->extentions; - ii->stat = hif->stat; - hp->len = sizeof(interface_info_t); - skb_put(skb, hp->len); -} - static int wdata_frame(mISDNdevice_t *dev, struct sk_buff *skb) { mISDN_head_t *hp; - mISDNif_t *hif = NULL; devicelayer_t *dl; int err = -ENXIO; @@ -1030,36 +1136,18 @@ wdata_frame(mISDNdevice_t *dev, struct sk_buff *skb) printk(KERN_DEBUG "%s: addr:%x\n", __FUNCTION__, hp->addr); if (!(dl=get_devlayer(dev, hp->addr))) return(err); - if (hp->addr & IF_UP) { - hif = &dl->inst.up; - if (IF_TYPE(hif) != IF_DOWN) { - printk(KERN_WARNING "%s: inst.up no down\n", __FUNCTION__); - hif = NULL; - } - } else if (hp->addr & IF_DOWN) { - hif = &dl->inst.down; - if (IF_TYPE(hif) != IF_UP) { - printk(KERN_WARNING "%s: inst.down no up\n", __FUNCTION__); - hif = NULL; - } - } - if (hif) { - if (device_debug & DEBUG_WDATA) - printk(KERN_DEBUG "%s: pr(%x) di(%x) l(%d)\n", - __FUNCTION__, hp->prim, hp->dinfo, hp->len); - if (hp->len < 0) { - printk(KERN_WARNING "%s: data negativ(%d)\n", - __FUNCTION__, hp->len); - return(-EINVAL); - } - err = hif->func(hif, skb); - if (device_debug & DEBUG_WDATA && err) - printk(KERN_DEBUG "%s: hif->func ret(%x)\n", - __FUNCTION__, err); - } else { - if (device_debug & DEBUG_WDATA) - printk(KERN_DEBUG "mISDN: no matching interface\n"); + if (device_debug & DEBUG_WDATA) + printk(KERN_DEBUG "%s: pr(%x) di(%x) l(%d)\n", + __FUNCTION__, hp->prim, hp->dinfo, hp->len); + if (hp->len < 0) { + printk(KERN_WARNING "%s: data negativ(%d)\n", + __FUNCTION__, hp->len); + return(-EINVAL); } + err = mISDN_queue_message(&dl->inst, hp->addr, skb); + if (device_debug & DEBUG_WDATA && err) + printk(KERN_DEBUG "%s: mISDN_send_message ret(%x)\n", + __FUNCTION__, err); return(err); } @@ -1070,7 +1158,7 @@ mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb) mISDN_head_t *hp; mISDNstack_t *st; devicelayer_t *dl; - mISDNlayer_t *layer; + mISDNinstance_t *inst; int lay; int err = 0; @@ -1154,9 +1242,9 @@ mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb) hp->len = 0; lay = ISDN_LAYER(lay); if ((st = get_stack4id(hp->addr))) { - if ((layer = getlayer4lay(st, lay))) { - if (layer->inst) - hp->dinfo = layer->inst->id; + if ((inst = getlayer4lay(st, lay))) { + if (inst) + hp->dinfo = inst->id; } } } @@ -1182,6 +1270,27 @@ mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb) hp->prim = MGR_NEWLAYER | CONFIRM; hp->len = create_layer(dev, skb); break; + case (MGR_REGLAYER | REQUEST): + lay = hp->dinfo; + hp->dinfo = 0; + if (!(st = get_stack4id(hp->addr))) + return(error_answer(dev, skb, -ENODEV)); + if (!(dl = get_devlayer(dev, lay))) + return(error_answer(dev, skb, -ENODEV)); + hp->prim = MGR_REGLAYER | CONFIRM; + hp->len = udev_obj.ctrl(st, MGR_REGLAYER | REQUEST, &dl->inst); + printk(KERN_DEBUG "MGR_REGLAYER | REQUEST: ret(%d)\n", hp->len); + break; + case (MGR_UNREGLAYER | REQUEST): + lay = hp->dinfo; + hp->dinfo = 0; + if (!(st = get_stack4id(hp->addr))) + return(error_answer(dev, skb, -ENODEV)); + if (!(dl = get_devlayer(dev, lay))) + return(error_answer(dev, skb, -ENODEV)); + hp->prim = MGR_UNREGLAYER | CONFIRM; + hp->len = udev_obj.ctrl(st, MGR_UNREGLAYER | REQUEST, &dl->inst); + break; case (MGR_DELLAYER | REQUEST): hp->prim = MGR_DELLAYER | CONFIRM; hp->dinfo = 0; @@ -1190,6 +1299,7 @@ mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb) else hp->len = -ENXIO; break; +#ifdef OBSOLETE case (MGR_GETIF | REQUEST): hp->prim = MGR_GETIF | CONFIRM; hp->dinfo = 0; @@ -1226,6 +1336,7 @@ mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb) hp->prim = MGR_DISCONNECT | CONFIRM; hp->dinfo = 0; break; +#endif case (MGR_NEWENTITY | REQUEST): hp->prim = MGR_NEWENTITY | CONFIRM; hp->len = new_entity_req(dev, &hp->dinfo); @@ -1288,7 +1399,7 @@ mISDN_wdata_if(mISDNdevice_t *dev, struct sk_buff *skb) hp->dinfo = 0; break; default: - if (hp->addr & IF_TYPEMASK) { + if (hp->addr & FLG_INSTANCE) { err = wdata_frame(dev, skb); if (err) { if (device_debug & DEBUG_WDATA) @@ -1342,6 +1453,7 @@ init_device(u_int minor) { return(dev); } +#ifdef FIXME mISDNdevice_t * get_free_rawdevice(void) { @@ -1366,6 +1478,7 @@ get_free_rawdevice(void) } return(NULL); } +#endif int free_device(mISDNdevice_t *dev) @@ -1481,7 +1594,7 @@ do_mISDN_read(struct file *file, char *buf, size_t count, loff_t * off) { mISDNdevice_t *dev = file->private_data; size_t len; - u_long flags; +// u_long flags; struct sk_buff *skb; if (*off != file->f_pos) @@ -1489,22 +1602,20 @@ do_mISDN_read(struct file *file, char *buf, size_t count, loff_t * off) if (!access_ok(VERIFY_WRITE, buf, count)) return(-EFAULT); if ((dev->minor == 0) && (count < mISDN_HEADER_LEN)) { - printk(KERN_WARNING "mISDN_read: count(%d) too small\n", count); + printk(KERN_WARNING "mISDN_read: count(%ld) too small\n", (long)count); return(-ENOSPC); } if (device_debug & DEBUG_DEV_OP) - printk(KERN_DEBUG "mISDN_read: file(%d) %p max %d\n", - dev->minor, file, count); - spin_lock_irqsave(&dev->rport.lock, flags); - while (skb_queue_empty(&dev->rport.queue)) { - spin_unlock_irqrestore(&dev->rport.lock, flags); + printk(KERN_DEBUG "mISDN_read: file(%d) %p max %ld\n", + dev->minor, file, (long)count); + if (skb_queue_empty(&dev->rport.queue)) { if (file->f_flags & O_NONBLOCK) return(-EAGAIN); - interruptible_sleep_on(&(dev->rport.procq)); + wait_event_interruptible(dev->rport.procq, (!skb_queue_empty(&dev->rport.queue))); if (signal_pending(current)) return(-ERESTARTSYS); - spin_lock_irqsave(&dev->rport.lock, flags); } +// spin_lock_irqsave(&dev->rport.lock, flags); len = 0; while ((skb = skb_dequeue(&dev->rport.queue))) { if (dev->minor == mISDN_CORE_DEVICE) { @@ -1520,7 +1631,7 @@ do_mISDN_read(struct file *file, char *buf, size_t count, loff_t * off) skb_queue_head(&dev->rport.queue, skb); if (len) break; - spin_unlock_irqrestore(&dev->rport.lock, flags); +// spin_unlock_irqrestore(&dev->rport.lock, flags); return(-ENOSPC); } } @@ -1528,7 +1639,7 @@ do_mISDN_read(struct file *file, char *buf, size_t count, loff_t * off) if (copy_to_user(buf, skb->data, skb->len)) { efault: skb_queue_head(&dev->rport.queue, skb); - spin_unlock_irqrestore(&dev->rport.lock, flags); +// spin_unlock_irqrestore(&dev->rport.lock, flags); return(-EFAULT); } len += skb->len; @@ -1539,10 +1650,10 @@ do_mISDN_read(struct file *file, char *buf, size_t count, loff_t * off) break; } *off += len; - spin_unlock_irqrestore(&dev->rport.lock, flags); +// spin_unlock_irqrestore(&dev->rport.lock, flags); if (device_debug & DEBUG_DEV_OP) - printk(KERN_DEBUG "mISDN_read: file(%d) %d\n", - dev->minor, len); + printk(KERN_DEBUG "mISDN_read: file(%d) %ld\n", + dev->minor, (long)len); return(len); } @@ -1571,36 +1682,34 @@ do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off) { mISDNdevice_t *dev = file->private_data; size_t len; - u_long flags; +// u_long flags; struct sk_buff *skb; mISDN_head_t head; if (*off != file->f_pos) return(-ESPIPE); if (device_debug & DEBUG_DEV_OP) - printk(KERN_DEBUG "mISDN_write: file(%d) %p count %d queue(%d)\n", - dev->minor, file, count, skb_queue_len(&dev->wport.queue)); + printk(KERN_DEBUG "mISDN_write: file(%d) %p count %ld queue(%d)\n", + dev->minor, file, (long)count, skb_queue_len(&dev->wport.queue)); if (!access_ok(VERIFY_WRITE, buf, count)) return(-EFAULT); if (dev->minor == 0) { if (count < mISDN_HEADER_LEN) return(-EINVAL); } - spin_lock_irqsave(&dev->wport.lock, flags); - while (skb_queue_len(&dev->wport.queue) >= dev->wport.maxqlen) { - spin_unlock_irqrestore(&dev->wport.lock, flags); + if (skb_queue_len(&dev->wport.queue) >= dev->wport.maxqlen) { if (file->f_flags & O_NONBLOCK) return(-EAGAIN); - interruptible_sleep_on(&(dev->wport.procq)); + wait_event_interruptible(dev->wport.procq, (skb_queue_len(&dev->wport.queue) < dev->wport.maxqlen)); if (signal_pending(current)) return(-ERESTARTSYS); - spin_lock_irqsave(&dev->wport.lock, flags); } +// spin_lock_irqsave(&dev->wport.lock, flags); if (dev->minor == mISDN_CORE_DEVICE) { len = count; while (len >= mISDN_HEADER_LEN) { if (copy_from_user(&head.addr, buf, mISDN_HEADER_LEN)) { - spin_unlock_irqrestore(&dev->rport.lock, flags); +// spin_unlock_irqrestore(&dev->rport.lock, flags); return(-EFAULT); } if (head.len > 0) @@ -1618,14 +1727,14 @@ do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off) /* since header is complete we can handle this later */ if (copy_from_user(skb_put(skb, len), buf, len)) { dev_kfree_skb(skb); - spin_unlock_irqrestore(&dev->rport.lock, flags); +// spin_unlock_irqrestore(&dev->rport.lock, flags); return(-EFAULT); } len = 0; } else { if (copy_from_user(skb_put(skb, head.len), buf, head.len)) { dev_kfree_skb(skb); - spin_unlock_irqrestore(&dev->rport.lock, flags); +// spin_unlock_irqrestore(&dev->rport.lock, flags); return(-EFAULT); } len -= head.len; @@ -1635,12 +1744,12 @@ do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off) skb_queue_tail(&dev->wport.queue, skb); } if (len) - printk(KERN_WARNING "%s: incomplete frame data (%d/%d)\n", __FUNCTION__, len, count); + printk(KERN_WARNING "%s: incomplete frame data (%ld/%ld)\n", __FUNCTION__, (long)len, (long)count); if (test_and_set_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag)) { - spin_unlock_irqrestore(&dev->wport.lock, flags); +// spin_unlock_irqrestore(&dev->wport.lock, flags); return(count-len); } - spin_unlock_irqrestore(&dev->wport.lock, flags); +// spin_unlock_irqrestore(&dev->wport.lock, flags); while ((skb = skb_dequeue(&dev->wport.queue))) { if (mISDN_wdata_if(dev, skb)) dev_kfree_skb(skb); @@ -1648,20 +1757,21 @@ do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off) } test_and_clear_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag); } else { /* raw device */ + len = 0; +#ifdef FIXME skb = alloc_stack_skb(count, PORT_SKB_RESERVE); - if (skb) { - spin_unlock_irqrestore(&dev->wport.lock, flags); + if (!skb) { +// spin_unlock_irqrestore(&dev->wport.lock, flags); return(0); } if (copy_from_user(skb_put(skb, count), buf, count)) { dev_kfree_skb(skb); - spin_unlock_irqrestore(&dev->wport.lock, flags); +// spin_unlock_irqrestore(&dev->wport.lock, flags); return(-EFAULT); } - len = 0; skb_queue_tail(&dev->wport.queue, skb); if (test_and_set_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag)) { - spin_unlock_irqrestore(&dev->wport.lock, flags); +// spin_unlock_irqrestore(&dev->wport.lock, flags); return(count); } while ((skb = skb_dequeue(&dev->wport.queue))) { @@ -1673,9 +1783,9 @@ do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off) } if (test_bit(FLG_mISDNPORT_ENABLED, &dev->wport.Flag)) { int ret; - spin_unlock_irqrestore(&dev->wport.lock, flags); +// spin_unlock_irqrestore(&dev->wport.lock, flags); ret = if_newhead(&dev->wport.pif, PH_DATA | REQUEST, (int)skb, skb); - spin_lock_irqsave(&dev->wport.lock, flags); +// spin_lock_irqsave(&dev->wport.lock, flags); if (ret) { printk(KERN_WARNING "%s: dev(%d) down err(%d)\n", __FUNCTION__, dev->minor, ret); @@ -1690,7 +1800,8 @@ do_mISDN_write(struct file *file, const char *buf, size_t count, loff_t * off) wake_up(&dev->wport.procq); } test_and_clear_bit(FLG_mISDNPORT_BUSY, &dev->wport.Flag); - spin_unlock_irqrestore(&dev->wport.lock, flags); +// spin_unlock_irqrestore(&dev->wport.lock, flags); +#endif } return(count - len); } @@ -1754,27 +1865,8 @@ static struct file_operations mISDN_fops = release: mISDN_close, }; -static int -from_up_down(mISDNif_t *hif, struct sk_buff *skb) { - - devicelayer_t *dl; - mISDN_head_t *hh; - int retval = -EINVAL; - - if (!hif || !hif->fdata || !skb) - return(-EINVAL); - dl = hif->fdata; - hh = mISDN_HEAD_P(skb); - hh->len = skb->len; - hh->addr = dl->iaddr | IF_TYPE(hif); - if (device_debug & DEBUG_RDATA) - printk(KERN_DEBUG "from_up_down: %x(%x) dinfo:%x len:%d\n", - hh->prim, hh->addr, hh->dinfo, hh->len); - retval = mISDN_rdata(dl->dev, skb); - return(retval); -} - +#ifdef OBSOLETE static int set_if(devicelayer_t *dl, u_int prim, mISDNif_t *hif) { @@ -1783,6 +1875,20 @@ set_if(devicelayer_t *dl, u_int prim, mISDNif_t *hif) err = mISDN_SetIF(&dl->inst, hif, prim, from_up_down, from_up_down, dl); return(err); } +#endif + +static void setstack_conf(devicelayer_t *dl) +{ + struct sk_buff *skb = create_link_skb(MGR_SETSTACK | INDICATION, 0, 0, NULL, 16); + mISDN_head_t *hh; + + if (!skb) + return; + hh = mISDN_HEAD_P(skb); + hh->addr = dl->id; + if (mISDN_rdata(dl->dev, skb)) + kfree_skb(skb); +} static int udev_manager(void *data, u_int prim, void *arg) { @@ -1812,6 +1918,7 @@ udev_manager(void *data, u_int prim, void *arg) { goto out; } switch(prim) { +#ifdef OBSOLETE case MGR_CONNECT | REQUEST: err = mISDN_ConnectIF(inst, arg); break; @@ -1823,6 +1930,14 @@ udev_manager(void *data, u_int prim, void *arg) { case MGR_DISCONNECT | INDICATION: err = mISDN_DisConnectIF(inst, arg); break; +#endif + case MGR_REGLAYER | CONFIRM: + err = 0; + break; + case MGR_SETSTACK | INDICATION: + setstack_conf(dl); + err = 0; + break; case MGR_RELEASE | INDICATION: if (device_debug & DEBUG_MGR_FUNC) printk(KERN_DEBUG "release_dev id %x\n", @@ -1844,20 +1959,32 @@ int init_mISDNdev (int debug) { int err,i; udev_obj.name = MName; + udev_obj.owner = THIS_MODULE; for (i=0; i<=MAX_LAYER_NR; i++) { udev_obj.DPROTO.protocol[i] = ISDN_PID_ANY; udev_obj.BPROTO.protocol[i] = ISDN_PID_ANY; } + spin_lock_init(&udev_obj.lock); INIT_LIST_HEAD(&udev_obj.ilist); udev_obj.own_ctrl = udev_manager; device_debug = debug; + if (register_chrdev(mISDN_MAJOR, "mISDN", &mISDN_fops)) { printk(KERN_WARNING "mISDN: Could not register devices\n"); return(-EIO); } - if ((err = mISDN_register(&udev_obj))) { + +#ifdef CLASSDEV_HAS_DEVT + udev_obj.class_dev.devt = MKDEV(mISDN_MAJOR, 0); +#endif + + err = mISDN_register(&udev_obj); + if (err) { printk(KERN_ERR "Can't register %s error(%d)\n", MName, err); - } + unregister_chrdev(mISDN_MAJOR, "mISDN"); + } else + devfs_mk_cdev(MKDEV(mISDN_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "mISDN"); + return(err); } @@ -1878,5 +2005,6 @@ int free_mISDNdev(void) { if ((err = unregister_chrdev(mISDN_MAJOR, "mISDN"))) { printk(KERN_WARNING "mISDN: devices busy on remove\n"); } + devfs_remove("mISDN"); return(err); } diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 52be072..1eb0ad5 100755 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -26,8 +26,7 @@ #include #include -#include "dchannel.h" -#include "bchannel.h" +#include "channel.h" #include "layer1.h" #include "helper.h" #include "debug.h" @@ -35,10 +34,6 @@ #include -#define SPIN_DEBUG -#define LOCK_STATISTIC -#include "hw_lock.h" - extern const char *CardType[]; const char *w6692_rev = "$Revision$"; @@ -52,39 +47,25 @@ typedef struct _w6692_bc { typedef struct _w6692pci { struct list_head list; - void *pdev; + struct pci_dev *pdev; u_int irq; u_int irqcnt; u_int addr; int pots; int led; - mISDN_HWlock_t lock; + spinlock_t lock; u_char imask; u_char pctl; u_char xaddr; u_char xdata; w6692_bc wbc[2]; - dchannel_t dch; - bchannel_t bch[2]; + channel_t dch; + channel_t bch[2]; } w6692pci; #define W_LED1_ON 1 #define W_LED1_S0STATUS 2 -static int lock_dev(void *data, int nowait) -{ - register mISDN_HWlock_t *lock = &((w6692pci *)data)->lock; - - return(lock_HW(lock, nowait)); -} - -static void unlock_dev(void *data) -{ - register mISDN_HWlock_t *lock = &((w6692pci *)data)->lock; - - unlock_HW(lock); -} - static __inline__ u_char ReadW6692(w6692pci *card, u_char offset) { @@ -109,6 +90,18 @@ WriteW6692B(w6692pci *card, int bchan, u_char offset, u_char value) outb(value, card->addr + (bchan ? 0x40 : 0) + offset); } +static void +enable_hwirq(w6692pci *card) +{ + WriteW6692(card, W_IMASK, card->imask); +} + +static void +disable_hwirq(w6692pci *card) +{ + WriteW6692(card, W_IMASK, 0xff); +} + static char *W6692Ver[] __initdata = {"W6692 V00", "W6692 V01", "W6692 V10", "W6692 V11"}; @@ -145,36 +138,25 @@ ph_command(w6692pci *card, u_char command) } static void -W6692_new_ph(dchannel_t *dch) +W6692_new_ph(channel_t *dch) { u_int prim = PH_SIGNAL | INDICATION; u_int para = 0; - mISDNif_t *upif = &dch->inst.up; - if (dch->debug) - printk(KERN_DEBUG "%s: event %lx\n", __FUNCTION__, dch->event); - if (!test_and_clear_bit(D_L1STATECHANGE, &dch->event)) - return; - switch (dch->ph_state) { + switch (dch->state) { case W_L1CMD_RST: - dch->inst.lock(dch->inst.data, 0); ph_command(dch->hw, W_L1CMD_DRC); - dch->inst.unlock(dch->inst.data); - prim = PH_CONTROL | INDICATION; - para = HW_RESET; - while(upif) { - if_link(upif, prim, para, 0, NULL, 0); - upif = upif->clone; - } - upif = &dch->inst.up; + mISDN_queue_data(&dch->inst, FLG_MSG_UP, PH_CONTROL | INDICATION, HW_RESET, 0, NULL, 0); /* fall trough */ case W_L1IND_CD: prim = PH_CONTROL | CONFIRM; para = HW_DEACTIVATE; + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); break; case W_L1IND_DRD: prim = PH_CONTROL | INDICATION; para = HW_DEACTIVATE; + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); break; case W_L1IND_CE: prim = PH_CONTROL | INDICATION; @@ -188,36 +170,35 @@ W6692_new_ph(dchannel_t *dch) break; case W_L1IND_AI8: para = INFO4_P8; + test_and_set_bit(FLG_ACTIVE, &dch->Flags); break; case W_L1IND_AI10: para = INFO4_P10; + test_and_set_bit(FLG_ACTIVE, &dch->Flags); break; 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); } static void W6692_empty_Dfifo(w6692pci *card, int count) { - dchannel_t *dch = &card->dch; + channel_t *dch = &card->dch; u_char *ptr; if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO)) mISDN_debugprint(&dch->inst, "empty_Dfifo"); if (!dch->rx_skb) { - if (!(dch->rx_skb = alloc_stack_skb(MAX_DFRAME_LEN_L1, dch->up_headerlen))) { + if (!(dch->rx_skb = alloc_stack_skb(dch->maxlen, dch->up_headerlen))) { printk(KERN_WARNING "mISDN: D receive out of memory\n"); WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); return; } } - if ((dch->rx_skb->len + count) >= MAX_DFRAME_LEN_L1) { + if ((dch->rx_skb->len + count) >= dch->maxlen) { if (dch->debug & L1_DEB_WARN) mISDN_debugprint(&dch->inst, "empty_Dfifo overrun %d", dch->rx_skb->len + count); @@ -228,18 +209,18 @@ W6692_empty_Dfifo(w6692pci *card, int count) insb(card->addr + W_D_RFIFO, ptr, count); WriteW6692(card, W_D_CMDR, W_D_CMDR_RACK); if (dch->debug & L1_DEB_ISAC_FIFO) { - char *t = dch->dlog; + char *t = dch->log; t += sprintf(t, "empty_Dfifo cnt %d", count); mISDN_QuickHex(t, ptr, count); - mISDN_debugprint(&dch->inst, dch->dlog); + mISDN_debugprint(&dch->inst, dch->log); } } static void W6692_fill_Dfifo(w6692pci *card) { - dchannel_t *dch = &card->dch; + channel_t *dch = &card->dch; int count; u_char *ptr; u_char cmd = W_D_CMDR_XMS; @@ -247,60 +228,71 @@ W6692_fill_Dfifo(w6692pci *card) if ((dch->debug & L1_DEB_ISAC) && !(dch->debug & L1_DEB_ISAC_FIFO)) mISDN_debugprint(&dch->inst, "fill_Dfifo"); - count = dch->tx_len - dch->tx_idx; + if (!dch->tx_skb) + return; + count = dch->tx_skb->len - dch->tx_idx; if (count <= 0) return; - if (count > 32) { + if (count > 32) count = 32; - } else + else cmd |= W_D_CMDR_XME; - ptr = dch->tx_buf + dch->tx_idx; + ptr = dch->tx_skb->data + dch->tx_idx; dch->tx_idx += count; outsb(card->addr + W_D_XFIFO, ptr, count); WriteW6692(card, W_D_CMDR, cmd); - if (test_and_set_bit(FLG_DBUSY_TIMER, &dch->DFlags)) { + if (test_and_set_bit(FLG_BUSY_TIMER, &dch->Flags)) { mISDN_debugprint(&dch->inst, "fill_Dfifo 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, "fill_Dfifo cnt %d", count); mISDN_QuickHex(t, ptr, count); - mISDN_debugprint(&dch->inst, dch->dlog); + mISDN_debugprint(&dch->inst, dch->log); } } static void d_retransmit(w6692pci *card) { - dchannel_t *dch = &card->dch; + channel_t *dch = &card->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)) + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) dchannel_sched_event(dch, D_CLEARBUSY); - if (test_bit(FLG_TX_BUSY, &dch->DFlags)) { +#endif + if (test_bit(FLG_TX_BUSY, &dch->Flags)) { /* Restart frame */ dch->tx_idx = 0; W6692_fill_Dfifo(card); + } else if (dch->tx_skb) { /* should not happen */ + int_error(); + test_and_set_bit(FLG_TX_BUSY, &dch->Flags); + dch->tx_idx = 0; + W6692_fill_Dfifo(card); } else { printk(KERN_WARNING "mISDN: w6692 XDU no TX_BUSY\n"); mISDN_debugprint(&dch->inst, "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->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); W6692_fill_Dfifo(card); - dchannel_sched_event(dch, D_XMTBUFREADY); } else { printk(KERN_WARNING "w6692 xdu irq TX_NEXT without skb\n"); + test_and_clear_bit(FLG_TX_NEXT, &dch->Flags); } } } @@ -342,45 +334,54 @@ handle_rxD(w6692pci *card) { if (count == 0) count = W_D_FIFO_THRESH; W6692_empty_Dfifo(card, count); - if (card->dch.rx_skb) { - skb_queue_tail(&card->dch.rqueue, card->dch.rx_skb); - } + if (card->dch.rx_skb) + mISDN_queueup_newhead(&card->dch.inst, 0, PH_DATA_IND, + MISDN_ID_ANY, card->dch.rx_skb); } card->dch.rx_skb = NULL; - dchannel_sched_event(&card->dch, D_RCVBUFREADY); } static void handle_txD(w6692pci *card) { - register dchannel_t *dch = &card->dch; + register channel_t *dch = &card->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)) + if (test_and_clear_bit(FLG_BUSY_TIMER, &dch->Flags)) + del_timer(&dch->timer); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) dchannel_sched_event(dch, D_CLEARBUSY); - if (dch->tx_idx < dch->tx_len) { +#endif + if (dch->tx_skb && dch->tx_idx < dch->tx_skb->len) { W6692_fill_Dfifo(card); } 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); W6692_fill_Dfifo(card); - dchannel_sched_event(dch, D_XMTBUFREADY); } else { printk(KERN_WARNING "w6692 txD 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 -handle_statusD(w6692pci *card) { - register dchannel_t *dch = &card->dch; +handle_statusD(w6692pci *card) +{ + register channel_t *dch = &card->dch; u_char exval, v1, cir; exval = ReadW6692(card, W_D_EXIR); @@ -418,8 +419,8 @@ handle_statusD(w6692pci *card) { v1 = cir & W_CIR_COD_MASK; if (card->dch.debug & L1_DEB_ISAC) mISDN_debugprint(&card->dch.inst, "ph_state_change %x -> %x", - dch->ph_state, v1); - dch->ph_state = v1; + dch->state, v1); + dch->state = v1; if (card->led & W_LED1_S0STATUS) { switch (v1) { case W_L1IND_AI8: @@ -431,7 +432,7 @@ handle_statusD(w6692pci *card) { break; } } - dchannel_sched_event(dch, D_L1STATECHANGE); + W6692_new_ph(dch); } if (cir & W_CIR_SCC) { v1 = ReadW6692(card, W_SQR); @@ -450,58 +451,68 @@ handle_statusD(w6692pci *card) { } static void -W6692_empty_Bfifo(bchannel_t *bch, int count) +W6692_empty_Bfifo(channel_t *bch, int count) { u_char *ptr; - w6692pci *card = bch->inst.data; + w6692pci *card = bch->inst.privat; if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO)) mISDN_debugprint(&bch->inst, "empty_Bfifo %d", count); - if (bch->protocol == ISDN_PID_NONE) { + if (unlikely(bch->state == ISDN_PID_NONE)) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "empty_Bfifo ISDN_PID_NONE"); WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - bch->rx_idx = 0; + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); return; } - if (bch->rx_idx + count > MAX_DATA_MEM) { + if (!bch->rx_skb) { + bch->rx_skb = alloc_stack_skb(bch->maxlen, bch->up_headerlen); + if (unlikely(!bch->rx_skb)) { + printk(KERN_WARNING "mISDN: B receive out of memory\n"); + WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); + return; + } + } + if (bch->rx_skb->len + count > bch->maxlen) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "empty_Bfifo incoming packet too large"); WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - bch->rx_idx = 0; + skb_trim(bch->rx_skb, 0); return; } - ptr = bch->rx_buf + bch->rx_idx; - bch->rx_idx += count; + ptr = skb_put(bch->rx_skb, count); insb(card->addr + W_B_RFIFO + (bch->channel ? 0x40 : 0), ptr, count); WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); if (bch->debug & L1_DEB_HSCX_FIFO) { - char *t = bch->blog; + char *t = bch->log; t += sprintf(t, "empty_Bfifo B%d cnt %d", bch->channel, count); mISDN_QuickHex(t, ptr, count); - mISDN_debugprint(&bch->inst, bch->blog); + mISDN_debugprint(&bch->inst, bch->log); } } static void -W6692_fill_Bfifo(bchannel_t *bch) +W6692_fill_Bfifo(channel_t *bch) { - w6692pci *card = bch->inst.data; + w6692pci *card = bch->inst.privat; int count; u_char *ptr, cmd = W_B_CMDR_RACT | W_B_CMDR_XMS; 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; - ptr = bch->tx_buf + bch->tx_idx; + ptr = bch->tx_skb->data + bch->tx_idx; if (count > W_B_FIFO_THRESH) { count = W_B_FIFO_THRESH; } else { - if (bch->protocol != ISDN_PID_L1_B_64TRANS) + if (test_bit(FLG_HDLC, &bch->Flags)) cmd |= W_B_CMDR_XME; } if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO)) @@ -511,23 +522,23 @@ W6692_fill_Bfifo(bchannel_t *bch) outsb(card->addr + W_B_XFIFO + (bch->channel ? 0x40 : 0), ptr, count); WriteW6692B(card, bch->channel, W_B_CMDR, cmd); if (bch->debug & L1_DEB_HSCX_FIFO) { - char *t = bch->blog; + char *t = bch->log; t += sprintf(t, "fill_Bfifo B%d cnt %d", bch->channel, count); mISDN_QuickHex(t, ptr, count); - mISDN_debugprint(&bch->inst, bch->blog); + mISDN_debugprint(&bch->inst, bch->log); } } static int -setvolume(bchannel_t *bch, int mic, struct sk_buff *skb) +setvolume(channel_t *bch, int mic, struct sk_buff *skb) { - w6692pci *card = bch->inst.data; + w6692pci *card = bch->inst.privat; u16 *vol = (u16 *)skb->data; u_char val; - if ((card->pots == 0) || (bch->protocol != ISDN_PID_L1_B_64TRANS)) + if ((card->pots == 0) || !test_bit(FLG_TRANSPARENT, &bch->Flags)) return(-ENODEV); if (skb->len < 2) return(-EINVAL); @@ -547,12 +558,12 @@ setvolume(bchannel_t *bch, int mic, struct sk_buff *skb) } static int -enable_pots(bchannel_t *bch) +enable_pots(channel_t *bch) { w6692_bc *bhw = bch->hw; - w6692pci *card = bch->inst.data; + w6692pci *card = bch->inst.privat; - if ((card->pots == 0) || (bch->protocol != ISDN_PID_L1_B_64TRANS)) + if ((card->pots == 0) || !test_bit(FLG_TRANSPARENT, &bch->Flags)) return(-ENODEV); bhw->b_mode |= W_B_MODE_EPCM | W_B_MODE_BSW0; @@ -564,10 +575,10 @@ enable_pots(bchannel_t *bch) } static int -disable_pots(bchannel_t *bch) +disable_pots(channel_t *bch) { w6692_bc *bhw = bch->hw; - w6692pci *card = bch->inst.data; + w6692pci *card = bch->inst.privat; if (card->pots == 0) return(-ENODEV); @@ -578,54 +589,61 @@ disable_pots(bchannel_t *bch) } static int -mode_w6692(bchannel_t *bch, int bc, int protocol) +mode_w6692(channel_t *bch, int bc, int protocol) { - w6692pci *card = bch->inst.data; + w6692pci *card = bch->inst.privat; w6692_bc *bhw = bch->hw; if (bch->debug & L1_DEB_HSCX) mISDN_debugprint(&bch->inst, "B%d protocol %x-->%x ch %d-->%d", - bch->channel, bch->protocol, protocol, bch->channel, bc); + bch->channel, bch->state, protocol, bch->channel, bc); 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; - bch->protocol = ISDN_PID_NONE; + bch->state = ISDN_PID_NONE; if (card->pots && (bhw->b_mode & W_B_MODE_EPCM)) disable_pots(bch); bhw->b_mode = 0; - bch->tx_len = 0; bch->tx_idx = 0; - bch->rx_idx = 0; if (bch->next_skb) { dev_kfree_skb(bch->next_skb); bch->next_skb = NULL; } - discard_queue(&bch->rqueue); + if (bch->tx_skb) { + dev_kfree_skb(bch->tx_skb); + bch->tx_skb = NULL; + } + if (bch->rx_skb) { + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode); WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_XRST); + 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; bhw->b_mode = W_B_MODE_MMS; WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode); WriteW6692B(card, bch->channel, W_B_EXIM, 0); WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST); - 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; bhw->b_mode = W_B_MODE_ITF; WriteW6692B(card, bch->channel, W_B_MODE, bhw->b_mode); WriteW6692B(card, bch->channel, W_B_ADM1, 0xff); WriteW6692B(card, bch->channel, W_B_ADM2, 0xff); WriteW6692B(card, bch->channel, W_B_EXIM, 0); WriteW6692B(card, bch->channel, W_B_CMDR, W_B_CMDR_RRST | W_B_CMDR_RACT | W_B_CMDR_XRST); - 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); @@ -635,36 +653,40 @@ mode_w6692(bchannel_t *bch, int bc, int protocol) } static void -send_next(bchannel_t *bch) +send_next(channel_t *bch) { - if (bch->protocol == ISDN_PID_NONE) + if (test_bit(FLG_ACTIVE, &bch->Flags)) return; - if (bch->tx_idx < bch->tx_len) + if (bch->tx_skb && bch->tx_idx < bch->tx_skb->len) W6692_fill_Bfifo(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); W6692_fill_Bfifo(bch); } else { - bch->tx_len = 0; + test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); printk(KERN_WARNING "W6692 tx irq TX_NEXT without skb\n"); - test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag); + 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 W6692B_interrupt(w6692pci *card, int ch) { - bchannel_t *bch = &card->bch[ch]; + channel_t *bch = &card->bch[ch]; int count; u_char stat, star = 0; struct sk_buff *skb; @@ -676,47 +698,60 @@ W6692B_interrupt(w6692pci *card, int ch) if (stat & W_B_EXI_RME) { star = ReadW6692B(card, ch, W_B_STAR); if (star & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { - if ((star & W_B_STAR_RDOV) && (bch->protocol != ISDN_PID_NONE)) { + if ((star & W_B_STAR_RDOV) && test_bit(FLG_ACTIVE, &bch->Flags)) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "B%d RDOV protocol=%x", - ch +1, bch->protocol); + ch +1, bch->state); #ifdef ERROR_STATISTIC bch->err_rdo++; #endif } - if ((star & W_B_STAR_CRCE) && (bch->protocol == ISDN_PID_L1_B_64HDLC)) { - if (bch->debug & L1_DEB_WARN) - mISDN_debugprint(&bch->inst, "B%d CRC error", ch +1); + if (test_bit(FLG_HDLC, &bch->Flags)) { + if (star & W_B_STAR_CRCE) { + if (bch->debug & L1_DEB_WARN) + mISDN_debugprint(&bch->inst, + "B%d CRC error", ch+1); #ifdef ERROR_STATISTIC - bch->err_crc++; + bch->err_crc++; #endif - } - if ((star & W_B_STAR_RMB) && (bch->protocol == ISDN_PID_L1_B_64HDLC)) { - if (bch->debug & L1_DEB_WARN) - mISDN_debugprint(&bch->inst, "B%d message abort", ch +1); + } + if (star & W_B_STAR_RMB) { + if (bch->debug & L1_DEB_WARN) + mISDN_debugprint(&bch->inst, + "B%d message abort", ch+1); #ifdef ERROR_STATISTIC - bch->err_inv++; + bch->err_inv++; #endif + } } WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); + if (bch->rx_skb) + skb_trim(bch->rx_skb, 0); } else { count = ReadW6692B(card, ch, W_B_RBCL) & (W_B_FIFO_THRESH - 1); if (count == 0) count = W_B_FIFO_THRESH; W6692_empty_Bfifo(bch, count); - if (bch->rx_idx > 0) { + if (bch->rx_skb && bch->rx_skb->len > 0) { if (bch->debug & L1_DEB_HSCX) - mISDN_debugprint(&bch->inst, "Bchan Frame %d", bch->rx_idx); - if (!(skb = alloc_stack_skb(bch->rx_idx, bch->up_headerlen))) - printk(KERN_WARNING "Bchan 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); + mISDN_debugprint(&bch->inst, "Bchan Frame %d", bch->rx_skb->len); + 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_sched_event(bch, B_RCVBUFREADY); + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, skb); } } - bch->rx_idx = 0; } if (stat & W_B_EXI_RMR) { if (!(stat & W_B_EXI_RME)) @@ -724,25 +759,21 @@ W6692B_interrupt(w6692pci *card, int ch) if (star & W_B_STAR_RDOV) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "B%d RDOV protocol=%x", - ch +1, bch->protocol); + ch +1, bch->state); #ifdef ERROR_STATISTIC bch->err_rdo++; #endif WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); } else { W6692_empty_Bfifo(bch, W_B_FIFO_THRESH); - if ((bch->protocol == ISDN_PID_L1_B_64TRANS) && (bch->rx_idx > 0)) { + if (test_bit(FLG_TRANSPARENT, &bch->Flags) && + bch->rx_skb && (bch->rx_skb->len > 0)) { /* receive audio data */ if (bch->debug & L1_DEB_HSCX) - mISDN_debugprint(&bch->inst, "Bchan Frame %d", bch->rx_idx); - if (!(skb = alloc_stack_skb(bch->rx_idx, bch->up_headerlen))) - printk(KERN_WARNING "Bchan 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); - } - bch_sched_event(bch, B_RCVBUFREADY); - bch->rx_idx = 0; + mISDN_debugprint(&bch->inst, + "Bchan Frame %d", bch->rx_skb->len); + queue_ch_frame(bch, INDICATION, MISDN_ID_ANY, bch->rx_skb); + bch->rx_skb = NULL; } } } @@ -750,7 +781,7 @@ W6692B_interrupt(w6692pci *card, int ch) if (!(star & W_B_STAR_RDOV)) { /* only if it is not handled yet */ if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "B%d RDOV IRQ protocol=%x", - ch +1, bch->protocol); + ch +1, bch->state); #ifdef ERROR_STATISTIC bch->err_rdo++; #endif @@ -766,14 +797,14 @@ W6692B_interrupt(w6692pci *card, int ch) if (star & W_B_STAR_XDOW) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "B%d XDOW protocol=%x", - ch +1, bch->protocol); + ch +1, bch->state); #ifdef ERROR_STATISTIC bch->err_xdu++; #endif WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); /* resend */ - if (bch->tx_len) { - if (bch->protocol != ISDN_PID_L1_B_64TRANS) + if (bch->tx_skb) { + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) bch->tx_idx = 0; } } @@ -784,14 +815,14 @@ W6692B_interrupt(w6692pci *card, int ch) if (stat & W_B_EXI_XDUN) { if (bch->debug & L1_DEB_WARN) mISDN_debugprint(&bch->inst, "B%d XDUN protocol=%x", - ch +1, bch->protocol); + ch +1, bch->state); #ifdef ERROR_STATISTIC bch->err_xdu++; #endif WriteW6692B(card, ch, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); /* resend */ - if (bch->tx_len) { - if (bch->protocol != ISDN_PID_L1_B_64TRANS) + if (bch->tx_skb) { + if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) bch->tx_idx = 0; } send_next(bch); @@ -802,47 +833,16 @@ static irqreturn_t w6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) { w6692pci *card = dev_id; - u_long flags; u_char ista; - spin_lock_irqsave(&card->lock.lock, flags); -#ifdef SPIN_DEBUG - card->lock.spin_adr = (void *)0x2001; -#endif + spin_lock(&card->lock); ista = ReadW6692(card, W_ISTA); if ((ista | card->imask) == card->imask) { /* possible a shared IRQ reqest */ -#ifdef SPIN_DEBUG - card->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&card->lock.lock, flags); + spin_unlock(&card->lock); return IRQ_NONE; } card->irqcnt++; - if (test_and_set_bit(STATE_FLAG_BUSY, &card->lock.state)) { - printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%lx\n", - __FUNCTION__, card->lock.state); -#ifdef SPIN_DEBUG - printk(KERN_ERR "%s: previous lock:%p\n", - __FUNCTION__, card->lock.busy_adr); -#endif -#ifdef LOCK_STATISTIC - card->lock.irq_fail++; -#endif - } else { -#ifdef LOCK_STATISTIC - card->lock.irq_ok++; -#endif -#ifdef SPIN_DEBUG - card->lock.busy_adr = w6692_interrupt; -#endif - } - - test_and_set_bit(STATE_FLAG_INIRQ, &card->lock.state); -#ifdef SPIN_DEBUG - card->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&card->lock.lock, flags); /* Begin IRQ handler */ if (card->dch.debug & L1_DEB_ISAC) mISDN_debugprint(&card->dch.inst, "ista %02x", ista); @@ -862,46 +862,29 @@ w6692_interrupt(int intno, void *dev_id, struct pt_regs *regs) if (ista & (W_INT_XINT0 | W_INT_XINT1)) /* XINT0/1 - never */ mISDN_debugprint(&card->dch.inst, "W6692 spurious XINT!"); /* End IRQ Handler */ - spin_lock_irqsave(&card->lock.lock, flags); -#ifdef SPIN_DEBUG - card->lock.spin_adr = (void *)0x2002; -#endif - if (!test_and_clear_bit(STATE_FLAG_INIRQ, &card->lock.state)) { - } - if (!test_and_clear_bit(STATE_FLAG_BUSY, &card->lock.state)) { - printk(KERN_ERR "%s: STATE_FLAG_BUSY not locked state(%lx)\n", - __FUNCTION__, card->lock.state); - } -#ifdef SPIN_DEBUG - card->lock.busy_adr = NULL; - card->lock.spin_adr = NULL; -#endif - spin_unlock_irqrestore(&card->lock.lock, flags); + spin_unlock(&card->lock); return IRQ_HANDLED; } static void -dbusy_timer_handler(dchannel_t *dch) +dbusy_timer_handler(channel_t *dch) { w6692pci *card = dch->hw; - int rbch, star; + 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; - } + if (test_bit(FLG_BUSY_TIMER, &dch->Flags)) { + spin_lock_irqsave(dch->inst.hwlock, flags); rbch = ReadW6692(card, W_D_RBCH); star = ReadW6692(card, W_D_STAR); if (dch->debug) mISDN_debugprint(&dch->inst, "D-Channel Busy RBCH %02x STAR %02x", rbch, star); if (star & W_D_STAR_XBZ) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &dch->DFlags); + 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 { @@ -911,7 +894,7 @@ dbusy_timer_handler(dchannel_t *dch) /* Transmitter reset */ WriteW6692(card, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */ } - dch->inst.unlock(dch->inst.data); + spin_unlock_irqrestore(dch->inst.hwlock, flags); } } @@ -919,23 +902,21 @@ void initW6692(w6692pci *card) { u_char val; - card->dch.hw_bh = W6692_new_ph; - card->dch.dbusytimer.function = (void *) dbusy_timer_handler; - card->dch.dbusytimer.data = (u_long) &card->dch; - init_timer(&card->dch.dbusytimer); + card->dch.timer.function = (void *) dbusy_timer_handler; + card->dch.timer.data = (u_long) &card->dch; + init_timer(&card->dch.timer); mode_w6692(&card->bch[0], 0, -1); mode_w6692(&card->bch[1], 1, -1); WriteW6692(card, W_D_CTL, 0x00); - WriteW6692(card, W_IMASK, 0xff); + disable_hwirq(card); WriteW6692(card, W_D_SAM, 0xff); WriteW6692(card, W_D_TAM, 0xff); WriteW6692(card, W_D_MODE, W_D_MODE_RACT); - card->dch.ph_state = W_L1CMD_RST; + card->dch.state = W_L1CMD_RST; ph_command(card, W_L1CMD_RST); ph_command(card, W_L1CMD_ECK); - /* Reenable all IRQ */ + /* enable all IRQ but extern */ card->imask = 0x18; - WriteW6692(card, W_IMASK, card->imask); WriteW6692(card, W_D_EXIM, 0x00); WriteW6692B(card, 0, W_B_EXIM, 0); WriteW6692B(card, 1, W_B_EXIM, 0); @@ -971,20 +952,21 @@ static void reset_w6692(w6692pci *card) static int init_card(w6692pci *card) { - int cnt = 3; + int cnt = 3; + u_long flags; - lock_dev(card, 0); - if (request_irq(card->irq, w6692_interrupt, SA_SHIRQ, - "w6692", card)) { - printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", - card->irq); - unlock_dev(card); + spin_lock_irqsave(&card->lock, flags); + disable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); + if (request_irq(card->irq, w6692_interrupt, SA_SHIRQ, "w6692", card)) { + printk(KERN_WARNING "mISDN: couldn't get interrupt %d\n", card->irq); return(-EIO); } + spin_lock_irqsave(&card->lock, flags); while (cnt) { initW6692(card); - /* RESET Receiver and Transmitter */ - unlock_dev(card); + enable_hwirq(card); + spin_unlock_irqrestore(&card->lock, flags); /* Timeout 10ms */ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout((10*HZ)/1000); @@ -997,15 +979,15 @@ static int init_card(w6692pci *card) if (cnt == 1) { return (-EIO); } else { + spin_lock_irqsave(&card->lock, flags); reset_w6692(card); cnt--; } } else { return(0); } - lock_dev(card, 0); } - unlock_dev(card); + spin_unlock_irqrestore(&card->lock, flags); return(-EIO); } @@ -1036,84 +1018,63 @@ MODULE_PARM(layermask, MODULE_PARM_T); /* Layer2 -> Layer 1 Transfer */ /******************************/ static int -w6692_l2l1B(mISDNif_t *hif, struct sk_buff *skb) +w6692_bmsg(channel_t *bch, struct sk_buff *skb) { - bchannel_t *bch; - int ret = -EINVAL; - mISDN_head_t *hh; + 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) { - printk(KERN_WARNING "%s: next_skb exist ERROR\n", - __FUNCTION__); - 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; - W6692_fill_Bfifo(bch); - bch->inst.unlock(bch->inst.data); - if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) - && bch->dev) - hif = &bch->dev->rport.pif; - else - hif = &bch->inst.up; - skb_trim(skb, 0); - return(if_newhead(hif, hh->prim | CONFIRM, - hh->dinfo, skb)); - } - } else if ((hh->prim == (PH_ACTIVATE | REQUEST)) || + 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); + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { + spin_lock_irqsave(bch->inst.hwlock, flags); ret = mode_w6692(bch, bch->channel, bch->inst.pid.protocol[1]); - bch->inst.unlock(bch->inst.data); + spin_unlock_irqrestore(bch->inst.hwlock, flags); } +#ifdef FIXME if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) if (bch->dev) if_link(&bch->dev->rport.pif, hh->prim | CONFIRM, 0, 0, NULL, 0); +#endif skb_trim(skb, 0); - return(if_newhead(&bch->inst.up, hh->prim | CONFIRM, ret, skb)); + return(mISDN_queueup_newhead(&bch->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(bch->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; + } + if (bch->rx_skb) { + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); mode_w6692(bch, bch->channel, ISDN_PID_NONE); - 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(bch->inst.hwlock, flags); skb_trim(skb, 0); - if (hh->prim != (MGR_DISCONNECT | REQUEST)) { + if (hh->prim != (PH_CONTROL | REQUEST)) { +#ifdef FIXME if (bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV) if (bch->dev) if_link(&bch->dev->rport.pif, hh->prim | CONFIRM, 0, 0, NULL, 0); - if (!if_newhead(&bch->inst.up, hh->prim | CONFIRM, 0, skb)) +#endif + if (!mISDN_queueup_newhead(&bch->inst, 0, + hh->prim | CONFIRM, 0, skb)) return(0); } - ret = 0; } else if (hh->prim == (PH_CONTROL | REQUEST)) { - ret = 0; - bch->inst.lock(bch->inst.data, 0); + spin_lock_irqsave(bch->inst.hwlock, flags); if (hh->dinfo == HW_POTS_ON) { ret = enable_pots(bch); } else if (hh->dinfo == HW_POTS_OFF) { @@ -1124,77 +1085,60 @@ w6692_l2l1B(mISDNif_t *hif, struct sk_buff *skb) ret = setvolume(bch, 0, skb); } else ret = -EINVAL; - bch->inst.unlock(bch->inst.data); - } else { - printk(KERN_WARNING "%s: unknown prim(%x)\n", - __FUNCTION__, hh->prim); - } + spin_unlock_irqrestore(bch->inst.hwlock, flags); + } else + ret = -EAGAIN; if (!ret) dev_kfree_skb(skb); return(ret); } static int -w6692_l1hwD(mISDNif_t *hif, struct sk_buff *skb) +w6692_dmsg(channel_t *dch, struct sk_buff *skb) { - dchannel_t *dch; - int ret = -EINVAL; - mISDN_head_t *hh; + int ret = 0; + mISDN_head_t *hh = mISDN_HEAD_P(skb); + u_long flags; - if (!hif || !skb) - return(ret); - hh = mISDN_HEAD_P(skb); - dch = hif->fdata; - ret = 0; - if (hh->prim == PH_DATA_REQ) { - if (dch->next_skb) { - mISDN_debugprint(&dch->inst, "w6692 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; - W6692_fill_Dfifo(dch->hw); - dch->inst.unlock(dch->inst.data); - return(if_newhead(&dch->inst.up, PH_DATA_CNF, - hh->dinfo, skb)); - } - } else if (hh->prim == (PH_SIGNAL | REQUEST)) { - dch->inst.lock(dch->inst.data,0); + if (hh->prim == (PH_SIGNAL | REQUEST)) { + spin_lock_irqsave(dch->inst.hwlock, flags); if (hh->dinfo == INFO3_P8) ph_command(dch->hw, W_L1CMD_AR8); else if (hh->dinfo == INFO3_P10) ph_command(dch->hw, W_L1CMD_AR10); else ret = -EINVAL; - dch->inst.unlock(dch->inst.data); + spin_unlock_irqrestore(dch->inst.hwlock, flags); } else if (hh->prim == (PH_CONTROL | REQUEST)) { - dch->inst.lock(dch->inst.data,0); + spin_lock_irqsave(dch->inst.hwlock, flags); if (hh->dinfo == HW_RESET) { - if (dch->ph_state != W_L1IND_DRD) + if (dch->state != W_L1IND_DRD) ph_command(dch->hw, W_L1CMD_RST); ph_command(dch->hw, W_L1CMD_ECK); } else if (hh->dinfo == HW_POWERUP) { ph_command(dch->hw, W_L1CMD_ECK); } 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)) + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + 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); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) dchannel_sched_event(dch, D_CLEARBUSY); +#endif } else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) { u_char val = 0; @@ -1205,15 +1149,51 @@ w6692_l1hwD(mISDNif_t *hif, struct sk_buff *skb) /* !!! not implemented yet */ } else { if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "w6692_l1hw unknown ctrl %x", + mISDN_debugprint(&dch->inst, "w6692_dmsg unknown ctrl %x", hh->dinfo); ret = -EINVAL; } - dch->inst.unlock(dch->inst.data); - } else { - if (dch->debug & L1_DEB_WARN) - mISDN_debugprint(&dch->inst, "w6692_l1hw unknown prim %x", - hh->prim); + spin_unlock_irqrestore(dch->inst.hwlock, flags); + } else + ret = -EAGAIN; + if (!ret) + dev_kfree_skb(skb); + return(ret); +} + +static int +w6692_l2l1(mISDNinstance_t *inst, struct sk_buff *skb) +{ + channel_t *chan = container_of(inst, channel_t, inst); + int ret = 0; + mISDN_head_t *hh = mISDN_HEAD_P(skb); + u_long flags; + + if ((hh->prim == PH_DATA_REQ) || (hh->prim == DL_DATA_REQ)) { + spin_lock_irqsave(inst->hwlock, flags); + ret = channel_senddata(chan, hh->dinfo, skb); + if (ret > 0) { /* direct TX */ + if (test_bit(FLG_BCHANNEL, &chan->Flags)) + W6692_fill_Dfifo(chan->hw); + else if (test_bit(FLG_DCHANNEL, &chan->Flags)) + W6692_fill_Bfifo(chan); + else + int_error(); + ret = 0; + } + spin_unlock_irqrestore(inst->hwlock, flags); + return(ret); + } + if (test_bit(FLG_DCHANNEL, &chan->Flags)) { + ret = w6692_dmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); + ret = -EINVAL; + } + if (test_bit(FLG_BCHANNEL, &chan->Flags)) { + ret = w6692_bmsg(chan, skb); + if (ret != -EAGAIN) + return(ret); ret = -EINVAL; } if (!ret) @@ -1225,6 +1205,7 @@ int __init setup_w6692(w6692pci *card) { u_int val; + if (!request_region(card->addr, 256, "w6692")) { printk(KERN_WARNING "mISDN: %s config port %x-%x already in use\n", @@ -1255,16 +1236,13 @@ setup_w6692(w6692pci *card) static void release_card(w6692pci *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); - /* disable all IRQ */ - WriteW6692(card, W_IMASK, 0xff); + u_long flags; + + 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); mode_w6692(&card->bch[0], 0, ISDN_PID_NONE); mode_w6692(&card->bch[1], 1, ISDN_PID_NONE); if (card->led) { @@ -1272,13 +1250,14 @@ release_card(w6692pci *card) WriteW6692(card, W_XDATA, card->xdata); } release_region(card->addr, 256); - mISDN_free_bch(&card->bch[1]); - mISDN_free_bch(&card->bch[0]); - mISDN_free_dch(&card->dch); - w6692.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); w6692.ctrl(&card->dch.inst, MGR_UNREGLAYER | REQUEST, NULL); + spin_lock_irqsave(&w6692.lock, flags); list_del(&card->list); - unlock_dev(card); + spin_unlock_irqrestore(&w6692.lock, flags); pci_disable_device(card->pdev); pci_set_drvdata(card->pdev, NULL); kfree(card); @@ -1290,6 +1269,7 @@ w6692_manager(void *data, u_int prim, void *arg) { mISDNinstance_t *inst = data; struct sk_buff *skb; int channel = -1; + u_long flags; if (debug & 0x10000) printk(KERN_DEBUG "%s: data(%p) prim(%x) arg(%p)\n", @@ -1300,6 +1280,7 @@ w6692_manager(void *data, u_int prim, void *arg) { __FUNCTION__, prim, arg); return(-EINVAL); } + spin_lock_irqsave(&w6692.lock, flags); list_for_each_entry(card, &w6692.ilist, list) { if (&card->dch.inst == inst) { channel = 2; @@ -1314,6 +1295,7 @@ w6692_manager(void *data, u_int prim, void *arg) { break; } } + spin_unlock_irqrestore(&w6692.lock, flags); if (channel<0) { printk(KERN_WARNING "%s: no channel data %p prim %x arg %p\n", __FUNCTION__, data, prim, arg); @@ -1323,36 +1305,26 @@ w6692_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 (w6692_l1hwD(&inst->down, 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 (w6692_l2l1B(&inst->down, skb)) - dev_kfree_skb(skb); - } - } - w6692.ctrl(inst->up.peer, MGR_DISCONNECT | REQUEST, &inst->up); + if ((skb = create_link_skb(PH_CONTROL | REQUEST, + HW_DEACTIVATE, 0, NULL, 0))) { + if (w6692_l2l1(inst, skb)) + dev_kfree_skb(skb); + } else + printk(KERN_WARNING "no SKB in %s MGR_UNREGLAYER | REQUEST\n", __FUNCTION__); w6692.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) { @@ -1361,33 +1333,18 @@ w6692_manager(void *data, u_int prim, void *arg) { w6692.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, w6692_l1hwD, NULL, - &card->dch)); - else - return(mISDN_SetIF(inst, arg, prim, w6692_l2l1B, 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 (w6692_l2l1B(&inst->down, skb)) + if (w6692_l2l1(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; @@ -1417,28 +1374,31 @@ static int __devinit setup_instance(w6692pci *card) { int i, err; mISDN_pid_t pid; + u_long flags; + spin_lock_irqsave(&w6692.lock, flags); list_add_tail(&card->list, &w6692.ilist); + spin_unlock_irqrestore(&w6692.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 = &card->pdev->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, &w6692, card); + mISDN_init_instance(&card->dch.inst, &w6692, card, w6692_l2l1); sprintf(card->dch.inst.name, "W6692_%d", w6692_cnt+1); mISDN_set_dchannel_pid(&pid, protocol[w6692_cnt], layermask[w6692_cnt]); - mISDN_init_dch(&card->dch); + mISDN_initchannel(&card->dch, MSK_INIT_DCHANNEL, MAX_DFRAME_LEN_L1); card->dch.hw = card; for (i=0; i<2; i++) { card->bch[i].channel = i; - mISDN_init_instance(&card->bch[i].inst, &w6692, card); + mISDN_init_instance(&card->bch[i].inst, &w6692, card, w6692_l2l1); 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 = &card->pdev->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->wbc[i]; } if (debug) @@ -1446,9 +1406,9 @@ static int __devinit setup_instance(w6692pci *card) card, &card->dch, &card->bch[0], &card->bch[1]); err = setup_w6692(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]); list_del(&card->list); kfree(card); return(err); @@ -1565,6 +1525,7 @@ static int __init w6692_init(void) #ifdef MODULE w6692.owner = THIS_MODULE; #endif + spin_lock_init(&w6692.lock); INIT_LIST_HEAD(&w6692.ilist); w6692.name = W6692Name; w6692.own_ctrl = w6692_manager; diff --git a/drivers/isdn/hardware/mISDN/x25_dte.c b/drivers/isdn/hardware/mISDN/x25_dte.c index d27d41d..44e17ec 100644 --- a/drivers/isdn/hardware/mISDN/x25_dte.c +++ b/drivers/isdn/hardware/mISDN/x25_dte.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/x25_l3.c b/drivers/isdn/hardware/mISDN/x25_l3.c index 3533f9e..f86d10a 100644 --- a/drivers/isdn/hardware/mISDN/x25_l3.c +++ b/drivers/isdn/hardware/mISDN/x25_l3.c @@ -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); diff --git a/drivers/isdn/hardware/mISDN/x25_l3.h b/drivers/isdn/hardware/mISDN/x25_l3.h index 1870d3d..eff0dd4 100644 --- a/drivers/isdn/hardware/mISDN/x25_l3.h +++ b/drivers/isdn/hardware/mISDN/x25_l3.h @@ -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 *); diff --git a/include/linux/isdn_compat.h b/include/linux/isdn_compat.h index b2076ad..ba21bd8 100644 --- a/include/linux/isdn_compat.h +++ b/include/linux/isdn_compat.h @@ -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 */ diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h index e6af616..9d95c44 100644 --- a/include/linux/mISDNif.h +++ b/include/linux/mISDNif.h @@ -9,16 +9,6 @@ #include #include -/* 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<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 */ diff --git a/std2kern b/std2kern index 1b1189d..a0f572a 100755 --- a/std2kern +++ b/std2kern @@ -1,6 +1,6 @@ #!/bin/sh -KERNELDIR=/usr/src/linux +KERNELDIR=/lib/modules/$(uname -r)/build PREPARSER="./preparser" UNIQUE=false VERBOSE=false @@ -224,6 +224,23 @@ while getopts :dhk:uc:vtidr a ; do done shift `expr $OPTIND - 1` +echo +echo "BE AWARE!!" +echo +echo "You are just attempting to overwrite your Kernel mISDN Sources" +echo "you probably prefer to use make install." +echo +echo "KERNELDIR=$KERNELDIR" +ls -ld $KERNELDIR +echo +echo "If you still want to patch this Kernel just answer yes:" +read i + +if [ ! $i == "yes" ] ; then + echo "OK exiting" + exit 1 +fi + if [ -z "$VERSION" -o -z "$PATCHLEVEL" ] ; then if ! [ -f $KERNELDIR/Makefile ] ; then echo "VERSION/PATCHLEVEL not set and no Makefile to read from" diff --git a/stddiff b/stddiff index d867bbc..07ba590 100755 --- a/stddiff +++ b/stddiff @@ -1,6 +1,6 @@ #!/bin/sh -KERNELDIR=/usr/src/linux +KERNELDIR=/lib/modules/$(uname -r)/build KERNFIRST=false PREPARSER="./preparser" DODIFF=dodiff