From d8bdfe8d82cf7c57b2a4061fc03b6e0a863064e1 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Tue, 28 Nov 2006 13:36:03 +0000 Subject: 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 --- xpp/card_fxs.c | 593 +++++++++++++++++++++++++++------------------------------ 1 file changed, 281 insertions(+), 312 deletions(-) (limited to 'xpp/card_fxs.c') 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, ®_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 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, ®_type, ®_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(®cmd, 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(®cmd, do_subreg) = 1; + REG_FIELD(®cmd, regnum) = 0x1E; // FIXME: card dependent... + REG_FIELD(®cmd, subreg) = reg_num; + break; + case 'D': + REG_FIELD(®cmd, do_subreg) = 0; + 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 == '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(®cmd, data_low) = data_low; + REG_FIELD(®cmd, data_high) = data_high; + 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("FXS", ®cmd); + ret = CALL_PROTO(FXS, REGISTER_REQUEST, xpd->xbus, xpd, + REG_FIELD(®cmd, chipsel), + writing, + REG_FIELD(®cmd, do_subreg), + REG_FIELD(®cmd, regnum), + REG_FIELD(®cmd, subreg), + REG_FIELD(®cmd, data_low), + REG_FIELD(®cmd, 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) { -- cgit v1.2.3