xpp: fxs: restore linefeed (for e.g. thermal alarm)
The si32260 chip may enter a state of thermal alarm to avoid overheating. This disables the channel. This commit allows automatic restoring of the channel after a certain timeout (poll_chan_linefeed, by default 30 seconds). Adds a per-channel counter ("overheats") in /proc/xpp/XBUS-<n>/XPD-<m>0/fxs_info to count such events. Signed-off-by: Tzafrir Cohen <tzafrir.cohen@xorcom.com>
This commit is contained in:
parent
9c9029d0b6
commit
960472ed35
@ -41,6 +41,7 @@ static DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware");
|
|||||||
#ifdef POLL_DIGITAL_INPUTS
|
#ifdef POLL_DIGITAL_INPUTS
|
||||||
static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs");
|
static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs");
|
||||||
#endif
|
#endif
|
||||||
|
static DEF_PARM(uint, poll_chan_linefeed, 30000, 0644, "Poll Channel Linefeed");
|
||||||
|
|
||||||
static DEF_PARM_BOOL(vmwi_ioctl, 1, 0644,
|
static DEF_PARM_BOOL(vmwi_ioctl, 1, 0644,
|
||||||
"Asterisk support VMWI notification via ioctl");
|
"Asterisk support VMWI notification via ioctl");
|
||||||
@ -140,6 +141,7 @@ enum neon_state {
|
|||||||
|
|
||||||
#define REG_TYPE6_TONEN 0x3E /* 62 - Hardware DTMF detection */
|
#define REG_TYPE6_TONEN 0x3E /* 62 - Hardware DTMF detection */
|
||||||
#define REG_TYPE6_TONEN_DTMF_DIS BIT(2) /* DTMF Disable */
|
#define REG_TYPE6_TONEN_DTMF_DIS BIT(2) /* DTMF Disable */
|
||||||
|
#define REG_TYPE6_LINEFEED 0x1E /* 30 - Linefeed */
|
||||||
#define REG_TYPE6_TONDTMF 0x3C /* 60 - DTMF Decode Status */
|
#define REG_TYPE6_TONDTMF 0x3C /* 60 - DTMF Decode Status */
|
||||||
#define REG_TYPE6_EXP_GPIOA 0x12 /* I/O Expander GPIOA */
|
#define REG_TYPE6_EXP_GPIOA 0x12 /* I/O Expander GPIOA */
|
||||||
#define REG_TYPE6_EXP_GPIOB 0x13 /* I/O Expander GPIOB */
|
#define REG_TYPE6_EXP_GPIOB 0x13 /* I/O Expander GPIOB */
|
||||||
@ -188,11 +190,13 @@ struct FXS_priv_data {
|
|||||||
xpp_line_t vbat_h; /* High voltage */
|
xpp_line_t vbat_h; /* High voltage */
|
||||||
struct timeval prev_key_time[CHANNELS_PERXPD];
|
struct timeval prev_key_time[CHANNELS_PERXPD];
|
||||||
int led_counter[NUM_LEDS][CHANNELS_PERXPD];
|
int led_counter[NUM_LEDS][CHANNELS_PERXPD];
|
||||||
|
int overheat_reset_counter[CHANNELS_PERXPD];
|
||||||
int ohttimer[CHANNELS_PERXPD];
|
int ohttimer[CHANNELS_PERXPD];
|
||||||
#define OHT_TIMER 6000 /* How long after RING to retain OHT */
|
#define OHT_TIMER 6000 /* How long after RING to retain OHT */
|
||||||
/* IDLE changing hook state */
|
/* IDLE changing hook state */
|
||||||
enum fxs_state idletxhookstate[CHANNELS_PERXPD];
|
enum fxs_state idletxhookstate[CHANNELS_PERXPD];
|
||||||
enum fxs_state lasttxhook[CHANNELS_PERXPD];
|
enum fxs_state lasttxhook[CHANNELS_PERXPD];
|
||||||
|
enum fxs_state polledhook[CHANNELS_PERXPD];
|
||||||
struct dahdi_vmwi_info vmwisetting[CHANNELS_PERXPD];
|
struct dahdi_vmwi_info vmwisetting[CHANNELS_PERXPD];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -273,7 +277,7 @@ static int linefeed_control(xbus_t *xbus, xpd_t *xpd, lineno_t chan,
|
|||||||
/* Make sure NEON state is off for */
|
/* Make sure NEON state is off for */
|
||||||
if (value == FXS_LINE_POL_OHTRANS && IS_SET(priv->neon_blinking, chan))
|
if (value == FXS_LINE_POL_OHTRANS && IS_SET(priv->neon_blinking, chan))
|
||||||
set_vm_led_mode(xpd->xbus, xpd, chan, 0);
|
set_vm_led_mode(xpd->xbus, xpd, chan, 0);
|
||||||
ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x1E, value);
|
ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_TYPE6_LINEFEED, value);
|
||||||
if (value == FXS_LINE_POL_ACTIVE && PHONEDEV(xpd).msg_waiting[chan])
|
if (value == FXS_LINE_POL_ACTIVE && PHONEDEV(xpd).msg_waiting[chan])
|
||||||
set_vm_led_mode(xpd->xbus, xpd, chan, PHONEDEV(xpd).msg_waiting[chan]);
|
set_vm_led_mode(xpd->xbus, xpd, chan, PHONEDEV(xpd).msg_waiting[chan]);
|
||||||
return ret;
|
return ret;
|
||||||
@ -630,10 +634,12 @@ err:
|
|||||||
|
|
||||||
static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
|
static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
|
||||||
{
|
{
|
||||||
|
struct FXS_priv_data *priv;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
BUG_ON(!xpd);
|
BUG_ON(!xpd);
|
||||||
|
priv = xpd->priv;
|
||||||
/*
|
/*
|
||||||
* Setup ring timers
|
* Setup ring timers
|
||||||
*/
|
*/
|
||||||
@ -649,6 +655,9 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err;
|
goto err;
|
||||||
for_each_line(xpd, i) {
|
for_each_line(xpd, i) {
|
||||||
|
if (XPD_HW(xpd).type == 6)
|
||||||
|
/* An arbitrary value that is not FXS_LINE_OPEN */
|
||||||
|
priv->polledhook[i] = FXS_LINE_ACTIVE;
|
||||||
linefeed_control(xbus, xpd, i, FXS_LINE_POL_ACTIVE);
|
linefeed_control(xbus, xpd, i, FXS_LINE_POL_ACTIVE);
|
||||||
}
|
}
|
||||||
XPD_DBG(GENERAL, xpd, "done\n");
|
XPD_DBG(GENERAL, xpd, "done\n");
|
||||||
@ -1425,6 +1434,36 @@ static void poll_inputs(xpd_t *xpd)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void poll_linefeed(xpd_t *xpd)
|
||||||
|
{
|
||||||
|
struct FXS_priv_data *priv;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (XPD_HW(xpd).type != 6)
|
||||||
|
return;
|
||||||
|
if (xpd->xpd_state != XPD_STATE_READY)
|
||||||
|
return;
|
||||||
|
priv = xpd->priv;
|
||||||
|
BUG_ON(!priv);
|
||||||
|
BUG_ON(!xpd->xbus);
|
||||||
|
|
||||||
|
XPD_DBG(GENERAL, xpd, "periodic poll");
|
||||||
|
for_each_line(xpd, i) {
|
||||||
|
if (IS_SET(PHONEDEV(xpd).digital_outputs, i)
|
||||||
|
|| IS_SET(PHONEDEV(xpd).digital_inputs, i))
|
||||||
|
continue;
|
||||||
|
if (priv->polledhook[i] == FXS_LINE_OPEN &&
|
||||||
|
priv->lasttxhook[i] != FXS_LINE_OPEN) {
|
||||||
|
LINE_NOTICE(xpd, i, "Overheat detected, resetting.");
|
||||||
|
priv->overheat_reset_counter[i]++;
|
||||||
|
linefeed_control(xpd->xbus, xpd, i,
|
||||||
|
priv->lasttxhook[i]);
|
||||||
|
}
|
||||||
|
SLIC_DIRECT_REQUEST(xpd->xbus, xpd, i, SLIC_READ,
|
||||||
|
REG_TYPE6_LINEFEED, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_linefeed(xpd_t *xpd)
|
static void handle_linefeed(xpd_t *xpd)
|
||||||
{
|
{
|
||||||
struct FXS_priv_data *priv;
|
struct FXS_priv_data *priv;
|
||||||
@ -1570,6 +1609,8 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
|
|||||||
poll_inputs(xpd);
|
poll_inputs(xpd);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if ((xpd->timer_count % poll_chan_linefeed) == 0)
|
||||||
|
poll_linefeed(xpd);
|
||||||
handle_fxs_leds(xpd);
|
handle_fxs_leds(xpd);
|
||||||
handle_linefeed(xpd);
|
handle_linefeed(xpd);
|
||||||
if (XPD_HW(xpd).type == 6)
|
if (XPD_HW(xpd).type == 6)
|
||||||
@ -1808,7 +1849,8 @@ static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
|
|||||||
priv = xpd->priv;
|
priv = xpd->priv;
|
||||||
BUG_ON(!priv);
|
BUG_ON(!priv);
|
||||||
if (info->h.bytes == REG_CMD_SIZE(REG)) {
|
if (info->h.bytes == REG_CMD_SIZE(REG)) {
|
||||||
indirect = (REG_FIELD(info, regnum) == 0x1E);
|
if ((XPD_HW(xpd).type == 1) && (REG_FIELD(info, regnum) == 0x1E))
|
||||||
|
indirect = 1;
|
||||||
regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum);
|
regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum);
|
||||||
XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
|
XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
|
||||||
(indirect) ? "I" : "D", regnum, REG_FIELD(info, data_low),
|
(indirect) ? "I" : "D", regnum, REG_FIELD(info, data_low),
|
||||||
@ -1835,6 +1877,12 @@ static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
|
|||||||
__u8 val = REG_FIELD(info, data_low);
|
__u8 val = REG_FIELD(info, data_low);
|
||||||
|
|
||||||
process_dtmf(xpd, info->h.portnum, val);
|
process_dtmf(xpd, info->h.portnum, val);
|
||||||
|
} else if ((XPD_HW(xpd).type == 6 && !indirect && regnum == REG_TYPE6_LINEFEED)) {
|
||||||
|
__u8 val = REG_FIELD(info, data_low);
|
||||||
|
|
||||||
|
LINE_DBG(SIGNAL, xpd, info->h.portnum,
|
||||||
|
"REG_TYPE6_LINEFEED: dataL=0x%X \n", val);
|
||||||
|
priv->polledhook[info->h.portnum] = val;
|
||||||
}
|
}
|
||||||
#ifdef POLL_DIGITAL_INPUTS
|
#ifdef POLL_DIGITAL_INPUTS
|
||||||
/*
|
/*
|
||||||
@ -2051,6 +2099,10 @@ static int proc_fxs_info_show(struct seq_file *sfile, void *not_used)
|
|||||||
LED_COUNTER(priv, i, led));
|
LED_COUNTER(priv, i, led));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
seq_printf(sfile, "\n%-12s", "overheats:");
|
||||||
|
for_each_line(xpd, i) {
|
||||||
|
seq_printf(sfile, "%4d", priv->overheat_reset_counter[i]);
|
||||||
|
}
|
||||||
seq_printf(sfile, "\n");
|
seq_printf(sfile, "\n");
|
||||||
spin_unlock_irqrestore(&xpd->lock, flags);
|
spin_unlock_irqrestore(&xpd->lock, flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user