wcb4xxp: Add support for wcb23x series

Adds support for Digium's new dual span wcb23x series cards. Also other minor
improvements for the new generation cards including the wcb23x and wcb43x

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
This commit is contained in:
Russ Meyerriecks 2015-06-11 14:59:12 -05:00
parent dd3c4ba015
commit 80e0426dd6
2 changed files with 187 additions and 118 deletions

View File

@ -110,7 +110,7 @@ static int led_fader_table[] = {
20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0, 20, 18, 16, 13, 11, 9, 8, 6, 4, 3, 2, 1, 0, 0,
}; };
// #define CREATE_WCB4XXP_PROCFS_ENTRY #undef CREATE_WCB4XXP_PROCFS_ENTRY
#ifdef CREATE_WCB4XXP_PROCFS_ENTRY #ifdef CREATE_WCB4XXP_PROCFS_ENTRY
#define PROCFS_NAME "wcb4xxp" #define PROCFS_NAME "wcb4xxp"
static struct proc_dir_entry *myproc; static struct proc_dir_entry *myproc;
@ -132,6 +132,8 @@ static struct devtype wcb41xp = {"Wildcard B410P", .ports = 4,
.card_type = B410P}; .card_type = B410P};
static struct devtype wcb43xp = {"Wildcard B430P", .ports = 4, static struct devtype wcb43xp = {"Wildcard B430P", .ports = 4,
.card_type = B430P}; .card_type = B430P};
static struct devtype wcb23xp = {"Wildcard B230P", .ports = 2,
.card_type = B230P};
static struct devtype hfc2s = {"HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .card_type = DUOBRI }; static struct devtype hfc2s = {"HFC-2S Junghanns.NET duoBRI PCI", .ports = 2, .card_type = DUOBRI };
static struct devtype hfc4s = {"HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .card_type = QUADBRI }; static struct devtype hfc4s = {"HFC-4S Junghanns.NET quadBRI PCI", .ports = 4, .card_type = QUADBRI };
static struct devtype hfc8s = {"HFC-8S Junghanns.NET octoBRI PCI", .ports = 8, .card_type = OCTOBRI }; static struct devtype hfc8s = {"HFC-8S Junghanns.NET octoBRI PCI", .ports = 8, .card_type = OCTOBRI };
@ -146,8 +148,10 @@ static struct devtype hfc4s_EV = {"CCD HFC-4S Eval. Board", .ports = 4,
.card_type = QUADBRI_EVAL }; .card_type = QUADBRI_EVAL };
#define IS_B430P(card) ((card)->card_type == B430P) #define IS_B430P(card) ((card)->card_type == B430P)
#define IS_B230P(card) ((card)->card_type == B230P)
#define IS_GEN2(card) (IS_B430P(card) || IS_B230P(card))
#define IS_B410P(card) ((card)->card_type == B410P) #define IS_B410P(card) ((card)->card_type == B410P)
#define CARD_HAS_EC(card) (IS_B410P(card) || IS_B430P(card)) #define CARD_HAS_EC(card) (IS_B410P(card) || IS_B430P(card) || IS_B230P(card))
static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec); static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);
static void b4xxp_update_leds(struct b4xxp *b4); static void b4xxp_update_leds(struct b4xxp *b4);
@ -415,7 +419,7 @@ static unsigned char b4xxp_getreg_ra(struct b4xxp *b4, unsigned char r, unsigned
* cleared, as it's used for reset */ * cleared, as it's used for reset */
static void hfc_gpio_set(struct b4xxp *b4, unsigned char bits) static void hfc_gpio_set(struct b4xxp *b4, unsigned char bits)
{ {
if (IS_B430P(b4)) { if (IS_GEN2(b4)) {
b4xxp_setreg8(b4, R_GPIO_OUT1, bits | 0x01); b4xxp_setreg8(b4, R_GPIO_OUT1, bits | 0x01);
flush_pci(); flush_pci();
} else { } else {
@ -449,7 +453,7 @@ static void hfc_gpio_init(struct b4xxp *b4)
/* GPIO0..7 input */ /* GPIO0..7 input */
b4xxp_setreg8(b4, R_GPIO_EN0, 0x00); b4xxp_setreg8(b4, R_GPIO_EN0, 0x00);
if (IS_B430P(b4)) if (IS_GEN2(b4))
b4xxp_setreg8(b4, R_GPIO_EN1, 0xf1); b4xxp_setreg8(b4, R_GPIO_EN1, 0xf1);
else else
b4xxp_setreg8(b4, R_GPIO_EN1, 0xf7); b4xxp_setreg8(b4, R_GPIO_EN1, 0xf7);
@ -835,7 +839,7 @@ static void ec_init(struct b4xxp *b4)
return; return;
/* Short circuit to the new zarlink echocan logic */ /* Short circuit to the new zarlink echocan logic */
if (IS_B430P(b4)) { if (IS_GEN2(b4)) {
zl_init(b4); zl_init(b4);
return; return;
} }
@ -1030,7 +1034,7 @@ static void hfc_reset(struct b4xxp *b4)
b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1); b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1);
flush_pci(); flush_pci();
if (IS_B430P(b4)) if (IS_GEN2(b4))
b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_4096); b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_4096);
else else
b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048); b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_2048);
@ -1195,6 +1199,9 @@ static void hfc_assign_fifo_zl(struct b4xxp *b4, int port, int bchan)
} }
/* record the host's FIFO # in the span fifo array */ /* record the host's FIFO # in the span fifo array */
if (IS_B230P(b4))
b4->spans[2-port].fifos[bchan] = fifo;
else
b4->spans[3-port].fifos[bchan] = fifo; b4->spans[3-port].fifos[bchan] = fifo;
spin_lock_irqsave(&b4->fifolock, irq_flags); spin_lock_irqsave(&b4->fifolock, irq_flags);
@ -1348,6 +1355,8 @@ static void hfc_assign_dchan_fifo(struct b4xxp *b4, int port)
/* record the host's FIFO # in the span fifo array */ /* record the host's FIFO # in the span fifo array */
if (IS_B430P(b4)) if (IS_B430P(b4))
b4->spans[3-port].fifos[2] = fifo; b4->spans[3-port].fifos[2] = fifo;
else if (IS_B230P(b4))
b4->spans[2-port].fifos[2] = fifo;
else else
b4->spans[port].fifos[2] = fifo; b4->spans[port].fifos[2] = fifo;
@ -1409,11 +1418,15 @@ static void hfc_reset_fifo_pair(struct b4xxp *b4, int fifo, int reset, int force
static void b4xxp_set_sync_src(struct b4xxp *b4, int port) static void b4xxp_set_sync_src(struct b4xxp *b4, int port)
{ {
int b; int b;
struct b4xxp_span *bspan;
if (port == -1) /* automatic */ /* -1 = no timing selection */
if (port == -1) {
b = 0; b = 0;
else } else {
b = (port & V_SYNC_SEL_MASK) | V_MAN_SYNC; bspan = &b4->spans[port];
b = (bspan->phy_port & V_SYNC_SEL_MASK) | V_MAN_SYNC;
}
b4xxp_setreg8(b4, R_ST_SYNC, b); b4xxp_setreg8(b4, R_ST_SYNC, b);
b4->syncspan = port; b4->syncspan = port;
@ -1481,7 +1494,7 @@ static void remove_sysfs_files(struct b4xxp *b4)
* Performs no hardware access whatsoever, but does use GFP_KERNEL so do not call from IRQ context. * Performs no hardware access whatsoever, but does use GFP_KERNEL so do not call from IRQ context.
* if full == 1, prints a "full" dump; otherwise just prints current state. * if full == 1, prints a "full" dump; otherwise just prints current state.
*/ */
static char *hfc_decode_st_state(struct b4xxp *b4, int port, unsigned char state, int full) static char *hfc_decode_st_state(struct b4xxp *b4, struct b4xxp_span *span, unsigned char state, int full)
{ {
int nt, sta; int nt, sta;
char s[128], *str; char s[128], *str;
@ -1498,10 +1511,10 @@ static char *hfc_decode_st_state(struct b4xxp *b4, int port, unsigned char state
return NULL; return NULL;
} }
nt = (b4->spans[port].te_mode == 0); nt = !span->te_mode;
sta = (state & V_ST_STA_MASK); sta = (state & V_ST_STA_MASK);
sprintf(str, "P%d: %s state %c%d (%s)", port + 1, (nt ? "NT" : "TE"), (nt ? 'G' : 'F'), sta, ststr[nt][sta]); sprintf(str, "P%d: %s state %c%d (%s)", span->port + 1, (nt ? "NT" : "TE"), (nt ? 'G' : 'F'), sta, ststr[nt][sta]);
if (full) { if (full) {
sprintf(s, " SYNC: %s, RX INFO0: %s", ((state & V_FR_SYNC) ? "yes" : "no"), ((state & V_INFO0) ? "yes" : "no")); sprintf(s, " SYNC: %s, RX INFO0: %s", ((state & V_FR_SYNC) ? "yes" : "no"), ((state & V_INFO0) ? "yes" : "no"));
@ -1522,28 +1535,29 @@ static char *hfc_decode_st_state(struct b4xxp *b4, int port, unsigned char state
* if 'auto' is nonzero, will put the state machine back in auto mode after setting the state. * if 'auto' is nonzero, will put the state machine back in auto mode after setting the state.
*/ */
static void hfc_handle_state(struct b4xxp_span *s); static void hfc_handle_state(struct b4xxp_span *s);
static void hfc_force_st_state(struct b4xxp *b4, int port, int state, int resume_auto) static void hfc_force_st_state(struct b4xxp *b4, struct b4xxp_span *s, int state, int resume_auto)
{ {
b4xxp_setreg_ra(b4, R_ST_SEL, port, A_ST_RD_STA, state | V_ST_LD_STA); b4xxp_setreg_ra(b4, R_ST_SEL, s->phy_port,
A_ST_RD_STA, state | V_ST_LD_STA);
udelay(6); udelay(6);
if (resume_auto) { if (resume_auto) {
b4xxp_setreg_ra(b4, R_ST_SEL, port, A_ST_RD_STA, state); b4xxp_setreg_ra(b4, R_ST_SEL, s->phy_port, A_ST_RD_STA, state);
} }
if (DBG_ST) { if (DBG_ST) {
char *x; char *x;
x = hfc_decode_st_state(b4, port, state, 1); x = hfc_decode_st_state(b4, s, state, 1);
dev_info(&b4->pdev->dev, dev_info(&b4->pdev->dev,
"forced port %d to state %d (auto: %d), " "forced port %d to state %d (auto: %d), new decode: %s\n",
"new decode: %s\n", port + 1, state, resume_auto, x); s->port + 1, state, resume_auto, x);
kfree(x); kfree(x);
} }
/* make sure that we activate any timers/etc needed by this state change */ /* make sure that we activate any timers/etc needed by this state change */
hfc_handle_state(&b4->spans[port]); hfc_handle_state(s);
} }
static void hfc_stop_st(struct b4xxp_span *s); static void hfc_stop_st(struct b4xxp_span *s);
@ -1578,10 +1592,10 @@ static void hfc_timer_expire(struct b4xxp_span *s, int t_no)
switch(t_no) { switch(t_no) {
case HFC_T1: /* switch to G4 (pending deact.), resume auto mode */ case HFC_T1: /* switch to G4 (pending deact.), resume auto mode */
hfc_force_st_state(b4, s->phy_port, 4, 1); hfc_force_st_state(b4, s, 4, 1);
break; break;
case HFC_T2: /* switch to G1 (deactivated), resume auto mode */ case HFC_T2: /* switch to G1 (deactivated), resume auto mode */
hfc_force_st_state(b4, s->phy_port, 1, 1); hfc_force_st_state(b4, s, 1, 1);
break; break;
case HFC_T3: /* switch to F3 (deactivated), resume auto mode */ case HFC_T3: /* switch to F3 (deactivated), resume auto mode */
hfc_stop_st(s); hfc_stop_st(s);
@ -1659,7 +1673,7 @@ static void hfc_handle_state(struct b4xxp_span *s)
if (DBG_ST) { if (DBG_ST) {
char *x; char *x;
x = hfc_decode_st_state(b4, s->phy_port, state, 1); x = hfc_decode_st_state(b4, s, state, 1);
dev_info(&b4->pdev->dev, dev_info(&b4->pdev->dev,
"port %d phy_port %d A_ST_RD_STA old=0x%02x now=0x%02x, decoded: %s\n", "port %d phy_port %d A_ST_RD_STA old=0x%02x now=0x%02x, decoded: %s\n",
s->port + 1, s->phy_port, s->oldstate, state, x); s->port + 1, s->phy_port, s->oldstate, state, x);
@ -1846,7 +1860,7 @@ static void hfc_init_all_st(struct b4xxp *b4)
struct b4xxp_span *s; struct b4xxp_span *s;
/* All other cards supported by this driver read jumpers for modes */ /* All other cards supported by this driver read jumpers for modes */
if (!IS_B430P(b4)) if (!IS_GEN2(b4))
gpio = b4xxp_getreg8(b4, R_GPI_IN3); gpio = b4xxp_getreg8(b4, R_GPI_IN3);
for (i=0; i < b4->numspans; i++) { for (i=0; i < b4->numspans; i++) {
@ -1858,6 +1872,11 @@ static void hfc_init_all_st(struct b4xxp *b4)
/* Port 0-3 in b4->spans[] are physically ports 3-0 */ /* Port 0-3 in b4->spans[] are physically ports 3-0 */
s->phy_port = b4->numspans-1-i; s->phy_port = b4->numspans-1-i;
s->port = i; s->port = i;
} else if (IS_B230P(b4)) {
/* The physical ports are reversed on the b230 */
/* Port 0-1 in b4->spans[] are physically ports 2-1 */
s->phy_port = b4->numspans - i;
s->port = i;
} else { } else {
s->phy_port = i; s->phy_port = i;
s->port = i; s->port = i;
@ -1870,8 +1889,8 @@ static void hfc_init_all_st(struct b4xxp *b4)
*/ */
if (IS_B410P(b4)) { if (IS_B410P(b4)) {
nt = ((gpio & (1 << (i + 4))) == 0); nt = ((gpio & (1 << (i + 4))) == 0);
} else if (IS_B430P(b4)) { } else if (IS_GEN2(b4)) {
/* Read default digital lineconfig reg on B430 */ /* Read default digital lineconfig reg on GEN2 */
int reg; int reg;
unsigned long flags; unsigned long flags;
@ -2257,7 +2276,7 @@ static void b4xxp_init_stage1(struct b4xxp *b4)
* incoming clock. * incoming clock.
*/ */
if (IS_B410P(b4) || IS_B430P(b4) || (b4->card_type == QUADBRI_EVAL)) if (IS_B410P(b4) || IS_GEN2(b4) || (b4->card_type == QUADBRI_EVAL))
b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02); b4xxp_setreg8(b4, R_BRG_PCM_CFG, 0x02);
else else
b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK); b4xxp_setreg8(b4, R_BRG_PCM_CFG, V_PCM_CLK);
@ -2293,7 +2312,7 @@ static void b4xxp_init_stage2(struct b4xxp *b4)
b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1); b4xxp_setreg8(b4, R_PCM_MD0, V_PCM_MD | V_PCM_IDX_MD1);
flush_pci(); flush_pci();
if (IS_B430P(b4)) { if (IS_GEN2(b4)) {
b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_4096); b4xxp_setreg8(b4, R_PCM_MD1, V_PLL_ADJ_00 | V_PCM_DR_4096);
b4xxp_setreg8(b4, R_PWM_MD, 0x50); b4xxp_setreg8(b4, R_PWM_MD, 0x50);
b4xxp_setreg8(b4, R_PWM0, 0x38); b4xxp_setreg8(b4, R_PWM0, 0x38);
@ -2352,6 +2371,10 @@ static void b4xxp_init_stage2(struct b4xxp *b4)
hfc_assign_fifo_zl(b4, span, 0); hfc_assign_fifo_zl(b4, span, 0);
hfc_assign_fifo_zl(b4, span, 1); hfc_assign_fifo_zl(b4, span, 1);
hfc_assign_dchan_fifo(b4, span); hfc_assign_dchan_fifo(b4, span);
} else if (IS_B230P(b4)) {
hfc_assign_fifo_zl(b4, span + 1, 0);
hfc_assign_fifo_zl(b4, span + 1, 1);
hfc_assign_dchan_fifo(b4, span + 1);
} else { } else {
if ((vpmsupport) && (CARD_HAS_EC(b4))) { if ((vpmsupport) && (CARD_HAS_EC(b4))) {
hfc_assign_bchan_fifo_ec(b4, span, 0); hfc_assign_bchan_fifo_ec(b4, span, 0);
@ -2454,11 +2477,16 @@ static void b4xxp_update_leds_hfc(struct b4xxp *b4)
static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val) static void b4xxp_set_span_led(struct b4xxp *b4, int span, unsigned char val)
{ {
if (IS_B430P(b4)) { if (IS_GEN2(b4)) {
unsigned long flags; unsigned long flags;
if (IS_B230P(b4)) {
b4->ledreg &= ~(0x03 << (span + 1)*2);
b4->ledreg |= (val << (span + 1)*2);
} else {
b4->ledreg &= ~(0x03 << span*2); b4->ledreg &= ~(0x03 << span*2);
b4->ledreg |= (val << span*2); b4->ledreg |= (val << span*2);
}
spin_lock_irqsave(&b4->seqlock, flags); spin_lock_irqsave(&b4->seqlock, flags);
/* Set multiplexer for led R/W */ /* Set multiplexer for led R/W */
@ -2488,7 +2516,7 @@ static void b4xxp_update_leds(struct b4xxp *b4)
return; return;
} }
if (!IS_B410P(b4) && !IS_B430P(b4)) { if (!IS_B410P(b4) && !IS_GEN2(b4)) {
/* Use the alternative function for non-Digium HFC-4S cards */ /* Use the alternative function for non-Digium HFC-4S cards */
b4xxp_update_leds_hfc(b4); b4xxp_update_leds_hfc(b4);
return; return;
@ -2535,7 +2563,7 @@ static const char *b4xxp_echocan_name(const struct dahdi_chan *chan)
if (IS_B410P(bspan->parent)) if (IS_B410P(bspan->parent))
return "LASVEGAS2"; return "LASVEGAS2";
if (IS_B430P(bspan->parent)) if (IS_GEN2(bspan->parent))
return "ZARLINK"; return "ZARLINK";
return NULL; return NULL;
@ -2569,22 +2597,23 @@ static int b4xxp_echocan_create(struct dahdi_chan *chan,
if (DBG_EC) if (DBG_EC)
printk("Enabling echo cancellation on chan %d span %d\n", chan->chanpos, chan->span->offset); printk("Enabling echo cancellation on chan %d span %d\n", chan->chanpos, chan->span->offset);
channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1; if (IS_GEN2(bspan->parent)) {
int group;
if (IS_B430P(bspan->parent)) {
/* Zarlink has 4 groups of 2 channel echo cancelers */
/* Each channel has it's own individual control reg */
int group = (3 - chan->span->offset) * 0x40;
int chan_offset = (chan->chanpos % 2) ? 0x00 : 0x20; int chan_offset = (chan->chanpos % 2) ? 0x00 : 0x20;
int reg; int reg;
unsigned long flags; unsigned long flags;
/* Zarlink has 4 groups of 2 channel echo cancelers */
/* Each channel has it's own individual control reg */
group = bspan->phy_port * 0x40;
spin_lock_irqsave(&bspan->parent->seqlock, flags); spin_lock_irqsave(&bspan->parent->seqlock, flags);
reg = __zl_read(bspan->parent, group + chan_offset); reg = __zl_read(bspan->parent, group + chan_offset);
reg &= ~(1 << 3); reg &= ~(1 << 3);
__zl_write(bspan->parent, group + chan_offset, reg); __zl_write(bspan->parent, group + chan_offset, reg);
spin_unlock_irqrestore(&bspan->parent->seqlock, flags); spin_unlock_irqrestore(&bspan->parent->seqlock, flags);
} else { } else {
channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1;
ec_write(bspan->parent, chan->chanpos - 1, channel, 0x7e); ec_write(bspan->parent, chan->chanpos - 1, channel, 0x7e);
} }
@ -2601,22 +2630,23 @@ static void echocan_free(struct dahdi_chan *chan, struct dahdi_echocan_state *ec
if (DBG_EC) if (DBG_EC)
printk("Disabling echo cancellation on chan %d span %d\n", chan->chanpos, chan->span->offset); printk("Disabling echo cancellation on chan %d span %d\n", chan->chanpos, chan->span->offset);
channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1; if (IS_GEN2(bspan->parent)) {
int group;
if (IS_B430P(bspan->parent)) {
/* Zarlink has 4 groups of 2 channel echo cancelers */
/* Each channel has it's own individual control reg */
int group = (3 - chan->span->offset) * 0x40;
int chan_offset = (chan->chanpos % 2) ? 0x00 : 0x20; int chan_offset = (chan->chanpos % 2) ? 0x00 : 0x20;
int reg; int reg;
unsigned long flags; unsigned long flags;
/* Zarlink has 4 groups of 2 channel echo cancelers */
/* Each channel has it's own individual control reg */
group = bspan->phy_port * 0x40;
spin_lock_irqsave(&bspan->parent->seqlock, flags); spin_lock_irqsave(&bspan->parent->seqlock, flags);
reg = __zl_read(bspan->parent, group + chan_offset); reg = __zl_read(bspan->parent, group + chan_offset);
reg |= (1 << 3); reg |= (1 << 3);
__zl_write(bspan->parent, group + chan_offset, reg); __zl_write(bspan->parent, group + chan_offset, reg);
spin_unlock_irqrestore(&bspan->parent->seqlock, flags); spin_unlock_irqrestore(&bspan->parent->seqlock, flags);
} else { } else {
channel = (chan->span->offset * 8) + ((chan->chanpos - 1) * 4) + 1;
ec_write(bspan->parent, chan->chanpos - 1, channel, 0x01); ec_write(bspan->parent, chan->chanpos - 1, channel, 0x01);
} }
} }
@ -2677,7 +2707,7 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
if (DBG) if (DBG)
dev_info(&b4->pdev->dev, "Configuring span %d offset %d to be sync %d\n", span->spanno, span->offset, lc->sync); dev_info(&b4->pdev->dev, "Configuring span %d offset %d to be sync %d\n", span->spanno, span->offset, lc->sync);
if (lc->sync < 0 || lc->sync > 4) { if (lc->sync < 0 || lc->sync > b4->numspans) {
dev_info(&b4->pdev->dev, dev_info(&b4->pdev->dev,
"Span %d has invalid sync priority (%d), removing " "Span %d has invalid sync priority (%d), removing "
"from sync source list\n", span->spanno, lc->sync); "from sync source list\n", span->spanno, lc->sync);
@ -2695,7 +2725,7 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
b4->spans[lc->sync - 1].sync = (span->offset + 1); b4->spans[lc->sync - 1].sync = (span->offset + 1);
/* B430 sets TE/NT and Termination resistance modes via dahdi_cfg */ /* B430 sets TE/NT and Termination resistance modes via dahdi_cfg */
if (IS_B430P(b4)) { if (IS_GEN2(b4)) {
int te_mode, term, reg; int te_mode, term, reg;
unsigned long flags; unsigned long flags;
@ -2703,7 +2733,7 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0; term = (lc->lineconfig & DAHDI_CONFIG_TERM) ? 1 : 0;
dev_info(&b4->pdev->dev, dev_info(&b4->pdev->dev,
"Configuring span %d in %s mode with termination resistance %s\n", "Configuring span %d in %s mode with termination resistance %s\n",
bspan->port+1, (te_mode) ? "TE" : "NT", bspan->port + 1, (te_mode) ? "TE" : "NT",
(term) ? "ENABLED" : "DISABLED"); (term) ? "ENABLED" : "DISABLED");
if (!te_mode && lc->sync) { if (!te_mode && lc->sync) {
@ -2718,22 +2748,24 @@ static int b4xxp_spanconfig(struct file *file, struct dahdi_span *span,
spin_lock_irqsave(&b4->seqlock, flags); spin_lock_irqsave(&b4->seqlock, flags);
hfc_gpio_set(b4, 0x20); hfc_gpio_set(b4, 0x20);
reg = hfc_sram_read(b4); reg = hfc_sram_read(b4);
hfc_gpio_set(b4, 0x00);
if (te_mode) if (te_mode)
reg &= ~(1 << (4 + bspan->port)); reg &= ~(1 << (7 - bspan->phy_port));
else else
reg |= (1 << (4 + bspan->port)); reg |= (1 << (7 - bspan->phy_port));
/* Setup Termination resistance */ /* Setup Termination resistance */
/* Bits 4 downto 0 correspond to spans 4-1 */ /* Bits 4 downto 0 correspond to spans 4-1 */
/* 1 sets resistance mode, 0 sets no resistance */ /* 1 sets resistance mode, 0 sets no resistance */
if (term) if (term)
reg |= (1 << (bspan->port)); reg |= (1 << (3 - bspan->phy_port));
else else
reg &= ~(1 << (bspan->port)); reg &= ~(1 << (3 - bspan->phy_port));
hfc_gpio_set(b4, 0x20); hfc_gpio_set(b4, 0x20);
hfc_sram_write(b4, reg); hfc_sram_write(b4, reg);
hfc_gpio_set(b4, 0x00);
spin_unlock_irqrestore(&b4->seqlock, flags); spin_unlock_irqrestore(&b4->seqlock, flags);
bspan->te_mode = te_mode; bspan->te_mode = te_mode;
@ -3026,6 +3058,40 @@ static void b4xxp_bottom_half(unsigned long data)
if (b4->shutdown) if (b4->shutdown)
return; return;
if (IS_GEN2(b4)) {
unsigned long timeout = jiffies + (HZ/10);
int i;
struct b4xxp_span *bspan;
for (i = 0; i < b4->numspans; i++) {
/* Map the ports from the virtual ports to the fifos */
bspan = &b4->spans[i];
b = (b4->fifo_irqstatus[2] >> (2 * bspan->phy_port));
if (b & V_IRQ_FIFOx_TX) {
while (hdlc_tx_frame(&b4->spans[i])) {
if (time_after(jiffies, timeout)) {
dev_err(&b4->pdev->dev,
"bottom_half timed out\n");
break;
}
}
}
if (b & V_IRQ_FIFOx_RX) {
while (hdlc_rx_frame(&b4->spans[i])) {
if (time_after(jiffies, timeout)) {
dev_err(&b4->pdev->dev,
"bottom_half timed out\n");
break;
}
}
}
}
b4->fifo_irqstatus[2] = 0;
} else {
/* HFC-4S d-chan fifos 8-11 *** HFC-8S d-chan fifos 16-23 */ /* HFC-4S d-chan fifos 8-11 *** HFC-8S d-chan fifos 16-23 */
if (b4->numspans == 8) { if (b4->numspans == 8) {
fifo_low = 16; fifo_low = 16;
@ -3035,16 +3101,16 @@ static void b4xxp_bottom_half(unsigned long data)
fifo_high = 11; fifo_high = 11;
} }
for (i=0; i < 8; i++) { for (i = 0; i < 8; i++) {
b = b2 = b4->fifo_irqstatus[i]; b = b2 = b4->fifo_irqstatus[i];
for (j=0; j < b4->numspans; j++) { for (j = 0; j < b4->numspans; j++) {
fifo = i*4 + j; fifo = i*4 + j;
if (b & V_IRQ_FIFOx_TX) { if (b & V_IRQ_FIFOx_TX) {
if (fifo >= fifo_low && fifo <= fifo_high) { if (fifo >= fifo_low && fifo <= fifo_high) {
/* d-chan fifos */ /* d-chan fifos */
/* /*
* WOW I don't like this. * 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, * It's bad enough that I have to send a fake frame to get an HDLC TX FIFO interrupt,
* but now, I have to loop until the whole frame is read, or I get RX interrupts * but now, I have to loop until the whole frame is read, or I get RX interrupts
@ -3052,9 +3118,6 @@ static void b4xxp_bottom_half(unsigned long data)
* Yuck. It works well, but yuck. * Yuck. It works well, but yuck.
*/ */
do { do {
if (IS_B430P(b4))
k = hdlc_tx_frame(&b4->spans[3-(fifo - fifo_low)]);
else
k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]); k = hdlc_tx_frame(&b4->spans[fifo - fifo_low]);
} while (k); } while (k);
} else { } else {
@ -3065,16 +3128,13 @@ static void b4xxp_bottom_half(unsigned long data)
if (b & V_IRQ_FIFOx_RX) { if (b & V_IRQ_FIFOx_RX) {
if (fifo >= fifo_low && fifo <= fifo_high) { /* dchan fifos */ 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. * 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 * for whatever reason, the HFC will not generate another interrupt if there are
* still HDLC frames waiting to be received. * still HDLC frames waiting to be received.
* i.e. I get an int when F1 changes, not when F1 != F2. * i.e. I get an int when F1 changes, not when F1 != F2.
*/ */
do { do {
if (IS_B430P(b4))
k = hdlc_rx_frame(&b4->spans[3-(fifo - fifo_low)]);
else
k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]); k = hdlc_rx_frame(&b4->spans[fifo - fifo_low]);
} while (k); } while (k);
} else { } else {
@ -3086,9 +3146,10 @@ static void b4xxp_bottom_half(unsigned long data)
b >>= 2; b >>= 2;
} }
/* zero the bits we just processed */ /* zero the bits we just processed */
b4->fifo_irqstatus[i] &= ~b2; b4->fifo_irqstatus[i] &= ~b2;
} }
}
/* /*
* timer interrupt * timer interrupt
@ -3112,6 +3173,10 @@ static void b4xxp_bottom_half(unsigned long data)
b = b4xxp_getreg8(b4, R_SCI); b = b4xxp_getreg8(b4, R_SCI);
if (b) { if (b) {
for (i=0; i < b4->numspans; i++) { for (i=0; i < b4->numspans; i++) {
if (IS_B230P(b4)) {
if (b & (1 << (i+1)))
hfc_handle_state(&b4->spans[1-i]);
} else {
if (b & (1 << i)) { if (b & (1 << i)) {
/* physical spans are reversed for b430 */ /* physical spans are reversed for b430 */
if (IS_B430P(b4)) if (IS_B430P(b4))
@ -3122,6 +3187,7 @@ static void b4xxp_bottom_half(unsigned long data)
} }
} }
} }
}
/* We're supposed to kick DAHDI here, too, but again, seeing too much latency between the interrupt and the bottom-half. */ /* We're supposed to kick DAHDI here, too, but again, seeing too much latency between the interrupt and the bottom-half. */
@ -3189,7 +3255,7 @@ static int b4xxp_proc_read_one(char *buf, struct b4xxp *b4)
struct b4xxp_span *s = &b4->spans[i]; struct b4xxp_span *s = &b4->spans[i];
state = b4xxp_getreg_ra(b4, R_ST_SEL, s->port, A_ST_RD_STA); state = b4xxp_getreg_ra(b4, R_ST_SEL, s->port, A_ST_RD_STA);
x = hfc_decode_st_state(b4, s->port, state, 0); x = hfc_decode_st_state(b4, s, state, 0);
sprintf(str, "%s\n", x); sprintf(str, "%s\n", x);
strcat(sBuf, str); strcat(sBuf, str);
kfree(x); kfree(x);
@ -3338,7 +3404,7 @@ static int __devinit b4xx_probe(struct pci_dev *pdev, const struct pci_device_id
b4xxp_init_stage1(b4); b4xxp_init_stage1(b4);
if (IS_B430P(b4)) { if (IS_GEN2(b4)) {
int version; int version;
unsigned long flags; unsigned long flags;
@ -3472,6 +3538,8 @@ static DEFINE_PCI_DEVICE_TABLE(b4xx_ids) =
{0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb41xp}, {0xd161, 0xb410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb41xp},
{0xd161, 0x8014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb43xp}, {0xd161, 0x8014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb43xp},
{0xd161, 0x8015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb43xp}, {0xd161, 0x8015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb43xp},
{0xd161, 0x8016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb23xp},
{0xd161, 0x8017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long)&wcb23xp},
{0x1397, 0x16b8, 0x1397, 0xb552, 0, 0, (unsigned long)&hfc8s}, {0x1397, 0x16b8, 0x1397, 0xb552, 0, 0, (unsigned long)&hfc8s},
{0x1397, 0x16b8, 0x1397, 0xb55b, 0, 0, (unsigned long)&hfc8s}, {0x1397, 0x16b8, 0x1397, 0xb55b, 0, 0, (unsigned long)&hfc8s},
{0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s}, {0x1397, 0x08b4, 0x1397, 0xb520, 0, 0, (unsigned long)&hfc4s},

View File

@ -428,7 +428,8 @@ enum cards_ids { /* Cards ==> Brand & Model */
BN8S0, /* BeroNet BN8S0 */ BN8S0, /* BeroNet BN8S0 */
BSWYX_SX2, /* Swyx 4xS0 SX2 QuadBri */ BSWYX_SX2, /* Swyx 4xS0 SX2 QuadBri */
QUADBRI_EVAL, /* HFC-4S CCD Eval. Board */ QUADBRI_EVAL, /* HFC-4S CCD Eval. Board */
B430P /* Digium B430P */ B430P, /* Digium B430P */
B230P /* Digium B230P */
}; };
/* This structure exists one per card */ /* This structure exists one per card */