Cronyx Site
About Cronyx
Products Prices Contact information Search English 
English Russian  Russian
Software Payment
What's new
F. A. Q.
Partners
Site map


Форум cronyx.ru (архив)

czaptel.ckmax  ::  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 ");
}



tau32pci на realtime ядре
kmax  ::  2006-02-20 18:23
   Не должно быть больших сложностей (+)ly  ::  2006-02-21 10:43
      протокол компиляцииkmax  ::  2006-02-21 12:36
         Нужны небольшие правки (+)ly  ::  2006-02-21 13:06
            Частично патч для realtime-ядерmithraen  ::  2006-03-13 18:14
               Спасибо (+)ly  ::  2006-03-13 18:19
            К сожалению ошибки остались прежниеkmax  ::  2006-02-21 15:03
               ваш czaptel.cly  ::  2006-02-21 15:17
                  czaptel.ckmax  ::  2006-02-21 18:41
                     Примерно так (+)ly  ::  2006-02-22 12:28
                        результатыkmax  ::  2006-02-24 11:02

Copyright © 1996-2024 Cronyx