Paltform总线与其它总线框架的关系探究

来源:互联网 发布:域名需要几天 编辑:程序博客网 时间:2024/05/17 04:05

    在学习驱动的过程中,学习过Platform、I2C、SPI、USB等总线架构,对于Platform总线的理解是在书藉(宋宝华的《Linux设备驱动详解》)上所述的“一个现实的Linux设备和驱动通常需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI等的设备而言,这自然不是问题。但是在嵌入式系统里面,在SOC系统中集成的独立控制器、挂接在SOC内存空间的外设等却不依附于此类总线。基于这一背景Linux发明了一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver”。

    对于这几句话,可能是我的误解以为PCI、USB这种设备的驱动程序有自己总线的框架,而与Platform并没有一丝关联,完全是相互独立的框架。而Platform只适用于GPIO这种没有总线协议的外设。

但是最近回顾仔细分析内核源码后,发现完全理解错误了。由其是那段话中的后半句(标红),根本被我直接忽略了。简单的说,一个完整的I2C框架或者其它框架是依赖于Platform总线的。下面以基于Linux2.6.22内核的S3C2440关于I2C驱动为例。

    下图所列的就是在各种博客上都能看到的I2C框架。



    第一次看这个图的时候,以为这就是I2C驱动的全部,可是我意外地I2C_S3C2410.c文件的adapter驱动入口函数i2c_adap_s3c_init中发现了platform_driver_register函数,(其实很明显,想不通为什么现在才发现),这个明明是platform框架才会用到的啊,在这里是什么意思。而且adapter又作为了platform的driver端(对platform的理解,三个部分组成,driver端是无关于硬件的驱动,而dev端则是定义了一堆资源,最后的核心Bus只是构造了连接driver和dev的纽扣并没有太多的核心代码),那么与之对应的platform的dev端在哪儿呢,经过搜索.id成员(至少linux2.6.22是通过id字符串构建联系的)发现平台资源在devs.c(arch\arm\plat-s3c24xx)中定义了,如下表所示。

<span style="font-size:18px;">static struct resource s3c_i2c_resource[] = {[0] = {.start = S3C24XX_PA_IIC,.end   = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_IIC,.end   = IRQ_IIC,.flags = IORESOURCE_IRQ,}};struct platform_device s3c_device_i2c = {.name  = "s3c2410-i2c",.id  = -1,.num_resources  = ARRAY_SIZE(s3c_i2c_resource),.resource  = s3c_i2c_resource,};EXPORT_SYMBOL(s3c_device_i2c);</span>

    使用该资源的地方在mach-smdk2440.c(arch\arm\mach-s3c2440)中,如下表所示。

<span style="font-size:18px;">static struct platform_device *smdk2440_devices[] __initdata = {&s3c_device_usb,&s3c_device_lcd,&s3c_device_wdt,&s3c_device_i2c,&s3c_device_iis,};static void __init smdk2440_map_io(void){s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));s3c24xx_init_clocks(16934400);s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));}static void __init smdk2440_machine_init(void){s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  //依次添加smdk_machine_init();}</span>

    至此,根据如上代码及所在内核的路径,不难可以总结如下。

    一个I2C完整的驱动,应该至少包括两个方面:一个是基于Platform总线(dev-bus-drv)的驱动。另外一个是基于I2C固有的框架。

    从硬件架构上分析,两者作用不相同。将一个I2C插入一个自带I2C控制器的处理器平台,这一过程从硬件上分析,包含了1处理器2平台3 I2C设备。

    处理器和平台的关系,可以说平台定制了处理器,比如定制使用处理器的哪些资源,例如哪些GPIO作为输出连接LED设备,哪些GPIO作为输入连接了按键,另外一个处理器可能有多个I2C控制器,而且与其它资源如GPIO复用,因此,平台也需要定制哪个I2C控制器作为与外设连接的端口。而Platform总线就是起到这个作用,在某个文件(通常是mach-xxx)中确定该开发板所使用的资源,而对应的控制器驱动方面,则专注于与硬件无关的驱动,如i2c-s3c24xx.c。一旦匹配后,会调用drv端定义的probe函数,对于i2c而言,probe函数,主要完成了注册一个adapter的作用,至此完成了处理器I2C内部控制器驱动的初始化,同时也注册了adapter,为i2c设备驱动层面起到了铺垫。

    平台和I2C设备的关系,就是指一个I2C设备与处理器相连接的过程,上述过程,只是专注于提供一个适用于该处理器也可以说是平台的传输I2C正确的方法,但是不同的I2C设备传输的数据含义是不相同的,因此,还需要一个设备驱动,设备驱动就是基于I2C固有的框架(adapter-bus-drv)驱动完成的。即一旦向BUS注册一个DRV,BUS会从ADAPTER链表中轮询每一个,去调用DRV的attach_adapter函数,(内容基本上就是利用i2c_probe函数根据地址向设备发送查询信号,一旦成功就会调用i2c_probe指定的接口函数)。

综上,完整的框架粗略如下图所示。基于上述,再次去理解本文开头引用的那段话相信会有全新的感悟。


0 0
原创粉丝点击