实现一个虚拟设备“自增器”,该设备把写入的数据自增1。

ganquan@debian:~/Driver/01$ cat Add.h

#ifndef _MYDRIVER_H
#define _MYDRIVER_H

#include <linux/cdev.h>       /*cdev*/
#include <linux/types.h>    /*ssize_t*/

/*设备对象*/
struct Add
{
struct cdev MyChrDevice;    /*Char device structure*/
};

/*驱动程序要实现的函数*/
ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

#endif    /*_MYDRIVER_H*/

ganquan@debian:~/Driver/01$ cat Add.c

#include <linux/init.h>			/*包含用于声明装载模块初始化和清除函数的宏*/
#include <linux/module.h>		/*包含装载模块需要的符号和函数定义*/
#include <linux/kernel.h>		/*printk()*/
#include <linux/fs.h>			/*申请设备号函数和数据结构,file_operation*/
#include <linux/types.h>		/*dev_t*/
#include <linux/kdev_t.h>		/*包含获取主设备号和次设备号的宏*/
#include <linux/slab.h>			/*kmalloc()*/
#include <linux/cdev.h>			/*cdev,cdev_init(),cdev_add()*/
#include <asm/uaccess.h>		/*copy_to_user(),copy_from_user()*/

#include "Add.h"

static int global_var = 0;
int Add_major = 0;	/*主设备号*/
int Add_minor = 0;	/*次设备号*/

struct Add *mydev;

struct file_operations Add_fops = {
	.owner = THIS_MODULE,
	.read = Add_read,
	.write = Add_write,
};

ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_to_user(buf,&global_var,sizeof(int)))
	{
		return -EFAULT;
	}

	return sizeof(int);
}
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_from_user(&global_var,buf,sizeof(int)))
	{
		return -EFAULT;
	}
	if(global_var != 0)
		global_var++;

	return sizeof(int);
}

static int MyDriver_init(void)
{
	int ret;
	int devno;
	dev_t dev;

	/*申请设备号*/
	ret = alloc_chrdev_region(&dev,0,1,"Add");
	if(ret < 0)
	{
		printk(KERN_ALERT "Can not get dev_t\n");
	}
	else
	{
		Add_major = MAJOR(dev);		/*MAJOR in <linux/kdev_t.h>*/
		Add_minor = MINOR(dev);		/*MINOR in <linux/kdev_t.h>*/
	}
	/*申请设备号结束*/

	/*分配设备内存空间*/
	mydev = kmalloc(sizeof(struct Add),GFP_KERNEL);
	if(!mydev)
	{
		printk(KERN_ALERT "kmalloc error\n");
	}
	/*分配内存空间结束*/

	/*初始化内存空间*/
	memset(mydev,0,sizeof(struct Add));

	/*注册字符设备*/
	devno = MKDEV(Add_major,Add_minor);
	cdev_init(&mydev->MyChrDevice,&Add_fops);
	mydev->MyChrDevice.owner = THIS_MODULE;
	mydev->MyChrDevice.ops = &Add_fops;
	ret = cdev_add(&mydev->MyChrDevice,devno,1);
	if(ret)
		printk(KERN_ALERT "Error %d adding Add\n",ret);
	/*注册字符设备结束*/
	return 0;
}

static void MyDriver_exit(void)
{
	dev_t devno;

    devno = MKDEV(Add_major,Add_minor);
	cdev_del(&mydev->MyChrDevice);
	unregister_chrdev_region(devno,1);
	kfree(mydev);
}

module_init(MyDriver_init);	/*声明模块加载初始化函数*/
module_exit(MyDriver_exit);	/*声明模块卸载清除函数*/

MODULE_LICENSE("GPL");		/*驱动许可证协议*/
MODULE_AUTHOR("GanQuan");	/*作者*/
MODULE_VERSION("0.0.1");	/*版本号*/

不变的Makefile:
ganquan@debian:~/Driver/01$ cat Makefile

obj-m := Add.o
	KDIR ?= /lib/modules/$(shell uname -r)/build
	PWD := $(shell pwd)
all:
	    $(MAKE) -C $(KDIR) M=$(PWD)

.PHONY:clean
clean:
	    rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions

驱动加载脚本:
ganquan@debian:~/Driver/01$ cat addload

#!/bin/bash
#author ganqan
#	imganquan@gmail.com
#load a module

module="Add"
device="Add"
mode="777"

/sbin/insmod ./${module}.ko || exit 1

major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)

mknod /dev/${module} c $major 0
chmod $mode /dev/${device}

devinfo=`ls -l /dev/${device}`

echo "insmod	:$module.ko"
echo "major	:$major"
echo "devinfo	:$devinfo"

驱动卸载脚本:
ganquan@debian:~/Driver/01$ cat addunload

#!/bin/bash
#author ganquan
#	imganquan@gmail.com
#unload a module

module="Add"
device="Add"
/sbin/rmmod $module || exit 1
rm -f /dev/${device}

很简单的测试程序:
ganquan@debian:~/Driver/01$ cat test.c

#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
	int fd,num;
	fd = open("/dev/Add", O_RDWR, S_IRUSR | S_IWUSR);
	if (fd != -1)
	{
		read(fd, &num, sizeof(int));
		printf("The MyDevice is %d\n", num);

		printf("Please input the num written to MyDevice\n");
		scanf("%d", &num);
		write(fd, &num, sizeof(int));
		read(fd, &num, sizeof(int));
		printf("The MyDevice is %d\n", num);
		close(fd);
	}
	else
		printf("Device open failure\n");
		return 0;
}

测试结果:

ganquan@debian:~/Driver/01$ sudo ./addload
insmod	:Add.ko
major	:249
devinfo	:crwxrwxrwx 1 root root 249, 0 2009-06-09 22:55 /dev/Add
ganquan@debian:~/Driver/01$ ./test
The MyDevice is 0
Please input the num written to MyDevice
7
The MyDevice is 8
ganquan@debian:~/Driver/01$ sudo ./addunload