diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-11-06 21:18:42 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-11-06 21:18:42 +0000 |
commit | 4953605453a7f7f1da8c70c4c12a4b557cfc2c24 (patch) | |
tree | 0d1bd64cb09f75bf0c7aca3b17820738965a0f77 /xpp/card_fxo.c | |
parent | 1148b31f800c4a280c9a26592a18d4478afc1a82 (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/trunk@1563 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_fxo.c')
-rw-r--r-- | xpp/card_fxo.c | 548 |
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, ®_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); - 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, ®_type, ®_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(®cmd, chipsel) = chipsel; + REG_FIELD(®cmd, 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(®cmd, regnum) = reg_num; + REG_FIELD(®cmd, 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(®cmd, data_low) = data_low; + REG_FIELD(®cmd, data_high) = 0; + REG_FIELD(®cmd, 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", ®cmd); + ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, REG_FIELD(®cmd, chipsel), writing, REG_FIELD(®cmd, regnum), REG_FIELD(®cmd, 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) { |