From 4953605453a7f7f1da8c70c4c12a4b557cfc2c24 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Mon, 6 Nov 2006 21:18:42 +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/trunk@1563 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- xpp/card_global.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 11 deletions(-) (limited to 'xpp/card_global.c') 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); -- cgit v1.2.3