summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c273
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);