summaryrefslogtreecommitdiff
path: root/xpp/xproto.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/xproto.c')
-rw-r--r--xpp/xproto.c199
1 files changed, 116 insertions, 83 deletions
diff --git a/xpp/xproto.c b/xpp/xproto.c
index f965c10..02741e6 100644
--- a/xpp/xproto.c
+++ b/xpp/xproto.c
@@ -43,27 +43,10 @@ bool valid_xpd_addr(const xpd_addr_t *addr)
return ((addr->subunit & ~BITMASK(SUBUNIT_BITS)) == 0) && ((addr->unit & ~BITMASK(UNIT_BITS)) == 0);
}
-int xpd_addr2num(const xpd_addr_t *addr)
-{
- BUG_ON(!valid_xpd_addr(addr));
- return addr->unit | (addr->subunit << UNIT_BITS);
-}
-
void xpd_set_addr(xpd_addr_t *addr, int xpd_num)
{
- addr->unit = xpd_num & BITMASK(UNIT_BITS);
- addr->subunit = (xpd_num >> UNIT_BITS) & BITMASK(SUBUNIT_BITS);
-}
-
-xpd_t *xpd_by_addr(const xbus_t *xbus, int unit, int subunit)
-{
- xpd_addr_t addr;
- int xpd_num;
-
- addr.unit = unit;
- addr.subunit = subunit;
- xpd_num = xpd_addr2num(&addr);
- return xpd_of(xbus, xpd_num);
+ addr->unit = XBUS_UNIT(xpd_num);
+ addr->subunit = XBUS_SUBUNIT(xpd_num);
}
/*---------------- General Protocol Management ----------------------------*/
@@ -142,25 +125,10 @@ xproto_handler_t xproto_card_handler(const xproto_table_t *table, byte opcode)
return xe->handler;
}
-static const xproto_entry_t *find_xproto_entry(xpd_t *xpd, byte opcode)
+void notify_bad_xpd(const char *funcname, xbus_t *xbus, const xpd_addr_t addr, const char *msg)
{
- 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;
+ NOTICE("%s: non-existing address %s(%1d%1d): %s\n",
+ funcname, xbus->busname, addr.unit, addr.subunit, msg);
}
int packet_process(xbus_t *xbus, xpacket_t *pack)
@@ -170,41 +138,63 @@ int packet_process(xbus_t *xbus, xpacket_t *pack)
xproto_handler_t handler;
xproto_table_t *table;
xpd_t *xpd;
- int ret = 0;
+ int ret = -EPROTO;
BUG_ON(!pack);
if(!valid_xpd_addr(&pack->addr)) {
if(printk_ratelimit())
dump_packet("packet_process -- bad address", pack, print_dbg);
- ret = -EPROTO;
goto out;
}
op = pack->opcode;
- xpd = xpd_by_addr(xbus, pack->addr.unit, pack->addr.subunit);
+ xpd = xpd_byaddr(xbus, pack->addr.unit, pack->addr.subunit);
/* XPD may be NULL (e.g: during bus polling */
- xe = find_xproto_entry(xpd, op);
+ xe = xproto_global_entry(op);
/*-------- Validations -----------*/
if(!xe) {
- if(printk_ratelimit()) {
- ERR("xpp: %s: %s/%d-%d: bad command op=0x%02X\n",
- __FUNCTION__, xbus->busname,
- pack->addr.unit, pack->addr.subunit, op);
- dump_packet("packet_process -- bad command", pack, print_dbg);
+ const xproto_table_t *xtable;
+
+ if(!xpd) {
+ if(printk_ratelimit()) {
+ NOTICE("%s: %s from %d%d opcode=0x%02X: no such global command.\n",
+ __FUNCTION__, xbus->busname,
+ pack->addr.unit, pack->addr.subunit, op);
+ dump_packet("packet_process -- no such global command", pack, 1);
+ }
+ goto out;
+ }
+ xtable = xproto_table(xpd->type);
+ if(!xtable) {
+ if(printk_ratelimit())
+ ERR("%s: %s/%s: no protocol table (type=%d)\n",
+ __FUNCTION__,
+ xbus->busname, xpd->xpdname,
+ xpd->type);
+ goto out;
+ }
+ xe = xproto_card_entry(xtable, op);
+ if(!xe) {
+ if(printk_ratelimit()) {
+ NOTICE("%s: %s/%s: bad command (type=%d,opcode=0x%x)\n",
+ __FUNCTION__,
+ xbus->busname, xpd->xpdname,
+ xpd->type, op);
+ dump_packet("packet_process -- bad command", pack, 1);
+ }
+ goto out;
}
- ret = -EPROTO;
- goto out;
}
table = xe->table;
BUG_ON(!table);
if(!table->packet_is_valid(pack)) {
if(printk_ratelimit()) {
- ERR("xpp: %s: wrong size %d for op=0x%02X\n",
+ ERR("xpp: %s: wrong size %d for opcode=0x%02X\n",
__FUNCTION__, pack->datalen, op);
dump_packet("packet_process -- wrong size", pack, print_dbg);
}
- ret = -EPROTO;
goto out;
}
+ ret = 0; /* All well */
handler = xe->handler;
BUG_ON(!handler);
XBUS_COUNTER(xbus, RX_BYTES) += pack->datalen;
@@ -215,33 +205,69 @@ out:
int xframe_receive(xbus_t *xbus, xframe_t *xframe)
{
- byte *p;
- byte *xpacket_start;
- byte *xframe_end;
- int ret = 0;
- static int rate_limit;
-
- if(print_dbg == 2 && ((rate_limit++ % 1003) == 0))
- dump_xframe("RCV_PCM", xbus, xframe);
+ byte *p;
+ byte *xpacket_start;
+ byte *xframe_end;
+ int ret = 0;
+ xpacket_t *pack;
+ int len;
+ bool is_pcm;
+
p = xpacket_start = xframe->packets;
xframe_end = xpacket_start + XFRAME_LEN(xframe);
- do {
- xpacket_t *pack = (xpacket_t *)p;
- int len = pack->datalen;
+ if(XFRAME_LEN(xframe) < RPACKET_HEADERSIZE) {
+ static int rate_limit;
+ if((rate_limit++ % 1003) == 0) {
+ NOTICE("%s: short xframe\n", xbus->busname);
+ dump_xframe("short xframe", xbus, xframe);
+ }
+ goto bad_proto;
+ }
+ /*
+ * We want to check that xframes do not mix PCM and other commands
+ */
+ is_pcm = ((xpacket_t *)p)->opcode == XPROTO_NAME(GLOBAL,PCM_READ);
+ if(print_dbg & DBG_PCM) {
+ static int rate_limit;
+
+ if(is_pcm && ((rate_limit++ % 1003) == 0))
+ dump_xframe("RX_XFRAME_PCM", xbus, xframe);
+ }
+ do {
+ pack = (xpacket_t *)p;
+ len = pack->datalen;
+ /* Sanity checks */
+ if(unlikely(is_pcm && pack->opcode != XPROTO_NAME(GLOBAL,PCM_READ) && printk_ratelimit())) {
+ NOTICE("%s: Non-PCM packet within a PCM xframe\n", xbus->busname);
+ dump_xframe("In PCM xframe", xbus, xframe);
+ // goto bad_proto;
+ } else if(unlikely(!is_pcm && pack->opcode == XPROTO_NAME(GLOBAL,PCM_READ) && printk_ratelimit())) {
+ NOTICE("%s: A PCM packet within a Non-PCM xframe\n", xbus->busname);
+ // goto bad_proto;
+ }
p += len;
- if(p > xframe_end) {
- ERR("%s: Invalid packet length %d\n", __FUNCTION__, len);
- ret = -EPROTO;
- goto out;
+ if(p > xframe_end || len < RPACKET_HEADERSIZE) {
+ static int rate_limit;
+
+ if((rate_limit++ % 1003) == 0) {
+ NOTICE("%s: Invalid packet length %d\n", xbus->busname, len);
+ dump_xframe("BAD LENGTH", xbus, xframe);
+ }
+ goto bad_proto;
}
ret = packet_process(xbus, pack);
if(unlikely(ret < 0))
goto out;
} while(p < xframe_end);
+ if(is_pcm)
+ XBUS_COUNTER(xbus, RX_XFRAME_PCM)++;
out:
xbus->ops->xframe_free(xbus, xframe);
return ret;
+bad_proto:
+ ret = -EPROTO;
+ goto out;
}
#define VERBOSE_DEBUG 1
@@ -290,34 +316,39 @@ void dump_packet(const char *msg, xpacket_t *packet, bool print_dbg)
printk("\n");
}
-void dump_reg_cmd(const char msg[], reg_cmd_t *regcmd)
+void dump_reg_cmd(const char msg[], const reg_cmd_t *regcmd, bool writing)
{
char action;
- char mode;
byte chipsel;
- byte regnum;
- byte data_low;
- byte data_high;
if(regcmd->bytes != sizeof(*regcmd) - 1) { /* The size byte is not included */
NOTICE("%s: Wrong size: regcmd->bytes = %d\n", __FUNCTION__, regcmd->bytes);
return;
}
- action = (REG_FIELD(regcmd, chipsel) & 0x80) ? 'R' : 'W';
+ if(writing && (REG_FIELD(regcmd, chipsel) & 0x80))
+ ERR("Sending register command with reading bit ON\n");
+ action = (writing) ? 'W' : 'R';
chipsel = REG_FIELD(regcmd, chipsel) & ~0x80;
- if(REG_FIELD(regcmd, regnum) == 0x1E) {
- mode = 'I';
- regnum = REG_FIELD(regcmd, subreg);
- data_low = REG_FIELD(regcmd, data_low);
- data_high = REG_FIELD(regcmd, data_high);
+ if(REG_FIELD(regcmd, do_subreg)) {
+ DBG("%s: %d %cS %02X %02X [%02X] # data_high=%X m=%d eof=%d\n", msg, chipsel, action,
+ REG_FIELD(regcmd, regnum),
+ REG_FIELD(regcmd, subreg),
+ REG_FIELD(regcmd, data_low),
+ REG_FIELD(regcmd, data_high),
+ regcmd->multibyte, regcmd->eoframe);
+ } else if(REG_FIELD(regcmd, regnum) == 0x1E) {
+ DBG("%s: %d %cI %02X [%02X %02X] # m=%d eof=%d\n", msg, chipsel, action,
+ REG_FIELD(regcmd, subreg),
+ REG_FIELD(regcmd, data_low),
+ REG_FIELD(regcmd, data_high),
+ regcmd->multibyte, regcmd->eoframe);
} else {
- mode = 'D';
- regnum = REG_FIELD(regcmd, regnum);
- data_low = REG_FIELD(regcmd, data_low);
- data_high = 0;
+ DBG("%s: %d %cD %02X [%02X] # data_high=%X m=%d eof=%d\n", msg, chipsel, action,
+ REG_FIELD(regcmd, regnum),
+ REG_FIELD(regcmd, data_low),
+ REG_FIELD(regcmd, data_high),
+ regcmd->multibyte, regcmd->eoframe);
}
- DBG("%d %c%c %02X %02X %02X # m=%d eof=%d\n", chipsel, action, mode, regnum,
- data_low, data_high, regcmd->multibyte, regcmd->eoframe);
}
const char *xproto_name(xpd_type_t xpd_type)
@@ -358,6 +389,8 @@ int xproto_register(const xproto_table_t *proto_table)
CHECK_XOP(card_init);
CHECK_XOP(card_remove);
CHECK_XOP(card_tick);
+ CHECK_XOP(card_pcm_fromspan);
+ CHECK_XOP(card_pcm_tospan);
CHECK_XOP(card_zaptel_preregistration);
CHECK_XOP(card_zaptel_postregistration);
CHECK_XOP(card_hooksig);
@@ -391,8 +424,8 @@ void xproto_unregister(const xproto_table_t *proto_table)
EXPORT_SYMBOL(dump_packet);
EXPORT_SYMBOL(dump_reg_cmd);
EXPORT_SYMBOL(xframe_receive);
+EXPORT_SYMBOL(notify_bad_xpd);
EXPORT_SYMBOL(valid_xpd_addr);
-EXPORT_SYMBOL(xpd_addr2num);
EXPORT_SYMBOL(xpd_set_addr);
EXPORT_SYMBOL(xproto_global_entry);
EXPORT_SYMBOL(xproto_card_entry);