I am generally writing linux drivers for embedded systems for three years, and I am using this sample driver interface for the startup. In this blog entry I will give steps for sample linux driver implementation and sample files.
First of all we need a “mydriver.h” for header definitions,

#ifndef __LOADYOURSELF_MYDRIVER__
#define __LOADYOURSELF_MYDRIVER__

///@file mydriver.h
///@brief mydriver header file for mydriver.

#ifndef __KERNEL__
# define __KERNEL__
#endif
#ifndef MODULE
# define MODULE
#endif

#define MODULE_NAME “sample_driver” //define your own module here
#endif

You can use this file for macro definitions for ioctl commands. So you can use directly this header file in your clients which they want to use these driver.

So continue with main driver file named "mydriver.c".

/*
* the source file for linux driver
*
* File Name: mydriver.c
*
* Programers:
*
*
* Synopsis:
*
* Description:
* New Basic driver implementation
*
* Modification History:
*
*
*/

///@file mydriver.c
///@brief mydriverdriver for linux implementation
///@bug

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <asm/io.h>

#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/miscdevice.h>

#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/signal.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
#include <linux/sched.h>
#include <asm/segment.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/videodev.h>
#include <asm/uaccess.h>

MODULE_DESCRIPTION("SAMPLE DRIVER");
MODULE_AUTHOR("LOADYOURSELF");
MODULE_LICENSE("GPL");

#include <linux/i2c.h> // for i2c interface
#include <linux/i2c-dev.h>

#include "mydriver.h"

static int mydriver_open(struct inode * inode,
struct file * filp);
static int mydriver_release(struct inode * inode,
struct file * filp);
static ssize_t mydriver_read(struct file * filp,
char * buf,
size_t count,
loff_t * l);
static ssize_t mydriver_write(struct file *file,
const char *buffer,
size_t count,
loff_t *ppos);
static int mydriver_ioctl(struct inode * inode,
struct file *filp,
unsigned int cmd ,
unsigned long arg);

struct file_operations g_mydriver_fops = { //main procedure connections
open: mydriver_open,
release: mydriver_release,
write: mydriver_write,
read: mydriver_read,
poll: NULL,
ioctl: mydriver_ioctl,
fasync: NULL,
};

///@brief mydriver open routine \n
/// allocate resource when opening the inode
///
///@param inode
///@param filp the pointer to the file descripter
///
///@return int return status
/// @li 0 sucessful
/// @li other failed
///

static int mydriver_open(struct inode * inode, struct file * filp)
{
//write your open statements here. For example initializations
return 0;
}

///@brief mydriver driver release routine \n
///
///
///@param inode
///@param filp the pointer to the file descripter
///
///@return int return status
/// @li 0 sucessful
/// @li other failed
///

static int mydriver_release(struct inode * inode, struct file * filp)
{
//write your close statements here. Close destructions
return 0;
}

///@brief mydriver read routine \n
/// read count of bytes to user defined buf address
///
///@param filp the pointer to the device file
///@param buf data buffer address given from user space
///@param count number of chars to be read
///@param l offset of the file
///
///@return ssize_t count of bytes have been read
///
///

static ssize_t mydriver_read(struct file * filp, char * buf, size_t count, loff_t * l)
{
//MAKE your read operations here.
return 1;
}

static ssize_t mydriver_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
//make your write operations here
return 1;
}

static int mydriver_ioctl(struct inode * inode,
struct file *filp,
unsigned int cmd ,
unsigned long arg)
{
//make your ioctl command operations here.
return 1;
}

///@brief mydriver driver init routine \n
/// initialize the mydriver
///
///@return int return status
/// @li 0 sucessful
/// @li other failed
///

#ifdef MODULE
int init_module(void)
#else
int __init mydriver_init(void)
#endif
{
int err;
err=register_chrdev(105, "mydriver", &g_mydriver_fops); //character device which will be accessed through /dev/mydriver
if (err < 0)
{
printk("can't register the device driver\n");
return err;
}
printk("mydriver Driver 0.0.1\n");

#ifdef DEBUG_MODE_mydriver
printk("Driver Added\n");
#endif
return 0;
}
///@brief mydriver cleanup routine \n
/// will be called when uninstall the mydriver, it will call devfs unregister functions
///
///

#ifdef MODULE
void cleanup_module(void)
#else
void __exit mydriver_cleanup(void)
#endif
{

#ifdef DEBUG_MODE_mydriver
printk("IN MYDRIVER CLEANUP\n");
#endif
unregister_chrdev(105, "mydriver");
#ifdef DEBUG_MODE_mydriver
printk("mydriver Driver Removed !!!\n");
#endif
}
#ifndef MODULE
module_init(mydriver_init);
module_exit(mydriver_cleanup);
#endif
/* end of file */

At the end you need to compile the new driver with a compile with:

gmake -C /usr/src/kernels/2.6.25.14-69.fc8-i686 M=$PWD modules


or

make -C /usr/src/kernels/2.6.25.14-69.fc8-i686 M=$PWD modules

which /usr/src/kernels/2.6.x shows your kernel source files. You need to run this command in your source directory which the mydriver.c located.

After this command you will have a mydriver.ko file and you can load to your kernel space with "insmod mydriver.ko" in the linux console. You can check that whether is it installed with lsmod command.

I tested it with a fedora core 8 system whose linux kernel version is 2.6.25.14-69.fc8

I hope this sample driver will help people who needs a startup point for a linux kernel driver development. You can contact with me for problems which are related with the source code above.