- doc locking

- bchannel helper functions
This commit is contained in:
Karsten Keil 2003-06-22 10:39:43 +00:00
parent 8293963b8e
commit ac037381e8
9 changed files with 309 additions and 327 deletions

View File

@ -11,11 +11,11 @@ O_TARGET := vmlinux-obj.o
# multi objects
SEDLFAXOBJ := sedl_fax.o debug.o helper.o fsm.o isar.o hisax_dch.o
SEDLFAXOBJ := sedl_fax.o debug.o helper.o fsm.o isar.o hisax_dch.o hisax_bch.o
FRITZOBJ := fritz_pci.o debug.o helper.o fsm.o hisax_dch.o
FRITZOBJ := fritz_pci.o debug.o helper.o fsm.o hisax_dch.o hisax_bch.o
HFC_PCIOBJ := hfc_pci.o debug.o helper.o hisax_dch.o
HFC_PCIOBJ := hfc_pci.o debug.o helper.o hisax_dch.o hisax_bch.o
hisaxisac-objs := isac.o arcofi.o debug.o

View File

@ -701,52 +701,9 @@ hdlc_down(hisaxif_t *hif, struct sk_buff *skb)
return(ret);
}
static void
hdlc_bh(bchannel_t *bch)
{
struct sk_buff *skb;
u_int pr;
int ret;
if (!bch)
return;
if (!bch->inst.up.func) {
printk(KERN_WARNING "HiSax: hdlc_bh without up.func\n");
return;
}
if (test_and_clear_bit(B_XMTBUFREADY, &bch->event)) {
skb = bch->next_skb;
if (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 (if_newhead(&bch->inst.up, pr, DINFO_SKB, skb))
dev_kfree_skb(skb);
}
}
if (test_and_clear_bit(B_RCVBUFREADY, &bch->event)) {
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(&bch->inst.up, pr, DINFO_SKB, skb);
if (ret < 0) {
printk(KERN_WARNING "hdlc_bh deliver err %d\n",
ret);
dev_kfree_skb(skb);
}
}
}
}
static void
inithdlc(fritzpnppci *fc)
{
fc->bch[0].tqueue.routine = (void *) (void *) hdlc_bh;
fc->bch[1].tqueue.routine = (void *) (void *) hdlc_bh;
modehdlc(&fc->bch[0], 0, -1);
modehdlc(&fc->bch[1], 1, -1);
}

View File

@ -0,0 +1,150 @@
/* $Id$
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#define __NO_VERSION__
#include <linux/hisaxif.h>
#include "hisaxl1.h"
#include "hisax_bch.h"
#include "helper.h"
static void
bchannel_bh(bchannel_t *bch)
{
struct sk_buff *skb;
u_int pr;
int ret;
hisax_head_t *hh;
hisaxif_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 = HISAX_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, DINFO_SKB, 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
init_bchannel(bchannel_t *bch) {
int devtyp = HISAX_RAW_DEVICE;
if (!(bch->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for blog\n");
return(-ENOMEM);
}
if (!(bch->rx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: 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
"HiSax: 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;
bch->tqueue.data = bch;
bch->tqueue.routine = (void *) (void *) bchannel_bh;
bch->hw_bh = NULL;
if (!bch->dev) {
if (bch->inst.obj->ctrl(&bch->dev, MGR_GETDEVICE | REQUEST,
&devtyp)) {
printk(KERN_WARNING
"HiSax: no raw device for bchannel\n");
}
}
return(0);
}
int
free_bchannel(bchannel_t *bch) {
if (bch->tqueue.sync)
printk(KERN_ERR"free_bchannel tqueue.sync\n");
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
"HiSax: del raw device error\n");
} else
bch->dev = NULL;
return(0);
}

View File

@ -60,6 +60,7 @@ typedef struct _bchannel_t {
u_char *conmsg;
struct timer_list transbusy;
struct tq_struct tqueue;
void (*hw_bh) (struct _bchannel_t *);
int event;
int err_crc;
int err_tx;

View File

@ -13,23 +13,11 @@
#include "hisax_dch.h"
static void
dchannel_rcv(dchannel_t *dch)
dchannel_bh(dchannel_t *dch)
{
struct sk_buff *skb;
int err;
while ((skb = skb_dequeue(&dch->rqueue))) {
err = if_newhead(&dch->inst.up, PH_DATA_IND, DINFO_SKB, skb);
if (err < 0) {
printk(KERN_WARNING "HiSax: dchannel deliver err %d\n", err);
dev_kfree_skb(skb);
}
}
}
static void
dchannel_bh(dchannel_t *dch)
{
if (!dch)
return;
if (dch->debug)
@ -46,18 +34,24 @@ dchannel_bh(dchannel_t *dch)
}
#endif
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
struct sk_buff *skb = dch->next_skb;
if (skb) {
if ((skb = dch->next_skb)) {
dch->next_skb = NULL;
skb_trim(skb, 0);
if (if_newhead(&dch->inst.up, PH_DATA_CNF, DINFO_SKB,
skb))
if (if_newhead(&dch->inst.up, PH_DATA_CNF, DINFO_SKB, skb))
dev_kfree_skb(skb);
}
}
if (test_and_clear_bit(D_RCVBUFREADY, &dch->event))
dchannel_rcv(dch);
if (test_and_clear_bit(D_RCVBUFREADY, &dch->event)) {
while ((skb = skb_dequeue(&dch->rqueue))) {
err = if_newhead(&dch->inst.up, PH_DATA_IND, DINFO_SKB, 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);
}

View File

@ -9,80 +9,6 @@
#define __NO_VERSION__
#include <linux/hisaxif.h>
#include "helper.h"
#include "hisax_bch.h"
int
init_bchannel(bchannel_t *bch) {
int devtyp = HISAX_RAW_DEVICE;
if (!(bch->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for blog\n");
return(-ENOMEM);
}
if (!(bch->rx_buf = kmalloc(MAX_DATA_MEM, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: 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
"HiSax: 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;
bch->tqueue.data = bch;
if (!bch->dev) {
if (bch->inst.obj->ctrl(&bch->dev, MGR_GETDEVICE | REQUEST,
&devtyp)) {
printk(KERN_WARNING
"HiSax: no raw device for bchannel\n");
}
}
return(0);
}
int
free_bchannel(bchannel_t *bch) {
if (bch->tqueue.sync)
printk(KERN_ERR"free_bchannel tqueue.sync\n");
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
"HiSax: del raw device error\n");
} else
bch->dev = NULL;
return(0);
}
int bprotocol2pid(void *bp, hisax_pid_t *pid) {
__u8 *p = bp;

View File

@ -1719,165 +1719,104 @@ hfcpci_l2l1(hisaxif_t *hif, struct sk_buff *skb)
/***************************/
/* handle L1 state changes */
/***************************/
static void
hfcD_newstate(dchannel_t *dch)
HW_hfcD_bh(dchannel_t *dch)
{
hfc_pci_t *hc = dch->inst.data;
u_int prim = PH_SIGNAL | INDICATION;
u_int para = 0;
hisaxif_t *upif = &dch->inst.up;
if (!hc->hw.nt_mode) {
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 {
printk(KERN_DEBUG "%s: NT newstate %x\n",
__FUNCTION__, dch->ph_state);
dch->inst.lock(dch->inst.data);
switch (dch->ph_state) {
case (2):
if (hc->hw.nt_timer < 0) {
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);
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);
/* 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;
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);
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);
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);
break;
default:
break;
}
dch->inst.unlock(dch->inst.data);
}
while(upif) {
if_link(upif, prim, para, 0, NULL, 0);
upif = upif->next;
}
}
static void
HW_hfcD_bh(dchannel_t *dch)
{
if (test_and_clear_bit(D_L1STATECHANGE, &dch->event))
hfcD_newstate(dch);
}
static void
hfcB_bh(bchannel_t *bch)
{
struct sk_buff *skb;
u_int pr;
int ret;
hisax_head_t *hh;
hisaxif_t *hif;
if (!bch)
return;
if (!bch->inst.up.func) {
printk(KERN_WARNING "HiSax: hdlc_bh without up.func\n");
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 = HISAX_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, DINFO_SKB, skb);
if (ret < 0) {
printk(KERN_WARNING "hdlc_bh deliver err %d\n",
ret);
dev_kfree_skb(skb);
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->next;
}
}
}
/********************************/
/* called for card init message */
/********************************/
@ -1887,8 +1826,6 @@ inithfcpci(hfc_pci_t *hc)
{
HFC_INFO("inithfcpci: entered\n");
hc->dch.hw_bh = HW_hfcD_bh;
hc->bch[0].tqueue.routine = (void *) (void *) hfcB_bh;
hc->bch[1].tqueue.routine = (void *) (void *) hfcB_bh;
hc->dch.dbusytimer.function = (void *) hfcpci_dbusy_timer;
hc->dch.dbusytimer.data = (long) &hc->dch;
init_timer(&hc->dch.dbusytimer);

View File

@ -1,6 +1,6 @@
/* $Id$
*
* hw_lock.h HArdware locking inline routines
* hw_lock.h Hardware locking inline routines
*
* Author Karsten Keil (keil@isdn4linux.de)
*
@ -8,7 +8,59 @@
*
*/
/* Description of the locking mechanism
*
* The locking must grant serialisized and atomic
* access to the ISDN hardware registers, if the lock
* is aquired no other process or IRQ is alloed to
* access ISDN hardware registers.
*
* In general here are 3 possible entry points:
* 1. the ISDN interrupt routine
* 2. ISDN timer routines in the hardware module
* 3. messages that came from upper layers
*
* Since most work must be do in the interrupt routine
* (to grant minimum IRQ latency) and only few things with
* need direct HW access must be done for messages from upper
* layers, we should allow other IRQs in our IRQ routines and
* only block our own routines in this case. Since the common IRQ
* routines allready mask the same IRQ, we only need to protect us
* from timer and uper layers. The disadvantage is, that we need to
* disable local IRQ for the 2. and 3. points, but since the routines
* which need hardware access are well known and small, the impact
* is very small.
*
* We have a two stage locking to make this working:
* A spinlock which protect the state LOCK Flag (STATE_FLAG_BUSY) and
* also protect us from local IRQs from the entry points 2 and 3.
*
* In the hardware IRQ we aquire the spinlock, set the STATE_FLAG_BUSY
* LOCK Flag and then release the spinlock. It can never happen that
* the STATE_FLAG_BUSY is allready set in this case, see later.
*
* In the other cases (from timer or upper layers) we aquire the spinlock
* test_and_set the STATE_FLAG_BUSY LOCK Flag, if it was allready set
* (a ISDN IRQ is running on the other CPU) we schedule timeout or add a other
* small timeout.
* If it was not set, we have the lock and we don't release the spinlock until we have
* done the harware work.
*
* To avoid any kind of deadlocking, it is important that we release the lock
* before we call functions that deliver to upper layers.
* To leave the impact of disabled local IRQ small, it is important to only protect
* small areas where hardware is accessed.
*
* The following routines handle the lock in the entry point from upper layers and other
* none IRQ cases (module init/exit stuff).
*
* They never called directly, but via the wrappers assigned to theinstance
* inst.lock / inst.unlock pointers.
*
* Here are two defines which can be used for DEBUGING and PROFILING
* SPIN_DEBUG and LOCK_STATISTIC
*
*/
#ifndef __hw_lock__
#define __hw_lock__

View File

@ -429,42 +429,8 @@ deliver_status(bchannel_t *bch, int status)
static void
isar_bh(bchannel_t *bch)
{
struct sk_buff *skb;
u_int pr;
int ret;
int tt;
if (!bch)
return;
if (!bch->inst.up.func) {
printk(KERN_WARNING "HiSax: isar_bh without up.func\n");
return;
}
if (test_and_clear_bit(B_XMTBUFREADY, &bch->event)) {
skb = bch->next_skb;
if (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 (if_newhead(&bch->inst.up, pr, DINFO_SKB, skb))
dev_kfree_skb(skb);
}
}
if (test_and_clear_bit(B_RCVBUFREADY, &bch->event)) {
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(&bch->inst.up, pr, DINFO_SKB, skb);
if (ret < 0) {
printk(KERN_WARNING "HiSax: isar deliver err %d\n",
ret);
dev_kfree_skb(skb);
}
}
}
if (test_and_clear_bit(B_LL_READY, &bch->event))
deliver_status(bch, HW_MOD_OK);
if (test_and_clear_bit(B_LL_NOCARRIER, &bch->event))
@ -476,12 +442,11 @@ isar_bh(bchannel_t *bch)
if (test_and_clear_bit(B_LL_FCERROR, &bch->event))
deliver_status(bch, HW_MOD_FCERROR);
if (test_and_clear_bit(B_TOUCH_TONE, &bch->event)) {
ret = bch->conmsg[0];
ret |= TOUCH_TONE_VAL;
tt = bch->conmsg[0];
tt |= TOUCH_TONE_VAL;
if_link(&bch->inst.up, PH_CONTROL | INDICATION,
0, sizeof(int), &ret, 0);
0, sizeof(int), &tt, 0);
}
}
static inline void
@ -1814,7 +1779,7 @@ int init_isar(bchannel_t *bch)
{
isar_hw_t *ih = bch->hw;
bch->tqueue.routine = (void *) (void *) isar_bh;
bch->hw_bh = isar_bh;
ih->ftimer.function = (void *) ftimer_handler;
ih->ftimer.data = (long) bch;
init_timer(&ih->ftimer);