parent
8293963b8e
commit
ac037381e8
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue