diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-07 20:58:46 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-07 20:58:46 +0000 |
commit | 8953e09799d8995e3667e5766a362d282700af20 (patch) | |
tree | 8ce49c141cdccd5b1398979e809a3bdeeff0e9d8 /xpp/xpp_zap.c | |
parent | 237daca586a95a8f46c5e3326acf9015a004bf1b (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.c | 149 |
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; } |