summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-07 20:58:46 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-07 20:58:46 +0000
commit8953e09799d8995e3667e5766a362d282700af20 (patch)
tree8ce49c141cdccd5b1398979e809a3bdeeff0e9d8 /xpp/xpp_zap.c
parent237daca586a95a8f46c5e3326acf9015a004bf1b (diff)
xpp driver rev. 3332:
* Reverse polarity and power denial detection. * A short led flash at registration time. * Add a real version of the xpp modules to them (independent of the Zaptel version). * Update our line status even when not registered. * Fixed a false SIG_CHANGED when inserting or removing cable to FXO. * Fixed compilation fixes for 2.6.20 (Bug #8982) * A cleaner fix for the bool changes of 2.6.19 . * Automatically detect echo_can_state_t at debug time. * Automaitcally set XPP_DEBUGFS (depending on debugfs) at compile time. * Bug-fixes to zaptel-helper. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@2113 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c149
1 files changed, 90 insertions, 59 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index cd10ff4..b3e7017 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -64,13 +64,13 @@ static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
-DEF_PARM(bool, pcm_tasklet, 0, "Handle PCM in a tasklet (lower interrupt load)");
-DEF_PARM(int, disable_pcm, 0, "Disable all PCM transmissions");
-DEF_PARM(int, print_dbg, 0, "Print DBG statements");
-DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)");
-DEF_PARM(bool, prefmaster, 1, "Do we want to be zaptel preferred sync master");
+DEF_PARM_BOOL(pcm_tasklet, 0, 0600, "Handle PCM in a tasklet (lower interrupt load)");
+DEF_PARM(int, disable_pcm, 0, 0600, "Disable all PCM transmissions");
+DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements");
+DEF_PARM_BOOL(zap_autoreg, 1, 0600, "Register spans automatically (1) or not (0)");
+DEF_PARM_BOOL(prefmaster, 1, 0600, "Do we want to be zaptel preferred sync master");
#ifdef XPP_EC_CHUNK
-DEF_PARM_RO(bool, xpp_ec, 1, "Do we use our own (1) or Zaptel's (0) echo canceller");
+DEF_PARM_BOOL(xpp_ec, 1, 0400, "Do we use our own (1) or Zaptel's (0) echo canceller");
#else
static int xpp_ec = 0;
#endif
@@ -166,44 +166,54 @@ static inline void send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
* - Takes into account BRI subunits
* - Returns an XPD pointer if we should transmit, NULL otherwise
*/
-static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, int *pline_count, xpp_line_t *plines)
+static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, size_t *pcm_len, xpp_line_t *plines)
{
bool is_bri;
bool digital_telephony;
int line_count = 0;
xpp_line_t lines;
xpd_t *xpd;
+ unsigned long flags;
+ int i;
xpd = xpd_by_addr(xbus, unit, 0);
if(!xpd || !xpd->card_present)
return NULL;
+ spin_lock_irqsave(&xpd->lock, flags);
is_bri = (xpd->type == XPD_TYPE_BRI_NT) || (xpd->type == XPD_TYPE_BRI_TE);
- digital_telephony = is_bri;
+ digital_telephony = is_bri; /* or PRI */
if(digital_telephony) {
- xpd_t *tmp_xpd;
int subunit;
+ /* without D-Channel */
lines = xpd->offhook & ~xpd->digital_signalling;
- line_count = xpd->channels - 1; /* without D-Channel */
+ for_each_line(xpd, i)
+ if(IS_SET(lines, i))
+ line_count++;
if(is_bri) {
+ /*
+ * BRI has a single PCM highway for all subunits, so
+ * we agregate the next subunits into the same
+ * transmition.
+ */
for(subunit = 1; subunit < MAX_SUBUNIT; subunit++) {
- tmp_xpd = xpd_by_addr(xbus, unit, subunit);
+ xpd_t *tmp_xpd = xpd_by_addr(xbus, unit, subunit);
+ xpp_line_t tmp_lines;
+
if(!tmp_xpd || !tmp_xpd->card_present)
continue;
- lines <<= SUBUNIT_PCM_SHIFT; /* B1, B2, D, E */
- lines |= tmp_xpd->offhook;
- lines &= ~(tmp_xpd->digital_signalling);
- line_count += tmp_xpd->channels - 1; /* Without D-channel */
+ tmp_lines = xpd->offhook & ~xpd->digital_signalling; /* Without D-channel */
+ for_each_line(tmp_xpd, i)
+ if(IS_SET(tmp_lines, i))
+ line_count++;
+ lines = (lines << SUBUNIT_PCM_SHIFT) | tmp_lines; /* B1, B2, D, E */
}
}
} else {
- int i;
-
lines = (xpd->offhook | xpd->cid_on);
- for_each_line(xpd, i) {
+ for_each_line(xpd, i)
if(IS_SET(lines, i))
line_count++;
- }
}
/*
* FIXME: Workaround a bug in sync code of the Astribank.
@@ -213,8 +223,9 @@ static xpd_t *unit_pcm_calc(const xbus_t *xbus, int unit, int *pline_count, xpp_
lines = BIT(0);
line_count = 1;
}
- *pline_count = line_count;
+ *pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE;
*plines = lines;
+ spin_unlock_irqrestore(&xpd->lock, flags);
return xpd;
}
@@ -223,16 +234,15 @@ static void xbus_tick(xbus_t *xbus)
int unit;
int i;
xpp_line_t lines;
- int line_count;
xpd_t *xpd;
xframe_t *xframe = NULL;
xpacket_t *pack = NULL;
+ size_t pcm_len;
for(unit = 0; unit < MAX_UNIT; unit++) {
- if((xpd = unit_pcm_calc(xbus, unit, &line_count, &lines)) == NULL)
+ if((xpd = unit_pcm_calc(xbus, unit, &pcm_len, &lines)) == NULL)
continue;
if(lines && SPAN_REGISTERED(xpd)) {
- int pcm_len = RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * ZT_CHUNKSIZE;
do {
// pack = NULL; /* FORCE single packet frames */
if(xframe && !pack) { /* FULL frame */
@@ -619,7 +629,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
for(j = 0; j < ZT_CHUNKSIZE; j++) {
len += sprintf(page + len, "%02X ", wchunk[j]);
}
- len += sprintf(page + len, " | %d ", xpd->delay_until_dialtone[i]);
+ len += sprintf(page + len, " | ");
}
}
#endif
@@ -778,7 +788,7 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
struct zt_span *span = &xpd->span;
if(!SPAN_REGISTERED(xpd)) {
- NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
+ // NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
return;
}
switch (alarm_flag) {
@@ -798,47 +808,45 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
{
- struct zt_chan *chan;
+ zt_rxsig_t rxsig;
BUG_ON(!xpd);
- if(!SPAN_REGISTERED(xpd))
- return;
- chan = &xpd->chans[pos];
- /*
- * We should not spinlock before calling zt_hooksig() as
- * it may call back into our xpp_hooksig() and cause
- * a nested spinlock scenario
- */
if(to_offhook) {
BIT_SET(xpd->offhook, pos);
- zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
+ rxsig = ZT_RXSIG_OFFHOOK;
} else {
BIT_CLR(xpd->offhook, pos);
BIT_CLR(xpd->cid_on, pos);
- zt_hooksig(chan, ZT_RXSIG_ONHOOK);
+ rxsig = ZT_RXSIG_ONHOOK;
}
+ /*
+ * We should not spinlock before calling zt_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ if(SPAN_REGISTERED(xpd))
+ zt_hooksig(&xpd->chans[pos], rxsig);
}
void update_zap_ring(xpd_t *xpd, int pos, bool on)
{
- struct zt_chan *chan;
+ zt_rxsig_t rxsig;
BUG_ON(!xpd);
- if(!SPAN_REGISTERED(xpd))
- return;
- chan = &xpd->chans[pos];
- /*
- * We should not spinlock before calling zt_hooksig() as
- * it may call back into our xpp_hooksig() and cause
- * a nested spinlock scenario
- */
if(on) {
BIT_CLR(xpd->cid_on, pos);
- zt_hooksig(chan, ZT_RXSIG_RING);
+ rxsig = ZT_RXSIG_RING;
} else {
BIT_SET(xpd->cid_on, pos);
- zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
+ rxsig = ZT_RXSIG_OFFHOOK;
}
+ /*
+ * We should not spinlock before calling zt_hooksig() as
+ * it may call back into our xpp_hooksig() and cause
+ * a nested spinlock scenario
+ */
+ if(SPAN_REGISTERED(xpd))
+ zt_hooksig(&xpd->chans[pos], rxsig);
}
#ifdef CONFIG_PROC_FS
@@ -886,7 +894,7 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
xbus_t *xbus;
xpd_t *xpd;
int ret;
- bool setit;
+ int setit;
// DBG("%s: count=%ld\n", __FUNCTION__, count);
if(count >= MAX_PROC_WRITE)
@@ -958,7 +966,7 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe
{
xpd_t *xpd = data;
char buf[MAX_PROC_WRITE];
- bool zt_reg;
+ int zt_reg;
int ret;
BUG_ON(!xpd);
@@ -1005,7 +1013,7 @@ static int proc_xpd_blink_write(struct file *file, const char __user *buffer, un
{
xpd_t *xpd = data;
char buf[MAX_PROC_WRITE];
- bool blink;
+ int blink;
int ret;
BUG_ON(!xpd);
@@ -1093,13 +1101,6 @@ static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
channels = tmp_xpd->channels;
chans = tmp_xpd->span.chans;
for (i = 0; i < channels; i++) {
- if (tmp_xpd->delay_until_dialtone[i] > 0) {
- tmp_xpd->delay_until_dialtone[i]--;
- if (tmp_xpd->delay_until_dialtone[i] <= 0) {
- tmp_xpd->delay_until_dialtone[i] = 0;
- wake_up_interruptible(&tmp_xpd->txstateq[i]);
- }
- }
if(IS_SET(lines, i)) {
if(SPAN_REGISTERED(tmp_xpd)) {
memcpy((u_char *)pcm, chans[i].writechunk, ZT_CHUNKSIZE);
@@ -1118,7 +1119,7 @@ static void xpp_transmitprep(xpd_t *xpd, xpp_line_t lines, xpacket_t *pack)
void fill_beep(u_char *buf, int num, int duration)
{
- bool alternate = (duration) ? (jiffies/(duration*HZ)) & 0x1 : 0;
+ bool alternate = (duration) ? (jiffies/(duration*1000)) & 0x1 : 0;
int which;
u_char *snd;
@@ -1272,6 +1273,10 @@ static int xpp_shutdown(struct zt_span *span)
return xpd->xops->span_shutdown(xpd);
}
+/*
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
int xpp_open(struct zt_chan *chan)
{
xpd_t *xpd = chan->pvt;
@@ -1420,7 +1425,11 @@ int xpp_maint(struct zt_span *span, int cmd)
return ret;
}
-/* Set signalling type (if appropriate) */
+/*
+ * Set signalling type (if appropriate)
+ * Called from zaptel with spinlock held on chan. Must not call back
+ * zaptel functions.
+ */
static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
{
DBG("channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
@@ -1586,6 +1595,28 @@ static int zaptel_register_xpd(xpd_t *xpd)
}
atomic_inc(&xpd->zt_registered);
xpd->xops->card_zaptel_postregistration(xpd, 1);
+ /*
+ * Update zaptel 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 zaptel call them with a spinlock on the channel
+ * and zt_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.
+ */
+ for_each_line(xpd, cn) {
+ struct zt_chan *chans = xpd->span.chans;
+
+ if(IS_SET(xpd->offhook, cn)) {
+ NOTICE("%s/%s/%d: Report OFFHOOK to zaptel\n",
+ xbus->busname, xpd->xpdname, cn);
+ zt_hooksig(&chans[cn], ZT_RXSIG_OFFHOOK);
+ }
+ }
+#endif
return 0;
}