summaryrefslogtreecommitdiff
path: root/xpp/xpp_zap.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-05-03 23:06:02 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-05-03 23:06:02 +0000
commit2dd60aaf18e98b0e9d3c06bd9dce5f1128fa55ad (patch)
tree1a1cd28888f191e6ce83bcbbe539124e2529c90b /xpp/xpp_zap.c
parent8c4db4e3acd9a7626e709af0494055487b589719 (diff)
xpp driver release 1.1.0 (first part of commit)
* FPGA firmware now loaded from PC (for newer models) * Driver for the FXO module * Moved most userspace files to the subdirectory utils (see also next commit) * Explicit license for firmware files * Optionally avoid auto-registration * Initializations parameters to chips given from userspace * And did I mention bugfixes? git-svn-id: http://svn.digium.com/svn/zaptel/trunk@1021 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r--xpp/xpp_zap.c1508
1 files changed, 399 insertions, 1109 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c
index 8e7937b..52b2846 100644
--- a/xpp/xpp_zap.c
+++ b/xpp/xpp_zap.c
@@ -33,40 +33,34 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
+#include <linux/device.h>
#include <linux/init.h>
#include <linux/delay.h> /* for udelay */
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <zaptel.h>
+#include <version.h> /* For zaptel version */
+#include "xbus-core.h"
#include "xproto.h"
#include "xpp_zap.h"
-static char revision[] = "$Revision$";
+static const char rcsid[] = "$Id$";
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *xpp_procdir = NULL;
+struct proc_dir_entry *xpp_proc_toplevel = NULL;
#define PROC_DIR "xpp"
-#define PROC_XBUSES "xbuses"
#define PROC_SYNC "sync"
-#define PROC_XBUS_SUMMARY "summary"
#define PROC_XPD_ZTREGISTER "zt_registration"
#define PROC_XPD_SUMMARY "summary"
#endif
-#undef WITH_RBS
-//#define WITH_RBS
-
#define XPP_CTL_MAJOR 42
-#define MAX_BUSES 16
#define MAX_QUEUE_LEN 10000
-#define LED_BLINK_PERIOD (HZ/8)
#define SAMPLE_TICKS 10000
+#define DELAY_UNTIL_DIALTONE 3000
-static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
-static xbus_t *xbuses_array[MAX_BUSES] = {};
-static int bus_count = 0;
static struct timer_list xpp_timer;
-xpd_t *sync_master = NULL; // Start with host based sync
+static xpd_t *sync_master = NULL; // Start with host based sync
static unsigned int xpp_timer_count = 0;
static unsigned int xpp_last_jiffies = 0;
struct workqueue_struct *xpp_worker = NULL;
@@ -75,12 +69,11 @@ static LIST_HEAD(xpd_list);
DEF_PARM(int, print_dbg, 0, "Print DBG statements");
DEF_PARM(int, max_queue_len, MAX_QUEUE_LEN, "Maximum Queue Length.");
-DEF_PARM(int, xbus_err_disable_bus, 1000, "Number of errors needed to disable bus");
DEF_PARM(int, ignore_xpds, 0, "a bitmask of xpd numbers to ignore");
-#ifdef SOFT_SIMULATOR
-DEF_PARM(ulong, softloop_xpds, 0, "a bitmask of software xpd numbers");
-#endif
+DEF_PARM(int, xbus_err_disable_bus, 1000, "Number of errors needed to disable bus"); // FIXME: unused now.
DEF_PARM(ulong, pcm_gen, 0, "a bitmask of line numbers for hardware tone generator");
+DEF_PARM(bool, have_sync_bus, 0, "True if all Astribank(TM) devices are connected via a sync-cable");
+DEF_PARM(bool, zap_autoreg, 1, "Register spans automatically (1) or not (0)");
DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd");
@@ -89,189 +82,20 @@ DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd"
static int xpd_zaptel_register(xpd_t *xpd);
static int xpd_zaptel_unregister(xpd_t *xpd);
-static void xbus_remove(xbus_t *xbus);
-static void xpd_blink_leds(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);
static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
-xbus_t *xbus_of(int xbus_num);
-static void xpd_cleanup(xpd_t *xpd);
-static void xpd_card_disable(xpd_t *xpd);
-static void update_xpd_status(xpd_t *xpd, int alarm_flag);
-
-#define SPAN_REGISTERED(xpd) ((xpd)->span.flags & ZT_FLAG_REGISTERED)
-
-/*------------------------- Packet Handling ------------------------*/
-static kmem_cache_t *packet_cache = NULL;
-static atomic_t xpacket_count = ATOMIC_INIT(0);
-
-void card_detected(void *data)
-{
- struct card_desc_struct *card_desc = (struct card_desc_struct *)data;
- xbus_t *xbus;
- xpd_t *xpd;
- int xpd_num;
- byte type;
- byte rev;
- const xops_t *xops;
- const xproto_table_t *proto_table;
-
- BUG_ON(!card_desc);
- BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
- xbus = card_desc->xbus;
- xpd_num = card_desc->xpd_num;
- type = card_desc->type;
- rev = card_desc->rev;
- BUG_ON(!xbus);
- DBG("%s: xpd_num=%d type=%d rev=%d\n", xbus->busname, xpd_num, type, rev);
- xpd = xpd_of(xbus, xpd_num);
- if(xpd) {
- if(type == XPD_TYPE(NOMODULE)) {
- NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
- xpd_card_disable(xpd);
- goto out;
- }
- NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
- goto out;
- }
- if(type == XPD_TYPE(NOMODULE)) {
- DBG("No module at address=%d\n", xpd_num);
- goto out;
- }
- proto_table = get_xproto_table(type);
- if(!proto_table) {
- NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type);
- goto out;
- }
- xops = &proto_table->xops;
- BUG_ON(!xops);
- xpd = xops->card_new(xbus, xpd_num, proto_table, rev);
- if(!xpd) {
- NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
- goto out;
- }
-#if 0
- /*
- * Is it nessessary?
- */
- if(xpd->type == XPD_TYPE_FXO) {
- int i;
-
- for(i = 0; i < xpd->channels; i++) {
- zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
- }
- }
-#endif
-#ifdef CONFIG_PROC_FS
- DBG("Creating xpd proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
- xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
- if(!xpd->proc_xpd_dir) {
- ERR("Failed to create proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
- goto err;
- }
- xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
- xpd_read_proc, xpd);
- if(!xpd->proc_xpd_summary) {
- ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
- goto err;
- }
- xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
- if (!xpd->proc_xpd_ztregister) {
- ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
- goto err;
- }
- xpd->proc_xpd_ztregister->data = xpd;
- xpd->proc_xpd_ztregister->read_proc = proc_xpd_ztregister_read;
- xpd->proc_xpd_ztregister->write_proc = proc_xpd_ztregister_write;
-#endif
- list_add(&xpd->xpd_list, &xpd_list);
- xbus->xpds[xpd->id] = xpd;
- xbus->num_xpds++;
- CALL_XMETHOD(card_init, xbus, xpd);
- // Turn off all channels
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0);
-// CALL_XMETHOD(LED, xbus, xpd, 0xFF, LED_RED, 0); // FIXME: Show activated channels
- // Turn on enabled channels
- CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
- atomic_set(&xpd->card_present, 1);
- xpd_zaptel_register(xpd);
-#if 0
- // FIXME: not yet initialized...
- xpp_check_hookstate(xpd, line_status);
-#endif
-
-out:
- memset(card_desc, 0, sizeof(struct card_desc_struct));
- kfree(card_desc);
- return;
-err:
- xpd_cleanup(xpd);
- goto out;
-}
-
-/**
- * Allocates a new XPP packet.
- * @xbus The XPP bus in which the packet will flow (for counters
- * maintenance)
- * @flags Flags for kernel memory allocation.
- * @returns A pointer to the new packet, or NULL in case of failure.
- *
- *
- * Packet allocation/deallocation:
- * Sent packets:
- * - Allocated by protocol commands
- * - Deallocated by xmus_xmitter
- * Receive packets:
- * - Allocated/deallocated by xbus_xmiter
- */
-xpacket_t *softloop_packet_new(xbus_t *xbus, int flags)
-{
- xpacket_t *pack;
-
- /* To avoid races we increament counter in advance and decrement it later
- * in case of failure */
- atomic_inc(&xbus->packet_counter);
- //DBG("Incremented packet_counter of bus %s (new packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
- pack = kmem_cache_alloc(packet_cache, flags);
- if (pack) {
- memset(pack, 0, sizeof(xpacket_t));
- atomic_inc(&xpacket_count);
- } else {
- atomic_dec(&xbus->packet_counter);
- //DBG("Decremented packet_counter of bus %s (failed new packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
- }
- return pack;
-}
-
-void softloop_packet_free(xbus_t *xbus, xpacket_t *p)
-{
- kmem_cache_free(packet_cache, p);
- atomic_dec(&xpacket_count);
- atomic_dec(&xbus->packet_counter);
- //DBG("Decremented packet_counter of bus %s (freed packet) to %d\n",
- // xbus->busname, atomic_read(&xbus->packet_counter));
-}
-
-int call_proto(xbus_t *xbus, xpacket_t *pack)
-{
- const xproto_entry_t *xe;
- int toxpd = XPD_NUM(pack->content.addr);
- xpd_t *xpd = xpd_of(xbus, toxpd);
-
- xe = find_xproto_entry(xpd, pack->content.opcode);
- return 0;
-}
+static void xpd_free(xpd_t *xpd);
static void external_sync(xpd_t *the_xpd)
{
int i, j;
- DBG("SYNC %s\n", (the_xpd) ? "EXTERNAL" : "HOST");
+ DBG("SYNC %s (%s sync cable)\n", (the_xpd)?"Astribanks":"HOST", (have_sync_bus)?"with":"without");
+ // Shut all down
for(i = 0; i < MAX_BUSES; i++) {
xbus_t *xbus = xbus_of(i);
if(!xbus)
@@ -279,21 +103,26 @@ static void external_sync(xpd_t *the_xpd)
if (!xbus->hardware_exists)
continue;
for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xbus->xpds[j];
- if(xpd)
- CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, (the_xpd != NULL));
+ xpd_t *xpd = xpd_of(xbus, j);
+ if(xpd) {
+ CALL_XMETHOD(SYNC_SOURCE, xbus, xpd, 1, 0);
+ }
}
}
+ if(the_xpd)
+ CALL_XMETHOD(SYNC_SOURCE, the_xpd->xbus, the_xpd, 1, 1);
}
-void set_sync_master(xpd_t *xpd)
+void sync_master_is(xpd_t *xpd)
{
- DBG("SYNC: %s => %s\n",
+ DBG("SYNC MASTER CHANGED: %s => %s\n",
(sync_master) ? sync_master->xpdname : "HOST",
- (xpd) ? xpd->xpdname : "HOST"
- );
+ (xpd) ? xpd->xpdname : "HOST");
sync_master = xpd;
- if(!sync_master) {
+ if(xpd) { // XPD
+ del_timer_sync(&xpp_timer);
+ xpp_tick((unsigned long)xpd);
+ } else { // HOST
external_sync(NULL);
if(!timer_pending(&xpp_timer)) {
xpp_timer.function = xpp_tick;
@@ -301,10 +130,6 @@ void set_sync_master(xpd_t *xpd)
xpp_timer.expires = jiffies + 1; /* Must be 1KHz rate */
add_timer(&xpp_timer);
}
- } else {
- del_timer_sync(&xpp_timer);
- external_sync(xpd);
- xpp_tick((unsigned long)xpd);
}
}
@@ -337,42 +162,45 @@ void xpp_tick(unsigned long param)
continue;
if (!xbus->hardware_exists)
continue;
+ if(!down_read_trylock(&xbus->in_use)) {
+ DBG("Dropped packet. %s is in_use\n", xbus->busname);
+ continue;
+ }
#if 0
if(xbus->open_counter == 0)
continue; // optimize, but zttool loopback won't function
#endif
for(j = 0; j < MAX_XPDS; j++) {
- xpd_t *xpd = xbus->xpds[j];
+ xpd_t *xpd = xpd_of(xbus, j);
if(!xpd)
continue;
- if(!atomic_read(&xpd->card_present))
+ if(!xpd->card_present)
continue;
xpd->timer_count++;
CALL_XMETHOD(card_tick, xbus, xpd);
if(!SPAN_REGISTERED(xpd))
continue;
- xpd_blink_leds(xpd);
if(xpd->direction == TO_PSTN)
xpp_ring_generate(xpd);
xpp_transmitprep(xpd);
xpp_receiveprep(xpd);
}
+ up_read(&xbus->in_use);
}
}
#if HZ != 1000
-#warning This module will not be usable since the kernel HZ setting is not 1000 ticks per second.
+#warning "xpp_timer must be sampled EXACTLY 1000/per second"
#endif
-static void xpd_cleanup(xpd_t *xpd)
+static void xpd_free(xpd_t *xpd)
{
xbus_t *xbus = NULL;
if(!xpd)
return;
xbus = xpd->xbus;
- xpd_card_disable(xpd);
DBG("%s/%s\n", xbus->busname, xpd->xpdname);
#ifdef CONFIG_PROC_FS
if(xpd->proc_xpd_dir) {
@@ -391,109 +219,121 @@ static void xpd_cleanup(xpd_t *xpd)
xpd->proc_xpd_dir = NULL;
}
#endif
+ if(xpd->writechunk)
+ kfree((void *)xpd->writechunk);
+ if(xpd->xproto)
+ xproto_put(xpd->xproto);
+ kfree(xpd);
}
-void init_xbus_packet_queue(packet_queue_t *q, const char name[])
-{
- INIT_LIST_HEAD(&q->head);
- spin_lock_init(&q->lock);
- q->count = 0;
- q->worst_count = 0;
- q->overflows = 0;
- snprintf(q->qname, XPD_NAMELEN, "%s", name);
-}
-#if 0
+/*------------------------- XPD Management -------------------------*/
+
/*
- * Assume the queue is locked
+ * Synchronous part of XPD detection.
+ * Called from xpp_worker workqueue.
*/
-void __dump_packet_queue(const char *msg, packet_queue_t *q)
-{
- xpacket_t *tmp;
-
- list_for_each_entry(tmp, &q->head, list) {
- dump_packet(msg, tmp);
- }
-}
-#endif
-
-void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q)
-{
- unsigned long flags;
- xpacket_t *pack;
- xpacket_t *next;
-
- spin_lock_irqsave(&q->lock, flags);
- DBG("queue=%s count=%d\n", q->qname, q->count);
- DBG(" total packets count=%d\n", atomic_read(&xpacket_count));
- list_for_each_entry_safe(pack, next, &q->head, list) {
- list_del(&pack->list);
- q->count--;
- xbus->ops->packet_free(xbus, pack);
- }
- if(q->count != 0)
- ERR("drain_xbus_packet_queue: queue %s still has %d packets\n",
- q->qname, q->count);
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack)
+void card_detected(void *data)
{
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
+ struct card_desc_struct *card_desc = (struct card_desc_struct *)data;
+ xbus_t *xbus;
+ xpd_t *xpd;
+ int xpd_num;
+ byte type;
+ byte rev;
+ const xops_t *xops;
+ const xproto_table_t *proto_table;
- if(q->count >= max_queue_len) {
- static unsigned long last_notice = 0; // rate limit
- if((jiffies - last_notice) < HZ) {
- NOTICE("xbus_enqueue_packet: dropping packet (queue len = %d, max=%d)\n",
- q->count, max_queue_len);
- last_notice = jiffies;
+ BUG_ON(!card_desc);
+ BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
+ xbus = card_desc->xbus;
+ xpd_num = card_desc->xpd_num;
+ type = card_desc->type;
+ rev = card_desc->rev;
+ BUG_ON(!xbus);
+ DBG("%s: xpd_num=%d type=%d rev=%d\n", xbus->busname, xpd_num, type, rev);
+ xpd = xpd_of(xbus, xpd_num);
+ if(xpd) {
+ if(type == XPD_TYPE_NOMODULE) {
+ NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num);
+ xpd_disconnect(xpd);
+ goto out;
}
- q->overflows++;
- xbus->ops->packet_free(xbus, pack);
+ NOTICE("%s: xpd #%d: already exists\n", __FUNCTION__, xpd_num);
goto out;
}
- list_add_tail(&pack->list, &q->head);
- q->count++;
-
- if(q->count > q->worst_count)
- q->worst_count = q->count;
-
- if(q->count < max_queue_len/100 && q->worst_count > q->count) // Decay worst_count
- q->worst_count--;
-
- // dump_packet("ENQUEUED", pack, print_dbg);
-out:
- spin_unlock_irqrestore(&q->lock, flags);
-}
-
-xpacket_t *xbus_dequeue_packet(packet_queue_t *q)
-{
- unsigned long flags;
- struct list_head *p;
- xpacket_t *pack = NULL;
+ if(type == XPD_TYPE_NOMODULE) {
+ DBG("No module at address=%d\n", xpd_num);
+ goto out;
+ }
+ proto_table = xproto_get(type);
+ if(!proto_table) {
+ NOTICE("%s: xpd #%d: missing protocol table for type=%d. Ignored.\n", __FUNCTION__, xpd_num, type);
+ goto out;
+ }
+ xops = &proto_table->xops;
+ BUG_ON(!xops);
+ xpd = xops->card_new(xbus, xpd_num, proto_table, rev);
+ if(!xpd) {
+ NOTICE("card_new(%s,%d,%d,%d) failed. Ignored.\n", xbus->busname, xpd_num, proto_table->type, rev);
+ goto err;
+ }
- spin_lock_irqsave(&q->lock, flags);
+ /* For USB-1 disable some channels */
+ if(xbus->max_packet_size < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
+ xpp_line_t no_pcm;
- if(list_empty(&q->head)) {
- // DBG("LIST EMPTY (count=%d)\n", q->count);
- goto out;
+ no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
+ xpd->no_pcm = no_pcm & xpd->enabled_chans;
+ NOTICE("%s: max packet size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
+ xbus->busname, xbus->max_packet_size, xpd->no_pcm);
+ }
+#ifdef CONFIG_PROC_FS
+ DBG("Creating xpd proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
+ xpd->proc_xpd_dir = proc_mkdir(xpd->xpdname, xbus->proc_xbus_dir);
+ if(!xpd->proc_xpd_dir) {
+ ERR("Failed to create proc directory for %s/%s\n", xbus->busname, xpd->xpdname);
+ goto err;
+ }
+ xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
+ xpd_read_proc, xpd);
+ if(!xpd->proc_xpd_summary) {
+ ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_SUMMARY, xbus->busname, xpd->xpdname);
+ goto err;
}
- p = q->head.next;
- list_del(p);
- q->count--;
- pack = list_entry(p, xpacket_t, list);
- // dump_packet("DEQUEUED", pack, print_dbg);
+ xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
+ if (!xpd->proc_xpd_ztregister) {
+ ERR("Failed to create proc '%s' for %s/%s\n", PROC_XPD_ZTREGISTER, xbus->busname, xpd->xpdname);
+ goto err;
+ }
+ xpd->proc_xpd_ztregister->data = xpd;
+ xpd->proc_xpd_ztregister->read_proc = proc_xpd_ztregister_read;
+ xpd->proc_xpd_ztregister->write_proc = proc_xpd_ztregister_write;
+#endif
+ if(CALL_XMETHOD(card_init, xbus, xpd) < 0)
+ goto err;
+ list_add(&xpd->xpd_list, &xpd_list);
+ xbus->xpds[xpd->id] = xpd;
+ xbus->num_xpds++;
+ // Turn off all channels
+ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ~0, 0);
+ xpd->card_present = 1;
+ // Turn on enabled channels
+ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
+
+ if(zap_autoreg)
+ xpd_zaptel_register(xpd);
out:
- spin_unlock_irqrestore(&q->lock, flags);
- return pack;
+ memset(card_desc, 0, sizeof(struct card_desc_struct));
+ kfree(card_desc);
+ return;
+err:
+ xpd_free(xpd);
+ goto out;
}
-/*------------------------- XPD Management -------------------------*/
-
#ifdef CONFIG_PROC_FS
/**
@@ -510,83 +350,82 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
int len = 0;
xpd_t *xpd = data;
xbus_t *xbus;
-#if SOFT_SIMULATOR
- struct xpd_sim *sim;
-#endif
- int channels;
int i;
if(!xpd)
goto out;
xbus = xpd->xbus;
-#if SOFT_SIMULATOR
- sim = &xbus->sim[xpd->id];
-#endif
- channels = xpd->channels;
- len += sprintf(page + len, "%s (%s ,card %s, span_registered=%s)%s\n"
+ len += sprintf(page + len, "%s (%s ,card %s, span %s) %s\n"
"timer_count: %d span->mainttimer=%d\n"
,
xpd->xpdname, xproto_name(xpd->type),
- (atomic_read(&xpd->card_present))?"present":"missing",
- (SPAN_REGISTERED(xpd))?"yes":"no",
- (xpd == sync_master) ? " SYNCER" : "",
+ (xpd->card_present) ? "present" : "missing",
+ (SPAN_REGISTERED(xpd)) ? "registered" : "NOT registered",
+ (xpd == sync_master) ? "SYNC MASTER" : "SYNC SLAVE",
xpd->timer_count, xpd->span.mainttimer
);
len += sprintf(page + len, "STATES:");
len += sprintf(page + len, "\n\t%-17s: ", "enabled");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->enabled_chans, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->digital_outputs, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "input_relays");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->digital_inputs, i));
}
len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(xpd->hookstate, i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "ring-state");
- for(i = 0; i < channels; i++) {
- len += sprintf(page + len, "%d ", xpd->lasttxhook[i]);
- }
len += sprintf(page + len, "\n\t%-17s: ", "ringing");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", xpd->ringing[i]);
}
#if 1
if(SPAN_REGISTERED(xpd)) {
- len += sprintf(page + len, "\nreadchunk: ");
- for(i = 0; i < channels; i++) {
+ len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | delay");
+ for_each_line(xpd, i) {
struct zt_chan *chans = xpd->span.chans;
- byte chunk[ZT_CHUNKSIZE];
+ byte rchunk[ZT_CHUNKSIZE];
+ byte wchunk[ZT_CHUNKSIZE];
+ byte *rp;
+ byte *wp;
int j;
- memcpy(chunk, chans[i].readchunk, ZT_CHUNKSIZE);
- len += sprintf(page + len, "\n\tport %2d> ", i);
+ if(IS_SET(xpd->digital_outputs, i))
+ continue;
+ if(IS_SET(xpd->digital_inputs, i))
+ continue;
+#if 1
+ rp = chans[i].readchunk;
+ wp = chans[i].writechunk;
+#else
+ rp = (byte *)xpd->readchunk + (ZT_CHUNKSIZE * i);
+ wp = chans[i].writechunk;
+#endif
+ memcpy(rchunk, rp, ZT_CHUNKSIZE);
+ memcpy(wchunk, wp, ZT_CHUNKSIZE);
+ len += sprintf(page + len, "\n port %2d> | ", i);
for(j = 0; j < ZT_CHUNKSIZE; j++) {
- len += sprintf(page + len, "%02X ", chunk[j]);
+ len += sprintf(page + len, "%02X ", rchunk[j]);
}
- }
- }
-#endif
-#if SOFT_SIMULATOR
- if(sim->simulated) {
- len += sprintf(page + len, "\nSIMULATED (xpd_type=%d, loopto=%d):", sim->xpd_type, sim->loopto);
- len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
- for(i = 0; i < channels; i++) {
- len += sprintf(page + len, "%d ", IS_SET(sim->hookstate, i));
+ len += sprintf(page + len, " | ");
+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
+ len += sprintf(page + len, "%02X ", wchunk[j]);
+ }
+ len += sprintf(page + len, " | %d ", xpd->delay_until_dialtone[i]);
}
}
#endif
#if 0
if(SPAN_REGISTERED(xpd)) {
len += sprintf(page + len, "\nSignalling:\n");
- for(i = 0; i < channels; i++) {
+ for_each_line(xpd, i) {
struct zt_chan *chan = &xpd->span.chans[i];
len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig);
}
@@ -620,7 +459,9 @@ out:
xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_t *proto_table, int channels, byte revision)
{
xpd_t *xpd = NULL;
+ size_t pcm_size;
size_t alloc_size = sizeof(xpd_t) + privsize;
+ int i;
INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
xpd_num, revision / 10, revision % 10, xbus->busname);
@@ -645,14 +486,20 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
xpd->id = xpd_num;
xpd->channels = channels;
xpd->chans = NULL;
- atomic_set(&xpd->card_present, 0);
+ xpd->card_present = 0;
snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%d", xpd_num);
xpd->hookstate = 0x0; /* ONHOOK */
xpd->type = proto_table->type;
+ xpd->xproto = proto_table;
xpd->xops = &proto_table->xops;
xpd->enabled_chans = enabled_channels[xpd_num];
xpd->digital_outputs = 0;
xpd->digital_inputs = 0;
+
+ for_each_line(xpd, i) {
+ xpd->idletxhookstate[i] = FXS_LINE_ENABLED; /* By default, don't send on hook */
+ }
+
atomic_set(&xpd->open_counter, 0);
xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_KERNEL);
@@ -660,33 +507,47 @@ xpd_t *xpd_alloc(size_t privsize, xbus_t *xbus, int xpd_num, const xproto_table_
ERR("%s: Unable to allocate channels\n", __FUNCTION__);
goto err;
}
- /* 8 channels, double buffer, Read/Write */
- int need = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2 * 2;
- if((xpd->writechunk = kmalloc(need, GFP_KERNEL)) == NULL) {
+ pcm_size = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2; /* Double Buffer */
+ alloc_size = pcm_size * 2; /* Read/Write */
+ if((xpd->writechunk = kmalloc(alloc_size, GFP_KERNEL)) == NULL) {
ERR("%s: Unable to allocate memory for writechunks\n", __FUNCTION__);
goto err;
}
/* Initialize Write/Buffers to all blank data */
- memset((void *)xpd->writechunk, 0x00, need);
- xpd->readchunk = xpd->writechunk + ZT_CHUNKSIZE * CHANNELS_PERXPD * 2;
+ memset((void *)xpd->writechunk, 0x00, alloc_size);
+ xpd->readchunk = xpd->writechunk + pcm_size;
return xpd;
err:
- if(xpd->chans)
- kfree((void *)xpd->chans);
- if(xpd->writechunk)
- kfree((void *)xpd->writechunk);
- if(xpd)
+ if(xpd) {
+ if(xpd->chans)
+ kfree((void *)xpd->chans);
+ if(xpd->writechunk)
+ kfree((void *)xpd->writechunk);
kfree(xpd);
+ }
return NULL;
}
-static void xpd_card_disable(xpd_t *xpd)
+void xpd_disconnect(xpd_t *xpd)
{
+ unsigned long flags;
+
BUG_ON(!xpd);
- atomic_set(&xpd->card_present, 0);
+
+ // TODO: elect a new sync master
+ if(sync_master == xpd)
+ sync_master_is(NULL);
+
+ spin_lock_irqsave(&xpd->lock, flags);
+ DBG("%s/%s (%p)\n", xpd->xbus->busname, xpd->xpdname, xpd->xproto);
+ if(!xpd->card_present) /* Multiple reports */
+ goto out;
+ xpd->card_present = 0;
if(SPAN_REGISTERED(xpd))
update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
+out:
+ spin_unlock_irqrestore(&xpd->lock, flags);
}
void xpd_remove(xpd_t *xpd)
@@ -696,22 +557,16 @@ void xpd_remove(xpd_t *xpd)
BUG_ON(!xpd);
xbus = xpd->xbus;
INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
-#if 0
- // TODO: elect a new sync master
- if(sync_master == xpd)
- set_sync_master(NULL);
-#endif
+
xpd_zaptel_unregister(xpd);
xbus->xpds[xpd->id] = NULL;
list_del(&xpd->xpd_list);
xbus->num_xpds--;
CALL_XMETHOD(card_remove, xbus, xpd);
- xpd_cleanup(xpd);
- kfree((void *)xpd->writechunk);
- kfree(xpd);
+ xpd_free(xpd);
}
-static void update_xpd_status(xpd_t *xpd, int alarm_flag)
+void update_xpd_status(xpd_t *xpd, int alarm_flag)
{
struct zt_span *span = &xpd->span;
@@ -734,80 +589,6 @@ static void update_xpd_status(xpd_t *xpd, int alarm_flag)
DBG("Update XPD alarms: %s -> %02X\n", xpd->span.name, alarm_flag);
}
-void phone_hook(xpd_t *xpd, int channo, bool offhook)
-{
- struct zt_chan *chan = &xpd->span.chans[channo];
-
- if(offhook && !IS_SET(xpd->hookstate, channo)) { // OFFHOOK
- DBG("OFFHOOK: channo=%d\n", chan->channo);
- xpd->ringing[channo] = 0;
- BIT_SET(xpd->hookstate, channo);
- zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
- if(!IS_SET(xpd->digital_outputs, channo) && !IS_SET(xpd->digital_inputs, channo)) {
- CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(channo), 0); // Power down (prevent overheating!!!)
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(channo), LED_GREEN, 1);
- }
- } else if(!offhook && IS_SET(xpd->hookstate, channo)) { // ONHOOK
- DBG("ONHOOK channo=%d\n", chan->channo);
- xpd->ringing[channo] = 0;
- BIT_CLR(xpd->hookstate, channo);
- zt_hooksig(chan, ZT_RXSIG_ONHOOK);
- if(!IS_SET(xpd->digital_outputs, channo) && !IS_SET(xpd->digital_inputs, channo)) {
- CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(channo), 0); // Power down (prevent overheating!!!)
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(channo), LED_GREEN, 0);
- }
- }
-}
-
-void xpp_check_hookstate(xpd_t *xpd, xpp_line_t fxs_off_hook)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&xpd->lock, flags);
- if(xpd->direction != TO_PHONE) {
- ERR("%s: %s: Only PHONE can report hookstate changes\n", __FUNCTION__, xpd->xpdname);
- goto out;
- }
- if(!SPAN_REGISTERED(xpd)) {
- NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
- goto out;
- }
- DBG("%s: hookstate=0x%04X fxs_off_hook=0x%04X\n", xpd->xpdname, xpd->hookstate, fxs_off_hook);
- for(i = 0; i < xpd->channels; i++) {
- phone_hook(xpd, i, IS_SET(fxs_off_hook, i));
- }
-out:
- spin_unlock_irqrestore(&xpd->lock, flags);
-}
-
-static void xpd_blink_leds(xpd_t *xpd)
-{
- int i;
- unsigned long flags;
-
- BUG_ON(!xpd);
-
- spin_lock_irqsave(&xpd->lock, flags);
- for(i = 0; i < xpd->channels; i++) {
- if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
- continue;
- if(xpd->ringing[i]) {
- // led state is toggled
- if((xpd->timer_count % LED_BLINK_PERIOD) == 0) {
- DBG("%s pos=%d ringing=%d led_on=%d\n", xpd->xpdname, i, xpd->ringing[i], xpd->led_on[i]);
- if(xpd->ringing[i] && xpd->led_on[i]) {
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 1);
- } else {
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
- }
- xpd->led_on[i] = !xpd->led_on[i];
- }
- }
- }
- spin_unlock_irqrestore(&xpd->lock, flags);
-}
-
static void xpp_ring_generate(xpd_t *xpd)
{
int i;
@@ -829,7 +610,7 @@ static void xpp_ring_generate(xpd_t *xpd)
* Ring detect logic:
* fxo_power is toggled
*/
- for(i = 0; i < xpd->channels; i++) {
+ for_each_enabled_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) {
@@ -839,10 +620,7 @@ static void xpp_ring_generate(xpd_t *xpd)
} else {
zt_hooksig(&xpd->chans[i], ZT_RXSIG_RING);
}
- xpd->ringing[i]--;
xpd->ringer_on[i] = !xpd->ringer_on[i];
- if (xpd->ringing[i] < 0)
- xpd->ringing[i]=0;
}
}
}
@@ -850,98 +628,13 @@ out:
spin_unlock_irqrestore(&xpd->lock, flags);
}
-/*------------------------- Bus Management -------------------------*/
-
-xbus_t *xbus_of(int xbus_num)
-{
- if(xbus_num < 0 || xbus_num >= MAX_BUSES)
- return NULL;
- return xbuses_array[xbus_num];
-}
-
-xpd_t *xpd_of(xbus_t *xbus, int xpd_num)
-{
- if(!VALID_XPD_NUM(xpd_num))
- return NULL;
- return xbus->xpds[xpd_num];
-}
-
-void xbus_reset_counters(xbus_t *xbus)
-{
- int i;
-
- DBG("Reseting counters of %s\n", xbus->busname);
- for(i = 0; i < XBUS_COUNTER_MAX; i++) {
- xbus->counters[i] = 0;
- }
-// xbus->xmit_queue.worst_count = 0;
-// xbus->xmit_queue.overflows = 0;
-}
-
#ifdef CONFIG_PROC_FS
-/**
- * Prints a general procfs entry for the bus, under xpp/BUSNAME/summary
- * @page TODO: figure out procfs
- * @start TODO: figure out procfs
- * @off TODO: figure out procfs
- * @count TODO: figure out procfs
- * @eof TODO: figure out procfs
- * @data an xbus_t pointer with the bus data.
- */
-static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = 0;
- unsigned long flags;
- xbus_t *xbus = data;
- int i;
-
- if(!xbus)
- goto out;
- spin_lock_irqsave(&xbus->lock, flags);
-
- len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
- xbus->busname,
- xbus->busdesc,
- (xbus->hardware_exists) ? "connected" : "missing",
- xbus->bus_type
- );
- len += sprintf(page + len, "open_counter=%d packet_count=%d\n",
- xbus->open_counter,
- atomic_read(&xbus->packet_counter)
- );
-#if SOFT_SIMULATOR
- len += sprintf(page + len, "XPDS SIM\n");
- for(i = 0; i < MAX_XPDS; i++) {
- struct xpd_sim *sim = &xbus->sim[i];
- xpd_t *xpd = xpd_of(xbus, i);
- len += sprintf(page + len, "\t%d> ignored=%d simulated=%d softloop_xpd=%d loopto=%d instanciated=%s\n",
- i, IS_SET(ignore_xpds, i), sim->simulated, sim->softloop_xpd, sim->loopto, (xpd) ? "yes" : "no");
- }
-#endif
- len += sprintf(page + len, "COUNTERS:\n");
- for(i = 0; i < XBUS_COUNTER_MAX; i++) {
- len += sprintf(page + len, "\t%-15s = %d\n",
- xbus_counters[i].name, xbus->counters[i]);
- }
- len += sprintf(page + len, "<-- len=%d\n", len);
- spin_unlock_irqrestore(&xbus->lock, flags);
-out:
- if (len <= off+count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-
-}
-
int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- int len = 0;
+ int len = 0;
+ unsigned int xpp_timer_rate;
+ unsigned int now;
len += sprintf(page + len, "# To modify sync source write into this file:\n");
len += sprintf(page + len, "# HOST - For host based sync\n");
@@ -952,8 +645,8 @@ int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, voi
else
len += sprintf(page + len, "%s/%s\n", sync_master->xbus->busname, sync_master->xpdname);
len += sprintf(page + len, "tick: #%d\n", xpp_timer_count);
- unsigned int xpp_timer_rate = 0;
- unsigned int now = jiffies;
+ xpp_timer_rate = 0;
+ now = jiffies;
if(now - xpp_last_jiffies > 0) {
xpp_timer_rate = ((xpp_timer_count % SAMPLE_TICKS) * 1000) / (now - xpp_last_jiffies);
len += sprintf(page + len, "tick rate: %4d/second (average over %d seconds)\n", xpp_timer_rate, SAMPLE_TICKS/HZ);
@@ -971,7 +664,6 @@ 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)
{
- DBG("%s: count=%ld\n", __FUNCTION__, count);
const int NUM_SIZE = 100;
char buf[NUM_SIZE];
int xbus_num;
@@ -979,31 +671,47 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
xbus_t *xbus;
xpd_t *xpd;
int ret;
+ bool setit;
+ // DBG("%s: count=%ld\n", __FUNCTION__, count);
if(count >= NUM_SIZE)
return -EINVAL;
if(copy_from_user(buf, buffer, count))
return -EFAULT;
buf[count] = '\0';
if(strncmp("HOST", buf, 4) == 0) {
- set_sync_master(NULL);
+ sync_master_is(NULL);
goto out;
}
- ret = sscanf(buf, "%d %d", &xbus_num, &xpd_num);
- if(ret != 2)
+ ret = sscanf(buf, "%d %d %d", &xbus_num, &xpd_num, &setit);
+ if(ret == 2) {
+ // For backward compatibility: before query was introduced,
+ // only two parameters were possible
+ setit = 1;
+ ret = 3;
+ }
+ if(ret != 3 || (setit != 0 && setit != 1)) {
+ ERR("Bad format for SYNC.\n");
+ ERR("Usage: <bus_num> <xpd_num> <0/1> # 0 - QUERY, 1 - SET\n");
return -EINVAL;
- DBG("%s: %d/%d\n", __FUNCTION__, xbus_num, xpd_num);
- if(xbus_num >= MAX_BUSES)
+ }
+ if(xbus_num >= MAX_BUSES) {
+ ERR("Invalid xbus number %d\n", xbus_num);
return -EINVAL;
+ }
xbus = xbus_of(xbus_num);
- if(!xbus)
+ if(!xbus) {
+ ERR("No bus %d exists\n", xbus_num);
return -EINVAL;
+ }
xpd = xpd_of(xbus, xpd_num);
if(!xpd) {
ERR("%s: XPD number %d does not exist\n", __FUNCTION__, xpd_num);
return -ENXIO;
}
- set_sync_master(xpd);
+ DBG("%s: %d/%d %s\n", __FUNCTION__, xbus_num, xpd_num, (setit)?"SET":"QUERY");
+ if(setit)
+ external_sync(xpd);
out:
return count;
}
@@ -1119,279 +827,6 @@ error:
return ret;
}
-static void xbus_poll(xbus_t *xbus, int probe_all)
-{
- int id;
- int ret;
- xpd_t **xpds;
- xpd_t *xpd;
-
- DBG("%s (probe_all=%d)\n", xbus->busname, probe_all);
- xpds = xbus->xpds;
- for(id = 0; id < MAX_XPDS; id++) {
- if(!xbus->hardware_exists)
- break;
- xpd = xpd_of(xbus, id);
- if(!probe_all) {
- if(!xpd) {
- DBG(" Skipping XPD #%d is MISSING\n", id);
- continue;
- }
- if(!atomic_read(&xpd->card_present)) {
- DBG(" Skipping XPD #%d not present\n", id);
- continue;
- }
- if(time_after(xpd->last_response+20, jiffies)) {
- DBG(" SKIP DESC_REQ\n");
- continue;
- }
- }
- if(IS_SET(ignore_xpds, id)) { /* skip xpds */
- DBG(" Ignoring XPD #%d\n", id);
- continue;
- }
- DBG(" Polling slot %d %s\n", id, xbus->busname);
- ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
- if(ret < 0) {
- NOTICE("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
- }
- }
-}
-
-void process_xbus_poll(void *data) {
- xbus_t *xbus = (xbus_t*) data;
-
- ERR("%s: issuing xbus_poll\n", __FUNCTION__);
- xbus_poll(xbus, 1);
-}
-
-
-#if SOFT_SIMULATOR
-/*
- * Assume xbus->lock is held
- */
-static void simulator_setup(xbus_t *xbus, ulong sim_xpds)
-{
- int i;
- int last_fxo = 0;
- bool first = 1;
-
- DBG("%s: sim_xpds=0x%lX\n", xbus->busname, sim_xpds);
- for(i = 0; i < MAX_XPDS; i++) {
- if (!IS_SET(sim_xpds, i) || xbus->sim[i].simulated)
- continue;
- if (first) {
- last_fxo=i;
- } else {
- // setting simulated twice here: in case of odd number of simulated XPDs
- xbus->sim[i].xpd_type = XPD_TYPE_FXO;
- xbus->sim[i].loopto = last_fxo;
- xbus->sim[i].simulated = 1;
- xbus->sim[last_fxo].xpd_type = XPD_TYPE_FXS;
- xbus->sim[last_fxo].loopto = i;
- xbus->sim[last_fxo].simulated = 1;
-
- }
- if(IS_SET(softloop_xpds, i))
- xbus->sim[i].softloop_xpd = 1;
- xbus->sim[i].hookstate = 0;
-
- first = !first;
- }
-}
-#endif
-
-void xbus_activate(xbus_t *xbus)
-{
- xbus_ops_t *ops;
-
- BUG_ON(!xbus);
- ops = xbus->ops;
- BUG_ON(!ops);
- BUG_ON(!xbus->priv);
- /* Sanity checks */
- if(!ops->packet_send) {
- ERR("%s: missing mandatory handler: packet_send=\n", __FUNCTION__);
- return;
- }
- if(!ops->packet_new || !ops->packet_free) {
- ops->packet_new = softloop_packet_new;
- ops->packet_free = softloop_packet_free;
- }
-
- xbus->hardware_exists = 1;
- DBG("Activating: %s\n", xbus->busname);
- /* Poll it */
- xbus_poll(xbus, 1);
-}
-
-void xbus_deactivate(xbus_t *xbus)
-{
- int i;
-
- BUG_ON(!xbus);
- DBG("%s\n", xbus->busname);
- xbus->hardware_exists = 0;
- for(i = 0; i < MAX_XPDS; i++) {
- xpd_t *xpd = xpd_of(xbus, i);
- if(!xpd)
- continue;
- if(xpd->id != i) {
- ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
- continue;
- }
- xpd_card_disable(xpd);
- }
- down_write(&xbus->in_use);
- DBG("%s (deactivated)\n", xbus->busname);
- if(xbus->open_counter == 0) {
- xbus_remove(xbus);
- }
-}
-
-
-static void xbus_cleanup(xbus_t *xbus)
-{
- BUG_ON(!xbus);
-#ifdef CONFIG_PROC_FS
- if(xbus->proc_xbus_dir) {
- if(xbus->proc_xbus_summary) {
- DBG("Removing proc '%s' for %s\n", PROC_XBUS_SUMMARY, xbus->busname);
- remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir);
- xbus->proc_xbus_summary = NULL;
- }
- DBG("Removing proc directory %s\n", xbus->busname);
- remove_proc_entry(xbus->busname, xpp_procdir);
- xbus->proc_xbus_dir = NULL;
- }
-#endif
- kfree(xbus);
-}
-
-xbus_t *xbus_new(ulong loopback_xpds)
-{
- unsigned long flags;
- int xbus_num;
- int err;
- xbus_t *xbus;
-
- xbus = kmalloc(sizeof(xbus_t), GFP_KERNEL);
- if(!xbus)
- return NULL;
- memset(xbus, 0, sizeof(xbus_t));
-
- spin_lock_irqsave(&xbuses_lock, flags);
- for(xbus_num = 0; xbus_num < MAX_BUSES; xbus_num++)
- if(xbuses_array[xbus_num] == NULL)
- break;
- if(xbus_num >= MAX_BUSES) {
- spin_unlock_irqrestore(&xbuses_lock, flags);
- err = -ENOMEM;
- goto nobus;
- }
- /* Found empty slot */
- xbuses_array[xbus_num] = xbus;
- bus_count++;
- spin_unlock_irqrestore(&xbuses_lock, flags);
-
- /* Init data structures */
- spin_lock_init(&xbus->lock);
- snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%d", xbus_num);
- INFO("New xbus: %s\n", xbus->busname);
- init_waitqueue_head(&xbus->packet_cache_empty);
- atomic_set(&xbus->packet_counter, 0);
- init_rwsem(&xbus->in_use);
- xbus->num = xbus_num;
- xbus->num_xpds = 0;
-#if SOFT_SIMULATOR
- xbus->sim_workqueue = create_singlethread_workqueue(xbus->busname);
- if(!xbus->sim_workqueue) {
- ERR("Failed to create workqueue for xbus %s\n", xbus->busname);
- err = -ENOMEM;
- goto nobus;
- }
- init_xbus_packet_queue(&xbus->sim_packet_queue, "SIM_PACKET_QUEUE");
- INIT_WORK(&xbus->sim_work, process_sim_queue, xbus);
- simulator_setup(xbus, loopback_xpds); // Hardware loopback must use simulator
- simulator_setup(xbus, softloop_xpds); // Add the soft loopback to the simulated set
-#endif
- xbus_reset_counters(xbus);
-#ifdef CONFIG_PROC_FS
- DBG("Creating xbus proc directory %s.\n",xbus->busname);
- xbus->proc_xbus_dir = proc_mkdir(xbus->busname, xpp_procdir);
- if(!xbus->proc_xbus_dir) {
- ERR("Failed to create proc directory for xbus %s\n", xbus->busname);
- err = -EIO;
- goto nobus;
- }
- xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
- xbus_read_proc, xbus);
- if (!xbus->proc_xbus_summary) {
- ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_SUMMARY, xbus->busname);
- err = -EIO;
- goto nobus;
- }
-#endif
- return xbus;
-nobus:
- spin_lock_irqsave(&xbuses_lock, flags);
- xbuses_array[xbus_num] = NULL;
- bus_count--;
- spin_unlock_irqrestore(&xbuses_lock, flags);
- xbus_cleanup(xbus);
- return NULL;
-}
-
-static void xbus_remove(xbus_t *xbus)
-{
- int i;
- unsigned long flags;
-
- BUG_ON(!xbus);
- DBG("%s\n", xbus->busname);
- spin_lock_irqsave(&xbuses_lock, flags);
- BUG_ON(xbus != xbus_of(xbus->num));
- xbuses_array[xbus->num] = NULL;
- bus_count--;
- spin_unlock_irqrestore(&xbuses_lock, flags);
-#if SOFT_SIMULATOR
- if(xbus->sim_workqueue) {
- cancel_delayed_work(&xbus->sim_work);
- }
-#endif
- INFO("Removing xbus(%d) %s\n", xbus->num, xbus->busname);
- for(i = 0; i < MAX_XPDS; i++) {
- xpd_t *xpd = xpd_of(xbus, i);
-
- if(xpd) {
- const xops_t *xops = xpd->xops;
-
- if(xpd->id != i) {
- ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
- continue;
- }
- BUG_ON(!xops);
- DBG(" Removing xpd id=%d\n", xpd->id);
- xpd_remove(xpd);
- }
- xbus->xpds[i] = NULL;
- }
-#if SOFT_SIMULATOR
- if(xbus->sim_workqueue) {
- flush_workqueue(xbus->sim_workqueue);
- destroy_workqueue(xbus->sim_workqueue);
- xbus->sim_workqueue = NULL;
- }
- drain_xbus_packet_queue(xbus, &xbus->sim_packet_queue);
-#endif
- int ret = wait_event_interruptible(xbus->packet_cache_empty,
- atomic_read(&xbus->packet_counter) == 0);
- if(ret) {
- ERR("waiting for packet_cache_empty interrupted!!!\n");
- }
- xbus_cleanup(xbus);
-}
-
#define XPP_MAX_LEN 512
@@ -1407,12 +842,12 @@ static void xpp_transmitprep(xpd_t *xpd)
int i;
int channels = xpd->channels;
struct zt_chan *chans = xpd->span.chans;
+ unsigned long flags;
+ spin_lock_irqsave(&xpd->lock, flags);
// if((xpd->timer_count % PREP_REPORT_RATE) < 10)
// DBG("%d\n", xpd->timer_count);
-// if(xpd->hookstate == 0)
-// return;
if (xpd->timer_count & 1) {
/* First part */
w = writechunk = xpd->writechunk /* + 1 */;
@@ -1422,18 +857,26 @@ static void xpp_transmitprep(xpd_t *xpd)
zt_transmit(&xpd->span);
for (i = 0; i < channels; i++) {
+ if (xpd->delay_until_dialtone[i] > 0) {
+ xpd->delay_until_dialtone[i]--;
+ if (xpd->delay_until_dialtone[i] <= 0) {
+ xpd->delay_until_dialtone[i] = 0;
+ wake_up_interruptible(&xpd->txstateq[i]);
+ }
+ }
if(IS_SET(xpd->hookstate, 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 || !sync_master) {
+// if(xpd->hookstate != 0 || sync_master != xpd) {
ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk);
if(ret < 0) {
DBG("failed to write PCM %d\n", ret);
}
- }
+// }
+ spin_unlock_irqrestore(&xpd->lock, flags);
}
void fill_beep(u_char *buf, int duration)
@@ -1446,9 +889,9 @@ void fill_beep(u_char *buf, int duration)
static u_char beep[] = {
// 0x7F, 0xBE, 0xD8, 0xBE, 0x80, 0x41, 0x24, 0x41, /* Dima */
// 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, /* silence */
- 0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10, /* Izzy */
+// 0x67, 0x90, 0x89, 0x90, 0xFF, 0x10, 0x09, 0x10, /* Izzy */
// 0x67, 0xCD, 0xC5, 0xCD, 0xFF, 0x49, 0x41, 0x49, /* Dima 2 */
-// 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, /* silence */
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, /* silence */
};
memcpy(buf, &beep[(which*8) % ARRAY_SIZE(beep)], ZT_CHUNKSIZE);
}
@@ -1459,7 +902,9 @@ static void xpp_receiveprep(xpd_t *xpd)
int i;
int channels = xpd->channels;
struct zt_chan *chans = xpd->span.chans;
+ unsigned long flags;
+ spin_lock_irqsave(&xpd->lock, flags);
// if((xpd->timer_count % PREP_REPORT_RATE) == 0)
// DBG("%d\n", xpd->timer_count);
@@ -1472,6 +917,8 @@ static void xpp_receiveprep(xpd_t *xpd)
for (i = 0; i < channels; i++) {
if(IS_SET(xpd->hookstate, 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);
}
readchunk += ZT_CHUNKSIZE;
@@ -1486,6 +933,7 @@ static void xpp_receiveprep(xpd_t *xpd)
}
#endif
zt_receive(&xpd->span);
+ spin_unlock_irqrestore(&xpd->lock, flags);
}
static int xpp_startup(struct zt_span *span)
@@ -1540,13 +988,18 @@ int xpp_close(struct zt_chan *chan)
spin_lock_irqsave(&xbus->lock, flags);
xbus->open_counter--;
atomic_dec(&xpd->open_counter);
+ if(xpd->direction == TO_PHONE) { /* Hangup phone */
+ xpd->idletxhookstate[chan->chanpos - 1] = FXS_LINE_ENABLED;
+ }
if (!xbus->hardware_exists && xbus->open_counter == 0)
should_remove = 1;
spin_unlock_irqrestore(&xbus->lock, flags);
DBG("chan=%d (open_counter=%d, should_remove=%d)\n", chan->chanpos, xbus->open_counter, should_remove);
- if(should_remove)
+ if(should_remove) {
+ DBG("Going to remove: %s\n", xbus->busname);
xbus_remove(xbus);
+ }
return 0;
}
@@ -1560,10 +1013,11 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
case ZT_ONHOOKTRANSFER:
if (get_user(x, (int *)arg))
return -EFAULT;
- if (xpd->lasttxhook[pos] == 0x1) {
+ xpd->ohttimer[pos] = x << 3;
+ xpd->idletxhookstate[pos] = FXS_LINE_CID; /* OHT mode when idle */
+ if (xpd->lasttxhook[pos] == FXS_LINE_ENABLED) {
/* Apply the change if appropriate */
- xpd->lasttxhook[pos] = 0x2;
- // CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, BIT(pos)); // CALLER ID
+ CALL_XMETHOD(CHAN_CID, xpd->xbus, xpd, BIT(pos)); // CALLER ID
}
DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos);
return -ENOTTY;
@@ -1591,212 +1045,104 @@ static int xpp_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
xbus_t *xbus;
int pos = chan->chanpos - 1;
int ret = 0;
-
- if(!xpd) {
- ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- xbus = xpd->xbus;
- if (txsig == ZT_TXSIG_START) {
- if(xpd->direction == TO_PHONE) {
- // A PHONE line: ZT_START will be treated as ZT_RING
- DBG("Got ZT_START for PHONE channel %d, treated as ZT_RING\n", pos);
- //hookstate = ZT_TXSIG_RING;
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_RING %s digital output ON\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
- return ret;
- }
- xpd->ringing[pos] = RINGS_NUM*2;
- DBG("ZT_RING %s ringing=%d\n", chan->name, xpd->ringing[pos]);
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
- if(ret) {
- DBG("ZT_RING Failed: ret=0x%02X\n", ret);
- return ret;
- }
- return ret;
- } else { /* TO_PSTN */
- // An FXO line: ZT_START will be treated as ZT_OFFHOOK
- DBG("Got ZT_START for FXO channel %d, treated as ZT_OFFHOOK\n", pos);
- txsig = ZT_TXSIG_OFFHOOK;
- }
- }
- switch(txsig) {
- case ZT_TXSIG_START:
- DBG("ZT_TXSIG_START: (doing OFFHOOK) %s (chan->dialing=%d)\n", chan->name, chan->dialing);
- break;
- /* Fall through */
- case ZT_TXSIG_OFFHOOK:
- DBG("ZT_TXSIG_OFFHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
- BIT_SET(xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to OFFHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_TXSIG_OFFHOOK %s digital output OFF\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
- if(ret) {
- DBG("ZT_TXSIG_OFFHOOK Failed: ret=0x%02X\n", ret);
+ DBG("Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig);
+ if(xpd->direction == TO_PSTN) {
+ /* XXX Enable hooksig for FXO XXX */
+ switch(txsig) {
+ case ZT_TXSIG_START:
+ // DBG("%s: ZT_TXSIG_START (drop through.)\n", chan->name);
+ case ZT_TXSIG_OFFHOOK:
+ // DBG("%s: ZT_TXSIG_OFFHOOK\n", chan->name);
+ do_sethook(xpd, pos, 1);
break;
- }
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
- break;
- //DBG("ZT_TXSIG_OFFHOOK %d\n", pos);
- //BIT_SET(xpd->hookstate, pos);
- //break;
- case ZT_TXSIG_KEWL:
- DBG("ZT_TXSIG_KEWL (doing ONHOOK): %d.\n", pos);
- break;
- /* Fall through */
- case ZT_TXSIG_ONHOOK:
- DBG("ZT_TXSIG_ONHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
- xpd->ringing[pos] = 0;
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_TXSIG_ONHOOK %s digital output OFF\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- BIT_CLR(xpd->hookstate, pos);
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
- if(ret) {
- DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
+ case ZT_TXSIG_ONHOOK:
+ // DBG("%s: ZT_TXSIG_ONHOOK\n", chan->name);
+ do_sethook(xpd, pos, 0);
break;
- }
- CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
- break;
- //DBG("ZT_TXSIG_ONHOOK: %d\n", pos);
- //BIT_CLR(xpd->hookstate, pos);
- //break;
- default:
- DBG("hooksig: unkown txsig=%d on channel %d\n", txsig, pos);
- return -EINVAL;
- }
- //ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
- //if(ret) {
- // DBG("ZT_TXSIG_START Failed: ret=0x%02X\n", ret);
- //}
- return ret;
-}
-#endif
-
-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;
-
- if(!xpd) {
- ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos);
- return -EINVAL;
- }
- xbus = xpd->xbus;
- DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
- switch(hookstate) {
- /* On-hook, off-hook: The PBX is playing a phone on an FXO line.
- * Can be ignored for an FXS line
- */
- case ZT_ONHOOK:
- if(IS_SET(xpd->digital_inputs, pos)) {
- NOTICE("%s: Trying to ONHOOK a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
+ default:
+ NOTICE("Can't set tx state to %s (%d)\n", txsig2str(txsig), txsig);
return -EINVAL;
- }
- if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
- return ret;
- }
- if(xpd->direction == TO_PHONE) { /* Stop ring */
- DBG("ZT_ONHOOK: %s hookstate=0x%04X (stop ringing pos=%d)\n", chan->name, xpd->hookstate, pos);
+ }
+ } else { /* TO_PHONE */
+ switch(txsig) {
+ case ZT_TXSIG_ONHOOK:
+ // DBG("%s: ZT_TXSIG_ONHOOK\n", chan->name);
xpd->ringing[pos] = 0;
-#if 1 // FIXME: Not needed -- verify
ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
-#endif
- xpd->lasttxhook[pos] = 1;
- ret = CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
- ret = CALL_XMETHOD(CHAN_POWER, xbus, xpd, BIT(pos), 0); // Power down (prevent overheating!!!)
- if(ret) {
- DBG("ZT_ONHOOK(stop ring) Failed: ret=0x%02X\n", ret);
- break;
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ case ZT_SIG_FXOKS:
+ case ZT_SIG_FXOLS:
+ xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
+ break;
+ case ZT_SIG_FXOGS:
+ xpd->lasttxhook[pos] = FXS_LINE_TIPOPEN;
+ break;
}
- } else {
- DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
+ break;
+ case ZT_TXSIG_OFFHOOK:
+ // DBG("%s: ZT_TXSIG_OFFHOOK\n", chan->name);
xpd->ringing[pos] = 0;
- BIT_CLR(xpd->hookstate, pos);
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
- if(ret) {
- DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
- break;
+ ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+ switch(chan->sig) {
+ case ZT_SIG_EM:
+ xpd->lasttxhook[pos] = FXS_LINE_REV_ACTIVE;
+ break;
+ default:
+ xpd->lasttxhook[pos] = xpd->idletxhookstate[pos];
+ break;
}
- }
- break;
- case ZT_START:
- DBG("ZT_START: %s hookstate=0x%04X (fall through ZT_OFFHOOK)\n", chan->name, xpd->hookstate);
- // Fall through
- case ZT_OFFHOOK:
- if(xpd->direction == TO_PHONE) {
- DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (PHONE)\n", chan->name, xpd->hookstate);
break;
- }
- DBG("ZT_OFFHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos);
- BIT_SET(xpd->hookstate, pos);
- xpd->ringing[pos] = 0;
- ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
- if(ret) {
- DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
- break;
- }
- break;
- case ZT_WINK:
- DBG("ZT_WINK %s\n", chan->name);
- break;
- case ZT_FLASH:
- DBG("ZT_FLASH %s\n", chan->name);
- break;
- case ZT_RING:
- DBG("ZT_RING %s pos=%d (ringing[pos]=%d)\n", chan->name, pos, xpd->ringing[pos]);
- if(xpd->direction == TO_PHONE) {
+ case ZT_TXSIG_START:
+ // DBG("%s: ZT_TXSIG_START\n", chan->name);
+ xpd->lasttxhook[pos] = FXS_LINE_RING;
+ xpd->ringing[pos] = 1;
if(IS_SET(xpd->digital_inputs, pos)) {
NOTICE("%s: Trying to RING a digital input channel %d. Ignoring\n", __FUNCTION__, pos);
return -EINVAL;
}
if(IS_SET(xpd->digital_outputs, pos)) {
- DBG("ZT_ONHOOK %s digital output ON\n", chan->name);
+ DBG("ZT_RING %s digital output ON\n", chan->name);
ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
return ret;
}
- xpd->ringing[pos] = RINGS_NUM*2;
- ret = CALL_XMETHOD(CHAN_POWER, xbus, xpd, BIT(pos), 1); // Power up (for ring)
ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
- if(ret) {
- DBG("ZT_RING Failed: ret=0x%02X\n", ret);
- }
- }
- break;
- case ZT_RINGOFF:
- DBG("ZT_RINGOFF %s\n", chan->name);
- break;
- default:
- DBG("UNKNOWN hookstate=0x%X\n", hookstate);
+ break;
+ case ZT_TXSIG_KEWL:
+ // DBG("%s: ZT_TXSIG_KEWL\n", chan->name);
+ xpd->lasttxhook[pos] = FXS_LINE_DISABLED;
+ break;
+ default:
+ NOTICE("%s: Can't set tx state to %s (%d)\n", __FUNCTION__, txsig2str(txsig), txsig);
+ return -EINVAL;
+ }
}
+ return 0;
+}
+
+#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);
@@ -1815,7 +1161,6 @@ int xpp_maint(struct zt_span *span, int cmd)
switch(cmd) {
case ZT_MAINT_NONE:
printk("XXX Turn off local and remote loops XXX\n");
- CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED
break;
case ZT_MAINT_LOCALLOOP:
printk("XXX Turn on local loopback XXX\n");
@@ -1825,12 +1170,10 @@ int xpp_maint(struct zt_span *span, int cmd)
break;
case ZT_MAINT_LOOPUP:
printk("XXX Send loopup code XXX\n");
- CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 1); // FIXME: Find usage for extra LED
// CALL_XMETHOD(LOOPBACK_AX, xpd->xbus, xpd, loopback_data, ARRAY_SIZE(loopback_data));
break;
case ZT_MAINT_LOOPDOWN:
printk("XXX Send loopdown code XXX\n");
- CALL_XMETHOD(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED
break;
case ZT_MAINT_LOOPSTOP:
printk("XXX Stop sending loop codes XXX\n");
@@ -1848,8 +1191,7 @@ int xpp_maint(struct zt_span *span, int cmd)
/* Set signalling type (if appropriate) */
static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
{
- DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
- dump_sigtype(print_dbg, " ", sigtype);
+ DBG("channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype));
// FIXME: sanity checks:
// - should be supported (within the sigcap)
// - should not replace fxs <->fxo ??? (covered by previous?)
@@ -1906,20 +1248,28 @@ static int xpp_watchdog(struct zt_span *span, int cause)
*/
static int xpd_zaptel_unregister(xpd_t *xpd)
{
+ unsigned long flags;
+
BUG_ON(!xpd);
+ spin_lock_irqsave(&xpd->lock, flags);
if(!SPAN_REGISTERED(xpd)) {
NOTICE("%s: %s is already unregistered\n", __FUNCTION__, xpd->xpdname);
+ spin_unlock_irqrestore(&xpd->lock, flags);
return -EIDRM;
}
if(sync_master == xpd)
- set_sync_master(NULL); // FIXME: it's better to elect a new prince
+ 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));
+ spin_unlock_irqrestore(&xpd->lock, flags);
return -EBUSY;
}
mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish.
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ if(xpd->card_present)
+ xpd->xops->card_zaptel_registration(xpd, 0);
zt_unregister(&xpd->span);
return 0;
}
@@ -1952,33 +1302,20 @@ static int xpd_zaptel_register(xpd_t *xpd)
xbus = xpd->xbus;
snprintf(span->name, MAX_SPANNAME, "%s/%s",
xbus->busname, xpd->xpdname);
- {
- char tmp[MAX_SPANNAME];
-#if SOFT_SIMULATOR
- struct xpd_sim *sim = &xbus->sim[xpd->id];
-
- if(sim->simulated)
- snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
- else
-#endif
- tmp[0] = '\0';
-
- snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s%s",
+ snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: %s",
xbus->num, xpd->id,
- (xpd->direction == TO_PHONE) ? "FXS" : "FXO",
- tmp
+ (xpd->direction == TO_PHONE) ? "FXS" : "FXO"
);
- }
for(i = 0; i < cn; i++) {
cur_chan = &xpd->chans[i];
DBG("setting channel %d (sigfxs=%d)\n", i, sigfxs);
if(IS_SET(xpd->digital_outputs, i)) {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d-%d", xpd->id, i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%d/%d/%d", xbus->num, xpd->id, i);
} else if(IS_SET(xpd->digital_inputs, i)) {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d-%d", xpd->id, i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d/%d/%d", xbus->num, xpd->id, i);
} else {
- snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d-%d", (sigfxs) ? "FXO" : "FXS", xpd->id, i);
+ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d/%d/%d", (sigfxs) ? "FXO" : "FXS", xbus->num, xpd->id, i);
}
cur_chan->chanpos = i + 1;
cur_chan->pvt = xpd;
@@ -2038,52 +1375,14 @@ static int xpd_zaptel_register(xpd_t *xpd)
xbus->num_xpds--;
return -ENODEV;
}
-// if(xpd->id == 0)
-// set_sync_master(xpd);
-
+ xpd->xops->card_zaptel_registration(xpd, 1);
return 0;
}
-
/*------------------------- Proc debugging interface ---------------*/
#ifdef CONFIG_PROC_FS
-static int xpp_zap_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = 0;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&xbuses_lock, flags);
- for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = xbus_of(i);
-
- if(xbus) {
- len += sprintf(page + len, "%s: CONNECTOR=%s STATUS=%s bus_type=%d\n",
- xbus->busname,
- xbus->busdesc,
- (xbus->hardware_exists) ? "connected" : "missing",
- xbus->bus_type
- );
- }
- }
-#if 0
- len += sprintf(page + len, "<-- len=%d\n", len);
-#endif
- spin_unlock_irqrestore(&xbuses_lock, flags);
- if (len <= off+count)
- *eof = 1;
- *start = page + off;
- len -= off;
- if (len > count)
- len = count;
- if (len < 0)
- len = 0;
- return len;
-
-}
-
#if 0
static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
@@ -2097,6 +1396,7 @@ static int xpp_zap_write_proc(struct file *file, const char __user *buffer, unsi
#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;
@@ -2186,6 +1486,7 @@ static struct file_operations xpp_fops = {
.release = xpp_sys_release,
};
+#endif
/*------------------------- Initialization -------------------------*/
@@ -2193,42 +1494,51 @@ static void do_cleanup(void)
{
if(timer_pending(&xpp_timer))
del_timer_sync(&xpp_timer);
- unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry(PROC_SYNC, xpp_procdir);
- remove_proc_entry(PROC_XBUSES, xpp_procdir);
- if(xpp_procdir) {
- remove_proc_entry(PROC_DIR, NULL);
- }
-#endif
if (xpp_worker) {
flush_workqueue(xpp_worker);
destroy_workqueue(xpp_worker);
xpp_worker = NULL;
}
- kmem_cache_destroy(packet_cache);
+#if 0
+ unregister_chrdev(XPP_CTL_MAJOR, THIS_MODULE->name);
+#endif
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry(PROC_SYNC, xpp_proc_toplevel);
+ if(xpp_proc_toplevel) {
+ remove_proc_entry(PROC_DIR, NULL);
+ }
+#endif
}
int __init xpp_zap_init(void)
{
- INFO("%s revision %s\n", THIS_MODULE->name, revision);
+ int ret;
+ struct proc_dir_entry *ent;
+
+ INFO("%s revision %s\n", THIS_MODULE->name, ZAPTEL_VERSION);
+#ifdef WITH_RBS
+ INFO("%s (RBS signalling)\n", THIS_MODULE->name);
+#else
+ INFO("%s (NO RBS signalling)\n", THIS_MODULE->name);
+#endif
+#ifdef HARD_CODED_INIT
+#ifdef OLD_CARD
+ INFO("%s (HARD_CODED_INIT: OLD_CARD)\n", THIS_MODULE->name);
+#else
+ INFO("%s (HARD_CODED_INIT: NEW_CARD)\n", THIS_MODULE->name);
+#endif
+#else
+ INFO("%s (DYNAMIC INIT REGISTERS)\n", THIS_MODULE->name);
+#endif
- packet_cache = kmem_cache_create("xpp_packets",
- sizeof(xpacket_t),
- 0, 0,
- NULL, NULL);
- if(!packet_cache) {
- return -ENOMEM;
- }
#ifdef CONFIG_PROC_FS
- xpp_procdir = proc_mkdir(PROC_DIR, NULL);
- if(!xpp_procdir) {
+ xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL);
+ if(!xpp_proc_toplevel) {
do_cleanup();
return -EIO;
}
- struct proc_dir_entry *ent;
- ent = create_proc_entry(PROC_SYNC, 0644, xpp_procdir);
+ ent = create_proc_entry(PROC_SYNC, 0644, xpp_proc_toplevel);
if(!ent) {
do_cleanup();
return -EFAULT;
@@ -2236,11 +1546,6 @@ int __init xpp_zap_init(void)
ent->read_proc = proc_sync_read;
ent->write_proc = proc_sync_write;
ent->data = NULL;
- ent = create_proc_read_entry(PROC_XBUSES, 0444, xpp_procdir, xpp_zap_read_proc, 0);
- if (!ent) {
- do_cleanup();
- return -EFAULT;
- }
#endif
xpp_worker = create_singlethread_workqueue("xppworker");
if(!xpp_worker) {
@@ -2248,55 +1553,40 @@ int __init xpp_zap_init(void)
do_cleanup();
return -ENOMEM;
}
+ ret = xbus_core_init();
+ if(ret) {
+ ERR("xbus_core_init failed (%d)\n", ret);
+ 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);
- set_sync_master(NULL); /* Internal ticking */
+ sync_master_is(NULL); /* Internal ticking */
return 0;
}
void __exit xpp_zap_cleanup(void)
{
-// unsigned long flags;
- int i;
-
- for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = xbus_of(i);
- if(!xbus)
- continue;
- xbus_remove(xbus);
- }
-// spin_lock_irqsave(&xbuses_lock, flags);
- if(bus_count) {
- ERR("%s: bus_count=%d!\n", __FUNCTION__, bus_count);
- }
-// spin_unlock_irqrestore(&xbuses_lock, flags);
+ xbus_core_shutdown();
do_cleanup();
}
EXPORT_SYMBOL(print_dbg);
EXPORT_SYMBOL(card_detected);
EXPORT_SYMBOL(xpd_alloc);
-EXPORT_SYMBOL(xbus_activate);
-EXPORT_SYMBOL(xbus_deactivate);
-EXPORT_SYMBOL(xpd_of);
-EXPORT_SYMBOL(xbus_new);
-EXPORT_SYMBOL(xbus_remove);
-EXPORT_SYMBOL(xbus_reset_counters);
+EXPORT_SYMBOL(xpd_disconnect);
EXPORT_SYMBOL(packet_send);
+EXPORT_SYMBOL(update_xpd_status);
EXPORT_SYMBOL(fill_beep);
-EXPORT_SYMBOL(xbus_enqueue_packet);
-EXPORT_SYMBOL(xbus_dequeue_packet);
-EXPORT_SYMBOL(init_xbus_packet_queue);
-EXPORT_SYMBOL(drain_xbus_packet_queue);
-EXPORT_SYMBOL(phone_hook);
-EXPORT_SYMBOL(xpp_check_hookstate);
EXPORT_SYMBOL(xpp_tick);
EXPORT_SYMBOL(xpp_open);
EXPORT_SYMBOL(xpp_close);
@@ -2306,7 +1596,7 @@ EXPORT_SYMBOL(xpp_maint);
MODULE_DESCRIPTION("XPP Zaptel Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("$Id$");
+MODULE_VERSION(ZAPTEL_VERSION);
module_init(xpp_zap_init);
module_exit(xpp_zap_cleanup);