- new locking, relaxed irq
- dchannel and bchannel helper routines - dchannel and bchannel hardware module
This commit is contained in:
parent
fbba4429c5
commit
458ed3d264
|
@ -34,9 +34,9 @@ include: $(KDIR)/include
|
|||
ln -s $(KDIR)/include
|
||||
|
||||
clean:
|
||||
rm -f $(TARGETS) $(TARGETDIR)/.*.flags $(TARGETDIR)/*.o
|
||||
rm -f $(TARGETS) $(TARGETDIR)/.*.flags $(TARGETDIR)/*.o $(TARGETDIR)/.depend
|
||||
rm -f $(TARGETDIR)/*~ newinclude/linux/*~ *~ .kversion
|
||||
rm -f -r modules
|
||||
rm -f -r modules .depend .hdepend
|
||||
|
||||
$(TARGET):
|
||||
$(MAKE) -f Makefile KDIR=$(KDIR) TARGETDIR=$(TARGETDIR) $(TARGET)
|
||||
|
|
|
@ -17,7 +17,7 @@ TOPDIR := $(KDIR)
|
|||
include $(KDIR)/.config
|
||||
include $(KDIR)/Makefile
|
||||
|
||||
CFLAGS := -I. -I $(KDIR)/drivers/isdn/avmb1 $(CFLAGS) -DLINUX
|
||||
CFLAGS := -I. -I $(KDIR)/drivers/isdn/avmb1 $(CFLAGS) -I $(MYDIR)/newinclude -DLINUX
|
||||
CC := $(filter-out -I$(HPATH), $(CC)) -I $(MYDIR)/newinclude -I $(HPATH)
|
||||
|
||||
ifdef CONFIG_MODVERSIONS
|
||||
|
@ -26,12 +26,22 @@ else
|
|||
CFLAGS := -DMODULE $(CFLAGS)
|
||||
endif
|
||||
|
||||
FINDHPATH += $(MYDIR)/newinclude/linux
|
||||
|
||||
MODLIB := $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)
|
||||
|
||||
newhisax: $(TARGETDIR) newhisax_mod
|
||||
newhisax: $(TARGETDIR) depend newhisax_mod
|
||||
$(MAKE) -C $(TARGETDIR) CFLAGS="$(CFLAGS)" MAKING_MODULES=1 modules
|
||||
|
||||
dep-files: scripts/mkdep archdep include/linux/version.h
|
||||
scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
|
||||
$(MAKE) $(patsubst %,_sfdep_%,$(TARGETDIR)) _FASTDEP_ALL_SUB_DIRS="$(TARGETDIR)"
|
||||
ifdef CONFIG_MODVERSIONS
|
||||
$(MAKE) update-modverfile
|
||||
endif
|
||||
|
||||
depend dep: dep-files
|
||||
|
||||
ifeq ($(PATCHLEVEL), 2)
|
||||
|
||||
TARGETMODDIR = misc
|
||||
|
|
|
@ -11,11 +11,11 @@ O_TARGET := vmlinux-obj.o
|
|||
|
||||
# multi objects
|
||||
|
||||
SEDLFAXOBJ := sedl_fax.o debug.o helper.o fsm.o isar.o
|
||||
SEDLFAXOBJ := sedl_fax.o debug.o helper.o fsm.o isar.o hisax_dch.o
|
||||
|
||||
FRITZOBJ := fritz_pci.o debug.o helper.o fsm.o
|
||||
FRITZOBJ := fritz_pci.o debug.o helper.o fsm.o hisax_dch.o
|
||||
|
||||
HFC_PCIOBJ := hfc_pci.o debug.o helper.o
|
||||
HFC_PCIOBJ := hfc_pci.o debug.o helper.o hisax_dch.o
|
||||
|
||||
hisaxisac-objs := isac.o arcofi.o debug.o
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
#define __NO_VERSION__
|
||||
#include "hisax_hw.h"
|
||||
#include "hisax_dch.h"
|
||||
#include "hisaxl1.h"
|
||||
#include "isac.h"
|
||||
#include "arcofi.h"
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
#define ARCOFI_RX_END 3
|
||||
#define ARCOFI_TIMEOUT 4
|
||||
|
||||
struct arcofi_msg {
|
||||
struct arcofi_msg *next;
|
||||
u_char receive;
|
||||
u_char len;
|
||||
u_char msg[10];
|
||||
};
|
||||
|
||||
extern int arcofi_fsm(dchannel_t *, int, void *);
|
||||
extern void init_arcofi(dchannel_t *);
|
||||
extern void clear_arcofi(dchannel_t *);
|
||||
|
|
|
@ -12,12 +12,18 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include "hisax_hw.h"
|
||||
#include <linux/delay.h>
|
||||
#include "hisax_dch.h"
|
||||
#include "hisax_bch.h"
|
||||
#include "isac.h"
|
||||
#include "hisaxl1.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define SPIN_DEBUG
|
||||
#define LOCK_STATISTIC
|
||||
#include "hw_lock.h"
|
||||
|
||||
static const char *avm_pci_rev = "$Revision$";
|
||||
|
||||
#define ISDN_CTYPE_FRITZPCI 1
|
||||
|
@ -80,17 +86,38 @@ static const char *avm_pci_rev = "$Revision$";
|
|||
|
||||
/* data struct */
|
||||
|
||||
struct hdlc_stat_reg {
|
||||
#ifdef __BIG_ENDIAN
|
||||
u_char fill __attribute__((packed));
|
||||
u_char mode __attribute__((packed));
|
||||
u_char xml __attribute__((packed));
|
||||
u_char cmd __attribute__((packed));
|
||||
#else
|
||||
u_char cmd __attribute__((packed));
|
||||
u_char xml __attribute__((packed));
|
||||
u_char mode __attribute__((packed));
|
||||
u_char fill __attribute__((packed));
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct hdlc_hw {
|
||||
union {
|
||||
u_int ctrl;
|
||||
struct hdlc_stat_reg sr;
|
||||
} ctrl;
|
||||
u_int stat;
|
||||
} hdlc_hw_t;
|
||||
|
||||
|
||||
typedef struct _fritzpnppci {
|
||||
struct _fritzpnppci *prev;
|
||||
struct _fritzpnppci *next;
|
||||
u_char subtyp;
|
||||
u_int irq;
|
||||
u_int addr;
|
||||
spinlock_t devlock;
|
||||
u_long flags;
|
||||
#ifdef SPIN_DEBUG
|
||||
void *lock_adr;
|
||||
#endif
|
||||
hisax_HWlock_t lock;
|
||||
isac_chip_t isac;
|
||||
hdlc_hw_t hdlc[2];
|
||||
dchannel_t dch;
|
||||
bchannel_t bch[2];
|
||||
} fritzpnppci;
|
||||
|
@ -98,24 +125,18 @@ typedef struct _fritzpnppci {
|
|||
|
||||
static void lock_dev(void *data)
|
||||
{
|
||||
register u_long flags;
|
||||
register fritzpnppci *card = data;
|
||||
|
||||
spin_lock_irqsave(&card->devlock, flags);
|
||||
card->flags = flags;
|
||||
#ifdef SPIN_DEBUG
|
||||
card->lock_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
fritzpnppci *card = data;
|
||||
register hisax_HWlock_t *lock = &card->lock;
|
||||
|
||||
lock_HW(lock);
|
||||
}
|
||||
|
||||
static void unlock_dev(void *data)
|
||||
{
|
||||
register fritzpnppci *card = data;
|
||||
|
||||
spin_unlock_irqrestore(&card->devlock, card->flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
card->lock_adr = NULL;
|
||||
#endif
|
||||
fritzpnppci *card = data;
|
||||
register hisax_HWlock_t *lock = &card->lock;
|
||||
|
||||
unlock_HW(lock);
|
||||
}
|
||||
|
||||
/* Interface functions */
|
||||
|
@ -227,45 +248,39 @@ bchannel_t *Sel_BCS(fritzpnppci *fc, int channel)
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
void inline
|
||||
hdlc_sched_event(bchannel_t *bch, int event)
|
||||
{
|
||||
bch->event |= 1 << event;
|
||||
queue_task(&bch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
||||
|
||||
void
|
||||
write_ctrl(bchannel_t *bch, int which) {
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
|
||||
if (fc->dch.debug & L1_DEB_HSCX)
|
||||
debugprint(&bch->inst, "hdlc %c wr%x ctrl %x",
|
||||
'A' + bch->channel, which, bch->hw.hdlc.ctrl.ctrl);
|
||||
'A' + bch->channel, which, hdlc->ctrl.ctrl);
|
||||
if (fc->subtyp == AVM_FRITZ_PCI) {
|
||||
WriteHDLCPCI(fc, bch->channel, HDLC_STATUS, bch->hw.hdlc.ctrl.ctrl);
|
||||
WriteHDLCPCI(fc, bch->channel, HDLC_STATUS, hdlc->ctrl.ctrl);
|
||||
} else {
|
||||
if (which & 4)
|
||||
WriteHDLCPnP(fc, bch->channel, HDLC_STATUS + 2,
|
||||
bch->hw.hdlc.ctrl.sr.mode);
|
||||
hdlc->ctrl.sr.mode);
|
||||
if (which & 2)
|
||||
WriteHDLCPnP(fc, bch->channel, HDLC_STATUS + 1,
|
||||
bch->hw.hdlc.ctrl.sr.xml);
|
||||
hdlc->ctrl.sr.xml);
|
||||
if (which & 1)
|
||||
WriteHDLCPnP(fc, bch->channel, HDLC_STATUS,
|
||||
bch->hw.hdlc.ctrl.sr.cmd);
|
||||
hdlc->ctrl.sr.cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
modehdlc(bchannel_t *bch, int bc, int protocol)
|
||||
{
|
||||
int hdlc = bch->channel;
|
||||
int hdlc_ch = bch->channel;
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
|
||||
if (bch->debug & L1_DEB_HSCX)
|
||||
debugprint(&bch->inst, "hdlc %c protocol %x-->%x ch %d-->%d",
|
||||
'A' + hdlc, bch->protocol, protocol, hdlc, bc);
|
||||
bch->hw.hdlc.ctrl.ctrl = 0;
|
||||
'A' + hdlc_ch, bch->protocol, protocol, hdlc_ch, bc);
|
||||
hdlc->ctrl.ctrl = 0;
|
||||
switch (protocol) {
|
||||
case (-1): /* used for init */
|
||||
bch->protocol = -1;
|
||||
|
@ -274,8 +289,8 @@ modehdlc(bchannel_t *bch, int bc, int protocol)
|
|||
case (ISDN_PID_NONE):
|
||||
if (bch->protocol == ISDN_PID_NONE)
|
||||
break;
|
||||
bch->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
bch->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
|
||||
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->channel = bc;
|
||||
|
@ -283,24 +298,24 @@ modehdlc(bchannel_t *bch, int bc, int protocol)
|
|||
case (ISDN_PID_L1_B_64TRANS):
|
||||
bch->protocol = protocol;
|
||||
bch->channel = bc;
|
||||
bch->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
bch->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.mode = HDLC_MODE_TRANS;
|
||||
write_ctrl(bch, 5);
|
||||
bch->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
|
||||
write_ctrl(bch, 1);
|
||||
bch->hw.hdlc.ctrl.sr.cmd = 0;
|
||||
hdlc_sched_event(bch, B_XMTBUFREADY);
|
||||
hdlc->ctrl.sr.cmd = 0;
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
break;
|
||||
case (ISDN_PID_L1_B_64HDLC):
|
||||
bch->protocol = protocol;
|
||||
bch->channel = bc;
|
||||
bch->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
bch->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.mode = HDLC_MODE_ITF_FLG;
|
||||
write_ctrl(bch, 5);
|
||||
bch->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS;
|
||||
hdlc->ctrl.sr.cmd = HDLC_CMD_XRS;
|
||||
write_ctrl(bch, 1);
|
||||
bch->hw.hdlc.ctrl.sr.cmd = 0;
|
||||
hdlc_sched_event(bch, B_XMTBUFREADY);
|
||||
hdlc->ctrl.sr.cmd = 0;
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
break;
|
||||
default:
|
||||
debugprint(&bch->inst, "prot not known %x", protocol);
|
||||
|
@ -365,10 +380,11 @@ hdlc_empty_fifo(bchannel_t *bch, int count)
|
|||
static void
|
||||
hdlc_fill_fifo(bchannel_t *bch)
|
||||
{
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
int count, cnt =0;
|
||||
u_char *p;
|
||||
u_int *ptr;
|
||||
fritzpnppci *fc = bch->inst.data;
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
int count, cnt =0;
|
||||
u_char *p;
|
||||
u_int *ptr;
|
||||
|
||||
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
|
||||
debugprint(&bch->inst, __FUNCTION__);
|
||||
|
@ -376,19 +392,19 @@ hdlc_fill_fifo(bchannel_t *bch)
|
|||
if (count <= 0)
|
||||
return;
|
||||
p = bch->tx_buf + bch->tx_idx;
|
||||
bch->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME;
|
||||
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)
|
||||
bch->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
|
||||
hdlc->ctrl.sr.cmd |= HDLC_CMD_XME;
|
||||
}
|
||||
if ((bch->debug & L1_DEB_HSCX) && !(bch->debug & L1_DEB_HSCX_FIFO))
|
||||
debugprint(&bch->inst, "%s: %d/%d", __FUNCTION__,
|
||||
count, bch->tx_idx);
|
||||
ptr = (u_int *) p;
|
||||
bch->tx_idx += count;
|
||||
bch->hw.hdlc.ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
|
||||
hdlc->ctrl.sr.xml = ((count == HDLC_FIFO_SIZE) ? 0 : count);
|
||||
write_ctrl(bch, 3); /* sets the correct index too */
|
||||
if (fc->subtyp == AVM_FRITZ_PCI) {
|
||||
while (cnt<count) {
|
||||
|
@ -423,8 +439,9 @@ hdlc_fill_fifo(bchannel_t *bch)
|
|||
|
||||
static void
|
||||
HDLC_irq(bchannel_t *bch, u_int stat) {
|
||||
int len;
|
||||
struct sk_buff *skb;
|
||||
int len;
|
||||
struct sk_buff *skb;
|
||||
hdlc_hw_t *hdlc = bch->hw;
|
||||
|
||||
if (bch->debug & L1_DEB_HSCX)
|
||||
debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
|
||||
|
@ -434,10 +451,10 @@ HDLC_irq(bchannel_t *bch, u_int stat) {
|
|||
debugprint(&bch->inst, "RDO");
|
||||
else
|
||||
debugprint(&bch->inst, "ch%d stat %#x", bch->channel, stat);
|
||||
bch->hw.hdlc.ctrl.sr.xml = 0;
|
||||
bch->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.xml = 0;
|
||||
hdlc->ctrl.sr.cmd |= HDLC_CMD_RRS;
|
||||
write_ctrl(bch, 1);
|
||||
bch->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS;
|
||||
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_RRS;
|
||||
write_ctrl(bch, 1);
|
||||
bch->rx_idx = 0;
|
||||
} else {
|
||||
|
@ -455,7 +472,7 @@ HDLC_irq(bchannel_t *bch, u_int stat) {
|
|||
skb_queue_tail(&bch->rqueue, skb);
|
||||
}
|
||||
bch->rx_idx = 0;
|
||||
hdlc_sched_event(bch, B_RCVBUFREADY);
|
||||
bch_sched_event(bch, B_RCVBUFREADY);
|
||||
} else {
|
||||
if (bch->debug & L1_DEB_HSCX)
|
||||
debugprint(&bch->inst, "invalid frame");
|
||||
|
@ -476,10 +493,10 @@ HDLC_irq(bchannel_t *bch, u_int stat) {
|
|||
debugprint(&bch->inst, "ch%d XDU", bch->channel);
|
||||
} else if (bch->debug & L1_DEB_WARN)
|
||||
debugprint(&bch->inst, "ch%d XDU without data", bch->channel);
|
||||
bch->hw.hdlc.ctrl.sr.xml = 0;
|
||||
bch->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS;
|
||||
hdlc->ctrl.sr.xml = 0;
|
||||
hdlc->ctrl.sr.cmd |= HDLC_CMD_XRS;
|
||||
write_ctrl(bch, 1);
|
||||
bch->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS;
|
||||
hdlc->ctrl.sr.cmd &= ~HDLC_CMD_XRS;
|
||||
write_ctrl(bch, 1);
|
||||
hdlc_fill_fifo(bch);
|
||||
} else if (stat & HDLC_INT_XPR) {
|
||||
|
@ -487,20 +504,20 @@ HDLC_irq(bchannel_t *bch, u_int stat) {
|
|||
hdlc_fill_fifo(bch);
|
||||
} else {
|
||||
bch->tx_idx = 0;
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flag)) {
|
||||
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);
|
||||
hdlc_fill_fifo(bch);
|
||||
hdlc_sched_event(bch, B_XMTBUFREADY);
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
} else {
|
||||
printk(KERN_WARNING "hdlc tx irq TX_NEXT without skb\n");
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
}
|
||||
} else {
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
hdlc_sched_event(bch, B_XMTBUFREADY);
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -545,21 +562,48 @@ HDLC_irq_main(fritzpnppci *fc)
|
|||
static void
|
||||
avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
fritzpnppci *fc = dev_id;
|
||||
fritzpnppci *fc = dev_id;
|
||||
u_long flags;
|
||||
u_char val;
|
||||
u_char sval;
|
||||
|
||||
if (!fc) {
|
||||
printk(KERN_WARNING "AVM PCI: Spurious interrupt!\n");
|
||||
return;
|
||||
}
|
||||
lock_dev(fc);
|
||||
spin_lock_irqsave(&fc->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = (void *)0x2001;
|
||||
#endif
|
||||
sval = inb(fc->addr + 2);
|
||||
if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) {
|
||||
/* possible a shared IRQ reqest */
|
||||
unlock_dev(fc);
|
||||
#ifdef SPIN_DEBUG
|
||||
fc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&fc->lock.lock, flags);
|
||||
return;
|
||||
}
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &fc->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%x\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_pcipnp_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);
|
||||
ISAC_interrupt(&fc->dch, val);
|
||||
|
@ -569,7 +613,21 @@ avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|||
}
|
||||
WriteISAC(fc, ISAC_MASK, 0xFF);
|
||||
WriteISAC(fc, ISAC_MASK, 0x0);
|
||||
unlock_dev(fc);
|
||||
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(%x)\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);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -590,8 +648,8 @@ hdlc_down(hisaxif_t *hif, struct sk_buff *skb)
|
|||
return(-EBUSY);
|
||||
}
|
||||
bch->inst.lock(bch->inst.data);
|
||||
if (test_and_set_bit(FLG_TX_BUSY, &bch->Flag)) {
|
||||
test_and_set_bit(FLG_TX_NEXT, &bch->Flag);
|
||||
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);
|
||||
|
@ -621,11 +679,11 @@ hdlc_down(hisaxif_t *hif, struct sk_buff *skb)
|
|||
(hh->prim == (DL_RELEASE | REQUEST)) ||
|
||||
(hh->prim == (MGR_DISCONNECT | REQUEST))) {
|
||||
bch->inst.lock(bch->inst.data);
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flag)) {
|
||||
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(FLG_TX_BUSY, &bch->Flag);
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
modehdlc(bch, bch->channel, 0);
|
||||
test_and_clear_bit(BC_FLG_ACTIV, &bch->Flag);
|
||||
bch->inst.unlock(bch->inst.data);
|
||||
|
@ -899,20 +957,20 @@ setup_fritz(fritzpnppci *fc, u_int io_cfg, u_int irq_cfg)
|
|||
printk(KERN_INFO "AVM PCI: stat %#x\n", val);
|
||||
printk(KERN_INFO "AVM PCI: Class %X Rev %d\n",
|
||||
val & 0xff, (val>>8) & 0xff);
|
||||
fc->bch[0].BC_Read_Reg = &ReadHDLC_s;
|
||||
fc->bch[0].BC_Write_Reg = &WriteHDLC_s;
|
||||
fc->bch[1].BC_Read_Reg = &ReadHDLC_s;
|
||||
fc->bch[1].BC_Write_Reg = &WriteHDLC_s;
|
||||
fc->bch[0].Read_Reg = &ReadHDLC_s;
|
||||
fc->bch[0].Write_Reg = &WriteHDLC_s;
|
||||
fc->bch[1].Read_Reg = &ReadHDLC_s;
|
||||
fc->bch[1].Write_Reg = &WriteHDLC_s;
|
||||
break;
|
||||
case AVM_FRITZ_PNP:
|
||||
val = inb(fc->addr);
|
||||
ver = inb(fc->addr + 1);
|
||||
printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver);
|
||||
reset_avmpcipnp(fc);
|
||||
fc->bch[0].BC_Read_Reg = &ReadHDLCPnP;
|
||||
fc->bch[0].BC_Write_Reg = &WriteHDLCPnP;
|
||||
fc->bch[1].BC_Read_Reg = &ReadHDLCPnP;
|
||||
fc->bch[1].BC_Write_Reg = &WriteHDLCPnP;
|
||||
fc->bch[0].Read_Reg = &ReadHDLCPnP;
|
||||
fc->bch[0].Write_Reg = &WriteHDLCPnP;
|
||||
fc->bch[1].Read_Reg = &ReadHDLCPnP;
|
||||
fc->bch[1].Write_Reg = &WriteHDLCPnP;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "AVM unknown subtype %d\n", fc->subtyp);
|
||||
|
@ -926,9 +984,11 @@ setup_fritz(fritzpnppci *fc, u_int io_cfg, u_int irq_cfg)
|
|||
fc->dch.write_reg = &WriteISAC;
|
||||
fc->dch.read_fifo = &ReadISACfifo;
|
||||
fc->dch.write_fifo = &WriteISACfifo;
|
||||
fc->dch.hw = &fc->isac;
|
||||
lock_dev(fc);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "lock_adr=%p now(%p)\n", &fc->lock_adr, fc->lock_adr);
|
||||
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);
|
||||
|
@ -1120,7 +1180,7 @@ Fritz_init(void)
|
|||
APPEND_TO_LIST(card, ((fritzpnppci *)fritz.ilist));
|
||||
card->dch.debug = debug;
|
||||
card->dch.inst.obj = &fritz;
|
||||
spin_lock_init(&card->devlock);
|
||||
lock_HW_init(&card->lock);
|
||||
card->dch.inst.lock = lock_dev;
|
||||
card->dch.inst.unlock = unlock_dev;
|
||||
card->dch.inst.data = card;
|
||||
|
@ -1149,6 +1209,7 @@ Fritz_init(void)
|
|||
sprintf(card->bch[i].inst.name, "%s B%d",
|
||||
card->dch.inst.name, i+1);
|
||||
init_bchannel(&card->bch[i]);
|
||||
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]);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations, defines for Bchannel hardware
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/hisaxif.h>
|
||||
#include <linux/tqueue.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MEMDBG
|
||||
#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
|
||||
|
||||
typedef struct _bchannel_t {
|
||||
int channel;
|
||||
int protocol;
|
||||
int Flag;
|
||||
int debug;
|
||||
hisaxstack_t *st;
|
||||
hisaxinstance_t inst;
|
||||
hisaxdevice_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 tq_struct tqueue;
|
||||
int event;
|
||||
int err_crc;
|
||||
int err_tx;
|
||||
int err_rdo;
|
||||
int err_inv;
|
||||
} bchannel_t;
|
||||
|
||||
extern int init_bchannel(bchannel_t *);
|
||||
extern int free_bchannel(bchannel_t *);
|
||||
|
||||
static inline void
|
||||
bch_sched_event(bchannel_t *bch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &bch->event);
|
||||
queue_task(&bch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations for dchannel HW
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/hisaxif.h>
|
||||
#include <linux/tqueue.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MEMDBG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#define MAX_DFRAME_LEN_L1 300
|
||||
#define MAX_MON_FRAME 32
|
||||
#define MAX_DLOG_SPACE 2048
|
||||
|
||||
#define HW_IOM1 0
|
||||
#define HW_IPAC 1
|
||||
#define HW_ISAR 2
|
||||
#define HW_ARCOFI 3
|
||||
#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 {
|
||||
hisaxinstance_t inst;
|
||||
u_int 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 err_crc;
|
||||
int err_tx;
|
||||
int err_rx;
|
||||
void *hw;
|
||||
struct timer_list dbusytimer;
|
||||
u_int event;
|
||||
struct sk_buff_head rqueue; /* D-channel receive queue */
|
||||
struct tq_struct tqueue;
|
||||
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 init_dchannel(dchannel_t *);
|
||||
extern int free_dchannel(dchannel_t *);
|
||||
|
||||
void set_dchannel_pid(hisax_pid_t *, int, int);
|
||||
|
||||
static inline void
|
||||
dchannel_sched_event(dchannel_t *dch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &dch->event);
|
||||
queue_task(&dch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
||||
|
||||
#ifdef __powerpc__
|
||||
#include <linux/pci.h>
|
||||
static inline int pci_enable_device(struct pci_dev *dev)
|
||||
{
|
||||
u16 cmd;
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR;
|
||||
cmd &= ~PCI_COMMAND_FAST_BACK;
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
#define pci_enable_device(dev) !dev
|
||||
#endif /* __powerpc__ */
|
|
@ -9,56 +9,7 @@
|
|||
#define __NO_VERSION__
|
||||
#include <linux/hisaxif.h>
|
||||
#include "helper.h"
|
||||
#include "hisax_hw.h"
|
||||
|
||||
int
|
||||
init_dchannel(dchannel_t *dch) {
|
||||
if (!(dch->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"HiSax: No memory for dlog\n");
|
||||
return(-ENOMEM);
|
||||
}
|
||||
if (!(dch->tx_buf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
|
||||
printk(KERN_WARNING
|
||||
"HiSax: 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;
|
||||
dch->tqueue.data = dch;
|
||||
skb_queue_head_init(&dch->rqueue);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
free_dchannel(dchannel_t *dch) {
|
||||
|
||||
if (dch->tqueue.sync)
|
||||
printk(KERN_ERR"free_dchannel tqueue.sync\n");
|
||||
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);
|
||||
}
|
||||
#include "hisax_bch.h"
|
||||
|
||||
int
|
||||
init_bchannel(bchannel_t *bch) {
|
||||
|
@ -164,29 +115,6 @@ int bprotocol2pid(void *bp, hisax_pid_t *pid) {
|
|||
return(0);
|
||||
}
|
||||
|
||||
void
|
||||
set_dchannel_pid(hisax_pid_t *pid, int protocol, int layermask) {
|
||||
|
||||
if (!layermask)
|
||||
layermask = ISDN_LAYER(0)| ISDN_LAYER(1) | ISDN_LAYER(2) |
|
||||
ISDN_LAYER(3) | ISDN_LAYER(4);
|
||||
|
||||
memset(pid, 0, sizeof(hisax_pid_t));
|
||||
pid->layermask = layermask;
|
||||
if (layermask & ISDN_LAYER(0))
|
||||
pid->protocol[0] = ISDN_PID_L0_TE_S0;
|
||||
if (layermask & ISDN_LAYER(1))
|
||||
pid->protocol[1] = ISDN_PID_L1_TE_S0;
|
||||
if (layermask & ISDN_LAYER(2))
|
||||
pid->protocol[2] = ISDN_PID_L2_LAPD;
|
||||
if (layermask & ISDN_LAYER(3)) {
|
||||
if (protocol == 2)
|
||||
pid->protocol[3] = ISDN_PID_L3_DSS1USER;
|
||||
}
|
||||
if (layermask & ISDN_LAYER(4))
|
||||
pid->protocol[4] = ISDN_PID_L4_CAPI20;
|
||||
}
|
||||
|
||||
int
|
||||
HasProtocol(hisaxobject_t *obj, int protocol)
|
||||
{
|
||||
|
|
|
@ -31,13 +31,18 @@
|
|||
#include <linux/kernel_stat.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "hisax_hw.h"
|
||||
#include "hisax_dch.h"
|
||||
#include "hisax_bch.h"
|
||||
#include "hfc_pci.h"
|
||||
#include "hisaxl1.h"
|
||||
#include "helper.h"
|
||||
#include "debug.h"
|
||||
#include <linux/isdn_compat.h>
|
||||
|
||||
#define SPIN_DEBUG
|
||||
#define LOCK_STATISTIC
|
||||
#include "hw_lock.h"
|
||||
|
||||
#define HFC_INFO(txt) printk(KERN_DEBUG txt)
|
||||
|
||||
extern const char *CardType[];
|
||||
|
@ -126,7 +131,6 @@ struct hfcPCI_hw {
|
|||
unsigned char mst_m;
|
||||
unsigned char int_m1;
|
||||
unsigned char int_m2;
|
||||
unsigned char int_s1;
|
||||
unsigned char sctrl;
|
||||
unsigned char sctrl_r;
|
||||
unsigned char sctrl_e;
|
||||
|
@ -163,11 +167,7 @@ typedef struct _hfc_pci {
|
|||
u_int cfg;
|
||||
u_int irq;
|
||||
hfcPCI_hw_t hw;
|
||||
spinlock_t devlock;
|
||||
u_long flags;
|
||||
#ifdef SPIN_DEBUG
|
||||
void *lock_adr;
|
||||
#endif
|
||||
hisax_HWlock_t lock;
|
||||
dchannel_t dch;
|
||||
bchannel_t bch[2];
|
||||
} hfc_pci_t;
|
||||
|
@ -175,24 +175,16 @@ typedef struct _hfc_pci {
|
|||
|
||||
static void lock_dev(void *data)
|
||||
{
|
||||
register u_long flags;
|
||||
register hfc_pci_t *card = data;
|
||||
|
||||
spin_lock_irqsave(&card->devlock, flags);
|
||||
card->flags = flags;
|
||||
#ifdef SPIN_DEBUG
|
||||
card->lock_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
register hisax_HWlock_t *lock = &((hfc_pci_t *)data)->lock;
|
||||
|
||||
lock_HW(lock);
|
||||
}
|
||||
|
||||
static void unlock_dev(void *data)
|
||||
{
|
||||
register hfc_pci_t *card = data;
|
||||
register hisax_HWlock_t *lock = &((hfc_pci_t *)data)->lock;
|
||||
|
||||
spin_unlock_irqrestore(&card->devlock, card->flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
card->lock_adr = NULL;
|
||||
#endif
|
||||
unlock_HW(lock);
|
||||
}
|
||||
|
||||
/* Interface functions */
|
||||
|
@ -203,13 +195,8 @@ static void unlock_dev(void *data)
|
|||
void
|
||||
release_io_hfcpci(hfc_pci_t *hc)
|
||||
{
|
||||
int flags;
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
hc->hw.int_m2 = 0; /* interrupt output off ! */
|
||||
Write_hfc(hc, HFCPCI_INT_M2, hc->hw.int_m2);
|
||||
restore_flags(flags);
|
||||
Write_hfc(hc, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
|
||||
|
@ -230,15 +217,12 @@ release_io_hfcpci(hfc_pci_t *hc)
|
|||
static void
|
||||
reset_hfcpci(hfc_pci_t *hc)
|
||||
{
|
||||
long flags;
|
||||
u_char val;
|
||||
int cnt = 0;
|
||||
|
||||
HFC_INFO("reset_hfcpci: entered\n");
|
||||
val = Read_hfc(hc, HFCPCI_CHIP_ID);
|
||||
printk(KERN_INFO "HFC_PCI: resetting HFC ChipId(%x)\n", val);
|
||||
save_flags(flags);
|
||||
cli();
|
||||
pcibios_write_config_word(hc->hw.pci_bus, hc->hw.pci_device_fn, 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);
|
||||
|
@ -247,11 +231,8 @@ reset_hfcpci(hfc_pci_t *hc)
|
|||
printk(KERN_DEBUG "HFC-PCI status(%x) before reset\n", val);
|
||||
hc->hw.cirm = HFCPCI_RESET; /* Reset On */
|
||||
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
|
||||
restore_flags(flags);
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_timeout((30 * HZ) / 1000); /* Timeout 30ms */
|
||||
save_flags(flags);
|
||||
cli();
|
||||
hc->hw.cirm = 0; /* Reset Off */
|
||||
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
|
||||
val = Read_hfc(hc, HFCPCI_STATUS);
|
||||
|
@ -333,7 +314,6 @@ reset_hfcpci(hfc_pci_t *hc)
|
|||
}
|
||||
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
|
||||
val = Read_hfc(hc, HFCPCI_INT_S2);
|
||||
restore_flags(flags);
|
||||
}
|
||||
|
||||
/***************************************************/
|
||||
|
@ -350,28 +330,6 @@ hfcpci_Timer(hfc_pci_t *hc)
|
|||
}
|
||||
|
||||
|
||||
/*********************************/
|
||||
/* schedule a new D-channel task */
|
||||
/*********************************/
|
||||
static void
|
||||
sched_event_D_pci(hfc_pci_t *hc, int event)
|
||||
{
|
||||
test_and_set_bit(event, &hc->dch.event);
|
||||
queue_task(&hc->dch.tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
||||
|
||||
/*********************************/
|
||||
/* schedule a new b_channel task */
|
||||
/*********************************/
|
||||
static void
|
||||
hfcpci_sched_event(bchannel_t *bch, int event)
|
||||
{
|
||||
bch->event |= 1 << event;
|
||||
queue_task(&bch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
/* select a b-channel entry matching and active */
|
||||
/************************************************/
|
||||
|
@ -520,10 +478,6 @@ receive_dmsg(hfc_pci_t *hc)
|
|||
z_type *zp;
|
||||
|
||||
df = &((fifo_area *) (hc->hw.fifos))->d_chan.d_rx;
|
||||
if (test_and_set_bit(FLG_LOCK_ATOMIC, &dch->DFlags)) {
|
||||
debugprint(&dch->inst, "rec_dmsg blocked");
|
||||
return (1);
|
||||
}
|
||||
while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) {
|
||||
zp = &df->za[df->f2 & D_FREG_MASK];
|
||||
rcnt = zp->z1 - zp->z2;
|
||||
|
@ -575,11 +529,10 @@ receive_dmsg(hfc_pci_t *hc)
|
|||
debugprint(&dch->inst, dch->dlog);
|
||||
}
|
||||
skb_queue_tail(&dch->rqueue, skb);
|
||||
sched_event_D_pci(hc, D_RCVBUFREADY);
|
||||
dchannel_sched_event(dch, D_RCVBUFREADY);
|
||||
} else
|
||||
printk(KERN_WARNING "HFC-PCI: D receive out of memory\n");
|
||||
}
|
||||
test_and_clear_bit(FLG_LOCK_ATOMIC, &dch->DFlags);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
@ -628,7 +581,7 @@ hfcpci_empty_fifo_trans(bchannel_t *bch, bzfifo_type * bz, u_char * bdata)
|
|||
memcpy(ptr, ptr1, fcnt); /* rest */
|
||||
}
|
||||
skb_queue_tail(&bch->rqueue, skb);
|
||||
hfcpci_sched_event(bch, B_RCVBUFREADY);
|
||||
bch_sched_event(bch, B_RCVBUFREADY);
|
||||
}
|
||||
|
||||
*z2r = new_z2; /* new position */
|
||||
|
@ -641,7 +594,6 @@ hfcpci_empty_fifo_trans(bchannel_t *bch, bzfifo_type * bz, u_char * bdata)
|
|||
void
|
||||
main_rec_hfcpci(bchannel_t *bch)
|
||||
{
|
||||
long flags;
|
||||
hfc_pci_t *hc = bch->inst.data;
|
||||
int rcnt, real_fifo;
|
||||
int receive, count = 5;
|
||||
|
@ -662,14 +614,6 @@ main_rec_hfcpci(bchannel_t *bch)
|
|||
}
|
||||
Begin:
|
||||
count--;
|
||||
save_flags(flags);
|
||||
cli();
|
||||
if (test_and_set_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags)) {
|
||||
restore_flags(flags);
|
||||
debugprint(&bch->inst, "rec_data ch(%x) blocked", bch->channel);
|
||||
return;
|
||||
}
|
||||
restore_flags(flags);
|
||||
if (bz->f1 != bz->f2) {
|
||||
if (bch->debug & L1_DEB_HSCX)
|
||||
debugprint(&bch->inst, "hfcpci rec ch(%x) f1(%d) f2(%d)",
|
||||
|
@ -685,7 +629,7 @@ main_rec_hfcpci(bchannel_t *bch)
|
|||
bch->channel, zp->z1, zp->z2, rcnt);
|
||||
if ((skb = hfcpci_empty_fifo(bch, bz, bdata, rcnt))) {
|
||||
skb_queue_tail(&bch->rqueue, skb);
|
||||
hfcpci_sched_event(bch, B_RCVBUFREADY);
|
||||
bch_sched_event(bch, B_RCVBUFREADY);
|
||||
}
|
||||
rcnt = bz->f1 - bz->f2;
|
||||
if (rcnt < 0)
|
||||
|
@ -703,7 +647,6 @@ main_rec_hfcpci(bchannel_t *bch)
|
|||
receive = hfcpci_empty_fifo_trans(bch, bz, bdata);
|
||||
else
|
||||
receive = 0;
|
||||
test_and_clear_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags);
|
||||
if (count && receive)
|
||||
goto Begin;
|
||||
return;
|
||||
|
@ -716,7 +659,6 @@ static void
|
|||
hfcpci_fill_dfifo(hfc_pci_t *hc)
|
||||
{
|
||||
dchannel_t *dch = &hc->dch;
|
||||
long flags;
|
||||
int fcnt;
|
||||
int count, new_z1, maxlen;
|
||||
dfifo_type *df;
|
||||
|
@ -773,12 +715,9 @@ hfcpci_fill_dfifo(hfc_pci_t *hc)
|
|||
src += maxlen; /* new position */
|
||||
memcpy(dst, src, count);
|
||||
}
|
||||
save_flags(flags);
|
||||
cli();
|
||||
df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */
|
||||
df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */
|
||||
df->f1 = new_f1; /* next frame */
|
||||
restore_flags(flags);
|
||||
if (dch->debug & L1_DEB_ISAC_FIFO) {
|
||||
char *t = dch->dlog;
|
||||
|
||||
|
@ -792,20 +731,6 @@ hfcpci_fill_dfifo(hfc_pci_t *hc)
|
|||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
hfcD_send_fifo(dchannel_t *dch)
|
||||
{
|
||||
hfc_pci_t *hc = dch->inst.data;
|
||||
|
||||
if (!test_and_set_bit(FLG_LOCK_ATOMIC, &dch->DFlags)) {
|
||||
hfcpci_fill_dfifo(hc);
|
||||
test_and_clear_bit(FLG_LOCK_ATOMIC, &dch->DFlags);
|
||||
} else {
|
||||
debugprint(&dch->inst, "hfcpci_fill_dfifo blocked");
|
||||
sched_event_D_pci(hc, D_BLOCKEDATOMIC);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************/
|
||||
/* B-channel send routine */
|
||||
/**************************/
|
||||
|
@ -813,7 +738,7 @@ static void
|
|||
hfcpci_fill_fifo(bchannel_t *bch)
|
||||
{
|
||||
hfc_pci_t *hc = bch->inst.data;
|
||||
int flags, maxlen, fcnt;
|
||||
int maxlen, fcnt;
|
||||
int count, new_z1;
|
||||
bzfifo_type *bz;
|
||||
u_char *bdata;
|
||||
|
@ -873,19 +798,19 @@ next_t_frame:
|
|||
} else if (bch->debug & L1_DEB_HSCX)
|
||||
debugprint(&bch->inst, "hfcpci_fill_fifo_trans ch(%x) frame length %d discarded",
|
||||
bch->channel, bch->tx_len);
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flag)) {
|
||||
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);
|
||||
hfcpci_sched_event(bch, B_XMTBUFREADY);
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
goto next_t_frame;
|
||||
} else
|
||||
printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
|
||||
}
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
bch->tx_idx = bch->tx_len;
|
||||
}
|
||||
return;
|
||||
|
@ -934,32 +859,13 @@ next_t_frame:
|
|||
src += maxlen; /* new position */
|
||||
memcpy(dst, src, count);
|
||||
}
|
||||
save_flags(flags);
|
||||
cli();
|
||||
bz->za[new_f1].z1 = new_z1; /* for next buffer */
|
||||
bz->f1 = new_f1; /* next frame */
|
||||
restore_flags(flags);
|
||||
bch->tx_idx = bch->tx_len;
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
test_and_clear_bit(BC_FLG_TX_BUSY, &bch->Flag);
|
||||
return;
|
||||
}
|
||||
|
||||
/**************************************/
|
||||
/* send B-channel data if not blocked */
|
||||
/**************************************/
|
||||
static void
|
||||
hfcpci_send_data(bchannel_t *bch)
|
||||
{
|
||||
hfc_pci_t *hc = bch->inst.data;
|
||||
|
||||
if (!test_and_set_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags)) {
|
||||
hfcpci_fill_fifo(bch);
|
||||
test_and_clear_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags);
|
||||
} else {
|
||||
debugprint(&bch->inst, "send_data ch(%x) blocked", bch->channel);
|
||||
hfcpci_sched_event(bch, B_BLOCKEDATOMIC);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**********************************************/
|
||||
|
@ -1003,13 +909,10 @@ dch_nt_l2l1(struct PStack *st, int pr, void *arg)
|
|||
static int
|
||||
hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic)
|
||||
{
|
||||
int flags;
|
||||
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)))) {
|
||||
save_flags(flags);
|
||||
cli();
|
||||
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 */
|
||||
|
@ -1024,7 +927,6 @@ hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic)
|
|||
hc->hw.nt_mode = 1;
|
||||
hc->hw.nt_timer = 0;
|
||||
cs->stlist->l2.l2l1 = dch_nt_l2l1;
|
||||
restore_flags(flags);
|
||||
debugl1(hc, "NT mode activated");
|
||||
return (0);
|
||||
}
|
||||
|
@ -1032,8 +934,6 @@ hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic)
|
|||
(hc->hw.nt_mode) || (ic->arg != 12))
|
||||
return (-EINVAL);
|
||||
|
||||
save_flags(flags);
|
||||
cli();
|
||||
if (i) {
|
||||
cs->logecho = 1;
|
||||
hc->hw.trm |= 0x20; /* enable echo chan */
|
||||
|
@ -1056,7 +956,6 @@ hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic)
|
|||
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);
|
||||
restore_flags(flags);
|
||||
return (0);
|
||||
} /* hfcpci_auxcmd */
|
||||
|
||||
|
@ -1066,7 +965,6 @@ hfcpci_auxcmd(hfc_pci_t *hc, isdn_ctrl * ic)
|
|||
static void
|
||||
receive_emsg(hfc_pci_t *hc)
|
||||
{
|
||||
long flags;
|
||||
int rcnt;
|
||||
int receive, count = 5;
|
||||
bzfifo_type *bz;
|
||||
|
@ -1076,18 +974,10 @@ receive_emsg(hfc_pci_t *hc)
|
|||
int total, maxlen, new_z2;
|
||||
u_char e_buffer[256];
|
||||
|
||||
save_flags(flags);
|
||||
bz = &((fifo_area *) (hc->hw.fifos))->b_chans.rxbz_b2;
|
||||
bdata = ((fifo_area *) (hc->hw.fifos))->b_chans.rxdat_b2;
|
||||
Begin:
|
||||
count--;
|
||||
cli();
|
||||
if (test_and_set_bit(FLG_LOCK_ATOMIC, &dch->DFlags)) {
|
||||
debugl1(hc, "echo_rec_data blocked");
|
||||
restore_flags(flags);
|
||||
return;
|
||||
}
|
||||
sti();
|
||||
if (bz->f1 != bz->f2) {
|
||||
if (hc->debug & L1_DEB_ISAC)
|
||||
debugl1(hc, "hfcpci e_rec f1(%d) f2(%d)",
|
||||
|
@ -1159,10 +1049,8 @@ receive_emsg(hfc_pci_t *hc)
|
|||
receive = 0;
|
||||
} else
|
||||
receive = 0;
|
||||
test_and_clear_bit(FLG_LOCK_ATOMIC, &dch->DFlags);
|
||||
if (count && receive)
|
||||
goto Begin;
|
||||
restore_flags(flags);
|
||||
return;
|
||||
} /* receive_emsg */
|
||||
|
||||
|
@ -1177,28 +1065,61 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|||
hfc_pci_t *hc = dev_id;
|
||||
u_char exval;
|
||||
bchannel_t *bch;
|
||||
int count = 15;
|
||||
long flags;
|
||||
u_char val, stat;
|
||||
|
||||
if (!hc) {
|
||||
printk(KERN_WARNING "HFC-PCI: Spurious interrupt!\n");
|
||||
return;
|
||||
}
|
||||
if (!(hc->hw.int_m2 & 0x08))
|
||||
spin_lock_irqsave(&hc->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
hc->lock.spin_adr = (void *)0x3001;
|
||||
#endif
|
||||
if (!(hc->hw.int_m2 & 0x08)) {
|
||||
#ifdef SPIN_DEBUG
|
||||
hc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&hc->lock.lock, flags);
|
||||
return; /* not initialised */
|
||||
}
|
||||
|
||||
if (HFCPCI_ANYINT & (stat = Read_hfc(hc, HFCPCI_STATUS))) {
|
||||
val = Read_hfc(hc, HFCPCI_INT_S1);
|
||||
if (hc->dch.debug & L1_DEB_ISAC)
|
||||
debugprint(&hc->dch.inst, "HFC-PCI: stat(%02x) s1(%02x)",
|
||||
stat, val);
|
||||
} else
|
||||
} else {
|
||||
/* shared */
|
||||
#ifdef SPIN_DEBUG
|
||||
hc->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&hc->lock.lock, flags);
|
||||
return;
|
||||
}
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &hc->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%x\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)
|
||||
debugprint(&hc->dch.inst, "HFC-PCI irq %x %s", val,
|
||||
test_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags) ?
|
||||
"locked" : "unlocked");
|
||||
debugprint(&hc->dch.inst, "HFC-PCI irq %x", val);
|
||||
val &= hc->hw.int_m1;
|
||||
if (val & 0x40) { /* state machine irq */
|
||||
exval = Read_hfc(hc, HFCPCI_STATES) & 0xf;
|
||||
|
@ -1206,144 +1127,137 @@ hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|||
debugprint(&hc->dch.inst, "ph_state chg %d->%d",
|
||||
hc->dch.ph_state, exval);
|
||||
hc->dch.ph_state = exval;
|
||||
sched_event_D_pci(hc, D_L1STATECHANGE);
|
||||
dchannel_sched_event(&hc->dch, D_L1STATECHANGE);
|
||||
val &= ~0x40;
|
||||
}
|
||||
if (val & 0x80) { /* timer irq */
|
||||
if (hc->hw.nt_mode) {
|
||||
if ((--hc->hw.nt_timer) < 0)
|
||||
sched_event_D_pci(hc, D_L1STATECHANGE);
|
||||
dchannel_sched_event(&hc->dch, D_L1STATECHANGE);
|
||||
}
|
||||
val &= ~0x80;
|
||||
Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER);
|
||||
}
|
||||
while (val) {
|
||||
save_flags(flags);
|
||||
cli();
|
||||
if (test_bit(FLG_LOCK_ATOMIC, &hc->dch.DFlags)) {
|
||||
hc->hw.int_s1 |= val;
|
||||
restore_flags(flags);
|
||||
return;
|
||||
}
|
||||
if (hc->hw.int_s1 & 0x18) {
|
||||
exval = val;
|
||||
val = hc->hw.int_s1;
|
||||
hc->hw.int_s1 = exval;
|
||||
}
|
||||
if (val & 0x08) {
|
||||
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
|
||||
if (hc->dch.debug)
|
||||
debugprint(&hc->dch.inst, "hfcpci spurious 0x08 IRQ");
|
||||
} else
|
||||
main_rec_hfcpci(bch);
|
||||
}
|
||||
if (val & 0x10) {
|
||||
// if (hc->logecho)
|
||||
// receive_emsg(hc);
|
||||
// else
|
||||
if (!(bch = Sel_BCS(hc, 2))) {
|
||||
if (hc->dch.debug)
|
||||
debugprint(&hc->dch.inst, "hfcpci spurious 0x10 IRQ");
|
||||
} else
|
||||
main_rec_hfcpci(bch);
|
||||
}
|
||||
if (val & 0x01) {
|
||||
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
|
||||
if (hc->dch.debug)
|
||||
debugprint(&hc->dch.inst, "hfcpci spurious 0x01 IRQ");
|
||||
} else {
|
||||
if (bch->tx_idx < bch->tx_len) {
|
||||
hfcpci_send_data(bch);
|
||||
} else {
|
||||
bch->tx_idx = 0;
|
||||
if (test_and_clear_bit(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_send_data(bch);
|
||||
hfcpci_sched_event(bch, B_XMTBUFREADY);
|
||||
} else {
|
||||
printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
bch->tx_len = 0;
|
||||
}
|
||||
} else {
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
hfcpci_sched_event(bch, B_XMTBUFREADY);
|
||||
bch->tx_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (val & 0x02) {
|
||||
if (!(bch = Sel_BCS(hc, 2))) {
|
||||
if (hc->dch.debug)
|
||||
debugprint(&hc->dch.inst, "hfcpci spurious 0x02 IRQ");
|
||||
} else {
|
||||
if (bch->tx_idx < bch->tx_len) {
|
||||
hfcpci_send_data(bch);
|
||||
} else {
|
||||
bch->tx_idx = 0;
|
||||
if (test_and_clear_bit(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_send_data(bch);
|
||||
hfcpci_sched_event(bch, B_XMTBUFREADY);
|
||||
} else {
|
||||
printk(KERN_WARNING "hfcB tx irq TX_NEXT without skb\n");
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
bch->tx_len = 0;
|
||||
}
|
||||
} else {
|
||||
test_and_clear_bit(FLG_TX_BUSY, &bch->Flag);
|
||||
hfcpci_sched_event(bch, B_XMTBUFREADY);
|
||||
bch->tx_len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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))
|
||||
sched_event_D_pci(hc, D_CLEARBUSY);
|
||||
if (hc->dch.tx_idx < hc->dch.tx_len) {
|
||||
hfcD_send_fifo(&hc->dch);
|
||||
} 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;
|
||||
hfcD_send_fifo(&hc->dch);
|
||||
sched_event_D_pci(hc, 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 (hc->hw.int_s1 && count--) {
|
||||
val = hc->hw.int_s1;
|
||||
hc->hw.int_s1 = 0;
|
||||
if (hc->dch.debug & L1_DEB_ISAC)
|
||||
debugprint(&hc->dch.inst, "HFC-PCI irq %x loop %d", val, 15 - count);
|
||||
if (val & 0x08) {
|
||||
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
|
||||
if (hc->dch.debug)
|
||||
debugprint(&hc->dch.inst, "hfcpci spurious 0x08 IRQ");
|
||||
} else
|
||||
val = 0;
|
||||
restore_flags(flags);
|
||||
main_rec_hfcpci(bch);
|
||||
}
|
||||
if (val & 0x10) {
|
||||
// if (hc->logecho)
|
||||
// receive_emsg(hc);
|
||||
// else
|
||||
if (!(bch = Sel_BCS(hc, 2))) {
|
||||
if (hc->dch.debug)
|
||||
debugprint(&hc->dch.inst, "hfcpci spurious 0x10 IRQ");
|
||||
} else
|
||||
main_rec_hfcpci(bch);
|
||||
}
|
||||
if (val & 0x01) {
|
||||
if (!(bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1))) {
|
||||
if (hc->dch.debug)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (val & 0x02) {
|
||||
if (!(bch = Sel_BCS(hc, 2))) {
|
||||
if (hc->dch.debug)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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(%x)\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);
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
|
@ -1364,7 +1278,6 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
hfc_pci_t *hc;
|
||||
int ret = -EINVAL;
|
||||
hisax_head_t *hh;
|
||||
long flags;
|
||||
|
||||
if (!hif || !skb)
|
||||
return(ret);
|
||||
|
@ -1387,7 +1300,7 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
dch->tx_len = skb->len;
|
||||
memcpy(dch->tx_buf, skb->data, dch->tx_len);
|
||||
dch->tx_idx = 0;
|
||||
hfcD_send_fifo(dch);
|
||||
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,
|
||||
|
@ -1426,7 +1339,7 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
sched_event_D_pci(hc, D_CLEARBUSY);
|
||||
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) {
|
||||
|
@ -1440,11 +1353,8 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
__FUNCTION__, slot);
|
||||
Write_hfc(hc, HFCPCI_B1_SSL, slot);
|
||||
Write_hfc(hc, HFCPCI_B1_RSL, slot);
|
||||
save_flags(flags);
|
||||
cli();
|
||||
hc->hw.conn = (hc->hw.conn & ~7) | 1;
|
||||
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
|
||||
restore_flags(flags);
|
||||
}
|
||||
if (2 & hh->dinfo) {
|
||||
if (test_bit(HFC_CFG_SW_DD_DU, &hc->cfg))
|
||||
|
@ -1455,20 +1365,14 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
__FUNCTION__, slot);
|
||||
Write_hfc(hc, HFCPCI_B2_SSL, slot);
|
||||
Write_hfc(hc, HFCPCI_B2_RSL, slot);
|
||||
save_flags(flags);
|
||||
cli();
|
||||
hc->hw.conn = (hc->hw.conn & ~0x38) | 0x08;
|
||||
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
|
||||
restore_flags(flags);
|
||||
}
|
||||
save_flags(flags);
|
||||
cli();
|
||||
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);
|
||||
restore_flags(flags);
|
||||
} else {
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
debugprint(&dch->inst, "%s: unknown ctrl %x",
|
||||
|
@ -1510,7 +1414,7 @@ HFCD_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
sched_event_D_pci(hc, D_CLEARBUSY);
|
||||
dchannel_sched_event(&hc->dch, D_CLEARBUSY);
|
||||
dch->inst.unlock(dch->inst.data);
|
||||
} else {
|
||||
if (dch->debug & L1_DEB_WARN)
|
||||
|
@ -1536,7 +1440,6 @@ static int
|
|||
mode_hfcpci(bchannel_t *bch, int bc, int protocol)
|
||||
{
|
||||
hfc_pci_t *hc = bch->inst.data;
|
||||
long flags;
|
||||
int fifo2;
|
||||
u_char rx_slot = 0, tx_slot = 0, pcm_mode;
|
||||
|
||||
|
@ -1556,8 +1459,6 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
|
|||
} else if (test_bit(HFC_CFG_PCM, &hc->cfg) && (protocol > ISDN_PID_NONE))
|
||||
printk(KERN_WARNING "%s: no pcm channel id but HFC_CFG_PCM\n",
|
||||
__FUNCTION__);
|
||||
save_flags(flags);
|
||||
cli();
|
||||
if (hc->chanlimit > 1) {
|
||||
hc->hw.bswapped = 0; /* B1 and B2 normal mode */
|
||||
hc->hw.sctrl_e &= ~0x80;
|
||||
|
@ -1582,7 +1483,6 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
|
|||
bch->channel = bc;
|
||||
case (ISDN_PID_NONE):
|
||||
if (bch->protocol == ISDN_PID_NONE) {
|
||||
restore_flags(flags);
|
||||
return(0);
|
||||
}
|
||||
if (bc & 2) {
|
||||
|
@ -1677,7 +1577,6 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
|
|||
#endif
|
||||
default:
|
||||
debugprint(&bch->inst, "prot not known %x", protocol);
|
||||
restore_flags(flags);
|
||||
return(-ENOPROTOOPT);
|
||||
}
|
||||
if (test_bit(HFC_CFG_PCM, &hc->cfg)) {
|
||||
|
@ -1723,8 +1622,7 @@ mode_hfcpci(bchannel_t *bch, int bc, int protocol)
|
|||
Write_hfc(hc, HFCPCI_CONNECT, hc->hw.conn);
|
||||
Write_hfc(hc, HFCPCI_CIRM, hc->hw.cirm);
|
||||
if (bch->protocol)
|
||||
hfcpci_sched_event(bch, B_XMTBUFREADY);
|
||||
restore_flags(flags);
|
||||
bch_sched_event(bch, B_XMTBUFREADY);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
@ -1750,8 +1648,8 @@ hfcpci_l2l1(hisaxif_t *hif, struct sk_buff *skb)
|
|||
return(-EBUSY);
|
||||
}
|
||||
bch->inst.lock(bch->inst.data);
|
||||
if (test_and_set_bit(FLG_TX_BUSY, &bch->Flag)) {
|
||||
test_and_set_bit(FLG_TX_NEXT, &bch->Flag);
|
||||
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);
|
||||
|
@ -1759,7 +1657,7 @@ hfcpci_l2l1(hisaxif_t *hif, struct sk_buff *skb)
|
|||
bch->tx_len = skb->len;
|
||||
memcpy(bch->tx_buf, skb->data, bch->tx_len);
|
||||
bch->tx_idx = 0;
|
||||
hfcpci_send_data(bch);
|
||||
hfcpci_fill_fifo(bch);
|
||||
bch->inst.unlock(bch->inst.data);
|
||||
if ((bch->inst.pid.protocol[2] == ISDN_PID_L2_B_RAWDEV)
|
||||
&& bch->dev)
|
||||
|
@ -1790,11 +1688,11 @@ hfcpci_l2l1(hisaxif_t *hif, struct sk_buff *skb)
|
|||
(hh->prim == (DL_RELEASE | REQUEST)) ||
|
||||
(hh->prim == (MGR_DISCONNECT | REQUEST))) {
|
||||
bch->inst.lock(bch->inst.data);
|
||||
if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flag)) {
|
||||
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(FLG_TX_BUSY, &bch->Flag);
|
||||
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);
|
||||
|
@ -1933,8 +1831,6 @@ hfcD_bh(dchannel_t *dch)
|
|||
// printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, dch->event);
|
||||
if (test_and_clear_bit(D_L1STATECHANGE, &dch->event))
|
||||
hfcD_newstate(dch);
|
||||
if (test_and_clear_bit(D_BLOCKEDATOMIC, &dch->event))
|
||||
hfcD_send_fifo(dch);
|
||||
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
|
||||
struct sk_buff *skb = dch->next_skb;
|
||||
hisax_head_t *hh;
|
||||
|
@ -1973,8 +1869,6 @@ hfcB_bh(bchannel_t *bch)
|
|||
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_BLOCKEDATOMIC, &bch->event))
|
||||
hfcpci_send_data(bch);
|
||||
if (test_and_clear_bit(B_XMTBUFREADY, &bch->event)) {
|
||||
skb = bch->next_skb;
|
||||
if (skb) {
|
||||
|
@ -2243,7 +2137,6 @@ setup_hfcpci(hfc_pci_t *hc)
|
|||
#endif
|
||||
strcpy(tmp, hfcpci_revision);
|
||||
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
|
||||
hc->hw.int_s1 = 0;
|
||||
hc->hw.cirm = 0;
|
||||
hc->dch.ph_state = 0;
|
||||
while (id_list[i].vendor_id) {
|
||||
|
@ -2307,7 +2200,8 @@ setup_hfcpci(hfc_pci_t *hc)
|
|||
init_timer(&hc->hw.timer);
|
||||
lock_dev(hc);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "lock_adr=%p now(%p)\n", &hc->lock_adr, hc->lock_adr);
|
||||
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);
|
||||
|
@ -2513,7 +2407,7 @@ HFC_init(void)
|
|||
APPEND_TO_LIST(card, ((hfc_pci_t *)HFC_obj.ilist));
|
||||
card->dch.debug = debug;
|
||||
card->dch.inst.obj = &HFC_obj;
|
||||
spin_lock_init(&card->devlock);
|
||||
lock_HW_init(&card->lock);
|
||||
card->dch.inst.lock = lock_dev;
|
||||
card->dch.inst.unlock = unlock_dev;
|
||||
card->dch.inst.data = card;
|
||||
|
|
|
@ -238,7 +238,6 @@ typedef union {
|
|||
u_char fill[32768];
|
||||
} fifo_area;
|
||||
|
||||
|
||||
#define Write_hfc(a,b,c) (*(((u_char *)a->hw.pci_io)+b) = c)
|
||||
#define Read_hfc(a,b) (*(((u_char *)a->hw.pci_io)+b))
|
||||
|
||||
|
|
|
@ -1,214 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* Basic declarations, defines for HiSax hardware drivers
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/hisaxif.h>
|
||||
#include <linux/tqueue.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/skbuff.h>
|
||||
#ifdef MEMDBG
|
||||
#include "memdbg.h"
|
||||
#endif
|
||||
|
||||
#define MAX_DFRAME_LEN_L1 300
|
||||
#define MAX_MON_FRAME 32
|
||||
#define MAX_DLOG_SPACE 2048
|
||||
#define MAX_BLOG_SPACE 256
|
||||
|
||||
struct hdlc_stat_reg {
|
||||
#ifdef __BIG_ENDIAN
|
||||
u_char fill __attribute__((packed));
|
||||
u_char mode __attribute__((packed));
|
||||
u_char xml __attribute__((packed));
|
||||
u_char cmd __attribute__((packed));
|
||||
#else
|
||||
u_char cmd __attribute__((packed));
|
||||
u_char xml __attribute__((packed));
|
||||
u_char mode __attribute__((packed));
|
||||
u_char fill __attribute__((packed));
|
||||
#endif
|
||||
};
|
||||
|
||||
struct isar_reg {
|
||||
unsigned int Flags;
|
||||
volatile u_char bstat;
|
||||
volatile u_char iis;
|
||||
volatile u_char cmsb;
|
||||
volatile u_char clsb;
|
||||
volatile u_char par[8];
|
||||
};
|
||||
|
||||
struct isar_hw {
|
||||
int dpath;
|
||||
int mml;
|
||||
u_char state;
|
||||
u_char cmd;
|
||||
u_char mod;
|
||||
u_char newcmd;
|
||||
u_char newmod;
|
||||
char try_mod;
|
||||
struct timer_list ftimer;
|
||||
u_char conmsg[16];
|
||||
struct isar_reg *reg;
|
||||
};
|
||||
|
||||
struct hdlc_hw {
|
||||
union {
|
||||
u_int ctrl;
|
||||
struct hdlc_stat_reg sr;
|
||||
} ctrl;
|
||||
u_int stat;
|
||||
};
|
||||
|
||||
|
||||
struct hfcB_hw {
|
||||
unsigned int *send;
|
||||
int f1;
|
||||
int f2;
|
||||
};
|
||||
|
||||
#define BC_FLG_INIT 1
|
||||
#define BC_FLG_ACTIV 2
|
||||
// #define BC_FLG_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
|
||||
|
||||
typedef struct _bchannel_t {
|
||||
int channel;
|
||||
int protocol;
|
||||
int Flag;
|
||||
int debug;
|
||||
hisaxstack_t *st;
|
||||
hisaxinstance_t inst;
|
||||
hisaxdevice_t *dev;
|
||||
u_char (*BC_Read_Reg)(void *, int, u_char);
|
||||
void (*BC_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 tq_struct tqueue;
|
||||
int event;
|
||||
int err_crc;
|
||||
int err_tx;
|
||||
int err_rdo;
|
||||
int err_inv;
|
||||
union {
|
||||
struct hdlc_hw hdlc;
|
||||
struct isar_hw isar;
|
||||
} hw;
|
||||
} bchannel_t;
|
||||
|
||||
struct arcofi_msg {
|
||||
struct arcofi_msg *next;
|
||||
u_char receive;
|
||||
u_char len;
|
||||
u_char msg[10];
|
||||
};
|
||||
|
||||
#define HW_IOM1 0
|
||||
#define HW_IPAC 1
|
||||
#define HW_ISAR 2
|
||||
#define HW_ARCOFI 3
|
||||
#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 {
|
||||
hisaxinstance_t inst;
|
||||
u_int 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 err_crc;
|
||||
int err_tx;
|
||||
int err_rx;
|
||||
void *hw;
|
||||
struct timer_list dbusytimer;
|
||||
u_int event;
|
||||
struct sk_buff_head rqueue; /* D-channel receive queue */
|
||||
struct tq_struct tqueue;
|
||||
} dchannel_t;
|
||||
|
||||
#define MON0_RX 1
|
||||
#define MON1_RX 2
|
||||
#define MON0_TX 4
|
||||
#define MON1_TX 8
|
||||
|
||||
/* L1 Debug */
|
||||
#define L1_DEB_WARN 0x01
|
||||
#define L1_DEB_INTSTAT 0x02
|
||||
#define L1_DEB_ISAC 0x04
|
||||
#define L1_DEB_ISAC_FIFO 0x08
|
||||
#define L1_DEB_HSCX 0x10
|
||||
#define L1_DEB_HSCX_FIFO 0x20
|
||||
#define L1_DEB_LAPD 0x40
|
||||
#define L1_DEB_IPAC 0x80
|
||||
#define L1_DEB_RECEIVE_FRAME 0x100
|
||||
#define L1_DEB_MONITOR 0x200
|
||||
#define DEB_DLOG_HEX 0x400
|
||||
#define DEB_DLOG_VERBOSE 0x800
|
||||
|
||||
int init_dchannel(dchannel_t *);
|
||||
int free_dchannel(dchannel_t *);
|
||||
int init_bchannel(bchannel_t *);
|
||||
int free_bchannel(bchannel_t *);
|
||||
|
||||
void set_dchannel_pid(hisax_pid_t *, int, int);
|
||||
|
||||
#ifdef __powerpc__
|
||||
#include <linux/pci.h>
|
||||
static inline int pci_enable_device(struct pci_dev *dev)
|
||||
{
|
||||
u16 cmd;
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR;
|
||||
cmd &= ~PCI_COMMAND_FAST_BACK;
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
#define pci_enable_device(dev) !dev
|
||||
#endif /* __powerpc__ */
|
|
@ -0,0 +1,118 @@
|
|||
/* $Id$
|
||||
*
|
||||
* hw_lock.h HArdware locking inline routines
|
||||
*
|
||||
* Author Karsten Keil (keil@isdn4linux.de)
|
||||
*
|
||||
* This file is (c) under GNU PUBLIC LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __hw_lock__
|
||||
#define __hw_lock__
|
||||
|
||||
typedef struct _hisax_HWlock {
|
||||
u_long flags;
|
||||
spinlock_t lock;
|
||||
#ifdef SPIN_DEBUG
|
||||
void *spin_adr;
|
||||
void *busy_adr;
|
||||
#endif
|
||||
volatile u_int state;
|
||||
#ifdef LOCK_STATISTIC
|
||||
u_int try_ok;
|
||||
u_int try_wait;
|
||||
u_int try_inirq;
|
||||
u_int try_mult;
|
||||
u_int irq_ok;
|
||||
u_int irq_fail;
|
||||
#endif
|
||||
} hisax_HWlock_t;
|
||||
|
||||
#define STATE_FLAG_BUSY 1
|
||||
#define STATE_FLAG_INIRQ 2
|
||||
|
||||
|
||||
static inline void lock_HW(hisax_HWlock_t *lock)
|
||||
{
|
||||
register u_long flags;
|
||||
#ifdef LOCK_STATISTIC
|
||||
int wait = 0;
|
||||
#endif
|
||||
|
||||
spin_lock_irqsave(&lock->lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->spin_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
while (test_and_set_bit(STATE_FLAG_BUSY, &lock->state)) {
|
||||
/* allready busy so we delay */
|
||||
spin_unlock_irqrestore(&lock->lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->spin_adr = NULL;
|
||||
#endif
|
||||
/* delay 1 jiffie is enought */
|
||||
if (in_interrupt()) {
|
||||
#ifdef LOCK_STATISTIC
|
||||
lock->try_inirq++;
|
||||
#endif
|
||||
printk(KERN_ERR "lock_HW: try to schedule in IRQ state(%x)\n",
|
||||
lock->state);
|
||||
mdelay(1);
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
if (wait++)
|
||||
lock->try_mult++;
|
||||
else
|
||||
lock->try_wait++;
|
||||
#endif
|
||||
schedule_timeout(1);
|
||||
}
|
||||
spin_lock_irqsave(&lock->lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->spin_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
}
|
||||
/* get the LOCK */
|
||||
lock->flags = flags;
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->busy_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
if (!wait)
|
||||
lock->try_ok++;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void unlock_HW(hisax_HWlock_t *lock)
|
||||
{
|
||||
if (!test_and_clear_bit(STATE_FLAG_BUSY, &lock->state)) {
|
||||
printk(KERN_ERR "lock_HW: STATE_FLAG_BUSY not locked state(%x)\n",
|
||||
lock->state);
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->busy_adr = NULL;
|
||||
lock->spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&lock->lock, lock->flags);
|
||||
}
|
||||
|
||||
static inline void lock_HW_init(hisax_HWlock_t *lock)
|
||||
{
|
||||
spin_lock_init(&lock->lock);
|
||||
lock->state = 0;
|
||||
#ifdef SPIN_DEBUG
|
||||
lock->busy_adr = NULL;
|
||||
lock->spin_adr = NULL;
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
lock->try_ok = 0;
|
||||
lock->try_wait = 0;
|
||||
lock->try_inirq = 0;
|
||||
lock->try_mult = 0;
|
||||
lock->irq_ok = 0;
|
||||
lock->irq_fail = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define __NO_VERSION__
|
||||
#include <linux/module.h>
|
||||
#include "hisax_hw.h"
|
||||
#include "hisax_dch.h"
|
||||
#include "isac.h"
|
||||
#include "arcofi.h"
|
||||
#include "hisaxl1.h"
|
||||
|
@ -95,26 +95,10 @@ isac_new_ph(dchannel_t *dch)
|
|||
}
|
||||
|
||||
static void
|
||||
isac_rcv(dchannel_t *dch)
|
||||
isac_hwbh(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: isac deliver err %d\n", err);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
isac_bh(dchannel_t *dch)
|
||||
{
|
||||
if (!dch)
|
||||
return;
|
||||
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, dch->event);
|
||||
if (dch->debug)
|
||||
printk(KERN_DEBUG "%s: event %x\n", __FUNCTION__, dch->event);
|
||||
#if 0
|
||||
if (test_and_clear_bit(D_CLEARBUSY, &dch->event)) {
|
||||
if (dch->debug)
|
||||
|
@ -128,19 +112,6 @@ isac_bh(dchannel_t *dch)
|
|||
#endif
|
||||
if (test_and_clear_bit(D_L1STATECHANGE, &dch->event))
|
||||
isac_new_ph(dch);
|
||||
if (test_and_clear_bit(D_XMTBUFREADY, &dch->event)) {
|
||||
struct sk_buff *skb = dch->next_skb;
|
||||
|
||||
if (skb) {
|
||||
dch->next_skb = NULL;
|
||||
skb_trim(skb, 0);
|
||||
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))
|
||||
isac_rcv(dch);
|
||||
#if ARCOFI_USE
|
||||
if (!test_bit(HW_ARCOFI, &dch->DFlags))
|
||||
return;
|
||||
|
@ -223,14 +194,6 @@ isac_fill_fifo(dchannel_t *dch)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
isac_sched_event(dchannel_t *dch, int event)
|
||||
{
|
||||
test_and_set_bit(event, &dch->event);
|
||||
queue_task(&dch->tqueue, &tq_immediate);
|
||||
mark_bh(IMMEDIATE_BH);
|
||||
}
|
||||
|
||||
void
|
||||
ISAC_interrupt(dchannel_t *dch, u_char val)
|
||||
{
|
||||
|
@ -269,7 +232,7 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
skb_queue_tail(&dch->rqueue, dch->rx_skb);
|
||||
}
|
||||
dch->rx_skb = NULL;
|
||||
isac_sched_event(dch, D_RCVBUFREADY);
|
||||
dchannel_sched_event(dch, D_RCVBUFREADY);
|
||||
}
|
||||
if (val & 0x40) { /* RPF */
|
||||
isac_empty_fifo(dch, 32);
|
||||
|
@ -283,7 +246,7 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
isac_sched_event(dch, D_CLEARBUSY);
|
||||
dchannel_sched_event(dch, D_CLEARBUSY);
|
||||
if (dch->tx_idx < dch->tx_len) {
|
||||
isac_fill_fifo(dch);
|
||||
} else {
|
||||
|
@ -294,7 +257,7 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
dch->next_skb->data, dch->tx_len);
|
||||
dch->tx_idx = 0;
|
||||
isac_fill_fifo(dch);
|
||||
isac_sched_event(dch, D_XMTBUFREADY);
|
||||
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);
|
||||
|
@ -312,7 +275,7 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
if (dch->debug & L1_DEB_ISAC)
|
||||
debugprint(&dch->inst, "ph_state change %x", dch->ph_state);
|
||||
/* unconditional reset procedure */
|
||||
isac_sched_event(dch, D_L1STATECHANGE);
|
||||
dchannel_sched_event(dch, D_L1STATECHANGE);
|
||||
}
|
||||
if (exval & 1) {
|
||||
exval = dch->read_reg(dch->inst.data, ISAC_CIR1);
|
||||
|
@ -342,7 +305,7 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
isac_sched_event(dch, D_CLEARBUSY);
|
||||
dchannel_sched_event(dch, D_CLEARBUSY);
|
||||
if (test_bit(FLG_TX_BUSY, &dch->DFlags)) {
|
||||
/* Restart frame */
|
||||
dch->tx_idx = 0;
|
||||
|
@ -358,7 +321,7 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
dch->tx_len);
|
||||
dch->tx_idx = 0;
|
||||
isac_fill_fifo(dch);
|
||||
isac_sched_event(dch, D_XMTBUFREADY);
|
||||
dchannel_sched_event(dch, D_XMTBUFREADY);
|
||||
} else {
|
||||
printk(KERN_WARNING "isac xdu irq TX_NEXT without skb\n");
|
||||
}
|
||||
|
@ -433,14 +396,14 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
isac->mocr |= 0x0a;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
isac_sched_event(dch, D_RX_MON0);
|
||||
dchannel_sched_event(dch, D_RX_MON0);
|
||||
}
|
||||
if (v1 & 0x40) {
|
||||
isac->mocr &= 0x0f;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
isac->mocr |= 0xa0;
|
||||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
isac_sched_event(dch, D_RX_MON1);
|
||||
dchannel_sched_event(dch, D_RX_MON1);
|
||||
}
|
||||
if (v1 & 0x02) {
|
||||
if ((!isac->mon_tx) || (isac->mon_txc &&
|
||||
|
@ -452,11 +415,11 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
if (isac->mon_txc &&
|
||||
(isac->mon_txp >= isac->mon_txc))
|
||||
isac_sched_event(dch, D_TX_MON0);
|
||||
dchannel_sched_event(dch, D_TX_MON0);
|
||||
goto AfterMOX0;
|
||||
}
|
||||
if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
|
||||
isac_sched_event(dch, D_TX_MON0);
|
||||
dchannel_sched_event(dch, D_TX_MON0);
|
||||
goto AfterMOX0;
|
||||
}
|
||||
dch->write_reg(dch->inst.data, ISAC_MOX0,
|
||||
|
@ -475,11 +438,11 @@ ISAC_interrupt(dchannel_t *dch, u_char val)
|
|||
dch->write_reg(dch->inst.data, ISAC_MOCR, isac->mocr);
|
||||
if (isac->mon_txc &&
|
||||
(isac->mon_txp >= isac->mon_txc))
|
||||
isac_sched_event(dch, D_TX_MON1);
|
||||
dchannel_sched_event(dch, D_TX_MON1);
|
||||
goto AfterMOX1;
|
||||
}
|
||||
if (isac->mon_txc && (isac->mon_txp >= isac->mon_txc)) {
|
||||
isac_sched_event(dch, D_TX_MON1);
|
||||
dchannel_sched_event(dch, D_TX_MON1);
|
||||
goto AfterMOX1;
|
||||
}
|
||||
dch->write_reg(dch->inst.data, ISAC_MOX1,
|
||||
|
@ -557,7 +520,7 @@ ISAC_l1hw(hisaxif_t *hif, struct sk_buff *skb)
|
|||
if (test_and_clear_bit(FLG_DBUSY_TIMER, &dch->DFlags))
|
||||
del_timer(&dch->dbusytimer);
|
||||
if (test_and_clear_bit(FLG_L1_DBUSY, &dch->DFlags))
|
||||
isac_sched_event(dch, D_CLEARBUSY);
|
||||
dchannel_sched_event(dch, D_CLEARBUSY);
|
||||
} else if ((hh->dinfo & HW_TESTLOOP) == HW_TESTLOOP) {
|
||||
tl = 0;
|
||||
if (1 & hh->dinfo)
|
||||
|
@ -617,8 +580,6 @@ ISAC_free(dchannel_t *dch) {
|
|||
kfree(isac->mon_tx);
|
||||
isac->mon_tx = NULL;
|
||||
}
|
||||
kfree(isac);
|
||||
dch->hw = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -665,7 +626,7 @@ static char *ISACVer[] =
|
|||
int
|
||||
ISAC_init(dchannel_t *dch)
|
||||
{
|
||||
isac_chip_t *isac = kmalloc(sizeof(isac_chip_t), GFP_ATOMIC);
|
||||
isac_chip_t *isac = dch->hw;
|
||||
u_char val;
|
||||
|
||||
dch->write_reg(dch->inst.data, ISAC_MASK, 0xff);
|
||||
|
@ -674,8 +635,7 @@ ISAC_init(dchannel_t *dch)
|
|||
|
||||
if (!isac)
|
||||
return(-ENOMEM);
|
||||
dch->hw = isac;
|
||||
dch->tqueue.routine = (void *) (void *) isac_bh;
|
||||
dch->hw_bh = isac_hwbh;
|
||||
isac->mon_tx = NULL;
|
||||
isac->mon_rx = NULL;
|
||||
dch->dbusytimer.function = (void *) dbusy_timer_handler;
|
||||
|
@ -701,7 +661,7 @@ ISAC_init(dchannel_t *dch)
|
|||
dch->write_reg(dch->inst.data, ISAC_TIMR, 0x00);
|
||||
dch->write_reg(dch->inst.data, ISAC_ADF1, 0x00);
|
||||
}
|
||||
isac_sched_event(dch, D_L1STATECHANGE);
|
||||
dchannel_sched_event(dch, D_L1STATECHANGE);
|
||||
ph_command(dch, ISAC_CMD_RS);
|
||||
dch->write_reg(dch->inst.data, ISAC_MASK, 0x0);
|
||||
return 0;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -8,6 +8,29 @@
|
|||
*
|
||||
*/
|
||||
|
||||
typedef struct _isar_reg {
|
||||
unsigned int Flags;
|
||||
volatile u_char bstat;
|
||||
volatile u_char iis;
|
||||
volatile u_char cmsb;
|
||||
volatile u_char clsb;
|
||||
volatile u_char par[8];
|
||||
} isar_reg_t;
|
||||
|
||||
typedef struct _isar_hw {
|
||||
int dpath;
|
||||
int mml;
|
||||
u_char state;
|
||||
u_char cmd;
|
||||
u_char mod;
|
||||
u_char newcmd;
|
||||
u_char newmod;
|
||||
char try_mod;
|
||||
struct timer_list ftimer;
|
||||
u_char conmsg[16];
|
||||
isar_reg_t *reg;
|
||||
} isar_hw_t;
|
||||
|
||||
#define ISAR_IRQMSK 0x04
|
||||
#define ISAR_IRQSTA 0x04
|
||||
#define ISAR_IRQBIT 0x75
|
||||
|
|
|
@ -34,3 +34,18 @@
|
|||
#define FLG_L1_PULL_REQ 6
|
||||
#define FLG_L1_UINT 7
|
||||
#define FLG_L1_DBLOCKED 8
|
||||
|
||||
/* L1 Debug */
|
||||
#define L1_DEB_WARN 0x01
|
||||
#define L1_DEB_INTSTAT 0x02
|
||||
#define L1_DEB_ISAC 0x04
|
||||
#define L1_DEB_ISAC_FIFO 0x08
|
||||
#define L1_DEB_HSCX 0x10
|
||||
#define L1_DEB_HSCX_FIFO 0x20
|
||||
#define L1_DEB_LAPD 0x40
|
||||
#define L1_DEB_IPAC 0x80
|
||||
#define L1_DEB_RECEIVE_FRAME 0x100
|
||||
#define L1_DEB_MONITOR 0x200
|
||||
#define DEB_DLOG_HEX 0x400
|
||||
#define DEB_DLOG_VERBOSE 0x800
|
||||
|
||||
|
|
|
@ -32,13 +32,18 @@
|
|||
#include <linux/kernel_stat.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include "hisax_hw.h"
|
||||
#include "hisax_dch.h"
|
||||
#include "hisax_bch.h"
|
||||
#include "isac.h"
|
||||
#include "isar.h"
|
||||
#include "hisaxl1.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$";
|
||||
|
@ -98,8 +103,6 @@ const char *Sedlbauer_Types[] =
|
|||
#define SEDL_RESET 0x3 /* same as DOS driver */
|
||||
|
||||
/* data struct */
|
||||
#define SPIN_DEBUG
|
||||
#define LOCK_STATISTIC
|
||||
|
||||
typedef struct _sedl_fax {
|
||||
struct _sedl_fax *prev;
|
||||
|
@ -110,28 +113,27 @@ typedef struct _sedl_fax {
|
|||
u_int addr;
|
||||
u_int isac;
|
||||
u_int isar;
|
||||
spinlock_t devlock;
|
||||
#ifdef SPIN_DEBUG
|
||||
void *spin_lock_adr;
|
||||
void *sem_lock_adr;
|
||||
#endif
|
||||
volatile u_int state;
|
||||
struct semaphore sem;
|
||||
#ifdef LOCK_STATISTIC
|
||||
u_int try_ok;
|
||||
u_int try_fail;
|
||||
u_int try_inirq;
|
||||
u_int try_pend;
|
||||
u_int irq_ok;
|
||||
u_int irq_fail;
|
||||
u_int irq_pend;
|
||||
#endif
|
||||
struct isar_reg ir;
|
||||
hisax_HWlock_t lock;
|
||||
isar_reg_t ir;
|
||||
isac_chip_t isac_hw;
|
||||
isar_hw_t isar_hw[2];
|
||||
dchannel_t dch;
|
||||
bchannel_t bch[2];
|
||||
} sedl_fax;
|
||||
|
||||
#define STATE_IRQ_PENDING 1
|
||||
static void lock_dev(void *data)
|
||||
{
|
||||
register hisax_HWlock_t *lock = &((sedl_fax *)data)->lock;
|
||||
|
||||
lock_HW(lock);
|
||||
}
|
||||
|
||||
static void unlock_dev(void *data)
|
||||
{
|
||||
register hisax_HWlock_t *lock = &((sedl_fax *)data)->lock;
|
||||
|
||||
unlock_HW(lock);
|
||||
}
|
||||
|
||||
static inline u_char
|
||||
readreg(unsigned int ale, unsigned int adr, u_char off)
|
||||
|
@ -255,119 +257,56 @@ do_sedl_interrupt(sedl_fax *sf)
|
|||
writereg(sf->addr, sf->isar, ISAR_IRQBIT, ISAR_IRQMSK);
|
||||
}
|
||||
|
||||
static int lock_dev(void *data)
|
||||
{
|
||||
register sedl_fax *sf = (sedl_fax *)data;
|
||||
|
||||
if (down_trylock(&sf->sem) != 0) {
|
||||
/* don't get it */
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->try_fail++;
|
||||
#endif
|
||||
if (!in_interrupt()) {
|
||||
down(&sf->sem);
|
||||
} else {
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->try_inirq++;
|
||||
#endif
|
||||
printk(KERN_ERR "Sedlbauer: try to get device lock in IRQ context\n");
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
#ifdef LOCK_STATISTIC
|
||||
else
|
||||
sf->try_ok++;
|
||||
#endif
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->sem_lock_adr = __builtin_return_address(0);
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
static void unlock_dev(void *data)
|
||||
{
|
||||
ulong flags;
|
||||
register sedl_fax *sf = (sedl_fax *)data;
|
||||
|
||||
spin_lock_irqsave(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = (void *)0x1001;
|
||||
#endif
|
||||
while(test_and_clear_bit(STATE_IRQ_PENDING, &sf->state)) {
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->try_pend++;
|
||||
#endif
|
||||
do_sedl_interrupt(sf);
|
||||
spin_lock_irqsave(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = (void *)0x1002;
|
||||
#endif
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->sem_lock_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
up(&sf->sem);
|
||||
}
|
||||
|
||||
static void
|
||||
speedfax_isa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
||||
{
|
||||
sedl_fax *sf = dev_id;
|
||||
u_long flags;
|
||||
|
||||
spin_lock_irqsave(&sf->devlock, flags);
|
||||
spin_lock_irqsave(&sf->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = (void *)0x2001;
|
||||
sf->lock.spin_adr = (void *)0x2001;
|
||||
#endif
|
||||
if (0==down_trylock(&sf->sem)) {
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &sf->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%x\n",
|
||||
__FUNCTION__, sf->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->sem_lock_adr = speedfax_isa_interrupt;
|
||||
printk(KERN_ERR "%s: previous lock:%p\n",
|
||||
__FUNCTION__, sf->lock.busy_adr);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->irq_ok++;
|
||||
sf->lock.irq_fail++;
|
||||
#endif
|
||||
while (1) {
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
do_sedl_interrupt(sf);
|
||||
spin_lock_irqsave(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = (void *)0x2002;
|
||||
#endif
|
||||
if (!test_and_clear_bit(STATE_IRQ_PENDING, &sf->state))
|
||||
break;
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->irq_pend++;
|
||||
#endif
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->sem_lock_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
up(&sf->sem);
|
||||
} else {
|
||||
test_and_set_bit(STATE_IRQ_PENDING, &sf->state);
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->irq_fail++;
|
||||
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);
|
||||
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(%x)\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);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -377,59 +316,58 @@ speedfax_pci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|||
u_long flags;
|
||||
u_char val;
|
||||
|
||||
spin_lock_irqsave(&sf->devlock, flags);
|
||||
spin_lock_irqsave(&sf->lock.lock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = (void *)0x3001;
|
||||
sf->lock.spin_adr = (void *)0x3001;
|
||||
#endif
|
||||
val = bytein(sf->cfg + TIGER_AUX_STATUS);
|
||||
if (val & SEDL_TIGER_IRQ_BIT) { /* for us or shared ? */
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
sf->lock.spin_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->lock.lock, flags);
|
||||
return; /* shared */
|
||||
}
|
||||
if (0==down_trylock(&sf->sem)) {
|
||||
if (test_and_set_bit(STATE_FLAG_BUSY, &sf->lock.state)) {
|
||||
printk(KERN_ERR "%s: STATE_FLAG_BUSY allready activ, should never happen state:%x\n",
|
||||
__FUNCTION__, sf->lock.state);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->sem_lock_adr = speedfax_pci_interrupt;
|
||||
printk(KERN_ERR "%s: previous lock:%p\n",
|
||||
__FUNCTION__, sf->lock.busy_adr);
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->irq_ok++;
|
||||
sf->lock.irq_fail++;
|
||||
#endif
|
||||
while (1) {
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
do_sedl_interrupt(sf);
|
||||
spin_lock_irqsave(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = (void *)0x3002;
|
||||
#endif
|
||||
if (!test_and_clear_bit(STATE_IRQ_PENDING, &sf->state))
|
||||
break;
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->irq_pend++;
|
||||
#endif
|
||||
}
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->sem_lock_adr = NULL;
|
||||
#endif
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
up(&sf->sem);
|
||||
} else {
|
||||
test_and_set_bit(STATE_IRQ_PENDING, &sf->state);
|
||||
spin_unlock_irqrestore(&sf->devlock, flags);
|
||||
#ifdef SPIN_DEBUG
|
||||
sf->spin_lock_adr = NULL;
|
||||
#endif
|
||||
#ifdef LOCK_STATISTIC
|
||||
sf->irq_fail++;
|
||||
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(%x)\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);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -649,6 +587,7 @@ setup_speedfax(sedl_fax *sf, u_int io_cfg, u_int irq_cfg)
|
|||
sf->dch.write_reg = &WriteISAC;
|
||||
sf->dch.read_fifo = &ReadISACfifo;
|
||||
sf->dch.write_fifo = &WriteISACfifo;
|
||||
sf->dch.hw = &sf->isac_hw;
|
||||
if (sf->subtyp != SEDL_SPEEDFAX_ISA) {
|
||||
sf->addr = sf->cfg + SEDL_PCI_ADR;
|
||||
sf->isac = sf->cfg + SEDL_PCI_ISAC;
|
||||
|
@ -668,16 +607,18 @@ setup_speedfax(sedl_fax *sf, u_int io_cfg, u_int irq_cfg)
|
|||
sf->isac = sf->cfg + SEDL_ISA_ISAC;
|
||||
sf->isar = sf->cfg + SEDL_ISA_ISAR;
|
||||
}
|
||||
sf->bch[0].hw.isar.reg = &sf->ir;
|
||||
sf->bch[1].hw.isar.reg = &sf->ir;
|
||||
sf->bch[0].BC_Read_Reg = &ReadISAR;
|
||||
sf->bch[0].BC_Write_Reg = &WriteISAR;
|
||||
sf->bch[1].BC_Read_Reg = &ReadISAR;
|
||||
sf->bch[1].BC_Write_Reg = &WriteISAR;
|
||||
sf->isar_hw[0].reg = &sf->ir;
|
||||
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);
|
||||
#ifdef SPIN_DEBUG
|
||||
printk(KERN_ERR "spin_lock_adr=%p now(%p)\n", &sf->spin_lock_adr, sf->spin_lock_adr);
|
||||
printk(KERN_ERR "sem_lock_adr=%p now(%p)\n", &sf->sem_lock_adr, sf->sem_lock_adr);
|
||||
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);
|
||||
|
@ -696,14 +637,12 @@ static void
|
|||
release_card(sedl_fax *card) {
|
||||
|
||||
#ifdef LOCK_STATISTIC
|
||||
printk(KERN_INFO "try_ok(%d) try_fail(%d) try_pend(%d) try_inirq(%d)\n",
|
||||
card->try_ok, card->try_fail, card->try_pend, card->try_inirq);
|
||||
printk(KERN_INFO "irq_ok(%d) irq_fail(%d) irq_pend(%d)\n",
|
||||
card->irq_ok, card->irq_fail, card->irq_pend);
|
||||
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
|
||||
while(lock_dev(card)) {
|
||||
printk(KERN_WARNING "Sedlbauer release_card waiting for lock\n");
|
||||
}
|
||||
lock_dev(card);
|
||||
free_irq(card->irq, card);
|
||||
free_isar(&card->bch[1]);
|
||||
free_isar(&card->bch[0]);
|
||||
|
@ -718,7 +657,6 @@ release_card(sedl_fax *card) {
|
|||
free_bchannel(&card->bch[0]);
|
||||
free_dchannel(&card->dch);
|
||||
REMOVE_FROM_LISTBASE(card, ((sedl_fax *)speedfax.ilist));
|
||||
test_and_clear_bit(STATE_IRQ_PENDING, &card->state);
|
||||
unlock_dev(card);
|
||||
kfree(card);
|
||||
sedl_cnt--;
|
||||
|
@ -906,8 +844,7 @@ Speedfax_init(void)
|
|||
APPEND_TO_LIST(card, ((sedl_fax *)speedfax.ilist));
|
||||
card->dch.debug = debug;
|
||||
card->dch.inst.obj = &speedfax;
|
||||
spin_lock_init(&card->devlock);
|
||||
init_MUTEX(&card->sem);
|
||||
lock_HW_init(&card->lock);
|
||||
card->dch.inst.lock = lock_dev;
|
||||
card->dch.inst.unlock = unlock_dev;
|
||||
card->dch.inst.data = card;
|
||||
|
|
|
@ -622,7 +622,7 @@ typedef struct _hisaxinstance {
|
|||
void *data;
|
||||
hisaxif_t up;
|
||||
hisaxif_t down;
|
||||
int (*lock)(void *);
|
||||
void (*lock)(void *);
|
||||
void (*unlock)(void *);
|
||||
} hisaxinstance_t;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Vendor: SuSE GmbH, Nuernberg, Germany
|
||||
Distribution: SuSE Linux 7.3 (i386)
|
||||
Distribution: SuSE Linux 8.2 (i386)
|
||||
Name: km_newhisax
|
||||
Release: 16
|
||||
Release: 17
|
||||
Packager: feedback@suse.de
|
||||
|
||||
Copyright: Karsten Keil GPL
|
||||
|
|
Loading…
Reference in New Issue