From a9ababa28c7ccedaf4be1501d009f99d9a7ba580 Mon Sep 17 00:00:00 2001 From: kpfleming Date: Wed, 15 Feb 2006 02:26:14 +0000 Subject: Merged revisions 949 via svnmerge from https://origsvn.digium.com/svn/zaptel/branches/1.2 ........ r949 | kpfleming | 2006-02-14 20:24:18 -0600 (Tue, 14 Feb 2006) | 2 lines initial import of Xorcom Astribank driver (issue #6452, with minor mods) ........ git-svn-id: http://svn.digium.com/svn/zaptel/trunk@950 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- xpp/xproto.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 xpp/xproto.c (limited to 'xpp/xproto.c') diff --git a/xpp/xproto.c b/xpp/xproto.c new file mode 100644 index 0000000..5a0d5c6 --- /dev/null +++ b/xpp/xproto.c @@ -0,0 +1,334 @@ +/* + * Written by Oron Peled + * Copyright (C) 2004-2005, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "xpd.h" +#include "xproto.h" +#include "xpp_zap.h" +#include + +static const char rcsid[] = "$Id$"; + +extern int print_dbg; +static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack); + +static const xproto_table_t *xprotocol_tables[XPD_TYPE_NOMODULE]; + +bool valid_xpd_addr(const xpd_addr_t *addr) +{ + return ((addr->bank_num & ~0x1) == 0) && ((addr->card_id & ~0x3) == 0); +} + +int xpd_addr2num(const xpd_addr_t *addr) +{ + BUG_ON(!valid_xpd_addr(addr)); + return addr->bank_num * 4 + addr->card_id; +} + +void xpd_set_addr(xpd_addr_t *addr, int xpd_num) +{ + if(xpd_num < 4) { + addr->card_id = xpd_num; + addr->bank_num = 0; + } else { + addr->card_id = xpd_num % 4; + addr->bank_num = xpd_num / 4; + } +} + + +/*---------------- General Protocol Management ----------------------------*/ + +const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, byte opcode) +{ + const xproto_entry_t *xe; + + //DBG("\n"); + xe = &table->entries[opcode]; + return (xe->handler != NULL) ? xe : NULL; +} + +const xproto_entry_t *xproto_global_entry(byte opcode) +{ + const xproto_entry_t *xe; + + xe = xproto_card_entry(&PROTO_TABLE(GLOBAL), opcode); + //DBG("opcode=0x%X xe=%p\n", opcode, xe); + return xe; +} + +const xproto_handler_t xproto_global_handler(byte opcode) +{ + return xproto_card_handler(&PROTO_TABLE(GLOBAL), opcode); +} + +const xproto_table_t *xproto_table(xpd_type_t cardtype) +{ + if(cardtype >= XPD_TYPE_NOMODULE) + return NULL; + return xprotocol_tables[cardtype]; +} + +const xproto_table_t *get_xproto_table(xpd_type_t cardtype) +{ + const xproto_table_t *xtable; + + if(cardtype >= XPD_TYPE_NOMODULE) + return NULL; + xtable = xprotocol_tables[cardtype]; + if(!xtable) { /* Try to load the relevant module */ + int ret = request_module("xpd-type-%d", cardtype); + if(ret != 0) { + NOTICE("%s: Failed to load module for type=%d. exit status=%d.\n", + __FUNCTION__, cardtype, ret); + /* Drop through: we may be luck... */ + } + xtable = xprotocol_tables[cardtype]; + } + return xtable; +} + +const xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode) +{ + const xproto_entry_t *xe; + + //DBG("\n"); + xe = xproto_card_entry(table, opcode); + return xe->handler; +} + +const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode) +{ + const xproto_entry_t *xe; + + xe = xproto_global_entry(opcode); + // DBG("opcode=0x%X xe=%p\n", opcode, xe); + if(!xe) { + const xproto_table_t *xtable; + + if(!xpd) + return NULL; + xtable = xproto_table(xpd->type); + if(!xtable) + return NULL; + xe = xproto_card_entry(xtable, opcode); + if(!xe) + return NULL; + } + return xe; +} + +const xops_t *get_xops(xpd_type_t xpd_type) +{ + const xproto_table_t *proto_table; + + if(xpd_type >= XPD_TYPE_NOMODULE) + return NULL; + proto_table = xprotocol_tables[xpd_type]; + if(!proto_table) + return NULL; + return &proto_table->xops; +} + +int packet_receive(xbus_t *xbus, xpacket_t *pack) +{ + int xpd_num; + + if(!valid_xpd_addr(&pack->content.addr)) { + static int rate_limit = 0; + + if((rate_limit++ % 5003) < 3) + dump_packet("bad address", pack, print_dbg); + xbus->ops->packet_free(xbus, pack); + return -EPROTO; + } + xpd_num = XPD_NUM(pack->content.addr); +#if SOFT_SIMULATOR + if(xbus->sim[xpd_num].simulated) { + //dump_packet("packet_receive -> simulate", pack, print_dbg); + return simulate_xpd(xbus, xpd_num, pack); + } else +#endif + { + //dump_packet("packet_receive -> process", pack, print_dbg); + return packet_process(xbus, xpd_num, pack); + } +} + +static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack) +{ + byte op; + const xproto_entry_t *xe; + xproto_handler_t handler; + xproto_table_t *table; + xpd_t *xpd; + int ret = 0; + + BUG_ON(!pack); + op = pack->content.opcode; + xpd_num = XPD_NUM(pack->content.addr); + xpd = xpd_of(xbus, xpd_num); + xe = find_xproto_entry(xpd, op); + /*-------- Validations -----------*/ + if(!xe) { + ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op); + dump_packet("packet_process -- bad command", pack, print_dbg); + ret = -EPROTO; + goto out; + } + table = xe->table; + BUG_ON(!table); + if(!table->packet_is_valid(pack)) { + ERR("xpp: %s: wrong size %d for op=0x%02X\n", + __FUNCTION__, pack->datalen, op); + dump_packet("packet_process -- wrong size", pack, print_dbg); + ret = -EPROTO; + goto out; + } + handler = xe->handler; + BUG_ON(!handler); + XBUS_COUNTER(xbus, RX_BYTES) += pack->datalen; + handler(xbus, xpd, xe, pack); +out: + xbus->ops->packet_free(xbus, pack); + return ret; +} + +#define VERBOSE_DEBUG 1 +#define ERR_REPORT_LIMIT 20 + +void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg) +{ + byte op = packet->content.opcode; + + if(!print_dbg) + return; + DBG("%s: @0x%1X%1X OP=0x%02X LEN=%d\n", + msg, + packet->content.addr.bank_num, + packet->content.addr.card_id, + op, + (byte)packet->datalen); +#if VERBOSE_DEBUG + { + int i; + byte *p = packet->content.data; + + for(i = 0; i < packet->datalen; i++) { + static int limiter = 0; + + if(i >= sizeof(xpacket_raw_t)) { + if(limiter < ERR_REPORT_LIMIT) { + ERR("%s: length overflow i=%d > sizeof(xpacket_raw_t)=%d\n", + __FUNCTION__, i+1, sizeof(xpacket_raw_t)); + } else if(limiter == ERR_REPORT_LIMIT) { + ERR("%s: error packet #%d... squelsh reports.\n", + __FUNCTION__, limiter); + } + limiter++; + break; + } + DBG(" %2d> %02X\n", i+1, p[i]); + } + } +#endif +} + +const char *xproto_name(xpd_type_t xpd_type) +{ + const xproto_table_t *proto_table; + + BUG_ON(xpd_type >= XPD_TYPE(NOMODULE)); + proto_table = xprotocol_tables[xpd_type]; + if(!proto_table) + return NULL; + return proto_table->name; +} + +#define CHECK_XOP(f) \ + if(!(xops)->f) { \ + ERR("%s: missing xmethod %s [%s (%d)]\n", __FUNCTION__, #f, name, type); \ + return -EINVAL; \ + } + +int xproto_register(const xproto_table_t *proto_table) +{ + int type; + const char *name; + const xops_t *xops; + + BUG_ON(!proto_table); + type = proto_table->type; + name = proto_table->name; + if(type >= XPD_TYPE(NOMODULE)) { + NOTICE("%s: Bad xproto type %d\n", __FUNCTION__, type); + return -EINVAL; + } + DBG("%s (%d)\n", name, type); + if(xprotocol_tables[type]) + NOTICE("%s: overriding registration of %s (%d)\n", __FUNCTION__, name, type); + xops = &proto_table->xops; + CHECK_XOP(card_new); + CHECK_XOP(card_init); + CHECK_XOP(card_remove); + CHECK_XOP(card_tick); + CHECK_XOP(SYNC_SOURCE); + CHECK_XOP(PCM_WRITE); + CHECK_XOP(CHAN_ENABLE); + CHECK_XOP(CHAN_POWER); + CHECK_XOP(CHAN_CID); + CHECK_XOP(RING); + CHECK_XOP(SETHOOK); + CHECK_XOP(LED); + CHECK_XOP(RELAY_OUT); + + xprotocol_tables[type] = proto_table; + return 0; +} + +void xproto_unregister(const xproto_table_t *proto_table) +{ + int type; + const char *name; + + BUG_ON(!proto_table); + type = proto_table->type; + name = proto_table->name; + DBG("%s (%d)\n", name, type); + if(type >= XPD_TYPE(NOMODULE)) { + NOTICE("%s: Bad xproto type %s (%d)\n", __FUNCTION__, name, type); + return; + } + if(!xprotocol_tables[type]) + NOTICE("%s: xproto type %s (%d) is already unregistered\n", __FUNCTION__, name, type); + xprotocol_tables[type] = NULL; +} + +EXPORT_SYMBOL(dump_packet); +EXPORT_SYMBOL(packet_receive); +EXPORT_SYMBOL(valid_xpd_addr); +EXPORT_SYMBOL(xpd_addr2num); +EXPORT_SYMBOL(xpd_set_addr); +EXPORT_SYMBOL(xproto_global_entry); +EXPORT_SYMBOL(xproto_card_entry); +EXPORT_SYMBOL(xproto_name); +EXPORT_SYMBOL(xproto_register); +EXPORT_SYMBOL(xproto_unregister); -- cgit v1.2.3