Back to ProjectsDAILD

 Introduction 

 

DAILD is a high-performance device driver for a digital data acquisition PCI card under Linux OS. Digital Acquisition Interface (DAI) or AIB10 is a custom digital data acquisition PCI card made at ICTI of Isfahan University of Technology working at high frequency and high resolution rates. DAILD is a Linux device driver at kernel-mode responsible for configuring the device as well as dispatching the received data to user-mode applications.

  • Programming Language: ISO/IEC 9899 C More Information
  • Compiled using: GNU C++ and GNU Make More Information
  • IDE: KDevelop More Information
  • Platform: Linux on i386 or x86-64
  • License: Proprietary
  • Development Time: Sep. 2006 ~ Aug. 2007
 

 Download 

 

 What is DAI PCI Card

 

DAI or AIB10 is a PCI PnP card. It is inserted in a PCI slot and connects to a external digital equipment which feeds the data. Its resources (IRQs, IO regions, Memory regions) are assigned by BIOS or if needed OS and is fully configurable by the driver. Its sole function is to receive packets of digital data as a packet (from external analog to digital converter) at beginning of each time slice (period) and deliver it to software.

Main characteristics:

  • The address of two memory banks of main memory is presented to device and it writes received packet in one of them in a time slice and the other on the next slice and switches to the first for the next one and so on.
  • When the data is completely written into the memory, an interrupt is issued by the device.
  • Also an interrupt is issued when an error occurs such as fifo overflow (internal) or not having enough time to write to memories. It is the responsibility of the driver to find out the reason of interrupt by reading special memory area of device.
  • All parameters like frequency of data arrival, frequency of sampling, data packet size (in each time slice) must be configured by driver prior to function.
  • All statistical data such as the current time slice number can be read by the driver.

 How to Compile the Driver

 

Make sure you have the source of the current running kernel (e.g. at /usr/src/kernel) as well as GCC and its tools. Extract the source into a folder for example ~/documents/aib10-1.0.4.src.

1. First prepare the kernel:

behdad@home:~> cd /usr/src/linux
behdad@home:/usr/src/linux> make cloneconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/docproc
  HOSTCC  scripts/basic/hash
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/kxgettext.o
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
Cloning configuration file /proc/config.gz

#
# configuration written to .config
#
behdad@home:/usr/src/linux> make prepare
scripts/kconfig/conf -s arch/x86/Kconfig
  CHK     include/linux/version.h
  CHK     include/linux/utsrelease.h
  CC      kernel/bounds.s
  GEN     include/linux/bounds.h
  CC      arch/x86/kernel/asm-offsets.s
  GEN     include/asm/asm-offsets.h
  CALL    scripts/checksyscalls.sh

2. Complie the dirver:

behdad@home:/usr/src/linux> cd ~/documents/aib10-1.0.4.src/
behdad@home:~/documents/aib10-1.0.4.src> make release
make -C /lib/modules/2.6.27.7-9-pae/build M=/home/behdad/documents/aib10-1.0.4.src modules
make[1]: Entering directory '/usr/src/linux-2.6.27.7-9-obj/i386/pae'
make -C ../../../linux-2.6.27.7-9 O=/usr/src/linux-2.6.27.7-9-obj/i386/pae/. modules
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/main.o
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/tools.o
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/hardware.o
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/fops.o
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/pci.o
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/ioctl.o
  CC [M]  /home/behdad/documents/aib10-1.0.4.src/sysfs.o
  LD [M]  /home/behdad/documents/aib10-1.0.4.src/aib10.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/behdad/documents/aib10-1.0.4.src/aib10.mod.o
  LD [M]  /home/behdad/documents/aib10-1.0.4.src/aib10.ko
make[1]: Leaving directory '/usr/src/linux-2.6.27.7-9-obj/i386/pae'
mkdir -p rel
rm -f rel/*.o rel/*.ko rel/*.mod.c
mv -f *.o *.ko *.mod.c rel
DAILD Compile & Invoke Screenshot
DAILD Compile & Invoke

 How to Invoke the Driver

 

To bring the driver or more specifically the module into the memory, from the rel/ or dbg/ subfolders, the following command must be invoked:

behdad@home:~/documents/aib10-1.0.4.src> cd rel/
behdad@home:~/documents/aib10-1.0.4.src/rel> sudo ../aib10 start
Starting aib10 module:                                     [  OK  ]
 

The aib10 file in source folder is a bash script which has four parameters: start, stop, status and restart. Part of the file regarding the start and stop procedures is shown in the following code. In start() the module is inserted, then it removes any dangling nodes in /dev from previous improper shutdowns. If a device is present, its major number is retrieved by searching in /proc/devices file and the proper node is created with appropriate permissions. In stop() the module is removed, then the created node is deleted.

Bash Scripts to Start or Stop the Driver
module="aib10"
device="aib10"
mode="666"
group="staff"

stop() {    
    # invoke rmmod with all arguments we got
    action $"Stopping $module module: " /sbin/rmmod $module.ko $2 $3
    RETVAL=$?
    [ $RETVAL -eq 0 ] || return $RETVAL
    
    rm -f /dev/${device} # remove stale nodes
    
    return $RETVAL
}




start() {
    # invoke insmod with all arguments we got
    action $"Starting $module module: " /sbin/insmod ./$module.ko $2 $3
    RETVAL=$?
    [ $RETVAL -eq 0 ] || return $RETVAL
    
    rm -f /dev/${device} # remove stale nodes
    
    # get the assigned major number and create the node
    major=$(awk '/aib10/ { print $1 }' /proc/devices)
    mknod /dev/${device} c $major 0
    
    # give appropriate group/permissions, and change the group.
    grep -q '^staff:' /etc/group || group="wheel"
    chgrp $group /dev/${device}
    chmod $mode /dev/${device}
    
    return $RETVAL
}

 How to Communicate with the Driver

 

For accessing a DAI device using the driver, a number of ordinary file manipulations must be done on a special device file /dev/aib10 created by the above aib10 shell script file. In fact, when the driver comes into the memory, it finds the devices that can handle and assigns itself to them.

Therefore when the shell script creates a node in /dev folder with proper major and minor numbers, the node is handled by the driver. The driver is capable of handling any desired number of DAI devices but we assume that one device is present.

As can be seen in the sample code, it is simple opening, reading, closing a file. The special device file /dev/aib10 is first opened using open system call. An ioctl is implemented in the driver which returns the size of each packet in bytes. In this sample, file is ioctl-ed with proper number available at ioctl.h file in driver source code. After that, a buffer is allocated for one packet and the read system call is invoked to read the most current received packet.

If a packet is read and another read is immediately invoked such that no data is available yet, the system call blocks until data is received by the driver and delivered to calling code. Therefore by consecutive read calls, all of the received data by the device can be captured.

Sample C++ Code Communicating with the Driver
#include <iostream>
#include <cstdlib>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h> 

#include "aib10/driver/ioctl.h"

using namespace std;

int main(int argc, char *argv[]) {
	long siz = 0, count = 0;

	int fd = open("/dev/aib10", O_RDWR);
	if (fd < 0) return fd; // Error in opening
  
	if (ioctl(fd, AIB10_IOC_GET_EMEMSIZE, &siz) < 0)
		return -1; // Error in ioctl-ing
	else
		cout << "Packet size: " << siz << endl;

	unsigned char* buffer = new unsigned char[siz];	

	if( (count = read(fd, buffer, siz)) <= 0 )
		cout << "ERROR, count=" << count << endl;
	else
		for (long i=0; i < count; i++) {
			printf("%02X ", buffer[i]);
			if ((i+1) % 16 == 0) cout << endl;
		}

	delete[] buffer;
	close(fd);
	return 0;
}

 Driver Internals

 

The events occurred when the driver is inserted into the kernel and then removed are roughly:

  1. Driver Loading:
    When the module is first loaded, it registers the driver with some devices using a list of supported Vendor IDs and Device IDs. Also two functions, probe and remove are also registered such that when a supported device is detected or removed, the kernel executes these two functions respectively. (done in main.c)
     
  2. Device Probing:
    When a DAI device is detected, the kernel executes probe function. In this function, the kernel is informed that the driver is willing to handle the device and registers Interrupt Service Routine (ISR) and callback system call functions like open, close, read, write and ioctl. (done in pci.c)
     
  3. Device Registration:
    Also In this function, an internal data structure which will contain all of the required data to operate the device is allocated and attached to custom part of the PCI device data structure of the kernel for later use. Device is initialized from hardware respect such as writing IO sections and etc. Major and minor codes for char device is obtained and registered (the one in /dev), sysfs entries are allocated and the device is enabled (the kernel now redirects interrupts and calls callback functions). (done in pci.c)
     
  4. Interrupt and ISR:
    If a data is received by the DAI card, it will interrupt and kernel executes the ISR function. This function first finds out if the interrupt is really belongs to DAI card (in case of share IRQs), if yes, acknowledges it and sets a variable that there is data and also wakes up any processes in read queue waiting for data (if there is at least one). (done in hardware.c)
     
  5. Device File Operations:
    From user space perspective, after the driver is brought into memory, an application needs to open the char device in /dev folder. After that whenever a read is performed by application, the corresponding read function in driver is executed. It will check if the data is ready or not. If so, it will copy the data from memory-mapped area of driver which device writes directly (of course with regard to bank numbers) to user space buffer allocated by application. If not, it will make the process to sleep (block) and add it to a read queue. (done in fops.c)
     
  6. Device IO Controlling:
    Besides the normal open, close, read and write, the driver implements a number of custom functions for configuring the device as well as passing some information to applications. These functions are called ioctls and implement from direct access to memory-mapped area and writing to IO region directly to informing the application from status and statistics of device. (done in ioctl.c)
     
  7. Driver Unloading:
    When an application is done with a device, it closes the char file. The driver is informed and will unregister the handle in its close function. When the driver is unloaded, all of the above events are done in reverse and in opposite. First the remove is called and all data structures of device is deallocated. The driver no longer handles the device. Then the driver informs the kernel that it will not handle any devices and unregisters itself. (done in main.c)

Notes about source code:

  1. Naming: Names of all of the functions declared by the driver are preceded by aib10_ prefix.
  2. Locking: Variables which has the possibility of been accessed from more than one concurrent process (e.g. ISR and read) are protected properly using locking mechanisms (e.g. mutex) available in kernel.
  3. Hardware Issues: All of the issues closely related to hardware functionality of the device is gathered in hardware.c.
  4. Debugging: Debugging is done using print_k function which writes to a special memory area of the kernel accessible from user space.
  5. Utilities: General utility functions are available in tools.c while utility functions specific to DAI are available in main.c.
 
Back to Projects
My HomeSite   My Sitemap
RSS     Valid XHTML 1.0!   Valid CSS!   Firefox Compatible   IExplore 6.0 Compatible  
Maintained by SiteIt! - AT! - © 2003-2010
Last Update: February 14, 2010