diff options
Diffstat (limited to 'xpp/xpp_proto.c')
-rw-r--r-- | xpp/xpp_proto.c | 1044 |
1 files changed, 0 insertions, 1044 deletions
diff --git a/xpp/xpp_proto.c b/xpp/xpp_proto.c deleted file mode 100644 index b020caf..0000000 --- a/xpp/xpp_proto.c +++ /dev/null @@ -1,1044 +0,0 @@ -#include <linux/module.h> -#include <linux/delay.h> /* for udelay */ -#include "xpd.h" -#include "xpp_proto.h" -#include "xpp_zap.h" - -static char rcsid[] = "$Id$"; - -extern int print_dbg; -#include "zap_debug.h" - -typedef struct xpp_command xpp_command_t; -typedef int (*xpp_handler_t)(xbus_t *xbus, int id, xpp_command_t *cmd, xpacket_t *packet); - -struct xpp_command { - xpp_opcode_t opcode; - unsigned int header_size; - bool varsize; - const char *name; - const char *desc; - xpp_handler_t handler; -}; - -#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[] = { -#include "slic_init.inc" -}; - -static int packet_process(xbus_t *xbus, int xpd_num, xpacket_t *pack); -static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet); -static bool pcm_valid(xpd_t *xpd, xpacket_t *reply); - -#define NEW_PACKET(p, xbus, name, to) \ - do { \ - p = xbus->ops->packet_new(xbus, GFP_ATOMIC); \ - if(!p) \ - return -ENOMEM; \ - PACKET_INIT(p, name); \ - XPD_ADDR_SET(p->content.addr, to); \ - } while(0); - -/*------------------------- SLIC Handling --------------------------*/ - -int proc_xpd_slic_read(char *page, char **start, off_t off, int count, int *eof, void *data) -{ - int len = 0; - unsigned long flags; - xpd_t *xpd = data; - //slic_reply_t *info; - - BUG_ON(!xpd); - spin_lock_irqsave(&xpd->lock, flags); -#if 0 - info = (slic_reply_t *)&xpd->slic_info; - len += sprintf(page + len, "SLIC_REPLY: %s reg_num=0x%X, dataH=0x%X dataL=0x%X\n", - (info->indirect)?"I":"D", - info->reg_num, info->data_high, info->data_low); -#endif - spin_unlock_irqrestore(&xpd->lock, flags); - if (len <= off+count) - *eof = 1; - *start = page + off; - len -= off; - if (len > count) - len = count; - if (len < 0) - len = 0; - return len; -} - -static int parse_slic_cmd(const char *buf, slic_cmd_t *sc) -{ - char op; /* [W]rite, [R]ead */ - char reg_type; /* [D]irect, [I]ndirect */ - int s1, s2, s3, s4; - int reg_num; - int data_low, data_high; - xpp_line_t lines; - int ret; - - ret = sscanf(buf, "%x %x %x %x %c%c %x %x %x", - &s1, &s2, &s3, &s4, &op, ®_type, ®_num, &data_high, &data_low); - lines = (s4 << 24) | (s3 << 16) | (s2 << 8) | (s1); - switch(op) { - case 'R': - if(reg_type == 'D' && ret == 7) { - // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num); - ret = slic_cmd_direct_read(sc, lines, reg_num); - } else if(reg_type == 'I' && ret == 7) { - // DBG("0x%X 0x%X 0x%X 0x%X %c %x\n", s1, s2, s3, s4, reg_type, reg_num); - ret = slic_cmd_indirect_read(sc, lines, reg_num); - } else { - NOTICE("%s: Bad read input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type); - goto err; - } - break; - case 'W': - if(reg_type == 'D' && ret == 8) { - // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high); - ret = slic_cmd_direct_write(sc, lines, reg_num, data_high); - } else if(reg_type == 'I' && ret == 9) { - // DBG("0x%X 0x%X 0x%X 0x%X %c %x %X %X\n", s1, s2, s3, s4, reg_type, reg_num, data_high, data_low); - ret = slic_cmd_indirect_write(sc, lines, reg_num, data_low, data_high); - } else { - NOTICE("%s: Bad write input: ret=%d buf='%s' reg_type=%c\n", __FUNCTION__, ret, buf, reg_type); - goto err; - } - break; - default: - NOTICE("%s: Bad input: ret=%d buf='%s' op=%c\n", __FUNCTION__, ret, buf, op); - goto err; - } - return ret; -err: - return -EINVAL; -} - -static int process_slic_cmdline(xpd_t *xpd, char *cmdline) -{ - xbus_t *xbus; - slic_cmd_t sc; - xpacket_t *pack_tx; - char *p; - int len = strlen(cmdline); - - BUG_ON(!xpd); - xbus = xpd->xbus; - if((p = strchr(cmdline, '#')) != NULL) /* Truncate comments */ - *p = '\0'; - if((p = strchr(cmdline, ';')) != NULL) /* Truncate comments */ - *p = '\0'; - for(p = cmdline; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ - ; - if(*p == '\0') - return 0; - len = parse_slic_cmd(p, &sc); - 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__); - return 0; - } - dump_slic_cmd("WRITE_SLIC", &sc); - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd) = sc; - pack_tx->datalen = len; - packet_send(xbus, pack_tx); - return 0; -} - -int proc_xpd_slic_write(struct file *file, const char __user *buffer, unsigned long count, void *data) -{ - xpd_t *xpd = data; - const int LINE_LEN = 500; - char buf[LINE_LEN]; - char *p; - int i; - int ret; - - BUG_ON(!xpd); - for(i = 0; i < count; /* noop */) { - for(p = buf; p < buf + LINE_LEN; p++) { /* read a line */ - if(i >= count) - break; - if(get_user(*p, buffer + i)) - return -EFAULT; - i++; - if(*p == '\n' || *p == '\r') /* whatever */ - break; - } - if(p >= buf + LINE_LEN) - return -E2BIG; - *p = '\0'; - ret = process_slic_cmdline(xpd, buf); - if(ret < 0) - return ret; - } - return count; -} - - - -/*------------------------- Protocol Functions ---------------------*/ - -#define HOSTCMD(name, ...) \ - DECLARE_CMD(name, ## __VA_ARGS__ ); \ - EXPORT_SYMBOL(xpp_proto_ ## name); \ - DECLARE_CMD(name, ## __VA_ARGS__ ) - - -/* 0x04 */ HOSTCMD(DESC_REQ, int xpd_num) -{ - int ret = 0; - xpacket_t *pack_tx; - - DBG("\n"); - if(!xbus) { - DBG("NO XBUS\n"); - return -EINVAL; - } - NEW_PACKET(pack_tx, xbus, DESC_REQ, xpd_num); - DBG("calling packet_send for a DESC_REQ packet.\n"); - ret = packet_send(xbus, pack_tx); - DBG("after packet_send, updating counter (ret=%d)\n", ret); - XBUS_COUNTER(xbus, DESC_REQ)++; - return ret; -} - -/* 0x0F */ HOSTCMD(CHAN_POWER, xpp_line_t lines, bool on) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - int len; - - BUG_ON(!xbus); - BUG_ON(!xpd); - lines &= xpd->enabled_chans; // Ignore disabled channels - if(!lines) { - return 0; - } - DBG("Channel Power: 0x%04X %s\n", lines, (on) ? "up" : "down"); - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - if(on) { - // Power up - len = slic_cmd_direct_write(sc, lines, 0x42, 0x06); - } else { - // Power down - len = slic_cmd_direct_write(sc, lines, 0x42, 0x00); - } - pack_tx->datalen = len; - - packet_send(xbus, pack_tx); - return ret; -} - -/* 0x0F */ HOSTCMD(CHAN_ENABLE, xpp_line_t lines, bool on) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - int len; - - 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"); - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - len = slic_cmd_direct_write(sc, lines, 0x40, (on)?0x01:0x00); - pack_tx->datalen = len; - - packet_send(xbus, pack_tx); - return ret; -} - -/* 0x0F */ HOSTCMD(RING, int pos, bool on) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - xpp_line_t mask = (1 << pos); - int len; - - BUG_ON(!xbus); - BUG_ON(!xpd); - mask &= xpd->enabled_chans; // Ignore disabled channels - if(!mask) { - return 0; - } - DBG("%s pos=%d %s\n", xpd->xpdname, pos, (on) ? "on" : "off"); - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - len = slic_cmd_direct_write(sc, mask, 0x40, (on)?0x04:0x01); - pack_tx->datalen = len; - - packet_send(xbus, pack_tx); - return ret; -} - -/* 0x0F */ HOSTCMD(SETHOOK, xpp_line_t hook_status) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - int len; - - BUG_ON(!xbus); - BUG_ON(!xpd); - hook_status &= xpd->enabled_chans; // Ignore disabled channels - if(!hook_status) { - return 0; - } - DBG("New hook_status: %d\n", hook_status); - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - /* FIXME: This is fake, until Dima implements FXO */ - len = slic_cmd_direct_write(sc, hook_status, 0x02, 0x00); - pack_tx->datalen = len; - - packet_send(xbus, pack_tx); - return ret; -} - -/* - * LED control is done via SLIC register 0x06: - * 7 6 5 4 3 2 1 0 - * +-----+-----+-----+-----+-----+-----+-----+-----+ - * | MR | MG | MB | R | OG | OB | G | B | - * +-----+-----+-----+-----+-----+-----+-----+-----+ - * - * B - BLUE LED (0 - OFF, 1 - ON) - * G - GREEN LED (0 - OFF, 1 - ON) - * OB - Output BLUE (this line is output) - * OG - Output GREEN (this line is output) - * R - RED LED (0 - OFF, 1 - ON) - * MB - Mask BLUE. (1 - B effect the BLUE LED) - * MR - Mask RED. (1 - R effect the RED LED) - * MG - Mask GREEN. (1 - G effect the GREEN LED) - * - * The BLUE LED (actually a relay out) is connected to line 0 and 4 only. - */ - -// GREEN RED BLUE -static int led_mask[NUM_LEDS] = { BIT(6), BIT(7), BIT(5) }; -static int led_vals[NUM_LEDS] = { BIT(1), BIT(4), BIT(0) }; - -/* 0x0F */ HOSTCMD(LED, xpp_line_t lines, byte which, bool on) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - int len; - int value; - int i; - - BUG_ON(!xbus); - BUG_ON(!xpd); - lines &= xpd->enabled_chans; // Ignore disabled channels - if(!lines) { - return 0; - } - DBG("LED: lines=0x%04X which=%d -- %s\n", lines, which, (on) ? "on" : "off"); - which = which % NUM_LEDS; - value = BIT(2) | BIT(3); - value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[which]); - if(on) - value |= led_vals[which]; - for(i = 0; i < CHANNELS_PERXPD; i++) { - if(!IS_SET(lines, i)) - continue; - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - len = slic_cmd_direct_write(sc, lines, 0x06, value); - DBG("LED pack: line=%d value=0x%04X\n", i, value); - pack_tx->datalen = len; - packet_send(xbus, pack_tx); - } - return ret; -} - -/* 0x0F */ HOSTCMD(RELAY_OUT, byte which, bool on) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - int len; - int value; - xpp_line_t lines; - int relay_channels[] = { 0, 4 }; - - BUG_ON(!xbus); - BUG_ON(!xpd); - - DBG("RELAY_OUT: which=%d -- %s\n", which, (on) ? "on" : "off"); - which = which % ARRAY_SIZE(relay_channels); - lines = BIT(relay_channels[which]); - value = BIT(2) | BIT(3); - value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_mask[LED_BLUE]); - if(on) - value |= led_vals[LED_BLUE]; - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - len = slic_cmd_direct_write(sc, lines, 0x06, value); - - DBG("RELAY_OUT pack: line=%d value=0x%04X\n", lines, value); - pack_tx->datalen = len; - packet_send(xbus, pack_tx); - return ret; -} - -/* 0x0F */ HOSTCMD(SLIC_INIT) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_data_t *slic; - struct slic_init_data *source; - int i; - - BUG_ON(!xbus); - BUG_ON(!xpd); - DBG("INITIALIZING SLIC\n"); - for(i = 0; i < ARRAY_SIZE(slic_init_data); i++) { - source = &slic_init_data[i]; - NEW_PACKET(pack_tx, xbus, SLIC_INIT, xpd->id); - PACKET_FIELD(pack_tx, SLIC_INIT, lines) = source->lines; - - slic = &PACKET_FIELD(pack_tx, SLIC_INIT, slic_data); - slic->len = source->slic_data.len; - memcpy(slic->data, source->slic_data.data, source->slic_data.len); - pack_tx->datalen = sizeof(xpp_line_t) + slic->len + 1; -// dump_packet("SLIC", pack_tx, print_dbg); - packet_send(xbus, pack_tx); - mdelay(10); // FIXME: Temporary -- Dima need to fix it - } - return ret; -} - -/* 0x0F */ HOSTCMD(SLIC_QUERY, int pos, byte reg_num) -{ - int ret = 0; - xpacket_t *pack_tx; - slic_cmd_t *sc; - int len; - - BUG_ON(!xbus); - BUG_ON(!xpd); - NEW_PACKET(pack_tx, xbus, SLIC_WRITE, xpd->id); - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - len = slic_cmd_direct_read(sc, (1<<pos), reg_num); - - pack_tx->datalen = len; - - packet_send(xbus, pack_tx); - return ret; -} - -/* 0x11 */ HOSTCMD(PCM_WRITE, xpp_line_t lines, volatile byte *buf) -{ - int ret = 0; - xpacket_t *pack_tx; - byte *pcm; - byte *start_pcm; - int i; - extern ulong pcm_gen; - - BUG_ON(!xbus); - BUG_ON(!xpd); - lines &= xpd->enabled_chans; - // DBG("PCM_WRITE\n"); - if(pcm_gen != 0) - return 0; -// if(lines == 0) -// return 0; - - /* - * FIXME: Workaround a bug in sync code of the Astribank. - * Send dummy PCM for sync. - */ - if(lines == 0) - lines = BIT(0); - - NEW_PACKET(pack_tx, xbus, PCM_WRITE, xpd->id); - PACKET_FIELD(pack_tx, PCM_WRITE, lines) = lines; - start_pcm = pcm = PACKET_FIELD(pack_tx, PCM_WRITE, pcm); - for(i = 0; i < CHANNELS_PERXPD; i++) { - if(IS_SET(lines, i)) { - memcpy(pcm, (byte *)buf, ZT_CHUNKSIZE); - pcm += ZT_CHUNKSIZE; - } - buf += ZT_CHUNKSIZE; - } - pack_tx->datalen = sizeof(xpp_line_t) + (pcm - start_pcm); - packet_send(xbus, pack_tx); - XPD_COUNTER(xpd, PCM_WRITE)++; - XBUS_COUNTER(xbus, PCM_WRITE)++; - return ret; -} - -/* 0x13 */ HOSTCMD(PCM_GEN, xpp_line_t lines, volatile byte *buf) -{ - xpacket_t *pack_tx; - bool gen_seq = ((lines != 0) && (buf != NULL)); - - BUG_ON(!xbus); - BUG_ON(!xpd); - lines &= xpd->enabled_chans; // Ignore disabled channels - if(!lines) { - return 0; - } - DBG("PCM_GEN lines=0x%04X %s\n", lines, (gen_seq) ? "seq" : "off"); - NEW_PACKET(pack_tx, xbus, PCM_GEN, xpd->id); - PACKET_FIELD(pack_tx, PCM_GEN, lines) = lines; - if(gen_seq) { - PACKET_FIELD(pack_tx, PCM_GEN, gen) = 0; - memcpy(&PACKET_FIELD(pack_tx, PCM_GEN, pcm_seq), (byte *)buf, ZT_CHUNKSIZE); - } else { - PACKET_FIELD(pack_tx, PCM_GEN, gen) = 2; - } - packet_send(xbus, pack_tx); - return 0; -} - -/* - * Sync source is controled by a mask byte to 0x19 command: - * 7 6 5 4 3 2 1 0 - * +-----+-----+-----+-----+-----+-----+-----+-----+ - * | | | | | | | RW | AB | - * +-----+-----+-----+-----+-----+-----+-----+-----+ - * - * RW - Read or set (0 - Write, 1 - Read) - * AB - This Astribank provide sync (0 - no, 1 - yes) - * - */ - -/* 0x19 */ HOSTCMD(SYNC_SOURCE, bool setit, bool is_master) -{ - xpacket_t *pack_tx; - byte mask = 0; - - BUG_ON(!xbus); - BUG_ON(!xpd); - if(is_master) - mask |= BIT(0); - if(!setit) - mask |= BIT(1); - DBG("SYNC_SOURCE %s setit=%s is_master=%s (mask=0x%X)\n", - xpd->xpdname, (setit)?"yes":"no", (is_master)?"yes":"no", mask); - NEW_PACKET(pack_tx, xbus, SYNC_SOURCE, xpd->id); - PACKET_FIELD(pack_tx, SYNC_SOURCE, mask) = mask; - packet_send(xbus, pack_tx); - return 0; -} - -/* 0x31 */ HOSTCMD(LOOPBACK_AX, byte *data, unsigned int size) -{ - xpacket_t *pack_tx; - - BUG_ON(!xbus); - BUG_ON(!xpd); - DBG("LOOPBACK_AX %d bytes\n", size); - NEW_PACKET(pack_tx, xbus, LOOPBACK_AX, xpd->id); - memcpy(&PACKET_FIELD(pack_tx, LOOPBACK_AX, data), data, size); - packet_send(xbus, pack_tx); - return 0; -} - -/*------------------------- Protocol Simulator ---------------------*/ - - -static int simulate_xpd(xbus_t *xbus, int xpd_num, xpacket_t *sent_packet) -{ - xpacket_t *pack = sent_packet; - struct xpd_sim *xpd_sim; - struct xpd_sim *loopto_sim; - xpp_opcode_t opcode; - int dest_xpd_num; - int ret = 0; - - // Sanity checks - BUG_ON(!xbus); - BUG_ON(xpd_num > MAX_XPDS || xpd_num < 0); - BUG_ON(!sent_packet); - BUG_ON(!xbus->sim[xpd_num].simulated); - - XBUS_COUNTER(xbus, SIM_PACKETS)++; - xpd_sim = &xbus->sim[xpd_num]; - opcode = pack->content.opcode; - dest_xpd_num = xpd_sim->loopto; - loopto_sim = &xbus->sim[dest_xpd_num]; -// DBG("before: addr=%d, opcode=0x%X\n", xpd_num, opcode); - switch(opcode) { - case XPP_DESC_REQ: - DBG("SIM DESC_REQ (xpd_num=%d)\n", xpd_num); - PACKET_INIT(pack, DEV_DESC); - PACKET_FIELD(pack, DEV_DESC, type) = xpd_sim->xpd_type; - dest_xpd_num = xpd_num; // Reply as the original XPD - break; - case XPP_PCM_WRITE: - PACKET_INIT(pack, PCM_READ); - XPD_ADDR_SET(pack->content.addr, dest_xpd_num); - break; - case XPP_SLIC_WRITE: -#if FINISHED_DECODING_SLICS - slic_cmd_t *sc; - int len; - - sc = &PACKET_FIELD(pack_tx, SLIC_WRITE, slic_cmd); - lines = sc->lines; - bool slic_write = ! (slic->data[0] & 0x80); - int slic_reg = slic->data[0] & ~0x80; - - if(slic->len == 2 && slic_write && slic_reg == 0x40) { // RING - bool on = (slic->data[1] == 0x04); - if(on) { - loopto_sim->hookstate |= lines; - } else { - loopto_sim->hookstate &= ~lines; - } - - DBG("SIM RING to: xpd=%d (type=%d): (%s) ringing=0x%04X lines=0x%04X\n", dest_xpd_num, loopto_sim->xpd_type, - (on)?"on":"off", loopto_sim->hookstate, lines); - PACKET_INIT(pack, SIG_CHANGED); - PACKET_FIELD(pack, SIG_CHANGED, type) = loopto_sim->xpd_type; - PACKET_FIELD(pack, SIG_CHANGED, sig_status) = loopto_sim->hookstate; - PACKET_FIELD(pack, SIG_CHANGED, sig_toggles) = lines; - dump_packet("SIM RING TO", pack, print_dbg); - break; - } else if(slic->len == 1 && slic_write && slic_reg == 0x02) { // SETHOOK - DBG("SIM SETHOOK: xpd=%d: hookstate=0x%04X lines=0x%04X\n", dest_xpd_num, loopto_sim->hookstate, lines); - PACKET_INIT(pack, SIG_CHANGED); - PACKET_FIELD(pack, SIG_CHANGED, type) = loopto_sim->xpd_type; - PACKET_FIELD(pack, SIG_CHANGED, sig_status) = lines; - PACKET_FIELD(pack, SIG_CHANGED, sig_toggles) = loopto_sim->hookstate ^ lines; - loopto_sim->hookstate = lines; - break; - } else if(slic->len == 2 && slic_write && slic_reg == 0x06) { // LED - DBG("SIM LED: xpd=%d: 0x%04X=%s\n", xpd_num, lines, (0x10)? "on" : "off"); - ret = 0; - goto junk; - } else if(slic->len == 2 && ! slic_write) { // SLIC_QUERY - DBG("SIM SLIC_QUERY: xpd=%d: register=0x%02X\n", xpd_num, slic_reg); - ret = 0; - goto junk; - } else if(slic->len >= 4) { // INITIALIZATION? - DBG("SIM INITIALIZATION? xpd=%d len=%d\n", xpd_num, slic->len); - ret = 0; - goto junk; - } - NOTICE("%s: xpd=%d: SLIC_WRITE: len=%d\n", __FUNCTION__, xpd_num, slic->len); -#endif - dump_packet("BAD SLIC_WRITE", pack, print_dbg); - // FALL THROUGH - default: - NOTICE("%s: xpd=%d: CANNOT SIMULATE OPCODE=0x%02X\n", - __FUNCTION__, xpd_num, opcode); -// dump_packet("BAD OPCODE", pack, print_dbg); - ret = -EINVAL; - goto junk; - } -// DBG("after reversing: addr=%d, opcode=0x%X\n", xpd_num, pack->header.opcode); - return packet_process(xbus, dest_xpd_num, pack); -junk: - 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) -{ - xpp_opcode_t op = (byte)packet->content.opcode; - - if(!print_dbg) - return; - DBG("%s: @0x%02X OP=0x%02X flags=0x%02X LEN=%d\n", - msg, - XPD_NUM(packet->content.addr), - op, - (byte)packet->flags, - (byte)packet->datalen); -#if VERBOSE_DEBUG - { - int i; - byte *p = packet->content.raw; - - for(i = 0; i < packet->datalen; i++) { - static int limiter = 0; - - if(i >= sizeof(xpp_packet_r_t)) { - if(limiter < ERR_REPORT_LIMIT) { - ERR("dump_packet: length overflow i=%d > sizeof(xpp_packet_r_t)=%d\n", - i+1, sizeof(xpp_packet_r_t)); - } else if(limiter == ERR_REPORT_LIMIT) { - ERR("dump_packet: error packet #%d... squelsh reports.\n", limiter); - } - limiter++; - break; - } - DBG(" %2d> %02X\n", i+1, p[i]); - } - } -#endif -} - -/*------------------------- Reply Handlers -------------------------*/ - -#define HANDLER_DEF(name) \ - int CALL_PROTO(name, xbus_t *xbus, int xpd_num, xpp_command_t *cmd, xpacket_t *reply) - -/* -static HANDLER_DEF(notimp) -{ - NOTICE("xpp protocol error: command %s is not implemented yet\n", cmd->name); - return -EPROTO; -} -*/ -static HANDLER_DEF(DEV_DESC) -{ - byte type = PACKET_FIELD(reply, DEV_DESC, type) & 0x7; // 3 LSB's - byte rev = PACKET_FIELD(reply, DEV_DESC, rev); - xpp_line_t line_status = PACKET_FIELD(reply, DEV_DESC, line_status); - xpd_t *xpd = xpd_of(xbus, xpd_num); - - if(xpd) { - NOTICE("Received DEV_DESC packet for an existing xpd %s of type %d\n", - xpd->xpdname, type); - return 0; - } - XBUS_COUNTER(xbus, DEV_DESC)++; - DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n", xpd_num, type, rev, line_status); - switch(type) { - case XPD_TYPE_FXS: - break; - case XPD_TYPE_FXO: - break; - case XPD_TYPE_NOMODULE: - DBG("No module at address=%d\n", xpd_num); - return 0; - default: - NOTICE("DEV_DESC: unkown type=%d\n", type); - return -EPROTO; - } - if((xpd = xpd_new(xbus, xpd_num, type, rev)) == NULL) { - NOTICE("xpd_new failed\n"); - } - xpp_check_hookstate(xpd, line_status); - return 0; -} - -/** - * Handle signalling - */ -static HANDLER_DEF(SIG_CHANGED) -{ - xpd_t *xpd = xpd_of(xbus, xpd_num); - xpp_line_t sig_status = PACKET_FIELD(reply, SIG_CHANGED, sig_status); - - if(!xpd) { - NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num); - return -EPROTO; - } - if(xpd->direction == TO_PHONE) { /* Hook state changes */ - DBG("%s (PHONE) sig_status=0x%04X\n", xpd->xpdname, sig_status); - xpp_check_hookstate(xpd, sig_status); - } else { /* TO_TRUNK - line ring changes */ - unsigned long flags; - int i; - - DBG("%s (TRUNK) sig_status=0x%04X\n", xpd->xpdname, sig_status); - spin_lock_irqsave(&xpd->lock, flags); - for(i = 0; i < xpd->channels; i++) { - if(IS_SET(sig_status, i)) { - xpd->ringing[i] = RINGS_NUM*2; - zt_hooksig(&xpd->chans[i], ZT_RXSIG_OFFHOOK); - } else { - zt_hooksig(&xpd->chans[i], ZT_RXSIG_ONHOOK); - xpd->ringing[i] = 0; - } - } - spin_unlock_irqrestore(&xpd->lock, flags); - } - return 0; -} - -static HANDLER_DEF(SLIC_REPLY) -{ - slic_reply_t *info = &PACKET_FIELD(reply, SLIC_REPLY, info); - xpd_t *xpd = xpd_of(xbus, xpd_num); - unsigned long flags; - - if(!xpd) { - NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num); - return -EPROTO; - } - spin_lock_irqsave(&xpd->lock, flags); - DBG("SLIC_REPLY: xpd #%d %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", - xpd_num, (info->indirect)?"I":"D", - info->reg_num, info->data_low, info->data_high); - spin_unlock_irqrestore(&xpd->lock, flags); - return 0; -} - -static HANDLER_DEF(PCM_READ) -{ - /* FIXME: work around temporary hardware bug */ - xpd_num = 0; - - xpp_line_t lines = PACKET_FIELD(reply, PCM_READ, lines); - const byte *pcm = PACKET_FIELD(reply, PCM_READ, pcm); - xpd_t *xpd = xpd_of(xbus, xpd_num); - volatile u_char *readchunk; - volatile u_char *r; - unsigned long flags; - int i; - - if(!xpd) { - NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num); - return -EPROTO; - } - // DBG("lines=0x%04X\n", lines); - - if(!pcm_valid(xpd, reply)) { - return -EPROTO; - } - spin_lock_irqsave(&xpd->lock, flags); - if (xpd->timer_count & 1) { - /* First part */ - r = readchunk = xpd->readchunk; - } else { - r = readchunk = xpd->readchunk + ZT_CHUNKSIZE * CHANNELS_PERXPD; - } - - /* Copy PCM and put each channel in its index */ - for (i = 0; i < CHANNELS_PERXPD; i++) { - if(IS_SET(lines, i)) { - memcpy((u_char *)r, pcm, ZT_CHUNKSIZE); - //memset((u_char *)r, 0x5A, ZT_CHUNKSIZE); // DEBUG - pcm += ZT_CHUNKSIZE; - } - r += ZT_CHUNKSIZE; - } - - XPD_COUNTER(xpd, PCM_READ)++; - XBUS_COUNTER(xpd->xbus, PCM_READ)++; - spin_unlock_irqrestore(&xpd->lock, flags); - if(xpd->id == 0) - xpp_tick(0); - return 0; -} - -static HANDLER_DEF(SYNC_REPLY) -{ - xpd_t *xpd = xpd_of(xbus, xpd_num); - - if(!xpd) { - NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num); - return -EPROTO; - } - DBG("SYNC_REPLY: 0x%X\n", PACKET_FIELD(reply, SYNC_REPLY, mask)); - return 0; -} - -static HANDLER_DEF(LOOPBACK_XA) -{ - xpd_t *xpd = xpd_of(xbus, xpd_num); - - if(!xpd) { - NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num); - return -EPROTO; - } - dump_packet("LOOPBACK_XA", reply, print_dbg); - CALL_PROTO(LED, xpd->xbus, xpd, xpd->enabled_chans, LED_RED, 0); // FIXME: Find usage for extra LED - return 0; -} - -static HANDLER_DEF(DIAG_FE) -{ - dump_packet("DIAG_FE", reply, print_dbg); - return 0; -} - -static const xpp_packet_r_t FOR_SIZE_CALC; // Ugly hack, so we have something to sizeof() - -#define C_(op,var,txt) \ - [ XPP_##op ] { \ - .opcode = XPP_##op, \ - .varsize = var, \ - .header_size = sizeof(FOR_SIZE_CALC.cmd_##op), \ - .name = #op, \ - .desc = txt, \ - .handler = PROTO_FUNC(op) \ - } - -static xpp_command_t xpp_commands[] = { - /* OP V DESCRIPTION */ - C_( DEV_DESC, 0, "Device description reply"), - C_( SIG_CHANGED, 0, "Signaling change (hookstate/ringing)"), - C_( SLIC_REPLY, 0, "Reply to slic state"), - C_( PCM_READ, 1, "Read PCM data"), - C_( SYNC_REPLY, 0, "SYNC_REPLY"), - C_( LOOPBACK_XA, 1, "LOOPBACK Reply"), - C_( DIAG_FE, 1, "DIAG FE Opcode"), -}; - -#undef C_ - -static unsigned int xpp_max_opcode(void) -{ - return ARRAY_SIZE(xpp_commands); -} - -static bool xpp_valid_opcode(xpp_opcode_t op) -{ - if(op <= 0 || op >= xpp_max_opcode()) - return 0; - return xpp_commands[op].opcode != XPP_NOTIMP; -} - -static xpp_command_t *xpp_command(xpp_opcode_t op) -{ - if(!xpp_valid_opcode(op)) - return 0; - return &xpp_commands[op]; -} - -static bool xpp_valid_size(xpp_opcode_t op, xpacket_t *pack) -{ - xpp_command_t *cmd = xpp_command(op); - unsigned int hsize = cmd->header_size; - unsigned int size = pack->datalen; - int varsize = cmd->varsize; - - // ERR("op=%d hsize=%d size=%d\n", op, hsize, size); - return (hsize == size) || - (varsize && size <= sizeof(struct xpp_packet_r)); -} - -static bool pcm_valid(xpd_t *xpd, xpacket_t *reply) -{ - xpp_opcode_t op; - xpp_command_t *cmd; - xpp_line_t lines = PACKET_FIELD(reply, PCM_READ, lines); - int i; - int count = 0; - - BUG_ON(!reply); - op = reply->content.opcode; - cmd = xpp_command(op); - if(!cmd) { - ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op); - return 0; - } - for (i = 0; i < CHANNELS_PERXPD; i++) - if(IS_SET(lines, i)) - count++; - if(reply->datalen != (sizeof(xpp_line_t) + count * 8)) { - static int rate_limit = 0; - - XPD_COUNTER(xpd, RECV_ERRORS)++; - if((rate_limit++ % 1000) <= 10) { - ERR("BAD PCM REPLY: reply->datalen=%d, count=%d\n", reply->datalen, count); - } - return 0; - } - return 1; -} - -int packet_receive(xbus_t *xbus, xpacket_t *pack) -{ - int xpd_num = XPD_NUM(pack->content.addr); - - if(!VALID_XPD_NUM(xpd_num)) { - dump_packet("martian packet", pack, print_dbg); - xbus->ops->packet_free(xbus, pack); - return -EPROTO; - } - if(xbus->sim[xpd_num].simulated) { - //dump_packet("packet_receive -> simulate", pack, print_dbg); - return simulate_xpd(xbus, xpd_num, pack); - } else { - //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) -{ - xpp_opcode_t op; - xpp_command_t *cmd; - xpp_handler_t handler; - int ret = 0; - - BUG_ON(!pack); - op = pack->content.opcode; - cmd = xpp_command(op); - /*-------- Validations -----------*/ - if(!cmd) { - ERR("xpp: %s -- bad command op=0x%02X\n", __FUNCTION__, op); - dump_packet("packet_process -- bad command", pack, print_dbg); - ret = -EPROTO; - goto out; - } - if(!xpp_valid_size(op, 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 = cmd->handler; - BUG_ON(!handler); - XBUS_COUNTER(xbus, RX_BYTES) += pack->datalen; - handler(xbus, xpd_num, cmd, pack); -out: - xbus->ops->packet_free(xbus, pack); - return ret; -} - - -void process_sim_queue(void *data) -{ - xbus_t *xbus = data; - xpacket_t *pack; - -// DBG("\n"); - BUG_ON(!xbus); - while((pack = xbus_dequeue_packet(&xbus->sim_packet_queue)) != NULL) { -// DBG("pack->addr=0x%X pack->opcode=0x%X\n", XPD_NUM(pack->addr), pack->header.opcode); - packet_receive(xbus, pack); - } -} - -/** - * processes a packet recieved from the lower-level. - * @xbus the data bus - * @pack the handled packet - * @returns return status (0 for success). - * - * Should not be blocking. - * Has separate handling for PCM packets (direct write) and command packets (queued) - */ - -EXPORT_SYMBOL(dump_packet); -EXPORT_SYMBOL(packet_receive); -EXPORT_SYMBOL(proc_xpd_slic_read); -EXPORT_SYMBOL(proc_xpd_slic_write); |