summaryrefslogtreecommitdiff
path: root/xpp/card_fxs.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-11-28 13:36:03 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-11-28 13:36:03 +0000
commitd8bdfe8d82cf7c57b2a4061fc03b6e0a863064e1 (patch)
treeb67e786e441a4b6951e05552d533a924d5dacccf /xpp/card_fxs.c
parent6ecdbe426f0630c1ffb85e5e93758ae3e53aba22 (diff)
r1557@boole: tzafrir | 2006-11-06 20:12:16 +0200
Merging xpp driver release 1.2 (rev. 2569), originally team/tzafrir/xpp_1.2 * Should build well. Almost final. * genzaptelconf: Also work when zap_autoreg=0 * README.Astribank updated for rev. 1.2. * xpp/utils/Makefile: Use $< with cc -c * Get xpp/utils configuration from autoconf (without changesin top dir) git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@1648 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_fxs.c')
-rw-r--r--xpp/card_fxs.c593
1 files changed, 281 insertions, 312 deletions
diff --git a/xpp/card_fxs.c b/xpp/card_fxs.c
index 9aaef63..3d659fa 100644
--- a/xpp/card_fxs.c
+++ b/xpp/card_fxs.c
@@ -58,74 +58,50 @@ enum fxs_leds {
#define NUM_LEDS 2
-static int SLIC_DIRECT_REQUEST(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, byte reg, byte dL)
-{
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
-
- 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, reg, dL);
- pack->datalen = len;
- packet_send(xbus, pack);
- return 0;
-}
+static /* 0x0F */ DECLARE_CMD(FXS, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high);
+/* Shortcuts */
+#define SLIC_WRITE 1
+#define SLIC_READ 0
+#define SLIC_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \
+ CALL_PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0)
+#define SLIC_INDIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL,dH) \
+ PROTO(FXS, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 1, (reg), 0, (dL), (dH))
+
+#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS)
/*---------------- FXS Protocol Commands ----------------------------------*/
-static /* 0x0F */ DECLARE_CMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, int pos);
-static /* 0x0F */ DECLARE_CMD(FXS, RING, int pos, bool on);
+static /* 0x0F */ DECLARE_CMD(FXS, XPD_STATE, bool on);
+static /* 0x0F */ DECLARE_CMD(FXS, CHAN_CID, lineno_t chan);
+static /* 0x0F */ DECLARE_CMD(FXS, RING, lineno_t chan, bool on);
static /* 0x0F */ DECLARE_CMD(FXS, RELAY_OUT, byte which, bool on);
-static /* 0x0F */ DECLARE_CMD(FXS, SLIC_QUERY, int pos, byte reg_num);
static bool fxs_packet_is_valid(xpacket_t *pack);
-static void fxs_packet_dump(xpacket_t *pack);
+static void fxs_packet_dump(const char *msg, xpacket_t *pack);
static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data);
-static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+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);
-#define PROC_SLIC_FNAME "slics"
+#define PROC_REGISTER_FNAME "slics"
#define PROC_FXS_INFO_FNAME "fxs_info"
struct FXS_priv_data {
- struct proc_dir_entry *xpd_slic;
+ struct proc_dir_entry *regfile;
struct proc_dir_entry *fxs_info;
- slic_reply_t requested_reply;
- slic_reply_t last_reply;
xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */
int blinking[NUM_LEDS][CHANNELS_PERXPD];
};
/*---------------- FXS: Static functions ----------------------------------*/
-static int do_chan_power(xbus_t *xbus, xpd_t *xpd, xpp_line_t lines, bool on)
+static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
{
- int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
+ int value = (on) ? 0x06 : 0x00;
BUG_ON(!xbus);
BUG_ON(!xpd);
- if(!lines) {
- return 0;
- }
- DBG("%s/%s: 0x%04X %s\n", xbus->busname, xpd->xpdname, 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;
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, chan, (on) ? "up" : "down");
+ return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x42, value);
}
#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0)
@@ -164,47 +140,34 @@ static const int led_register_vals[] = { BIT(4), BIT(1), BIT(0) };
* - A line number
* - ALL_LINES
*/
-static int do_led(xpd_t *xpd, lineno_t pos, byte which, bool on)
+static int do_led(xpd_t *xpd, lineno_t chan, byte which, bool on)
{
int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
- int value;
struct FXS_priv_data *priv;
- xpp_line_t lines;
+ int value;
xbus_t *xbus;
BUG_ON(!xpd);
xbus = xpd->xbus;
priv = xpd->priv;
which = which % NUM_LEDS;
- if(IS_SET(xpd->digital_outputs, pos) || IS_SET(xpd->digital_inputs, pos))
+ if(IS_SET(xpd->digital_outputs, chan) || IS_SET(xpd->digital_inputs, chan))
goto out;
- if(pos == ALL_LINES) {
- lines = ~0;
+ if(chan == ALL_CHANS) {
priv->ledstate[which] = (on) ? ~0 : 0;
} else {
- lines = BIT(pos);
if(on) {
- BIT_SET(priv->ledstate[which], pos);
+ BIT_SET(priv->ledstate[which], chan);
} else {
- BIT_CLR(priv->ledstate[which], pos);
+ BIT_CLR(priv->ledstate[which], chan);
}
}
- if(!lines) // Nothing to do
- goto out;
- DBG("%s/%s: LED: lines=0x%04X which=%d -- %s\n", xbus->busname, xpd->xpdname, lines, which, (on) ? "on" : "off");
+ DBG("%s/%s/%d: LED: which=%d -- %s\n", xbus->busname, xpd->xpdname, chan, which, (on) ? "on" : "off");
value = BIT(2) | BIT(3);
value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
if(on)
value |= led_register_vals[which];
- 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);
- pack->datalen = len;
- packet_send(xbus, pack);
-
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x06, value);
out:
return ret;
}
@@ -212,14 +175,12 @@ out:
static void handle_fxs_leds(xpd_t *xpd)
{
int i;
- unsigned long flags;
const enum fxs_leds colors[] = { LED_GREEN, LED_RED };
int color;
unsigned int timer_count;
struct FXS_priv_data *priv;
BUG_ON(!xpd);
- spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
timer_count = xpd->timer_count;
for(color = 0; color < ARRAY_SIZE(colors); color++) {
@@ -245,7 +206,6 @@ static void handle_fxs_leds(xpd_t *xpd)
}
}
- spin_unlock_irqrestore(&xpd->lock, flags);
}
/*---------------- FXS: Methods -------------------------------------------*/
@@ -277,11 +237,11 @@ static void clean_proc(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!xpd);
priv = xpd->priv;
#ifdef CONFIG_PROC_FS
- if(priv->xpd_slic) {
+ if(priv->regfile) {
DBG("Removing xpd SLIC file %s/%s\n", xbus->busname, xpd->xpdname);
- priv->xpd_slic->data = NULL;
- remove_proc_entry(PROC_SLIC_FNAME, xpd->proc_xpd_dir);
- priv->xpd_slic = NULL;
+ priv->regfile->data = NULL;
+ remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir);
+ priv->regfile = NULL;
}
if(priv->fxs_info) {
DBG("Removing xpd FXS_INFO file %s/%s\n", xbus->busname, xpd->xpdname);
@@ -308,16 +268,16 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
}
priv->fxs_info->owner = THIS_MODULE;
DBG("Creating SLICs file for %s/%s\n", xbus->busname, xpd->xpdname);
- priv->xpd_slic = create_proc_entry(PROC_SLIC_FNAME, 0644, xpd->proc_xpd_dir);
- if(!priv->xpd_slic) {
+ priv->regfile = create_proc_entry(PROC_REGISTER_FNAME, 0644, xpd->proc_xpd_dir);
+ if(!priv->regfile) {
ERR("Failed to create proc file for SLICs of %s/%s\n", xbus->busname, xpd->xpdname);
ret = -ENOENT;
goto err;
}
- priv->xpd_slic->owner = THIS_MODULE;
- priv->xpd_slic->write_proc = proc_xpd_slic_write;
- priv->xpd_slic->read_proc = proc_xpd_slic_read;
- priv->xpd_slic->data = xpd;
+ 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
ret = run_initialize_registers(xpd);
if(ret < 0)
@@ -326,7 +286,7 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
* Setup ring timers
*/
/* Software controled ringing (for CID) */
- ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_LINES, 0x22, 0x00); /* Ringing Oscilator Control */
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_CHANS, SLIC_WRITE, 0x22, 0x00); /* Ringing Oscilator Control */
if(ret < 0)
goto err;
DBG("%s/%s: done\n", xbus->busname, xpd->xpdname);
@@ -495,9 +455,9 @@ static void poll_inputs(xbus_t *xbus, xpd_t *xpd)
BUG_ON(xpd->id != 0); // Only unit #0 has digital inputs
for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
- int pos = input_channels[i];
+ byte pos = input_channels[i];
- CALL_PROTO(FXS, SLIC_QUERY, xbus, xpd, pos, 0x06);
+ SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_READ, 0x06, 0);
}
}
@@ -522,161 +482,125 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
/*---------------- FXS: HOST COMMANDS -------------------------------------*/
-static /* 0x0F */ HOSTCMD(FXS, CHAN_ENABLE, xpp_line_t lines, bool on)
+/* 0x0F */ HOSTCMD(FXS, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
{
int ret = 0;
xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
- enum fxs_state value = (on) ? 0x01 : 0x00;
- unsigned long flags;
+ reg_cmd_t *reg_cmd;
+
+ if(!xbus) {
+ DBG("NO XBUS\n");
+ return -EINVAL;
+ }
+ XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id);
+#if 0
+ DBG("%s/%s/%d: %c%c R%02X S%02X %02X %02X\n",
+ xbus->busname, xpd->xpdname, chipsel,
+ (writing)?'W':'R',
+ (do_subreg)?'S':'D',
+ regnum, subreg, data_low, data_high);
+#endif
+ reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
+ pack->datalen = sizeof(*reg_cmd);
+ reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
+ REG_FIELD(reg_cmd, chipsel) = chipsel;
+ REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
+ REG_FIELD(reg_cmd, do_subreg) = do_subreg;
+ REG_FIELD(reg_cmd, regnum) = regnum;
+ REG_FIELD(reg_cmd, subreg) = subreg;
+ REG_FIELD(reg_cmd, data_low) = data_low;
+ REG_FIELD(reg_cmd, data_high) = data_high;
+ ret = packet_send(xbus, pack);
+ return ret;
+}
+
+static /* 0x0F */ HOSTCMD(FXS, XPD_STATE, bool on)
+{
+ int ret = 0;
int i;
+ enum fxs_state value = (on) ? 0x01 : 0x00;
+ unsigned long flags;
+ struct FXS_priv_data *priv;
BUG_ON(!xbus);
BUG_ON(!xpd);
- if(!lines) {
- return 0;
- }
- DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
- // Make sure we use normal (low battery) power
- for_each_line(xpd, i)
- if (BIT_SET(lines,i))
- do_chan_power(xbus, xpd, BIT(i), 0);
- 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, value);
- pack->datalen = len;
+ priv = xpd->priv;
+ spin_lock_irqsave(&xpd->lock, flags);
+ DBG("%s/%s: %s\n", xbus->busname, xpd->xpdname, (on) ? "on" : "off");
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, ALL_CHANS, SLIC_WRITE, 0x40, value);
for_each_line(xpd, i)
xpd->lasttxhook[i] = value;
-
- packet_send(xbus, pack);
- spin_lock_irqsave(&xpd->lock, flags);
if(on) {
- do_led(xpd, ALL_LINES, LED_GREEN, LED_ON);
+ MARK_LED(priv, ALL_CHANS, LED_GREEN, LED_ON);
} else {
- do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF);
+ MARK_LED(priv, ALL_CHANS, LED_GREEN, LED_OFF);
}
spin_unlock_irqrestore(&xpd->lock, flags);
return ret;
}
-static /* 0x0F */ HOSTCMD(FXS, CHAN_CID, int pos)
+static /* 0x0F */ HOSTCMD(FXS, CHAN_CID, lineno_t chan)
{
int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
int i;
- xpp_line_t lines = BIT(pos);
BUG_ON(!xbus);
BUG_ON(!xpd);
- if(!lines) {
- return 0;
- }
- DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, pos);
- //do_chan_power(xbus, xpd, BIT(pos), 0); // Low battery for normal (non-ring) operation
- 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, FXS_LINE_CID);
- packet_send(xbus, pack);
+ DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, FXS_LINE_CID);
for_each_line(xpd, i)
xpd->lasttxhook[i] = FXS_LINE_CID;
return ret;
}
-static /* 0x0F */ HOSTCMD(FXS, RING, int pos, bool on)
+static /* 0x0F */ HOSTCMD(FXS, RING, lineno_t chan, bool on)
{
- int ret = 0;
+ int ret = 0;
struct FXS_priv_data *priv;
- xpacket_t *pack;
- slic_cmd_t *sc;
- xpp_line_t mask = BIT(pos);
- int len;
- enum fxs_state value = (on) ? 0x04 : 0x01;
+ enum fxs_state value = (on) ? 0x04 : 0x01;
BUG_ON(!xbus);
BUG_ON(!xpd);
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, chan, (on) ? "on" : "off");
priv = xpd->priv;
- if(!mask) {
- return 0;
- }
- DBG("%s/%s/%d %s\n", xbus->busname, xpd->xpdname, pos, (on) ? "on" : "off");
- do_chan_power(xbus, xpd, BIT(pos), on); // Power up (for ring)
- 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, value);
- xpd->lasttxhook[pos] = value;
- pack->datalen = len;
-
- packet_send(xbus, pack);
+ do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
+ ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, 0x40, value);
+ xpd->lasttxhook[chan] = value;
if(on) {
- MARK_BLINK(priv,pos,LED_GREEN,LED_BLINK);
+ MARK_BLINK(priv,chan,LED_GREEN,LED_BLINK);
} else {
- if(IS_BLINKING(priv, pos, LED_GREEN))
- MARK_BLINK(priv,pos,LED_GREEN,0);
+ if(IS_BLINKING(priv, chan, LED_GREEN))
+ MARK_BLINK(priv,chan,LED_GREEN,0);
}
return ret;
}
static /* 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_register_mask[OUTPUT_RELAY]);
if(on)
value |= led_register_vals[OUTPUT_RELAY];
- 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;
-}
-
-static /* 0x0F */ HOSTCMD(FXS, SLIC_QUERY, int pos, byte reg_num)
-{
- int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
-
- BUG_ON(!xbus);
- BUG_ON(!xpd);
- // DBG("\n");
- XPACKET_NEW(pack, xbus, FXS, SLIC_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXS, SLIC_WRITE, slic_cmd);
- len = slic_cmd_direct_read(sc, BIT(pos), reg_num);
-
- pack->datalen = len;
-
- packet_send(xbus, pack);
- return ret;
+ return SLIC_DIRECT_REQUEST(xbus, xpd, relay_channels[which], SLIC_WRITE, 0x06, value);
}
/*---------------- FXS: Astribank Reply Handlers --------------------------*/
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);
+ 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);
struct FXS_priv_data *priv;
- int i;
+ int i;
+ unsigned long flags;
BUG_ON(!xpd);
BUG_ON(xpd->direction != TO_PHONE);
@@ -686,12 +610,19 @@ HANDLER_DEF(FXS, SIG_CHANGED)
NOTICE("%s: %s/%s is not registered. Skipping.\n", __FUNCTION__, xbus->busname, xpd->xpdname);
return -ENODEV;
}
+#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);
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)) {
xpd->ringing[i] = 0; // No more ringing...
- do_chan_power(xpd->xbus, xpd, BIT(i), 0); // When not ringing, VBAT is always Low
MARK_BLINK(priv,i,LED_GREEN,0);
if(IS_SET(sig_status, i)) {
DBG("%s/%s/%d: OFFHOOK\n", xbus->busname, xpd->xpdname, i);
@@ -704,15 +635,17 @@ HANDLER_DEF(FXS, SIG_CHANGED)
}
}
}
+ spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
}
-HANDLER_DEF(FXS, SLIC_REPLY)
+HANDLER_DEF(FXS, REGISTER_REPLY)
{
- slic_reply_t *info = &RPACKET_FIELD(pack, FXS, SLIC_REPLY, info);
- xpp_line_t lines = RPACKET_FIELD(pack, FXS, SLIC_REPLY, lines);
+ reg_cmd_t *info = &RPACKET_FIELD(pack, FXS, REGISTER_REPLY, reg_cmd);
unsigned long flags;
struct FXS_priv_data *priv;
+ byte regnum;
+ bool indirect;
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
@@ -722,14 +655,22 @@ HANDLER_DEF(FXS, SLIC_REPLY)
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
+ indirect = (REG_FIELD(info, regnum) == 0x1E);
+ regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum);
#if 0
- 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);
+ DBG("REGISTER_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
+ xpd->id, (indirect)?"I":"D",
+ regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high));
#endif
- if(xpd->id == 0 && info->indirect == 0 && info->reg_num == 0x06) { /* Digital Inputs Poll Result */
- int i;
- bool offhook = (info->data_low & 0x1) == 0;
+ if(!SPAN_REGISTERED(xpd))
+ goto out;
+ /*
+ * Process digital inputs polling results
+ */
+ if(xpd->id == 0 && regnum == 0x06) {
+ int i;
+ bool offhook = (REG_FIELD(info, data_low) & 0x1) == 0;
+ xpp_line_t lines = BIT(REG_FIELD(info, chipsel));
/* Map SLIC number into line number */
for(i = 0; i < ARRAY_SIZE(input_channels); i++) {
@@ -751,10 +692,13 @@ HANDLER_DEF(FXS, SLIC_REPLY)
}
}
}
+out:
/* Update /proc info only if reply relate to the last slic read request */
- if(priv->requested_reply.indirect == info->indirect &&
- priv->requested_reply.reg_num == info->reg_num) {
- priv->last_reply = *info;
+ if(
+ REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) &&
+ REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) &&
+ REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) {
+ xpd->last_reply = *info;
}
spin_unlock_irqrestore(&xpd->lock, flags);
return 0;
@@ -763,9 +707,9 @@ HANDLER_DEF(FXS, SLIC_REPLY)
xproto_table_t PROTO_TABLE(FXS) = {
.owner = THIS_MODULE,
.entries = {
- /* Card Opcode */
- XENTRY( FXS, SIG_CHANGED ),
- XENTRY( FXS, SLIC_REPLY ),
+ /* Prototable Card Opcode */
+ XENTRY( FXS, FXS, SIG_CHANGED ),
+ XENTRY( FXS, FXS, REGISTER_REPLY ),
},
.name = "FXS",
.type = XPD_TYPE_FXS,
@@ -780,7 +724,7 @@ xproto_table_t PROTO_TABLE(FXS) = {
.RING = XPROTO_CALLER(FXS, RING),
.RELAY_OUT = XPROTO_CALLER(FXS, RELAY_OUT),
- .CHAN_ENABLE = XPROTO_CALLER(FXS, CHAN_ENABLE),
+ .XPD_STATE = XPROTO_CALLER(FXS, XPD_STATE),
.CHAN_CID = XPROTO_CALLER(FXS, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
@@ -799,9 +743,9 @@ static bool fxs_packet_is_valid(xpacket_t *pack)
return xe != NULL;
}
-static void fxs_packet_dump(xpacket_t *pack)
+static void fxs_packet_dump(const char *msg, xpacket_t *pack)
{
- DBG("\n");
+ DBG("%s\n", msg);
}
/*------------------------- SLIC Handling --------------------------*/
@@ -857,112 +801,39 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
return len;
}
-static 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;
- struct FXS_priv_data *priv;
-
- BUG_ON(!xpd);
- spin_lock_irqsave(&xpd->lock, flags);
- priv = xpd->priv;
- BUG_ON(!priv);
- info = &priv->last_reply;
- 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, "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);
- 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 #
+ *
+ * Direct/Indirect
+ * |
+ * | Reg#
+ * | |
+ * | | Data (only in Write)
+ * | | |
+ * | | +-+-+
+ * v v v v
+ * FF WD 06 01 05
+ * ^ ^
+ * | |
+ * | Write/Read
+ * |
+ * Chan#
+ *
*/
-static int parse_slic_cmd(const char *buf, slic_cmd_t *sc, slic_reply_t *requested_reply)
+static int handle_register_command(xpd_t *xpd, char *cmdline)
{
- 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, &reg_type, &reg_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);
- if(requested_reply) {
- requested_reply->indirect = 0;
- requested_reply->reg_num = 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);
- if(requested_reply) {
- requested_reply->indirect = 1;
- requested_reply->reg_num = 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;
- struct FXS_priv_data *priv;
- slic_cmd_t sc;
- xpacket_t *pack;
+ 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;
- int len = strlen(cmdline);
+ reg_cmd_t regcmd;
+ xbus_t *xbus;
+ int ret;
- BUG_ON(!xpd);
- xbus = xpd->xbus;
- priv = xpd->priv;
if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */
*p = '\0';
if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */
@@ -971,22 +842,85 @@ static int process_slic_cmdline(xpd_t *xpd, char *cmdline)
;
if(*p == '\0')
return 0;
- len = parse_slic_cmd(p, &sc, &priv->requested_reply);
- if(len < 0)
- return len;
- if(!sc.lines) {
- NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__);
- return 0;
+
+ elements = sscanf(cmdline, "%d %c%c %x %x %x",
+ &chipsel,
+ &op, &reg_type, &reg_num,
+ &data_low,
+ &data_high);
+ // DBG("'%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);
+ return -EINVAL;
}
- 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;
+ if(!VALID_CHIPSEL(chipsel)) {
+ ERR("Bad chipsel number: %d\n", chipsel);
+ return -EINVAL;
+ }
+ 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);
+ return -EINVAL;
+ }
+ 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);
+ return -EINVAL;
+ }
+ 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);
+ return -EINVAL;
+ }
+ 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;
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ if(!down_read_trylock(&xbus->in_use)) {
+ DBG("Dropped packet. %s is in_use\n", xbus->busname);
+ return -EBUSY;
+ }
+ xpd->requested_reply = regcmd;
+ if(print_dbg)
+ dump_reg_cmd("FXS", &regcmd);
+ ret = CALL_PROTO(FXS, 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));
+ up_read(&xbus->in_use);
+ return ret;
}
-static int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+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];
@@ -1009,7 +943,7 @@ static int proc_xpd_slic_write(struct file *file, const char __user *buffer, uns
if(p >= buf + MAX_PROC_WRITE)
return -E2BIG;
*p = '\0';
- ret = process_slic_cmdline(xpd, buf);
+ ret = handle_register_command(xpd, buf);
if(ret < 0)
return ret;
mdelay(1);
@@ -1017,6 +951,41 @@ static int proc_xpd_slic_write(struct file *file, const char __user *buffer, uns
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;
+}
+
int __init card_fxs_startup(void)
{