Friday, December 14, 2007

Using I/O ports in C programs

Routines for accessing I/O ports are in /usr/include/asm/io.h (or linux/include/asm-i386/io.h in the kernel source distribution). The routines there are inline macros, so it is enough to #include ; you do not need any additional libraries.

Permissions

Before you access any ports, you must give your program permission to do so by calling the ioperm() function (declared in unistd.h) before any I/O port accesses. The syntax is ioperm(from, num, turn_on), where from is the first port number to give access to, and num the number of consecutive ports to give access to. The last argument is a Boolean value specifying whether to give access to the program to the ports (true (1)) or to remove access (false (0)). ioperm() can only give access to ports 0x000 through 0x3ff; for higher ports, you need to use iopl() (which gives you access to all ports at once).

Accessing the ports

To input a byte (8 bits) from a port, call inb(port), it returns the byte it got. To output a byte, call outb(value, port) (please note the order of the parameters).


wait for more ;)

Page copy protected against web site content infringement by Copyscape

Sunday, December 9, 2007

Character Device Drivers

Device drivers are mainly categorized in four different categories namely character drivers, block drivers, terminal drivers and streams. Character drivers transmit information from the user to the device (or vice versa) byte per byte. The following figure will make it easy to understand this class of drivers:


The file_operations Structure

The file_operations structure is defined in linux/fs.h, and holds pointers to functions defined by the driver that perform various operations on the device. Each field of the structure corresponds to the address of some function defined by the driver to handle a requested operation.

The file structure

Each device is represented in the kernel by a file structure, which is defined in linux/fs.h. It's not the same thing as a FILE, which is defined by glibc and would never appear in a kernel space function. It represents an abstract open `file' which is represented by a structure named inode.

Registering A Device

Adding a driver to your system means registering it with the kernel. This is synonymous with assigning it a major number during the module's initialization. You do this by using the register_chrdev function, defined by linux/fs.h.

int register_chrdev(unsigned int major, const char *name,struct file_operations *fops);

where unsigned int major is the major number you want to request, const char *name is the name of the device as it'll appear in /proc/devices and struct file_operations *fops is a pointer to the file_operations table for your driver. A negative return value means the registration failed. If you pass a major number of 0 to register_chrdev, the return value will be the dynamically allocated major number. The downside is that you can't make a device file in advance, since you don't know what the major number will be.

Unregistering A Device

We can't allow the kernel module to be rmmod'ed whenever root feels like it. If the device file is opened by a process and then we remove the kernel module, using the file would cause a call to the memory location where the appropriate function (read/write) used to be. If we're lucky, no other code was loaded there, and we'll get an ugly error message. If we're unlucky, another kernel module was loaded into the same location, which means a jump into the middle of another function within the kernel. The results of this would be impossible to predict, but they can't be very positive.

Accessing Device Files

Device files are supposed to represent physical devices. Most physical devices are used for output as well as input, so there has to be some mechanism for device drivers in the kernel to get the output to send to the device from processes. This is done by opening the device file for output and writing to it, just like writing to a file.




Page copy protected against web site content infringement by Copyscape

Friday, November 23, 2007

Compiling a Device Driver Module


In many cases drivers compiled for similar kernel versions will work. Pre-compiled modules in the form of RPMS for popular distributions are frequently available. If a pre-compiled module is not available; you'll have to compile one from the driver source code, or the source code RPM (SRPM).
* Verify that the source code for your current kernel version is installed.
* If you don't have a /usr/include/linux/version.h file, do cd /usr/src/linux; make include/linux/version.h
* Copy the driver source code to a source directory
* Compile the file using the compile-command at the bottom of the driver source file. If a compile-command is not there use the following compile command:

gcc -DMODULE -D__KERNEL__ -O6 -c driver.c

* As 'root', test the module by doing "insmod driver.o".
* Install the driver module in the proper location for your distribution. This is usually /lib/modules/kernel-version/net/driver.o. The command to do this is
install -m 644 driver.o /lib/modules/`uname -r`/net/


Testing the New Module

As 'root', load the module using "insmod driver.o" and execute the appropriate 'route add -net ...' for your local network.
If the networking works correctly, add the module to your system configuration. For Slackware and most other systems, add the insmod command to /etc/rc.d/rc.inet1 or /etc/rc.d/rc.local. RedHat users should add the insmod line to /etc/rc.d/rc.modules or copy driver.o to /lib/modules/`uname -r`/net/ and add the following line to /etc/conf.modules:

alias eth0 driver

Consider the following command "/sbin/insmod driver.o full_duplex=1,0,1". This command sets the full_duplex flag for the first and third cards of this type.
To set module parameters when the module is loaded automatically, add the following line to /etc/conf.modules

alias eth0 driver

options driver full_duplex=1,0,1 debug=0

....to be contd. ;)


Page copy protected against web site content infringement by Copyscape