[Pkg-voip-commits] r1127 - in zaptel/trunk/debian: . patches
Tzafrir Cohen
tzafrir-guest at costa.debian.org
Tue Jan 3 21:05:49 UTC 2006
Author: tzafrir-guest
Date: 2006-01-03 21:05:47 +0000 (Tue, 03 Jan 2006)
New Revision: 1127
Modified:
zaptel/trunk/debian/genzaptelconf
zaptel/trunk/debian/genzaptelconf.8
zaptel/trunk/debian/patches/xpp.dpatch
Log:
* genzaptelconf: version 0.41. Bugfixes.
* xpp.dpatch: newer version
Modified: zaptel/trunk/debian/genzaptelconf
===================================================================
--- zaptel/trunk/debian/genzaptelconf 2006-01-03 21:00:14 UTC (rev 1126)
+++ zaptel/trunk/debian/genzaptelconf 2006-01-03 21:05:47 UTC (rev 1127)
@@ -30,7 +30,6 @@
#
# If you have any technical questions, contact
# Tzafrir Cohen <tzafrir.cohen at xorcom.com>
-# $Id:$
#
# The script uses a number of bash-specific features
@@ -38,10 +37,9 @@
# Don't override variables here. Override them in /etc/default/zaptel
# /etc/default/zaptel may override the following variables
-VERSION=0.4.0
+VERSION=0.4.1
+VERSION_FULL="$VERSION $Id: genzaptelconf 84 2006-01-01 18:52:28Z tzafrir $"
lc_country=us
-#method=ls
-#method=ks
base_exten=6000
# If set: no context changes are made in zapata-channels.conf
#context_manual=yes
@@ -191,7 +189,7 @@
usage() {
program=`basename $0`
- echo >&2 "$program: generate zaptel.conf (version $VERSION)"
+ echo >&2 "$program: generate zaptel.conf (version $VERSION_FULL)"
echo >&2 "usage:"
echo >&2 " $program [-sdv] [-m k|l|g] [-c <country_code>] [-r |-e <base_exten>] "
echo >&2 " $program [-sdv] -l"
@@ -201,7 +199,6 @@
echo >&2 "Options:"
echo >&2 " -c CODE: set the country code (default: $lc_country)"
echo >&2 " -e NUM: set the base extension number (default: $base_exten)"
- echo >&2 " -m: set signalling method (gs/ks/ls, default: $method)"
echo >&2 " -l: output a list of detected channels instead of zaptel.conf"
echo >&2 " -d: Perform hardware detection"
echo >&2 " -u: Unload zaptel modules"
@@ -216,6 +213,10 @@
local chan=$1
local sig=$2 #fxs/fxo
local mode=$3
+ local method='ks'
+ if [ "$lc_country" = il ] && [ "$sig" = 'fxs' ]
+ then method=ls
+ fi
case "$mode" in
zaptel) echo "${sig}$method=$chan" ;;
list) echo $chan $sig;;
@@ -275,7 +276,8 @@
then
echo "context=$context_phones"
fi
- else # we have may have set it. So reset it:
+ else # this is an FXO (trunk/phone: FXO signalling)
+ # we have may have set it. So reset it:
echo "callerid=\"\" <0>"
echo "mailbox="
if [ "$group_manual" != "yes" ]
@@ -286,12 +288,20 @@
then
echo "context=$context_lines"
fi
- echo "cidsignalling=v23"
- case $line in
- *WCFXO*) echo "cidstart=history";;
- *) echo "cidstart=polarity";; #a TDM400
- esac
+ if [ "$lc_country" = 'uk' ]
+ then
+ echo "cidsignalling=v23"
+ case $line in
+ *WCFXO*) echo "cidstart=history";;
+ *) echo "cidstart=polarity";; #a TDM400
+ esac
+ fi
echo ";;; line=\"$line\""
+ # if kewlstart is not used, busydetect has to be employed:
+ if [ "$method" = 'ls' ]
+ then echo 'busydetect=yes'
+ else echo 'busydetect=no'
+ fi
fi
echo "channel => $chan"
@@ -681,12 +691,6 @@
u) do_unload=yes ;;
v) verbose=yes ;;
l) mode='list' ;;
- m)
- case "$OPTARG" in
- k|l|g)method=${OPTARG}s ;;
- *) echo >&2 "unknown signalling method ${OPTARG}s, defaulting to \"$method\"";;
- esac
- ;;
M) do_module_list=yes; do_detect=yes ;;
s) force_stop_ast=yes ;;
r)
@@ -711,7 +715,6 @@
# the list was generated from the source of zaptel:
#grep '{.*[0-9]\+,.*"[a-z][a-z]"' zonedata.c | cut -d'"' -f 2 | xargs |tr ' ' '|'
us|au|fr|nl|uk|fi|es|jp|no|at|nz|it|gr|tw|cl|se|be|sg|il|br|hu|lt|pl|za|pt|ee|mx|in|de|ch|dk|cz|cn):;;
- de)lc_country=us;; # used in earlier versions that did not have 'de'
*)
lc_country=us
echo >&2 "unknown country-code $lc_country, defaulting to \"us\""
@@ -722,14 +725,6 @@
loadzone=$lc_country
defaultzone=$loadzone
-# Choose reasonable default for signaling method (by country)
-if [ "" = "$method" ]; then
- case "$lc_country" in
- il) method=ls ;;
- *) method=ks ;;
- esac
-fi
-
# make sure asterisk is not in our way
if [ "$force_stop_ast" = 'yes' ]
then
Modified: zaptel/trunk/debian/genzaptelconf.8
===================================================================
--- zaptel/trunk/debian/genzaptelconf.8 2006-01-03 21:00:14 UTC (rev 1126)
+++ zaptel/trunk/debian/genzaptelconf.8 2006-01-03 21:05:47 UTC (rev 1127)
@@ -5,7 +5,7 @@
.SH SYNOPSIS
.PP
.B genzaptelconf
-[-sdv] [-m k|l] [-c <country_code>] [-r |-e <base_exten>]
+[-sdv] [-c <country_code>] [-r |-e <base_exten>]
.B genzaptelconf
[-sdv] -l -- only list to standard output
@@ -27,7 +27,7 @@
.I PRI
and
.I BRI
-(HFC, with ZapHFC) cards are basically identified as well. However the span
+(HFC, with ZapBRI) cards are basically identified as well. However the span
configiration is a default that I only hope is sane. Looking for feedback
.SH OPTIONS
@@ -93,19 +93,6 @@
option as well.
.RE
-
-.B -m k|l
-.RS
-Sets the signalling mode: Kewlstart or Loopstart. By default the
-signalling mode is ks for any country other than Israel (il), where it is
-ls .
-
-Alternatively set the value of
-.I method
-in
-.I /etc/default/zaptel
-.RE
-
.B -r
.RS
Try to guess a useful
@@ -184,8 +171,58 @@
.I genzaptelconf
and
.I /etc/init.d/zaptel .
+It is sourced by both scripts and can thus be used to override settings
+of variables from those scripts.
+Some of the variables that can be set in /etc/default/zaptel and affect
+genzaptelconf:
+
+.I lc_country
+.RS
+The default country. Can be also overriden by the option -c
.RE
+.I base_exten
+.RS
+The base number used for automatic numbering
+.RE
+
+.I context_manual
+.RS
+If set to 'yes', no context changes are made in zapata-channels.conf
+.RE
+
+.I context_lines
+.RS
+The context into which calls will go from zaptel trunks.
+.RE
+
+.I context_phones
+.RS
+The context into which calls will go from zaptel phones.
+.RE
+
+.I context_manual
+.RS
+If set to 'yes', no group settings are made in zapata-channels.conf
+.RE
+
+.I group_lines
+.RS
+The group number for zaptel trunks.
+.RE
+
+.I group_phones
+.RS
+The group number for zaptel phones.
+.RE
+
+.I ALL_MODULES
+.RS
+modules list. Used for unloading and modules detection. The order of modules
+is the same for both.
+.RE
+.RE
+
.I /etc/modules
.RS
A debian-specific list of kernel modules to be loaded by modprobe at
Modified: zaptel/trunk/debian/patches/xpp.dpatch
===================================================================
--- zaptel/trunk/debian/patches/xpp.dpatch 2006-01-03 21:00:14 UTC (rev 1126)
+++ zaptel/trunk/debian/patches/xpp.dpatch 2006-01-03 21:05:47 UTC (rev 1127)
@@ -2,12 +2,1395 @@
## xpp.dpatch by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
##
## All lines beginning with `## DP:' are a description of the patch.
-## DP: No description.
+## DP: The zaptel drivers for the Xorcom Astribank and friends.
+## DP: Revision 168.
@DPATCH@
-diff -urNad trunk/xpp/FPGA_bulkloop.hex /tmp/dpep.oAj2YR/trunk/xpp/FPGA_bulkloop.hex
---- trunk/xpp/FPGA_bulkloop.hex 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/FPGA_bulkloop.hex 2005-09-22 18:16:26.000000000 +0300
+diff -urNad zaptel-1.0.10/xpp/card_fxs.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.c
+--- zaptel-1.0.10/xpp/card_fxs.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.c 2006-01-03 15:08:38.089954000 +0200
+@@ -0,0 +1,548 @@
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include <linux/module.h>
++#include "xpd.h"
++#include "xproto.h"
++#include "xpp_zap.h"
++#include <linux/delay.h>
++
++static const char rcsid[] = "$Id: card_fxs.c 168 2006-01-03 12:51:06Z oron $";
++
++extern int print_dbg;
++
++/*---------------- FXS Protocol Commands ----------------------------------*/
++static bool fxs_packet_is_valid(xpacket_t *pack);
++static void fxs_packet_dump(xpacket_t *pack);
++
++#define S_(s,l,...) \
++ { \
++ .lines = s, \
++ { \
++ .len = l, \
++ .data = { __VA_ARGS__ }, \
++ } \
++ }
++struct slic_init_data {
++ xpp_line_t lines;
++ slic_data_t slic_data;
++} slic_init_data[] = {
++#include "slic_init.inc"
++};
++#undef S_
++
++/*---------------- FXS: Methods -------------------------------------------*/
++
++static int FXS_card_new(xbus_t *xbus, xpd_t *xpd, byte rev)
++{
++ int channels = min(8, CHANNELS_PERXPD);
++
++ xpd->direction = TO_PHONE;
++ if(xpd->id == 0) {
++ DBG("First XPD detected. Initialize digital outputs\n");
++ channels += 2;
++ xpd->digital_outputs = BIT(8) | BIT(9); // Two extra channels
++ }
++ xpd->channels = channels;
++ return 0;
++}
++
++static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
++{
++ CALL_PROTO(FXS, SLIC_INIT, xbus, xpd);
++ return 0;
++}
++
++static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
++{
++ return 0;
++}
++
++xops_t FXS_xops = {
++ .card_new = FXS_card_new,
++ .card_init = FXS_card_init,
++ .card_remove = FXS_card_remove,
++
++ .RING = XPROTO_CALLER(FXS, RING),
++ .LED = XPROTO_CALLER(FXS, LED),
++ .RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT),
++ .CHAN_ENABLE = XPROTO_CALLER(FXS, CHAN_ENABLE),
++ .CHAN_POWER = XPROTO_CALLER(FXS, CHAN_POWER),
++ .CHAN_CID = XPROTO_CALLER(FXS, CHAN_CID),
++
++ .SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
++ .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
++};
++
++/*---------------- FXS: HOST COMMANDS -------------------------------------*/
++
++/* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_cmd_t *sc;
++ int len;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
++ return 0;
++ }
++ DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, lines, 0x40, (on)?0x01:0x00);
++ pack->datalen = len;
++
++ packet_send(xbus, pack);
++ return ret;
++}
++
++/* 0x0F */ HOSTCMD(FXS, CHAN_POWER, xpp_line_t lines, bool on)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_cmd_t *sc;
++ int len;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
++ return 0;
++ }
++ DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down");
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
++ if(on) {
++ // Power up
++ len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
++ } else {
++ // Power down
++ len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
++ }
++ pack->datalen = len;
++
++ packet_send(xbus, pack);
++ return ret;
++}
++
++/* 0x0F */ HOSTCMD(FXS, CHAN_CID, xpp_line_t lines)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_cmd_t *sc;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
++ return 0;
++ }
++ DBG("Channel CID: 0x%04X\n", lines);
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
++ pack->datalen = slic_cmd_direct_write(sc, lines, 0x40, 0x02);
++ packet_send(xbus, pack);
++ return ret;
++}
++
++
++/* 0x0F */ HOSTCMD(FXS, RING, int pos, bool on)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_cmd_t *sc;
++ xpp_line_t mask = (1 << pos);
++ int len;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ mask &= xpd->enabled_chans; // Ignore disabled channels
++ if(!mask) {
++ return 0;
++ }
++ DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off");
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
++ pack->datalen = len;
++
++ packet_send(xbus, pack);
++ return ret;
++}
++
++/* 0x0F */ HOSTCMD(FXS, SETHOOK, xpp_line_t hook_status)
++{
++ DBG("\n");
++ return 0;
++}
++
++/*
++ * LED control is done via SLIC register 0x06:
++ * 7 6 5 4 3 2 1 0
++ * +-----+-----+-----+-----+-----+-----+-----+-----+
++ * | MR | MG | MB | R | OG | OB | G | B |
++ * +-----+-----+-----+-----+-----+-----+-----+-----+
++ *
++ * B - BLUE LED (0 - OFF, 1 - ON)
++ * G - GREEN LED (0 - OFF, 1 - ON)
++ * OB - Output BLUE (this line is output)
++ * OG - Output GREEN (this line is output)
++ * R - RED LED (0 - OFF, 1 - ON)
++ * MB - Mask BLUE. (1 - B effect the BLUE LED)
++ * MR - Mask RED. (1 - R effect the RED LED)
++ * MG - Mask GREEN. (1 - G effect the GREEN LED)
++ *
++ * The BLUE LED (actually a relay out) is connected to line 0 and 4 only.
++ */
++
++// GREEN RED BLUE
++static const int led_mask[NUM_LEDS] = { BIT(7), BIT(6), BIT(5) };
++static const int led_vals[NUM_LEDS] = { BIT(4), BIT(1), BIT(0) };
++
++/* 0x0F */ HOSTCMD(FXS, LED, xpp_line_t lines, byte which, bool on)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_cmd_t *sc;
++ int len;
++ int value;
++ int i;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
++ return 0;
++ }
++ DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off");
++ which = which % NUM_LEDS;
++ value = BIT(2) | BIT(3);
++ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]);
++ if(on)
++ value |= led_vals[which];
++ for(i = 0; i < CHANNELS_PERXPD; i++) {
++ if(!IS_SET(lines, i))
++ continue;
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, lines, 0x06, value);
++ DBG("LED pack: line=%d value=0x%04X\n", i, value);
++ pack->datalen = len;
++ packet_send(xbus, pack);
++ }
++ return ret;
++}
++
++/* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_cmd_t *sc;
++ int len;
++ int value;
++ xpp_line_t lines;
++ int relay_channels[] = { 0, 4 };
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++
++ DBG("RELAY_OUT: which=%d -- %s\n", which, (on) ? "on" : "off");
++ which = which % ARRAY_SIZE(relay_channels);
++ lines = BIT(relay_channels[which]);
++ value = BIT(2) | BIT(3);
++ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]);
++ if(on)
++ value |= led_vals[LED_BLUE];
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, lines, 0x06, value);
++
++ DBG("RELAY_OUT pack: line=%d value=0x%04X\n", lines, value);
++ pack->datalen = len;
++ packet_send(xbus, pack);
++ return ret;
++}
++
++/* 0x0F */ HOSTCMD(FXS, SLIC_INIT)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ slic_data_t *slic;
++ struct slic_init_data *source;
++ int i;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ DBG("INITIALIZING SLIC\n");
++ for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
++ source = &slic_init_data[i];
++ XPACKET_NEW(pack, xbus, FXS, SLIC_INIT, xpd->id);
++ RPACKET_FIELD(pack, FXS, SLIC_INIT, lines) = source->lines;
++
++ slic = &RPACKET_FIELD(pack, FXS, SLIC_INIT, slic_data);
++ slic->len = source->slic_data.len;
++ memcpy(slic->data, source->slic_data.data, source->slic_data.len);
++ pack->datalen = sizeof(xpp_line_t) + slic->len + 1;
++// dump_packet("SLIC", pack, print_dbg);
++ packet_send(xbus, pack);
++ mdelay(10); // FIXME: check with Dima
++ }
++ return ret;
++}
++
++/* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
++{
++ DBG("\n");
++ return 0;
++}
++
++/*---------------- FXS: Astribank Reply Handlers --------------------------*/
++
++HANDLER_DEF(FXS, SIG_CHANGED)
++{
++ xpp_line_t sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
++
++ if(!xpd) {
++ NOTICE("%s: received %s for non-existing xpd: %d\n",
++ __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
++ return -EPROTO;
++ }
++ if(xpd->direction == TO_PHONE) { /* Hook state changes */
++ DBG("%s (PHONE) sig_status=0x%04X\n", xpd->xpdname, sig_status);
++ xpp_check_hookstate(xpd, sig_status);
++ } else { /* TO_TRUNK - line ring changes */
++ unsigned long flags;
++ int i;
++
++ DBG("%s (TRUNK) sig_status=0x%04X\n", xpd->xpdname, sig_status);
++ spin_lock_irqsave(&xpd->lock, flags);
++ for(i = 0; i < xpd->channels; i++) {
++ if(IS_SET(sig_status, i)) {
++ xpd->ringing[i] = RINGS_NUM*2;
++ zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK);
++ } else {
++ zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK);
++ xpd->ringing[i] = 0;
++ }
++ }
++ spin_unlock_irqrestore(&xpd->lock, flags);
++ }
++ return 0;
++}
++
++HANDLER_DEF(FXS, SLIC_REPLY)
++{
++ slic_reply_t *info = &RPACKET_FIELD(pack, FXS, SLIC_REPLY, info);
++ unsigned long flags;
++
++ if(!xpd) {
++ NOTICE("%s: received %s for non-existing xpd: %d\n",
++ __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr));
++ return -EPROTO;
++ }
++ spin_lock_irqsave(&xpd->lock, flags);
++ DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
++ xpd->id, (info->indirect)?"I":"D",
++ info->reg_num, info->data_low, info->data_high);
++ spin_unlock_irqrestore(&xpd->lock, flags);
++ return 0;
++}
++
++
++xproto_table_t PROTO_TABLE(FXS) = {
++ .entries = {
++ /* Card Opcode */
++ XENTRY( FXS, SIG_CHANGED ),
++ XENTRY( FXS, SLIC_REPLY ),
++ },
++ .name = "FXS",
++ .packet_is_valid = fxs_packet_is_valid,
++ .packet_dump = fxs_packet_dump,
++};
++
++static bool fxs_packet_is_valid(xpacket_t *pack)
++{
++ const xproto_entry_t *xe;
++
++ DBG("\n");
++ xe = xproto_card_entry(&PROTO_TABLE(FXS), pack->content.opcode);
++ return xe != NULL;
++}
++
++static void fxs_packet_dump(xpacket_t *pack)
++{
++ DBG("\n");
++}
++
++/*------------------------- SLIC Handling --------------------------*/
++
++int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++ int len = 0;
++ unsigned long flags;
++ xpd_t *xpd = data;
++ //slic_reply_t *info;
++
++ BUG_ON(!xpd);
++ spin_lock_irqsave(&xpd->lock, flags);
++#if 0
++ info = (slic_reply_t *)&xpd->slic_info;
++ len += sprintf(page + len, "SLIC_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n",
++ (info->indirect)?"I":"D",
++ info->reg_num, info->data_high, info->data_low);
++#endif
++ spin_unlock_irqrestore(&xpd->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;
++}
++
++/*
++ * Direct/Indirect
++ * v
++ * FF FF FF FF WD 06 1
++ * ^---------^ ^ Reg
++ * | Write/Read
++ * |
++ * SLIC #
++ */
++static int parse_slic_cmd(const char *buf, slic_cmd_t *sc)
++{
++ char op; /* [W]rite, [R]ead */
++ char reg_type; /* [D]irect, [I]ndirect */
++ int s1, s2, s3, s4;
++ int reg_num;
++ int data_low, data_high;
++ xpp_line_t lines;
++ int ret;
++
++ ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x",
++ &s1, &s2, &s3, &s4, &op, ®_type, ®_num, &data_high, &data_low);
++ lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1);
++ switch(op) {
++ case 'R':
++ if(reg_type == 'D' && ret == 7) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
++ ret = slic_cmd_direct_read(sc, lines, reg_num);
++ } else if(reg_type == 'I' && ret == 7) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
++ ret = slic_cmd_indirect_read(sc, lines, reg_num);
++ } else {
++ NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
++ goto err;
++ }
++ break;
++ case 'W':
++ if(reg_type == 'D' && ret == 8) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high);
++ ret = slic_cmd_direct_write(sc, lines, reg_num, data_high);
++ } else if(reg_type == 'I' && ret == 9) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low);
++ ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high);
++ } else {
++ NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
++ goto err;
++ }
++ break;
++ default:
++ NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op);
++ goto err;
++ }
++ return ret;
++err:
++ return -EINVAL;
++}
++
++static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
++{
++ xbus_t *xbus;
++ slic_cmd_t sc;
++ xpacket_t *pack;
++ char *p;
++ int len = strlen(cmdline);
++
++ BUG_ON(!xpd);
++ xbus = xpd->xbus;
++ if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */
++ *p = '\0';
++ if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */
++ *p = '\0';
++ for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */
++ ;
++ if(*p == '\0')
++ return 0;
++ len = parse_slic_cmd(p, &sc);
++ if(len < 0)
++ return len;
++ sc.lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!sc.lines) {
++ NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__);
++ return 0;
++ }
++ dump_slic_cmd("WRITE_SLIC", &sc);
++ XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
++ RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd) = sc;
++ pack->datalen = len;
++ packet_send(xbus, pack);
++ return 0;
++}
++
++int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
++{
++ xpd_t *xpd = data;
++ const int LINE_LEN = 500;
++ char buf[LINE_LEN];
++ char *p;
++ int i;
++ int ret;
++
++ BUG_ON(!xpd);
++ for(i = 0; i < count; /* noop */) {
++ for(p = buf; p < buf + LINE_LEN; p++) { /* read a line */
++ if(i >= count)
++ break;
++ if(get_user(*p, buffer + i))
++ return -EFAULT;
++ i++;
++ if(*p == '\n' || *p == '\r') /* whatever */
++ break;
++ }
++ if(p >= buf + LINE_LEN)
++ return -E2BIG;
++ *p = '\0';
++ ret = process_slic_cmdline(xpd, buf);
++ if(ret < 0)
++ return ret;
++ }
++ return count;
++}
++
++
+diff -urNad zaptel-1.0.10/xpp/card_fxs.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.h
+--- zaptel-1.0.10/xpp/card_fxs.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_fxs.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,67 @@
++#ifndef CARD_FXS_H
++#define CARD_FXS_H
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include "xpd.h"
++#include "slic.h"
++#include "xproto.h"
++
++DEF_RPACKET_DATA(FXS, SIG_CHANGED,
++ byte type; /* unused -- we have it from DEV_DESC */
++ xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
++ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */
++ );
++DEF_RPACKET_DATA(FXS, SLIC_REPLY, /* Get status of a single SLIC (for debugging) */
++ xpp_line_t lines;
++ slic_reply_t info;
++ );
++DEF_RPACKET_DATA(FXS, SLIC_INIT,
++ xpp_line_t lines;
++ slic_data_t slic_data;
++ );
++DEF_RPACKET_DATA(FXS, SLIC_WRITE,
++ slic_cmd_t slic_cmd;
++ );
++
++#ifdef __KERNEL__
++
++#include <linux/fs.h>
++
++/* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
++/* 0x0F */ DECLARE_CMD(FXS, CHAN_POWER, xpp_line_t lines, bool on);
++/* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, xpp_line_t lines);
++/* 0x0F */ DECLARE_CMD(FXS, RING, int pos, bool on);
++/* 0x0F */ DECLARE_CMD(FXS, SETHOOK, xpp_line_t hook_status);
++/* 0x0F */ DECLARE_CMD(FXS, LED, xpp_line_t lines, byte which, bool on);
++/* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
++/* 0x0F */ DECLARE_CMD(FXS, SLIC_INIT);
++/* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
++
++extern xproto_table_t PROTO_TABLE(FXS);
++extern xops_t FXS_xops;
++int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
++int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
++
++#endif
++
++#endif /* CARD_FXS_H */
+diff -urNad zaptel-1.0.10/xpp/card_global.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.c
+--- zaptel-1.0.10/xpp/card_global.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.c 2006-01-03 15:08:38.089954000 +0200
+@@ -0,0 +1,270 @@
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include "xdefs.h"
++#include "xpd.h"
++#include "xpp_zap.h"
++#include "xproto.h"
++#include <linux/module.h>
++
++static const char rcsid[] = "$Id: card_global.c 165 2006-01-03 12:36:57Z oron $";
++
++extern int print_dbg;
++static bool pcm_valid(xpd_t *xpd, xpacket_t *pack);
++
++/*---------------- GLOBAL Protocol Commands -------------------------------*/
++
++static bool global_packet_is_valid(xpacket_t *pack);
++static void global_packet_dump(xpacket_t *pack);
++
++/*---------------- GLOBAL: HOST COMMANDS ----------------------------------*/
++
++/* 0x04 */ HOSTCMD(GLOBAL, DESC_REQ, int xpd_num)
++{
++ int ret = 0;
++ xpacket_t *pack;
++
++ if(!xbus) {
++ DBG("NO XBUS\n");
++ return -EINVAL;
++ }
++ XPACKET_NEW(pack, xbus, GLOBAL, DESC_REQ, xpd_num);
++ DBG("on %s #%d\n", xbus->busname, xpd_num);
++ ret = packet_send(xbus, pack);
++ XBUS_COUNTER(xbus, DESC_REQ)++;
++ return ret;
++}
++
++/* 0x11 */ HOSTCMD(GLOBAL, PCM_WRITE, xpp_line_t lines, volatile byte *buf)
++{
++ int ret = 0;
++ xpacket_t *pack;
++ byte *pcm;
++ byte *start_pcm;
++ int i;
++ extern ulong pcm_gen;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ lines &= xpd->enabled_chans;
++ if(pcm_gen != 0)
++ return 0;
++// if(lines == 0)
++// return 0;
++
++ /*
++ * FIXME: Workaround a bug in sync code of the Astribank.
++ * Send dummy PCM for sync.
++ */
++ if(lines == 0)
++ lines = BIT(0);
++
++ XPACKET_NEW(pack, xbus, GLOBAL, PCM_WRITE, xpd->id);
++ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
++ start_pcm = pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
++ for(i = 0; i < CHANNELS_PERXPD; i++) {
++ if(IS_SET(lines, i)) {
++ memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE);
++ pcm += ZT_CHUNKSIZE;
++ }
++ buf += ZT_CHUNKSIZE;
++ }
++ pack->datalen = sizeof(xpp_line_t) + (pcm - start_pcm);
++ packet_send(xbus, pack);
++ XPD_COUNTER(xpd, PCM_WRITE)++;
++ XBUS_COUNTER(xbus, PCM_WRITE)++;
++ return ret;
++}
++
++/* 0x19 */ HOSTCMD(GLOBAL, SYNC_SOURCE, bool setit, bool is_master)
++{
++ xpacket_t *pack;
++ byte mask = 0;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ if(is_master)
++ mask |= BIT(0);
++ if(!setit)
++ mask |= BIT(1);
++ DBG("SYNC_SOURCE %s setit=%s is_master=%s (mask=0x%X)\n",
++ xpd->xpdname, (setit)?"yes":"no", (is_master)?"yes":"no", mask);
++ XPACKET_NEW(pack, xbus, GLOBAL, SYNC_SOURCE, xpd->id);
++ RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, mask) = mask;
++ packet_send(xbus, pack);
++ return 0;
++}
++
++xops_t GLOBAL_xops = {
++ .DESC_REQ = XPROTO_CALLER(GLOBAL, DESC_REQ),
++ .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE),
++ .SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
++};
++
++/*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
++
++HANDLER_DEF(GLOBAL, DEV_DESC)
++{
++ byte rev = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, rev);
++ byte type = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, type);
++ xpp_line_t line_status = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, line_status);
++ int xpd_num = XPD_NUM(pack->content.addr);
++ xops_t *xops;
++
++ DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n",
++ xpd_num, type, rev, line_status);
++ if(xpd) {
++ if(type == XPD_TYPE(NOMODULE)) {
++ NOTICE("DEV_DESC: xpd #%d: removed\n", xpd_num);
++ xpd_remove(xpd);
++ return 0;
++ }
++ NOTICE("DEV_DESC: xpd #%d: already exists\n", xpd_num);
++ return 0;
++ }
++ if(type == XPD_TYPE_NOMODULE) {
++ DBG("No module at address=%d\n", xpd_num);
++ return 0;
++ }
++ xops = get_xops(type);
++ if(!xops) {
++ NOTICE("DEV_DESC: xpd #%d: missing xops for type=%d\n", xpd_num, type);
++ return -EINVAL;
++ }
++ xpd = xpd_new(xbus, xpd_num, type, rev);
++ if(!xpd) {
++ NOTICE("xpd_new failed\n");
++ return -EINVAL;
++ }
++ xpp_check_hookstate(xpd, line_status);
++ return 0;
++}
++
++HANDLER_DEF(GLOBAL, PCM_READ)
++{
++ /* FIXME: work around temporary hardware bug */
++ xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
++ const byte *pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
++ volatile u_char *readchunk;
++ volatile u_char *r;
++ unsigned long flags;
++ int i;
++
++ if(!xpd) {
++#if 0
++ int xpd_num = XPD_NUM(pack->content.addr);
++ NOTICE("%s: received %s for non-existing xpd: %d\n",
++ __FUNCTION__, cmd->name, xpd_num);
++#endif
++ return -EPROTO;
++ }
++ // DBG("lines=0x%04X\n", lines);
++
++ if(!pcm_valid(xpd, pack)) {
++ return -EPROTO;
++ }
++ spin_lock_irqsave(&xpd->lock, flags);
++ if (xpd->timer_count & 1) {
++ /* First part */
++ r = readchunk = xpd->readchunk;
++ } else {
++ r = readchunk = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD;
++ }
++
++ /* Copy PCM and put each channel in its index */
++ for (i = 0; i < CHANNELS_PERXPD; i++) {
++ if(IS_SET(lines, i)) {
++ memcpy((u_char *)r, pcm, ZT_CHUNKSIZE);
++ //memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG
++ pcm += ZT_CHUNKSIZE;
++ }
++ r += ZT_CHUNKSIZE;
++ }
++
++ XPD_COUNTER(xpd, PCM_READ)++;
++ XBUS_COUNTER(xpd->xbus, PCM_READ)++;
++ spin_unlock_irqrestore(&xpd->lock, flags);
++ xpp_tick((unsigned long)xpd);
++ return 0;
++}
++
++HANDLER_DEF(GLOBAL, SYNC_REPLY)
++{
++ if(!xpd) {
++ int xpd_num = XPD_NUM(pack->content.addr);
++ NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
++ return -EPROTO;
++ }
++ DBG("SYNC_REPLY: 0x%X\n", RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, mask));
++ return 0;
++}
++
++
++xproto_table_t PROTO_TABLE(GLOBAL) = {
++ .entries = {
++ /* Card Opcode */
++ XENTRY( GLOBAL, DEV_DESC ),
++ XENTRY( GLOBAL, PCM_READ ),
++ XENTRY( GLOBAL, SYNC_REPLY ),
++ },
++ .name = "GLOBAL",
++ .packet_is_valid = global_packet_is_valid,
++ .packet_dump = global_packet_dump,
++};
++
++static bool global_packet_is_valid(xpacket_t *pack)
++{
++ const xproto_entry_t *xe;
++
++ //DBG("\n");
++ xe = xproto_global_entry(pack->content.opcode);
++ return xe != NULL;
++}
++
++static void global_packet_dump(xpacket_t *pack)
++{
++ DBG("\n");
++}
++
++static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
++{
++ xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
++ int i;
++ int count = 0;
++
++ BUG_ON(!pack);
++ BUG_ON(pack->content.opcode != XPROTO_NAME(GLOBAL, PCM_READ));
++ for (i = 0; i < CHANNELS_PERXPD; i++)
++ if(IS_SET(lines, i))
++ count++;
++ if(pack->datalen != (sizeof(xpp_line_t) + count * 8)) {
++ static int rate_limit = 0;
++
++ XPD_COUNTER(xpd, RECV_ERRORS)++;
++ if((rate_limit++ % 1000) <= 10) {
++ ERR("BAD PCM REPLY: pack->datalen=%d, count=%d\n", pack->datalen, count);
++ }
++ return 0;
++ }
++ return 1;
++}
++
+diff -urNad zaptel-1.0.10/xpp/card_global.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.h
+--- zaptel-1.0.10/xpp/card_global.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/card_global.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,56 @@
++#ifndef CARD_GLOBAL_H
++#define CARD_GLOBAL_H
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include "xdefs.h"
++#include "xproto.h"
++
++DEF_RPACKET_DATA(GLOBAL, DESC_REQ);
++DEF_RPACKET_DATA(GLOBAL, DEV_DESC,
++ byte rev; /* Revision number */
++ byte type; /* LSB: 1 - to_phone, 0 - to_line */
++ xpp_line_t line_status; /* hook/ring status, depending on unit */
++ );
++DEF_RPACKET_DATA(GLOBAL, PCM_WRITE,
++ xpp_line_t lines; // Must be 0xFF
++ byte pcm[PCM_CHUNKSIZE];
++ );
++DEF_RPACKET_DATA(GLOBAL, PCM_READ,
++ xpp_line_t lines; // Must be 0xFF
++ byte pcm[PCM_CHUNKSIZE];
++ );
++DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE,
++ byte mask;
++ );
++DEF_RPACKET_DATA(GLOBAL, SYNC_REPLY,
++ byte mask;
++ );
++
++
++/* 0x04 */ DECLARE_CMD(GLOBAL, DESC_REQ, int xpd_num);
++/* 0x11 */ DECLARE_CMD(GLOBAL, PCM_WRITE, xpp_line_t hookstate, volatile byte *buf);
++/* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, bool setit, bool is_master);
++
++extern xproto_table_t PROTO_TABLE(GLOBAL);
++
++#endif /* CARD_GLOBAL_H */
+diff -urNad zaptel-1.0.10/xpp/cards.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.c
+--- zaptel-1.0.10/xpp/cards.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.c 2006-01-03 14:01:24.370308595 +0200
+@@ -0,0 +1,394 @@
++#include <linux/module.h>
++#include "xpd.h"
++#include "xpp_zap.h"
++#include "xpp_proto.h"
++#include "cards.h"
++
++static char rcsid[] = "$Id: cards.c 150 2005-12-12 09:27:57Z oron $";
++
++extern int print_dbg;
++#include "zap_debug.h"
++
++#define MAX_SLIC_REGISTERS 100
++
++struct FXS_private_data {
++ slic_reply_t last_slic_reply;
++};
++
++/*------------------------- FXS Functions --------------------------*/
++int FXS_card_new(xpd_t *xpd)
++{
++ xpd->direction = TO_PHONE;
++ xpd->channels = min(8, CHANNELS_PERXPD);
++ if(xpd->id == 0) {
++ DBG("First XPD detected. Initialize digital outputs\n");
++ xpd->channels += 2;
++ xpd->digital_outputs = BIT(8) | BIT(9); // Two extra channels
++ }
++ return 0;
++}
++
++int FXS_card_remove(xpd_t *xpd)
++{
++ return 0;
++}
++
++static int FXS_card_startup(struct zt_span *span)
++{
++ DBG("\n");
++ return 0;
++}
++
++/*
++ * Called only for 'span' keyword in /etc/zaptel.conf
++ */
++static int FXS_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
++{
++ xpd_t *xpd = span->pvt;
++
++ DBG("%s\n", xpd->xpdname);
++ return 0;
++}
++
++/* Set signalling type (if appropriate) */
++static int FXS_card_chanconfig(struct zt_chan *chan, int sigtype)
++{
++ DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
++ dump_sigtype(print_dbg, " ", sigtype);
++ // FIXME: sanity checks:
++ // - should be supported (within the sigcap)
++ // - should not replace fxs <->fxo ??? (covered by previous?)
++ return 0;
++}
++
++/*
++ * Called only for 'span' keyword in /etc/zaptel.conf
++ */
++static int FXS_card_shutdown(struct zt_span *span)
++{
++ xpd_t *xpd = span->pvt;
++
++ DBG("%s\n", xpd->xpdname);
++ return 0;
++}
++
++static int FXS_card_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_outputs, pos)) {
++ DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
++ ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
++ return ret;
++ }
++ 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_PROTO(RING, xbus, xpd, pos, 0); // RING off
++#endif
++ ret = CALL_PROTO(LED, xpd->xbus, xpd, BIT(pos), LED_GREEN, 0);
++ ret = CALL_PROTO(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;
++ }
++ 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:
++ DBG("ZT_OFFHOOK: %s hookstate=0x%04X -- ignoring (FXS)\n", chan->name, xpd->hookstate);
++ 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(IS_SET(xpd->digital_outputs, pos)) {
++ DBG("ZT_ONHOOK %s digital output ON\n", chan->name);
++ ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
++ return ret;
++ }
++ xpd->ringing[pos] = RINGS_NUM*2;
++ ret = CALL_PROTO(CHAN_POWER, xbus, xpd, (1 << pos), 1); // Power up (for ring)
++ ret = CALL_PROTO(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);
++ }
++ return ret;
++}
++
++static int FXS_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ default:
++ return xpp_ioctl(chan, cmd, arg);
++ }
++ return 0;
++}
++
++#if 0
++int FXS_zaptel_setup(xpd_t *xpd)
++{
++ struct zt_chan *cur_chan;
++ struct zt_span *span;
++ xbus_t *xbus;
++ int i;
++ int cn;
++
++ BUG_ON(!xpd);
++
++ sigfxs = ! (xpd->direction == TO_PHONE); /* signaling is opposite */
++ cn = xpd->channels;
++ DBG("Initializing span: xpd %d have %d channels.\n", xpd->id, cn);
++
++ xpd->chans = kmalloc(sizeof(struct zt_chan)*cn, GFP_ATOMIC);
++ if (xpd->chans == NULL) {
++ ERR("xpd: Unable to allocate channels\n");
++ return -ENOMEM;
++ }
++ memset(xpd->chans, 0, sizeof(struct zt_chan)*cn);
++ memset(&xpd->span, 0, sizeof(struct zt_span));
++
++ span = &xpd->span;
++ xbus = xpd->xbus;
++ snprintf(span->name, MAX_SPANNAME, "%s/%s",
++ xbus->busname, xpd->xpdname);
++ {
++ char tmp[MAX_SPANNAME];
++ struct xpd_sim *sim = &xbus->sim[xpd->id];
++
++ if(sim->simulated)
++ snprintf(tmp, MAX_SPANNAME, " (sim to=%d)", sim->loopto);
++ else
++ 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\n", i);
++ snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%d-%d", xpd->id, i);
++ cur_chan->chanpos = i + 1;
++ cur_chan->pvt = xpd;
++ cur_chan->sigcap =
++#if 1
++ ZT_SIG_FXOKS |
++ ZT_SIG_FXOLS |
++ ZT_SIG_FXOGS |
++#else
++ ZT_SIG_SF |
++ ZT_SIG_EM |
++#endif
++ 0;
++ }
++ span->deflaw = ZT_LAW_MULAW;
++ init_waitqueue_head(&span->maintq);
++ span->pvt = xpd;
++ span->channels = cn;
++ span->chans = xpd->chans;
++
++ span->startup = FXS_xpp_startup;
++ span->shutdown = FXS_xpp_shutdown;
++ span->spanconfig = FXS_xpp_spanconfig;
++ span->chanconfig = FXS_xpp_chanconfig;
++ span->open = xpp_open;
++ span->close = xpp_close;
++#ifdef WITH_RBS
++ span->flags = ZT_FLAG_RBS;
++ span->hooksig = xpp_hooksig; /* Only with RBS bits */
++#else
++ span->sethook = FXS_xpp_sethook;
++#endif
++ span->ioctl = FXS_xpp_ioctl;
++ span->maint = xpp_maint;
++#ifdef CONFIG_ZAPTEL_WATCHDOG
++ span->watchdog = xpp_watchdog;
++#endif
++
++ return 0;
++}
++#endif
++
++int FXS_zaptel_cleanup(xpd_t *xpd)
++{
++ return 0;
++}
++
++/*------------------------- FXO Functions --------------------------*/
++static int FXO_card_new(xpd_t *xpd)
++{
++ xpd->direction = TO_TRUNK;
++ xpd->channels = min(8, CHANNELS_PERXPD);
++ return 0;
++}
++
++static int FXO_card_remove(xpd_t *xpd)
++{
++ return 0;
++}
++
++static int FXO_card_startup(struct zt_span *span)
++{
++ DBG("\n");
++ return 0;
++}
++
++/*
++ * Called only for 'span' keyword in /etc/zaptel.conf
++ */
++static int FXO_card_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
++{
++ xpd_t *xpd = span->pvt;
++
++ DBG("%s\n", xpd->xpdname);
++ return 0;
++}
++
++/* Set signalling type (if appropriate) */
++static int FXO_card_chanconfig(struct zt_chan *chan, int sigtype)
++{
++ DBG("channel %d (%s), sigtype %d.\n", chan->channo, chan->name, sigtype);
++ dump_sigtype(print_dbg, " ", sigtype);
++ // FIXME: sanity checks:
++ // - should be supported (within the sigcap)
++ // - should not replace fxs <->fxo ??? (covered by previous?)
++ return 0;
++}
++
++/*
++ * Called only for 'span' keyword in /etc/zaptel.conf
++ */
++static int FXO_card_shutdown(struct zt_span *span)
++{
++ xpd_t *xpd = span->pvt;
++
++ DBG("%s\n", xpd->xpdname);
++ return 0;
++}
++
++
++static int FXO_card_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);
++ 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_outputs, pos)) {
++ DBG("ZT_ONHOOK %s digital output OFF\n", chan->name);
++ ret = CALL_PROTO(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
++ return ret;
++ }
++ 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_PROTO(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:
++ 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_PROTO(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]);
++ break;
++ case ZT_RINGOFF:
++ DBG("ZT_RINGOFF %s\n", chan->name);
++ break;
++ default:
++ DBG("UNKNOWN hookstate=0x%X\n", hookstate);
++ }
++ return ret;
++}
++
++static int FXO_card_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
++{
++ switch (cmd) {
++ default:
++ return xpp_ioctl(chan, cmd, arg);
++ }
++ return 0;
++}
++
++
++/*------------------------- Function table -------------------------*/
++
++#define DEF_(t) \
++ [XPD_TYPE_ ## t] { \
++ .card_new = t ## _card_new, \
++ .card_remove = t ## _card_remove, \
++ .card_startup = t ## _card_startup, \
++ .card_shutdown = t ## _card_shutdown, \
++ .card_spanconfig = t ## _card_spanconfig, \
++ .card_chanconfig = t ## _card_chanconfig, \
++ .card_sethook = t ## _card_sethook, \
++ .card_ioctl = t ## _card_ioctl, \
++ }
++
++xops_t xpd_card_ops[XPD_TYPE_NOMODULE] = {
++ DEF_(FXS),
++ DEF_(FXO)
++};
++
++xops_t *get_xops(xpd_type_t xpd_type)
++{
++ if(xpd_type >= XPD_TYPE_NOMODULE)
++ return NULL;
++ return &xpd_card_ops[xpd_type];
++}
+diff -urNad zaptel-1.0.10/xpp/cards.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.h
+--- zaptel-1.0.10/xpp/cards.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/cards.h 2006-01-03 14:01:24.370308595 +0200
+@@ -0,0 +1,23 @@
++#ifndef CARDS_H
++#define CARDS_H
++
++#include "xpd.h"
++
++struct xpd_card_ops {
++ int (*card_new)(xpd_t *xpd);
++ int (*card_remove)(xpd_t *xpd);
++#if 0
++ int (*zaptel_setup)(xpd_t *xpd);
++ int (*zaptel_cleanup)(xpd_t *xpd);
++#endif
++ int (*card_startup)(struct zt_span *span);
++ int (*card_shutdown)(struct zt_span *span);
++ int (*card_spanconfig)(struct zt_span *span, struct zt_lineconfig *lc);
++ int (*card_chanconfig)(struct zt_chan *chan, int sigtype);
++ int (*card_sethook)(struct zt_chan *chan, int hookstate);
++ int (*card_ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
++};
++
++xops_t *get_xops(xpd_type_t xpd_type);
++
++#endif /* CARDS_H */
+diff -urNad zaptel-1.0.10/xpp/FPGA_XPD.hex /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/FPGA_XPD.hex
+--- zaptel-1.0.10/xpp/FPGA_XPD.hex 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/FPGA_XPD.hex 2006-01-03 13:22:53.823218000 +0200
@@ -0,0 +1,243 @@
+:0A0B3C000001020203030404050592
+:100546005010C0C0F9A4B0999282F880988883C6EA
@@ -33,253 +1416,6 @@
+:1003D700D2AF90E680E020E105D2041206D090E685
+:1003E70080E054F7F0538EF8C20390E6C2E054FB66
+:1003F700F000000000000090E6187410F000000004
-+:1004070090E61A7408F000000090E6017413F000FB
-+:100417000000300105120080C2013003F5120B5AAB
-+:1004270050F0C203120A7B20001690E682E030E704
-+:1004370004E020E1EF90E682E030E604E020E0E42B
-+:080447001209FC120B5C80CAD3
-+:0B0B310090E50DE030E402C322D32267
-+:1000800090E6B9E0700302013F1470030201BC2442
-+:10009000FE700302023F24FB700302013914700357
-+:1000A00002013314700302012714700302012D248E
-+:1000B0000560030202A3120B5E40030202AF90E64A
-+:1000C000BBE024FE602714603824FD601114602713
-+:1000D00024067050E52390E6B3F0E524803C120B33
-+:1000E00031503EE52B90E6B3F0E52C802DE52590D0
-+:1000F000E6B3F0E5268023E52790E6B3F0E5288017
-+:100100001990E6BAE0FF120A28AA06A9077B01EABD
-+:10011000494B600DEE90E6B3F0EF90E6B4F00202CA
-+:10012000AF02029E02029E120B0E0202AF120B4E93
-+:100130000202AF120B460202AF120AFC0202AF1219
-+:100140000B6040030202AF90E6B8E0247F60151414
-+:10015000601924027063A200E43325E0FFA202E4E8
-+:10016000334F8041E490E740F0803F90E6BCE0549C
-+:100170007EFF7E00E0D394807C0040047D018002FD
-+:100180007D00EC4EFEED4F243CF582740B3EF58372
-+:10019000E493FF3395E0FEEF24A1FFEE34E68F8277
-+:1001A000F583E0540190E740F0E4A3F090E68AF094
-+:1001B00090E68B7402F00202AF02029E120B6240C4
-+:1001C000030202AF90E6B8E024FE6016240260034A
-+:1001D0000202AF90E6BAE0B40105C2000202AF022B
-+:1001E000029E90E6BAE0705590E6BCE0547EFF7E39
-+:1001F00000E0D394807C0040047D0180027D00EC0F
-+:100200004EFEED4F243CF582740B3EF583E493FFE4
-+:100210003395E0FEEF24A1FFEE34E68F82F583E014
-+:1002200054FEF090E6BCE05480131313541FFFE01B
-+:10023000540F2F90E683F0E04420F08072805F122C
-+:100240000B64506B90E6B8E024FE60192402704EF7
-+:1002500090E6BAE0B40104D200805490E6BAE064BB
-+:1002600002604C803990E6BCE0547EFF7E00E0D313
-+:1002700094807C0040047D0180027D00EC4EFEED08
-+:100280004F243CF582740B3EF583E493FF3395E0F5
-+:10029000FEEF24A1FFEE34E68F82F583800D90E619
-+:1002A000A08008120A53500790E6A0E04401F090A5
-+:0602B000E6A0E04480F02E
-+:0102B6002225
-+:03003300020B5667
-+:040B560053D8EF324F
-+:100700001201000200000040B404041000000102C5
-+:1007100000010A06000200000040010009022E004C
-+:1007200001010080320904000004FF0000000705F9
-+:10073000020200020007050402000200070586020B
-+:100740000002000705880200020009022E000101D4
-+:100750000080320904000004FF00000007050202C7
-+:100760004000000705040240000007058602400023
-+:100770000007058802400000040309041C0341002F
-+:100780007300740072006900620061006E006B000B
-+:10079000320030003000360028035800500044007A
-+:1007A00028004200610073006500640020006F00B3
-+:1007B0006E002000410058005500500050002900F4
-+:0207C000000037
-+:100559005010B0C0F9A4B0999282F880988883C6E7
-+:10056900A1868E4110ABFF4110AD004110AEFF4195
-+:0705790010AC004110AF00BF
-+:1006370090E600E054E74410F000000090E60474F0
-+:1006470080F00000007406F0000000E4F0000000F5
-+:1006570090E610F090E611F000000090E613F0002D
-+:10066700000090E615F090E61074A0F090E611F007
-+:1006770000000000000090E61274AAF0000000904D
-+:10068700E61474EAF000000090E6047480F00000BD
-+:10069700007404F0000000E4F000000090E64974E4
-+:1006A70082F0000000F000000090E6187410F000DF
-+:1006B700000090E61A7408F090E6917480F000004C
-+:0906C70000F000000043AF012225
-+:020B5A00D322A4
-+:020B5C00D322A2
-+:020B5E00D322A0
-+:080B460090E6BAE0F51BD32292
-+:100AFC0090E740E51BF0E490E68AF090E68B04F07A
-+:020B0C00D322F2
-+:080B4E0090E6BAE0F51AD3228B
-+:100B0E0090E740E51AF0E490E68AF090E68B04F068
-+:020B1E00D322E0
-+:020B6000D3229E
-+:020B6200D3229C
-+:020B6400D3229A
-+:100A530090E6B9E0242F600D04701990E604E0FFDE
-+:100A6300430780800890E604E0FF53077F000000FF
-+:070A7300EFF08002D322C363
-+:010A7A002259
-+:100AA000C0E0C083C082D2015391EF90E65D740133
-+:080AB000F0D082D083D0E032C7
-+:100AD000C0E0C083C0825391EF90E65D7404F0D013
-+:060AE00082D083D0E03259
-+:100AE600C0E0C083C0825391EF90E65D7402F0D0FF
-+:060AF60082D083D0E03243
-+:1009C600C0E0C083C082852925852A2685268285A2
-+:1009D6002583A37402F08521278522288528828510
-+:1009E6002783A37407F05391EF90E65D7410F0D05F
-+:0609F60082D083D0E03244
-+:100AB800C0E0C083C082D2035391EF90E65D740812
-+:080AC800F0D082D083D0E032AF
-+:1007C200C0E0C083C08290E680E030E7208521252A
-+:1007D200852226852682852583A37402F085292712
-+:1007E200852A28852882852783A37407F05391EFF1
-+:0D07F20090E65D7420F0D082D083D0E0321C
-+:0106FF0032C8
-+:0107FF0032C7
-+:010B6600325C
-+:010B6700325B
-+:010B6800325A
-+:010B69003259
-+:010B6A003258
-+:010B6B003257
-+:010B6C003256
-+:010B6D003255
-+:010B6E003254
-+:010B6F003253
-+:010B70003252
-+:010B71003251
-+:010B72003250
-+:010B7300324F
-+:010B7400324E
-+:010B7500324D
-+:010B7600324C
-+:010B7700324B
-+:010B7800324A
-+:010B79003249
-+:010B7A003248
-+:010B7B003247
-+:010B7C003246
-+:010B7D003245
-+:010B7E003244
-+:010B7F003243
-+:010B80003242
-+:010B81003241
-+:010B82003240
-+:010B8300323F
-+:010B8400323E
-+:010B8500323D
-+:10098A00C0E0C083C08290E6D1E09010ACF090E65F
-+:10099A00D0E4F000000090E6D17402F000000053A9
-+:1009AA0091BF00000090E66104F000000090E69913
-+:0C09BA0004F075BB06D082D083D0E03280
-+:010B8600323C
-+:03004300020800B0
-+:03005300020800A0
-+:10080000020AA000020AE600020AD000020AB800AA
-+:100810000209C6000207C2000206FF000207FF002D
-+:10082000020B6600020B6700020B6800020B6900F6
-+:10083000020B6A00020B6B00020B6C00020B6D00D6
-+:10084000020B6E000207FF00020B6F00020B70002C
-+:10085000020B7100020B7200020B7300020B74009A
-+:10086000020B75000207FF000207FF000207FF00EE
-+:10087000020B7600020B7700020B7800020B790066
-+:10088000020B7A00020B7B00020B7C00020B7D0046
-+:10089000020B7E00020B7F00020B8000020B810026
-+:1008A000020B8200020B8300020B8400020B850006
-+:0808B00002098A00020B860018
-+:1009FC0090E682E030E004E020E60B90E682E03006
-+:100A0C00E119E030E71590E680E04401F07F147EB8
-+:0C0A1C000012094490E680E054FEF02235
-+:1006D00030040990E680E0440AF0800790E680E06C
-+:1006E0004408F07FDC7E0512094490E65D74FFF05B
-+:0F06F00090E65FF05391EF90E680E054F7F02230
-+:020A2800A9071C
-+:100A2A00AE2DAF2E8F828E83A3E064037017AD01C3
-+:100A3A0019ED7001228F828E83E07C002FFDEC3E3F
-+:080A4A00FEAF0580DFE4FEFFB2
-+:010A52002281
-+:100A7B0090E682E044C0F090E681F04387010000ED
-+:040A8B000000002245
-+:100944008E188F1990E600E054187012E5192401EE
-+:10095400FFE43518C313F518EF13F519801590E665
-+:1009640000E05418FFBF100BE51925E0F519E51850
-+:1009740033F518E5191519AE18700215184E6005EF
-+:06098400120A8F80EE2232
-+:100A8F007400F58690FDA57C05A3E582458370F97A
-+:010A9F002234
-+:1005800060801000011113213C01010703030305E2
-+:10059000010000000C0D0C0C0E0E0E0E410000367A
-+:1005A0000900003F010A013B0101010701010201AD
-+:1005B0000000000002020000020202024049004066
-+:1005C0000000003F010101010101010700000000DE
-+:1005D000000000000E0E0E0E0E0E0E0E00000000AB
-+:1005E0000000003F0139010101010107000302027F
-+:1005F000020202020E0E0E0E0E0E0E0E002D000056
-+:100600000000003F60241087000000000000000090
-+:1006100000000000000000000000833611170004F5
-+:10062000030201813616170004030201471080E01F
-+:0606300000000ECE4E009A
-+:10044F0090E60174CEF090E6F574FFF0901080E026
-+:10045F0090E6F3F0901081E090E6C3F0901082E008
-+:10046F0090E6C1F0901083E090E6C2F0901085E026
-+:10047F0090E6C0F0901086E090E6F4F075AF077448
-+:10048F0010F59A7400F59B759DE4E4F59EFF90E6D8
-+:10049F007BE090E67CF00FBF80F490E67174FFF084
-+:1004AF00F5B490E672E04480F043B680000000E4BB
-+:1004BF0090E6C4F000000090E6C5F0901087E09041
-+:1004CF00E6C6F0901088E090E6C7F0901089E090B3
-+:1004DF00E6C8F090108AE090E6C9F090108BE0909B
-+:1004EF00E6CAF090108CE090E6CBF090108DE09083
-+:1004FF00E6CCF090108EE090E6CDF000000090E694
-+:10050F00D27401F000000090E6E204F00000000059
-+:10051F00000090E6EB14F000000000000000000067
-+:10052F0090E6C0F090E6C1F090E6247408F0000069
-+:06053F0000E490E625F047
-+:010545002293
-+:030000000208B83B
-+:0C08B800787FE4F6D8FD75812E0208FF61
-+:100B2000EB9FF5F0EA9E42F0E99D42F0E89C45F02B
-+:010B300022A2
-+:1008C4000202B7E493A3F8E493A34003F68001F291
-+:1008D40008DFF48029E493A3F85407240CC8C33335
-+:1008E400C4540F4420C8834004F456800146F6DF04
-+:1008F400E4800B0102040810204080900546E47E49
-+:10090400019360BCA3FF543F30E509541FFEE493F8
-+:10091400A360010ECF54C025E060A840B8E493A3BF
-+:10092400FAE493A3F8E493A3C8C582C8CAC583CAEA
-+:10093400F0A3C8C582C8CAC583CADFE9DEE780BEA2
-+:0106360000C3
-+:00000001FF
-diff -urNad trunk/xpp/FPGA_XPD.hex /tmp/dpep.oAj2YR/trunk/xpp/FPGA_XPD.hex
---- trunk/xpp/FPGA_XPD.hex 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/FPGA_XPD.hex 2005-09-25 15:31:51.000000000 +0300
-@@ -0,0 +1,243 @@
-+:0A0B3C000001020203030404050592
-+:100546005010C0C0F9A4B0999282F880988883C6EA
-+:03055600A1868EED
-+:1002B700E4F513F512F511F510C203C200C202C22C
-+:1002C700011206377E077F008E238F24752B077553
-+:1002D7002C1275210775221C752907752A4A752D59
-+:1002E70007752E78EE54C070030203B875140075B5
-+:1002F70015808E168F17C374C09FFF74079ECF2477
-+:1003070002CF3400FEE48F0F8E0EF50DF50CF50BC2
-+:10031700F50AF509F508AF0FAE0EAD0DAC0CAB0B3A
-+:10032700AA0AA909A808C3120B205033E517250B01
-+:10033700F582E516350AF583E0FFE515250BF5820D
-+:10034700E514350AF583EFF0E50B2401F50BE435E9
-+:100357000AF50AE43509F509E43508F50880B78593
-+:10036700142385152474002480FF740734FFFEC30B
-+:10037700E52C9FF52CE52B9EF52BC3E5269FF5264F
-+:10038700E5259EF525C3E5289FF528E5279EF52752
-+:10039700C3E5229FF522E5219EF521C3E52A9FF5B6
-+:1003A7002AE5299EF529C3E52E9FF52EE52D9EF515
-+:1003B7002DD2E843D82090E668E0440BF090E65C45
-+:1003C700E0443DF0000000000000E4F5A20000005A
-+:1003D700D2AF90E680E020E105D2041206D090E685
-+:1003E70080E054F7F0538EF8C20390E6C2E054FB66
-+:1003F700F000000000000090E6187410F000000004
+:1004070090E61A7408F000000090E6017403F0000B
+:100417000000300105120080C2013003F5120B5AAB
+:1004270050F0C203120A7B20001690E682E030E704
@@ -499,22 +1635,25 @@
+:10093400F0A3C8C582C8CAC583CADFE9DEE780BEA2
+:0106360000C3
+:00000001FF
-diff -urNad trunk/xpp/gen_slic_init /tmp/dpep.oAj2YR/trunk/xpp/gen_slic_init
---- trunk/xpp/gen_slic_init 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/gen_slic_init 2005-11-06 18:00:07.000000000 +0200
-@@ -0,0 +1,34 @@
+diff -urNad zaptel-1.0.10/xpp/gen_slic_init /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/gen_slic_init
+--- zaptel-1.0.10/xpp/gen_slic_init 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/gen_slic_init 2006-01-03 15:08:38.089954000 +0200
+@@ -0,0 +1,37 @@
+#! /usr/bin/perl -w
+
+use strict;
+
++my $input;
+my $header;
+my $comment;
+
+ at ARGV == 2 or die "Usage: $0 <infile> <outfile>\n";
++$input = $ARGV[0];
+$header = $ARGV[1];
++open(IF, "$input") or die "Failed to write '$input': $!\n";
+open(HF, ">$header") or die "Failed to write '$header': $!\n";
+
-+while(<>) {
++while(<IF>) {
+ chomp;
+ undef $comment;
+ s/\r//; # CRLF -> LF
@@ -537,26 +1676,229 @@
+ }
+ print HF "\n";
+}
-diff -urNad trunk/xpp/Makefile /tmp/dpep.oAj2YR/trunk/xpp/Makefile
---- trunk/xpp/Makefile 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/Makefile 2005-11-10 04:05:17.000000000 +0200
-@@ -0,0 +1,5 @@
+diff -urNad zaptel-1.0.10/xpp/Makefile /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/Makefile
+--- zaptel-1.0.10/xpp/Makefile 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/Makefile 2006-01-03 13:22:53.565151000 +0200
+@@ -0,0 +1,4 @@
+EXTRA_CFLAGS = -I$(src)/..
+
+obj-m = xpp.o xpp_usb.o
-+xpp-y += xpp_proto.o xpp_zap.o zap_debug.o
++xpp-y += xproto.o card_global.o card_fxs.o slic.o xpp_zap.o zap_debug.o
+diff -urNad zaptel-1.0.10/xpp/slic.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.c
+--- zaptel-1.0.10/xpp/slic.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.c 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,129 @@
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
+
-diff -urNad trunk/xpp/slic_init.inc /tmp/dpep.oAj2YR/trunk/xpp/slic_init.inc
---- trunk/xpp/slic_init.inc 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/slic_init.inc 2005-11-06 18:04:13.000000000 +0200
-@@ -0,0 +1,51 @@
++#include "xproto.h"
++#include "slic.h"
++
++static const char rcsid[] = "$Id: slic.c 161 2006-01-03 09:13:40Z oron $";
++
++#ifdef __KERNEL__
++#include <linux/module.h>
++
++extern int print_dbg;
++#include "zap_debug.h"
++#else
++#include <stdio.h>
++#endif
++
++int slic_cmd_direct_write(slic_cmd_t *sc, xpp_line_t lines, byte reg, byte data)
++{
++ struct slic_reg_d *p = (struct slic_reg_d *)&sc->content;
++
++ sc->lines = lines;
++ sc->bytes = sizeof(struct slic_reg_d);
++ SLIC_REG_INIT(p, 0, reg, data);
++ return sizeof(xpp_line_t) + 1 + sc->bytes;
++}
++
++int slic_cmd_direct_read(slic_cmd_t *sc, xpp_line_t lines, byte reg)
++{
++ struct slic_reg_d *p = (struct slic_reg_d *)&sc->content;
++
++ sc->lines = lines;
++ sc->bytes = sizeof(struct slic_reg_d);
++ SLIC_REG_INIT(p, 1, reg, 0);
++ return sizeof(xpp_line_t) + 1 + sc->bytes;
++}
++
++int slic_cmd_indirect_write(slic_cmd_t *sc, xpp_line_t lines, byte reg, byte data_low, byte data_high)
++{
++ struct slic_reg_iw *p = (struct slic_reg_iw *)&sc->content;
++
++ sc->lines = lines;
++ sc->bytes = sizeof(struct slic_reg_iw);
++ SLIC_REG_INIT(&p->iw_data_low, 0, 0x1C, data_low);
++ SLIC_REG_INIT(&p->iw_data_high, 0, 0x1D, data_high);
++ SLIC_REG_INIT(&p->iw_reg, 0, 0x1E, reg);
++ return sizeof(xpp_line_t) + 1 + sc->bytes;
++}
++
++int slic_cmd_indirect_read(slic_cmd_t *sc, xpp_line_t lines, byte reg)
++{
++ struct slic_reg_ir *p = (struct slic_reg_ir *)&sc->content;
++
++ sc->lines = lines;
++ sc->bytes = sizeof(struct slic_reg_ir);
++ SLIC_REG_INIT(&p->ir_reg, 0, 0x1E, reg);
++ return sizeof(xpp_line_t) + 1 + sc->bytes;
++}
++
++void dump_slic_cmd(const char msg[], slic_cmd_t *sc)
++{
++ int i;
++ struct slic_reg_d *sr;
++ int last_data_low = -1;
++ int last_data_high = -1;
++
++ sr = (struct slic_reg_d *)&sc->content;
++ if(sc->bytes > sizeof(sc->content)) {
++ NOTICE("%s: Bug: sc->bytes = %d\n", __FUNCTION__, sc->bytes);
++ return;
++ }
++ if(sc->bytes % 2) {
++ NOTICE("%s: Bug: ODD sc->bytes = %d\n", __FUNCTION__, sc->bytes);
++ return;
++ }
++ for(i = 0; i < sc->bytes/2; i++, sr++) {
++ if(sr->reg_num == 0x1C) {
++ last_data_low = sr->reg_data;
++ continue;
++ }
++ if(sr->reg_num == 0x1D) {
++ last_data_high = sr->reg_data;
++ continue;
++ }
++ if(sr->reg_num == 0x1E) {
++ if(last_data_low == -1 && last_data_high == -1) // Indirect Read
++ DBG("%s: LINES=0x%08X bytes=%d INDIRECT READ: register=0x%02X\n", msg, sc->lines, sc->bytes, sr->reg_data);
++ else if(last_data_low == -1 || last_data_high == -1) {
++ NOTICE("%s: BUG: PARTIAL INDIRECT: register=%d last_data_low=0x%X last_data_high=0x%X\n",
++ msg, sr->reg_data, last_data_low, last_data_high);
++ } else
++ DBG("%s: LINES=0x%08X bytes=%d INDIRECT WRITE: register=%d data_low=0x%02x data_high=0x%02X\n",
++ msg, sc->lines, sc->bytes, sr->reg_data, (byte)last_data_low, (byte)last_data_high);
++ last_data_low = last_data_high = -1;
++ } else {
++ DBG("%s: LINES=0x%08X bytes=%d DIRECT %s: register=%d data=0x%02X\n",
++ msg, sc->lines, sc->bytes, (sr->read) ? "READ" : "WRITE", sr->reg_num, sr->reg_data);
++ }
++ }
++}
++
++#ifdef __KERNEL__
++
++EXPORT_SYMBOL(slic_cmd_direct_write);
++EXPORT_SYMBOL(slic_cmd_direct_read);
++EXPORT_SYMBOL(slic_cmd_indirect_write);
++EXPORT_SYMBOL(slic_cmd_indirect_read);
++EXPORT_SYMBOL(dump_slic_cmd);
++
++#endif
+diff -urNad zaptel-1.0.10/xpp/slic.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.h
+--- zaptel-1.0.10/xpp/slic.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,65 @@
++#ifndef SLIC_H
++#define SLIC_H
++
++#include "xdefs.h"
++
++/*------------------------------ SLIC Data Structures ----------------------*/
++
++struct slic_reg_d { /* SLIC Register Direct Read/Write */
++ byte reg_num:7;
++ byte read:1;
++ byte reg_data;
++} __attribute__((packed));
++
++struct slic_reg_iw { /* SLIC Register Indirect-Write */
++ struct slic_reg_d iw_data_low;
++ struct slic_reg_d iw_data_high;
++ struct slic_reg_d iw_reg;
++} __attribute__((packed));
++
++struct slic_reg_ir { /* SLIC Register Indirect-Read */
++ struct slic_reg_d ir_reg;
++} __attribute__((packed));
++
++typedef struct slic_cmd {
++ xpp_line_t lines;
++ byte bytes;
++ union {
++ struct slic_reg_d direct;
++ struct slic_reg_iw indirect_write;
++ struct slic_reg_ir indirect_read;
++ } content;
++} __attribute__((packed)) slic_cmd_t;
++
++typedef struct slic_reply {
++ byte size;
++ byte reg_num:7;
++ byte indirect:1;
++ byte data_low;
++ byte data_high;
++} __attribute__((packed)) slic_reply_t;
++
++#define SLIC_REG_INIT(slic_reg, reading, num, data) \
++ do { \
++ (slic_reg)->read = reading; \
++ (slic_reg)->reg_num = num; \
++ (slic_reg)->reg_data = data; \
++ } while(0);
++
++/* OLD SLIC_INIT data */
++typedef struct slic_data {
++ byte len;
++ byte data[40];
++} __attribute__((packed)) slic_data_t;
++
++
++/*------------------------------ SLIC Initializers -------------------------*/
++
++int slic_cmd_direct_write(slic_cmd_t *sc, xpp_line_t lines, byte reg, byte data);
++int slic_cmd_direct_read(slic_cmd_t *sc, xpp_line_t lines, byte reg);
++int slic_cmd_indirect_write(slic_cmd_t *sc, xpp_line_t lines, byte reg, byte data_low, byte data_high);
++int slic_cmd_indirect_read(slic_cmd_t *sc, xpp_line_t lines, byte reg);
++void dump_slic_cmd(const char msg[], slic_cmd_t *sc);
++
++
++#endif /* SLIC_H */
+diff -urNad zaptel-1.0.10/xpp/slic_init.inc /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic_init.inc
+--- zaptel-1.0.10/xpp/slic_init.inc 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/slic_init.inc 2006-01-03 15:08:39.122220000 +0200
+@@ -0,0 +1,65 @@
+// ----------------------------------==== 8-channel FXS unit initialization ===-----------------------------------------
++
+// INTERNAL PS
+// Change SLICs states to "Open state"s (Off,all transfers tristated to avoid data collision), Voltage sense
+S_(0x000000FF, 0x04, 0x40, 0x00, 0x6C, 0x01),
+
++
+// ------------------------------------- Initialization of indirect registers ------------------------------------------
-+
++S_(0x000000FF, 0x02, 0x40, 0x00),
+S_(0x000000FF, 0x18, 0x1C, 0xC2, 0x1D, 0x55, 0x1E, 0x00, 0x1C, 0xE6, 0x1D, 0x51, 0x1E, 0x01, 0x1C, 0x85, 0x1D, 0x4B, 0x1E, 0x02, 0x1C, 0x37, 0x1D, 0x49, 0x1E, 0x03),
+S_(0x000000FF, 0x18, 0x1C, 0x33, 0x1D, 0x33, 0x1E, 0x04, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x05, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x06, 0x1C, 0x98, 0x1D, 0x01, 0x1E, 0x07),
+S_(0x000000FF, 0x18, 0x1C, 0x98, 0x1D, 0x01, 0x1E, 0x08, 0x1C, 0x11, 0x1D, 0x06, 0x1E, 0x09, 0x1C, 0x02, 0x1D, 0x02, 0x1E, 0x0A, 0x1C, 0xE5, 0x1D, 0x00, 0x1E, 0x0B),
@@ -582,15 +1924,20 @@
+S_(0x000000FF, 0x0C, 0x15, 0x00, 0x16, 0x03, 0x17, 0x00, 0x12, 0xFF, 0x13, 0xFF, 0x14, 0xFF),
+
+// Ring timers settings
-+S_(0x000000FF, 0x0A, 0x30, 0x80, 0x31, 0x3E, 0x32, 0x80, 0x33, 0x3E, 0x22, 0x18),
++S_(0x000000FF, 0x06, 0x30, 0x80, 0x31, 0x3E, 0x32, 0x80),
++S_(0x000000FF, 0x02, 0x33, 0x3E),
++S_(0x000000FF, 0x02, 0x22, 0x18),
+
-+// Battery feed control(DCSW), Automatic control of Ring Trip and Loop Closure, Manual VBATH, VBATL
-+S_(0x000000FF, 0x02, 0x43, 0x16),
++// Battery feed control(DCSW), Automatic control of Ring Trip and Loop Closure, VBATH, VBATL
++S_(0x000000FF, 0x02, 0x42, 0x00),
++S_(0x000000FF, 0x02, 0x43, 0x1E),
+S_(0x000000FF, 0x04, 0x4A, 0x31, 0x4B, 0x10),
+
-+// SLICs calibration
-+S_(0x000000FF, 0x0C, 0x61, 0x1F, 0x60, 0x5F, 0x45, 0x20, 0x46, 0x02, 0x42, 0x04, 0x47, 0x04),
++S_(0x000000FF, 0x02, 0x45, 0x0A),
++S_(0x000000FF, 0x02, 0x46, 0x0B),
++S_(0x000000FF, 0x02, 0x47, 0x00),
+
++
+// Setting of SLICs offsets
+S_(0x00000001, 0x08, 0x02, 0x01, 0x03, 0x00, 0x04, 0x01, 0x05, 0x00),
+S_(0x00000002, 0x08, 0x02, 0x09, 0x03, 0x00, 0x04, 0x09, 0x05, 0x00),
@@ -601,10 +1948,17 @@
+S_(0x00000040, 0x08, 0x02, 0x31, 0x03, 0x00, 0x04, 0x31, 0x05, 0x00),
+S_(0x00000080, 0x08, 0x02, 0x39, 0x03, 0x00, 0x04, 0x39, 0x05, 0x00),
+
-diff -urNad trunk/xpp/sync.sh /tmp/dpep.oAj2YR/trunk/xpp/sync.sh
---- trunk/xpp/sync.sh 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/sync.sh 2005-11-14 16:43:00.829030244 +0200
-@@ -0,0 +1,21 @@
++// Change SLICs states to "Normal state"s (On, after offsets are set already)
++
++
++S_(0x000000FF, 0x02, 0x40, 0x1),
++S_(0x000000FF, 0x02, 0x42, 0x06),
++// -------------------------------------------------------------
++
+diff -urNad zaptel-1.0.10/xpp/sync.sh /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/sync.sh
+--- zaptel-1.0.10/xpp/sync.sh 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/sync.sh 2006-01-03 15:35:29.050560735 +0200
+@@ -0,0 +1,30 @@
+#!/bin/sh
+
+set -e
@@ -614,22 +1968,117 @@
+XPP_DIR=$SVN_ROOT/xpp-zaptel/zaptel/xpp
+TARGET_DIR=xpp
+
-+(cd $SVN_ROOT/xpp-zaptel; svn update)
++curdir=$PWD
++cd $SVN_ROOT/xpp-zaptel
++ svn update
++ cd xortel
++ make FIRMWARE="$SVN_ROOT/fpgafirmware/init.dat" ../zaptel/xpp/slic_init.inc
++cd $curdir
+
-+cp -a $XORTEL_DIR/FPGA_*.hex ${TARGET_DIR}/
++cp -a $XORTEL_DIR/FPGA_XPD.hex ${TARGET_DIR}/
+cp -a $XORTEL_DIR/xpd.h ${TARGET_DIR}/
-+cp -a $XORTEL_DIR/xpp_{proto,zap}.{c,h} ${TARGET_DIR}/
++cp -a $XORTEL_DIR/xpp_zap.[ch] ${TARGET_DIR}/
++cp -a $XORTEL_DIR/xproto.[ch] ${TARGET_DIR}/
++cp -a $XORTEL_DIR/xdefs.h ${TARGET_DIR}/
+cp -a $XORTEL_DIR/xpp_usb.c ${TARGET_DIR}/
+cp -a $XORTEL_DIR/zap_debug.[ch] ${TARGET_DIR}/
++cp -a $XORTEL_DIR/slic.[ch] ${TARGET_DIR}/
++cp -a $XORTEL_DIR/card_*.[ch] ${TARGET_DIR}/
+cp -a $XORTEL_DIR/xpp_fxloader{,.usermap} ${TARGET_DIR}/
+cp -a $XORTEL_DIR/xpp_modprobe ${TARGET_DIR}/
+cp -a $XORTEL_DIR/gen_slic_init ${TARGET_DIR}/
+cp -a $XPP_DIR/Makefile ${TARGET_DIR}/
+cp -a $XPP_DIR/slic_init.inc ${TARGET_DIR}/
-diff -urNad trunk/xpp/xpd.h /tmp/dpep.oAj2YR/trunk/xpp/xpd.h
---- trunk/xpp/xpd.h 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpd.h 2005-11-06 18:00:07.000000000 +0200
-@@ -0,0 +1,318 @@
+diff -urNad zaptel-1.0.10/xpp/xdefs.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xdefs.h
+--- zaptel-1.0.10/xpp/xdefs.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xdefs.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,82 @@
++#ifndef XDEFS_H
++#define XDEFS_H
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifdef __KERNEL__
++
++#include <linux/kernel.h>
++
++#define DBG(fmt, ...) \
++ ((print_dbg) && printk(KERN_DEBUG "DBG-%s: %s: " fmt, \
++ THIS_MODULE->name, __FUNCTION__, ## __VA_ARGS__))
++#define INFO(fmt, ...) printk(KERN_INFO "INFO-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
++#define NOTICE(fmt, ...) printk(KERN_NOTICE "NOTICE-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
++#define ERR(fmt, ...) printk(KERN_ERR "ERR-%s: " fmt, THIS_MODULE->name, ## __VA_ARGS__)
++
++#else
++
++#include <stdint.h>
++typedef uint32_t __u32;
++
++#include <stdio.h>
++
++#define DBG(fmt, ...) printf("DBG: %s: " fmt, __FUNCTION__, ## __VA_ARGS__)
++#define INFO(fmt, ...) printf("INFO: " fmt, ## __VA_ARGS__)
++#define NOTICE(fmt, ...) printf("NOTICE: " fmt, ## __VA_ARGS__)
++#define ERR(fmt, ...) printf("ERR: " fmt, ## __VA_ARGS__)
++#define __user
++
++struct list_head { struct list_head *next; struct list_head *prev; };
++
++#endif
++
++typedef char *charp;
++typedef unsigned char byte;
++typedef int bool;
++typedef struct xbus xbus_t;
++typedef struct xpd xpd_t;
++typedef struct xpacket_raw xpacket_raw_t;
++typedef struct xpacket xpacket_t;
++typedef struct xops xops_t;
++typedef __u32 xpp_line_t; /* at most 31 lines for E1 */
++
++
++#define BIT_SET(x,i) ((x) |= (1 << (i)))
++#define BIT_CLR(x,i) ((x) &= ~(1 << (i)))
++#define IS_SET(x,i) (((x) & (1 << (i))) != 0)
++#define BIT(i) (1 << (i))
++
++#undef SUPPORT_USB1
++
++#ifdef SUPPORT_USB1
++/*
++ * packet size <= 64 bytes:
++ * ZT_CHUNKSIZE * 7 channels + header size <= 64
++ */
++#define CHANNELS_PERXPD 7 /* 7 * ZT_CHUNKSIZE + header <= 64 bytes */
++#else
++#define CHANNELS_PERXPD 30 /* Depends on xpp_line_t and protocol fields */
++#endif
++
++
++#endif /* XDEFS_H */
+diff -urNad zaptel-1.0.10/xpp/xpd.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpd.h
+--- zaptel-1.0.10/xpp/xpd.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpd.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,294 @@
+#ifndef XPD_H
+#define XPD_H
+
@@ -655,25 +2104,18 @@
+ *
+ */
+
-+/*
-+ * Undef to disable packet logging
-+#define XPP_PACKET_LOG
-+ */
++#include "xdefs.h"
++#include "xproto.h"
+
+#ifdef __KERNEL__
+#include <linux/kernel.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/moduleparam.h>
-+#else
-+#include <stdint.h>
-+typedef uint32_t __u32;
+#endif
+
+#include <zaptel.h>
+
-+typedef char *charp;
-+
+#ifdef __KERNEL__
+#define DEF_PARM(type,name,init,desc) \
+ type name = init; \
@@ -708,51 +2150,19 @@
+#define XPD_DESCLEN 20
+#define XBUS_NAMELEN 20 /* must be <= from maximal workqueue name */
+#define XBUS_DESCLEN 40
-+#define MAX_XPDS 8 // 1 FXS + 2 E1/T1 + 1 (Quad * E1/T1)
+
-+#undef SUPPORT_USB1
++/* Hardware does not check bank_num yet. So only 4 cards can be used */
++#define MAX_XPDS 4 // 1 FXS + 2 E1/T1 + 1 (Quad * E1/T1)
+
-+#ifdef SUPPORT_USB1
-+/*
-+ * packet size <= 64 bytes:
-+ * ZT_CHUNKSIZE * 7 channels + header size <= 64
-+ */
-+#define CHANNELS_PERXPD 7 /* 7 * ZT_CHUNKSIZE + header <= 64 bytes */
-+#else
-+#define CHANNELS_PERXPD 30 /* Depends on xpp_line_t and protocol fields */
-+#endif
-+
-+#define XPD_NUM(x) ((x).id)
-+#define XPD_ADDR_SET(x,val) do { (x).id = val; (x).reserved = 0; } while(0);
+#define VALID_XPD_NUM(x) ((x) < MAX_XPDS && (x) >= 0)
+
-+typedef unsigned char byte;
-+typedef int bool;
-+typedef __u32 xpp_line_t; /* at most 31 lines for E1 */
++typedef struct xbus_ops xbus_ops_t;
+
-+typedef struct xpp_addr {
-+ byte id:4;
-+ byte reserved:4;
-+} __attribute__((packed)) xpp_addr_t;
-+
-+
-+typedef struct xbus xbus_t;
-+typedef struct xbus_ops xbus_ops_t;
-+typedef struct xpd xpd_t;
-+typedef struct xpp_packet xpacket_t;
-+
+typedef enum xbus_type {
+ FIRMWARE_LOOPBACK = 1,
+ FIRMWARE_XPP = 2,
+} xbus_type_t;
+
-+typedef enum xpd_type {
-+ XPD_TYPE_FXO = 0x2,
-+ XPD_TYPE_FXS = 0x3,
-+ //XPD_TYPE_E1 = ,
-+ XPD_TYPE_NOMODULE = 0x7,
-+} xpd_type_t;
-+
+#ifdef __KERNEL__
+
+
@@ -822,11 +2232,12 @@
+
+ /* Simulator data */
+ xbus_type_t bus_type;
++#if SOFT_SIMULATOR
+ struct xpd_sim sim[MAX_XPDS];
+ struct workqueue_struct *sim_workqueue;
-+ struct work_struct sim_work; // workqueue job for running zt_register
-+ struct work_struct poll_work; // workqueue job for issuing poll
++ struct work_struct sim_work; // workqueue job for running simulator
+ packet_queue_t sim_packet_queue;
++#endif
+
+ spinlock_t lock;
+
@@ -838,7 +2249,7 @@
+ struct timer_list poll_timer;
+ struct rw_semaphore in_use;
+ int num_xpds;
-+ void *priv;
++ void *priv; /* Pointer to transport level data structures */
+
+#ifdef XPP_PACKET_LOG
+ struct cyclic_buff *packet_log;
@@ -847,6 +2258,7 @@
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *procdir;
+ struct proc_dir_entry *procsummary;
++ struct proc_dir_entry *proc_ztregister;
+#endif
+
+ /* statistics */
@@ -867,6 +2279,7 @@
+#define BIT_SET(x,i) ((x) |= (1 << (i)))
+#define BIT_CLR(x,i) ((x) &= ~(1 << (i)))
+#define IS_SET(x,i) (((x) & (1 << (i))) != 0)
++#define BIT(i) (1 << (i))
+
+enum {
+ XPD_N_PCM_READ,
@@ -891,8 +2304,14 @@
+
+#define XPD_COUNTER_MAX (sizeof(xpd_counters)/sizeof(xpd_counters[0]))
+
-+#define NUM_LEDS 2
++enum leds {
++ LED_GREEN,
++ LED_RED,
++ LED_BLUE,
++};
+
++#define NUM_LEDS 3
++
+struct xpd {
+ char xpdname[XPD_NAMELEN];
+ struct zt_span span;
@@ -903,16 +2322,18 @@
+ xpp_line_t enabled_chans; /* hardware activation: 0 - off, 1 - on */
+ xpp_line_t hookstate; /* 0 - ONHOOK, 1 - OFHOOK */
+ xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
++ xpp_line_t digital_outputs; /* 0 - no, 1 - yes */
+
+ int ringing[CHANNELS_PERXPD];
+ bool ringer_on[CHANNELS_PERXPD]; /* For ring toggling */
+ bool led_on[CHANNELS_PERXPD]; /* For led toggling */
++ int lasttxhook[CHANNELS_PERXPD];
+
-+ atomic_t span_registered; /* is span zt_registered ? */
+ struct work_struct xpd_post_init;
+ xbus_t *xbus;
+
+ spinlock_t lock;
++ atomic_t open_counter; /* Number of open channels */
+
+ int flags;
+ enum {
@@ -927,11 +2348,15 @@
+
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *xpd_proc;
++ struct proc_dir_entry *xpd_slic;
+#endif
+ // Bit numbers of board_flags
+
+ int counters[XPD_COUNTER_MAX];
+
++ xops_t *xops; /* Card level operations */
++ void *card; /* Card level private data */
++
+ unsigned int recv_errors;
+ unsigned int seq_errors;
+ unsigned long last_response; /* in jiffies */
@@ -948,9 +2373,9 @@
+#endif
+
+#endif /* XPD_H */
-diff -urNad trunk/xpp/xpp_fxloader /tmp/dpep.oAj2YR/trunk/xpp/xpp_fxloader
---- trunk/xpp/xpp_fxloader 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_fxloader 2005-10-09 12:51:54.000000000 +0200
+diff -urNad zaptel-1.0.10/xpp/xpp_fxloader /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader
+--- zaptel-1.0.10/xpp/xpp_fxloader 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader 2006-01-03 13:22:53.823218000 +0200
@@ -0,0 +1,11 @@
+#!/bin/bash
+
@@ -963,31 +2388,31 @@
+ fxload -t fx2 -D "$DEVICE" -I "$FIRMWARE" || exit 1
+fi
+
-diff -urNad trunk/xpp/xpp_fxloader.usermap /tmp/dpep.oAj2YR/trunk/xpp/xpp_fxloader.usermap
---- trunk/xpp/xpp_fxloader.usermap 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_fxloader.usermap 2005-10-09 12:51:54.000000000 +0200
+diff -urNad zaptel-1.0.10/xpp/xpp_fxloader.usermap /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader.usermap
+--- zaptel-1.0.10/xpp/xpp_fxloader.usermap 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_fxloader.usermap 2006-01-03 13:22:53.823218000 +0200
@@ -0,0 +1,2 @@
+# module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info
+xpp_fxloader 0x0003 0x04b4 0x8613 0x0000 0x0000 0x00 0x00 0x00 0x00 0x00 0x00 0x0
-diff -urNad trunk/xpp/xpp_modprobe /tmp/dpep.oAj2YR/trunk/xpp/xpp_modprobe
---- trunk/xpp/xpp_modprobe 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_modprobe 2005-11-03 09:45:31.000000000 +0200
+diff -urNad zaptel-1.0.10/xpp/xpp_modprobe /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_modprobe
+--- zaptel-1.0.10/xpp/xpp_modprobe 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_modprobe 2006-01-03 13:22:53.823218000 +0200
@@ -0,0 +1,4 @@
+options zaptel debug=1
+options wcfxo debug=1
+options xpp print_dbg=1 ignore_xpds=0x00 softloop_xpds=0x00 enabled_channels=0x000000FF pcm_gen=0x00000000 max_queue_len=20000
+options usb_test vendor=0x4B4 product=0x8613 altsetting=1 innum=2 outnum=4
-diff -urNad trunk/xpp/xpp_proto.c /tmp/dpep.oAj2YR/trunk/xpp/xpp_proto.c
---- trunk/xpp/xpp_proto.c 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_proto.c 2005-11-10 04:05:18.000000000 +0200
-@@ -0,0 +1,823 @@
+diff -urNad zaptel-1.0.10/xpp/xpp_proto.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.c
+--- zaptel-1.0.10/xpp/xpp_proto.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.c 2006-01-03 14:01:24.370308595 +0200
+@@ -0,0 +1,1044 @@
+#include <linux/module.h>
+#include <linux/delay.h> /* for udelay */
+#include "xpd.h"
+#include "xpp_proto.h"
+#include "xpp_zap.h"
+
-+static char rcsid[] = "$Id: xpp_proto.c 123 2005-11-09 13:21:20Z oron $";
++static char rcsid[] = "$Id: xpp_proto.c 136 2005-12-12 07:10:40Z oron $";
+
+extern int print_dbg;
+#include "zap_debug.h"
@@ -1024,13 +2449,6 @@
+static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet);
+static bool pcm_valid(xpd_t *xpd, xpacket_t *reply);
+
-+/*------------------------- Protocol Functions ---------------------*/
-+
-+#define HOSTCMD(name, ...) \
-+ DECLARE_CMD(name, ## __VA_ARGS__ ); \
-+ EXPORT_SYMBOL(xpp_proto_ ## name); \
-+ DECLARE_CMD(name, ## __VA_ARGS__ )
-+
+#define NEW_PACKET(p, xbus, name, to) \
+ do { \
+ p = xbus->ops->packet_new(xbus, GFP_ATOMIC); \
@@ -1040,7 +2458,156 @@
+ XPD_ADDR_SET(p->content.addr, to); \
+ } while(0);
+
++/*------------------------- SLIC Handling --------------------------*/
+
++int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++ int len = 0;
++ unsigned long flags;
++ xpd_t *xpd = data;
++ //slic_reply_t *info;
++
++ BUG_ON(!xpd);
++ spin_lock_irqsave(&xpd->lock, flags);
++#if 0
++ info = (slic_reply_t *)&xpd->slic_info;
++ len += sprintf(page + len, "SLIC_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n",
++ (info->indirect)?"I":"D",
++ info->reg_num, info->data_high, info->data_low);
++#endif
++ spin_unlock_irqrestore(&xpd->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;
++}
++
++static int parse_slic_cmd(const char *buf, slic_cmd_t *sc)
++{
++ char op; /* [W]rite, [R]ead */
++ char reg_type; /* [D]irect, [I]ndirect */
++ int s1, s2, s3, s4;
++ int reg_num;
++ int data_low, data_high;
++ xpp_line_t lines;
++ int ret;
++
++ ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x",
++ &s1, &s2, &s3, &s4, &op, ®_type, ®_num, &data_high, &data_low);
++ lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1);
++ switch(op) {
++ case 'R':
++ if(reg_type == 'D' && ret == 7) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
++ ret = slic_cmd_direct_read(sc, lines, reg_num);
++ } else if(reg_type == 'I' && ret == 7) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num);
++ ret = slic_cmd_indirect_read(sc, lines, reg_num);
++ } else {
++ NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
++ goto err;
++ }
++ break;
++ case 'W':
++ if(reg_type == 'D' && ret == 8) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high);
++ ret = slic_cmd_direct_write(sc, lines, reg_num, data_high);
++ } else if(reg_type == 'I' && ret == 9) {
++ // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low);
++ ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high);
++ } else {
++ NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type);
++ goto err;
++ }
++ break;
++ default:
++ NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op);
++ goto err;
++ }
++ return ret;
++err:
++ return -EINVAL;
++}
++
++static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
++{
++ xbus_t *xbus;
++ slic_cmd_t sc;
++ xpacket_t *pack_tx;
++ char *p;
++ int len = strlen(cmdline);
++
++ BUG_ON(!xpd);
++ xbus = xpd->xbus;
++ if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */
++ *p = '\0';
++ if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */
++ *p = '\0';
++ for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */
++ ;
++ if(*p == '\0')
++ return 0;
++ len = parse_slic_cmd(p, &sc);
++ if(len < 0)
++ return len;
++ sc.lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!sc.lines) {
++ NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__);
++ return 0;
++ }
++ dump_slic_cmd("WRITE_SLIC", &sc);
++ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
++ PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd) = sc;
++ pack_tx->datalen = len;
++ packet_send(xbus, pack_tx);
++ return 0;
++}
++
++int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
++{
++ xpd_t *xpd = data;
++ const int LINE_LEN = 500;
++ char buf[LINE_LEN];
++ char *p;
++ int i;
++ int ret;
++
++ BUG_ON(!xpd);
++ for(i = 0; i < count; /* noop */) {
++ for(p = buf; p < buf + LINE_LEN; p++) { /* read a line */
++ if(i >= count)
++ break;
++ if(get_user(*p, buffer + i))
++ return -EFAULT;
++ i++;
++ if(*p == '\n' || *p == '\r') /* whatever */
++ break;
++ }
++ if(p >= buf + LINE_LEN)
++ return -E2BIG;
++ *p = '\0';
++ ret = process_slic_cmdline(xpd, buf);
++ if(ret < 0)
++ return ret;
++ }
++ return count;
++}
++
++
++
++/*------------------------- Protocol Functions ---------------------*/
++
++#define HOSTCMD(name, ...) \
++ DECLARE_CMD(name, ## __VA_ARGS__ ); \
++ EXPORT_SYMBOL(xpp_proto_ ## name); \
++ DECLARE_CMD(name, ## __VA_ARGS__ )
++
++
+/* 0x04 */ HOSTCMD(DESC_REQ, int xpd_num)
+{
+ int ret = 0;
@@ -1063,29 +2630,26 @@
+{
+ int ret = 0;
+ xpacket_t *pack_tx;
-+ slic_data_t *slic;
-+ int seq = 0;
++ slic_cmd_t *sc;
++ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
-+ if(!(xpd->enabled_chans & lines)) { // Ignore disabled channels
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
+ return 0;
+ }
-+ DBG("Channel Power: 0x%4X %s\n", lines, (on) ? "up" : "down");
++ DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down");
+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = lines;
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
+ if(on) {
+ // Power up
-+ slic->data[seq++] = 0x42;
-+ slic->data[seq++] = 0x06;
++ len = slic_cmd_direct_write(sc, lines, 0x42, 0x06);
+ } else {
+ // Power down
-+ slic->data[seq++] = 0x42;
-+ slic->data[seq++] = 0x00;
++ len = slic_cmd_direct_write(sc, lines, 0x42, 0x00);
+ }
-+ slic->len = seq;
-+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
++ pack_tx->datalen = len;
+
+ packet_send(xbus, pack_tx);
+ return ret;
@@ -1095,21 +2659,20 @@
+{
+ int ret = 0;
+ xpacket_t *pack_tx;
-+ slic_data_t *slic;
++ slic_cmd_t *sc;
++ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
-+ if(!(xpd->enabled_chans & lines)) { // Ignore disabled channels
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
+ return 0;
+ }
+ DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = lines;
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
-+ slic->len = 2;
-+ slic->data[0] = 0x40;
-+ slic->data[1] = (on)? 0x01 : 0x00;
-+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, lines, 0x40, (on)?0x01:0x00);
++ pack_tx->datalen = len;
+
+ packet_send(xbus, pack_tx);
+ return ret;
@@ -1119,23 +2682,21 @@
+{
+ int ret = 0;
+ xpacket_t *pack_tx;
-+ slic_data_t *slic;
++ slic_cmd_t *sc;
+ xpp_line_t mask = (1 << pos);
-+ int seq = 0;
++ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
-+ if(!(mask & xpd->enabled_chans)) { // Ignore disabled channels
++ mask &= xpd->enabled_chans; // Ignore disabled channels
++ if(!mask) {
+ return 0;
+ }
+ DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off");
+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = mask;
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
-+ slic->data[seq++] = 0x40;
-+ slic->data[seq++] = (on)? 0x04 : 0x01;
-+ slic->len = seq;
-+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
++ pack_tx->datalen = len;
+
+ packet_send(xbus, pack_tx);
+ return ret;
@@ -1145,21 +2706,21 @@
+{
+ int ret = 0;
+ xpacket_t *pack_tx;
-+ slic_data_t *slic;
++ slic_cmd_t *sc;
++ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
-+ if(!(xpd->enabled_chans & hook_status)) { // Ignore disabled channels
++ hook_status &= xpd->enabled_chans; // Ignore disabled channels
++ if(!hook_status) {
+ return 0;
+ }
+ DBG("New hook_status: %d\n", hook_status);
+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = hook_status;
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
+ /* FIXME: This is fake, until Dima implements FXO */
-+ slic->len = 1;
-+ slic->data[0] = 0x02;
-+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
++ len = slic_cmd_direct_write(sc, hook_status, 0x02, 0x00);
++ pack_tx->datalen = len;
+
+ packet_send(xbus, pack_tx);
+ return ret;
@@ -1167,28 +2728,35 @@
+
+/*
+ * LED control is done via SLIC register 0x06:
-+ * 8 7 6 5 4 3 2 1 0
-+ * +-----+-----+-----+-----+-----+-----+-----+-----+-----+
-+ * | MR | MG | | | R | W | | G | |
-+ * +-----+-----+-----+-----+-----+-----+-----+-----+-----+
++ * 7 6 5 4 3 2 1 0
++ * +-----+-----+-----+-----+-----+-----+-----+-----+
++ * | MR | MG | MB | R | OG | OB | G | B |
++ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ *
-+ * MR - Mask Red. (1 - R effect the Red LED)
-+ * MG - Mask Green. (1 - G effect the Green LED)
-+ * R - Red LED (0 - OFF, 1 - ON)
-+ * G - Green LED (0 - OFF, 1 - ON)
-+ * W - Write (actually change the LED state)
++ * B - BLUE LED (0 - OFF, 1 - ON)
++ * G - GREEN LED (0 - OFF, 1 - ON)
++ * OB - Output BLUE (this line is output)
++ * OG - Output GREEN (this line is output)
++ * R - RED LED (0 - OFF, 1 - ON)
++ * MB - Mask BLUE. (1 - B effect the BLUE LED)
++ * MR - Mask RED. (1 - R effect the RED LED)
++ * MG - Mask GREEN. (1 - G effect the GREEN LED)
++ *
++ * The BLUE LED (actually a relay out) is connected to line 0 and 4 only.
+ */
+
++// GREEN RED BLUE
++static int led_mask[NUM_LEDS] = { BIT(6), BIT(7), BIT(5) };
++static int led_vals[NUM_LEDS] = { BIT(1), BIT(4), BIT(0) };
++
+/* 0x0F */ HOSTCMD(LED, xpp_line_t lines, byte which, bool on)
+{
+ int ret = 0;
+ xpacket_t *pack_tx;
-+ slic_data_t *slic;
++ slic_cmd_t *sc;
++ int len;
+ int value;
+ int i;
-+ // GREEN RED
-+ int mask[NUM_LEDS] = { 0x40, 0x80 };
-+ int leds[NUM_LEDS] = { 0x02, 0x10 };
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
@@ -1198,27 +2766,53 @@
+ }
+ DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off");
+ which = which % NUM_LEDS;
-+ value = 0x08;
-+ value |= (0xC0 & ~mask[which]);
++ value = BIT(2) | BIT(3);
++ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]);
+ if(on)
-+ value |= leds[which];
++ value |= led_vals[which];
+ for(i = 0; i < CHANNELS_PERXPD; i++) {
+ if(!IS_SET(lines, i))
+ continue;
+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = (1 << i);
-+
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, lines, 0x06, value);
+ DBG("LED pack: line=%d value=0x%04X\n", i, value);
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
-+ slic->len = 2;
-+ slic->data[0] = 0x06;
-+ slic->data[1] = value;
-+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
++ pack_tx->datalen = len;
+ packet_send(xbus, pack_tx);
+ }
+ return ret;
+}
+
++/* 0x0F */ HOSTCMD(RELAY_OUT, byte which, bool on)
++{
++ int ret = 0;
++ xpacket_t *pack_tx;
++ slic_cmd_t *sc;
++ int len;
++ int value;
++ xpp_line_t lines;
++ int relay_channels[] = { 0, 4 };
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++
++ DBG("RELAY_OUT: which=%d -- %s\n", which, (on) ? "on" : "off");
++ which = which % ARRAY_SIZE(relay_channels);
++ lines = BIT(relay_channels[which]);
++ value = BIT(2) | BIT(3);
++ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]);
++ if(on)
++ value |= led_vals[LED_BLUE];
++ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_write(sc, lines, 0x06, value);
++
++ DBG("RELAY_OUT pack: line=%d value=0x%04X\n", lines, value);
++ pack_tx->datalen = len;
++ packet_send(xbus, pack_tx);
++ return ret;
++}
++
+/* 0x0F */ HOSTCMD(SLIC_INIT)
+{
+ int ret = 0;
@@ -1232,10 +2826,10 @@
+ DBG("INITIALIZING SLIC\n");
+ for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) {
+ source = &slic_init_data[i];
-+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = source->lines;
++ NEW_PACKET(pack_tx, xbus, SLIC_INIT, xpd->id);
++ PACKET_FIELD(pack_tx, SLIC_INIT, lines) = source->lines;
+
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
++ slic = &PACKET_FIELD(pack_tx, SLIC_INIT, slic_data);
+ slic->len = source->slic_data.len;
+ memcpy(slic->data, source->slic_data.data, source->slic_data.len);
+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
@@ -1250,18 +2844,16 @@
+{
+ int ret = 0;
+ xpacket_t *pack_tx;
-+ slic_data_t *slic;
++ slic_cmd_t *sc;
++ int len;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id);
-+ PACKET_FIELD(pack_tx, SLIC_WRITE, lines) = (1 << pos);
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
++ len = slic_cmd_direct_read(sc, (1<<pos), reg_num);
+
-+ slic = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_data);
-+ slic->len = 2;
-+ slic->data[0] = 0x80 | (reg_num & ~0x80); // MSB: 1 -- read, 0 -- write
-+ slic->data[1] = 0x00;
-+ pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1;
++ pack_tx->datalen = len;
+
+ packet_send(xbus, pack_tx);
+ return ret;
@@ -1278,14 +2870,20 @@
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
-+ if(!(xpd->enabled_chans & lines)) { // Ignore disabled channels
-+ return 0;
-+ }
++ lines &= xpd->enabled_chans;
+ // DBG("PCM_WRITE\n");
+ if(pcm_gen != 0)
+ return 0;
++// if(lines == 0)
++// return 0;
++
++ /*
++ * FIXME: Workaround a bug in sync code of the Astribank.
++ * Send dummy PCM for sync.
++ */
+ if(lines == 0)
-+ return 0;
++ lines = BIT(0);
++
+ NEW_PACKET(pack_tx, xbus, PCM_WRITE, xpd->id);
+ PACKET_FIELD(pack_tx, PCM_WRITE, lines) = lines;
+ start_pcm = pcm = PACKET_FIELD(pack_tx, PCM_WRITE, pcm);
@@ -1310,7 +2908,8 @@
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
-+ if(!(xpd->enabled_chans & lines)) { // Ignore disabled channels
++ lines &= xpd->enabled_chans; // Ignore disabled channels
++ if(!lines) {
+ return 0;
+ }
+ DBG("PCM_GEN lines=0x%04X %s\n", lines, (gen_seq) ? "seq" : "off");
@@ -1326,10 +2925,40 @@
+ return 0;
+}
+
++/*
++ * Sync source is controled by a mask byte to 0x19 command:
++ * 7 6 5 4 3 2 1 0
++ * +-----+-----+-----+-----+-----+-----+-----+-----+
++ * | | | | | | | RW | AB |
++ * +-----+-----+-----+-----+-----+-----+-----+-----+
++ *
++ * RW - Read or set (0 - Write, 1 - Read)
++ * AB - This Astribank provide sync (0 - no, 1 - yes)
++ *
++ */
++
++/* 0x19 */ HOSTCMD(SYNC_SOURCE, bool setit, bool is_master)
++{
++ xpacket_t *pack_tx;
++ byte mask = 0;
++
++ BUG_ON(!xbus);
++ BUG_ON(!xpd);
++ if(is_master)
++ mask |= BIT(0);
++ if(!setit)
++ mask |= BIT(1);
++ DBG("SYNC_SOURCE %s setit=%s is_master=%s (mask=0x%X)\n",
++ xpd->xpdname, (setit)?"yes":"no", (is_master)?"yes":"no", mask);
++ NEW_PACKET(pack_tx, xbus, SYNC_SOURCE, xpd->id);
++ PACKET_FIELD(pack_tx, SYNC_SOURCE, mask) = mask;
++ packet_send(xbus, pack_tx);
++ return 0;
++}
++
+/* 0x31 */ HOSTCMD(LOOPBACK_AX, byte *data, unsigned int size)
+{
+ xpacket_t *pack_tx;
-+
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
@@ -1346,10 +2975,8 @@
+static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet)
+{
+ xpacket_t *pack = sent_packet;
-+ xpp_line_t lines;
+ struct xpd_sim *xpd_sim;
+ struct xpd_sim *loopto_sim;
-+ slic_data_t *slic;
+ xpp_opcode_t opcode;
+ int dest_xpd_num;
+ int ret = 0;
@@ -1378,8 +3005,12 @@
+ XPD_ADDR_SET(pack->content.addr, dest_xpd_num);
+ break;
+ case XPP_SLIC_WRITE:
-+ lines = PACKET_FIELD(pack, SLIC_WRITE, lines);
-+ slic = &PACKET_FIELD(pack, SLIC_WRITE, slic_data);
++#if FINISHED_DECODING_SLICS
++ slic_cmd_t *sc;
++ int len;
++
++ sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd);
++ lines = sc->lines;
+ bool slic_write = ! (slic->data[0] & 0x80);
+ int slic_reg = slic->data[0] & ~0x80;
+
@@ -1421,6 +3052,7 @@
+ goto junk;
+ }
+ NOTICE("%s: xpd=%d: SLIC_WRITE: len=%d\n", __FUNCTION__, xpd_num, slic->len);
++#endif
+ dump_packet("BAD SLIC_WRITE", pack, print_dbg);
+ // FALL THROUGH
+ default:
@@ -1514,7 +3146,7 @@
+ NOTICE("DEV_DESC: unkown type=%d\n", type);
+ return -EPROTO;
+ }
-+ if((xpd = xpd_new(xbus, xpd_num, type)) == NULL) {
++ if((xpd = xpd_new(xbus, xpd_num, type, rev)) == NULL) {
+ NOTICE("xpd_new failed\n");
+ }
+ xpp_check_hookstate(xpd, line_status);
@@ -1558,30 +3190,27 @@
+
+static HANDLER_DEF(SLIC_REPLY)
+{
-+ byte dataL = PACKET_FIELD(reply, SLIC_REPLY, dataL);
-+ byte dataH = PACKET_FIELD(reply, SLIC_REPLY, dataH);
-+ const char *str = "";
++ slic_reply_t *info = &PACKET_FIELD(reply, SLIC_REPLY, info);
++ xpd_t *xpd = xpd_of(xbus, xpd_num);
++ unsigned long flags;
+
-+#if 0
-+ switch (dataL) {
-+ case 0x04:
-+ str = "RINGING";
-+ break;
-+ case 0x11:
-+ str = "NORMAL";
-+ break;
-+ default:
-+ str = "?????";
-+ break;
++ if(!xpd) {
++ NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
++ return -EPROTO;
+ }
-+#endif
-+ DBG("SLIC_REPLY: xpd #%d dataH=0x%X dataL=0x%X [%s]\n",
-+ xpd_num, dataH, dataL, str);
++ spin_lock_irqsave(&xpd->lock, flags);
++ DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
++ xpd_num, (info->indirect)?"I":"D",
++ info->reg_num, info->data_low, info->data_high);
++ spin_unlock_irqrestore(&xpd->lock, flags);
+ return 0;
+}
+
+static HANDLER_DEF(PCM_READ)
+{
++ /* FIXME: work around temporary hardware bug */
++ xpd_num = 0;
++
+ xpp_line_t lines = PACKET_FIELD(reply, PCM_READ, lines);
+ const byte *pcm = PACKET_FIELD(reply, PCM_READ, pcm);
+ xpd_t *xpd = xpd_of(xbus, xpd_num);
@@ -1620,9 +3249,23 @@
+ XPD_COUNTER(xpd, PCM_READ)++;
+ XBUS_COUNTER(xpd->xbus, PCM_READ)++;
+ spin_unlock_irqrestore(&xpd->lock, flags);
++ if(xpd->id == 0)
++ xpp_tick(0);
+ return 0;
+}
+
++static HANDLER_DEF(SYNC_REPLY)
++{
++ xpd_t *xpd = xpd_of(xbus, xpd_num);
++
++ if(!xpd) {
++ NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
++ return -EPROTO;
++ }
++ DBG("SYNC_REPLY: 0x%X\n", PACKET_FIELD(reply, SYNC_REPLY, mask));
++ return 0;
++}
++
+static HANDLER_DEF(LOOPBACK_XA)
+{
+ xpd_t *xpd = xpd_of(xbus, xpd_num);
@@ -1632,7 +3275,7 @@
+ return -EPROTO;
+ }
+ dump_packet("LOOPBACK_XA", reply, print_dbg);
-+ CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, 1, 0); // FIXME: Find usage for extra LED
++ CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED
+ return 0;
+}
+
@@ -1660,8 +3303,9 @@
+ C_( SIG_CHANGED, 0, "Signaling change (hookstate/ringing)"),
+ C_( SLIC_REPLY, 0, "Reply to slic state"),
+ C_( PCM_READ, 1, "Read PCM data"),
++ C_( SYNC_REPLY, 0, "SYNC_REPLY"),
++ C_( LOOPBACK_XA, 1, "LOOPBACK Reply"),
+ C_( DIAG_FE, 1, "DIAG FE Opcode"),
-+ C_( LOOPBACK_XA, 1, "LOOPBACK Reply"),
+};
+
+#undef C_
@@ -1692,7 +3336,7 @@
+ unsigned int size = pack->datalen;
+ int varsize = cmd->varsize;
+
-+// ERR("op=%d hsize=%d size=%d\n", op, hsize, size);
++ // ERR("op=%d hsize=%d size=%d\n", op, hsize, size);
+ return (hsize == size) ||
+ (varsize && size <= sizeof(struct xpp_packet_r));
+}
@@ -1804,14 +3448,17 @@
+
+EXPORT_SYMBOL(dump_packet);
+EXPORT_SYMBOL(packet_receive);
-diff -urNad trunk/xpp/xpp_proto.h /tmp/dpep.oAj2YR/trunk/xpp/xpp_proto.h
---- trunk/xpp/xpp_proto.h 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_proto.h 2005-11-03 15:01:15.000000000 +0200
-@@ -0,0 +1,167 @@
++EXPORT_SYMBOL(proc_xpd_slic_read);
++EXPORT_SYMBOL(proc_xpd_slic_write);
+diff -urNad zaptel-1.0.10/xpp/xpp_proto.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.h
+--- zaptel-1.0.10/xpp/xpp_proto.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_proto.h 2006-01-03 14:01:24.370308595 +0200
+@@ -0,0 +1,188 @@
+#ifndef XPP_PROTO_H
+#define XPP_PROTO_H
+
+#include "xpd.h"
++#include "slic.h"
+#ifdef __KERNEL__
+#include <linux/list.h>
+#endif
@@ -1832,6 +3479,7 @@
+ XPP_RING = 0x0F, // Write to SLIC
+ XPP_SETHOOK = 0x0F, // Write to SLIC
+ XPP_LED = 0x0F, // Write to SLIC
++ XPP_RELAY_OUT = 0x0F, // Write to SLIC
+ XPP_SLIC_INIT = 0x0F, // Write to SLIC
+ XPP_SLIC_QUERY = 0x0F, // Write to SLIC
+//
@@ -1841,6 +3489,10 @@
+ XPP_PCM_READ = 0x12,
+//
+ XPP_PCM_GEN = 0x13,
++//
++ XPP_SYNC_SOURCE = 0x19,
++ XPP_SYNC_REPLY = 0x1A,
++//
+ XPP_LOOPBACK_AX = 0x31,
+ XPP_LOOPBACK_XA = 0x32,
+ XPP_DIAG_FE = 0xFE,
@@ -1866,10 +3518,12 @@
+/* 0x0F */ DECLARE_CMD(RING, int pos, bool on);
+/* 0x0F */ DECLARE_CMD(SETHOOK, xpp_line_t hook_status);
+/* 0x0F */ DECLARE_CMD(LED, xpp_line_t lines, byte which, bool on);
++/* 0x0F */ DECLARE_CMD(RELAY_OUT, byte which, bool on);
+/* 0x0F */ DECLARE_CMD(SLIC_INIT);
+/* 0x0F */ DECLARE_CMD(SLIC_QUERY, int pos, byte reg_num);
+/* 0x11 */ DECLARE_CMD(PCM_WRITE, xpp_line_t hookstate, volatile byte *buf);
+/* 0x13 */ DECLARE_CMD(PCM_GEN, xpp_line_t lines, volatile byte *buf);
++/* 0x19 */ DECLARE_CMD(SYNC_SOURCE, bool setit, bool is_master);
+/* 0x31 */ DECLARE_CMD(LOOPBACK_AX, byte *data, unsigned int size);
+
+#define H_(op, ...) struct { \
@@ -1900,13 +3554,16 @@
+ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */
+ );
+
++ H_(SLIC_INIT,
++ xpp_line_t lines;
++ slic_data_t slic_data;
++ );
+ H_(SLIC_WRITE,
-+ xpp_line_t lines;
-+ slic_data_t slic_data;
++ slic_cmd_t slic_cmd;
+ );
+ H_(SLIC_REPLY, /* Get status of a single SLIC (for debugging) */
-+ byte dataL;
-+ byte dataH;
++ xpp_line_t lines;
++ slic_reply_t info;
+ );
+
+ H_(PCM_WRITE,
@@ -1923,6 +3580,14 @@
+ byte gen;
+ byte pcm_seq[ZT_CHUNKSIZE];
+ );
++
++ H_(SYNC_SOURCE,
++ byte mask;
++ );
++ H_(SYNC_REPLY,
++ byte mask;
++ );
++
+ H_(LOOPBACK_AX,
+ byte data[XPP_MAX_DATA]; // FIXME: what data size?
+ );
@@ -1971,14 +3636,16 @@
+void process_sim_queue(void *xbus);
+int validate_reply(xpacket_t *reply);
+int packet_receive(xbus_t *xbus, xpacket_t *pack);
++int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
++int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
+
+#endif
+
+#endif /* XPP_PROTO_H */
-diff -urNad trunk/xpp/xpp_usb.c /tmp/dpep.oAj2YR/trunk/xpp/xpp_usb.c
---- trunk/xpp/xpp_usb.c 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_usb.c 2005-11-14 10:37:50.000000000 +0200
-@@ -0,0 +1,838 @@
+diff -urNad zaptel-1.0.10/xpp/xpp_usb.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_usb.c
+--- zaptel-1.0.10/xpp/xpp_usb.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_usb.c 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,869 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2004-2005, Xorcom
@@ -2015,13 +3682,14 @@
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
++#include <asm/timex.h>
+#include <linux/proc_fs.h>
+#include <linux/usb.h>
-+#include "xpp_proto.h"
+#include "xpd.h"
++#include "xproto.h"
+#include "xpp_zap.h"
+
-+static char revision[] = "$Revision: 125 $";
++static char revision[] = "$Revision: 159 $";
+
+DEF_PARM(int, print_dbg, 1, "Print DBG statements"); /* must be before zap_debug.h */
+
@@ -2036,6 +3704,9 @@
+#define PROC_USBXPP_SUMMARY "xpp_usb"
+#endif
+
++static cycles_t stamp_last_pcm_read;
++static cycles_t accumulate_diff;
++
+struct xusb_model_info;
+
+struct xusb_endpoint {
@@ -2182,55 +3853,70 @@
+static int xusb_packet_send(xbus_t *xbus, xpacket_t *pack)
+{
+ struct xpp_usb_bus *xusb = xbus->priv;
-+ int toxpd = XPD_NUM(pack->content.addr);
+ struct urb *urb;
+ int ret = 0;
-+
++ size_t size;
++
+ BUG_ON(!pack);
+ if(!xusb->present) {
+ NOTICE("tried to send packets to non-exitant USB device. Ignored\n");
+ goto error;
+ }
-+ if (xbus->sim[toxpd].softloop_xpd) {
-+ // "send" through loopback queue
-+ //DBG("%s: ENQUEUE toxpd=%d, opcode=%X\n", xbus->busname, toxpd, pack->content.opcode);
-+ XBUS_COUNTER(xbus, SOFTSIM_PACKETS)++;
-+ xbus_enqueue_packet(xbus, &xbus->sim_packet_queue, pack);
-+ ret = queue_work(xbus->sim_workqueue, &xbus->sim_work);
-+ if(ret < 0) {
-+ ERR("%s: queue_work failed with %d (ignoring)\n", __FUNCTION__, ret);
-+ goto error;
++#if SOFT_SIMULATOR
++ {
++ int toxpd = XPD_NUM(pack->content.addr);
++
++ if (xbus->sim[toxpd].softloop_xpd) {
++ // "send" through loopback queue
++ //DBG("%s: ENQUEUE toxpd=%d, opcode=%X\n", xbus->busname, toxpd, pack->content.opcode);
++ XBUS_COUNTER(xbus, SOFTSIM_PACKETS)++;
++ xbus_enqueue_packet(xbus, &xbus->sim_packet_queue, pack);
++ ret = queue_work(xbus->sim_workqueue, &xbus->sim_work);
++ if(ret < 0) {
++ ERR("%s: queue_work failed with %d (ignoring)\n", __FUNCTION__, ret);
++ goto error;
++ }
+ }
-+ } else {
-+ size_t size = min(PACKET_LEN(pack), (size_t)xusb->ep_out.max_size);
-+ if(pack->content.opcode == XPP_PCM_WRITE) {
-+ XUSB_COUNTER(xusb, PCM_WRITES)++;
++ return 0;
++ }
++#endif
++ size = min(PACKET_LEN(pack), (size_t)xusb->ep_out.max_size);
++ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) {
++ XUSB_COUNTER(xusb, PCM_WRITES)++;
++
++#if 1
++ /*
++ * DEBUG: high-res timing of PCM_READ to PCM_WRITE
++ */
++ cycles_t diff = get_cycles() - stamp_last_pcm_read;
++ accumulate_diff += diff;
++#endif
+#if 0
-+ static int rate_limit;
-+ if((rate_limit++ % 1000) == 0)
-+ dump_packet("USB SEND PCM", pack, print_dbg);
++ static int rate_limit;
++ if((rate_limit++ % 1009) < 3) {
++ dump_packet("USB SEND PCM", pack, print_dbg);
++ }
+#endif
-+ } else {
-+ dump_packet("USB_PACKET_SEND", pack, print_dbg);
-+ }
-+ urb = xpp_urb_new(xusb, xusb->ep_out.epnum, size, xpp_send_callback);
-+ if (!urb) {
-+ ERR("No free urbs available\n");
-+ ret = -ENOMEM;
-+ goto error;
-+ }
++ } else {
++ dump_packet("USB_PACKET_SEND", pack, print_dbg);
++ }
++ urb = xpp_urb_new(xusb, xusb->ep_out.epnum, size, xpp_send_callback);
++ if (!urb) {
++ ERR("No free urbs available\n");
++ ret = -ENOMEM;
++ goto error;
++ }
+
-+ /* FIXME: FIXME: FIXME: we use copy+free until low-level drivers allocate memory themselves */
-+ memcpy(urb->transfer_buffer, &pack->content, size);
-+ xbus->ops->packet_free(xbus, pack);
++ /* FIXME: FIXME: FIXME: we use copy+free until low-level drivers allocate memory themselves */
++ memcpy(urb->transfer_buffer, &pack->content, size);
++ xbus->ops->packet_free(xbus, pack);
+
-+ ret = usb_submit_urb(urb, GFP_KERNEL);
-+ if(ret < 0) {
-+ ERR("%s: failed submit_urb\n", __FUNCTION__);
-+ XUSB_COUNTER(xusb, TX_ERRORS)++;
-+ xpp_urb_delete(urb);
-+ return -EBADF;
-+ }
++ ret = usb_submit_urb(urb, GFP_KERNEL);
++ if(ret < 0) {
++ ERR("%s: failed submit_urb\n", __FUNCTION__);
++ XUSB_COUNTER(xusb, TX_ERRORS)++;
++ xpp_urb_delete(urb);
++ return -EBADF;
+ }
+ return 0;
+error:
@@ -2383,7 +4069,7 @@
+ }
+ if(epnum & USB_DIR_IN) { // Input
+ if(epnum == model_info->in.epnum) {
-+ if(endpoint->wMaxPacketSize < sizeof(xpp_packet_r_t)) {
++ if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
+ ERR("USB input endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
+ break;
+ }
@@ -2392,7 +4078,7 @@
+ }
+ } else { // Output
+ if(epnum == model_info->out.epnum) {
-+ if(endpoint->wMaxPacketSize < sizeof(xpp_packet_r_t)) {
++ if(endpoint->wMaxPacketSize < sizeof(xpacket_raw_t)) {
+ ERR("USB output endpoint 0x%X support only wMaxPacketSize=%d (need USB-2)\n", epnum, endpoint->wMaxPacketSize);
+ break;
+ }
@@ -2611,15 +4297,17 @@
+
+static void xpp_send_callback(struct urb *urb, struct pt_regs *regs)
+{
-+ struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
++ struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
+ xbus_t *xbus = xusb->xbus;
+
+ BUG_ON(!xbus);
-+ /* sync/async unlink faults aren't errors */
-+ if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) {
-+ DBG("nonzero read bulk status received: %d", urb->status);
++ /* sync/async unlink faults aren't errors */
++ if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) {
++ static int rate_limit;
++ if((rate_limit++ % 1000) < 10)
++ DBG("nonzero read bulk status received: %d", urb->status);
+ XUSB_COUNTER(xusb, TX_ERRORS)++;
-+ }
++ }
+ if(!xusb->present) {
+ ERR("A packet from non-connected device?\n");
+ return;
@@ -2631,7 +4319,7 @@
+
+static void xpp_receive_callback(struct urb *urb, struct pt_regs *regs)
+{
-+ struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
++ struct xpp_usb_bus *xusb = (struct xpp_usb_bus *)urb->context;
+ xbus_t *xbus = xusb->xbus;
+
+ xpacket_t *pack;
@@ -2639,7 +4327,7 @@
+ int retval;
+
+ BUG_ON(!xbus);
-+ if (urb->status) {
++ if (urb->status) {
+ /* sync/async unlink faults aren't errors */
+ if (!(urb->status == -EOVERFLOW || urb->status == -EMSGSIZE)) {
+ ERR("Dropped connection due to bad URB status: %d\n", urb->status);
@@ -2648,7 +4336,7 @@
+ DBG("nonzero read bulk status received: %d\n", urb->status);
+ goto end;
+ }
-+ }
++ }
+ if(!down_read_trylock(&xbus->in_use)) {
+ ERR("%s: xbus is going down\n", __FUNCTION__);
+ return;
@@ -2663,23 +4351,30 @@
+ ERR("%s: Not enough memory for packets. Dropping\n", __FUNCTION__);
+ goto end;
+ }
-+
++
+ size = urb->actual_length;
+ memcpy(&pack->content, urb->transfer_buffer, size);
-+
-+ pack->datalen = size - sizeof(xpp_addr_t) - 1; // opcode size
++
++ pack->datalen = size - sizeof(xpd_addr_t) - 1; // opcode size
+ // DBG("datalen of new packet: %d\n", pack->datalen);
+
+ // Send UP
-+ if(pack->content.opcode == XPP_PCM_READ) {
++ if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_READ)) {
+ XUSB_COUNTER(xusb, PCM_READS)++;
++
++#if 1
++ /*
++ * DEBUG: high-res timing of PCM_READ to PCM_WRITE
++ */
++ stamp_last_pcm_read = get_cycles();
++#endif
+ // fill_beep((u_char *)&PACKET_FIELD(pack, PCM_READS, pcm), 2); // Debugging BEEP
+#if 0
+ static int rate_limit;
+ if((rate_limit++ % 1000) == 0)
+ dump_packet("USB RECEIVE PCM", pack, print_dbg);
+#endif
-+ } else if(pack->content.opcode == XPP_PCM_WRITE) { // FIRMWARE_LOOPBACK
++ } else if(pack->content.opcode == XPROTO_NAME(GLOBAL,PCM_WRITE)) { // FIRMWARE_LOOPBACK
+#if 0
+ static int rate_limit;
+ if((rate_limit++ % 1000) == 0)
@@ -2689,7 +4384,7 @@
+ char title[XBUS_DESCLEN];
+
+ snprintf(title, XBUS_DESCLEN, "USB_PACKET_RECEIVE callback (%s)", xbus->busname);
-+ // dump_packet(title, pack, print_dbg);
++ dump_packet(title, pack, print_dbg);
+ }
+ packet_receive(xbus, pack);
+ XUSB_COUNTER(xusb, RX_PACKETS)++;
@@ -2745,8 +4440,10 @@
+ ERR("%s: BUG: xpd->id=%d != j=%d\n", __FUNCTION__, xpd->id, j);
+ continue;
+ }
-+ CALL_PROTO(CHAN_ENABLE, xbus, xpd, 0xFF, 0); // Disable all hardware channels
-+ CALL_PROTO(LED, xbus, xpd, 0xFF, 1, 0); // FIXME: Show activated channels
++#if 0 // FIXME: retest after new driver start working
++ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, 0xFF, 0); // Disable all hardware channels
++ CALL_XMETHOD(LED, xbus, xpd, 0xFF, 1, 0); // FIXME: Show activated channels
++#endif
+ }
+ }
+ }
@@ -2787,6 +4484,7 @@
+ xusb->ep_out.epnum,
+ xusb->ep_out.max_size
+ );
++ len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff);
+ len += sprintf(page + len, "\nCOUNTERS:\n");
+ for(i = 0; i < XUSB_COUNTER_MAX; i++) {
+ len += sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name, xusb->counters[i]);
@@ -2813,14 +4511,14 @@
+MODULE_DESCRIPTION("XPP USB Driver");
+MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
+MODULE_LICENSE("GPL");
-+MODULE_VERSION("$Id: xpp_usb.c 125 2005-11-10 15:42:41Z oron $");
++MODULE_VERSION("$Id: xpp_usb.c 159 2006-01-03 08:49:05Z oron $");
+
+module_init(xpp_usb_init);
+module_exit(xpp_usb_cleanup);
-diff -urNad trunk/xpp/xpp_zap.c /tmp/dpep.oAj2YR/trunk/xpp/xpp_zap.c
---- trunk/xpp/xpp_zap.c 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_zap.c 2005-11-10 04:05:18.000000000 +0200
-@@ -0,0 +1,1881 @@
+diff -urNad zaptel-1.0.10/xpp/xpp_zap.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.c
+--- zaptel-1.0.10/xpp/xpp_zap.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.c 2006-01-03 15:08:38.089954000 +0200
+@@ -0,0 +1,2273 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2004, Xorcom
@@ -2861,17 +4559,19 @@
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <zaptel.h>
-+#include "xpp_proto.h"
++#include "xproto.h"
+#include "xpp_zap.h"
-+#include "xpd.h"
+
-+static char revision[] = "$Revision: 124 $";
++static char revision[] = "$Revision: 167 $";
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *xpp_procdir = NULL;
+#define PROC_DIR "xpp"
+#define PROC_XBUSES "xbuses"
++#define PROC_SYNC "sync"
+#define PROC_XBUS_SUMMARY "summary"
++#define PROC_XBUS_ZTREGISTER "zt_registration"
++#define PROC_SLIC_FNAME "%s.slic"
+#endif
+
+#undef WITH_RBS
@@ -2881,6 +4581,7 @@
+#define MAX_BUSES 16
+#define MAX_QUEUE_LEN 10000
+#define LED_BLINK_PERIOD (HZ/8)
++#define SAMPLE_TICKS 10000
+
+#define N_(x) [ x] = #x
+static const char *xpd_type_names[] = {
@@ -2890,11 +4591,13 @@
+};
+#undef N_
+
-+static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
-+static xbus_t *xbuses_array[MAX_BUSES] = {};
-+static int bus_count = 0;
-+static bool pcm_write_enable = 1; // DEBUG
++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;
++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;
+
+static LIST_HEAD(xpd_list);
+
@@ -2902,20 +4605,28 @@
+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");
+
+#include "zap_debug.h"
+
++
++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);
++xbus_t *xbus_of(int xbus_num);
+
++#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);
@@ -2967,16 +4678,82 @@
+ // xbus->busname, atomic_read(&xbus->packet_counter));
+}
+
-+static void xpp_timer_tick(unsigned long param)
++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 external_sync(xpd_t *the_xpd)
++{
++ int i, j;
++
++ DBG("SYNC %s\n", (the_xpd) ? "EXTERNAL" : "HOST");
++ for(i = 0; i < MAX_BUSES; i++) {
++ xbus_t *xbus = xbus_of(i);
++ if(!xbus)
++ continue;
++ if (!xbus->hardware_exists)
++ continue;
++ for(j = 0; j < MAX_XPDS; j++) {
++ xpd_t *xpd = xbus->xpds[j];
++ if(xpd)
++ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, xpd, 1, (the_xpd != NULL));
++ }
++ }
++}
++
++void set_sync_master(xpd_t *xpd)
++{
++ DBG("SYNC: %s => %s\n",
++ (sync_master) ? sync_master->xpdname : "HOST",
++ (xpd) ? xpd->xpdname : "HOST"
++ );
++ sync_master = xpd;
++ if(!sync_master) {
++ external_sync(NULL);
++ if(!timer_pending(&xpp_timer)) {
++ xpp_timer.function = xpp_tick;
++ xpp_timer.data = 0;
++ 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);
++ }
++}
++
++void xpp_tick(unsigned long param)
++{
+ xbus_t *xbus;
-+ xpd_t *xpd;
++ xpd_t *the_xpd = (xpd_t *)param;
+ int i;
+ int j;
+
-+ mod_timer(&xpp_timer, jiffies + 1); /* Must be 1KHz rate */
++ if(!the_xpd) { /* Called from timer */
++#if 0
++ static int rate_limit = 0;
++ if(rate_limit++ % 1000 == 0)
++ DBG("FROM_TIMER\n");
++#endif
++ mod_timer(&xpp_timer, jiffies + 1); /* Must be 1KHz rate */
++ }
++ else if(the_xpd != sync_master)
++ return;
++ /* Statistics */
++ if((xpp_timer_count % SAMPLE_TICKS) == 0) {
++ xpp_last_jiffies = jiffies;
++ }
++ xpp_timer_count++;
++
+ for(i = 0; i < MAX_BUSES; i++) {
-+ xbus = xbuses_array[i];
++ xbus = xbus_of(i);
+ if(!xbus)
+ continue;
+ if (!xbus->hardware_exists)
@@ -2986,13 +4763,16 @@
+ continue; // optimize, but zttool loopback won't function
+#endif
+ for(j = 0; j < MAX_XPDS; j++) {
-+ xpd = xbus->xpds[j];
++ xpd_t *xpd = xbus->xpds[j];
++
+ if(!xpd)
+ continue;
+ xpd->timer_count++;
-+ xpd_blink_leds(xpd);
+ if(xpd->state != XPD_STATE_ACTIVE)
+ continue;
++ if(!SPAN_REGISTERED(xpd))
++ continue;
++ xpd_blink_leds(xpd);
+ if(xpd->direction == TO_TRUNK)
+ xpp_ring_generate(xpd);
+ xpp_transmitprep(xpd);
@@ -3016,7 +4796,8 @@
+ * registration to zaptel is done "off-line" by posting a registration to the
+ * "reg" workqueue that calls this function.
+ */
-+void xpd_initialize(void *data) {
++void xpd_initialize(void *data)
++{
+ xpd_t *xpd = (xpd_t *)data;
+ xbus_t *xbus;
+
@@ -3027,43 +4808,37 @@
+ xbus = xpd->xbus;
+#ifdef CONFIG_PROC_FS
+ DBG("Creating xpd proc file %s.\n", xpd->xpdname);
-+ xpd->xpd_proc = create_proc_read_entry(xpd->xpdname, 0644, xpd->xbus->procdir,
++ xpd->xpd_proc = create_proc_read_entry(xpd->xpdname, 0644, xbus->procdir,
+ xpd_read_proc, xpd);
+ if(!xpd->xpd_proc) {
+ ERR("Failed to create proc file for xpd %s\n", xpd->xpdname);
+ return;
+ }
++ {
++ char fname[NAME_MAX];
++
++ snprintf(fname, NAME_MAX, PROC_SLIC_FNAME, xpd->xpdname);
++ DBG("Creating xpd slic file %s.\n", fname);
++ xpd->xpd_slic = create_proc_entry(fname, 0644, xbus->procdir);
++ if(!xpd->xpd_slic) {
++ ERR("Failed to create proc file for SLIC xpd %s\n", fname);
++ return;
++ }
++ xpd->xpd_slic->write_proc = proc_xpd_slic_write;
++ xpd->xpd_slic->read_proc = proc_xpd_slic_read;
++ xpd->xpd_slic->data = xpd;
++ }
+#endif
+ list_add(&xpd->xpd_list, &xpd_list);
+ xbus->xpds[xpd->id] = xpd;
+ xbus->num_xpds++;
-+ CALL_PROTO(SLIC_INIT, xbus, xpd);
++ CALL_XMETHOD(card_init, xbus, xpd);
+ // Turn off all channels
-+ CALL_PROTO(CHAN_ENABLE, xbus, xpd, 0xFF, 0);
-+// CALL_PROTO(LED, xbus, xpd, 0xFF, 1, 0); // FIXME: Show activated 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_PROTO(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
-+ DBG("Registering span of %s.\n", xpd->xpdname);
-+ if(zt_register(&xpd->span, 1)) {
-+ 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--;
-+ xpd->state = XPD_STATE_ZAPTEL_ERR;
-+ return;
-+ }
-+#if 0
-+ {
-+ static char buf[ZT_CHUNKSIZE] = { 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67 }; /* silence */
-+ // static char buf[ZT_CHUNKSIZE] = { 0x7F, 0xBE, 0xD8, 0xBE, 0x80, 0x41, 0x24, 0x41 }; /* Dima */
-+ CALL_PROTO(PCM_GEN, xbus, xpd->id, pcm_gen, buf);
-+ }
-+#endif
-+
-+ atomic_inc(&xpd->span_registered);
-+
-+ xpd->state = XPD_STATE_ACTIVE;
++ CALL_XMETHOD(CHAN_ENABLE, xbus, xpd, xpd->enabled_chans, 1);
++ xpd_zaptel_register(xpd);
+}
+
+void init_xbus_packet_queue(packet_queue_t *q, const char name[])
@@ -3183,7 +4958,9 @@
+ int len = 0;
+ xpd_t *xpd = data;
+ xbus_t *xbus;
++#if SOFT_SIMULATOR
+ struct xpd_sim *sim;
++#endif
+ int channels;
+ int i;
+
@@ -3191,12 +4968,15 @@
+ goto out;
+
+ xbus = xpd->xbus;
++#if SOFT_SIMULATOR
+ sim = &xbus->sim[xpd->id];
++#endif
+ channels = xpd->channels;
-+ len += sprintf(page + len, "%s (%s ,state=%d, span_registered=%d)\n"
++ len += sprintf(page + len, "%s (%s ,state=%d, span_registered=%s)%s\n"
+ "timer_count: %d span->mainttimer=%d\n"
+ ,
-+ xpd->xpdname, xpd_type_names[xpd->type], xpd->state, atomic_read(&xpd->span_registered),
++ xpd->xpdname, xpd_type_names[xpd->type], xpd->state, (SPAN_REGISTERED(xpd))?"yes":"no",
++ (xpd == sync_master) ? " SYNCER" : "",
+ xpd->timer_count, xpd->span.mainttimer
+ );
+ len += sprintf(page + len, "STATES:");
@@ -3204,26 +4984,39 @@
+ 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++) {
++ len += sprintf(page + len, "%d ", IS_SET(xpd->digital_outputs, i));
++ }
+ len += sprintf(page + len, "\n\t%-17s: ", "hookstate");
+ for(i = 0; i < channels; 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++) {
+ len += sprintf(page + len, "%d ", xpd->ringing[i]);
+ }
+#if 1
-+ len += sprintf(page + len, "\nreadchunk: ");
-+ for(i = 0; i < channels; i++) {
-+ struct zt_chan *chans = xpd->span.chans;
-+ int j;
++ if(SPAN_REGISTERED(xpd)) {
++ len += sprintf(page + len, "\nreadchunk: ");
++ for(i = 0; i < channels; i++) {
++ struct zt_chan *chans = xpd->span.chans;
++ byte chunk[ZT_CHUNKSIZE];
++ int j;
+
-+ len += sprintf(page + len, "\n\tport %2d> ", i);
-+ for(j = 0; j < ZT_CHUNKSIZE; j++) {
-+ len += sprintf(page + len, "%02X ", chans[i].readchunk[j]);
++ memcpy(chunk, chans[i].readchunk, ZT_CHUNKSIZE);
++ len += sprintf(page + len, "\n\tport %2d> ", i);
++ for(j = 0; j < ZT_CHUNKSIZE; j++) {
++ len += sprintf(page + len, "%02X ", chunk[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");
@@ -3231,11 +5024,14 @@
+ len += sprintf(page + len, "%d ", IS_SET(sim->hookstate, i));
+ }
+ }
++#endif
+#if 0
-+ len += sprintf(page + len, "\nSignalling:\n");
-+ for(i = 0; i < channels; 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);
++ if(SPAN_REGISTERED(xpd)) {
++ len += sprintf(page + len, "\nSignalling:\n");
++ for(i = 0; i < channels; 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);
++ }
+ }
+#endif
+ len += sprintf(page + len, "\nCOUNTERS:\n");
@@ -3259,28 +5055,31 @@
+
+#endif
+
-+static int span_init(xpd_t *xpd);
-+
-+xpd_t *xpd_new(xbus_t *xbus, int xpd_num, xpd_type_t type)
++xpd_t *xpd_new(xbus_t *xbus, int xpd_num, xpd_type_t type, byte revision)
+{
-+ int ret;
+ unsigned long flags;
-+ int channels;
-+ xpd_t *xpd = NULL;
++ xpd_t *xpd = NULL;
++ xops_t *xops;
+
+ spin_lock_irqsave(&xbus->lock, flags);
-+ INFO("New XPD #%d detected on xbus %s\n", xpd_num, xbus->busname);
++ INFO("New XPD #%d (Revision %d.%d) detected on xbus %s\n",
++ xpd_num, revision / 10, revision % 10, xbus->busname);
+ if(!VALID_XPD_NUM(xpd_num)) {
-+ ERR("xpd_new: illegal xpd id = %d\n", xpd_num);
++ ERR("%s: illegal xpd id = %d\n", __FUNCTION__, xpd_num);
+ goto err;
+ }
++ if((xops = get_xops(type)) == NULL) {
++ ERR("%s: no xops for type=%d\n", __FUNCTION__, type);
++ goto err;
++ }
+ if((xpd = kmalloc(sizeof(xpd_t), GFP_ATOMIC)) == NULL) {
-+ ERR("xpd_new: Unable to allocate memory for xpd\n");
++ ERR("%s: Unable to allocate memory for xpd\n", __FUNCTION__);
+ goto err;
+ }
+ memset(xpd, 0, sizeof(xpd_t));
+
+ spin_lock_init(&xpd->lock);
++ xpd->xops = xops;
+ xpd->xbus = xbus;
+ xpd->id = xpd_num;
+ xpd->chans = NULL;
@@ -3289,50 +5088,47 @@
+ xpd->hookstate = 0x0; /* ONHOOK */
+ xpd->type = type;
+ xpd->enabled_chans = enabled_channels[xpd_num];
++ xpd->digital_outputs = 0;
++ atomic_set(&xpd->open_counter, 0);
+
-+ switch(xpd->type) {
-+ case XPD_TYPE_FXS:
-+ channels = xpd->channels = min(8, CHANNELS_PERXPD);
-+ xpd->direction = TO_PHONE;
-+ break;
-+ case XPD_TYPE_FXO:
-+ channels = xpd->channels = min(8, CHANNELS_PERXPD);
-+ xpd->direction = TO_TRUNK;
-+ break;
-+#if 0
-+ case XPD_TYPE_E1:
-+ channels = xpd->channels = CHANNELS_PERXPD;
-+ break;
-+#endif
-+ case XPD_TYPE_NOMODULE:
-+ default:
-+ ERR("%s: bad xpd->type=0x%X\n", __FUNCTION__, xpd->type);
-+ goto err;
-+ }
-+
+ INIT_WORK(&xpd->xpd_post_init, xpd_initialize, xpd);
+
++ CALL_XMETHOD(card_new, xbus, xpd, revision);
++ if(xpd_setup(xpd) != 0)
++ goto err;
++
++ spin_unlock_irqrestore(&xbus->lock, flags);
++ return xpd;
++err:
++ spin_unlock_irqrestore(&xbus->lock, flags);
++ if(xpd->chans)
++ kfree((void *)xpd->chans);
++ if(xpd->writechunk)
++ kfree((void *)xpd->writechunk);
++ if(xpd)
++ kfree(xpd);
++ return NULL;
++}
++
++int xpd_setup(xpd_t *xpd)
++{
++ xpd->chans = kmalloc(sizeof(struct zt_chan)*xpd->channels, GFP_ATOMIC);
++ if (xpd->chans == NULL) {
++ ERR("%s: Unable to allocate channels\n", __FUNCTION__);
++ return -ENOMEM;
++ }
+ /* 8 channels, double buffer, Read/Write */
+ int need = ZT_MAX_CHUNKSIZE * CHANNELS_PERXPD * 2 * 2;
+ if((xpd->writechunk = kmalloc(need, GFP_ATOMIC)) == NULL) {
-+ ERR("xpd_new: Unable to allocate memory for writechunks\n");
-+ goto err;
++ ERR("%s: Unable to allocate memory for writechunks\n", __FUNCTION__);
++ kfree(xpd->chans);
++ xpd->chans = NULL;
++ return -ENOMEM;
+ }
+ /* Initialize Write/Buffers to all blank data */
+ memset((void *)xpd->writechunk, 0x00, need);
+ xpd->readchunk = xpd->writechunk + ZT_CHUNKSIZE * CHANNELS_PERXPD * 2;
+
-+ if((ret = span_init(xpd)) < 0) {
-+ ERR("Unable to initialize new span\n");
-+ goto err;
-+ }
-+ DBG("Queueing xpd_post_init for xpd %d\n", xpd->id);
-+ if(!queue_work(xpd_init_workqueue, &xpd->xpd_post_init)) {
-+ ERR("Failed to queue xpd_post_init work\n");
-+ goto err;
-+ }
-+
-+
+#if 0
+ /*
+ * Is it nessessary?
@@ -3345,41 +5141,42 @@
+ }
+ }
+#endif
-+ spin_unlock_irqrestore(&xbus->lock, flags);
-+ return xpd;
-+err:
-+ spin_unlock_irqrestore(&xbus->lock, flags);
-+ if(xpd->writechunk)
-+ kfree((void *)xpd->writechunk);
-+ if(xpd)
-+ kfree(xpd);
-+ return NULL;
++
++ DBG("Queueing xpd_post_init for xpd %d\n", xpd->id);
++ if(!queue_work(xpd_init_workqueue, &xpd->xpd_post_init)) {
++ ERR("Failed to queue xpd_post_init work\n");
++ return -EINVAL;
++ }
++ return 0;
+}
+
-+static void xpd_remove(xbus_t *xbus, xpd_t *xpd)
++void xpd_remove(xpd_t *xpd)
+{
-+ BUG_ON(xpd == NULL);
-+ BUG_ON(xbus == NULL);
-+ BUG_ON(xpd->xbus != xbus); // xpd belong to another xbus
++ xbus_t *xbus;
++
++ BUG_ON(!xpd);
++ xbus = xpd->xbus;
+ INFO("Remove XPD #%d from xbus=%s\n", xpd->id, xbus->busname);
+ xpd->state = XPD_STATE_OFF;
-+ if (atomic_read(&xpd->span_registered)) {
-+ zt_unregister(&xpd->span);
-+ atomic_dec(&xpd->span_registered);
-+ }
-+ if(xpd->chans) { /* Already registered */
-+ kfree(xpd->chans);
-+ }
++ xpd_zaptel_unregister(xpd);
+#ifdef CONFIG_PROC_FS
+ if(xpd->xpd_proc) {
+ DBG("Removing proc entry %s\n", xpd->xpdname);
+ remove_proc_entry(xpd->xpdname, xbus->procdir);
+ }
++ if(xpd->xpd_slic) {
++ char fname[NAME_MAX];
++
++ snprintf(fname, NAME_MAX, PROC_SLIC_FNAME, xpd->xpdname);
++ DBG("Removing proc entry %s\n", fname);
++ remove_proc_entry(fname, xbus->procdir);
++ }
+#endif
+ xbus->xpds[xpd->id] = NULL;
+ list_del(&xpd->xpd_list);
+ xbus->num_xpds--;
+ cancel_delayed_work(&xpd->xpd_post_init);
++ CALL_XMETHOD(card_remove, xbus, xpd);
+ kfree((void *)xpd->writechunk);
+ kfree(xpd);
+}
@@ -3388,6 +5185,10 @@
+{
+ struct zt_span *span = &xpd->span;
+
++ if(!SPAN_REGISTERED(xpd)) {
++ NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
++ return;
++ }
+ switch (alarm_flag) {
+ case ZT_ALARM_NONE:
+ xpd->state = XPD_STATE_ACTIVE;
@@ -3412,11 +5213,15 @@
+ int i;
+ unsigned long flags;
+
++ spin_lock_irqsave(&xpd->lock, flags);
+ if(xpd->direction != TO_PHONE) {
+ ERR("%s: %s: Only FXS can report hookstate changes\n", __FUNCTION__, xpd->xpdname);
-+ return;
++ goto out;
+ }
-+ spin_lock_irqsave(&xpd->lock, flags);
++ 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++) {
+ struct zt_chan *chan = &xpd->span.chans[i];
@@ -3425,17 +5230,18 @@
+ xpd->ringing[i] = 0;
+ BIT_SET(xpd->hookstate, i);
+ zt_hooksig(chan, ZT_RXSIG_OFFHOOK);
-+ CALL_PROTO(CHAN_POWER, xpd->xbus, xpd, (1 << i), 0); // Power down (prevent overheating!!!)
-+ CALL_PROTO(LED, xpd->xbus, xpd, (1 << i), 0, 1);
++ CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!)
++ CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 1);
+ } else if(!IS_SET(fxs_off_hook, i) && IS_SET(xpd->hookstate, i)) { // ONHOOK
+ DBG("ONHOOK channo=%d\n", chan->channo);
+ xpd->ringing[i] = 0;
+ BIT_CLR(xpd->hookstate, i);
+ zt_hooksig(chan, ZT_RXSIG_ONHOOK);
-+ CALL_PROTO(CHAN_POWER, xpd->xbus, xpd, (1 << i), 0); // Power down (prevent overheating!!!)
-+ CALL_PROTO(LED, xpd->xbus, xpd, (1 << i), 0, 0);
++ CALL_XMETHOD(CHAN_POWER, xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!)
++ CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
+ }
+ }
++out:
+ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
@@ -3446,22 +5252,24 @@
+
+ BUG_ON(!xpd);
+
++ spin_lock_irqsave(&xpd->lock, flags);
+ for(i = 0; i < xpd->channels; i++) {
-+ spin_lock_irqsave(&xpd->lock, flags);
++ if(IS_SET(xpd->digital_outputs, i))
++ continue;
+ if(xpd->ringing[i]) {
+ // led state is toggled
+ if((xpd->timer_count % LED_BLINK_PERIOD) == 0) {
-+ DBG("%s pos=%d =%d led_on=%d\n", xpd->xpdname, i, xpd->ringing[i], xpd->led_on[i]);
++ 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_PROTO(LED, xpd->xbus, xpd, (1 << i), 0, 1);
++ CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 1);
+ } else {
-+ CALL_PROTO(LED, xpd->xbus, xpd, (1 << i), 0, 0);
++ 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);
+ }
++ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+static void xpp_ring_generate(xpd_t *xpd)
@@ -3472,17 +5280,20 @@
+
+ BUG_ON(!xpd);
+
++ spin_lock_irqsave(&xpd->lock, flags);
+ if(xpd->direction != TO_TRUNK && ((bug_counter++ % 1000) == 0)) {
+ ERR("%s: %s: Only FXO can report ring changes\n", __FUNCTION__, xpd->xpdname);
-+ return;
++ goto out;
+ }
-+
++ if(!SPAN_REGISTERED(xpd)) {
++ NOTICE("%s: %s is not registered. Skipping.\n", __FUNCTION__, xpd->xpdname);
++ goto out;
++ }
+ /*
+ * Ring detect logic:
+ * fxo_power is toggled
+ */
+ for(i = 0; i < xpd->channels; i++) {
-+ spin_lock_irqsave(&xpd->lock, flags);
+ if(xpd->ringing[i] || xpd->ringer_on[i]) {
+ // ring state is only changed once per second:
+ if((xpd->timer_count % 1000) == 0) {
@@ -3498,8 +5309,9 @@
+ xpd->ringing[i]=0;
+ }
+ }
-+ spin_unlock_irqrestore(&xpd->lock, flags);
+ }
++out:
++ spin_unlock_irqrestore(&xpd->lock, flags);
+}
+
+/*------------------------- Bus Management -------------------------*/
@@ -3562,6 +5374,7 @@
+ 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];
@@ -3569,6 +5382,7 @@
+ 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",
@@ -3589,6 +5403,142 @@
+
+}
+
++int proc_sync_read(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++ int len = 0;
++
++ if(!sync_master)
++ len += sprintf(page + len, "HOST\n");
++ else
++ len += sprintf(page + len, "%s/%s\n", sync_master->xbus->busname, sync_master->xpdname);
++ len += sprintf(page + len, "xpp_timer_count=%d\n", xpp_timer_count);
++ unsigned int xpp_timer_rate = 0;
++ unsigned int 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, "xpp_timer_rate=%d\n", xpp_timer_rate);
++ }
++ if (len <= off+count)
++ *eof = 1;
++ *start = page + off;
++ len -= off;
++ if (len > count)
++ len = count;
++ if (len < 0)
++ len = 0;
++ return len;
++}
++
++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;
++ int xpd_num;
++ xbus_t *xbus;
++ xpd_t *xpd;
++ int ret;
++
++ 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);
++ goto out;
++ }
++ ret = sscanf(buf, "%d %d", &xbus_num, &xpd_num);
++ if(ret != 2)
++ return -EINVAL;
++ DBG("%s: %d/%d\n", __FUNCTION__, xbus_num, xpd_num);
++ if(xbus_num >= MAX_BUSES)
++ return -EINVAL;
++ xbus = xbus_of(xbus_num);
++ if(!xbus)
++ 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);
++out:
++ return count;
++}
++
++int proc_xbus_ztregister_read(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, "# To (un)register an XPD write into this file: <ID> <1/0>\n");
++ len += sprintf(page + len, "# ID\tExists\tRegistered\n");
++ for(i = 0; i < MAX_XPDS; i++) {
++ xpd_t *xpd = xbus->xpds[i];
++ bool registered = xpd && SPAN_REGISTERED(xpd);
++ len += sprintf(page + len, "%d\t%s\t%s\n", i, (xpd)?"yes":"no", (registered)?"yes":"no");
++ }
++ 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;
++}
++
++static int proc_xbus_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
++{
++ xbus_t *xbus = data;
++ xpd_t *xpd;
++ int xpd_num;
++ const int NUM_SIZE = 100;
++ char buf[NUM_SIZE];
++ bool zt_reg;
++ int ret;
++
++ BUG_ON(!xbus);
++ if(count >= NUM_SIZE)
++ return -EINVAL;
++ if(copy_from_user(buf, buffer, count))
++ return -EFAULT;
++ buf[count] = '\0';
++ ret = sscanf(buf, "%d %d", &xpd_num, &zt_reg);
++ if(ret != 2)
++ return -EINVAL;
++ xpd = xpd_of(xbus, xpd_num);
++ if(!xpd) {
++ ERR("%s: XPD number %d does not exist\n", __FUNCTION__, xpd_num);
++ return -ENXIO;
++ }
++ DBG("%s: %s: xpd #%d %s\n", __FUNCTION__, xbus->busname, xpd_num, (zt_reg) ? "register" : "unregister");
++ if(zt_reg)
++ ret = xpd_zaptel_register(xpd);
++ else
++ ret = xpd_zaptel_unregister(xpd);
++ return (ret < 0) ? ret : count;
++}
++
++int xpd_slic_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
++{
++ xpd_t *xpd = data;
++
++ BUG_ON(!xpd);
++ return count;
++}
++
+#endif
+
+/**
@@ -3622,6 +5572,22 @@
+ ret = -EINVAL;
+ goto error;
+ }
++#if 0
++ // DEBUG: For Dima
++ if(pack_tx->content.opcode == XPP_PCM_WRITE) {
++ static int rate_limit;
++ static int count;
++
++ if(sync_master == NULL)
++ count = 0;
++ if(count++ > 5) {
++ ret = 0;
++ goto error;
++ }
++ if(rate_limit++ % 1000 == 0)
++ INFO("DEBUG: TRANSMIT (PCM_WRITE)\n");
++ }
++#endif
+ if(down_read_trylock(&xbus->in_use)) {
+ ret = xbus->ops->packet_send(xbus, pack_tx);
+ XBUS_COUNTER(xbus, TX_BYTES) += pack_tx->datalen;
@@ -3669,7 +5635,7 @@
+ continue;
+ }
+ DBG(" Polling slot %d %s\n", id, xbus->busname);
-+ ret = CALL_PROTO(DESC_REQ, xbus, NULL, id);
++ 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);
+ }
@@ -3684,6 +5650,7 @@
+}
+
+
++#if SOFT_SIMULATOR
+/*
+ * Assume xbus->lock is held
+ */
@@ -3716,6 +5683,7 @@
+ first = !first;
+ }
+}
++#endif
+
+void xbus_activate(xbus_t *xbus)
+{
@@ -3750,13 +5718,15 @@
+ xbus->hardware_exists = 0;
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
-+ if(xpd) {
-+ if(xpd->id != i) {
-+ ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
-+ continue;
-+ }
-+ update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
++ if(!xpd)
++ continue;
++ if(xpd->id != i) {
++ ERR("%s: BUG: xpd->id=%d != i=%d\n", __FUNCTION__, xpd->id, i);
++ continue;
+ }
++ if (!SPAN_REGISTERED(xpd))
++ continue;
++ update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
+ }
+ down_write(&xbus->in_use);
+ DBG("%s (deactivated)\n", xbus->busname);
@@ -3776,6 +5746,11 @@
+ remove_proc_entry(PROC_XBUS_SUMMARY, xbus->procdir);
+ xbus->procsummary = NULL;
+ }
++ if(xbus->proc_ztregister) {
++ DBG("Removing proc entry " PROC_XBUS_ZTREGISTER ".\n");
++ remove_proc_entry(PROC_XBUS_ZTREGISTER, xbus->procdir);
++ xbus->proc_ztregister = NULL;
++ }
+ DBG("Removing proc entry %s.\n",xbus->busname);
+ remove_proc_entry(xbus->busname, xpp_procdir);
+ xbus->procdir = NULL;
@@ -3818,6 +5793,8 @@
+ 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);
@@ -3825,12 +5802,11 @@
+ goto nobus;
+ }
+ init_xbus_packet_queue(&xbus->sim_packet_queue, "SIM_PACKET_QUEUE");
-+ xbus->num_xpds = 0;
+ INIT_WORK(&xbus->sim_work, process_sim_queue, xbus);
-+ INIT_WORK(&xbus->poll_work, process_xbus_poll, xbus);
-+ xbus_reset_counters(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->procdir = proc_mkdir(xbus->busname, xpp_procdir);
@@ -3842,10 +5818,19 @@
+ xbus->procsummary = create_proc_read_entry(PROC_XBUS_SUMMARY, 0644, xbus->procdir,
+ xbus_read_proc, xbus);
+ if (!xbus->procsummary) {
-+ ERR("Failed to create proc read entry for xbus %s\n", xbus->busname);
++ ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_SUMMARY, xbus->busname);
+ err = -EIO;
+ goto nobus;
+ }
++ xbus->proc_ztregister = create_proc_entry(PROC_XBUS_ZTREGISTER, 0644, xbus->procdir);
++ if (!xbus->proc_ztregister) {
++ ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_ZTREGISTER, xbus->busname);
++ err = -EIO;
++ goto nobus;
++ }
++ xbus->proc_ztregister->data = xbus;
++ xbus->proc_ztregister->read_proc = proc_xbus_ztregister_read;
++ xbus->proc_ztregister->write_proc = proc_xbus_ztregister_write;
+#endif
+ return xbus;
+nobus:
@@ -3862,36 +5847,44 @@
+ int i;
+ unsigned long flags;
+
-+ DBG("\n");
+ BUG_ON(!xbus);
++ DBG("%s\n", xbus->busname);
+ spin_lock_irqsave(&xbuses_lock, flags);
-+ BUG_ON(xbus != xbuses_array[xbus->num]);
++ 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);
-+ cancel_delayed_work(&xbus->poll_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) {
++ 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(xbus, xpd);
++ BUG_ON(!xops->card_remove);
++ 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) {
@@ -3916,7 +5909,7 @@
+ int channels = xpd->channels;
+ struct zt_chan *chans = xpd->span.chans;
+
-+// if((xpd->timer_count % PREP_REPORT_RATE) == 0)
++// if((xpd->timer_count % PREP_REPORT_RATE) < 10)
+// DBG("%d\n", xpd->timer_count);
+
+// if(xpd->hookstate == 0)
@@ -3932,13 +5925,15 @@
+ for (i = 0; i < channels; i++) {
+ if(IS_SET(xpd->hookstate, i)) {
+ memcpy((u_char *)w, chans[i].writechunk, ZT_CHUNKSIZE);
-+ // fill_beep((u_char *)w, 2);
++ // fill_beep((u_char *)w, 5);
+ }
+ w += ZT_CHUNKSIZE;
+ }
-+ ret = CALL_PROTO(PCM_WRITE, xpd->xbus, xpd, xpd->hookstate, writechunk);
-+ if(ret < 0) {
-+ DBG("failed to write PCM %d\n", ret);
++ 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);
++ }
+ }
+}
+
@@ -3952,9 +5947,9 @@
+ 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, 0xCD, 0xC5, 0xCD, 0xFF, 0x49, 0x41, 0x49, /* Dima 2 */
-+ 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, /* silence */
++ 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 */
+ };
+ memcpy(buf, &beep[(which*8) % ARRAY_SIZE(beep)], ZT_CHUNKSIZE);
+}
@@ -3983,7 +5978,7 @@
+ readchunk += ZT_CHUNKSIZE;
+ }
+
-+#if 1
++#if 0
+ /* FIXME: need to Echo cancel double buffered data */
+ for (i = 0;i < xpd->span.channels; i++) {
+ zt_ec_chunk(&chans[i], chans[i].readchunk, xpd->ec_chunk2[i]);
@@ -4022,7 +6017,7 @@
+ return 0;
+}
+
-+static int xpp_open(struct zt_chan *chan)
++int xpp_open(struct zt_chan *chan)
+{
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus = xpd->xbus;
@@ -4030,12 +6025,13 @@
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ xbus->open_counter++;
++ atomic_inc(&xpd->open_counter);
+ DBG("chan=%d (open_counter=%d)\n", chan->chanpos, xbus->open_counter);
+ spin_unlock_irqrestore(&xbus->lock, flags);
+ return 0;
+}
+
-+static int xpp_close(struct zt_chan *chan)
++int xpp_close(struct zt_chan *chan)
+{
+ xpd_t *xpd = chan->pvt;
+ xbus_t *xbus = xpd->xbus;
@@ -4044,6 +6040,7 @@
+
+ spin_lock_irqsave(&xbus->lock, flags);
+ xbus->open_counter--;
++ atomic_dec(&xpd->open_counter);
+ if (!xbus->hardware_exists && xbus->open_counter == 0)
+ should_remove = 1;
+ spin_unlock_irqrestore(&xbus->lock, flags);
@@ -4054,25 +6051,36 @@
+ return 0;
+}
+
-+static int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
++int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg)
+{
+ xpd_t *xpd = chan->pvt;
+ int pos = chan->chanpos - 1;
+ int x;
+
+ switch (cmd) {
-+ case ZT_ONHOOKTRANSFER:
-+ if (get_user(x, (int *)arg))
-+ return -EFAULT;
-+ DBG("xpd=%d: ZT_ONHOOKTRANSFER (%d millis) chan=%d\n", xpd->id, x, pos);
-+ break;
-+ default:
-+ 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));
-+ DBG(" IOC_NR=0x%02X\n", _IOC_NR(cmd));
-+ DBG(" IOC_SIZE=0x%02X\n", _IOC_SIZE(cmd));
-+ return -ENOTTY;
++ case ZT_ONHOOKTRANSFER:
++ if (get_user(x, (int *)arg))
++ return -EFAULT;
++ if (xpd->lasttxhook[pos] == 0x1) {
++ /* Apply the change if appropriate */
++ xpd->lasttxhook[pos] = 0x2;
++ // 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;
++ case ZT_TONEDETECT:
++ if (get_user(x, (int *)arg))
++ return -EFAULT;
++ DBG("xpd=%d: ZT_TONEDETECT chan=%d: TONEDETECT_ON=%d TONEDETECT_MUTE=%d\n",
++ xpd->id, pos, (x & ZT_TONEDETECT_ON), (x & ZT_TONEDETECT_MUTE));
++ return -ENOTTY;
++ default:
++ 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));
++ DBG(" IOC_NR=0x%02X\n", _IOC_NR(cmd));
++ DBG(" IOC_SIZE=0x%02X\n", _IOC_SIZE(cmd));
++ return -ENOTTY;
+ }
+ return 0;
+}
@@ -4097,9 +6105,14 @@
+ DBG("Got ZT_START for FXS channel %d, treated as ZT_RING\n", pos);
+ //hookstate = ZT_TXSIG_RING;
+
++ 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_PROTO(RING, xbus, xpd->id, (1 << pos));
++ ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
+ if(ret) {
+ DBG("ZT_RING Failed: ret=0x%02X\n", ret);
+ return ret;
@@ -4120,12 +6133,17 @@
+ DBG("ZT_TXSIG_OFFHOOK: %s hookstate=0x%04X\n", chan->name, xpd->hookstate);
+ BIT_SET(xpd->hookstate, pos);
+ xpd->ringing[pos] = 0;
-+ ret = CALL_PROTO(SETHOOK, xbus, xpd->id, xpd->hookstate);
++ 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_PROTO(LED, xpd->xbus, xpd, (1 << i), 0, 0);
++ CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
+ break;
+ //DBG("ZT_TXSIG_OFFHOOK %d\n", pos);
+ //BIT_SET(xpd->hookstate, pos);
@@ -4137,13 +6155,18 @@
+ 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_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_PROTO(SETHOOK, xbus, xpd->id, xpd->hookstate);
++ ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
+ if(ret) {
+ DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
+ break;
+ }
-+ CALL_PROTO(LED, xpd->xbus, xpd, (1 << i), 0, 0);
++ CALL_XMETHOD(LED, xpd->xbus, xpd, BIT(i), LED_GREEN, 0);
+ break;
+ //DBG("ZT_TXSIG_ONHOOK: %d\n", pos);
+ //BIT_CLR(xpd->hookstate, pos);
@@ -4152,7 +6175,7 @@
+ DBG("hooksig: unkown txsig=%d on channel %d\n", txsig, pos);
+ return -EINVAL;
+ }
-+ //ret = CALL_PROTO(SETHOOK, xbus, xpd->id, xpd->hookstate);
++ //ret = CALL_XMETHOD(SETHOOK, xbus, xpd->id, xpd->hookstate);
+ //if(ret) {
+ // DBG("ZT_TXSIG_START Failed: ret=0x%02X\n", ret);
+ //}
@@ -4160,7 +6183,7 @@
+}
+#endif
+
-+int xpp_sethook(struct zt_chan *chan, int hookstate)
++static int xpp_sethook(struct zt_chan *chan, int hookstate)
+{
+ int pos = chan->chanpos - 1;
+ xpd_t *xpd = chan->pvt;
@@ -4172,19 +6195,26 @@
+ return -EINVAL;
+ }
+ xbus = xpd->xbus;
-+ // DBG("%s (%d) (old=0x%04X, hook-command=%d)\n", chan->name, pos, xpd->hookstate, hookstate);
++ 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_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_PROTO(RING, xbus, xpd, pos, 0); // RING off
++ ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+#endif
-+ ret = CALL_PROTO(CHAN_POWER, xbus, xpd, (1 << pos), 0); // Power down (prevent overheating!!!)
++ 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;
@@ -4193,7 +6223,7 @@
+ 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_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
++ ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
+ if(ret) {
+ DBG("ZT_ONHOOK Failed: ret=0x%02X\n", ret);
+ break;
@@ -4211,7 +6241,7 @@
+ 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_PROTO(SETHOOK, xbus, xpd, xpd->hookstate);
++ ret = CALL_XMETHOD(SETHOOK, xbus, xpd, xpd->hookstate);
+ if(ret) {
+ DBG("ZT_OFFHOOK Failed: ret=0x%02X\n", ret);
+ break;
@@ -4226,9 +6256,14 @@
+ 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_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_PROTO(CHAN_POWER, xbus, xpd, (1 << pos), 1); // Power up (for ring)
-+ ret = CALL_PROTO(RING, xbus, xpd, pos, 1); // RING on
++ 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);
+ }
@@ -4248,18 +6283,20 @@
+int xpp_setchunksize(struct zt_span *span, int chunksize);
+
+/* Enable maintenance modes */
-+static int xpp_maint(struct zt_span *span, int cmd)
++int xpp_maint(struct zt_span *span, int cmd)
+{
+ xpd_t *xpd = span->pvt;
+ int ret = 0;
++#if 0
+ char loopback_data[] = "THE-QUICK-BROWN-FOX-JUMPED-OVER-THE-LAZY-DOG";
++#endif
+
+ BUG_ON(!xpd);
+ DBG("%s: span->mainttimer=%d\n", __FUNCTION__, span->mainttimer);
+ switch(cmd) {
+ case ZT_MAINT_NONE:
+ printk("XXX Turn off local and remote loops XXX\n");
-+ CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, 1, 0); // FIXME: Find usage for extra LED
++ 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");
@@ -4269,12 +6306,12 @@
+ break;
+ case ZT_MAINT_LOOPUP:
+ printk("XXX Send loopup code XXX\n");
-+ CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, 1, 1); // FIXME: Find usage for extra LED
-+ CALL_PROTO(LOOPBACK_AX, xpd->xbus, xpd, loopback_data, ARRAY_SIZE(loopback_data));
++ 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_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, 1, 0); // FIXME: Find usage for extra LED
++ 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");
@@ -4289,7 +6326,6 @@
+ return ret;
+}
+
-+
+/* Set signalling type (if appropriate) */
+static int xpp_chanconfig(struct zt_chan *chan, int sigtype)
+{
@@ -4338,26 +6374,39 @@
+}
+#endif
+
-+#if 0
-+static void dump_xpp(xpd_t *xpd, const char *msg)
++/**
++ * Unregister an xpd from zaptel and release related resources
++ * @xpd The xpd to be unregistered
++ * @returns 0 on success, errno otherwise
++ *
++ * Checks that nobody holds an open channel.
++ *
++ * Called by:
++ * - User action through /proc
++ * - During xpd_remove()
++ */
++static int xpd_zaptel_unregister(xpd_t *xpd)
+{
-+ int i;
-+ struct zt_chan *cur_chan;
-+ struct zt_span *span = &xpd->span;
++ BUG_ON(!xpd);
+
-+ DBG("xpd=%p: %s\n", xpd, msg);
-+ DBG(" Span name is: %s\n", span->name);
-+ DBG(" pvt: %p\n", span->pvt);
-+ for(i = 0; i < span->channels; i++) {
-+ cur_chan = &(span->chans[i]);
-+ DBG(" Channel %d (%p) name ='%s'\n",
-+ cur_chan->channo, cur_chan, cur_chan->name);
++ if (!SPAN_REGISTERED(xpd)) {
++ NOTICE("%s: %s is already unregistered\n", __FUNCTION__, xpd->xpdname);
++ return -EIDRM;
+ }
-+ DBG(" Parallel device: %p\n", xpd->pdev);
++ if(atomic_read(&xpd->open_counter)) {
++ NOTICE("%s: %s is busy (open_counter=%d). Skipping.\n", __FUNCTION__, xpd->xpdname, atomic_read(&xpd->open_counter));
++ return -EBUSY;
++ }
++ if(sync_master == xpd)
++ set_sync_master(NULL); // FIXME: it's better to elect a new prince
++ update_xpd_status(xpd, ZT_ALARM_NOTOPEN);
++ xpd->state = XPD_STATE_OFF;
++ mdelay(2); // FIXME: This is to give chance for transmit/receiveprep to finish.
++ zt_unregister(&xpd->span);
++ return 0;
+}
-+#endif
+
-+static int span_init(xpd_t *xpd)
++static int xpd_zaptel_register(xpd_t *xpd)
+{
+ struct zt_chan *cur_chan;
+ struct zt_span *span;
@@ -4365,19 +6414,21 @@
+ int sigfxs;
+ int i;
+ int cn;
++ xops_t *xops;
+
-+ if(!xpd)
-+ return -EINVAL;
++ BUG_ON(!xpd);
++ xops = xpd->xops;
++
++ if (SPAN_REGISTERED(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);
+
-+ xpd->chans = kmalloc(sizeof(struct zt_chan)*cn, GFP_ATOMIC);
-+ if (xpd->chans == NULL) {
-+ ERR("xpd: Unable to allocate channels\n");
-+ return -ENOMEM;
-+ }
+ memset(xpd->chans, 0, sizeof(struct zt_chan)*cn);
++ memset(&xpd->span, 0, sizeof(struct zt_span));
+
+ span = &xpd->span;
+ xbus = xpd->xbus;
@@ -4385,11 +6436,13 @@
+ 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",
@@ -4452,6 +6505,22 @@
+#endif
+
+ DBG("Finished span_load: ZT_FLAG_RUNNING=%d\n", span->flags & ZT_FLAG_RUNNING);
++
++ DBG("Registering span of %s.\n", xpd->xpdname);
++ 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--;
++ xpd->state = XPD_STATE_ZAPTEL_ERR;
++ return -ENODEV;
++ }
++ xpd->state = XPD_STATE_ACTIVE;
++ CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, xpd, 0, 0); // Query SYNC_SOURCE
++// if(xpd->id == 0)
++// set_sync_master(xpd);
++
+ return 0;
+}
+
@@ -4473,7 +6542,7 @@
+ len += sprintf(page + len, "\txpacket_count=%d\n", atomic_read(&xpacket_count));
+ len += sprintf(page + len, "\tbus_count=%d\n", bus_count);
+ for(i = 0; i < MAX_BUSES; i++) {
-+ xbus_t *xbus = xbuses_array[i];
++ xbus_t *xbus = xbus_of(i);
+
+ if(xbus) {
+ len += sprintf(page + len, "%s: HW=%s bus_type=%d connected=%s\n",
@@ -4518,10 +6587,8 @@
+ unsigned int busnum = MINOR_XBUS_NUM(minor);
+ unsigned long flags;
+
-+ if(busnum >= MAX_BUSES)
-+ return -EINVAL;
+ spin_lock_irqsave(&xbuses_lock, flags);
-+ xbus = xbuses_array[busnum];
++ xbus = xbus_of(busnum);
+ spin_unlock_irqrestore(&xbuses_lock, flags);
+ if(xbus == NULL)
+ return -ENODEV;
@@ -4552,6 +6619,7 @@
+ return 0;
+}
+
++#if 0
+static ssize_t xpp_sys_write (struct file * file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
@@ -4568,9 +6636,9 @@
+ }
+ if(count == 0)
+ return 0;
-+ if(count >= sizeof(xpp_packet_r_t)) {
++ if(count >= sizeof(xpacket_raw_t)) {
+ DBG("count=%d, partial write...\n", count);
-+ count = sizeof(xpp_packet_r_t);
++ count = sizeof(xpacket_raw_t);
+ }
+ pack_tx = xbus->ops->packet_new(xbus, GFP_KERNEL);
+ if (!pack_tx) {
@@ -4588,11 +6656,14 @@
+ packet_send(xbus, pack_tx);
+ return count;
+}
++#endif
+
+static struct file_operations xpp_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
++#if 0
+ .write = xpp_sys_write,
++#endif
+ .ioctl = xpp_sys_ioctl,
+ .open = xpp_sys_open,
+ .release = xpp_sys_release,
@@ -4607,6 +6678,7 @@
+ 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);
@@ -4639,6 +6711,14 @@
+ }
+ struct proc_dir_entry *ent;
+
++ ent = create_proc_entry(PROC_SYNC, 0644, xpp_procdir);
++ if(!ent) {
++ do_cleanup();
++ return -EFAULT;
++ }
++ ent->read_proc = proc_sync_read;
++ ent->write_proc = proc_sync_write;
++ ent->data = NULL;
+ ent = create_proc_read_entry(PROC_XBUSES, 0644, xpp_procdir, xpp_zap_read_proc, 0);
+ if (!ent) {
+ do_cleanup();
@@ -4660,22 +6740,26 @@
+
+ /* Only timer init. We add it only *after* zt_register */
+ init_timer(&xpp_timer);
-+ xpp_timer.function = xpp_timer_tick;
-+ xpp_timer.data = 0;
-+ xpp_timer.expires = jiffies + 1; /* Must be 1KHz rate */
-+ add_timer(&xpp_timer);
++ set_sync_master(NULL); /* Internal ticking */
+ return 0;
+}
+
+void __exit xpp_zap_cleanup(void)
+{
-+ unsigned long flags;
++// 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)
++ 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);
++// spin_unlock_irqrestore(&xbuses_lock, flags);
+ do_cleanup();
+}
+
@@ -4685,6 +6769,7 @@
+EXPORT_SYMBOL(xbus_deactivate);
+EXPORT_SYMBOL(xpd_of);
+EXPORT_SYMBOL(xbus_new);
++EXPORT_SYMBOL(xbus_remove);
+EXPORT_SYMBOL(xbus_reset_counters);
+EXPORT_SYMBOL(packet_send);
+EXPORT_SYMBOL(fill_beep);
@@ -4694,18 +6779,23 @@
+EXPORT_SYMBOL(drain_xbus_packet_queue);
+EXPORT_SYMBOL(update_xpd_status);
+EXPORT_SYMBOL(xpp_check_hookstate);
++EXPORT_SYMBOL(xpp_tick);
++EXPORT_SYMBOL(xpp_open);
++EXPORT_SYMBOL(xpp_close);
++EXPORT_SYMBOL(xpp_ioctl);
++EXPORT_SYMBOL(xpp_maint);
+
+MODULE_DESCRIPTION("XPP Zaptel Driver");
+MODULE_AUTHOR("Oron Peled <oron at actcom.co.il>");
+MODULE_LICENSE("GPL");
-+MODULE_VERSION("$Id: xpp_zap.c 124 2005-11-09 18:42:02Z oron $");
++MODULE_VERSION("$Id: xpp_zap.c 167 2006-01-03 12:39:36Z oron $");
+
+module_init(xpp_zap_init);
+module_exit(xpp_zap_cleanup);
-diff -urNad trunk/xpp/xpp_zap.h /tmp/dpep.oAj2YR/trunk/xpp/xpp_zap.h
---- trunk/xpp/xpp_zap.h 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/xpp_zap.h 2005-11-03 15:01:15.000000000 +0200
-@@ -0,0 +1,36 @@
+diff -urNad zaptel-1.0.10/xpp/xpp_zap.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.h
+--- zaptel-1.0.10/xpp/xpp_zap.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xpp_zap.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,44 @@
+#ifndef XPP_ZAP_H
+#define XPP_ZAP_H
+
@@ -4729,22 +6819,529 @@
+void update_xpd_status(xpd_t *xpd, int alarm_flag);
+void xpp_check_hookstate(xpd_t *xpd, xpp_line_t fxs_off_hook);
+xpd_t *xpd_of(xbus_t *xbus, int xpd_num);
-+xpd_t *xpd_new(xbus_t *xbus, int xpd_num, xpd_type_t type);
++xpd_t *xpd_new(xbus_t *xbus, int xpd_num, xpd_type_t type, byte revision);
++int xpd_setup(xpd_t *xpd);
++void xpd_remove(xpd_t *xpd);
+void fill_beep(u_char *buf, int duration);
++void xpp_tick(unsigned long param);
++int xpp_open(struct zt_chan *chan);
++int xpp_close(struct zt_chan *chan);
++int xpp_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long arg);
++int xpp_maint(struct zt_span *span, int cmd);
+
+#include <linux/proc_fs.h>
+
+#ifdef CONFIG_PROC_FS
-+extern struct proc_dir_entry *xpp_procdir;
++extern struct proc_dir_entry *xpp_procdir;
+#endif
++extern xpd_t *sync_master;
+
+// Number of rings our simulated phone will ring:
+#define RINGS_NUM 3
+
+#endif /* XPP_ZAP_H */
-diff -urNad trunk/xpp/zap_debug.c /tmp/dpep.oAj2YR/trunk/xpp/zap_debug.c
---- trunk/xpp/zap_debug.c 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/zap_debug.c 2005-11-10 04:05:18.000000000 +0200
+diff -urNad zaptel-1.0.10/xpp/xproto.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.c
+--- zaptel-1.0.10/xpp/xproto.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.c 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,244 @@
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include "xpd.h"
++#include "xproto.h"
++#include "xpp_zap.h"
++#include <linux/module.h>
++
++static const char rcsid[] = "$Id: xproto.c 164 2006-01-03 11:14:34Z oron $";
++
++extern int print_dbg;
++static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack);
++
++bool valid_xpd_addr(const xpd_addr_t *addr)
++{
++ return ((addr->bank_num & ~0x1) == 0) && ((addr->card_id & ~0x3) == 0);
++}
++
++int xpd_addr2num(const xpd_addr_t *addr)
++{
++ BUG_ON(!valid_xpd_addr(addr));
++ return addr->bank_num * 4 + addr->card_id;
++}
++
++void xpd_set_addr(xpd_addr_t *addr, int xpd_num)
++{
++ if(xpd_num < 4) {
++ addr->card_id = xpd_num;
++ addr->bank_num = 0;
++ } else {
++ addr->card_id = xpd_num % 4;
++ addr->bank_num = xpd_num / 4;
++ }
++}
++
++
++/*---------------- General Protocol Management ----------------------------*/
++
++#define XTABLE_ENTRY(name) [ XPD_TYPE(name) ] &name ## _protocol_table
++
++xproto_table_t *xprotocol_tables[] = {
++ XTABLE_ENTRY(FXS),
++};
++
++const xproto_entry_t *xproto_global_entry(byte opcode)
++{
++ const xproto_entry_t *xe;
++
++ xe = xproto_card_entry(&PROTO_TABLE(GLOBAL), opcode);
++ //DBG("opcode=0x%X xe=%p\n", opcode, xe);
++ return xe;
++}
++
++const xproto_handler_t xproto_global_handler(byte opcode)
++{
++ return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode);
++}
++
++const xproto_table_t *get_xproto_table(xpd_type_t cardtype)
++{
++ return xprotocol_tables[cardtype];
++}
++
++const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode)
++{
++ const xproto_entry_t *xe;
++
++ //DBG("\n");
++ xe = &table->entries[opcode];
++ return (xe->handler != NULL) ? xe : NULL;
++}
++
++const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
++{
++ const xproto_entry_t *xe;
++
++ //DBG("\n");
++ xe = xproto_card_entry(table, opcode);
++ return xe->handler;
++}
++
++const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
++{
++ const xproto_entry_t *xe;
++
++ xe = xproto_global_entry(opcode);
++ // DBG("opcode=0x%X xe=%p\n", opcode, xe);
++ if(!xe) {
++ const xproto_table_t *xtable;
++
++ if(!xpd)
++ return NULL;
++ xtable = get_xproto_table(xpd->type);
++ if(!xtable)
++ return NULL;
++ xe = xproto_card_entry(xtable, opcode);
++ if(!xe)
++ return NULL;
++ }
++ return xe;
++}
++
++#define DEF_(t) \
++ [ XPD_TYPE_ ## t ] = & t ## _xops
++
++xops_t *xpd_card_ops[XPD_TYPE_NOMODULE] = {
++ DEF_(FXS),
++};
++
++xops_t *get_xops(xpd_type_t xpd_type)
++{
++ if(xpd_type >= XPD_TYPE_NOMODULE)
++ return NULL;
++ return xpd_card_ops[xpd_type];
++}
++
++int packet_receive(xbus_t *xbus, xpacket_t *pack)
++{
++ int xpd_num;
++
++ if(!valid_xpd_addr(&pack->content.addr)) {
++ static int rate_limit = 0;
++
++ if((rate_limit++ % 5003) < 3)
++ dump_packet("bad address", pack, print_dbg);
++ xbus->ops->packet_free(xbus, pack);
++ return -EPROTO;
++ }
++ xpd_num = XPD_NUM(pack->content.addr);
++#if SOFT_SIMULATOR
++ if(xbus->sim[xpd_num].simulated) {
++ //dump_packet("packet_receive -> simulate", pack, print_dbg);
++ return simulate_xpd(xbus, xpd_num, pack);
++ } else
++#endif
++ {
++ //dump_packet("packet_receive -> process", pack, print_dbg);
++ return packet_process(xbus, xpd_num, pack);
++ }
++}
++
++static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack)
++{
++ byte op;
++ const xproto_entry_t *xe;
++ xproto_handler_t handler;
++ xproto_table_t *table;
++ xpd_t *xpd;
++ int ret = 0;
++
++ BUG_ON(!pack);
++ op = pack->content.opcode;
++ xpd_num = XPD_NUM(pack->content.addr);
++ xpd = xpd_of(xbus, xpd_num);
++ xe = find_xproto_entry(xpd, op);
++ /*-------- Validations -----------*/
++ if(!xe) {
++ ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op);
++ dump_packet("packet_process -- bad command", pack, print_dbg);
++ ret = -EPROTO;
++ goto out;
++ }
++ table = xe->table;
++ BUG_ON(!table);
++ if(!table->packet_is_valid(pack)) {
++ ERR("xpp: %s: wrong size %d for op=0x%02X\n",
++ __FUNCTION__, pack->datalen, op);
++ dump_packet("packet_process -- wrong size", pack, print_dbg);
++ ret = -EPROTO;
++ goto out;
++ }
++ handler = xe->handler;
++ BUG_ON(!handler);
++ XBUS_COUNTER(xbus, RX_BYTES) += pack->datalen;
++ handler(xbus, xpd, xe, pack);
++out:
++ xbus->ops->packet_free(xbus, pack);
++ return ret;
++}
++
++#define VERBOSE_DEBUG 1
++#define ERR_REPORT_LIMIT 20
++
++void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg)
++{
++ byte op = packet->content.opcode;
++
++ if(!print_dbg)
++ return;
++ DBG("%s: @0x%1X%1X OP=0x%02X LEN=%d\n",
++ msg,
++ packet->content.addr.bank_num,
++ packet->content.addr.card_id,
++ op,
++ (byte)packet->datalen);
++#if VERBOSE_DEBUG
++ {
++ int i;
++ byte *p = packet->content.data;
++
++ for(i = 0; i < packet->datalen; i++) {
++ static int limiter = 0;
++
++ if(i >= sizeof(xpacket_raw_t)) {
++ if(limiter < ERR_REPORT_LIMIT) {
++ ERR("%s: length overflow i=%d > sizeof(xpacket_raw_t)=%d\n",
++ __FUNCTION__, i+1, sizeof(xpacket_raw_t));
++ } else if(limiter == ERR_REPORT_LIMIT) {
++ ERR("%s: error packet #%d... squelsh reports.\n",
++ __FUNCTION__, limiter);
++ }
++ limiter++;
++ break;
++ }
++ DBG(" %2d> %02X\n", i+1, p[i]);
++ }
++ }
++#endif
++}
++
++EXPORT_SYMBOL(dump_packet);
++EXPORT_SYMBOL(packet_receive);
++EXPORT_SYMBOL(valid_xpd_addr);
++EXPORT_SYMBOL(xpd_addr2num);
++EXPORT_SYMBOL(xpd_set_addr);
+diff -urNad zaptel-1.0.10/xpp/xproto.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.h
+--- zaptel-1.0.10/xpp/xproto.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/xproto.h 2006-01-03 13:22:53.823218000 +0200
+@@ -0,0 +1,247 @@
++#ifndef XPROTO_H
++#define XPROTO_H
++/*
++ * Written by Oron Peled <oron at actcom.co.il>
++ * Copyright (C) 2004-2005, Xorcom
++ *
++ * All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#include "xdefs.h"
++
++#ifdef __KERNEL__
++#include <linux/list.h>
++#endif
++
++#define XPD_TYPE(n) XPD_TYPE_ ## n
++#define PROTO_TABLE(n) n ## _protocol_table
++
++typedef enum xpd_type {
++ XPD_TYPE(FXO) = 0x02,
++ XPD_TYPE(FXS) = 0x03,
++ XPD_TYPE(NOMODULE) = 0x0F,
++} xpd_type_t;
++
++#define LINE_BITS (sizeof(xpp_line_t)*8)
++#define PCM_CHUNKSIZE (CHANNELS_PERXPD * 8) /* samples of 8 bytes */
++
++typedef struct xpd_addr {
++ byte card_id:4;
++ byte bank_num:4;
++} __attribute__((packed)) xpd_addr_t;
++
++bool valid_xpd_addr(const xpd_addr_t *addr);
++int xpd_addr2num(const xpd_addr_t *addr);
++void xpd_set_addr(xpd_addr_t *addr, int xpd_num);
++
++#define XPD_NUM(x) xpd_addr2num(&x)
++#define XPD_ADDR_SET(x,val) xpd_set_addr(&x, val)
++#define MAX_XPACKET_DATALEN 100
++
++#define XPROTO_NAME(card,op) card ## _ ## op
++#define XPROTO_HANDLER(card,op) XPROTO_NAME(card,op ## _handler)
++#define XPROTO_CALLER(card,op) XPROTO_NAME(card,op ## _send)
++
++#define HANDLER_DEF(card,op) \
++ int XPROTO_HANDLER(card,op) ( \
++ xbus_t *xbus, \
++ xpd_t *xpd, \
++ const xproto_entry_t *cmd, \
++ xpacket_t *pack)
++
++#define CALL_PROTO(card,op, ...) XPROTO_CALLER(card,op)( __VA_ARGS__ )
++
++#define DECLARE_CMD(card,op, ...) \
++ int CALL_PROTO(card, op, xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ )
++
++#define HOSTCMD(card, op, ...) \
++ DECLARE_CMD(card, op, ## __VA_ARGS__ ); \
++ EXPORT_SYMBOL(XPROTO_CALLER(card, op)); \
++ DECLARE_CMD(card, op, ## __VA_ARGS__ )
++
++#define RPACKET_NAME(card,op) XPROTO_NAME(RPACKET_ ## card, op)
++#define RPACKET_TYPE(card,op) struct RPACKET_NAME(card, op)
++
++#define DEF_RPACKET_DATA(card,op, ...) \
++ struct RPACKET_NAME(card,op) { \
++ byte opcode; \
++ xpd_addr_t addr; \
++ __VA_ARGS__ \
++ } __attribute__((packed))
++
++#define RPACKET_CAST(p,card,op) ((RPACKET_TYPE(card,op) *)p)
++#define RPACKET_FIELD(p,card,op,field) (RPACKET_CAST(p,card,op)->field)
++#define RPACKET_SIZE(card,op) sizeof(RPACKET_TYPE(card,op))
++
++#define PACKET_LEN(p) \
++ ((p)->datalen + sizeof(xpd_addr_t) + 1)
++
++#define XENTRY(card,op) \
++ [ XPROTO_NAME(card,op) ] { \
++ .handler = XPROTO_HANDLER(card,op), \
++ .datalen = RPACKET_SIZE(card,op), \
++ .name = #op, \
++ .table = &PROTO_TABLE(card) \
++ }
++
++
++#define XPACKET_INIT(p, card, op) \
++ do { \
++ p->content.opcode = XPROTO_NAME(card,op); \
++ p->datalen = RPACKET_SIZE(card,op); \
++ } while(0)
++
++#define XPACKET_NEW(p, xbus, card, op, to) \
++ do { \
++ p = xbus->ops->packet_new(xbus, GFP_ATOMIC); \
++ if(!p) \
++ return -ENOMEM; \
++ XPACKET_INIT(p, card, op); \
++ XPD_ADDR_SET(p->content.addr, to); \
++ } while(0);
++
++typedef struct xproto_entry xproto_entry_t;
++typedef struct xproto_table xproto_table_t;
++
++typedef int (*xproto_handler_t)(
++ xbus_t *xbus,
++ xpd_t *xpd,
++ const xproto_entry_t *cmd,
++ xpacket_t *pack);
++
++struct xproto_entry {
++ xproto_handler_t handler;
++ int datalen;
++ const char *name;
++ xproto_table_t *table;
++};
++
++struct xproto_table {
++ xproto_entry_t entries[255]; /* Indexed by opcode */
++ const char *name;
++ bool (*packet_is_valid)(xpacket_t *pack);
++ void (*packet_dump)(xpacket_t *pack);
++};
++
++const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode);
++
++const xproto_table_t *get_xproto_table(xpd_type_t cardtype);
++const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode);
++const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode);
++
++const xproto_entry_t *xproto_global_entry(byte opcode);
++const xproto_handler_t xproto_global_handler(byte opcode);
++
++#define XMETHOD(name, ...) \
++ int (*name)(xbus_t *xbus, xpd_t *xpd, ## __VA_ARGS__ );
++
++#if 0
++#define CALL_XMETHOD(name, xbus, xpd, ...) \
++ ( \
++ (xpd) && (xpd)->xops && (xpd)->xops->name && \
++ (xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ ) \
++ )
++#else
++#define CALL_XMETHOD(name, xbus, xpd, ...) \
++ (xpd)->xops->name(xbus, xpd, ## __VA_ARGS__ )
++#endif
++
++struct xops {
++ XMETHOD(card_new, byte rev);
++ XMETHOD(card_init);
++ XMETHOD(card_remove);
++
++ XMETHOD(DESC_REQ, int xpd_num);
++ XMETHOD(SYNC_SOURCE, bool setit, bool is_master);
++ XMETHOD(PCM_WRITE, xpp_line_t hookstate, volatile byte *buf);
++
++ XMETHOD(CHAN_ENABLE, xpp_line_t lines, bool on);
++ XMETHOD(CHAN_POWER, xpp_line_t lines, bool on);
++ XMETHOD(CHAN_CID, xpp_line_t lines);
++ XMETHOD(RING, int pos, bool on);
++ XMETHOD(SETHOOK, xpp_line_t hook_status);
++ XMETHOD(LED, xpp_line_t lines, byte which, bool on);
++ XMETHOD(RELAY_OUT, byte which, bool on);
++ XMETHOD(SLIC_INIT);
++ XMETHOD(SLIC_QUERY, int pos, byte reg_num);
++};
++
++xops_t *get_xops(xpd_type_t xpd_type);
++
++#undef XMETHOD
++
++#include "card_global.h"
++#include "card_fxs.h"
++
++enum opcodes {
++ XPROTO_NAME(GLOBAL, DESC_REQ) = 0x04,
++ XPROTO_NAME(GLOBAL, DEV_DESC) = 0x05,
++/**/
++ XPROTO_NAME(GLOBAL, PCM_WRITE) = 0x11,
++ XPROTO_NAME(GLOBAL, PCM_READ) = 0x12,
++/**/
++ XPROTO_NAME(GLOBAL, SYNC_SOURCE) = 0x19,
++ XPROTO_NAME(GLOBAL, SYNC_REPLY) = 0x1A,
++
++ XPROTO_NAME(FXS, SIG_CHANGED) = 0x06,
++/**/
++ XPROTO_NAME(FXS, SLIC_WRITE) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, CHAN_ENABLE) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, CHAN_POWER) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, CHAN_CID) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, RING) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, SETHOOK) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, RELAY_OUT) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, SLIC_INIT) = 0x0F, /* Write to SLIC */
++ XPROTO_NAME(FXS, SLIC_QUERY) = 0x0F, /* Write to SLIC */
++/**/
++ XPROTO_NAME(FXS, SLIC_REPLY) = 0x10,
++};
++
++
++#define MEMBER(card,op) RPACKET_TYPE(card,op) RPACKET_NAME(card,op)
++
++struct xpacket_raw {
++ byte opcode;
++ xpd_addr_t addr;
++ union {
++ MEMBER(GLOBAL, DESC_REQ);
++ MEMBER(GLOBAL, DEV_DESC);
++ MEMBER(GLOBAL, PCM_WRITE);
++ MEMBER(GLOBAL, PCM_READ);
++ MEMBER(GLOBAL, SYNC_REPLY);
++
++ MEMBER(FXS, SIG_CHANGED);
++ MEMBER(FXS, SLIC_REPLY);
++
++ byte data[0];
++ };
++} __attribute__((packed));
++
++struct xpacket {
++ xpacket_raw_t content;
++ size_t datalen;
++ struct list_head list;
++};
++
++
++void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg);
++int packet_receive(xbus_t *xbus, xpacket_t *pack);
++
++#endif /* XPROTO_H */
+diff -urNad zaptel-1.0.10/xpp/zap_debug.c /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.c
+--- zaptel-1.0.10/xpp/zap_debug.c 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.c 2006-01-03 13:22:53.823218000 +0200
@@ -0,0 +1,136 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
@@ -4779,7 +7376,7 @@
+#include <zaptel.h>
+#include "zap_debug.h"
+
-+static char rcsid[] = "$Id: zap_debug.c 124 2005-11-09 18:42:02Z oron $";
++static const char rcsid[] = "$Id: zap_debug.c 161 2006-01-03 09:13:40Z oron $";
+
+#define P_(x) [ x ] = { .value = x, .name = #x, }
+static struct {
@@ -4882,9 +7479,9 @@
+EXPORT_SYMBOL(dump_poll);
+EXPORT_SYMBOL(event2str);
+EXPORT_SYMBOL(dump_sigtype);
-diff -urNad trunk/xpp/zap_debug.h /tmp/dpep.oAj2YR/trunk/xpp/zap_debug.h
---- trunk/xpp/zap_debug.h 1970-01-01 02:00:00.000000000 +0200
-+++ /tmp/dpep.oAj2YR/trunk/xpp/zap_debug.h 2005-11-10 04:05:18.000000000 +0200
+diff -urNad zaptel-1.0.10/xpp/zap_debug.h /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.h
+--- zaptel-1.0.10/xpp/zap_debug.h 1970-01-01 02:00:00.000000000 +0200
++++ /tmp/dpep.lpTITx/zaptel-1.0.10/xpp/zap_debug.h 2006-01-03 13:22:53.823218000 +0200
@@ -0,0 +1,16 @@
+#ifndef ZAP_DEBUG_H
+#define ZAP_DEBUG_H
More information about the Pkg-voip-commits
mailing list