Wednesday, July 30, 2008

Customizing BCM96338 (1)

First of all, a big thanks to Google and http://www.cyberciti.biz/tips/hacking-beetel-220x-adsl-router-broadcom-bcm6338.html

Once you are in (Ok, if you haven't opened that page till now, telnet to device, login as admin, enter 'sh' as the option), explore the device file system. Go to bin and do a echo *

You will find that there are iptables and a bunch of other applications that we can use. In the coming posts I will explain how to setup the iptable rules to forward a connection coming from outside to a host within your local network.

Well, this could have been achieved by setting up a DMZ or NAT from the webpage. Unfortunately, these did not work for me. This is the only reason that I am forced to try my luck with iptables.

Wednesday, July 23, 2008

more on data flow

In the ZAP_IRQ_HANDLER, (This is a macro defined in the zaptel.h) the data is copied from the hardware and back. This is done in a card specific manner. In tor2.c, the data is present in specific locations of xilinx memory region. We read and write from that region.

The next step is to read the rbs (robbed bits signaling) bits. These bits are read and compared with the stored rbs bits. If there is a difference, zt_rbsbits is called. The signaling bits are processed based on what is the type of the channel signaling (FXO, FXS, E1, E&M etc). This function in turn calls __zt_hooksig_pvt. This in turn stores the signaling bits in the event buffer of the channel and then wakes up the processes waiting on the eventbufq.

In case of tro2.c, the status byte is read and it is used in processing alarms. Time sync channel is also handled here.

The processing of the data happens in the bottom half. In case of tor2.c, it also depends on if the tasklets are enabled for the driver. If the tasklets are enabled, a corresponding function is scheduled to run. Else, the processing happens in the interrupt context only. In this case, tor2_run is called directly.

tor2_run then calls zt_receive and zt_transmit. This is done for every span. Also, the argument to the function is the span structure in each case.

data flow

In a program, data flow diagrams are as important as the function call trees. As we now have some idea of the working how zaptel calls hardware specific functions, let us briefly see how the data is moving across zaptel and hardware drivers.

Responsible functions: ZAP_IRQ_HANDLER, tor2_run

data -> interrupt -> ZAP_IRQ_HANDLER -> tor2_run -> zt_receive / zt_transmit

Details soon...

Tuesday, July 22, 2008

open & close

Function: tor2_open
Argument: struct zt_chan *chan
Function: Do device specific open. In this case, just increments module usage count

Function: tor2_close
Argument: struct zt_chan *chan
Function: Do device specific open. In this case,just decrements module usage count

The call flow


Before we proceed further, let us have a look at the call flow. Asterisk calls the zaptel using system calls on the devices created by zaptel. A large chunk of such calls are ioctl calls.

To give an example, when a channel has to be configured, asterisk, through chan_zap.so, makes a ZT_CHANCONFIG ioctl. The user data is put into the form of zt_chanconfig structure and passed to the ioctl function.

zt_ctl_ioctl function is invoked as a result of this. This in turn does some generic operations such as error checking etc and then assigns the values from the user space structure to the kernel space structure.

When, there are device specific job to be done, zt_ctl_ioctl calls the device specific function that is already populated in the span structure that we used while registering our device with zaptel. In this particular case, they don't handle the clear function. For clear, they call the

res = chans[ch.chan]->span->chanconfig(chans[ch.chan], ch.sigtype);

In short, in this example we have seen
Asterisk <--> chan_zap.so <-> zaptel.ko (kernel) <-> device driver <-> Zaptel device <-> Phone/switch/PSTN

Monday, July 21, 2008

tor2_spanconfig

Arguments:
  1. struct zt_span *span - This is a pointer to current span structure on which the operation is taking place
  2. struct zt_lineconfig *lc - This is the user supplied data
Functionalities: This is used to set the parameters present in zaptel.conf to the driver. The parameters are present in the lc structure. These parameters are extracted and set in the span structure. In tor2.c, this function is responsible mainly for changing the sync source status of the span.

sync source status of the span: Is whether the current span is an input source, output source or a sink of a time pulse.

This function also takes care about restarting the card if it is currently running


static int tor2_spanconfig(struct zt_span *span, struct zt_lineconfig *lc)
{
int i;
struct tor2_span *p = span->pvt;

if (debug)
printk("Tor2: Configuring span %d\n", span->spanno);

span->syncsrc = p->tor->syncsrc;

/* remove this span number from the current sync sources, if there */
for (i = 0; i <>tor->syncs[i] == span->spanno) {
p->tor->syncs[i] = 0;
p->tor->psyncs[i] = 0;
}
}
p->tor->syncpos[p->span] = lc->sync;
/* if a sync src, put it in the proper place */
if (lc->sync) {
p->tor->syncs[lc->sync - 1] = span->spanno;
p->tor->psyncs[lc->sync - 1] = p->span + 1;
}
/* If we're already running, then go ahead and apply the changes */
if (span->flags & ZT_FLAG_RUNNING)
return tor2_startup(span);

return 0;
}

Moral of my asterisk story

Very simple...

If you have to make a PRI E1/T1 card driver compatible with asterisk...

1. The driver should define span structure
2. The driver should define functions such as ioctl, spanconfig, open, close, rbsbits etc
3. The span variables should be populated with corresponding functions and values
4. In the device init, call zt_register with the populated span.

Next: What are the functions of methods populated in span?

How span is populated

The function that configures a span is


static void init_spans(struct tor2 *tor)
{
int x, y, c;
for (x = 0; x <>spans[x].name, "Tor2/%d/%d", tor->num, x + 1);
snprintf(tor->spans[x].desc, sizeof(tor->spans[x].desc) - 1,
"Tormenta 2 (PCI) fQuad %s Card %d Span %d",
(tor->cardtype == TYPE_T1) ? "T1" : "E1", tor->num, x + 1);
tor->spans[x].manufacturer = "Digium";
strncpy(tor->spans[x].devicetype, tor->type, sizeof(tor->spans[x].devicetype) - 1);
snprintf(tor->spans[x].location, sizeof(tor->spans[x].location) - 1,
"PCI Bus %02d Slot %02d", tor->pci->bus->number, PCI_SLOT(tor->pci->devfn) + 1);
tor->spans[x].spanconfig = tor2_spanconfig;
tor->spans[x].chanconfig = tor2_chanconfig;
tor->spans[x].startup = tor2_startup;
tor->spans[x].shutdown = tor2_shutdown;
tor->spans[x].rbsbits = tor2_rbsbits;
tor->spans[x].maint = tor2_maint;
tor->spans[x].open = tor2_open;
tor->spans[x].close = tor2_close;
if (tor->cardtype == TYPE_T1) {
tor->spans[x].channels = 24;
tor->spans[x].deflaw = ZT_LAW_MULAW;
tor->spans[x].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
tor->spans[x].spantype = "T1";
} else {
tor->spans[x].channels = 31;
tor->spans[x].deflaw = ZT_LAW_ALAW;
tor->spans[x].linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
tor->spans[x].spantype = "E1";
}
tor->spans[x].chans = tor->chans[x];
tor->spans[x].flags = ZT_FLAG_RBS;
tor->spans[x].ioctl = tor2_ioctl;
tor->spans[x].pvt = &tor->tspans[x];
tor->tspans[x].tor = tor;
tor->tspans[x].span = x;
init_waitqueue_head(&tor->spans[x].maintq);
for (y=0;yspans[x].channels;y++) {
struct zt_chan *mychans = tor->chans[x] + y;
sprintf(mychans->name, "Tor2/%d/%d/%d", tor->num, x + 1, y + 1);
mychans->sigcap = ZT_SIG_EM | ZT_SIG_CLEAR | ZT_SIG_FXSLS | ZT_SIG_FXSGS | ZT_SIG_FXSKS |
ZT_SIG_FXOLS | ZT_SIG_FXOGS | ZT_SIG_FXOKS | ZT_SIG_CAS | ZT_SIG_SF | ZT_SIG_EM_E1;
c = (x * tor->spans[x].channels) + y;
mychans->pvt = &tor->tchans[c];
mychans->chanpos = y + 1;
tor->tchans[c].span = x;
tor->tchans[c].tor = tor;
}
}
}


These are the function assignments:
tor->spans[x].spanconfig = tor2_spanconfig;
tor->spans[x].chanconfig = tor2_chanconfig;
tor->spans[x].startup = tor2_startup;
tor->spans[x].shutdown = tor2_shutdown;
tor->spans[x].rbsbits = tor2_rbsbits;
tor->spans[x].maint = tor2_maint;
tor->spans[x].open = tor2_open;
tor->spans[x].close = tor2_close;
tor->spans[x].ioctl = tor2_ioctl;

The variable initialization
<snip what="name initialization">

tor->spans[x].channels = 24;
tor->spans[x].deflaw = ZT_LAW_MULAW;
tor->spans[x].linecompat = ZT_CONFIG_AMI | ZT_CONFIG_B8ZS | ZT_CONFIG_D4 | ZT_CONFIG_ESF;
tor->spans[x].spantype = "T1";
Or
tor->spans[x].channels = 31;
tor->spans[x].deflaw = ZT_LAW_ALAW;
tor->spans[x].linecompat = ZT_CONFIG_HDB3 | ZT_CONFIG_CCS | ZT_CONFIG_CRC4;
tor->spans[x].spantype = "E1";

tor->spans[x].chans = tor->chans[x];
tor->spans[x].flags = ZT_FLAG_RBS;
tor->spans[x].pvt = &tor->tspans[x];


tor2.c scratch pad

I am going to use this post as the scratch pad while reading through tor2.c

Init function: tor2_init
This function registers a pci driver. The driver structure is a global variable "tor2_driver". It has a probe function called "tor2_probe" and a function to remove the driver "tor2_remove".

Probe function: tor2_probe
  1. Does card specific PCI initialization
  2. Calls init_spans(tor);
  3. Calls tor2_launch(cards[x]);
Span initialization: init_spans
This function populates the spans structure within tor structure.

Register with zaptel: tor2_launch
This function registers the spans with the zaptel driver.
And then... the action begins...

Saturday, July 19, 2008

case study

I am just starting the study of tor2.c. This will help me understand the device driver for a asterisk compatible card better. As I understand, this driver is registered as a pci driver. The interesting part is the probe function. It is through this function the drivers get registered in the zaptel. The details will follow.

A simpler key

Just the same structure from my previous post with all the optional components removed.

struct zt_span {
spinlock_t lock;
void *pvt; /* Private stuff */
char name[40]; /* Span name */
char desc[80]; /* Span description */
const char *spantype; /* span type in text form */
const char *manufacturer; /* span's device manufacturer */
char devicetype[80]; /* span's device type */
char location[40]; /* span device's location in system */
int deflaw; /* Default law (ZT_MULAW or ZT_ALAW) */
int alarms; /* Pending alarms on span */
int flags;
int irq; /* IRQ for this span's hardware */
int lbo; /* Span Line-Buildout */
int lineconfig; /* Span line configuration */
int linecompat; /* Span line compatibility */
int channels; /* Number of channels in span */
int txlevel; /* Tx level */
int rxlevel; /* Rx level */
int syncsrc; /* current sync src (gets copied here) */
unsigned int bpvcount; /* BPV counter */
unsigned int crc4count; /* CRC4 error counter */
unsigned int ebitcount; /* current E-bit error count */
unsigned int fascount; /* current FAS error count */

int maintstat; /* Maintenance state */
wait_queue_head_t maintq; /* Maintenance queue */
int mainttimer; /* Maintenance timer */

int irqmisses; /* Interrupt misses */

int timingslips; /* Clock slips */

struct zt_chan *chans; /* Member channel structures */

/* ==== Span Callback Operations ==== */
/* Req: Set the requested chunk size. This is the unit in which you must
report results for conferencing, etc */
int (*setchunksize)(struct zt_span *span, int chunksize);

/* ==== Channel Callback Operations ==== */

int (*echocan_with_params)(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p);

/* Okay, now we get to the signalling. You have several options: */

/* Option 1: If you're a T1 like interface, you can just provide a
rbsbits function and we'll assert robbed bits for you. Be sure to
set the ZT_FLAG_RBS in this case. */

/* Opt: If the span uses A/B bits, set them here */
int (*rbsbits)(struct zt_chan *chan, int bits);


/* Used by zaptel only -- no user servicable parts inside */
int spanno; /* Span number for zaptel */
int offset; /* Offset within a given card */
int lastalarms; /* Previous alarms */

#ifdef CONFIG_DEVFS_FS
devfs_handle_t dhandle; /* Directory name */
#endif
/* If the watchdog detects no received data, it will call the
watchdog routine */
int (*watchdog)(struct zt_span *span, int cause);
#ifdef CONFIG_ZAPTEL_WATCHDOG
int watchcounter;
int watchstate;
#endif
};

The key to zaptel

We need to have a deep understanding of the following structure to work with zaptel. This is the structure passed by individual driver to zaptel at the time of registration.

struct zt_span {
spinlock_t lock;
void *pvt; /* Private stuff */
char name[40]; /* Span name */
char desc[80]; /* Span description */
const char *spantype; /* span type in text form */
const char *manufacturer; /* span's device manufacturer */
char devicetype[80]; /* span's device type */
char location[40]; /* span device's location in system */
int deflaw; /* Default law (ZT_MULAW or ZT_ALAW) */
int alarms; /* Pending alarms on span */
int flags;
int irq; /* IRQ for this span's hardware */
int lbo; /* Span Line-Buildout */
int lineconfig; /* Span line configuration */
int linecompat; /* Span line compatibility */
int channels; /* Number of channels in span */
int txlevel; /* Tx level */
int rxlevel; /* Rx level */
int syncsrc; /* current sync src (gets copied here) */
unsigned int bpvcount; /* BPV counter */
unsigned int crc4count; /* CRC4 error counter */
unsigned int ebitcount; /* current E-bit error count */
unsigned int fascount; /* current FAS error count */

int maintstat; /* Maintenance state */
wait_queue_head_t maintq; /* Maintenance queue */
int mainttimer; /* Maintenance timer */

int irqmisses; /* Interrupt misses */

int timingslips; /* Clock slips */

struct zt_chan *chans; /* Member channel structures */

/* ==== Span Callback Operations ==== */
/* Req: Set the requested chunk size. This is the unit in which you must
report results for conferencing, etc */
int (*setchunksize)(struct zt_span *span, int chunksize);

/* Opt: Configure the span (if appropriate) */
int (*spanconfig)(struct zt_span *span, struct zt_lineconfig *lc);

/* Opt: Start the span */
int (*startup)(struct zt_span *span);

/* Opt: Shutdown the span */
int (*shutdown)(struct zt_span *span);

/* Opt: Enable maintenance modes */
int (*maint)(struct zt_span *span, int mode);

#ifdef ZAPTEL_SYNC_TICK
/* Opt: send sync to spans */
int (*sync_tick)(struct zt_span *span, int is_master);
#endif

/* ==== Channel Callback Operations ==== */
/* Opt: Set signalling type (if appropriate) */
int (*chanconfig)(struct zt_chan *chan, int sigtype);

/* Opt: Prepare a channel for I/O */
int (*open)(struct zt_chan *chan);

/* Opt: Close channel for I/O */
int (*close)(struct zt_chan *chan);

/* Opt: IOCTL */
int (*ioctl)(struct zt_chan *chan, unsigned int cmd, unsigned long data);

/* Opt: Native echo cancellation (simple) */
int (*echocan)(struct zt_chan *chan, int ecval);

int (*echocan_with_params)(struct zt_chan *chan, struct zt_echocanparams *ecp, struct zt_echocanparam *p);

/* Okay, now we get to the signalling. You have several options: */

/* Option 1: If you're a T1 like interface, you can just provide a
rbsbits function and we'll assert robbed bits for you. Be sure to
set the ZT_FLAG_RBS in this case. */

/* Opt: If the span uses A/B bits, set them here */
int (*rbsbits)(struct zt_chan *chan, int bits);

/* Option 2: If you don't know about sig bits, but do have their
equivalents (i.e. you can disconnect battery, detect off hook,
generate ring, etc directly) then you can just specify a
sethook function, and we'll call you with appropriate hook states
to set. Still set the ZT_FLAG_RBS in this case as well */
int (*hooksig)(struct zt_chan *chan, zt_txsig_t hookstate);

/* Option 3: If you can't use sig bits, you can write a function
which handles the individual hook states */
int (*sethook)(struct zt_chan *chan, int hookstate);

/* Opt: Dacs the contents of chan2 into chan1 if possible */
int (*dacs)(struct zt_chan *chan1, struct zt_chan *chan2);

/* Opt: Used to tell an onboard HDLC controller that there is data ready to transmit */
void (*hdlc_hard_xmit)(struct zt_chan *chan);

/* Used by zaptel only -- no user servicable parts inside */
int spanno; /* Span number for zaptel */
int offset; /* Offset within a given card */
int lastalarms; /* Previous alarms */

#ifdef CONFIG_DEVFS_FS
devfs_handle_t dhandle; /* Directory name */
#endif
/* If the watchdog detects no received data, it will call the
watchdog routine */
int (*watchdog)(struct zt_span *span, int cause);
#ifdef CONFIG_ZAPTEL_WATCHDOG
int watchcounter;
int watchstate;
#endif
};