--- a/drivers/dahdi/wcb4xxp/base.c 2009-06-24 13:17:03.000000000 +0000 +++ b/drivers/dahdi/wcb4xxp/base.c 2009-06-24 13:40:15.000000000 +0000 @@ -75,7 +75,7 @@ #define DBG_SPANFILTER ((1 << bspan->port) & spanfilter) static int debug = 0; -static int spanfilter = 15; +static int spanfilter = 255; /* Bitmap .. 1, 2, 4, 8, 16, 32, 64, 128 for ports 1-8 */ #ifdef LOOPBACK_SUPPORTED static int loopback = 0; #endif @@ -114,9 +114,21 @@ 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 */ + enum cards_ids card_type; /* Card type - Digium B410P, ... */ }; -static struct devtype wcb4xxp = { "Wildcard B410P", 0 }; +static struct devtype wcb4xxp = { "Wildcard B410P", .ports = 4, .has_ec = 1, .card_type = B410P }; +static struct devtype hfc2s = { "HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .has_ec = 0, .card_type = DUOBRI }; +static struct devtype hfc4s = { "HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .has_ec = 0, .card_type = QUADBRI }; +static struct devtype hfc8s = { "HFC-4S Junghanns.NET octoBRI PCI", .ports = 8, .has_ec = 0, .card_type = OCTOBRI }; +static struct devtype hfc2s_OV ={ "OpenVox B200P", .ports = 2, .has_ec = 0, .card_type = B200P_OV }; +static struct devtype hfc4s_OV ={ "OpenVox B400P", .ports = 4, .has_ec = 0, .card_type = B400P_OV }; +static struct devtype hfc8s_OV ={ "OpenVox B800P", .ports = 8, .has_ec = 0, .card_type = B800P_OV }; +static struct devtype hfc2s_BN ={ "BeroNet BN2S0", .ports = 2, .has_ec = 0, .card_type = BN2S0 }; +static struct devtype hfc4s_BN ={ "BeroNet BN4S0", .ports = 4, .has_ec = 0, .card_type = BN4S0 }; +static struct devtype hfc8s_BN ={ "BeroNet BN8S0", .ports = 8, .has_ec = 0, .card_type = BN8S0 }; static int echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp, struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec); @@ -403,7 +415,14 @@ mb(); - b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0); /* GPIO0..7 S/T, 8..15 GPIO */ + if ((b4->card_type == OCTOBRI) || (b4->card_type == B800P_OV) || (b4->card_type == BN8S0)) + { + b4xxp_setreg8(b4, R_GPIO_SEL, 0x00); /* GPIO0..15 S/T - HFC-8S uses GPIO8-15 for S/T ports 5-8 */ + } + else + { + b4xxp_setreg8(b4, R_GPIO_SEL, 0xf0); /* GPIO0..7 S/T, 8..15 GPIO */ + } mb(); @@ -618,13 +637,16 @@ unsigned char b; unsigned int i, j, mask; + if (! b4->has_ec) /* Avoid Echo Cancelling for non hardware echo canceller cards */ + 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 */ @@ -1008,7 +1030,15 @@ int fifo, hfc_chan; unsigned long irq_flags; - fifo = port + 8; + if ((b4->card_type == B800P_OV) || (b4->card_type == OCTOBRI) || (b4->card_type == BN8S0)) + { + fifo = port + 16; /* In HFC-8S cards we can't use ports 8-11 for dchan FIFOs */ + } + else + { + fifo = port + 8; + } + hfc_chan = (port * 4) + 2; /* record the host's FIFO # in the span fifo array */ @@ -1210,7 +1240,7 @@ 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++) { @@ -1413,12 +1443,21 @@ 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 + */ + if (b4->card_type == B410P) + 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")); @@ -1774,9 +1813,15 @@ /* * set up the clock controller - * we have a 24.576MHz crystal, so the PCM clock is 2x the incoming clock. + * B410P has a 24.576MHz crystal, so the PCM clock is 2x the incoming clock. + * Other cards have a 49.152Mhz crystal, so the PCM clock equals incoming clock. */ - b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02); + + if (b4->card_type == B410P) + 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 */ @@ -1807,7 +1852,7 @@ /* * set up the flow controller. - * B channel map: + * B channel map: (4 ports cards with Hardware Echo Cancel present & active) * FIFO 0 connects Port 1 B0 using HFC channel 16 and PCM timeslots 0/1. * FIFO 1 connects Port 1 B1 using HFC channel 17 and PCM timeslots 4/5. * FIFO 2 connects Port 2 B0 using HFC channel 20 and PCM timeslots 8/9. @@ -1822,14 +1867,35 @@ * * D channels are handled by FIFOs 8-11. * FIFO 8 connects Port 1 D using HFC channel 3 - * FIFO 9 connects Port 1 D using HFC channel 7 - * FIFO 10 connects Port 1 D using HFC channel 11 - * FIFO 11 connects Port 1 D using HFC channel 15 + * FIFO 9 connects Port 2 D using HFC channel 7 + * FIFO 10 connects Port 3 D using HFC channel 11 + * FIFO 11 connects Port 4 D using HFC channel 15 + * + * D channel FIFOs are operated in HDLC mode and interrupt on end of frame. + * + * B channel map: (8 ports cards without Hardware Echo Cancel) + * FIFO 0 connects Port 1 B0 using HFC channel 0 + * FIFO 1 connects Port 1 B1 using HFC channel 1 + * FIFO 2 connects Port 2 B0 using HFC channel 4 + * FIFO 3 connects Port 2 B1 using HFC channel 5 + * ......................... + * FIFO 14 connects Port 8 B0 using HFC channel 28 + * FIFO 15 connects Port 8 B1 using HFC channel 29 + * + * All B channel FIFOs have their HDLC controller in transparent mode, + * and only the FIFO for B0 on each port has its interrupt operational. * + * D channels are handled by FIFOs 16-23. + * FIFO 16 connects Port 1 D using HFC channel 3 + * FIFO 17 connects Port 2 D using HFC channel 7 + * FIFO 18 connects Port 3 D using HFC channel 11 + * FIFO 19 connects Port 4 D using HFC channel 15 + * ................ + * FIFO 23 connects Port 8 D using HFC channel 31 * D channel FIFOs are operated in HDLC mode and interrupt on end of frame. */ for (span=0; span < b4->numspans; span++) { - if (vpmsupport) { + if ((vpmsupport) && (b4->has_ec)) { hfc_assign_bchan_fifo_ec(b4, span, 0); hfc_assign_bchan_fifo_ec(b4, span, 1); } else { @@ -1854,6 +1920,145 @@ ec_write(b4, 0, 0x1a8 + 3, val); } +static void b4xxp_update_leds_hfc_8s(struct b4xxp *b4) +{ + unsigned long lled; + unsigned long leddw; + int i,j; + struct b4xxp_span *bspan; + lled = 0; + j=8; + + b4->blinktimer++; + for (i=0; i < 8; i++) { + bspan = &b4->spans[i]; + j = j -1 ; /* Leds are in reverse order - Led 7 => Port 0 */ + if (bspan->span.flags & DAHDI_FLAG_RUNNING) { + if (bspan->span.alarms) { + lled |= 1 << j; /* Led OFF in alarm state */ + } else if (bspan->span.mainttimer || bspan->span.maintstat) { + if (b4->blinktimer >= 0x7f) /* Led Blinking in maint state */ + { + lled |= 1 << j; + } + else + { + lled |= 0 << j; + } + } else { + + lled |= 0 << j; /* Led ON - No alarms */ + } + } + else + lled |= 1 << j; /* Led OFF - Not running */ + } + /* Write Leds...*/ + 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 == 0xff) { + b4->blinktimer = -1; + } +} + +static void b4xxp_update_leds_hfc(struct b4xxp *b4) +{ + int i, leds; + int led[4]; + struct b4xxp_span *bspan; + + b4->blinktimer++; + for (i=0; i < b4->numspans; i++) { + bspan = &b4->spans[i]; + + if (bspan->span.flags & DAHDI_FLAG_RUNNING) { + if (bspan->span.alarms) { + if (b4->blinktimer >= 0x7f) /* Red blinking -> Alarm */ + { + led[i] = 2; + } + else + { + led[i] = 0; + } + } else if (bspan->span.mainttimer || bspan->span.maintstat) { + if (b4->blinktimer >= 0x7f) /* Green blinking -> Maint status */ + { + led[i] = 1; + } + else + { + led[i] = 0; + } + } else { + /* No Alarm - Green */ + led[i] = 1; + } + } + else + led[i] = 0; /* OFF - Not running */ + } + + /* Each card manage leds in a different way. So one section per card type */ + + if (b4->card_type == B400P_OV) { + 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); /* Tested OK */ + b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); + b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); + } + + else if (b4->card_type == QUADBRI) { + 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); /* UNTESTED */ + b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); + b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); + } + + else if (b4->card_type == BN4S0) { + 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); /* UNTESTED */ + b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); + b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); + } + + else if (b4->card_type == B200P_OV) { + leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | + ((led[0] & 1) << 4) | ((led[1] & 1) << 5); + b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); + b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); /* Tested OK */ + } + + else if (b4->card_type == DUOBRI) { + leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | + ((led[0] & 1) << 4) | ((led[1] & 1) << 5); + b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); + b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); /* UNTESTED */ + } + + else if (b4->card_type == BN2S0) { + leds = ((led[0] > 0) << 0) | ((led[1] > 0) << 1) | + ((led[0] & 1) << 4) | ((led[1] & 1) << 5); + b4xxp_setreg8(b4, R_GPIO_EN1, leds & 0x0f); + b4xxp_setreg8(b4, R_GPIO_OUT1, leds >> 4); /* UNTESTED */ + } + + if (b4->blinktimer == 0xff) { + b4->blinktimer = -1; + } + +} + static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val) { int shift, spanmask; @@ -1871,6 +2076,18 @@ int i; struct b4xxp_span *bspan; + if (b4->numspans == 8) { + /* Use the alternative function for non-Digium HFC-8S cards */ + b4xxp_update_leds_hfc_8s(b4); + return; + } + + if (b4->card_type != B410P) { + /* Use the alternative function for non-Digium HFC-4S cards */ + b4xxp_update_leds_hfc(b4); + return; + } + b4->blinktimer++; for (i=0; i < b4->numspans; i++) { bspan = &b4->spans[i]; @@ -2174,7 +2391,7 @@ 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_create = echocan_create; /* HDLC stuff */ @@ -2281,13 +2498,24 @@ static void b4xxp_bottom_half(unsigned long data) { struct b4xxp *b4 = (struct b4xxp *)data; - int i, j, k, gotrxfifo, fifo; + int i, j, k, gotrxfifo, fifo, fifo_low, fifo_high; unsigned char b, b2; if (b4->shutdown) return; gotrxfifo = 0; + if ( b4->numspans == 8 ) /* HFC-4S d-chan fifos 8-11 *** HFC-8S d-chan fifos 16-23 */ + { + fifo_low = 16; + fifo_high = 23; + } + else + { + fifo_low = 8; + fifo_high = 11; + } + for (i=0; i < 8; i++) { b = b2 = b4->fifo_irqstatus[i]; @@ -2296,7 +2524,7 @@ fifo = i*4 + j; if (b & V_IRQ_FIFOx_TX) { - if (fifo >=8 && fifo <= 11) { /* d-chan fifo */ + if (fifo >= fifo_low && fifo <= fifo_high) { /* d-chan fifos */ /* * WOW I don't like this. * It's bad enough that I have to send a fake frame to get an HDLC TX FIFO interrupt, @@ -2305,7 +2533,7 @@ * Yuck. It works well, but yuck. */ do { - k = hdlc_tx_frame(&b4->spans[fifo - 8]); + k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]); } while (k); } else { if (printk_ratelimit()) @@ -2314,7 +2542,7 @@ } if (b & V_IRQ_FIFOx_RX) { - if (fifo >=8 && fifo <= 11) { + if (fifo >= fifo_low && fifo <= fifo_high) { /* dchan fifos */ /* * I have to loop here until hdlc_rx_frame says there are no more frames waiting. * for whatever reason, the HFC will not generate another interrupt if there are @@ -2322,7 +2550,7 @@ * i.e. I get an int when F1 changes, not when F1 != F2. */ do { - k = hdlc_rx_frame(&b4->spans[fifo - 8]); + k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]); } while (k); } else { if (printk_ratelimit()) @@ -2404,8 +2632,8 @@ sprintf(sBuf, "Card %d, PCI identifier %s, IRQ %d\n", b4->cardno + 1, b4->dev->bus_id, b4->irq); strcat(sBuf,"Tx:\n"); - for (j=0; j<8; j++) { - for (i=0; i<12; i++) { + for (j=0; j<(b4->numspans * 2) ; j++) { /* B Channels */ + for (i=0; i<(b4->numspans * 3) ; i++) { /* All Channels */ chan = b4->spans[i/3].chans[i%3]; sprintf(str, "%02x ", chan->writechunk[j]); strcat(sBuf, str); @@ -2415,8 +2643,8 @@ } strcat(sBuf, "\nRx:\n"); - for (j=0; j < 8; j++) { - for (i=0; i < 12; i++) { + for (j=0; j < (b4->numspans * 2); j++) { /* B Channels */ + for (i=0; i < (b4->numspans * 3); i++) { /* All Channels */ chan = b4->spans[i / 3].chans[i % 3]; sprintf(str, "%02x%c", chan->readchunk[j], (i == 11) ? '\n' : ' '); strcat(sBuf, str); @@ -2424,7 +2652,7 @@ } 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]; @@ -2519,7 +2747,8 @@ /* 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->card_type = dt->card_type; b4->pdev = pdev; b4->dev = &pdev->dev; pci_set_drvdata(pdev, b4); @@ -2533,7 +2762,7 @@ spin_lock_init(&b4->fifolock); x = b4xxp_getreg8(b4, R_CHIP_ID); - if (x != 0xc0) { /* wrong chip? */ + if ((x != 0xc0) && ( x != 0x80)) { /* wrong chip? */ dev_err(&pdev->dev, "Unknown/unsupported controller detected (R_CHIP_ID = 0x%02x)\n", x); goto err_out_free_mem; } @@ -2548,7 +2777,7 @@ */ /* TODO: determine whether this is a 2, 4 or 8 port card */ - b4->numspans = 4; + b4->numspans = dt->ports; 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); @@ -2696,7 +2925,17 @@ static struct pci_device_id b4xx_ids[] __devinitdata = { { 0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb4xxp }, - { 0, } + { 0x1397, 0x16b8, 0x1397, 0xe552, 0, 0, (unsigned long)&hfc8s }, + { 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, 0x16b8, 0x1397, 0xe998, 0, 0, (unsigned long)&hfc8s_OV }, + { 0x1397, 0x08b4, 0x1397, 0xb566, 0, 0, (unsigned long)&hfc2s_BN }, + { 0x1397, 0x08b4, 0x1397, 0xb560, 0, 0, (unsigned long)&hfc4s_BN }, + { 0x1397, 0x16b8, 0x1397, 0xb562, 0, 0, (unsigned long)&hfc8s_BN }, + {0, } + }; static struct pci_driver b4xx_driver = { @@ -2756,7 +2995,7 @@ MODULE_PARM_DESC(timer_3_ms, "TE: msec to wait for link activation, NT: unused."); MODULE_AUTHOR("Digium Incorporated "); -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); --- a/drivers/dahdi/wcb4xxp/wcb4xxp.h 2009-06-24 13:17:03.000000000 +0000 +++ b/drivers/dahdi/wcb4xxp/wcb4xxp.h 2009-06-24 13:18:07.000000000 +0000 @@ -378,7 +378,7 @@ #define HFC_T3 2 #define WCB4XXP_MAGIC 0xb410c0de -#define MAX_SPANS_PER_CARD 4 +#define MAX_SPANS_PER_CARD 8 #define WCB4XXP_CHANNELS_PER_SPAN 3 /* 2 B-channels and 1 D-Channel for each BRI span */ #define WCB4XXP_HDLC_BUF_LEN 32 /* arbitrary, just the max # of byts we will send to DAHDI per call */ @@ -415,6 +415,19 @@ struct dahdi_chan _chans[WCB4XXP_CHANNELS_PER_SPAN]; /* Backing memory */ }; +enum cards_ids { /* Cards ==> Brand & Model */ + B410P = 0, /* Digium B410P */ + B200P_OV, /* OpenVox B200P */ + B400P_OV, /* OpenVox B400P */ + B800P_OV, /* OpenVox B800P */ + DUOBRI, /* HFC-2S Junghanns.NET duoBRI PCI */ + QUADBRI, /* HFC-4S Junghanns.NET quadBRI PCI */ + OCTOBRI, /* HFC-8S Junghanns.NET octoBRI PCI */ + BN2S0, /* BeroNet BN2S0 */ + BN4S0, /* Beronet BN4S0 */ + BN8S0 /* BeroNet BN8S0 */ + }; + /* This structure exists one per card */ struct b4xxp { unsigned magic; /* magic value to make sure we're looking at our struct */ @@ -449,10 +462,12 @@ int globalconfig; /* Whether global setup has been done */ int syncspan; /* span that HFC uses for sync on this card */ int running; /* interrupts are enabled */ - + struct b4xxp_span spans[MAX_SPANS_PER_CARD]; /* Individual spans */ int order; /* Order */ int flags; /* Device flags */ + int has_ec; /* Has ECHO Cancel */ + enum cards_ids card_type; /* Card Identifier (using ids_cards enum)*/ int master; /* Are we master */ int ledreg; /* copy of the LED Register */ unsigned int gpio;