用面向对象思想分析linux字符设备驱动开发

时间:2021-05-18 23:37:29

这段时间在学习linux的内核驱动,写一下我的学习心得。大家一起交流交流。

之前开发都是采用C++、C#、java来开发,第一次采用纯C的语言来开发。因此或多或少都会在开发的时候采用面向对象的思想来思考问题。C语言虽然是面向过程的语言,但是在linux的内核中到处都可以看到其采用面向对象的思想,最典型的就是文件系统,llinux把各种文件系统都可以转换成一种标准的文件系统,提供统一的接口给用户。

    另一个例子就是在linux系统中,一切皆文件,对硬件设备的访问、操作都可以像文件一样通过read、write、open等接口(系统调用)来操作。下面结合linux内核驱动开发中的scull例子来详细描述一下。

    开发scull的大致步骤如下:

    1.获取主次设备号,初始化字符设备。

     获取主次设备号这里就不讲了。scull使用scull_dev类型的结构表示设备,其定义:

     struct scull_dev { 

        struct scull_qset *data;  /* Pointer to first quantum set */ 

        int quantum;  /* the current quantum size */ 

        int qset;  /* the current array size */ 

        unsigned long size;  /* amount of data stored here */ 

        unsigned int access_key;  /* used by sculluid and scullpriv */ 

        struct semaphore sem;  /* mutual exclusion semaphore  */ 

        struct cdev cdev; /* Char device structure */

     };

     在这里我们可以把cdev看作是基类,scull_dev继承cdev。在C语言中,没有继承机制,因此采用包含一个结构体对象来实现继承。而其他的成员则是在cdev基础上扩展的,是scull_dev自己所拥有的信息(资源)。因而采用面向对象思想来看这一步骤,就是继承cdev字符设备基类,实现一个我们所要开发的字符设备类,即scull_dev.

     这一步也很好理解,因为scull_dev也属于字符设备,属于cdev的一种。

    2.实现系统调用

    在linux系统中,一切皆文件,因而对设备的调用同文件的调用是一样的。在scull中需要定义一个file_operations对象,并在初始化的时候调用cdev_init(&dev->cdev, &scull_fops)绑定这些实现函数到字符设备。

    struct file_operations scull_fops = {

        .owner =  THIS_MODULE, 

        .llseek =  scull_llseek, 

        .read =  scull_read, 

        .write =  scull_write, 

        .ioctl =  scull_ioctl, 

        .open =  scull_open, 

        .release =  scull_release,  

    };  

    其中,scull_read,scull_release等就是我们要实现的函数。采用面向对象的思想话我们可以把这些函数看成是cdev的虚函数(接口,也许可能属于更上一层的接口),是我们继承cdev后需要按照我们自己需求实现的接口。系统调用read后根据虚函数机制,程序变根据虚指针选择scull_dev的scull_read。结合上面的步骤,如果linux中内核代码是C++,我们可以得到scull_dev的C++代码

    class cdev

    {

    public:

        cdev();

        virtual ~cdev();

 

        virtual int open();//参数我就不写了

        virtual int close();

        virtual ssize_t read();

        .....

    private:

        //一些其他成员变量或其他

    }

 

    class scull_dev:public cdev

    {

    public:

        scull_dev();

        int open();//即scull_open

        int close();//即scull_close

        .....

 

    private:

        struct scull_qset *data;  /* Pointer to first quantum set */ 

        int quantum;  /* the current quantum size */ 

        int qset;  /* the current array size */ 

        unsigned long size;  /* amount of data stored here */ 

        unsigned int access_key;  /* used by sculluid and scullpriv */ 

        struct semaphore sem;  /* mutual exclusion semaphore  */ 

    }

    因此结合上面二个步骤,我们开发字符设备驱动非常简单,只是要实现一个我们自己需要的字符设备,即生成一个结构体,该结构体包括cdev这个结构体,再实现一些系统调用。在实现这些函数中,要注意一些其他的细节就可以了,比如同步、延时、休眠等。

 

    这里只是采用面向对象的思想来分析字符设备驱动的开发而已,可以使字符设备的开发思路非常明了。