diff options
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r-- | xpp/xpp_zap.c | 273 |
1 files changed, 79 insertions, 194 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c index e1d15ed..33ec4c6 100644 --- a/xpp/xpp_zap.c +++ b/xpp/xpp_zap.c @@ -56,7 +56,6 @@ struct proc_dir_entry *xpp_proc_toplevel = NULL; #define PROC_XPD_SUMMARY "summary" #endif -#define XPP_CTL_MAJOR 42 #define MAX_QUEUE_LEN 10000 #define SAMPLE_TICKS 10000 #define DELAY_UNTIL_DIALTONE 3000 @@ -79,7 +78,6 @@ DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)"); static int zaptel_register_xpd(xpd_t *xpd); static int zaptel_unregister_xpd(xpd_t *xpd); -static void xpp_ring_generate(xpd_t *xpd); static void xpp_transmitprep(xpd_t *xpd); static void xpp_receiveprep(xpd_t *xpd); static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -178,8 +176,6 @@ void xpp_tick(unsigned long param) CALL_XMETHOD(card_tick, xbus, xpd); if(!SPAN_REGISTERED(xpd)) continue; - if(xpd->direction == TO_PSTN) - xpp_ring_generate(xpd); xpp_transmitprep(xpd); xpp_receiveprep(xpd); } @@ -402,14 +398,30 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo for_each_line(xpd, i) { len += sprintf(page + len, "%d ", IS_SET(xpd->digital_inputs, i)); } - len += sprintf(page + len, "\n\t%-17s: ", "hookstate"); + len += sprintf(page + len, "\n\t%-17s: ", "offhook"); for_each_line(xpd, i) { - len += sprintf(page + len, "%d ", IS_SET(xpd->hookstate, i)); + len += sprintf(page + len, "%d ", IS_SET(xpd->offhook, i)); + } + len += sprintf(page + len, "\n\t%-17s: ", "cid_on"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%d ", IS_SET(xpd->cid_on, i)); + } + len += sprintf(page + len, "\n\t%-17s: ", "lasttxhook"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%d ", xpd->lasttxhook[i]); + } + len += sprintf(page + len, "\n\t%-17s: ", "idletxhookstate"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%d ", xpd->idletxhookstate[i]); } len += sprintf(page + len, "\n\t%-17s: ", "ringing"); for_each_line(xpd, i) { len += sprintf(page + len, "%d ", xpd->ringing[i]); } + len += sprintf(page + len, "\n\t%-17s: ", "no_pcm"); + for_each_line(xpd, i) { + len += sprintf(page + len, "%d ", IS_SET(xpd->no_pcm, i)); + } #if 1 if(SPAN_REGISTERED(xpd)) { len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | delay"); @@ -430,7 +442,7 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo wp = chans[i].writechunk; #else rp = (byte *)xpd->readchunk + (ZT_CHUNKSIZE * i); - wp = chans[i].writechunk; + wp = (byte *)xpd->writechunk + (ZT_CHUNKSIZE * i); #endif memcpy(rchunk, rp, ZT_CHUNKSIZE); memcpy(wchunk, wp, ZT_CHUNKSIZE); @@ -511,7 +523,7 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_ xpd->chans = NULL; xpd->card_present = 0; snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%d", xpd_num); - xpd->hookstate = 0x0; /* ONHOOK */ + xpd->offhook = 0x0; /* ONHOOK */ xpd->type = proto_table->type; xpd->xproto = proto_table; xpd->xops = &proto_table->xops; @@ -522,6 +534,7 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_ xpd->idletxhookstate[i] = FXS_LINE_ENABLED; /* By default, don't send on hook */ } + atomic_set(&xpd->zt_registered, 0); atomic_set(&xpd->open_counter, 0); xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL); @@ -622,55 +635,49 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag) DBG("Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag); } -void update_line_status(xpd_t *xpd, int pos, bool good) +void update_line_status(xpd_t *xpd, int pos, bool to_offhook) { struct zt_chan *chan; BUG_ON(!xpd); + if(!SPAN_REGISTERED(xpd)) + return; chan = &xpd->chans[pos]; - if(good) + /* + * 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); - else + } else { + BIT_CLR(xpd->offhook, pos); + BIT_CLR(xpd->cid_on, pos); zt_hooksig(chan, ZT_RXSIG_ONHOOK); + } } -static void xpp_ring_generate(xpd_t *xpd) +void update_zap_ring(xpd_t *xpd, int pos, bool on) { - int i; - static int bug_counter = 0; - unsigned long flags; + struct zt_chan *chan; BUG_ON(!xpd); - - spin_lock_irqsave(&xpd->lock, flags); - if(xpd->direction != TO_PSTN && ((bug_counter++ % 1000) == 0)) { - ERR("%s: %s: Only FXO can report ring changes\n", __FUNCTION__, xpd->xpdname); - goto out; - } - if(!SPAN_REGISTERED(xpd)) { - NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname); - goto out; - } + if(!SPAN_REGISTERED(xpd)) + return; + chan = &xpd->chans[pos]; /* - * Ring detect logic: - * fxo_power is toggled + * We should not spinlock before calling zt_hooksig() as + * it may call back into our xpp_hooksig() and cause + * a nested spinlock scenario */ - for_each_line(xpd, i) { - if(xpd->ringing[i] || xpd->ringer_on[i]) { - // ring state is only changed once per second: - if((xpd->timer_count % 1000) == 0) { - DBG("pos=%d ringing=%d ringer_on=%d\n", i, xpd->ringing[i], xpd->ringer_on[i]); - if(xpd->ringer_on[i]) { - zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK); - } else { - zt_hooksig(&xpd->chans[i], ZT_RXSIG_RING); - } - xpd->ringer_on[i] = !xpd->ringer_on[i]; - } - } + if(on) { + BIT_CLR(xpd->cid_on, pos); + zt_hooksig(chan, ZT_RXSIG_RING); + } else { + BIT_SET(xpd->cid_on, pos); + zt_hooksig(chan, ZT_RXSIG_OFFHOOK); } -out: - spin_unlock_irqrestore(&xpd->lock, flags); } #ifdef CONFIG_PROC_FS @@ -709,8 +716,7 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { - const int NUM_SIZE = 100; - char buf[NUM_SIZE]; + char buf[MAX_PROC_WRITE]; int xbus_num; int xpd_num; xbus_t *xbus; @@ -719,7 +725,7 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne bool setit; // DBG("%s: count=%ld\n", __FUNCTION__, count); - if(count >= NUM_SIZE) + if(count >= MAX_PROC_WRITE) return -EINVAL; if(copy_from_user(buf, buffer, count)) return -EFAULT; @@ -786,13 +792,12 @@ int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { xpd_t *xpd = data; - const int NUM_SIZE = 100; - char buf[NUM_SIZE]; + char buf[MAX_PROC_WRITE]; bool zt_reg; int ret; BUG_ON(!xpd); - if(count >= NUM_SIZE) + if(count >= MAX_PROC_WRITE) return -EINVAL; if(copy_from_user(buf, buffer, count)) return -EFAULT; @@ -899,7 +904,13 @@ static void xpp_transmitprep(xpd_t *xpd) } else { w = writechunk = xpd->writechunk + ZT_CHUNKSIZE * CHANNELS_PERXPD /* + 1 */; } + spin_unlock_irqrestore(&xpd->lock, flags); + /* + * This should be out of spinlocks, as it may call back our hook setting + * methods + */ zt_transmit(&xpd->span); + spin_lock_irqsave(&xpd->lock, flags); for (i = 0; i < channels; i++) { if (xpd->delay_until_dialtone[i] > 0) { @@ -909,14 +920,14 @@ static void xpp_transmitprep(xpd_t *xpd) wake_up_interruptible(&xpd->txstateq[i]); } } - if(IS_SET(xpd->hookstate, i) || IS_SET(xpd->cid_on, i)) { + if(IS_SET(xpd->offhook, i) || IS_SET(xpd->cid_on, i)) { memcpy((u_char *)w, chans[i].writechunk, ZT_CHUNKSIZE); // fill_beep((u_char *)w, 5); } w += ZT_CHUNKSIZE; } -// if(xpd->hookstate != 0 || sync_master != xpd) { - ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate | xpd->cid_on, writechunk); +// if(xpd->offhook != 0 || sync_master != xpd) { + ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->offhook | xpd->cid_on, writechunk); if(ret < 0) { DBG("failed to write PCM %d\n", ret); } @@ -985,7 +996,7 @@ static void xpp_receiveprep(xpd_t *xpd) } for (i = 0; i < channels; i++) { - if(IS_SET(xpd->hookstate, i)) { + if(IS_SET(xpd->offhook, i) || IS_SET(xpd->cid_on, i)) { // memset((u_char *)readchunk, 0x5A, ZT_CHUNKSIZE); // DEBUG // fill_beep((u_char *)readchunk, 1); // DEBUG: BEEP memcpy(chans[i].readchunk, (u_char *)readchunk, ZT_CHUNKSIZE); @@ -1007,8 +1018,12 @@ static void xpp_receiveprep(xpd_t *xpd) memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE); } #endif - zt_receive(&xpd->span); spin_unlock_irqrestore(&xpd->lock, flags); + /* + * This should be out of spinlocks, as it may call back our hook setting + * methods + */ + zt_receive(&xpd->span); } static int xpp_startup(struct zt_span *span) @@ -1086,7 +1101,7 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg) switch (cmd) { case ZT_ONHOOKTRANSFER: - if (get_user(x, (int *)arg)) + if (get_user(x, (int __user *)arg)) return -EFAULT; xpd->ohttimer[pos] = x << 3; xpd->idletxhookstate[pos] = FXS_LINE_CID; /* OHT mode when idle */ @@ -1097,7 +1112,7 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg) DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos); return -ENOTTY; case ZT_TONEDETECT: - if (get_user(x, (int *)arg)) + if (get_user(x, (int __user *)arg)) return -EFAULT; DBG("xpd=%d: ZT_TONEDETECT chan=%d: TONEDETECT_ON=%d TONEDETECT_MUTE=%d\n", xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE)); @@ -1120,7 +1135,6 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg) return 0; } -#ifdef WITH_RBS static int xpp_hooksig(struct zt_chan *chan, zt_txsig_t txsig) { xpd_t *xpd = chan->pvt; @@ -1134,24 +1148,6 @@ static int xpp_hooksig(struct zt_chan *chan, zt_txsig_t txsig) return CALL_XMETHOD(card_hooksig, xbus, xpd, pos, txsig); } -#else - -static int xpp_sethook(struct zt_chan *chan, int hookstate) -{ - int pos = chan->chanpos - 1; - xpd_t *xpd = chan->pvt; - xbus_t *xbus; - int ret = 0; - - BUG_ON(!xpd); - xbus = xpd->xbus; - DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate); - ret = CALL_XMETHOD(card_sethook, xpd->xbus, xpd, pos, hookstate); - return ret; -} - -#endif - /* Req: Set the requested chunk size. This is the unit in which you must report results for conferencing, etc */ int xpp_setchunksize(struct zt_span *span, int chunksize); @@ -1286,7 +1282,7 @@ static int zaptel_unregister_xpd(xpd_t *xpd) spin_lock_irqsave(&xpd->lock, flags); if(!SPAN_REGISTERED(xpd)) { - NOTICE("%s: %s is already unregistered\n", __FUNCTION__, xpd->xpdname); + NOTICE("%s/%s is already unregistered\n", xpd->xbus->busname, xpd->xpdname); spin_unlock_irqrestore(&xpd->lock, flags); return -EIDRM; } @@ -1294,7 +1290,7 @@ static int zaptel_unregister_xpd(xpd_t *xpd) sync_master_is(NULL); // FIXME: it's better to elect a new prince update_xpd_status(xpd, ZT_ALARM_NOTOPEN); if(atomic_read(&xpd->open_counter)) { - NOTICE("%s: %s is busy (open_counter=%d). Skipping.\n", __FUNCTION__, xpd->xpdname, atomic_read(&xpd->open_counter)); + NOTICE("%s/%s is busy (open_counter=%d). Skipping.\n", xpd->xbus->busname, xpd->xpdname, atomic_read(&xpd->open_counter)); spin_unlock_irqrestore(&xpd->lock, flags); return -EBUSY; } @@ -1302,6 +1298,7 @@ static int zaptel_unregister_xpd(xpd_t *xpd) spin_unlock_irqrestore(&xpd->lock, flags); if(xpd->card_present) xpd->xops->card_zaptel_preregistration(xpd, 0); + atomic_dec(&xpd->zt_registered); zt_unregister(&xpd->span); if(xpd->card_present) xpd->xops->card_zaptel_postregistration(xpd, 0); @@ -1343,12 +1340,8 @@ static int zaptel_register_xpd(xpd_t *xpd) span->chanconfig = xpp_chanconfig; span->open = xpp_open; span->close = xpp_close; -#ifdef WITH_RBS span->flags = ZT_FLAG_RBS; span->hooksig = xpp_hooksig; /* Only with RBS bits */ -#else - span->sethook = xpp_sethook; -#endif span->ioctl = xpp_ioctl; span->maint = xpp_maint; #ifdef XPP_EC_CHUNK @@ -1365,6 +1358,7 @@ static int zaptel_register_xpd(xpd_t *xpd) ERR("%s/%s: Failed to zt_register span\n", xbus->busname, xpd->xpdname); return -ENODEV; } + atomic_inc(&xpd->zt_registered); xpd->xops->card_zaptel_postregistration(xpd, 1); return 0; } @@ -1381,115 +1375,17 @@ static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsi #endif -/*------------------------- File Operations ------------------------*/ - -#define MINOR_XBUS_NUM(m) ((m) >> 4) -#define MINOR_XPD_NUM(m) ((m) & 0xF); - -#if 0 -static int xpp_sys_open (struct inode * inode, struct file * file) -{ - xbus_t *xbus; - unsigned int minor = iminor(inode); - unsigned int busnum = MINOR_XBUS_NUM(minor); - unsigned long flags; - - spin_lock_irqsave(&xbuses_lock, flags); - xbus = xbus_of(busnum); - spin_unlock_irqrestore(&xbuses_lock, flags); - if(xbus == NULL) - return -ENODEV; - file->private_data = xbus; - DBG("unit %d xbus %s\n", busnum, xbus->busname); - return 0; -} - -static int xpp_sys_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - switch(cmd) { - default: - return -ENOTTY; - } - return 0; -} - -static int xpp_sys_release (struct inode * inode, struct file * file) -{ - unsigned int minor = iminor(inode); - unsigned int busnum = MINOR_XBUS_NUM(minor); - xbus_t *xbus = file->private_data; - DBG("unit %d xbus %s\n", busnum, xbus->busname); - if(xbus == NULL) { - ERR("xpp_sys_release: xbus has dissappeared\n"); - return -EINVAL; - } - return 0; -} - -#if 0 -static ssize_t xpp_sys_write (struct file * file, const char __user * buf, - size_t count, loff_t * ppos) -{ - unsigned int minor = iminor(file->f_dentry->d_inode); - unsigned int busnum = MINOR_XBUS_NUM(minor); - int xpdnum = MINOR_XPD_NUM(minor) - xbus_t *xbus = file->private_data; - xpacket_t *pack_tx; - - DBG("count=%d from %d/%d xbus %s\n", count, busnum, xpdnum, xbus->busname); - if(xbus == NULL) { - ERR("xpp_sys_write: xbus has dissappeared\n"); - return -EINVAL; - } - if(count == 0) - return 0; - if(count >= sizeof(xpacket_raw_t)) { - DBG("count=%d, partial write...\n", count); - count = sizeof(xpacket_raw_t); - } - pack_tx = xbus->ops->packet_new(xbus, GFP_KERNEL); - if (!pack_tx) { - return -ENOMEM; - } - if (copy_from_user (pack_tx->content.raw, buf, count)) { - return -EFAULT; - } - xpd_set_addr(&pack_tx->content.addr, xpdnum); - pack_tx->datalen = count; - // pack_tx->flags |= XPP_PACKET_FIREANDFORGET; - DBG("sending op=%d to %d\n", pack_tx->content.opcode, xpdnum); - xbus_reset_counters(xbus); - pcm_write_enable = 1; - packet_send(xbus, pack_tx); - return count; -} -#endif - -static struct file_operations xpp_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, -#if 0 - .write = xpp_sys_write, -#endif - .ioctl = xpp_sys_ioctl, - .open = xpp_sys_open, - .release = xpp_sys_release, -}; - -#endif - /*------------------------- Initialization -------------------------*/ static void do_cleanup(void) { if(timer_pending(&xpp_timer)) del_timer_sync(&xpp_timer); -#if 0 - unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name); -#endif #ifdef CONFIG_PROC_FS + DBG("Removing '%s' from proc\n", PROC_SYNC); remove_proc_entry(PROC_SYNC, xpp_proc_toplevel); if(xpp_proc_toplevel) { + DBG("Removing '%s' from proc\n", PROC_DIR); remove_proc_entry(PROC_DIR, NULL); xpp_proc_toplevel = NULL; } @@ -1501,12 +1397,8 @@ int __init xpp_zap_init(void) int ret; struct proc_dir_entry *ent; - INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION); -#ifdef WITH_RBS - INFO("FEATURE: %s (RBS signalling)\n", THIS_MODULE->name); -#else - INFO("FEATURE: %s (NO RBS signalling)\n", THIS_MODULE->name); -#endif + INFO("%s revision %s MAX_XPDS=%d\n", THIS_MODULE->name, ZAPTEL_VERSION, + MAX_XPDS); #if WITH_ECHO_SUPPRESSION INFO("FEATURE: %s (with ECHO_SUPPRESSION)\n", THIS_MODULE->name); #else @@ -1540,14 +1432,6 @@ int __init xpp_zap_init(void) do_cleanup(); return ret; } - -#if 0 - if (register_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name, &xpp_fops)) { - printk (KERN_WARNING "%s: unable to get major %d\n", THIS_MODULE->name, XPP_CTL_MAJOR); - do_cleanup(); - return -EIO; - } -#endif /* Only timer init. We add it only *after* zt_register */ init_timer(&xpp_timer); @@ -1567,6 +1451,7 @@ EXPORT_SYMBOL(xpd_alloc); EXPORT_SYMBOL(xpd_disconnect); EXPORT_SYMBOL(packet_send); EXPORT_SYMBOL(update_xpd_status); +EXPORT_SYMBOL(update_zap_ring); EXPORT_SYMBOL(update_line_status); EXPORT_SYMBOL(fill_beep); EXPORT_SYMBOL(xpp_tick); |