summaryrefslogtreecommitdiff
path: root/xpp/card_fxs.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/card_fxs.c')
-rw-r--r--xpp/card_fxs.c707
1 files changed, 282 insertions, 425 deletions
diff --git a/xpp/card_fxs.c b/xpp/card_fxs.c
index c6168c6..eeb02c9 100644
--- a/xpp/card_fxs.c
+++ b/xpp/card_fxs.c
@@ -33,16 +33,16 @@
static const char rcsid[] = "$Id$";
-DEF_PARM(int, print_dbg, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */
-DEF_PARM_BOOL(reversepolarity, 0, 0644, "Reverse Line Polarity");
-DEF_PARM_BOOL(vmwineon, 0, 0644, "Indicate voicemail to a neon lamp");
-DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware");
+static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before zap_debug.h */
+static DEF_PARM_BOOL(reversepolarity, 0, 0644, "Reverse Line Polarity");
+static DEF_PARM_BOOL(vmwineon, 0, 0644, "Indicate voicemail to a neon lamp");
+static DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware");
#ifdef POLL_DIGITAL_INPUTS
-DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs");
+static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs");
#endif
#ifdef ZT_VMWI
-DEF_PARM_BOOL(vmwi_ioctl, 0, 0644, "Asterisk support VMWI notification via ioctl");
+static DEF_PARM_BOOL(vmwi_ioctl, 0, 0644, "Asterisk support VMWI notification via ioctl");
#else
#define vmwi_ioctl 0 /* not supported */
#endif
@@ -68,12 +68,14 @@ enum fxs_leds {
/* Shortcuts */
#define SLIC_WRITE 1
#define SLIC_READ 0
-#define SLIC_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \
- xpp_register_request((xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0)
-#define SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH) \
- xpp_register_request((xbus), (xpd), (chipsel), (writing), 1, 0x1E, (reg), (dL), (dH))
+#define SLIC_DIRECT_REQUEST(xbus,xpd,port,writing,reg,dL) \
+ xpp_register_request((xbus), (xpd), (port), (writing), (reg), 0, 0, (dL), 0, 0, 0)
+#define SLIC_INDIRECT_REQUEST(xbus,xpd,port,writing,reg,dL,dH) \
+ xpp_register_request((xbus), (xpd), (port), (writing), 0x1E, 1, (reg), (dL), 1, (dH), 0)
-#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS)
+#define VALID_PORT(port) (((port) >= 0 && (port) <= 7) || (port) == PORT_BROADCAST)
+
+#define REG_DIGITAL_IOCTRL 0x06 /* LED and RELAY control */
/* Values of SLIC linefeed control register (0x40) */
enum fxs_state {
@@ -93,14 +95,16 @@ enum fxs_state {
/*
* DTMF detection
*/
-#define SLIC_REG_DTMF 0x18 /* 24 */
-#define SLIC_REG_VOLTAGE 0x42 /* 66 */
+#define REG_DTMF_DECODE 0x18 /* 24 - DTMF Decode Status */
+#define REG_BATTERY 0x42 /* 66 - Battery Feed Control */
+#define REG_BATTERY_BATSL BIT(1) /* Battery Feed Select */
+
+#define REG_LOOPCLOSURE 0x44 /* 68 - Loop Closure/Ring Trip Detect Status */
+#define REG_LOOPCLOSURE_LCR BIT(0) /* Loop Closure Detect Indicator. */
/*---------------- FXS Protocol Commands ----------------------------------*/
static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, RING, lineno_t chan, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
static bool fxs_packet_is_valid(xpacket_t *pack);
static void fxs_packet_dump(const char *msg, xpacket_t *pack);
@@ -108,8 +112,6 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
#ifdef WITH_METERING
static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
#endif
-static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
#define PROC_REGISTER_FNAME "slics"
@@ -119,7 +121,6 @@ static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
#endif
struct FXS_priv_data {
- struct proc_dir_entry *regfile;
#ifdef WITH_METERING
struct proc_dir_entry *meteringfile;
#endif
@@ -163,12 +164,12 @@ static int linefeed_control(xbus_t *xbus, xpd_t *xpd, lineno_t chan, enum fxs_st
static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
{
- int value = (on) ? 0x06 : 0x00;
+ int value = (on) ? REG_BATTERY_BATSL : 0x00;
BUG_ON(!xbus);
BUG_ON(!xpd);
LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "up" : "down");
- return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, SLIC_REG_VOLTAGE, value);
+ return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value);
}
/*
@@ -217,7 +218,7 @@ static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
which = which % NUM_LEDS;
if(IS_SET(xpd->digital_outputs, chan) || IS_SET(xpd->digital_inputs, chan))
goto out;
- if(chan == ALL_CHANS) {
+ if(chan == PORT_BROADCAST) {
priv->ledstate[which] = (on) ? ~0 : 0;
} else {
if(on) {
@@ -231,7 +232,8 @@ static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
if(on)
value |= led_register_vals[which];
- ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x06, value);
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE,
+ REG_DIGITAL_IOCTRL, value);
out:
return ret;
}
@@ -240,7 +242,7 @@ static void handle_fxs_leds(xpd_t *xpd)
{
int i;
const enum fxs_leds colors[] = { LED_GREEN, LED_RED };
- int color;
+ enum fxs_leds color;
unsigned int timer_count;
struct FXS_priv_data *priv;
@@ -251,7 +253,7 @@ static void handle_fxs_leds(xpd_t *xpd)
for_each_line(xpd, i) {
if(IS_SET(xpd->digital_outputs | xpd->digital_inputs, i))
continue;
- if(xpd->blink_mode || IS_BLINKING(priv, i, color)) { // Blinking
+ if((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking
int mod_value = LED_COUNTER(priv, i, color);
if(!mod_value)
@@ -301,46 +303,13 @@ static int metering_gen(xpd_t *xpd, lineno_t chan, bool on)
/*---------------- FXS: Methods -------------------------------------------*/
-static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, byte revision)
-{
- xpd_t *xpd = NULL;
- int channels;
- int regular_channels;
-
- if(subtype == 2)
- regular_channels = min(6, CHANNELS_PERXPD);
- else
- regular_channels = min(8, CHANNELS_PERXPD);
- channels = regular_channels;
- if(unit == 0)
- channels += 6; /* 2 DIGITAL OUTPUTS, 4 DIGITAL INPUTS */
- xpd = xpd_alloc(sizeof(struct FXS_priv_data), proto_table, channels);
- if(!xpd)
- return NULL;
- if(unit == 0) {
- XBUS_DBG(GENERAL, xbus, "First XPD detected. Initialize digital outputs/inputs\n");
- xpd->digital_outputs = BITMASK(LINES_DIGI_OUT) << regular_channels;
- xpd->digital_inputs = BITMASK(LINES_DIGI_INP) << (regular_channels + LINES_DIGI_OUT);
- }
- xpd->direction = TO_PHONE;
- xpd->revision = revision;
- xpd->type_name = proto_table->name;
- return xpd;
-}
-
-static void clean_proc(xbus_t *xbus, xpd_t *xpd)
+static void fxs_proc_remove(xbus_t *xbus, xpd_t *xpd)
{
struct FXS_priv_data *priv;
BUG_ON(!xpd);
priv = xpd->priv;
#ifdef CONFIG_PROC_FS
- if(priv->regfile) {
- XPD_DBG(PROC, xpd, "Removing xpd SLIC file\n");
- priv->regfile->data = NULL;
- remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir);
- priv->regfile = NULL;
- }
#ifdef WITH_METERING
if(priv->meteringfile) {
XPD_DBG(PROC, xpd, "Removing xpd metering tone file\n");
@@ -357,20 +326,18 @@ static void clean_proc(xbus_t *xbus, xpd_t *xpd)
#endif
}
-static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
+static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd)
{
struct FXS_priv_data *priv;
- int ret = 0;
- int i;
BUG_ON(!xpd);
priv = xpd->priv;
+
#ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating FXS_INFO file\n");
priv->fxs_info = create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxs_info_read, xpd);
if(!priv->fxs_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXS_INFO_FNAME);
- ret = -ENOENT;
goto err;
}
priv->fxs_info->owner = THIS_MODULE;
@@ -379,7 +346,6 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
priv->meteringfile = create_proc_entry(PROC_METERING_FNAME, 0200, xpd->proc_xpd_dir);
if(!priv->meteringfile) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME);
- ret = -ENOENT;
goto err;
}
priv->meteringfile->owner = THIS_MODULE;
@@ -387,31 +353,75 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
priv->meteringfile->read_proc = NULL;
priv->meteringfile->data = xpd;
#endif
- XPD_DBG(PROC, xpd, "Creating SLICs file\n");
- priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir);
- if(!priv->regfile) {
- XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_REGISTER_FNAME);
- ret = -ENOENT;
- goto err;
- }
- priv->regfile->owner = THIS_MODULE;
- priv->regfile->write_proc = proc_xpd_register_write;
- priv->regfile->read_proc = proc_xpd_register_read;
- priv->regfile->data = xpd;
#endif
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, byte subtype, int subunits, bool to_phone)
+{
+ xpd_t *xpd = NULL;
+ int channels;
+ int regular_channels;
+ struct FXS_priv_data *priv;
+ int i;
+
+ if(!to_phone) {
+ XBUS_NOTICE(xbus,
+ "XPD=%d%d: try to instanciate FXS with reverse direction\n",
+ unit, subunit);
+ return NULL;
+ }
+ if(subtype == 2)
+ regular_channels = min(6, CHANNELS_PERXPD);
+ else
+ regular_channels = min(8, CHANNELS_PERXPD);
+ channels = regular_channels;
+ if(unit == 0)
+ channels += 6; /* 2 DIGITAL OUTPUTS, 4 DIGITAL INPUTS */
+ xpd = xpd_alloc(sizeof(struct FXS_priv_data), proto_table, channels);
+ if(!xpd)
+ return NULL;
+ if(unit == 0) {
+ XBUS_DBG(GENERAL, xbus, "First XPD detected. Initialize digital outputs/inputs\n");
+ xpd->digital_outputs = BITMASK(LINES_DIGI_OUT) << regular_channels;
+ xpd->digital_inputs = BITMASK(LINES_DIGI_INP) << (regular_channels + LINES_DIGI_OUT);
+ }
+ xpd->direction = TO_PHONE;
+ xpd->type_name = "FXS";
+ if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
+ goto err;
+ if(fxs_proc_create(xbus, xpd) < 0)
+ goto err;
+ priv = xpd->priv;
for_each_line(xpd, i) {
priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
}
- ret = run_initialize_registers(xpd);
- if(ret < 0)
- goto err;
+ return xpd;
+err:
+ xpd_free(xpd);
+ return NULL;
+}
+
+static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
+{
+ struct FXS_priv_data *priv;
+ int ret = 0;
+ int i;
+
+ BUG_ON(!xpd);
+ priv = xpd->priv;
/*
* Setup ring timers
*/
/* Software controled ringing (for CID) */
- ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_CHANS, SLIC_WRITE, 0x22, 0x00); /* Ringing Oscilator Control */
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, PORT_BROADCAST, SLIC_WRITE, 0x22, 0x00); /* Ringing Oscilator Control */
if(ret < 0)
goto err;
+ for_each_line(xpd, i) {
+ linefeed_control(xbus, xpd, i, FXS_LINE_POL_ACTIVE);
+ }
XPD_DBG(GENERAL, xpd, "done\n");
for_each_line(xpd, i) {
do_led(xpd, i, LED_GREEN, 0);
@@ -427,9 +437,19 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
}
restore_leds(xpd);
pcm_recompute(xpd, 0);
+ /*
+ * We should query our offhook state long enough time after we
+ * set the linefeed_control()
+ * So we do this after the LEDs
+ */
+ for_each_line(xpd, i) {
+ if(IS_SET(xpd->digital_outputs | xpd->digital_inputs, i))
+ continue;
+ SLIC_DIRECT_REQUEST(xbus, xpd, i, SLIC_READ, REG_LOOPCLOSURE, 0);
+ }
return 0;
err:
- clean_proc(xbus, xpd);
+ fxs_proc_remove(xbus, xpd);
XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret);
return ret;
}
@@ -441,7 +461,7 @@ static int FXS_card_remove(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!xpd);
priv = xpd->priv;
XPD_DBG(GENERAL, xpd, "\n");
- clean_proc(xbus, xpd);
+ fxs_proc_remove(xbus, xpd);
return 0;
}
@@ -481,6 +501,7 @@ static int FXS_card_zaptel_preregistration(xpd_t *xpd, bool on)
for_each_line(xpd, i) {
MARK_ON(priv, i, LED_GREEN);
msleep(4);
+ MARK_ON(priv, i, LED_RED);
}
return 0;
}
@@ -519,6 +540,103 @@ static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit)
BIT_CLR(xpd->mute_dtmf, pos);
}
+static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
+{
+ int ret = 0;
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+
+ LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)");
+ if (!vmwineon)
+ return 0;
+ if (on) {
+ /* A write to register 0x40 will now turn on/off the VM led */
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
+ } else {
+ /* A write to register 0x40 will now turn on/off the ringer */
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
+ ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
+ ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
+ }
+
+ return (ret ? -EPROTO : 0);
+}
+
+static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
+{
+ struct FXS_priv_data *priv;
+ bool on;
+
+ BUG_ON(!xpd);
+ if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
+ return;
+ priv = xpd->priv;
+ on = IS_SET(xpd->msg_waiting, pos);
+ LINE_DBG(SIGNAL, xpd, pos, "%s\n", (on)?"ON":"OFF");
+ set_vm_led_mode(xbus, xpd, pos, on);
+ do_chan_power(xbus, xpd, pos, on);
+ linefeed_control(xbus, xpd, pos, (on) ? FXS_LINE_RING : priv->idletxhookstate[pos]);
+}
+
+static int relay_out(xpd_t *xpd, int pos, bool on)
+{
+ int value;
+ int which = pos;
+ int relay_channels[] = { 0, 4 };
+
+ BUG_ON(!xpd);
+ /* map logical position to output port number (0/1) */
+ which -= (xpd->subtype == 2) ? 6 : 8;
+ LINE_DBG(SIGNAL, xpd, pos, "which=%d -- %s\n", which, (on) ? "on" : "off");
+ which = which % ARRAY_SIZE(relay_channels);
+ value = BIT(2) | BIT(3);
+ value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]);
+ if(on)
+ value |= led_register_vals[OUTPUT_RELAY];
+ return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, relay_channels[which],
+ SLIC_WRITE, REG_DIGITAL_IOCTRL, value);
+}
+
+static int send_ring(xpd_t *xpd, lineno_t chan, bool on)
+{
+ int ret = 0;
+ xbus_t *xbus;
+ struct FXS_priv_data *priv;
+ enum fxs_state value = (on) ? FXS_LINE_RING : FXS_LINE_POL_ACTIVE;
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on)?"on":"off");
+ priv = xpd->priv;
+ set_vm_led_mode(xbus, xpd, chan, 0);
+ do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
+ ret = linefeed_control(xbus, xpd, chan, value);
+ if(on) {
+ MARK_BLINK(priv, chan, LED_GREEN, LED_BLINK_RING);
+ } else {
+ if(IS_BLINKING(priv, chan, LED_GREEN))
+ MARK_BLINK(priv, chan, LED_GREEN, 0);
+ }
+ return ret;
+}
+
static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
{
struct FXS_priv_data *priv;
@@ -548,8 +666,8 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
__pcm_recompute(xpd, 0); /* already spinlocked */
spin_unlock_irqrestore(&xpd->lock, flags);
if(IS_SET(xpd->digital_outputs, pos)) {
- LINE_DBG(SIGNAL, xpd, pos, "digital output OFF\n");
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 0);
+ LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig));
+ ret = relay_out(xpd, pos, 0);
return ret;
}
if (priv->lasttxhook[pos] == FXS_LINE_OPEN) {
@@ -561,7 +679,7 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
if(IS_SET(xpd->offhook, pos))
MARK_ON(priv, pos, LED_GREEN);
}
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 0); // RING off
+ ret = send_ring(xpd, pos, 0); // RING off
if (!IS_SET(xpd->offhook, pos))
start_stop_vm_led(xbus, xpd, pos);
txhook = priv->lasttxhook[pos];
@@ -580,6 +698,10 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
ret = linefeed_control(xbus, xpd, pos, txhook);
break;
case ZT_TXSIG_OFFHOOK:
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ LINE_NOTICE(xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig));
+ return -EINVAL;
+ }
txhook = priv->lasttxhook[pos];
if(xpd->ringing[pos]) {
BIT_SET(xpd->cid_on, pos);
@@ -605,14 +727,17 @@ static int FXS_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig)
BIT_CLR(priv->search_fsk_pattern, pos);
pcm_recompute(xpd, 0);
if(IS_SET(xpd->digital_outputs, pos)) {
- LINE_DBG(SIGNAL, xpd, pos, "%s digital output ON\n", txsig2str(txsig));
- ret = CALL_XMETHOD(RELAY_OUT, xpd->xbus, xpd, pos-8, 1);
+ LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig));
+ ret = relay_out(xpd, pos, 1);
return ret;
}
- ret = CALL_XMETHOD(RING, xbus, xpd, pos, 1); // RING on
+ ret = send_ring(xpd, pos, 1); // RING on
break;
case ZT_TXSIG_KEWL:
- LINE_DBG(SIGNAL, xpd, pos, "KEWL START\n");
+ if(IS_SET(xpd->digital_outputs, pos)) {
+ LINE_DBG(SIGNAL, xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig));
+ return -EINVAL;
+ }
linefeed_control(xbus, xpd, pos, FXS_LINE_OPEN);
MARK_OFF(priv, pos, LED_GREEN);
break;
@@ -653,7 +778,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
if (get_user(val, (int __user *)arg))
return -EFAULT;
LINE_DBG(SIGNAL, xpd, pos, "ZT_ONHOOKTRANSFER (%d millis)\n", val);
- BUG_ON(pos == ALL_CHANS);
if (IS_SET(xpd->digital_inputs | xpd->digital_outputs, pos))
return 0; /* Nothing to do */
BIT_CLR(xpd->cid_on, pos);
@@ -757,60 +881,6 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
return -ENOTTY;
}
-static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos, int on)
-{
- int ret = 0;
- BUG_ON(!xbus);
- BUG_ON(!xpd);
-
- LINE_DBG(SIGNAL, xpd, pos, "%s%s\n", (on)?"ON":"OFF", (vmwineon)?"":" (Ignored)");
- if (!vmwineon)
- return 0;
- if (on) {
- /* A write to register 0x40 will now turn on/off the VM led */
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03);
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B);
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46);
- } else {
- /* A write to register 0x40 will now turn on/off the ringer */
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00);
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x60, 0x01);
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xF0, 0x7E);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
- ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
- ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36);
- }
-
- return (ret ? -EPROTO : 0);
-}
-
-static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
-{
- struct FXS_priv_data *priv;
- bool on;
-
- BUG_ON(!xpd);
- if (!vmwineon || IS_SET(xpd->digital_outputs | xpd->digital_inputs, pos))
- return;
- priv = xpd->priv;
- on = IS_SET(xpd->msg_waiting, pos);
- LINE_DBG(SIGNAL, xpd, pos, "%s\n", (on)?"ON":"OFF");
- set_vm_led_mode(xbus, xpd, pos, on);
- do_chan_power(xbus, xpd, pos, on);
- linefeed_control(xbus, xpd, pos, (on) ? FXS_LINE_RING : priv->idletxhookstate[pos]);
-}
-
static int FXS_card_open(xpd_t *xpd, lineno_t chan)
{
struct FXS_priv_data *priv;
@@ -819,7 +889,10 @@ static int FXS_card_open(xpd_t *xpd, lineno_t chan)
BUG_ON(!xpd);
priv = xpd->priv;
is_offhook = IS_SET(xpd->offhook, chan);
- LINE_DBG(GENERAL, xpd, chan, "(is %shook)\n", (is_offhook)?"off":"on");
+ if(is_offhook)
+ LINE_NOTICE(xpd, chan, "Already offhook during open. OK.\n");
+ else
+ LINE_DBG(SIGNAL, xpd, chan, "is onhook\n");
/*
* Delegate updating zaptel to FXS_card_tick():
* The problem is that zt_hooksig() is spinlocking the channel and
@@ -883,13 +956,12 @@ static void handle_linefeed(xpd_t *xpd)
priv->ohttimer[i]--;
if (!priv->ohttimer[i]) {
priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE;
+ BIT_CLR(xpd->cid_on, i);
+ BIT_CLR(priv->search_fsk_pattern, i);
+ pcm_recompute(xpd, 0);
if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) {
- enum fxs_state txhook = FXS_LINE_POL_ACTIVE;
/* Apply the change if appropriate */
- BIT_CLR(xpd->cid_on, i);
- BIT_CLR(priv->search_fsk_pattern, i);
- pcm_recompute(xpd, 0);
- linefeed_control(xpd->xbus, xpd, i, txhook);
+ linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE);
}
}
}
@@ -939,10 +1011,10 @@ static void detect_vmwi(xpd_t *xpd)
LINE_DBG(GENERAL, xpd, pos, "MSG:");
for(j = 0; j < ZT_CHUNKSIZE; j++) {
- if(print_dbg)
+ if(debug)
printk(" %02X", writechunk[j]);
}
- if(print_dbg)
+ if(debug)
printk("\n");
}
#endif
@@ -993,14 +1065,11 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
if(!IS_SET(priv->update_offhook_state, i))
continue;
/*
- * Update LEDs and zaptel with current state of line.
+ * Update zaptel with current state of line.
*/
if(IS_SET(xpd->offhook, i)) {
- LINE_NOTICE(xpd, i, "Already offhook during open. OK.\n");
- MARK_ON(priv, i, LED_GREEN);
update_line_status(xpd, i, 1);
} else {
- MARK_OFF(priv, i, LED_GREEN);
update_line_status(xpd, i, 0);
}
BIT_CLR(priv->update_offhook_state, i);
@@ -1015,99 +1084,40 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
/*---------------- FXS: HOST COMMANDS -------------------------------------*/
-/* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on)
+static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on)
{
- int i;
- enum fxs_state value = (on) ? FXS_LINE_POL_ACTIVE : FXS_LINE_OPEN;
- unsigned long flags;
- struct FXS_priv_data *priv;
-
BUG_ON(!xbus);
BUG_ON(!xpd);
- priv = xpd->priv;
- spin_lock_irqsave(&xpd->lock, flags);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off");
- for_each_line(xpd, i)
- linefeed_control(xbus, xpd, i, value);
- if(on) {
- MARK_ON(priv, ALL_CHANS, LED_GREEN);
- } else {
- MARK_OFF(priv, ALL_CHANS, LED_GREEN);
- }
- spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
}
-/* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
-{
- int ret = 0;
- struct FXS_priv_data *priv;
- enum fxs_state value = (on) ? FXS_LINE_RING : FXS_LINE_POL_ACTIVE;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on)?"on":"off");
- priv = xpd->priv;
- set_vm_led_mode(xbus, xpd, chan, 0);
- do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
- ret = linefeed_control(xbus, xpd, chan, value);
- if(on) {
- MARK_BLINK(priv, chan, LED_GREEN, LED_BLINK_RING);
- } else {
- if(IS_BLINKING(priv, chan, LED_GREEN))
- MARK_BLINK(priv, chan, LED_GREEN, 0);
- }
- return ret;
-}
-
-/* 0x0F */ HOSTCMD(FXS, RELAY_OUT, byte which, bool on)
-{
- int value;
- int relay_channels[] = { 0, 4 };
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- XPD_DBG(SIGNAL, xpd, "RELAY_OUT: which=%d -- %s\n", which, (on) ? "on" : "off");
- which = which % ARRAY_SIZE(relay_channels);
- value = BIT(2) | BIT(3);
- value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]);
- if(on)
- value |= led_register_vals[OUTPUT_RELAY];
- return SLIC_DIRECT_REQUEST(xbus, xpd, relay_channels[which], SLIC_WRITE, 0x06, value);
-}
-
/*---------------- FXS: Astribank Reply Handlers --------------------------*/
-HANDLER_DEF(FXS, SIG_CHANGED)
+/*
+ * Should be called with spinlocked XPD
+ */
+static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_mask)
{
- xpp_line_t sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
- xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles);
+ xbus_t *xbus;
struct FXS_priv_data *priv;
int i;
- unsigned long flags;
BUG_ON(!xpd);
BUG_ON(xpd->direction != TO_PHONE);
+ xbus = xpd->xbus;
priv = xpd->priv;
- XPD_DBG(SIGNAL, xpd, "(PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status);
-#if 0
- Is this needed?
- for_each_line(xpd, i) {
- if(IS_SET(sig_toggles, i))
- do_chan_power(xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!)
- }
-#endif
- spin_lock_irqsave(&xpd->lock, flags);
+ XPD_DBG(SIGNAL, xpd, "offhook=0x%X change_mask=0x%X\n", offhook, change_mask);
for_each_line(xpd, i) {
if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i))
continue;
- if(IS_SET(sig_toggles, i)) {
+ if(IS_SET(change_mask, i)) {
xpd->ringing[i] = 0; /* No more ringing... */
#ifdef WITH_METERING
metering_gen(xpd, i, 0); /* Stop metering... */
#endif
MARK_BLINK(priv, i, LED_GREEN, 0);
- if(IS_SET(sig_status, i)) {
+ if(IS_SET(offhook, i)) {
LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n");
MARK_ON(priv, i, LED_GREEN);
update_line_status(xpd, i, 1);
@@ -1119,6 +1129,26 @@ HANDLER_DEF(FXS, SIG_CHANGED)
}
}
__pcm_recompute(xpd, 0); /* in a spinlock */
+}
+
+HANDLER_DEF(FXS, SIG_CHANGED)
+{
+ xpp_line_t sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
+ xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles);
+ unsigned long flags;
+
+ BUG_ON(!xpd);
+ BUG_ON(xpd->direction != TO_PHONE);
+ XPD_DBG(SIGNAL, xpd, "(PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status);
+#if 0
+ Is this needed?
+ for_each_line(xpd, i) {
+ if(IS_SET(sig_toggles, i))
+ do_chan_power(xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!)
+ }
+#endif
+ spin_lock_irqsave(&xpd->lock, flags);
+ process_hookstate(xpd, sig_status, sig_toggles);
spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
}
@@ -1128,7 +1158,7 @@ static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info)
{
int i;
bool offhook = (REG_FIELD(info, data_low) & 0x1) == 0;
- xpp_line_t lines = BIT(REG_FIELD(info, chipsel));
+ xpp_line_t lines = BIT(info->portnum);
/* Map SLIC number into line number */
for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
@@ -1168,6 +1198,8 @@ static void process_dtmf(xpd_t *xpd, xpp_line_t lines, byte val)
if(!dtmf_detection)
return;
+ if(!SPAN_REGISTERED(xpd))
+ return;
priv = xpd->priv;
val &= 0xF;
if(val <= 0) {
@@ -1225,26 +1257,37 @@ static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
(indirect)?"I":"D",
regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high));
- if(!SPAN_REGISTERED(xpd))
- goto out;
+ if(!indirect && regnum == REG_DTMF_DECODE) {
+ byte val = REG_FIELD(info, data_low);
+ xpp_line_t lines = BIT(info->portnum);
+
+ process_dtmf(xpd, lines, val);
+ }
#ifdef POLL_DIGITAL_INPUTS
/*
* Process digital inputs polling results
*/
- if(xpd->xbus_idx == 0 && !indirect && regnum == 0x06)
+ else if(xpd->xbus_idx == 0 && !indirect && regnum == REG_DIGITAL_IOCTRL) {
process_digital_inputs(xpd, info);
+ }
#endif
- if(!indirect && regnum == SLIC_REG_DTMF) {
+ else if(!indirect && regnum == REG_LOOPCLOSURE) { /* OFFHOOK ? */
byte val = REG_FIELD(info, data_low);
- xpp_line_t lines = BIT(REG_FIELD(info, chipsel));
-
+ xpp_line_t mask = BIT(info->portnum);
+ xpp_line_t offhook;
+
+ offhook = (val & REG_LOOPCLOSURE_LCR) ? mask : 0;
+ LINE_DBG(SIGNAL, xpd, info->portnum,
+ "REG_LOOPCLOSURE: dataL=0x%X (offhook=0x%X mask=0x%X\n",
+ val, offhook, mask);
+ process_hookstate(xpd, offhook, mask);
+ } else {
#if 0
- XPD_DBG(SIGNAL, xpd, "DTMF result lines=0x%04X val=%d\n",
- lines, val);
+ XPD_NOTICE(xpd, "Spurious register reply(ignored): %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
+ (indirect)?"I":"D",
+ regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high));
#endif
- process_dtmf(xpd, lines, val);
}
-out:
/* Update /proc info only if reply relate to the last slic read request */
if(
REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
@@ -1262,7 +1305,8 @@ static xproto_table_t PROTO_TABLE(FXS) = {
/* Prototable Card Opcode */
XENTRY( FXS, FXS, SIG_CHANGED ),
},
- .name = "FXS",
+ .name = "FXS", /* protocol name */
+ .ports_per_subunit = 8,
.type = XPD_TYPE_FXS,
.xops = {
.card_new = FXS_card_new,
@@ -1279,8 +1323,6 @@ static xproto_table_t PROTO_TABLE(FXS) = {
.card_ioctl = FXS_card_ioctl,
.card_register_reply = FXS_card_register_reply,
- .RING = XPROTO_CALLER(FXS, RING),
- .RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT),
.XPD_STATE = XPROTO_CALLER(FXS, XPD_STATE),
},
.packet_is_valid = fxs_packet_is_valid,
@@ -1372,191 +1414,6 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
return len;
}
-/*
- *
- * Direct/Indirect
- * |
- * | Reg#
- * | |
- * | | Data (only in Write)
- * | | |
- * | | +-+-+
- * v v v v
- * FF WD 06 01 05
- * ^ ^
- * | |
- * | Write/Read
- * |
- * Chan#
- *
- */
-static int handle_register_command(xpd_t *xpd, char *cmdline)
-{
- unsigned chipsel;
- unsigned data_low = 0;
- unsigned data_high = 0;
- char op; /* [W]rite, [R]ead */
- char reg_type; /* [D]irect, [I]ndirect */
- int reg_num;
- int elements;
- bool writing;
- char *p;
- reg_cmd_t regcmd;
- xbus_t *xbus;
- int ret = -EINVAL;
-
- 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;
- if(!XBUS_GET(xbus)) {
- XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n");
- return -EBUSY;
- }
- elements = sscanf(cmdline, "%d %c%c %x %x %x",
- &chipsel,
- &op, &reg_type, &reg_num,
- &data_low,
- &data_high);
- XPD_DBG(REGS, xpd, "'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, data_low, data_high);
- if(elements < 4) { // At least: chipsel, op, reg_type, reg_num
- ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline);
- goto out;
- }
- if(!VALID_CHIPSEL(chipsel)) {
- ERR("Bad chipsel number: %d\n", chipsel);
- goto out;
- }
- REG_FIELD(&regcmd, chipsel) = chipsel;
- switch(op) {
- case 'W':
- writing = 1;
- break;
- case 'R':
- writing = 0;
- break;
- default:
- ERR("Unkown operation type '%c'\n", op);
- goto out;
- }
- switch(reg_type) {
- case 'I':
- REG_FIELD(&regcmd, do_subreg) = 1;
- REG_FIELD(&regcmd, regnum) = 0x1E; // FIXME: card dependent...
- REG_FIELD(&regcmd, subreg) = reg_num;
- break;
- case 'D':
- REG_FIELD(&regcmd, do_subreg) = 0;
- REG_FIELD(&regcmd, regnum) = reg_num;
- REG_FIELD(&regcmd, subreg) = 0;
- break;
- default:
- ERR("Unkown register type '%c'\n", reg_type);
- goto out;
- }
- if(
- (op == 'W' && reg_type == 'D' && elements != 5) ||
- (op == 'W' && reg_type == 'I' && elements != 6) ||
- (op == 'R' && reg_type == 'D' && elements != 4) ||
- (op == 'R' && reg_type == 'I' && elements != 4)
- ) {
- ERR("%s: '%s' (%d elements): %d %c%c %02X %02X %02X\n", __FUNCTION__,
- cmdline, elements,
- chipsel, op, reg_type, reg_num, data_low, data_high);
- goto out;
- }
- regcmd.bytes = sizeof(regcmd) - 1;
- REG_FIELD(&regcmd, data_low) = data_low;
- REG_FIELD(&regcmd, data_high) = data_high;
- REG_FIELD(&regcmd, read_request) = writing;
- xpd->requested_reply = regcmd;
- if(print_dbg)
- dump_reg_cmd("FXS", &regcmd, 1);
- ret = xpp_register_request(xpd->xbus, xpd,
- REG_FIELD(&regcmd, chipsel),
- writing,
- REG_FIELD(&regcmd, do_subreg),
- REG_FIELD(&regcmd, regnum),
- REG_FIELD(&regcmd, subreg),
- REG_FIELD(&regcmd, data_low),
- REG_FIELD(&regcmd, data_high));
-out:
- XBUS_PUT(xbus);
- return ret;
-}
-
-static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
-{
- xpd_t *xpd = data;
- char buf[MAX_PROC_WRITE];
- char *p;
- int i;
- int ret;
-
- if(!xpd)
- return -ENODEV;
- for(i = 0; i < count; /* noop */) {
- for(p = buf; p < buf + MAX_PROC_WRITE; 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 + MAX_PROC_WRITE)
- return -E2BIG;
- *p = '\0';
- ret = handle_register_command(xpd, buf);
- if(ret < 0)
- return ret;
- msleep(1);
- }
- return count;
-}
-
-static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data)
-{
- int len = 0;
- unsigned long flags;
- xpd_t *xpd = data;
- reg_cmd_t *info;
- byte regnum;
- bool indirect;
-
- if(!xpd)
- return -ENODEV;
- spin_lock_irqsave(&xpd->lock, flags);
- info = &xpd->last_reply;
- indirect = (REG_FIELD(info, regnum) == 0x1E);
- regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum);
- len += sprintf(page + len, "# Writing bad data into this file may damage your hardware!\n");
- len += sprintf(page + len, "# Consult firmware docs first\n");
- len += sprintf(page + len, "#\n");
- len += sprintf(page + len, "#CH\tD/I\tReg.\tDL DH\n");
- len += sprintf(page + len, "%2d\tR%c\t%02X\t%02X %02X\n",
- REG_FIELD(info, chipsel),
- (indirect)?'I':'D',
- regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high));
- 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;
-}
-
#ifdef WITH_METERING
static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
@@ -1581,7 +1438,7 @@ static int proc_xpd_metering_write(struct file *file, const char __user *buffer,
return -EINVAL;
}
chan = num;
- if(chan != ALL_CHANS && chan > xpd->channels) {
+ if(chan != PORT_BROADCAST && chan > xpd->channels) {
XPD_ERR(xpd, "Metering tone: bad channel number %d\n", chan);
return -EINVAL;
}
@@ -1593,7 +1450,7 @@ static int proc_xpd_metering_write(struct file *file, const char __user *buffer,
}
#endif
-int __init card_fxs_startup(void)
+static int __init card_fxs_startup(void)
{
INFO("revision %s\n", XPP_VERSION);
#ifdef POLL_DIGITAL_INPUTS
@@ -1616,7 +1473,7 @@ int __init card_fxs_startup(void)
return 0;
}
-void __exit card_fxs_cleanup(void)
+static void __exit card_fxs_cleanup(void)
{
xproto_unregister(&PROTO_TABLE(FXS));
}