]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/isdn/hardware/mISDN/hfcmulti.c
mISDN: Add ISDN sample clock API to mISDN core
[linux-2.6-omap-h63xx.git] / drivers / isdn / hardware / mISDN / hfcmulti.c
index 1eac03f39d0005e0e75b75f3925e1924193e794b..592db93105f957e1c98bb9addd198567ccdee21d 100644 (file)
  *     Give the value of the clock control register (A_ST_CLK_DLY)
  *     of the S/T interfaces in TE mode.
  *     This register is needed for the TBR3 certification, so don't change it.
+ *
+ * clock:
+ *     NOTE: only one clockdelay_te value must be given once
+ *     Selects interface with clock source for mISDN and applications.
+ *     Set to card number starting with 1. Set to -1 to disable.
+ *     By default, the first card is used as clock source.
  */
 
 /*
  * #define HFC_REGISTER_DEBUG
  */
 
-static const char *hfcmulti_revision = "2.02";
+#define HFC_MULTI_VERSION      "2.03"
 
 #include <linux/module.h>
 #include <linux/pci.h>
@@ -165,15 +171,10 @@ static LIST_HEAD(HFClist);
 static spinlock_t HFClock; /* global hfc list lock */
 
 static void ph_state_change(struct dchannel *);
-static void (*hfc_interrupt)(void);
-static void (*register_interrupt)(void);
-static int (*unregister_interrupt)(void);
-static int interrupt_registered;
 
 static struct hfc_multi *syncmaster;
-int plxsd_master; /* if we have a master card (yet) */
+static int plxsd_master; /* if we have a master card (yet) */
 static spinlock_t plx_lock; /* may not acquire other lock inside */
-EXPORT_SYMBOL(plx_lock);
 
 #define        TYP_E1          1
 #define        TYP_4S          4
@@ -185,7 +186,6 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30  };
 #define        CLKDEL_TE       0x0f    /* CLKDEL in TE mode */
 #define        CLKDEL_NT       0x6c    /* CLKDEL in NT mode
                                   (0x60 MUST be included!) */
-static u_char silence =        0xff;   /* silence by LAW */
 
 #define        DIP_4S  0x1             /* DIP Switches for Beronet 1S/2S/4S cards */
 #define        DIP_8S  0x2             /* DIP Switches for Beronet 8S+ cards */
@@ -196,12 +196,13 @@ static u_char silence =   0xff;   /* silence by LAW */
  */
 
 static uint    type[MAX_CARDS];
-static uint    pcm[MAX_CARDS];
-static uint    dslot[MAX_CARDS];
+static int     pcm[MAX_CARDS];
+static int     dslot[MAX_CARDS];
 static uint    iomode[MAX_CARDS];
 static uint    port[MAX_PORTS];
 static uint    debug;
 static uint    poll;
+static int     clock;
 static uint    timer;
 static uint    clockdelay_te = CLKDEL_TE;
 static uint    clockdelay_nt = CLKDEL_NT;
@@ -210,14 +211,16 @@ static int        HFC_cnt, Port_cnt, PCM_cnt = 99;
 
 MODULE_AUTHOR("Andreas Eversberg");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(HFC_MULTI_VERSION);
 module_param(debug, uint, S_IRUGO | S_IWUSR);
 module_param(poll, uint, S_IRUGO | S_IWUSR);
+module_param(clock, int, S_IRUGO | S_IWUSR);
 module_param(timer, uint, S_IRUGO | S_IWUSR);
 module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR);
 module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR);
 module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR);
-module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR);
+module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR);
 module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR);
 module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR);
 
@@ -422,7 +425,7 @@ HFC_wait_debug(struct hfc_multi *hc, const char *function, int line)
 #endif
 
 /* write fifo data (REGIO) */
-void
+static void
 write_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
 {
        outb(A_FIFO_DATA0, (hc->pci_iobase)+4);
@@ -443,7 +446,7 @@ write_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
        }
 }
 /* write fifo data (PCIMEM) */
-void
+static void
 write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
 {
        while (len>>2) {
@@ -465,7 +468,7 @@ write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
        }
 }
 /* read fifo data (REGIO) */
-void
+static void
 read_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
 {
        outb(A_FIFO_DATA0, (hc->pci_iobase)+4);
@@ -487,7 +490,7 @@ read_fifo_regio(struct hfc_multi *hc, u_char *data, int len)
 }
 
 /* read fifo data (PCIMEM) */
-void
+static void
 read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len)
 {
        while (len>>2) {
@@ -706,7 +709,7 @@ vpm_out(struct hfc_multi *c, int which, unsigned short addr,
 }
 
 
-void
+static void
 vpm_init(struct hfc_multi *wc)
 {
        unsigned char reg;
@@ -789,7 +792,8 @@ vpm_init(struct hfc_multi *wc)
        }
 }
 
-void
+#ifdef UNUSED
+static void
 vpm_check(struct hfc_multi *hctmp)
 {
        unsigned char gpi2;
@@ -799,6 +803,7 @@ vpm_check(struct hfc_multi *hctmp)
        if ((gpi2 & 0x3) != 0x3)
                printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2);
 }
+#endif /* UNUSED */
 
 
 /*
@@ -812,7 +817,7 @@ vpm_check(struct hfc_multi *hctmp)
  *
  */
 
-void
+static void
 vpm_echocan_on(struct hfc_multi *hc, int ch, int taps)
 {
        unsigned int timeslot;
@@ -844,7 +849,7 @@ vpm_echocan_on(struct hfc_multi *hc, int ch, int taps)
        vpm_out(hc, unit, timeslot, 0x7e);
 }
 
-void
+static void
 vpm_echocan_off(struct hfc_multi *hc, int ch)
 {
        unsigned int timeslot;
@@ -887,8 +892,9 @@ vpm_echocan_off(struct hfc_multi *hc, int ch)
 static inline void
 hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
 {
-       struct hfc_multi *hc, *next, *pcmmaster = 0;
-       u_int *plx_acc_32, pv;
+       struct hfc_multi *hc, *next, *pcmmaster = NULL;
+       void __iomem *plx_acc_32;
+       u_int pv;
        u_long flags;
 
        spin_lock_irqsave(&HFClock, flags);
@@ -916,7 +922,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
        /* Disable sync of all cards */
        list_for_each_entry_safe(hc, next, &HFClist, list) {
                if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
-                       plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+                       plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                        pv = readl(plx_acc_32);
                        pv &= ~PLX_SYNC_O_EN;
                        writel(pv, plx_acc_32);
@@ -938,7 +944,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
                        printk(KERN_DEBUG "id=%d (0x%p) = syncronized with "
                                "interface.\n", hc->id, hc);
                /* Enable new sync master */
-               plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+               plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                pv = readl(plx_acc_32);
                pv |= PLX_SYNC_O_EN;
                writel(pv, plx_acc_32);
@@ -968,7 +974,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm)
                                            "QUARTZ is automatically "
                                            "enabled by HFC-%dS\n", hc->type);
                        }
-                       plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+                       plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                        pv = readl(plx_acc_32);
                        pv |= PLX_SYNC_O_EN;
                        writel(pv, plx_acc_32);
@@ -1013,7 +1019,8 @@ plxsd_checksync(struct hfc_multi *hc, int rm)
 static void
 release_io_hfcmulti(struct hfc_multi *hc)
 {
-       u_int   *plx_acc_32, pv;
+       void __iomem *plx_acc_32;
+       u_int   pv;
        u_long  plx_flags;
 
        if (debug & DEBUG_HFCMULTI_INIT)
@@ -1033,7 +1040,7 @@ release_io_hfcmulti(struct hfc_multi *hc)
                        printk(KERN_DEBUG "%s: release PLXSD card %d\n",
                            __func__, hc->id + 1);
                spin_lock_irqsave(&plx_lock, plx_flags);
-               plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+               plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                writel(PLX_GPIOC_INIT, plx_acc_32);
                pv = readl(plx_acc_32);
                /* Termination off */
@@ -1055,9 +1062,9 @@ release_io_hfcmulti(struct hfc_multi *hc)
        test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */
        pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0);
        if (hc->pci_membase)
-               iounmap((void *)hc->pci_membase);
+               iounmap(hc->pci_membase);
        if (hc->plx_membase)
-               iounmap((void *)hc->plx_membase);
+               iounmap(hc->plx_membase);
        if (hc->pci_iobase)
                release_region(hc->pci_iobase, 8);
 
@@ -1080,7 +1087,8 @@ init_chip(struct hfc_multi *hc)
        u_long                  flags, val, val2 = 0, rev;
        int                     i, err = 0;
        u_char                  r_conf_en, rval;
-       u_int                   *plx_acc_32, pv;
+       void __iomem            *plx_acc_32;
+       u_int                   pv;
        u_long                  plx_flags, hfc_flags;
        int                     plx_count;
        struct hfc_multi        *pos, *next, *plx_last_hc;
@@ -1154,7 +1162,7 @@ init_chip(struct hfc_multi *hc)
                        printk(KERN_DEBUG "%s: initializing PLXSD card %d\n",
                            __func__, hc->id + 1);
                spin_lock_irqsave(&plx_lock, plx_flags);
-               plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+               plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                writel(PLX_GPIOC_INIT, plx_acc_32);
                pv = readl(plx_acc_32);
                /* The first and the last cards are terminating the PCM bus */
@@ -1190,8 +1198,7 @@ init_chip(struct hfc_multi *hc)
                                        "we disable termination\n",
                                    __func__, plx_last_hc->id + 1);
                        spin_lock_irqsave(&plx_lock, plx_flags);
-                       plx_acc_32 = (u_int *)(plx_last_hc->plx_membase
-                                       + PLX_GPIOC);
+                       plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC;
                        pv = readl(plx_acc_32);
                        pv &= ~PLX_TERM_ON;
                        writel(pv, plx_acc_32);
@@ -1240,7 +1247,7 @@ init_chip(struct hfc_multi *hc)
        /* Speech Design PLX bridge pcm and sync mode */
        if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
                spin_lock_irqsave(&plx_lock, plx_flags);
-               plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+               plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                pv = readl(plx_acc_32);
                /* Connect PCM */
                if (hc->hw.r_pcm_md0 & V_PCM_MD) {
@@ -1352,8 +1359,7 @@ controller_fail:
                        /* retry with master clock */
                        if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
                                spin_lock_irqsave(&plx_lock, plx_flags);
-                               plx_acc_32 = (u_int *)(hc->plx_membase +
-                                       PLX_GPIOC);
+                               plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                                pv = readl(plx_acc_32);
                                pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N;
                                pv |= PLX_SYNC_O_EN;
@@ -1389,7 +1395,7 @@ controller_fail:
                if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip))
                        plxsd_master = 1;
                spin_lock_irqsave(&plx_lock, plx_flags);
-               plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC);
+               plx_acc_32 = hc->plx_membase + PLX_GPIOC;
                pv = readl(plx_acc_32);
                pv |=  PLX_DSP_RES_N;
                writel(pv, plx_acc_32);
@@ -1417,19 +1423,6 @@ controller_fail:
        HFC_outb(hc, R_TI_WD, poll_timer);
        hc->hw.r_irqmsk_misc |= V_TI_IRQMSK;
 
-       /*
-        * set up 125us interrupt, only if function pointer is available
-        * and module parameter timer is set
-        */
-       if (timer && hfc_interrupt && register_interrupt) {
-               /* only one chip should use this interrupt */
-               timer = 0;
-               interrupt_registered = 1;
-               hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK;
-               /* deactivate other interrupts in ztdummy */
-               register_interrupt();
-       }
-
        /* set E1 state machine IRQ */
        if (hc->type == 1)
                hc->hw.r_irqmsk_misc |= V_STA_IRQMSK;
@@ -1989,6 +1982,17 @@ next_frame:
                return; /* no data */
        }
 
+       /* "fill fifo if empty" feature */
+       if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags)
+               && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) {
+               if (debug & DEBUG_HFCMULTI_FILL)
+                       printk(KERN_DEBUG "%s: buffer empty, so we have "
+                               "underrun\n", __func__);
+               /* fill buffer, to prevent future underrun */
+               hc->write_fifo(hc, hc->silence_data, poll >> 1);
+               Zspace -= (poll >> 1);
+       }
+
        /* if audio data and connected slot */
        if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending)
                && slot_tx >= 0) {
@@ -2025,7 +2029,6 @@ next_frame:
                        __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i,
                        temp ? "HDLC":"TRANS");
 
-
        /* Have to prep the audio data */
        hc->write_fifo(hc, d, ii - i);
        *idxp = ii;
@@ -2064,7 +2067,7 @@ next_frame:
         * no more data at all. this prevents sending an undefined value.
         */
        if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags))
-               HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence);
+               HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
 }
 
 
@@ -2581,12 +2584,12 @@ hfcmulti_interrupt(int intno, void *dev_id)
        static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0,
            iq5 = 0, iq6 = 0, iqcnt = 0;
 #endif
-       static int              count;
        struct hfc_multi        *hc = dev_id;
        struct dchannel         *dch;
        u_char                  r_irq_statech, status, r_irq_misc, r_irq_oview;
        int                     i;
-       u_short                 *plx_acc, wval;
+       void __iomem            *plx_acc;
+       u_short                 wval;
        u_char                  e1_syncsta, temp;
        u_long                  flags;
 
@@ -2606,7 +2609,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
 
        if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
                spin_lock_irqsave(&plx_lock, flags);
-               plx_acc = (u_short *)(hc->plx_membase + PLX_INTCSR);
+               plx_acc = hc->plx_membase + PLX_INTCSR;
                wval = readw(plx_acc);
                spin_unlock_irqrestore(&plx_lock, flags);
                if (!(wval & PLX_INTCSR_LINTI1_STATUS))
@@ -2634,6 +2637,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
                iqcnt = 0;
        }
 #endif
+
        if (!r_irq_statech &&
            !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA |
            V_MISC_IRQSTA | V_FR_IRQSTA))) {
@@ -2688,23 +2692,20 @@ hfcmulti_interrupt(int intno, void *dev_id)
                                        plxsd_checksync(hc, 0);
                        }
                }
-               if (r_irq_misc & V_TI_IRQ)
+               if (r_irq_misc & V_TI_IRQ) {
+                       if (hc->iclock_on)
+                               mISDN_clock_update(hc->iclock, poll, NULL);
                        handle_timer_irq(hc);
+               }
 
                if (r_irq_misc & V_DTMF_IRQ) {
-                       /* -> DTMF IRQ */
                        hfcmulti_dtmf(hc);
                }
-               /* TODO: REPLACE !!!! 125 us Interrupts are not acceptable  */
                if (r_irq_misc & V_IRQ_PROC) {
-                       /* IRQ every 125us */
-                       count++;
-                       /* generate 1kHz signal */
-                       if (count == 8) {
-                               if (hfc_interrupt)
-                                       hfc_interrupt();
-                               count = 0;
-                       }
+                       static int irq_proc_cnt;
+                       if (!irq_proc_cnt++)
+                               printk(KERN_WARNING "%s: got V_IRQ_PROC -"
+                                   " this should not happen\n", __func__);
                }
 
        }
@@ -2951,7 +2952,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
                        HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
                        HFC_wait(hc);
                        /* tx silence */
-                       HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence);
+                       HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
                        HFC_outb(hc, R_SLOT, (((ch / 4) * 8) +
                            ((ch % 4) * 4)) << 1);
                        HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1));
@@ -2966,7 +2967,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx,
                        HFC_outb(hc, R_INC_RES_FIFO, V_RES_F);
                        HFC_wait(hc);
                        /* tx silence */
-                       HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence);
+                       HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence);
                        /* enable RX fifo */
                        HFC_outb(hc, R_FIFO, (ch<<1)|1);
                        HFC_wait(hc);
@@ -3458,7 +3459,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
        switch (cq->op) {
        case MISDN_CTRL_GETOP:
                cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP
-                       | MISDN_CTRL_RX_OFF;
+                       | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY;
                break;
        case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */
                hc->chan[bch->slot].rx_off = !!cq->p1;
@@ -3473,6 +3474,12 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq)
                        printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n",
                            __func__, bch->nr, hc->chan[bch->slot].rx_off);
                break;
+       case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */
+               test_and_set_bit(FLG_FILLEMPTY, &bch->Flags);
+               if (debug & DEBUG_HFCMULTI_MSG)
+                       printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d "
+                               "off=%d)\n", __func__, bch->nr, !!cq->p1);
+               break;
        case MISDN_CTRL_HW_FEATURES: /* fill features structure */
                if (debug & DEBUG_HFCMULTI_MSG)
                        printk(KERN_DEBUG "%s: HW_FEATURE request\n",
@@ -3989,6 +3996,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch,
        }
        if (test_and_set_bit(FLG_OPEN, &bch->Flags))
                return -EBUSY; /* b-channel can be only open once */
+       test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags);
        bch->ch.protocol = rq->protocol;
        hc->chan[ch].rx_off = 0;
        rq->ch = &bch->ch;
@@ -4078,6 +4086,15 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg)
        return err;
 }
 
+static int
+clockctl(void *priv, int enable)
+{
+       struct hfc_multi *hc = priv;
+
+       hc->iclock_on = enable;
+       return 0;
+}
+
 /*
  * initialize the card
  */
@@ -4091,7 +4108,7 @@ init_card(struct hfc_multi *hc)
 {
        int     err = -EIO;
        u_long  flags;
-       u_short *plx_acc;
+       void    __iomem *plx_acc;
        u_long  plx_flags;
 
        if (debug & DEBUG_HFCMULTI_INIT)
@@ -4113,7 +4130,7 @@ init_card(struct hfc_multi *hc)
 
        if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
                spin_lock_irqsave(&plx_lock, plx_flags);
-               plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR);
+               plx_acc = hc->plx_membase + PLX_INTCSR;
                writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE),
                        plx_acc); /* enable PCI & LINT1 irq */
                spin_unlock_irqrestore(&plx_lock, plx_flags);
@@ -4162,7 +4179,7 @@ init_card(struct hfc_multi *hc)
 error:
        if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) {
                spin_lock_irqsave(&plx_lock, plx_flags);
-               plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR);
+               plx_acc = hc->plx_membase + PLX_INTCSR;
                writew(0x00, plx_acc); /*disable IRQs*/
                spin_unlock_irqrestore(&plx_lock, plx_flags);
        }
@@ -4492,10 +4509,14 @@ release_card(struct hfc_multi *hc)
                printk(KERN_WARNING "%s: release card (%d) entered\n",
                    __func__, hc->id);
 
+       /* unregister clock source */
+       if (hc->iclock)
+               mISDN_unregister_clock(hc->iclock);
+
+       /* disable irq */
        spin_lock_irqsave(&hc->lock, flags);
        disable_hwirq(hc);
        spin_unlock_irqrestore(&hc->lock, flags);
-
        udelay(1000);
 
        /* dimm leds */
@@ -4825,6 +4846,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct hfc_multi        *hc;
        u_long          flags;
        u_char          dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
+       int             i;
 
        if (HFC_cnt >= MAX_CARDS) {
                printk(KERN_ERR "too many cards (max=%d).\n",
@@ -4858,11 +4880,11 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        hc->id = HFC_cnt;
        hc->pcm = pcm[HFC_cnt];
        hc->io_mode = iomode[HFC_cnt];
-       if (dslot[HFC_cnt] < 0) {
+       if (dslot[HFC_cnt] < 0 && hc->type == 1) {
                hc->dslot = 0;
                printk(KERN_INFO "HFC-E1 card has disabled D-channel, but "
                        "31 B-channels\n");
-       } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32) {
+       } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) {
                hc->dslot = dslot[HFC_cnt];
                printk(KERN_INFO "HFC-E1 card has alternating D-channel on "
                        "time slot %d\n", dslot[HFC_cnt]);
@@ -4873,9 +4895,17 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        hc->masterclk = -1;
        if (type[HFC_cnt] & 0x100) {
                test_and_set_bit(HFC_CHIP_ULAW, &hc->chip);
-               silence = 0xff; /* ulaw silence */
+               hc->silence = 0xff; /* ulaw silence */
        } else
-               silence = 0x2a; /* alaw silence */
+               hc->silence = 0x2a; /* alaw silence */
+       if ((poll >> 1) > sizeof(hc->silence_data)) {
+               printk(KERN_ERR "HFCMULTI error: silence_data too small, "
+                       "please fix\n");
+               return -EINVAL;
+       }
+       for (i = 0; i < (poll >> 1); i++)
+               hc->silence_data[i] = hc->silence;
+
        if (!(type[HFC_cnt] & 0x200))
                test_and_set_bit(HFC_CHIP_DTMF, &hc->chip);
 
@@ -4942,9 +4972,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        switch (m->dip_type) {
        case DIP_4S:
                /*
-                * get DIP Setting for beroNet 1S/2S/4S cards
-                *  check if Port Jumper config matches
-                * module param 'protocol'
+                * Get DIP setting for beroNet 1S/2S/4S cards
                 * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) +
                 * GPI 19/23 (R_GPI_IN2))
                 */
@@ -4963,9 +4991,8 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        case DIP_8S:
                /*
-                * get DIP Setting for beroNet 8S0+ cards
-                *
-                * enable PCI auxbridge function
+                * Get DIP Setting for beroNet 8S0+ cards
+                * Enable PCI auxbridge function
                 */
                HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK);
                /* prepare access to auxport */
@@ -5000,6 +5027,10 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent)
        list_add_tail(&hc->list, &HFClist);
        spin_unlock_irqrestore(&HFClock, flags);
 
+       /* use as clock source */
+       if (clock == HFC_cnt + 1)
+               hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc);
+
        /* initialize hardware */
        ret_err = init_card(hc);
        if (ret_err) {
@@ -5134,8 +5165,7 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = {
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
        PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
-       PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)},
-           /* IOB8ST Recording */
+       PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
                PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST  */
        { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD,
@@ -5185,18 +5215,16 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct hm_map   *m = (struct hm_map *)ent->driver_data;
        int             ret;
 
-       if (m == NULL) {
-               if (ent->vendor == PCI_VENDOR_ID_CCD)
-                       if (ent->device == PCI_DEVICE_ID_CCD_HFC4S ||
-                           ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
-                           ent->device == PCI_DEVICE_ID_CCD_HFCE1)
-                               printk(KERN_ERR
-                                   "unknown HFC multiport controller "
-                                   "(vendor:%x device:%x subvendor:%x "
-                                   "subdevice:%x) Please contact the "
-                                   "driver maintainer for support.\n",
-                                   ent->vendor, ent->device,
-                                   ent->subvendor, ent->subdevice);
+       if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && (
+           ent->device == PCI_DEVICE_ID_CCD_HFC4S ||
+           ent->device == PCI_DEVICE_ID_CCD_HFC8S ||
+           ent->device == PCI_DEVICE_ID_CCD_HFCE1)) {
+               printk(KERN_ERR
+                   "Unknown HFC multiport controller (vendor:%x device:%x "
+                   "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device,
+                   ent->subvendor, ent->subdevice);
+               printk(KERN_ERR
+                   "Please contact the driver maintainer for support.\n");
                return -ENODEV;
        }
        ret = hfcmulti_init(pdev, ent);
@@ -5219,22 +5247,9 @@ HFCmulti_cleanup(void)
 {
        struct hfc_multi *card, *next;
 
-       /* unload interrupt function symbol */
-       if (hfc_interrupt)
-               symbol_put(ztdummy_extern_interrupt);
-       if (register_interrupt)
-               symbol_put(ztdummy_register_interrupt);
-       if (unregister_interrupt) {
-               if (interrupt_registered) {
-                       interrupt_registered = 0;
-                       unregister_interrupt();
-               }
-               symbol_put(ztdummy_unregister_interrupt);
-       }
-
+       /* get rid of all devices of this driver */
        list_for_each_entry_safe(card, next, &HFClist, list)
                release_card(card);
-       /* get rid of all devices of this driver */
        pci_unregister_driver(&hfcmultipci_driver);
 }
 
@@ -5243,8 +5258,10 @@ HFCmulti_init(void)
 {
        int err;
 
+       printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION);
+
 #ifdef IRQ_DEBUG
-       printk(KERN_ERR "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
+       printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__);
 #endif
 
        spin_lock_init(&HFClock);
@@ -5253,22 +5270,11 @@ HFCmulti_init(void)
        if (debug & DEBUG_HFCMULTI_INIT)
                printk(KERN_DEBUG "%s: init entered\n", __func__);
 
-       hfc_interrupt = symbol_get(ztdummy_extern_interrupt);
-       register_interrupt = symbol_get(ztdummy_register_interrupt);
-       unregister_interrupt = symbol_get(ztdummy_unregister_interrupt);
-       printk(KERN_INFO "mISDN: HFC-multi driver %s\n",
-           hfcmulti_revision);
-
        switch (poll) {
        case 0:
                poll_timer = 6;
                poll = 128;
                break;
-               /*
-                * wenn dieses break nochmal verschwindet,
-                * gibt es heisse ohren :-)
-                * "without the break you will get hot ears ???"
-                */
        case 8:
                poll_timer = 2;
                break;
@@ -5295,20 +5301,12 @@ HFCmulti_init(void)
 
        }
 
+       if (!clock)
+               clock = 1;
+
        err = pci_register_driver(&hfcmultipci_driver);
        if (err < 0) {
                printk(KERN_ERR "error registering pci driver: %x\n", err);
-               if (hfc_interrupt)
-                       symbol_put(ztdummy_extern_interrupt);
-               if (register_interrupt)
-                       symbol_put(ztdummy_register_interrupt);
-               if (unregister_interrupt) {
-                       if (interrupt_registered) {
-                               interrupt_registered = 0;
-                               unregister_interrupt();
-                       }
-                       symbol_put(ztdummy_unregister_interrupt);
-               }
                return err;
        }
        return 0;