diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-07-06 13:47:05 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-07-06 13:47:05 +0000 |
commit | 39a1812c1ef76b6a792f00087f1e507616bbbb25 (patch) | |
tree | e50633c999779c514ef16f4a2ce7a70fc7511c9e /xpp/card_fxo.c | |
parent | 70ef1183eba2d2fe4f00668fd3438b7f1c842c94 (diff) |
Tons of updates to the Astribank (xpp) driver:
* xpd_fxo.ko (FXO span) is now operational
* Remove obsolete .inc initialization files (we use user-space init)
* Added an install target to the utils dir.
* Updated README.Astribank accordingly.
* Using RBS signalling, as caller ID did not work well otherwise.
* Better handling of USB protocol errors.
* Fixed some procfs-related races.
* per-card-module ioctls.
* fxotune support.
* opermode support (set through /etc/default/zaptel for now)
* Userspace initialization script can also read registers.
* Power calibration works (and implemented in perl)
* some fine-tuning to the regster initialization parameters.
* Leds turn on before registration and turn off after it.
git-svn-id: http://svn.digium.com/svn/zaptel/trunk@1204 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_fxo.c')
-rw-r--r-- | xpp/card_fxo.c | 337 |
1 files changed, 193 insertions, 144 deletions
diff --git a/xpp/card_fxo.c b/xpp/card_fxo.c index bd3e141..d383e5d 100644 --- a/xpp/card_fxo.c +++ b/xpp/card_fxo.c @@ -34,6 +34,15 @@ 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(bool, report_battery, 0, "Report battery status to zaptel"); + +/* Signaling is opposite (fxs signalling for fxo card) */ +#if 1 +#define FXO_DEFAULT_SIGCAP (ZT_SIG_FXSKS | ZT_SIG_FXSLS) +#else +#define FXO_DEFAULT_SIGCAP (ZT_SIG_SF) +#endif enum fxo_leds { LED_GREEN, @@ -44,39 +53,19 @@ enum fxo_leds { /*---------------- FXO Protocol Commands ----------------------------------*/ -/* 0x0F */ DECLARE_CMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on); -/* 0x0F */ DECLARE_CMD(FXO, CHAN_CID, xpp_line_t lines); -/* 0x0F */ DECLARE_CMD(FXO, RING, int pos, bool on); -/* 0x0F */ DECLARE_CMD(FXO, SETHOOK, int pos, bool offhook); -/* 0x0F */ DECLARE_CMD(FXO, RELAY_OUT, byte which, bool on); -/* 0x0F */ DECLARE_CMD(FXO, DAA_INIT); -/* 0x0F */ DECLARE_CMD(FXO, DAA_QUERY, int pos, byte reg_num); +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, SETHOOK, int pos, bool offhook); +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 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); - -#define S_(s,l,...) \ - { \ - .lines = s, \ - { \ - .len = l, \ - .data = { __VA_ARGS__ }, \ - } \ - } -struct slic_init_data { - xpp_line_t lines; - slic_data_t slic_data; -} slic_init_data[] = { -#ifdef OLD_CARD -#include "init_data_4_19.inc" -#else -#include "init_data_4_20.inc" -#endif -}; -#undef S_ +static int process_slic_cmdline(xpd_t *xpd, char *cmdline); #define PROC_DAA_FNAME "slics" #define PROC_FXO_INFO_FNAME "fxo_info" @@ -126,7 +115,7 @@ static int do_led(xpd_t *xpd, lineno_t pos, byte which, bool on) BIT_CLR(priv->ledstate[which], pos); } } - if(!(lines & xpd->enabled_chans)) // Ignore disabled channels + 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); @@ -151,7 +140,7 @@ static void handle_fxo_leds(xpd_t *xpd) spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; timer_count = xpd->timer_count; - for_each_enabled_line(xpd, i) { + 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)) { @@ -172,10 +161,16 @@ static void handle_fxo_leds(xpd_t *xpd) static void do_sethook(xpd_t *xpd, int pos, bool offhook) { - unsigned long flags; + unsigned long flags; + struct FXO_priv_data *priv; BUG_ON(!xpd); BUG_ON(xpd->direction == TO_PHONE); // We can SETHOOK state only on PSTN + priv = xpd->priv; + BUG_ON(!priv); + if(!IS_SET(priv->battery, pos)) { + DBG("%s/%s/%d: WARNING: called while battery is off\n", xpd->xbus->busname, xpd->xpdname, pos); + } spin_lock_irqsave(&xpd->lock, flags); xpd->ringing[pos] = 0; // No more rings CALL_XMETHOD(SETHOOK, xpd->xbus, xpd, pos, offhook); @@ -228,6 +223,7 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) { struct FXO_priv_data *priv; int ret = 0; + int i; BUG_ON(!xpd); priv = xpd->priv; @@ -237,41 +233,34 @@ static int FXO_card_init(xbus_t *xbus, xpd_t *xpd) if(!priv->fxo_info) { ERR("Failed to create proc '%s' for %s/%s\n", PROC_FXO_INFO_FNAME, xbus->busname, xpd->xpdname); ret = -ENOENT; - goto out; + goto err; } + 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) { ERR("Failed to create proc file for DAAs of %s/%s\n", xbus->busname, xpd->xpdname); - goto out; + 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; #endif -#ifdef HARD_CODED_INIT - CALL_PROTO(FXO, DAA_INIT, xbus, xpd); -#else ret = run_initialize_registers(xpd); if(ret < 0) - goto out; -#endif - if(xpd->direction == TO_PSTN) { - int i; - - // Hanghup all lines - for_each_enabled_line(xpd, i) { - init_waitqueue_head(&xpd->txstateq[i]); - do_sethook(xpd, i, 0); - } - } -out: - if(ret < 0) { - clean_proc(xbus, xpd); - ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret); - } else { - DBG("done: %s/%s\n", xbus->busname, xpd->xpdname); + 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); + return 0; +err: + clean_proc(xbus, xpd); + ERR("%s/%s: Failed initializing registers (%d)\n", xbus->busname, xpd->xpdname, ret); return ret; } @@ -286,11 +275,43 @@ static int FXO_card_remove(xbus_t *xbus, xpd_t *xpd) return 0; } -static int FXO_card_zaptel_registration(xpd_t *xpd, bool on) +static int FXO_card_zaptel_preregistration(xpd_t *xpd, bool on) { xbus_t *xbus; struct FXO_priv_data *priv; + int i; unsigned long flags; + + BUG_ON(!xpd); + xbus = xpd->xbus; + BUG_ON(!xbus); + priv = xpd->priv; + BUG_ON(!priv); + DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on); + snprintf(xpd->span.desc, MAX_SPANDESC, "Xorcom XPD #%d/%d: FXO", xbus->num, xpd->id); + for_each_line(xpd, i) { + struct zt_chan *cur_chan = &xpd->chans[i]; + + DBG("setting FXO channel %d\n", i); + snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXO/%d/%d/%d", xbus->num, xpd->id, i); + cur_chan->chanpos = i + 1; + cur_chan->pvt = xpd; + cur_chan->sigcap = FXO_DEFAULT_SIGCAP; + } + spin_lock_irqsave(&xpd->lock, flags); + do_led(xpd, ALL_LINES, LED_GREEN, LED_OFF); + spin_unlock_irqrestore(&xpd->lock, flags); + for_each_line(xpd, i) { + do_led(xpd, i, LED_GREEN, LED_ON); + mdelay(50); + } + return 0; +} + +static int FXO_card_zaptel_postregistration(xpd_t *xpd, bool on) +{ + xbus_t *xbus; + struct FXO_priv_data *priv; int i; BUG_ON(!xpd); @@ -299,42 +320,48 @@ static int FXO_card_zaptel_registration(xpd_t *xpd, bool on) priv = xpd->priv; BUG_ON(!priv); DBG("%s/%s (%d)\n", xbus->busname, xpd->xpdname, on); - if(on) { - for_each_line(xpd, i) { - spin_lock_irqsave(&xpd->lock, flags); - do_led(xpd, i, LED_GREEN, LED_ON); - spin_unlock_irqrestore(&xpd->lock, flags); - mdelay(50); - } - for_each_line(xpd, i) { - spin_lock_irqsave(&xpd->lock, flags); - do_led(xpd, i, LED_GREEN, LED_OFF); - spin_unlock_irqrestore(&xpd->lock, flags); - mdelay(50); - } - } else { - for_each_line(xpd, i) { - spin_lock_irqsave(&xpd->lock, flags); - do_led(xpd, i, LED_GREEN, LED_ON); - spin_unlock_irqrestore(&xpd->lock, flags); - mdelay(100); - spin_lock_irqsave(&xpd->lock, flags); - do_led(xpd, i, LED_GREEN, LED_OFF); - spin_unlock_irqrestore(&xpd->lock, flags); - } + for_each_line(xpd, i) { + do_led(xpd, i, LED_GREEN, LED_OFF); + mdelay(50); + } + return 0; +} + +#ifdef WITH_RBS +int FXO_card_hooksig(xbus_t *xbus, xpd_t *xpd, int pos, zt_txsig_t txsig) +{ + struct FXO_priv_data *priv; + + priv = xpd->priv; + BUG_ON(!priv); + DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, txsig2str(txsig)); + BUG_ON(xpd->direction != TO_PSTN); + /* XXX Enable hooksig for FXO XXX */ + switch(txsig) { + case ZT_TXSIG_START: + break; + case ZT_TXSIG_OFFHOOK: + do_sethook(xpd, pos, 1); + break; + case ZT_TXSIG_ONHOOK: + do_sethook(xpd, pos, 0); + break; + default: + NOTICE("Can't set tx state to %s (%d)\n", txsig2str(txsig), txsig); + return -EINVAL; } return 0; } +#else int FXO_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate) { - int ret = 0; + int ret = 0; + struct FXO_priv_data *priv; DBG("%s/%s/%d: %s\n", xbus->busname, xpd->xpdname, pos, hookstate2str(hookstate)); switch(hookstate) { - /* On-hook, off-hook: The PBX is playing a phone on an FXO line. - * Can be ignored for an FXS line - */ + /* On-hook, off-hook: The PBX is playing a phone on an FXO line. */ case ZT_ONHOOK: do_sethook(xpd, pos, 0); break; @@ -353,7 +380,7 @@ int FXO_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate) WARN("No code yet\n"); break; case ZT_RING: - DBG("%s/%s/%d: (ringing[%d]=%d)\n", xbus->busname, xpd->xpdname, pos, pos, xpd->ringing[pos]); + DBG("%s/%s/%d: ZT_RING: %d\n", xbus->busname, xpd->xpdname, pos, xpd->ringing[pos]); break; case ZT_RINGOFF: WARN("No code yet\n"); @@ -361,12 +388,13 @@ int FXO_card_sethook(xbus_t *xbus, xpd_t *xpd, int pos, int hookstate) } return ret; } +#endif static void poll_battery(xbus_t *xbus, xpd_t *xpd) { int i; - for_each_enabled_line(xpd, i) { + for_each_line(xpd, i) { CALL_PROTO(FXO, DAA_QUERY, xbus, xpd, i, DAA_VBAT_REGISTER); } } @@ -374,23 +402,75 @@ static void poll_battery(xbus_t *xbus, xpd_t *xpd) static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) { - static int rate_limit = 0; + static unsigned rate_limit = 0; struct FXO_priv_data *priv; BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); rate_limit++; - if((rate_limit % 100) == 0) { + if(poll_battery_interval != 0 && (rate_limit % poll_battery_interval) == 0) { poll_battery(xbus, xpd); } handle_fxo_leds(xpd); 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; +}; + +static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) +{ + union echotune echoregs; + int i,ret; + + 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*)arg, sizeof(echoregs.wctdm_struct))) + return -EFAULT; + + /* Set the ACIM register */ + /* 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] + ); + /* FIXME: code duplicated from proc_xpd_register_write */ + ret = process_slic_cmdline(xpd, buf); + if(ret < 0) + return ret; + mdelay(1); + } + + DBG("-- Set echo registers successfully\n"); + + break; + default: + return -ENOTTY; + } + return 0; +} + /*---------------- FXO: HOST COMMANDS -------------------------------------*/ -/* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on) +static /* 0x0F */ HOSTCMD(FXO, CHAN_ENABLE, xpp_line_t lines, bool on) { unsigned long flags; int ret = 0; @@ -398,19 +478,18 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) BUG_ON(!xbus); BUG_ON(!xpd); - lines &= xpd->enabled_chans; // Ignore disabled channels if(!lines) { return 0; } DBG("Channel Activation: 0x%4X %s\n", lines, (on) ? "on" : "off"); if(on) { - for_each_enabled_line(xpd, i) { + for_each_line(xpd, i) { spin_lock_irqsave(&xpd->lock, flags); do_led(xpd, i, LED_GREEN, LED_ON); spin_unlock_irqrestore(&xpd->lock, flags); mdelay(20); } - for_each_enabled_line(xpd, i) { + for_each_line(xpd, i) { spin_lock_irqsave(&xpd->lock, flags); do_led(xpd, i, LED_GREEN, LED_OFF); spin_unlock_irqrestore(&xpd->lock, flags); @@ -420,32 +499,31 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) return ret; } -/* 0x0F */ HOSTCMD(FXO, CHAN_CID, xpp_line_t lines) +static /* 0x0F */ HOSTCMD(FXO, CHAN_CID, int pos) { int ret = 0; + xpp_line_t lines = BIT(pos); BUG_ON(!xbus); BUG_ON(!xpd); - lines &= xpd->enabled_chans; // Ignore disabled channels if(!lines) { return 0; } - DBG("Channel CID: 0x%04X\n", lines); + DBG("%s/%s/%d:\n", xbus->busname, xpd->xpdname, pos); return ret; } -/* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on) +static /* 0x0F */ HOSTCMD(FXO, RING, int pos, bool on) { int ret = 0; xpacket_t *pack; slic_cmd_t *sc; - xpp_line_t mask = (1 << pos); + xpp_line_t mask = BIT(pos); int len; BUG_ON(!xbus); BUG_ON(!xpd); - mask &= xpd->enabled_chans; // Ignore disabled channels if(!mask) { return 0; } @@ -459,7 +537,7 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) return ret; } -/* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook) +static /* 0x0F */ HOSTCMD(FXO, SETHOOK, int pos, bool offhook) { int ret = 0; xpacket_t *pack; @@ -470,56 +548,26 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd) BUG_ON(!xbus); BUG_ON(!xpd); - value = (offhook) ? 0x01 : 0x00; + value = (offhook) ? 0x09 : 0x08; // value |= BIT(3); /* Bit 3 is for CID */ DBG("%s/%s/%d: SETHOOK: value=0x%02X %s\n", xbus->busname, xpd->xpdname, pos, value, (offhook)?"OFFHOOK":"ONHOOK"); spin_lock_irqsave(&xpd->lock, flags); - if(!IS_SET(xpd->enabled_chans, pos)) - goto out; 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), 0x05, value); pack->datalen = len; packet_send(xbus, pack); do_led(xpd, pos, LED_GREEN, (offhook)?LED_ON:LED_OFF); -out: spin_unlock_irqrestore(&xpd->lock, flags); return ret; } -/* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on) +static /* 0x0F */ HOSTCMD(FXO, RELAY_OUT, byte which, bool on) { return -ENOSYS; } -/* 0x0F */ HOSTCMD(FXO, DAA_INIT) -{ - int ret = 0; - xpacket_t *pack; - slic_data_t *slic; - struct slic_init_data *source; - int i; - - BUG_ON(!xbus); - BUG_ON(!xpd); - DBG("INITIALIZING DAA\n"); - for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) { - source = &slic_init_data[i]; - XPACKET_NEW(pack, xbus, FXO, DAA_INIT, xpd->id); - RPACKET_FIELD(pack, FXO, DAA_INIT, lines) = source->lines; - - slic = &RPACKET_FIELD(pack, FXO, DAA_INIT, slic_data); - slic->len = source->slic_data.len; - memcpy(slic->data, source->slic_data.data, source->slic_data.len); - pack->datalen = sizeof(xpp_line_t) + slic->len + 1; -// dump_packet("DAA", pack, print_dbg); - packet_send(xbus, pack); - mdelay(1); // FIXME: check with Dima - } - return ret; -} - -/* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num) +static /* 0x0F */ HOSTCMD(FXO, DAA_QUERY, int pos, byte reg_num) { int ret = 0; xpacket_t *pack; @@ -588,22 +636,16 @@ HANDLER_DEF(FXO, DAA_REPLY) if(abs(info->data_low) < BAT_THRESHOLD) { priv->battery &= ~lines; - // DBG("BATTERY OFF (%04X) = %d\n", lines, info->data_low); + // DBG("%s/%s: BATTERY OFF (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low); } else { priv->battery |= lines; - // DBG("BATTERY ON (%04X) = %d\n", lines, info->data_low); + // DBG("%s/%s: BATTERY ON (%04X) = %d\n", xpd->xbus->busname, xpd->xpdname, lines, info->data_low); } changed_lines = last_batt_on ^ priv->battery; for_each_line(xpd, i) { - if(!IS_SET(changed_lines, i) || IS_SET(xpd->hookstate, i)) - continue; -#if 0 - /* FIXME: We don't want to affect the whole span */ - if(IS_SET(priv->battery, i)) - update_xpd_status(xpd, ZT_ALARM_NONE); - else - update_xpd_status(xpd, ZT_ALARM_RED); -#endif + if(IS_SET(changed_lines, i)) { + update_line_status(xpd, i, IS_SET(priv->battery, i)); + } } } #if 0 @@ -635,9 +677,15 @@ xproto_table_t PROTO_TABLE(FXO) = { .card_new = FXO_card_new, .card_init = FXO_card_init, .card_remove = FXO_card_remove, - .card_zaptel_registration = FXO_card_zaptel_registration, + .card_zaptel_preregistration = FXO_card_zaptel_preregistration, + .card_zaptel_postregistration = FXO_card_zaptel_postregistration, +#ifdef WITH_RBS + .card_hooksig = FXO_card_hooksig, +#else .card_sethook = FXO_card_sethook, +#endif .card_tick = FXO_card_tick, + .card_ioctl = FXO_card_ioctl, .RING = XPROTO_CALLER(FXO, RING), .SETHOOK = XPROTO_CALLER(FXO, SETHOOK), @@ -676,7 +724,8 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in struct FXO_priv_data *priv; int i; - BUG_ON(!xpd); + if(!xpd) + return -ENODEV; spin_lock_irqsave(&xpd->lock, flags); priv = xpd->priv; BUG_ON(!priv); @@ -830,9 +879,8 @@ static int process_slic_cmdline(xpd_t *xpd, char *cmdline) len = parse_slic_cmd(p, &sc, &priv->requested_reply); if(len < 0) return len; - sc.lines &= xpd->enabled_chans; // Ignore disabled channels if(!sc.lines) { - NOTICE("%s: no enabled channels are marked. Skip.\n", __FUNCTION__); + NOTICE("%s: no channels are marked. Skip.\n", __FUNCTION__); return 0; } dump_slic_cmd("WRITE_DAA", &sc); @@ -852,7 +900,8 @@ static int proc_xpd_slic_write(struct file *file, const char __user *buffer, uns int i; int ret; - BUG_ON(!xpd); + if(!xpd) + return -ENODEV; for(i = 0; i < count; /* noop */) { for(p = buf; p < buf + LINE_LEN; p++) { /* read a line */ if(i >= count) |