summaryrefslogtreecommitdiff
path: root/xpp/card_fxo.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/card_fxo.c')
-rw-r--r--xpp/card_fxo.c548
1 files changed, 254 insertions, 294 deletions
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c
index ed77684..7672db3 100644
--- a/xpp/card_fxo.c
+++ b/xpp/card_fxo.c
@@ -33,8 +33,8 @@
static const char rcsid[] = "$Id$";
-DEF_PARM(int, print_dbg, 0, "Print DBG statements"); /* must be before zap_debug.h */
-DEF_PARM(uint, poll_battery_interval, 100, "Poll battery interval in milliseconds");
+DEF_PARM(int, print_dbg, 0, "Print DBG statements");
+DEF_PARM(uint, poll_battery_interval, 100, "Poll battery interval in milliseconds (0 - disable)");
DEF_PARM(bool, report_battery, 0, "Report battery status to zaptel");
/* Signaling is opposite (fxs signalling for fxo card) */
@@ -54,22 +54,30 @@ enum fxo_leds {
#define BAT_THRESHOLD 3
#define BAT_DEBOUNCE 3 /* compensate for battery voltage fluctuation (in poll_battery_interval's) */
+static /* 0x0F */ DECLARE_CMD(FXO, REGISTER_REQUEST, byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high);
+/* Shortcuts */
+#define DAA_WRITE 1
+#define DAA_READ 0
+#define DAA_DIRECT_REQUEST(xbus,xpd,chipsel,writing,reg,dL) \
+ CALL_PROTO(FXO, REGISTER_REQUEST, (xbus), (xpd), (chipsel), (writing), 0, (reg), 0, (dL), 0)
+
+#define VALID_CHIPSEL(x) (((chipsel) >= 0 && (chipsel) <= 7) || (chipsel) == ALL_CHANS)
+
/*---------------- FXO Protocol Commands ----------------------------------*/
-static /* 0x0F */ DECLARE_CMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on);
-static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, int pos);
-static /* 0x0F */ DECLARE_CMD(FXO, RING, int pos, bool on);
+static /* 0x0F */ DECLARE_CMD(FXO, XPD_STATE, bool on);
+static /* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, lineno_t chan);
+static /* 0x0F */ DECLARE_CMD(FXO, RING, lineno_t chan, bool on);
static /* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on);
-static /* 0x0F */ DECLARE_CMD(FXO, DAA_QUERY, int pos, byte reg_num);
static bool fxo_packet_is_valid(xpacket_t *pack);
-static void fxo_packet_dump(xpacket_t *pack);
+static void fxo_packet_dump(const char *msg, xpacket_t *pack);
static int proc_fxo_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 process_slic_cmdline(xpd_t *xpd, char *cmdline);
+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 int handle_register_command(xpd_t *xpd, char *cmdline);
-#define PROC_DAA_FNAME "slics"
+#define PROC_REGISTER_FNAME "slics"
#define PROC_FXO_INFO_FNAME "fxo_info"
#ifdef SOFT_RING
@@ -80,11 +88,9 @@ static int process_slic_cmdline(xpd_t *xpd, char *cmdline);
#define DAA_RING_REGISTER 0x05
struct FXO_priv_data {
- struct proc_dir_entry *xpd_slic;
+ struct proc_dir_entry *regfile;
struct proc_dir_entry *fxo_info;
uint poll_counter;
- slic_reply_t requested_reply;
- slic_reply_t last_reply;
xpp_line_t battery;
ushort battery_debounce[CHANNELS_PERXPD];
xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */
@@ -119,42 +125,29 @@ void MARK_LED(xpd_t *xpd, lineno_t pos, byte color, bool on)
/*
* LED control is done via DAA register 0x20
*/
-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;
struct FXO_priv_data *priv;
- xpp_line_t lines;
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");
- XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, lines, 0x20, on);
- // DBG("LED pack: line=%d %s\n", i, (on)?"on":"off");
- pack->datalen = len;
- packet_send(xbus, pack);
+ DBG("%s/%s/%d: LED: which=%d -- %s\n", xbus->busname, xpd->xpdname, chan, which, (on) ? "on" : "off");
+ ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, on);
out:
return ret;
}
@@ -221,9 +214,6 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
struct FXO_priv_data *priv;
int ret = 0;
bool value;
- xpacket_t *pack;
- slic_cmd_t *sc;
- int len;
BUG_ON(!xpd);
BUG_ON(xpd->direction == TO_PHONE); // We can SETHOOK state only on PSTN
@@ -238,11 +228,7 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
value = (to_offhook) ? 0x09 : 0x08; /* Bit 3 is for CID */
DBG("%s/%s/%d: SETHOOK: value=0x%02X %s\n", xbus->busname, xpd->xpdname, pos, value, (to_offhook)?"OFFHOOK":"ONHOOK");
MARK_LED(xpd, pos, LED_GREEN, (to_offhook)?LED_ON:LED_OFF);
- XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, BIT(pos), DAA_RING_REGISTER, value);
- pack->datalen = len;
- packet_send(xbus, pack);
+ ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_RING_REGISTER, value);
#ifdef SOFT_RING
priv->ring_sig[pos] = 0;
#endif
@@ -282,10 +268,10 @@ static void clean_proc(xbus_t *xbus, xpd_t *xpd)
priv = xpd->priv;
DBG("%s/%s\n", xbus->busname, xpd->xpdname);
#ifdef CONFIG_PROC_FS
- if(priv->xpd_slic) {
+ if(priv->regfile) {
DBG("Removing xpd DAA file %s/%s\n", xbus->busname, xpd->xpdname);
- remove_proc_entry(PROC_DAA_FNAME, xpd->proc_xpd_dir);
- priv->xpd_slic = NULL;
+ remove_proc_entry(PROC_REGISTER_FNAME, xpd->proc_xpd_dir);
+ priv->regfile->data = NULL;
}
if(priv->fxo_info) {
DBG("Removing xpd FXO_INFO file %s/%s\n", xbus->busname, xpd->xpdname);
@@ -313,16 +299,16 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd)
}
priv->fxo_info->owner = THIS_MODULE;
DBG("Creating DAAs file for %s/%s\n", xbus->busname, xpd->xpdname);
- priv->xpd_slic = create_proc_entry(PROC_DAA_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 DAAs 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)
@@ -430,7 +416,7 @@ static void poll_battery(xbus_t *xbus, xpd_t *xpd)
int i;
for_each_line(xpd, i) {
- CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_VBAT_REGISTER);
+ DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_VBAT_REGISTER, 0);
}
}
@@ -444,7 +430,7 @@ static void poll_ring(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!priv);
for_each_line(xpd, i) {
if(priv->ring_sig[i])
- CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_RING_REGISTER);
+ DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_RING_REGISTER, 0);
}
}
#endif
@@ -496,16 +482,11 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
/* quick and dirty registers writing: */
for (i=0; i<sizeof(echotune_reg); i++) {
char buf[22];
- xpp_line_t lines = BIT(pos);
- sprintf(buf, "%02X %02X %02X %02X WD %2X %2X",
- (lines & 0xFF),
- ((lines >> 8) & 0xFF),
- ((lines >> 16) & 0xFF),
- ((lines >> 24) & 0xFF),
- echotune_reg[i],echoregs.coeff[i]
+ sprintf(buf, "%d WD %2X %2X",
+ pos,echotune_reg[i],echoregs.coeff[i]
);
/* FIXME: code duplicated from proc_xpd_register_write */
- ret = process_slic_cmdline(xpd, buf);
+ ret = handle_register_command(xpd, buf);
if(ret < 0)
return ret;
mdelay(1);
@@ -522,17 +503,46 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
/*---------------- FXO: HOST COMMANDS -------------------------------------*/
-static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
+/* 0x0F */ HOSTCMD(FXO, 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;
+ 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(FXO, XPD_STATE, bool on)
{
int ret = 0;
int i;
BUG_ON(!xbus);
BUG_ON(!xpd);
- if(!lines) {
- return 0;
- }
- DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off");
+ DBG("%s/%s: %s\n", xbus->busname, xpd->xpdname, (on) ? "on" : "off");
if(on) {
for_each_line(xpd, i) {
MARK_LED(xpd, i, LED_GREEN, LED_ON);
@@ -546,42 +556,23 @@ static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on)
return ret;
}
-static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos)
+static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, lineno_t chan)
{
int ret = 0;
- 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);
+ DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan);
return ret;
}
-static /* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on)
+static /* 0x0F */ HOSTCMD(FXO, RING, lineno_t chan, bool on)
{
- int ret = 0;
- xpacket_t *pack;
- slic_cmd_t *sc;
- xpp_line_t mask = BIT(pos);
- int len;
-
BUG_ON(!xbus);
BUG_ON(!xpd);
- if(!mask) {
- return 0;
- }
- DBG("%s/%s/%d %s\n", xpd->xbus->busname, xpd->xpdname, pos, (on) ? "on" : "off");
- XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
- len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01);
- pack->datalen = len;
-
- packet_send(xbus, pack);
- return ret;
+ DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, chan, (on) ? "on" : "off");
+ return DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x40, (on)?0x04:0x01);
}
static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
@@ -589,26 +580,6 @@ static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on)
return -ENOSYS;
}
-static /* 0x0F */ HOSTCMD(FXO, DAA_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, FXO, DAA_WRITE, xpd->id);
- sc = &RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd);
- len = slic_cmd_direct_read(sc, BIT(pos), reg_num);
-
- pack->datalen = len;
-
- packet_send(xbus, pack);
- return ret;
-}
-
/*---------------- FXO: Astribank Reply Handlers --------------------------*/
HANDLER_DEF(FXO, SIG_CHANGED)
@@ -658,10 +629,10 @@ HANDLER_DEF(FXO, SIG_CHANGED)
HANDLER_DEF(FXO, DAA_REPLY)
{
- slic_reply_t *info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, info);
- xpp_line_t lines = RPACKET_FIELD(pack, FXO, DAA_REPLY, lines);
+ reg_cmd_t *info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, regcmd);
unsigned long flags;
struct FXO_priv_data *priv;
+ lineno_t chipsel;
if(!xpd) {
NOTICE("%s: received %s for non-existing xpd: %d\n",
@@ -671,68 +642,62 @@ HANDLER_DEF(FXO, DAA_REPLY)
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
- if(!info->indirect && info->reg_num == DAA_VBAT_REGISTER) {
- byte bat = abs((signed char)info->data_low);
- int i;
-
- for_each_line(xpd, i) {
- if(!IS_SET(lines, i))
- continue;
- if(bat < BAT_THRESHOLD) {
- /*
- * Check for battery voltage fluctuations
- */
- if(IS_SET(priv->battery, i) && priv->battery_debounce[i]++ > BAT_DEBOUNCE) {
- DBG("%s/%s: BATTERY OFF (%04X) voltage=%d\n", xpd->xbus->busname, xpd->xpdname, lines, bat);
- BIT_CLR(priv->battery, i);
- update_line_status(xpd, i, 0);
- }
- } else {
- priv->battery_debounce[i] = 0;
- if(!IS_SET(priv->battery, i)) {
- DBG("%s/%s: BATTERY ON (%04X) voltage=%d\n", xpd->xbus->busname, xpd->xpdname, lines, bat);
- BIT_SET(priv->battery, i);
- }
+ chipsel = REG_FIELD(info, chipsel);
+
+ /*
+ * Update battery status
+ */
+ if(REG_FIELD(info, regnum) == DAA_VBAT_REGISTER) {
+ byte bat = abs((signed char)REG_FIELD(info, data_low));
+
+ if(bat < BAT_THRESHOLD) {
+ /*
+ * Check for battery voltage fluctuations
+ */
+ if(IS_SET(priv->battery, chipsel) && priv->battery_debounce[chipsel]++ > BAT_DEBOUNCE) {
+ DBG("%s/%s/%d: BATTERY OFF voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
+ BIT_CLR(priv->battery, chipsel);
+ update_line_status(xpd, chipsel, 0);
+ }
+ } else {
+ priv->battery_debounce[chipsel] = 0;
+ if(!IS_SET(priv->battery, chipsel)) {
+ DBG("%s/%s/%d: BATTERY ON voltage=%d\n", xpd->xbus->busname, xpd->xpdname, chipsel, bat);
+ BIT_SET(priv->battery, chipsel);
}
}
}
#ifdef SOFT_RING
- if(!info->indirect && info->reg_num == DAA_RING_REGISTER) {
- bool ringit = (info->data_low & (0x20 | 0x40)) ? 1 : 0; /* Ring positive | Ring negative */
- int i;
-
- for_each_line(xpd, i) {
- if(!IS_SET(lines, i))
- continue;
- if (!priv->ring_sig[i])
- continue;
- if(ringit) {
- if(priv->ring_thresh[i] > RING_THRESHOLD) {
- mark_ring(xpd, i, 1);
- priv->noring_thresh[i] = 0;
- } else
- priv->ring_thresh[i]++;
- } else {
- if(priv->noring_thresh[i] > NORING_THRESHOLD) {
- mark_ring(xpd, i, 0);
- priv->ring_thresh[i] = 0;
- } else
- priv->noring_thresh[i]++;
- }
+ if(REG_FIELD(info, regnum) == DAA_RING_REGISTER && priv->ring_sig[chipsel]) {
+ bool ringit = (REG_FIELD(info, data_low) & (0x20 | 0x40)) ? 1 : 0; /* Ring positive | Ring negative */
+
+ if(ringit) {
+ if(priv->ring_thresh[chipsel] > RING_THRESHOLD) {
+ mark_ring(xpd, chipsel, 1);
+ priv->noring_thresh[chipsel] = 0;
+ } else
+ priv->ring_thresh[chipsel]++;
+ } else {
+ if(priv->noring_thresh[chipsel] > NORING_THRESHOLD) {
+ mark_ring(xpd, chipsel, 0);
+ priv->ring_thresh[chipsel] = 0;
+ } else
+ priv->noring_thresh[chipsel]++;
}
}
#endif
#if 0
- if (info->reg_num != 29)
DBG("DAA_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
- xpd->id, (info->indirect)?"I":"D",
+ xpd->id, (info->size == 3)?"I":"D",
info->reg_num, info->data_low, info->data_high);
#endif
/* 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;
@@ -742,9 +707,9 @@ HANDLER_DEF(FXO, DAA_REPLY)
xproto_table_t PROTO_TABLE(FXO) = {
.owner = THIS_MODULE,
.entries = {
- /* Card Opcode */
- XENTRY( FXO, SIG_CHANGED ),
- XENTRY( FXO, DAA_REPLY ),
+ /* Prototable Card Opcode */
+ XENTRY( FXO, FXO, SIG_CHANGED ),
+ XENTRY( FXO, FXO, DAA_REPLY ),
},
.name = "FXO",
.type = XPD_TYPE_FXO,
@@ -760,7 +725,7 @@ xproto_table_t PROTO_TABLE(FXO) = {
.RING = XPROTO_CALLER(FXO, RING),
.RELAY_OUT = XPROTO_CALLER(FXO, RELAY_OUT),
- .CHAN_ENABLE = XPROTO_CALLER(FXO, CHAN_ENABLE),
+ .XPD_STATE = XPROTO_CALLER(FXO, XPD_STATE),
.CHAN_CID = XPROTO_CALLER(FXO, CHAN_CID),
.SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE),
@@ -779,9 +744,9 @@ static bool fxo_packet_is_valid(xpacket_t *pack)
return xe != NULL;
}
-static void fxo_packet_dump(xpacket_t *pack)
+static void fxo_packet_dump(const char *msg, xpacket_t *pack)
{
- DBG("\n");
+ DBG("%s\n", msg);
}
/*------------------------- DAA Handling --------------------------*/
@@ -809,11 +774,6 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
len += sprintf(page + len, "%2d ", IS_SET(priv->ledstate[LED_GREEN], i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "ledcontrol");
- for_each_line(xpd, i) {
- if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
- len += sprintf(page + len, "%2d ", IS_SET(priv->ledcontrol[LED_GREEN], i));
- }
len += sprintf(page + len, "\n\t%-17s: ", "blinking");
for_each_line(xpd, i) {
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
@@ -833,17 +793,13 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
len += sprintf(page + len, "\n\t%-17s: ", "ring_sig");
for_each_line(xpd, i) {
if(!IS_SET(xpd->digital_outputs, i) && !IS_SET(xpd->digital_inputs, i))
- len += sprintf(page + len, "%d ", priv->ring_sig[i]);
+ len += sprintf(page + len, "%2d ", priv->ring_sig[i]);
}
#endif
len += sprintf(page + len, "\n\t%-17s: ", "battery");
for_each_line(xpd, i) {
len += sprintf(page + len, "%2d ", IS_SET(priv->battery, i));
}
- len += sprintf(page + len, "\n\t%-17s: ", "battery_debounce");
- for_each_line(xpd, i) {
- len += sprintf(page + len, "%2d ", priv->battery_debounce[i]);
- }
len += sprintf(page + len, "\n");
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count)
@@ -857,113 +813,38 @@ static int proc_fxo_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 FXO_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, "DAA_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
- * |
- * DAA #
+ *
+ * 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)
-{
- 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 FXO_priv_data *priv;
- slic_cmd_t sc;
- xpacket_t *pack;
+static int handle_register_command(xpd_t *xpd, char *cmdline)
+{
+ unsigned chipsel;
+ unsigned data_low = 0;
+ char op; /* [W]rite, [R]ead */
+ char reg_type; /* [D]irect */
+ 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 */
@@ -972,22 +853,70 @@ 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",
+ &chipsel,
+ &op, &reg_type, &reg_num,
+ &data_low);
+ // DBG("'%s': %d %c%c %02X %02X %02X\n", cmdline, chipsel, op, reg_type, reg_num, data_low);
+ if(elements < 4) { // At least: chipsel, op, reg_type, reg_num
+ ERR("Not enough arguments: (%d args) '%s'\n", elements, cmdline);
+ return -EINVAL;
+ }
+ if(!VALID_CHIPSEL(chipsel)) {
+ ERR("Bad chipsel number: %d\n", chipsel);
+ return -EINVAL;
+ }
+ REG_FIELD(&regcmd, chipsel) = chipsel;
+ REG_FIELD(&regcmd, do_subreg) = 0;
+ switch(op) {
+ case 'W':
+ writing = 1;
+ break;
+ case 'R':
+ writing = 0;
+ break;
+ default:
+ ERR("Unkown operation type '%c'\n", op);
+ return -EINVAL;
}
- dump_slic_cmd("WRITE_DAA", &sc);
- XPACKET_NEW(pack, xbus, FXO, DAA_WRITE, xpd->id);
- RPACKET_FIELD(pack, FXO, DAA_WRITE, slic_cmd) = sc;
- pack->datalen = len;
- packet_send(xbus, pack);
- return 0;
+ switch(reg_type) {
+ case 'D':
+ 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 == 'R' && reg_type == 'D' && elements != 4)
+ ) {
+ ERR("%s: '%s' (%d elements): %d %c%c %02X %02X\n", __FUNCTION__,
+ cmdline, elements,
+ chipsel, op, reg_type, reg_num, data_low);
+ return -EINVAL;
+ }
+ regcmd.bytes = sizeof(regcmd) - 1;
+ REG_FIELD(&regcmd, data_low) = data_low;
+ REG_FIELD(&regcmd, data_high) = 0;
+ 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("FXO", &regcmd);
+ ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, REG_FIELD(&regcmd, chipsel), writing, REG_FIELD(&regcmd, regnum), REG_FIELD(&regcmd, data_low));
+ 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];
@@ -1010,7 +939,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);
@@ -1018,6 +947,37 @@ 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;
+
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ info = &xpd->last_reply;
+ regnum = 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\n");
+ len += sprintf(page + len, "%2d\tRD\t%02X\t%02X\n",
+ REG_FIELD(info, chipsel),
+ regnum, REG_FIELD(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;
+}
int __init card_fxo_startup(void)
{