summaryrefslogtreecommitdiff
path: root/xpp/card_global.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-11-28 13:36:03 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-11-28 13:36:03 +0000
commitd8bdfe8d82cf7c57b2a4061fc03b6e0a863064e1 (patch)
treeb67e786e441a4b6951e05552d533a924d5dacccf /xpp/card_global.c
parent6ecdbe426f0630c1ffb85e5e93758ae3e53aba22 (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/branches/1.2@1648 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_global.c')
-rw-r--r--xpp/card_global.c149
1 files changed, 138 insertions, 11 deletions
diff --git a/xpp/card_global.c b/xpp/card_global.c
index dda4480..4740eab 100644
--- a/xpp/card_global.c
+++ b/xpp/card_global.c
@@ -29,13 +29,24 @@
static const char rcsid[] = "$Id$";
+DEF_PARM(charp,initdir, "/usr/share/zaptel", "The directory of card initialization scripts");
+/*
+ * BRI: Temporary software workaround for firmware limitation:
+ * - The BRI firmware count PCM channel number globally across subunits.
+ * - The module parameter 'bri_pcmshift' enables us to cheat and shift
+ * each B-channel, 4 bits for each subsequent subunit.
+ * - Eventually, this should be fixed in the firmware, otherwise we won't
+ * handle PRI (all the space we have is 32bits).
+ */
+DEF_PARM(bool,bri_pcmshift, 1, "TESTING: shift bri PCM bits by subunit number");
+
extern int print_dbg;
static bool pcm_valid(xpd_t *xpd, xpacket_t *pack);
/*---------------- GLOBAL Protocol Commands -------------------------------*/
static bool global_packet_is_valid(xpacket_t *pack);
-static void global_packet_dump(xpacket_t *pack);
+static void global_packet_dump(const char *msg, xpacket_t *pack);
/*---------------- GLOBAL: HOST COMMANDS ----------------------------------*/
@@ -66,9 +77,6 @@ static void global_packet_dump(xpacket_t *pack);
BUG_ON(!xbus);
BUG_ON(!xpd);
lines &= ~xpd->no_pcm;
-// if(lines == 0)
-// return 0;
-
/*
* FIXME: Workaround a bug in sync code of the Astribank.
* Send dummy PCM for sync.
@@ -86,6 +94,10 @@ static void global_packet_dump(xpacket_t *pack);
}
buf += ZT_CHUNKSIZE;
}
+ if(bri_pcmshift) { /* workaround for pcm problem in BRI */
+ lines = lines << (xpd->addr.subunit * 4);
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
+ }
pack->datalen = sizeof(xpp_line_t) + (pcm - start_pcm);
packet_send(xbus, pack);
XPD_COUNTER(xpd, PCM_WRITE)++;
@@ -176,6 +188,10 @@ HANDLER_DEF(GLOBAL, PCM_READ)
}
// DBG("lines=0x%04X\n", lines);
+ if(bri_pcmshift) { /* workaround for pcm problem in BRI */
+ lines = (lines >> (xpd->addr.subunit * 4)) & 0x7;
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
+ }
if(!pcm_valid(xpd, pack)) {
return -EPROTO;
}
@@ -201,6 +217,7 @@ HANDLER_DEF(GLOBAL, PCM_READ)
XBUS_COUNTER(xpd->xbus, PCM_READ)++;
spin_unlock_irqrestore(&xpd->lock, flags);
xpp_tick((unsigned long)xpd);
+
return 0;
}
@@ -222,14 +239,44 @@ HANDLER_DEF(GLOBAL, SYNC_REPLY)
return 0;
}
+HANDLER_DEF(GLOBAL, ERROR_CODE)
+{
+ byte errorcode = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode);
+ reg_cmd_t *bad_cmd;
+ char xpdname[XPD_NAMELEN];
+
+ BUG_ON(!xbus);
+ if(!xpd) {
+ int xpd_num = XPD_NUM(pack->content.addr);
+ snprintf(xpdname, XPD_NAMELEN, "....#%d", xpd_num);
+ } else {
+ snprintf(xpdname, XPD_NAMELEN, "%s", xpd->xpdname);
+ }
+ NOTICE("%s/%s: %s CODE = 0x%X\n", xbus->busname, xpdname, cmd->name, errorcode);
+ switch(errorcode) {
+ case 1:
+ bad_cmd = &RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, info.bad_spi_cmd);
+ dump_packet("BAD_SPI_CMD", pack, 1);
+ break;
+ default:
+ NOTICE("%s/%s: %s UNKNOWN CODE = 0x%X\n", xbus->busname, xpdname, cmd->name, errorcode);
+ dump_packet("PACKET", pack, 1);
+ }
+ /*
+ * FIXME: Should implement an error recovery plan
+ */
+ return 0;
+}
+
xproto_table_t PROTO_TABLE(GLOBAL) = {
.entries = {
- /* Card Opcode */
- XENTRY( GLOBAL, NULL_REPLY ),
- XENTRY( GLOBAL, DEV_DESC ),
- XENTRY( GLOBAL, PCM_READ ),
- XENTRY( GLOBAL, SYNC_REPLY ),
+ /* Prototable Card Opcode */
+ XENTRY( GLOBAL, GLOBAL, NULL_REPLY ),
+ XENTRY( GLOBAL, GLOBAL, DEV_DESC ),
+ XENTRY( GLOBAL, GLOBAL, PCM_READ ),
+ XENTRY( GLOBAL, GLOBAL, SYNC_REPLY ),
+ XENTRY( GLOBAL, GLOBAL, ERROR_CODE ),
},
.name = "GLOBAL",
.packet_is_valid = global_packet_is_valid,
@@ -245,9 +292,9 @@ static bool global_packet_is_valid(xpacket_t *pack)
return xe != NULL;
}
-static void global_packet_dump(xpacket_t *pack)
+static void global_packet_dump(const char *msg, xpacket_t *pack)
{
- DBG("\n");
+ DBG("%s\n", msg);
}
static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
@@ -267,9 +314,89 @@ static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
XPD_COUNTER(xpd, RECV_ERRORS)++;
if((rate_limit++ % 1000) <= 10) {
ERR("BAD PCM REPLY: pack->datalen=%d, count=%d\n", pack->datalen, count);
+ dump_packet("BAD PCM REPLY", pack, 1);
}
return 0;
}
return 1;
}
+#define MAX_ENV_STR 20
+#define MAX_PATH_STR 60
+
+int run_initialize_registers(xpd_t *xpd)
+{
+ int ret;
+ xbus_t *xbus;
+ char busstr[MAX_ENV_STR];
+ char xpdstr[MAX_ENV_STR];
+ char unitstr[MAX_ENV_STR];
+ char subunitstr[MAX_ENV_STR];
+ char typestr[MAX_ENV_STR];
+ char revstr[MAX_ENV_STR];
+ char init_card[MAX_PATH_STR];
+ char *argv[] = {
+ init_card,
+ NULL
+ };
+ char *envp[] = {
+ busstr,
+ xpdstr,
+ unitstr,
+ subunitstr,
+ typestr,
+ revstr,
+ NULL
+ };
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ if(!initdir || !initdir[0]) {
+ NOTICE("%s/%s: Missing initdir parameter\n", xbus->busname, xpd->xpdname);
+ return -EINVAL;
+ }
+ snprintf(busstr, MAX_ENV_STR, "XPD_BUS=%s", xbus->busname);
+ snprintf(xpdstr, MAX_ENV_STR, "XPD_NAME=%s", xpd->xpdname);
+ snprintf(unitstr, MAX_ENV_STR, "XPD_UNIT=%d", xpd->addr.unit);
+ snprintf(subunitstr, MAX_ENV_STR, "XPD_SUBUNIT=%d", xpd->addr.subunit);
+ snprintf(typestr, MAX_ENV_STR, "XPD_TYPE=%d", xpd->type);
+ snprintf(revstr, MAX_ENV_STR, "XPD_REVISION=%d", xpd->revision);
+ if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d",
+ initdir, xpd->type, xpd->revision) > MAX_PATH_STR) {
+ NOTICE("%s/%s: Cannot initialize. pathname is longer than %d characters.\n",
+ xbus->busname, xpd->xpdname, MAX_PATH_STR);
+ return -E2BIG;
+ }
+ if(!down_read_trylock(&xbus->in_use)) {
+ ERR("Skipped register initialization. %s is going down\n", xbus->busname);
+ return -ENODEV;
+ }
+ DBG("%s/%s: running '%s' for type=%d revision=%d\n",
+ xbus->busname, xpd->xpdname, init_card, xpd->type, xpd->revision);
+ ret = call_usermodehelper(init_card, argv, envp, 1);
+ /*
+ * Carefully report results
+ */
+ if(ret == 0)
+ DBG("%s/%s: '%s' finished OK\n", xbus->busname, xpd->xpdname, init_card);
+ else if(ret < 0) {
+ ERR("%s/%s: Failed running '%s' (errno %d)\n",
+ xbus->busname, xpd->xpdname, init_card, ret);
+ } else {
+ byte exitval = ((unsigned)ret >> 8) & 0xFF;
+ byte sigval = ret & 0xFF;
+
+ if(!exitval) {
+ ERR("%s/%s: '%s' killed by signal %d\n",
+ xbus->busname, xpd->xpdname, init_card, sigval);
+ } else {
+ ERR("%s/%s: '%s' aborted with exitval %d\n",
+ xbus->busname, xpd->xpdname, init_card, exitval);
+ }
+ ret = -EINVAL;
+ }
+ up_read(&xbus->in_use);
+ return ret;
+}
+
+EXPORT_SYMBOL(run_initialize_registers);