diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-09 19:12:55 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2007-02-09 19:12:55 +0000 |
commit | cc599ab08d6f58a2d5e57db4150e2f9efe1112b8 (patch) | |
tree | 3f6df61996f5a6df4f05cd447c2b120ae8b4669e /xpp/card_fxo.c | |
parent | eeaa77f409b4e0e158e62cb852e462ccef317f3f (diff) |
Merged revisions 2123-2124 via svnmerge from
https://origsvn.digium.com/svn/zaptel/branches/1.4
........
r2123 | tzafrir | 2007-02-08 02:05:17 +0200 (Thu, 08 Feb 2007) | 27 lines
Branch 1.4 is back in sync (currently: xorcom rev. 3332):
* Performance improvements for multi-XPD (span) devices.
* Astribank BRI driver (in next commit).
* Changes under /proc:
- XBUS and XPD numbers have two digits.
- Every script wildcard should be replaced from XBUS-? to XBUS-[0-9]*
- Added /proc/xpp/XBUS-*/XPD-*/blink: echo 1 to start and 0 to stop.
* Several countries (South Africa, UAE, anybody else) require a shorter
ring delay. Adjust FXO reg 0x17 (23)'s bits 0:2 to 011.
* Use tasklets to move most of the interrupt PCM copying out of the interrupt.
* Debugfs-based code to dump data to userspace (used to debug BRI D channel).
* Pretend every 2.6.9 actually has later RHEL's typedefs.
* fpga_load supports /dev/bus/usb .
* Fixed physical order sorting in genzaptelconf.
* Reverse polarity and power denial detection.
* A short led flash at registration time.
* Add a real version of the xpp modules to them (independent of the Zaptel
version).
* Update our line status even when not registered.
* Fixed a false SIG_CHANGED when inserting or removing cable to FXO.
* Fixed compilation fixes for 2.6.20 (Bug #8982)
* A cleaner fix for the bool changes of 2.6.19 .
* Automatically detect echo_can_state_t at debug time.
* Automaitcally set XPP_DEBUGFS (depending on debugfs) at compile time.
* Bug-fixes to zaptel-helper. Moved to xpp/utils .
* Xbus protocol version: 2.4 (Zaptel 1.2.12/1.4.0 had 2.3).
XPS Init scripts renamed accordingly.
........
r2124 | tzafrir | 2007-02-08 02:30:56 +0200 (Thu, 08 Feb 2007) | 1 line
Now 'chans' is used after all.
........
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2144 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_fxo.c')
-rw-r--r-- | xpp/card_fxo.c | 341 |
1 files changed, 224 insertions, 117 deletions
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c index 7187d08..70d6018 100644 --- a/xpp/card_fxo.c +++ b/xpp/card_fxo.c @@ -29,12 +29,13 @@ #include "xpp_zap.h" #include "card_fxo.h" #include "zap_debug.h" +#include "xbus-core.h" static const char rcsid[] = "$Id$"; -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"); +DEF_PARM(int, print_dbg, 0, 0600, "Print DBG statements"); +DEF_PARM(uint, poll_battery_interval, 100, 0600, "Poll battery interval in milliseconds (0 - disable)"); +DEF_PARM(int, ring_debounce, 50, 0600, "Number of ticks to debounce a false RING indication"); /* Signaling is opposite (fxs signalling for fxo card) */ #if 1 @@ -65,7 +66,6 @@ static /* 0x0F */ DECLARE_CMD(FXO, REGISTER_REQUEST, byte chipsel, bool writing, /*---------------- FXO Protocol Commands ----------------------------------*/ 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); @@ -79,33 +79,38 @@ static int handle_register_command(xpd_t *xpd, char *cmdline); #define PROC_REGISTER_FNAME "slics" #define PROC_FXO_INFO_FNAME "fxo_info" +#define DAA_CURRENT_REGISTER 0x1C #define DAA_RING_REGISTER 0x05 struct FXO_priv_data { - struct proc_dir_entry *regfile; - struct proc_dir_entry *fxo_info; - uint poll_counter; - xpp_line_t battery; - ushort battery_debounce[CHANNELS_PERXPD]; - 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]; + struct proc_dir_entry *regfile; + struct proc_dir_entry *fxo_info; + uint poll_counter; + xpp_line_t battery; + ushort battery_debounce[CHANNELS_PERXPD]; + xpp_line_t polarity; + ushort polarity_counter[CHANNELS_PERXPD]; + uint offhook_timestamp[CHANNELS_PERXPD]; + ushort current_counter[CHANNELS_PERXPD]; + xpp_line_t ledstate[NUM_LEDS]; /* 0 - OFF, 1 - ON */ + xpp_line_t ledcontrol[NUM_LEDS]; /* 0 - OFF, 1 - ON */ + int led_counter[NUM_LEDS][CHANNELS_PERXPD]; + atomic_t ring_debounce[CHANNELS_PERXPD]; }; -/*---------------- FXO: Static functions ----------------------------------*/ +/* + * LED counter values: + * n>1 : BLINK every n'th tick + */ +#define LED_COUNTER(priv,pos,color) ((priv)->led_counter[color][pos]) +#define IS_BLINKING(priv,pos,color) (LED_COUNTER(priv,pos,color) > 0) +#define MARK_BLINK(priv,pos,color,t) ((priv)->led_counter[color][pos] = (t)) +#define MARK_OFF(priv,pos,color) do { BIT_CLR((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0) +#define MARK_ON(priv,pos,color) do { BIT_SET((priv)->ledcontrol[color],(pos)); MARK_BLINK((priv),(pos),(color),0); } while(0) -#define IS_BLINKING(priv,pos,color) ((priv)->blinking[color][pos] != 0) -#define MARK_BLINK(priv,pos,color,val) ((priv)->blinking[color][pos] = (val)) +#define LED_BLINK_RING (1000/8) /* in ticks */ -void MARK_LED(xpd_t *xpd, lineno_t pos, byte color, bool on) -{ - struct FXO_priv_data *priv = xpd->priv; - - if(on) - BIT_SET(priv->ledcontrol[color], pos); - else - BIT_CLR(priv->ledcontrol[color], pos); -} +/*---------------- FXO: Static functions ----------------------------------*/ /* * LED control is done via DAA register 0x20 @@ -152,9 +157,13 @@ static void handle_fxo_leds(xpd_t *xpd) for_each_line(xpd, i) { if(IS_SET(xpd->digital_outputs, i) || IS_SET(xpd->digital_inputs, i)) continue; - if(IS_BLINKING(priv,i,color)) { + if(xpd->blink_mode || IS_BLINKING(priv,i,color)) { + int mod_value = LED_COUNTER(priv, i, color); + + if(!mod_value) + mod_value = DEFAULT_LED_PERIOD; /* safety value */ // led state is toggled - if((timer_count % LED_BLINK_PERIOD) == 0) { + if((timer_count % mod_value) == 0) { DBG("%s/%s/%d: ledstate=%s\n", xpd->xbus->busname, xpd->xpdname, i, (IS_SET(priv->ledstate[color], i))?"ON":"OFF"); if(!IS_SET(priv->ledstate[color], i)) { @@ -178,10 +187,11 @@ static void mark_ring(xpd_t *xpd, lineno_t pos, bool on, bool update_zap) priv = xpd->priv; BUG_ON(!priv); + atomic_set(&priv->ring_debounce[pos], 0); /* Stop debouncing */ if(on && !xpd->ringing[pos]) { DBG("%s/%s/%d: START\n", xpd->xbus->busname, xpd->xpdname, pos); xpd->ringing[pos] = 1; - MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK); + MARK_BLINK(priv, pos, LED_GREEN, LED_BLINK_RING); if(update_zap) update_zap_ring(xpd, pos, on); } else if(!on && xpd->ringing[pos]) { @@ -214,18 +224,19 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook) mark_ring(xpd, pos, 0, 0); // No more rings 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); + if(to_offhook) + MARK_ON(priv, pos, LED_GREEN); + else + MARK_OFF(priv, pos, LED_GREEN); ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, DAA_RING_REGISTER, value); if(to_offhook) { BIT_SET(xpd->offhook, pos); + priv->offhook_timestamp[pos] = priv->poll_counter; } else { BIT_CLR(xpd->offhook, pos); BIT_CLR(xpd->cid_on, pos); - xpd->delay_until_dialtone[pos] = 0; } spin_unlock_irqrestore(&xpd->lock, flags); - if(to_offhook) - wake_up_interruptible(&xpd->txstateq[pos]); return ret; } @@ -299,10 +310,20 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) goto err; // Hanghup all lines for_each_line(xpd, i) { - init_waitqueue_head(&xpd->txstateq[i]); do_sethook(xpd, i, 0); } DBG("done: %s/%s\n", xbus->busname, xpd->xpdname); + for_each_line(xpd, i) { + do_led(xpd, i, LED_GREEN, 0); + } + for_each_line(xpd, i) { + do_led(xpd, i, LED_GREEN, 1); + msleep(50); + } + for_each_line(xpd, i) { + do_led(xpd, i, LED_GREEN, 0); + msleep(50); + } return 0; err: clean_proc(xbus, xpd); @@ -343,10 +364,9 @@ static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on) cur_chan->pvt = xpd; cur_chan->sigcap = FXO_DEFAULT_SIGCAP; } - MARK_LED(xpd, ALL_LINES, LED_GREEN, LED_OFF); for_each_line(xpd, i) { - MARK_LED(xpd, i, LED_GREEN, LED_ON); - msleep(50); + MARK_ON(priv, i, LED_GREEN); + msleep(4); } return 0; } @@ -364,8 +384,10 @@ static int FXO_card_zaptel_postregistration(xpd_t *xpd, bool on) BUG_ON(!priv); DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on); for_each_line(xpd, i) { - MARK_LED(xpd, i, LED_GREEN, LED_OFF); - msleep(50); + MARK_OFF(priv, i, LED_GREEN); + msleep(2); + // MARK_OFF(priv, i, LED_RED); + msleep(2); } return 0; } @@ -404,6 +426,35 @@ static void poll_battery(xbus_t *xbus, xpd_t *xpd) } } +static void poll_current(xbus_t *xbus, xpd_t *xpd) +{ + int i; + + for_each_line(xpd, i) { + if (IS_SET(xpd->offhook, i)) + DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_CURRENT_REGISTER, 0); + } +} + +static void handle_fxo_ring(xpd_t *xpd) +{ + struct FXO_priv_data *priv; + int i; + + priv = xpd->priv; + for_each_line(xpd, i) { + if(atomic_read(&priv->ring_debounce[i]) > 0) { + /* Maybe start ring */ + if(atomic_dec_and_test(&priv->ring_debounce[i])) + mark_ring(xpd, i, 1, 1); + } else if (atomic_read(&priv->ring_debounce[i]) < 0) { + /* Maybe stop ring */ + if(atomic_inc_and_test(&priv->ring_debounce[i])) + mark_ring(xpd, i, 0, 1); + } + } +} + static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) { struct FXO_priv_data *priv; @@ -413,54 +464,51 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) BUG_ON(!priv); if(poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) { poll_battery(xbus, xpd); + poll_current(xbus, xpd); } handle_fxo_leds(xpd); + handle_fxo_ring(xpd); priv->poll_counter++; return 0; } /* FIXME: based on data from from wctdm.h */ #include <wctdm.h> -static const int echotune_reg[] = {30,45,46,47,58,49,50,51,52}; -union echotune { - /* "coeff 0" is acim */ - unsigned char coeff[sizeof(echotune_reg)]; - struct wctdm_echo_coefs wctdm_struct; -}; +/* + * The first register is the ACIM, the other are coefficient registers. + * We define the array size explicitly to track possible inconsistencies + * if the struct is modified. + */ +static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52}; static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) { - union echotune echoregs; - int i,ret; + int i,ret; + unsigned char echotune_data[ARRAY_SIZE(echotune_regs)]; BUG_ON(!xpd); - DBG("cmd: 0x%X, expecting: 0x%X, pos=%d.\n", cmd, WCTDM_SET_ECHOTUNE, pos); switch (cmd) { case WCTDM_SET_ECHOTUNE: DBG("-- Setting echo registers: \n"); /* first off: check if this span is fxs. If not: -EINVALID */ - if (copy_from_user(&echoregs.wctdm_struct, - (struct wctdm_echo_coefs __user *)arg, sizeof(echoregs.wctdm_struct))) + if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data))) return -EFAULT; - /* Set the ACIM register */ - /* quick and dirty registers writing: */ - for (i=0; i<sizeof(echotune_reg); i++) { - char buf[22]; - sprintf(buf, "%d WD %2X %2X", - pos,echotune_reg[i],echoregs.coeff[i] - ); - /* FIXME: code duplicated from proc_xpd_register_write */ - ret = handle_register_command(xpd, buf); - if(ret < 0) + for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) { + DBG("Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]); + ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]); + if (ret < 0) { + NOTICE("%s/%s/%d: Couldn't write %0x02X to register %0x02X\n", + xpd->xbus->busname, xpd->xpdname, pos, echotune_data[i], echotune_regs[i]); return ret; + } msleep(1); } DBG("-- Set echo registers successfully\n"); - break; default: + DBG("%s/%s/%d: Unknown command 0x%X.\n", xpd->xbus->busname, xpd->xpdname, pos, cmd); return -ENOTTY; } return 0; @@ -471,6 +519,7 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a /* 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; + xframe_t *xframe; xpacket_t *pack; reg_cmd_t *reg_cmd; @@ -478,7 +527,7 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a DBG("NO XBUS\n"); return -EINVAL; } - XPACKET_NEW(pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->id); + XFRAME_NEW(xframe, 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, @@ -487,7 +536,6 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a 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; @@ -496,42 +544,23 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a 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); + ret = xframe_send(xbus, xframe); return ret; } static /* 0x0F */ HOSTCMD(FXO, XPD_STATE, bool on) { - int ret = 0; - int i; + int ret = 0; + struct FXO_priv_data *priv; BUG_ON(!xbus); BUG_ON(!xpd); + priv = xpd->priv; + BUG_ON(!priv); 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); - msleep(20); - } - for_each_line(xpd, i) { - MARK_LED(xpd, i, LED_GREEN, LED_OFF); - msleep(20); - } - } return ret; } -static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, lineno_t chan) -{ - int ret = 0; - - BUG_ON(!xbus); - BUG_ON(!xpd); - DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, chan); - return ret; -} - - static /* 0x0F */ HOSTCMD(FXO, RING, lineno_t chan, bool on) { BUG_ON(!xbus); @@ -557,7 +586,7 @@ HANDLER_DEF(FXO, SIG_CHANGED) if(!xpd) { NOTICE("%s: received %s for non-existing xpd: %d\n", - __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr)); + __FUNCTION__, cmd->name, XPD_NUM(pack->addr)); return -EPROTO; } priv = xpd->priv; @@ -565,19 +594,109 @@ HANDLER_DEF(FXO, SIG_CHANGED) DBG("%s/%s: (PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", xpd->xbus->busname, xpd->xpdname, sig_toggles, sig_status); spin_lock_irqsave(&xpd->lock, flags); for_each_line(xpd, i) { + int debounce; + if(IS_SET(sig_toggles, i)) { if(!IS_SET(priv->battery, i)) { - DBG("%s/%s/%d: battery is off. ignore false alarm.\n", + DBG("%s/%s/%d: SIG_CHANGED while battery is off.\n", xbus->busname, xpd->xpdname, i); - continue; + // FIXME: allow dialing without battery polling... + // continue; } - mark_ring(xpd, i, IS_SET(sig_status, i), 1); + /* First report false ring alarms */ + debounce = atomic_read(&priv->ring_debounce[i]); + if(debounce) + NOTICE("%s/%s/%d: debounced %d ticks\n", xbus->busname, xpd->xpdname, i, debounce); + /* + * Now set a new ring alarm. + * It will be checked in handle_fxo_ring() + */ + debounce = (IS_SET(sig_status, i)) ? ring_debounce : -ring_debounce; + atomic_set(&priv->ring_debounce[i], debounce); } } spin_unlock_irqrestore(&xpd->lock, flags); return 0; } +static void update_battery_status(xpd_t *xpd, byte data_low, lineno_t chipsel) +{ + struct FXO_priv_data *priv; + byte bat = abs((signed char)data_low); + byte pol = IS_SET(data_low, 7); + + priv = xpd->priv; + BUG_ON(!priv); + 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); + } + } + /* + * Handle reverse polarity + */ + if (IS_SET(xpd->offhook, chipsel)) { /* Learn the current polarity */ + if (priv->poll_counter - priv->offhook_timestamp[chipsel] < 3) { + priv->polarity_counter[chipsel] = 0; + if (pol) + BIT_SET(priv->polarity, chipsel); + else + BIT_CLR(priv->polarity, chipsel); + } + else if (IS_SET(priv->polarity, chipsel) != pol) { /* Polarity has reversed */ + priv->polarity_counter[chipsel]++; + if (priv->polarity_counter[chipsel] >= 2) { + if (pol) + BIT_SET(priv->polarity, chipsel); + else + BIT_CLR(priv->polarity, chipsel); + priv->polarity_counter[chipsel] = 0; + /* Inform Zaptel */ + zt_qevent_lock(&xpd->chans[chipsel], ZT_EVENT_POLARITY); +#if 0 + /* + * These two lines hangup the channel (by sending a message to + * the firmware), and inform Zaptel that the line has been hung-up. + * They are not needed if Asterisk does the hangup after receiving + * a notification from Zaptel (which is sent by the above zt_qevent_lock(). + * Asterisk does that if it has "hanguponpolarityswitch=1" in zapata.conf. + */ + do_sethook(xpd, chipsel, 0); + update_line_status(xpd, chipsel, 0); +#endif + } + } + } +} + +static void update_power_denial(xpd_t *xpd, byte data_low, lineno_t chipsel) +{ + struct FXO_priv_data *priv; + + priv = xpd->priv; + BUG_ON(!priv); + if (IS_SET(xpd->offhook, chipsel) && data_low < 3) { + priv->current_counter[chipsel]++; + if (priv->current_counter[chipsel] >= 10) { + priv->current_counter[chipsel] = 0; + do_sethook(xpd, chipsel, 0); + update_line_status(xpd, chipsel, 0); + } + } else + priv->current_counter[chipsel] = 0; +} + HANDLER_DEF(FXO, DAA_REPLY) { reg_cmd_t *info = &RPACKET_FIELD(pack, FXO, DAA_REPLY, regcmd); @@ -587,36 +706,20 @@ HANDLER_DEF(FXO, DAA_REPLY) if(!xpd) { NOTICE("%s: received %s for non-existing xpd: %d\n", - __FUNCTION__, cmd->name, XPD_NUM(pack->content.addr)); + __FUNCTION__, cmd->name, XPD_NUM(pack->addr)); return -EPROTO; } spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); 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); - } - } + switch(REG_FIELD(info, regnum)) { + case DAA_VBAT_REGISTER: + update_battery_status(xpd, REG_FIELD(info, data_low), chipsel); + break; + case DAA_CURRENT_REGISTER: + update_power_denial(xpd, REG_FIELD(info, data_low), chipsel); + break; } #if 0 DBG("DAA_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", @@ -658,10 +761,8 @@ xproto_table_t PROTO_TABLE(FXO) = { .RING = XPROTO_CALLER(FXO, RING), .RELAY_OUT = XPROTO_CALLER(FXO, RELAY_OUT), .XPD_STATE = XPROTO_CALLER(FXO, XPD_STATE), - .CHAN_CID = XPROTO_CALLER(FXO, CHAN_CID), .SYNC_SOURCE = XPROTO_CALLER(GLOBAL, SYNC_SOURCE), - .PCM_WRITE = XPROTO_CALLER(GLOBAL, PCM_WRITE), }, .packet_is_valid = fxo_packet_is_valid, .packet_dump = fxo_packet_dump, @@ -672,7 +773,7 @@ static bool fxo_packet_is_valid(xpacket_t *pack) const xproto_entry_t *xe; //DBG("\n"); - xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->content.opcode); + xe = xproto_card_entry(&PROTO_TABLE(FXO), pack->opcode); return xe != NULL; } @@ -896,7 +997,12 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count int __init card_fxo_startup(void) { - INFO("%s\n", THIS_MODULE->name); + if(ring_debounce <= 0) { + ERR("%s: ring_debounce=%d. Must be positive number of ticks\n", + THIS_MODULE->name, ring_debounce); + return -EINVAL; + } + INFO("%s revision %s\n", THIS_MODULE->name, XPP_VERSION); xproto_register(&PROTO_TABLE(FXO)); return 0; } @@ -909,6 +1015,7 @@ void __exit card_fxo_cleanup(void) MODULE_DESCRIPTION("XPP FXO Card Driver"); MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>"); MODULE_LICENSE("GPL"); +MODULE_VERSION(XPP_VERSION); MODULE_ALIAS_XPD(XPD_TYPE_FXO); module_init(card_fxo_startup); |