|  
 | Форум cronyx.ru (архив)
 
     | czaptel.c | kmax  ::  2006-02-21 18:41 | 
 /** Zaptel protocol layer for Cronyx serial (E1) adapters.
 *
 * Copyright (C) 2005 Cronyx Engineering.
 * Author: Roman Kurakin, <rik@cronyx.ru>
 *
 * This software is distributed with NO WARRANTIES, not even the implied
 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Authors grant any other persons or organisations permission to use
 * or modify this software as long as this message is kept with the software,
 * all derivative works or modified versions.
 *
 * $Id: czaptel.c,v 1.3.2.1 2005/11/07 08:31:51 rik Exp $
 */
 #include "module.h"
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
 #include <linux/timer.h>
 #include <linux/pkt_sched.h>
 #include "cserial.h"
 #include "zaptel.h"
 
 /* Module information */
 MODULE_AUTHOR("Roma Kurakin <rik@cronyx.ru>, Cronyx Engineering.");
 MODULE_DESCRIPTION("Zaptel protocol driver " CRONYX_VERSION_INFO "
");
 #ifdef MODULE_LICENSE
 MODULE_LICENSE("Dual BSD/GPL");
 #endif
 
 typedef struct _zaptel_t {
 chan_t *chan;
 int running;
 
 int num;
 int usecount;
 int dead;
 int sync;
 volatile unsigned char writechunk[ZT_MAX_CHUNKSIZE * 32 * 2];		/* Double-word aligned write memory */
 volatile unsigned char readchunk[ZT_MAX_CHUNKSIZE * 32 * 2];		/* Double-word aligned read memory */
 unsigned char ec_chunk1[31][ZT_CHUNKSIZE];
 unsigned char ec_chunk2[31][ZT_CHUNKSIZE];
 struct zt_span span;		/* Span */
 struct zt_chan chans[31];	/* Channels */
 struct sk_buff *txskb;
 int flag;
 int txbusy;
 int cas;
 #define CAS_LOF		1
 #define CAS_SYNC	2
 #define CAS_ALL_ZERO	4
 int cas_state;
 int cas_lofcount;
 int cas_rbsbits[16];
 int cas_rbsbits_copy[16];
 int cas_rbsbits_tx[16];
 int cas_tx_index;
 int cas_shift;
 int cas_half;
 } zaptel_t;
 
 static void zaptel_transmit_done (chan_t *h);
 
 static void zaptel_receive (chan_t *h, struct sk_buff *skb)
 {
 zaptel_t *p = h->sw;
 int x;
 int y;
 int i;
 unsigned char rxs;
 
 if (skb->len % 32 != 0) {
 printk (KERN_ERR "Data should be 32*N length
");
 SET_SKB_FREE (skb);
 KFREE_SKB (skb, FREE_READ);
 return;
 }
 
 /* XXX */
 if (skb->len % (32 * ZT_CHUNKSIZE)) {
 LOG2 (p->chan, "Data should be 32*ZT_CHUNKSIZE*N length
");
 }
 /* XXX add check for FAS */
 
 for (i = 1; i <= skb->len; i += 32 * ZT_CHUNKSIZE) {
 p->cas_half = p->cas_half ? 0 : 8;
 for (y=0;y<ZT_CHUNKSIZE;y++) {
 for (x=0;x<p->span.channels;x++) {
 p->chans[x].readchunk[y] =
 skb->data[i + 32 * y + x]; /* Note i starts from 1 */
 }
 }
 if (p->cas) {
 for (y=0;y<ZT_CHUNKSIZE;y++) { /* hacky ZT_CHNUKSIZE==8 */
 p->cas_rbsbits[y+p->cas_half] = skb->data[i + 32 * y + 15];
 }
 /* Check if we are in sync */
 if (p->cas_state & CAS_SYNC) {
 if (p->cas_rbsbits[p->cas_shift]&0xf0) {
 if (p->cas_lofcount < 2) {
 LOG (p->chan, "LOF (%d)
", p->cas_lofcount);
 p->cas_lofcount++;
 } else {
 LOG (p->chan, "LOF, out of frame sync
");
 p->cas_state ^= (CAS_SYNC | CAS_LOF);
 }
 }
 }
 /* Try to find cas */
 if ((p->cas_state & CAS_LOF) && p->cas_half) {
 for (y=0;y<16;y++) {
 if ((p->cas_rbsbits[p->cas_shift]&0xf0) == 0) {
 p->cas_state ^= (CAS_SYNC | CAS_LOF);
 LOG (p->chan, "Got multifram sync
");
 break;
 }
 p->cas_shift = (p->cas_shift + 1) & 0x0f;
 }
 }
 if (p->cas_half) {
 LOG2 (h, "shift: %d %x
", p->cas_shift, p->cas_state);
 LOG2 (h, "1: %02x%02x%02x%02x
", p->cas_rbsbits[0], p->cas_rbsbits[1], p->cas_rbsbits[2], p->cas_rbsbits[3]);
 LOG2 (h, "2: %02x%02x%02x%02x
", p->cas_rbsbits[4+0], p->cas_rbsbits[4+1], p->cas_rbsbits[4+2], p->cas_rbsbits[4+3]);
 LOG2 (h, "3: %02x%02x%02x%02x
", p->cas_rbsbits[8+0], p->cas_rbsbits[8+1], p->cas_rbsbits[8+2], p->cas_rbsbits[8+3]);
 LOG2 (h, "4: %02x%02x%02x%02x
", p->cas_rbsbits[12+0], p->cas_rbsbits[12+1], p->cas_rbsbits[12+2], p->cas_rbsbits[12+3]);
 }
 /* XXX do some logic here in cas of LOF */
 if ((p->cas_state & CAS_SYNC) && p->cas_half) {
 for (y=1; y<16; y++) {
 rxs = p->cas_rbsbits[(p->cas_shift + y) & 0x0f];
 if (!(p->chans[y+15].sig & ZT_SIG_CLEAR)) {
 if (p->chans[i+15].rxsig != (rxs&0x0f)) {
 /*							printk (KERN_ERR "Change detected %d %d %x
", y, 1, rxs);*/
 zt_rbsbits(&p->chans[y+15], (rxs&0x0f));
 }
 }
 rxs >>= 4;
 if (!(p->chans[y-1].sig & ZT_SIG_CLEAR)) {
 if (p->chans[y-1].rxsig != rxs) {
 /*							printk (KERN_ERR "Change detected %d %d %x
", y, 0, rxs);*/
 zt_rbsbits(&p->chans[y-1], rxs);
 }
 }
 #if 1
 if (p->cas_rbsbits[(p->cas_shift + y) & 0x0f]!=p->cas_rbsbits_copy[(p->cas_shift + y) & 0x0f]) {
 LOG2 (h, "Changed %d %x->%x
", (p->cas_shift + y) & 0x0f, p->cas_rbsbits_copy[(p->cas_shift + y) & 0x0f], p->cas_rbsbits[(p->cas_shift + y) & 0x0f]);
 p->cas_rbsbits_copy[(p->cas_shift + y) & 0x0f] = p->cas_rbsbits[(p->cas_shift + y) & 0x0f];
 }
 #endif
 }
 }
 }
 for (x=0;x<p->span.channels;x++) {
 zt_ec_chunk(&p->chans[x], p->chans[x].readchunk,
 p->ec_chunk2[x]);
 memcpy(p->ec_chunk2[x],p->ec_chunk1[x],ZT_CHUNKSIZE);
 memcpy(p->ec_chunk1[x],p->chans[x].writechunk,ZT_CHUNKSIZE);
 }
 zt_receive(&p->span);
 }
 SET_SKB_FREE (skb);
 KFREE_SKB (skb, FREE_READ);
 zaptel_transmit_done (h);
 }
 
 static void zaptel_receive_error (chan_t *h, int errcode)
 {
 /*	zaptel_t *p = h->sw;*/
 
 LOG2 (h, "receive error %x
", errcode);
 
 /*
 * XXXRIK: we are not ready yet to treat errors, so just log
 * it and ignore. That is Ok for now.
 */
 return;
 }
 
 static void zaptel_transmit_done (chan_t *h)
 {
 /*	static unsigned char buf[32*ZT_CHUNKSIZE];*/
 zaptel_t *p = h->sw;
 struct sk_buff *skb;
 int y;
 int x;
 int k;
 int res;
 int multiplier;
 
 if (test_and_set_bit (0, (void *)&p->txbusy) != 0)
 return;
 
 if (p->flag && p->txskb == 0) {
 printk (KERN_ERR "Bad p->flag state detected
");
 p->flag = 0;
 }
 
 if (p->flag == 0) {
 unsigned char *buf;
 
 multiplier = h->mtu / (32 * ZT_CHUNKSIZE);
 
 skb = dev_alloc_skb (32*ZT_CHUNKSIZE * multiplier);
 
 if (!skb) {
 p->txbusy = 0;
 LOG2 (h, "ENOMEMM
");
 return;
 }
 
 p->txskb = skb;
 skb_put (skb, 32*ZT_CHUNKSIZE * multiplier);
 p->flag = 1;
 
 for (buf = skb->data; buf < skb->data + 32*ZT_CHUNKSIZE*multiplier; buf += 32*ZT_CHUNKSIZE) {
 zt_transmit(&p->span);
 for (y=0;y<ZT_CHUNKSIZE;y++) {
 if (p->cas && p->cas_rbsbits_tx[0] != 0x0b) {
 printk (KERN_ERR "Ups, wrong CAS transmit table
");
 }
 for (x=0;x<p->span.channels;x++) {
 buf [y*32+x+1] = p->chans[x].writechunk[y];
 }
 if (p->cas) {
 buf [y*32+16] = p->cas_rbsbits_tx[p->cas_tx_index];
 p->cas_tx_index = (p->cas_tx_index + 1) & 0x0f;
 }
 }
 }
 }
 
 k = p->txskb->len;
 res = h->transmit (h, p->txskb);
 if (res > 0) {
 p->flag = 0;
 /* XXXRIK do the same on unload/detach */
 KFREE_SKB (p->txskb, FREE_WRITE);
 p->txskb = 0;
 }
 LOG2 (h, "tr res:%d %d
", res, k);
 p->txbusy = 0;
 }
 
 static int zap_ioctl(struct zt_chan *chan, unsigned int cmd, unsigned long data)
 {
 switch(cmd) {
 default:
 return -ENOTTY;
 }
 }
 
 static int zap_close(struct zt_chan *chan)
 {
 zaptel_t *p = chan->pvt;
 p->usecount--;
 #ifndef LINUX26
 MOD_DEC_USE_COUNT;
 #endif
 if (!p->usecount && p->chan && p->chan->down)
 p->chan->down(p->chan);
 
 /* If we're dead, release us now */
 if (!p->usecount && p->dead) {
 /*		zt_unregister(&p->span);*/
 /*		kfree(wc);*/
 /*		printk("Freed a Wildcard
");*/
 }
 return 0;
 }
 
 static int zap_open(struct zt_chan *chan)
 {
 zaptel_t *p = chan->pvt;
 if (p->dead)
 return -ENODEV;
 if (!p->usecount && p->chan && p->chan->up)
 p->chan->up(p->chan);
 p->usecount++;
 LOG2 (p->chan, "ZAP_OPEN: %d
", p->usecount);
 if (p->usecount == 1) {
 zaptel_transmit_done (p->chan);
 zaptel_transmit_done (p->chan);
 zaptel_transmit_done (p->chan);
 }
 #ifndef LINUX26
 MOD_INC_USE_COUNT;
 #endif
 return 0;
 }
 
 static int zap_rbsbits(struct zt_chan *chan, int bits)
 {
 zaptel_t *p = chan->pvt;
 /*	int b,o;*/
 unsigned char mask;
 
 LOG (p->chan, " rbsbits trunk:%d set bits: %x(was %x)
",
 chan->chanpos, bits, p->cas_rbsbits_tx[chan->chanpos%16]);
 /* Byte offset */
 if (p->cas_rbsbits_tx[0] != 0x0b) {
 printk (KERN_ERR "Ups, wrong CAS transmit table
");
 }
 if (chan->chanpos < 16) {
 mask = ((bits << 4) | p->chans[chan->chanpos - 1 + 16].txsig);
 p->cas_rbsbits_tx[chan->chanpos] = mask;
 } else if (chan->chanpos > 16) {
 mask = (bits | (p->chans[chan->chanpos - 1 - 16].txsig << 4));
 p->cas_rbsbits_tx[chan->chanpos - 16] = mask;
 }
 p->chans[chan->chanpos - 1].txsig = bits;
 if (p->cas_rbsbits_tx[0] != 0x0b) {
 printk (KERN_ERR "Ups, wrong CAS transmit table
");
 }
 return 0;
 }
 
 static int zap_startup(struct zt_span *span)
 {
 zaptel_t *p = span->pvt;
 chan_t *h = p->chan;
 int i, alreadyrunning = span->flags & ZT_FLAG_RUNNING;
 
 /* initialize the start value for the entire chunk of last ec buffer */
 for(i = 0; i < span->channels; i++)
 {
 memset(p->ec_chunk1[i],
 ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
 memset(p->ec_chunk2[i],
 ZT_LIN2X(0,&span->chans[i]),ZT_CHUNKSIZE);
 }
 
 /* Reset framer with proper parameters and start */
 /* Build up config */
 if (p->span.lineconfig & ZT_CONFIG_CCS) {
 LOG (h, "Set CCS mode
");
 p->cas = 0;
 } else {
 LOG (h, "Set CAS mode
");
 p->cas = 1;
 p->cas_state = CAS_LOF;
 }
 if (p->span.lineconfig & ZT_CONFIG_HDB3) {
 LOG (h, "Set HDB3 mode: ignore we are always HDB3
");
 } else {
 LOG (h, "Set AMI mode: ignore we are always HDB3
");
 }
 if (p->span.lineconfig & ZT_CONFIG_CRC4) {
 LOG (h, "Set CRC4 mode: ignore, use sconfig instead
");
 }
 if (!alreadyrunning) {
 p->span.flags |= ZT_FLAG_RUNNING;
 }
 LOG2(h, "Startup flags is %d
", span->flags);
 
 if (!alreadyrunning) {
 /* Only if we're not already going */
 span->flags |= ZT_FLAG_RUNNING;
 }
 return 0;
 }
 
 static int zap_shutdown(struct zt_span *span)
 {
 /*	zaptel_t *p = span->pvt;*/
 /*	unsigned long flags;*/
 
 span->flags &= ~ZT_FLAG_RUNNING;
 
 return 0;
 }
 
 static int zap_maint(struct zt_span *span, int cmd)
 {
 zaptel_t *p = span->pvt;
 int res = 0;
 
 switch(cmd) {
 case ZT_MAINT_NONE:
 /* loop=off, rloop=off */
 LOG2 (p->chan, "No loops, not supported
");
 break;
 case ZT_MAINT_LOCALLOOP:
 /* loop=on, rloop=? */
 LOG2 (p->chan, "Local loop, not supported
");
 break;
 case ZT_MAINT_REMOTELOOP:
 /* loop=?, rloop=on */
 LOG2 (p->chan, "Local rloop, not supported
");
 break;
 case ZT_MAINT_LOOPUP:
 case ZT_MAINT_LOOPDOWN:
 case ZT_MAINT_LOOPSTOP:
 res = -ENOSYS;
 break;
 default:
 LOG2(p->chan, "Unknown maint command: %d
", cmd);
 res = -EINVAL;
 break;
 }
 return res;
 }
 
 static int zap_chanconfig(struct zt_chan *chan, int sigtype)
 {
 return 0;
 }
 
 static int zap_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
 {
 zaptel_t *p = span->pvt;
 span->lineconfig = lc->lineconfig;
 span->txlevel = lc->lbo;
 span->rxlevel = 0;
 /* Do we want to SYNC on receive or not */
 p->sync = lc->sync;
 /* If already running, apply changes immediately */
 if (span->flags & ZT_FLAG_RUNNING)
 return zap_startup (span);
 return 0;
 }
 
 static int zaptel_attach (chan_t *h)
 {
 zaptel_t *p;
 int x;
 
 p = kmalloc (sizeof (zaptel_t), GFP_KERNEL);
 if (! p)
 return -ENOMEM;
 memset (p, 0, sizeof (zaptel_t));
 h->sw = p;
 p->chan = h;
 p->cas_rbsbits_tx[0] = 0x0b;
 memset (p->cas_rbsbits_tx+1, 0xff, 15);
 p->span.spanconfig = zap_spanconfig;
 p->span.chanconfig = zap_chanconfig;
 p->span.startup = zap_startup;
 p->span.shutdown = zap_shutdown;
 p->span.rbsbits = zap_rbsbits;
 p->span.maint = zap_maint;
 p->span.open = zap_open;
 p->span.close = zap_close;
 p->span.ioctl = zap_ioctl;
 p->span.channels = 31;
 p->span.chans = p->chans;
 p->span.flags = 0; /*ZT_FLAG_RBS;*/
 p->span.linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS;
 p->span.pvt = p;
 p->span.deflaw = ZT_LAW_ALAW;
 for (x=0;x<p->span.channels;x++) {
 sprintf(p->chans[x].name, "CP0/%d/%d", 0, x + 1);
 p->chans[x].sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_EM_E1 |
 ZT_SIG_FXSLS | ZT_SIG_FXSGS |
 ZT_SIG_FXSKS | ZT_SIG_FXOLS |
 ZT_SIG_FXOGS | ZT_SIG_FXOKS |
 ZT_SIG_CAS | ZT_SIG_SF;
 p->chans[x].pvt = p;
 p->chans[x].chanpos = x + 1;
 }
 if (zt_register(&p->span, 0)) {
 printk("Unable to register span with zaptel
");
 return 0; /* XXX do smth bad */
 }
 #if LINUX_VERSION_CODE < 0x020600
 MOD_INC_USE_COUNT;
 #else
 try_module_get (THIS_MODULE);
 #endif
 return 0;
 }
 
 static int zaptel_detach (chan_t *h)
 {
 zaptel_t *p = h->sw;
 
 if (p) {
 /* Release span, possibly delayed */
 if (!p->usecount)
 zt_unregister(&p->span);
 else
 p->dead = 1;
 }
 
 kfree (p);
 h->sw = 0;
 #if LINUX_VERSION_CODE < 0x020600
 MOD_DEC_USE_COUNT;
 #else
 module_put (THIS_MODULE);
 #endif
 return 0;
 }
 
 static int zaptel_control (chan_t *h, unsigned int cmd, unsigned long arg)
 {
 /*	zaptel_t *p = h->sw;*/
 
 return 0;
 }
 
 /*
 * Protocol callbacks
 */
 static proto_t zaptel_tab = {
 "zaptel", 0,
 
 /* Interface to channel */
 zaptel_receive,
 zaptel_receive_error,
 zaptel_transmit_done,
 0,			/* modem event */
 
 /* I/O interface */
 0,			/* open */
 0,			/* close */
 0,			/* read */
 0,			/* write */
 0,			/* select */
 0,			/* fasync */
 
 /* Control interface */
 zaptel_attach,
 zaptel_detach,
 zaptel_control,			/* control */
 };
 
 /*//////////////////////////////////////////////////////////////////////
 * Loadable module control
 */
 int init_module (void)
 {
 #if LINUX_VERSION_CODE < 0x020600
 EXPORT_NO_SYMBOLS;
 #endif
 binder_register_protocol (&zaptel_tab);
 printk (KERN_DEBUG "Zaptel protocol loaded
");
 return 0;
 }
 
 void cleanup_module (void)
 {
 binder_unregister_protocol (&zaptel_tab);
 printk (KERN_DEBUG "Zaptel protocol unloaded
");
 }
 
 
 |