summaryrefslogtreecommitdiff
path: root/xpp/xpp_proto.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/xpp_proto.c')
-rw-r--r--xpp/xpp_proto.c1044
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, &reg_type, &reg_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);