summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2009-01-18 09:55:48 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2009-01-18 09:55:48 +0000
commitf89c302cbde0ea699009df9e5286be5001f16c20 (patch)
tree41fa4bf87faacf1979e54ac579c5dcc65e1c62aa
parent7d1e606f63ae5ce4c4932f3d65e18adf519b9aee (diff)
xpp.r6616: More sysfs migration, FXO enhancements, BRI fixes
* Fix cases where the command_queue overflowed during initialization. * More migrations to sysfs: - Add a 'transport' attribute to our astribank devices which points to the usb device we use. E.g: /sys/bus/astribanks/devices/xbus-00/transport is symlinked to ../../../../../../devices/pci0000:00/0000:00:10.4/usb5/5-4 - Move /proc/xpp/XBUS-??/XPD-??/span to /sys/bus/xpds/devices/??:?:?/span - Migrate from /proc/xpp/sync to: /sys/bus/astribanks/drivers/xppdrv/sync * PRI: change the "timing" priority to match the convention used by other PRI cards -- I.e: lower numbers (not 0) have higher priority. * FXO: - Power denial: create two module parameters instead of hard-coded constants (power_denial_safezone, power_denial_minlen). For sites that get non-standard power-denial signals from central office on offhook. - Don't hangup on power-denial, just notify Dahdi and wait for - Fix caller-id detection for the case central office sends it before first ring without any indication before. Asterisk's desicion. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@5663 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/xpp/card_bri.c146
-rw-r--r--drivers/dahdi/xpp/card_fxo.c190
-rw-r--r--drivers/dahdi/xpp/card_fxs.c134
-rw-r--r--drivers/dahdi/xpp/card_global.c4
-rw-r--r--drivers/dahdi/xpp/card_pri.c47
-rwxr-xr-xdrivers/dahdi/xpp/init_card_1_302
-rwxr-xr-xdrivers/dahdi/xpp/init_card_2_302
-rwxr-xr-xdrivers/dahdi/xpp/init_card_3_302
-rwxr-xr-xdrivers/dahdi/xpp/init_card_4_302
-rw-r--r--drivers/dahdi/xpp/xbus-core.c67
-rw-r--r--drivers/dahdi/xpp/xbus-core.h3
-rw-r--r--drivers/dahdi/xpp/xbus-pcm.c235
-rw-r--r--drivers/dahdi/xpp/xbus-pcm.h6
-rw-r--r--drivers/dahdi/xpp/xbus-sysfs.c91
-rw-r--r--drivers/dahdi/xpp/xpd.h10
-rw-r--r--drivers/dahdi/xpp/xpp_dahdi.c123
-rw-r--r--drivers/dahdi/xpp/xpp_dahdi.h6
-rw-r--r--drivers/dahdi/xpp/xpp_usb.c2
-rw-r--r--drivers/dahdi/xpp/xproto.c1
-rw-r--r--drivers/dahdi/xpp/xproto.h3
20 files changed, 618 insertions, 458 deletions
diff --git a/drivers/dahdi/xpp/card_bri.c b/drivers/dahdi/xpp/card_bri.c
index 571a10f..07d5614 100644
--- a/drivers/dahdi/xpp/card_bri.c
+++ b/drivers/dahdi/xpp/card_bri.c
@@ -208,7 +208,6 @@ struct BRI_priv_data {
bool reg30_good;
uint reg30_ticks;
bool layer1_up;
- xpp_line_t card_pcm_mask;
/*
* D-Chan: buffers + extra state info.
@@ -460,8 +459,8 @@ static int rx_dchan(xpd_t *xpd, reg_cmd_t *regcmd)
#ifdef XPP_DEBUGFS
xbus_log(xbus, xpd, 0, regcmd, sizeof(reg_cmd_t)); /* 0 = RX */
#endif
- dchan = xpd->span.chans[2];
- if(!IS_SET(xpd->offhook, 2)) { /* D-chan is used? */
+ dchan = XPD_CHAN(xpd, 2);
+ if(!IS_OFFHOOK(xpd, 2)) { /* D-chan is used? */
static int rate_limit;
if((rate_limit++ % 1000) == 0)
@@ -525,7 +524,7 @@ out:
static int tx_dchan(xpd_t *xpd)
{
struct BRI_priv_data *priv;
- struct dahdi_chan *dchan;
+ struct dahdi_chan *dchan;
int len;
int eoframe;
int ret;
@@ -534,7 +533,7 @@ static int tx_dchan(xpd_t *xpd)
BUG_ON(!priv);
if(!SPAN_REGISTERED(xpd) || !(xpd->span.flags & DAHDI_FLAG_RUNNING))
return 0;
- dchan = xpd->chans[2];
+ dchan = XPD_CHAN(xpd, 2);
len = dchan->bytes2transmit; /* dchan's hdlc package len */
eoframe = dchan->eoftx; /* dchan's end of frame */
dchan->bytes2transmit = 0;
@@ -561,6 +560,7 @@ static int tx_dchan(xpd_t *xpd)
priv->txframe_begin = 1;
else
priv->txframe_begin = 0;
+ XPD_DBG(COMMANDS, xpd, "eoframe=%d len=%d\n", eoframe, len);
ret = send_multibyte_request(xpd->xbus, xpd->addr.unit, xpd->addr.subunit,
eoframe, priv->dchan_tbuf, len);
if(ret < 0)
@@ -657,9 +657,6 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
{
xbus_t *xbus;
struct BRI_priv_data *priv;
- xpp_line_t tmp_pcm_mask;
- int tmp_pcm_len;
- unsigned long flags;
int i;
BUG_ON(!xpd);
@@ -676,7 +673,7 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
xpd->span.deflaw = DAHDI_LAW_ALAW;
BIT_SET(xpd->digital_signalling, 2); /* D-Channel */
for_each_line(xpd, i) {
- struct dahdi_chan *cur_chan = xpd->chans[i];
+ struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i);
XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i);
snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d",
@@ -701,35 +698,11 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
} else
cur_chan->sigcap = BRI_BCHAN_SIGCAP;
}
- xpd->offhook = BIT(0) | BIT(1); /* 2*bchan */
-
- /*
- * Compute PCM lentgh and mask
- * We know all cards have been initialized until now
- */
- tmp_pcm_mask = 0;
- if(xpd->addr.subunit == 0) {
- int line_count = 0;
-
- for(i = 0; i < MAX_SUBUNIT; i++) {
- xpd_t *sub_xpd = xpd_byaddr(xbus, xpd->addr.unit, i);
- if(sub_xpd) {
- tmp_pcm_mask |= PCM_SHIFT(sub_xpd->wanted_pcm_mask, i);
- line_count += 2;
- }
- }
- tmp_pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE;
- } else
- tmp_pcm_len = 0;
- spin_lock_irqsave(&xpd->lock, flags);
- xpd->pcm_len = tmp_pcm_len;
- xpd->wanted_pcm_mask = xpd->offhook;
- priv->card_pcm_mask = tmp_pcm_mask;
+ CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
xpd->span.spanconfig = bri_spanconfig;
xpd->span.chanconfig = bri_chanconfig;
xpd->span.startup = bri_startup;
xpd->span.shutdown = bri_shutdown;
- spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
}
@@ -939,15 +912,38 @@ static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
return 0;
}
+static int BRI_card_open(xpd_t *xpd, lineno_t pos)
+{
+ struct BRI_priv_data *priv;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
+ if(pos == 2) {
+ LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK the whole span\n");
+ BIT_SET(xpd->offhook_state, 0);
+ BIT_SET(xpd->offhook_state, 1);
+ BIT_SET(xpd->offhook_state, 2);
+ CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);
+ }
+ return 0;
+}
+
static int BRI_card_close(xpd_t *xpd, lineno_t pos)
{
- struct dahdi_chan *chan = xpd->span.chans[pos];
+ struct dahdi_chan *chan = XPD_CHAN(xpd, pos);
/* Clear D-Channel pending data */
chan->bytes2receive = 0;
chan->eofrx = 0;
chan->bytes2transmit = 0;
chan->eoftx = 0;
+ if(pos == 2) {
+ LINE_DBG(SIGNAL, xpd, pos, "ONHOOK the whole span\n");
+ BIT_CLR(xpd->offhook_state, 0);
+ BIT_CLR(xpd->offhook_state, 1);
+ BIT_CLR(xpd->offhook_state, 2);
+ CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);
+ }
return 0;
}
@@ -1014,7 +1010,7 @@ static int bri_startup(struct dahdi_span *span)
{
xpd_t *xpd = span->pvt;
struct BRI_priv_data *priv;
- struct dahdi_chan *dchan;
+ struct dahdi_chan *dchan;
BUG_ON(!xpd);
priv = xpd->priv;
@@ -1027,7 +1023,7 @@ static int bri_startup(struct dahdi_span *span)
// Turn on all channels
CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1);
if(SPAN_REGISTERED(xpd)) {
- dchan = span->chans[2];
+ dchan = XPD_CHAN(xpd, 2);
span->flags |= DAHDI_FLAG_RUNNING;
/*
* Dahdi (wrongly) assume that D-Channel need HDLC decoding
@@ -1062,14 +1058,74 @@ static int bri_shutdown(struct dahdi_span *span)
return 0;
}
-static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_lines, xpacket_t *pack)
+void BRI_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t dont_care)
+{
+ int i;
+ int line_count;
+ xpp_line_t pcm_mask;
+ xpd_t *main_xpd;
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+ main_xpd = xpd_byaddr(xbus, xpd->addr.unit, 0);
+ if(!main_xpd) {
+ XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n");
+ return;
+ }
+ /*
+ * We calculate all subunits, so use the main lock
+ * as a mutex for the whole operation.
+ */
+ spin_lock_irqsave(&main_xpd->lock_recompute_pcm, flags);
+ line_count = 0;
+ pcm_mask = 0;
+ for(i = 0; i < MAX_SUBUNIT; i++) {
+ xpd_t *sub_xpd = xpd_byaddr(xbus, main_xpd->addr.unit, i);
+
+ if(sub_xpd) {
+ xpp_line_t lines =
+ sub_xpd->offhook_state & ~sub_xpd->digital_signalling;
+
+ if(lines) {
+ pcm_mask |= PCM_SHIFT(lines, i);
+ line_count += 2;
+ }
+ /* subunits have fake pcm_len and wanted_pcm_mask */
+ if(i > 0) {
+ sub_xpd->pcm_len = 0;
+ sub_xpd->wanted_pcm_mask = lines;
+ }
+ }
+ }
+ /*
+ * FIXME: Workaround a bug in sync code of the Astribank.
+ * Send dummy PCM for sync.
+ */
+ if(main_xpd->addr.unit == 0 && line_count == 0) {
+ pcm_mask = BIT(0);
+ line_count = 1;
+ }
+ /*
+ * The main unit account for all subunits (pcm_len and wanted_pcm_mask).
+ */
+ main_xpd->pcm_len = (line_count)
+ ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE
+ : 0L;
+ main_xpd->wanted_pcm_mask = pcm_mask;
+ XPD_DBG(SIGNAL, main_xpd, "pcm_len=%d wanted_pcm_mask=0x%X (%s)\n",
+ main_xpd->pcm_len, main_xpd->wanted_pcm_mask,
+ xpd->xpdname);
+ spin_unlock_irqrestore(&main_xpd->lock_recompute_pcm, flags);
+}
+
+static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
{
byte *pcm;
- struct dahdi_chan **chans;
unsigned long flags;
int i;
int subunit;
xpp_line_t pcm_mask = 0;
+ xpp_line_t wanted_lines;
BUG_ON(!xbus);
@@ -1083,18 +1139,20 @@ static void BRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t wanted_li
if(!tmp_xpd || !tmp_xpd->card_present)
continue;
spin_lock_irqsave(&tmp_xpd->lock, flags);
- chans = tmp_xpd->span.chans;
+ wanted_lines = tmp_xpd->wanted_pcm_mask;
for_each_line(tmp_xpd, i) {
+ struct dahdi_chan *chan = XPD_CHAN(tmp_xpd, i);
+
if(IS_SET(wanted_lines, i)) {
if(SPAN_REGISTERED(tmp_xpd)) {
#ifdef DEBUG_PCMTX
- int channo = tmp_xpd->span.chans[i]->channo;
+ int channo = chan->channo;
if(pcmtx >= 0 && pcmtx_chan == channo)
memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE);
else
#endif
- memcpy((u_char *)pcm, chans[i]->writechunk, DAHDI_CHUNKSIZE);
+ memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE);
} else
memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE;
@@ -1138,7 +1196,7 @@ static void BRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
volatile u_char *r;
if(IS_SET(tmp_mask, i)) {
- r = tmp_xpd->span.chans[i]->readchunk;
+ r = XPD_CHAN(tmp_xpd, i)->readchunk;
// memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG
memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE;
@@ -1391,9 +1449,11 @@ static xproto_table_t PROTO_TABLE(BRI) = {
.card_dahdi_postregistration = BRI_card_dahdi_postregistration,
.card_hooksig = BRI_card_hooksig,
.card_tick = BRI_card_tick,
+ .card_pcm_recompute = BRI_card_pcm_recompute,
.card_pcm_fromspan = BRI_card_pcm_fromspan,
.card_pcm_tospan = BRI_card_pcm_tospan,
.card_ioctl = BRI_card_ioctl,
+ .card_open = BRI_card_open,
.card_close = BRI_card_close,
.card_register_reply = BRI_card_register_reply,
diff --git a/drivers/dahdi/xpp/card_fxo.c b/drivers/dahdi/xpp/card_fxo.c
index d56382e..61ea204 100644
--- a/drivers/dahdi/xpp/card_fxo.c
+++ b/drivers/dahdi/xpp/card_fxo.c
@@ -40,6 +40,8 @@ static DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval
#endif
static DEF_PARM(int, ring_debounce, 50, 0644, "Number of ticks to debounce a false RING indication");
static DEF_PARM(int, caller_id_style, 0, 0444, "Caller-Id detection style: 0 - [BELL], 1 - [ETSI_FSK], 2 - [ETSI_DTMF]");
+static DEF_PARM(int, power_denial_safezone, 650, 0644, "msec after offhook to ignore power-denial ( (0 - disable power-denial)");
+static DEF_PARM(int, power_denial_minlen, 80, 0644, "Minimal detected power-denial length (msec) (0 - disable power-denial)");
enum cid_style {
CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */
@@ -71,8 +73,6 @@ enum fxo_leds {
#define BAT_THRESHOLD 3
#define BAT_DEBOUNCE 1000 /* compensate for battery voltage fluctuation (in ticks) */
#define POWER_DENIAL_CURRENT 3
-#define POWER_DENIAL_TIME 80 /* ticks */
-#define POWER_DENIAL_SAFEZONE 100 /* ticks */
#define POWER_DENIAL_DELAY 2500 /* ticks */
/* Shortcuts */
@@ -138,10 +138,8 @@ struct FXO_priv_data {
enum polarity_state polarity[CHANNELS_PERXPD];
ushort polarity_debounce[CHANNELS_PERXPD];
enum power_state power[CHANNELS_PERXPD];
- xpp_line_t maybe_power_denial;
- ushort power_denial_debounce[CHANNELS_PERXPD];
ushort power_denial_delay[CHANNELS_PERXPD];
- ushort power_denial_minimum[CHANNELS_PERXPD];
+ ushort power_denial_length[CHANNELS_PERXPD];
ushort power_denial_safezone[CHANNELS_PERXPD];
xpp_line_t cidfound; /* 0 - OFF, 1 - ON */
unsigned int cidtimer[CHANNELS_PERXPD];
@@ -169,14 +167,33 @@ struct FXO_priv_data {
/*---------------- FXO: Static functions ----------------------------------*/
+static const char *power2str(enum power_state pw)
+{
+ switch(pw) {
+ case POWER_UNKNOWN: return "UNKOWN";
+ case POWER_OFF: return "OFF";
+ case POWER_ON: return "ON";
+ }
+ return NULL;
+}
+
+static void power_change(xpd_t *xpd, int portno, enum power_state pw)
+{
+ struct FXO_priv_data *priv;
+
+ priv = xpd->priv;
+ LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n",
+ power2str(priv->power[portno]),
+ power2str(pw));
+ priv->power[portno] = pw;
+}
+
static void reset_battery_readings(xpd_t *xpd, lineno_t pos)
{
struct FXO_priv_data *priv = xpd->priv;
priv->nobattery_debounce[pos] = 0;
- priv->power_denial_debounce[pos] = 0;
priv->power_denial_delay[pos] = 0;
- BIT_CLR(priv->maybe_power_denial, pos);
}
static const int led_register_mask[] = { BIT(7), BIT(6), BIT(5) };
@@ -259,30 +276,15 @@ static void handle_fxo_leds(xpd_t *xpd)
static void update_dahdi_ring(xpd_t *xpd, int pos, bool on)
{
- enum dahdi_rxsig rxsig;
-
BUG_ON(!xpd);
- if(on) {
- if(caller_id_style == CID_STYLE_BELL) {
- LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
- BIT_CLR(xpd->cid_on, pos);
- }
- rxsig = DAHDI_RXSIG_RING;
- } else {
- if(caller_id_style == CID_STYLE_BELL) {
- LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: on\n");
- BIT_SET(xpd->cid_on, pos);
- }
- rxsig = DAHDI_RXSIG_OFFHOOK;
- }
- pcm_recompute(xpd, 0);
+ if(caller_id_style == CID_STYLE_BELL)
+ oht_pcm(xpd, pos, !on);
/*
* We should not spinlock before calling dahdi_hooksig() as
* it may call back into our xpp_hooksig() and cause
* a nested spinlock scenario
*/
- if(SPAN_REGISTERED(xpd))
- dahdi_hooksig(xpd->chans[pos], rxsig);
+ notify_rxsig(xpd, pos, (on) ? DAHDI_RXSIG_RING : DAHDI_RXSIG_OFFHOOK);
}
static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_dahdi)
@@ -343,24 +345,22 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
else
MARK_OFF(priv, pos, LED_GREEN);
ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value);
- if(to_offhook) {
- BIT_SET(xpd->offhook, pos);
- } else {
- BIT_CLR(xpd->offhook, pos);
- }
- if(caller_id_style != CID_STYLE_ETSI_DTMF) {
- LINE_DBG(SIGNAL, xpd, pos, "Caller-ID PCM: off\n");
- BIT_CLR(xpd->cid_on, pos);
- }
+ mark_offhook(xpd, pos, to_offhook);
+ if(caller_id_style != CID_STYLE_ETSI_DTMF)
+ oht_pcm(xpd, pos, 0);
#ifdef WITH_METERING
priv->metering_count[pos] = 0;
priv->metering_tone_state = 0L;
DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_REG_METERING, 0x2D);
#endif
reset_battery_readings(xpd, pos); /* unstable during hook changes */
- priv->power_denial_safezone[pos] = (to_offhook) ? POWER_DENIAL_SAFEZONE : 0;
- if(!to_offhook)
- priv->power[pos] = POWER_UNKNOWN;
+ if(to_offhook) {
+ priv->power_denial_safezone[pos] = power_denial_safezone;
+ } else {
+ power_change(xpd, pos, POWER_UNKNOWN);
+ priv->power_denial_length[pos] = 0;
+ priv->power_denial_safezone[pos] = 0;
+ }
priv->cidtimer[pos] = xpd->timer_count;
spin_unlock_irqrestore(&xpd->lock, flags);
return ret;
@@ -461,10 +461,11 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
for_each_line(xpd, i) {
do_sethook(xpd, i, 0);
priv->polarity[i] = POL_UNKNOWN; /* will be updated on next battery sample */
+ priv->polarity_debounce[i] = 0;
priv->battery[i] = BATTERY_UNKNOWN; /* will be updated on next battery sample */
priv->power[i] = POWER_UNKNOWN; /* will be updated on next battery sample */
if(caller_id_style == CID_STYLE_ETSI_DTMF)
- BIT_SET(xpd->cid_on, i);
+ oht_pcm(xpd, i, 1);
}
XPD_DBG(GENERAL, xpd, "done\n");
for_each_line(xpd, i) {
@@ -478,7 +479,7 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
do_led(xpd, i, LED_GREEN, 0);
msleep(50);
}
- pcm_recompute(xpd, 0);
+ CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
return 0;
}
@@ -509,7 +510,7 @@ static int FXO_card_dahdi_preregistration(xpd_t *xpd, bool on)
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF");
xpd->span.spantype = "FXO";
for_each_line(xpd, i) {
- struct dahdi_chan *cur_chan = xpd->chans[i];
+ struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i);
XPD_DBG(GENERAL, xpd, "setting FXO channel %d\n", i);
snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%02d/%1d%1d/%d",
@@ -563,7 +564,6 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig
/* XXX Enable hooksig for FXO XXX */
switch(txsig) {
case DAHDI_TXSIG_START:
- break;
case DAHDI_TXSIG_OFFHOOK:
ret = do_sethook(xpd, pos, 1);
break;
@@ -575,7 +575,6 @@ static int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig
txsig2str(txsig), txsig);
return -EINVAL;
}
- pcm_recompute(xpd, 0);
return ret;
}
@@ -592,11 +591,11 @@ static void dahdi_report_battery(xpd_t *xpd, lineno_t chan)
break;
case BATTERY_OFF:
LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_RED\n");
- dahdi_alarm_channel(xpd->chans[chan], DAHDI_ALARM_RED);
+ dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_RED);
break;
case BATTERY_ON:
LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_NONE\n");
- dahdi_alarm_channel(xpd->chans[chan], DAHDI_ALARM_NONE);
+ dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_NONE);
break;
}
}
@@ -626,7 +625,7 @@ static void poll_metering(xbus_t *xbus, xpd_t *xpd)
int i;
for_each_line(xpd, i) {
- if (IS_SET(xpd->offhook, i))
+ if (IS_OFFHOOK(xpd, i))
DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0);
}
}
@@ -656,20 +655,13 @@ static void handle_fxo_power_denial(xpd_t *xpd)
struct FXO_priv_data *priv;
int i;
+ if(!power_denial_safezone)
+ return; /* Ignore power denials */
priv = xpd->priv;
for_each_line(xpd, i) {
- if(priv->power_denial_minimum[i] > 0) {
- priv->power_denial_minimum[i]--;
- if(priv->power_denial_minimum[i] <= 0) {
- /*
- * But maybe the FXS started to ring (and the firmware haven't
- * detected it yet). This would cause false power denials.
- * So we just flag it and schedule more ticks to wait.
- */
- LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n");
- priv->power_denial_debounce[i] = 0;
- BIT_SET(priv->maybe_power_denial, i);
- }
+ if(xpd->ringing[i] || !IS_OFFHOOK(xpd, i)) {
+ priv->power_denial_delay[i] = 0;
+ continue;
}
if(priv->power_denial_safezone[i] > 0) {
if(--priv->power_denial_safezone[i]) {
@@ -678,25 +670,36 @@ static void handle_fxo_power_denial(xpd_t *xpd)
*/
DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0);
}
+ continue;
}
- if(IS_SET(priv->maybe_power_denial, i) && !xpd->ringing[i] && IS_SET(xpd->offhook, i)) {
+ if(priv->power_denial_length[i] > 0) {
+ priv->power_denial_length[i]--;
+ if(priv->power_denial_length[i] <= 0) {
+ /*
+ * But maybe the FXS started to ring (and the firmware haven't
+ * detected it yet). This would cause false power denials.
+ * So we just flag it and schedule more ticks to wait.
+ */
+ LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n");
+ priv->power_denial_delay[i] = POWER_DENIAL_DELAY;
+ }
+ continue;
+ }
+ if (priv->power_denial_delay[i] > 0) {
/*
* Ring detection by the firmware takes some time.
* Therefore we delay our decision until we are
* sure that no ring has started during this time.
*/
- priv->power_denial_delay[i]++;
- if (priv->power_denial_delay[i] >= POWER_DENIAL_DELAY) {
+ priv->power_denial_delay[i]--;
+ if (priv->power_denial_delay[i] <= 0) {
LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n");
priv->power_denial_delay[i] = 0;
- BIT_CLR(priv->maybe_power_denial, i);
- do_sethook(xpd, i, 0);
- update_line_status(xpd, i, 0);
- pcm_recompute(xpd, 0);
+ /*
+ * Let Asterisk decide what to do
+ */
+ notify_rxsig(xpd, i, DAHDI_RXSIG_ONHOOK);
}
- } else {
- priv->power_denial_delay[i] = 0;
- BIT_CLR(priv->maybe_power_denial, i);
}
}
}
@@ -705,7 +708,7 @@ static void handle_fxo_power_denial(xpd_t *xpd)
* For caller-id CID_STYLE_ETSI_DTMF:
* - No indication is passed before the CID
* - We try to detect it and send "fake" polarity reversal.
- * - The zapata.conf should have cidstart=polarity
+ * - The chan_dahdi.conf should have cidstart=polarity
* - Based on an idea in http://bugs.digium.com/view.php?id=9096
*/
static void check_etsi_dtmf(xpd_t *xpd)
@@ -721,7 +724,7 @@ static void check_etsi_dtmf(xpd_t *xpd)
timer_count = xpd->timer_count;
for_each_line(xpd, portno) {
/* Skip offhook and ringing ports */
- if(IS_SET(xpd->offhook, portno) || xpd->ringing[portno])
+ if(IS_OFFHOOK(xpd, portno) || xpd->ringing[portno])
continue;
if(IS_SET(priv->cidfound, portno)) {
if(timer_count > priv->cidtimer[portno] + 4000) {
@@ -733,7 +736,7 @@ static void check_etsi_dtmf(xpd_t *xpd)
continue;
}
if(timer_count > priv->cidtimer[portno] + 400) {
- struct dahdi_chan *chan = xpd->span.chans[portno];
+ struct dahdi_chan *chan = XPD_CHAN(xpd, portno);
int sample;
int i;
@@ -773,7 +776,6 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
return 0;
}
-/* FIXME: based on data from from wctdm.h */
#include <dahdi/wctdm_user.h>
/*
* The first register is the ACIM, the other are coefficient registers.
@@ -912,8 +914,11 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno)
priv->battery[portno] = BATTERY_OFF;
if(SPAN_REGISTERED(xpd))
dahdi_report_battery(xpd, portno);
- priv->polarity[portno] = POL_UNKNOWN; /* What's the polarity ? */
- priv->power[portno] = POWER_UNKNOWN; /* What's the current ? */
+ /* What's the polarity ? */
+ priv->polarity[portno] = POL_UNKNOWN;
+ priv->polarity_debounce[portno] = 0;
+ /* What's the current ? */
+ power_change(xpd, portno, POWER_UNKNOWN);
/*
* Stop further processing for now
*/
@@ -966,7 +971,7 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno)
msec = priv->polarity_debounce[portno]++ * poll_battery_interval;
if (msec >= POLREV_THRESHOLD) {
priv->polarity_debounce[portno] = 0;
- if(pol != POL_UNKNOWN) {
+ if(pol != POL_UNKNOWN && priv->polarity[portno] != POL_UNKNOWN) {
char *polname = NULL;
if(pol == POL_POSITIVE)
@@ -983,14 +988,12 @@ static void update_battery_voltage(xpd_t *xpd, byte data_low, xportno_t portno)
* 2. In some countries used to report caller-id during onhook
* but before first ring.
*/
- if(caller_id_style == CID_STYLE_ETSI_FSK) {
- LINE_DBG(SIGNAL, xpd, portno, "Caller-ID PCM: on\n");
- BIT_SET(xpd->cid_on, portno); /* will be cleared on ring/offhook */
- }
+ if(caller_id_style == CID_STYLE_ETSI_FSK)
+ oht_pcm(xpd, portno, 1); /* will be cleared on ring/offhook */
if(SPAN_REGISTERED(xpd)) {
LINE_DBG(SIGNAL, xpd, portno,
"Send DAHDI_EVENT_POLARITY: %s\n", polname);
- dahdi_qevent_lock(xpd->chans[portno], DAHDI_EVENT_POLARITY);
+ dahdi_qevent_lock(XPD_CHAN(xpd, portno), DAHDI_EVENT_POLARITY);
}
}
priv->polarity[portno] = pol;
@@ -1014,7 +1017,7 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno)
* During ringing, current is not stable.
* During onhook there should not be current anyway.
*/
- if(xpd->ringing[portno] || !IS_SET(xpd->offhook, portno))
+ if(xpd->ringing[portno] || !IS_OFFHOOK(xpd, portno))
goto ignore_it;
/*
* Power denial with no battery voltage is meaningless
@@ -1026,20 +1029,20 @@ static void update_battery_current(xpd_t *xpd, byte data_low, xportno_t portno)
goto ignore_it;
if(data_low < POWER_DENIAL_CURRENT) {
if(priv->power[portno] == POWER_ON) {
- LINE_DBG(SIGNAL, xpd, portno, "power: ON -> OFF\n");
- priv->power[portno] = POWER_OFF;
- priv->power_denial_minimum[portno] = POWER_DENIAL_TIME;
+ power_change(xpd, portno, POWER_OFF);
+ priv->power_denial_length[portno] = power_denial_minlen;
}
} else {
- LINE_DBG(SIGNAL, xpd, portno, "power: ON\n");
- priv->power[portno] = POWER_ON;
- priv->power_denial_minimum[portno] = 0;
- update_line_status(xpd, portno, 1);
+ if(priv->power[portno] != POWER_ON) {
+ power_change(xpd, portno, POWER_ON);
+ priv->power_denial_length[portno] = 0;
+ /* We are now OFFHOOK */
+ hookstate_changed(xpd, portno, 1);
+ }
}
return;
ignore_it:
- BIT_CLR(priv->maybe_power_denial, portno);
- priv->power_denial_debounce[portno] = 0;
+ priv->power_denial_delay[portno] = 0;
}
#ifdef WITH_METERING
@@ -1125,6 +1128,7 @@ static xproto_table_t PROTO_TABLE(FXO) = {
.card_dahdi_postregistration = FXO_card_dahdi_postregistration,
.card_hooksig = FXO_card_hooksig,
.card_tick = FXO_card_tick,
+ .card_pcm_recompute = generic_card_pcm_recompute,
.card_pcm_fromspan = generic_card_pcm_fromspan,
.card_pcm_tospan = generic_card_pcm_tospan,
.card_ioctl = FXO_card_ioctl,
@@ -1242,14 +1246,6 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
curr = ".";
len += sprintf(page + len, "%4s ", curr);
}
- len += sprintf(page + len, "\n\t%-17s: ", "maybe");
- for_each_line(xpd, i) {
- len += sprintf(page + len, "%4d ", IS_SET(priv->maybe_power_denial, i));
- }
- len += sprintf(page + len, "\n\t%-17s: ", "debounce");
- for_each_line(xpd, i) {
- len += sprintf(page + len, "%4d ", priv->power_denial_debounce[i]);
- }
len += sprintf(page + len, "\n\t%-17s: ", "safezone");
for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->power_denial_safezone[i]);
diff --git a/drivers/dahdi/xpp/card_fxs.c b/drivers/dahdi/xpp/card_fxs.c
index cbd4ddd..b79dbe7 100644
--- a/drivers/dahdi/xpp/card_fxs.c
+++ b/drivers/dahdi/xpp/card_fxs.c
@@ -174,6 +174,21 @@ static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value);
}
+static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on)
+{
+ struct FXS_priv_data *priv;
+
+ priv = xpd->priv;
+ BUG_ON(!xpd);
+ if(vmwineon && on) {
+ LINE_DBG(SIGNAL, xpd, pos, "START\n");
+ BIT_SET(priv->search_fsk_pattern, pos);
+ } else {
+ LINE_DBG(SIGNAL, xpd, pos, "STOP\n");
+ BIT_CLR(priv->search_fsk_pattern, pos);
+ }
+}
+
/*
* LED and RELAY control is done via SLIC register 0x06:
* 7 6 5 4 3 2 1 0
@@ -286,7 +301,7 @@ static void restore_leds(xpd_t *xpd)
priv = xpd->priv;
for_each_line(xpd, i) {
- if(IS_SET(xpd->offhook, i))
+ if(IS_OFFHOOK(xpd, i))
MARK_ON(priv, i, LED_GREEN);
else
MARK_OFF(priv, i, LED_GREEN);
@@ -436,7 +451,7 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
msleep(50);
}
restore_leds(xpd);
- pcm_recompute(xpd, 0);
+ CALL_XMETHOD(card_pcm_recompute, xbus, xpd, 0);
/*
* We should query our offhook state long enough time after we
* set the linefeed_control()
@@ -479,7 +494,7 @@ static int FXS_card_dahdi_preregistration(xpd_t *xpd, bool on)
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
xpd->span.spantype = "FXS";
for_each_line(xpd, i) {
- struct dahdi_chan *cur_chan = xpd->chans[i];
+ struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i);
XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i);
if(IS_SET(xpd->digital_outputs, i)) {
@@ -536,19 +551,18 @@ static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit)
BIT_SET(xpd->mute_dtmf, pos);
else
BIT_CLR(xpd->mute_dtmf, pos);
+ CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0); /* already spinlocked */
}
-static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, bool msg_waiting)
{
int ret = 0;
BUG_ON(!xbus);
BUG_ON(!xpd);
- LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)");
- if (!vmwineon)
- return 0;
- if (on) {
+ if (vmwineon && msg_waiting) {
/* A write to register 0x40 will now turn on/off the VM led */
+ LINE_DBG(SIGNAL, xpd, pos, "NEON\n");
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
@@ -561,6 +575,7 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
} else {
/* A write to register 0x40 will now turn on/off the ringer */
+ LINE_DBG(SIGNAL, xpd, pos, "RINGER\n");
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
@@ -572,7 +587,6 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
}
-
return (ret ? -EPROTO : 0);
}
@@ -582,7 +596,7 @@ static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
bool on;
BUG_ON(!xpd);
- if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+ if (IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
return;
priv = xpd->priv;
on = IS_SET(xpd->msg_waiting, pos);
@@ -651,17 +665,16 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig
return 0;
}
if(SPAN_REGISTERED(xpd))
- chan = xpd->span.chans[pos];
+ chan = XPD_CHAN(xpd, pos);
switch(txsig) {
case DAHDI_TXSIG_ONHOOK:
spin_lock_irqsave(&xpd->lock, flags);
xpd->ringing[pos] = 0;
- BIT_CLR(xpd->cid_on, pos);
- BIT_CLR(priv->search_fsk_pattern, pos);
+ oht_pcm(xpd, pos, 0);
+ vmwi_search(xpd, pos, 0);
BIT_CLR(priv->want_dtmf_events, pos);
BIT_CLR(priv->want_dtmf_mute, pos);
__do_mute_dtmf(xpd, pos, 0);
- __pcm_recompute(xpd, 0); /* already spinlocked */
spin_unlock_irqrestore(&xpd->lock, flags);
if(IS_SET(xpd->digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig));
@@ -674,11 +687,11 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig
*/
LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n");
linefeed_control(xbus, xpd, pos, FXS_LINE_POL_ACTIVE);
- if(IS_SET(xpd->offhook, pos))
+ if(IS_OFFHOOK(xpd, pos))
MARK_ON(priv, pos, LED_GREEN);
}
ret = send_ring(xpd, pos, 0); // RING off
- if (!IS_SET(xpd->offhook, pos))
+ if (!IS_OFFHOOK(xpd, pos))
start_stop_vm_led(xbus, xpd, pos);
txhook = priv->lasttxhook[pos];
if(chan) {
@@ -702,8 +715,7 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig
}
txhook = priv->lasttxhook[pos];
if(xpd->ringing[pos]) {
- BIT_SET(xpd->cid_on, pos);
- pcm_recompute(xpd, 0);
+ oht_pcm(xpd, pos, 1);
txhook = FXS_LINE_OHTRANS;
}
xpd->ringing[pos] = 0;
@@ -721,9 +733,8 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, enum dahdi_txsig
break;
case DAHDI_TXSIG_START:
xpd->ringing[pos] = 1;
- BIT_CLR(xpd->cid_on, pos);
- BIT_CLR(priv->search_fsk_pattern, pos);
- pcm_recompute(xpd, 0);
+ oht_pcm(xpd, pos, 0);
+ vmwi_search(xpd, pos, 0);
if(IS_SET(xpd->digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig));
ret = relay_out(xpd, pos, 1);
@@ -778,14 +789,15 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
LINE_DBG(SIGNAL, xpd, pos, "DAHDI_ONHOOKTRANSFER (%d millis)\n", val);
if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
return 0; /* Nothing to do */
- BIT_CLR(xpd->cid_on, pos);
+ oht_pcm(xpd, pos, 1); /* Get ready of VMWI FSK tones */
if(priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE) {
- priv->ohttimer[pos] = OHT_TIMER;
+ priv->ohttimer[pos] = val;
priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS;
- BIT_SET(priv->search_fsk_pattern, pos);
- pcm_recompute(xpd, priv->search_fsk_pattern);
+ vmwi_search(xpd, pos, 1);
+ CALL_XMETHOD(card_pcm_recompute, xbus, xpd, priv->search_fsk_pattern);
+ LINE_DBG(SIGNAL, xpd, pos, "Start OHT_TIMER. wanted_pcm_mask=0x%X\n", xpd->wanted_pcm_mask);
}
- if(!IS_SET(xpd->offhook, pos))
+ if(vmwineon && !IS_OFFHOOK(xpd, pos))
start_stop_vm_led(xbus, xpd, pos);
return 0;
case DAHDI_TONEDETECT:
@@ -804,7 +816,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
BIT_CLR(priv->want_dtmf_events, pos);
BIT_CLR(priv->want_dtmf_mute, pos);
__do_mute_dtmf(xpd, pos, 0);
- __pcm_recompute(xpd, 0); /* already spinlocked */
spin_unlock_irqrestore(&xpd->lock, flags);
return -ENOTTY;
}
@@ -836,7 +847,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
} else {
BIT_CLR(priv->want_dtmf_mute, pos);
__do_mute_dtmf(xpd, pos, 0);
- __pcm_recompute(xpd, 0);
}
spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
@@ -882,12 +892,10 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
static int FXS_card_open(xpd_t *xpd, lineno_t chan)
{
struct FXS_priv_data *priv;
- bool is_offhook;
BUG_ON(!xpd);
priv = xpd->priv;
- is_offhook = IS_SET(xpd->offhook, chan);
- if(is_offhook)
+ if(IS_OFFHOOK(xpd, chan))
LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n");
else
LINE_DBG(SIGNAL, xpd, chan, "is onhook\n");
@@ -953,10 +961,10 @@ static void handle_linefeed(xpd_t *xpd)
if (priv->ohttimer[i]) {
priv->ohttimer[i]--;
if (!priv->ohttimer[i]) {
+ LINE_DBG(SIGNAL, xpd, i, "ohttimer expired\n");
priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
- BIT_CLR(xpd->cid_on, i);
- BIT_CLR(priv->search_fsk_pattern, i);
- pcm_recompute(xpd, 0);
+ oht_pcm(xpd, i, 0);
+ vmwi_search(xpd, i, 0);
if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) {
/* Apply the change if appropriate */
linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE);
@@ -992,16 +1000,23 @@ static void detect_vmwi(xpd_t *xpd)
static const byte FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF };
static const byte FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F };
int i;
+ xpp_line_t ignore_mask;
BUG_ON(!xpd);
xbus = xpd->xbus;
priv = xpd->priv;
BUG_ON(!priv);
+ ignore_mask =
+ xpd->offhook_state |
+ ~xpd->oht_pcm_pass |
+ ~priv->search_fsk_pattern |
+ xpd->digital_inputs |
+ xpd->digital_outputs;
for_each_line(xpd, i) {
- struct dahdi_chan *chan = xpd->span.chans[i];
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
byte *writechunk = chan->writechunk;
- if(IS_SET(xpd->offhook | xpd->cid_on | xpd->digital_inputs | xpd->digital_outputs, i))
+ if(IS_SET(ignore_mask, i))
continue;
#if 0
if(writechunk[0] != 0x7F && writechunk[0] != 0) {
@@ -1016,10 +1031,12 @@ static void detect_vmwi(xpd_t *xpd)
printk("\n");
}
#endif
- if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE)))
+ if(unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE))) {
+ LINE_DBG(SIGNAL, xpd, i, "Found common FSK pattern. Start looking for ON/OFF patterns.\n");
BIT_SET(priv->found_fsk_pattern, i);
- else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
+ } else if(unlikely(IS_SET(priv->found_fsk_pattern, i))) {
BIT_CLR(priv->found_fsk_pattern, i);
+ oht_pcm(xpd, i, 0);
if(unlikely(mem_equal(writechunk, FSK_ON_PATTERN, DAHDI_CHUNKSIZE))) {
LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n");
BIT_SET(xpd->msg_waiting, i);
@@ -1056,25 +1073,27 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
#endif
handle_fxs_leds(xpd);
handle_linefeed(xpd);
- if(priv->update_offhook_state) { /* set in FXS_card_open() */
- int i;
+ /*
+ * Hack alert (FIXME):
+ * Asterisk did FXS_card_open() and we wanted to report
+ * offhook state. However, the channel is spinlocked by dahdi
+ * so we marked it in the priv->update_offhook_state mask and
+ * now we take care of notification to dahdi and Asterisk
+ */
+ if(priv->update_offhook_state) {
+ enum dahdi_rxsig rxsig;
+ int i;
for_each_line(xpd, i) {
if(!IS_SET(priv->update_offhook_state, i))
continue;
- /*
- * Update dahdi with current state of line.
- */
- if(IS_SET(xpd->offhook, i)) {
- update_line_status(xpd, i, 1);
- } else {
- update_line_status(xpd, i, 0);
- }
+ rxsig = IS_OFFHOOK(xpd, i) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK;
+ notify_rxsig(xpd, i, rxsig); /* Notify after open() */
BIT_CLR(priv->update_offhook_state, i);
}
}
if(SPAN_REGISTERED(xpd)) {
- if(vmwineon && !vmwi_ioctl)
+ if(vmwineon && !vmwi_ioctl && priv->search_fsk_pattern)
detect_vmwi(xpd); /* Detect via FSK modulation */
}
return 0;
@@ -1123,11 +1142,11 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
if(IS_SET(offhook, i)) {
LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n");
MARK_ON(priv, i, LED_GREEN);
- update_line_status(xpd, i, 1);
+ hookstate_changed(xpd, i, 1);
} else {
LINE_DBG(SIGNAL, xpd, i, "ONHOOK\n");
MARK_OFF(priv, i, LED_GREEN);
- update_line_status(xpd, i, 0);
+ hookstate_changed(xpd, i, 0);
}
/*
* Must switch to low power. In high power, an ONHOOK
@@ -1136,7 +1155,6 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
do_chan_power(xbus, xpd, i, 0);
}
}
- __pcm_recompute(xpd, 0); /* in a spinlock */
}
HANDLER_DEF(FXS, SIG_CHANGED)
@@ -1178,12 +1196,12 @@ static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info)
BIT_CLR(lines, channo);
BIT_SET(lines, newchanno);
xpd->ringing[newchanno] = 0; // Stop ringing. No leds for digital inputs.
- if(offhook && !IS_SET(xpd->offhook, newchanno)) { // OFFHOOK
+ if(offhook && !IS_OFFHOOK(xpd, newchanno)) { // OFFHOOK
LINE_DBG(SIGNAL, xpd, newchanno, "OFFHOOK\n");
- update_line_status(xpd, newchanno, 1);
- } else if(!offhook && IS_SET(xpd->offhook, newchanno)) { // ONHOOK
+ hookstate_changed(xpd, newchanno, 1);
+ } else if(!offhook && IS_OFFHOOK(xpd, newchanno)) { // ONHOOK
LINE_DBG(SIGNAL, xpd, newchanno, "ONHOOK\n");
- update_line_status(xpd, newchanno, 0);
+ hookstate_changed(xpd, newchanno, 0);
}
}
}
@@ -1249,11 +1267,10 @@ static void process_dtmf(xpd_t *xpd, uint portnum, byte val)
__do_mute_dtmf(xpd, portnum, 1);
else
__do_mute_dtmf(xpd, portnum, 0);
- __pcm_recompute(xpd, 0); /* XPD is locked */
if(want_event) {
int event = (key_down) ? DAHDI_EVENT_DTMFDOWN : DAHDI_EVENT_DTMFUP;
- dahdi_qevent_lock(xpd->chans[portnum], event | digit);
+ dahdi_qevent_lock(XPD_CHAN(xpd, portnum), event | digit);
}
}
@@ -1330,6 +1347,7 @@ static xproto_table_t PROTO_TABLE(FXS) = {
.card_dahdi_postregistration = FXS_card_dahdi_postregistration,
.card_hooksig = FXS_card_hooksig,
.card_tick = FXS_card_tick,
+ .card_pcm_recompute = generic_card_pcm_recompute,
.card_pcm_fromspan = generic_card_pcm_fromspan,
.card_pcm_tospan = generic_card_pcm_tospan,
.card_open = FXS_card_open,
diff --git a/drivers/dahdi/xpp/card_global.c b/drivers/dahdi/xpp/card_global.c
index a8264e4..7f7397b 100644
--- a/drivers/dahdi/xpp/card_global.c
+++ b/drivers/dahdi/xpp/card_global.c
@@ -374,7 +374,9 @@ static int proc_xpd_register_write(struct file *file, const char __user *buffer,
XPD_NOTICE(xpd, "Failed writing command: '%s'\n", buf);
return ret;
}
- msleep(1); /* don't overflow command queue */
+ /* Don't flood command_queue */
+ if(xframe_queue_count(&xpd->xbus->command_queue) > 5)
+ msleep(6);
}
return count;
}
diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c
index e590339..3cdf3a8 100644
--- a/drivers/dahdi/xpp/card_pri.c
+++ b/drivers/dahdi/xpp/card_pri.c
@@ -587,7 +587,7 @@ static void set_clocking(xpd_t *xpd)
xbus_t *xbus;
xpd_t *best_xpd = NULL;
int best_subunit = -1; /* invalid */
- int best_subunit_prio = 0;
+ unsigned int best_subunit_prio = INT_MAX;
int i;
xbus = xpd->xbus;
@@ -602,7 +602,7 @@ static void set_clocking(xpd_t *xpd)
priv = subxpd->priv;
if(priv->alarms != 0)
continue;
- if(subxpd->timing_priority > best_subunit_prio) {
+ if(subxpd->timing_priority > 0 && subxpd->timing_priority < best_subunit_prio) {
best_xpd = subxpd;
best_subunit = i;
best_subunit_prio = subxpd->timing_priority;
@@ -1016,7 +1016,7 @@ static int PRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
xpd->span.linecompat = pri_linecompat(priv->pri_protocol);
xpd->span.deflaw = priv->deflaw;
for_each_line(xpd, i) {
- struct dahdi_chan *cur_chan = xpd->chans[i];
+ struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i);
bool is_dchan = i == PRI_DCHAN_IDX(priv);
XPD_DBG(GENERAL, xpd, "setting PRI channel %d (%s)\n", i,
@@ -1032,7 +1032,7 @@ static int PRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
} else
cur_chan->sigcap = PRI_BCHAN_SIGCAP;
}
- xpd->offhook = xpd->wanted_pcm_mask;
+ xpd->offhook_state = xpd->wanted_pcm_mask;
xpd->span.spanconfig = pri_spanconfig;
xpd->span.chanconfig = pri_chanconfig;
xpd->span.startup = pri_startup;
@@ -1081,9 +1081,9 @@ static void dchan_state(xpd_t *xpd, bool up)
if(SPAN_REGISTERED(xpd) && d >= 0 && d < xpd->channels) {
byte *pcm;
- pcm = (byte *)xpd->span.chans[d]->readchunk;
+ pcm = (byte *)XPD_CHAN(xpd, d)->readchunk;
pcm[0] = 0x00;
- pcm = (byte *)xpd->span.chans[d]->writechunk;
+ pcm = (byte *)XPD_CHAN(xpd, d)->writechunk;
pcm[0] = 0x00;
}
XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n");
@@ -1212,7 +1212,7 @@ static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
static int PRI_card_close(xpd_t *xpd, lineno_t pos)
{
- //struct dahdi_chan *chan = &xpd->span.chans[pos];
+ //struct dahdi_chan *chan = XPD_CHAN(xpd, pos);
dchan_state(xpd, 0);
return 0;
}
@@ -1321,13 +1321,13 @@ static int pri_rbsbits(struct dahdi_chan *chan, int bits)
* send 31 channels to the device, but they should be called 1-31 rather
* than 0-30 .
*/
-static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
+static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
{
struct PRI_priv_data *priv;
byte *pcm;
- struct dahdi_chan **chans;
unsigned long flags;
int i;
+ xpp_line_t wanted_lines;
int physical_chan;
int physical_mask = 0;
@@ -1338,9 +1338,11 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
BUG_ON(!priv);
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
spin_lock_irqsave(&xpd->lock, flags);
- chans = xpd->span.chans;
+ wanted_lines = xpd->wanted_pcm_mask;
physical_chan = 0;
for_each_line(xpd, i) {
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
+
if(priv->pri_protocol == PRI_PROTO_E1) {
/* In E1 - Only 0'th channel is unused */
if(i == 0) {
@@ -1352,28 +1354,28 @@ static void PRI_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xp
physical_chan++;
}
}
- if(IS_SET(lines, i)) {
+ if(IS_SET(wanted_lines, i)) {
physical_mask |= BIT(physical_chan);
if(SPAN_REGISTERED(xpd)) {
#ifdef DEBUG_PCMTX
- int channo = xpd->span.chans[i]->channo;
+ int channo = XPD_CHAN(xpd, i)->channo;
if(pcmtx >= 0 && pcmtx_chan == channo)
memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE);
else
#endif
- memcpy((u_char *)pcm, chans[i]->writechunk, DAHDI_CHUNKSIZE);
+ memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE);
if(i == PRI_DCHAN_IDX(priv)) {
- if(priv->dchan_tx_sample != chans[i]->writechunk[0]) {
- priv->dchan_tx_sample = chans[i]->writechunk[0];
+ if(priv->dchan_tx_sample != chan->writechunk[0]) {
+ priv->dchan_tx_sample = chan->writechunk[0];
priv->dchan_tx_counter++;
- } else if(chans[i]->writechunk[0] == 0xFF)
+ } else if(chan->writechunk[0] == 0xFF)
dchan_state(xpd, 0);
else
- chans[i]->writechunk[0] = 0xFF; /* Clobber for next tick */
+ chan->writechunk[0] = 0xFF; /* Clobber for next tick */
}
} else
- memset((u_char *)pcm, DAHDI_XLAW(0, chans[i]), DAHDI_CHUNKSIZE);
+ memset((u_char *)pcm, DAHDI_XLAW(0, chan), DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE;
}
physical_chan++;
@@ -1397,7 +1399,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
{
struct PRI_priv_data *priv;
byte *pcm;
- struct dahdi_chan **chans;
xpp_line_t physical_mask;
unsigned long flags;
int i;
@@ -1410,7 +1411,6 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
physical_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
spin_lock_irqsave(&xpd->lock, flags);
- chans = xpd->span.chans;
logical_chan = 0;
for (i = 0; i < CHANNELS_PERXPD; i++) {
volatile u_char *r;
@@ -1437,7 +1437,7 @@ static void PRI_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
dchan_state(xpd, 0);
}
if(IS_SET(physical_mask, i)) {
- r = chans[logical_chan]->readchunk;
+ r = XPD_CHAN(xpd, logical_chan)->readchunk;
// memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG
memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE;
@@ -1554,9 +1554,9 @@ static void process_cas_dchan(xpd_t *xpd, byte regnum, byte data_low)
rsnum, chan1+1, chan2+1, priv->cas_rs_e[pos], data_low);
if(SPAN_REGISTERED(xpd)) {
if(old1 != new1)
- dahdi_rbsbits(xpd->span.chans[chan1], new1);
+ dahdi_rbsbits(XPD_CHAN(xpd, chan1), new1);
if(old2 != new2)
- dahdi_rbsbits(xpd->span.chans[chan2], new2);
+ dahdi_rbsbits(XPD_CHAN(xpd, chan2), new2);
}
priv->dchan_rx_counter++;
priv->cas_rs_e[pos] = data_low;
@@ -1635,6 +1635,7 @@ static xproto_table_t PROTO_TABLE(PRI) = {
.card_dahdi_postregistration = PRI_card_dahdi_postregistration,
.card_hooksig = PRI_card_hooksig,
.card_tick = PRI_card_tick,
+ .card_pcm_recompute = generic_card_pcm_recompute,
.card_pcm_fromspan = PRI_card_pcm_fromspan,
.card_pcm_tospan = PRI_card_pcm_tospan,
.card_ioctl = PRI_card_ioctl,
diff --git a/drivers/dahdi/xpp/init_card_1_30 b/drivers/dahdi/xpp/init_card_1_30
index 96ab2ca..fafd2c1 100755
--- a/drivers/dahdi/xpp/init_card_1_30
+++ b/drivers/dahdi/xpp/init_card_1_30
@@ -47,7 +47,7 @@ use Getopt::Std;
my $program = basename("$0");
my $init_dir = dirname("$0");
-BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); }
+BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
use XppConfig $init_dir;
my $unit_id;
my %opts;
diff --git a/drivers/dahdi/xpp/init_card_2_30 b/drivers/dahdi/xpp/init_card_2_30
index 13a28cf..34f8a0b 100755
--- a/drivers/dahdi/xpp/init_card_2_30
+++ b/drivers/dahdi/xpp/init_card_2_30
@@ -47,7 +47,7 @@ use Getopt::Std;
my $program = basename("$0");
my $init_dir = dirname("$0");
-BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf", "$init_dir/utils/zconf"); }
+BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
use XppConfig $init_dir;
my $unit_id;
my %opts;
diff --git a/drivers/dahdi/xpp/init_card_3_30 b/drivers/dahdi/xpp/init_card_3_30
index c06e885..3355f7b 100755
--- a/drivers/dahdi/xpp/init_card_3_30
+++ b/drivers/dahdi/xpp/init_card_3_30
@@ -60,7 +60,7 @@ use Getopt::Std;
my $program = basename("$0");
my $init_dir = dirname("$0");
-BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); }
+BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
use XppConfig $init_dir;
my $unit_id;
my %opts;
diff --git a/drivers/dahdi/xpp/init_card_4_30 b/drivers/dahdi/xpp/init_card_4_30
index 1748ac2..6d56398 100755
--- a/drivers/dahdi/xpp/init_card_4_30
+++ b/drivers/dahdi/xpp/init_card_4_30
@@ -58,7 +58,7 @@ use Getopt::Std;
my $program = basename("$0");
my $init_dir = dirname("$0");
-BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); }
+BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir"); }
use XppConfig $init_dir;
my $unit_id;
my %opts;
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c
index 09d5de9..6be6f0e 100644
--- a/drivers/dahdi/xpp/xbus-core.c
+++ b/drivers/dahdi/xpp/xbus-core.c
@@ -68,7 +68,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
#ifdef OLD_PROC
static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data);
#endif
-static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv);
+static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv);
static void transport_destroy(xbus_t *xbus);
/* Data structures */
@@ -813,7 +813,11 @@ static int xbus_initialize(xbus_t *xbus)
int unit;
int subunit;
xpd_t *xpd;
+ struct timeval time_start;
+ struct timeval time_end;
+ unsigned long timediff;
+ do_gettimeofday(&time_start);
XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n",
refcount_xbus(xbus));
for(unit = 0; unit < MAX_UNIT; unit++) {
@@ -843,8 +847,13 @@ static int xbus_initialize(xbus_t *xbus)
goto err;
}
}
+ do_gettimeofday(&time_end);
+ timediff = usec_diff(&time_end, &time_start);
+ timediff /= 1000*100;
+ XBUS_INFO(xbus, "Initialized in %ld.%1ld sec\n", timediff/10, timediff%10);
return 0;
err:
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
return -EINVAL;
}
@@ -909,7 +918,7 @@ void xbus_populate(void *data)
* all others will reach the device before it.
*/
xbus_request_sync(xbus, SYNC_MODE_PLL);
- elect_syncer("xbus_poll(end)"); /* FIXME: try to do it later */
+ elect_syncer("xbus_populate(end)"); /* FIXME: try to do it later */
out:
XBUS_DBG(DEVICES, xbus, "Leaving\n");
wake_up(&worker->wait_for_xpd_initialization);
@@ -917,6 +926,7 @@ out:
up(&xbus->in_worker);
return;
failed:
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
goto out;
}
@@ -1193,7 +1203,6 @@ void xbus_deactivate(xbus_t *xbus, bool is_disconnected)
xpd_unreg_request(xpd);
}
}
- elect_syncer("deactivate");
XBUS_DBG(DEVICES, xbus, "[%s] Waiting for queues\n", xbus->label);
xbus_command_queue_clean(xbus);
xbus_command_queue_waitempty(xbus);
@@ -1202,6 +1211,7 @@ void xbus_deactivate(xbus_t *xbus, bool is_disconnected)
xbus_release_xpds(xbus);
if(!is_disconnected)
xbus_setstate(xbus, XBUS_STATE_IDLE);
+ elect_syncer("deactivate");
}
void xbus_disconnect(xbus_t *xbus)
@@ -1305,7 +1315,7 @@ void xbus_free(xbus_t *xbus)
KZFREE(xbus);
}
-xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
+xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv)
{
int err;
xbus_t *xbus = NULL;
@@ -1319,7 +1329,7 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
}
snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num);
XBUS_DBG(DEVICES, xbus, "\n");
- transport_init(xbus, ops, max_send_size, priv);
+ transport_init(xbus, ops, max_send_size, transport_device, priv);
spin_lock_init(&xbus->lock);
init_waitqueue_head(&xbus->command_queue_empty);
init_timer(&xbus->command_timer);
@@ -1378,9 +1388,9 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
goto nobus;
}
#endif
- xframe_queue_init(&xbus->command_queue, 10, 500, "command_queue", xbus);
+ xframe_queue_init(&xbus->command_queue, 10, 200, "command_queue", xbus);
xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus);
- xframe_queue_init(&xbus->send_pool, 10, 200, "send_pool", xbus);
+ xframe_queue_init(&xbus->send_pool, 10, 100, "send_pool", xbus);
xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus);
xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus);
tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus);
@@ -1505,6 +1515,21 @@ out:
}
+static bool xpds_done(xbus_t *xbus)
+{
+ struct xbus_workqueue *worker;
+
+ if(XBUS_IS(xbus, FAIL))
+ return 1; /* Nothing to wait for */
+ if(!XBUS_IS(xbus, RECVD_DESC))
+ return 1; /* We are not in the initialization phase */
+ worker = xbus->worker;
+ if(worker->xpds_init_done)
+ return 1; /* All good */
+ /* Keep waiting */
+ return 0;
+}
+
int waitfor_xpds(xbus_t *xbus, char *buf)
{
struct xbus_workqueue *worker;
@@ -1525,19 +1550,9 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
"Waiting for card initialization of %d XPD's max %d seconds\n",
worker->num_units,
INITIALIZATION_TIMEOUT/HZ);
- /*
- * when polling is finished xbus_poll():
- * - Unset worker->is_polling
- * - Sets worker->count_xpds_to_initialize.
- * So we wait until polling is finished (is_polling == 0) and:
- * - No poll answers from Astribank (e.g: defective firmware).
- * - Or no units to initialize (e.g: mini-AB with only main card).
- * - Or we finished initializing all existing units.
- * - Or A timeout passed.
- */
ret = wait_event_interruptible_timeout(
worker->wait_for_xpd_initialization,
- !XBUS_IS(xbus, RECVD_DESC) || worker->xpds_init_done,
+ xpds_done(xbus),
INITIALIZATION_TIMEOUT);
if(ret == 0) {
XBUS_ERR(xbus, "Card Initialization Timeout\n");
@@ -1552,11 +1567,15 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
"Finished initialization of %d XPD's in %d seconds.\n",
worker->num_units_initialized,
(INITIALIZATION_TIMEOUT - ret)/HZ);
- spin_lock_irqsave(&xbus->lock, flags);
- len += sprintf(buf, "XPDS_READY: %s: %d/%d\n",
+ if(XBUS_IS(xbus, FAIL)) {
+ len += sprintf(buf, "FAILED: %s\n", xbus->busname);
+ } else {
+ spin_lock_irqsave(&xbus->lock, flags);
+ len += sprintf(buf, "XPDS_READY: %s: %d/%d\n",
xbus->busname,
worker->num_units_initialized, worker->num_units);
- spin_unlock_irqrestore(&xbus->lock, flags);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ }
out:
put_xbus(__FUNCTION__, xbus); /* from start of waitfor_xpds_show() */
return len;
@@ -1566,10 +1585,7 @@ out:
static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
- unsigned long flags;
xbus_t *xbus = data;
- struct xbus_workqueue *worker;
- int ret;
if(!xbus)
goto out;
@@ -1709,7 +1725,7 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
}
#endif
-static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv)
+static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv)
{
BUG_ON(!xbus);
BUG_ON(!ops);
@@ -1719,6 +1735,7 @@ static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_s
BUG_ON(!ops->free_xframe);
xbus->transport.ops = ops;
xbus->transport.max_send_size = max_send_size;
+ xbus->transport.transport_device = transport_device;
xbus->transport.priv = priv;
xbus->transport.xbus_state = XBUS_STATE_START;
spin_lock_init(&xbus->transport.state_lock);
diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h
index 057e6cd..8cfb48c 100644
--- a/drivers/dahdi/xpp/xbus-core.h
+++ b/drivers/dahdi/xpp/xbus-core.h
@@ -103,6 +103,7 @@ const char *xbus_statename(enum xbus_state st);
struct xbus_transport {
struct xbus_ops *ops;
void *priv;
+ struct device *transport_device;
ushort max_send_size;
enum xbus_state xbus_state;
spinlock_t state_lock;
@@ -297,7 +298,7 @@ xpacket_t *xframe_next_packet(xframe_t *xframe, int len);
xpd_t *xpd_of(const xbus_t *xbus, int xpd_num);
xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit);
bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate);
-xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv);
+xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv);
void xbus_free(xbus_t *xbus);
int xbus_connect(xbus_t *xbus);
int xbus_activate(xbus_t *xbus);
diff --git a/drivers/dahdi/xpp/xbus-pcm.c b/drivers/dahdi/xpp/xbus-pcm.c
index 9e6ce8d..d89991d 100644
--- a/drivers/dahdi/xpp/xbus-pcm.c
+++ b/drivers/dahdi/xpp/xbus-pcm.c
@@ -56,7 +56,7 @@ static struct xpp_ticker dahdi_ticker;
*/
static struct xpp_ticker *ref_ticker = NULL;
static spinlock_t ref_ticker_lock = SPIN_LOCK_UNLOCKED;
-static bool force_dahdi_sync = 0; /* from "/proc/xpp/sync" */
+static bool force_dahdi_sync = 0; /* from /sys/bus/astribanks/drivers/xppdrv/sync */
static xbus_t *global_ticker;
static struct xpp_ticker global_ticks_series;
@@ -170,9 +170,12 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
driftinfo->delta_tick = new_delta_tick;
if(lost_ticks) {
+ static int rate_limit;
+
driftinfo->lost_ticks++;
driftinfo->lost_tick_count += abs(lost_ticks);
- if(printk_ratelimit()) {
+
+ if((rate_limit++ % 1003) == 0) {
XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
lost_ticks,
(abs(lost_ticks) > 1) ? "s": "");
@@ -445,14 +448,8 @@ int dahdi_sync_tick(struct dahdi_span *span, int is_master)
if(is_master) {
static int rate_limit;
- if(xpd->xbus != syncer && ((rate_limit % 1003) == 0)) {
- XPD_ERR(xpd,
- "Dahdi master, but syncer=%s\n",
- xpd->xbus->busname);
- }
- if((rate_limit % 5003) == 0)
- XPD_NOTICE(xpd, "Dahdi master: ignore DAHDI sync\n");
- rate_limit++;
+ if((rate_limit++ % 1003) == 0)
+ XPD_NOTICE(xpd, "Is a DAHDI sync master: ignore sync from DAHDI\n");
goto noop;
}
/* Now we know for sure someone else is dahdi sync master */
@@ -461,7 +458,7 @@ int dahdi_sync_tick(struct dahdi_span *span, int is_master)
if((rate_limit++ % 5003) == 0)
XBUS_DBG(SYNC, syncer,
- "Already a syncer, ignore DAHDI sync\n");
+ "is a SYNCer: ignore sync from DAHDI\n");
goto noop;
}
/* ignore duplicate calls from all our registered spans */
@@ -488,12 +485,15 @@ noop:
* if new_syncer is NULL, than we move all to SYNC_MODE_PLL
* for DAHDI sync.
*/
-static void update_sync_master(xbus_t *new_syncer)
+static void update_sync_master(xbus_t *new_syncer, bool force_dahdi)
{
- const char *msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC";
+ const char *msg;
int i;
unsigned long flags;
+ WARN_ON(new_syncer && force_dahdi); /* Ambigous */
+ force_dahdi_sync = force_dahdi;
+ msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC";
DBG(SYNC, "%s => %s\n",
(syncer) ? syncer->busname : msg,
(new_syncer) ? new_syncer->busname : msg);
@@ -545,9 +545,9 @@ void elect_syncer(const char *msg)
xbus_t *xbus = xbus_num(i);
if(!xbus)
continue;
- if(!the_xbus)
- the_xbus = xbus;
if(XBUS_IS(xbus, READY)) {
+ if(!the_xbus)
+ the_xbus = xbus; /* First candidate */
for(j = 0; j < MAX_XPDS; j++) {
xpd_t *xpd = xpd_of(xbus, j);
@@ -568,26 +568,25 @@ void elect_syncer(const char *msg)
} else
DBG(SYNC, "%s: No more syncers\n", msg);
if(the_xbus != syncer)
- update_sync_master(the_xbus);
+ update_sync_master(the_xbus, force_dahdi_sync);
}
/*
* This function is used by FXS/FXO. The pcm_mask argument signifies
* channels which should be *added* to the automatic calculation.
* Normally, this argument is 0.
- *
- * The caller should spinlock the XPD before calling it.
*/
-void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
+void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask)
{
int i;
int line_count = 0;
+ unsigned long flags;
- XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask);
+ spin_lock_irqsave(&xpd->lock_recompute_pcm, flags);
+ //XPD_DBG(SIGNAL, xpd, "pcm_mask=0x%X\n", pcm_mask);
/* Add/remove all the trivial cases */
- pcm_mask |= xpd->offhook;
- pcm_mask |= xpd->cid_on;
- pcm_mask &= ~xpd->digital_signalling; /* No PCM in D-Channels */
+ pcm_mask |= xpd->offhook_state;
+ pcm_mask |= xpd->oht_pcm_pass;
pcm_mask &= ~xpd->digital_inputs;
pcm_mask &= ~xpd->digital_outputs;
for_each_line(xpd, i)
@@ -605,18 +604,9 @@ void __pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE
: 0L;
xpd->wanted_pcm_mask = pcm_mask;
-}
-
-/*
- * A spinlocked version of __pcm_recompute()
- */
-void pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&xpd->lock, flags);
- __pcm_recompute(xpd, pcm_mask);
- spin_unlock_irqrestore(&xpd->lock, flags);
+ XPD_DBG(SIGNAL, xpd, "pcm_len=%d wanted_pcm_mask=0x%X\n",
+ xpd->pcm_len, xpd->wanted_pcm_mask);
+ spin_unlock_irqrestore(&xpd->lock_recompute_pcm, flags);
}
void fill_beep(u_char *buf, int num, int duration)
@@ -647,17 +637,18 @@ void fill_beep(u_char *buf, int num, int duration)
static void do_ec(xpd_t *xpd)
{
- struct dahdi_chan **chans = xpd->span.chans;
- int i;
+ int i;
for (i = 0;i < xpd->span.channels; i++) {
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
+
if(unlikely(IS_SET(xpd->digital_signalling, i))) /* Don't echo cancel BRI D-chans */
continue;
if(!IS_SET(xpd->wanted_pcm_mask, i)) /* No ec for unwanted PCM */
continue;
- dahdi_ec_chunk(chans[i], chans[i]->readchunk, xpd->ec_chunk2[i]);
+ dahdi_ec_chunk(chan, chan->readchunk, xpd->ec_chunk2[i]);
memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], DAHDI_CHUNKSIZE);
- memcpy(xpd->ec_chunk1[i], chans[i]->writechunk, DAHDI_CHUNKSIZE);
+ memcpy(xpd->ec_chunk1[i], chan->writechunk, DAHDI_CHUNKSIZE);
}
}
@@ -761,31 +752,33 @@ dropit:
* Generic implementations of card_pcmfromspan()/card_pcmtospan()
* For FXS/FXO
*/
-void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
+void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
{
- byte *pcm;
- struct dahdi_chan **chans;
- unsigned long flags;
- int i;
+ byte *pcm;
+ unsigned long flags;
+ xpp_line_t wanted_lines;
+ int i;
BUG_ON(!xbus);
BUG_ON(!xpd);
BUG_ON(!pack);
- RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
+ wanted_lines = xpd->wanted_pcm_mask;
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = wanted_lines;
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
spin_lock_irqsave(&xpd->lock, flags);
- chans = xpd->span.chans;
for (i = 0; i < xpd->channels; i++) {
- if(IS_SET(lines, i)) {
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
+
+ if(IS_SET(wanted_lines, i)) {
if(SPAN_REGISTERED(xpd)) {
#ifdef DEBUG_PCMTX
- int channo = xpd->span.chans[i]->channo;
+ int channo = chan->channo;
if(pcmtx >= 0 && pcmtx_chan == channo)
memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE);
else
#endif
- memcpy((u_char *)pcm, chans[i]->writechunk, DAHDI_CHUNKSIZE);
+ memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE);
} else
memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE;
@@ -814,7 +807,7 @@ void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack)
if(!SPAN_REGISTERED(xpd))
goto out;
for (i = 0; i < xpd->channels; i++) {
- volatile u_char *r = xpd->span.chans[i]->readchunk;
+ volatile u_char *r = XPD_CHAN(xpd, i)->readchunk;
bool got_data = IS_SET(pcm_mask, i);
if(got_data && !IS_SET(pcm_mute, i)) {
@@ -914,7 +907,6 @@ static void xbus_tick(xbus_t *xbus)
xpd_t *xpd;
xframe_t *xframe = NULL;
xpacket_t *pack = NULL;
- size_t pcm_len;
bool sent_sync_bit = 0;
/*
@@ -930,7 +922,7 @@ static void xbus_tick(xbus_t *xbus)
xmit_mask |= xpd->silence_pcm;
xmit_mask |= xpd->digital_signalling;
for_each_line(xpd, j) {
- xpd->chans[j].chanmute = (optimize_chanmute)
+ XPD_CHAN(xpd, j)->chanmute = (optimize_chanmute)
? !IS_SET(xmit_mask, j)
: 0;
}
@@ -946,6 +938,8 @@ static void xbus_tick(xbus_t *xbus)
* Fill xframes
*/
for(i = 0; i < MAX_XPDS; i++) {
+ size_t pcm_len;
+
if((xpd = xpd_of(xbus, i)) == NULL)
continue;
pcm_len = xpd->pcm_len;
@@ -978,7 +972,7 @@ static void xbus_tick(xbus_t *xbus)
XPACKET_ADDR_SYNC(pack) = 1;
sent_sync_bit = 1;
}
- CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, xpd->wanted_pcm_mask, pack);
+ CALL_XMETHOD(card_pcm_fromspan, xbus, xpd, pack);
XBUS_COUNTER(xbus, TX_PACK_PCM)++;
}
}
@@ -1070,7 +1064,50 @@ void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe)
xbus->xbus_frag_count++;
}
-#ifdef CONFIG_PROC_FS
+int exec_sync_command(const char *buf, size_t count)
+{
+ int ret = count;
+ int xbusno;
+ xbus_t *xbus;
+
+ if(strncmp("DAHDI", buf, 6) == 0) { /* Ignore the newline */
+ DBG(SYNC, "DAHDI\n");
+ update_sync_master(NULL, 1);
+ } else if(sscanf(buf, "SYNC=%d\n", &xbusno) == 1) {
+ DBG(SYNC, "SYNC=%d\n", xbusno);
+ if((xbus = xbus_num(xbusno)) == NULL) {
+ ERR("No bus %d exists\n", xbusno);
+ return -ENXIO;
+ }
+ update_sync_master(xbus, 0);
+ } else if(sscanf(buf, "QUERY=%d\n", &xbusno) == 1) {
+ DBG(SYNC, "QUERY=%d\n", xbusno);
+ if((xbus = xbus_num(xbusno)) == NULL) {
+ ERR("No bus %d exists\n", xbusno);
+ return -ENXIO;
+ }
+ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0);
+ } else {
+ ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+int fill_sync_string(char *buf, size_t count)
+{
+ int len = 0;
+
+ if(!syncer) {
+ len += snprintf(buf, count, "%s\n",
+ (force_dahdi_sync) ? "DAHDI" : "NO-SYNC");
+ } else
+ len += snprintf(buf, count, "SYNC=%02d\n", syncer->num);
+ return len;
+}
+
+#ifdef OLD_PROC
+#ifdef CONFIG_PROC_FS
static int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -1079,17 +1116,13 @@ static int proc_sync_read(char *page, char **start, off_t off, int count, int *e
unsigned long usec;
do_gettimeofday(&now);
+ NOTICE("%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
len += sprintf(page + len, "# To modify sync source write into this file:\n");
len += sprintf(page + len, "# DAHDI - Another dahdi device provide sync\n");
len += sprintf(page + len, "# SYNC=nn - XBUS-nn provide sync\n");
len += sprintf(page + len, "# QUERY=nn - Query XBUS-nn for sync information (DEBUG)\n");
- if(!syncer) {
- if(force_dahdi_sync)
- len += sprintf(page + len, "DAHDI\n");
- else
- len += sprintf(page + len, "NO-SYNC\n");
- } else
- len += sprintf(page + len, "SYNC=%02d\n", syncer->num);
+ len += fill_sync_string(page + len, PAGE_SIZE - len);
#ifdef DAHDI_SYNC_TICK
if(force_dahdi_sync) {
len += sprintf(page + len,
@@ -1123,68 +1156,26 @@ static int proc_sync_read(char *page, char **start, off_t off, int count, int *e
static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
char buf[MAX_PROC_WRITE];
- int xbusno;
- int xpd_num;
- xbus_t *xbus;
- xpd_t *xpd;
// DBG(SYNC, "%s: count=%ld\n", __FUNCTION__, count);
+ NOTICE("%s: DEPRECATED: %s[%d] write to /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
if(count >= MAX_PROC_WRITE)
return -EINVAL;
if(copy_from_user(buf, buffer, count))
return -EFAULT;
buf[count] = '\0';
- if(strncmp("DAHDI", buf, 5) == 0) {
- DBG(SYNC, "DAHDI\n");
- force_dahdi_sync=1;
- update_sync_master(NULL);
- } else if(sscanf(buf, "SYNC=%d", &xbusno) == 1) {
- DBG(SYNC, "SYNC=%d\n", xbusno);
- if((xbus = xbus_num(xbusno)) == NULL) {
- ERR("No bus %d exists\n", xbusno);
- return -ENXIO;
- }
- update_sync_master(xbus);
- } else if(sscanf(buf, "QUERY=%d", &xbusno) == 1) {
- DBG(SYNC, "QUERY=%d\n", xbusno);
- if((xbus = xbus_num(xbusno)) == NULL) {
- ERR("No bus %d exists\n", xbusno);
- return -ENXIO;
- }
- CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0);
- } else if(sscanf(buf, "%d %d", &xbusno, &xpd_num) == 2) {
- NOTICE("Using deprecated syntax to update %s file\n",
- PROC_SYNC);
- if(xpd_num != 0) {
- ERR("Currently can only set sync for XPD #0\n");
- return -EINVAL;
- }
- if((xbus = xbus_num(xbusno)) == NULL) {
- ERR("No bus %d exists\n", xbusno);
- return -ENXIO;
- }
- if((xpd = xpd_of(xbus, xpd_num)) == NULL) {
- XBUS_ERR(xbus, "No xpd %d exists\n", xpd_num);
- return -ENXIO;
- }
- update_sync_master(xbus);
- } else {
- ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf);
- count = -EINVAL;
- }
- return count;
+ return exec_sync_command(buf, count);
}
static struct proc_dir_entry *top;
#endif
+#endif /* OLD_PROC */
int xbus_pcm_init(struct proc_dir_entry *toplevel)
{
int ret = 0;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
-#endif
#ifdef OPTIMIZE_CHANMUTE
INFO("FEATURE: with CHANMUTE optimization (%sactivated)\n",
@@ -1197,27 +1188,34 @@ int xbus_pcm_init(struct proc_dir_entry *toplevel)
#endif
xpp_ticker_init(&global_ticks_series);
xpp_ticker_init(&dahdi_ticker);
-#ifdef CONFIG_PROC_FS
- top = toplevel;
- ent = create_proc_entry(PROC_SYNC, 0644, top);
- if(!ent) {
- ret = -EFAULT;
- goto err;
+#ifdef OLD_PROC
+#ifdef CONFIG_PROC_FS
+ {
+ struct proc_dir_entry *ent;
+
+ top = toplevel;
+ ent = create_proc_entry(PROC_SYNC, 0644, top);
+ if(ent) {
+ ent->read_proc = proc_sync_read;
+ ent->write_proc = proc_sync_write;
+ ent->data = NULL;
+ } else {
+ ret = -EFAULT;
+ }
}
- ent->read_proc = proc_sync_read;
- ent->write_proc = proc_sync_write;
- ent->data = NULL;
#endif
-err:
+#endif /* OLD_PROC */
return ret;
}
void xbus_pcm_shutdown(void)
{
+#ifdef OLD_PROC
#ifdef CONFIG_PROC_FS
DBG(GENERAL, "Removing '%s' from proc\n", PROC_SYNC);
remove_proc_entry(PROC_SYNC, top);
#endif
+#endif /* OLD_PROC */
}
@@ -1227,8 +1225,7 @@ EXPORT_SYMBOL(elect_syncer);
#ifdef DAHDI_SYNC_TICK
EXPORT_SYMBOL(dahdi_sync_tick);
#endif
-EXPORT_SYMBOL(__pcm_recompute);
-EXPORT_SYMBOL(pcm_recompute);
+EXPORT_SYMBOL(generic_card_pcm_recompute);
EXPORT_SYMBOL(generic_card_pcm_tospan);
EXPORT_SYMBOL(generic_card_pcm_fromspan);
#ifdef DEBUG_PCMTX
diff --git a/drivers/dahdi/xpp/xbus-pcm.h b/drivers/dahdi/xpp/xbus-pcm.h
index a7529c8..be33044 100644
--- a/drivers/dahdi/xpp/xbus-pcm.h
+++ b/drivers/dahdi/xpp/xbus-pcm.h
@@ -100,9 +100,9 @@ int xbus_pcm_init(struct proc_dir_entry *top);
void xbus_pcm_shutdown(void);
int send_pcm_frame(xbus_t *xbus, xframe_t *xframe);
void pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask);
-void __pcm_recompute(xpd_t *xpd, xpp_line_t tmp_pcm_mask); /* non locking */
void xframe_receive_pcm(xbus_t *xbus, xframe_t *xframe);
-void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack);
+void generic_card_pcm_recompute(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask);
+void generic_card_pcm_fromspan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack);
void generic_card_pcm_tospan(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack);
void fill_beep(u_char *buf, int num, int duration);
const char *sync_mode_name(enum sync_mode mode);
@@ -112,6 +112,8 @@ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift);
int xbus_command_queue_tick(xbus_t *xbus);
void xbus_reset_counters(xbus_t *xbus);
void elect_syncer(const char *msg);
+int exec_sync_command(const char *buf, size_t count);
+int fill_sync_string(char *buf, size_t count);
#ifdef DAHDI_SYNC_TICK
int dahdi_sync_tick(struct dahdi_span *span, int is_master);
#endif
diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c
index 4dd0f0d..8d1f35a 100644
--- a/drivers/dahdi/xpp/xbus-sysfs.c
+++ b/drivers/dahdi/xpp/xbus-sysfs.c
@@ -38,7 +38,6 @@
#include "xpd.h"
#include "xpp_dahdi.h"
#include "xbus-core.h"
-#include "card_global.h"
#ifdef XPP_DEBUGFS
#include "xpp_log.h"
#endif
@@ -49,6 +48,23 @@ static const char rcsid[] = "$Id$";
/* Command line parameters */
extern int debug;
+/*--------- xpp driver attributes -*/
+static ssize_t sync_show(struct device_driver *driver, char *buf)
+{
+ DBG(SYNC, "\n");
+ return fill_sync_string(buf, PAGE_SIZE);
+}
+
+static ssize_t sync_store(struct device_driver *driver, const char *buf, size_t count)
+{
+ /* DBG(SYNC, "%s\n", buf); */
+ return exec_sync_command(buf, count);
+}
+
+static struct driver_attribute xpp_attrs[] = {
+ __ATTR(sync, S_IRUGO | S_IWUSR, sync_show, sync_store),
+};
+
/*--------- Sysfs Bus handling ----*/
static DEVICE_ATTR_READER(xbus_state_show, dev, buf)
{
@@ -320,19 +336,19 @@ void astribank_uevent_send(xbus_t *xbus, enum kobject_action act)
xbus->astribank.bus_id, act);
#if defined(OLD_HOTPLUG_SUPPORT_269)
- {
- /* Copy from new kernels lib/kobject_uevent.c */
- static const char *str[] = {
- [KOBJ_ADD] "add",
- [KOBJ_REMOVE] "remove",
- [KOBJ_CHANGE] "change",
- [KOBJ_MOUNT] "mount",
- [KOBJ_UMOUNT] "umount",
- [KOBJ_OFFLINE] "offline",
- [KOBJ_ONLINE] "online"
- };
- kobject_hotplug(str[act], kobj);
- }
+ {
+ /* Copy from new kernels lib/kobject_uevent.c */
+ static const char *str[] = {
+ [KOBJ_ADD] "add",
+ [KOBJ_REMOVE] "remove",
+ [KOBJ_CHANGE] "change",
+ [KOBJ_MOUNT] "mount",
+ [KOBJ_UMOUNT] "umount",
+ [KOBJ_OFFLINE] "offline",
+ [KOBJ_ONLINE] "online"
+ };
+ kobject_hotplug(str[act], kobj);
+ }
#elif defined(OLD_HOTPLUG_SUPPORT)
kobject_hotplug(kobj, act);
#else
@@ -340,11 +356,6 @@ void astribank_uevent_send(xbus_t *xbus, enum kobject_action act)
#endif
}
-static void xpp_release(struct device *dev)
-{
- DBG(DEVICES, "SYSFS %s\n", dev->bus_id);
-}
-
static void astribank_release(struct device *dev)
{
xbus_t *xbus;
@@ -369,11 +380,7 @@ static struct bus_type toplevel_bus_type = {
.uevent = astribank_uevent,
#endif
.dev_attrs = xbus_dev_attrs,
-};
-
-static struct device toplevel_device = {
- .bus_id = "xpp",
- .release = xpp_release
+ .drv_attrs = xpp_attrs,
};
static int astribank_probe(struct device *dev)
@@ -479,6 +486,9 @@ static DEVICE_ATTR_WRITER(chipregs_store, dev, buf, count)
}
}
p += i + 1;
+ /* Don't flood command_queue */
+ if(xframe_queue_count(&xpd->xbus->command_queue) > 5)
+ msleep(6);
}
return count;
}
@@ -559,6 +569,19 @@ static DEVICE_ATTR_WRITER(span_store, dev, buf, count)
return (ret < 0) ? ret : count;
}
+static DEVICE_ATTR_READER(type_show, dev, buf)
+{
+ xpd_t *xpd;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ len += sprintf(buf, "%s\n", xpd->type_name);
+ return len;
+}
+
static int xpd_match(struct device *dev, struct device_driver *driver)
{
struct xpd_driver *xpd_driver;
@@ -580,6 +603,7 @@ static struct device_attribute xpd_dev_attrs[] = {
__ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store),
__ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store),
__ATTR(span, S_IRUGO | S_IWUSR, span_show, span_store),
+ __ATTR_RO(type),
__ATTR_NULL,
};
@@ -666,6 +690,7 @@ void xbus_sysfs_remove(xbus_t *xbus)
XBUS_DBG(DEVICES, xbus, "\n");
astribank = &xbus->astribank;
BUG_ON(!astribank);
+ sysfs_remove_link(&astribank->kobj, "transport");
if(!astribank->driver_data)
return;
BUG_ON(astribank->driver_data != xbus);
@@ -682,7 +707,7 @@ int xbus_sysfs_create(xbus_t *xbus)
BUG_ON(!astribank);
XBUS_DBG(DEVICES, xbus, "\n");
astribank->bus = &toplevel_bus_type;
- astribank->parent = &toplevel_device;
+ astribank->parent = xbus->transport.transport_device;
snprintf(astribank->bus_id, BUS_ID_SIZE, "xbus-%02d", xbus->num);
astribank->driver_data = xbus;
astribank->release = astribank_release;
@@ -690,7 +715,15 @@ int xbus_sysfs_create(xbus_t *xbus)
if(ret) {
XBUS_ERR(xbus, "%s: device_register failed: %d\n", __FUNCTION__, ret);
astribank->driver_data = NULL;
+ goto out;
}
+ ret = sysfs_create_link(&astribank->kobj, &astribank->parent->kobj, "transport");
+ if(ret < 0) {
+ XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n", __FUNCTION__, ret);
+ astribank->driver_data = NULL;
+ goto out;
+ }
+out:
return ret;
}
@@ -704,11 +737,6 @@ int __init xpp_driver_init(void)
__FUNCTION__, toplevel_bus_type.name, ret);
goto failed_bus;
}
- if((ret = device_register(&toplevel_device)) < 0) {
- ERR("%s: device_register(%s) failed. Error number %d",
- __FUNCTION__, toplevel_device.bus_id, ret);
- goto failed_busdevice;
- }
if((ret = driver_register(&xpp_driver)) < 0) {
ERR("%s: driver_register(%s) failed. Error number %d",
__FUNCTION__, xpp_driver.name, ret);
@@ -723,8 +751,6 @@ int __init xpp_driver_init(void)
failed_xpd_bus:
driver_unregister(&xpp_driver);
failed_xpp_driver:
- device_unregister(&toplevel_device);
-failed_busdevice:
bus_unregister(&toplevel_bus_type);
failed_bus:
return ret;
@@ -735,7 +761,6 @@ void xpp_driver_exit(void)
DBG(DEVICES, "SYSFS\n");
bus_unregister(&xpd_type);
driver_unregister(&xpp_driver);
- device_unregister(&toplevel_device);
bus_unregister(&toplevel_bus_type);
}
diff --git a/drivers/dahdi/xpp/xpd.h b/drivers/dahdi/xpp/xpd.h
index 2e0363a..daf1954 100644
--- a/drivers/dahdi/xpp/xpd.h
+++ b/drivers/dahdi/xpp/xpd.h
@@ -156,6 +156,8 @@ struct xpd {
char xpdname[XPD_NAMELEN];
struct dahdi_span span;
struct dahdi_chan *chans[32];
+#define XPD_CHAN(xpd,chan) ((xpd)->chans[(chan)])
+
int channels;
xpd_type_t type;
const char *type_name;
@@ -163,8 +165,8 @@ struct xpd {
xpd_direction_t direction; /* TO_PHONE, TO_PSTN */
int subunits; /* all siblings */
xpp_line_t no_pcm; /* Temporary: disable PCM (for USB-1) */
- xpp_line_t offhook; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */
- xpp_line_t cid_on;
+ xpp_line_t offhook_state; /* Actual chip state: 0 - ONHOOK, 1 - OFHOOK */
+ xpp_line_t oht_pcm_pass; /* Transfer on-hook PCM */
xpp_line_t msg_waiting; /* Voice Mail Waiting Indication */
xpp_line_t digital_outputs; /* 0 - no, 1 - yes */
xpp_line_t digital_inputs; /* 0 - no, 1 - yes */
@@ -175,6 +177,8 @@ struct xpd {
struct device xpd_dev;
#define dev_to_xpd(dev) container_of(dev, struct xpd, xpd_dev)
+ /* Assure atomicity of changes to pcm_len and wanted_pcm_mask */
+ spinlock_t lock_recompute_pcm;
/* maintained by card drivers */
uint pcm_len; /* allocation length of PCM packet (dynamic) */
xpp_line_t wanted_pcm_mask;
@@ -187,7 +191,7 @@ struct xpd {
spinlock_t lock;
atomic_t dahdi_registered; /* Am I fully registered with dahdi */
- atomic_t open_counter; /* open channels */
+ atomic_t open_counter; /* Number of open channels */
int flags;
unsigned long blink_mode; /* bitmask of blinking ports */
diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c
index 9c4963f..b1ec98c 100644
--- a/drivers/dahdi/xpp/xpp_dahdi.c
+++ b/drivers/dahdi/xpp/xpp_dahdi.c
@@ -338,11 +338,11 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
}
len += sprintf(page + len, "\n\t%-17s: ", "offhook");
for_each_line(xpd, i) {
- len += sprintf(page + len, "%d ", IS_SET(xpd->offhook, i));
+ len += sprintf(page + len, "%d ", IS_OFFHOOK(xpd, i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "cid_on");
+ len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass");
for_each_line(xpd, i) {
- len += sprintf(page + len, "%d ", IS_SET(xpd->cid_on, i));
+ len += sprintf(page + len, "%d ", IS_SET(xpd->oht_pcm_pass, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting");
for_each_line(xpd, i) {
@@ -360,7 +360,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
if(SPAN_REGISTERED(xpd)) {
len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | W D");
for_each_line(xpd, i) {
- struct dahdi_chan *chan = xpd->span.chans[i];
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
byte rchunk[DAHDI_CHUNKSIZE];
byte wchunk[DAHDI_CHUNKSIZE];
byte *rp;
@@ -396,7 +396,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
if(SPAN_REGISTERED(xpd)) {
len += sprintf(page + len, "\nSignalling:\n");
for_each_line(xpd, i) {
- struct dahdi_chan *chan = &xpd->span.chans[i];
+ struct dahdi_chan *chan = XPD_CHAN(xpd, i);
len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig);
}
}
@@ -508,9 +508,10 @@ __must_check xpd_t *xpd_alloc(xbus_t *xbus,
}
xpd->priv = (byte *)xpd + sizeof(xpd_t);
spin_lock_init(&xpd->lock);
+ spin_lock_init(&xpd->lock_recompute_pcm);
xpd->channels = channels;
xpd->card_present = 0;
- xpd->offhook = 0x0; /* ONHOOK */
+ xpd->offhook_state = 0x0; /* ONHOOK */
xpd->type = proto_table->type;
xpd->xproto = proto_table;
xpd->xops = &proto_table->xops;
@@ -574,7 +575,7 @@ void xpd_unreg_request(xpd_t *xpd)
/* TODO: Should this be done before releasing the spinlock? */
XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to close them\n");
for (i=0; i<xpd->span.channels; i++) {
- dahdi_qevent_lock(xpd->chans[i],DAHDI_EVENT_REMOVED);
+ dahdi_qevent_lock(XPD_CHAN(xpd, i),DAHDI_EVENT_REMOVED);
}
}
spin_unlock_irqrestore(&xpd->lock, flags);
@@ -619,18 +620,64 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
}
-void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
+/*
+ * Used to block/pass PCM during onhook-transfers. E.g:
+ * - Playing FSK after FXS ONHOOK for MWI (non-neon style)
+ * - Playing DTFM/FSK for FXO Caller-ID detection.
+ */
+void oht_pcm(xpd_t *xpd, int pos, bool pass)
{
- enum dahdi_rxsig rxsig;
+ if(pass) {
+ LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: pass\n");
+ BIT_SET(xpd->oht_pcm_pass, pos);
+ } else {
+ LINE_DBG(SIGNAL, xpd, pos, "OHT PCM: block\n");
+ BIT_CLR(xpd->oht_pcm_pass, pos);
+ }
+ CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);
+}
- BUG_ON(!xpd);
+/*
+ * Update our hookstate -- for PCM block/pass
+ */
+void mark_offhook(xpd_t *xpd, int pos, bool to_offhook)
+{
if(to_offhook) {
- BIT_SET(xpd->offhook, pos);
- rxsig = DAHDI_RXSIG_OFFHOOK;
+ LINE_DBG(SIGNAL, xpd, pos, "OFFHOOK\n");
+ BIT_SET(xpd->offhook_state, pos);
} else {
- BIT_CLR(xpd->offhook, pos);
- BIT_CLR(xpd->cid_on, pos);
- rxsig = DAHDI_RXSIG_ONHOOK;
+ LINE_DBG(SIGNAL, xpd, pos, "ONHOOK\n");
+ BIT_CLR(xpd->offhook_state, pos);
+ }
+ CALL_XMETHOD(card_pcm_recompute, xpd->xbus, xpd, 0);
+}
+
+/*
+ * Send a signalling notification to Asterisk
+ */
+void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig)
+{
+ /*
+ * We should not spinlock before calling dahdi_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", rxsig2str(rxsig));
+ if(SPAN_REGISTERED(xpd))
+ dahdi_hooksig(XPD_CHAN(xpd, pos), rxsig);
+}
+
+/*
+ * Called when hardware state changed:
+ * - FXS -- the phone was picked up or hanged-up.
+ * - FXO -- we answered the phone or handed-up.
+ */
+void hookstate_changed(xpd_t *xpd, int pos, bool to_offhook)
+{
+ BUG_ON(!xpd);
+ mark_offhook(xpd, pos, to_offhook);
+ if(!to_offhook) {
+ oht_pcm(xpd, pos, 0);
/*
* To prevent latest PCM to stay in buffers
* indefinitely, mark this channel for a
@@ -640,14 +687,7 @@ void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
*/
BIT_SET(xpd->silence_pcm, pos);
}
- /*
- * We should not spinlock before calling dahdi_hooksig() as
- * it may call back into our xpp_hooksig() and cause
- * a nested spinlock scenario
- */
- LINE_DBG(SIGNAL, xpd, pos, "rxsig=%s\n", (rxsig == DAHDI_RXSIG_ONHOOK) ? "ONHOOK" : "OFFHOOK");
- if(SPAN_REGISTERED(xpd))
- dahdi_hooksig(xpd->chans[pos], rxsig);
+ notify_rxsig(xpd, pos, (to_offhook) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK);
}
#ifdef CONFIG_PROC_FS
@@ -805,8 +845,6 @@ int xpp_open(struct dahdi_chan *chan)
LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n",
current->comm, current->pid,
atomic_read(&xpd->open_counter));
- if(IS_SET(xpd->digital_signalling, pos)) /* D-chan offhook */
- BIT_SET(xpd->offhook, pos);
spin_unlock_irqrestore(&xbus->lock, flags);
if(xpd->xops->card_open)
xpd->xops->card_open(xpd, pos);
@@ -821,8 +859,6 @@ int xpp_close(struct dahdi_chan *chan)
unsigned long flags;
spin_lock_irqsave(&xbus->lock, flags);
- if(IS_SET(xpd->digital_signalling, pos)) /* D-chan onhook */
- BIT_CLR(xpd->offhook, pos);
spin_unlock_irqrestore(&xbus->lock, flags);
if(xpd->xops->card_close)
xpd->xops->card_close(xpd, pos);
@@ -1008,7 +1044,7 @@ int dahdi_register_xpd(xpd_t *xpd)
XPD_DBG(DEVICES, xpd, "Initializing span: %d channels.\n", cn);
memset(&xpd->span, 0, sizeof(struct dahdi_span));
for(i = 0; i < cn; i++) {
- memset(xpd->chans[i], 0, sizeof(struct dahdi_chan));
+ memset(XPD_CHAN(xpd, i), 0, sizeof(struct dahdi_chan));
}
span = &xpd->span;
@@ -1076,26 +1112,18 @@ int dahdi_register_xpd(xpd_t *xpd)
atomic_inc(&xpd->dahdi_registered);
xpd->xops->card_dahdi_postregistration(xpd, 1);
/*
- * Update dahdi about our state
- */
-#if 0
- /*
- * FIXME: since asterisk didn't open the channel yet, the report
- * is discarded anyway. OTOH, we cannot report in xpp_open or
- * xpp_chanconfig since dahdi call them with a spinlock on the channel
- * and dahdi_hooksig tries to acquire the same spinlock, resulting in
- * double spinlock deadlock (we are lucky that RH/Fedora kernel are
- * compiled with spinlock debugging).... tough.
+ * Update dahdi about our state:
+ * - Since asterisk didn't open the channel yet,
+ * the report is discarded anyway.
+ * - Our FXS driver have another notification mechanism that
+ * is triggered (indirectly) by the open() of the channe.
+ * - The real fix should be in Asterisk (to get the correct state
+ * after open).
*/
for_each_line(xpd, cn) {
- struct dahdi_chan *chans = xpd->span.chans;
-
- if(IS_SET(xpd->offhook, cn)) {
- LINE_NOTICE(xpd, cn, "Report OFFHOOK to dahdi\n");
- dahdi_hooksig(&chans[cn], DAHDI_RXSIG_OFFHOOK);
- }
+ if(IS_OFFHOOK(xpd, cn))
+ notify_rxsig(xpd, cn, DAHDI_RXSIG_OFFHOOK);
}
-#endif
return 0;
}
@@ -1163,7 +1191,10 @@ EXPORT_SYMBOL(xpd_alloc);
EXPORT_SYMBOL(xpd_free);
EXPORT_SYMBOL(xpd_unreg_request);
EXPORT_SYMBOL(update_xpd_status);
-EXPORT_SYMBOL(update_line_status);
+EXPORT_SYMBOL(oht_pcm);
+EXPORT_SYMBOL(mark_offhook);
+EXPORT_SYMBOL(notify_rxsig);
+EXPORT_SYMBOL(hookstate_changed);
EXPORT_SYMBOL(xpp_open);
EXPORT_SYMBOL(xpp_close);
EXPORT_SYMBOL(xpp_ioctl);
diff --git a/drivers/dahdi/xpp/xpp_dahdi.h b/drivers/dahdi/xpp/xpp_dahdi.h
index 7b5695a..8bf471b 100644
--- a/drivers/dahdi/xpp/xpp_dahdi.h
+++ b/drivers/dahdi/xpp/xpp_dahdi.h
@@ -35,13 +35,17 @@ xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits,
void xpd_free(xpd_t *xpd);
void xpd_remove(xpd_t *xpd);
void update_xpd_status(xpd_t *xpd, int alarm_flag);
-void update_line_status(xpd_t *xpd, int pos, bool good);
+void hookstate_changed(xpd_t *xpd, int pos, bool good);
int xpp_open(struct dahdi_chan *chan);
int xpp_close(struct dahdi_chan *chan);
int xpp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long arg);
int xpp_maint(struct dahdi_span *span, int cmd);
void report_bad_ioctl(const char *msg, xpd_t *xpd, int pos, unsigned int cmd);
int total_registered_spans(void);
+void oht_pcm(xpd_t *xpd, int pos, bool pass);
+void mark_offhook(xpd_t *xpd, int pos, bool to_offhook);
+#define IS_OFFHOOK(xpd,pos) IS_SET((xpd)->offhook_state, (pos))
+void notify_rxsig(xpd_t *xpd, int pos, enum dahdi_rxsig rxsig);
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
diff --git a/drivers/dahdi/xpp/xpp_usb.c b/drivers/dahdi/xpp/xpp_usb.c
index 2346fb4..2edec52 100644
--- a/drivers/dahdi/xpp/xpp_usb.c
+++ b/drivers/dahdi/xpp/xpp_usb.c
@@ -721,7 +721,7 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
/* let the user know what node this device is now attached to */
DBG(DEVICES, "USB XPP device now attached to minor %d\n", xusb->minor);
- xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), xusb);
+ xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), &udev->dev, xusb);
if(!xbus) {
retval = -ENOMEM;
goto probe_failed;
diff --git a/drivers/dahdi/xpp/xproto.c b/drivers/dahdi/xpp/xproto.c
index 53b6fce..3b454b1 100644
--- a/drivers/dahdi/xpp/xproto.c
+++ b/drivers/dahdi/xpp/xproto.c
@@ -437,6 +437,7 @@ int xproto_register(const xproto_table_t *proto_table)
CHECK_XOP(card_init);
CHECK_XOP(card_remove);
CHECK_XOP(card_tick);
+ CHECK_XOP(card_pcm_recompute);
CHECK_XOP(card_pcm_fromspan);
CHECK_XOP(card_pcm_tospan);
CHECK_XOP(card_dahdi_preregistration);
diff --git a/drivers/dahdi/xpp/xproto.h b/drivers/dahdi/xpp/xproto.h
index dbb720e..92eca4f 100644
--- a/drivers/dahdi/xpp/xproto.h
+++ b/drivers/dahdi/xpp/xproto.h
@@ -221,7 +221,8 @@ struct xops {
int (*card_init)(xbus_t *xbus, xpd_t *xpd);
int (*card_remove)(xbus_t *xbus, xpd_t *xpd);
int (*card_tick)(xbus_t *xbus, xpd_t *xpd);
- void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, xpacket_t *pack);
+ void (*card_pcm_recompute)(xbus_t *xbus, xpd_t *xpd, xpp_line_t pcm_mask);
+ void (*card_pcm_fromspan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack);
void (*card_pcm_tospan)(xbus_t *xbus, xpd_t *xpd, xpacket_t *pack);
int (*card_dahdi_preregistration)(xpd_t *xpd, bool on);
int (*card_dahdi_postregistration)(xpd_t *xpd, bool on);