Linux 2.6下的platform_driver和platform_device(结合G870加密磁头驱动分析)

首先介绍一下注册一个驱动的步骤:
1、定义一个platform_driver结构
2、初始化这个结构,指定其probe、remove等函数,并初始化其中的driver变量

3、实现其probe、remove等函数


看platform_driver结构,定义于include/linux/platform_device.h文件中:
struct platform_driver {
    int (*probe)(struct platform_device *);
    int (*remove)(struct platform_device *);
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*suspend_late)(struct platform_device *, pm_message_t state);
    int (*resume_early)(struct platform_device *);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
};

    可见,它包含了设备操作的几个功能函数,同样重要的是,它还包含了一个device_driver结构。刚才提到了驱动程序中需要初始化这个变量。下面看一下这个变量的定义,位于include/linux/device.h中:

struct device_driver {
    const char        * name;
    struct bus_type        * bus;
    struct kobject        kobj;
    struct klist        klist_devices;
    struct klist_node    knode_bus;
    struct module        * owner;
    const char         * mod_name;  /* used for built-in modules */
    struct module_kobject    * mkobj;
    int    (*probe)    (struct device * dev);
    int    (*remove)    (struct device * dev);
    void    (*shutdown)    (struct device * dev);
    int    (*suspend)    (struct device * dev, pm_message_t state);
    int    (*resume)    (struct device * dev);
};

    需要注意这两个变量:name和owner。那么的作用主要是为了和相关的platform_device关联起来,owner的作用是说明模块的所有者,驱动程序中一般初始化为THIS_MODULE。

   加密磁头的platform_driver定义如下:

static struct platform_driver secure_head_driver = {
    .driver = {
               .name = "secure_head",
              },
    .suspend = secure_head_suspend,
    .resume = secure_head_resume,
    .probe = secure_head_module_probe,
    .remove = secure_head_module_remove,
};

注意其中的driver这个结构体,只初始化了name。接着看一下和driver相关的另一个结构,定义如下:


struct platform_device {
    const char    * name;
    int        id;
    struct device    dev;
    u32        num_resources;
    struct resource    * resource;
};

该结构中也有一个name变量。platform_driver从字面上来看就知道是设备驱动。设备驱动是为谁服务的呢?当然是设备了。platform_device就描述了设备对象。加密磁头的platform_device定义如下(定义在arch/arm/mach-mx25/devices.c中):

static struct platform_device mxc_secure_head_device = {
    .name = "secure_head",
    .id = 0,
    .num_resources = ARRAY_SIZE(imx_secure_head_resources),
    .resource = imx_secure_head_resources,
    .dev = {
            .release = NULL,
           },
};

它的name变量和刚才上面的platform_driver的name变量是一致的,内核正是通过这个一致性来为驱动程序找到资源,即platform_device中的resource。这个结构的定义如下,位于include/linux/ioport.h中:

struct resource {
    resource_size_t start;
    resource_size_t end;
    const char *name;
    unsigned long flags;
    struct resource *parent, *sibling, *child;
};

下面是磁头的resource的定义:

static struct resource imx_secure_head_resources[] = {
    [0] = {
           .start = IOMUX_TO_IRQ(MX25_PIN_DE_B),
           .end = IOMUX_TO_IRQ(MX25_PIN_DE_B),
           .flags = IORESOURCE_IRQ,
           },
};

      注意:其中IORESOURCE_IRQ表示这个是中断资源,IOMUX_TO_IRQ(MX25_PIN_DE_B)为加密磁头所对应的中断引脚的映射地址。这样在注册设备时内核才知道这些数据。

     上面把驱动程序中涉及到的主要结构都介绍了,下面主要说一下驱动程序中怎样对这个结构进行处理,以使驱动程序能运行。相信大家都知道module_init()这个宏。驱动模块加载的时候会调用这个宏。它接收一个函数为参数,作为它的参数的函数将会对上面提到的platform_driver进行处理。下面是加密磁头中这个函数的定义:

static int __init secure_head_module_init(void)
{
    return platform_driver_register(&secure_head_driver);
}

   注意函数体的最后一行,它调用的是platform_driver_register这个函数。这个函数定义于driver/base/platform.c中,原型如下:

int platform_driver_register(struct platform_driver *drv)

 它的功能就是为上面提到的plarform_driver中的driver这个结构中的probe、remove这些变量指定功能函数。

    到目前为止,内核就已经知道了有这么一个驱动模块。内核启动的时候,就会调用与该驱动相关的probe函数。我们来看一下probe函数实现了什么功能。

    probe函数的原型为

    int xxx_probe(struct platform_device *pdev)

    即它的返回类型为int,接收一个platform_device类型的指针作为参数。返回类型就是我们熟悉的错误代码了,而接收的这个参数呢,我们上面已经说过,驱动程序为设备服务,就需要知道设备的信息。而这个参数,就包含了与设备相关的信息。

   probe函数接收到plarform_device这个参数后,就需要从中提取出需要的信息。它一般会通过调用内核提供的platform_get_resource和platform_get_irq等函数来获得相关信息。如通过platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。通过platform_get_irq得到设备的中断号以后,就可以调用request_irq函数来向系统申请中断。这些操作在设备驱动程序中一般都要完成。下面是secure_head_module_probe的定义:

static int secure_head_module_probe(struct platform_device *pdev)
{
    int ret = 0;
    int retval;
    struct device *temp_class;

    printk("[sec] secure_head_module_probe.\n");
    /* create the chrdev */
    secure_head_major = register_chrdev(0, "secure_head", &secure_head_fops);  //注册字符设备
    if(secure_head_major < 0)//返回负表示创建字符设备失败
    {
        dev_err(&pdev->dev, "Unable to get a major for secure_head\n");
        return secure_head_major;
    }

    //用udev在/dev/下动态生成设备文件,这样用户就不用手工调用mknod了.
    //首先使用class_create在/sysfs下创建类,再使用device_create注册设备到/sysfs中
    secure_head_class = class_create(THIS_MODULE, "secure_head");
    if (IS_ERR(secure_head_class))
    {
        dev_err(&pdev->dev, "Error creating secure_head class.\n");
        ret = PTR_ERR(secure_head_class);
        goto err_out1;
    }
    temp_class = device_create(secure_head_class, NULL,MKDEV(secure_head_major, 0), NULL, "secure_head");
    if (IS_ERR(temp_class))
    {
        dev_err(&pdev->dev, "Error creating secure_head class device.\n");
        ret = PTR_ERR(temp_class);
        goto err_out2;
    }
    spin_lock_init(&securehead_lock);
//    gpio_secure_head_active();
    irq = platform_get_irq(pdev, 0);//获取ADC设备的中断资源
    set_irq_type(irq, IRQF_TRIGGER_RISING); //磁头DAV触发中断
    retval = request_irq(irq,secure_head_interrupt,0, SEC_NAME, SEC_NAME);

    magicCardTimer.expires = jiffies + msecs_to_jiffies(timeOutVal);
    magicCardTimer.function = magic_timeout_hadle;
    init_timer(&magicCardTimer);
    if(retval)
    {
        printk("[sec] request irq error!");
        return retval;
    }
    pr_info("secure_head irq: %d\n",irq);
    return ret;

err_out2:
    class_destroy(secure_head_class);
    device_destroy(secure_head_class, MKDEV(secure_head_major, 0));
err_out1:
    unregister_chrdev(secure_head_major, "secure_head");
    return ret;
}

      在完成了上面这些工作和一些其他必须的初始化操作后,就可以向系统注册我们在/dev目录下能看到的设备文件了。所以接下来就是完成对file_operations 结构体的定义了:

static struct file_operations secure_head_fops = {
    .owner = THIS_MODULE,
    .ioctl = secure_head_ioctl,
    .open = secure_head_open,
    .release = secure_head_free,
};

        当用户打开一个设备,并调用其read、write等函数的时候,就可以通过上面的file_operations来找到相关的函数。所以,用户驱动程序还需要实现这些函数,具体实现和相关的设备有密切的关系,这里就不再介绍了。

你可能感兴趣的:(加密,linux,struct,Module,Class,resources)