summaryrefslogtreecommitdiff
path: root/xpp/card_global.c
diff options
context:
space:
mode:
authorkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-02-15 02:24:18 +0000
committerkpfleming <kpfleming@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-02-15 02:24:18 +0000
commit41e0e5c06fead266ce179424b18134aeac2c5762 (patch)
tree246b5055fddf29d43c4d1a7c195ff3f3e1460ac4 /xpp/card_global.c
parent6aa681528c72a21a011883dcdcd35130bd066eac (diff)
initial import of Xorcom Astribank driver (issue #6452, with minor mods)
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@949 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/card_global.c')
-rw-r--r--xpp/card_global.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/xpp/card_global.c b/xpp/card_global.c
new file mode 100644
index 0000000..8b73f6e
--- /dev/null
+++ b/xpp/card_global.c
@@ -0,0 +1,256 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * 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 "xdefs.h"
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xproto.h"
+#include <linux/module.h>
+
+static const char rcsid[] = "$Id$";
+
+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);
+
+/*---------------- GLOBAL: HOST COMMANDS ----------------------------------*/
+
+/* 0x04 */ HOSTCMD(GLOBAL, DESC_REQ, int xpd_num)
+{
+ int ret = 0;
+ xpacket_t *pack;
+
+ if(!xbus) {
+ DBG("NO XBUS\n");
+ return -EINVAL;
+ }
+ XPACKET_NEW(pack, xbus, GLOBAL, DESC_REQ, xpd_num);
+ DBG("on %s #%d\n", xbus->busname, xpd_num);
+ ret = packet_send(xbus, pack);
+ XBUS_COUNTER(xbus, DESC_REQ)++;
+ return ret;
+}
+
+/* 0x11 */ HOSTCMD(GLOBAL, PCM_WRITE, xpp_line_t lines, volatile byte *buf)
+{
+ int ret = 0;
+ xpacket_t *pack;
+ byte *pcm;
+ byte *start_pcm;
+ int i;
+ extern ulong pcm_gen;
+
+ BUG_ON(!xbus);
+ BUG_ON(!xpd);
+ lines &= xpd->enabled_chans;
+ 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);
+
+ XPACKET_NEW(pack, xbus, GLOBAL, PCM_WRITE, xpd->id);
+ RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines) = lines;
+ start_pcm = pcm = RPACKET_FIELD(pack, GLOBAL, 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->datalen = sizeof(xpp_line_t) + (pcm - start_pcm);
+ packet_send(xbus, pack);
+ XPD_COUNTER(xpd, PCM_WRITE)++;
+ XBUS_COUNTER(xbus, PCM_WRITE)++;
+ return ret;
+}
+
+/* 0x19 */ HOSTCMD(GLOBAL, SYNC_SOURCE, bool setit, bool is_master)
+{
+ xpacket_t *pack;
+ 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);
+ XPACKET_NEW(pack, xbus, GLOBAL, SYNC_SOURCE, xpd->id);
+ RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, mask) = mask;
+ packet_send(xbus, pack);
+ return 0;
+}
+
+/*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
+
+HANDLER_DEF(GLOBAL, DEV_DESC)
+{
+ byte rev = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, rev);
+ byte type = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, type);
+ xpp_line_t line_status = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, line_status);
+ int xpd_num = XPD_NUM(pack->content.addr);
+ struct card_desc_struct *card_desc;
+
+ DBG("xpd=%d type=%d rev=%d line_status=0x%04X\n",
+ xpd_num, type, rev, line_status);
+ if((card_desc = kmalloc(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) {
+ ERR("%s: Card description allocation failed.\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+ memset(card_desc, 0, sizeof(struct card_desc_struct));
+ card_desc->magic = CARD_DESC_MAGIC;
+ card_desc->xbus = xbus;
+ card_desc->type = type;
+ card_desc->rev = rev;
+ card_desc->xpd_num = xpd_num;
+ INIT_WORK(&card_desc->work, card_detected, card_desc);
+ DBG("Queueing xpp_worker for xpd %d\n", xpd_num);
+ if(!queue_work(xpp_worker, &card_desc->work)) {
+ ERR("Failed to queue card description work\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+HANDLER_DEF(GLOBAL, PCM_READ)
+{
+ /* FIXME: work around temporary hardware bug */
+ xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
+ const byte *pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
+ volatile u_char *readchunk;
+ volatile u_char *r;
+ unsigned long flags;
+ int i;
+
+ if(!xpd) {
+#if 0
+ int xpd_num = XPD_NUM(pack->content.addr);
+ NOTICE("%s: received %s for non-existing xpd: %d\n",
+ __FUNCTION__, cmd->name, xpd_num);
+#endif
+ return -EPROTO;
+ }
+ // DBG("lines=0x%04X\n", lines);
+
+ if(!pcm_valid(xpd, pack)) {
+ 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);
+ xpp_tick((unsigned long)xpd);
+ return 0;
+}
+
+HANDLER_DEF(GLOBAL, SYNC_REPLY)
+{
+ if(!xpd) {
+ int xpd_num = XPD_NUM(pack->content.addr);
+ NOTICE("%s: received %s for non-existing xpd: %d\n", __FUNCTION__, cmd->name, xpd_num);
+ return -EPROTO;
+ }
+ DBG("SYNC_REPLY: 0x%X\n", RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, mask));
+ return 0;
+}
+
+
+xproto_table_t PROTO_TABLE(GLOBAL) = {
+ .entries = {
+ /* Card Opcode */
+ XENTRY( GLOBAL, DEV_DESC ),
+ XENTRY( GLOBAL, PCM_READ ),
+ XENTRY( GLOBAL, SYNC_REPLY ),
+ },
+ .name = "GLOBAL",
+ .packet_is_valid = global_packet_is_valid,
+ .packet_dump = global_packet_dump,
+};
+
+static bool global_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe;
+
+ //DBG("\n");
+ xe = xproto_global_entry(pack->content.opcode);
+ return xe != NULL;
+}
+
+static void global_packet_dump(xpacket_t *pack)
+{
+ DBG("\n");
+}
+
+static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
+{
+ xpp_line_t lines = RPACKET_FIELD(pack, GLOBAL, PCM_READ, lines);
+ int i;
+ int count = 0;
+
+ BUG_ON(!pack);
+ BUG_ON(pack->content.opcode != XPROTO_NAME(GLOBAL, PCM_READ));
+ for (i = 0; i < CHANNELS_PERXPD; i++)
+ if(IS_SET(lines, i))
+ count++;
+ if(pack->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: pack->datalen=%d, count=%d\n", pack->datalen, count);
+ }
+ return 0;
+ }
+ return 1;
+}
+