说明之前:文档建立在实际的项目中:
硬件环境是三星x210,软件是android4.0 ubuntu13.04
EDITING AREA
从 Linux 2.6 起引入了一套新的驱动管理和注册机制:Platform_device 和Platform_driver。
Linux 中大部分的设备驱动,都可以使用这套机制, 设备用Platform_device 表示,驱动用Platform_driver 进行注册。
Linux platform driver 机制和传统的device driver 机制( 通过driver_register 函数进行注册) 相比,一个十分明显的优势在于platform 机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform device 提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性( 这些标准接口是安全的) 。
Platform 机制的本身使用并不复杂,由两部分组成: platform_device 和platfrom_driver 。
通过 Platform 机制开发发底层驱动的大致流程为:
定义platform_device -> 注册platform_device-> 定义platform_driver-> 注册platform_driver 。
MMC/SD/SDIO(以下简称MMC)的驱动从大的方面来说分为主设备驱动和从设备驱动
指的是集成于CPU内部的MMC controller,笔者用的是4412芯片,从datasheet可以看出,里面集成了四个MMC controller,分别是mmc0,mmc1,mmc2,mmc3。 并且从上一篇文章我们知道,WIFI模块是接在mmc3 这个host上面。SDIO 的初始化是用的MMC的端口,一般来说,一个是给SD使用的,另外一个给WIFI使用。x210板子的MMC硬件如下:
在linux系统中,将每个host设备封装成platform_device来逐一进行注册。对于笔者所使用的内核(3.2.0版本)来说,每一个host设备所对应的platform_device文件位于目录($KERNEL_SOURCE)/arch/arm/plat-samsung下,分别为dev-hsmmc.c,dev-hsmmc1.c,dev-hsmmc2.c,dev-hsmmc3.c,为了与实际WIFI模块对应,我们重点进入dev-hsmmc3.c文件看一看。
struct platform_device s3c_device_hsmmc3 = { .name = "s3c-sdhci", .id = 3, .num_resources = ARRAY_SIZE(s3c_hsmmc3_resource), .resource = s3c_hsmmc3_resource, .dev = { .dma_mask = &s3c_device_hsmmc3_dmamask, .coherent_dma_mask = 0xffffffffUL, .platform_data = &s3c_hsmmc3_def_platdata, }, };
从上图可以看出,该文件里面定义了一个名为s3c_device_hsmmc3的platform_device
x210系统下的板子的设置如下:
hanson@hanson-desktop:~/x210_ics_rtm_v13/kernel/arch/arm/mach-s5pv210$ vim mach-x210.c
文件里面的函数初始化,
static void __init smdkv210_machine_init(void) { s3c_pm_init(); x210_dm9000_init(); platform_add_devices(smdkv210_devices, ARRAY_SIZE(smdkv210_devices));
------------------
static struct platform_device *smdkv210_devices[] __initdata = { &s3c_device_adc, &s3c_device_cfcon, &s3c_device_fb, &s3c_device_hsmmc0, &s3c_device_hsmmc1, &s3c_device_hsmmc2, &s3c_device_hsmmc3, &s3c_device_i2c0, &s3c_device_i2c1, &s3c_device_i2c2,
总结来说,系统化在初始化的时候,就已经将s3c_device_hsmmc3(也就是那个host mmc3)注册进了platform总线(其他的mmc0,mmc1,mmc2都是一个道理)。
static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, .remove = __devexit_p(sdhci_s3c_remove), .suspend = sdhci_s3c_suspend, .resume = sdhci_s3c_resume, .driver = { .owner = THIS_MODULE, .name = "s3c-sdhci", }, };
当然,对于熟悉platform机制的朋友来说,此时仅仅只是注册了platform_device ,而对应的platform_driver还没有注册。下面就来说说这个platform_driver的注册,它是在$(KERNEL_SOURCE)/drivers/mmc/host目录下的sdhci-s3c.c文件中进行的,该文件中有如下的一个注册函数调用:
static int __init sdhci_s3c_init(void) { return platform_driver_register(&sdhci_s3c_driver); }在对sdhci_s3c_driver进行注册的过程中,系统会根据sdhci_s3c_driver->driver.name成员变量(此处是“s3c-sdhci”)在platform_bus 总线上寻找同名字的platform_dvice(这个过程称之为“探测”),通过上面对s3c_device_hsmmc3的注册分析,发现s3c_device_mmc3.name也刚好是“s3c-sdhci”,所以他俩刚好可以配对,探测成功,同时当大家查阅s3c_device_hsmmc,s3c_device_hsmmc1以及s3c_device_hsmmc2的时候发现他们的name成员变量都是“s3c-sdhci”,,所以会有四次成功的探测,每一次探测成功,就会调用sdhci_s3c_driver.probe函数---sdhci_s3c_probe,这个函数至关重要,在整个驱动注册过程中起着核心作用,关于它的详细内容,
http://processors.wiki.ti.com/index.php/WL18xx_Platform_Integration_Guide
http://blog.csdn.net/xieweihua2012/article/details/12844733