I am currently looking at the call flow in asterisk when a sip message reaches the client.
1. The i/o callback generates a sip request (struct sip_request) and then calls the handle_request_do function
2. The handle request function calls tje find_call function
3. The find call function find a call corresponding to the request with the help of callid
4. If the find call function cannot find the correspond call, it will check if the call can be created (Only some type of sip requests can create a call. For example, A 'BYE' cannot create a call)
5. If a call can be created, the same will be created.
6. If a call is found/created, the corresponding private structure is returned to the callee
My blog on Linux and programming. Covers Linux, VoIP, C, mysql, php and everything else that I come across while tinkering with my Linux boxes.
Showing posts with label asterisk. Show all posts
Showing posts with label asterisk. Show all posts
Wednesday, December 17, 2008
Tuesday, September 9, 2008
Shady Asterisk
Hmm... you must be wondering why I call him so. Because he is of dubious character. He appears nice outside and what does he do within?
I got a feel of it when I was writing the channel. I wrote the skeleton channel and made an entry for that in extensions.conf.
exten => 200,1,Dial(Sarin/200)
exten => 200,n,Hangup()
From the console do "console dial 200". Then I got a message that "Couldn't call 200". I checked again and again to find what has gone wrong. Nothing as far as I could see.
Then I enabled debug mode. To enable the debug mode in asterisk, I had to do two things.
1.1 Edit the /etc/asterisk/logger.conf.
1.2 Look for a line that looks like "console => notice,warning,error"
1.3 Add debug to that list. "console => notice,warning,error,debug"
2. Now start asterisk with debug option. "asterisk -vvvdc"
(This for enabling debug prints on console)
Then, when I tried to call that number, I found that response from "ast_call" indicates a failure. And, what was causing it?
ast_call checks ast_check_hangup. Inside that function, there is this block of code:
if (!chan->tech_pvt) /* yes if no technology private data */
return 1;
Shame on you asterisk. You were checking the private elements of a channel!. You had no business poking around that pointer. It is private to the channel and it is upto the channel to decide to have it or not to have it (have it as NULL). If you wanted to do anything with it, you should not have called it pvt!
Anyway, I assigned a int pointer to it and then things went fine.
I got a feel of it when I was writing the channel. I wrote the skeleton channel and made an entry for that in extensions.conf.
exten => 200,1,Dial(Sarin/200)
exten => 200,n,Hangup()
From the console do "console dial 200". Then I got a message that "Couldn't call 200". I checked again and again to find what has gone wrong. Nothing as far as I could see.
Then I enabled debug mode. To enable the debug mode in asterisk, I had to do two things.
1.1 Edit the /etc/asterisk/logger.conf.
1.2 Look for a line that looks like "console => notice,warning,error"
1.3 Add debug to that list. "console => notice,warning,error,debug"
2. Now start asterisk with debug option. "asterisk -vvvdc"
(This for enabling debug prints on console)
Then, when I tried to call that number, I found that response from "ast_call" indicates a failure. And, what was causing it?
ast_call checks ast_check_hangup. Inside that function, there is this block of code:
if (!chan->tech_pvt) /* yes if no technology private data */
return 1;
Shame on you asterisk. You were checking the private elements of a channel!. You had no business poking around that pointer. It is private to the channel and it is upto the channel to decide to have it or not to have it (have it as NULL). If you wanted to do anything with it, you should not have called it pvt!
Anyway, I assigned a int pointer to it and then things went fine.
Monday, September 1, 2008
The channel woes
Today I was trying to register an asterisk channel. However my module registration failed with the error that module does not provide any description. I had half a mind to edit the line from Loader.c and load my module. However, I also noticed that I was compiling the module for one version (SVN trunk) and using it on some other version (1.4.15).
Then I downloaded asterisk from svn and compiled and installed it on some other machine. Then I just put in my simple module code, compiled, copied to /usr/lib/asterisk/modules/ and on the command line told "module load chan_thin" The stuff that was not happening for last two days just happened!
The sad part of my story is this. Till now the asterisk was giving me this message: "Module 'chan_thin.so' does not provide a description". I had tried various things including injecting the code of AST_MODULE_INFO macro into my module and adding checks on the functions used by that macro. I kept getting that vague error only because of some version change. (OK, it is still my mistake. Lot of things could have happened in a version change)
Anyway, now I have a module that goes in and does nothing. I have also checked oss channel driver in asterisk. I feel that is the most simple channel driver which I can use as a datum. More on it later. Before I end, let me put down a partial function call tree.
1. AST_MODULE_INFO -> Defines the module info and the register function. This registers ast_module_info
2. load_module -> This is made available to asterisk using ast_module_info structure. It is called when we load the module. For channel registration, ast_channel_register is called during load module. It passes a structure ast_channel_tech
3. ast_channel_tech -> This has all the callback functions. For OSS channel, the structure is as follows.
4. oss_request -> This is the function that is called by asterisk when a call comes to your channel. The number is passed to you as a parameter to the function.
Got to do few more things. Rest later.
Then I downloaded asterisk from svn and compiled and installed it on some other machine. Then I just put in my simple module code, compiled, copied to /usr/lib/asterisk/modules/ and on the command line told "module load chan_thin" The stuff that was not happening for last two days just happened!
The sad part of my story is this. Till now the asterisk was giving me this message: "Module 'chan_thin.so' does not provide a description". I had tried various things including injecting the code of AST_MODULE_INFO macro into my module and adding checks on the functions used by that macro. I kept getting that vague error only because of some version change. (OK, it is still my mistake. Lot of things could have happened in a version change)
Anyway, now I have a module that goes in and does nothing. I have also checked oss channel driver in asterisk. I feel that is the most simple channel driver which I can use as a datum. More on it later. Before I end, let me put down a partial function call tree.
1. AST_MODULE_INFO -> Defines the module info and the register function. This registers ast_module_info
2. load_module -> This is made available to asterisk using ast_module_info structure. It is called when we load the module. For channel registration, ast_channel_register is called during load module. It passes a structure ast_channel_tech
3. ast_channel_tech -> This has all the callback functions. For OSS channel, the structure is as follows.
static struct ast_channel_tech oss_tech = {
.type = "Console",
.description = tdesc,
.capabilities = AST_FORMAT_SLINEAR, /* overwritten later */
.requester = oss_request,
.send_digit_begin = oss_digit_begin,
.send_digit_end = oss_digit_end,
.send_text = oss_text,
.hangup = oss_hangup,
.answer = oss_answer,
.read = oss_read,
.call = oss_call,
.write = oss_write,
.write_video = console_write_video,
.indicate = oss_indicate,
.fixup = oss_fixup,
};
4. oss_request -> This is the function that is called by asterisk when a call comes to your channel. The number is passed to you as a parameter to the function.
Got to do few more things. Rest later.
Sunday, August 31, 2008
Making of a channel
I need to answer 5 technical questions before I start making the channel
1. What does asterisk need from the channel? (What are the bare minimum features/functionalities of a channel?)
2. What all can asterisk take from the channel? (What is the largest possible set of features/functionalities that a channel can support out of the box?)
3. What are the features of the channel needed by the customer?
4. Is there any feature that a normal asterisk channel cannot support or it is very difficult to support?
5. How to add support to a new feature in channel?
I am searching the answer for the first question now.
1. What does asterisk need from the channel? (What are the bare minimum features/functionalities of a channel?)
2. What all can asterisk take from the channel? (What is the largest possible set of features/functionalities that a channel can support out of the box?)
3. What are the features of the channel needed by the customer?
4. Is there any feature that a normal asterisk channel cannot support or it is very difficult to support?
5. How to add support to a new feature in channel?
I am searching the answer for the first question now.
Asterisk Channel
We have decided to make a new channel in Asterisk and almost completely move away from the zaptel channel. We had a discussion where we discussed how to proceed with the creation of the channel. In the discussion I was told that there is only a standard load_module function that is provided by Asterisk to define the channel. However, I was sure from my previous encounters with the channel that there needs to be something more than that and I even vaguely remembered that it is a structure.
Today I went back and had a look at the channel code and I found that channels infact use the structure ast_channel. I have not seen the code in detail. Will come back and post more once I see the channels in detail.
Today I went back and had a look at the channel code and I found that channels infact use the structure ast_channel. I have not seen the code in detail. Will come back and post more once I see the channels in detail.
Tuesday, August 19, 2008
DAHDI
As we know that zaptel is renamed to DAHDI, below are the links from which you can fetch DAHDI. I have not gone into the depths of DAHDI, but it looks like it is just a name change.
http://svn.digium.com/svn/dahdi/tools/trunk
http://svn.digium.com/svn/dahdi/linux/trunk
http://svn.digium.com/svn/dahdi/tools/trunk
http://svn.digium.com/svn/dahdi/linux/trunk
Wednesday, August 13, 2008
Training for Ankit (3)
The zap driver:
1. Used wcfxo.c as the datum
2. Created the following dummy functions
wcfxo_open
wcfxo_close
wcfxo_read
wcfxo_write
wcfxo_hooksig
3. Made the hello_spaninit function to initialize the span
4. Made the zaptel settings as I have shown in the first post in this series
5. Start zaptel service
6. Build and insert module
7. Run ztcfg
8. On the console, dial 1000
9. tail -f /var/log/messages should show message from hooksig
10. On the console, hangup
11. tail -f /var/log/messages should show message from hooksig
12. Since syslog buffers the message and does stuff like "Last message repeated X times" you might not see the second message immediately
#include
#include
#include "zaptel.h"
MODULE_LICENSE("GPL");
extern int gpltest;
struct hpvt {
int pos;
struct zt_span span;
struct zt_chan chan;
char variety[128];
}hello;
static int hello_spanInit();
static int hello_init(void)
{
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
hello_spanInit();
printk(KERN_ALERT "After: Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Before: Goodbye, cruel world\n");
zt_unregister(&hello.span);
printk(KERN_ALERT "After: Goodbye, cruel world\n");
}
static int wcfxo_open(struct zt_chan *c)
{
printk(KERN_ALERT "Open called\n");
return 0;
}
static int wcfxo_close(struct zt_chan *c)
{
printk(KERN_ALERT "Close called\n");
return 0;
}
static int wcfxo_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
{
printk(KERN_ALERT "Hooksig called\n");
return 0;
}
static int wcfxo_watchdog(struct zt_span *span, int event)
{
printk("FXO: Restarting DMA\n");
return 0;
}
static int hello_spanInit()
{
struct hpvt *wc=&hello;
strcpy(hello.variety,"Thinvent");
hello.pos=0;
/* Zapata stuff */
sprintf(hello.span.name, "SARIN/%d", wc->pos);
snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
sprintf(wc->chan.name, "SARIN/%d/%d", wc->pos, 0);
snprintf(wc->span.location, sizeof(wc->span.location) - 1,"HERE!");
wc->span.manufacturer = "SARIN";
strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
wc->chan.sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;
wc->chan.chanpos = 1;
wc->span.chans = &wc->chan;
wc->span.channels = 1;
wc->span.hooksig = wcfxo_hooksig;
// wc->span.irq = wc->dev->irq;
wc->span.open = wcfxo_open;
wc->span.close = wcfxo_close;
wc->span.flags = ZT_FLAG_RBS;
wc->span.deflaw = ZT_LAW_MULAW;
wc->span.watchdog = wcfxo_watchdog;
#ifdef ENABLE_TASKLETS
tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc);
#endif
init_waitqueue_head(&wc->span.maintq);
wc->span.pvt = wc;
wc->chan.pvt = wc;
if (zt_register(&wc->span, 0)) {
printk("Unable to register span with zaptel\n");
return -1;
}
return 0;
}
module_init(hello_init);
module_exit(hello_exit);
Make file
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
1. Used wcfxo.c as the datum
2. Created the following dummy functions
wcfxo_open
wcfxo_close
wcfxo_read
wcfxo_write
wcfxo_hooksig
3. Made the hello_spaninit function to initialize the span
4. Made the zaptel settings as I have shown in the first post in this series
5. Start zaptel service
6. Build and insert module
7. Run ztcfg
8. On the console, dial 1000
9. tail -f /var/log/messages should show message from hooksig
10. On the console, hangup
11. tail -f /var/log/messages should show message from hooksig
12. Since syslog buffers the message and does stuff like "Last message repeated X times" you might not see the second message immediately
#include
#include
#include "zaptel.h"
MODULE_LICENSE("GPL");
extern int gpltest;
struct hpvt {
int pos;
struct zt_span span;
struct zt_chan chan;
char variety[128];
}hello;
static int hello_spanInit();
static int hello_init(void)
{
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
hello_spanInit();
printk(KERN_ALERT "After: Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Before: Goodbye, cruel world\n");
zt_unregister(&hello.span);
printk(KERN_ALERT "After: Goodbye, cruel world\n");
}
static int wcfxo_open(struct zt_chan *c)
{
printk(KERN_ALERT "Open called\n");
return 0;
}
static int wcfxo_close(struct zt_chan *c)
{
printk(KERN_ALERT "Close called\n");
return 0;
}
static int wcfxo_hooksig(struct zt_chan *chan, zt_txsig_t txsig)
{
printk(KERN_ALERT "Hooksig called\n");
return 0;
}
static int wcfxo_watchdog(struct zt_span *span, int event)
{
printk("FXO: Restarting DMA\n");
return 0;
}
static int hello_spanInit()
{
struct hpvt *wc=&hello;
strcpy(hello.variety,"Thinvent");
hello.pos=0;
/* Zapata stuff */
sprintf(hello.span.name, "SARIN/%d", wc->pos);
snprintf(wc->span.desc, sizeof(wc->span.desc) - 1, "%s Board %d", wc->variety, wc->pos + 1);
sprintf(wc->chan.name, "SARIN/%d/%d", wc->pos, 0);
snprintf(wc->span.location, sizeof(wc->span.location) - 1,"HERE!");
wc->span.manufacturer = "SARIN";
strncpy(wc->span.devicetype, wc->variety, sizeof(wc->span.devicetype) - 1);
wc->chan.sigcap = ZT_SIG_FXSKS | ZT_SIG_FXSLS | ZT_SIG_SF;
wc->chan.chanpos = 1;
wc->span.chans = &wc->chan;
wc->span.channels = 1;
wc->span.hooksig = wcfxo_hooksig;
// wc->span.irq = wc->dev->irq;
wc->span.open = wcfxo_open;
wc->span.close = wcfxo_close;
wc->span.flags = ZT_FLAG_RBS;
wc->span.deflaw = ZT_LAW_MULAW;
wc->span.watchdog = wcfxo_watchdog;
#ifdef ENABLE_TASKLETS
tasklet_init(&wc->wcfxo_tlet, wcfxo_tasklet, (unsigned long)wc);
#endif
init_waitqueue_head(&wc->span.maintq);
wc->span.pvt = wc;
wc->chan.pvt = wc;
if (zt_register(&wc->span, 0)) {
printk("Unable to register span with zaptel\n");
return -1;
}
return 0;
}
module_init(hello_init);
module_exit(hello_exit);
Make file
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
Tuesday, August 12, 2008
Training for Ankit (2)
Ok, we built the kernel module. What do we do with it now?
1. Insert the kernel module to kernel
insmod tzap.ko
2. See the messages appearing in /var/log/messages
At this point, Ankit asked me why tail /var/log/messages? Why can't we see that directly?
Ans: Insmod calls the hello_init function. The message comes from
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
Now, KERN_ALERT is a priority for kernel messages. ALERT is not a high priority so that the message comes on our Terminal. We changed the line to
printk(KERN_EMERG "Before: Hello, world %d \n",gpltest);
This time, the message appeared on the Terminal. I then showed him /etc/syslog.conf and told him that, it is syslog which reads these messages and decides what to do with it. I showed him my /etc/syslog.conf and explained how various messages are destined to go to various locations.
3. Unloading the module
This is done with the command rmmod tzap. hello_exit is called when this happens.
4. Module license line.
MODULE_LICENSE("GPL"); or something like that tells the module is licensed under GPL license. This has an important for our customer. They will have to GPL the code if they plan to access the symbols that are exported using EXPORT_SYMBOL_GPL. Anyway, they are lucky and zaptel does not have GPL exports.
5. Init & Exit
module_init and module_exit defines the entry points for insmod and rmmod.
6. One more step __init and __exit
These macros tell the kernel that the functions thus defined are specific to module loading and unloading. I told him to remember the Linux boot process and the line "Freeing unused kernel memory". This is possible because if I mark a function as __init, the kernel knows it has no need of the function after initialization. This allows the kernel to free some memory after boot-up
1. Insert the kernel module to kernel
insmod tzap.ko
2. See the messages appearing in /var/log/messages
At this point, Ankit asked me why tail /var/log/messages? Why can't we see that directly?
Ans: Insmod calls the hello_init function. The message comes from
printk(KERN_ALERT "Before: Hello, world %d \n",gpltest);
Now, KERN_ALERT is a priority for kernel messages. ALERT is not a high priority so that the message comes on our Terminal. We changed the line to
printk(KERN_EMERG "Before: Hello, world %d \n",gpltest);
This time, the message appeared on the Terminal. I then showed him /etc/syslog.conf and told him that, it is syslog which reads these messages and decides what to do with it. I showed him my /etc/syslog.conf and explained how various messages are destined to go to various locations.
3. Unloading the module
This is done with the command rmmod tzap. hello_exit is called when this happens.
4. Module license line.
MODULE_LICENSE("GPL"); or something like that tells the module is licensed under GPL license. This has an important for our customer. They will have to GPL the code if they plan to access the symbols that are exported using EXPORT_SYMBOL_GPL. Anyway, they are lucky and zaptel does not have GPL exports.
5. Init & Exit
module_init and module_exit defines the entry points for insmod and rmmod.
6. One more step __init and __exit
These macros tell the kernel that the functions thus defined are specific to module loading and unloading. I told him to remember the Linux boot process and the line "Freeing unused kernel memory". This is possible because if I mark a function as __init, the kernel knows it has no need of the function after initialization. This allows the kernel to free some memory after boot-up
Training for Ankit (1)
Today I was at customers development centre. Ankit is to develop the driver for the hardware they develop. This post will record the session that I had with Ankit.
Ankit was new to kernel programming. Even I have not mastered this beast well. Neverthless, I got Ankit started with it.
1. Zaptel discussion
It is not necessary to define a span in case of an FXS/FXO. Just need to define a channel.
However, for registering fxs/fxo also, we pass a span argument to zaptel. I asked Ankit to look at span as an abstraction for a device (E1 card, FXS etc) which 'n' channels. (n = 1, for FXS)
I showed him how to define a fxo channel.
zaptel.conf
loadzone = us
defaultzone = us
fxsks=1
zapata.conf (Additions only)
signalling=fxs_ks
callerid="Green Phone"<(256) 428-6121>
channel => 1
extensions.conf additions
exten => 1000,1,Dial(Zap/1)
2. Kernel module programming
To program kernel modules, you need to have kernel source for your current kernel.
I asked him to first download LDD3.
Then, we copied the code from second chapter and compiled the module.
This had to be done on my laptop, as he did not have kernel sources installed on his system.
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Then we created the makefile
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=`pwd` modules
With the make file in place, we compiled the module and inserted it.
Ankit was new to kernel programming. Even I have not mastered this beast well. Neverthless, I got Ankit started with it.
1. Zaptel discussion
It is not necessary to define a span in case of an FXS/FXO. Just need to define a channel.
However, for registering fxs/fxo also, we pass a span argument to zaptel. I asked Ankit to look at span as an abstraction for a device (E1 card, FXS etc) which 'n' channels. (n = 1, for FXS)
I showed him how to define a fxo channel.
zaptel.conf
loadzone = us
defaultzone = us
fxsks=1
zapata.conf (Additions only)
signalling=fxs_ks
callerid="Green Phone"<(256) 428-6121>
channel => 1
extensions.conf additions
exten => 1000,1,Dial(Zap/1)
2. Kernel module programming
To program kernel modules, you need to have kernel source for your current kernel.
I asked him to first download LDD3.
Then, we copied the code from second chapter and compiled the module.
This had to be done on my laptop, as he did not have kernel sources installed on his system.
#include
#include
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, world\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
Then we created the makefile
obj-m += tzap.o
EXTRA_CFLAGS += -I/root/zaptel/kernel
all:
make -C /lib/modules/$(shell uname -r)/build M=`pwd` modules
With the make file in place, we compiled the module and inserted it.
- obj-m is a variable understood by kernel build system
- obj-m = tzap.o indicates that the name of your module source file is tzap.c
- EXTRA_CFLAGS defines the extra compile time flags specific for your module
- In this case that extra flag is not really necessary. But as we do more work with this driver, we will need it.
- Make command arguments: -C
Tells the make to change to before actually running - Make command arguments: M=`pwd`defines M, which will be used by kernel build system to determine the directory in which module source is present
- Make command arguments: modules is the target to build
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.
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...
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
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:
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
- struct zt_span *span - This is a pointer to current span structure on which the operation is taking place
- struct zt_lineconfig *lc - This is the user supplied data
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?
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
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...
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
- Does card specific PCI initialization
- Calls init_spans(tor);
- Calls tor2_launch(cards[x]);
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
};
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
};
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
};
Subscribe to:
Posts (Atom)