diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-10-29 17:06:09 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-10-29 17:06:09 -0800 |
| commit | d488b0d41fd6bb41cde1fa067a8416b384da0b6d (patch) | |
| tree | 30d2b7b455445bc7c9f0fd57b8887206c23e84e8 | |
| parent | d8c084f9fd65a1bf948acc5bf08b066f85160cba (diff) | |
| parent | 580c8fb64e2976e3a41a67852501a3596ccf3ade (diff) | |
Merge http://linux-isdn.bkbits.net/linux-2.5.isdn
into home.transmeta.com:/home/torvalds/v2.5/linux
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, ðer_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 */ |
