diff options
Diffstat (limited to 'xpp/xpp_zap.c')
-rw-r--r-- | xpp/xpp_zap.c | 1649 |
1 files changed, 460 insertions, 1189 deletions
diff --git a/xpp/xpp_zap.c b/xpp/xpp_zap.c index 8e7937b..fc61af0 100644 --- a/xpp/xpp_zap.c +++ b/xpp/xpp_zap.c @@ -33,245 +33,66 @@ #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 "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; - -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(ulong, pcm_gen, 0, "a bitmask of line numbers for hardware tone generator"); - -DEF_ARRAY(ulong, enabled_channels, MAX_XPDS, ~0, "Enabled channels for each xpd"); +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)"); #include "zap_debug.h" +#ifdef XPP_EC_CHUNK +#include "echo_supress/ec_xpp.h" +#endif -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 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); 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 +100,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 +127,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,43 +159,49 @@ 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); + if(!xbus) + return; DBG("%s/%s\n", xbus->busname, xpd->xpdname); + xbus_unregister_xpd(xbus, xpd); #ifdef CONFIG_PROC_FS if(xpd->proc_xpd_dir) { if(xpd->proc_xpd_summary) { @@ -391,109 +219,149 @@ static void xpd_cleanup(xpd_t *xpd) xpd->proc_xpd_dir = NULL; } #endif + if(xpd->writechunk) + kfree((void *)xpd->writechunk); + xpd->writechunk = NULL; + if(xpd->xproto) + xproto_put(xpd->xproto); + xpd->xproto = NULL; + 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 -/* - * Assume the queue is locked - */ -void __dump_packet_queue(const char *msg, packet_queue_t *q) -{ - xpacket_t *tmp; +/*------------------------- XPD Management -------------------------*/ - list_for_each_entry(tmp, &q->head, list) { - dump_packet(msg, tmp); - } -} -#endif +#define REV(x,y) (10 * (x) + (y)) +static byte good_revs[] = { + REV(1,9), + REV(2,0), +}; +#undef REV -void drain_xbus_packet_queue(xbus_t *xbus, packet_queue_t *q) +static bool good_rev(byte rev) { - 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); + int i; + + for(i = 0; i < ARRAY_SIZE(good_revs); i++) { + if(good_revs[i] == rev) + return 1; + } + return 0; } -void xbus_enqueue_packet(xbus_t *xbus, packet_queue_t *q, xpacket_t *pack) +/* + * Synchronous part of XPD detection. + * Called from xbus_poll() + */ +void card_detected(struct card_desc_struct *card_desc) { - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); + xbus_t *xbus; + xpd_t *xpd = NULL; + 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 = xpd_addr2num(&card_desc->xpd_addr); + type = card_desc->type; + rev = card_desc->rev; + BUG_ON(!xbus); + if(!good_rev(rev)) { + NOTICE("%s: New XPD #%d (%d-%d) type=%d has bad firmware revision %d.%d\n", xbus->busname, + xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit, + type, rev / 10, rev % 10); + goto err; + } + INFO("%s: New XPD #%d (%d-%d) type=%d Revision %d.%d\n", xbus->busname, + xpd_num, card_desc->xpd_addr.unit, card_desc->xpd_addr.subunit, + type, rev / 10, rev % 10); + xpd = xpd_of(xbus, xpd_num); + if(xpd) { + if(type == XPD_TYPE_NOMODULE) { + NOTICE("%s: xpd #%d: removed\n", __FUNCTION__, xpd_num); + BUG(); + 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; + } + xpd->addr = card_desc->xpd_addr; - 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; + 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; } - 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_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_summary->owner = THIS_MODULE; + 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->owner = THIS_MODULE; + 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 + xbus_register_xpd(xbus, xpd); + if(CALL_XMETHOD(card_init, xbus, xpd) < 0) + goto err; + // Turn off all channels + CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ~0, 0); + xpd->card_present = 1; + // Turn on all channels + CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, ALL_LINES, 1); + + if(zap_autoreg) + zaptel_register_xpd(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 +378,78 @@ 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++) { - 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,10 +483,11 @@ 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); + DBG("%s: xpd #%d\n", xbus->busname, xpd_num); if(!VALID_XPD_NUM(xpd_num)) { ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num); goto err; @@ -645,14 +509,19 @@ 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 +529,61 @@ 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) +/* FIXME: this should be removed once digium patch their zaptel.h + * I simply wish to avoid changing zaptel.h in the xpp patches. + */ +#ifndef ZT_EVENT_REMOVED +#define ZT_EVENT_REMOVED (20) +#endif + +void xpd_disconnect(xpd_t *xpd) { + unsigned long flags; + BUG_ON(!xpd); - atomic_set(&xpd->card_present, 0); - if(SPAN_REGISTERED(xpd)) + + // 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)) { + int i; + update_xpd_status(xpd, ZT_ALARM_NOTOPEN); + /* TODO: Should this be done before releasing the spinlock? */ + DBG("Queuing ZT_EVENT_REMOVED on all channels to ask user to release them\n"); + for (i=0; i<xpd->span.channels; i++) + zt_qevent_lock(&xpd->chans[i],ZT_EVENT_REMOVED); + } +out: + spin_unlock_irqrestore(&xpd->lock, flags); } void xpd_remove(xpd_t *xpd) @@ -695,23 +592,14 @@ 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--; + INFO("%s: Remove XPD #%d from\n", xbus->busname, xpd->id); + + zaptel_unregister_xpd(xpd); 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,78 +622,16 @@ 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) +void update_line_status(xpd_t *xpd, int pos, bool good) { - struct zt_chan *chan = &xpd->span.chans[channo]; + struct zt_chan *chan; - if(offhook && !IS_SET(xpd->hookstate, channo)) { // OFFHOOK - DBG("OFFHOOK: channo=%d\n", chan->channo); - xpd->ringing[channo] = 0; - BIT_SET(xpd->hookstate, channo); + BUG_ON(!xpd); + chan = &xpd->chans[pos]; + if(good) 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); + else 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) @@ -829,7 +655,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_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 +665,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 +673,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 +690,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 +709,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 +716,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; } @@ -1050,9 +803,9 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe DBG("%s: %s/%s %s\n", __FUNCTION__, xpd->xbus->busname, xpd->xpdname, (zt_reg) ? "register" : "unregister"); if(zt_reg) - ret = xpd_zaptel_register(xpd); + ret = zaptel_register_xpd(xpd); else - ret = xpd_zaptel_unregister(xpd); + ret = zaptel_unregister_xpd(xpd); return (ret < 0) ? ret : count; } @@ -1119,279 +872,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 +887,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 +902,26 @@ static void xpp_transmitprep(xpd_t *xpd) zt_transmit(&xpd->span); for (i = 0; i < channels; i++) { - if(IS_SET(xpd->hookstate, 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) || 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 || !sync_master) { - ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk); +// if(xpd->hookstate != 0 || sync_master != xpd) { + ret = CALL_XMETHOD(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate | xpd->cid_on, 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,20 +934,46 @@ 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); } +#ifdef XPP_EC_CHUNK +/* + * Taken from zaptel.c + */ +static inline void xpp_ec_chunk(struct zt_chan *chan, unsigned char *rxchunk, const unsigned char *txchunk) +{ + short rxlin; + int x; + unsigned long flags; + + /* Perform echo cancellation on a chunk if necessary */ + if (!chan->ec) + return; + spin_lock_irqsave(&chan->lock, flags); + for (x=0;x<ZT_CHUNKSIZE;x++) { + rxlin = ZT_XLAW(rxchunk[x], chan); + rxlin = xpp_echo_can_update(chan->ec, ZT_XLAW(txchunk[x], chan), rxlin); + rxchunk[x] = ZT_LIN2X((int)rxlin, chan); + } + spin_unlock_irqrestore(&chan->lock, flags); +} +#endif + + static void xpp_receiveprep(xpd_t *xpd) { volatile u_char *readchunk; 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,20 +986,29 @@ 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); + } else { + memset(chans[i].readchunk, 0x7F, ZT_CHUNKSIZE); // SILENCE } readchunk += ZT_CHUNKSIZE; } -#if 0 +#if WITH_ECHO_SUPPRESSION /* FIXME: need to Echo cancel double buffered data */ for (i = 0;i < xpd->span.channels; i++) { +#ifdef XPP_EC_CHUNK + xpp_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]); +#else zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]); +#endif memcpy(xpd->ec_chunk2[i], xpd->ec_chunk1[i], ZT_CHUNKSIZE); memcpy(xpd->ec_chunk1[i], chans[i].writechunk, ZT_CHUNKSIZE); } #endif zt_receive(&xpd->span); + spin_unlock_irqrestore(&xpd->lock, flags); } static int xpp_startup(struct zt_span *span) @@ -1540,13 +1063,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 +1088,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, pos); // CALLER ID } DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos); return -ENOTTY; @@ -1574,6 +1103,13 @@ int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg) xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE)); return -ENOTTY; default: + /* Some span-specific commands before we give up: */ + if (xpd->xops->card_ioctl != NULL) { + x = xpd->xops->card_ioctl(xpd, pos, cmd, arg); + if (x != -ENOTTY) + return x; + } + DBG("ENOTTY: chan=%d cmd=0x%x\n", pos, cmd); DBG(" IOC_TYPE=0x%02X\n", _IOC_TYPE(cmd)); DBG(" IOC_DIR=0x%02X\n", _IOC_DIR(cmd)); @@ -1590,109 +1126,15 @@ static int xpp_hooksig(struct zt_chan *chan, zt_txsig_t txsig) xpd_t *xpd = chan->pvt; 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; - 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); - 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); - 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; + BUG_ON(!xpd); + xbus = xpd->xbus; + BUG_ON(!xbus); + DBG("Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig); + return CALL_XMETHOD(card_hooksig, xbus, xpd, pos, txsig); } -#endif + +#else static int xpp_sethook(struct zt_chan *chan, int hookstate) { @@ -1701,102 +1143,15 @@ static int xpp_sethook(struct zt_chan *chan, int hookstate) xbus_t *xbus; int ret = 0; - if(!xpd) { - ERR("%s: channel=%d without an XPD!\n", __FUNCTION__, pos); - return -EINVAL; - } + BUG_ON(!xpd); 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); - 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); - 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; - } - } else { - DBG("ZT_ONHOOK: %s hookstate=0x%04X (pos=%d)\n", chan->name, xpd->hookstate, pos); - 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; - } - } - 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) { - 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); - 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); - } + 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 +1170,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 +1179,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 +1200,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?) @@ -1878,6 +1229,29 @@ int (*hooksig)(struct zt_chan *chan, zt_txsig_t hookstate); int (*sethook)(struct zt_chan *chan, int hookstate); #endif +#ifdef XPP_EC_CHUNK +static int xpp_echocan(struct zt_chan *chan, int len) +{ + if(len == 0) { /* shut down */ + /* zaptel calls this also during channel initialization */ + if(chan->ec) { + xpp_echo_can_free(chan->ec); + } + return 0; + } + if(chan->ec) { + ERR("%s: Trying to override an existing EC (%p)\n", __FUNCTION__, chan->ec); + return -EINVAL; + } + chan->ec = xpp_echo_can_create(len, 0); + if(!chan->ec) { + ERR("%s: Failed creating xpp EC (len=%d)\n", __FUNCTION__, len); + return -EINVAL; + } + return 0; +} +#endif + #ifdef CONFIG_ZAPTEL_WATCHDOG /* * If the watchdog detects no received data, it will call the @@ -1904,33 +1278,40 @@ static int xpp_watchdog(struct zt_span *span, int cause) * - User action through /proc * - During xpd_remove() */ -static int xpd_zaptel_unregister(xpd_t *xpd) +static int zaptel_unregister_xpd(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_preregistration(xpd, 0); zt_unregister(&xpd->span); + if(xpd->card_present) + xpd->xops->card_zaptel_postregistration(xpd, 0); return 0; } -static int xpd_zaptel_register(xpd_t *xpd) +static int zaptel_register_xpd(xpd_t *xpd) { - struct zt_chan *cur_chan; struct zt_span *span; xbus_t *xbus; - int sigfxs; - int i; int cn; const xops_t *xops; @@ -1941,7 +1322,6 @@ static int xpd_zaptel_register(xpd_t *xpd) ERR("xpd %s already registered\n", xpd->xpdname); return -EEXIST; } - sigfxs = ! (xpd->direction == TO_PHONE); /* signaling is opposite */ cn = xpd->channels; DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn); @@ -1950,59 +1330,7 @@ static int xpd_zaptel_register(xpd_t *xpd) span = &xpd->span; 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", - xbus->num, xpd->id, - (xpd->direction == TO_PHONE) ? "FXS" : "FXO", - tmp - ); - } - 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); - } else if(IS_SET(xpd->digital_inputs, i)) { - snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%d-%d", xpd->id, i); - } else { - snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%d-%d", (sigfxs) ? "FXO" : "FXS", xpd->id, i); - } - cur_chan->chanpos = i + 1; - cur_chan->pvt = xpd; - if (sigfxs) - cur_chan->sigcap = -#if 1 - ZT_SIG_FXSKS | - ZT_SIG_FXSLS | -#else - ZT_SIG_SF | -#endif - 0; - else - cur_chan->sigcap = -#if 1 - ZT_SIG_FXOKS | - ZT_SIG_FXOLS | - ZT_SIG_FXOGS | -#else - ZT_SIG_SF | - ZT_SIG_EM | -#endif - 0; - } + snprintf(span->name, MAX_SPANNAME, "%s/%s", xbus->busname, xpd->xpdname); span->deflaw = ZT_LAW_MULAW; init_waitqueue_head(&span->maintq); span->pvt = xpd; @@ -2023,67 +1351,28 @@ static int xpd_zaptel_register(xpd_t *xpd) #endif span->ioctl = xpp_ioctl; span->maint = xpp_maint; +#ifdef XPP_EC_CHUNK + span->echocan = xpp_echocan; +#endif #ifdef CONFIG_ZAPTEL_WATCHDOG span->watchdog = xpp_watchdog; #endif - DBG("Finished span_load: ZT_FLAG_RUNNING=%d\n", span->flags & ZT_FLAG_RUNNING); - DBG("Registering span of %s.\n", xpd->xpdname); + xpd->xops->card_zaptel_preregistration(xpd, 1); if(zt_register(&xpd->span, 1)) { xbus_t *xbus = xpd->xbus; - ERR("Failed to zt_register of span of xpd %s.\n", xpd->xpdname); - xbus->xpds[xpd->id] = NULL; - list_del(&xpd->xpd_list); - xbus->num_xpds--; + ERR("%s/%s: Failed to zt_register span\n", xbus->busname, xpd->xpdname); return -ENODEV; } -// if(xpd->id == 0) -// set_sync_master(xpd); - + xpd->xops->card_zaptel_postregistration(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 +1386,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; @@ -2164,7 +1454,7 @@ static ssize_t xpp_sys_write (struct file * file, const char __user * buf, if (copy_from_user (pack_tx->content.raw, buf, count)) { return -EFAULT; } - XPD_ADDR_SET(pack_tx->content.addr, xpdnum); + 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); @@ -2186,6 +1476,7 @@ static struct file_operations xpp_fops = { .release = xpp_sys_release, }; +#endif /*------------------------- Initialization -------------------------*/ @@ -2193,42 +1484,47 @@ 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 - remove_proc_entry(PROC_SYNC, xpp_procdir); - remove_proc_entry(PROC_XBUSES, xpp_procdir); - if(xpp_procdir) { + remove_proc_entry(PROC_SYNC, xpp_proc_toplevel); + if(xpp_proc_toplevel) { 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); } 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("FEATURE: %s (RBS signalling)\n", THIS_MODULE->name); +#else + INFO("FEATURE: %s (NO RBS signalling)\n", THIS_MODULE->name); +#endif +#if WITH_ECHO_SUPPRESSION + INFO("FEATURE: %s (with ECHO_SUPPRESSION)\n", THIS_MODULE->name); +#else + INFO("FEATURE: %s (without ECHO_SUPPRESSION)\n", THIS_MODULE->name); +#endif +#ifdef XPP_EC_CHUNK + INFO("FEATURE: %s (with XPP_EC_CHUNK)\n", THIS_MODULE->name); +#else + INFO("FEATURE: %s (without XPP_EC_CHUNK)\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,67 +1532,42 @@ 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) { - ERR("Failed to create card detector workqueue.\n"); + ret = xbus_core_init(); + if(ret) { + ERR("xbus_core_init failed (%d)\n", ret); do_cleanup(); - return -ENOMEM; + 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(update_line_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 +1577,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); |