在驱动中增加对udev的支持

 

先看一下转载:http://blog.chinaunix.net/u3/110644/showart_2208979.html

自学驱动以来,一直都是在加载模块后采用手动创建节点,虽然这个过程比较简单,毕竟还是有点麻烦,尤其是在调试模块的时候。

#insmod module_name.ko

#mknod /dev/module_name c MAJOR MINOR

#

在2.4里设备文件采用的是devfs,在2.6里已经用udev取代devfs,为解决上面那样手动创建节点的麻烦,我们可以在程序里加上创建节点这项,如下:

以字符设备char_dev为例,在驱动初始化的代码里调用class_create为该设备创建一个class,再为每个设备调用 class_device_create创建对应的设备,这样的module被加载时,undev daemon就会自动在/dev下创建char_dev设备文件。大概方法如下:

struct class *myclass = class_create(THIS_MODULE, “char_dev”);
class_device_create(myclass, NULL, MKDEV(major_num, 0), NULL, “char_dev”);

当然,在exit函数中要把创建的class移除:
class_destory(&xxx_dev->cdev);
class_device_desotry(my_class,MKDEV(major_num,0));

下面介绍下函数class_creat和class_device_creat的原型:

class_create()
-------------------------------------------------
linux-2.6.22/include/linux/device.h
struct class *class_create(struct module *owner, const char *name)
    class_create - create a struct class structure
    @owner: pointer to the module that is to "own" this struct class
    @name: pointer to a string for the name of this class.
在/sys/class/下创建类目录


class_device_create()
-------------------------------------------------
linux-2.6.22/include/linux/device.h
struct class_device *class_device_creat(struct class        *cls,
                                         struct class_device *parent,
                                         dev_t               devt,
                                         struct device       *device,
                                         const char          *fmt, ...)

    class_device_create - creates a class device and registers it with sysfs
    @cls: pointer to the struct class that this device should be registered to.
    @parent: pointer to the parent struct class_device of this new device, if any.
    @devt: the dev_t for the char device to be added.
    @device: a pointer to a struct device that is assiociated with this class device.
    @fmt: string for the class device's name

void class_destroy(struct class *cls);/*销毁/sys/class下的类   */

void class_device_destroy(struct class *cls, dev_t devt);   /*销毁一个类设备*/

参数含义同上

补充:

在Linux2.6中,针对上面的这个问题不同的版本有些修改,使用前要先查看下/.../include/linux/device.h里的函数声明,如我用的是Linux2.6.29,里面就没有class_device_create函数,而直接使用device_create就可以了,而在之前的版本如Linux2.6.15,里面就要用class_device_create函数 。

 

 

上面的内容说的很有用。

此前,我按照《linux设备驱动开发详解》的例程学习,发现驱动并不能正常工作。鄙人实在是太菜了,甚至没想过用手工去创建设备节点,所以常常为设备节点的事苦恼。

下面,我结合自己的实践,分享下我的实验成果:

驱动源码:

#include <linux/init.h>

#include <linux/module.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/sched.h>

#include <linux/mm.h>

#include <linux/device.h>

#include <asm/io.h>

#include <asm/system.h>

#include <asm/uaccess.h>

 

#define MAJOR_NUM 251

/*此处要根据自己的/proc/device/目录下的情况,选一下不重复的主设备号就好*/

#define DEVSIZE 0X1000

MODULE_LICENSE("GPL");

 

/*定义设备结构体,其中包括分配cdev*/

struct globalvar_dev{

       struct cdev cdev;

       unsigned char mem[DEVSIZE];

};

struct globalvar_dev dev;     

struct class *myclass;

 

static ssize_t globalvar_read(struct file *filp,char*buf,size_t count,loff_t *ppos)

{

       unsigned long p=*ppos;

       int ret=0;

/*分析和获取有效的读长度*/

       if(p>=DEVSIZE)//要读的字节数太大

              return 0;

       if(count>DEVSIZE-p)//要求的字节数太大

              count=DEVSIZE-p;

       if(copy_to_user(buf,(void *)(dev.mem+p),count)){

              ret=-EFAULT;

              }

       else{

              *ppos +=count;

              ret = count;

              printk(KERN_INFO "read %d bytes from %ld\n",count,p);

              }

 

       return ret;

}

 

static ssize_t globalvar_write(struct file *filp,const char*buf,size_t count,loff_t *ppos)

{

       unsigned long p = *ppos;

       int ret = 0;

       /*分析和获取有效的读长度*/

       if(p>=DEVSIZE)//要读的字节数太大

              return 0;

       if(count>DEVSIZE-p)//要求的字节数太大

              count=DEVSIZE-p;

 

       if(copy_from_user(dev.mem+p,buf,count))

              ret = -EFAULT;

       else{

              *ppos += count;

              ret = count;

              printk(KERN_INFO "written %d byte from %ld\n",count,p);

              }

 

       return ret;      

}

 

static loff_t globalvar_llseek(struct file *filp,loff_t offset,int orig)

{

 

       loff_t ret;

       switch(orig)

       {

              case 0:

                     if (offset<0){

                            ret=-EINVAL;

                            break;

                            }

                     if((unsigned int)offset >DEVSIZE){

                            ret=-EINVAL;

                            break;

                            }

                     filp->f_pos=(unsigned int)offset;

                     ret=filp->f_pos;

                     break;

              case 1:

                     if (filp->f_pos+offset<0){

                            ret=-EINVAL;

                            break;

                            }

                     if(filp->f_pos+(unsigned int)offset >DEVSIZE){

                            ret=-EINVAL;

                            break;

                            }

                     filp->f_pos+=(unsigned int)offset;

                     ret=filp->f_pos;

                     break;    

              case 2:

                     if (DEVSIZE-1+offset<0){

                            ret=-EINVAL;

                            break;

                            }

                     if(DEVSIZE-1+(unsigned int)offset >DEVSIZE){

                            ret=-EINVAL;

                            break;

                            }

                     filp->f_pos=DEVSIZE-1+(unsigned int)offset;

                     ret=filp->f_pos;

                     break;    

              default:

                     ret = -EINVAL;

              }

       return ret;

}

struct file_operations globalvar_fops=

{

       .owner=THIS_MODULE,

       .write=globalvar_write,

       .read=globalvar_read,

       .llseek=globalvar_llseek,

       };

 

static int  __init  globalvar_init(void)

{

int err;

int result;

 

//第一步:取得设备号

dev_t devno = MKDEV(MAJOR_NUM,0);/*主,次设备号*/

if(MAJOR_NUM)

/*register_chrdev_region(设备号指针,设备号数目,设备名)*/

       result=register_chrdev_region(devno,1,"globalvar");

else

{

/*alloc_chrdev_region(分配到的设备号指针,起始次设备号,

需要分配的设备号数目,设备名称)*/

       result = alloc_chrdev_region(&devno,0,1,"globalvar");

       //MAJOR_NUM=MAJOR(devno);

}

 

/*第二步:初始化cdev*/

cdev_init(&dev.cdev,&globalvar_fops);/*建立cdev和file_operations之间的连接*/

dev.cdev.owner=THIS_MODULE;

dev.cdev.ops=&globalvar_fops;

 

/*第三步:注册字符设备*/

/*cdev_add(cdev结构指针,设备号,设备数目)*/

err=cdev_add(&dev.cdev,devno,1);

if(err)

       printk(KERN_NOTICE "Error %d adding globalvar",err);

 

 

/*增加对udev的支持*/

myclass = class_create(THIS_MODULE, "globalvar");

device_create(myclass, NULL, MKDEV(MAJOR_NUM, 0), NULL, "globalvar");

 

printk("globalvar installs success");

return 0;

 

}

 

 

static void __exit globalvar_exit(void)

       class_destroy(myclass);

       device_destroy(myclass,MKDEV(MAJOR_NUM,0));

      cdev_del(&dev.cdev);/*注销cdev结构*/

       unregister_chrdev_region(MKDEV(MAJOR_NUM,0),1);/*注销设备号*/

       printk("globalvar exits success");

 

}

 

                           

module_init(globalvar_init);

module_exit(globalvar_exit);

 

上面引用的文章已经说的很清楚,如果你手工创建节点,就不需要红色字体的内容。加上红色字体内容后,如果你的平台已经有了udev ,那么它就会自动创建设备节点。

 

测试源码:

#include<sys/types.h>

#include<sys/stat.h>

#include<stdio.h>

#include<fcntl.h>

void main()

{

       FILE *fp0 =NULL;

       char Buf[4096];

       strcpy(Buf,"globalvar is char dev!");

       printf("BUF:%s\n",Buf);

 

       fp0=fopen("/dev/globalvar","r+");

       if(fp0==NULL){

              printf("Open globalvar Error!\n");

              return -1;

              }

 

       fwrite(Buf,sizeof(Buf),1,fp0);

       fseek(fp0,0,SEEK_SET);

 

       strcpy(Buf,"Buf is NULL!");

       printf("BUF:%s\n",Buf);

 

       fread(Buf,sizeof(Buf),1,fp0);

       printf("BUF: %s\n",Buf);

      

       return 0;

}

以上源码,我已测试通过。只是还有一点不毛病:

在驱动中增加对udev的支持_第1张图片

看到了吗?本来就是

BUF:glogalvar is char dev!

Read 4096 bytes from

……

我不知道怎么搞的,它们混到一块儿了,不过,这个问题应该和驱动没有关系。如果哪们仁兄知道怎么回事,还请告诉我一下。好了,基本上就这样了。

你可能感兴趣的:(在驱动中增加对udev的支持)