Linux 2.6.32内核字符设备驱动模板
原文转自(http://www.embedhq.org/html/jsbw/2011/0214/1066.html)
//=======================字符设备驱动模板开始===========================//
#defineCHAR_DEV_DEVICE_NAME"char_dev"//设备名
structclass*char_dev_class;//class结构用于自动创建设备结点
staticintmajor=0;/*0表示动态分配主设备号,可以设置成未被系统分配的具体的数字。*/
staticstructcdevchar_dev_devs;//定义一个cdev结构
//设备建立子函数,被char_dev_init函数调用
staticvoidchar_dev_setup_cdev(structcdev*dev,intminor,structfile_operations*fops)
{
interr,devno=MKDEV(major,minor);
cdev_init(dev,fops);
dev->owner=THIS_MODULE;
dev->ops=fops;
err=cdev_add(dev,devno,1);
if(err)
{
printk(KERN_NOTICE"Error%daddingchar_dev%d\n",err,minor);
}
}
//file_operations结构体设置,该设备的所有对外接口在这里明确,此处只写出了几常用的
staticstructfile_operationschar_dev_fops=
{
.owner=THIS_MODULE,
.open=char_dev_open,//打开设备
.release=char_dev_release,//关闭设备
.read=char_dev_read,//实现设备读功能
.write=char_dev_write,//实现设备写功能
.ioctl=char_dev_ioctl,//实现设备控制功能
};
//进行初始化设置,打开设备,对应应用空间的open系统调用
intchar_dev_open(structinode*inode,structfile*filp)
{
...//这里可以进行一些初始化
return0;
}
//释放设备,关闭设备,对应应用空间的close系统调用
staticintchar_dev_release(structinode*node,structfile*file)
{
...//这里可以进行一些资源的释放
return0;
}
//实现读功能,读设备,对应应用空间的read系统调用
ssize_tchar_dev_read(structfile*file,char__user*buff,size_tcount,loff_t*offp)
{
...
return0;
}
//实现写功能,写设备,对应应用空间的write系统调用
ssize_tchar_dev_write(structfile*file,constchar__user*buff,size_tcount,loff_t*offp)
{
...
return0;
}
//实现主要控制功能,控制设备,对应应用空间的ioctl系统调用
staticintchar_dev_ioctl(structinode*inode,structfile*file,unsignedintcmd,unsignedlongarg)
{
...
return0;
}
//设备初始化
staticintchar_dev_init(void)
{
intresult;
dev_tdev=MKDEV(major,0);
if(major)
{
//给定设备号注册
result=register_chrdev_region(dev,1,CHAR_DEV_DEVICE_NAME);
}
else
{
//动态分配设备号
result=alloc_chrdev_region(&dev,0,1,CHAR_DEV_DEVICE_NAME);
major=MAJOR(dev);
}
char_dev_setup_cdev(&char_dev_devs,0,&char_dev_fops);
printk("Themajorofthechar_devdeviceis%d\n",major);
//====有中断的可以在此注册中断:request_irq,并要实现中断服务程序===//
//创建设备结点
char_dev_class=class_create(THIS_MODULE,"ad_class");
if(IS_ERR(char_dev_class))
{
printk("Err:failedincreatingclass.\n");
return0;
}
device_create(char_dev_class,NULL,dev,NULL,"char_dev");
return0;
}
//设备注销
staticvoidchar_dev_cleanup(void)
{
device_destroy(adc_class,dev);
class_destroy(adc_class);
cdev_del(&char_dev_devs);//字符设备的注销*/
unregister_chrdev_region(MKDEV(major,0),1);//设备号的注销
//========有中断的可以在此注销中断:free_irq======//
printk("char_devdeviceuninstalled\n");
}
module_init(char_dev_init);//模块初始化接口
module_exit(char_dev_cleanup);//模块注销接口
//以下两句不能省略,否则编译不通过
MODULE_AUTHOR("www.embedhq.org");
MODULE_LICENSE("GPL");
//====================字符设备驱动模板结束========================//
用Makefile模板编译,Makefile如下:
//=======================Makefile开始===========================//
ifeq($(KERNELRELEASE),)
#KERNELDIR?=/your/target/source/directory/
KERNELDIR?=/opt/kernal/linux-2.6.32.10/
PWD:=$(shellpwd)
modules:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules
modules_install:
$(MAKE)-C$(KERNELDIR)M=$(PWD)modules_install
clean:
rm-rf*.o*~core.depend.*.cmd*.ko*.mod.c.tmp_versions
.PHONY:modulesmodules_installclean
//=========================Makefile结束=============================//
make编译后生成char_dev.ko,控制台输入加载和卸载命令,还可以使用lsmod查看已经加载的模块信息。
insmodchar_dev.ko#加载驱动,会执行module_init中的语句
rmmodchar_dev#卸载驱动,会执行module_exit中的语句