latest source from my side, no change to hfc_multi

Modified Files:
 Tag: mqueue
	mISDN/drivers/isdn/hardware/mISDN/dsp.h
	mISDN/drivers/isdn/hardware/mISDN/dsp_cmx.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_core.c
	mISDN/drivers/isdn/hardware/mISDN/dsp_tones.c
	mISDN/drivers/isdn/hardware/mISDN/hfc_multi.c
This commit is contained in:
Andreas Eversberg 2005-10-18 21:51:36 +00:00
parent 82d37c7fc3
commit b914ab29eb
5 changed files with 191 additions and 193 deletions

View File

@ -29,11 +29,9 @@
#define DSP_OPT_ULAW (1<<0)
#define DSP_OPT_NOHARDWARE (1<<1)
#ifdef HAS_WORKQUEUE
#include <linux/workqueue.h>
#else
#include <linux/tqueue.h>
#endif
#define FEAT_STATE_INIT 1
#define FEAT_STATE_WAIT 2
#include <linux/timer.h>
#ifdef MISDN_MEMDEBUG
@ -159,8 +157,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;
@ -182,6 +178,8 @@ typedef struct _dsp {
/* 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;

View File

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

View File

@ -153,9 +153,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.
@ -197,42 +194,6 @@ 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
@ -395,12 +356,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 +372,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,23 +382,26 @@ 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;
if (!hif || !hif->fdata || !skb)
if (!skb)
return(-EINVAL);
dsp = hif->fdata;
if (!dsp->inst.down.func)
return(-ENXIO);
dsp = inst->privat;
if (!dsp) {
dev_kfree_skb(skb);
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:
@ -448,6 +410,7 @@ dsp_from_up(mISDNif_t *hif, struct sk_buff *skb)
if (!dsp->tone.tone)
dsp_cmx_transmit(dsp, skb);
unlock_HW(&dsp_lock);
dev_kfree_skb(skb);
break;
case PH_CONTROL | REQUEST:
lock_HW(&dsp_lock, 0);
@ -459,32 +422,30 @@ dsp_from_up(mISDNif_t *hif, struct sk_buff *skb)
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);
unlock_HW(&dsp_lock);
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);
unlock_HW(&dsp_lock);
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 +454,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;
@ -502,11 +463,13 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
int cont;
struct sk_buff *nskb;
if (!hif || !hif->fdata || !skb)
if (!skb)
return(-EINVAL);
dsp = hif->fdata;
if (!dsp->inst.up.func)
return(-ENXIO);
dsp = inst->privat;
if (!dsp) {
dev_kfree_skb(skb);
return(-EIO);
}
hh = mISDN_HEAD_P(skb);
switch(hh->prim)
@ -530,14 +493,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++;
}
}
@ -556,19 +513,37 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
|| 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);
// NOTE: b_active will be importaint to trigger sending by a forthcoming dsp clock.
if (dsp->b_active) {
/* get data from cmx */
nskb = dsp_cmx_send(dsp, skb->len, 0);
if (!nskb) {
dev_kfree_skb(skb);
printk(KERN_ERR "%s: failed to create tx packet\n", __FUNCTION__);
}
/* 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 */
if (mISDN_queue_down(&dsp->inst, 0, nskb)) {
dev_kfree_skb(nskb);
printk(KERN_ERR "%s: failed to send tx packet\n", __FUNCTION__);
}
}
}
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);
unlock_HW(&dsp_lock);
break;
case PH_CONTROL | INDICATION:
lock_HW(&dsp_lock, 0);
if (dsp_debug & DEBUG_DSP_DTMFCOEFF)
@ -578,28 +553,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:
@ -621,17 +590,13 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
dsp->W_rx = dsp->R_rx = dsp->conf->W_max;
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
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;
ret = mISDN_queue_up(&dsp->inst, 0, skb);
unlock_HW(&dsp_lock);
return(dsp->inst.up.func(&dsp->inst.up, skb));
break;
case PH_DEACTIVATE | CONFIRM:
lock_HW(&dsp_lock, 0);
if (dsp_debug & DEBUG_DSP_CORE)
@ -640,15 +605,37 @@ dsp_from_down(mISDNif_t *hif, struct sk_buff *skb)
dsp->b_active = 0;
dsp_cmx_hardware(dsp->conf, dsp);
hh->prim = DL_RELEASE | CONFIRM;
ret = mISDN_queue_up(&dsp->inst, 0, skb);
unlock_HW(&dsp_lock);
return(dsp->inst.up.func(&dsp->inst.up, 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);
}
@ -663,15 +650,10 @@ release_dsp(dsp_t *dsp)
conference_t *conf;
lock_HW(&dsp_lock, 0);
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,17 +664,6 @@ 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);
@ -705,6 +676,48 @@ 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
*/
@ -725,8 +738,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;
@ -736,8 +748,6 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
}
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
/* set frame size to start */
ndsp->largest = 64 << 1;
@ -753,8 +763,14 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
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);
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);
}
lock_HW(&dsp_lock, 0);
/* append and register */
list_add_tail(&ndsp->list, &dsp_obj.ilist);
@ -772,39 +788,6 @@ new_dsp(mISDNstack_t *st, mISDN_pid_t *pid)
}
/*
* 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
*/
@ -833,9 +816,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 +830,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)

View File

@ -437,7 +437,7 @@ dsp_tone_hw_message(dsp_t *dsp, u8 *sample, int len)
return;
}
/* unlocking is not required, because we don't expect a response */
if (dsp->inst.down.func(&dsp->inst.down, nskb))
if (mISDN_queue_down(&dsp->inst, 0, nskb))
dev_kfree_skb(nskb);
}

View File

@ -2,7 +2,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)
@ -26,9 +28,6 @@
* Thanx to Cologne Chip AG for this great controller!
*/
// warning Experimental version!! This version supports the new mqueue mechanisnm
// changings by Peter Sprenger (sprengermoving-bytes.de)
/* module parameters:
* type:
Value 1 = HFC-E1 (1 port) 0x01
@ -116,7 +115,11 @@ static void ph_state_change(dchannel_t *dch);
extern const char *CardType[];
<<<<<<< hfc_multi.c
static const char *hfcmulti_revision = "$Revision$";
=======
static const char *hfcmulti_revision = "$Revision$";
>>>>>>> 1.23.2.9
static int HFC_cnt, HFC_idx;
@ -2803,8 +2806,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;
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);
@ -3057,17 +3062,6 @@ release_port(hfc_multi_t *hc, int port)
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__);
@ -3130,8 +3124,10 @@ release_port(hfc_multi_t *hc, int port)
kfree(hc->chan[i].dch);
hc->chan[i].dch = NULL;
}
kfree(hc->chan[i].rx_buf);
hc->chan[i].rx_buf = 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);
@ -3155,14 +3151,30 @@ 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);
/* 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 is from list and delete */
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_WARNING "%s: remove instance from list\n", __FUNCTION__);
list_del(&hc->list);
unlock_dev(hc);
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_WARNING "%s: delete instance\n", __FUNCTION__);
kfree(hc);
HFC_cnt--;
if (debug & DEBUG_HFCMULTI_INIT)
printk(KERN_WARNING "%s: card successfully removed\n", __FUNCTION__);
} else
unlock_dev(hc);
}
@ -3753,8 +3765,10 @@ static int __devinit hfcpci_probe(struct pci_dev *pdev, const struct pci_device_
kfree(hc->chan[i].dch);
hc->chan[i].dch = NULL;
}
kfree(hc->chan[i].rx_buf);
hc->chan[i].rx_buf = 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);