MINI2440看门狗驱动 —— 案说平台设备&驱动

0 前言

    关于平台设备驱动的资料网上非常多,本文并不打算重复这些描述,而是以看门狗平台设备和驱动为例子进行阐述。本文的源码均来自Linux内核(linux-2.6.39.4已经支持mini2440,无需作任何移植)。

1 平台设备

1.1 定义

(1)设备

struct platform_device s3c_device_wdt = { 
    .name       = "s3c2410-wdt",                
    .id     = -1,                               
    .num_resources  = ARRAY_SIZE(s3c_wdt_resource), 
    .resource   = s3c_wdt_resource,                 
};
EXPORT_SYMBOL(s3c_device_wdt); 
// @file: arch/arm/plat-samsung/dev-wdt.c

(2)资源

static struct resource s3c_wdt_resource[] = { 
    [0] = { 
        .start  = S3C_PA_WDT,           
        .end    = S3C_PA_WDT + SZ_1K,   
        .flags  = IORESOURCE_MEM,       
    },  
    [1] = { 
        .start  = IRQ_WDT,              
        .end    = IRQ_WDT,              
        .flags  = IORESOURCE_IRQ,       
    }   
};
// @file: arch/arm/plat-samsung/dev-wdt.c

1.2 引用

    定义一个平台设备数组mini2440_devices,该数组包含了mini2440开发板的所有平台设备,其中当然包括上述s3c_device_wdt

static struct platform_device *mini2440_devices[] __initdata = {
    ...
	&s3c_device_wdt,
    ...
};
// @file: arch/arm/mach-s3c2440/mach-mini2440.c

1.3 注册

(1)注册函数

    mini2440_init()调用platform_add_devices()将上述mini2440_devices注册到系统,即可完成平台设备的注册:

static void __init mini2440_init(void)
{
    ...
	platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
    ...

}
// @file: arch/arm/mach-s3c2440/mach-mini2440.c

(2)注册时机

    上述mini2440_init()函数是何时被调用的呢?答案是在内核初始化设备的时候:

MACHINE_START(MINI2440, "MINI2440")
    /* Maintainer: Michel Pollet <buserror@gmail.com> */
    .atag_offset    = 0x100,
    .map_io     = mini2440_map_io,
    .init_machine   = mini2440_init,  // 瞧这里!
    .init_irq   = s3c2440_init_irq,
    .init_time  = mini2440_init_time,
MACHINE_END
// @file: arch/arm/mach-s3c2440/mach-mini2440.c

2 平台驱动

2.1 定义

    为了和平台设备匹配,平台驱动的name要与平台设备的name一致:

static struct platform_driver s3c2410wdt_driver = {
	.probe		= s3c2410wdt_probe,
	.remove		= __devexit_p(s3c2410wdt_remove),
	.shutdown	= s3c2410wdt_shutdown,
	.suspend	= s3c2410wdt_suspend,
	.resume		= s3c2410wdt_resume,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "s3c2410-wdt",
	},
};
// @file: drivers/watchdog/s3c2410_wdt.c

    上述s3c2410wdt_probes3c2410wdt_removes3c2410wdt_shutdowns3c2410wdt_suspend以及s3c2410wdt_resume都在同一个源文件中定义,详见源文件drivers/watchdog/s3c2410_wdt.c。

2.2 注册

    在模块加载函数watchdog_init()中调用platform_driver_register()函数注册上述平台驱动s3c2410wdt_driver

static int __init watchdog_init(void)
{
	printk(banner); 
	return platform_driver_register(&s3c2410wdt_driver); 
}
// @file: drivers/watchdog/s3c2410_wdt.c

3 设备与驱动匹配

3.1 匹配函数

    系统自动调用platform_match()函数实现平台设备和平台驱动的匹配:

static int platform_match(struct device *dev, struct device_driver *drv)
{
    struct platform_device *pdev = to_platform_device(dev);
    struct platform_driver *pdrv = to_platform_driver(drv);

    /* Attempt an OF style match first */
    if (of_driver_match_device(dev, drv))
        return 1;

    /* Then try to match against the id table */
    if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

    /* fall-back to driver name match */
    return (strcmp(pdev->name, drv->name) == 0);
}
// @file: drivers/base/platform.c

3.2 匹配时机

    内核中调用上述匹配函数platform_match()函数的地方不多,只有两个,一个是early_platform_match()函数,另外一个是early_platform_left()函数:

(1)early_platform_match()

static  __init struct platform_device *
early_platform_match(struct early_platform_driver *epdrv, int id)
{
    struct platform_device *pd;

    list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
        if (platform_match(&pd->dev, &epdrv->pdrv->driver))
            if (pd->id == id)
                return pd; 
    
    return NULL;
}
// @file: drivers/base/platform.c

(2)early_platform_left()

static  __init int early_platform_left(struct early_platform_driver *epdrv,
                       int id)
{
    struct platform_device *pd;

    list_for_each_entry(pd, &early_platform_device_list, dev.devres_head)
        if (platform_match(&pd->dev, &epdrv->pdrv->driver))
            if (pd->id >= id)
                return 1;

    return 0;
}
// @file: drivers/base/platform.c

    分析上述两个函数可知道,内核通过遍历所有平台设备和平台驱动来进行匹配。

4 总结

    平台设备台通常是集体注册的,而平台驱动则各自独立注册。

参考资料

[1]平台设备驱动总结
[2]linux平台设备驱动架构详解 Linux Platform Device and Driver

[3]Linux驱动开发入门与实战(2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneSea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值