Linux-Platform 字符设备驱动

来源:互联网 发布:爱普生打印机端口设置 编辑:程序博客网 时间:2024/06/04 22:08

初学Linux,做一些记录,以便以后查找。

直接贴代码,代码中的注释是个人目前的理解,理解有问题还请大神指出。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
//iTop4412_Kernel_3.0/arch/arm/mach-exynos/mach-itop4412.c
//和平台设备定义的设备名一致
#define DRIVER_NAME "lqled"  


struct demo_cdev            //一个设备节点
{
char data[200];        //设备节点所需要的存储
int data_pos;          //数据长度
struct cdev node;      //设备节点的系统描述
};


struct dev_class 

struct class *class;     //设备节点所属的类
dev_t dev_id;            //设备号
int num;                 //类下节点数量         
char *name;              //类的名字,也是节点名字公共部分
};
struct dev_class cdev_class = {
.num = 4,
.name = "Demo%d",
};
struct demo_cdev *pdemo_cdev;
struct file_operations demo_fops = { //对设备节点(文件)的操作函数
.owner = THIS_MODULE,
};


static int demo_probe(struct platform_device *pdv)
{
int i,ret,devno;
printk(KERN_EMERG "demo_probe\n");
//创建一个类
cdev_class.class = class_create(THIS_MODULE,cdev_class.name);
if(!cdev_class.class) return -1;
//自动分配设备号
ret = alloc_chrdev_region(&cdev_class.dev_id,0,cdev_class.num,cdev_class.name);
if(ret < 0){
class_destroy(cdev_class.class);
return ret;
}
//为指针初始化
pdemo_cdev = kmalloc(sizeof(struct demo_cdev) * cdev_class.num,GFP_KERNEL);
if(!pdemo_cdev){
class_destroy(cdev_class.class);
unregister_chrdev_region(cdev_class.dev_id,cdev_class.num);
return -1;
}
//对分配的空间初始化
memset(pdemo_cdev,0,sizeof(struct demo_cdev) * cdev_class.num);
//对每个设备节点初始化
for(i = 0 ; i < cdev_class.num ; i++){
//计算设备号
devno = MKDEV(MAJOR(cdev_class.dev_id),i);
//将设备节点与操作函数匹配
cdev_init(&pdemo_cdev[i].node,&demo_fops);
pdemo_cdev[i].node.owner = THIS_MODULE;
pdemo_cdev[i].node.ops = &demo_fops;
//添加一个节点
cdev_add(&pdemo_cdev[i].node,devno,1);
device_create(cdev_class.class,NULL,devno,NULL,cdev_class.name,i);
}
return 0; 
}


static int demo_remove(struct platform_device *pdv)
{
int i,devno;
printk(KERN_EMERG "demo_remove\n");
//除去设备节点
for(i = 0 ; i < cdev_class.num ; i++){
devno = MKDEV(MAJOR(cdev_class.dev_id),i);
cdev_del(&(pdemo_cdev[i].node));
device_destroy(cdev_class.class,devno);
}
//释放设备类
class_destroy(cdev_class.class);
//释放内存
kfree(pdemo_cdev);
//释放设备号
unregister_chrdev_region(cdev_class.dev_id,cdev_class.num);
return 0;
}


struct platform_driver demo_driver = { //驱动加载、卸载、休眠等操作时调用的函数
.probe = demo_probe,
.remove = demo_remove,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
}
};


static int Module_Init(void)
{
printk(KERN_EMERG "Module_Init!\n");
return platform_driver_register(&demo_driver);
}


static void Module_Exit(void)
{
platform_driver_unregister(&demo_driver);
printk(KERN_EMERG "Module_Exit!\n");
}


module_init(Module_Init);
module_exit(Module_Exit);


MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("LiQiang");


0 0
原创粉丝点击