By 高焕堂 2011/09/09  

[ IT史上最完整、最经典的软件框架开发技术宝典 (上百篇经典文章&eBooks) ] 

[ 請指教:高老師的免費on-line教學視頻 ] 

                                                                                                            

[Go Back]  

 

天字第一号框架模式与Android/Linux 驱动开发 

3. Linux驱动框架:诞生轮胎

3.1  撰写file子类别,并诞生其对象(即轮胎) 

      编写驱动模块的程序代码:adder_module.c档案。

<引入标头档>

     在撰写驱动程序时,必须先# include 一些标头档(Head File): 

#include <linux/module.h>

#include <linux/fcntl.h>

#include <linux/semaphore.h>

#include <linux/kdev_t.h>

#include <linux/types.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/kernel.h>

#include <linux/uaccess.h>

 

<定义子类别:add_file>

   兹定义如下:

    struct add_file {

        int data[2];

        struct file* common;

        struct semaphore sem;

    };

    由于C程序代码并没有类别机制,所以运用指标来指向父类别的对象,如指令:

               struct file* common; 

这个common指标就是用来指向父类别(即file类别)的对象,它是在驱动模块初始化时由 Linux自动诞生的。

<诞生add_file的物件>

               struct add_file adder;

      这拿 add_file子类别来诞生一个对象,名称为:adder。这个对象是以静态(static)方式宣告的,会在驱动模块加载时刻(loading time)诞生出来。

 

3.2  撰写子类别的函数,来实作(implement)接口 

<撰写add_file的函数>

int add_open(struct inode *inode, struct file *filp){

        filp->private_data = &adder;

        adder.common = filp;

        return 0;

}

ssize_t add_access(int access_dir, struct file *filp, char __user *buf, size_t count){

        int *data = filp->private_data->data;

        ssize_t retval = 0;

        if(down_interruptible(&device->sem))  return -ERESTARTSYS;

        if(access_dir == 0) {

                int sum = data[0] + data[1];

                if(count != sizeof(int))  goto out;

                retval = copy_to_user(buf, &sum, sizeof(int));

           }

        else {       

                  if(count != sizeof(int) * 2)  goto out;

                  retval = copy_from_user(data, buf, count);

           }

        if(retval) {

                retval = -EFAULT;

                goto out;

        }

 out:

       up(&adder.sem);

       return retval;

}

int add_read(struct file *filp,  char __user *buf, size_t count, loff_t *f_pos){

        return add_access(0, filp, buf, count);

}

int add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){

        return add_access(1, filp, (char __user *)buf, count);

}

int add_release(struct inode *inode, struct file *filp){

        return 0;

}

     这些都是为了来实作file_operations接口里的抽象函数。 

<诞生file_operations的物件:fop物件>

    struct file_operations fop={

        .owner = THIS_MODULE,

        .open = add_open,

        .read = add_read,

        .write = add_write,

        .release = add_release,

    };

    这个file_operations类别只定义了函数,而没有定义数据项(data item),这相当于C++的纯粹抽象类别(pure abstract class),也相当于Java的接口(Interface)定义。这个对象也是以静态(static)方式宣告的,会在驱动模块加载时刻(loading time)诞生出来。就在fop对象诞生时刻,让fop接口的函数连结add_file子类别的函数,就体现了:add_file子类别实作(implement)了file抽象类别的抽象函数(定义于file父类别的file_opeartions接口里)[歡迎光臨 高煥堂 網頁:http://www.cnblogs.com/myEIT/ ]

     刚才说过了,在OO概念里,接口就相当于纯粹抽象类别,所以上图6里的小圆圈(就是接口的符号),也能以类别图形来表示,如下图: 

 

  图8、由add_file子类别实作file_operations接口

       现在已经定义及诞生了轮胎(即adder对象)。但是还不能用,因为还有装配到汽车、没有连结到引擎。于是,我们需要将轮胎装配到汽车上。此时,可以运用GoF的Factory Method设计模式。 

                                                                                                            

[Go Back]