Index: drivers/dahdi/wcb4xxp/wcb4xxp.h
===================================================================
--- drivers/dahdi/wcb4xxp/wcb4xxp.h	(revision 6031)
+++ drivers/dahdi/wcb4xxp/wcb4xxp.h	(working copy)
@@ -452,6 +452,7 @@ struct b4xxp {
 	struct b4xxp_span spans[MAX_SPANS_PER_CARD];	/* Individual spans */
 	int order;				/* Order */
 	int flags;				/* Device flags */
+	int has_ec;				/* Has ECHO Cancel */
 	int master;				/* Are we master */
 	int ledreg;				/* copy of the LED Register */
 	unsigned int gpio;
Index: drivers/dahdi/wcb4xxp/base.c
===================================================================
--- drivers/dahdi/wcb4xxp/base.c	(revision 6031)
+++ drivers/dahdi/wcb4xxp/base.c	(working copy)
@@ -110,9 +110,21 @@ static struct proc_dir_entry *myproc;
 struct devtype {
 	char *desc;
 	unsigned int flags;
+	int ports;   /* Number of ports the card has */
+	int has_ec;  /* Does the card have an Echo Canceller module?
+			Often abused to tell if this card is a B410P or not */
 };
 
-static struct devtype wcb4xxp = { "Wildcard B410P", 0 };
+static struct devtype wcb4xxp = { "Wildcard B410P", .ports = 4, .has_ec = 1  };
+static struct devtype hfc2s =	{ "HFC-2S Junghanns.NET duoBRI PCI", .ports = 2 };
+static struct devtype hfc4s =	{ "HFC-4S Junghanns.NET quadBRI PCI", .ports = 4 };
+/* Junghanns octoBRI card. Needs testing. Remmed-out for now.
+   Also needs to have its PCI ID added.
+static struct devtype hfc8s =	{ "HFC-4S Junghanns.NET octoBRI PCI", .ports = 8 };
+*/
+static struct devtype hfc2s_OV ={ "OpenVox B200P", .ports = 2 };
+static struct devtype hfc4s_OV ={ "OpenVox B400P", .ports = 4 };
+static struct devtype hfc8s_OV ={ "OpenVox B800P", .ports = 8 };
 
 
 #if 0
@@ -600,13 +612,16 @@ static void ec_init(struct b4xxp *b4)
 	unsigned char b;
 	unsigned int i, j, mask;
 
+	if (! b4->has_ec)
+		return;
+
 /* Setup GPIO */
 	for (i=0; i < NUM_EC; i++) {
 		b = ec_read(b4, i, 0x1a0);
 
 		dev_info(b4->dev, "VPM %d/%d init: chip ver %02x\n", i, NUM_EC - 1, b);
 
-		for (j=0; j < 4; j++) {
+		for (j=0; j < b4->numspans; j++) {
 			ec_write(b4, i, 0x1a8 + j, 0x00);	/* GPIO out */
 			ec_write(b4, i, 0x1ac + j, 0x00);	/* GPIO dir */
 			ec_write(b4, i, 0x1b0 + j, 0x00);	/* GPIO sel */
@@ -625,7 +640,7 @@ static void ec_init(struct b4xxp *b4)
 		mask = 0x02020202 << (i * 4);
 
 /* Setup the tdm channel masks for all chips*/
-		for (j=0; j < 4; j++)
+		for (j=0; j < b4->numspans; j++)
 			ec_write(b4, i, 0x33 - j, (mask >> (j << 3)) & 0xff);
 
 /* Setup convergence rate */
@@ -863,7 +878,8 @@ static void hfc_assign_bchan_fifo_ec(struct b4xxp
 
 	if (first) {
 		first = 0;
-		dev_info(b4->dev, "Hardware echo cancellation enabled.\n");
+		if (b4->has_ec)
+			dev_info(b4->dev, "Hardware echo cancellation enabled.\n");
 	}
 
 	fifo = port * 2;
@@ -1192,7 +1208,7 @@ static void hfc_update_st_timers(struct b4xxp *b4)
 	int i, j;
 	struct b4xxp_span *s;
 
-	for (i=0; i < 4; i++) {
+	for (i=0; i < b4->numspans; i++) {
 		s = &b4->spans[i];
 
 		for (j=HFC_T1; j <= HFC_T3; j++) {
@@ -1395,12 +1411,22 @@ static void hfc_init_all_st(struct b4xxp *b4)
 
 	gpio = b4xxp_getreg8(b4, R_GPI_IN3);
 
-	for (i=0; i < 4; i++) {
+	for (i=0; i < b4->numspans; i++) {
 		s = &b4->spans[i];
 		s->parent = b4;
 		s->port = i;
 
-		nt = ((gpio & (1 << (i + 4))) == 0);		/* GPIO=0 = NT mode */
+		/* The way the Digium B410P card reads the NT/TE mode 
+		 * jumper is the oposite of how other HFC-4S cards do: 
+		 * - In B410P: GPIO=0: NT
+		 * - In Junghanns: GPIO=0: TE
+		 * The code below assumes has_ec <=> B410P
+		 */
+		if (b4->has_ec)
+			nt = ((gpio & (1 << (i + 4))) == 0);
+		else
+			nt = ((gpio & (1 << (i + 4))) != 0);
+
 		s->te_mode = !nt;
 
 		dev_info(b4->dev, "Port %d: %s mode\n", i + 1, (nt ? "NT" : "TE"));
@@ -1758,7 +1784,12 @@ static void b4xxp_init_stage1(struct b4xxp *b4)
  * set up the clock controller
  * we have a 24.576MHz crystal, so the PCM clock is 2x the incoming clock.
  */
-	b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02);
+	
+	if (b4->has_ec)
+	    b4xxp_setreg8(b4, R_BRG_PCM_CFG,0x02);
+	else
+	    b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK);
+	    
 	flush_pci();
 
 	udelay(100);				/* wait a bit for clock to settle */
@@ -1836,6 +1867,81 @@ static void b4xxp_setleds(struct b4xxp *b4, unsign
 	ec_write(b4, 0, 0x1a8 + 3, val);
 }
 
+/* FIXME: unexplained bit magic ahead */
+/* This function handles LED blinking for cards that are not the Digium
+ * B410P
+ */
+static void b4xxp_update_leds_hfc(struct b4xxp *b4)
+{
+	unsigned long lled;
+	unsigned long leddw;
+	int i, leds;
+	int led[4];
+	struct b4xxp_span *bspan;
+	lled = 0;
+	
+	b4->blinktimer++;
+	for (i=0; i < b4->numspans; i++) {
+		bspan = &b4->spans[i];
+
+		/* FIXME: should lled be set unconditionally below? */
+		if (bspan->span.flags & DAHDI_FLAG_RUNNING) {
+			if (bspan->span.alarms) {
+				if (b4->blinktimer == (led_fader_table[b4->alarmpos] >> 1))
+					led[i] = 2;
+				lled |= 0 << i;
+				if (b4->blinktimer == 0xf)
+					led[i] = 0;
+				lled |= 1 << i;
+			} else if (bspan->span.mainttimer || bspan->span.maintstat) {
+				if (b4->blinktimer == (led_fader_table[b4->alarmpos] >> 1))
+					led[i] = 1;
+				lled |= 0 << i;
+				if (b4->blinktimer == 0xf)
+					led[i] = 0;
+					lled |= 1 << i;
+			} else {
+				/* No Alarm */
+				led[i] = 1;
+				lled |= 0 << i;
+			}
+		} 
+		else
+			led[i] = 0;
+	}
+
+	/* FIXME: Here should probably come a comment explaining the magic */
+	if (b4->numspans == 4) {
+		leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | 
+			((led[2] > 0) << 2) | ((led[3] > 0) << 3) | 
+			((led[0] & 1) << 4) | ((led[1] & 1) << 5) |
+			((led[2] & 1) << 6) | ((led[3] & 1) << 7); /* changed by james.zhu to set the leds of B400P */
+		b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); 
+		b4xxp_setreg8(b4, R_GPIO_OUT1, leds  >> 4); 
+	    
+	} else if (b4->numspans == 2) {
+		b4xxp_setreg8(b4, R_GPIO_SEL,0x20 | 0x10);
+		b4xxp_setreg8(b4, R_GPIO_EN1,0xf);
+		b4xxp_setreg8(b4, R_GPIO_OUT1,
+				(led[0] | (led[1] << 1) | (led[2] << 2) | 
+				 (led[3] << 3)));
+	} else if (b4->numspans == 8) {
+		leddw = lled << 24 | lled << 16 | lled << 8 | lled;
+		b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x21);
+		iowrite16(0x4000, b4->ioaddr + 4);
+		iowrite32(leddw, b4->ioaddr);
+		b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x20);
+	}
+	if (b4->blinktimer == 0xf) {
+		b4->blinktimer = -1;
+		b4->alarmpos++;
+		if (b4->alarmpos >= (sizeof(led_fader_table) / 
+					sizeof(led_fader_table[0])))
+			b4->alarmpos = 0;
+	}
+
+}
+
 static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val)
 {
 	int shift, spanmask;
@@ -1848,11 +1954,18 @@ static void b4xxp_set_span_led(struct b4xxp *b4, i
 	b4xxp_setleds(b4, b4->ledreg);
 }
 
+
 static void b4xxp_update_leds(struct b4xxp *b4)
 {
 	int i;
 	struct b4xxp_span *bspan;
 
+	 if (!b4->has_ec) {
+		 /* Use the alternative function for non-Digium cards: */
+		 b4xxp_update_leds_hfc(b4);
+		 return;
+	 }
+
 	b4->blinktimer++;
 	for (i=0; i < b4->numspans; i++) {
 		bspan = &b4->spans[i];
@@ -1884,6 +1997,8 @@ static void b4xxp_update_leds(struct b4xxp *b4)
 	}
 }
 
+
+
 static int b4xxp_echocan(struct dahdi_chan *chan, int eclen)
 {
 	struct b4xxp *b4 = chan->pvt;
@@ -2139,7 +2254,7 @@ static void init_spans(struct b4xxp *b4)
 		bspan->span.close  = b4xxp_close;
 		bspan->span.ioctl = b4xxp_ioctl;
 		bspan->span.hdlc_hard_xmit = b4xxp_hdlc_hard_xmit;
-		if (vpmsupport)
+		if (vpmsupport && b4->has_ec)
 			bspan->span.echocan = b4xxp_echocan;
 
 /* HDLC stuff */
@@ -2389,7 +2504,7 @@ static int b4xxp_proc_read_one(char *buf, struct b
 	}
 
 	strcat(sBuf, "\nPort states:\n");
-	for (i=0; i < 4; i++) {
+	for (i=0; i < b4->numspans; i++) {
 		int state;
 		char *x;
 		struct b4xxp_span *s = &b4->spans[i];
@@ -2484,6 +2599,7 @@ static int __devinit b4xx_probe(struct pci_dev *pd
 /* card found, enabled and main struct allocated.  Fill it out. */
 	b4->magic = WCB4XXP_MAGIC;
 	b4->variety = dt->desc;
+	b4->has_ec = dt->has_ec;
 
 	b4->pdev = pdev;
 	b4->dev = &pdev->dev;
@@ -2513,7 +2629,8 @@ static int __devinit b4xx_probe(struct pci_dev *pd
 */
 
 /* TODO: determine whether this is a 2, 4 or 8 port card */
-	b4->numspans = 4;
+	b4->numspans = dt->ports;
+	vpmsupport = dt->has_ec;
 	b4->syncspan = -1;		/* sync span is unknown */
 	if (b4->numspans > MAX_SPANS_PER_CARD) {
 		dev_err(b4->dev, "Driver does not know how to handle a %d span card!\n", b4->numspans);
@@ -2661,6 +2778,11 @@ static void __devexit b4xxp_remove(struct pci_dev
 static struct pci_device_id b4xx_ids[] __devinitdata =
 {
 	{ 0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb4xxp },
+	{ 0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s },
+	{ 0x1397, 0x08b4, 0x1397, 0xb556, 0, 0, (unsigned long)&hfc2s },
+	{ 0x1397, 0x08b4, 0x1397, 0xe884, 0, 0, (unsigned long)&hfc2s_OV },
+	{ 0x1397, 0x08b4, 0x1397, 0xe888, 0, 0, (unsigned long)&hfc4s_OV },
+	{ 0x1397, 0x08b4, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV },
 	{ 0, }
 };
 
@@ -2721,7 +2843,7 @@ MODULE_PARM_DESC(timer_1_ms, "NT: msec to wait for
 MODULE_PARM_DESC(timer_3_ms, "TE: msec to wait for link activation, NT: unused.");
 
 MODULE_AUTHOR("Digium Incorporated <support@digium.com>");
-MODULE_DESCRIPTION("B410P quad-port BRI module driver.");
+MODULE_DESCRIPTION("B410P & Similars multi-port BRI module driver.");
 MODULE_LICENSE("GPL");
 
 MODULE_DEVICE_TABLE(pci, b4xx_ids);
