Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07003408 authored by Andreas Eversberg's avatar Andreas Eversberg Committed by David S. Miller
Browse files

mISDN: Added support for fragmentation of E1 interfaces of hfcmulti driver.



Fragmentation is usefull if multiple devices are connected to an E1
interface. Each fragment will have a subset of the available timeslots.
These devices require a cascde connection or a multiplexer.

Signed-off-by: default avatarAndreas Eversberg <jolly@eversberg.eu>
Signed-off-by: default avatarKarsten Keil <keil@b1-systems.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 864fd636
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -208,7 +208,10 @@ struct hfc_multi {
	u_long		ledstate; /* save last state of leds */
	int		opticalsupport; /* has the e1 board */
					/* an optical Interface */
	int		dslot;	/* channel # of d-channel (E1) default 16 */

	u_int		bmask[32]; /* bitmask of bchannels for port */
	u_char		dnum[32]; /* array of used dchannel numbers for port */
	u_char		created[32]; /* what port is created */
	u_int		activity_tx; /* if there is data TX / RX */
	u_int		activity_rx; /* bitmask according to port number */
				     /* (will be cleared after */
@@ -234,7 +237,6 @@ struct hfc_multi {
	 * the bch->channel is equvalent to the hfc-channel
	 */
	struct hfc_chan	chan[32];
	u_char		created[8]; /* what port is created */
	signed char	slot_owner[256]; /* owner channel of slot */
};

+232 −164
Original line number Diff line number Diff line
@@ -103,14 +103,26 @@
 *	Omit this value, if all cards are interconnected or none is connected.
 *	If unsure, don't give this parameter.
 *
 * dslot:
 *	NOTE: only one dslot value must be given for every card.
 *	Also this value must be given for non-E1 cards. If omitted, the E1
 *	card has D-channel on time slot 16, which is default.
 *	If 1..15 or 17..31, an alternate time slot is used for D-channel.
 *	In this case, the application must be able to handle this.
 *	If -1 is given, the D-channel is disabled and all 31 slots can be used
 *	for B-channel. (only for specific applications)
 * dmask and bmask:
 *	NOTE: One dmask value must be given for every HFC-E1 card.
 *	If omitted, the E1 card has D-channel on time slot 16, which is default.
 *	dmask is a 32 bit mask. The bit must be set for an alternate time slot.
 *	If multiple bits are set, multiple virtual card fragments are created.
 *	For each bit set, a bmask value must be given. Each bit on the bmask
 *	value stands for a B-channel. The bmask may not overlap with dmask or
 *	with other bmask values for that card.
 *	Example: dmask=0x00020002 bmask=0x0000fffc,0xfffc0000
 *		This will create one fragment with D-channel on slot 1 with
 *		B-channels on slots 2..15, and a second fragment with D-channel
 *		on slot 17 with B-channels on slot 18..31. Slot 16 is unused.
 *	If bit 0 is set (dmask=0x00000001) the D-channel is on slot 0 and will
 *	not function.
 *	Example: dmask=0x00000001 bmask=0xfffffffe
 *		This will create a port with all 31 usable timeslots as
 *		B-channels.
 *	If no bits are set on bmask, no B-channel is created for that fragment.
 *	Example: dmask=0xfffffffe bmask=0,0,0,0.... (31 0-values for bmask)
 *		This will create 31 ports with one D-channel only.
 *	If you don't know how to use it, you don't need it!
 *
 * iomode:
@@ -172,6 +184,7 @@

#define	MAX_CARDS	8
#define	MAX_PORTS	(8 * MAX_CARDS)
#define	MAX_FRAGS	(32 * MAX_CARDS)

static LIST_HEAD(HFClist);
static spinlock_t HFClock; /* global hfc list lock */
@@ -203,7 +216,8 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 };

static uint	type[MAX_CARDS];
static int	pcm[MAX_CARDS];
static int	dslot[MAX_CARDS];
static uint	dmask[MAX_CARDS];
static uint	bmask[MAX_FRAGS];
static uint	iomode[MAX_CARDS];
static uint	port[MAX_PORTS];
static uint	debug;
@@ -218,7 +232,7 @@ static uint clockdelay_nt = CLKDEL_NT;
#define HWID_MINIP16	3
static uint	hwid = HWID_NONE;

static int	HFC_cnt, Port_cnt, PCM_cnt = 99;
static int	HFC_cnt, E1_cnt, bmask_cnt, Port_cnt, PCM_cnt = 99;

MODULE_AUTHOR("Andreas Eversberg");
MODULE_LICENSE("GPL");
@@ -231,7 +245,8 @@ 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, int, NULL, S_IRUGO | S_IWUSR);
module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR);
module_param_array(dmask, uint, NULL, S_IRUGO | S_IWUSR);
module_param_array(bmask, uint, 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);
module_param(hwid, uint, S_IRUGO | S_IWUSR); /* The hardware ID */
@@ -1619,9 +1634,9 @@ hfcmulti_leds(struct hfc_multi *hc)
		led[1] = 0;
		led[2] = 0;
		led[3] = 0;
		dch = hc->chan[hc->dslot].dch;
		dch = hc->chan[hc->dnum[0]].dch;
		if (dch) {
			if (hc->chan[hc->dslot].los)
			if (hc->chan[hc->dnum[0]].los)
				led[1] = 1;
			if (hc->e1_state != 1) {
				led[0] = 1;
@@ -2453,55 +2468,55 @@ handle_timer_irq(struct hfc_multi *hc)
			}
		}
	if (hc->ctype == HFC_TYPE_E1 && hc->created[0]) {
		dch = hc->chan[hc->dslot].dch;
		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) {
		dch = hc->chan[hc->dnum[0]].dch;
		/* LOS */
		temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_SIG_LOS;
			if (!temp && hc->chan[hc->dslot].los)
		hc->chan[hc->dnum[0]].los = temp;
		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) {
			if (!temp && hc->chan[hc->dnum[0]].los)
				signal_state_up(dch, L1_SIGNAL_LOS_ON,
						"LOS detected");
			if (temp && !hc->chan[hc->dslot].los)
			if (temp && !hc->chan[hc->dnum[0]].los)
				signal_state_up(dch, L1_SIGNAL_LOS_OFF,
						"LOS gone");
			hc->chan[hc->dslot].los = temp;
		}
		if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dslot].cfg)) {
		if (test_bit(HFC_CFG_REPORT_AIS, &hc->chan[hc->dnum[0]].cfg)) {
			/* AIS */
			temp = HFC_inb_nodebug(hc, R_SYNC_STA) & V_AIS;
			if (!temp && hc->chan[hc->dslot].ais)
			if (!temp && hc->chan[hc->dnum[0]].ais)
				signal_state_up(dch, L1_SIGNAL_AIS_ON,
						"AIS detected");
			if (temp && !hc->chan[hc->dslot].ais)
			if (temp && !hc->chan[hc->dnum[0]].ais)
				signal_state_up(dch, L1_SIGNAL_AIS_OFF,
						"AIS gone");
			hc->chan[hc->dslot].ais = temp;
			hc->chan[hc->dnum[0]].ais = temp;
		}
		if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dslot].cfg)) {
		if (test_bit(HFC_CFG_REPORT_SLIP, &hc->chan[hc->dnum[0]].cfg)) {
			/* SLIP */
			temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_RX;
			if (!temp && hc->chan[hc->dslot].slip_rx)
			if (!temp && hc->chan[hc->dnum[0]].slip_rx)
				signal_state_up(dch, L1_SIGNAL_SLIP_RX,
						" bit SLIP detected RX");
			hc->chan[hc->dslot].slip_rx = temp;
			hc->chan[hc->dnum[0]].slip_rx = temp;
			temp = HFC_inb_nodebug(hc, R_SLIP) & V_FOSLIP_TX;
			if (!temp && hc->chan[hc->dslot].slip_tx)
			if (!temp && hc->chan[hc->dnum[0]].slip_tx)
				signal_state_up(dch, L1_SIGNAL_SLIP_TX,
						" bit SLIP detected TX");
			hc->chan[hc->dslot].slip_tx = temp;
			hc->chan[hc->dnum[0]].slip_tx = temp;
		}
		if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dslot].cfg)) {
		if (test_bit(HFC_CFG_REPORT_RDI, &hc->chan[hc->dnum[0]].cfg)) {
			/* RDI */
			temp = HFC_inb_nodebug(hc, R_RX_SL0_0) & V_A;
			if (!temp && hc->chan[hc->dslot].rdi)
			if (!temp && hc->chan[hc->dnum[0]].rdi)
				signal_state_up(dch, L1_SIGNAL_RDI_ON,
						"RDI detected");
			if (temp && !hc->chan[hc->dslot].rdi)
			if (temp && !hc->chan[hc->dnum[0]].rdi)
				signal_state_up(dch, L1_SIGNAL_RDI_OFF,
						"RDI gone");
			hc->chan[hc->dslot].rdi = temp;
			hc->chan[hc->dnum[0]].rdi = temp;
		}
		temp = HFC_inb_nodebug(hc, R_JATT_DIR);
		switch (hc->chan[hc->dslot].sync) {
		switch (hc->chan[hc->dnum[0]].sync) {
		case 0:
			if ((temp & 0x60) == 0x60) {
				if (debug & DEBUG_HFCMULTI_SYNC)
@@ -2510,10 +2525,10 @@ handle_timer_irq(struct hfc_multi *hc)
					       "in clock sync\n",
					       __func__, hc->id);
				HFC_outb(hc, R_RX_OFF,
					 hc->chan[hc->dslot].jitter | V_RX_INIT);
				    hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
				HFC_outb(hc, R_TX_OFF,
					 hc->chan[hc->dslot].jitter | V_RX_INIT);
				hc->chan[hc->dslot].sync = 1;
				    hc->chan[hc->dnum[0]].jitter | V_RX_INIT);
				hc->chan[hc->dnum[0]].sync = 1;
				goto check_framesync;
			}
			break;
@@ -2524,7 +2539,7 @@ handle_timer_irq(struct hfc_multi *hc)
					       "%s: (id=%d) E1 "
					       "lost clock sync\n",
					       __func__, hc->id);
				hc->chan[hc->dslot].sync = 0;
				hc->chan[hc->dnum[0]].sync = 0;
				break;
			}
		check_framesync:
@@ -2535,7 +2550,7 @@ handle_timer_irq(struct hfc_multi *hc)
					       "%s: (id=%d) E1 "
					       "now in frame sync\n",
					       __func__, hc->id);
				hc->chan[hc->dslot].sync = 2;
				hc->chan[hc->dnum[0]].sync = 2;
			}
			break;
		case 2:
@@ -2545,7 +2560,7 @@ handle_timer_irq(struct hfc_multi *hc)
					       "%s: (id=%d) E1 lost "
					       "clock & frame sync\n",
					       __func__, hc->id);
				hc->chan[hc->dslot].sync = 0;
				hc->chan[hc->dnum[0]].sync = 0;
				break;
			}
			temp = HFC_inb_nodebug(hc, R_SYNC_STA);
@@ -2555,7 +2570,7 @@ handle_timer_irq(struct hfc_multi *hc)
					       "%s: (id=%d) E1 "
					       "lost frame sync\n",
					       __func__, hc->id);
				hc->chan[hc->dslot].sync = 1;
				hc->chan[hc->dnum[0]].sync = 1;
			}
			break;
		}
@@ -2696,7 +2711,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
	int			i;
	void __iomem		*plx_acc;
	u_short			wval;
	u_char			e1_syncsta, temp;
	u_char			e1_syncsta, temp, temp2;
	u_long			flags;

	if (!hc) {
@@ -2771,7 +2786,7 @@ hfcmulti_interrupt(int intno, void *dev_id)
		if (r_irq_misc & V_STA_IRQ) {
			if (hc->ctype == HFC_TYPE_E1) {
				/* state machine */
				dch = hc->chan[hc->dslot].dch;
				dch = hc->chan[hc->dnum[0]].dch;
				e1_syncsta = HFC_inb_nodebug(hc, R_SYNC_STA);
				if (test_bit(HFC_CHIP_PLXSD, &hc->chip)
				    && hc->e1_getclock) {
@@ -2781,23 +2796,26 @@ hfcmulti_interrupt(int intno, void *dev_id)
						hc->syncronized = 0;
				}
				/* undocumented: status changes during read */
				dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA);
				while (dch->state != (temp =
				temp = HFC_inb_nodebug(hc, R_E1_RD_STA);
				while (temp != (temp2 =
						      HFC_inb_nodebug(hc, R_E1_RD_STA))) {
					if (debug & DEBUG_HFCMULTI_STATE)
						printk(KERN_DEBUG "%s: reread "
						       "STATE because %d!=%d\n",
						       __func__, temp,
						       dch->state);
					dch->state = temp; /* repeat */
						    __func__, temp, temp2);
					temp = temp2; /* repeat */
				}
				dch->state = HFC_inb_nodebug(hc, R_E1_RD_STA)
					& 0x7;
				schedule_event(dch, FLG_PHCHANGE);
				/* broadcast state change to all fragments */
				if (debug & DEBUG_HFCMULTI_STATE)
					printk(KERN_DEBUG
					       "%s: E1 (id=%d) newstate %x\n",
					       __func__, hc->id, dch->state);
					    __func__, hc->id, temp & 0x7);
				for (i = 0; i < hc->ports; i++) {
					dch = hc->chan[hc->dnum[i]].dch;
					dch->state = temp & 0x7;
					schedule_event(dch, FLG_PHCHANGE);
				}

				if (test_bit(HFC_CHIP_PLXSD, &hc->chip))
					plxsd_checksync(hc, 0);
			}
@@ -3870,31 +3888,37 @@ hfcmulti_initmode(struct dchannel *dch)
	if (debug & DEBUG_HFCMULTI_INIT)
		printk(KERN_DEBUG "%s: entered\n", __func__);

	i = dch->slot;
	pt = hc->chan[i].port;
	if (hc->ctype == HFC_TYPE_E1) {
		hc->chan[hc->dslot].slot_tx = -1;
		hc->chan[hc->dslot].slot_rx = -1;
		hc->chan[hc->dslot].conf = -1;
		if (hc->dslot) {
			mode_hfcmulti(hc, hc->dslot, dch->dev.D.protocol,
		/* E1 */
		hc->chan[hc->dnum[pt]].slot_tx = -1;
		hc->chan[hc->dnum[pt]].slot_rx = -1;
		hc->chan[hc->dnum[pt]].conf = -1;
		if (hc->dnum[pt]) {
			mode_hfcmulti(hc, dch->slot, dch->dev.D.protocol,
				      -1, 0, -1, 0);
			dch->timer.function = (void *) hfcmulti_dbusy_timer;
			dch->timer.data = (long) dch;
			init_timer(&dch->timer);
		}
		for (i = 1; i <= 31; i++) {
			if (i == hc->dslot)
			if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
				continue;
			hc->chan[i].slot_tx = -1;
			hc->chan[i].slot_rx = -1;
			hc->chan[i].conf = -1;
			mode_hfcmulti(hc, i, ISDN_P_NONE, -1, 0, -1, 0);
		}
		/* E1 */
		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dslot].cfg)) {
	}
	if (hc->ctype == HFC_TYPE_E1 && pt == 0) {
		/* E1, port 0 */
		dch = hc->chan[hc->dnum[0]].dch;
		if (test_bit(HFC_CFG_REPORT_LOS, &hc->chan[hc->dnum[0]].cfg)) {
			HFC_outb(hc, R_LOS0, 255); /* 2 ms */
			HFC_outb(hc, R_LOS1, 255); /* 512 ms */
		}
		if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dslot].cfg)) {
		if (test_bit(HFC_CFG_OPTICAL, &hc->chan[hc->dnum[0]].cfg)) {
			HFC_outb(hc, R_RX0, 0);
			hc->hw.r_tx0 = 0 | V_OUT_EN;
		} else {
@@ -3907,12 +3931,12 @@ hfcmulti_initmode(struct dchannel *dch)
		HFC_outb(hc, R_TX_FR0, 0x00);
		HFC_outb(hc, R_TX_FR1, 0xf8);

		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg))
		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
			HFC_outb(hc, R_TX_FR2, V_TX_MF | V_TX_E | V_NEG_E);

		HFC_outb(hc, R_RX_FR0, V_AUTO_RESYNC | V_AUTO_RECO | 0);

		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dslot].cfg))
		if (test_bit(HFC_CFG_CRC4, &hc->chan[hc->dnum[0]].cfg))
			HFC_outb(hc, R_RX_FR1, V_RX_MF | V_RX_MF_SYNC);

		if (dch->dev.D.protocol == ISDN_P_NT_E1) {
@@ -3975,8 +3999,9 @@ hfcmulti_initmode(struct dchannel *dch)
			hc->syncronized = 0;
			plxsd_checksync(hc, 0);
		}
	} else {
		i = dch->slot;
	}
	if (hc->ctype != HFC_TYPE_E1) {
		/* ST */
		hc->chan[i].slot_tx = -1;
		hc->chan[i].slot_rx = -1;
		hc->chan[i].conf = -1;
@@ -3992,8 +4017,6 @@ hfcmulti_initmode(struct dchannel *dch)
		hc->chan[i - 1].slot_rx = -1;
		hc->chan[i - 1].conf = -1;
		mode_hfcmulti(hc, i - 1, ISDN_P_NONE, -1, 0, -1, 0);
		/* ST */
		pt = hc->chan[i].port;
		/* select interface */
		HFC_outb(hc, R_ST_SEL, pt);
		/* undocumented: delay after R_ST_SEL */
@@ -4571,6 +4594,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch)
		}
		/* free channels */
		for (i = 0; i <= 31; i++) {
			if (!((1 << i) & hc->bmask[pt])) /* skip unused chan */
				continue;
			if (hc->chan[i].bch) {
				if (debug & DEBUG_HFCMULTI_INIT)
					printk(KERN_DEBUG
@@ -4626,7 +4651,8 @@ release_port(struct hfc_multi *hc, struct dchannel *dch)
	spin_unlock_irqrestore(&hc->lock, flags);

	if (debug & DEBUG_HFCMULTI_INIT)
		printk(KERN_DEBUG "%s: free port %d channel D\n", __func__, pt);
		printk(KERN_DEBUG "%s: free port %d channel D(%d)\n", __func__,
			pt+1, ci);
	mISDN_freedchannel(dch);
	kfree(dch);

@@ -4648,15 +4674,19 @@ release_card(struct hfc_multi *hc)
	if (hc->iclock)
		mISDN_unregister_clock(hc->iclock);

	/* disable irq */
	/* disable and free irq */
	spin_lock_irqsave(&hc->lock, flags);
	disable_hwirq(hc);
	spin_unlock_irqrestore(&hc->lock, flags);
	udelay(1000);
	if (hc->irq) {
		if (debug & DEBUG_HFCMULTI_INIT)
			printk(KERN_DEBUG "%s: free irq %d (hc=%p)\n",
			    __func__, hc->irq, hc);
		free_irq(hc->irq, hc);
		hc->irq = 0;

	/* dimm leds */
	if (hc->leds)
		hfcmulti_leds(hc);
	}

	/* disable D-channels & B-channels */
	if (debug & DEBUG_HFCMULTI_INIT)
@@ -4667,15 +4697,11 @@ release_card(struct hfc_multi *hc)
			release_port(hc, hc->chan[ch].dch);
	}

	/* release hardware & irq */
	if (hc->irq) {
		if (debug & DEBUG_HFCMULTI_INIT)
			printk(KERN_DEBUG "%s: free irq %d\n",
			       __func__, hc->irq);
		free_irq(hc->irq, hc);
		hc->irq = 0;
	/* dimm leds */
	if (hc->leds)
		hfcmulti_leds(hc);

	}
	/* release hardware */
	release_io_hfcmulti(hc);

	if (debug & DEBUG_HFCMULTI_INIT)
@@ -4693,61 +4719,9 @@ release_card(struct hfc_multi *hc)
		       __func__);
}

static int
init_e1_port(struct hfc_multi *hc, struct hm_map *m)
static void
init_e1_port_hw(struct hfc_multi *hc, struct hm_map *m)
{
	struct dchannel	*dch;
	struct bchannel	*bch;
	int		ch, ret = 0;
	char		name[MISDN_MAX_IDLEN];

	dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL);
	if (!dch)
		return -ENOMEM;
	dch->debug = debug;
	mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
	dch->hw = hc;
	dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
	dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
		(1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
	dch->dev.D.send = handle_dmsg;
	dch->dev.D.ctrl = hfcm_dctrl;
	dch->dev.nrbchan = (hc->dslot) ? 30 : 31;
	dch->slot = hc->dslot;
	hc->chan[hc->dslot].dch = dch;
	hc->chan[hc->dslot].port = 0;
	hc->chan[hc->dslot].nt_timer = -1;
	for (ch = 1; ch <= 31; ch++) {
		if (ch == hc->dslot) /* skip dchannel */
			continue;
		bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL);
		if (!bch) {
			printk(KERN_ERR "%s: no memory for bchannel\n",
			       __func__);
			ret = -ENOMEM;
			goto free_chan;
		}
		hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL);
		if (!hc->chan[ch].coeff) {
			printk(KERN_ERR "%s: no memory for coeffs\n",
			       __func__);
			ret = -ENOMEM;
			kfree(bch);
			goto free_chan;
		}
		bch->nr = ch;
		bch->slot = ch;
		bch->debug = debug;
		mISDN_initbchannel(bch, MAX_DATA_MEM);
		bch->hw = hc;
		bch->ch.send = handle_bmsg;
		bch->ch.ctrl = hfcm_bctrl;
		bch->ch.nr = ch;
		list_add(&bch->ch.list, &dch->dev.bchannels);
		hc->chan[ch].bch = bch;
		hc->chan[ch].port = 0;
		set_channelmap(bch->nr, dch->dev.channelmap);
	}
	/* set optical line type */
	if (port[Port_cnt] & 0x001) {
		if (!m->opticalsupport)  {
@@ -4763,7 +4737,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
				       __func__,
				       HFC_cnt + 1, 1);
			test_and_set_bit(HFC_CFG_OPTICAL,
					 &hc->chan[hc->dslot].cfg);
			    &hc->chan[hc->dnum[0]].cfg);
		}
	}
	/* set LOS report */
@@ -4773,7 +4747,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
			       "LOS report: card(%d) port(%d)\n",
			       __func__, HFC_cnt + 1, 1);
		test_and_set_bit(HFC_CFG_REPORT_LOS,
				 &hc->chan[hc->dslot].cfg);
		    &hc->chan[hc->dnum[0]].cfg);
	}
	/* set AIS report */
	if (port[Port_cnt] & 0x008) {
@@ -4782,7 +4756,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
			       "AIS report: card(%d) port(%d)\n",
			       __func__, HFC_cnt + 1, 1);
		test_and_set_bit(HFC_CFG_REPORT_AIS,
				 &hc->chan[hc->dslot].cfg);
		    &hc->chan[hc->dnum[0]].cfg);
	}
	/* set SLIP report */
	if (port[Port_cnt] & 0x010) {
@@ -4792,7 +4766,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
			       "card(%d) port(%d)\n",
			       __func__, HFC_cnt + 1, 1);
		test_and_set_bit(HFC_CFG_REPORT_SLIP,
				 &hc->chan[hc->dslot].cfg);
		    &hc->chan[hc->dnum[0]].cfg);
	}
	/* set RDI report */
	if (port[Port_cnt] & 0x020) {
@@ -4802,7 +4776,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
			       "card(%d) port(%d)\n",
			       __func__, HFC_cnt + 1, 1);
		test_and_set_bit(HFC_CFG_REPORT_RDI,
				 &hc->chan[hc->dslot].cfg);
		    &hc->chan[hc->dnum[0]].cfg);
	}
	/* set CRC-4 Mode */
	if (!(port[Port_cnt] & 0x100)) {
@@ -4811,7 +4785,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
			       " card(%d) port(%d)\n",
			       __func__, HFC_cnt + 1, 1);
		test_and_set_bit(HFC_CFG_CRC4,
				 &hc->chan[hc->dslot].cfg);
		    &hc->chan[hc->dnum[0]].cfg);
	} else {
		if (debug & DEBUG_HFCMULTI_INIT)
			printk(KERN_DEBUG "%s: PORT turn off CRC4"
@@ -4843,20 +4817,85 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m)
	}
	/* set elastic jitter buffer */
	if (port[Port_cnt] & 0x3000) {
		hc->chan[hc->dslot].jitter = (port[Port_cnt]>>12) & 0x3;
		hc->chan[hc->dnum[0]].jitter = (port[Port_cnt]>>12) & 0x3;
		if (debug & DEBUG_HFCMULTI_INIT)
			printk(KERN_DEBUG
			       "%s: PORT set elastic "
			       "buffer to %d: card(%d) port(%d)\n",
			       __func__, hc->chan[hc->dslot].jitter,
			    __func__, hc->chan[hc->dnum[0]].jitter,
			       HFC_cnt + 1, 1);
	} else
		hc->chan[hc->dslot].jitter = 2; /* default */
		hc->chan[hc->dnum[0]].jitter = 2; /* default */
}

static int
init_e1_port(struct hfc_multi *hc, struct hm_map *m, int pt)
{
	struct dchannel	*dch;
	struct bchannel	*bch;
	int		ch, ret = 0;
	char		name[MISDN_MAX_IDLEN];
	int		bcount = 0;

	dch = kzalloc(sizeof(struct dchannel), GFP_KERNEL);
	if (!dch)
		return -ENOMEM;
	dch->debug = debug;
	mISDN_initdchannel(dch, MAX_DFRAME_LEN_L1, ph_state_change);
	dch->hw = hc;
	dch->dev.Dprotocols = (1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1);
	dch->dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) |
	    (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK));
	dch->dev.D.send = handle_dmsg;
	dch->dev.D.ctrl = hfcm_dctrl;
	dch->slot = hc->dnum[pt];
	hc->chan[hc->dnum[pt]].dch = dch;
	hc->chan[hc->dnum[pt]].port = pt;
	hc->chan[hc->dnum[pt]].nt_timer = -1;
	for (ch = 1; ch <= 31; ch++) {
		if (!((1 << ch) & hc->bmask[pt])) /* skip unused channel */
			continue;
		bch = kzalloc(sizeof(struct bchannel), GFP_KERNEL);
		if (!bch) {
			printk(KERN_ERR "%s: no memory for bchannel\n",
			    __func__);
			ret = -ENOMEM;
			goto free_chan;
		}
		hc->chan[ch].coeff = kzalloc(512, GFP_KERNEL);
		if (!hc->chan[ch].coeff) {
			printk(KERN_ERR "%s: no memory for coeffs\n",
			    __func__);
			ret = -ENOMEM;
			kfree(bch);
			goto free_chan;
		}
		bch->nr = ch;
		bch->slot = ch;
		bch->debug = debug;
		mISDN_initbchannel(bch, MAX_DATA_MEM);
		bch->hw = hc;
		bch->ch.send = handle_bmsg;
		bch->ch.ctrl = hfcm_bctrl;
		bch->ch.nr = ch;
		list_add(&bch->ch.list, &dch->dev.bchannels);
		hc->chan[ch].bch = bch;
		hc->chan[ch].port = pt;
		set_channelmap(bch->nr, dch->dev.channelmap);
		bcount++;
	}
	dch->dev.nrbchan = bcount;
	if (pt == 0)
		init_e1_port_hw(hc, m);
	if (hc->ports > 1)
		snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d-%d",
				HFC_cnt + 1, pt+1);
	else
		snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1);
	ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name);
	if (ret)
		goto free_chan;
	hc->created[0] = 1;
	hc->created[pt] = 1;
	return ret;
free_chan:
	release_port(hc, dch);
@@ -4989,7 +5028,8 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
	struct hfc_multi	*hc;
	u_long		flags;
	u_char		dips = 0, pmj = 0; /* dip settings, port mode Jumpers */
	int		i;
	int		i, ch;
	u_int		maskcheck;

	if (HFC_cnt >= MAX_CARDS) {
		printk(KERN_ERR "too many cards (max=%d).\n",
@@ -5023,18 +5063,36 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
	hc->id = HFC_cnt;
	hc->pcm = pcm[HFC_cnt];
	hc->io_mode = iomode[HFC_cnt];
	if (dslot[HFC_cnt] < 0 && hc->ctype == HFC_TYPE_E1) {
		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
	    && hc->ctype == HFC_TYPE_E1) {
		hc->dslot = dslot[HFC_cnt];
		printk(KERN_INFO "HFC-E1 card has alternating D-channel on "
		       "time slot %d\n", dslot[HFC_cnt]);
	} else
		hc->dslot = 16;
	if (hc->ctype == HFC_TYPE_E1 && dmask[E1_cnt]) {
		/* fragment card */
		pt = 0;
		maskcheck = 0;
		for (ch = 0; ch <= 31; ch++) {
			if (!((1 << ch) & dmask[E1_cnt]))
				continue;
			hc->dnum[pt] = ch;
			hc->bmask[pt] = bmask[bmask_cnt++];
			if ((maskcheck & hc->bmask[pt])
			 || (dmask[E1_cnt] & hc->bmask[pt])) {
				printk(KERN_INFO
				       "HFC-E1 #%d has overlapping B-channels on fragment #%d\n",
				       E1_cnt + 1, pt);
				return -EINVAL;
			}
			maskcheck |= hc->bmask[pt];
			printk(KERN_INFO
			       "HFC-E1 #%d uses D-channel on slot %d and a B-channel map of 0x%08x\n",
				E1_cnt + 1, ch, hc->bmask[pt]);
			pt++;
		}
		hc->ports = pt;
	}
	if (hc->ctype == HFC_TYPE_E1 && !dmask[E1_cnt]) {
		/* default card layout */
		hc->dnum[0] = 16;
		hc->bmask[0] = 0xfffefffe;
		hc->ports = 1;
	}

	/* set chip specific features */
	hc->masterclk = -1;
@@ -5117,23 +5175,33 @@ hfcmulti_init(struct hm_map *m, struct pci_dev *pdev,
			goto free_card;
		}
		if (hc->ctype == HFC_TYPE_E1)
			ret_err = init_e1_port(hc, m);
			ret_err = init_e1_port(hc, m, pt);
		else
			ret_err = init_multi_port(hc, pt);
		if (debug & DEBUG_HFCMULTI_INIT)
			printk(KERN_DEBUG
			    "%s: Registering D-channel, card(%d) port(%d) "
			       "result %d\n",
			       __func__, HFC_cnt + 1, pt, ret_err);
			    __func__, HFC_cnt + 1, pt + 1, ret_err);

		if (ret_err) {
			while (pt) { /* release already registered ports */
				pt--;
				release_port(hc, hc->chan[(pt << 2) + 2].dch);
				if (hc->ctype == HFC_TYPE_E1)
					release_port(hc,
						hc->chan[hc->dnum[pt]].dch);
				else
					release_port(hc,
						hc->chan[(pt << 2) + 2].dch);
			}
			goto free_card;
		}
		Port_cnt++;
		if (hc->ctype != HFC_TYPE_E1)
			Port_cnt++; /* for each S0 port */
	}
	if (hc->ctype == HFC_TYPE_E1) {
		Port_cnt++; /* for each E1 port */
		E1_cnt++;
	}

	/* disp switches */