本文的copyright归yuweixian4230@163.com 所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:yuweixian
博客:yuweixian4230.blog.chinaunix.net
1. device_create()文件包含: #include 函数定义: 函数位置: src/drivers/base/core.c 函数格式:
- extern struct device *device_create(struct class *cls, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
函数功能: 函数device_create()用于动态的建立逻辑设备,并对新的逻辑设备类进行相应初始化,将其与函数的第一个参数所代表的逻辑类关联起来,然后将此逻辑设备加到linux内核系统的设备驱动程序模型中。函数能够自动在/sys/devices/virtual目录下创建新的逻辑设备目录,在/dev目录下创建于逻辑类对应的设备文件 参数说明: struct class cls:与即将创建额逻辑设备相关的逻辑类,在“class类 class_create使用”说明了。 dev_t dev:设备号 void *drvdata: void类型的指针,代表回调函数的输入参数 const char *fmt: 逻辑设备的设备名,即在目录 /sys/devices/virtual创建的逻辑设备目录的目录名。 2.函数device_destroy()文件包含:#include 函数定义: src/drivers/base/core.c void device_destroy(struct class *dev, dev_t devt); 函数功能: 函数device_destroy()用于从linux内核系统设备驱动程序模型中移除一个设备,并删除/sys/devices/virtual目录下对应的设备目录及/dev/目录下对应的设备文件 ====================================================================== class_create() 和 device_create()有什么关系呢??
在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。什么事udev??请查看“ 收集 3个介绍uedv 网址资料 ”
内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。
在下面的例子中具体说明关系!!!!!!!!
1. 首先通过 mem_class = class_create(THIS_MODULE,"ywx_class_char"); 语句建立了逻辑设备类,在 /sys/class/ 下新建了 ywx_class_char目录 查看:
- ywx@ywx:/sys/class$ls ywx_class_char
- ywx_device_char
2. 通过语句 device_create(mem_class,NULL,MKDEV(MEM_MAJOR,MEM_MINOR),NULL,"ywx_device_char"); 阿在 /dev/ 下自动建立了 ywx_device_char 设备节点 ,具体查看:
- ywx@ywx:/dev$ ls-l ywx_device_char
- crw-------1 root root240, 02012-01-03 15:40ywx_device_char
3.那么 class_create 和 device_create还有什么关系呢?? 在/sys/devices/virtual/建立了 “ywx_class_char”在/sys/devices/virtual/ywx/class/char/下建立了 ywx_device_char 目录
- ywx@ywx:/sys/devices/virtual/ywx_class_char/ywx_device_char$ ls-la
- total 0
- drwxr-xr-x 3 root root 0 2012-01-03 15:40.
- drwxr-xr-x 3 root root 0 2012-01-03 15:40..
- -r--r--r--1 root root40962012-01-03 16:10dev 这个就是我们在驱动中分配的大小4KB
- drwxr-xr-x 2 root root 0 2012-01-03 16:10 power
- lrwxrwxrwx1 root root 0 2012-01-03 15:40 subsystem->../../../../class/ywx_class_char符号链接设备
- -rw-r--r--1 root root 4096 2012-01-03 15:40 uevent
====================================================================== drivers/i2c/i2c-dev.c 也有关于 class_create的例子
i2c_dev_class = class_create( THIS_MODULE, "i2c-dev");
====================================================================自己的字符设备驱动程序程 序代码附加: cdev_init_add_del.rar 将rar修改为tar.bz2
- #include<linux/kernel.h>
- #include<linux/module.h>
- #include<linux/init.h>
- #include<linux/cdev.h>
- #include<linux/device.h>
- #include<linux/slab.h>//kmalloc
- #include<linux/vmalloc.h>//vmalloc()
- #include<linux/types.h>//ssize_t
- #include<linux/fs.h>//file_operaiotns
- #include<linux/uaccess.h>//copy_from_user
- #define MEM_MALLOC_SIZE 4096////缓冲区大小
- #define MEM_MAJOR 240////主设备号
- #define MEM_MINOR 0
- char*mem_spvm=NULL;////缓冲区指针,指向内存区
- struct cdev*mem_cdev=NULL;//字符设备对象指针
- structclass*mem_class=NULL;//设备类指针
- staticint__init mem_init(void);
- static void __exit mem_exit(void);
- staticintmem_open(struct inode*inode,struct file*filp);
- staticintmem_release(struct inode*inode,struct file*filp);
- static ssize_t mem_read(struct file*filp,char __user*buf,size_t count,loff_t*fpos);
- static ssize_t mem_write(struct file*filp,char __user*buf,size_t count,loff_t*fops);
- staticconststruct file_operations mem_fops={
- .owner=THIS_MODULE,
- .open=mem_open,
- .release=mem_release,
- .read=mem_read,
- .write=mem_write,
- };
- staticint__init mem_init(void)
- {
- intret;
- //创建设备号 主次设备号
- intdevno=MKDEV(MEM_MAJOR,MEM_MINOR);
- printk("mem_init initial...\n");
- //开辟内核内存缓冲区
- mem_spvm=(char*)vmalloc(MEM_MALLOC_SIZE);
- if(mem_spvm==NULL)
- {
- printk("vmalloc mem_spvm error\n");
- return-ENOMEM;//
- }
- //
- mem_cdev=cdev_alloc();
- if(mem_cdev==NULL)
- {
- printk("cdev_alloc error\n");
- return-ENOMEM;
- }
- cdev_init(mem_cdev,&mem_fops);
- mem_cdev->owner=THIS_MODULE;
- ret=cdev_add(mem_cdev,devno,1);//将字符设备键入内核系统
- if(ret)
- {
- cdev_del(mem_cdev);
- mem_cdev=NULL;
- printk("cdev_add error\n");
- return-1;
- }
- //
- mem_class=class_create(THIS_MODULE,"ywx_class_char");
- if(IS_ERR(mem_class))
- {
- printk("class_create error..\n");
- return-1;
- }
- device_create(mem_class,NULL,MKDEV(MEM_MAJOR,MEM_MINOR),NULL,"ywx_device_char");
- printk("init finished..\n");
- return 0;
- }
- static void __exit mem_exit(void)
- {
- printk("mem_exit starting..\n");
- if(mem_cdev!=NULL)
- cdev_del(mem_cdev);
- printk("cdev_del ok\n");
- device_destroy(mem_class,MKDEV(MEM_MAJOR,MEM_MINOR));
- class_destroy(mem_class);
- if(mem_spvm!=NULL)
- vfree(mem_spvm);
- printk("vfree ok\n");
- printk("mem_exit finished..\n");
- }
- staticintmem_open(struct inode*inode,struct file*filp)
- {
- printk("open vmalloc space..\n");
- try_module_get(THIS_MODULE);//模块引用计数器自加
- printk("open vamlloc space ok..\n");
- return 0;
- }
- staticintmem_release(struct inode*inode,struct file*filp)
- {
- printk("close vmalloc space..\n");
- module_put(THIS_MODULE);//模块引用计数器自减
- return 0;
- }
- static ssize_t mem_read(struct file*filp,char __user*buf,size_t count,loff_t*fpos)
- {
- intret=-1;
- char*tmp;
- printk("copy data to the user space\n");
- tmp=mem_spvm;
- if(count>MEM_MALLOC_SIZE)
- count=MEM_MALLOC_SIZE;
- if(tmp!=NULL)//将内核数据写入到用户空间
- ret=copy_to_user(buf,tmp,count);
- if(ret==0)
- {
- printk("read copy data success\n");
- return count;
- }
- else
- {
- printk("read copy data error\n");
- return 0;
- }
- }
- static ssize_t mem_write(struct file*filp,char __user*buf,size_t count,loff_t*fops)
- {
- intret=-1;
- char*tmp;
- printk("read data from the user space.\n");
- tmp=mem_spvm;
- if(count>MEM_MALLOC_SIZE)
- count=MEM_MALLOC_SIZE;
- if(tmp!=NULL)
- ret=copy_from_user(tmp,buf,count);
- if(ret==0)
- {
- printk("write copy data success.\n");
- return count;
- }
- else
- {
- printk("write copy data error.\n");
- return 0;
- }
- }
- MODULE_LICENSE("GPL");
- module_init(mem_init);
- module_exit(mem_exit);
应用程序:
- #include<stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<fcntl.h>
- #include<string.h>//memset()
- intmain(intargc,char*argv[])
- {
- intfd,cnt;
- char buf[256];
- inti;
- printf("char device testing..\n");
- fd=open("/dev/ywx_device_char",O_RDWR);
- if(fd==0)
- {
- printf("open failed.\n");
- return 1;
- }
- printf("input the data for kernel:");
- scanf("%s",buf);
- cnt=write(fd,buf,256);
- if(cnt==0)
- printf("write error\n");
- printf("clear buf,and will read from kernel...\n");
- for(i=0;i<256;i++)
- buf[i]=32;//32=" "
- cnt=read(fd,buf,256);
- if(cnt>0)
- printf("read data from kernel is:%s\n",buf);
- else
- printf("read data error\n");
- close(fd);
- printf("close app..\n");
- return 0;
- }
应用程序测试:
- root@ywx:/home/ywx/desktop/module/api_/cdev_init_add_del/app#./app
- char device testing..
- input the dataforkernel:yuweixian4230.blog.chinaunix.net
- clear buf,andwill read from kernel...
- read data from kernelis:yuweixian4230.blog.chinaunix.net
- close app..