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:
parent
dd3c4ba015
commit
80e0426dd6
@ -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},
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user