summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-10-29 17:06:09 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2002-10-29 17:06:09 -0800
commitd488b0d41fd6bb41cde1fa067a8416b384da0b6d (patch)
tree30d2b7b455445bc7c9f0fd57b8887206c23e84e8
parentd8c084f9fd65a1bf948acc5bf08b066f85160cba (diff)
parent580c8fb64e2976e3a41a67852501a3596ccf3ade (diff)
Merge http://linux-isdn.bkbits.net/linux-2.5.isdn
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--drivers/isdn/hisax/amd7930.c26
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c8
-rw-r--r--drivers/isdn/hisax/asuscom.c20
-rw-r--r--drivers/isdn/hisax/avm_a1.c4
-rw-r--r--drivers/isdn/hisax/avm_a1p.c62
-rw-r--r--drivers/isdn/hisax/avm_pci.c70
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c20
-rw-r--r--drivers/isdn/hisax/bkm_a8.c21
-rw-r--r--drivers/isdn/hisax/callc.c6
-rw-r--r--drivers/isdn/hisax/config.c44
-rw-r--r--drivers/isdn/hisax/diva.c41
-rw-r--r--drivers/isdn/hisax/elsa.c46
-rw-r--r--drivers/isdn/hisax/elsa_ser.c53
-rw-r--r--drivers/isdn/hisax/enternow_pci.c21
-rw-r--r--drivers/isdn/hisax/gazel.c19
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c9
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c2
-rw-r--r--drivers/isdn/hisax/hfc_pci.c9
-rw-r--r--drivers/isdn/hisax/hfc_sx.c9
-rw-r--r--drivers/isdn/hisax/hfcscard.c10
-rw-r--r--drivers/isdn/hisax/hisax.h8
-rw-r--r--drivers/isdn/hisax/hscx.c2
-rw-r--r--drivers/isdn/hisax/icc.c29
-rw-r--r--drivers/isdn/hisax/ipacx.c57
-rw-r--r--drivers/isdn/hisax/isac.c29
-rw-r--r--drivers/isdn/hisax/isar.c54
-rw-r--r--drivers/isdn/hisax/isdnl1.c8
-rw-r--r--drivers/isdn/hisax/isdnl2.c9
-rw-r--r--drivers/isdn/hisax/isurf.c5
-rw-r--r--drivers/isdn/hisax/ix1_micro.c19
-rw-r--r--drivers/isdn/hisax/jade.c21
-rw-r--r--drivers/isdn/hisax/jade_irq.c22
-rw-r--r--drivers/isdn/hisax/l3dss1.c11
-rw-r--r--drivers/isdn/hisax/l3ni1.c11
-rw-r--r--drivers/isdn/hisax/mic.c15
-rw-r--r--drivers/isdn/hisax/netjet.c33
-rw-r--r--drivers/isdn/hisax/niccy.c15
-rw-r--r--drivers/isdn/hisax/nj_s.c14
-rw-r--r--drivers/isdn/hisax/nj_u.c13
-rw-r--r--drivers/isdn/hisax/s0box.c11
-rw-r--r--drivers/isdn/hisax/saphir.c26
-rw-r--r--drivers/isdn/hisax/sedlbauer.c30
-rw-r--r--drivers/isdn/hisax/sportster.c5
-rw-r--r--drivers/isdn/hisax/teleint.c24
-rw-r--r--drivers/isdn/hisax/teles0.c4
-rw-r--r--drivers/isdn/hisax/teles3.c8
-rw-r--r--drivers/isdn/hisax/w6692.c55
-rw-r--r--drivers/isdn/i4l/Config.in2
-rw-r--r--drivers/isdn/i4l/Makefile7
-rw-r--r--drivers/isdn/i4l/isdn_audio.c35
-rw-r--r--drivers/isdn/i4l/isdn_audio.h4
-rw-r--r--drivers/isdn/i4l/isdn_ciscohdlck.c130
-rw-r--r--drivers/isdn/i4l/isdn_ciscohdlck.h16
-rw-r--r--drivers/isdn/i4l/isdn_common.c2458
-rw-r--r--drivers/isdn/i4l/isdn_common.h101
-rw-r--r--drivers/isdn/i4l/isdn_concap.c24
-rw-r--r--drivers/isdn/i4l/isdn_concap.h5
-rw-r--r--drivers/isdn/i4l/isdn_fsm.c11
-rw-r--r--drivers/isdn/i4l/isdn_net.c77
-rw-r--r--drivers/isdn/i4l/isdn_net.h84
-rw-r--r--drivers/isdn/i4l/isdn_net_lib.c389
-rw-r--r--drivers/isdn/i4l/isdn_net_lib.h224
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c1158
-rw-r--r--drivers/isdn/i4l/isdn_ppp.h42
-rw-r--r--drivers/isdn/i4l/isdn_ppp_ccp.c54
-rw-r--r--drivers/isdn/i4l/isdn_ppp_ccp.h19
-rw-r--r--drivers/isdn/i4l/isdn_ppp_mp.c352
-rw-r--r--drivers/isdn/i4l/isdn_ppp_mp.h58
-rw-r--r--drivers/isdn/i4l/isdn_ppp_vj.c128
-rw-r--r--drivers/isdn/i4l/isdn_ppp_vj.h61
-rw-r--r--drivers/isdn/i4l/isdn_tty.c670
-rw-r--r--drivers/isdn/i4l/isdn_tty.h33
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c47
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.h5
-rw-r--r--drivers/isdn/i4l/isdn_v110.c187
-rw-r--r--drivers/isdn/i4l/isdn_v110.h12
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c9
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.h11
-rw-r--r--drivers/isdn/icn/icn.c1
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c7
-rw-r--r--include/linux/isdn.h262
-rw-r--r--include/linux/isdn/fsm.h (renamed from drivers/isdn/i4l/isdn_fsm.h)9
-rw-r--r--include/linux/isdn_ppp.h157
-rw-r--r--include/linux/isdnif.h8
84 files changed, 3855 insertions, 4040 deletions
diff --git a/drivers/isdn/hisax/amd7930.c b/drivers/isdn/hisax/amd7930.c
index 5040215aa4ff..9826d7b4b21a 100644
--- a/drivers/isdn/hisax/amd7930.c
+++ b/drivers/isdn/hisax/amd7930.c
@@ -106,8 +106,9 @@ static const char *amd7930_revision = "$Revision: 1.5.6.4 $";
static void Bchan_fill_fifo(struct BCState *, struct sk_buff *);
static void
-Bchan_xmt_bh(struct BCState *bcs)
+Bchan_xmt_bh(void *data)
{
+ struct BCState *bcs = data;
struct sk_buff *skb;
if (bcs->hw.amd7930.tx_skb != NULL) {
@@ -120,14 +121,14 @@ Bchan_xmt_bh(struct BCState *bcs)
} else {
clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event |= 1 << B_XMTBUFREADY;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
}
static void
Bchan_xmit_callback(struct BCState *bcs)
{
- schedule_work(&bcs->hw.amd7930.tq_xmt);
+ schedule_work(&bcs->hw.amd7930.xmt_work);
}
/* B channel transmission: two modes (three, if you count L1_MODE_NULL)
@@ -259,12 +260,13 @@ Bchan_recv_callback(struct BCState *bcs)
(void *) &Bchan_recv_callback, (void *) bcs);
}
- schedule_work(&hw->tq_rcv);
+ schedule_work(&hw->rcv_work);
}
static void
-Bchan_rcv_bh(struct BCState *bcs)
+Bchan_rcv_bh(void *data)
{
+ struct BCState *bcs = data;
struct IsdnCardState *cs = bcs->cs;
struct amd7930_hw *hw = &bcs->hw.amd7930;
struct sk_buff *skb;
@@ -305,7 +307,7 @@ Bchan_rcv_bh(struct BCState *bcs)
skb_queue_tail(&bcs->rqueue, hw->rv_skb);
hw->rv_skb = skb;
bcs->event |= 1 << B_RCVBUFREADY;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
} else if (len > 0) {
/* Small packet received */
@@ -316,7 +318,7 @@ Bchan_rcv_bh(struct BCState *bcs)
memcpy(skb_put(skb, len), hw->rv_skb->tail, len);
skb_queue_tail(&bcs->rqueue, skb);
bcs->event |= 1 << B_RCVBUFREADY;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
} else {
/* Reception Error */
@@ -332,7 +334,7 @@ Bchan_rcv_bh(struct BCState *bcs)
RCV_BUFSIZE/RCV_BUFBLKS);
skb_queue_tail(&bcs->rqueue, skb);
bcs->event |= 1 << B_RCVBUFREADY;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
}
@@ -416,12 +418,8 @@ Bchan_init(struct BCState *bcs)
return;
}
- bcs->hw.amd7930.tq_rcv.sync = 0;
- INIT_WORK(&bcs->hw.amd7930.tq_rcv, (void (*)(void *)) &Bchan_rcv_bh,
- (void *) bcs);
-
- INIT_WORK(&bcs->hw.amd7930.tq_xmt, (void (*)(void *)) &Bchan_xmt_bh,
- (void *) bcs);
+ INIT_WORK(&bcs->hw.amd7930.rcv_work, &Bchan_rcv_bh, bcs);
+ INIT_WORK(&bcs->hw.amd7930.xmt_work, &Bchan_xmt_bh, bcs);
}
static void
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index 02fbf3d54b5f..369a81f0d050 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -232,9 +232,9 @@ Amd7930_new_ph(struct IsdnCardState *cs)
static void
-Amd7930_bh(struct IsdnCardState *cs)
+Amd7930_bh(void *data)
{
-
+ struct IsdnCardState *cs = data;
struct PStack *stptr;
if (!cs)
@@ -277,7 +277,7 @@ Amd7930_sched_event(struct IsdnCardState *cs, int event) // ok
}
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
static void
@@ -790,7 +790,7 @@ Amd7930_init(struct IsdnCardState *cs)
cs->dc.amd7930.old_state = 0;
cs->dc.amd7930.lmr1 = 0x40;
cs->dc.amd7930.ph_command = Amd7930_ph_command;
- INIT_WORK(&cs->tqueue, (void *) (void *) Amd7930_bh, NULL);
+ INIT_WORK(&cs->work, Amd7930_bh, cs);
cs->setstack_d = setstack_Amd7930;
cs->DC_Close = DC_Close_Amd7930;
cs->dbusytimer.function = (void *) dbusy_timer_handler;
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index 637418d514b8..cf943f1bddc4 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -24,6 +24,7 @@ extern const char *CardType[];
const char *Asuscom_revision = "$Revision: 1.11.6.3 $";
+static spinlock_t asuscom_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -46,13 +47,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&asuscom_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&asuscom_lock, flags);
return (ret);
}
@@ -69,13 +69,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&asuscom_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&asuscom_lock, flags);
}
static inline void
@@ -263,14 +262,10 @@ release_io_asuscom(struct IsdnCardState *cs)
static void
reset_asuscom(struct IsdnCardState *cs)
{
- long flags;
-
if (cs->subtyp == ASUS_IPAC)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20);
else
byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
if (cs->subtyp == ASUS_IPAC)
@@ -286,7 +281,6 @@ reset_asuscom(struct IsdnCardState *cs)
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0);
writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12);
}
- restore_flags(flags);
}
static int
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
index 38a741a888a9..a87cfd0796d0 100644
--- a/drivers/isdn/hisax/avm_a1.c
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -179,7 +179,6 @@ setup_avm_a1(struct IsdnCard *card)
{
u_char val;
struct IsdnCardState *cs = card->cs;
- long flags;
char tmp[64];
strcpy(tmp, avm_revision);
@@ -254,9 +253,7 @@ setup_avm_a1(struct IsdnCard *card)
release_ioregs(cs, 0x1f);
return (0);
}
- save_flags(flags);
byteout(cs->hw.avm.cfg_reg, 0x0);
- sti();
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x1);
HZDELAY(HZ / 5 + 1);
@@ -269,7 +266,6 @@ setup_avm_a1(struct IsdnCard *card)
HZDELAY(HZ / 5 + 1);
byteout(cs->hw.avm.cfg_reg, 0x0);
HZDELAY(HZ / 5 + 1);
- restore_flags(flags);
val = bytein(cs->hw.avm.cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
index d5d8d07ed24f..2f3f377400d6 100644
--- a/drivers/isdn/hisax/avm_a1p.c
+++ b/drivers/isdn/hisax/avm_a1p.c
@@ -57,116 +57,109 @@
#define bytein(addr) inb(addr)
static const char *avm_revision = "$Revision: 2.7.6.2 $";
+static spinlock_t avm_a1p_lock = SPIN_LOCK_UNLOCKED;
static inline u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- long flags;
+ unsigned long flags;
u_char ret;
offset -= 0x20;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
return ret;
}
static inline void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- long flags;
+ unsigned long flags;
offset -= 0x20;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
}
static inline void
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
}
static inline void
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
}
static inline u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
u_char ret;
- long flags;
+ unsigned long flags;
offset -= 0x20;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
return ret;
}
static inline void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
- long flags;
+ unsigned long flags;
offset -= 0x20;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
}
static inline void
ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
}
static inline void
WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_a1p_lock, flags);
byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_a1p_lock, flags);
}
/*
@@ -253,7 +246,6 @@ setup_avm_a1_pcmcia(struct IsdnCard *card)
{
u_char model, vers;
struct IsdnCardState *cs = card->cs;
- long flags;
char tmp[64];
@@ -267,9 +259,7 @@ setup_avm_a1_pcmcia(struct IsdnCard *card)
cs->irq = card->para[0];
- save_flags(flags);
outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
- sti();
byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
HZDELAY(HZ / 5 + 1);
@@ -279,8 +269,6 @@ setup_avm_a1_pcmcia(struct IsdnCard *card)
byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, ASL0_W_TDISABLE|ASL0_W_TRESET);
- restore_flags(flags);
-
model = bytein(cs->hw.avm.cfg_reg+MODREG_OFFSET);
vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET);
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index a0681c24148e..7a5a885926e4 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -23,6 +23,7 @@
extern const char *CardType[];
static const char *avm_pci_rev = "$Revision: 1.22.6.6 $";
+static spinlock_t avm_pci_lock = SPIN_LOCK_UNLOCKED;
#define AVM_FRITZ_PCI 1
#define AVM_FRITZ_PNP 2
@@ -80,13 +81,12 @@ ReadISAC(struct IsdnCardState *cs, u_char offset)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
register u_char val;
- register long flags;
+ register unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
outb(idx, cs->hw.avm.cfg_reg + 4);
val = inb(cs->hw.avm.isac + (offset & 0xf));
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
return (val);
}
@@ -94,13 +94,12 @@ static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW;
- register long flags;
+ register unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
outb(idx, cs->hw.avm.cfg_reg + 4);
outb(value, cs->hw.avm.isac + (offset & 0xf));
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
}
static void
@@ -122,13 +121,12 @@ ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset)
{
register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
register u_int val;
- register long flags;
+ register unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
outl(idx, cs->hw.avm.cfg_reg + 4);
val = inl(cs->hw.avm.isac + offset);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
return (val);
}
@@ -136,13 +134,12 @@ static inline void
WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value)
{
register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
- register long flags;
+ register unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
outl(idx, cs->hw.avm.cfg_reg + 4);
outl(value, cs->hw.avm.isac + offset);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
}
static inline u_char
@@ -150,13 +147,12 @@ ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset)
{
register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
register u_char val;
- register long flags;
+ register unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
outb(idx, cs->hw.avm.cfg_reg + 4);
val = inb(cs->hw.avm.isac + offset);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
return (val);
}
@@ -164,13 +160,12 @@ static inline void
WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value)
{
register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1;
- register long flags;
+ register unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
outb(idx, cs->hw.avm.cfg_reg + 4);
outb(value, cs->hw.avm.isac + offset);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
}
static u_char
@@ -200,7 +195,7 @@ void inline
hdlc_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
void
@@ -390,11 +385,10 @@ hdlc_fill_fifo(struct BCState *bcs)
static void
fill_hdlc(struct BCState *bcs)
{
- long flags;
- save_flags(flags);
- cli();
+ unsigned long flags;
+ spin_lock_irqsave(&avm_pci_lock, flags);
hdlc_fill_fifo(bcs);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
}
static inline void
@@ -493,8 +487,7 @@ HDLC_irq_main(struct IsdnCardState *cs)
long flags;
struct BCState *bcs;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
if (cs->subtyp == AVM_FRITZ_PCI) {
stat = ReadHDLCPCI(cs, 0, HDLC_STATUS);
} else {
@@ -523,27 +516,26 @@ HDLC_irq_main(struct IsdnCardState *cs)
} else
HDLC_irq(bcs, stat);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
}
void
hdlc_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
switch (pr) {
case (PH_DATA | REQUEST):
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&avm_pci_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
} else {
st->l1.bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->hw.hdlc.count = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&avm_pci_lock, flags);
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
}
break;
@@ -716,11 +708,7 @@ avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
static void
reset_avmpcipnp(struct IsdnCardState *cs)
{
- long flags;
-
printk(KERN_INFO "AVM PCI/PnP: reset\n");
- save_flags(flags);
- sti();
outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index 31173d211133..75f361e241be 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -21,6 +21,7 @@
#include "bkm_ax.h"
extern const char *CardType[];
+static spinlock_t bkm_a4t_lock = SPIN_LOCK_UNLOCKED;
const char *bkm_a4t_revision = "$Revision: 1.13.6.6 $";
@@ -29,16 +30,15 @@ static inline u_char
readreg(unsigned int ale, unsigned long adr, u_char off)
{
register u_int ret;
- long flags;
+ unsigned long flags;
unsigned int *po = (unsigned int *) adr; /* Postoffice */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&bkm_a4t_lock, flags);
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_READ);
__WAITI20__(po);
ret = *po;
- restore_flags(flags);
+ spin_unlock_irqrestore(&bkm_a4t_lock, flags);
return ((unsigned char) ret);
}
@@ -56,15 +56,14 @@ readfifo(unsigned int ale, unsigned long adr, u_char off, u_char * data, int siz
static inline void
writereg(unsigned int ale, unsigned long adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
unsigned int *po = (unsigned int *) adr; /* Postoffice */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&bkm_a4t_lock, flags);
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_WRITE | data);
__WAITI20__(po);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bkm_a4t_lock, flags);
}
@@ -197,12 +196,8 @@ enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
static void
reset_bkm(struct IsdnCardState *cs)
{
- long flags;
-
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
- save_flags(flags);
- sti();
/* Issue the I20 soft reset */
pI20_Regs->i20SysControl = 0xFF; /* all in */
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -229,7 +224,6 @@ reset_bkm(struct IsdnCardState *cs)
g_A4T_ISAR_RES);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
- restore_flags(flags);
}
}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index c4d5e8ba2c44..a0b4282dae01 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -25,7 +25,7 @@
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
-
+static spinlock_t bkm_a8_lock = SPIN_LOCK_UNLOCKED;
const char sct_quadro_revision[] = "$Revision: 1.14.6.7 $";
static const char *sct_quadro_subtypes[] =
@@ -45,12 +45,11 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
- save_flags(flags);
- cli();
+ unsigned long flags;
+ spin_lock_irqsave(&bkm_a8_lock, flags);
wordout(ale, off);
ret = wordin(adr) & 0xFF;
- restore_flags(flags);
+ spin_unlock_irqrestore(&bkm_a8_lock, flags);
return (ret);
}
@@ -68,12 +67,11 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
- save_flags(flags);
- cli();
+ unsigned long flags;
+ spin_lock_irqsave(&bkm_a8_lock, flags);
wordout(ale, off);
wordout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&bkm_a8_lock, flags);
}
static inline void
@@ -223,19 +221,14 @@ enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
static void
reset_bkm(struct IsdnCardState *cs)
{
- long flags;
-
if (cs->subtyp == SCT_1) {
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10 * HZ) / 1000);
- restore_flags(flags);
}
}
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 565d774e42b2..79f2ae84865e 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -37,6 +37,7 @@ static void release_b_st(struct Channel *chanp);
static struct Fsm callcfsm;
static int chancount;
+static spinlock_t callc_lock = SPIN_LOCK_UNLOCKED;
/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
#define ALERT_REJECT 0
@@ -1803,8 +1804,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
return 0;
} else if (chanp->debug & 0x800)
link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt,MAX_DATA_MEM);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&callc_lock, flags);
nskb = skb_clone(skb, GFP_ATOMIC);
if (nskb) {
nskb->truesize = nskb->len;
@@ -1819,7 +1819,7 @@ HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb)
dev_kfree_skb(skb);
} else
len = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&callc_lock, flags);
}
return (len);
}
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 8def6d6218ff..dffa55531a81 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -99,6 +99,7 @@ const char *CardType[] = {
};
void HiSax_closecard(int cardnr);
+static spinlock_t hisax_config_lock = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_HISAX_ELSA
#define DEFAULT_CARD ISDN_CTYPE_ELSA
@@ -708,14 +709,13 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
{
/* if head == NULL the fmt contains the full info */
- long flags;
+ unsigned long flags;
int count, i;
u_char *p;
isdn_ctrl ic;
int len;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&hisax_config_lock, flags);
p = tmpbuf;
if (head) {
p += jiftime(p, jiffies);
@@ -732,13 +732,13 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
if (!cs) {
printk(KERN_WARNING "HiSax: No CardStatus for message %s",
p);
- restore_flags(flags);
+ spin_unlock_irqrestore(&hisax_config_lock, flags);
return;
}
if (len > HISAX_STATUS_BUFSIZE) {
printk(KERN_WARNING "HiSax: status overflow %d/%d\n",
len, HISAX_STATUS_BUFSIZE);
- restore_flags(flags);
+ spin_unlock_irqrestore(&hisax_config_lock, flags);
return;
}
count = len;
@@ -767,7 +767,7 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt,
count++;
}
#endif
- restore_flags(flags);
+ spin_unlock_irqrestore(&hisax_config_lock, flags);
if (count) {
ic.command = ISDN_STAT_STAVAIL;
ic.driver = cs->myid;
@@ -787,16 +787,12 @@ void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...)
int ll_run(struct IsdnCardState *cs, int addfeatures)
{
- long flags;
isdn_ctrl ic;
- save_flags(flags);
- cli();
ic.driver = cs->myid;
ic.command = ISDN_STAT_RUN;
cs->iif.features |= addfeatures;
cs->iif.statcallb(&ic);
- restore_flags(flags);
return 0;
}
@@ -857,28 +853,23 @@ static void closecard(int cardnr)
static int __devinit init_card(struct IsdnCardState *cs)
{
int irq_cnt, cnt = 3;
- long flags;
if (!cs->irq)
return cs->cardmsg(cs, CARD_INIT, NULL);
- save_flags(flags);
- cli();
+
irq_cnt = kstat_irqs(cs->irq);
printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
cs->irq, irq_cnt);
if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
cs->irq);
- restore_flags(flags);
return 1;
}
while (cnt) {
cs->cardmsg(cs, CARD_INIT, NULL);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
/* Timeout 10ms */
schedule_timeout((10 * HZ) / 1000);
- restore_flags(flags);
printk(KERN_INFO "%s: IRQ %d count %d\n",
CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
if (kstat_irqs(cs->irq) == irq_cnt) {
@@ -897,19 +888,15 @@ static int __devinit init_card(struct IsdnCardState *cs)
return 0;
}
}
- restore_flags(flags);
return 3;
}
static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
{
- long flags;
int ret = 0;
struct IsdnCard *card = cards + cardnr;
struct IsdnCardState *cs;
- save_flags(flags);
- cli();
cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
if (!cs) {
printk(KERN_WARNING
@@ -1173,7 +1160,6 @@ static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
cs->tx_skb = NULL;
cs->tx_cnt = 0;
cs->event = 0;
- cs->tqueue.data = cs;
skb_queue_head_init(&cs->rq);
skb_queue_head_init(&cs->sq);
@@ -1216,7 +1202,6 @@ static int __devinit checkcard(int cardnr, char *id, int *busy_flag)
kfree(cs);
card->cs = NULL;
out:
- restore_flags(flags);
return ret;
}
@@ -1542,10 +1527,7 @@ static int __init HiSax_init(void)
static void __exit HiSax_exit(void)
{
int cardnr = nrcards - 1;
- long flags;
- save_flags(flags);
- cli();
while (cardnr >= 0)
HiSax_closecard(cardnr--);
Isdnl1Free();
@@ -1553,7 +1535,6 @@ static void __exit HiSax_exit(void)
Isdnl2Free();
Isdnl3Free();
CallcFree();
- restore_flags(flags);
printk(KERN_INFO "HiSax module removed\n");
}
@@ -1756,7 +1737,7 @@ static void hisax_b_l2l1(struct PStack *st, int pr, void *arg);
static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg);
static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs);
static void hisax_bc_close(struct BCState *bcs);
-static void hisax_bh(struct IsdnCardState *cs);
+static void hisax_bh(void *data);
static void EChannel_proc_rcv(struct hisax_d_if *d_if);
int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
@@ -1788,7 +1769,7 @@ int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[],
hisax_d_if->cs = cs;
cs->hw.hisax_d_if = hisax_d_if;
cs->cardmsg = hisax_cardmsg;
- INIT_WORK(&cs->tqueue, (void *) (void *) hisax_bh, NULL);
+ INIT_WORK(&cs->work, hisax_bh, cs);
cs->channel[0].d_st->l1.l2l1 = hisax_d_l2l1;
for (i = 0; i < 2; i++) {
cs->bcs[i].BC_SetStack = hisax_bc_setstack;
@@ -1817,11 +1798,12 @@ void hisax_unregister(struct hisax_d_if *hisax_d_if)
static void hisax_sched_event(struct IsdnCardState *cs, int event)
{
cs->event |= 1 << event;
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
-static void hisax_bh(struct IsdnCardState *cs)
+static void hisax_bh(void *data)
{
+ struct IsdnCardState *cs = data;
struct PStack *st;
int pr;
@@ -1843,7 +1825,7 @@ static void hisax_bh(struct IsdnCardState *cs)
static void hisax_b_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg)
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 6bebe3feac8f..20ca4c4c1c6b 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -29,6 +29,7 @@
extern const char *CardType[];
const char *Diva_revision = "$Revision: 1.25.6.5 $";
+static spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -85,13 +86,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&diva_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&diva_lock, flags);
return (ret);
}
@@ -108,13 +108,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&diva_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&diva_lock, flags);
}
static inline void
@@ -408,13 +407,12 @@ MemwaitforXFW(struct IsdnCardState *cs, int hscx)
static inline void
MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&diva_lock, flags);
MemwaitforCEC(cs, hscx);
MemWriteHSCX(cs, hscx, HSCX_CMDR, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&diva_lock, flags);
}
static void
@@ -422,7 +420,7 @@ Memhscx_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
- long flags;
+ unsigned long flags;
int cnt;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
@@ -435,8 +433,7 @@ Memhscx_empty_fifo(struct BCState *bcs, int count)
bcs->hw.hscx.rcvidx = 0;
return;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&diva_lock, flags);
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
cnt = count;
while (cnt--)
@@ -444,7 +441,7 @@ Memhscx_empty_fifo(struct BCState *bcs, int count)
MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80);
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
- restore_flags(flags);
+ spin_unlock_irqrestore(&diva_lock, flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
@@ -462,7 +459,7 @@ Memhscx_fill_fifo(struct BCState *bcs)
int more, count, cnt;
int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags)? 64: 32;
u_char *ptr,*p;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
@@ -481,8 +478,7 @@ Memhscx_fill_fifo(struct BCState *bcs)
count = bcs->tx_skb->len;
cnt = count;
MemwaitforXFW(cs, bcs->hw.hscx.hscx);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&diva_lock, flags);
p = ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
@@ -491,7 +487,7 @@ Memhscx_fill_fifo(struct BCState *bcs)
memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0,
*p++);
MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa);
- restore_flags(flags);
+ spin_unlock_irqrestore(&diva_lock, flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
@@ -753,10 +749,6 @@ release_io_diva(struct IsdnCardState *cs)
static void
reset_diva(struct IsdnCardState *cs)
{
- long flags;
-
- save_flags(flags);
- sti();
if (cs->subtyp == DIVA_IPAC_ISA) {
writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -803,7 +795,6 @@ reset_diva(struct IsdnCardState *cs)
}
byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
}
- restore_flags(flags);
}
#define DIVA_ASSIGN 1
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 460b183b3af6..600c959a6a49 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -32,6 +32,7 @@
#include <linux/serial_reg.h>
extern const char *CardType[];
+static spinlock_t elsa_lock = SPIN_LOCK_UNLOCKED;
const char *Elsa_revision = "$Revision: 2.26.6.6 $";
const char *Elsa_Types[] =
@@ -145,13 +146,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_lock, flags);
return (ret);
}
@@ -168,13 +168,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_lock, flags);
}
static inline void
@@ -253,26 +252,24 @@ static inline u_char
readitac(struct IsdnCardState *cs, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_lock, flags);
byteout(cs->hw.elsa.ale, off);
ret = bytein(cs->hw.elsa.itac);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_lock, flags);
return (ret);
}
static inline void
writeitac(struct IsdnCardState *cs, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_lock, flags);
byteout(cs->hw.elsa.ale, off);
byteout(cs->hw.elsa.itac, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_lock, flags);
}
static inline int
@@ -486,8 +483,6 @@ release_io_elsa(struct IsdnCardState *cs)
static void
reset_elsa(struct IsdnCardState *cs)
{
- long flags;
-
if (cs->hw.elsa.timer) {
/* Wait 1 Timer */
byteout(cs->hw.elsa.timer, 0);
@@ -507,8 +502,6 @@ reset_elsa(struct IsdnCardState *cs)
byteout(cs->hw.elsa.trig, 0xff);
}
if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) {
- save_flags(flags);
- sti();
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
@@ -516,7 +509,6 @@ reset_elsa(struct IsdnCardState *cs)
set_current_state(TASK_UNINTERRUPTIBLE);
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
- restore_flags(flags);
if (cs->subtyp != ELSA_PCMCIA_IPAC) {
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0);
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c);
@@ -677,7 +669,6 @@ static int
Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
int ret = 0;
- long flags;
switch (mt) {
case CARD_RESET:
@@ -706,16 +697,13 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
} else if (cs->subtyp == ELSA_QS3000PCI) {
ret = 0;
} else {
- save_flags(flags);
cs->hw.elsa.counter = 0;
- sti();
cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
byteout(cs->hw.elsa.timer, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((110*HZ)/1000);
- restore_flags(flags);
cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
@@ -798,7 +786,6 @@ probe_elsa_adr(unsigned int adr, int typ)
{
int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0,
pc_2 = 0, pfp_1 = 0, pfp_2 = 0;
- long flags;
/* In case of the elsa pcmcia card, this region is in use,
reserved for us by the card manager. So we do not check it
@@ -809,8 +796,6 @@ probe_elsa_adr(unsigned int adr, int typ)
adr);
return (0);
}
- save_flags(flags);
- cli();
for (i = 0; i < 16; i++) {
in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */
in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */
@@ -823,7 +808,6 @@ probe_elsa_adr(unsigned int adr, int typ)
pfp_1 += 0x40 & in1;
pfp_2 += 0x40 & in2;
}
- restore_flags(flags);
printk(KERN_INFO "Elsa: Probing IO 0x%x", adr);
if (65 == ++p16_1 * ++p16_2) {
printk(" PCC-16/PCF found\n");
@@ -878,7 +862,6 @@ static struct pci_bus *pnp_c __devinitdata = NULL;
int __devinit
setup_elsa(struct IsdnCard *card)
{
- long flags;
int bytecnt;
u_char val, pci_rev;
struct IsdnCardState *cs = card->cs;
@@ -1170,10 +1153,7 @@ setup_elsa(struct IsdnCard *card)
return (0);
}
}
- save_flags(flags);
- sti();
HZDELAY(1); /* wait >=10 ms */
- restore_flags(flags);
if (TimerRun(cs)) {
printk(KERN_WARNING "Elsa: timer do not run down\n");
release_io_elsa(cs);
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 6ef49f05b299..336e7078a7c9 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -30,6 +30,7 @@ static u_char deb[32];
const char *ModemIn[] = {"RBR","IER","IIR","LCR","MCR","LSR","MSR","SCR"};
const char *ModemOut[] = {"THR","IER","FCR","LCR","MCR","LSR","MSR","SCR"};
#endif
+static spinlock_t elsa_ser_lock = SPIN_LOCK_UNLOCKED;
static char *MInit_1 = "AT&F&C1E0&D2\r\0";
static char *MInit_2 = "ATL2M1S64=13\r\0";
@@ -134,14 +135,13 @@ static void change_speed(struct IsdnCardState *cs, int baud)
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
debugl1(cs,"modem quot=0x%x", quot);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */
serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */
serial_outp(cs, UART_LCR, cval); /* reset DLAB */
serial_inp(cs, UART_RX);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
}
static int mstartup(struct IsdnCardState *cs)
@@ -150,7 +150,7 @@ static int mstartup(struct IsdnCardState *cs)
int retval=0;
- save_flags(flags); cli();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
/*
* Clear the FIFO buffers and disable them
@@ -207,7 +207,7 @@ static int mstartup(struct IsdnCardState *cs)
change_speed(cs, BASE_BAUD);
cs->hw.elsa.MFlag = 1;
errout:
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
return retval;
}
@@ -224,7 +224,7 @@ static void mshutdown(struct IsdnCardState *cs)
printk(KERN_DEBUG"Shutting down serial ....");
#endif
- save_flags(flags); cli(); /* Disable interrupts */
+ spin_lock_irqsave(&elsa_ser_lock, flags); /* Disable interrupts */
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
@@ -245,7 +245,7 @@ static void mshutdown(struct IsdnCardState *cs)
serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT));
serial_inp(cs, UART_RX); /* read data port to reset things */
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
#ifdef SERIAL_DEBUG_OPEN
printk(" done\n");
#endif
@@ -256,14 +256,13 @@ write_modem(struct BCState *bcs) {
int ret=0;
struct IsdnCardState *cs = bcs->cs;
int count, len, fp;
- long flags;
+ unsigned long flags;
if (!bcs->tx_skb)
return 0;
if (bcs->tx_skb->len <= 0)
return 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
len = bcs->tx_skb->len;
if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt)
len = MAX_MODEM_BUF - cs->hw.elsa.transcnt;
@@ -289,7 +288,7 @@ write_modem(struct BCState *bcs) {
cs->hw.elsa.IER |= UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
return(ret);
}
@@ -460,14 +459,13 @@ void
modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
int count, fp;
u_char *msg = buf;
- long flags;
+ unsigned long flags;
if (!len)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
return;
}
fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp;
@@ -488,17 +486,16 @@ modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
cs->hw.elsa.IER |= UART_IER_THRI;
serial_outp(cs, UART_IER, cs->hw.elsa.IER);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
}
void
modem_set_init(struct IsdnCardState *cs) {
- long flags;
+ unsigned long flags;
int timeout;
#define RCV_DELAY 20000
- save_flags(flags);
- sti();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
modem_write_cmd(cs, MInit_1, strlen(MInit_1));
timeout = 1000;
while(timeout-- && cs->hw.elsa.transcnt)
@@ -541,17 +538,16 @@ modem_set_init(struct IsdnCardState *cs) {
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
udelay(RCV_DELAY);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
}
void
modem_set_dial(struct IsdnCardState *cs, int outgoing) {
- long flags;
+ unsigned long flags;
int timeout;
#define RCV_DELAY 20000
- save_flags(flags);
- sti();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800));
timeout = 1000;
while(timeout-- && cs->hw.elsa.transcnt)
@@ -567,26 +563,25 @@ modem_set_dial(struct IsdnCardState *cs, int outgoing) {
udelay(1000);
debugl1(cs, "msi tout=%d", timeout);
udelay(RCV_DELAY);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
}
void
modem_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
if (pr == (PH_DATA | REQUEST)) {
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&elsa_ser_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
} else {
st->l1.bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->hw.hscx.count = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&elsa_ser_lock, flags);
write_modem(st->l1.bcs);
}
} else if (pr == (PH_ACTIVATE | REQUEST)) {
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index c6c486c93612..143389debdcb 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -75,7 +75,7 @@
const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
-
+static spinlock_t enternow_pci_lock = SPIN_LOCK_UNLOCKED;
/* *************************** I/O-Interface functions ************************************* */
@@ -137,13 +137,9 @@ static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
static void
reset_enpci(struct IsdnCardState *cs)
{
- long flags;
-
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: reset");
- save_flags(flags);
- sti();
/* Reset on, (also for AMD) */
cs->hw.njet.ctrl_reg = 0x07;
OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
@@ -156,13 +152,11 @@ reset_enpci(struct IsdnCardState *cs)
set_current_state(TASK_UNINTERRUPTIBLE);
/* 80ms delay */
schedule_timeout((80*HZ)/1000);
- restore_flags(flags);
cs->hw.njet.auxd = 0; // LED-status
cs->hw.njet.dmactrl = 0;
OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
-
}
@@ -237,7 +231,7 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
BYTE sval, ir;
- long flags;
+ unsigned long flags;
if (!cs) {
@@ -257,8 +251,7 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
/* DMA-Interrupt: B-channel-stuff */
/* set bits in sval to indicate which page is free */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&enternow_pci_lock, flags);
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
@@ -275,11 +268,11 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&enternow_pci_lock, flags);
return;
}
cs->hw.njet.irqstat0 = sval;
- restore_flags(flags);
+ spin_unlock_irqrestore(&enternow_pci_lock, flags);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
@@ -290,7 +283,7 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
write_tiger(cs);
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
} else
- restore_flags(flags);
+ spin_unlock_irqrestore(&enternow_pci_lock, flags);
}
@@ -303,7 +296,7 @@ setup_enternow_pci(struct IsdnCard *card)
int bytecnt;
struct IsdnCardState *cs = card->cs;
char tmp[64];
- long flags;
+ unsigned long flags;
#if CONFIG_PCI
#ifdef __BIG_ENDIAN
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 37cce53235dd..2ad414bee102 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -22,6 +22,7 @@
extern const char *CardType[];
const char *gazel_revision = "$Revision: 2.11.6.7 $";
+static spinlock_t gazel_lock = SPIN_LOCK_UNLOCKED;
#define R647 1
#define R685 2
@@ -72,26 +73,24 @@ static inline u_char
readreg_ipac(unsigned int adr, u_short off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&gazel_lock, flags);
byteout(adr, off);
ret = bytein(adr + 4);
- restore_flags(flags);
+ spin_unlock_irqrestore(&gazel_lock, flags);
return ret;
}
static inline void
writereg_ipac(unsigned int adr, u_short off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&gazel_lock, flags);
byteout(adr, off);
byteout(adr + 4, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&gazel_lock, flags);
}
@@ -357,18 +356,14 @@ release_io_gazel(struct IsdnCardState *cs)
static int
reset_gazel(struct IsdnCardState *cs)
{
- long flags;
unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg;
switch (cs->subtyp) {
case R647:
- save_flags(flags);
- cli();
writereg(addr, 0, 0);
HZDELAY(10);
writereg(addr, 0, 1);
HZDELAY(2);
- restore_flags(flags);
break;
case R685:
plxcntrl = inl(addr + PLX_CNTRL);
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 65b9e22913ee..72bddf88bbff 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -202,7 +202,7 @@ static void
hfc_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
static struct sk_buff
@@ -608,8 +608,9 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
}
static void
-hfcd_bh(struct IsdnCardState *cs)
+hfcd_bh(void *data)
{
+ struct IsdnCardState *cs = data;
/* struct PStack *stptr;
*/
if (!cs)
@@ -645,7 +646,7 @@ void
sched_event_D(struct IsdnCardState *cs, int event)
{
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
static
@@ -1127,7 +1128,7 @@ init2bds0(struct IsdnCardState *cs)
cs->dbusytimer.function = (void *) hfc_dbusy_timer;
cs->dbusytimer.data = (long) cs;
init_timer(&cs->dbusytimer);
- INIT_WORK(&cs->tqueue, (void *) (void *) hfcd_bh, NULL);
+ INIT_WORK(&cs->work, hfcd_bh, cs);
if (!cs->hw.hfcD.send)
cs->hw.hfcD.send = init_send_hfcd(16);
if (!cs->bcs[0].hw.hfc.send)
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index f6c39022701d..2605c29776d7 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -86,7 +86,7 @@ void
hfc_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
static void
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index e606de8c5bf1..eb1e71cd78ca 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -194,7 +194,7 @@ static void
sched_event_D_pci(struct IsdnCardState *cs, int event)
{
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
/*********************************/
@@ -204,7 +204,7 @@ static void
hfcpci_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
/************************************************/
@@ -1535,8 +1535,9 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
/* handle L1 state changes */
/***************************/
static void
-hfcpci_bh(struct IsdnCardState *cs)
+hfcpci_bh(void *data)
{
+ struct IsdnCardState *cs = data;
unsigned long flags;
/* struct PStack *stptr;
*/
@@ -1622,7 +1623,7 @@ inithfcpci(struct IsdnCardState *cs)
cs->dbusytimer.function = (void *) hfcpci_dbusy_timer;
cs->dbusytimer.data = (long) cs;
init_timer(&cs->dbusytimer);
- INIT_WORK(&cs->tqueue, (void *) (void *) hfcpci_bh, NULL);
+ INIT_WORK(&cs->work, hfcpci_bh, cs);
cs->BC_Send_Data = &hfcpci_send_data;
cs->bcs[0].BC_SetStack = setstack_2b;
cs->bcs[1].BC_SetStack = setstack_2b;
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index dd8172c5443c..0a3c5901aa14 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -464,7 +464,7 @@ static void
sched_event_D_sx(struct IsdnCardState *cs, int event)
{
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
/*********************************/
@@ -474,7 +474,7 @@ static void
hfcsx_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
/************************************************/
@@ -1323,8 +1323,9 @@ setstack_2b(struct PStack *st, struct BCState *bcs)
/* handle L1 state changes */
/***************************/
static void
-hfcsx_bh(struct IsdnCardState *cs)
+hfcsx_bh(void *data)
{
+ struct IsdnCardState *cs = data;
unsigned long flags;
/* struct PStack *stptr;
*/
@@ -1410,7 +1411,7 @@ inithfcsx(struct IsdnCardState *cs)
cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
cs->dbusytimer.data = (long) cs;
init_timer(&cs->dbusytimer);
- INIT_WORK(&cs->tqueue, (void *) (void *) hfcsx_bh, NULL);
+ INIT_WORK(&cs->work, hfcsx_bh, cs);
cs->BC_Send_Data = &hfcsx_send_data;
cs->bcs[0].BC_SetStack = setstack_2b;
cs->bcs[1].BC_SetStack = setstack_2b;
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index ed9b26af61c4..a627304a72c1 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -64,15 +64,11 @@ release_io_hfcs(struct IsdnCardState *cs)
static void
reset_hfcs(struct IsdnCardState *cs)
{
- long flags;
-
printk(KERN_INFO "HFCS: resetting card\n");
cs->hw.hfcD.cirm = HFCD_RESET;
if (cs->typ == ISDN_CTYPE_TELES3C)
cs->hw.hfcD.cirm |= HFCD_MEM8K;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000);
cs->hw.hfcD.cirm = 0;
@@ -103,14 +99,11 @@ reset_hfcs(struct IsdnCardState *cs)
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */
cs->hw.hfcD.sctrl = 0;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl);
- restore_flags(flags);
}
static int
hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
- long flags;
-
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "HFCS: card_msg %x", mt);
switch (mt) {
@@ -124,14 +117,11 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
cs->hw.hfcD.timer.expires = jiffies + 75;
add_timer(&cs->hw.hfcD.timer);
init2bds0(cs);
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((80*HZ)/1000);
cs->hw.hfcD.ctmt |= HFCD_TIM800;
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt);
cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m);
- restore_flags(flags);
return(0);
case CARD_TEST:
return(0);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index dceac063b896..e692e6468aa4 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -453,8 +453,8 @@ struct amd7930_hw {
int rv_buff_out;
struct sk_buff *rv_skb;
struct hdlc_state *hdlc_state;
- struct work_struct tq_rcv;
- struct work_struct tq_xmt;
+ struct work_struct rcv_work;
+ struct work_struct xmt_work;
};
#define BC_FLG_INIT 1
@@ -495,7 +495,7 @@ struct BCState {
u_char *blog;
u_char *conmsg;
struct timer_list transbusy;
- struct work_struct tqueue;
+ struct work_struct work;
unsigned long event;
int (*BC_SetStack) (struct PStack *, struct BCState *);
void (*BC_Close) (struct BCState *);
@@ -954,7 +954,7 @@ struct IsdnCardState {
struct sk_buff *tx_skb;
int tx_cnt;
long event;
- struct work_struct tqueue;
+ struct work_struct work;
struct timer_list dbusytimer;
#ifdef ERROR_STATISTIC
int err_crc;
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
index 0770479e41d0..174be03de2e1 100644
--- a/drivers/isdn/hisax/hscx.c
+++ b/drivers/isdn/hisax/hscx.c
@@ -95,7 +95,7 @@ void
hscx_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
void
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index aee1cca364d2..e97d962155c5 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -23,6 +23,7 @@
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 0
+static spinlock_t icc_lock = SPIN_LOCK_UNLOCKED;
static char *ICCVer[] __initdata =
{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
@@ -77,8 +78,9 @@ icc_new_ph(struct IsdnCardState *cs)
}
static void
-icc_bh(struct IsdnCardState *cs)
+icc_bh(void *data)
{
+ struct IsdnCardState *cs = data;
struct PStack *stptr;
if (!cs)
@@ -112,7 +114,7 @@ void
icc_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "icc_empty_fifo");
@@ -127,11 +129,10 @@ icc_empty_fifo(struct IsdnCardState *cs, int count)
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&icc_lock, flags);
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, ICC_CMDR, 0x80);
- restore_flags(flags);
+ spin_unlock_irqrestore(&icc_lock, flags);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -146,7 +147,7 @@ icc_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "icc_fill_fifo");
@@ -163,8 +164,7 @@ icc_fill_fifo(struct IsdnCardState *cs)
more = !0;
count = 32;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&icc_lock, flags);
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
@@ -177,7 +177,7 @@ icc_fill_fifo(struct IsdnCardState *cs)
init_timer(&cs->dbusytimer);
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
- restore_flags(flags);
+ spin_unlock_irqrestore(&icc_lock, flags);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -191,7 +191,7 @@ void
icc_sched_event(struct IsdnCardState *cs, int event)
{
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
void
@@ -200,7 +200,7 @@ icc_interrupt(struct IsdnCardState *cs, u_char val)
u_char exval, v1;
struct sk_buff *skb;
unsigned int count;
- long flags;
+ unsigned long flags;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ICC interrupt %x", val);
@@ -227,8 +227,7 @@ icc_interrupt(struct IsdnCardState *cs, u_char val)
if (count == 0)
count = 32;
icc_empty_fifo(cs, count);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&icc_lock, flags);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = alloc_skb(count, GFP_ATOMIC)))
@@ -238,7 +237,7 @@ icc_interrupt(struct IsdnCardState *cs, u_char val)
skb_queue_tail(&cs->rq, skb);
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&icc_lock, flags);
}
cs->rcvidx = 0;
icc_sched_event(cs, D_RCVBUFREADY);
@@ -624,7 +623,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
void __init
initicc(struct IsdnCardState *cs)
{
- INIT_WORK(&cs->tqueue, (void *) (void *) icc_bh, NULL);
+ INIT_WORK(&cs->work, icc_bh, cs);
cs->setstack_d = setstack_icc;
cs->DC_Close = DC_Close_icc;
cs->dc.icc.mon_tx = NULL;
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index 57755ac9c919..f027466f23ad 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -23,7 +23,7 @@
#define MAX_DFRAME_LEN_L1 300
#define B_FIFO_SIZE 64
#define D_FIFO_SIZE 32
-
+static spinlock_t ipacx_lock = SPIN_LOCK_UNLOCKED;
// ipacx interrupt mask values
#define _MASK_IMASK 0x2E // global mask
@@ -38,7 +38,7 @@ static inline void cic_int(struct IsdnCardState *cs);
static void dch_l2l1(struct PStack *st, int pr, void *arg);
static void dbusy_timer_handler(struct IsdnCardState *cs);
static void ipacx_new_ph(struct IsdnCardState *cs);
-static void dch_bh(struct IsdnCardState *cs);
+static void dch_bh(void *data);
static void dch_sched_event(struct IsdnCardState *cs, int event);
static void dch_empty_fifo(struct IsdnCardState *cs, int count);
static void dch_fill_fifo(struct IsdnCardState *cs);
@@ -272,8 +272,9 @@ ipacx_new_ph(struct IsdnCardState *cs)
// bottom half handler for D channel
//----------------------------------------------------------
static void
-dch_bh(struct IsdnCardState *cs)
+dch_bh(void *data)
{
+ struct IsdnCardState *cs = data;
struct PStack *st;
if (!cs) return;
@@ -305,7 +306,7 @@ static void
dch_sched_event(struct IsdnCardState *cs, int event)
{
set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
//----------------------------------------------------------
@@ -314,7 +315,7 @@ dch_sched_event(struct IsdnCardState *cs, int event)
static void
dch_empty_fifo(struct IsdnCardState *cs, int count)
{
- long flags;
+ unsigned long flags;
u_char *ptr;
if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
@@ -332,11 +333,10 @@ dch_empty_fifo(struct IsdnCardState *cs, int count)
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ipacx_lock, flags);
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
if (cs->debug &L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -353,7 +353,7 @@ dch_empty_fifo(struct IsdnCardState *cs, int count)
static void
dch_fill_fifo(struct IsdnCardState *cs)
{
- long flags;
+ unsigned long flags;
int count;
u_char cmd, *ptr;
@@ -371,8 +371,7 @@ dch_fill_fifo(struct IsdnCardState *cs)
cmd = 0x0A; // XTF | XME
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ipacx_lock, flags);
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
@@ -387,7 +386,7 @@ dch_fill_fifo(struct IsdnCardState *cs)
init_timer(&cs->dbusytimer);
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
if (cs->debug &L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -406,7 +405,7 @@ dch_int(struct IsdnCardState *cs)
{
struct sk_buff *skb;
u_char istad, rstad;
- long flags;
+ unsigned long flags;
int count;
istad = cs->readisac(cs, IPACX_ISTAD);
@@ -430,8 +429,7 @@ dch_int(struct IsdnCardState *cs)
count &= D_FIFO_SIZE-1;
if (count == 0) count = D_FIFO_SIZE;
dch_empty_fifo(cs, count);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ipacx_lock, flags);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = dev_alloc_skb(count)))
@@ -441,7 +439,7 @@ dch_int(struct IsdnCardState *cs)
skb_queue_tail(&cs->rq, skb);
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
}
cs->rcvidx = 0;
dch_sched_event(cs, D_RCVBUFREADY);
@@ -510,7 +508,7 @@ dch_init(struct IsdnCardState *cs)
{
printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
- INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs);
+ INIT_WORK(&cs->work, dch_bh, cs);
cs->setstack_d = dch_setstack;
cs->dbusytimer.function = (void *) dbusy_timer_handler;
@@ -535,20 +533,19 @@ static void
bch_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
switch (pr) {
case (PH_DATA | REQUEST):
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ipacx_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
} else {
st->l1.bcs->tx_skb = skb;
set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->hw.hscx.count = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
bch_fill_fifo(st->l1.bcs);
}
break;
@@ -593,7 +590,7 @@ static void
bch_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
//----------------------------------------------------------
@@ -604,7 +601,7 @@ bch_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr, hscx;
struct IsdnCardState *cs;
- long flags;
+ unsigned long flags;
int cnt;
cs = bcs->cs;
@@ -622,8 +619,7 @@ bch_empty_fifo(struct BCState *bcs, int count)
}
// Read data uninterruptible
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ipacx_lock, flags);
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
cnt = count;
while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB);
@@ -631,7 +627,7 @@ bch_empty_fifo(struct BCState *bcs, int count)
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
if (cs->debug &L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
@@ -651,7 +647,7 @@ bch_fill_fifo(struct BCState *bcs)
struct IsdnCardState *cs;
int more, count, cnt;
u_char *ptr, *p, hscx;
- long flags;
+ unsigned long flags;
cs = bcs->cs;
if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
@@ -670,15 +666,14 @@ bch_fill_fifo(struct BCState *bcs)
}
cnt = count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ipacx_lock, flags);
p = ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++);
cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
- restore_flags(flags);
+ spin_unlock_irqrestore(&ipacx_lock, flags);
if (cs->debug &L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index f90ee9a78bd0..a23f1184d4f5 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -22,6 +22,7 @@
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 1
+static spinlock_t isac_lock = SPIN_LOCK_UNLOCKED;
static char *ISACVer[] __devinitdata =
{"2086/2186 V1.1", "2085 B1", "2085 B2",
@@ -81,8 +82,9 @@ isac_new_ph(struct IsdnCardState *cs)
}
static void
-isac_bh(struct IsdnCardState *cs)
+isac_bh(void *data)
{
+ struct IsdnCardState *cs = data;
struct PStack *stptr;
if (!cs)
@@ -116,7 +118,7 @@ void
isac_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "isac_empty_fifo");
@@ -131,11 +133,10 @@ isac_empty_fifo(struct IsdnCardState *cs, int count)
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isac_lock, flags);
cs->readisacfifo(cs, ptr, count);
cs->writeisac(cs, ISAC_CMDR, 0x80);
- restore_flags(flags);
+ spin_unlock_irqrestore(&isac_lock, flags);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -150,7 +151,7 @@ isac_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "isac_fill_fifo");
@@ -167,8 +168,7 @@ isac_fill_fifo(struct IsdnCardState *cs)
more = !0;
count = 32;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isac_lock, flags);
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
@@ -181,7 +181,7 @@ isac_fill_fifo(struct IsdnCardState *cs)
init_timer(&cs->dbusytimer);
cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
add_timer(&cs->dbusytimer);
- restore_flags(flags);
+ spin_unlock_irqrestore(&isac_lock, flags);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -195,7 +195,7 @@ void
isac_sched_event(struct IsdnCardState *cs, int event)
{
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
void
@@ -204,7 +204,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
u_char exval, v1;
struct sk_buff *skb;
unsigned int count;
- long flags;
+ unsigned long flags;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC interrupt %x", val);
@@ -231,8 +231,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
if (count == 0)
count = 32;
isac_empty_fifo(cs, count);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isac_lock, flags);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = alloc_skb(count, GFP_ATOMIC)))
@@ -242,7 +241,7 @@ isac_interrupt(struct IsdnCardState *cs, u_char val)
skb_queue_tail(&cs->rq, skb);
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&isac_lock, flags);
}
cs->rcvidx = 0;
isac_sched_event(cs, D_RCVBUFREADY);
@@ -626,7 +625,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
void __devinit
initisac(struct IsdnCardState *cs)
{
- INIT_WORK(&cs->tqueue, (void *) (void *) isac_bh, NULL);
+ INIT_WORK(&cs->work, isac_bh, cs);
cs->setstack_d = setstack_isac;
cs->DC_Close = DC_Close_isac;
cs->dc.isac.mon_tx = NULL;
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 6eec59bc3207..ec5ec93c38f8 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -28,7 +28,7 @@ const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
void isar_setup(struct IsdnCardState *cs);
static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
static inline void ll_deliver_faxstat(struct BCState *bcs, u_char status);
-
+static spinlock_t isar_lock = SPIN_LOCK_UNLOCKED;
static inline int
waitforHIA(struct IsdnCardState *cs, int timeout)
{
@@ -47,7 +47,7 @@ int
sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
u_char *msg)
{
- long flags;
+ unsigned long flags;
int i;
if (!waitforHIA(cs, 4000))
@@ -56,8 +56,7 @@ sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isar_lock, flags);
cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg);
cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len);
cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0);
@@ -81,7 +80,7 @@ sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
#endif
}
cs->BC_Write_Reg(cs, 1, ISAR_HIS, his);
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
waitforHIA(cs, 10000);
return(1);
}
@@ -134,7 +133,7 @@ waitrecmsg(struct IsdnCardState *cs, u_char *len,
u_char *msg, int maxdelay)
{
int timeout = 0;
- long flags;
+ unsigned long flags;
struct isar_reg *ir = cs->bcs[0].hw.isar.reg;
@@ -145,12 +144,11 @@ waitrecmsg(struct IsdnCardState *cs, u_char *len,
printk(KERN_WARNING"isar recmsg IRQSTA timeout\n");
return(0);
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isar_lock, flags);
get_irq_infos(cs, ir);
rcv_mbox(cs, ir, msg);
*len = ir->clsb;
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
return(1);
}
@@ -192,7 +190,7 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
u_short sadr, left, *sp;
u_char *p = buf;
u_char *msg, *tmpmsg, *mp, tmp[64];
- long flags;
+ unsigned long flags;
struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
struct {u_short sadr;
@@ -346,8 +344,7 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
/* NORMAL mode entered */
/* Enable IRQs of ISAR */
cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA);
- save_flags(flags);
- sti();
+ spin_lock_irqsave(&isar_lock, flags);
cnt = 1000; /* max 1s */
while ((!ireg->bstat) && cnt) {
udelay(1000);
@@ -415,7 +412,7 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf)
isar_setup(cs);
ret = 0;
reterrflg:
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
reterror:
cs->debug = debug;
if (ret)
@@ -432,8 +429,10 @@ extern void BChannel_bh(struct BCState *);
#define B_LL_OK 10
static void
-isar_bh(struct BCState *bcs)
+isar_bh(void *data)
{
+ struct BCState *bcs = data;
+
BChannel_bh(bcs);
if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event))
ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR);
@@ -447,7 +446,7 @@ static void
isar_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
static inline void
@@ -669,7 +668,7 @@ isar_fill_fifo(struct BCState *bcs)
int count;
u_char msb;
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "isar_fill_fifo");
@@ -687,8 +686,7 @@ isar_fill_fifo(struct BCState *bcs)
count = bcs->tx_skb->len;
msb = HDLC_FED;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isar_lock, flags);
ptr = bcs->tx_skb->data;
if (!bcs->hw.isar.txcnt) {
msb |= HDLC_FST;
@@ -739,7 +737,7 @@ isar_fill_fifo(struct BCState *bcs)
printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode);
break;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
}
inline
@@ -1163,12 +1161,11 @@ static char debbuf[128];
void
isar_int_main(struct IsdnCardState *cs)
{
- long flags;
+ unsigned long flags;
struct isar_reg *ireg = cs->bcs[0].hw.isar.reg;
struct BCState *bcs;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isar_lock, flags);
get_irq_infos(cs, ireg);
switch (ireg->iis & ISAR_IIS_MSCMSD) {
case ISAR_IIS_RDATA:
@@ -1254,7 +1251,7 @@ isar_int_main(struct IsdnCardState *cs)
ireg->iis, ireg->cmsb, ireg->clsb);
break;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
}
static void
@@ -1560,7 +1557,7 @@ isar_setup(struct IsdnCardState *cs)
cs->bcs[i].mode = 0;
cs->bcs[i].hw.isar.dpath = i + 1;
modeisar(&cs->bcs[i], 0, 0);
- INIT_WORK(&cs->bcs[i].tqueue, (void *) (void *) isar_bh, NULL);
+ INIT_WORK(&cs->bcs[i].work, isar_bh, &cs->bcs[i]);
}
}
@@ -1568,22 +1565,21 @@ void
isar_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
switch (pr) {
case (PH_DATA | REQUEST):
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isar_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
} else {
st->l1.bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
if (st->l1.bcs->cs->debug & L1_DEB_HSCX)
debugl1(st->l1.bcs->cs, "DRQ set BC_FLG_BUSY");
st->l1.bcs->hw.isar.txcnt = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&isar_lock, flags);
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
}
break;
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 22643af00e4b..9ffdb7a423a7 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -299,10 +299,10 @@ BChannel_proc_rcv(struct BCState *bcs)
}
void
-BChannel_bh(struct BCState *bcs)
+BChannel_bh(void *data)
{
- if (!bcs)
- return;
+ struct BCState *bcs = data;
+
if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event))
BChannel_proc_rcv(bcs);
if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event))
@@ -345,7 +345,7 @@ init_bcstate(struct IsdnCardState *cs,
bcs->cs = cs;
bcs->channel = bc;
- INIT_WORK(&bcs->tqueue, (void *) (void *) BChannel_bh, bcs);
+ INIT_WORK(&bcs->work, BChannel_bh, bcs);
bcs->BC_SetStack = NULL;
bcs->BC_Close = NULL;
bcs->Flag = 0;
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 87ead71602b7..a9df21b94d8a 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -20,7 +20,7 @@
#include "isdnl2.h"
const char *l2_revision = "$Revision: 2.25.6.4 $";
-
+static spinlock_t isdnl2_lock = SPIN_LOCK_UNLOCKED;
static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
static struct Fsm l2fsm;
@@ -1256,7 +1256,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
u_char header[MAX_HEADER_LEN];
int i;
int unsigned p1;
- long flags;
+ unsigned long flags;
if (!cansend(st))
return;
@@ -1265,8 +1265,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
if (!skb)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&isdnl2_lock, flags);
if(test_bit(FLG_MOD128, &l2->flag))
p1 = (l2->vs - l2->va) % 128;
else
@@ -1289,7 +1288,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
header[i++] = (l2->vr << 5) | (l2->vs << 1);
l2->vs = (l2->vs + 1) % 8;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&isdnl2_lock, flags);
p1 = skb->data - skb->head;
if (p1 >= i)
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index 7cb12d598cdc..59d506a5522a 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -134,19 +134,14 @@ release_io_isurf(struct IsdnCardState *cs)
static void
reset_isurf(struct IsdnCardState *cs, u_char chips)
{
- long flags;
-
printk(KERN_INFO "ISurf: resetting card\n");
byteout(cs->hw.isurf.reset, chips); /* Reset On */
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
- restore_flags(flags);
}
static int
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index 314b84f89d9a..2cdeb86d44f7 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -26,6 +26,7 @@
extern const char *CardType[];
const char *ix1_revision = "$Revision: 2.10.6.2 $";
+static spinlock_t ix1_micro_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -43,13 +44,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ix1_micro_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&ix1_micro_lock, flags);
return (ret);
}
@@ -66,13 +66,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&ix1_micro_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&ix1_micro_lock, flags);
}
static inline void
@@ -184,19 +183,15 @@ release_io_ix1micro(struct IsdnCardState *cs)
static void
ix1_reset(struct IsdnCardState *cs)
{
- long flags;
int cnt;
/* reset isac */
- save_flags(flags);
cnt = 3 * (HZ / 10) + 1;
- sti();
while (cnt--) {
byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1);
HZDELAY(1); /* wait >=10 ms */
}
byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0);
- restore_flags(flags);
}
static int
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index b3d75918e907..2fa2f12600fd 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -18,6 +18,7 @@
#include "isdnl1.h"
#include <linux/interrupt.h>
+static spinlock_t jade_lock = SPIN_LOCK_UNLOCKED;
int __init
JadeVersion(struct IsdnCardState *cs, char *s)
@@ -50,10 +51,9 @@ static void
jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
{
int to = 50;
- long flags;
+ unsigned long flags;
u_char ret;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&jade_lock, flags);
/* Write the data */
cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value);
/* Say JADE we wanna write indirect reg 'reg' */
@@ -68,12 +68,12 @@ jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
/* Got acknowledge */
break;
if (!to) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_lock, flags);
printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
return;
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_lock, flags);
}
@@ -138,27 +138,26 @@ void
jade_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
static void
jade_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
switch (pr) {
case (PH_DATA | REQUEST):
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&jade_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_lock, flags);
} else {
st->l1.bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->hw.hscx.count = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_lock, flags);
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
}
break;
diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c
index e81547acf36f..79a72d372d61 100644
--- a/drivers/isdn/hisax/jade_irq.c
+++ b/drivers/isdn/hisax/jade_irq.c
@@ -9,6 +9,7 @@
* of the GNU General Public License, incorporated herein by reference.
*
*/
+static spinlock_t jade_irq_lock = SPIN_LOCK_UNLOCKED;
static inline void
waitforCEC(struct IsdnCardState *cs, int jade, int reg)
@@ -33,13 +34,12 @@ waitforXFW(struct IsdnCardState *cs, int jade)
static inline void
WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&jade_irq_lock, flags);
waitforCEC(cs, jade, reg);
WRITEJADE(cs, jade, reg, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_irq_lock, flags);
}
@@ -49,7 +49,7 @@ jade_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "jade_empty_fifo");
@@ -63,11 +63,10 @@ jade_empty_fifo(struct BCState *bcs, int count)
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&jade_irq_lock, flags);
READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_irq_lock, flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
@@ -85,7 +84,7 @@ jade_fill_fifo(struct BCState *bcs)
int more, count;
int fifo_size = 32;
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "jade_fill_fifo");
@@ -103,15 +102,14 @@ jade_fill_fifo(struct BCState *bcs)
count = bcs->tx_skb->len;
waitforXFW(cs, bcs->hw.hscx.hscx);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&jade_irq_lock, flags);
ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
- restore_flags(flags);
+ spin_unlock_irqrestore(&jade_irq_lock, flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index c066e544c090..585e7ffe3992 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -27,6 +27,7 @@
extern char *HiSax_getrev(const char *revision);
const char *dss1_revision = "$Revision: 2.30.6.2 $";
+static spinlock_t l3dss1_lock = SPIN_LOCK_UNLOCKED;
#define EXT_BEARER_CAPS 1
@@ -53,8 +54,7 @@ static unsigned char new_invoke_id(struct PStack *p)
i = 32; /* maximum search depth */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&l3dss1_lock, flags);
retval = p->prot.dss1.last_invoke_id + 1; /* try new id */
while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) {
@@ -68,7 +68,7 @@ static unsigned char new_invoke_id(struct PStack *p)
retval = 0;
p->prot.dss1.last_invoke_id = retval;
p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7));
- restore_flags(flags);
+ spin_unlock_irqrestore(&l3dss1_lock, flags);
return(retval);
} /* new_invoke_id */
@@ -81,10 +81,9 @@ static void free_invoke_id(struct PStack *p, unsigned char id)
if (!id) return; /* 0 = invalid value */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&l3dss1_lock, flags);
p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7));
- restore_flags(flags);
+ spin_unlock_irqrestore(&l3dss1_lock, flags);
} /* free_invoke_id */
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
index 42fce1c65ab3..0b9332c9597b 100644
--- a/drivers/isdn/hisax/l3ni1.c
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -25,6 +25,7 @@
extern char *HiSax_getrev(const char *revision);
const char *ni1_revision = "$Revision: 2.5.6.3 $";
+static spinlock_t l3ni1_lock = SPIN_LOCK_UNLOCKED;
#define EXT_BEARER_CAPS 1
@@ -51,8 +52,7 @@ static unsigned char new_invoke_id(struct PStack *p)
i = 32; /* maximum search depth */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&l3ni1_lock, flags);
retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
@@ -66,7 +66,7 @@ static unsigned char new_invoke_id(struct PStack *p)
retval = 0;
p->prot.ni1.last_invoke_id = retval;
p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
- restore_flags(flags);
+ spin_unlock_irqrestore(&l3ni1_lock, flags);
return(retval);
} /* new_invoke_id */
@@ -79,10 +79,9 @@ static void free_invoke_id(struct PStack *p, unsigned char id)
if (!id) return; /* 0 = invalid value */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&l3ni1_lock, flags);
p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
- restore_flags(flags);
+ spin_unlock_irqrestore(&l3ni1_lock, flags);
} /* free_invoke_id */
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
index 7e58a68138c1..97d94239927c 100644
--- a/drivers/isdn/hisax/mic.c
+++ b/drivers/isdn/hisax/mic.c
@@ -19,6 +19,7 @@
extern const char *CardType[];
const char *mic_revision = "$Revision: 1.10.6.2 $";
+static spinlock_t mic_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -34,13 +35,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mic_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&mic_lock, flags);
return (ret);
}
@@ -58,13 +58,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&mic_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&mic_lock, flags);
}
static inline void
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 525cd6544e79..2fb306def1db 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -26,37 +26,36 @@
#include "netjet.h"
const char *NETjet_revision = "$Revision: 1.24.6.6 $";
+static spinlock_t netjet_lock = SPIN_LOCK_UNLOCKED;
/* Interface functions */
u_char
NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
{
- long flags;
+ unsigned long flags;
u_char ret;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&netjet_lock, flags);
cs->hw.njet.auxd &= 0xfc;
cs->hw.njet.auxd |= (offset>>4) & 3;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
ret = bytein(cs->hw.njet.isac + ((offset & 0xf)<<2));
- restore_flags(flags);
+ spin_unlock_irqrestore(&netjet_lock, flags);
return(ret);
}
void
NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&netjet_lock, flags);
cs->hw.njet.auxd &= 0xfc;
cs->hw.njet.auxd |= (offset>>4) & 3;
byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
byteout(cs->hw.njet.isac + ((offset & 0xf)<<2), value);
- restore_flags(flags);
+ spin_unlock_irqrestore(&netjet_lock, flags);
}
void
@@ -434,7 +433,7 @@ static void got_frame(struct BCState *bcs, int count) {
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->event |= 1 << B_RCVBUFREADY;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME)
printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec");
@@ -790,7 +789,7 @@ static void write_raw(struct BCState *bcs, u_int *buf, int cnt) {
cnt - s_cnt);
}
bcs->event |= 1 << B_XMTBUFREADY;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
}
} else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
@@ -839,19 +838,18 @@ static void
tiger_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
switch (pr) {
case (PH_DATA | REQUEST):
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&netjet_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&netjet_lock, flags);
} else {
st->l1.bcs->tx_skb = skb;
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
- restore_flags(flags);
+ spin_unlock_irqrestore(&netjet_lock, flags);
}
break;
case (PH_PULL | INDICATION):
@@ -859,11 +857,10 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n");
break;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&netjet_lock, flags);
st->l1.bcs->tx_skb = skb;
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
- restore_flags(flags);
+ spin_unlock_irqrestore(&netjet_lock, flags);
break;
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index a71c447b3ca2..6caaac80c54f 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -25,6 +25,7 @@
extern const char *CardType[];
const char *niccy_revision = "$Revision: 1.15.6.6 $";
+static spinlock_t niccy_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -50,13 +51,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&niccy_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&niccy_lock, flags);
return (ret);
}
@@ -73,13 +73,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&niccy_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&niccy_lock, flags);
}
static inline void
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index 3d97c12f34f2..5a5600103366 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -16,6 +16,7 @@
#include "netjet.h"
const char *NETjet_S_revision = "$Revision: 2.7.6.6 $";
+static spinlock_t nj_s_lock = SPIN_LOCK_UNLOCKED;
static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
{
@@ -31,7 +32,7 @@ netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
- long flags;
+ unsigned long flags;
if (!cs) {
printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n");
@@ -48,8 +49,7 @@ netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
NETjet_WriteIC(cs, ISAC_MASK, 0x0);
}
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&nj_s_lock, flags);
/* start new code 13/07/00 GE */
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
@@ -67,11 +67,11 @@ netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&nj_s_lock, flags);
return;
}
cs->hw.njet.irqstat0 = sval;
- restore_flags(flags);
+ spin_unlock_irqrestore(&nj_s_lock, flags);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
@@ -83,7 +83,7 @@ netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
/* end new code 13/07/00 GE */
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
} else
- restore_flags(flags);
+ spin_unlock_irqrestore(&nj_s_lock, flags);
/* if (!testcnt--) {
cs->hw.njet.dmactrl = 0;
@@ -149,7 +149,7 @@ setup_netjet_s(struct IsdnCard *card)
int bytecnt;
struct IsdnCardState *cs = card->cs;
char tmp[64];
- long flags;
+ unsigned long flags;
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 0728a860a5cb..6d28c10e4d9f 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -16,6 +16,7 @@
#include "netjet.h"
const char *NETjet_U_revision = "$Revision: 2.8.6.6 $";
+static spinlock_t nj_u_lock = SPIN_LOCK_UNLOCKED;
static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
{
@@ -31,7 +32,7 @@ netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
- long flags;
+ unsigned long flags;
if (!cs) {
printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n");
@@ -48,8 +49,7 @@ netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
NETjet_WriteIC(cs, ICC_MASK, 0x0);
}
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&nj_u_lock, flags);
/* start new code 13/07/00 GE */
/* set bits in sval to indicate which page is free */
if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
@@ -67,11 +67,11 @@ netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
{
if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&nj_u_lock, flags);
return;
}
cs->hw.njet.irqstat0 = sval;
- restore_flags(flags);
+ spin_unlock_irqrestore(&nj_u_lock, flags);
if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
/* we have a read dma int */
@@ -83,7 +83,7 @@ netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
/* end new code 13/07/00 GE */
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
} else
- restore_flags(flags);
+ spin_unlock_irqrestore(&nj_u_lock, flags);
/* if (!testcnt--) {
cs->hw.njet.dmactrl = 0;
@@ -196,7 +196,6 @@ setup_netjet_u(struct IsdnCard *card)
save_flags(flags);
sti();
-
cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
index 4a9ea1ab9933..1e8d88da0884 100644
--- a/drivers/isdn/hisax/s0box.c
+++ b/drivers/isdn/hisax/s0box.c
@@ -18,13 +18,13 @@
extern const char *CardType[];
const char *s0box_revision = "$Revision: 2.4.6.2 $";
+static spinlock_t s0box_lock = SPIN_LOCK_UNLOCKED;
static inline void
writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&s0box_lock, flags);
outb_p(0x1c,padr+2);
outb_p(0x14,padr+2);
outb_p((addr+off)&0x7f,padr);
@@ -33,7 +33,7 @@ writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
outb_p(0x17,padr+2);
outb_p(0x14,padr+2);
outb_p(0x1c,padr+2);
- restore_flags(flags);
+ spin_unlock_irqrestore(&s0box_lock, flags);
}
static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf,
@@ -45,8 +45,7 @@ readreg(unsigned int padr, signed int addr, u_char off) {
register u_char n1, n2;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&s0box_lock, flags);
outb_p(0x1c,padr+2);
outb_p(0x14,padr+2);
outb_p((addr+off)|0x80,padr);
@@ -57,7 +56,7 @@ readreg(unsigned int padr, signed int addr, u_char off) {
n2 = (inb_p(padr+1) >> 3) & 0x17;
outb_p(0x14,padr+2);
outb_p(0x1c,padr+2);
- restore_flags(flags);
+ spin_unlock_irqrestore(&s0box_lock, flags);
return nibtab[n1] | (nibtab[n2] << 4);
}
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index 352392be38d2..4fbd2ee7bcd2 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -20,6 +20,7 @@
extern const char *CardType[];
static char *saphir_rev = "$Revision: 1.8.6.2 $";
+static spinlock_t saphir_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -35,13 +36,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&saphir_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&saphir_lock, flags);
return (ret);
}
@@ -58,13 +58,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&saphir_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&saphir_lock, flags);
}
static inline void
@@ -182,14 +181,9 @@ SaphirWatchDog(struct IsdnCardState *cs)
void
release_io_saphir(struct IsdnCardState *cs)
{
- long flags;
-
- save_flags(flags);
- cli();
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
- del_timer(&cs->hw.saphir.timer);
+ del_timer_sync(&cs->hw.saphir.timer);
cs->hw.saphir.timer.function = NULL;
- restore_flags(flags);
if (cs->hw.saphir.cfg_reg)
release_region(cs->hw.saphir.cfg_reg, 6);
}
@@ -197,7 +191,6 @@ release_io_saphir(struct IsdnCardState *cs)
static int
saphir_reset(struct IsdnCardState *cs)
{
- long flags;
u_char irq_val;
switch(cs->irq) {
@@ -220,15 +213,12 @@ saphir_reset(struct IsdnCardState *cs)
return (1);
}
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
- save_flags(flags);
- sti();
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
- restore_flags(flags);
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
return (0);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 48e0bbbc4bfe..694eb354c1cb 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -50,6 +50,7 @@
#include <linux/isapnp.h>
extern const char *CardType[];
+static spinlock_t sedlbauer_lock = SPIN_LOCK_UNLOCKED;
const char *Sedlbauer_revision = "$Revision: 1.25.6.6 $";
@@ -121,13 +122,12 @@ static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&sedlbauer_lock, flags);
byteout(ale, off);
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&sedlbauer_lock, flags);
return (ret);
}
@@ -144,13 +144,12 @@ readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&sedlbauer_lock, flags);
byteout(ale, off);
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&sedlbauer_lock, flags);
}
static inline void
@@ -422,16 +421,12 @@ release_io_sedlbauer(struct IsdnCardState *cs)
static void
reset_sedlbauer(struct IsdnCardState *cs)
{
- long flags;
-
printk(KERN_INFO "Sedlbauer: resetting card\n");
if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) &&
(cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) {
if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
@@ -442,28 +437,21 @@ reset_sedlbauer(struct IsdnCardState *cs)
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0);
writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12);
- restore_flags(flags);
} else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) &&
(cs->hw.sedl.bus == SEDL_BUS_PCI)) {
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
- save_flags(flags);
- sti();
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((20*HZ)/1000);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((20*HZ)/1000);
- restore_flags(flags);
} else {
byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
- restore_flags(flags);
}
}
}
@@ -552,7 +540,6 @@ setup_sedlbauer(struct IsdnCard *card)
struct IsdnCardState *cs = card->cs;
char tmp[64];
u16 sub_vendor_id, sub_id;
- long flags;
strcpy(tmp, Sedlbauer_revision);
printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -685,12 +672,9 @@ setup_sedlbauer(struct IsdnCard *card)
byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
- save_flags(flags);
- sti();
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
- restore_flags(flags);
#else
printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
return (0);
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index b14044b93b7d..687cf8504c71 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -147,19 +147,14 @@ release_io_sportster(struct IsdnCardState *cs)
void
reset_sportster(struct IsdnCardState *cs)
{
- long flags;
-
cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
- restore_flags(flags);
}
static int
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index 167850af27f8..372f5ed34241 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -19,6 +19,7 @@
extern const char *CardType[];
const char *TeleInt_revision = "$Revision: 1.14.6.2 $";
+static spinlock_t teleint_lock = SPIN_LOCK_UNLOCKED;
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -28,21 +29,20 @@ readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
int max_delay = 2000;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&teleint_lock, flags);
byteout(ale, off);
ret = HFC_BUSY & bytein(ale);
while (ret && --max_delay)
ret = HFC_BUSY & bytein(ale);
if (!max_delay) {
printk(KERN_WARNING "TeleInt Busy not inactive\n");
- restore_flags(flags);
+ spin_unlock_irqrestore(&teleint_lock, flags);
return (0);
}
ret = bytein(adr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&teleint_lock, flags);
return (ret);
}
@@ -72,21 +72,20 @@ writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
register u_char ret;
int max_delay = 2000;
- long flags;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&teleint_lock, flags);
byteout(ale, off);
ret = HFC_BUSY & bytein(ale);
while (ret && --max_delay)
ret = HFC_BUSY & bytein(ale);
if (!max_delay) {
printk(KERN_WARNING "TeleInt Busy not inactive\n");
- restore_flags(flags);
+ spin_unlock_irqrestore(&teleint_lock, flags);
return;
}
byteout(adr, data);
- restore_flags(flags);
+ spin_unlock_irqrestore(&teleint_lock, flags);
}
static inline void
@@ -220,20 +219,15 @@ release_io_TeleInt(struct IsdnCardState *cs)
static void
reset_TeleInt(struct IsdnCardState *cs)
{
- long flags;
-
printk(KERN_INFO "TeleInt: resetting card\n");
cs->hw.hfc.cirm |= HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */
- save_flags(flags);
- sti();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((30*HZ)/1000);
cs->hw.hfc.cirm &= ~HFC_RESET;
byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((10*HZ)/1000);
- restore_flags(flags);
}
static int
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 8dbbdd70baf0..dfe161baf900 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -196,10 +196,7 @@ static int
reset_teles0(struct IsdnCardState *cs)
{
u_char cfval;
- long flags;
- save_flags(flags);
- sti();
if (cs->hw.teles0.cfg_reg) {
switch (cs->irq) {
case 2:
@@ -240,7 +237,6 @@ reset_teles0(struct IsdnCardState *cs)
HZDELAY(HZ / 5 + 1);
writeb(1, cs->hw.teles0.membase + 0x80); mb();
HZDELAY(HZ / 5 + 1);
- restore_flags(flags);
return(0);
}
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index be444a8c2f88..02662ebae6cf 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -174,7 +174,6 @@ release_io_teles3(struct IsdnCardState *cs)
static int
reset_teles3(struct IsdnCardState *cs)
{
- long flags;
u_char irqcfg;
if (cs->typ != ISDN_CTYPE_TELESPCMCIA) {
@@ -208,28 +207,21 @@ reset_teles3(struct IsdnCardState *cs)
default:
return(1);
}
- save_flags(flags);
byteout(cs->hw.teles3.cfg_reg + 4, irqcfg);
- sti();
HZDELAY(HZ / 10 + 1);
byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1);
HZDELAY(HZ / 10 + 1);
- restore_flags(flags);
} else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
- save_flags(flags);
byteout(cs->hw.teles3.cfg_reg, 0xff);
HZDELAY(2);
byteout(cs->hw.teles3.cfg_reg, 0x00);
HZDELAY(2);
- restore_flags(flags);
} else {
/* Reset off for 16.3 PnP , thanks to Georg Acher */
- save_flags(flags);
byteout(cs->hw.teles3.isac + 0x3c, 0);
HZDELAY(2);
byteout(cs->hw.teles3.isac + 0x3c, 1);
HZDELAY(2);
- restore_flags(flags);
}
}
return(0);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 715b84e4d773..bfa0eb2af7b3 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -43,6 +43,8 @@ extern const char *CardType[];
const char *w6692_revision = "$Revision: 1.12.6.6 $";
+static spinlock_t w6692_lock = SPIN_LOCK_UNLOCKED;
+
#define DBUSY_TIMER_VALUE 80
static char *W6692Ver[] __initdata =
@@ -102,8 +104,9 @@ W6692_new_ph(struct IsdnCardState *cs)
}
static void
-W6692_bh(struct IsdnCardState *cs)
+W6692_bh(void *data)
{
+ struct IsdnCardState *cs = data;
struct PStack *stptr;
if (!cs)
@@ -135,21 +138,21 @@ void
W6692_sched_event(struct IsdnCardState *cs, int event)
{
test_and_set_bit(event, &cs->event);
- schedule_work(&cs->tqueue);
+ schedule_work(&cs->work);
}
static void
W6692B_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
- schedule_work(&bcs->tqueue);
+ schedule_work(&bcs->work);
}
static void
W6692_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "W6692_empty_fifo");
@@ -164,11 +167,10 @@ W6692_empty_fifo(struct IsdnCardState *cs, int count)
}
ptr = cs->rcvbuf + cs->rcvidx;
cs->rcvidx += count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&w6692_lock, flags);
cs->readW6692fifo(cs, ptr, count);
cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK);
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock, flags);
if (cs->debug & L1_DEB_ISAC_FIFO) {
char *t = cs->dlog;
@@ -183,7 +185,7 @@ W6692_fill_fifo(struct IsdnCardState *cs)
{
int count, more;
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
debugl1(cs, "W6692_fill_fifo");
@@ -200,14 +202,13 @@ W6692_fill_fifo(struct IsdnCardState *cs)
more = !0;
count = W_D_FIFO_THRESH;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&w6692_lock, flags);
ptr = cs->tx_skb->data;
skb_pull(cs->tx_skb, count);
cs->tx_cnt += count;
cs->writeW6692fifo(cs, ptr, count);
cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME));
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock , flags);
if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
debugl1(cs, "W6692_fill_fifo dbusytimer running");
del_timer(&cs->dbusytimer);
@@ -229,7 +230,7 @@ W6692B_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "W6692B_empty_fifo");
@@ -243,11 +244,10 @@ W6692B_empty_fifo(struct BCState *bcs, int count)
}
ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx;
bcs->hw.w6692.rcvidx += count;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&w6692_lock, flags);
READW6692BFIFO(cs, bcs->channel, ptr, count);
cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock , flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
@@ -264,7 +264,7 @@ W6692B_fill_fifo(struct BCState *bcs)
struct IsdnCardState *cs = bcs->cs;
int more, count;
u_char *ptr;
- long flags;
+ unsigned long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
@@ -282,15 +282,14 @@ W6692B_fill_fifo(struct BCState *bcs)
} else
count = bcs->tx_skb->len;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&w6692_lock, flags);
ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.w6692.count += count;
WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock , flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
@@ -411,7 +410,7 @@ W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
u_char val, exval, v1;
struct sk_buff *skb;
unsigned int count;
- long flags;
+ unsigned long flags;
int icnt = 5;
if (!cs) {
@@ -442,8 +441,7 @@ W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (count == 0)
count = W_D_FIFO_THRESH;
W6692_empty_fifo(cs, count);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&w6692_lock, flags);
if ((count = cs->rcvidx) > 0) {
cs->rcvidx = 0;
if (!(skb = alloc_skb(count, GFP_ATOMIC)))
@@ -453,7 +451,7 @@ W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
skb_queue_tail(&cs->rq, skb);
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock , flags);
}
cs->rcvidx = 0;
W6692_sched_event(cs, D_RCVBUFREADY);
@@ -745,20 +743,19 @@ static void
W6692_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
- long flags;
+ unsigned long flags;
switch (pr) {
case (PH_DATA | REQUEST):
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&w6692_lock, flags);
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock , flags);
} else {
st->l1.bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->hw.w6692.count = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&w6692_lock , flags);
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
}
break;
@@ -887,7 +884,7 @@ void resetW6692(struct IsdnCardState *cs)
void __init initW6692(struct IsdnCardState *cs, int part)
{
if (part & 1) {
- INIT_WORK(&cs->tqueue, (void *) (void *) W6692_bh, NULL);
+ INIT_WORK(&cs->work, W6692_bh, cs);
cs->setstack_d = setstack_W6692;
cs->DC_Close = DC_Close_W6692;
cs->dbusytimer.function = (void *) dbusy_timer_handler;
diff --git a/drivers/isdn/i4l/Config.in b/drivers/isdn/i4l/Config.in
index 2b19e0eddf6c..40bebca3c651 100644
--- a/drivers/isdn/i4l/Config.in
+++ b/drivers/isdn/i4l/Config.in
@@ -3,6 +3,8 @@
#
if [ "$CONFIG_INET" != "n" ]; then
+ bool ' Support raw-IP and other simple protocols' CONFIG_ISDN_NET_SIMPLE
+ bool ' Support CISCO HDLC' CONFIG_ISDN_NET_CISCO
bool ' Support synchronous PPP' CONFIG_ISDN_PPP
if [ "$CONFIG_ISDN_PPP" != "n" ]; then
bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile
index 3bf0d170754f..4458d5d4478b 100644
--- a/drivers/isdn/i4l/Makefile
+++ b/drivers/isdn/i4l/Makefile
@@ -11,15 +11,18 @@ obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Multipart objects.
-isdn-objs := isdn_net.o isdn_net_lib.o \
+isdn-objs := isdn_net_lib.o \
isdn_fsm.o \
- isdn_ciscohdlck.o \
isdn_tty.o isdn_v110.o \
isdn_common.o \
# Optional parts of multipart objects.
+isdn-objs-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o
+isdn-objs-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o
isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o
+isdn-objs-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o
+isdn-objs-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o
isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
index bdd92d81d13d..47b90e49b8d8 100644
--- a/drivers/isdn/i4l/isdn_audio.c
+++ b/drivers/isdn/i4l/isdn_audio.c
@@ -1,21 +1,20 @@
-/* $Id: isdn_audio.c,v 1.21.6.3 2002/08/13 09:45:33 keil Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
+/* Linux ISDN subsystem, audio conversion and compression
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * DTMF code (c) 1996 by Christian Mock (cm@tahina.priv.at)
- * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de)
+ * 1996 by Christian Mock (cm@tahina.priv.at)
+ * 1998 by Armin Schindler (mac@gismo.telekom.de)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
+ * DTMF code by Christian Mock
+ * Silence detection by Armin Schindler
*/
#include <linux/isdn.h>
#include "isdn_audio.h"
#include "isdn_common.h"
-
-char *isdn_audio_revision = "$Revision: 1.21.6.3 $";
+#include "isdn_tty.h"
/*
* Misc. lookup-tables.
@@ -507,7 +506,7 @@ isdn_audio_goertzel(int *sample, modem_info * info)
((sk2 * sk2) >> AMP_BITS);
}
skb_queue_tail(&info->dtmf_queue, skb);
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+ mod_timer(&info->read_timer, jiffies + 4);
}
void
@@ -518,8 +517,6 @@ isdn_audio_eval_dtmf(modem_info * info)
dtmf_state *s;
int silence;
int i;
- int di;
- int ch;
unsigned long flags;
int grp[2];
char what;
@@ -564,15 +561,11 @@ isdn_audio_eval_dtmf(modem_info * info)
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
- di = isdn_slot_driver(info->isdn_slot);
- ch = isdn_slot_channel(info->isdn_slot);
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
+ isdn_tty_queue_tail(info, skb, 2);
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
+ mod_timer(&info->read_timer, jiffies + 4);
} else
kfree_skb(skb);
s->last = what;
@@ -661,8 +654,6 @@ isdn_audio_put_dle_code(modem_info * info, u_char code)
{
struct sk_buff *skb;
unsigned long flags;
- int di;
- int ch;
char *p;
skb = dev_alloc_skb(2);
@@ -685,15 +676,11 @@ isdn_audio_put_dle_code(modem_info * info, u_char code)
ISDN_AUDIO_SKB_LOCK(skb) = 0;
save_flags(flags);
cli();
- di = isdn_slot_driver(info->isdn_slot);
- ch = isdn_slot_channel(info->isdn_slot);
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += 2;
+ isdn_tty_queue_tail(info, skb, 2);
restore_flags(flags);
/* Schedule dequeuing */
if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]);
+ mod_timer(&info->read_timer, jiffies + 4);
}
void
diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h
index e60c980c953a..e08d7d2a0700 100644
--- a/drivers/isdn/i4l/isdn_audio.h
+++ b/drivers/isdn/i4l/isdn_audio.h
@@ -1,6 +1,4 @@
-/* $Id: isdn_audio.h,v 1.9.6.1 2001/09/23 22:24:31 kai Exp $
- *
- * Linux ISDN subsystem, audio conversion and compression (linklevel).
+/* Linux ISDN subsystem, audio conversion and compression
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
*
diff --git a/drivers/isdn/i4l/isdn_ciscohdlck.c b/drivers/isdn/i4l/isdn_ciscohdlck.c
index cab5b1a2100f..f8e903aa1b3c 100644
--- a/drivers/isdn/i4l/isdn_ciscohdlck.c
+++ b/drivers/isdn/i4l/isdn_ciscohdlck.c
@@ -1,5 +1,4 @@
-/*
- * Linux ISDN subsystem, CISCO HDLC network interfaces
+/* Linux ISDN subsystem, CISCO HDLC network interfaces
*
* Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
* 1995,96 by Thinking Objects Software GmbH Wuerzburg
@@ -14,7 +13,7 @@
*/
#include "isdn_common.h"
-#include "isdn_net.h"
+#include "isdn_net_lib.h"
#include "isdn_ciscohdlck.h"
#include <linux/if_arp.h>
@@ -56,6 +55,7 @@ static int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
isdn_net_local *mlp = dev->priv;
+ struct inl_cisco *cisco = mlp->inl_priv;
unsigned long len = 0;
int period;
char debserint;
@@ -67,13 +67,13 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
switch (cmd) {
/* get/set keepalive period */
case SIOCGKEEPPERIOD:
- len = sizeof(mlp->cisco_keepalive_period);
+ len = sizeof(cisco->keepalive_period);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
- (char *)&mlp->cisco_keepalive_period, len))
+ (char *)&cisco->keepalive_period, len))
rc = -EFAULT;
break;
case SIOCSKEEPPERIOD:
- len = sizeof(mlp->cisco_keepalive_period);
+ len = sizeof(cisco->keepalive_period);
if (copy_from_user((char *)&period,
(char *)ifr->ifr_ifru.ifru_data, len)) {
rc = -EFAULT;
@@ -83,21 +83,21 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
rc = -EINVAL;
break;
}
- mod_timer(&mlp->cisco_timer, jiffies + period * HZ);
+ mod_timer(&cisco->timer, jiffies + period * HZ);
printk(KERN_INFO "%s: Keepalive period set "
"to %d seconds.\n", dev->name, period);
- mlp->cisco_keepalive_period = period;
+ cisco->keepalive_period = period;
break;
/* get/set debugging */
case SIOCGDEBSERINT:
- len = sizeof(mlp->cisco_debserint);
+ len = sizeof(cisco->debserint);
if (copy_to_user((char *)ifr->ifr_ifru.ifru_data,
- (char *)&mlp->cisco_debserint, len))
+ (char *)&cisco->debserint, len))
rc = -EFAULT;
break;
case SIOCSDEBSERINT:
- len = sizeof(mlp->cisco_debserint);
+ len = sizeof(cisco->debserint);
if (copy_from_user((char *)&debserint,
(char *)ifr->ifr_ifru.ifru_data, len)) {
rc = -EFAULT;
@@ -107,7 +107,7 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
rc = -EINVAL;
break;
}
- mlp->cisco_debserint = debserint;
+ cisco->debserint = debserint;
break;
default:
@@ -122,10 +122,11 @@ static void
isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
{
isdn_net_local *mlp = (isdn_net_local *) data;
- isdn_net_dev *idev;
+ isdn_net_dev *idev;
+ struct inl_cisco *cisco = mlp->inl_priv;
struct sk_buff *skb;
unsigned char *p;
- unsigned long last_cisco_myseq = mlp->cisco_myseq;
+ unsigned long last_cisco_myseq = cisco->myseq;
int myseq_diff = 0;
if (list_empty(&mlp->online)) {
@@ -133,33 +134,33 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
return;
}
idev = list_entry(mlp->online.next, isdn_net_dev, online);
- mlp->cisco_myseq++;
+ cisco->myseq++;
- myseq_diff = (mlp->cisco_myseq - mlp->cisco_mineseen);
- if (mlp->cisco_line_state && (myseq_diff >= 3 || myseq_diff <= -3)) {
+ myseq_diff = cisco->myseq - cisco->mineseen;
+ if (cisco->line_state && (myseq_diff >= 3 || myseq_diff <= -3)) {
/* line up -> down */
- mlp->cisco_line_state = 0;
+ cisco->line_state = 0;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to down\n", idev->name);
/* should stop routing higher-level data accross */
- } else if (!mlp->cisco_line_state &&
+ } else if (!cisco->line_state &&
myseq_diff >= 0 && myseq_diff <= 2) {
/* line down -> up */
- mlp->cisco_line_state = 1;
+ cisco->line_state = 1;
printk (KERN_WARNING
"UPDOWN: Line protocol on Interface %s,"
" changed state to up\n", idev->name);
/* restart routing higher-level data accross */
}
- if (mlp->cisco_debserint)
+ if (cisco->debserint)
printk (KERN_DEBUG "%s: HDLC "
- "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n",
- idev->name, last_cisco_myseq, mlp->cisco_mineseen,
- (last_cisco_myseq == mlp->cisco_mineseen) ? '*' : 040,
- mlp->cisco_yourseq,
- (mlp->cisco_line_state) ? "line up" : "line down");
+ "myseq %u, mineseen %u%c, yourseen %u, %s\n",
+ idev->name, cisco->myseq, cisco->mineseen,
+ (last_cisco_myseq == cisco->mineseen) ? '*' : 040,
+ cisco->yourseq,
+ (cisco->line_state) ? "line up" : "line down");
skb = isdn_net_ciscohdlck_alloc_skb(idev, 4 + 14);
if (!skb)
@@ -174,13 +175,13 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data)
/* slarp keepalive */
p += put_u32(p, CISCO_SLARP_KEEPALIVE);
- p += put_u32(p, mlp->cisco_myseq);
- p += put_u32(p, mlp->cisco_yourseq);
+ p += put_u32(p, cisco->myseq);
+ p += put_u32(p, cisco->yourseq);
p += put_u16(p, 0xffff); // reliablity, always 0xffff
isdn_net_write_super(idev, skb);
- mod_timer(&mlp->cisco_timer, jiffies + mlp->cisco_keepalive_period * HZ);
+ mod_timer(&cisco->timer, jiffies + cisco->keepalive_period * HZ);
}
static void
@@ -220,24 +221,25 @@ static void
isdn_ciscohdlck_connected(isdn_net_dev *idev)
{
isdn_net_local *lp = idev->mlp;
+ struct inl_cisco *cisco = lp->inl_priv;
- lp->cisco_myseq = 0;
- lp->cisco_mineseen = 0;
- lp->cisco_yourseq = 0;
- lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT;
- lp->cisco_last_slarp_in = 0;
- lp->cisco_line_state = 0;
- lp->cisco_debserint = 0;
+ cisco->myseq = 0;
+ cisco->mineseen = 0;
+ cisco->yourseq = 0;
+ cisco->keepalive_period = 10;
+ cisco->last_slarp_in = 0;
+ cisco->line_state = 0;
+ cisco->debserint = 0;
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
/* send slarp request because interface/seq.no.s reset */
isdn_net_ciscohdlck_slarp_send_request(lp);
- init_timer(&lp->cisco_timer);
- lp->cisco_timer.data = (unsigned long) lp;
- lp->cisco_timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
- lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ;
- add_timer(&lp->cisco_timer);
+ init_timer(&cisco->timer);
+ cisco->timer.data = (unsigned long) lp;
+ cisco->timer.function = isdn_net_ciscohdlck_slarp_send_keepalive;
+ cisco->timer.expires = jiffies + cisco->keepalive_period * HZ;
+ add_timer(&cisco->timer);
}
netif_wake_queue(&lp->dev);
}
@@ -246,9 +248,10 @@ static void
isdn_ciscohdlck_disconnected(isdn_net_dev *idev)
{
isdn_net_local *lp = idev->mlp;
+ struct inl_cisco *cisco = lp->inl_priv;
if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) {
- del_timer(&lp->cisco_timer);
+ del_timer(&cisco->timer);
}
}
@@ -296,6 +299,7 @@ static void
isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb)
{
isdn_net_local *mlp = idev->mlp;
+ struct inl_cisco *cisco = mlp->inl_priv;
unsigned char *p;
int period;
u32 code;
@@ -312,7 +316,7 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb)
switch (code) {
case CISCO_SLARP_REQUEST:
- mlp->cisco_yourseq = 0;
+ cisco->yourseq = 0;
isdn_net_ciscohdlck_slarp_send_reply(idev);
break;
case CISCO_SLARP_REPLY:
@@ -339,21 +343,20 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_dev *idev, struct sk_buff *skb)
HIPQUAD(addr), HIPQUAD(mask));
break;
case CISCO_SLARP_KEEPALIVE:
- period = (int)((jiffies - mlp->cisco_last_slarp_in
- + HZ/2 - 1) / HZ);
- if (mlp->cisco_debserint &&
- (period != mlp->cisco_keepalive_period) &&
- mlp->cisco_last_slarp_in) {
+ period = (jiffies - cisco->last_slarp_in + HZ/2 - 1) / HZ;
+ if (cisco->debserint &&
+ (period != cisco->keepalive_period) &&
+ cisco->last_slarp_in) {
printk(KERN_DEBUG "%s: Keepalive period mismatch - "
"is %d but should be %d.\n",
- idev->name, period, mlp->cisco_keepalive_period);
+ idev->name, period, cisco->keepalive_period);
}
- mlp->cisco_last_slarp_in = jiffies;
+ cisco->last_slarp_in = jiffies;
p += get_u32(p, &my_seq);
p += get_u32(p, &your_seq);
p += get_u16(p, &unused);
- mlp->cisco_yourseq = my_seq;
- mlp->cisco_mineseen = your_seq;
+ cisco->yourseq = my_seq;
+ cisco->mineseen = your_seq;
break;
}
}
@@ -362,6 +365,7 @@ static void
isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
+ struct inl_cisco *cisco = lp->inl_priv;
unsigned char *p;
u8 addr;
u8 ctrl;
@@ -388,7 +392,7 @@ isdn_ciscohdlck_receive(isdn_net_local *lp, isdn_net_dev *idev,
isdn_net_ciscohdlck_slarp_in(idev, skb);
goto out_free;
case CISCO_TYPE_CDP:
- if (lp->cisco_debserint)
+ if (cisco->debserint)
printk(KERN_DEBUG "%s: Received CDP packet. use "
"\"no cdp enable\" on cisco.\n", idev->name);
goto out_free;
@@ -418,7 +422,23 @@ isdn_ciscohdlck_header(struct sk_buff *skb, struct net_device *dev,
return 4;
}
-struct isdn_netif_ops ciscohdlck_ops = {
+static int
+isdn_ciscohdlck_open(isdn_net_local *lp)
+{
+ lp->inl_priv = kmalloc(sizeof(struct inl_cisco), GFP_KERNEL);
+ if (!lp->inl_priv)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void
+isdn_ciscohdlck_close(isdn_net_local *lp)
+{
+ kfree(lp->inl_priv);
+}
+
+struct isdn_netif_ops isdn_ciscohdlck_ops = {
.hard_start_xmit = isdn_net_start_xmit,
.hard_header = isdn_ciscohdlck_header,
.do_ioctl = isdn_ciscohdlck_dev_ioctl,
@@ -427,4 +447,6 @@ struct isdn_netif_ops ciscohdlck_ops = {
.receive = isdn_ciscohdlck_receive,
.connected = isdn_ciscohdlck_connected,
.disconnected = isdn_ciscohdlck_disconnected,
+ .open = isdn_ciscohdlck_open,
+ .close = isdn_ciscohdlck_close,
};
diff --git a/drivers/isdn/i4l/isdn_ciscohdlck.h b/drivers/isdn/i4l/isdn_ciscohdlck.h
index 24cd87d2f674..dda0d7a07744 100644
--- a/drivers/isdn/i4l/isdn_ciscohdlck.h
+++ b/drivers/isdn/i4l/isdn_ciscohdlck.h
@@ -1,5 +1,4 @@
-/*
- * Linux ISDN subsystem, CISCO HDLC network interfaces
+/* Linux ISDN subsystem, CISCO HDLC network interfaces
*
* Copyright 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
* 2001 by Bjoern A. Zeeb <i4l@zabbadoz.net>
@@ -11,6 +10,17 @@
#ifndef ISDN_CISCOHDLCK_H
#define ISDN_CISCOHDLCK_H
-extern struct isdn_netif_ops ciscohdlck_ops;
+extern struct isdn_netif_ops isdn_ciscohdlck_ops;
+
+struct inl_cisco {
+ u32 myseq; /* local keepalive seq. for Cisco */
+ u32 mineseen; /* returned keepalive seq. from remote */
+ u32 yourseq; /* remote keepalive seq. for Cisco */
+ int keepalive_period; /* keepalive period */
+ int last_slarp_in; /* jiffie of last recvd keepalive pkt */
+ char line_state; /* state of line */
+ char debserint; /* debugging flags */
+ struct timer_list timer;
+};
#endif
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 37a7968aabb7..f3b158796419 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1,6 +1,4 @@
-/* $Id: isdn_common.c,v 1.114.6.16 2001/11/06 20:58:28 kai Exp $
- *
- * Linux ISDN subsystem, common used functions (linklevel).
+/* Linux ISDN subsystem, common used functions
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
@@ -8,7 +6,6 @@
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#include <linux/config.h>
@@ -21,14 +18,14 @@
#include <linux/smp_lock.h>
#include <linux/ctype.h>
#include "isdn_common.h"
-#include "isdn_tty.h"
+#include "isdn_net_lib.h"
#include "isdn_net.h"
+#include "isdn_tty.h"
#include "isdn_ppp.h"
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
#endif
#include <linux/isdn_divertif.h>
-#include "isdn_v110.h"
#include <linux/devfs_fs_kernel.h>
MODULE_DESCRIPTION("ISDN4Linux: link layer");
@@ -37,94 +34,982 @@ MODULE_LICENSE("GPL");
isdn_dev *dev;
-struct isdn_slot {
- int di; /* driver index */
- int ch; /* channel index (per driver) */
- int usage; /* how is it used */
- char num[ISDN_MSNLEN]; /* the current phone number */
- unsigned long ibytes; /* Statistics incoming bytes */
- unsigned long obytes; /* Statistics outgoing bytes */
- struct isdn_v110 iv110; /* For V.110 */
- int m_idx; /* Index for mdm.... */
- isdn_net_dev *idev; /* pointer to isdn_net_dev */
+static void isdn_lock_driver(struct isdn_driver *drv);
+static void isdn_unlock_driver(struct isdn_driver *drv);
+
+static void isdn_register_devfs(int);
+static void isdn_unregister_devfs(int);
+
+/* ====================================================================== */
+
+static struct isdn_slot slots[ISDN_MAX_CHANNELS];
+
+static struct fsm slot_fsm;
+static void slot_debug(struct fsm_inst *fi, char *fmt, ...);
+
+static char *slot_st_str[] = {
+ "ST_SLOT_NULL",
+ "ST_SLOT_BOUND",
+ "ST_SLOT_IN",
+ "ST_SLOT_WAIT_DCONN",
+ "ST_SLOT_DCONN",
+ "ST_SLOT_WAIT_BCONN",
+ "ST_SLOT_ACTIVE",
+ "ST_SLOT_WAIT_BHUP",
+ "ST_SLOT_WAIT_DHUP",
};
-static struct isdn_slot slot[ISDN_MAX_CHANNELS];
+static char *ev_str[] = {
+ "EV_DRV_REGISTER",
+ "EV_STAT_RUN",
+ "EV_STAT_STOP",
+ "EV_STAT_UNLOAD",
+ "EV_STAT_STAVAIL",
+ "EV_STAT_ADDCH",
+ "EV_STAT_ICALL",
+ "EV_STAT_DCONN",
+ "EV_STAT_BCONN",
+ "EV_STAT_BHUP",
+ "EV_STAT_DHUP",
+ "EV_STAT_BSENT",
+ "EV_STAT_CINF",
+ "EV_STAT_CAUSE",
+ "EV_STAT_DISPLAY",
+ "EV_STAT_FAXIND",
+ "EV_STAT_AUDIO",
+ "EV_CMD_CLREAZ",
+ "EV_CMD_SETEAZ",
+ "EV_CMD_SETL2",
+ "EV_CMD_SETL3",
+ "EV_CMD_DIAL",
+ "EV_CMD_ACCEPTD",
+ "EV_CMD_ACCEPTB",
+ "EV_CMD_HANGUP",
+ "EV_DATA_REQ",
+ "EV_DATA_IND",
+ "EV_SLOT_BIND",
+ "EV_SLOT_UNBIND",
+};
-static char *isdn_revision = "$Revision: 1.114.6.16 $";
+static int __slot_command(struct isdn_slot *slot, isdn_ctrl *cmd);
-extern char *isdn_net_revision;
-extern char *isdn_tty_revision;
-#ifdef CONFIG_ISDN_PPP
-extern char *isdn_ppp_revision;
-#else
-static char *isdn_ppp_revision = ": none $";
-#endif
-#ifdef CONFIG_ISDN_AUDIO
-extern char *isdn_audio_revision;
-#else
-static char *isdn_audio_revision = ": none $";
-#endif
-extern char *isdn_v110_revision;
+static void isdn_v110_setl2(struct isdn_slot *slot, isdn_ctrl *cmd);
+static void __isdn_v110_open(struct isdn_slot *slot);
+static void __isdn_v110_close(struct isdn_slot *slot);
+static void __isdn_v110_bsent(struct isdn_slot *slot, int pr, isdn_ctrl *cmd);
+static int isdn_v110_data_ind(struct isdn_slot *slot, struct sk_buff *skb);
+static int isdn_v110_data_req(struct isdn_slot *slot, struct sk_buff *skb);
-#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
-static isdn_divert_if *divert_if; /* = NULL */
-#else
-#define divert_if ((isdn_divert_if *) NULL)
-#endif
+static inline int
+do_event_cb(struct isdn_slot *slot, int pr, void *arg)
+{
+ if (slot->event_cb)
+ return slot->event_cb(slot, pr, arg);
+ return -ENXIO;
+}
-static void set_global_features(void);
-static void isdn_register_devfs(int);
-static void isdn_unregister_devfs(int);
-static int isdn_wildmat(char *s, char *p);
-static int isdn_command(isdn_ctrl *cmd);
+static int
+slot_bind(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+
+ isdn_lock_driver(slot->drv);
+ fsm_change_state(fi, ST_SLOT_BOUND);
-void
-isdn_lock_drivers(void)
+ return 0;
+}
+
+/* just pass through command */
+static int
+slot_command(struct fsm_inst *fi, int pr, void *arg)
{
- int i;
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *c = arg;
- for (i = 0; i < dev->drivers; i++) {
- isdn_ctrl cmd;
+ return __slot_command(slot, c);
+}
- cmd.driver = i;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_LOCK;
- isdn_command(&cmd);
- dev->drv[i]->locks++;
+/* just pass through status */
+static int
+slot_stat(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+
+ do_event_cb(slot, pr, arg);
+ return 0;
+}
+
+/* just pass through command */
+static int
+slot_setl2(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *c = arg;
+
+ isdn_v110_setl2(slot, c);
+
+ return __slot_command(slot, c);
+}
+
+static int
+slot_dial(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *ctrl = arg;
+ int retval;
+
+ retval = __slot_command(slot, ctrl);
+ if (retval >= 0)
+ fsm_change_state(fi, ST_SLOT_WAIT_DCONN);
+
+ return retval;
+}
+
+static int
+slot_acceptd(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *ctrl = arg;
+ int retval;
+
+ retval = __slot_command(slot, ctrl);
+ if (retval >= 0)
+ fsm_change_state(fi, ST_SLOT_WAIT_DCONN);
+
+ return retval;
+}
+
+static int
+slot_acceptb(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *ctrl = arg;
+ int retval;
+
+ retval = __slot_command(slot, ctrl);
+ if (retval >= 0)
+ fsm_change_state(fi, ST_SLOT_WAIT_BCONN);
+
+ return retval;
+}
+
+static int
+slot_actv_hangup(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *ctrl = arg;
+ int retval;
+
+ retval = __slot_command(slot, ctrl);
+ if (retval >= 0) {
+ fsm_change_state(fi, ST_SLOT_WAIT_BHUP);
}
+ return retval;
}
-void
-isdn_MOD_INC_USE_COUNT(void)
+static int
+slot_dconn(struct fsm_inst *fi, int pr, void *arg)
{
- MOD_INC_USE_COUNT;
- isdn_lock_drivers();
+ struct isdn_slot *slot = fi->userdata;
+
+ fsm_change_state(fi, ST_SLOT_DCONN);
+ do_event_cb(slot, pr, arg);
+ return 0;
}
-void
-isdn_unlock_drivers(void)
+static int
+slot_bconn(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+
+ fsm_change_state(fi, ST_SLOT_ACTIVE);
+ __isdn_v110_open(slot);
+
+ isdn_info_update();
+
+ do_event_cb(slot, pr, arg);
+ return 0;
+}
+
+static int
+slot_bhup(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+
+ __isdn_v110_close(slot);
+ fsm_change_state(fi, ST_SLOT_WAIT_DHUP);
+
+ do_event_cb(slot, pr, arg);
+ return 0;
+}
+
+static int
+slot_dhup(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+
+ fsm_change_state(fi, ST_SLOT_BOUND);
+
+ do_event_cb(slot, pr, arg);
+ return 0;
+}
+
+static int
+slot_data_req(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ return isdn_v110_data_req(slot, skb);
+}
+
+static int
+slot_data_ind(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ struct sk_buff *skb = arg;
+
+ /* Update statistics */
+ slot->ibytes += skb->len;
+
+ return isdn_v110_data_ind(slot, skb);
+}
+
+static int
+slot_bsent(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *ctrl = arg;
+
+ __isdn_v110_bsent(slot, pr, ctrl);
+ return 0;
+}
+
+static int
+slot_icall(struct fsm_inst *fi, int pr, void *arg)
{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl *ctrl = arg;
+ int retval;
+
+ isdn_lock_driver(slot->drv);
+ fsm_change_state(fi, ST_SLOT_IN);
+ slot_debug(fi, "ICALL: %s\n", ctrl->parm.num);
+ if (dev->global_flags & ISDN_GLOBAL_STOPPED)
+ return 0;
+
+ strcpy(slot->num, ctrl->parm.setup.phone);
+ /* Try to find a network-interface which will accept incoming call */
+ retval = isdn_net_find_icall(slot, &ctrl->parm.setup);
+
+ /* already taken by net now? */
+ if (fi->state != ST_SLOT_IN)
+ goto out;
+
+ retval = isdn_tty_find_icall(slot, &ctrl->parm.setup);
+ out:
+ return 0;
+}
+
+/* should become broadcast later */
+static int
+slot_in_dhup(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+
+ isdn_unlock_driver(slot->drv);
+ fsm_change_state(fi, ST_SLOT_NULL);
+ do_event_cb(slot, pr, arg);
+ return 0;
+}
+
+static int
+slot_unbind(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_slot *slot = fi->userdata;
+ isdn_ctrl cmd;
+
+ isdn_unlock_driver(slot->drv);
+ fsm_change_state(fi, ST_SLOT_NULL);
+ strcpy(slot->num, "???");
+ cmd.parm.num[0] = '\0';
+ isdn_slot_command(slot, ISDN_CMD_SETEAZ, &cmd);
+ slot->ibytes = 0;
+ slot->obytes = 0;
+ slot->usage = ISDN_USAGE_NONE;
+ isdn_info_update();
+ return 0;
+}
+
+static struct fsm_node slot_fn_tbl[] = {
+ { ST_SLOT_NULL, EV_SLOT_BIND, slot_bind },
+ { ST_SLOT_NULL, EV_STAT_ICALL, slot_icall },
+
+ { ST_SLOT_BOUND, EV_CMD_CLREAZ, slot_command },
+ { ST_SLOT_BOUND, EV_CMD_SETEAZ, slot_command },
+ { ST_SLOT_BOUND, EV_CMD_SETL2, slot_setl2 },
+ { ST_SLOT_BOUND, EV_CMD_SETL3, slot_command },
+ { ST_SLOT_BOUND, EV_CMD_DIAL, slot_dial },
+ { ST_SLOT_BOUND, EV_SLOT_UNBIND, slot_unbind },
+
+ { ST_SLOT_IN, EV_CMD_SETL2, slot_setl2 },
+ { ST_SLOT_IN, EV_CMD_SETL3, slot_command },
+ { ST_SLOT_IN, EV_CMD_ACCEPTD, slot_acceptd },
+ { ST_SLOT_IN, EV_STAT_DHUP, slot_in_dhup },
+
+ { ST_SLOT_WAIT_DCONN, EV_STAT_DCONN, slot_dconn },
+ { ST_SLOT_WAIT_DCONN, EV_STAT_DHUP, slot_dhup },
+
+ { ST_SLOT_DCONN, EV_CMD_ACCEPTB, slot_acceptb },
+ { ST_SLOT_DCONN, EV_STAT_BCONN, slot_bconn },
+
+ { ST_SLOT_WAIT_BCONN, EV_STAT_BCONN, slot_bconn },
+
+ { ST_SLOT_ACTIVE, EV_DATA_REQ, slot_data_req },
+ { ST_SLOT_ACTIVE, EV_DATA_IND, slot_data_ind },
+ { ST_SLOT_ACTIVE, EV_CMD_HANGUP, slot_actv_hangup },
+ { ST_SLOT_ACTIVE, EV_STAT_BSENT, slot_bsent },
+ { ST_SLOT_ACTIVE, EV_STAT_BHUP, slot_bhup },
+ { ST_SLOT_ACTIVE, EV_STAT_FAXIND, slot_stat },
+ { ST_SLOT_ACTIVE, EV_STAT_AUDIO, slot_stat },
+
+ { ST_SLOT_WAIT_BHUP, EV_STAT_BHUP, slot_bhup },
+
+ { ST_SLOT_WAIT_DHUP, EV_STAT_DHUP, slot_dhup },
+};
+
+static struct fsm slot_fsm = {
+ .st_cnt = ARRAY_SIZE(slot_st_str),
+ .st_str = slot_st_str,
+ .ev_cnt = ARRAY_SIZE(ev_str),
+ .ev_str = ev_str,
+ .fn_cnt = ARRAY_SIZE(slot_fn_tbl),
+ .fn_tbl = slot_fn_tbl,
+};
+
+static void slot_debug(struct fsm_inst *fi, char *fmt, ...)
+{
+ va_list args;
+ struct isdn_slot *slot = fi->userdata;
+ char buf[128];
+ char *p = buf;
+
+ va_start(args, fmt);
+ p += sprintf(p, "slot %d(%d:%d): ", slot-slots, slot->di, slot->ch);
+ p += vsprintf(p, fmt, args);
+ va_end(args);
+ printk(KERN_DEBUG "%s\n", buf);
+}
+
+/* ====================================================================== */
+
+static spinlock_t stat_lock = SPIN_LOCK_UNLOCKED;
+
+static struct fsm drv_fsm;
+
+enum {
+ ST_DRV_NULL,
+ ST_DRV_LOADED,
+ ST_DRV_RUNNING,
+};
+
+static char *drv_st_str[] = {
+ "ST_DRV_NULL",
+ "ST_DRV_LOADED",
+ "ST_DRV_RUNNING",
+};
+
+#define DRV_FLAG_REJBUS 1
+
+/* Description of hardware-level-driver */
+struct isdn_driver {
+ int di;
+ char id[20];
+ atomic_t refcnt;
+ unsigned long flags; /* Misc driver Flags */
+ unsigned long features;
+ int locks; /* Number of locks */
+ int channels; /* Number of channels */
+ wait_queue_head_t st_waitq; /* Wait-Queue for status-reads */
+ int maxbufsize; /* Maximum Buffersize supported*/
+ int stavail; /* Chars avail on Status-device*/
+ isdn_if *interface; /* Interface to driver */
+ char msn2eaz[10][ISDN_MSNLEN]; /* MSN->EAZ */
+ struct fsm_inst fi;
+} driver;
+
+static int __drv_command(struct isdn_driver *drv, isdn_ctrl *cmd);
+
+static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
+static struct isdn_driver *drivers[ISDN_MAX_DRIVERS];
+
+static int
+isdn_writebuf_skb(struct isdn_slot *slot, struct sk_buff *skb)
+{
+ struct sk_buff *skb2;
+ struct isdn_driver *drv = slot->drv;
+ int hl = drv->interface->hl_hdrlen;
+ int retval;
+
+ if (skb_headroom(skb) >= hl) {
+ retval = drv->interface->writebuf_skb(slot->di, slot->ch, 1, skb);
+ goto out;
+ }
+ skb2 = skb_realloc_headroom(skb, hl);
+ if (!skb2) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ retval = drv->interface->writebuf_skb(slot->di, slot->ch, 1, skb2);
+ if (retval < 0)
+ kfree_skb(skb2);
+ else
+ kfree_skb(skb);
+
+ out:
+ if (retval > 0)
+ slots->obytes += retval;
+
+ return retval;
+}
+
+int
+__isdn_drv_lookup(char *drvid)
+{
+ int drvidx;
+
+ for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+ if (!drivers[drvidx])
+ continue;
+
+ if (strcmp(drivers[drvidx]->id, drvid) == 0)
+ return drvidx;
+ }
+ return -1;
+}
+
+int
+isdn_drv_lookup(char *drvid)
+{
+ unsigned long flags;
+ int drvidx;
+
+ spin_lock_irqsave(&drivers_lock, flags);
+ drvidx = __isdn_drv_lookup(drvid);
+ spin_unlock_irqrestore(&drivers_lock, flags);
+ return drvidx;
+}
+
+static void
+drv_destroy(struct isdn_driver *drv)
+{
+ kfree(drv);
+}
+
+static inline struct isdn_driver *
+get_drv(struct isdn_driver *drv)
+{
+ printk("get_drv %d: %d -> %d\n", drv->di, atomic_read(&drv->refcnt),
+ atomic_read(&drv->refcnt) + 1);
+ atomic_inc(&drv->refcnt);
+ return drv;
+}
+
+static inline void
+put_drv(struct isdn_driver *drv)
+{
+ printk("put_drv %d: %d -> %d\n", drv->di, atomic_read(&drv->refcnt),
+ atomic_read(&drv->refcnt) - 1);
+ if (atomic_dec_and_test(&drv->refcnt)) {
+ drv_destroy(drv);
+ }
+}
+
+static struct isdn_driver *
+get_drv_by_nr(int di)
+{
+ unsigned long flags;
+ struct isdn_driver *drv;
+
+ if (di < 0)
+ return NULL;
+
+ spin_lock_irqsave(&drivers_lock, flags);
+ drv = drivers[di];
+ if (drv)
+ get_drv(drv);
+ spin_unlock_irqrestore(&drivers_lock, flags);
+ return drv;
+}
+
+char *
+isdn_drv_drvid(int di)
+{
+ if (!drivers[di]) {
+ isdn_BUG();
+ return "";
+ }
+ return drivers[di]->id;
+}
+
+/*
+ * Helper keeping track of the features the drivers support
+ */
+static void
+set_global_features(void)
+{
+ unsigned long flags;
+ int drvidx;
+
+ dev->global_features = 0;
+ spin_lock_irqsave(&drivers_lock, flags);
+ for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
+ if (!drivers[drvidx])
+ continue;
+ if (drivers[drvidx]->fi.state != ST_DRV_RUNNING)
+ continue;
+ dev->global_features |= drivers[drvidx]->features;
+ }
+ spin_unlock_irqrestore(&drivers_lock, flags);
+}
+
+/*
+ * driver state machine
+ */
+static int isdn_add_channels(struct isdn_driver *, int, int, int);
+static void isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb);
+static int isdn_status_callback(isdn_ctrl * c);
+static int isdn_dc2minor(int di, int ch);
+
+static void isdn_v110_add_features(struct isdn_driver *drv);
+
+static int
+drv_register(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_driver *drv = fi->userdata;
+ isdn_if *iif = arg;
+
+ fsm_change_state(fi, ST_DRV_LOADED);
+ drv->maxbufsize = iif->maxbufsize;
+ drv->interface = iif;
+ iif->channels = drv->di;
+ iif->rcvcallb_skb = isdn_receive_skb_callback;
+ iif->statcallb = isdn_status_callback;
+
+ isdn_info_update();
+}
+
+static int
+drv_stat_run(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_driver *drv = fi->userdata;
+ fsm_change_state(fi, ST_DRV_RUNNING);
+
+ drv->features = drv->interface->features;
+ isdn_v110_add_features(drv);
+ set_global_features();
+}
+
+static int
+drv_stat_stop(struct fsm_inst *fi, int pr, void *arg)
+{
+ fsm_change_state(fi, ST_DRV_LOADED);
+ set_global_features();
+}
+
+static int
+drv_stat_unload(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_driver *drv = fi->userdata;
+ unsigned long flags;
int i;
- for (i = 0; i < dev->drivers; i++)
- if (dev->drv[i]->locks > 0) {
- isdn_ctrl cmd;
+ spin_lock_irqsave(&drivers_lock, flags);
+ drivers[drv->di] = NULL;
+ spin_unlock_irqrestore(&drivers_lock, flags);
+ put_drv(drv);
- cmd.driver = i;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_UNLOCK;
- isdn_command(&cmd);
- dev->drv[i]->locks--;
+ while (drv->locks > 0) {
+ isdn_ctrl cmd;
+ cmd.driver = drv->di;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_UNLOCK;
+ __drv_command(drv, &cmd);
+ drv->locks--;
+ }
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ if (slots[i].di == drv->di) {
+ slots[i].di = -1;
+ slots[i].drv = NULL;
+ slots[i].ch = -1;
+ slots[i].usage &= ~ISDN_USAGE_DISABLED;
+ isdn_unregister_devfs(i);
}
+ }
+ dev->channels -= drv->channels;
+
+ isdn_info_update();
+ return 0;
}
-void
-isdn_MOD_DEC_USE_COUNT(void)
+static int
+drv_stat_addch(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_driver *drv = fi->userdata;
+ isdn_ctrl *c = arg;
+
+ isdn_add_channels(drv, c->driver, c->arg, 1);
+ isdn_info_update();
+}
+
+static int
+drv_stat_stavail(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_driver *drv = fi->userdata;
+ unsigned long flags;
+ isdn_ctrl *c = arg;
+
+ spin_lock_irqsave(&stat_lock, flags);
+ drv->stavail += c->arg;
+ spin_unlock_irqrestore(&stat_lock, flags);
+ wake_up_interruptible(&drv->st_waitq);
+}
+
+static int
+drv_to_slot(struct fsm_inst *fi, int pr, void *arg)
+{
+ struct isdn_driver *drv = fi->userdata;
+ isdn_ctrl *c = arg;
+ int sl = isdn_dc2minor(drv->di, c->arg & 0xff);
+
+ if (sl < 0) {
+ isdn_BUG();
+ return 1;
+ }
+ return fsm_event(&slots[sl].fi, pr, arg);
+}
+
+static struct fsm_node drv_fn_tbl[] = {
+ { ST_DRV_NULL, EV_DRV_REGISTER, drv_register },
+
+ { ST_DRV_LOADED, EV_STAT_RUN, drv_stat_run },
+ { ST_DRV_LOADED, EV_STAT_STAVAIL, drv_stat_stavail },
+ { ST_DRV_LOADED, EV_STAT_ADDCH, drv_stat_addch },
+ { ST_DRV_LOADED, EV_STAT_UNLOAD, drv_stat_unload },
+
+ { ST_DRV_RUNNING, EV_STAT_STOP, drv_stat_stop },
+ { ST_DRV_RUNNING, EV_STAT_STAVAIL, drv_stat_stavail },
+ { ST_DRV_RUNNING, EV_STAT_ICALL, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_DCONN, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_BCONN, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_BHUP, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_DHUP, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_BSENT, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_CINF, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_CAUSE, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_DISPLAY, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_FAXIND, drv_to_slot },
+ { ST_DRV_RUNNING, EV_STAT_AUDIO, drv_to_slot },
+};
+
+static struct fsm drv_fsm = {
+ .st_cnt = ARRAY_SIZE(drv_st_str),
+ .st_str = drv_st_str,
+ .ev_cnt = ARRAY_SIZE(ev_str),
+ .ev_str = ev_str,
+ .fn_cnt = ARRAY_SIZE(drv_fn_tbl),
+ .fn_tbl = drv_fn_tbl,
+};
+
+static void drv_debug(struct fsm_inst *fi, char *fmt, ...)
+{
+ va_list args;
+ struct isdn_driver *drv = fi->userdata;
+ char buf[128];
+ char *p = buf;
+
+ va_start(args, fmt);
+ p += sprintf(p, "%s: ", drv->id);
+ p += vsprintf(p, fmt, args);
+ va_end(args);
+ printk(KERN_DEBUG "%s\n", buf);
+}
+
+/* ====================================================================== */
+/* callbacks from hardware driver */
+/* ====================================================================== */
+
+/* Receive a packet from B-Channel. */
+static void
+isdn_receive_skb_callback(int di, int ch, struct sk_buff *skb)
{
- MOD_DEC_USE_COUNT;
- isdn_unlock_drivers();
+ struct isdn_driver *drv;
+ int sl;
+
+ drv = get_drv_by_nr(di);
+ if (!drv) {
+ /* hardware driver is buggy - driver isn't registered */
+ isdn_BUG();
+ goto out;
+ }
+ /* we short-cut here instead of going through the driver fsm */
+ if (drv->fi.state != ST_DRV_RUNNING) {
+ /* hardware driver is buggy - driver isn't running */
+ isdn_BUG();
+ goto out;
+ }
+ sl = isdn_dc2minor(di, ch);
+ if (sl < 0) {
+ isdn_BUG();
+ goto out;
+ }
+ if (fsm_event(&slots[sl].fi, EV_DATA_IND, skb))
+ dev_kfree_skb(skb);
+ out:
+ put_drv(drv);
+}
+
+/* Receive status indications */
+static int
+isdn_status_callback(isdn_ctrl *c)
+{
+ struct isdn_driver *drv;
+ int rc;
+
+ drv = get_drv_by_nr(c->driver);
+ if (!drv) {
+ /* hardware driver is buggy - driver isn't registered */
+ isdn_BUG();
+ return 1;
+ }
+
+ switch (c->command) {
+ case ISDN_STAT_STAVAIL:
+ rc = fsm_event(&drv->fi, EV_STAT_STAVAIL, c);
+ break;
+ case ISDN_STAT_RUN:
+ rc = fsm_event(&drv->fi, EV_STAT_RUN, c);
+ break;
+ case ISDN_STAT_STOP:
+ rc = fsm_event(&drv->fi, EV_STAT_STOP, c);
+ break;
+ case ISDN_STAT_UNLOAD:
+ rc = fsm_event(&drv->fi, EV_STAT_UNLOAD, c);
+ break;
+ case ISDN_STAT_ADDCH:
+ rc = fsm_event(&drv->fi, EV_STAT_ADDCH, c);
+ break;
+ case ISDN_STAT_ICALL:
+ rc = fsm_event(&drv->fi, EV_STAT_ICALL, c);
+ break;
+ case ISDN_STAT_DCONN:
+ rc = fsm_event(&drv->fi, EV_STAT_DCONN, c);
+ break;
+ case ISDN_STAT_BCONN:
+ rc = fsm_event(&drv->fi, EV_STAT_BCONN, c);
+ break;
+ case ISDN_STAT_BHUP:
+ rc = fsm_event(&drv->fi, EV_STAT_BHUP, c);
+ break;
+ case ISDN_STAT_DHUP:
+ rc = fsm_event(&drv->fi, EV_STAT_DHUP, c);
+ break;
+ case ISDN_STAT_BSENT:
+ rc = fsm_event(&drv->fi, EV_STAT_BSENT, c);
+ break;
+ case ISDN_STAT_CINF:
+ rc = fsm_event(&drv->fi, EV_STAT_CINF, c);
+ break;
+ case ISDN_STAT_CAUSE:
+ rc = fsm_event(&drv->fi, EV_STAT_CAUSE, c);
+ break;
+ case ISDN_STAT_DISPLAY:
+ rc = fsm_event(&drv->fi, EV_STAT_DISPLAY, c);
+ break;
+ case ISDN_STAT_FAXIND:
+ rc = fsm_event(&drv->fi, EV_STAT_FAXIND, c);
+ break;
+ case ISDN_STAT_AUDIO:
+ rc = fsm_event(&drv->fi, EV_STAT_AUDIO, c);
+ break;
+#if 0
+ case ISDN_STAT_ICALL:
+ /* Find any ttyI, waiting for D-channel setup */
+ if (isdn_tty_stat_callback(i, c)) {
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_ACCEPTB;
+ isdn_command(&cmd);
+ break;
+ }
+ break;
+ switch (r) {
+ case 0:
+ if (divert_if)
+ if ((retval = divert_if->stat_callback(c)))
+ return(retval); /* processed */
+ if ((!retval) && (drivers[di]->flags & DRV_FLAG_REJBUS)) {
+ /* No tty responding */
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ isdn_command(&cmd);
+ retval = 2;
+ }
+ break;
+ case 1: /* incoming call accepted by net interface */
+
+ case 2: /* For calling back, first reject incoming call ... */
+ case 3: /* Interface found, but down, reject call actively */
+ retval = 2;
+ printk(KERN_INFO "isdn: Rejecting Call\n");
+ cmd.driver = di;
+ cmd.arg = c->arg;
+ cmd.command = ISDN_CMD_HANGUP;
+ isdn_command(&cmd);
+ if (r == 3)
+ break;
+ /* Fall through */
+ case 4:
+ /* ... then start callback. */
+ break;
+ case 5:
+ /* Number would eventually match, if longer */
+ retval = 3;
+ break;
+ }
+ dbg_statcallb("ICALL: ret=%d\n", retval);
+ return retval;
+ break;
+ case ISDN_STAT_DHUP:
+ if (divert_if)
+ divert_if->stat_callback(c);
+ break;
+ case ISDN_STAT_BCONN:
+ break;
+ case ISDN_STAT_BHUP:
+ break;
+#endif
+#if 0 // FIXME
+ case ISDN_STAT_DISCH:
+ save_flags(flags);
+ cli();
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+ if ((slots[i].di == di) &&
+ (slots[i].ch == c->arg)) {
+ if (c->parm.num[0])
+ slots[i].usage &= ~ISDN_USAGE_DISABLED;
+ else if (USG_NONE(isdn_slot_usage(i)))
+ slots[i].usage |= ISDN_USAGE_DISABLED;
+ else
+ retval = -1;
+ break;
+ }
+ restore_flags(flags);
+ break;
+ case CAPI_PUT_MESSAGE:
+ return(isdn_capi_rec_hl_msg(&c->parm.cmsg));
+ case ISDN_STAT_PROT:
+ case ISDN_STAT_REDIR:
+ if (divert_if)
+ return(divert_if->stat_callback(c));
+#endif
+ default:
+ rc = 1;
+ }
+ put_drv(drv);
+ return rc;
+}
+
+/* ====================================================================== */
+
+/*
+ * Register a new ISDN interface
+ */
+int
+register_isdn(isdn_if *iif)
+{
+ struct isdn_driver *drv;
+ unsigned long flags;
+ int drvidx;
+
+ drv = kmalloc(sizeof(*drv), GFP_KERNEL);
+ if (!drv) {
+ printk(KERN_WARNING "register_isdn: out of mem\n");
+ goto fail;
+ }
+ memset(drv, 0, sizeof(*drv));
+
+ atomic_set(&drv->refcnt, 0);
+ drv->fi.fsm = &drv_fsm;
+ drv->fi.state = ST_DRV_NULL;
+ drv->fi.debug = 1;
+ drv->fi.userdata = drv;
+ drv->fi.printdebug = drv_debug;
+
+ spin_lock_irqsave(&drivers_lock, flags);
+ for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
+ if (!drivers[drvidx])
+ break;
+
+ if (drvidx == ISDN_MAX_DRIVERS)
+ goto fail_unlock;
+
+ if (!strlen(iif->id))
+ sprintf(iif->id, "line%d", drvidx);
+
+ if (__isdn_drv_lookup(iif->id) >= 0)
+ goto fail_unlock;
+
+ strcpy(drv->id, iif->id);
+ if (isdn_add_channels(drv, drvidx, iif->channels, 0))
+ goto fail_unlock;
+
+ drv->di = drvidx;
+ drivers[drvidx] = get_drv(drv);
+ spin_unlock_irqrestore(&drivers_lock, flags);
+
+ fsm_event(&drv->fi, EV_DRV_REGISTER, iif);
+ return 1;
+
+ fail_unlock:
+ spin_unlock_irqrestore(&drivers_lock, flags);
+ kfree(drv);
+ fail:
+ return 0;
+}
+
+/* ====================================================================== */
+
+#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
+static isdn_divert_if *divert_if; /* = NULL */
+#else
+#define divert_if ((isdn_divert_if *) NULL)
+#endif
+
+static int isdn_wildmat(char *s, char *p);
+
+static void
+isdn_lock_driver(struct isdn_driver *drv)
+{
+ isdn_ctrl cmd;
+
+ cmd.driver = drv->di;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_LOCK;
+ __drv_command(drv, &cmd);
+}
+
+static void
+isdn_unlock_driver(struct isdn_driver *drv)
+{
+ isdn_ctrl cmd;
+
+ cmd.driver = drv->di;
+ cmd.arg = 0;
+ cmd.command = ISDN_CMD_UNLOCK;
+ __drv_command(drv, &cmd);
}
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
@@ -235,177 +1120,54 @@ int isdn_msncmp( const char * msn1, const char * msn2 )
return isdn_wildmat( TmpMsn1, TmpMsn2 );
}
-int
+static int
isdn_dc2minor(int di, int ch)
{
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (slot[i].ch == ch && slot[i].di == di)
+ if (slots[i].ch == ch && slots[i].di == di)
return i;
return -1;
}
-static int isdn_timer_cnt2 = 0;
-static int isdn_timer_cnt3 = 0;
-
-static void
-isdn_timer_funct(ulong dummy)
-{
- int tf = dev->tflags;
- if (tf & ISDN_TIMER_FAST) {
- if (tf & ISDN_TIMER_MODEMREAD)
- isdn_tty_readmodem();
- if (tf & ISDN_TIMER_MODEMPLUS)
- isdn_tty_modem_escape();
- if (tf & ISDN_TIMER_MODEMXMIT)
- isdn_tty_modem_xmit();
- }
- if (tf & ISDN_TIMER_SLOW) {
- if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) {
- isdn_timer_cnt2 = 0;
- if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) {
- isdn_timer_cnt3 = 0;
- if (tf & ISDN_TIMER_MODEMRING)
- isdn_tty_modem_ring();
- }
- if (tf & ISDN_TIMER_CARRIER)
- isdn_tty_carrier_timeout();
- }
- }
- if (tf)
- {
- unsigned long flags;
-
- save_flags(flags);
- cli();
- mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
- restore_flags(flags);
- }
-}
-
-void
-isdn_timer_ctrl(int tf, int onoff)
-{
- unsigned long flags;
- int old_tflags;
-
- save_flags(flags);
- cli();
- if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
- /* If the slow-timer wasn't activated until now */
- isdn_timer_cnt2 = 0;
- }
- old_tflags = dev->tflags;
- if (onoff)
- dev->tflags |= tf;
- else
- dev->tflags &= ~tf;
- if (dev->tflags && !old_tflags)
- mod_timer(&dev->timer, jiffies+ISDN_TIMER_RES);
- restore_flags(flags);
-}
-
-/*
- * Receive a packet from B-Channel. (Called from low-level-module)
- */
-static void
-isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb)
-{
- int i;
-
- if ((i = isdn_dc2minor(di, channel)) == -1) {
- dev_kfree_skb(skb);
- return;
- }
- /* Update statistics */
- slot[i].ibytes += skb->len;
-
- /* First, try to deliver data to network-device */
- if (isdn_net_rcv_skb(i, skb))
- return;
-
- /* V.110 handling
- * makes sense for async streams only, so it is
- * called after possible net-device delivery.
- */
- if (slot[i].iv110.v110) {
- atomic_inc(&slot[i].iv110.v110use);
- skb = isdn_v110_decode(slot[i].iv110.v110, skb);
- atomic_dec(&slot[i].iv110.v110use);
- if (!skb)
- return;
- }
-
- /* No network-device found, deliver to tty or raw-channel */
- if (skb->len) {
- if (isdn_tty_rcv_skb(i, di, channel, skb))
- return;
- wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]);
- } else
- dev_kfree_skb(skb);
-}
-
-/*
- * Intercept command from Linklevel to Lowlevel.
- * If layer 2 protocol is V.110 and this is not supported by current
- * lowlevel-driver, use driver's transparent mode and handle V.110 in
- * linklevel instead.
- */
static int
-isdn_command(isdn_ctrl *cmd)
+__drv_command(struct isdn_driver *drv, isdn_ctrl *c)
{
- int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
-
- if (cmd->driver == -1) {
- printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
- return(1);
- }
- if (cmd->command == ISDN_CMD_SETL2) {
- unsigned long l2prot = (cmd->arg >> 8) & 255;
- unsigned long features = (dev->drv[cmd->driver]->interface->features
- >> ISDN_FEATURE_L2_SHIFT) &
- ISDN_FEATURE_L2_MASK;
- unsigned long l2_feature = (1 << l2prot);
-
- switch (l2prot) {
- case ISDN_PROTO_L2_V11096:
- case ISDN_PROTO_L2_V11019:
- case ISDN_PROTO_L2_V11038:
- /* If V.110 requested, but not supported by
- * HL-driver, set emulator-flag and change
- * Layer-2 to transparent
- */
- if (!(features & l2_feature)) {
- slot[idx].iv110.v110emu = l2prot;
- cmd->arg = (cmd->arg & 255) |
- (ISDN_PROTO_L2_TRANS << 8);
- } else
- slot[idx].iv110.v110emu = 0;
- }
- }
#ifdef ISDN_DEBUG_COMMAND
- switch (cmd->command) {
+ switch (c->command) {
+ case ISDN_CMD_LOCK:
+ printk(KERN_DEBUG "ISDN_CMD_LOCK %d/%ld\n", c->driver, c->arg & 0xff); break;
+ case ISDN_CMD_UNLOCK:
+ printk(KERN_DEBUG "ISDN_CMD_UNLOCK %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_SETL2:
- printk(KERN_DEBUG "ISDN_CMD_SETL2 %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_SETL2 %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_SETL3:
- printk(KERN_DEBUG "ISDN_CMD_SETL3 %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_SETL3 %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_DIAL:
- printk(KERN_DEBUG "ISDN_CMD_DIAL %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_DIAL %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_ACCEPTD:
- printk(KERN_DEBUG "ISDN_CMD_ACCEPTD %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_ACCEPTD %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_ACCEPTB:
- printk(KERN_DEBUG "ISDN_CMD_ACCEPTB %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_ACCEPTB %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_HANGUP:
- printk(KERN_DEBUG "ISDN_CMD_HANGUP %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_HANGUP %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_CLREAZ:
- printk(KERN_DEBUG "ISDN_CMD_CLREAZ %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_CLREAZ %d/%ld\n", c->driver, c->arg & 0xff); break;
case ISDN_CMD_SETEAZ:
- printk(KERN_DEBUG "ISDN_CMD_SETEAZ %d\n", idx); break;
+ printk(KERN_DEBUG "ISDN_CMD_SETEAZ %d/%ld\n", c->driver, c->arg & 0xff); break;
default:
- printk(KERN_DEBUG "%s: cmd = %d\n", __FUNCTION__, cmd->command);
+ printk(KERN_DEBUG "%s: cmd = %d\n", __FUNCTION__, c->command);
}
#endif
- return dev->drv[cmd->driver]->interface->command(cmd);
+ return drv->interface->command(c);
+}
+
+static int
+__slot_command(struct isdn_slot *slot, isdn_ctrl *cmd)
+{
+ struct isdn_driver *drv = slot->drv;
+
+ return __drv_command(drv, cmd);
}
/*
@@ -431,283 +1193,6 @@ isdn_capi_rec_hl_msg(capi_msg *cm) {
}
}
-static int
-isdn_status_callback(isdn_ctrl * c)
-{
- int di;
- ulong flags;
- int i;
- int r;
- int retval = 0;
- isdn_ctrl cmd;
- struct list_head *l;
-
- di = c->driver;
- i = isdn_dc2minor(di, c->arg);
- switch (c->command) {
- case ISDN_STAT_BSENT:
- if (i < 0)
- return -1;
- if (isdn_net_stat_callback(i, c))
- return 0;
- if (isdn_v110_stat_callback(&slot[i].iv110, c))
- return 0;
- if (isdn_tty_stat_callback(i, c))
- return 0;
- wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]);
- break;
- case ISDN_STAT_STAVAIL:
- save_flags(flags);
- cli();
- dev->drv[di]->stavail += c->arg;
- restore_flags(flags);
- wake_up_interruptible(&dev->drv[di]->st_waitq);
- break;
- case ISDN_STAT_RUN:
- dev->drv[di]->flags |= DRV_FLAG_RUNNING;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (slot[i].di == di)
- isdn_slot_all_eaz(i);
- set_global_features();
- break;
- case ISDN_STAT_STOP:
- dev->drv[di]->flags &= ~DRV_FLAG_RUNNING;
- break;
- case ISDN_STAT_ICALL:
- if (i < 0)
- return -1;
- dbg_statcallb("ICALL: %d (%d,%ld) %s\n", i, di, c->arg, c->parm.num);
- if (dev->global_flags & ISDN_GLOBAL_STOPPED)
- return 0;
-
- /* Try to find a network-interface which will accept incoming call */
- r = isdn_net_find_icall(di, c->arg, i, &c->parm.setup);
- switch (r) {
- case 0:
- /* No network-device replies.
- * Try ttyI's.
- * These return 0 on no match, 1 on match and
- * 3 on eventually match, if CID is longer.
- */
- if (c->command == ISDN_STAT_ICALL)
- if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return(retval);
- if (divert_if)
- if ((retval = divert_if->stat_callback(c)))
- return(retval); /* processed */
- if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) {
- /* No tty responding */
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- retval = 2;
- }
- break;
- case 1: /* incoming call accepted by net interface */
- list_for_each(l, &isdn_net_devs) {
- isdn_net_dev *p = list_entry(l, isdn_net_dev, global_list);
- if (p->isdn_slot == i) {
- strcpy(cmd.parm.setup.eazmsn, p->mlp->msn);
- isdn_slot_set_usage(i, (isdn_slot_usage(i) & ISDN_USAGE_EXCLUSIVE) | ISDN_USAGE_NET);
- strcpy(isdn_slot_num(i), c->parm.setup.phone);
-
- isdn_slot_command(i, ISDN_CMD_ACCEPTD, &cmd);
- retval = 1;
- break;
- }
- }
- break;
-
- case 2: /* For calling back, first reject incoming call ... */
- case 3: /* Interface found, but down, reject call actively */
- retval = 2;
- printk(KERN_INFO "isdn: Rejecting Call\n");
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_HANGUP;
- isdn_command(&cmd);
- if (r == 3)
- break;
- /* Fall through */
- case 4:
- /* ... then start callback. */
- break;
- case 5:
- /* Number would eventually match, if longer */
- retval = 3;
- break;
- }
- dbg_statcallb("ICALL: ret=%d\n", retval);
- return retval;
- break;
- case ISDN_STAT_CINF:
- if (i < 0)
- return -1;
- dbg_statcallb("CINF: %d %s\n", i, c->parm.num);
- if (strcmp(c->parm.num, "0"))
- isdn_net_stat_callback(i, c);
- isdn_tty_stat_callback(i, c);
- break;
- case ISDN_STAT_CAUSE:
- dbg_statcallb("CAUSE: %d %s\n", i, c->parm.num);
- printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n",
- dev->drvid[di], c->arg, c->parm.num);
- isdn_tty_stat_callback(i, c);
- if (divert_if)
- divert_if->stat_callback(c);
- break;
- case ISDN_STAT_DISPLAY:
- dbg_statcallb("DISPLAY: %d %s\n", i, c->parm.display);
- isdn_tty_stat_callback(i, c);
- if (divert_if)
- divert_if->stat_callback(c);
- break;
- case ISDN_STAT_DCONN:
- if (i < 0)
- return -1;
- dbg_statcallb("DCONN: %d\n", i);
- /* Find any net-device, waiting for D-channel setup */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(&slot[i].iv110, c);
- /* Find any ttyI, waiting for D-channel setup */
- if (isdn_tty_stat_callback(i, c)) {
- cmd.driver = di;
- cmd.arg = c->arg;
- cmd.command = ISDN_CMD_ACCEPTB;
- isdn_command(&cmd);
- break;
- }
- break;
- case ISDN_STAT_DHUP:
- if (i < 0)
- return -1;
- dbg_statcallb("DHUP: %d\n", i);
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(&slot[i].iv110, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- if (divert_if)
- divert_if->stat_callback(c);
- break;
- case ISDN_STAT_BCONN:
- if (i < 0)
- return -1;
- dbg_statcallb("BCONN: %ld\n", c->arg);
- /* Signal B-channel-connect to network-devices */
- dev->drv[di]->online |= (1 << (c->arg));
- isdn_info_update();
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(&slot[i].iv110, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_BHUP:
- if (i < 0)
- return -1;
- dbg_statcallb("BHUP: %d\n", i);
- dev->drv[di]->online &= ~(1 << (c->arg));
- isdn_info_update();
- /* Signal hangup to network-devices */
- if (isdn_net_stat_callback(i, c))
- break;
- isdn_v110_stat_callback(&slot[i].iv110, c);
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_NODCH:
- if (i < 0)
- return -1;
- dbg_statcallb("NODCH: %ld\n", c->arg);
- if (isdn_net_stat_callback(i, c))
- break;
- if (isdn_tty_stat_callback(i, c))
- break;
- break;
- case ISDN_STAT_ADDCH:
- if (isdn_add_channels(dev->drv[di], di, c->arg, 1))
- return -1;
- isdn_info_update();
- break;
- case ISDN_STAT_DISCH:
- save_flags(flags);
- cli();
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if ((slot[i].di == di) &&
- (slot[i].ch == c->arg)) {
- if (c->parm.num[0])
- isdn_slot_set_usage(i, isdn_slot_usage(i) & ~ISDN_USAGE_DISABLED);
- else if (USG_NONE(isdn_slot_usage(i)))
- isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_DISABLED);
- else
- retval = -1;
- break;
- }
- restore_flags(flags);
- break;
- case ISDN_STAT_UNLOAD:
- while (dev->drv[di]->locks > 0) {
- isdn_ctrl cmd;
- cmd.driver = di;
- cmd.arg = 0;
- cmd.command = ISDN_CMD_UNLOCK;
- isdn_command(&cmd);
- dev->drv[di]->locks--;
- }
- save_flags(flags);
- cli();
- isdn_tty_stat_callback(i, c);
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (slot[i].di == di) {
- slot[i].di = -1;
- slot[i].ch = -1;
- slot[i].usage &= ~ISDN_USAGE_DISABLED;
- isdn_unregister_devfs(i);
- }
- dev->drivers--;
- dev->channels -= dev->drv[di]->channels;
- kfree(dev->drv[di]->rcverr);
- kfree(dev->drv[di]->rcvcount);
- for (i = 0; i < dev->drv[di]->channels; i++)
- skb_queue_purge(&dev->drv[di]->rpqueue[i]);
- kfree(dev->drv[di]->rpqueue);
- kfree(dev->drv[di]->rcv_waitq);
- kfree(dev->drv[di]);
- dev->drv[di] = NULL;
- dev->drvid[di][0] = '\0';
- isdn_info_update();
- set_global_features();
- restore_flags(flags);
- return 0;
- case ISDN_STAT_L1ERR:
- break;
- case CAPI_PUT_MESSAGE:
- return(isdn_capi_rec_hl_msg(&c->parm.cmsg));
-#ifdef CONFIG_ISDN_TTY_FAX
- case ISDN_STAT_FAXIND:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
-#ifdef CONFIG_ISDN_AUDIO
- case ISDN_STAT_AUDIO:
- isdn_tty_stat_callback(i, c);
- break;
-#endif
- case ISDN_STAT_PROT:
- case ISDN_STAT_REDIR:
- if (divert_if)
- return(divert_if->stat_callback(c));
- default:
- return -1;
- }
- return 0;
-}
-
/*
* Get integer from char-pointer, set pointer to end of number
*/
@@ -721,120 +1206,16 @@ isdn_getnum(char **p)
return v;
}
-#define DLE 0x10
-
-/*
- * isdn_slot_readbchan() tries to get data from the read-queue.
- * It MUST be called with interrupts off.
- */
-int
-isdn_slot_readbchan(int sl, u_char * buf, u_char * fp, int len)
-{
- int count;
- int count_pull;
- int count_put;
- int dflag;
- int di = isdn_slot_driver(sl);
- int ch = isdn_slot_channel(sl);
- struct sk_buff *skb;
- u_char *cp;
-
- if (!dev->drv[di])
- return 0;
- if (skb_queue_empty(&dev->drv[di]->rpqueue[ch]))
- return 0;
-
- if (len > dev->drv[di]->rcvcount[ch])
- len = dev->drv[di]->rcvcount[ch];
- cp = buf;
- count = 0;
- while (len) {
- if (!(skb = skb_peek(&dev->drv[di]->rpqueue[ch])))
- break;
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_LOCK(skb))
- break;
- ISDN_AUDIO_SKB_LOCK(skb) = 1;
- if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << ch))) {
- char *p = skb->data;
- unsigned long DLEmask = (1 << ch);
-
- dflag = 0;
- count_pull = count_put = 0;
- while ((count_pull < skb->len) && (len > 0)) {
- len--;
- if (dev->drv[di]->DLEflag & DLEmask) {
- *cp++ = DLE;
- dev->drv[di]->DLEflag &= ~DLEmask;
- } else {
- *cp++ = *p;
- if (*p == DLE) {
- dev->drv[di]->DLEflag |= DLEmask;
- (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
- }
- p++;
- count_pull++;
- }
- count_put++;
- }
- if (count_pull >= skb->len)
- dflag = 1;
- } else {
-#endif
- /* No DLE's in buff, so simply copy it */
- dflag = 1;
- if ((count_pull = skb->len) > len) {
- count_pull = len;
- dflag = 0;
- }
- count_put = count_pull;
- memcpy(cp, skb->data, count_put);
- cp += count_put;
- len -= count_put;
-#ifdef CONFIG_ISDN_AUDIO
- }
-#endif
- count += count_put;
- if (fp) {
- memset(fp, 0, count_put);
- fp += count_put;
- }
- if (dflag) {
- /* We got all the data in this buff.
- * Now we can dequeue it.
- */
- if (fp)
- *(fp - 1) = 0xff;
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- skb = skb_dequeue(&dev->drv[di]->rpqueue[ch]);
- dev_kfree_skb(skb);
- } else {
- /* Not yet emptied this buff, so it
- * must stay in the queue, for further calls
- * but we pull off the data we got until now.
- */
- skb_pull(skb, count_pull);
-#ifdef CONFIG_ISDN_AUDIO
- ISDN_AUDIO_SKB_LOCK(skb) = 0;
-#endif
- }
- dev->drv[di]->rcvcount[ch] -= count_put;
- }
- return count;
-}
-
static __inline int
isdn_minor2drv(int minor)
{
- return slot[minor].di;
+ return slots[minor].di;
}
static __inline int
isdn_minor2chan(int minor)
{
- return slot[minor].ch;
+ return slots[minor].ch;
}
static char *
@@ -847,32 +1228,32 @@ isdn_statstr(void)
sprintf(istatbuf, "idmap:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", (slot[i].di < 0) ? "-" : dev->drvid[slot[i].di]);
+ sprintf(p, "%s ", (slots[i].di < 0) ? "-" : isdn_drv_drvid(slots[i].di));
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\nchmap:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", slot[i].ch);
+ sprintf(p, "%d ", slots[i].ch);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\ndrmap:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", slot[i].di);
+ sprintf(p, "%d ", slots[i].di);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\nusage:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%d ", slot[i].usage);
+ sprintf(p, "%d ", slots[i].usage);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\nflags:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- if (dev->drv[i]) {
- sprintf(p, "%ld ", dev->drv[i]->online);
+ if (drivers[i]) {
+ sprintf(p, "0 ");
p = istatbuf + strlen(istatbuf);
} else {
sprintf(p, "? ");
@@ -882,7 +1263,7 @@ isdn_statstr(void)
sprintf(p, "\nphone:\t");
p = istatbuf + strlen(istatbuf);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- sprintf(p, "%s ", isdn_slot_num(i));
+ sprintf(p, "%s ", slots[i].num);
p = istatbuf + strlen(istatbuf);
}
sprintf(p, "\n");
@@ -1026,8 +1407,8 @@ isdn_status_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
sizeof(ulong) * ISDN_MAX_CHANNELS * 2)))
return ret;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- put_user(slot[i].ibytes, p++);
- put_user(slot[i].obytes, p++);
+ put_user(slots[i].ibytes, p++);
+ put_user(slots[i].obytes, p++);
}
return 0;
} else
@@ -1057,132 +1438,128 @@ static struct file_operations isdn_status_fops =
*/
static int
-isdn_ctrl_open(struct inode *ino, struct file *filep)
+isdn_ctrl_open(struct inode *ino, struct file *file)
{
- uint minor = minor(ino->i_rdev);
- int drvidx;
+ unsigned int minor = minor(ino->i_rdev);
+ int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
+ struct isdn_driver *drv;
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
+ drv = get_drv_by_nr(drvidx);
+ if (!drv)
return -ENODEV;
- isdn_lock_drivers();
+ isdn_lock_driver(drv);
+
+ file->private_data = drv;
return 0;
}
static int
-isdn_ctrl_release(struct inode *ino, struct file *filep)
+isdn_ctrl_release(struct inode *ino, struct file *file)
{
- lock_kernel();
+ struct isdn_driver *drv = file->private_data;
if (dev->profd == current)
dev->profd = NULL;
- isdn_unlock_drivers();
+ isdn_unlock_driver(drv);
+ put_drv(drv);
- unlock_kernel();
return 0;
}
static ssize_t
isdn_ctrl_read(struct file *file, char *buf, size_t count, loff_t * off)
{
- uint minor = minor(file->f_dentry->d_inode->i_rdev);
- ulong flags;
+ struct isdn_driver *drv = file->private_data;
+ unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
int len = 0;
- int drvidx;
- int retval;
+
if (off != &file->f_pos)
return -ESPIPE;
- lock_kernel();
-
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
+ if (!drv->interface->readstat) {
+ isdn_BUG();
+ return 0;
}
- if (!dev->drv[drvidx]->stavail) {
+ add_wait_queue(&drv->st_waitq, &wait);
+ for (;;) {
+ spin_lock_irqsave(&stat_lock, flags);
+ len = drv->stavail;
+ spin_unlock_irqrestore(&stat_lock, flags);
+ if (len > 0)
+ break;
+ if (signal_pending(current)) {
+ len = -ERESTARTSYS;
+ break;
+ }
if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- goto out;
+ len = -EAGAIN;
+ break;
}
- interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
+ schedule();
}
- if (dev->drv[drvidx]->interface->readstat) {
- if (count > dev->drv[drvidx]->stavail)
- count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->
- readstat(buf, count, 1, drvidx,
- isdn_minor2chan(minor));
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&drv->st_waitq, &wait);
+
+ if (len < 0)
+ return len;
+
+ if (count > len)
+ count = len;
+
+ len = drv->interface->readstat(buf, count, 1, drv->di,
+ isdn_minor2chan(minor));
+
+ spin_lock_irqsave(&stat_lock, flags);
+ if (len) {
+ drv->stavail -= len;
} else {
- len = 0;
+ isdn_BUG();
+ drv->stavail = 0;
}
- save_flags(flags);
- cli();
- if (len)
- dev->drv[drvidx]->stavail -= len;
- else
- dev->drv[drvidx]->stavail = 0;
- restore_flags(flags);
+ spin_unlock_irqrestore(&stat_lock, flags);
+
*off += len;
- retval = len;
-
- out:
- unlock_kernel();
- return retval;
+ return len;
}
static ssize_t
isdn_ctrl_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
- uint minor = minor(file->f_dentry->d_inode->i_rdev);
- int drvidx;
+ struct isdn_driver *drv = file->private_data;
+ unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
int retval;
if (off != &file->f_pos)
return -ESPIPE;
- lock_kernel();
-
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0) {
- retval = -ENODEV;
- goto out;
- }
- if (!dev->drv[drvidx]->interface->writecmd) {
+ if (!drv->interface->writecmd) {
retval = -EINVAL;
goto out;
}
- retval = dev->drv[drvidx]->interface->
- writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
+ retval = drv->interface->
+ writecmd(buf, count, 1, drv->di,
+ isdn_minor2chan(minor - ISDN_MINOR_CTRL));
out:
- unlock_kernel();
return retval;
}
static unsigned int
isdn_ctrl_poll(struct file *file, poll_table *wait)
{
+ struct isdn_driver *drv = file->private_data;
unsigned int mask = 0;
- unsigned int minor = minor(file->f_dentry->d_inode->i_rdev);
- int drvidx;
- drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
- if (drvidx < 0)
- /* driver deregistered while file open */
- return POLLHUP;
-
- lock_kernel();
-
- poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
+ poll_wait(file, &drv->st_waitq, wait);
mask = POLLOUT | POLLWRNORM;
- if (dev->drv[drvidx]->stavail)
+ if (drv->stavail)
mask |= POLLIN | POLLRDNORM;
- unlock_kernel();
return mask;
}
@@ -1240,7 +1617,6 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
case IIOCSETBRJ:
drvidx = -1;
if (arg) {
- int i;
char *p;
if (copy_from_user((char *) &iocts, (char *) arg,
sizeof(isdn_ioctl_struct)))
@@ -1248,20 +1624,15 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
if (strlen(iocts.drvid)) {
if ((p = strchr(iocts.drvid, ',')))
*p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
+ drvidx = isdn_drv_lookup(iocts.drvid);
}
}
if (drvidx == -1)
return -ENODEV;
if (iocts.arg)
- dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS;
+ drivers[drvidx]->flags |= DRV_FLAG_REJBUS;
else
- dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS;
+ drivers[drvidx]->flags &= ~DRV_FLAG_REJBUS;
return 0;
case IIOCSIGPRF:
dev->profd = current;
@@ -1279,14 +1650,14 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
return ret;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_to_user(p, dev->mdm.info[i].emu.profile,
+ if (copy_to_user(p, isdn_mdm.info[i].emu.profile,
ISDN_MODEM_NUMREG))
return -EFAULT;
p += ISDN_MODEM_NUMREG;
- if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN))
+ if (copy_to_user(p, isdn_mdm.info[i].emu.pmsn, ISDN_MSNLEN))
return -EFAULT;
p += ISDN_MSNLEN;
- if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
+ if (copy_to_user(p, isdn_mdm.info[i].emu.plmsn, ISDN_LMSNLEN))
return -EFAULT;
p += ISDN_LMSNLEN;
}
@@ -1306,14 +1677,14 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
return ret;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if (copy_from_user(dev->mdm.info[i].emu.profile, p,
+ if (copy_from_user(isdn_mdm.info[i].emu.profile, p,
ISDN_MODEM_NUMREG))
return -EFAULT;
p += ISDN_MODEM_NUMREG;
- if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
+ if (copy_from_user(isdn_mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
return -EFAULT;
p += ISDN_LMSNLEN;
- if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
+ if (copy_from_user(isdn_mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
return -EFAULT;
p += ISDN_MSNLEN;
}
@@ -1330,15 +1701,7 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
(char *) arg,
sizeof(isdn_ioctl_struct)))
return -EFAULT;
- if (strlen(iocts.drvid)) {
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
+ drvidx = isdn_drv_lookup(iocts.drvid);
if (drvidx == -1)
return -ENODEV;
if (cmd == IIOCSETMAP) {
@@ -1359,7 +1722,7 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
/* Fall through */
case ',':
bname[j] = '\0';
- strcpy(dev->drv[drvidx]->msn2eaz[i], bname);
+ strcpy(drivers[drvidx]->msn2eaz[i], bname);
j = ISDN_MSNLEN;
break;
default:
@@ -1375,8 +1738,8 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
p = (char *) iocts.arg;
for (i = 0; i < 10; i++) {
sprintf(bname, "%s%s",
- strlen(dev->drv[drvidx]->msn2eaz[i]) ?
- dev->drv[drvidx]->msn2eaz[i] : "_",
+ strlen(drivers[drvidx]->msn2eaz[i]) ?
+ drivers[drvidx]->msn2eaz[i] : "_",
(i < 9) ? "," : "\0");
if (copy_to_user(p, bname, strlen(bname) + 1))
return -EFAULT;
@@ -1400,21 +1763,9 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
else
return -EINVAL;
if (arg) {
- int i;
- char *p;
if (copy_from_user((char *) &iocts, (char *) arg, sizeof(isdn_ioctl_struct)))
return -EFAULT;
- if (strlen(iocts.drvid)) {
- if ((p = strchr(iocts.drvid, ',')))
- *p = 0;
- drvidx = -1;
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (!(strcmp(dev->drvid[i], iocts.drvid))) {
- drvidx = i;
- break;
- }
- } else
- drvidx = 0;
+ drvidx = isdn_drv_lookup(iocts.drvid);
if (drvidx == -1)
return -ENODEV;
if ((ret = verify_area(VERIFY_WRITE, (void *) arg,
@@ -1424,7 +1775,7 @@ isdn_ctrl_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
c.command = ISDN_CMD_IOCTL;
c.arg = cmd;
memcpy(c.parm.num, (char *) &iocts.arg, sizeof(ulong));
- ret = isdn_command(&c);
+ ret = __drv_command(drivers[drvidx], &c);
memcpy((char *) &iocts.arg, c.parm.num, sizeof(ulong));
if (copy_to_user((char *) arg, &iocts, sizeof(isdn_ioctl_struct)))
return -EFAULT;
@@ -1498,7 +1849,7 @@ static struct file_operations isdn_fops =
char *
isdn_map_eaz2msn(char *msn, int di)
{
- driver *this = dev->drv[di];
+ struct isdn_driver *this = drivers[di];
int i;
if (strlen(msn) == 1) {
@@ -1514,167 +1865,78 @@ isdn_map_eaz2msn(char *msn, int di)
* Find an unused ISDN-channel, whose feature-flags match the
* given L2- and L3-protocols.
*/
-#define L2V (~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038))
-
-int
+struct isdn_slot *
isdn_get_free_slot(int usage, int l2_proto, int l3_proto,
int pre_dev, int pre_chan, char *msn)
{
+ struct isdn_slot *slot;
int i;
- ulong flags;
- ulong features;
- ulong vfeatures;
+ unsigned long flags;
+ unsigned long features;
save_flags(flags);
cli();
features = ((1 << l2_proto) | (0x10000 << l3_proto));
- vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) &
- ~(ISDN_FEATURE_L2_V11096|ISDN_FEATURE_L2_V11019|ISDN_FEATURE_L2_V11038));
- /* If Layer-2 protocol is V.110, accept drivers with
- * transparent feature even if these don't support V.110
- * because we can emulate this in linklevel.
- */
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_NONE(slot[i].usage) &&
- (slot[i].di != -1)) {
- int d = slot[i].di;
- if (!strcmp(isdn_map_eaz2msn(msn, d), "-"))
- continue;
- if (slot[i].usage & ISDN_USAGE_DISABLED)
- continue; /* usage not allowed */
- if (!dev->drv[d]->flags & DRV_FLAG_RUNNING)
- continue;
- if (((dev->drv[d]->interface->features & features) == features) ||
- (((dev->drv[d]->interface->features & vfeatures) == vfeatures) &&
- (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) {
- if (pre_dev < 0 || pre_chan < 0 ||
- (pre_dev == d && pre_chan == slot[i].ch)) {
- isdn_slot_set_usage(i, usage);
- restore_flags(flags);
- return i;
- }
- }
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ slot = &slots[i];
+
+ if (!slot->drv || slot->drv->fi.state != ST_DRV_RUNNING)
+ continue;
+
+ if (!USG_NONE(slots[i].usage))
+ continue;
+
+ if (slots[i].usage & ISDN_USAGE_DISABLED)
+ continue;
+
+ if (slots[i].di == -1)
+ continue;
+
+ if (strcmp(isdn_map_eaz2msn(msn, slot->di), "-") == 0)
+ continue;
+
+ if (!(drivers[slot->di]->features & features) == features)
+ continue;
+
+ if (pre_dev < 0 || pre_chan < 0 ||
+ (pre_dev == slot->di && pre_chan == slot->ch)) {
+ slot->usage = usage;
+ isdn_info_update();
+ fsm_event(&slot->fi, EV_SLOT_BIND, NULL);
+ return slot;
}
+ }
restore_flags(flags);
- return -1;
+ return NULL;
}
/*
* Set state of ISDN-channel to 'unused'
*/
void
-isdn_free_channel(int di, int ch, int usage)
-{
- int sl;
-
- sl = isdn_dc2minor(di, ch);
- isdn_slot_free(sl);
-}
-
-void
-isdn_slot_free(int sl)
+isdn_slot_free(struct isdn_slot *slot)
{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- strcpy(isdn_slot_num(sl), "???");
- slot[sl].ibytes = 0;
- slot[sl].obytes = 0;
-// 20.10.99 JIM, try to reinitialize v110 !
- slot[sl].iv110.v110emu = 0;
- atomic_set(&slot[sl].iv110.v110use, 0);
- isdn_v110_close(slot[sl].iv110.v110);
- slot[sl].iv110.v110 = NULL;
-// 20.10.99 JIM, try to reinitialize v110 !
- isdn_slot_set_usage(sl, ISDN_USAGE_NONE);
- skb_queue_purge(&dev->drv[isdn_slot_driver(sl)]->rpqueue[isdn_slot_channel(sl)]);
- restore_flags(flags);
+ fsm_event(&slot->fi, EV_SLOT_UNBIND, NULL);
}
/*
* Return: length of data on success, -ERRcode on failure.
*/
int
-isdn_slot_write(int sl, struct sk_buff *skb)
+isdn_slot_write(struct isdn_slot *slot, struct sk_buff *skb)
{
- int ret;
- struct sk_buff *nskb = NULL;
- int v110_ret = skb->len;
- int di = isdn_slot_driver(sl);
- int ch = isdn_slot_channel(sl);
-
- BUG_ON(sl < 0);
-
- if (slot[sl].iv110.v110) {
- atomic_inc(&slot[sl].iv110.v110use);
- nskb = isdn_v110_encode(slot[sl].iv110.v110, skb);
- atomic_dec(&slot[sl].iv110.v110use);
- if (!nskb)
- return 0;
- v110_ret = *((int *)nskb->data);
- skb_pull(nskb, sizeof(int));
- if (!nskb->len) {
- dev_kfree_skb(nskb);
- return v110_ret;
- }
- /* V.110 must always be acknowledged */
- ret = dev->drv[di]->interface->writebuf_skb(di, ch, 1, nskb);
- } else {
- int hl = isdn_slot_hdrlen(sl);
-
- if( skb_headroom(skb) < hl ){
- /*
- * This should only occur when new HL driver with
- * increased hl_hdrlen was loaded after netdevice
- * was created and connected to the new driver.
- *
- * The V.110 branch (re-allocates on its own) does
- * not need this
- */
- struct sk_buff * skb_tmp;
-
- skb_tmp = skb_realloc_headroom(skb, hl);
- printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed");
- if (!skb_tmp) return -ENOMEM; /* 0 better? */
- ret = dev->drv[di]->interface->writebuf_skb(di, ch, 1, skb_tmp);
- if( ret > 0 ){
- dev_kfree_skb(skb);
- } else {
- dev_kfree_skb(skb_tmp);
- }
- } else {
- ret = dev->drv[di]->interface->writebuf_skb(di, ch, 1, skb);
- }
- }
- if (ret > 0) {
- slot[sl].obytes += ret;
- if (slot[sl].iv110.v110) {
- atomic_inc(&slot[sl].iv110.v110use);
- slot[sl].iv110.v110->skbuser++;
- atomic_dec(&slot[sl].iv110.v110use);
- /* For V.110 return unencoded data length */
- ret = v110_ret;
- /* if the complete frame was send we free the skb;
- if not upper function will requeue the skb */
- if (ret == skb->len)
- dev_kfree_skb(skb);
- }
- } else
- if (slot[sl].iv110.v110)
- dev_kfree_skb(nskb);
- return ret;
+ return fsm_event(&slot->fi, EV_DATA_REQ, skb);
}
-int
-isdn_add_channels(driver *d, int drvidx, int n, int adding)
+static int
+isdn_add_channels(struct isdn_driver *d, int drvidx, int n, int adding)
{
int j, k, m;
ulong flags;
init_waitqueue_head(&d->st_waitq);
- if (d->flags & DRV_FLAG_RUNNING)
- return -1;
+
if (n < 1) return 0;
m = (adding) ? d->channels + n : n;
@@ -1684,70 +1946,20 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
ISDN_MAX_CHANNELS);
return -1;
}
-
- if ((adding) && (d->rcverr))
- kfree(d->rcverr);
- if (!(d->rcverr = kmalloc(sizeof(int) * m, GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n");
- return -1;
- }
- memset((char *) d->rcverr, 0, sizeof(int) * m);
-
- if ((adding) && (d->rcvcount))
- kfree(d->rcvcount);
- if (!(d->rcvcount = kmalloc(sizeof(int) * m, GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n");
- if (!adding) kfree(d->rcverr);
- return -1;
- }
- memset((char *) d->rcvcount, 0, sizeof(int) * m);
-
- if ((adding) && (d->rpqueue)) {
- for (j = 0; j < d->channels; j++)
- skb_queue_purge(&d->rpqueue[j]);
- kfree(d->rpqueue);
- }
- if (!(d->rpqueue = kmalloc(sizeof(struct sk_buff_head) * m, GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n");
- if (!adding) {
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- for (j = 0; j < m; j++) {
- skb_queue_head_init(&d->rpqueue[j]);
- }
-
- if ((adding) && (d->rcv_waitq))
- kfree(d->rcv_waitq);
- d->rcv_waitq = kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
- if (!d->rcv_waitq) {
- printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
- if (!adding) {
- kfree(d->rpqueue);
- kfree(d->rcvcount);
- kfree(d->rcverr);
- }
- return -1;
- }
- d->snd_waitq = d->rcv_waitq + m;
- for (j = 0; j < m; j++) {
- init_waitqueue_head(&d->rcv_waitq[j]);
- init_waitqueue_head(&d->snd_waitq[j]);
- }
-
dev->channels += n;
save_flags(flags);
cli();
- for (j = d->channels; j < m; j++)
- for (k = 0; k < ISDN_MAX_CHANNELS; k++)
- if (slot[k].ch < 0) {
- slot[k].ch = j;
- slot[k].di = drvidx;
+ for (j = d->channels; j < m; j++) {
+ for (k = 0; k < ISDN_MAX_CHANNELS; k++) {
+ if (slots[k].ch < 0) {
+ slots[k].ch = j;
+ slots[k].di = drvidx;
+ slots[k].drv = d;
isdn_register_devfs(k);
break;
}
+ }
+ }
restore_flags(flags);
d->channels = m;
return 0;
@@ -1757,20 +1969,6 @@ isdn_add_channels(driver *d, int drvidx, int n, int adding)
* Low-level-driver registration
*/
-static void
-set_global_features(void)
-{
- int drvidx;
-
- dev->global_features = 0;
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
- if (!dev->drv[drvidx])
- continue;
- if (dev->drv[drvidx]->interface)
- dev->global_features |= dev->drv[drvidx]->interface->features;
- }
-}
-
#if defined(CONFIG_ISDN_DIVERSION) || defined(CONFIG_ISDN_DIVERSION_MODULE)
static char *map_drvname(int di)
@@ -1830,105 +2028,34 @@ EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
#endif
int
-register_isdn(isdn_if * i)
-{
- driver *d;
- int j;
- ulong flags;
- int drvidx;
-
- if (dev->drivers >= ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n",
- ISDN_MAX_DRIVERS);
- return 0;
- }
- if (!i->writebuf_skb) {
- printk(KERN_WARNING "register_isdn: No write routine given.\n");
- return 0;
- }
- if (!(d = kmalloc(sizeof(driver), GFP_KERNEL))) {
- printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n");
- return 0;
- }
- memset((char *) d, 0, sizeof(driver));
-
- d->maxbufsize = i->maxbufsize;
- d->pktcount = 0;
- d->stavail = 0;
- d->flags = DRV_FLAG_LOADED;
- d->online = 0;
- d->interface = i;
- d->channels = 0;
- for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++)
- if (!dev->drv[drvidx])
- break;
- if (isdn_add_channels(d, drvidx, i->channels, 0)) {
- kfree(d);
- return 0;
- }
- i->channels = drvidx;
- i->rcvcallb_skb = isdn_receive_skb_callback;
- i->statcallb = isdn_status_callback;
- if (!strlen(i->id))
- sprintf(i->id, "line%d", drvidx);
- save_flags(flags);
- cli();
- for (j = 0; j < drvidx; j++)
- if (!strcmp(i->id, dev->drvid[j]))
- sprintf(i->id, "line%d", drvidx);
- dev->drv[drvidx] = d;
- strcpy(dev->drvid[drvidx], i->id);
- isdn_info_update();
- dev->drivers++;
- set_global_features();
- restore_flags(flags);
- return 1;
-}
-
-int
-isdn_slot_driver(int sl)
-{
- BUG_ON(sl < 0);
-
- return slot[sl].di;
-}
-
-int
-isdn_slot_channel(int sl)
+isdn_slot_maxbufsize(struct isdn_slot *slot)
{
- BUG_ON(sl < 0);
-
- return slot[sl].ch;
+ return slot->drv->maxbufsize;
}
int
-isdn_slot_hdrlen(int sl)
+isdn_slot_hdrlen(struct isdn_slot *slot)
{
- int di = isdn_slot_driver(sl);
-
- return dev->drv[di]->interface->hl_hdrlen;
+ return slot->drv->interface->hl_hdrlen;
}
char *
-isdn_slot_map_eaz2msn(int sl, char *msn)
+isdn_slot_map_eaz2msn(struct isdn_slot *slot, char *msn)
{
- int di = isdn_slot_driver(sl);
-
- return isdn_map_eaz2msn(msn, di);
+ return isdn_map_eaz2msn(msn, slot->di);
}
int
-isdn_slot_command(int sl, int cmd, isdn_ctrl *ctrl)
+isdn_slot_command(struct isdn_slot *slot, int cmd, isdn_ctrl *ctrl)
{
-
ctrl->command = cmd;
- ctrl->driver = isdn_slot_driver(sl);
+ ctrl->driver = slot->di;
switch (cmd) {
case ISDN_CMD_SETL2:
case ISDN_CMD_SETL3:
case ISDN_CMD_PROT_IO:
- ctrl->arg &= ~0xff; ctrl->arg |= isdn_slot_channel(sl);
+ ctrl->arg &= ~0xff; ctrl->arg |= slot->ch;
break;
case ISDN_CMD_DIAL:
if (dev->global_flags & ISDN_GLOBAL_STOPPED)
@@ -1936,19 +2063,37 @@ isdn_slot_command(int sl, int cmd, isdn_ctrl *ctrl)
/* fall through */
default:
- ctrl->arg = isdn_slot_channel(sl);
+ ctrl->arg = slot->ch;
break;
}
-
- return isdn_command(ctrl);
+ switch (cmd) {
+ case ISDN_CMD_CLREAZ:
+ return fsm_event(&slot->fi, EV_CMD_CLREAZ, ctrl);
+ case ISDN_CMD_SETEAZ:
+ return fsm_event(&slot->fi, EV_CMD_SETEAZ, ctrl);
+ case ISDN_CMD_SETL2:
+ return fsm_event(&slot->fi, EV_CMD_SETL2, ctrl);
+ case ISDN_CMD_SETL3:
+ return fsm_event(&slot->fi, EV_CMD_SETL3, ctrl);
+ case ISDN_CMD_DIAL:
+ return fsm_event(&slot->fi, EV_CMD_DIAL, ctrl);
+ case ISDN_CMD_ACCEPTD:
+ return fsm_event(&slot->fi, EV_CMD_ACCEPTD, ctrl);
+ case ISDN_CMD_ACCEPTB:
+ return fsm_event(&slot->fi, EV_CMD_ACCEPTB, ctrl);
+ case ISDN_CMD_HANGUP:
+ return fsm_event(&slot->fi, EV_CMD_HANGUP, ctrl);
+ }
+ HERE;
+ return -1;
}
int
-isdn_slot_dial(int sl, struct dial_info *dial)
+isdn_slot_dial(struct isdn_slot *slot, struct dial_info *dial)
{
isdn_ctrl cmd;
int retval;
- char *msn = isdn_slot_map_eaz2msn(sl, dial->msn);
+ char *msn = isdn_slot_map_eaz2msn(slot, dial->msn);
/* check for DOV */
if (dial->si1 == 7 && tolower(dial->phone[0]) == 'v') { /* DOV call */
@@ -1956,24 +2101,25 @@ isdn_slot_dial(int sl, struct dial_info *dial)
dial->phone++; /* skip v/V */
}
- strcpy(isdn_slot_num(sl), dial->phone);
- isdn_slot_set_usage(sl, isdn_slot_usage(sl) | ISDN_USAGE_OUTGOING);
+ strcpy(slot->num, dial->phone);
+ slot->usage |= ISDN_USAGE_OUTGOING;
+ isdn_info_update();
- retval = isdn_slot_command(sl, ISDN_CMD_CLREAZ, &cmd);
+ retval = isdn_slot_command(slot, ISDN_CMD_CLREAZ, &cmd);
if (retval)
return retval;
strcpy(cmd.parm.num, msn);
- retval = isdn_slot_command(sl, ISDN_CMD_SETEAZ, &cmd);
+ retval = isdn_slot_command(slot, ISDN_CMD_SETEAZ, &cmd);
cmd.arg = dial->l2_proto << 8;
cmd.parm.fax = dial->fax;
- retval = isdn_slot_command(sl, ISDN_CMD_SETL2, &cmd);
+ retval = isdn_slot_command(slot, ISDN_CMD_SETL2, &cmd);
if (retval)
return retval;
cmd.arg = dial->l3_proto << 8;
- retval = isdn_slot_command(sl, ISDN_CMD_SETL3, &cmd);
+ retval = isdn_slot_command(slot, ISDN_CMD_SETL3, &cmd);
if (retval)
return retval;
@@ -1982,78 +2128,12 @@ isdn_slot_dial(int sl, struct dial_info *dial)
strcpy(cmd.parm.setup.eazmsn, msn);
strcpy(cmd.parm.setup.phone, dial->phone);
- printk(KERN_INFO "ISDN: slot %d: Dialing %s -> %s (SI %d/%d) (B %d/%d)\n",
- sl, cmd.parm.setup.eazmsn, cmd.parm.setup.phone,
+ printk(KERN_INFO "ISDN: Dialing %s -> %s (SI %d/%d) (B %d/%d)\n",
+ cmd.parm.setup.eazmsn, cmd.parm.setup.phone,
cmd.parm.setup.si1, cmd.parm.setup.si2,
dial->l2_proto, dial->l3_proto);
- return isdn_slot_command(sl, ISDN_CMD_DIAL, &cmd);
-}
-
-void
-isdn_slot_all_eaz(int sl)
-{
- isdn_ctrl cmd;
-
- cmd.parm.num[0] = '\0';
- isdn_slot_command(sl, ISDN_CMD_SETEAZ, &cmd);
-}
-
-int
-isdn_slot_usage(int sl)
-{
- BUG_ON(sl < 0);
-
- return slot[sl].usage;
-}
-
-void
-isdn_slot_set_usage(int sl, int usage)
-{
- BUG_ON(sl < 0);
-
- slot[sl].usage = usage;
- isdn_info_update();
-}
-
-int
-isdn_slot_m_idx(int sl)
-{
- BUG_ON(sl < 0);
-
- return slot[sl].m_idx;
-}
-
-void
-isdn_slot_set_m_idx(int sl, int midx)
-{
- BUG_ON(sl < 0);
-
- slot[sl].m_idx = midx;
-}
-
-char *
-isdn_slot_num(int sl)
-{
- BUG_ON(sl < 0);
-
- return slot[sl].num;
-}
-
-void
-isdn_slot_set_idev(int sl, isdn_net_dev *idev)
-{
- BUG_ON(sl < 0);
-
- slot[sl].idev = idev;
-}
-
-isdn_net_dev *
-isdn_slot_idev(int sl)
-{
- BUG_ON(sl < 0);
-
- return slot[sl].idev;
+ return isdn_slot_command(slot, ISDN_CMD_DIAL, &cmd);
}
int
@@ -2063,9 +2143,9 @@ isdn_hard_header_len(void)
int max = 0;
for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) {
- if (dev->drv[drvidx] &&
- max < dev->drv[drvidx]->interface->hl_hdrlen) {
- max = dev->drv[drvidx]->interface->hl_hdrlen;
+ if (drivers[drvidx] &&
+ max < drivers[drvidx]->interface->hl_hdrlen) {
+ max = drivers[drvidx]->interface->hl_hdrlen;
}
}
return max;
@@ -2077,21 +2157,6 @@ isdn_hard_header_len(void)
*****************************************************************************
*/
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_handle;
@@ -2179,25 +2244,32 @@ static int __init isdn_init(void)
{
int i;
int retval;
- char tmprev[50];
+
+ retval = fsm_new(&slot_fsm);
+ if (retval)
+ goto err;
+
+ retval = fsm_new(&drv_fsm);
+ if (retval)
+ goto err_slot_fsm;
dev = vmalloc(sizeof(*dev));
if (!dev) {
retval = -ENOMEM;
- goto err;
+ goto err_drv_fsm;
}
memset(dev, 0, sizeof(*dev));
- init_timer(&dev->timer);
- dev->timer.function = isdn_timer_funct;
init_MUTEX(&dev->sem);
init_waitqueue_head(&dev->info_waitq);
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- slot[i].di = -1;
- slot[i].ch = -1;
- slot[i].m_idx = -1;
- strcpy(isdn_slot_num(i), "???");
- init_waitqueue_head(&dev->mdm.info[i].open_wait);
- init_waitqueue_head(&dev->mdm.info[i].close_wait);
+ slots[i].di = -1;
+ slots[i].ch = -1;
+ strcpy(slots[i].num, "???");
+ slots[i].fi.fsm = &slot_fsm;
+ slots[i].fi.state = ST_SLOT_NULL;
+ slots[i].fi.debug = 1;
+ slots[i].fi.userdata = slots + i;
+ slots[i].fi.printdebug = slot_debug;
}
retval = register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops);
if (retval) {
@@ -2218,26 +2290,9 @@ static int __init isdn_init(void)
}
#endif /* CONFIG_ISDN_PPP */
- strcpy(tmprev, isdn_revision);
- printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_tty_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_net_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_ppp_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_audio_revision);
- printk("%s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_v110_revision);
- printk("%s", isdn_getrev(tmprev));
-
-#ifdef MODULE
- printk(" loaded\n");
-#else
- printk("\n");
-#endif
+ isdn_net_lib_init();
+ printk(KERN_NOTICE "ISDN subsystem initialized\n");
isdn_info_update();
- isdn_net_init();
return 0;
err_tty_modem:
@@ -2247,6 +2302,10 @@ static int __init isdn_init(void)
unregister_chrdev(ISDN_MAJOR, "isdn");
err_vfree:
vfree(dev);
+ err_drv_fsm:
+ fsm_free(&drv_fsm);
+ err_slot_fsm:
+ fsm_free(&slot_fsm);
err:
return retval;
}
@@ -2256,25 +2315,144 @@ static int __init isdn_init(void)
*/
static void __exit isdn_exit(void)
{
- unsigned long flags;
-
#ifdef CONFIG_ISDN_PPP
isdn_ppp_cleanup();
#endif
- save_flags(flags);
- cli();
- isdn_net_exit();
+ isdn_net_lib_exit();
isdn_tty_exit();
- if (unregister_chrdev(ISDN_MAJOR, "isdn"))
- BUG();
-
+ unregister_chrdev(ISDN_MAJOR, "isdn");
isdn_cleanup_devfs();
- del_timer(&dev->timer);
- restore_flags(flags);
- /* call vfree with interrupts enabled, else it will hang */
vfree(dev);
+ fsm_free(&drv_fsm);
+ fsm_free(&slot_fsm);
}
module_init(isdn_init);
module_exit(isdn_exit);
+
+static void
+isdn_v110_add_features(struct isdn_driver *drv)
+{
+ unsigned long features = drv->features >> ISDN_FEATURE_L2_SHIFT;
+
+ if (features & ISDN_FEATURE_L2_TRANS)
+ drv->features |= (ISDN_FEATURE_L2_V11096|
+ ISDN_FEATURE_L2_V11019|
+ ISDN_FEATURE_L2_V11038) <<
+ ISDN_FEATURE_L2_SHIFT;
+}
+
+static void
+__isdn_v110_open(struct isdn_slot *slot)
+{
+ if (!slot->iv110.v110emu)
+ return;
+
+ isdn_v110_open(slot, &slot->iv110);
+}
+
+static void
+__isdn_v110_close(struct isdn_slot *slot)
+{
+ if (!slot->iv110.v110emu)
+ return;
+
+ isdn_v110_close(slot, &slot->iv110);
+}
+
+static void
+__isdn_v110_bsent(struct isdn_slot *slot, int pr, isdn_ctrl *c)
+{
+ if (!slot->iv110.v110emu) {
+ do_event_cb(slot, pr, c);
+ return;
+ }
+ isdn_v110_bsent(slot, &slot->iv110);
+}
+
+/*
+ * Intercept command from Linklevel to Lowlevel.
+ * If layer 2 protocol is V.110 and this is not supported by current
+ * lowlevel-driver, use driver's transparent mode and handle V.110 in
+ * linklevel instead.
+ */
+static void
+isdn_v110_setl2(struct isdn_slot *slot, isdn_ctrl *cmd)
+{
+ struct isdn_driver *drv = slot->drv;
+
+ unsigned long l2prot = (cmd->arg >> 8) & 255;
+ unsigned long l2_feature = 1 << l2prot;
+ unsigned long features = drv->interface->features >>
+ ISDN_FEATURE_L2_SHIFT;
+
+ switch (l2prot) {
+ case ISDN_PROTO_L2_V11096:
+ case ISDN_PROTO_L2_V11019:
+ case ISDN_PROTO_L2_V11038:
+ /* If V.110 requested, but not supported by
+ * HL-driver, set emulator-flag and change
+ * Layer-2 to transparent
+ */
+ if (!(features & l2_feature)) {
+ slot->iv110.v110emu = l2prot;
+ cmd->arg = (cmd->arg & 255) |
+ (ISDN_PROTO_L2_TRANS << 8);
+ } else
+ slot->iv110.v110emu = 0;
+ }
+}
+
+static int
+isdn_v110_data_ind(struct isdn_slot *slot, struct sk_buff *skb)
+{
+ if (!slot->iv110.v110emu)
+ goto recv;
+
+ skb = isdn_v110_decode(slot->iv110.v110, skb);
+ if (!skb)
+ return 0;
+
+recv:
+ if (slot->event_cb)
+ slot->event_cb(slot, EV_DATA_IND, skb);
+ return 0;
+}
+
+static int
+isdn_v110_data_req(struct isdn_slot *slot, struct sk_buff *skb)
+{
+ int retval, v110_ret;
+ struct sk_buff *nskb = NULL;
+
+ if (!slot->iv110.v110emu)
+ return isdn_writebuf_skb(slot, skb);
+
+ atomic_inc(&slot->iv110.v110use);
+ nskb = isdn_v110_encode(slot->iv110.v110, skb);
+ atomic_dec(&slot->iv110.v110use);
+ if (!nskb)
+ return -ENOMEM;
+
+ v110_ret = *(int *)nskb->data;
+ skb_pull(nskb, sizeof(int));
+ if (!nskb->len) {
+ dev_kfree_skb(nskb);
+ return v110_ret;
+ }
+
+ retval = isdn_writebuf_skb(slot, nskb);
+ if (retval <= 0) {
+ dev_kfree_skb(nskb);
+ return retval;
+ }
+ dev_kfree_skb(skb);
+
+ atomic_inc(&slot->iv110.v110use);
+ slot->iv110.v110->skbuser++;
+ atomic_dec(&slot->iv110.v110use);
+
+ /* For V.110 return unencoded data length */
+ return v110_ret;
+}
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
index 64e1c1e9c819..ff80a0063722 100644
--- a/drivers/isdn/i4l/isdn_common.h
+++ b/drivers/isdn/i4l/isdn_common.h
@@ -1,7 +1,4 @@
-/* $Id: isdn_common.h,v 1.21.6.1 2001/09/23 22:24:31 kai Exp $
- *
- * header for Linux ISDN subsystem
- * common used functions and debugging-switches (linklevel).
+/* Linux ISDN subsystem, common used functions and debugging-switches
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
@@ -13,6 +10,7 @@
*/
#include <linux/isdn.h>
+#include "isdn_v110.h"
#undef ISDN_DEBUG_MODEM_OPEN
#undef ISDN_DEBUG_MODEM_IOCTL
@@ -22,7 +20,7 @@
#undef ISDN_DEBUG_MODEM_DUMP
#undef ISDN_DEBUG_MODEM_VOICE
#undef ISDN_DEBUG_AT
-#define ISDN_DEBUG_NET_DUMP
+#undef ISDN_DEBUG_NET_DUMP
#define ISDN_DEBUG_NET_DIAL
#define ISDN_DEBUG_NET_ICALL
#define ISDN_DEBUG_STATCALLB
@@ -59,20 +57,30 @@ extern void isdn_MOD_INC_USE_COUNT(void);
extern void isdn_MOD_DEC_USE_COUNT(void);
extern void isdn_lock_drivers(void);
extern void isdn_unlock_drivers(void);
-extern void isdn_free_channel(int di, int ch, int usage);
-extern int isdn_dc2minor(int di, int ch);
extern void isdn_info_update(void);
extern char *isdn_map_eaz2msn(char *msn, int di);
-extern void isdn_timer_ctrl(int tf, int onoff);
extern int isdn_getnum(char **);
extern int isdn_msncmp( const char *, const char *);
-extern int isdn_add_channels(driver *, int, int, int);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#else
static inline void isdn_dumppkt(char *s, u_char *d, int l, int m) { }
#endif
+struct isdn_slot {
+ int di; /* driver index */
+ struct isdn_driver *drv; /* driver */
+ int ch; /* channel index (per driver) */
+ int usage; /* how is it used */
+ char num[ISDN_MSNLEN]; /* the current phone number */
+ unsigned long ibytes; /* Statistics incoming bytes */
+ unsigned long obytes; /* Statistics outgoing bytes */
+ struct isdn_v110 iv110; /* For V.110 */
+ void *priv; /* pointer to isdn_net_dev */
+ int (*event_cb)(struct isdn_slot *, int pr, void *arg);
+ struct fsm_inst fi;
+};
+
struct dial_info {
int l2_proto;
int l3_proto;
@@ -83,22 +91,59 @@ struct dial_info {
unsigned char *phone;
};
-extern int isdn_get_free_slot(int, int, int, int, int, char *);
-extern void isdn_slot_free(int slot);
-extern void isdn_slot_all_eaz(int slot);
-extern int isdn_slot_command(int slot, int cmd, isdn_ctrl *);
-extern int isdn_slot_dial(int slot, struct dial_info *dial);
-extern char *isdn_slot_map_eaz2msn(int slot, char *msn);
-extern int isdn_slot_write(int slot, struct sk_buff *);
-extern int isdn_slot_readbchan(int slot, u_char *, u_char *, int);
-extern int isdn_slot_hdrlen(int slot);
-extern int isdn_slot_driver(int slot);
-extern int isdn_slot_channel(int slot);
-extern int isdn_slot_usage(int slot);
-extern void isdn_slot_set_usage(int slot, int usage);
-extern char *isdn_slot_num(int slot);
-extern int isdn_slot_m_idx(int slot);
-extern void isdn_slot_set_m_idx(int slot, int midx);
-extern void isdn_slot_set_idev(int sl, isdn_net_dev *);
-extern isdn_net_dev *isdn_slot_idev(int sl);
-extern int isdn_hard_header_len(void);
+struct isdn_slot *isdn_get_free_slot(int, int, int, int, int, char *);
+void isdn_slot_free(struct isdn_slot *);
+int isdn_slot_command(struct isdn_slot *, int cmd, isdn_ctrl *);
+int isdn_slot_dial(struct isdn_slot *, struct dial_info *dial);
+char *isdn_slot_map_eaz2msn(struct isdn_slot *, char *msn);
+int isdn_slot_write(struct isdn_slot *, struct sk_buff *);
+int isdn_slot_hdrlen(struct isdn_slot *);
+int isdn_slot_maxbufsize(struct isdn_slot *);
+int isdn_hard_header_len(void);
+
+int isdn_drv_lookup(char *drvid);
+char *isdn_drv_drvid(int di);
+
+enum {
+ ST_SLOT_NULL,
+ ST_SLOT_BOUND,
+ ST_SLOT_IN,
+ ST_SLOT_WAIT_DCONN,
+ ST_SLOT_DCONN,
+ ST_SLOT_WAIT_BCONN,
+ ST_SLOT_ACTIVE,
+ ST_SLOT_WAIT_BHUP,
+ ST_SLOT_WAIT_DHUP,
+};
+
+enum {
+ EV_DRV_REGISTER,
+ EV_STAT_RUN,
+ EV_STAT_STOP,
+ EV_STAT_UNLOAD,
+ EV_STAT_STAVAIL,
+ EV_STAT_ADDCH,
+ EV_STAT_ICALL,
+ EV_STAT_DCONN,
+ EV_STAT_BCONN,
+ EV_STAT_BHUP,
+ EV_STAT_DHUP,
+ EV_STAT_BSENT,
+ EV_STAT_CINF,
+ EV_STAT_CAUSE,
+ EV_STAT_DISPLAY,
+ EV_STAT_FAXIND,
+ EV_STAT_AUDIO,
+ EV_CMD_CLREAZ,
+ EV_CMD_SETEAZ,
+ EV_CMD_SETL2,
+ EV_CMD_SETL3,
+ EV_CMD_DIAL,
+ EV_CMD_ACCEPTD,
+ EV_CMD_ACCEPTB,
+ EV_CMD_HANGUP,
+ EV_DATA_REQ,
+ EV_DATA_IND,
+ EV_SLOT_BIND,
+ EV_SLOT_UNBIND,
+};
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
index 935358fe2bb2..0bc42ad91364 100644
--- a/drivers/isdn/i4l/isdn_concap.c
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -1,16 +1,12 @@
-/* $Id: isdn_concap.c,v 1.8.6.1 2001/09/23 22:24:31 kai Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
+/* Linux ISDN subsystem, protocol encapsulation
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific
* stuff goes here. Stuff that depends only on the concap protocol goes to
* another -- protocol specific -- source file.
- *
*/
@@ -115,8 +111,8 @@ static int
isdn_x25_open(isdn_net_local *lp)
{
struct net_device * dev = & lp -> netdev -> dev;
- struct concap_proto * cprot = lp -> netdev -> cprot;
- struct concap_proto * dops = lp -> dops;
+ struct concap_proto * cprot = lp -> netdev -> ind_priv;
+ struct concap_proto * dops = lp -> inl_priv;
unsigned long flags;
save_flags(flags);
@@ -130,7 +126,7 @@ isdn_x25_open(isdn_net_local *lp)
static void
isdn_x25_close(isdn_net_local *lp)
{
- struct concap_proto * cprot = lp -> netdev -> cprot;
+ struct concap_proto * cprot = lp -> netdev -> ind_priv;
if( cprot && cprot -> pops ) cprot -> pops -> close( cprot );
}
@@ -138,7 +134,7 @@ isdn_x25_close(isdn_net_local *lp)
static void
isdn_x25_connected(isdn_net_local *lp)
{
- struct concap_proto *cprot = lp -> netdev -> cprot;
+ struct concap_proto *cprot = lp -> netdev -> ind_priv;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
/* try if there are generic concap receiver routines */
@@ -152,7 +148,7 @@ isdn_x25_connected(isdn_net_local *lp)
static void
isdn_x25_disconnected(isdn_net_local *lp)
{
- struct concap_proto *cprot = lp -> netdev -> cprot;
+ struct concap_proto *cprot = lp -> netdev -> ind_priv;
struct concap_proto_ops *pops = cprot ? cprot -> pops : 0;
/* try if there are generic encap protocol
@@ -177,7 +173,7 @@ isdn_x25_start_xmit(struct sk_buff *skb, struct net_device *dev)
when a dl_establish request is received from the upper layer.
*/
isdn_net_local *lp = (isdn_net_local *) dev->priv;
- struct concap_proto * cprot = lp -> netdev -> cprot;
+ struct concap_proto * cprot = lp -> netdev -> ind_priv;
int ret = cprot -> pops -> encap_and_xmit ( cprot , skb);
if (ret)
@@ -190,7 +186,7 @@ static void
isdn_x25_receive(isdn_net_dev *p, isdn_net_local *olp, struct sk_buff *skb)
{
isdn_net_local *lp = &p->local;
- struct concap_proto *cprot = lp -> netdev -> cprot;
+ struct concap_proto *cprot = lp -> netdev -> ind_priv;
/* try if there are generic sync_device receiver routines */
if(cprot)
@@ -211,7 +207,7 @@ isdn_x25_init(struct net_device *dev)
/* ... , prepare for configuration of new one ... */
switch ( lp->p_encap ){
case ISDN_NET_ENCAP_X25IFACE:
- lp -> dops = &isdn_concap_reliable_dl_dops;
+ lp -> inl_priv = &isdn_concap_reliable_dl_dops;
}
/* ... and allocate new one ... */
p -> cprot = isdn_concap_new( cfg -> p_encap );
@@ -237,7 +233,7 @@ isdn_x25_cleanup(isdn_net_dev *p)
if( cprot && cprot -> pops )
cprot -> pops -> proto_del ( cprot );
p -> cprot = NULL;
- lp -> dops = NULL;
+ lp -> inl_priv = NULL;
restore_flags(flags);
}
diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
index 8150d6f595e0..49ee3cb27101 100644
--- a/drivers/isdn/i4l/isdn_concap.h
+++ b/drivers/isdn/i4l/isdn_concap.h
@@ -1,10 +1,7 @@
-/* $Id: isdn_concap.h,v 1.3.6.1 2001/09/23 22:24:31 kai Exp $
- *
- * Linux ISDN subsystem, protocol encapsulation
+/* Linux ISDN subsystem, protocol encapsulation
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
extern struct concap_device_ops isdn_concap_reliable_dl_dops;
diff --git a/drivers/isdn/i4l/isdn_fsm.c b/drivers/isdn/i4l/isdn_fsm.c
index 52de59763fe8..673b3ad9d632 100644
--- a/drivers/isdn/i4l/isdn_fsm.c
+++ b/drivers/isdn/i4l/isdn_fsm.c
@@ -1,17 +1,14 @@
-/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $
- *
- * Finite state machine
+/* Linux ISDN subsystem, finite state machine
*
* Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- * by Kai Germaschewski <kai.germaschewski@gmx.de>
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+ * 2001-2002 by Kai Germaschewski <kai@germaschewski.name>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* Thanks to Jan den Ouden
* Fritz Elfert
- *
*/
#include <linux/kernel.h>
@@ -19,7 +16,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include "isdn_fsm.h"
+#include <linux/isdn/fsm.h>
int
fsm_new(struct fsm *fsm)
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index f41603c1287d..370e3e5f8011 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1,6 +1,4 @@
-/* $Id: isdn_net.c,v 1.140.6.11 2001/11/06 20:58:28 kai Exp $
- *
- * Linux ISDN subsystem, network interfaces and related functions (linklevel).
+/* Linux ISDN subsystem, network interfaces and related functions (linklevel).
*
* Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
* 1995,96 by Thinking Objects Software GmbH Wuerzburg
@@ -9,31 +7,14 @@
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
- * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
- * guy@traverse.com.au
- * Outgoing calls - looks for a 'V' in first char of dialed number
- * Incoming calls - checks first character of eaz as follows:
- * Numeric - accept DATA only - original functionality
- * 'V' - accept VOICE (DOV) only
- * 'B' - accept BOTH DATA and DOV types
- *
*/
-#include <linux/config.h>
#include <linux/isdn.h>
-#include <net/arp.h>
-#include <net/dst.h>
-#include <net/pkt_sched.h>
#include <linux/inetdevice.h>
+#include <net/arp.h>
#include "isdn_common.h"
+#include "isdn_net_lib.h"
#include "isdn_net.h"
-#include "isdn_ppp.h"
-#include <linux/concap.h>
-#include "isdn_concap.h"
-#include "isdn_ciscohdlck.h"
-
-char *isdn_net_revision = "$Revision: 1.140.6.11 $";
// ISDN_NET_ENCAP_IPTYP
// ethernet type field
@@ -52,13 +33,14 @@ static void
isdn_iptyp_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- idev->huptimer = 0;
- get_u16(skb->data, &skb->protocol);
+ u16 protocol;
+
+ get_u16(skb->data, &protocol);
skb_pull(skb, 2);
- netif_rx(skb);
+ isdn_netif_rx(idev, skb, protocol);
}
-static struct isdn_netif_ops iptyp_ops = {
+struct isdn_netif_ops isdn_iptyp_ops = {
.hard_start_xmit = isdn_net_start_xmit,
.hard_header = isdn_iptyp_header,
.flags = IFF_NOARP | IFF_POINTOPOINT,
@@ -84,13 +66,11 @@ static void
isdn_uihdlc_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- idev->huptimer = 0;
skb_pull(skb, 2);
- skb->protocol = htons(ETH_P_IP);
- netif_rx(skb);
+ isdn_netif_rx(idev, skb, htons(ETH_P_IP));
}
-static struct isdn_netif_ops uihdlc_ops = {
+struct isdn_netif_ops isdn_uihdlc_ops = {
.hard_start_xmit = isdn_net_start_xmit,
.hard_header = isdn_uihdlc_header,
.flags = IFF_NOARP | IFF_POINTOPOINT,
@@ -112,7 +92,7 @@ isdn_rawip_receive(isdn_net_local *lp, isdn_net_dev *idev,
netif_rx(skb);
}
-static struct isdn_netif_ops rawip_ops = {
+struct isdn_netif_ops isdn_rawip_ops = {
.hard_start_xmit = isdn_net_start_xmit,
.flags = IFF_NOARP | IFF_POINTOPOINT,
.type = ARPHRD_PPP,
@@ -127,9 +107,7 @@ static void
isdn_ether_receive(isdn_net_local *lp, isdn_net_dev *idev,
struct sk_buff *skb)
{
- idev->huptimer = 0;
- skb->protocol = eth_type_trans(skb, skb->dev);
- netif_rx(skb);
+ isdn_netif_rx(idev, skb, eth_type_trans(skb, &lp->dev));
}
static int
@@ -164,38 +142,9 @@ isdn_ether_init(isdn_net_local *lp)
return 0;
}
-static struct isdn_netif_ops ether_ops = {
+struct isdn_netif_ops isdn_ether_ops = {
.hard_start_xmit = isdn_net_start_xmit,
- .hard_header = eth_header,
.receive = isdn_ether_receive,
.init = isdn_ether_init,
.open = isdn_ether_open,
};
-
-// ======================================================================
-
-void
-isdn_net_init(void)
-{
- isdn_net_lib_init();
-
- register_isdn_netif(ISDN_NET_ENCAP_ETHER, &ether_ops);
- register_isdn_netif(ISDN_NET_ENCAP_RAWIP, &rawip_ops);
- register_isdn_netif(ISDN_NET_ENCAP_IPTYP, &iptyp_ops);
- register_isdn_netif(ISDN_NET_ENCAP_UIHDLC, &uihdlc_ops);
- register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLC, &ciscohdlck_ops);
- register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLCK, &ciscohdlck_ops);
-#ifdef CONFIG_ISDN_X25
- register_isdn_netif(ISDN_NET_ENCAP_X25IFACE, &isdn_x25_ops);
-#endif
-#ifdef CONFIG_ISDN_PPP
- register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP, &isdn_ppp_ops);
-#endif
-}
-
-void
-isdn_net_exit(void)
-{
- isdn_net_lib_exit();
-}
-
diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
index 14f94befc91f..049f2aa3059c 100644
--- a/drivers/isdn/i4l/isdn_net.h
+++ b/drivers/isdn/i4l/isdn_net.h
@@ -1,83 +1,15 @@
-/* $Id: isdn_net.h,v 1.19.6.4 2001/09/28 08:05:29 kai Exp $
- *
- * header for Linux ISDN subsystem, network related functions (linklevel).
+/* Linux ISDN subsystem, network related functions
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/isdn.h>
-
-void isdn_net_init(void);
-void isdn_net_exit(void);
-void isdn_net_lib_init(void);
-void isdn_net_lib_exit(void);
-void isdn_net_hangup_all(void);
-int isdn_net_ioctl(struct inode *, struct file *, uint, ulong);
-
-int register_isdn_netif(int encap, struct isdn_netif_ops *ops);
-int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev);
-void isdn_net_online(isdn_net_dev *idev);
-void isdn_net_offline(isdn_net_dev *idev);
-
-int isdn_net_stat_callback(int, isdn_ctrl *);
-int isdn_net_find_icall(int, int, int, setup_parm *);
-int isdn_net_rcv_skb(int, struct sk_buff *);
-
-int isdn_net_hangup(isdn_net_dev *);
-int isdn_net_dial_req(isdn_net_dev *);
-void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
-void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb);
-int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev);
-isdn_net_dev *isdn_net_get_xmit_dev(isdn_net_local *mlp);
-
-static inline int
-put_u8(unsigned char *p, u8 x)
-{
- *p = x;
- return 1;
-}
-
-static inline int
-put_u16(unsigned char *p, u16 x)
-{
- *((u16 *)p) = htons(x);
- return 2;
-}
-
-static inline int
-put_u32(unsigned char *p, u32 x)
-{
- *((u32 *)p) = htonl(x);
- return 4;
-}
-
-static inline int
-get_u8(unsigned char *p, u8 *x)
-{
- *x = *p;
- return 1;
-}
-
-static inline int
-get_u16(unsigned char *p, u16 *x)
-{
- *x = ntohs(*((u16 *)p));
- return 2;
-}
-
-static inline int
-get_u32(unsigned char *p, u32 *x)
-{
- *x = ntohl(*((u32 *)p));
- return 4;
-}
-
-
+extern struct isdn_netif_ops isdn_iptyp_ops;
+extern struct isdn_netif_ops isdn_uihdlc_ops;
+extern struct isdn_netif_ops isdn_rawip_ops;
+extern struct isdn_netif_ops isdn_ether_ops;
diff --git a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c
index ba0144200c1f..f5dc1e8ddd95 100644
--- a/drivers/isdn/i4l/isdn_net_lib.c
+++ b/drivers/isdn/i4l/isdn_net_lib.c
@@ -1,5 +1,4 @@
-/*
- * Linux ISDN subsystem, Network interface configuration
+/* Linux ISDN subsystem, network interface support code
*
* Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
* 1995,96 by Thinking Objects Software GmbH Wuerzburg
@@ -10,6 +9,17 @@
* of the GNU General Public License, incorporated herein by reference.
*/
+/*
+ * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02
+ * guy@traverse.com.au
+ * Outgoing calls - looks for a 'V' in first char of dialed number
+ * Incoming calls - checks first character of eaz as follows:
+ * Numeric - accept DATA only - original functionality
+ * 'V' - accept VOICE (DOV) only
+ * 'B' - accept BOTH DATA and DOV types
+ *
+ */
+
/* Locking works as follows:
*
* The configuration of isdn_net_devs works via ioctl on
@@ -44,9 +54,10 @@
#include <linux/capability.h>
#include <linux/rtnetlink.h>
#include "isdn_common.h"
+#include "isdn_net_lib.h"
#include "isdn_net.h"
#include "isdn_ppp.h"
-#include "isdn_fsm.h"
+#include "isdn_ciscohdlck.h"
#define ISDN_NET_TX_TIMEOUT (20*HZ)
@@ -117,21 +128,21 @@ static char *isdn_net_st_str[] = {
};
enum {
- EV_TIMER_INCOMING,
- EV_TIMER_DIAL,
- EV_TIMER_DIAL_WAIT,
- EV_TIMER_CB_OUT,
- EV_TIMER_CB_IN,
- EV_TIMER_HUP,
- EV_STAT_DCONN,
- EV_STAT_BCONN,
- EV_STAT_DHUP,
- EV_STAT_BHUP,
- EV_STAT_CINF,
- EV_STAT_BSENT,
- EV_DO_DIAL,
- EV_DO_CALLBACK,
- EV_DO_ACCEPT,
+ EV_NET_TIMER_INCOMING,
+ EV_NET_TIMER_DIAL,
+ EV_NET_TIMER_DIAL_WAIT,
+ EV_NET_TIMER_CB_OUT,
+ EV_NET_TIMER_CB_IN,
+ EV_NET_TIMER_HUP,
+ EV_NET_STAT_DCONN,
+ EV_NET_STAT_BCONN,
+ EV_NET_STAT_DHUP,
+ EV_NET_STAT_BHUP,
+ EV_NET_STAT_CINF,
+ EV_NET_STAT_BSENT,
+ EV_NET_DO_DIAL,
+ EV_NET_DO_CALLBACK,
+ EV_NET_DO_ACCEPT,
};
static char *isdn_net_ev_str[] = {
@@ -141,15 +152,15 @@ static char *isdn_net_ev_str[] = {
"EV_NET_TIMER_CB_OUT",
"EV_NET_TIMER_CB_IN",
"EV_NET_TIMER_HUP",
- "EV_STAT_DCONN",
- "EV_STAT_BCONN",
- "EV_STAT_DHUP",
- "EV_STAT_BHUP",
- "EV_STAT_CINF",
- "EV_STAT_BSENT",
- "EV_DO_DIAL",
- "EV_DO_CALLBACK",
- "EV_DO_ACCEPT",
+ "EV_NET_STAT_DCONN",
+ "EV_NET_STAT_BCONN",
+ "EV_NET_STAT_DHUP",
+ "EV_NET_STAT_BHUP",
+ "EV_NET_STAT_CINF",
+ "EV_NET_STAT_BSENT",
+ "EV_NET_DO_DIAL",
+ "EV_NET_DO_CALLBACK",
+ "EV_NET_DO_ACCEPT",
};
/* Definitions for hupflags: */
@@ -253,7 +264,7 @@ static int
isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
{
isdn_net_local *mlp = idev->mlp;
- int i, retval;
+ int retval;
int drvidx = -1;
int chidx = -1;
char drvid[25];
@@ -276,35 +287,28 @@ isdn_net_bind(isdn_net_dev *idev, isdn_net_ioctl_cfg *cfg)
/* The channel-number is appended to the driver-Id with a comma */
*c = 0;
chidx = simple_strtol(c + 1, NULL, 10);
-
- for (i = 0; i < ISDN_MAX_DRIVERS; i++) {
- /* Lookup driver-Id in array */
- if (!strcmp(dev->drvid[i], drvid)) {
- drvidx = i;
- break;
- }
- }
+ drvidx = isdn_drv_lookup(drvid);
if (drvidx == -1 || chidx == -1) {
/* Either driver-Id or channel-number invalid */
retval = -ENODEV;
goto out;
}
}
- if (cfg->exclusive == (idev->exclusive >= 0) &&
+ if (cfg->exclusive == !!idev->exclusive &&
drvidx == idev->pre_device && chidx == idev->pre_channel) {
/* no change */
retval = 0;
goto out;
}
- if (idev->exclusive >= 0) {
+ if (idev->exclusive) {
isdn_slot_free(idev->exclusive);
- idev->exclusive = -1;
+ idev->exclusive = NULL;
}
if (cfg->exclusive) {
/* If binding is exclusive, try to grab the channel */
idev->exclusive = isdn_get_free_slot(ISDN_USAGE_NET | ISDN_USAGE_EXCLUSIVE,
mlp->l2_proto, mlp->l3_proto, drvidx, chidx, cfg->eaz);
- if (idev->exclusive < 0) {
+ if (!idev->exclusive) {
/* Grab failed, because desired channel is in use */
retval = -EBUSY;
goto out;
@@ -364,12 +368,11 @@ isdn_net_addif(char *name, isdn_net_local *mlp)
tasklet_init(&idev->tlet, isdn_net_tasklet, (unsigned long) idev);
skb_queue_head_init(&idev->super_tx_queue);
- idev->isdn_slot = -1;
+ idev->isdn_slot = NULL;
idev->pre_device = -1;
idev->pre_channel = -1;
- idev->exclusive = -1;
+ idev->exclusive = NULL;
- idev->ipppd = NULL;
idev->pppbind = -1;
init_timer(&idev->dial_timer);
@@ -405,7 +408,7 @@ isdn_net_addif(char *name, isdn_net_local *mlp)
mlp->hupflags = ISDN_INHUP;
mlp->onhtime = 10;
mlp->dialmax = 1;
- mlp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
+ mlp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL | ISDN_NET_SECURE;
mlp->cbdelay = 5 * HZ; /* Wait 5 secs before call-back */
mlp->dialtimeout = 60 * HZ;/* Wait 1 min for connection */
mlp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
@@ -459,11 +462,12 @@ isdn_net_addslave(char *parm)
rtnl_lock();
- if (netif_running(&mlp->dev))
- return -EBUSY;
-
+ if (netif_running(&mlp->dev)) {
+ retval = -EBUSY;
+ goto out;
+ }
retval = isdn_net_addif(p, mlp);
-
+ out:
rtnl_unlock();
return retval;
}
@@ -535,8 +539,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
{
isdn_net_dev *idev = isdn_net_findif(cfg->name);
isdn_net_local *mlp;
- ulong features;
- int i, retval;
+ int retval;
if (!idev)
return -ENODEV;
@@ -549,19 +552,6 @@ isdn_net_setcfg(isdn_net_ioctl_cfg *cfg)
retval = -EBUSY;
goto out;
}
- /* See if any registered driver supports the features we want */
- features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) |
- ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT);
- for (i = 0; i < ISDN_MAX_DRIVERS; i++)
- if (dev->drv[i] &&
- (dev->drv[i]->interface->features & features) == features)
- break;
-
- if (i == ISDN_MAX_DRIVERS) {
- printk(KERN_WARNING "isdn_net: No driver with selected features\n");
- retval = -ENODEV;
- goto out;
- }
retval = isdn_net_set_encap(mlp, cfg->p_encap);
if (retval)
@@ -653,9 +643,9 @@ isdn_net_getcfg(isdn_net_ioctl_cfg *cfg)
mlp = idev->mlp;
strcpy(cfg->eaz, mlp->msn);
- cfg->exclusive = idev->exclusive >= 0;
+ cfg->exclusive = !!idev->exclusive;
if (idev->pre_device >= 0) {
- sprintf(cfg->drvid, "%s,%d", dev->drvid[idev->pre_device],
+ sprintf(cfg->drvid, "%s,%d", isdn_drv_drvid(idev->pre_device),
idev->pre_channel);
} else {
cfg->drvid[0] = '\0';
@@ -814,6 +804,29 @@ isdn_net_dial_out(char *name)
return isdn_net_dial(idev);
}
+static int
+__isdn_net_dial_slave(isdn_net_local *mlp)
+{
+ isdn_net_dev *idev;
+
+ list_for_each_entry(idev, &mlp->slaves, slaves) {
+ if (isdn_net_dial(idev) == 0)
+ return 0;
+ }
+ return -EBUSY;
+}
+
+static int
+isdn_net_dial_slave(char *name)
+{
+ isdn_net_dev *idev = isdn_net_findif(name);
+
+ if (!idev)
+ return -ENODEV;
+
+ return __isdn_net_dial_slave(idev->mlp);
+}
+
/*
* Force a hangup of a network-interface.
*/
@@ -840,25 +853,18 @@ static int
isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone *peer)
{
isdn_net_dev *idev = isdn_net_findif(phone->name);
- int idx;
+ struct isdn_slot *slot;
if (!idev)
return -ENODEV;
- /* FIXME
- * Theoretical race: while this executes, the remote number might
- * become invalid (hang up) or change (new connection), resulting
- * in (partially) wrong number copied to user. This race
- * currently ignored.
- */
- idx = idev->isdn_slot;
- if (idx < 0)
- return -ENOTCONN;
- /* for pre-bound channels, we need this extra check */
- if (strncmp(isdn_slot_num(idx), "???", 3) == 0 )
+
+ if (idev->fi.state != ST_ACTIVE)
return -ENOTCONN;
- strncpy(phone->phone, isdn_slot_num(idx), ISDN_MSNLEN);
- phone->outgoing = USG_OUTGOING(isdn_slot_usage(idx));
+ slot = idev->isdn_slot;
+
+ strncpy(phone->phone, slot->num, ISDN_MSNLEN);
+ phone->outgoing = USG_OUTGOING(slot->usage);
if (copy_to_user(peer, phone, sizeof(*peer)))
return -EFAULT;
@@ -972,22 +978,20 @@ isdn_net_ioctl(struct inode *ino, struct file *file, uint cmd, ulong arg)
}
retval = isdn_net_getpeer(&phone, (isdn_net_ioctl_phone *) arg);
break;
-#ifdef CONFIG_ISDN_PPP
case IIOCNETALN: /* Add link */
if (copy_from_user(name, (char *) arg, sizeof(name))) {
retval = -EFAULT;
break;
}
- retval = isdn_ppp_dial_slave(name);
+ retval = isdn_net_dial_slave(name);
break;
case IIOCNETDLN: /* Delete link */
if (copy_from_user(name, (char *) arg, sizeof(name))) {
retval = -EFAULT;
break;
}
- retval = isdn_ppp_hangup_slave(name);
+ retval = isdn_net_force_hangup(name);
break;
-#endif
default:
retval = -ENOTTY;
}
@@ -1191,14 +1195,15 @@ isdn_net_unbind_channel(isdn_net_dev *idev)
if (mlp->ops->unbind)
mlp->ops->unbind(idev);
- isdn_slot_set_idev(idev->isdn_slot, NULL);
+ idev->isdn_slot->priv = NULL;
+ idev->isdn_slot->event_cb = NULL;
skb_queue_purge(&idev->super_tx_queue);
if (idev->isdn_slot != idev->exclusive)
isdn_slot_free(idev->isdn_slot);
- idev->isdn_slot = -1;
+ idev->isdn_slot = NULL;
if (idev->fi.state != ST_NULL) {
lp_put(mlp);
@@ -1206,24 +1211,29 @@ isdn_net_unbind_channel(isdn_net_dev *idev)
}
}
+static int isdn_net_event_callback(struct isdn_slot *slot, int pr, void *arg);
+
/*
* Assign an ISDN-channel to a net-interface
*/
static int
-isdn_net_bind_channel(isdn_net_dev *idev, int slot)
+isdn_net_bind_channel(isdn_net_dev *idev, struct isdn_slot *slot)
{
isdn_net_local *mlp = idev->mlp;
int retval = 0;
- idev->isdn_slot = slot;
- isdn_slot_set_idev(idev->isdn_slot, idev);
-
if (mlp->ops->bind)
retval = mlp->ops->bind(idev);
if (retval < 0)
- isdn_net_unbind_channel(idev);
+ goto out;
+
+ idev->isdn_slot = slot;
+ slot->priv = idev;
+ slot->event_cb = isdn_net_event_callback;
+ slot->usage |= ISDN_USAGE_NET;
+ out:
return retval;
}
@@ -1233,7 +1243,7 @@ isdn_net_dial(isdn_net_dev *idev)
int retval;
lp_get(idev->mlp);
- retval = fsm_event(&idev->fi, EV_DO_DIAL, NULL);
+ retval = fsm_event(&idev->fi, EV_NET_DO_DIAL, NULL);
if (retval == -ESRCH) /* event not handled in this state */
retval = -EBUSY;
@@ -1348,29 +1358,13 @@ isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev)
return 0;
}
-
-static void
-isdn_net_dial_slave(isdn_net_local *mlp)
-{
- isdn_net_dev *idev;
-
- if (ISDN_NET_DIALMODE(*mlp) != ISDN_NET_DM_AUTO)
- return;
-
- list_for_each_entry(idev, &mlp->slaves, slaves) {
- if (fsm_event(&idev->fi, EV_DO_DIAL, NULL) != -ESRCH) {
- break;
- }
- }
-}
-
static int
accept_icall(struct fsm_inst *fi, int pr, void *arg)
{
isdn_net_dev *idev = fi->userdata;
isdn_net_local *mlp = idev->mlp;
isdn_ctrl cmd;
- int slot = (int) arg;
+ struct isdn_slot *slot = arg;
isdn_net_bind_channel(idev, slot);
@@ -1383,9 +1377,10 @@ accept_icall(struct fsm_inst *fi, int pr, void *arg)
isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL2, &cmd);
cmd.arg = mlp->l3_proto << 8;
isdn_slot_command(idev->isdn_slot, ISDN_CMD_SETL3, &cmd);
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_ACCEPTD, &cmd);
idev->dial_timer.expires = jiffies + mlp->dialtimeout;
- idev->dial_event = EV_TIMER_INCOMING;
+ idev->dial_event = EV_NET_TIMER_INCOMING;
add_timer(&idev->dial_timer);
fsm_change_state(&idev->fi, ST_IN_WAIT_DCONN);
return 0;
@@ -1400,7 +1395,7 @@ do_callback(struct fsm_inst *fi, int pr, void *arg)
printk(KERN_DEBUG "%s: start callback\n", idev->name);
idev->dial_timer.expires = jiffies + mlp->cbdelay;
- idev->dial_event = EV_TIMER_CB_IN;
+ idev->dial_event = EV_NET_TIMER_CB_IN;
add_timer(&idev->dial_timer);
fsm_change_state(&idev->fi, ST_WAIT_BEFORE_CB);
@@ -1408,12 +1403,11 @@ do_callback(struct fsm_inst *fi, int pr, void *arg)
}
static int
-isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
- char *eaz, char *nr)
+isdn_net_dev_icall(isdn_net_dev *idev, struct isdn_slot *slot,
+ int si1, char *eaz, char *nr)
{
isdn_net_local *mlp = idev->mlp;
struct isdn_net_phone *ph;
- int slot = isdn_dc2minor(di, ch);
char *my_eaz;
/* check acceptable call types for DOV */
@@ -1431,9 +1425,6 @@ isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
if (*my_eaz == 'b' || *my_eaz == 'B')
my_eaz++; /* skip to allow a match */
}
- if (!USG_NONE(isdn_slot_usage(slot))) // FIXME?
- return 0;
-
/* check called number */
switch (isdn_msncmp(eaz, my_eaz)) {
case 1: /* no match */
@@ -1443,11 +1434,11 @@ isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
}
dbg_net_icall("%s: pdev=%d di=%d pch=%d ch = %d\n", idev->name,
- idev->pre_device, di, idev->pre_channel, ch);
+ idev->pre_device, slot->di, idev->pre_channel, slot->ch);
/* check if exclusive */
- if ((isdn_slot_usage(slot) & ISDN_USAGE_EXCLUSIVE) &&
- (idev->pre_channel != ch || idev->pre_device != di)) {
+ if ((slot->usage & ISDN_USAGE_EXCLUSIVE) &&
+ (idev->pre_channel != slot->ch || idev->pre_device != slot->di)) {
dbg_net_icall("%s: excl check failed\n", idev->name);
return 0;
}
@@ -1471,7 +1462,7 @@ isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
lp_get(mlp);
/* check callback */
if (mlp->flags & ISDN_NET_CALLBACK) {
- if (fsm_event(&idev->fi, EV_DO_CALLBACK, NULL)) {
+ if (fsm_event(&idev->fi, EV_NET_DO_CALLBACK, NULL)) {
lp_put(mlp);
return 0;
}
@@ -1481,7 +1472,7 @@ isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
printk(KERN_INFO "%s: call from %s -> %s accepted\n",
idev->name, nr, eaz);
- if (fsm_event(&idev->fi, EV_DO_ACCEPT, (void *) slot)) {
+ if (fsm_event(&idev->fi, EV_NET_DO_ACCEPT, slot)) {
lp_put(mlp);
return 0;
}
@@ -1505,7 +1496,7 @@ isdn_net_dev_icall(isdn_net_dev *idev, int di, int ch, int si1,
* would eventually match if CID was longer.
*/
int
-isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
+isdn_net_find_icall(struct isdn_slot *slot, setup_parm *setup)
{
isdn_net_local *lp;
isdn_net_dev *idev;
@@ -1545,8 +1536,8 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
return 0;
}
- dbg_net_icall("n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
- isdn_slot_usage(idx));
+ dbg_net_icall("n_fi: di=%d ch=%d usg=%#x\n", slot->di, slot->ch,
+ slot->usage);
retval = 0;
spin_lock_irqsave(&running_devs_lock, flags);
@@ -1555,7 +1546,7 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup)
spin_unlock_irqrestore(&running_devs_lock, flags);
list_for_each_entry(idev, &lp->slaves, slaves) {
- retval = isdn_net_dev_icall(idev, di, ch, si1, eaz, nr);
+ retval = isdn_net_dev_icall(idev, slot, si1, eaz, nr);
if (retval > 0)
break;
}
@@ -1604,7 +1595,7 @@ do_dial(struct fsm_inst *fi, int pr, void *arg)
{
isdn_net_dev *idev = fi->userdata;
isdn_net_local *mlp = idev->mlp;
- int slot;
+ struct isdn_slot *slot;
if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_OFF)
return -EPERM;
@@ -1612,13 +1603,13 @@ do_dial(struct fsm_inst *fi, int pr, void *arg)
if (list_empty(&mlp->phone[1])) /* no number to dial ? */
return -EINVAL;
- if (idev->exclusive >= 0)
+ if (idev->exclusive)
slot = idev->exclusive;
else
slot = isdn_get_free_slot(ISDN_USAGE_NET, mlp->l2_proto,
mlp->l3_proto, idev->pre_device,
idev->pre_channel, mlp->msn);
- if (slot < 0)
+ if (!slot)
return -EAGAIN;
if (isdn_net_bind_channel(idev, slot) < 0) {
@@ -1663,10 +1654,10 @@ dialout_next(struct fsm_inst *fi, int pr, void *arg)
/* For outgoing callback, use cbdelay instead of dialtimeout */
if (mlp->cbdelay && (mlp->flags & ISDN_NET_CBOUT)) {
idev->dial_timer.expires = jiffies + mlp->cbdelay;
- idev->dial_event = EV_TIMER_CB_OUT;
+ idev->dial_event = EV_NET_TIMER_CB_OUT;
} else {
idev->dial_timer.expires = jiffies + mlp->dialtimeout;
- idev->dial_event = EV_TIMER_DIAL;
+ idev->dial_event = EV_NET_TIMER_DIAL;
}
fsm_change_state(&idev->fi, ST_OUT_WAIT_DCONN);
add_timer(&idev->dial_timer);
@@ -1699,7 +1690,7 @@ dial_timeout(struct fsm_inst *fi, int pr, void *arg)
isdn_net_hangup(idev);
return 0;
}
- idev->dial_event = EV_TIMER_DIAL_WAIT;
+ idev->dial_event = EV_NET_TIMER_DIAL_WAIT;
mod_timer(&idev->dial_timer, jiffies + mlp->dialwait);
return 0;
}
@@ -1710,7 +1701,6 @@ connect_fail(struct fsm_inst *fi, int pr, void *arg)
isdn_net_dev *idev = fi->userdata;
del_timer(&idev->dial_timer);
- isdn_slot_all_eaz(idev->isdn_slot);
printk(KERN_INFO "%s: connection failed\n", idev->name);
isdn_net_unbind_channel(idev);
return 0;
@@ -1748,7 +1738,7 @@ bconn(struct fsm_inst *fi, int pr, void *arg)
if (mlp->onhtime) {
idev->huptimer = 0;
- idev->dial_event = EV_TIMER_HUP;
+ idev->dial_event = EV_NET_TIMER_HUP;
mod_timer(&idev->dial_timer, jiffies + HZ);
} else {
del_timer(&idev->dial_timer);
@@ -1794,7 +1784,6 @@ dhup(struct fsm_inst *fi, int pr, void *arg)
isdn_net_dev *idev = fi->userdata;
printk(KERN_INFO "%s: Chargesum is %d\n", idev->name, idev->charge);
- isdn_slot_all_eaz(idev->isdn_slot);
isdn_net_unbind_channel(idev);
return 0;
}
@@ -1862,39 +1851,45 @@ isdn_net_hangup(isdn_net_dev *idev)
del_timer(&idev->dial_timer);
printk(KERN_INFO "%s: local hangup\n", idev->name);
- isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
+ // FIXME via state machine
+ if (idev->isdn_slot)
+ isdn_slot_command(idev->isdn_slot, ISDN_CMD_HANGUP, &cmd);
return 1;
}
+static int isdn_net_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb);
+
/*
* Handle status-messages from ISDN-interfacecard.
* This function is called from within the main-status-dispatcher
* isdn_status_callback, which itself is called from the low-level driver.
- * Return: 1 = event handled, 0 = not handled
*/
-int
-isdn_net_stat_callback(int idx, isdn_ctrl *c)
+static int
+isdn_net_event_callback(struct isdn_slot *slot, int pr, void *arg)
{
- isdn_net_dev *idev = isdn_slot_idev(idx);
+ isdn_net_dev *idev = slot->priv;
if (!idev) {
+ isdn_BUG();
return 0;
}
- switch (c->command) {
- case ISDN_STAT_DCONN:
- return fsm_event(&idev->fi, EV_STAT_DCONN, c);
- case ISDN_STAT_BCONN:
- return fsm_event(&idev->fi, EV_STAT_BCONN, c);
- case ISDN_STAT_BHUP:
- return fsm_event(&idev->fi, EV_STAT_BHUP, c);
- case ISDN_STAT_DHUP:
- return fsm_event(&idev->fi, EV_STAT_DHUP, c);
- case ISDN_STAT_CINF:
- return fsm_event(&idev->fi, EV_STAT_CINF, c);
- case ISDN_STAT_BSENT:
- return fsm_event(&idev->fi, EV_STAT_BSENT, c);
+ switch (pr) {
+ case EV_DATA_IND:
+ return isdn_net_rcv_skb(slot, arg);
+ case EV_STAT_DCONN:
+ return fsm_event(&idev->fi, EV_NET_STAT_DCONN, arg);
+ case EV_STAT_BCONN:
+ return fsm_event(&idev->fi, EV_NET_STAT_BCONN, arg);
+ case EV_STAT_BHUP:
+ return fsm_event(&idev->fi, EV_NET_STAT_BHUP, arg);
+ case EV_STAT_DHUP:
+ return fsm_event(&idev->fi, EV_NET_STAT_DHUP, arg);
+ case EV_STAT_CINF:
+ return fsm_event(&idev->fi, EV_NET_STAT_CINF, arg);
+ case EV_STAT_BSENT:
+ return fsm_event(&idev->fi, EV_NET_STAT_BSENT, arg);
default:
- printk("unknown stat %d\n", c->command);
+ printk("unknown pr %d\n", pr);
return 0;
}
}
@@ -1925,37 +1920,37 @@ got_bsent(struct fsm_inst *fi, int pr, void *arg)
}
static struct fsm_node isdn_net_fn_tbl[] = {
- { ST_NULL, EV_DO_DIAL, do_dial },
- { ST_NULL, EV_DO_ACCEPT, accept_icall },
- { ST_NULL, EV_DO_CALLBACK, do_callback },
+ { ST_NULL, EV_NET_DO_DIAL, do_dial },
+ { ST_NULL, EV_NET_DO_ACCEPT, accept_icall },
+ { ST_NULL, EV_NET_DO_CALLBACK, do_callback },
- { ST_OUT_WAIT_DCONN, EV_TIMER_DIAL, dial_timeout },
- { ST_OUT_WAIT_DCONN, EV_STAT_DCONN, out_dconn },
- { ST_OUT_WAIT_DCONN, EV_STAT_DHUP, connect_fail },
- { ST_OUT_WAIT_DCONN, EV_TIMER_CB_OUT, hang_up },
+ { ST_OUT_WAIT_DCONN, EV_NET_TIMER_DIAL, dial_timeout },
+ { ST_OUT_WAIT_DCONN, EV_NET_STAT_DCONN, out_dconn },
+ { ST_OUT_WAIT_DCONN, EV_NET_STAT_DHUP, connect_fail },
+ { ST_OUT_WAIT_DCONN, EV_NET_TIMER_CB_OUT, hang_up },
- { ST_OUT_WAIT_BCONN, EV_TIMER_DIAL, dial_timeout },
- { ST_OUT_WAIT_BCONN, EV_STAT_BCONN, bconn },
- { ST_OUT_WAIT_BCONN, EV_STAT_DHUP, connect_fail },
+ { ST_OUT_WAIT_BCONN, EV_NET_TIMER_DIAL, dial_timeout },
+ { ST_OUT_WAIT_BCONN, EV_NET_STAT_BCONN, bconn },
+ { ST_OUT_WAIT_BCONN, EV_NET_STAT_DHUP, connect_fail },
- { ST_IN_WAIT_DCONN, EV_TIMER_INCOMING, hang_up },
- { ST_IN_WAIT_DCONN, EV_STAT_DCONN, in_dconn },
- { ST_IN_WAIT_DCONN, EV_STAT_DHUP, connect_fail },
+ { ST_IN_WAIT_DCONN, EV_NET_TIMER_INCOMING, hang_up },
+ { ST_IN_WAIT_DCONN, EV_NET_STAT_DCONN, in_dconn },
+ { ST_IN_WAIT_DCONN, EV_NET_STAT_DHUP, connect_fail },
- { ST_IN_WAIT_BCONN, EV_TIMER_INCOMING, hang_up },
- { ST_IN_WAIT_BCONN, EV_STAT_BCONN, bconn },
- { ST_IN_WAIT_BCONN, EV_STAT_DHUP, connect_fail },
+ { ST_IN_WAIT_BCONN, EV_NET_TIMER_INCOMING, hang_up },
+ { ST_IN_WAIT_BCONN, EV_NET_STAT_BCONN, bconn },
+ { ST_IN_WAIT_BCONN, EV_NET_STAT_DHUP, connect_fail },
- { ST_ACTIVE, EV_TIMER_HUP, check_hup },
- { ST_ACTIVE, EV_STAT_BHUP, bhup },
- { ST_ACTIVE, EV_STAT_CINF, got_cinf },
- { ST_ACTIVE, EV_STAT_BSENT, got_bsent },
+ { ST_ACTIVE, EV_NET_TIMER_HUP, check_hup },
+ { ST_ACTIVE, EV_NET_STAT_BHUP, bhup },
+ { ST_ACTIVE, EV_NET_STAT_CINF, got_cinf },
+ { ST_ACTIVE, EV_NET_STAT_BSENT, got_bsent },
- { ST_WAIT_DHUP, EV_STAT_DHUP, dhup },
+ { ST_WAIT_DHUP, EV_NET_STAT_DHUP, dhup },
- { ST_WAIT_BEFORE_CB, EV_TIMER_CB_IN, do_dial },
+ { ST_WAIT_BEFORE_CB, EV_NET_TIMER_CB_IN, do_dial },
- { ST_OUT_DIAL_WAIT, EV_TIMER_DIAL_WAIT, dialout_next },
+ { ST_OUT_DIAL_WAIT, EV_NET_TIMER_DIAL_WAIT, dialout_next },
};
static struct fsm isdn_net_fsm = {
@@ -2224,7 +2219,8 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} else {
/* subsequent overload: if slavedelay exceeded, start dialing */
if (time_after(jiffies, idev->sqfull_stamp + mlp->slavedelay)) {
- isdn_net_dial_slave(mlp);
+ if (ISDN_NET_DIALMODE(*mlp) == ISDN_NET_DM_AUTO)
+ __isdn_net_dial_slave(mlp);
}
}
} else {
@@ -2267,10 +2263,10 @@ isdn_net_write_super(isdn_net_dev *idev, struct sk_buff *skb)
* interface. If found, deliver packet to receiver-function and return 1,
* else return 0.
*/
-int
-isdn_net_rcv_skb(int idx, struct sk_buff *skb)
+static int
+isdn_net_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb)
{
- isdn_net_dev *idev = isdn_slot_idev(idx);
+ isdn_net_dev *idev = slot->priv;
isdn_net_local *mlp;
if (!idev) {
@@ -2297,6 +2293,20 @@ isdn_net_rcv_skb(int idx, struct sk_buff *skb)
return 1;
}
+/*
+ * After handling connection-type specific stuff, the receiver function
+ * can use this function to pass the skb on to the network layer.
+ */
+void
+isdn_netif_rx(isdn_net_dev *idev, struct sk_buff *skb, u16 protocol)
+{
+ idev->huptimer = 0;
+
+ skb->protocol = protocol;
+ skb->dev = &idev->mlp->dev;
+ netif_rx(skb);
+}
+
/* ====================================================================== */
/* init / exit */
/* ====================================================================== */
@@ -2305,12 +2315,27 @@ void
isdn_net_lib_init(void)
{
fsm_new(&isdn_net_fsm);
+
+#ifdef CONFIG_ISDN_NET_SIMPLE
+ register_isdn_netif(ISDN_NET_ENCAP_ETHER, &isdn_ether_ops);
+ register_isdn_netif(ISDN_NET_ENCAP_RAWIP, &isdn_rawip_ops);
+ register_isdn_netif(ISDN_NET_ENCAP_IPTYP, &isdn_iptyp_ops);
+ register_isdn_netif(ISDN_NET_ENCAP_UIHDLC, &isdn_uihdlc_ops);
+#endif
+#ifdef CONFIG_ISDN_NET_CISCO
+ register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLC, &isdn_ciscohdlck_ops);
+ register_isdn_netif(ISDN_NET_ENCAP_CISCOHDLCK, &isdn_ciscohdlck_ops);
+#endif
+#ifdef CONFIG_ISDN_X25
+ register_isdn_netif(ISDN_NET_ENCAP_X25IFACE, &isdn_x25_ops);
+#endif
+#ifdef CONFIG_ISDN_PPP
+ register_isdn_netif(ISDN_NET_ENCAP_SYNCPPP, &isdn_ppp_ops);
+#endif
}
void
isdn_net_lib_exit(void)
{
- isdn_net_cleanup();
-
fsm_free(&isdn_net_fsm);
}
diff --git a/drivers/isdn/i4l/isdn_net_lib.h b/drivers/isdn/i4l/isdn_net_lib.h
new file mode 100644
index 000000000000..0258036dc0fb
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_net_lib.h
@@ -0,0 +1,224 @@
+/* Linux ISDN subsystem, network interface support code
+ *
+ * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __ISDN_NET_LIB_H__
+#define __ISDN_NET_LIB_H__
+
+#include <linux/isdn.h>
+
+typedef struct isdn_net_local_s isdn_net_local;
+typedef struct isdn_net_dev_s isdn_net_dev;
+
+struct isdn_netif_ops {
+ int (*hard_start_xmit) (struct sk_buff *skb,
+ struct net_device *dev);
+ int (*hard_header) (struct sk_buff *skb,
+ struct net_device *dev,
+ unsigned short type,
+ void *daddr,
+ void *saddr,
+ unsigned len);
+ int (*do_ioctl)(struct net_device *dev,
+ struct ifreq *ifr, int cmd);
+
+ unsigned short flags; /* interface flags (a la BSD) */
+ unsigned short type; /* interface hardware type */
+ unsigned char addr_len;/* hardware address length */
+ void (*receive)(struct isdn_net_local_s *,
+ struct isdn_net_dev_s *,
+ struct sk_buff *);
+ void (*connected)(struct isdn_net_dev_s *);
+ void (*disconnected)(struct isdn_net_dev_s *);
+ int (*bind)(struct isdn_net_dev_s *);
+ void (*unbind)(struct isdn_net_dev_s *);
+ int (*init)(struct isdn_net_local_s *);
+ void (*cleanup)(struct isdn_net_local_s *);
+ int (*open)(struct isdn_net_local_s *);
+ void (*close)(struct isdn_net_local_s *);
+};
+
+/* our interface to isdn_common.c */
+void isdn_net_lib_init(void);
+void isdn_net_lib_exit(void);
+void isdn_net_hangup_all(void);
+int isdn_net_ioctl(struct inode *, struct file *, uint, ulong);
+int isdn_net_find_icall(struct isdn_slot *slot, setup_parm *setup);
+
+/* provided for interface types to use */
+void isdn_net_writebuf_skb(isdn_net_dev *, struct sk_buff *skb);
+void isdn_net_write_super(isdn_net_dev *, struct sk_buff *skb);
+void isdn_net_online(isdn_net_dev *idev);
+void isdn_net_offline(isdn_net_dev *idev);
+int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev);
+void isdn_netif_rx(isdn_net_dev *idev, struct sk_buff *skb, u16 protocol);
+isdn_net_dev *isdn_net_get_xmit_dev(isdn_net_local *mlp);
+int isdn_net_hangup(isdn_net_dev *);
+int isdn_net_autodial(struct sk_buff *skb, struct net_device *ndev);
+int isdn_net_dial_req(isdn_net_dev *);
+int register_isdn_netif(int encap, struct isdn_netif_ops *ops);
+
+/* ====================================================================== */
+
+/* Feature- and status-flags for a net-interface */
+#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */
+#define ISDN_NET_CALLBACK 0x04 /* activate callback */
+#define ISDN_NET_CBHUP 0x08 /* hangup before callback */
+#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */
+
+#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */
+
+/* Phone-list-element */
+struct isdn_net_phone {
+ struct list_head list;
+ char num[ISDN_MSNLEN];
+};
+
+/* per network interface data (dev->priv) */
+
+struct isdn_net_local_s {
+ ulong magic;
+ struct net_device dev; /* interface to upper levels */
+ struct net_device_stats stats; /* Ethernet Statistics */
+ struct isdn_netif_ops *ops;
+ void *inl_priv; /* interface types can put their
+ private data here */
+ int flags; /* Connection-flags */
+ int dialmax; /* Max. Number of Dial-retries */
+ int dialtimeout; /* How long shall we try on dialing */
+ int dialwait; /* wait after failed attempt */
+
+ int cbdelay; /* Delay before Callback starts */
+ char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
+
+ u_char cbhup; /* Flag: Reject Call before Callback*/
+ int hupflags; /* Flags for charge-unit-hangup: */
+ int onhtime; /* Time to keep link up */
+
+ u_char p_encap; /* Packet encapsulation */
+ u_char l2_proto; /* Layer-2-protocol */
+ u_char l3_proto; /* Layer-3-protocol */
+
+ ulong slavedelay; /* Dynamic bundling delaytime */
+ int triggercps; /* BogoCPS needed for trigger slave */
+ struct list_head phone[2]; /* List of remote-phonenumbers */
+ /* phone[0] = Incoming Numbers */
+ /* phone[1] = Outgoing Numbers */
+
+ struct list_head slaves; /* list of all bundled channels
+ protected by serializing config
+ ioctls / no change allowed when
+ interface is running */
+ struct list_head online; /* list of all bundled channels
+ which can be used for actual
+ data (IP) transfer
+ protected by xmit_lock */
+
+ spinlock_t xmit_lock; /* used to protect the xmit path of
+ a net_device, including all
+ associated channels's frame_cnt */
+ struct list_head running_devs; /* member of global running_devs */
+ atomic_t refcnt; /* references held by ISDN code */
+
+};
+
+
+/* per ISDN channel (ISDN interface) data */
+
+struct isdn_net_dev_s {
+ struct isdn_slot *isdn_slot; /* Index to isdn device/channel */
+ struct isdn_slot *exclusive; /* NULL if non excl */
+ int pre_device; /* Preselected isdn-device */
+ int pre_channel; /* Preselected isdn-channel */
+
+ struct timer_list dial_timer; /* dial events timer */
+ struct fsm_inst fi; /* call control state machine */
+ int dial_event; /* event in case of timer expiry */
+ int dial; /* # of phone number just dialed */
+ int outgoing; /* Flag: outgoing call */
+ int dialretry; /* Counter for Dialout-retries */
+
+ int cps; /* current speed of this interface */
+ int transcount; /* byte-counter for cps-calculation */
+ int last_jiffies; /* when transcount was reset */
+ int sqfull; /* Flag: netdev-queue overloaded */
+ ulong sqfull_stamp; /* Start-Time of overload */
+
+ int huptimer; /* Timeout-counter for auto-hangup */
+ int charge; /* Counter for charging units */
+ int charge_state; /* ChargeInfo state machine */
+ unsigned long chargetime; /* Timer for Charging info */
+ int chargeint; /* Interval between charge-infos */
+
+ int pppbind; /* ippp device for bindings */
+
+ struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
+ /* be transmitted asap */
+ int frame_cnt; /* number of frames currently */
+ /* queued in HL driver */
+ struct tasklet_struct tlet;
+
+ isdn_net_local *mlp; /* Ptr to master device for all devs*/
+
+ struct list_head slaves; /* member of local->slaves */
+ struct list_head online; /* member of local->online */
+
+ char name[10]; /* Name of device */
+ struct list_head global_list; /* global list of all isdn_net_devs */
+ void *ind_priv; /* interface types can put their
+ private data here */
+};
+
+/* ====================================================================== */
+
+static inline int
+put_u8(unsigned char *p, u8 x)
+{
+ *p = x;
+ return 1;
+}
+
+static inline int
+put_u16(unsigned char *p, u16 x)
+{
+ *((u16 *)p) = htons(x);
+ return 2;
+}
+
+static inline int
+put_u32(unsigned char *p, u32 x)
+{
+ *((u32 *)p) = htonl(x);
+ return 4;
+}
+
+static inline int
+get_u8(unsigned char *p, u8 *x)
+{
+ *x = *p;
+ return 1;
+}
+
+static inline int
+get_u16(unsigned char *p, u16 *x)
+{
+ *x = ntohs(*((u16 *)p));
+ return 2;
+}
+
+static inline int
+get_u32(unsigned char *p, u32 *x)
+{
+ *x = ntohl(*((u32 *)p));
+ return 4;
+}
+
+
+#endif
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 13395d86720a..33465ebbaffb 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -1,12 +1,10 @@
-/* $Id: isdn_ppp.c,v 1.85.6.9 2001/11/06 20:58:28 kai Exp $
+/* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
- * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
- *
- * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#include <linux/module.h>
@@ -17,12 +15,15 @@
#include <linux/if_arp.h>
#include "isdn_common.h"
+#include "isdn_net_lib.h"
#include "isdn_ppp.h"
#include "isdn_ppp_ccp.h"
-#include "isdn_net.h"
+#include "isdn_ppp_vj.h"
+#include "isdn_ppp_mp.h"
-static struct sk_buff *
-isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask);
+/* ====================================================================== */
+
+#define IPPP_MAX_RQ_LEN 8 /* max #frames queued for ipppd to read */
static int
isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *);
@@ -42,7 +43,7 @@ isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *);
* idev->ipppd is safe without further locking.
*/
-#define IPPPD_DEBUG
+#undef IPPPD_DEBUG
#ifdef IPPPD_DEBUG
#define ipppd_debug(i, fmt, arg...) \
@@ -211,6 +212,8 @@ static ssize_t
ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
isdn_net_dev *idev;
+ struct inl_ppp *inl_ppp;
+ struct ind_ppp *ind_ppp;
struct ipppd *ipppd;
struct sk_buff *skb;
char *p;
@@ -234,6 +237,8 @@ ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off)
retval = -ENODEV;
goto out;
}
+ ind_ppp = idev->ind_priv;
+ inl_ppp = idev->mlp->inl_priv;
/* Daemon needs to send at least full header, AC + proto */
if (count < 4) {
retval = -EMSGSIZE;
@@ -258,10 +263,10 @@ ipppd_write(struct file *file, const char *buf, size_t count, loff_t *off)
/* Keeps CCP/compression states in sync */
switch (proto) {
case PPP_CCP:
- ippp_ccp_send_ccp(idev->mlp->ccp, skb);
+ ippp_ccp_send_ccp(inl_ppp->ccp, skb);
break;
case PPP_CCPFRAG:
- ippp_ccp_send_ccp(idev->ccp, skb);
+ ippp_ccp_send_ccp(ind_ppp->ccp, skb);
break;
}
/* FIXME: Somewhere we need protection against the
@@ -302,8 +307,6 @@ ipppd_poll(struct file *file, poll_table * wait)
if (!skb_queue_empty(&is->rq) || is->flags & IPPPD_FL_WAKEUP) {
is->flags &= ~IPPPD_FL_WAKEUP;
mask |= POLLIN | POLLRDNORM;
- set_current_state(TASK_INTERRUPTIBLE); // FIXME
- schedule_timeout(HZ);
}
out:
@@ -335,6 +338,8 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
unsigned long arg)
{
isdn_net_dev *idev;
+ struct ind_ppp *ind_ppp = NULL;
+ struct inl_ppp *inl_ppp = NULL;
unsigned long val;
int r;
struct ipppd *is;
@@ -342,28 +347,16 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
unsigned int cfg;
is = file->private_data;
- idev = is->idev;
ipppd_debug(is, "cmd %#x", cmd);
+ // FIXME that needs locking?
+ idev = is->idev;
+ if (idev) {
+ ind_ppp = idev->ind_priv;
+ inl_ppp = idev->mlp->inl_priv;
+ }
switch (cmd) {
- case PPPIOCBUNDLE:
-#ifdef CONFIG_ISDN_MPP
- if (is->state != IPPPD_ST_CONNECTED) {
- r = -EINVAL;
- break;
- }
- r = get_arg(arg, &val, sizeof(val));
- if (r)
- break;
-
- printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n",
- is->minor, is->unit, val);
- r = isdn_ppp_bundle(is, val);
-#else
- r = -EINVAL;
-#endif
- break;
case PPPIOCGUNIT: /* get ppp/isdn unit number */
r = set_arg(arg, &is->unit, sizeof(is->unit));
break;
@@ -376,8 +369,8 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
break;
is->debug = val;
if (idev) {
- idev->debug = val;
- idev->mlp->debug = val;
+ ind_ppp->debug = val;
+ inl_ppp->debug = val;
}
break;
case PPPIOCGCOMPRESSORS:
@@ -401,33 +394,40 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
}
switch (cmd) {
+ case PPPIOCBUNDLE:
+ r = get_arg(arg, &val, sizeof(val));
+ if (r)
+ break;
+
+ r = ippp_mp_bundle(idev, val);
+ break;
case PPPIOCGIFNAME:
r = set_arg(arg, idev->name, strlen(idev->name)+1);
break;
case PPPIOCGMPFLAGS: /* get configuration flags */
- r = set_arg(arg, &idev->mlp->mpppcfg, sizeof(idev->mlp->mpppcfg));
+ r = set_arg(arg, &inl_ppp->mp_cfg, sizeof(inl_ppp->mp_cfg));
break;
case PPPIOCSMPFLAGS: /* set configuration flags */
r = get_arg(arg, &val, sizeof(val));
if (r)
break;
- idev->mlp->mpppcfg = val;
+ inl_ppp->mp_cfg = val;
break;
case PPPIOCGFLAGS: /* get configuration flags */
- cfg = idev->pppcfg | ippp_ccp_get_flags(idev->ccp);
+ cfg = ind_ppp->pppcfg | ippp_ccp_get_flags(ind_ppp->ccp);
r = set_arg(arg, &cfg, sizeof(cfg));
break;
case PPPIOCSFLAGS: /* set configuration flags */
r = get_arg(arg, &val, sizeof(val));
if (r)
break;
- if ((val & SC_ENABLE_IP) && !(idev->pppcfg & SC_ENABLE_IP)) {
- idev->pppcfg = val;
+ if ((val & SC_ENABLE_IP) && !(ind_ppp->pppcfg & SC_ENABLE_IP)) {
+ ind_ppp->pppcfg = val;
/* OK .. we are ready to send buffers */
isdn_net_online(idev);
break;
}
- idev->pppcfg = val;
+ ind_ppp->pppcfg = val;
break;
case PPPIOCGIDLE: /* get idle time information */
{
@@ -440,32 +440,18 @@ ipppd_ioctl(struct inode *ino, struct file *file, unsigned int cmd,
r = get_arg(arg, &val, sizeof(val));
if (r)
break;
- r = ippp_ccp_set_mru(idev->ccp, val);
+ r = ippp_ccp_set_mru(ind_ppp->ccp, val);
break;
case PPPIOCSMPMRU:
break;
case PPPIOCSMPMTU:
break;
-#ifdef CONFIG_ISDN_PPP_VJ
case PPPIOCSMAXCID: /* set the maximum compression slot id */
- {
- struct slcompress *sltmp;
r = get_arg(arg, &val, sizeof(val));
if (r)
break;
- val++;
- sltmp = slhc_init(16, val);
- if (!sltmp) {
- r = -ENOMEM;
- break;
- }
- if (idev->mlp->slcomp)
- slhc_free(idev->mlp->slcomp);
- idev->mlp->slcomp = sltmp;
- r = 0;
+ r = ippp_vj_set_maxcid(idev, val);
break;
- }
-#endif
case PPPIOCSCOMPRESSOR:
r = get_arg(arg, &data, sizeof(data));
if (r)
@@ -563,42 +549,24 @@ ipppd_queue_read(struct ipppd *is, u16 proto, unsigned char *buf, int len)
}
/* ====================================================================== */
+/* interface to isdn_net_lib */
+/* ====================================================================== */
-/* Prototypes */
-static void isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
- struct sk_buff *skb, int proto);
-static int isdn_ppp_if_get_unit(char *namebuf);
-static void
-isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto);
+/* Prototypes */
+static int
+isdn_ppp_if_get_unit(char *namebuf);
static void
-isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb);
+isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb, u16 proto);
static struct sk_buff *
isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask);
-static void
-isdn_ppp_lp_push_header(void *priv, struct sk_buff *skb, u16 proto);
-
/* New CCP stuff */
static void
isdn_ppp_dev_kick_up(void *priv);
-#ifdef CONFIG_ISDN_MPP
-static ippp_bundle * isdn_ppp_bundle_arr = NULL;
-
-static int isdn_ppp_mp_bundle_array_init(void);
-static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to);
-static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *idev,
- struct sk_buff *skb);
-static void isdn_ppp_mp_cleanup(isdn_net_local *lp );
-
-static int isdn_ppp_bundle(struct ipppd *, int unit);
-#endif /* CONFIG_ISDN_MPP */
-
-char *isdn_ppp_revision = "$Revision: 1.85.6.9 $";
-
/*
* frame log (debug)
*/
@@ -620,23 +588,30 @@ isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,int unit,int slot
}
}
-
-static void
-isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
+void
+ippp_push_proto(struct ind_ppp *ind_ppp, struct sk_buff *skb, u16 proto)
{
- unsigned char *p;
-
- if (skb_headroom(skb) < 4) {
+ if (skb_headroom(skb) < 2) {
isdn_BUG();
return;
}
-
- if ((idev->pppcfg & SC_COMP_PROT) && proto <= 0xff)
+ if ((ind_ppp->pppcfg & SC_COMP_PROT) && proto <= 0xff)
put_u8(skb_push(skb, 1), proto);
else
put_u16(skb_push(skb, 2), proto);
- if (idev->pppcfg & SC_COMP_AC)
+}
+
+static void
+ippp_push_ac(struct ind_ppp *ind_ppp, struct sk_buff *skb)
+{
+ unsigned char *p;
+
+ if (skb_headroom(skb) < 2) {
+ isdn_BUG();
+ return;
+ }
+ if (ind_ppp->pppcfg & SC_COMP_AC)
return;
p = skb_push(skb, 2);
@@ -652,13 +627,13 @@ isdn_ppp_push_header(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
static void
isdn_ppp_unbind(isdn_net_dev *idev)
{
- struct ipppd *is = idev->ipppd;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct ipppd *is = ind_ppp->ipppd;
if (!is) {
isdn_BUG();
return;
}
-
ipppd_debug(is, "");
if (is->state != IPPPD_ST_ASSIGNED)
@@ -667,12 +642,15 @@ isdn_ppp_unbind(isdn_net_dev *idev)
is->state = IPPPD_ST_OPEN;
/* is->idev will be invalid shortly */
- ippp_ccp_free(idev->ccp);
+ ippp_ccp_free(ind_ppp->ccp);
is->idev = NULL;
/* lose the reference we took on isdn_ppp_bind */
ipppd_put(is);
- idev->ipppd = NULL;
+ ind_ppp->ipppd = NULL;
+
+ kfree(ind_ppp);
+ idev->ind_priv = NULL;
return;
}
@@ -683,15 +661,19 @@ isdn_ppp_unbind(isdn_net_dev *idev)
int
isdn_ppp_bind(isdn_net_dev *idev)
{
+ struct ind_ppp *ind_ppp;
int unit = 0;
unsigned long flags;
int retval = 0;
struct ipppd *ipppd;
- if (idev->ipppd) {
+ if (idev->ind_priv) {
isdn_BUG();
- return 0;
+ return -EIO;
}
+ ind_ppp = kmalloc(sizeof(struct ind_ppp), GFP_KERNEL);
+ if (!ind_ppp)
+ return -ENOMEM;
spin_lock_irqsave(&ipppds_lock, flags);
if (idev->pppbind < 0) { /* device bound to ippp device ? */
@@ -743,39 +725,40 @@ isdn_ppp_bind(isdn_net_dev *idev)
ipppd->state = IPPPD_ST_ASSIGNED;
ipppd->idev = idev;
/* we hold a reference until isdn_ppp_unbind() */
- idev->ipppd = ipppd_get(ipppd);
+ ipppd_get(ipppd);
spin_unlock_irqrestore(&ipppds_lock, flags);
- idev->pppcfg = 0; /* config flags */
- /* seq no last seen, maybe set to bundle min, when joining? */
- idev->pppseq = -1;
-
- idev->ccp = ippp_ccp_alloc();
- if (!idev->ccp) {
+ idev->ind_priv = ind_ppp;
+ ind_ppp->pppcfg = 0; /* config flags */
+ ind_ppp->ipppd = ipppd;
+ ind_ppp->ccp = ippp_ccp_alloc();
+ if (!ind_ppp->ccp) {
retval = -ENOMEM;
goto out;
}
- idev->ccp->proto = PPP_COMPFRAG;
- idev->ccp->priv = idev;
- idev->ccp->alloc_skb = isdn_ppp_dev_alloc_skb;
- idev->ccp->push_header = isdn_ppp_dev_push_header;
- idev->ccp->xmit = isdn_ppp_dev_xmit;
- idev->ccp->kick_up = isdn_ppp_dev_kick_up;
-
-#ifdef CONFIG_ISDN_MPP
- retval = isdn_ppp_mp_init(lp, NULL);
-#endif /* CONFIG_ISDN_MPP */
- out:
- if (retval) {
- idev->ipppd->state = IPPPD_ST_OPEN;
- ipppd_put(idev->ipppd);
- idev->ipppd = NULL;
- }
+ ind_ppp->ccp->proto = PPP_COMPFRAG;
+ ind_ppp->ccp->priv = idev;
+ ind_ppp->ccp->alloc_skb = isdn_ppp_dev_alloc_skb;
+ ind_ppp->ccp->xmit = isdn_ppp_dev_xmit;
+ ind_ppp->ccp->kick_up = isdn_ppp_dev_kick_up;
+
+ retval = ippp_mp_bind(idev);
+ if (retval)
+ goto out;
+
+ return 0;
+ out:
+ ipppd->state = IPPPD_ST_OPEN;
+ ipppd_put(ipppd);
+ ind_ppp->ipppd = NULL;
+ kfree(ind_ppp);
+ idev->ind_priv = NULL;
return retval;
err:
spin_unlock_irqrestore(&ipppds_lock, flags);
+ kfree(ind_ppp);
return retval;
}
@@ -787,7 +770,8 @@ isdn_ppp_bind(isdn_net_dev *idev)
static void
isdn_ppp_connected(isdn_net_dev *idev)
{
- struct ipppd *ipppd = idev->ipppd;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct ipppd *ipppd = ind_ppp->ipppd;
ipppd_debug(ipppd, "");
@@ -799,11 +783,12 @@ isdn_ppp_connected(isdn_net_dev *idev)
static void
isdn_ppp_disconnected(isdn_net_dev *idev)
{
- struct ipppd *ipppd = idev->ipppd;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct ipppd *ipppd = ind_ppp->ipppd;
ipppd_debug(ipppd, "");
- if (idev->pppcfg & SC_ENABLE_IP)
+ if (ind_ppp->pppcfg & SC_ENABLE_IP)
isdn_net_offline(idev);
if (ipppd->state != IPPPD_ST_CONNECTED)
@@ -813,15 +798,7 @@ isdn_ppp_disconnected(isdn_net_dev *idev)
ipppd->flags |= IPPPD_FL_HUP;
wake_up(&ipppd->wq);
-#ifdef CONFIG_ISDN_MPP
- spin_lock(&idev->pb->lock);
- if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */
- isdn_ppp_mp_cleanup(lp);
-
- lp->netdev->pb->ref_ct--;
- spin_unlock(&lp->netdev->pb->lock);
-#endif /* CONFIG_ISDN_MPP */
-
+ ippp_mp_disconnected(idev);
}
/*
@@ -831,50 +808,41 @@ isdn_ppp_disconnected(isdn_net_dev *idev)
int
isdn_ppp_init(void)
{
-#ifdef CONFIG_ISDN_MPP
- if( isdn_ppp_mp_bundle_array_init() < 0 )
- return -ENOMEM;
-#endif /* CONFIG_ISDN_MPP */
-
return 0;
}
void
isdn_ppp_cleanup(void)
{
-#ifdef CONFIG_ISDN_MPP
- if (isdn_ppp_bundle_arr)
- kfree(isdn_ppp_bundle_arr);
-#endif /* CONFIG_ISDN_MPP */
-
}
/*
* check for address/control field and skip if allowed
* retval != 0 -> discard packet silently
*/
-static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb)
+static int
+isdn_ppp_skip_ac(struct ind_ppp *ind_ppp, struct sk_buff *skb)
{
u8 val;
if (skb->len < 1)
- return -1;
+ return -EINVAL;
get_u8(skb->data, &val);
if (val != PPP_ALLSTATIONS) {
/* if AC compression was not negotiated, but no AC present,
discard packet */
- if (idev->pppcfg & SC_REJ_COMP_AC)
- return -1;
+ if (ind_ppp->pppcfg & SC_REJ_COMP_AC)
+ return -EINVAL;
return 0;
}
if (skb->len < 2)
- return -1;
+ return -EINVAL;
get_u8(skb->data + 1, &val);
if (val != PPP_UI)
- return -1;
+ return -EINVAL;
/* skip address/control (AC) field */
skb_pull(skb, 2);
@@ -885,38 +853,38 @@ static int isdn_ppp_skip_ac(isdn_net_dev *idev, struct sk_buff *skb)
* get the PPP protocol header and pull skb
* retval < 0 -> discard packet silently
*/
-int isdn_ppp_strip_proto(struct sk_buff *skb)
+int
+isdn_ppp_strip_proto(struct sk_buff *skb, u16 *proto)
{
- u16 proto;
u8 val;
if (skb->len < 1)
- return -1;
+ return -EINVAL;
get_u8(skb->data, &val);
if (val & 0x1) {
/* protocol field is compressed */
- proto = val;
+ *proto = val;
skb_pull(skb, 1);
} else {
if (skb->len < 2)
return -1;
- get_u16(skb->data, &proto);
+ get_u16(skb->data, proto);
skb_pull(skb, 2);
}
- return proto;
+ return 0;
}
/*
* handler for incoming packets on a syncPPP interface
*/
-static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
- struct sk_buff *skb)
+static void
+isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev, struct sk_buff *skb)
{
- struct ipppd *is;
- int proto;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct ipppd *is = ind_ppp->ipppd;
+ u16 proto;
- is = idev->ipppd;
if (!is)
goto err;
@@ -926,117 +894,64 @@ static void isdn_ppp_receive(isdn_net_local *lp, isdn_net_dev *idev,
isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,-1);
}
- if (isdn_ppp_skip_ac(idev, skb) < 0)
+ if (isdn_ppp_skip_ac(ind_ppp, skb) < 0)
goto err;
- proto = isdn_ppp_strip_proto(skb);
- if (proto < 0)
+ if (isdn_ppp_strip_proto(skb, &proto))
goto err;
- /* Don't reset huptimer on LCP packets. */
- if (proto != PPP_LCP)
- idev->huptimer = 0;
-
-#ifdef CONFIG_ISDN_MPP
- if (is->compflags & SC_LINK_DECOMP_ON) {
- skb = isdn_ppp_decompress(skb, is, NULL, &proto);
- if (!skb) // decompression error
- goto put;
- }
-
- if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
- if (proto == PPP_MP) {
- isdn_ppp_mp_receive(lp, idev, skb);
- goto put;
- }
- }
- isdn_ppp_push_higher(lp, idev, skb, proto);
- put:
-#else
- isdn_ppp_push_higher(lp, idev, skb, proto);
-#endif
+ ippp_mp_receive(idev, skb, proto);
return;
err:
+ lp->stats.rx_dropped++;
kfree_skb(skb);
}
/*
- * we receive a reassembled frame, MPPP has been taken care of before.
* address/control and protocol have been stripped from the skb
- * note: net_dev has to be master net_dev
*/
-static void
-isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
- struct sk_buff *skb, int proto)
+void
+ippp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
{
- struct net_device *dev = &lp->dev;
- struct ipppd *is = idev->ipppd;
+ isdn_net_local *lp = idev->mlp;
+ struct inl_ppp *inl_ppp = lp->inl_priv;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct ipppd *is = ind_ppp->ipppd;
if (is->debug & 0x10) {
printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
- isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit, -1);
+ isdn_ppp_frame_log("rpush", skb->data, skb->len, 256, is->unit, -1);
}
- skb = ippp_ccp_decompress(lp->ccp, skb, &proto);
- if (!skb) // decompression error
- goto out;
+ /* all packets need to be passed through the compressor */
+ skb = ippp_ccp_decompress(inl_ppp->ccp, skb, &proto);
+ if (!skb) /* decompression error */
+ goto error;
switch (proto) {
case PPP_IPX: /* untested */
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: IPX\n");
- skb->protocol = htons(ETH_P_IPX);
+ isdn_netif_rx(idev, skb, htons(ETH_P_IPX));
break;
case PPP_IP:
if (is->debug & 0x20)
printk(KERN_DEBUG "isdn_ppp: IP\n");
- skb->protocol = htons(ETH_P_IP);
+ isdn_netif_rx(idev, skb, htons(ETH_P_IP));
break;
case PPP_COMP:
case PPP_COMPFRAG:
printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n");
goto drop;
-#ifdef CONFIG_ISDN_PPP_VJ
case PPP_VJC_UNCOMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
- if (slhc_remember(lp->slcomp, skb->data, skb->len) <= 0) {
- printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
- goto drop;
- }
- skb->protocol = htons(ETH_P_IP);
- break;
case PPP_VJC_COMP:
- if (is->debug & 0x20)
- printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
- {
- struct sk_buff *skb_old = skb;
- int pkt_len;
- skb = dev_alloc_skb(skb_old->len + 128);
-
- if (!skb) {
- printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
- skb = skb_old;
- goto drop;
- }
- skb_put(skb, skb_old->len + 128);
- memcpy(skb->data, skb_old->data, skb_old->len);
- pkt_len = slhc_uncompress(lp->slcomp,
- skb->data, skb_old->len);
- kfree_skb(skb_old);
- if (pkt_len < 0)
- goto drop;
-
- skb_trim(skb, pkt_len);
- skb->protocol = htons(ETH_P_IP);
- }
+ ippp_vj_decompress(idev, skb, proto);
break;
-#endif
case PPP_CCPFRAG:
- ippp_ccp_receive_ccp(idev->ccp, skb);
+ ippp_ccp_receive_ccp(ind_ppp->ccp, skb);
goto ccp;
case PPP_CCP:
- ippp_ccp_receive_ccp(lp->ccp, skb);
+ ippp_ccp_receive_ccp(inl_ppp->ccp, skb);
ccp:
/* Dont pop up ResetReq/Ack stuff to the daemon any
longer - the job is done already */
@@ -1049,20 +964,16 @@ isdn_ppp_push_higher(isdn_net_local *lp, isdn_net_dev *idev,
ipppd_queue_read(is, proto, skb->data, skb->len);
goto free;
}
-
- /* Reset hangup-timer */
- idev->huptimer = 0;
-
- skb->dev = dev;
- netif_rx(skb);
- /* net_dev->local->stats.rx_packets++; done in isdn_net.c */
- out:
return;
drop:
lp->stats.rx_dropped++;
free:
kfree_skb(skb);
+ return;
+
+ error:
+ lp->stats.rx_dropped++;
}
/*
@@ -1077,8 +988,10 @@ static int
isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
isdn_net_local *mlp = ndev->priv;
+ struct inl_ppp *inl_ppp = mlp->inl_priv;
+ struct ind_ppp *ind_ppp;
isdn_net_dev *idev = list_entry(mlp->online.next, isdn_net_dev, online);
- unsigned int proto = PPP_IP; /* 0x21 */
+ u16 proto = PPP_IP; /* 0x21 */
struct ipppd *ipppd;
ndev->trans_start = jiffies;
@@ -1094,10 +1007,9 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
proto = PPP_IPX; /* untested */
break;
default:
- printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n",
+ printk(KERN_INFO "isdn_ppp: skipped unsupported protocol: %#x.\n",
skb->protocol);
- dev_kfree_skb(skb);
- goto out;
+ goto drop;
}
idev = isdn_net_get_xmit_dev(mlp);
@@ -1105,126 +1017,33 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
printk(KERN_INFO "%s: IP frame delayed.\n", ndev->name);
goto stop;
}
- if (!(idev->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
+ ind_ppp = idev->ind_priv;
+ if (!(ind_ppp->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */
isdn_BUG();
goto stop;
}
- ipppd = idev->ipppd;
+ ipppd = ind_ppp->ipppd;
idev->huptimer = 0;
- /*
- * after this line .. requeueing in the device queue is no longer allowed!!!
- */
-
- if (ipppd->debug & 0x4)
- printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len);
if (ipppd->debug & 0x40)
- isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipppd->unit, -1);
+ isdn_ppp_frame_log("xmit0", skb->data, skb->len, 256, ipppd->unit, -1);
-#ifdef CONFIG_ISDN_PPP_VJ
- if (proto == PPP_IP && idev->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */
- struct sk_buff *new_skb;
- unsigned short hl;
- /*
- * we need to reserve enought space in front of
- * sk_buff. old call to dev_alloc_skb only reserved
- * 16 bytes, now we are looking what the driver want.
- */
- hl = isdn_slot_hdrlen(idev->isdn_slot) + IPPP_MAX_HEADER;;
- /*
- * Note: hl might still be insufficient because the method
- * above does not account for a possibible MPPP slave channel
- * which had larger HL header space requirements than the
- * master.
- */
- new_skb = alloc_skb(hl+skb->len, GFP_ATOMIC);
- if (new_skb) {
- u_char *buf;
- int pktlen;
-
- skb_reserve(new_skb, hl);
- new_skb->dev = skb->dev;
- skb_put(new_skb, skb->len);
- buf = skb->data;
-
- pktlen = slhc_compress(mlp->slcomp, skb->data, skb->len, new_skb->data,
- &buf, !(idev->pppcfg & SC_NO_TCP_CCID));
-
- if (buf != skb->data) {
- if (new_skb->data != buf)
- printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n");
- dev_kfree_skb(skb);
- skb = new_skb;
- } else {
- dev_kfree_skb(new_skb);
- }
+ /* after this line,requeueing is no longer allowed! */
+ skb = ippp_vj_compress(idev, skb, &proto);
- skb_trim(skb, pktlen);
- if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */
- proto = PPP_VJC_COMP;
- skb->data[0] ^= SL_TYPE_COMPRESSED_TCP;
- } else {
- if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP)
- proto = PPP_VJC_UNCOMP;
- skb->data[0] = (skb->data[0] & 0x0f) | 0x40;
- }
- }
- }
-#endif
+ /* normal (single link) or bundle compression */
+ skb = ippp_ccp_compress(inl_ppp->ccp, skb, &proto);
- /*
- * normal (single link) or bundle compression
- */
- skb = ippp_ccp_compress(mlp->ccp, skb, &proto);
-
- if (ipppd->debug & 0x24)
- printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto);
-
-#ifdef CONFIG_ISDN_MPP
- if (ipt->mpppcfg & SC_MP_PROT) {
- /* we get mp_seqno from static isdn_net_local */
- long mp_seqno = ipts->mp_seqno;
- ipts->mp_seqno++;
- if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
- unsigned char *data = isdn_ppp_skb_push(&skb, 3);
- if(!data)
- goto unlock;
- mp_seqno &= 0xfff;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */
- data[1] = mp_seqno & 0xff;
- data[2] = proto; /* PID compression */
- } else {
- unsigned char *data = isdn_ppp_skb_push(&skb, 5);
- if(!data)
- goto unlock;
- data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */
- data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */
- data[2] = (mp_seqno >> 8) & 0xff;
- data[3] = (mp_seqno >> 0) & 0xff;
- data[4] = proto; /* PID compression */
- }
- proto = PPP_MP; /* MP Protocol, 0x003d */
- }
-#endif
+ if (ipppd->debug & 0x40)
+ isdn_ppp_frame_log("xmit1", skb->data, skb->len, 32, ipppd->unit, -1);
-#if 0
- /*
- * 'link in bundle' compression ...
- */
- if (ipt->compflags & SC_LINK_COMP_ON)
- skb = isdn_ppp_compress(skb,&proto,ipt,ipts,1);
-#endif
-
- isdn_ppp_push_header(idev, skb, proto);
-
- if (ipppd->debug & 0x40) {
- printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
- isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipppd->unit, -1);
- }
-
- isdn_net_writebuf_skb(idev, skb);
+ ippp_push_proto(ind_ppp, skb, proto);
+ ippp_mp_xmit(idev, skb, proto);
+ return 0;
- out:
+ drop:
+ kfree_skb(skb);
+ mlp->stats.tx_dropped++;
return 0;
stop:
@@ -1232,483 +1051,21 @@ isdn_ppp_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return 1;
}
-#ifdef CONFIG_ISDN_MPP
-
-/* this is _not_ rfc1990 header, but something we convert both short and long
- * headers to for convinience's sake:
- * byte 0 is flags as in rfc1990
- * bytes 1...4 is 24-bit seqence number converted to host byte order
- */
-#define MP_HEADER_LEN 5
-
-#define MP_LONGSEQ_MASK 0x00ffffff
-#define MP_SHORTSEQ_MASK 0x00000fff
-#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
-#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
-#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1)
-#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1)
-
-/* sequence-wrap safe comparisions (for long sequence)*/
-#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT)
-#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT)
-#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT)
-#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT)
-
-#define MP_SEQ(f) ((*(u32*)(f->data+1)))
-#define MP_FLAGS(f) (f->data[0])
-
-static int isdn_ppp_mp_bundle_array_init(void)
-{
- int i;
- int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
- if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz,
- GFP_KERNEL)) == NULL )
- return -ENOMEM;
- memset(isdn_ppp_bundle_arr, 0, sz);
- for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
- spin_lock_init(&isdn_ppp_bundle_arr[i].lock);
- return 0;
-}
-
-static ippp_bundle * isdn_ppp_mp_bundle_alloc(void)
-{
- int i;
- for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
- if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
- return (isdn_ppp_bundle_arr + i);
- return NULL;
-}
-
-static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
-{
- isdn_net_dev *idev = lp->netdev;
- struct ipppd * is;
-
- if (idev->ppp_slot < 0) {
- printk(KERN_ERR "%s: >ppp_slot(%d) out of range\n",
- __FUNCTION__ , idev->ppp_slot);
- return -EINVAL;
- }
-
- is = ippp_table[idev->ppp_slot];
- if (add_to) {
- if( lp->netdev->pb )
- lp->netdev->pb->ref_ct--;
- lp->netdev->pb = add_to;
- } else { /* first link in a bundle */
- is->mp_seqno = 0;
- if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL)
- return -ENOMEM;
-
- lp->netdev->pb->frags = NULL;
- lp->netdev->pb->frames = 0;
- lp->netdev->pb->seq = LONG_MAX;
- }
- lp->netdev->pb->ref_ct++;
-
- is->pppseq = 0;
- return 0;
-}
-
-static u32 isdn_ppp_mp_get_seq( int short_seq,
- struct sk_buff * skb, u32 last_seq );
-static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
- struct sk_buff * from, struct sk_buff * to );
-static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
- struct sk_buff * from, struct sk_buff * to );
-static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
-static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
-
-static void isdn_ppp_mp_receive(isdn_net_local *lp, isdn_net_dev *dev,
- struct sk_buff *skb)
+void
+ippp_xmit(isdn_net_dev *idev, struct sk_buff *skb)
{
- isdn_net_dev *idev = lp->netdev;
- struct ipppd *is;
- isdn_net_dev *qdev;
- ippp_bundle * mp;
- isdn_mppp_stats * stats;
- struct sk_buff * newfrag, * frag, * start, *nextf;
- u32 newseq, minseq, thisseq;
- unsigned long flags;
- int slot;
-
- spin_lock_irqsave(&lp->netdev->pb->lock, flags);
- mp = lp->netdev->pb;
- stats = &mp->stats;
- slot = idev->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d)\n",
- __FUNCTION__, slot);
- stats->frame_drops++;
- dev_kfree_skb(skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
- is = ippp_table[slot];
- if( ++mp->frames > stats->max_queue_len )
- stats->max_queue_len = mp->frames;
-
- if (is->debug & 0x8)
- isdn_ppp_mp_print_recv_pkt(slot, skb);
-
- newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ,
- skb, is->pppseq);
-
-
- /* if this packet seq # is less than last already processed one,
- * toss it right away, but check for sequence start case first
- */
- if( mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT) ) {
- mp->seq = newseq; /* the first packet: required for
- * rfc1990 non-compliant clients --
- * prevents constant packet toss */
- } else if( MP_LT(newseq, mp->seq) ) {
- stats->frame_drops++;
- isdn_ppp_mp_free_skb(mp, skb);
- spin_unlock_irqrestore(&mp->lock, flags);
- return;
- }
-
- /* find the minimum received sequence number over all links */
- is->pppseq = minseq = newseq;
- list_for_each_entry(qdev, &lp->online, online) {
- slot = qdev->ppp_slot;
- if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n",
- __FUNCTION__ ,slot);
- } else {
- u32 lls = ippp_table[slot]->pppseq;
- if (MP_LT(lls, minseq))
- minseq = lls;
- }
- }
- if (MP_LT(minseq, mp->seq))
- minseq = mp->seq; /* can't go beyond already processed
- * packets */
- newfrag = skb;
-
- /* if this new fragment is before the first one, then enqueue it now. */
- if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) {
- newfrag->next = frag;
- mp->frags = frag = newfrag;
- newfrag = NULL;
- }
-
- start = MP_FLAGS(frag) & MP_BEGIN_FRAG &&
- MP_SEQ(frag) == mp->seq ? frag : NULL;
-
- /*
- * main fragment traversing loop
- *
- * try to accomplish several tasks:
- * - insert new fragment into the proper sequence slot (once that's done
- * newfrag will be set to NULL)
- * - reassemble any complete fragment sequence (non-null 'start'
- * indicates there is a continguous sequence present)
- * - discard any incomplete sequences that are below minseq -- due
- * to the fact that sender always increment sequence number, if there
- * is an incomplete sequence below minseq, no new fragments would
- * come to complete such sequence and it should be discarded
- *
- * loop completes when we accomplished the following tasks:
- * - new fragment is inserted in the proper sequence ('newfrag' is
- * set to NULL)
- * - we hit a gap in the sequence, so no reassembly/processing is
- * possible ('start' would be set to NULL)
- *
- * algorightm for this code is derived from code in the book
- * 'PPP Design And Debugging' by James Carlson (Addison-Wesley)
- */
- while (start != NULL || newfrag != NULL) {
-
- thisseq = MP_SEQ(frag);
- nextf = frag->next;
-
- /* drop any duplicate fragments */
- if (newfrag != NULL && thisseq == newseq) {
- isdn_ppp_mp_free_skb(mp, newfrag);
- newfrag = NULL;
- }
-
- /* insert new fragment before next element if possible. */
- if (newfrag != NULL && (nextf == NULL ||
- MP_LT(newseq, MP_SEQ(nextf)))) {
- newfrag->next = nextf;
- frag->next = nextf = newfrag;
- newfrag = NULL;
- }
-
- if (start != NULL) {
- /* check for misplaced start */
- if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) {
- printk(KERN_WARNING"isdn_mppp(seq %d): new "
- "BEGIN flag with no prior END", thisseq);
- stats->seqerrs++;
- stats->frame_drops++;
- start = isdn_ppp_mp_discard(mp, start,frag);
- nextf = frag->next;
- }
- } else if (MP_LE(thisseq, minseq)) {
- if (MP_FLAGS(frag) & MP_BEGIN_FRAG)
- start = frag;
- else {
- if (MP_FLAGS(frag) & MP_END_FRAG)
- stats->frame_drops++;
- if( mp->frags == frag )
- mp->frags = nextf;
- isdn_ppp_mp_free_skb(mp, frag);
- frag = nextf;
- continue;
- }
- }
-
- /* if start is non-null and we have end fragment, then
- * we have full reassembly sequence -- reassemble
- * and process packet now
- */
- if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) {
- minseq = mp->seq = (thisseq+1) & MP_LONGSEQ_MASK;
- /* Reassemble the packet then dispatch it */
- isdn_ppp_mp_reassembly(lp->netdev, lp, start, nextf);
-
- start = NULL;
- frag = NULL;
-
- mp->frags = nextf;
- }
-
- /* check if need to update start pointer: if we just
- * reassembled the packet and sequence is contiguous
- * then next fragment should be the start of new reassembly
- * if sequence is contiguous, but we haven't reassembled yet,
- * keep going.
- * if sequence is not contiguous, either clear everyting
- * below low watermark and set start to the next frag or
- * clear start ptr.
- */
- if (nextf != NULL &&
- ((thisseq+1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) {
- /* if we just reassembled and the next one is here,
- * then start another reassembly. */
-
- if (frag == NULL) {
- if (MP_FLAGS(nextf) & MP_BEGIN_FRAG)
- start = nextf;
- else
- {
- printk(KERN_WARNING"isdn_mppp(seq %d):"
- " END flag with no following "
- "BEGIN", thisseq);
- stats->seqerrs++;
- }
- }
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct ipppd *ipppd = ind_ppp->ipppd;
- } else {
- if ( nextf != NULL && frag != NULL &&
- MP_LT(thisseq, minseq)) {
- /* we've got a break in the sequence
- * and we not at the end yet
- * and we did not just reassembled
- *(if we did, there wouldn't be anything before)
- * and we below the low watermark
- * discard all the frames below low watermark
- * and start over */
- stats->frame_drops++;
- mp->frags = isdn_ppp_mp_discard(mp,start,nextf);
- }
- /* break in the sequence, no reassembly */
- start = NULL;
- }
-
- frag = nextf;
- } /* while -- main loop */
-
- if (mp->frags == NULL)
- mp->frags = frag;
-
- /* rather straighforward way to deal with (not very) possible
- * queue overflow */
- if (mp->frames > MP_MAX_QUEUE_LEN) {
- stats->overflows++;
- while (mp->frames > MP_MAX_QUEUE_LEN) {
- frag = mp->frags->next;
- isdn_ppp_mp_free_skb(mp, mp->frags);
- mp->frags = frag;
- }
- }
- spin_unlock_irqrestore(&mp->lock, flags);
-}
+ ippp_push_ac(ind_ppp, skb);
-static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
-{
- struct sk_buff * frag = lp->netdev->pb->frags;
- struct sk_buff * nextfrag;
- while( frag ) {
- nextfrag = frag->next;
- isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
- frag = nextfrag;
- }
- lp->netdev->pb->frags = NULL;
-}
-
-static u32 isdn_ppp_mp_get_seq( int short_seq,
- struct sk_buff * skb, u32 last_seq )
-{
- u32 seq;
- int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
-
- if( !short_seq )
- {
- seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK;
- skb_push(skb,1);
+ if (ipppd->debug & 0x40) {
+ isdn_ppp_frame_log("xmit3", skb->data, skb->len, 32, ipppd->unit, -1);
}
- else
- {
- /* convert 12-bit short seq number to 24-bit long one
- */
- seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK;
- /* check for seqence wrap */
- if( !(seq & MP_SHORTSEQ_MAXBIT) &&
- (last_seq & MP_SHORTSEQ_MAXBIT) &&
- (unsigned long)last_seq <= MP_LONGSEQ_MAX )
- seq |= (last_seq + MP_SHORTSEQ_MAX+1) &
- (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
- else
- seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK);
-
- skb_push(skb, 3); /* put converted seqence back in skb */
- }
- *(u32*)(skb->data+1) = seq; /* put seqence back in _host_ byte
- * order */
- skb->data[0] = flags; /* restore flags */
- return seq;
-}
-
-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
- struct sk_buff * from, struct sk_buff * to )
-{
- if( from )
- while (from != to) {
- struct sk_buff * next = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = next;
- }
- return from;
-}
-
-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
- struct sk_buff * from, struct sk_buff * to )
-{
- isdn_net_dev *idev = lp->netdev;
- ippp_bundle * mp = net_dev->pb;
- int proto;
- struct sk_buff * skb;
- unsigned int tot_len;
-
- if (idev->ppp_slot < 0 || idev->ppp_slot > ISDN_MAX_CHANNELS) {
- printk(KERN_ERR "%s: ppp_slot(%d) out of range\n",
- __FUNCTION__ , idev->ppp_slot);
- return;
- }
- if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
- if( ippp_table[idev->ppp_slot]->debug & 0x40 )
- printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
- "len %d\n", MP_SEQ(from), from->len );
- skb = from;
- skb_pull(skb, MP_HEADER_LEN);
- mp->frames--;
- } else {
- struct sk_buff * frag;
- int n;
-
- for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
- tot_len += frag->len - MP_HEADER_LEN;
-
- if( ippp_table[idev->ppp_slot]->debug & 0x40 )
- printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
- "to %d, len %d\n", MP_SEQ(from),
- (MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
- if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
- printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
- "of size %d\n", tot_len);
- isdn_ppp_mp_discard(mp, from, to);
- return;
- }
-
- while( from != to ) {
- unsigned int len = from->len - MP_HEADER_LEN;
-
- memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
- frag = from->next;
- isdn_ppp_mp_free_skb(mp, from);
- from = frag;
- }
- }
- proto = isdn_ppp_strip_proto(skb);
- isdn_ppp_push_higher(lp, idev, skb, proto);
-}
-
-static void isdn_ppp_mp_free_skb(ippp_bundle * mp, struct sk_buff * skb)
-{
- dev_kfree_skb(skb);
- mp->frames--;
-}
-
-static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb )
-{
- printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n",
- slot, (int) skb->len,
- (int) skb->data[0], (int) skb->data[1], (int) skb->data[2],
- (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]);
+ isdn_net_writebuf_skb(idev, skb);
}
-static int
-isdn_ppp_bundle(struct ipppd *is, int unit)
-{
- char ifn[IFNAMSIZ + 1];
- isdn_net_dev *p;
- isdn_net_dev *idev, *nidev;
- int rc;
- unsigned long flags;
-
- sprintf(ifn, "ippp%d", unit);
- p = isdn_net_findif(ifn);
- if (!p) {
- printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&p->pb->lock, flags);
-
- nidev = is->idev;
- idev = list_entry(p->mlp->online.next, isdn_net_dev, online);
- if( nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS ||
- idev ->ppp_slot < 0 || idev ->ppp_slot >= ISDN_MAX_CHANNELS ) {
- printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
- nidev->ppp_slot < 0 || nidev->ppp_slot >= ISDN_MAX_CHANNELS ?
- nidev->ppp_slot : idev->ppp_slot );
- rc = -EINVAL;
- goto out;
- }
-
- isdn_net_add_to_bundle(p->mlp, nidev);
-
- ippp_table[nidev->ppp_slot]->unit = ippp_table[idev->ppp_slot]->unit;
-
- /* maybe also SC_CCP stuff */
- ippp_table[nidev->ppp_slot]->pppcfg |= ippp_table[idev->ppp_slot]->pppcfg &
- (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
- ippp_table[nidev->ppp_slot]->mpppcfg |= ippp_table[idev->ppp_slot]->mpppcfg &
- (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
- rc = isdn_ppp_mp_init(nidev->mlp, p->pb);
-out:
- spin_unlock_irqrestore(&p->pb->lock, flags);
- return rc;
-}
-
-#endif /* CONFIG_ISDN_MPP */
-
/*
* network device ioctl handlers
*/
@@ -1718,6 +1075,7 @@ isdn_ppp_dev_ioctl_stats(struct ifreq *ifr, struct net_device *dev)
{
struct ppp_stats *res, t;
isdn_net_local *lp = (isdn_net_local *) dev->priv;
+ struct inl_ppp *inl_ppp = lp->inl_priv;
struct slcompress *slcomp;
int err;
@@ -1738,7 +1096,7 @@ isdn_ppp_dev_ioctl_stats(struct ifreq *ifr, struct net_device *dev)
t.p.ppp_obytes = lp->stats.tx_bytes;
t.p.ppp_oerrors = lp->stats.tx_errors;
#ifdef CONFIG_ISDN_PPP_VJ
- slcomp = lp->slcomp;
+ slcomp = inl_ppp->slcomp;
if (slcomp) {
t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed;
t.vj.vjs_compressed = slcomp->sls_o_compressed;
@@ -1810,61 +1168,6 @@ isdn_ppp_if_get_unit(char *name)
return unit;
}
-
-int
-isdn_ppp_dial_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *idev;
- isdn_net_dev *sdev;
-
- idev = isdn_net_findif(name);
- if (!idev)
- return 1;
-
- if (!isdn_net_bound(idev))
- return 5;
-
- sdev = idev->slave;
- while (sdev) {
- if (!isdn_net_bound(sdev))
- break;
- sdev = sdev->slave;
- }
- if (!sdev)
- return 2;
-
- isdn_net_dial_req(sdev);
- return 0;
-#else
- return -1;
-#endif
-}
-
-int
-isdn_ppp_hangup_slave(char *name)
-{
-#ifdef CONFIG_ISDN_MPP
- isdn_net_dev *idev, *sdev;
-
- idev = isdn_net_findif(name);
- if (!idev)
- return 1;
-
- if (!isdn_net_bound(idev))
- return 5;
-
- sdev = idev->slave;
- if (!sdev || !isdn_net_bound(sdev))
- return 2;
-
- isdn_net_hangup(sdev);
- return 0;
-#else
- return -1;
-#endif
-}
-
/*
* PPP compression stuff
*/
@@ -1876,21 +1179,24 @@ isdn_ppp_hangup_slave(char *name)
static void isdn_ppp_dev_kick_up(void *priv)
{
isdn_net_dev *idev = priv;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
- ipppd_queue_read(idev->ipppd, PPP_COMPFRAG, NULL, 0);
+ ipppd_queue_read(ind_ppp->ipppd, PPP_COMPFRAG, NULL, 0);
}
static void isdn_ppp_lp_kick_up(void *priv)
{
isdn_net_local *lp = priv;
isdn_net_dev *idev;
+ struct ind_ppp *ind_ppp;
if (list_empty(&lp->online)) {
isdn_BUG();
return;
}
idev = list_entry(lp->online.next, isdn_net_dev, online);
- ipppd_queue_read(idev->ipppd, PPP_COMP, NULL, 0);
+ ind_ppp = idev->ind_priv;
+ ipppd_queue_read(ind_ppp->ipppd, PPP_COMP, NULL, 0);
}
/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. */
@@ -1909,7 +1215,7 @@ __isdn_ppp_alloc_skb(isdn_net_dev *idev, int len, unsigned int gfp_mask)
return skb;
}
-static struct sk_buff *
+struct sk_buff *
isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask)
{
isdn_net_dev *idev = priv;
@@ -1932,46 +1238,31 @@ isdn_ppp_lp_alloc_skb(void *priv, int len, int gfp_mask)
}
static void
-isdn_ppp_dev_push_header(void *priv, struct sk_buff *skb, u16 proto)
-{
- isdn_net_dev *idev = priv;
-
- isdn_ppp_push_header(idev, skb, proto);
-}
-
-static void
-isdn_ppp_lp_push_header(void *priv, struct sk_buff *skb, u16 proto)
-{
- isdn_net_local *lp = priv;
- isdn_net_dev *idev;
-
- if (list_empty(&lp->online)) {
- isdn_BUG();
- return;
- }
- idev = list_entry(lp->online.next, isdn_net_dev, online);
- isdn_ppp_push_header(idev, skb, proto);
-}
-
-static void
-isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb)
+isdn_ppp_dev_xmit(void *priv, struct sk_buff *skb, u16 proto)
{
isdn_net_dev *idev = priv;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ ippp_push_proto(ind_ppp, skb, proto);
+ ippp_push_ac(ind_ppp, skb);
isdn_net_write_super(idev, skb);
}
static void
-isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb)
+isdn_ppp_lp_xmit(void *priv, struct sk_buff *skb, u16 proto)
{
isdn_net_local *lp = priv;
isdn_net_dev *idev;
+ struct ind_ppp *ind_ppp;
if (list_empty(&lp->online)) {
isdn_BUG();
return;
}
idev = list_entry(lp->online.next, isdn_net_dev, online);
+ ind_ppp = idev->ind_priv;
+ ippp_push_proto(ind_ppp, skb, proto);
+ ippp_push_ac(ind_ppp, skb);
isdn_net_write_super(idev, skb);
}
@@ -1979,13 +1270,15 @@ static int
isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *data)
{
struct ippp_ccp *ccp;
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
if (data->flags & IPPP_COMP_FLAG_LINK)
- ccp = idev->ccp;
+ ccp = ind_ppp->ccp;
else
- ccp = idev->mlp->ccp;
+ ccp = inl_ppp->ccp;
- return ippp_ccp_set_compressor(ccp, idev->ipppd->unit, data);
+ return ippp_ccp_set_compressor(ccp, ind_ppp->ipppd->unit, data);
}
// ISDN_NET_ENCAP_SYNCPPP
@@ -1994,34 +1287,48 @@ isdn_ppp_set_compressor(isdn_net_dev *idev, struct isdn_ppp_comp_data *data)
static int
isdn_ppp_open(isdn_net_local *lp)
{
- lp->mpppcfg = 0; /* mppp configuration */
- lp->mp_seqno = 0; /* MP sequence number */
+ struct inl_ppp *inl_ppp;
-#ifdef CONFIG_ISDN_PPP_VJ
- lp->slcomp = slhc_init(16, 16);
-#endif
- lp->ccp = ippp_ccp_alloc();
- if (!lp->ccp)
+ inl_ppp = kmalloc(sizeof(*inl_ppp), GFP_KERNEL);
+ if (!inl_ppp)
return -ENOMEM;
- lp->ccp->proto = PPP_COMP;
- lp->ccp->priv = lp;
- lp->ccp->alloc_skb = isdn_ppp_lp_alloc_skb;
- lp->ccp->push_header = isdn_ppp_lp_push_header;
- lp->ccp->xmit = isdn_ppp_lp_xmit;
- lp->ccp->kick_up = isdn_ppp_lp_kick_up;
+ lp->inl_priv = inl_ppp;
+
+ inl_ppp->slcomp = ippp_vj_alloc();
+ if (!inl_ppp->slcomp)
+ goto err;
+
+ inl_ppp->ccp = ippp_ccp_alloc();
+ if (!inl_ppp->ccp)
+ goto err_vj;
+
+ inl_ppp->ccp->proto = PPP_COMP;
+ inl_ppp->ccp->priv = lp;
+ inl_ppp->ccp->alloc_skb = isdn_ppp_lp_alloc_skb;
+ inl_ppp->ccp->xmit = isdn_ppp_lp_xmit;
+ inl_ppp->ccp->kick_up = isdn_ppp_lp_kick_up;
+
return 0;
+
+ err_vj:
+ ippp_vj_free(inl_ppp->slcomp);
+ err:
+ kfree(inl_ppp);
+ lp->inl_priv = NULL;
+ return -ENOMEM;
}
static void
isdn_ppp_close(isdn_net_local *lp)
{
-#ifdef CONFIG_ISDN_PPP_VJ
- slhc_free(lp->slcomp);
- lp->slcomp = NULL;
-#endif
- ippp_ccp_free(lp->ccp);
- lp->ccp = NULL;
+ struct inl_ppp *inl_ppp = lp->inl_priv;
+
+ ippp_ccp_free(inl_ppp->ccp);
+ ippp_vj_free(inl_ppp->slcomp);
+
+ kfree(inl_ppp);
+ lp->inl_priv = NULL;
}
struct isdn_netif_ops isdn_ppp_ops = {
@@ -2037,3 +1344,4 @@ struct isdn_netif_ops isdn_ppp_ops = {
.open = isdn_ppp_open,
.close = isdn_ppp_close,
};
+
diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h
index 20745b31ef1d..ea7b8eb0aeef 100644
--- a/drivers/isdn/i4l/isdn_ppp.h
+++ b/drivers/isdn/i4l/isdn_ppp.h
@@ -1,16 +1,13 @@
-/* $Id: isdn_ppp.h,v 1.17.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel).
+/* Linux ISDN subsystem, functions for synchronous PPP (linklevel).
*
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
-#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */
-#include <linux/isdn_ppp.h> /* for isdn_ppp info */
+#include "isdn_net_lib.h"
extern struct file_operations isdn_ppp_fops;
extern struct isdn_netif_ops isdn_ppp_ops;
@@ -20,10 +17,41 @@ void isdn_ppp_cleanup(void);
int isdn_ppp_dial_slave(char *);
int isdn_ppp_hangup_slave(char *);
+struct inl_ppp {
+ unsigned long debug;
+ struct slcompress *slcomp;
+ struct ippp_ccp *ccp; /* CCP for this channel */
+ unsigned int mp_cfg;
+ struct sk_buff_head mp_frags; /* fragments list */
+ u32 mp_rxseq; /* last processed packet seq # */
+ u32 mp_txseq; /* current tx seq # */
+};
+
+struct ind_ppp {
+ struct ipppd *ipppd; /* /dev/ipppX which controls us */
+ unsigned int pppcfg;
+ unsigned long debug;
+ struct ippp_ccp *ccp; /* CCP for this channel (multilink) */
+ u32 mp_rxseq; /* last seq no seen on this channel */
+};
+
void
isdn_ppp_frame_log(char *info, char *data, int len, int maxlen,
int unit, int slot);
+
int
-isdn_ppp_strip_proto(struct sk_buff *skb);
+isdn_ppp_strip_proto(struct sk_buff *skb, u16 *proto);
+
+void
+ippp_push_proto(struct ind_ppp *ind_ppp, struct sk_buff *skb, u16 proto);
+
+void
+ippp_xmit(isdn_net_dev *idev, struct sk_buff *skb);
+
+void
+ippp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto);
+
+struct sk_buff *
+isdn_ppp_dev_alloc_skb(void *priv, int len, int gfp_mask);
#define IPPP_MAX_HEADER 10
diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.c b/drivers/isdn/i4l/isdn_ppp_ccp.c
index ab573e7a6376..5a8f2dc7e01b 100644
--- a/drivers/isdn/i4l/isdn_ppp_ccp.c
+++ b/drivers/isdn/i4l/isdn_ppp_ccp.c
@@ -1,10 +1,50 @@
+/* Linux ISDN subsystem, PPP CCP support
+ *
+ * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
#include "isdn_ppp_ccp.h"
#include "isdn_common.h"
-#include "isdn_net.h"
+#include "isdn_net_lib.h"
#include "isdn_ppp.h"
#include <linux/ppp-comp.h>
+/* ====================================================================== */
+enum ippp_ccp_reset_states {
+ CCPResetIdle,
+ CCPResetSentReq,
+ CCPResetRcvdReq,
+ CCPResetSentAck,
+ CCPResetRcvdAck
+};
+
+struct ippp_ccp_reset_state {
+ enum ippp_ccp_reset_states state;/* State of this transaction */
+ struct ippp_ccp *ccp; /* Backlink */
+ unsigned char id; /* id index */
+ unsigned char ta:1; /* The timer is active (flag) */
+ unsigned char expra:1; /* We expect a ResetAck at all */
+ int dlen; /* Databytes stored in data */
+ struct timer_list timer; /* For timeouts/retries */
+ /* This is a hack but seems sufficient for the moment. We do not want
+ to have this be yet another allocation for some bytes, it is more
+ memory management overhead than the whole mess is worth. */
+ unsigned char data[IPPP_RESET_MAXDATABYTES];
+};
+
+/* The data structure keeping track of the currently outstanding CCP Reset
+ transactions. */
+struct ippp_ccp_reset {
+ struct ippp_ccp_reset_state *rs[256]; /* One per possible id */
+ unsigned char lastid; /* Last id allocated */
+};
+
/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary,
but absolutely nontrivial. The most abstruse problem we are facing is
that the generation, reception and all the handling of timeouts and
@@ -62,7 +102,6 @@ do_xmit_reset(struct ippp_ccp *ccp, unsigned char code, unsigned char id,
u16 proto = ccp->proto == PPP_COMP ? PPP_CCP : PPP_CCPFRAG;
skb = ccp->alloc_skb(ccp->priv, 4 + len, GFP_ATOMIC);
- ccp->push_header(ccp->priv, skb, proto);
p = skb_put(skb, 4);
p += put_u8 (p, code);
@@ -74,7 +113,7 @@ do_xmit_reset(struct ippp_ccp *ccp, unsigned char code, unsigned char id,
isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, -1, -1);
- ccp->xmit(ccp->priv, skb);
+ ccp->xmit(ccp->priv, skb, proto);
}
/* The timer callback function which is called when a ResetReq has timed out,
@@ -250,7 +289,7 @@ ippp_ccp_get_flags(struct ippp_ccp *ccp)
* and a new skb otherwise
*/
struct sk_buff *
-ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto)
+ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, u16 *proto)
{
struct sk_buff *skb;
@@ -260,7 +299,7 @@ ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto)
return skb_in;
}
/* we do not compress control protocols */
- if (*proto < 0 || *proto > 0x3fff) {
+ if (*proto > 0x3fff) {
return skb_in;
}
if (!ccp->compressor || !ccp->comp_stat) {
@@ -294,7 +333,7 @@ ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto)
*/
struct sk_buff *
-ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto)
+ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, u16 *proto)
{
struct sk_buff *skb;
struct isdn_ppp_resetparams rsparm;
@@ -344,8 +383,7 @@ ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb_in, int *proto)
kfree_skb(skb);
return NULL;
}
- *proto = isdn_ppp_strip_proto(skb);
- if (*proto < 0) {
+ if (isdn_ppp_strip_proto(skb, proto)) {
kfree_skb(skb);
return NULL;
}
diff --git a/drivers/isdn/i4l/isdn_ppp_ccp.h b/drivers/isdn/i4l/isdn_ppp_ccp.h
index d9ece852d24f..7d4a89639818 100644
--- a/drivers/isdn/i4l/isdn_ppp_ccp.h
+++ b/drivers/isdn/i4l/isdn_ppp_ccp.h
@@ -1,3 +1,13 @@
+/* Linux ISDN subsystem, PPP CCP support
+ *
+ * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
#include <linux/kernel.h>
#include <linux/isdn_ppp.h>
@@ -16,7 +26,7 @@
*/
struct ippp_ccp {
- int proto;
+ u16 proto;
struct isdn_ppp_compressor *compressor;
struct isdn_ppp_compressor *decompressor;
void *comp_stat;
@@ -26,9 +36,8 @@ struct ippp_ccp {
int mru;
int debug;
void *priv;
- void (*xmit)(void *priv, struct sk_buff *skb);
+ void (*xmit)(void *priv, struct sk_buff *skb, u16 proto);
void (*kick_up)(void *priv);
- void (*push_header)(void *priv, struct sk_buff *skb, u16);
struct sk_buff *(*alloc_skb)(void *priv, int len, int gfp_mask);
};
@@ -45,10 +54,10 @@ unsigned int
ippp_ccp_get_flags(struct ippp_ccp *ccp);
struct sk_buff *
-ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto);
+ippp_ccp_compress(struct ippp_ccp *ccp, struct sk_buff *skb, u16 *proto);
struct sk_buff *
-ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb, int *proto);
+ippp_ccp_decompress(struct ippp_ccp *ccp, struct sk_buff *skb, u16 *proto);
void
ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb);
diff --git a/drivers/isdn/i4l/isdn_ppp_mp.c b/drivers/isdn/i4l/isdn_ppp_mp.c
new file mode 100644
index 000000000000..e0a702e0973a
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ppp_mp.c
@@ -0,0 +1,352 @@
+/* Linux ISDN subsystem, PPP CCP support
+ *
+ * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "isdn_ppp_mp.h"
+#include "isdn_ppp_ccp.h"
+#include "isdn_common.h"
+#include "isdn_net_lib.h"
+#include "isdn_ppp.h"
+
+/* ====================================================================== */
+
+#define MP_END_FRAG 0x40
+#define MP_BEGIN_FRAG 0x80
+
+#define MP_MAX_QUEUE_LEN 16
+
+/* ====================================================================== */
+
+int
+ippp_mp_bind(isdn_net_dev *idev)
+{
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+
+ /* seq no last seen, maybe set to bundle min, when joining? */
+ ind_ppp->mp_rxseq = 0;
+
+ if (!list_empty(&idev->mlp->online))
+ return 0;
+
+ /* first channel for this link, do some setup */
+
+ inl_ppp->mp_cfg = 0; /* MPPP configuration */
+ inl_ppp->mp_txseq = 0; /* MPPP tx sequence number */
+ inl_ppp->mp_rxseq = (u32) -1;
+ skb_queue_head_init(&inl_ppp->mp_frags);
+
+ return 0;
+}
+
+int
+ippp_mp_bundle(isdn_net_dev *idev, int unit)
+{
+ isdn_net_local *lp = idev->mlp;
+ char ifn[IFNAMSIZ + 1];
+ isdn_net_dev *n_idev;
+ struct ind_ppp *ind_ppp;
+
+ printk(KERN_DEBUG "%s: %s: slave unit: %d\n",
+ __FUNCTION__, idev->name, unit);
+
+ sprintf(ifn, "ippp%d", unit);
+ list_for_each_entry(n_idev, &lp->slaves, slaves) {
+ if (strcmp(n_idev->name, ifn) == 0)
+ goto found;
+ }
+
+ printk(KERN_INFO "%s: cannot find %s\n", __FUNCTION__, ifn);
+ return -ENODEV;
+
+ found:
+ ind_ppp = n_idev->ind_priv;
+ if (!ind_ppp->ipppd) {
+ printk(KERN_INFO "%s: no ipppd?\n", __FUNCTION__);
+ return -ENXIO;
+ }
+ ind_ppp->pppcfg |= SC_ENABLE_IP;
+ isdn_net_online(n_idev);
+
+ return 0;
+}
+
+void
+ippp_mp_disconnected(isdn_net_dev *idev)
+{
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+
+ if (!list_empty(&idev->mlp->online))
+ return;
+
+ /* we're the last link going down */
+ skb_queue_purge(&inl_ppp->mp_frags);
+}
+
+void
+ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
+{
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+ unsigned char *p;
+ long txseq;
+
+ if (!(inl_ppp->mp_cfg & SC_MP_PROT)) {
+ return ippp_xmit(idev, skb);
+ }
+
+ /* we could do something smarter than just sending
+ * the complete packet as fragment... */
+
+ txseq = inl_ppp->mp_txseq++;
+
+ if (inl_ppp->mp_cfg & SC_OUT_SHORT_SEQ) {
+ /* sequence number: 12bit */
+ p = skb_push(skb, 2);
+ p[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((txseq >> 8) & 0xf);
+ p[1] = txseq & 0xff;
+ } else {
+ /* sequence number: 24bit */
+ p = skb_push(skb, 4);
+ p[0] = MP_BEGIN_FRAG | MP_END_FRAG;
+ p[1] = (txseq >> 16) & 0xff;
+ p[2] = (txseq >> 8) & 0xff;
+ p[3] = (txseq >> 0) & 0xff;
+ }
+ proto = PPP_MP;
+ skb = ippp_ccp_compress(ind_ppp->ccp, skb, &proto);
+ ippp_push_proto(ind_ppp, skb, proto);
+ ippp_xmit(idev, skb);
+}
+
+static void mp_receive(isdn_net_dev *idev, struct sk_buff *skb);
+
+void
+ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
+{
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+
+ if (inl_ppp->mp_cfg & SC_REJ_MP_PROT)
+ goto out;
+
+ skb = ippp_ccp_decompress(ind_ppp->ccp, skb, &proto);
+ if (!skb)
+ goto drop;
+
+ if (proto == PPP_MP)
+ return mp_receive(idev, skb);
+
+ out:
+ return ippp_receive(idev, skb, proto);
+
+ drop:
+ idev->mlp->stats.rx_errors++;
+ kfree_skb(skb);
+}
+
+#define MP_LONGSEQ_MASK 0x00ffffff
+#define MP_SHORTSEQ_MASK 0x00000fff
+#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK
+#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK
+#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK+1)>>1)
+#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK+1)>>1)
+
+/* sequence-wrap safe comparisions (for long sequence)*/
+#define MP_LT(a,b) ((a-b)&MP_LONGSEQ_MAXBIT)
+#define MP_LE(a,b) !((b-a)&MP_LONGSEQ_MAXBIT)
+#define MP_GT(a,b) ((b-a)&MP_LONGSEQ_MAXBIT)
+#define MP_GE(a,b) !((a-b)&MP_LONGSEQ_MAXBIT)
+
+#define MP_SEQUENCE(skb) (skb)->priority
+#define MP_FLAGS(skb) (skb)->cb[0]
+
+static u32
+get_seq(struct sk_buff *skb, u32 last_seq, int short_seq)
+{
+ u32 seq;
+ u16 shseq;
+ u8 flags;
+ int delta;
+
+ get_u8(skb->data, &flags);
+ if (short_seq) {
+ /* convert 12-bit short seq number to 24-bit long one */
+ get_u16(skb->data, &shseq);
+ delta = (shseq & MP_SHORTSEQ_MASK) -
+ (last_seq & MP_SHORTSEQ_MASK);
+ /* check for seqence wrap */
+ if (delta < 0)
+ delta += MP_SHORTSEQ_MAX + 1;
+
+ seq = last_seq + delta;
+ skb_pull(skb, 2);
+ } else {
+ get_u32(skb->data, &seq);
+ skb_pull(skb, 4);
+ }
+ seq &= MP_LONGSEQ_MASK;
+ MP_SEQUENCE(skb) = seq;
+ MP_FLAGS(skb) = flags;
+ return seq;
+}
+
+static int
+mp_insert_frag(struct sk_buff_head *frags, struct sk_buff *skb)
+{
+ struct sk_buff *p;
+
+ /* If our queue of not yet reassembled fragments grows too
+ large, throw away the oldest fragment */
+ if (skb_queue_len(frags) > MP_MAX_QUEUE_LEN)
+ kfree_skb(skb_dequeue(frags));
+
+ for (p = frags->next; p != (struct sk_buff *) frags; p = p->next) {
+ if (MP_LE(MP_SEQUENCE(skb), MP_SEQUENCE(p)))
+ break;
+ }
+ /* duplicate ? */
+ if (MP_SEQUENCE(skb) == MP_SEQUENCE(p))
+ return -EBUSY;
+
+ __skb_insert(skb, p->prev, p, frags);
+ return 0;
+}
+
+struct sk_buff *
+mp_complete_seq(isdn_net_local *lp, struct sk_buff *b, struct sk_buff *e)
+{
+ struct sk_buff *p, *n, *skb;
+ int len = 0;
+
+ if (b->next == e) {
+ /* sequence with only one frag */
+ skb_unlink(b);
+ return b;
+ }
+ for (p = b, n = p->next; p != e; p = n, n = p->next ) {
+ len += p->len;
+ }
+ // FIXME check against mrru?
+ skb = dev_alloc_skb(len);
+ if (!skb)
+ lp->stats.rx_errors++;
+
+ for (p = b, n = p->next; p != e; p = n, n = p->next ) {
+ if (skb)
+ memcpy(skb_put(skb, p->len), p->data, p->len);
+
+ skb_unlink(p);
+ kfree_skb(p);
+ }
+ return skb;
+}
+
+struct sk_buff *
+mp_reassemble(isdn_net_local *lp)
+{
+ struct inl_ppp *inl_ppp = lp->inl_priv;
+ struct sk_buff_head *frags = &inl_ppp->mp_frags;
+ struct sk_buff *p, *n, *pp, *start;
+ u32 min_seq = inl_ppp->mp_rxseq;
+ u32 next_seq = 0;
+
+ again:
+ start = NULL;
+ for (p = frags->next, n = p->next; p != (struct sk_buff *) frags; p = n, n = p->next ) {
+ if (!start) {
+ if (MP_FLAGS(p) & MP_BEGIN_FRAG) {
+ start = p;
+ next_seq = MP_SEQUENCE(p);
+ } else {
+ /* start frag is missing */
+ goto frag_missing;
+ }
+ }
+ /* we've seen the first fragment of this series */
+ if (MP_SEQUENCE(p) != next_seq) {
+ /* previous frag is missing */
+ goto frag_missing;
+ }
+ if (MP_FLAGS(p) & MP_END_FRAG) {
+ /* we got a full sequence */
+ return mp_complete_seq(lp, start, p->next);
+ }
+ next_seq = MP_SEQUENCE(p) + 1;
+ }
+ return NULL;
+
+ frag_missing:
+ if (MP_SEQUENCE(p) - 1 > min_seq)
+ /* may come later */
+ return NULL;
+
+ /* for all fragments up to p */
+ p = p->next;
+ for (pp = frags->next, n = pp->next; pp != p; pp = n, n = pp->next ) {
+ skb_unlink(pp);
+ kfree_skb(pp);
+ lp->stats.rx_errors++;
+ }
+ goto again;
+
+}
+
+static void
+mp_receive(isdn_net_dev *idev, struct sk_buff *skb)
+{
+ isdn_net_local *lp = idev->mlp;
+ struct inl_ppp *inl_ppp = lp->inl_priv;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ isdn_net_dev *qdev;
+ struct sk_buff_head *frags = &inl_ppp->mp_frags;
+ u32 seq;
+ u16 proto;
+
+ if (skb->len < (inl_ppp->mp_cfg & SC_IN_SHORT_SEQ ? 2 : 4))
+ goto drop;
+
+ seq = get_seq(skb, ind_ppp->mp_rxseq, inl_ppp->mp_cfg & SC_IN_SHORT_SEQ);
+ ind_ppp->mp_rxseq = seq;
+
+ if (inl_ppp->mp_rxseq == (u32) -1) {
+ /* first packet */
+ inl_ppp->mp_rxseq = seq;
+ }
+ if (MP_LT(seq, inl_ppp->mp_rxseq)) {
+ goto drop;
+ }
+ /* Find the minimum sequence number received over all channels.
+ * No fragments with numbers lower than this will arrive later. */
+ inl_ppp->mp_rxseq = seq;
+ list_for_each_entry(qdev, &lp->online, online) {
+ struct ind_ppp *ind_ppp = qdev->ind_priv;
+ if (MP_LT(ind_ppp->mp_rxseq, inl_ppp->mp_rxseq))
+ inl_ppp->mp_rxseq = ind_ppp->mp_rxseq;
+ }
+
+ /* Insert the skb into the list of received fragments, ordered by
+ * sequence number */
+ if (mp_insert_frag(frags, skb))
+ goto drop;
+
+ while ((skb = mp_reassemble(lp))) {
+ if (isdn_ppp_strip_proto(skb, &proto)) {
+ kfree_skb(skb);
+ continue;
+ }
+ ippp_receive(idev, skb, proto);
+ }
+ return;
+
+ drop:
+ lp->stats.rx_errors++;
+ kfree_skb(skb);
+}
diff --git a/drivers/isdn/i4l/isdn_ppp_mp.h b/drivers/isdn/i4l/isdn_ppp_mp.h
new file mode 100644
index 000000000000..e684edebcd07
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ppp_mp.h
@@ -0,0 +1,58 @@
+/* Linux ISDN subsystem, PPP CCP support
+ *
+ * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de)
+ * 1995,96 by Thinking Objects Software GmbH Wuerzburg
+ * 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __ISDN_PPP_MP_H__
+#define __ISDN_PPP_MP_H__
+
+#include "isdn_net_lib.h"
+
+#ifdef CONFIG_ISDN_MPP
+
+int ippp_mp_bind(isdn_net_dev *idev);
+void ippp_mp_disconnected(isdn_net_dev *idev);
+int ippp_mp_bundle(isdn_net_dev *idev, int val);
+void ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb, u16 proto);
+void ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto);
+
+#else
+
+static inline int
+ippp_mp_bind(isdn_net_dev *idev)
+{
+ return 0;
+}
+
+static void
+ippp_mp_disconnected(isdn_net_dev *idev)
+{
+}
+
+static inline int
+ippp_mp_bundle(isdn_net_dev *idev, int val)
+{
+ return -EINVAL;
+}
+
+static inline void
+ippp_mp_xmit(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
+{
+ ippp_xmit(idev, skb, proto);
+}
+
+static inline void
+ippp_mp_receive(isdn_net_dev *idev, struct sk_buff *skb, u16 proto)
+{
+ ippp_receive(idev, skb, proto);
+}
+
+#endif
+
+#endif
diff --git a/drivers/isdn/i4l/isdn_ppp_vj.c b/drivers/isdn/i4l/isdn_ppp_vj.c
new file mode 100644
index 000000000000..ff48fa7f35e2
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ppp_vj.c
@@ -0,0 +1,128 @@
+/* Linux ISDN subsystem, PPP VJ header compression
+ *
+ * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#include "isdn_ppp_vj.h"
+#include "isdn_common.h"
+#include "isdn_net_lib.h"
+#include "isdn_ppp.h"
+
+struct slcompress *
+ippp_vj_alloc(void)
+{
+ return slhc_init(16, 16);
+}
+
+void
+ippp_vj_free(struct slcompress *slcomp)
+{
+ slhc_free(slcomp);
+}
+
+int
+ippp_vj_set_maxcid(isdn_net_dev *idev, int val)
+{
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+ struct slcompress *sltmp;
+
+ sltmp = slhc_init(16, val + 1);
+ if (!sltmp)
+ return -ENOMEM;
+
+ if (inl_ppp->slcomp)
+ slhc_free(inl_ppp->slcomp);
+
+ inl_ppp->slcomp = sltmp;
+ return 0;
+}
+
+void
+ippp_vj_decompress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 proto)
+{
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+ struct slcompress *slcomp = inl_ppp->slcomp;
+ struct sk_buff *skb;
+ int len;
+
+ switch (proto) {
+ case PPP_VJC_UNCOMP:
+ if (slhc_remember(slcomp, skb_old->data, skb_old->len) <= 0)
+ goto drop;
+
+ skb = skb_old;
+ break;
+ case PPP_VJC_COMP:
+ skb = dev_alloc_skb(skb_old->len + 128);
+ if (!skb)
+ goto drop;
+
+ memcpy(skb->data, skb_old->data, skb_old->len);
+ len = slhc_uncompress(slcomp, skb->data, skb_old->len);
+ if (len < 0)
+ goto drop_both;
+
+ skb_put(skb, len);
+ kfree_skb(skb_old);
+ break;
+ default:
+ isdn_BUG();
+ goto drop;
+ }
+ isdn_netif_rx(idev, skb, htons(ETH_P_IP));
+ return;
+
+ drop_both:
+ kfree_skb(skb);
+ drop:
+ kfree_skb(skb_old);
+ idev->mlp->stats.rx_dropped++;
+}
+
+struct sk_buff *
+ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto)
+{
+ struct inl_ppp *inl_ppp = idev->mlp->inl_priv;
+ struct ind_ppp *ind_ppp = idev->ind_priv;
+ struct slcompress *slcomp = inl_ppp->slcomp;
+ struct sk_buff *skb;
+ unsigned char *buf;
+ int len;
+
+ if (!(ind_ppp->pppcfg & SC_COMP_TCP) || *proto != PPP_IP)
+ return skb_old;
+
+ skb = isdn_ppp_dev_alloc_skb(idev, skb_old->len, GFP_ATOMIC);
+ if (!skb)
+ return skb_old;
+
+ skb_put(skb, skb_old->len);
+ buf = skb_old->data;
+ // FIXME flag should be per bundle
+ len = slhc_compress(slcomp, skb_old->data, skb_old->len, skb->data,
+ &buf, !(ind_ppp->pppcfg & SC_NO_TCP_CCID));
+
+ if (buf == skb_old->data) {
+ kfree_skb(skb);
+ skb = skb_old;
+ } else {
+ kfree_skb(skb_old);
+ }
+ skb_trim(skb, len);
+
+ /* cslip style -> PPP */
+ if ((skb->data[0] & SL_TYPE_COMPRESSED_TCP) == SL_TYPE_COMPRESSED_TCP) {
+ skb->data[0] &= ~SL_TYPE_COMPRESSED_TCP;
+ *proto = PPP_VJC_COMP;
+ } else if ((skb->data[0] & SL_TYPE_UNCOMPRESSED_TCP) == SL_TYPE_UNCOMPRESSED_TCP) {
+ skb->data[0] &= ~SL_TYPE_UNCOMPRESSED_TCP;
+ skb->data[0] |= SL_TYPE_IP;
+ *proto = PPP_VJC_UNCOMP;
+ }
+ return skb;
+}
+
diff --git a/drivers/isdn/i4l/isdn_ppp_vj.h b/drivers/isdn/i4l/isdn_ppp_vj.h
new file mode 100644
index 000000000000..e1fdeac199b7
--- /dev/null
+++ b/drivers/isdn/i4l/isdn_ppp_vj.h
@@ -0,0 +1,61 @@
+/* Linux ISDN subsystem, PPP VJ header compression
+ *
+ * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * 1999-2002 by Kai Germaschewski <kai@germaschewski.name>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef __ISDN_PPP_VJ_H__
+#define __ISDN_PPP_VJ_H__
+
+#include "isdn_net_lib.h"
+
+#ifdef CONFIG_ISDN_PPP_VJ
+
+
+struct slcompress *
+ippp_vj_alloc(void);
+
+void
+ippp_vj_free(struct slcompress *slcomp);
+
+int
+ippp_vj_set_maxcid(isdn_net_dev *idev, int val);
+
+void
+ippp_vj_decompress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 proto);
+
+struct sk_buff *
+ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto);
+
+
+#else
+
+
+static inline struct slcompress *
+ippp_vj_alloc(void)
+{ return (struct slcompress *) !NULL; }
+
+static inline void
+ippp_vj_free(struct slcompress *slcomp)
+{ }
+
+static inline int
+ippp_vj_set_maxcid(isdn_net_dev *idev, int val)
+{ return -EINVAL; }
+
+static inline struct sk_buff *
+ippp_vj_decompress(struct slcompress *slcomp, struct sk_buff *skb_old,
+ u16 proto)
+{ return skb_old; }
+
+static inline struct sk_buff *
+ippp_vj_compress(isdn_net_dev *idev, struct sk_buff *skb_old, u16 *proto)
+{ return skb_old; }
+
+
+#endif
+
+#endif
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index c7b3f8ce4c71..32fe087ce1a2 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1,17 +1,20 @@
-/* $Id: isdn_tty.c,v 1.94.6.9 2001/11/06 20:58:29 kai Exp $
- *
- * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
+/* Linux ISDN subsystem, tty functions and AT-command emulator
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
-#undef ISDN_TTY_STAT_DEBUG
-#include <linux/config.h>
+#define ISDN_TTY_STAT_DEBUG
+#define ISDN_DEBUG_MODEM_HUP
+#define ISDN_DEBUG_MODEM_VOICE
+#define ISDN_DEBUG_MODEM_OPEN
+#define ISDN_DEBUG_MODEM_IOCTL
+#define ISDN_DEBUG_MODEM_ICALL
+
+#include <linux/module.h>
#include <linux/isdn.h>
#include "isdn_common.h"
#include "isdn_tty.h"
@@ -21,21 +24,40 @@
#define VBUFX (VBUF/16)
#endif
+#define RING_TIMEOUT (5*HZ) /* repeat RING every 5 secs */
#define FIX_FILE_TRANSFER
#define DUMMY_HAYES_AT
/* Prototypes */
+static void isdn_tty_modem_xmit(struct modem_info *info);
static int isdn_tty_edit_at(const char *, int, modem_info *, int);
-static void isdn_tty_check_esc(const u_char *, u_char, int, int *, int *, int);
+static void isdn_tty_escape_timer(unsigned long data);
+static void isdn_tty_ring_timer(unsigned long data);
+static void isdn_tty_connect_timer(unsigned long data);
+static void isdn_tty_check_esc(struct modem_info *info,
+ const unsigned char *p, int count);
static void isdn_tty_modem_reset_regs(modem_info *, int);
static void isdn_tty_cmd_ATA(modem_info *);
static void isdn_tty_flush_buffer(struct tty_struct *);
static void isdn_tty_modem_result(int, modem_info *);
+static int isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c);
+static int isdn_tty_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb);
#ifdef CONFIG_ISDN_AUDIO
static int isdn_tty_countDLE(unsigned char *, int);
#endif
+static int
+isdn_tty_event_callback(struct isdn_slot *slot, int pr, void *arg)
+{
+ switch (pr) {
+ case EV_DATA_IND:
+ return isdn_tty_rcv_skb(slot, arg);
+ default:
+ return isdn_tty_stat_callback(slot, arg);
+ }
+}
+
/* Leave this unchanged unless you know what you do! */
#define MODEM_PARANOIA_CHECK
#define MODEM_DO_RESTART
@@ -48,14 +70,13 @@ static char *isdn_ttyname_ttyI = "ttyI";
static char *isdn_ttyname_cui = "cui";
#endif
+struct isdn_modem isdn_mdm;
+
static int bit2si[8] =
{1, 5, 7, 7, 7, 7, 7, 7};
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.94.6.9 $";
-
-
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. This
* is done to speed up tty-receiving if the receive-queue is empty.
@@ -111,82 +132,166 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
return 0;
}
+/*
+ * isdn_slot_readbchan() tries to get data from the read-queue.
+ * It MUST be called with interrupts off.
+ */
+static int
+isdn_tty_readbchan(struct modem_info *info, u_char * buf, u_char * fp, int len)
+{
+ int count;
+ int count_pull;
+ int count_put;
+ int dflag;
+ struct sk_buff *skb;
+ u_char *cp;
+
+ if (skb_queue_empty(&info->rpqueue))
+ return 0;
+
+ if (len > info->rcvcount)
+ len = info->rcvcount;
+ cp = buf;
+ count = 0;
+ while (len) {
+ if (!(skb = skb_peek(&info->rpqueue)))
+ break;
+#ifdef CONFIG_ISDN_AUDIO
+ if (ISDN_AUDIO_SKB_LOCK(skb))
+ break;
+ ISDN_AUDIO_SKB_LOCK(skb) = 1;
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb) || info->DLEflag) {
+ char *p = skb->data;
+
+ dflag = 0;
+ count_pull = count_put = 0;
+ while ((count_pull < skb->len) && (len > 0)) {
+ len--;
+ if (info->DLEflag) {
+ *cp++ = DLE;
+ info->DLEflag = 0;
+ } else {
+ *cp++ = *p;
+ if (*p == DLE) {
+ info->DLEflag = 1;
+ (ISDN_AUDIO_SKB_DLECOUNT(skb))--;
+ }
+ p++;
+ count_pull++;
+ }
+ count_put++;
+ }
+ if (count_pull >= skb->len)
+ dflag = 1;
+ } else {
+#endif
+ /* No DLE's in buff, so simply copy it */
+ dflag = 1;
+ if ((count_pull = skb->len) > len) {
+ count_pull = len;
+ dflag = 0;
+ }
+ count_put = count_pull;
+ memcpy(cp, skb->data, count_put);
+ cp += count_put;
+ len -= count_put;
+#ifdef CONFIG_ISDN_AUDIO
+ }
+#endif
+ count += count_put;
+ if (fp) {
+ memset(fp, 0, count_put);
+ fp += count_put;
+ }
+ if (dflag) {
+ /* We got all the data in this buff.
+ * Now we can dequeue it.
+ */
+ if (fp)
+ *(fp - 1) = 0xff;
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ skb = skb_dequeue(&info->rpqueue);
+ dev_kfree_skb(skb);
+ } else {
+ /* Not yet emptied this buff, so it
+ * must stay in the queue, for further calls
+ * but we pull off the data we got until now.
+ */
+ skb_pull(skb, count_pull);
+#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+#endif
+ }
+ info->rcvcount -= count_put;
+ }
+ return count;
+}
+
/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
* It tries getting received data from the receive queue an stuff it into
* the tty's flip-buffer.
*/
-void
-isdn_tty_readmodem(void)
+static void
+isdn_tty_readmodem(unsigned long data)
{
- int resched = 0;
- int midx;
- int i;
+ struct modem_info *info = (struct modem_info *) data;
int c;
int r;
ulong flags;
struct tty_struct *tty;
- modem_info *info;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if ((midx = isdn_slot_m_idx(i)) >= 0) {
- info = &dev->mdm.info[midx];
- if (info->online) {
- r = 0;
+ if (!info->online)
+ return;
+
+ r = 0;
#ifdef CONFIG_ISDN_AUDIO
- isdn_audio_eval_dtmf(info);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_eval_silence(info);
-#endif
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- c = TTY_FLIPBUF_SIZE - tty->flip.count;
- if (c > 0) {
- save_flags(flags);
- cli();
- r = isdn_slot_readbchan(info->isdn_slot,
- tty->flip.char_buf_ptr,
- tty->flip.flag_buf_ptr, c);
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- memset(tty->flip.flag_buf_ptr, 0, r);
- tty->flip.count += r;
- tty->flip.flag_buf_ptr += r;
- tty->flip.char_buf_ptr += r;
- if (r)
- schedule_delayed_work(&tty->flip.work, 1);
- restore_flags(flags);
- }
- } else
- r = 1;
- } else
- r = 1;
- if (r) {
- info->rcvsched = 0;
- resched = 1;
- } else
- info->rcvsched = 1;
+ isdn_audio_eval_dtmf(info);
+ if ((info->vonline & 1) && (info->emu.vpar[1]))
+ isdn_audio_eval_silence(info);
+#endif
+ if ((tty = info->tty)) {
+ if (info->mcr & UART_MCR_RTS) {
+ c = TTY_FLIPBUF_SIZE - tty->flip.count;
+ if (c > 0) {
+ save_flags(flags);
+ cli();
+ r = isdn_tty_readbchan(info,
+ tty->flip.char_buf_ptr,
+ tty->flip.flag_buf_ptr, c);
+ /* CISCO AsyncPPP Hack */
+ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+ memset(tty->flip.flag_buf_ptr, 0, r);
+ tty->flip.count += r;
+ tty->flip.flag_buf_ptr += r;
+ tty->flip.char_buf_ptr += r;
+ if (r)
+ schedule_delayed_work(&tty->flip.work, 1);
+ restore_flags(flags);
}
- }
- }
- if (!resched)
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
+ } else
+ r = 1;
+ } else
+ r = 1;
+
+ if (r) {
+ info->rcvsched = 0;
+ mod_timer(&info->read_timer, jiffies + 4);
+ } else
+ info->rcvsched = 1;
}
-int
-isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
+static int
+isdn_tty_rcv_skb(struct isdn_slot *slot, struct sk_buff *skb)
{
ulong flags;
- int midx;
#ifdef CONFIG_ISDN_AUDIO
int ifmt;
#endif
modem_info *info;
- if ((midx = isdn_slot_m_idx(i)) < 0) {
- /* if midx is invalid, packet is not for tty */
- return 0;
- }
- info = &dev->mdm.info[midx];
+ info = slot->priv;
#ifdef CONFIG_ISDN_AUDIO
ifmt = 1;
@@ -269,7 +374,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
/* Try to deliver directly via tty-flip-buf if queue is empty */
save_flags(flags);
cli();
- if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
+ if (skb_queue_empty(&info->rpqueue))
if (isdn_tty_try_read(info, skb)) {
restore_flags(flags);
return 1;
@@ -277,17 +382,15 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
/* Direct deliver failed or queue wasn't empty.
* Queue up for later dequeueing via timer-irq.
*/
- __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
- dev->drv[di]->rcvcount[channel] +=
- (skb->len
+ isdn_tty_queue_tail(info, skb, skb->len
#ifdef CONFIG_ISDN_AUDIO
+ ISDN_AUDIO_SKB_DLECOUNT(skb)
#endif
- );
+ );
restore_flags(flags);
/* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+ if (dev->modempoll && info->rcvsched)
+ mod_timer(&info->read_timer, jiffies + 4);
return 1;
}
@@ -627,7 +730,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
int si = 7;
int l2 = m->mdmreg[REG_L2PROT];
ulong flags;
- int i;
+ struct isdn_slot *slot;
int j;
for (j = 7; j >= 0; j--)
@@ -650,8 +753,8 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
+ slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
+ if (!slot) {
restore_flags(flags);
isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
@@ -663,8 +766,11 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
.msn = m->msn,
.phone = n,
};
- info->isdn_slot = i;
- isdn_slot_set_m_idx(i, info->line);
+
+ info->isdn_slot = slot;
+ slot->usage |= ISDN_USAGE_MODEM;
+ slot->priv = info;
+ slot->event_cb = isdn_tty_event_callback;
info->last_dir = 1;
info->last_l2 = l2;
strcpy(info->last_num, n);
@@ -676,9 +782,8 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m)
}
#endif
info->dialing = 1;
- info->emu.carrierwait = 0;
isdn_slot_dial(info->isdn_slot, &dial);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
+ mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ);
}
}
@@ -690,13 +795,13 @@ void
isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
- int slot;
+ struct isdn_slot *slot;
if (!info)
return;
slot = info->isdn_slot;
- if (slot < 0)
+ if (!slot)
return;
#ifdef ISDN_DEBUG_MODEM_HUP
@@ -743,11 +848,12 @@ isdn_tty_modem_hup(modem_info * info, int local)
if (local)
isdn_slot_command(slot, ISDN_CMD_HANGUP, &cmd);
- isdn_slot_all_eaz(slot);
info->emu.mdmreg[REG_RINGCNT] = 0;
+ skb_queue_purge(&info->rpqueue);
+ slot->priv = NULL;
+ slot->event_cb = NULL;
isdn_slot_free(slot);
- isdn_slot_set_m_idx(slot, -1);
- info->isdn_slot = -1;
+ info->isdn_slot = NULL;
}
/*
@@ -781,7 +887,6 @@ isdn_tty_suspend(char *id, modem_info * info, atemu * m)
cmd.parm.cmsg.Length = l+18;
cmd.parm.cmsg.Command = CAPI_FACILITY;
cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = isdn_slot_driver(info->isdn_slot) + 1;
cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
cmd.parm.cmsg.para[1] = 0;
cmd.parm.cmsg.para[2] = l + 3;
@@ -808,7 +913,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
int l2 = m->mdmreg[REG_L2PROT];
isdn_ctrl cmd;
ulong flags;
- int i;
+ struct isdn_slot *slot;
int j;
int l;
@@ -833,14 +938,15 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
+ slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
+ if (!slot) {
restore_flags(flags);
isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
- info->isdn_slot = i;
- isdn_slot_set_m_idx(i, info->line);
- isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_OUTGOING);
+ info->isdn_slot = slot;
+ slot->usage |= ISDN_USAGE_MODEM;
+ slot->priv = info;
+ slot->event_cb = isdn_tty_event_callback;
info->last_dir = 1;
// strcpy(info->last_num, n);
restore_flags(flags);
@@ -852,7 +958,6 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
cmd.parm.cmsg.Length = l+18;
cmd.parm.cmsg.Command = CAPI_FACILITY;
cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = isdn_slot_driver(info->isdn_slot) + 1;
cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
cmd.parm.cmsg.para[1] = 0;
cmd.parm.cmsg.para[2] = l+3;
@@ -864,7 +969,7 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m)
// strcpy(dev->num[i], n);
isdn_info_update();
isdn_slot_command(info->isdn_slot, CAPI_PUT_MESSAGE, &cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
+ mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ);
}
}
@@ -880,7 +985,7 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
int l2 = m->mdmreg[REG_L2PROT];
isdn_ctrl cmd;
ulong flags;
- int i;
+ struct isdn_slot *slot;
int j;
int l;
@@ -909,14 +1014,15 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
m->mdmreg[REG_SI1I] = si2bit[si];
save_flags(flags);
cli();
- i = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
- if (i < 0) {
+ slot = isdn_get_free_slot(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn);
+ if (!slot) {
restore_flags(flags);
isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
} else {
- info->isdn_slot = i;
- isdn_slot_set_m_idx(i, info->line);
- isdn_slot_set_usage(i, isdn_slot_usage(i) | ISDN_USAGE_OUTGOING);
+ info->isdn_slot = slot;
+ slot->usage |= ISDN_USAGE_MODEM;
+ slot->priv = info;
+ slot->event_cb = isdn_tty_event_callback;
info->last_dir = 1;
restore_flags(flags);
info->last_l2 = l2;
@@ -927,7 +1033,6 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
cmd.parm.cmsg.Length = l+14;
cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
cmd.parm.cmsg.Subcommand = CAPI_REQ;
- cmd.parm.cmsg.adr.Controller = isdn_slot_driver(info->isdn_slot) + 1;
cmd.parm.cmsg.para[0] = l+1;
strncpy(&cmd.parm.cmsg.para[1], msg, l);
cmd.parm.cmsg.para[l+1] = 0xd;
@@ -1028,7 +1133,6 @@ isdn_tty_startup(modem_info * info)
return 0;
save_flags(flags);
cli();
- isdn_MOD_INC_USE_COUNT();
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line);
#endif
@@ -1066,7 +1170,6 @@ isdn_tty_shutdown(modem_info * info)
#endif
save_flags(flags);
cli(); /* Disable interrupts */
- isdn_MOD_DEC_USE_COUNT();
info->msr &= ~UART_MSR_RI;
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
@@ -1099,7 +1202,6 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
{
int c;
int total = 0;
- int di;
modem_info *info = (modem_info *) tty->driver_data;
atemu *m = &info->emu;
@@ -1113,9 +1215,8 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
c = count;
if (c > info->xmit_size - info->xmit_count)
c = info->xmit_size - info->xmit_count;
- di = isdn_slot_driver(info->isdn_slot);
- if (di >= 0 && c > dev->drv[di]->maxbufsize)
- c = dev->drv[di]->maxbufsize;
+ if (info->isdn_slot && c > isdn_slot_maxbufsize(info->isdn_slot))
+ c = isdn_slot_maxbufsize(info->isdn_slot);
if (c <= 0)
break;
if ((info->online > 1)
@@ -1123,13 +1224,6 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
|| (info->vonline & 3)
#endif
) {
-#ifdef CONFIG_ISDN_AUDIO
- if (!info->vonline)
-#endif
- isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
- &(m->pluscount),
- &(m->lastplus),
- from_user);
if (from_user) {
if (copy_from_user(&(info->xmit_buf[info->xmit_count]), buf, c)) {
total = -EFAULT;
@@ -1138,6 +1232,10 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
} else
memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
#ifdef CONFIG_ISDN_AUDIO
+ if (!info->vonline)
+#endif
+ isdn_tty_check_esc(info, &info->xmit_buf[info->xmit_count], c);
+#ifdef CONFIG_ISDN_AUDIO
if (info->vonline) {
int cc = isdn_tty_handleDLEdown(info, m, c);
if (info->vonline & 2) {
@@ -1206,11 +1304,7 @@ isdn_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int co
}
atomic_dec(&info->xmit_lock);
if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
- if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
+ isdn_tty_modem_xmit(info);
}
out:
if (from_user)
@@ -1278,7 +1372,7 @@ isdn_tty_flush_chars(struct tty_struct *tty)
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_chars"))
return;
if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
+ isdn_tty_modem_xmit(info);
}
/*
@@ -1666,13 +1760,16 @@ static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
modem_info *info;
- int retval,
- line;
+ int retval, line;
+
+ /* FIXME. This is not unload-race free AFAICS */
+
+ MOD_INC_USE_COUNT;
line = minor(tty->device) - tty->driver.minor_start;
if (line < 0 || line > ISDN_MAX_CHANNELS)
return -ENODEV;
- info = &dev->mdm.info[line];
+ info = &isdn_mdm.info[line];
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_open"))
return -ENODEV;
#ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1726,7 +1823,8 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
ulong timeout;
if (!info || isdn_tty_paranoia_check(info, tty->device, "isdn_tty_close"))
- return;
+ goto out;
+
save_flags(flags);
cli();
if (tty_hung_up_p(filp)) {
@@ -1734,7 +1832,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n");
#endif
- return;
+ goto out;
}
if ((tty->count == 1) && (info->count != 1)) {
/*
@@ -1758,7 +1856,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
#endif
- return;
+ goto out;
}
info->flags |= ISDN_ASYNC_CLOSING;
/*
@@ -1813,6 +1911,8 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close normal exit\n");
#endif
+ out:
+ MOD_DEC_USE_COUNT;
}
/*
@@ -1942,11 +2042,11 @@ modem_write_profile(atemu * m)
int
isdn_tty_init(void)
{
- modem *m;
+ struct isdn_modem *m;
int i, retval;
modem_info *info;
- m = &dev->mdm;
+ m = &isdn_mdm;
memset(&m->tty_modem, 0, sizeof(struct tty_driver));
m->tty_modem.magic = TTY_DRIVER_MAGIC;
m->tty_modem.name = isdn_ttyname_ttyI;
@@ -2025,7 +2125,22 @@ isdn_tty_init(void)
info->normal_termios = m->tty_modem.init_termios;
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
- info->isdn_slot = -1;
+ info->isdn_slot = NULL;
+ init_timer(&info->escape_timer);
+ info->escape_timer.data = (unsigned long) info;
+ info->escape_timer.function = isdn_tty_escape_timer;
+ init_timer(&info->ring_timer);
+ info->ring_timer.data = (unsigned long) info;
+ info->ring_timer.function = isdn_tty_ring_timer;
+ init_timer(&info->connect_timer);
+ info->connect_timer.data = (unsigned long) info;
+ info->connect_timer.function = isdn_tty_connect_timer;
+ init_timer(&info->read_timer);
+ info->read_timer.data = (unsigned long) info;
+ info->read_timer.function = isdn_tty_readmodem;
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ skb_queue_head_init(&info->rpqueue);
info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
skb_queue_head_init(&info->xmit_queue);
#ifdef CONFIG_ISDN_AUDIO
@@ -2052,9 +2167,9 @@ isdn_tty_init(void)
#endif
kfree(info->xmit_buf - 4);
}
- tty_unregister_driver(&dev->mdm.cua_modem);
+ tty_unregister_driver(&isdn_mdm.cua_modem);
err_unregister_tty:
- tty_unregister_driver(&dev->mdm.tty_modem);
+ tty_unregister_driver(&isdn_mdm.tty_modem);
err:
return retval;
}
@@ -2062,20 +2177,20 @@ isdn_tty_init(void)
void
isdn_tty_exit(void)
{
- modem *m = &dev->mdm;
modem_info *info;
int i;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &m->info[i];
+ info = &isdn_mdm.info[i];
isdn_tty_cleanup_xmit(info);
+ skb_queue_purge(&info->rpqueue);
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
kfree(info->xmit_buf - 4);
}
- tty_unregister_driver(&dev->mdm.cua_modem);
- tty_unregister_driver(&dev->mdm.tty_modem);
+ tty_unregister_driver(&isdn_mdm.cua_modem);
+ tty_unregister_driver(&isdn_mdm.tty_modem);
}
/*
@@ -2141,12 +2256,11 @@ isdn_tty_match_icall(char *cid, atemu *emu, int di)
* CID is longer.
*/
int
-isdn_tty_find_icall(int di, int ch, setup_parm *setup)
+isdn_tty_find_icall(struct isdn_slot *slot, setup_parm *setup)
{
char *eaz;
int i;
int wret;
- int idx;
int si1;
int si2;
char *nr;
@@ -2171,16 +2285,15 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
save_flags(flags);
cli();
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
+ modem_info *info = &isdn_mdm.info[i];
if (info->count == 0)
continue;
if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
(info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
- idx = isdn_dc2minor(di, ch);
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
- printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
+ printk(KERN_DEBUG "m_fi: sl=%d flags=%08lx drv=%d ch=%d usg=%d\n", sl,
info->flags, info->isdn_driver, info->isdn_channel,
dev->usage[idx]);
#endif
@@ -2188,27 +2301,27 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
#ifndef FIX_FILE_TRANSFER
(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
#endif
- (info->isdn_slot == -1) &&
- (USG_NONE(isdn_slot_usage(idx)))) {
+ (!info->isdn_slot)) {
int matchret;
- if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
+ if ((matchret = isdn_tty_match_icall(eaz, &info->emu, slot->di)) > wret)
wret = matchret;
if (!matchret) { /* EAZ is matching */
- info->isdn_slot = idx;
- isdn_slot_set_m_idx(idx, info->line);
- strcpy(isdn_slot_num(idx), nr);
+ info->isdn_slot = slot;
+ slot->usage |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]);
+ slot->priv = info;
+ slot->event_cb = isdn_tty_event_callback;
+ strcpy(slot->num, nr);
strcpy(info->emu.cpn, eaz);
info->emu.mdmreg[REG_SI1I] = si2bit[si1];
info->emu.mdmreg[REG_PLAN] = setup->plan;
info->emu.mdmreg[REG_SCREEN] = setup->screen;
- isdn_slot_set_usage(idx, (isdn_slot_usage(idx) & ISDN_USAGE_EXCLUSIVE) | isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]));
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
info->line);
info->msr |= UART_MSR_RI;
isdn_tty_modem_result(RESULT_RING, info);
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
+ mod_timer(&info->ring_timer, jiffies + RING_TIMEOUT);
return 1;
}
}
@@ -2216,24 +2329,22 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
}
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
- ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
+ (wret != 2)? "rejected" : "ignored");
return (wret == 2)?3:0;
}
#define TTY_IS_ACTIVE(info) \
(info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
-int
-isdn_tty_stat_callback(int i, isdn_ctrl *c)
+static int
+isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c)
{
- int mi;
+ isdn_ctrl cmd;
modem_info *info;
char *e;
- if (i < 0)
- return 0;
- if ((mi = isdn_slot_m_idx(i)) >= 0) {
- info = &dev->mdm.info[mi];
+ info = slot->priv;
+ if (1) {
switch (c->command) {
case ISDN_STAT_CINF:
printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
@@ -2246,15 +2357,12 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#ifdef ISDN_TTY_STAT_DEBUG
printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
#endif
- if ((info->isdn_slot == isdn_dc2minor(c->driver, c->arg))) {
- info->msr |= UART_MSR_CTS;
- if (info->send_outstanding)
- if (!(--info->send_outstanding))
- info->lsr |= UART_LSR_TEMT;
- isdn_tty_tint(info);
- return 1;
- }
- break;
+ info->msr |= UART_MSR_CTS;
+ if (info->send_outstanding)
+ if (!(--info->send_outstanding))
+ info->lsr |= UART_LSR_TEMT;
+ isdn_tty_tint(info);
+ return 1;
case ISDN_STAT_CAUSE:
#ifdef ISDN_TTY_STAT_DEBUG
printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
@@ -2281,6 +2389,7 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
#endif
if (TTY_IS_ACTIVE(info)) {
if (info->dialing == 1) {
+ isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTB, &cmd);
info->dialing = 2;
return 1;
}
@@ -2330,14 +2439,14 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
info->last_dir = 0;
info->dialing = 0;
info->rcvsched = 1;
- if (USG_MODEM(isdn_slot_usage(i))) {
+ if (USG_MODEM(slot->usage)) {
if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
strcpy(info->emu.connmsg, c->parm.num);
isdn_tty_modem_result(RESULT_CONNECT, info);
} else
isdn_tty_modem_result(RESULT_CONNECT64000, info);
}
- if (USG_VOICE(isdn_slot_usage(i)))
+ if (USG_VOICE(slot->usage))
isdn_tty_modem_result(RESULT_VCON, info);
return 1;
}
@@ -2354,34 +2463,6 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
return 1;
}
break;
- case ISDN_STAT_NODCH:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
-#endif
- if (TTY_IS_ACTIVE(info)) {
- if (info->dialing) {
- info->dialing = 0;
- info->last_l2 = -1;
- info->last_si = 0;
- sprintf(info->last_cause, "0000");
- isdn_tty_modem_result(RESULT_NO_DIALTONE, info);
- }
- isdn_tty_modem_hup(info, 0);
- return 1;
- }
- break;
- case ISDN_STAT_UNLOAD:
-#ifdef ISDN_TTY_STAT_DEBUG
- printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
-#endif
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- info = &dev->mdm.info[i];
- if (isdn_slot_driver(info->isdn_slot) == c->driver) {
- if (info->online)
- isdn_tty_modem_hup(info, 1);
- }
- }
- return 1;
#ifdef CONFIG_ISDN_TTY_FAX
case ISDN_STAT_FAXIND:
if (TTY_IS_ACTIVE(info)) {
@@ -2428,7 +2509,6 @@ isdn_tty_at_cout(char *msg, modem_info * info)
ulong flags;
struct sk_buff *skb = 0;
char *sp = 0;
- int di,ch;
if (!msg) {
printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n");
@@ -2444,9 +2524,8 @@ isdn_tty_at_cout(char *msg, modem_info * info)
/* use queue instead of direct flip, if online and */
/* data is in queue or flip buffer is full */
- di = isdn_slot_driver(info->isdn_slot); ch = isdn_slot_channel(info->isdn_slot);
if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) ||
- (!skb_queue_empty(&dev->drv[di]->rpqueue[ch])))) {
+ (!skb_queue_empty(&info->rpqueue)))) {
skb = alloc_skb(strlen(msg)
#ifdef CONFIG_ISDN_AUDIO
+ sizeof(isdn_audio_skb)
@@ -2489,13 +2568,11 @@ isdn_tty_at_cout(char *msg, modem_info * info)
}
}
if (skb) {
- __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb);
- dev->drv[di]->rcvcount[ch] += skb->len;
+ isdn_tty_queue_tail(info, skb, skb->len);
restore_flags(flags);
/* Schedule dequeuing */
- if ((dev->modempoll) && (info->rcvsched))
- isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
-
+ if (dev->modempoll && info->rcvsched)
+ mod_timer(&info->read_timer, jiffies + 4);
} else {
restore_flags(flags);
schedule_delayed_work(&tty->flip.work, 1);
@@ -2508,7 +2585,7 @@ isdn_tty_at_cout(char *msg, modem_info * info)
static void
isdn_tty_on_hook(modem_info * info)
{
- if (info->isdn_slot >= 0) {
+ if (info->isdn_slot) {
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
#endif
@@ -2525,55 +2602,56 @@ isdn_tty_off_hook(void)
#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */
#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec */
+static void
+isdn_tty_escape_timer(unsigned long data)
+{
+ struct modem_info *info = (struct modem_info *) data;
+
+ if (!info->online)
+ return;
+
+ info->emu.pluscount = 0;
+ info->online = 0;
+ isdn_tty_modem_result(RESULT_OK, info);
+}
+
/*
* Check Buffer for Modem-escape-sequence, activate timer-callback to
* isdn_tty_modem_escape() if sequence found.
- *
- * Parameters:
- * p pointer to databuffer
- * plus escape-character
- * count length of buffer
- * pluscount count of valid escape-characters so far
- * lastplus timestamp of last character
*/
-static void
-isdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount,
- int *lastplus, int from_user)
+static void isdn_tty_check_esc(struct modem_info *info,
+ const unsigned char *p, int count)
{
- char cbuf[3];
+ unsigned char plus = info->emu.mdmreg[REG_ESC];
if (plus > 127)
return;
+
if (count > 3) {
p += count - 3;
count = 3;
- *pluscount = 0;
+ info->emu.pluscount = 0;
+ info->emu.lastplus = jiffies;
}
- if (from_user) {
- if (copy_from_user(cbuf, p, count))
- return;
- p = cbuf;
- }
- while (count > 0) {
- if (*(p++) == plus) {
- if ((*pluscount)++) {
- /* Time since last '+' > 0.5 sec. ? */
- if (time_after(jiffies, *lastplus + PLUSWAIT1))
- *pluscount = 1;
- } else {
- /* Time since last non-'+' < 1.5 sec. ? */
- if (time_before(jiffies, *lastplus + PLUSWAIT2))
- *pluscount = 0;
- }
- if ((*pluscount == 3) && (count == 1))
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
- if (*pluscount > 3)
- *pluscount = 1;
- } else
- *pluscount = 0;
- *lastplus = jiffies;
- count--;
+ for (; count > 0; info->emu.lastplus = jiffies, count--) {
+ if (*(p++) != plus) {
+ info->emu.pluscount = 0;
+ continue;
+ }
+ if (info->emu.pluscount == 0) {
+ if (time_after(jiffies, info->emu.lastplus + PLUSWAIT2))
+ info->emu.pluscount = 1;
+ } else {
+ if (time_after(jiffies, info->emu.lastplus + PLUSWAIT1))
+ info->emu.pluscount = 1;
+ else
+ info->emu.pluscount++;
+ }
}
+ if (info->emu.pluscount == 3)
+ mod_timer(&info->escape_timer, jiffies + PLUSWAIT2);
+ else
+ del_timer(&info->escape_timer);
}
/*
@@ -2668,7 +2746,7 @@ isdn_tty_modem_result(int code, modem_info * info)
/* print CID, _before_ _every_ ring */
if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) {
isdn_tty_at_cout("\r\nCALLER NUMBER: ", info);
- isdn_tty_at_cout(isdn_slot_num(info->isdn_slot), info);
+ isdn_tty_at_cout(info->isdn_slot->num, info);
if (m->mdmreg[REG_CDN] & BIT_CDN) {
isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
isdn_tty_at_cout(info->emu.cpn, info);
@@ -2697,7 +2775,7 @@ isdn_tty_modem_result(int code, modem_info * info)
(m->mdmreg[REG_RINGCNT] == 1)) {
isdn_tty_at_cout("\r\n", info);
isdn_tty_at_cout("CALLER NUMBER: ", info);
- isdn_tty_at_cout(isdn_slot_num(info->isdn_slot), info);
+ isdn_tty_at_cout(info->isdn_slot->num, info);
if (m->mdmreg[REG_CDN] & BIT_CDN) {
isdn_tty_at_cout("\r\nCALLED NUMBER: ", info);
isdn_tty_at_cout(info->emu.cpn, info);
@@ -3209,7 +3287,7 @@ isdn_tty_cmd_ATA(modem_info * info)
if (info->msr & UART_MSR_RI) {
/* Accept incoming call */
info->last_dir = 0;
- strcpy(info->last_num, isdn_slot_num(info->isdn_slot));
+ strcpy(info->last_num, info->isdn_slot->num);
m->mdmreg[REG_RINGCNT] = 0;
info->msr &= ~UART_MSR_RI;
l2 = m->mdmreg[REG_L2PROT];
@@ -3235,9 +3313,8 @@ isdn_tty_cmd_ATA(modem_info * info)
#endif
isdn_slot_command(info->isdn_slot, ISDN_CMD_SETL3, &cmd);
info->dialing = 16;
- info->emu.carrierwait = 0;
isdn_slot_command(info->isdn_slot, ISDN_CMD_ACCEPTD, &cmd);
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
+ mod_timer(&info->connect_timer, jiffies + info->emu.mdmreg[REG_WAITC] * HZ);
} else
isdn_tty_modem_result(RESULT_NO_ANSWER, info);
}
@@ -3907,99 +3984,34 @@ isdn_tty_edit_at(const char *p, int count, modem_info * info, int user)
return total;
}
-/*
- * Switch all modem-channels who are online and got a valid
- * escape-sequence 1.5 seconds ago, to command-mode.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_escape(void)
+static void
+isdn_tty_ring_timer(unsigned long data)
{
- int ton = 0;
- int i;
- int midx;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEM(isdn_slot_usage(i)))
- if ((midx = isdn_slot_m_idx(i)) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->online) {
- ton = 1;
- if ((info->emu.pluscount == 3) &&
- time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
- info->emu.pluscount = 0;
- info->online = 0;
- isdn_tty_modem_result(RESULT_OK, info);
- }
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
-}
+ struct modem_info *info = (struct modem_info *) data;
-/*
- * Put a RING-message to all modem-channels who have the RI-bit set.
- * This function is called every second via timer-interrupt from within
- * timer-dispatcher isdn_timer_function()
- */
-void
-isdn_tty_modem_ring(void)
-{
- int ton = 0;
- int i;
+ if (!(info->msr & UART_MSR_RI))
+ return;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->msr & UART_MSR_RI) {
- ton = 1;
- isdn_tty_modem_result(RESULT_RING, info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton);
+ isdn_tty_modem_result(RESULT_RING, info);
+ mod_timer(&info->ring_timer, jiffies + RING_TIMEOUT);
}
-
-/*
- * For all online tty's, try sending data to
- * the lower levels.
- */
-void
-isdn_tty_modem_xmit(void)
+
+static void
+isdn_tty_modem_xmit(struct modem_info *info)
{
- int ton = 1;
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->online) {
- ton = 1;
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
- }
- isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
+ isdn_tty_senddown(info);
+ isdn_tty_tint(info);
}
-/*
- * Check all channels if we have a 'no carrier' timeout.
- * Timeout value is set by Register S7.
- */
-void
-isdn_tty_carrier_timeout(void)
+static void
+isdn_tty_connect_timer(unsigned long data)
{
- int ton = 0;
- int i;
+ struct modem_info *info = (struct modem_info *) data;
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if (info->dialing) {
- if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
- info->dialing = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- }
- else
- ton = 1;
- }
+ if (info->dialing) {
+ info->dialing = 0;
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
+ isdn_tty_modem_hup(info, 1);
}
- isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
}
+
diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
index 8cad26a3714a..2a902f74b586 100644
--- a/drivers/isdn/i4l/isdn_tty.h
+++ b/drivers/isdn/i4l/isdn_tty.h
@@ -1,13 +1,10 @@
-/* $Id: isdn_tty.h,v 1.22.6.2 2001/09/23 22:24:32 kai Exp $
- *
- * header for Linux ISDN subsystem, tty related functions (linklevel).
+/* Linux ISDN subsystem, tty related functions
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#include <linux/config.h>
@@ -101,16 +98,9 @@
((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \
(info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2))
-extern void isdn_tty_modem_escape(void);
-extern void isdn_tty_modem_ring(void);
-extern void isdn_tty_carrier_timeout(void);
-extern void isdn_tty_modem_xmit(void);
extern int isdn_tty_init(void);
-extern void isdn_tty_readmodem(void);
-extern int isdn_tty_find_icall(int, int, setup_parm *);
+extern int isdn_tty_find_icall(struct isdn_slot *slot, setup_parm *setup);
extern void isdn_tty_cleanup_xmit(modem_info *);
-extern int isdn_tty_stat_callback(int, isdn_ctrl *);
-extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
extern int isdn_tty_capi_facility(capi_msg *cm);
extern void isdn_tty_at_cout(char *, modem_info *);
extern void isdn_tty_modem_hup(modem_info *, int);
@@ -122,3 +112,22 @@ extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *);
extern int isdn_tty_init(void);
extern void isdn_tty_exit(void);
+
+struct isdn_modem {
+ int refcount; /* Number of opens */
+ struct tty_driver tty_modem; /* tty-device */
+ struct tty_driver cua_modem; /* cua-device */
+ struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
+ struct termios *modem_termios[ISDN_MAX_CHANNELS];
+ struct termios *modem_termios_locked[ISDN_MAX_CHANNELS];
+ modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
+};
+
+extern struct isdn_modem isdn_mdm;
+
+static inline void
+isdn_tty_queue_tail(modem_info *info, struct sk_buff *skb, int len)
+{
+ __skb_queue_tail(&info->rpqueue, skb);
+ info->rcvcount += len;
+}
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
index 2f7a5a0f2b48..c216f92aaece 100644
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ b/drivers/isdn/i4l/isdn_ttyfax.c
@@ -1,6 +1,4 @@
-/* $Id: isdn_ttyfax.c,v 1.7.6.2 2001/09/23 22:24:32 kai Exp $
- *
- * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
+/* Linux ISDN subsystem, tty_fax AT-command emulator
*
* Copyright 1999 by Armin Schindler (mac@melware.de)
* Copyright 1999 by Ralf Spachmann (mel@melware.de)
@@ -8,7 +6,6 @@
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#undef ISDN_TTY_FAX_STAT_DEBUG
@@ -19,26 +16,8 @@
#include "isdn_tty.h"
#include "isdn_ttyfax.h"
-
-static char *isdn_tty_fax_revision = "$Revision: 1.7.6.2 $";
-
#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
-static char *
-isdn_getrev(const char *revision)
-{
- char *rev;
- char *p;
-
- if ((p = strchr(revision, ':'))) {
- rev = p + 2;
- p = strchr(rev, '$');
- *--p = 0;
- } else
- rev = "???";
- return rev;
-}
-
/*
* Fax Class 2 Modem results
*
@@ -74,7 +53,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info)
case 2: /* +FCON */
/* Append CPN, if enabled */
if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
- (!(isdn_slot_usage(info->isdn_slot) & ISDN_USAGE_OUTGOING))) {
+ (!(info->isdn_slot->usage & ISDN_USAGE_OUTGOING))) {
sprintf(rs, "/%s", m->cpn);
isdn_tty_at_cout(rs, info);
}
@@ -322,7 +301,8 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
static char *cmd[] =
{"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
isdn_ctrl c;
- int par, i;
+ int par;
+ struct isdn_slot *slot;
long flags;
for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
@@ -364,7 +344,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
#endif
- if (info->isdn_slot < 0) {
+ if (!info->isdn_slot) {
save_flags(flags);
cli();
if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
@@ -373,18 +353,16 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
PARSE_ERROR1;
}
/* get a temporary connection to the first free fax driver */
- i = isdn_get_free_slot(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
+ slot = isdn_get_free_slot(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
- if (i < 0) {
+ if (!slot) {
restore_flags(flags);
PARSE_ERROR1;
}
- info->isdn_slot = i;
- isdn_slot_set_m_idx(i, info->line);
- isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
- isdn_slot_free(info->isdn_slot);
- isdn_slot_set_m_idx(i, -1);
- info->isdn_slot = -1;
+ info->isdn_slot = slot;
+ isdn_slot_command(slot, ISDN_CMD_FAXCMD, &c);
+ isdn_slot_free(slot);
+ info->isdn_slot = NULL;
restore_flags(flags);
} else {
isdn_slot_command(info->isdn_slot, ISDN_CMD_FAXCMD, &c);
@@ -1065,8 +1043,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
#ifdef ISDN_TTY_FAX_STAT_DEBUG
printk(KERN_DEBUG "isdn_tty: FREV?\n");
#endif
- strcpy(rss, isdn_tty_fax_revision);
- sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
+ sprintf(rs, "\r\nRev: 1.0");
isdn_tty_at_cout(rs, info);
return 0;
}
diff --git a/drivers/isdn/i4l/isdn_ttyfax.h b/drivers/isdn/i4l/isdn_ttyfax.h
index 244ada3ca127..3567899e4e88 100644
--- a/drivers/isdn/i4l/isdn_ttyfax.h
+++ b/drivers/isdn/i4l/isdn_ttyfax.h
@@ -1,6 +1,4 @@
-/* $Id: isdn_ttyfax.h,v 1.2.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * header for Linux ISDN subsystem, tty_fax related functions (linklevel).
+/* Linux ISDN subsystem, tty_fax related functions
*
* Copyright 1999 by Armin Schindler (mac@melware.de)
* Copyright 1999 by Ralf Spachmann (mel@melware.de)
@@ -8,7 +6,6 @@
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c
index 1676de4975cc..be702981df0e 100644
--- a/drivers/isdn/i4l/isdn_v110.c
+++ b/drivers/isdn/i4l/isdn_v110.c
@@ -1,12 +1,9 @@
-/* $Id: isdn_v110.c,v 1.5.6.4 2001/09/23 22:24:32 kai Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
+/* Linux ISDN subsystem, V.110
*
* Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#include <linux/string.h>
@@ -16,11 +13,10 @@
#include <linux/isdn.h>
#include "isdn_v110.h"
+#include "isdn_common.h"
#undef ISDN_V110_DEBUG
-char *isdn_v110_revision = "$Revision: 1.5.6.4 $";
-
#define V110_38400 255
#define V110_19200 15
#define V110_9600 3
@@ -86,7 +82,7 @@ FlipBits(unsigned char c, int keylen)
* structures and returns a pointer to these.
*/
static isdn_v110_stream *
-isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
+do_isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
{
int i;
isdn_v110_stream *v;
@@ -131,8 +127,8 @@ isdn_v110_open(unsigned char key, int hdrlen, int maxsize)
}
/* isdn_v110_close frees private V.110 data structures */
-void
-isdn_v110_close(isdn_v110_stream * v)
+static void
+do_isdn_v110_close(isdn_v110_stream * v)
{
if (v == NULL)
return;
@@ -514,99 +510,94 @@ buffer_full:
return nskb;
}
+
+void
+isdn_v110_open(struct isdn_slot *slot, struct isdn_v110 *iv110)
+{
+ isdn_v110_stream *v;
+ int hdrlen = isdn_slot_hdrlen(slot);
+ int maxsize = isdn_slot_maxbufsize(slot);
+
+ atomic_inc(&iv110->v110use);
+ switch (iv110->v110emu) {
+ case ISDN_PROTO_L2_V11096:
+ iv110->v110 = do_isdn_v110_open(V110_9600, hdrlen, maxsize);
+ break;
+ case ISDN_PROTO_L2_V11019:
+ iv110->v110 = do_isdn_v110_open(V110_19200, hdrlen, maxsize);
+ break;
+ case ISDN_PROTO_L2_V11038:
+ iv110->v110 = do_isdn_v110_open(V110_38400, hdrlen, maxsize);
+ break;
+ }
+ if ((v = iv110->v110)) {
+ while (v->SyncInit) {
+ struct sk_buff *skb = isdn_v110_sync(v);
+ if (isdn_slot_write(slot, skb) <= 0) {
+ dev_kfree_skb(skb);
+ /* Unable to send, try later */
+ break;
+ }
+ v->SyncInit--;
+ v->skbidle++;
+ }
+ } else
+ printk(KERN_WARNING "isdn_v110: Couldn't open stream\n");
+ atomic_dec(&iv110->v110use);
+}
+
+void
+isdn_v110_close(struct isdn_slot *slot, struct isdn_v110 *iv110)
+{
+ while (1) {
+ atomic_inc(&iv110->v110use);
+ if (atomic_dec_and_test(&iv110->v110use)) {
+ do_isdn_v110_close(iv110->v110);
+ iv110->v110 = NULL;
+ break;
+ }
+ }
+}
+
int
-isdn_v110_stat_callback(struct isdn_v110 *iv110, isdn_ctrl *c)
+isdn_v110_bsent(struct isdn_slot *slot, struct isdn_v110 *iv110)
{
- isdn_v110_stream *v = NULL;
- int i;
- int ret;
-
- switch (c->command) {
- case ISDN_STAT_BSENT:
- /* Keep the send-queue of the driver filled
- * with frames:
- * If number of outstanding frames < 3,
- * send down an Idle-Frame (or an Sync-Frame, if
- * v->SyncInit != 0).
- */
- if (!(v = iv110->v110))
- return 0;
- atomic_inc(&iv110->v110use);
- if (v->skbidle > 0) {
- v->skbidle--;
- ret = 1;
+ isdn_v110_stream *v = iv110->v110;
+ int i, ret;
+
+ /* Keep the send-queue of the driver filled
+ * with frames:
+ * If number of outstanding frames < 3,
+ * send down an Idle-Frame (or an Sync-Frame, if
+ * v->SyncInit != 0).
+ */
+ atomic_inc(&iv110->v110use);
+ if (v->skbidle > 0) {
+ v->skbidle--;
+ ret = 1;
+ } else {
+ if (v->skbuser > 0)
+ v->skbuser--;
+ ret = 0;
+ }
+ for (i = v->skbuser + v->skbidle; i < 2; i++) {
+ struct sk_buff *skb;
+ if (v->SyncInit > 0)
+ skb = isdn_v110_sync(v);
+ else
+ skb = isdn_v110_idle(v);
+ if (skb) {
+ if (isdn_slot_write(slot, skb) <= 0) {
+ dev_kfree_skb(skb);
+ break;
} else {
- if (v->skbuser > 0)
- v->skbuser--;
- ret = 0;
- }
- for (i = v->skbuser + v->skbidle; i < 2; i++) {
- struct sk_buff *skb;
- if (v->SyncInit > 0)
- skb = isdn_v110_sync(v);
- else
- skb = isdn_v110_idle(v);
- if (skb) {
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- break;
- } else {
- if (v->SyncInit)
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- break;
- }
- atomic_dec(&iv110->v110use);
- return ret;
- case ISDN_STAT_DHUP:
- case ISDN_STAT_BHUP:
- while (1) {
- atomic_inc(&iv110->v110use);
- if (atomic_dec_and_test(&iv110->v110use)) {
- isdn_v110_close(iv110->v110);
- iv110->v110 = NULL;
- break;
- }
- sti();
+ if (v->SyncInit)
+ v->SyncInit--;
+ v->skbidle++;
}
+ } else
break;
- case ISDN_STAT_BCONN:
- if (iv110->v110emu && (iv110->v110 == NULL)) {
- int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen;
- int maxsize = dev->drv[c->driver]->interface->maxbufsize;
- atomic_inc(&iv110->v110use);
- switch (iv110->v110emu) {
- case ISDN_PROTO_L2_V11096:
- iv110->v110 = isdn_v110_open(V110_9600, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11019:
- iv110->v110 = isdn_v110_open(V110_19200, hdrlen, maxsize);
- break;
- case ISDN_PROTO_L2_V11038:
- iv110->v110 = isdn_v110_open(V110_38400, hdrlen, maxsize);
- break;
- default:;
- }
- if ((v = iv110->v110)) {
- while (v->SyncInit) {
- struct sk_buff *skb = isdn_v110_sync(v);
- if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) {
- dev_kfree_skb(skb);
- /* Unable to send, try later */
- break;
- }
- v->SyncInit--;
- v->skbidle++;
- }
- } else
- printk(KERN_WARNING "isdn_v110: Couldn't open stream\n");
- atomic_dec(&iv110->v110use);
- }
- break;
- default:
- return 0;
}
- return 0;
+ atomic_dec(&iv110->v110use);
+ return ret;
}
diff --git a/drivers/isdn/i4l/isdn_v110.h b/drivers/isdn/i4l/isdn_v110.h
index b6563c259e44..36b404f56f48 100644
--- a/drivers/isdn/i4l/isdn_v110.h
+++ b/drivers/isdn/i4l/isdn_v110.h
@@ -1,12 +1,9 @@
-/* $Id: isdn_v110.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * Linux ISDN subsystem, V.110 related functions (linklevel).
+/* Linux ISDN subsystem, V.110 related functions
*
* Copyright by Thomas Pfeiffer (pfeiffer@pds.de)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#ifndef ISDN_V110_H
@@ -29,7 +26,10 @@ extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *);
*/
extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *);
-extern int isdn_v110_stat_callback(struct isdn_v110 *v110, isdn_ctrl *);
-extern void isdn_v110_close(isdn_v110_stream * v);
+extern void isdn_v110_open(struct isdn_slot *slot, struct isdn_v110 *iv110);
+
+extern void isdn_v110_close(struct isdn_slot *slot, struct isdn_v110 *iv110);
+
+extern int isdn_v110_bsent(struct isdn_slot *slot, struct isdn_v110 *iv110);
#endif
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
index edbf4eed016d..d394b4a39bd4 100644
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ b/drivers/isdn/i4l/isdn_x25iface.c
@@ -1,10 +1,10 @@
-/* $Id: isdn_x25iface.c,v 1.9.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * Linux ISDN subsystem, X.25 related functions
+/* * Linux ISDN subsystem, X.25 related functions
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
+ */
+
+/*
* stuff needed to support the Linux X.25 PLP code on top of devices that
* can provide a lab_b service using the concap_proto mechanism.
* This module supports a network interface wich provides lapb_sematics
@@ -17,7 +17,6 @@
*
*/
-/* #include <linux/isdn.h> */
#include <linux/netdevice.h>
#include <linux/concap.h>
#include <linux/wanrouter.h>
diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h
index ef69d3af9628..12fc46c471af 100644
--- a/drivers/isdn/i4l/isdn_x25iface.h
+++ b/drivers/isdn/i4l/isdn_x25iface.h
@@ -1,17 +1,16 @@
-/* $Id: isdn_x25iface.h,v 1.3.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * header for Linux ISDN subsystem, x.25 related functions
+/* Linux ISDN subsystem, x.25 related functions
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#ifndef _LINUX_ISDN_X25IFACE_H
#define _LINUX_ISDN_X25IFACE_H
#define ISDN_X25IFACE_MAGIC 0x1e75a2b9
-/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */
+
+#undef DEBUG_ISDN_X25
+
#ifdef DEBUG_ISDN_X25
# define IX25DEBUG(fmt,args...) printk(KERN_DEBUG fmt , ## args)
#else
@@ -26,8 +25,6 @@
extern struct concap_proto_ops * isdn_x25iface_concap_proto_ops_pt;
extern struct concap_proto * isdn_x25iface_proto_new(void);
-
-
#endif
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index fb1f030d9c92..ef49d7201cc2 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -424,7 +424,6 @@ static icn_stat icn_stat_table[] =
{"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
{"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
{"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
{"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
{"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
{"E_L1: ACTIVATION FAILED",
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index 612c7b19c85a..ce799f4cb3a7 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -71,9 +71,6 @@ isdnloop_bchan_send(isdnloop_card * card, int ch)
printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n");
dev_kfree_skb(skb);
- cmd.command = ISDN_STAT_L1ERR;
- cmd.parm.errcode = ISDN_STAT_L1ERR_SEND;
- card->interface.statcallb(&cmd);
};
cmd.command = ISDN_STAT_BSENT;
cmd.parm.length = len;
@@ -166,7 +163,6 @@ static isdnloop_stat isdnloop_stat_table[] =
{"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
{"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
{"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"NO D-CHAN", ISDN_STAT_NODCH, 0}, /* No D-channel available */
{"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
{"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
{"E_L1: ACTIVATION FAILED",
@@ -1339,6 +1335,9 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card)
case ISDN_PROTO_L2_HDLC:
sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
break;
+ case ISDN_PROTO_L2_TRANS:
+ sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1);
+ break;
default:
return -EINVAL;
}
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 0d0ce25b333e..2f429e27a007 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -1,10 +1,9 @@
-/* $Id: isdn.h,v 1.111.6.9 2001/09/23 22:25:05 kai Exp $
- *
- * Main header for the Linux ISDN subsystem (linklevel).
+/* Linux ISDN subsystem, main header
*
* Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
* Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name)
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
@@ -15,9 +14,7 @@
#define __ISDN_H__
#include <linux/ioctl.h>
-
-// FIXME!!!
-#include <../drivers/isdn/i4l/isdn_fsm.h>
+#include <linux/isdn/fsm.h>
#ifdef CONFIG_COBALT_MICRO_SERVER
/* Save memory */
@@ -238,210 +235,9 @@ typedef struct {
#define USG_MODEMORVOICE(x) (((x & ISDN_USAGE_MASK)==ISDN_USAGE_MODEM) || \
((x & ISDN_USAGE_MASK)==ISDN_USAGE_VOICE) )
-/* Timer-delays and scheduling-flags */
-#define ISDN_TIMER_RES 4 /* Main Timer-Resolution */
-#define ISDN_TIMER_02SEC (HZ/ISDN_TIMER_RES/5) /* Slow-Timer1 .2 sec */
-#define ISDN_TIMER_1SEC (HZ/ISDN_TIMER_RES) /* Slow-Timer2 1 sec */
-#define ISDN_TIMER_RINGING 5 /* tty RINGs = ISDN_TIMER_1SEC * this factor */
-#define ISDN_TIMER_KEEPINT 10 /* Cisco-Keepalive = ISDN_TIMER_1SEC * this factor */
-#define ISDN_TIMER_MODEMREAD 1
-#define ISDN_TIMER_MODEMPLUS 2
-#define ISDN_TIMER_MODEMRING 4
-#define ISDN_TIMER_MODEMXMIT 8
-#define ISDN_TIMER_CARRIER 256 /* Wait for Carrier */
-#define ISDN_TIMER_FAST (ISDN_TIMER_MODEMREAD | ISDN_TIMER_MODEMPLUS | \
- ISDN_TIMER_MODEMXMIT)
-#define ISDN_TIMER_SLOW (ISDN_TIMER_MODEMRING | ISDN_TIMER_CARRIER)
-
/* GLOBAL_FLAGS */
#define ISDN_GLOBAL_STOPPED 1
-/*=================== Start of ip-over-ISDN stuff =========================*/
-
-/* Feature- and status-flags for a net-interface */
-#define ISDN_NET_SECURE 0x02 /* Accept calls from phonelist only */
-#define ISDN_NET_CALLBACK 0x04 /* activate callback */
-#define ISDN_NET_CBHUP 0x08 /* hangup before callback */
-#define ISDN_NET_CBOUT 0x10 /* remote machine does callback */
-
-#define ISDN_NET_MAGIC 0x49344C02 /* for paranoia-checking */
-
-/* Phone-list-element */
-struct isdn_net_phone {
- struct list_head list;
- char num[ISDN_MSNLEN];
-};
-
-/*
- Principles when extending structures for generic encapsulation protocol
- ("concap") support:
- - Stuff which is hardware specific (here i4l-specific) goes in
- the netdev -> local structure (here: isdn_net_local)
- - Stuff which is encapsulation protocol specific goes in the structure
- which holds the linux device structure (here: isdn_net_device)
-*/
-
-struct isdn_net_dev_s;
-struct isdn_net_local_s;
-
-struct isdn_netif_ops {
- int (*hard_start_xmit) (struct sk_buff *skb,
- struct net_device *dev);
- int (*hard_header) (struct sk_buff *skb,
- struct net_device *dev,
- unsigned short type,
- void *daddr,
- void *saddr,
- unsigned len);
- int (*do_ioctl)(struct net_device *dev,
- struct ifreq *ifr, int cmd);
-
- unsigned short flags; /* interface flags (a la BSD) */
- unsigned short type; /* interface hardware type */
- unsigned char addr_len;/* hardware address length */
- void (*receive)(struct isdn_net_local_s *,
- struct isdn_net_dev_s *,
- struct sk_buff *);
- void (*connected)(struct isdn_net_dev_s *);
- void (*disconnected)(struct isdn_net_dev_s *);
- int (*bind)(struct isdn_net_dev_s *);
- void (*unbind)(struct isdn_net_dev_s *);
- int (*init)(struct isdn_net_local_s *);
- void (*cleanup)(struct isdn_net_local_s *);
- int (*open)(struct isdn_net_local_s *);
- void (*close)(struct isdn_net_local_s *);
-};
-
-/* Local interface-data */
-typedef struct isdn_net_local_s {
- ulong magic;
- struct net_device_stats stats; /* Ethernet Statistics */
- int flags; /* Connection-flags */
- int dialmax; /* Max. Number of Dial-retries */
- int dialtimeout; /* How long shall we try on dialing */
- int dialwait; /* wait after failed attempt */
-
- int cbdelay; /* Delay before Callback starts */
- char msn[ISDN_MSNLEN]; /* MSNs/EAZs for this interface */
-
- u_char cbhup; /* Flag: Reject Call before Callback*/
- int hupflags; /* Flags for charge-unit-hangup: */
- int onhtime; /* Time to keep link up */
-
- u_char p_encap; /* Packet encapsulation */
- u_char l2_proto; /* Layer-2-protocol */
- u_char l3_proto; /* Layer-3-protocol */
-
- ulong slavedelay; /* Dynamic bundling delaytime */
- int triggercps; /* BogoCPS needed for trigger slave */
- struct list_head phone[2]; /* List of remote-phonenumbers */
- /* phone[0] = Incoming Numbers */
- /* phone[1] = Outgoing Numbers */
-
- struct list_head slaves; /* list of all bundled channels
- protected by serializing config
- ioctls / no change allowed when
- interface is running */
- struct list_head online; /* list of all bundled channels
- which can be used for actual
- data (IP) transfer
- protected by xmit_lock */
-
- spinlock_t xmit_lock; /* used to protect the xmit path of
- a net_device, including all
- associated channels's frame_cnt */
- struct list_head running_devs; /* member of global running_devs */
- atomic_t refcnt; /* references held by ISDN code */
-
-#ifdef CONFIG_ISDN_X25
- struct concap_device_ops *dops; /* callbacks used by encapsulator */
-#endif
-#ifdef CONFIG_ISDN_PPP
- unsigned int mpppcfg;
- long mp_seqno;
- struct ippp_ccp *ccp;
- unsigned long debug;
-#ifdef CONFIG_ISDN_PPP_VJ
- unsigned char *cbuf;
- struct slcompress *slcomp;
-#endif
-#endif
-
- /* use an own struct for that in later versions */
- ulong cisco_myseq; /* Local keepalive seq. for Cisco */
- ulong cisco_mineseen; /* returned keepalive seq. from remote */
- ulong cisco_yourseq; /* Remote keepalive seq. for Cisco */
- int cisco_keepalive_period; /* keepalive period */
- ulong cisco_last_slarp_in; /* jiffie of last keepalive packet we received */
- char cisco_line_state; /* state of line according to keepalive packets */
- char cisco_debserint; /* debugging flag of cisco hdlc with slarp */
-
- struct timer_list cisco_timer;
-
- struct isdn_netif_ops *ops;
-
- struct net_device dev; /* interface to upper levels */
-} isdn_net_local;
-
-/* the interface itself */
-typedef struct isdn_net_dev_s {
- int isdn_slot; /* Index to isdn device/channel */
- int pre_device; /* Preselected isdn-device */
- int pre_channel; /* Preselected isdn-channel */
- int exclusive; /* -1 if non excl./idx to excl chan */
-
- struct timer_list dial_timer; /* dial events timer */
- struct fsm_inst fi; /* call control state machine */
- int dial_event; /* event in case of timer expiry */
- int dial; /* # of phone number just dialed */
- int outgoing; /* Flag: outgoing call */
- int dialretry; /* Counter for Dialout-retries */
-
- int cps; /* current speed of this interface */
- int transcount; /* byte-counter for cps-calculation */
- int last_jiffies; /* when transcount was reset */
- int sqfull; /* Flag: netdev-queue overloaded */
- ulong sqfull_stamp; /* Start-Time of overload */
-
- int huptimer; /* Timeout-counter for auto-hangup */
- int charge; /* Counter for charging units */
- int charge_state; /* ChargeInfo state machine */
- unsigned long chargetime; /* Timer for Charging info */
- int chargeint; /* Interval between charge-infos */
-
- int pppbind; /* ippp device for bindings */
- struct ipppd *ipppd; /* /dev/ipppX which controls us */
-
- struct sk_buff_head super_tx_queue; /* List of supervisory frames to */
- /* be transmitted asap */
- int frame_cnt; /* number of frames currently */
- /* queued in HL driver */
- struct tasklet_struct tlet;
-
- isdn_net_local *mlp; /* Ptr to master device for all devs*/
-
- struct list_head slaves; /* member of local->slaves */
- struct list_head online; /* member of local->online */
-
- char name[10]; /* Name of device */
- struct list_head global_list; /* global list of all isdn_net_devs */
-#ifdef CONFIG_ISDN_PPP
- unsigned int pppcfg;
- unsigned int pppseq; /* last seq no seen */
- struct ippp_ccp *ccp;
- unsigned long debug;
-
- ippp_bundle * pb; /* pointer to the common bundle structure
- * with the per-bundle data */
-#endif
-#ifdef CONFIG_ISDN_X25
- struct concap_proto *cprot; /* connection oriented encapsulation protocol */
-#endif
-
-} isdn_net_dev;
-
-/*===================== End of ip-over-ISDN stuff ===========================*/
-
/*======================= Start of ISDN-tty stuff ===========================*/
#define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */
@@ -494,7 +290,6 @@ typedef struct atemu {
int mdmcmdl; /* Length of Modem-Commandbuffer */
int pluscount; /* Counter for +++ sequence */
int lastplus; /* Timestamp of last + */
- int carrierwait; /* Seconds of carrier waiting */
char mdmcmd[255]; /* Modem-Commandbuffer */
unsigned int charge; /* Charge units of current connection */
} atemu;
@@ -516,7 +311,9 @@ typedef struct modem_info {
/* 2 = B-Channel is up, deliver d.*/
int dialing; /* Dial in progress or ATA */
int rcvsched; /* Receive needs schedule */
- int isdn_slot; /* Index to isdn-driver/channel */
+ struct isdn_slot *isdn_slot; /* Ptr to isdn-driver/channel */
+ struct sk_buff_head rpqueue; /* Queue of recv'd packets */
+ int rcvcount; /* Byte-counters for B rx */
int ncarrier; /* Flag: schedule NO CARRIER */
unsigned char last_cause[8]; /* Last cause message */
unsigned char last_num[ISDN_MSNLEN];
@@ -533,6 +330,7 @@ typedef struct modem_info {
struct sk_buff_head xmit_queue; /* transmit queue */
atomic_t xmit_lock; /* Semaphore for isdn_tty_write */
#ifdef CONFIG_ISDN_AUDIO
+ unsigned long DLEflag; /* Insert DLE at next read */
int vonline; /* Voice-channel status */
/* Bit 0 = recording */
/* Bit 1 = playback */
@@ -549,6 +347,10 @@ typedef struct modem_info {
#endif
struct tty_struct *tty; /* Pointer to corresponding tty */
atemu emu; /* AT-emulator data */
+ struct timer_list escape_timer; /* to recognize +++ escape */
+ struct timer_list ring_timer; /* for writing 'RING' responses */
+ struct timer_list connect_timer; /* waiting for CONNECT */
+ struct timer_list read_timer; /* read incoming data */
struct termios normal_termios; /* For saving termios structs */
struct termios callout_termios;
wait_queue_head_t open_wait, close_wait;
@@ -557,17 +359,6 @@ typedef struct modem_info {
#define ISDN_MODEM_WINSIZE 8
-/* Description of one ISDN-tty */
-typedef struct {
- int refcount; /* Number of opens */
- struct tty_driver tty_modem; /* tty-device */
- struct tty_driver cua_modem; /* cua-device */
- struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */
- struct termios *modem_termios[ISDN_MAX_CHANNELS];
- struct termios *modem_termios_locked[ISDN_MAX_CHANNELS];
- modem_info info[ISDN_MAX_CHANNELS]; /* Private data */
-} modem;
-
/*======================= End of ISDN-tty stuff ============================*/
/*======================== Start of V.110 stuff ============================*/
@@ -602,37 +393,10 @@ typedef struct {
char *private;
} infostruct;
-#define DRV_FLAG_RUNNING 1
-#define DRV_FLAG_REJBUS 2
-#define DRV_FLAG_LOADED 4
-
-/* Description of hardware-level-driver */
-typedef struct {
- ulong online; /* Channel-Online flags */
- ulong flags; /* Misc driver Flags */
- int locks; /* Number of locks for this driver */
- int channels; /* Number of channels */
- wait_queue_head_t st_waitq; /* Wait-Queue for status-read's */
- int maxbufsize; /* Maximum Buffersize supported */
- unsigned long pktcount; /* Until now: unused */
- int stavail; /* Chars avail on Status-device */
- isdn_if *interface; /* Interface to driver */
- int *rcverr; /* Error-counters for B-Ch.-receive */
- int *rcvcount; /* Byte-counters for B-Ch.-receive */
-#ifdef CONFIG_ISDN_AUDIO
- unsigned long DLEflag; /* Flags: Insert DLE at next read */
-#endif
- struct sk_buff_head *rpqueue; /* Pointers to start of Rcv-Queue */
- wait_queue_head_t *rcv_waitq; /* Wait-Queues for B-Channel-Reads */
- wait_queue_head_t *snd_waitq; /* Wait-Queue for B-Channel-Send's */
- char msn2eaz[10][ISDN_MSNLEN]; /* Mapping-Table MSN->EAZ */
-} driver;
-
/* Main driver-data */
typedef struct isdn_devt {
unsigned short flags; /* Bitmapped Flags: */
/* */
- int drivers; /* Current number of drivers */
int channels; /* Current number of channels */
int net_verbose; /* Verbose-Flag */
int modempoll; /* Flag: tty-read active */
@@ -641,11 +405,7 @@ typedef struct isdn_devt {
int global_flags;
infostruct *infochain; /* List of open info-devs. */
wait_queue_head_t info_waitq; /* Wait-Queue for isdninfo */
- struct timer_list timer; /* Misc.-function Timer */
- driver *drv[ISDN_MAX_DRIVERS]; /* Array of drivers */
- char drvid[ISDN_MAX_DRIVERS][20];/* Driver-ID */
struct task_struct *profd; /* For iprofd */
- modem mdm; /* tty-driver-data */
struct semaphore sem; /* serialize list access*/
unsigned long global_features;
#ifdef CONFIG_DEVFS_FS
diff --git a/drivers/isdn/i4l/isdn_fsm.h b/include/linux/isdn/fsm.h
index 4a48a401da45..95beb142b392 100644
--- a/drivers/isdn/i4l/isdn_fsm.h
+++ b/include/linux/isdn/fsm.h
@@ -1,14 +1,11 @@
-/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $
- *
- * Finite state machine
+/* Linux ISDN subsystem, finite state machine
*
* Author Karsten Keil
- * Copyright by Karsten Keil <keil@isdn4linux.de>
- * by Kai Germaschewski <kai.germaschewski@gmx.de>
+ * Copyright by Karsten Keil <keil@isdn4linux.de>
+ * 2001-2002 by Kai Germaschewski <kai@germaschewski.name>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
*/
#ifndef __ISDN_FSM_H__
diff --git a/include/linux/isdn_ppp.h b/include/linux/isdn_ppp.h
index ec6016c37421..669822e2868a 100644
--- a/include/linux/isdn_ppp.h
+++ b/include/linux/isdn_ppp.h
@@ -1,10 +1,15 @@
-/*
+/* Linux ISDN subsystem, sync PPP, interface to ipppd
+ *
+ * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
+ * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg
+ * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * Copyright 2000-2002 by Kai Germaschewski (kai@germaschewski.name)
+ *
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
-
#ifndef _LINUX_ISDN_PPP_H
#define _LINUX_ISDN_PPP_H
@@ -16,22 +21,21 @@
struct pppcallinfo
{
- int calltype;
- unsigned char local_num[64];
- unsigned char remote_num[64];
- int charge_units;
+ int calltype;
+ unsigned char local_num[64];
+ unsigned char remote_num[64];
+ int charge_units;
};
-#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
-#define PPPIOCBUNDLE _IOW('t',129,int)
-#define PPPIOCGMPFLAGS _IOR('t',130,int)
-#define PPPIOCSMPFLAGS _IOW('t',131,int)
-#define PPPIOCSMPMTU _IOW('t',132,int)
-#define PPPIOCSMPMRU _IOW('t',133,int)
-#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long [8])
-#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
-#define PPPIOCGIFNAME _IOR('t',136, char [IFNAMSIZ] )
-
+#define PPPIOCGCALLINFO _IOWR('t',128,struct pppcallinfo)
+#define PPPIOCBUNDLE _IOW('t',129,int)
+#define PPPIOCGMPFLAGS _IOR('t',130,int)
+#define PPPIOCSMPFLAGS _IOW('t',131,int)
+#define PPPIOCSMPMTU _IOW('t',132,int)
+#define PPPIOCSMPMRU _IOW('t',133,int)
+#define PPPIOCGCOMPRESSORS _IOR('t',134,unsigned long[8])
+#define PPPIOCSCOMPRESSOR _IOW('t',135,int)
+#define PPPIOCGIFNAME _IOR('t',136,char[IFNAMSIZ])
#define SC_MP_PROT 0x00000200
#define SC_REJ_MP_PROT 0x00000400
@@ -44,26 +48,19 @@ struct pppcallinfo
#define IPPP_COMP_FLAG_LINK 0x2
struct isdn_ppp_comp_data {
- int num;
- unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
- int optlen;
- int flags;
+ int num;
+ unsigned char options[ISDN_PPP_COMP_MAX_OPTIONS];
+ int optlen;
+ int flags;
};
#ifdef __KERNEL__
-
-#include <linux/config.h>
#include <linux/skbuff.h>
#include <linux/ppp_defs.h>
#define DECOMP_ERR_NOMEM (-10)
-#define MP_END_FRAG 0x40
-#define MP_BEGIN_FRAG 0x80
-
-#define MP_MAX_QUEUE_LEN 16
-
/*
* We need a way for the decompressor to influence the generation of CCP
* Reset-Requests in a variety of ways. The decompressor is already returning
@@ -82,15 +79,15 @@ struct isdn_ppp_comp_data {
#define IPPP_RESET_MAXDATABYTES 32
struct isdn_ppp_resetparams {
- unsigned char valid:1; /* rw Is this structure filled at all ? */
- unsigned char rsend:1; /* rw Should we send one at all ? */
- unsigned char idval:1; /* rw Is the id field valid ? */
- unsigned char dtval:1; /* rw Is the data field valid ? */
- unsigned char expra:1; /* rw Is an Ack expected for this Req ? */
- unsigned char id; /* wo Send CCP ResetReq with this id */
- unsigned short maxdlen; /* ro Max bytes to be stored in data field */
- unsigned short dlen; /* rw Bytes stored in data field */
- unsigned char *data; /* wo Data for ResetReq info field */
+ unsigned char valid:1; /* rw Is this structure filled at all ? */
+ unsigned char rsend:1; /* rw Should we send one at all ? */
+ unsigned char idval:1; /* rw Is the id field valid ? */
+ unsigned char dtval:1; /* rw Is the data field valid ? */
+ unsigned char expra:1; /* rw Is an Ack expected for this Req ? */
+ unsigned char id; /* wo Send CCP ResetReq with this id */
+ unsigned short maxdlen; /* ro Max bytes to be stored in data field */
+ unsigned short dlen; /* rw Bytes stored in data field */
+ unsigned char *data; /* wo Data for ResetReq info field */
};
/*
@@ -98,89 +95,37 @@ struct isdn_ppp_resetparams {
* check the original include for more information
*/
struct isdn_ppp_compressor {
- struct isdn_ppp_compressor *next, *prev;
- int num; /* CCP compression protocol number */
+ struct isdn_ppp_compressor *next, *prev;
+ int num; /* CCP compression protocol number */
- void *(*alloc) (struct isdn_ppp_comp_data *);
- void (*free) (void *state);
- int (*init) (void *state, struct isdn_ppp_comp_data *,
- int unit,int debug);
+ void *(*alloc) (struct isdn_ppp_comp_data *);
+ void (*free) (void *state);
+ int (*init) (void *state, struct isdn_ppp_comp_data *,
+ int unit,int debug);
- /* The reset entry needs to get more exact information about the
- ResetReq or ResetAck it was called with. The parameters are
- obvious. If reset is called without a Req or Ack frame which
- could be handed into it, code MUST be set to 0. Using rsparm,
- the reset entry can control if and how a ResetAck is returned. */
+ /* The reset entry needs to get more exact information about the
+ ResetReq or ResetAck it was called with. The parameters are
+ obvious. If reset is called without a Req or Ack frame which
+ could be handed into it, code MUST be set to 0. Using rsparm,
+ the reset entry can control if and how a ResetAck is returned. */
- void (*reset) (void *state, unsigned char code, unsigned char id,
- unsigned char *data, unsigned len,
- struct isdn_ppp_resetparams *rsparm);
+ void (*reset) (void *state, unsigned char code, unsigned char id,
+ unsigned char *data, unsigned len,
+ struct isdn_ppp_resetparams *rsparm);
- int (*compress) (void *state, struct sk_buff *in,
- struct sk_buff *skb_out, int proto);
+ int (*compress) (void *state, struct sk_buff *in,
+ struct sk_buff *skb_out, int proto);
int (*decompress) (void *state,struct sk_buff *in,
struct sk_buff *skb_out,
struct isdn_ppp_resetparams *rsparm);
- void (*incomp) (void *state, struct sk_buff *in,int proto);
- void (*stat) (void *state, struct compstat *stats);
+ void (*incomp) (void *state, struct sk_buff *in,int proto);
+ void (*stat) (void *state, struct compstat *stats);
};
extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *);
extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *);
-typedef struct {
- unsigned long seqerrs;
- unsigned long frame_drops;
- unsigned long overflows;
- unsigned long max_queue_len;
-} isdn_mppp_stats;
-
-typedef struct {
- int mp_mrru; /* unused */
- struct sk_buff * frags; /* fragments sl list -- use skb->next */
- long frames; /* number of frames in the frame list */
- unsigned int seq; /* last processed packet seq #: any packets
- * with smaller seq # will be dropped
- * unconditionally */
- spinlock_t lock;
- int ref_ct;
- /* statistics */
- isdn_mppp_stats stats;
-} ippp_bundle;
-
-#define IPPP_MAX_RQ_LEN 8
-
-/* The data structure for one CCP reset transaction */
-enum ippp_ccp_reset_states {
- CCPResetIdle,
- CCPResetSentReq,
- CCPResetRcvdReq,
- CCPResetSentAck,
- CCPResetRcvdAck
-};
-
-struct ippp_ccp_reset_state {
- enum ippp_ccp_reset_states state; /* State of this transaction */
- struct ippp_ccp *ccp; /* Backlink */
- unsigned char id; /* id index */
- unsigned char ta:1; /* The timer is active (flag) */
- unsigned char expra:1; /* We expect a ResetAck at all */
- int dlen; /* Databytes stored in data */
- struct timer_list timer; /* For timeouts/retries */
- /* This is a hack but seems sufficient for the moment. We do not want
- to have this be yet another allocation for some bytes, it is more
- memory management overhead than the whole mess is worth. */
- unsigned char data[IPPP_RESET_MAXDATABYTES];
-};
-
-/* The data structure keeping track of the currently outstanding CCP Reset
- transactions. */
-struct ippp_ccp_reset {
- struct ippp_ccp_reset_state *rs[256]; /* One per possible id */
- unsigned char lastid; /* Last id allocated by the engine */
-};
-
#endif /* __KERNEL__ */
#endif /* _LINUX_ISDN_PPP_H */
diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h
index c9718d4de584..342dd971b1b6 100644
--- a/include/linux/isdnif.h
+++ b/include/linux/isdnif.h
@@ -202,14 +202,12 @@ typedef struct
#define ISDN_STAT_LOAD 265 /* Signal new lowlevel-driver is loaded */
#define ISDN_STAT_UNLOAD 266 /* Signal unload of lowlevel-driver */
#define ISDN_STAT_BSENT 267 /* Signal packet sent */
-#define ISDN_STAT_NODCH 268 /* Signal no D-Channel */
#define ISDN_STAT_ADDCH 269 /* Add more Channels */
#define ISDN_STAT_CAUSE 270 /* Cause-Message */
#define ISDN_STAT_ICALLW 271 /* Incoming call without B-chan waiting */
#define ISDN_STAT_REDIR 272 /* Redir result */
#define ISDN_STAT_PROT 273 /* protocol IO specific callback */
#define ISDN_STAT_DISPLAY 274 /* deliver a received display message */
-#define ISDN_STAT_L1ERR 275 /* Signal Layer-1 Error */
#define ISDN_STAT_FAXIND 276 /* FAX indications from HL-driver */
#define ISDN_STAT_AUDIO 277 /* DTMF, DSP indications */
#define ISDN_STAT_DISCH 278 /* Disable/Enable channel usage */
@@ -221,12 +219,6 @@ typedef struct
#define ISDN_AUDIO_DTMF 1 /* Rx/Tx DTMF */
/*
- * Values for errcode field
- */
-#define ISDN_STAT_L1ERR_SEND 1
-#define ISDN_STAT_L1ERR_RECV 2
-
-/*
* Values for feature-field of interface-struct.
*/
/* Layer 2 */