Platform设备模型

本文目的是介绍怎么使用平台驱动模型,而不去深究其platform driver的内部实现细节。首先进入Documentation/driver-model/目录,这里的文档隆重介绍了driver开发的三兄弟:Bus,Device,Driver。这三个概念勾勒出一个老司机驾驶一辆个性卡车使向无边远方的画

面,Bus这条使向无边远方的路正是计算机中总线,driver驱动着外设device不知疲劳地行使。

include/linux/device.h

/**

 *struct bus_type - The bus type of the device

从buf_type结构体定义看出,bus是连接CPU和各外设的通道,其可是实实在在的总线如USB,PCI等,也可以是如platform bus的虚拟总线。当有device和device driver加入某总线时,该bus的bus_type中的match被调用,一般按照名字匹配,如果匹配成功,则driver定义的probe函数被调用,类似driver的其他操作也会引起bus的相关定义被执行。这些属于Bus管理device和driver的操作,驱动工程师要实现driver中的probe,remove,suspend等操作,在同一个文件中driver的定义如下:

/**

 *struct device_driver - The basic device driver structure

没错,这driver就是向系统提供一些设备信息,以及操作设备的接口。其中bus告知系统其归属那个bus,bus根据name进行match匹配。of_match_table用于匹配Devicetree中设备,acpi_match_table供服务器BIOS发现ACPI管理的设备,似乎说明一个driver可以驱动多个设备。三兄弟中最后该露面的device显然就是对外设的抽象啦,也在同一文件中定义:

/**

 *struct device - The basic device structure

其中platform_data在platform_txt中有一段说明

In many cases, the memory and IRQ resourcesassociated with the platform device are not enough to let the device'sdriver work.  Board setup code will often provide additional informationusing the device's platform_data field to hold additional information.

确Bus,Driver,Device三兄弟的身份后,驱动的编写可以分步进行:

1.定义bus,driver,device;

2.向系统添加bus和device,注册driver

按照这个步骤和框架,具体总线和设备驱动往往封装自己的驱动三兄弟,如PCI总线用函数pci_register_driver注册自己的驱动,在BIOS启动时扫描枚举PCI总线上的所有设备,调用PCI总线上的设备驱动。类似于PCI总线,虚拟出一个通用的platform设备模型,首先看看

Documentation/driver-model/platform.txt

Platformdevices

~~~~~~~~~~~~~~~~

Platformdevices are devices that typically appear as autonomous

entitiesin the system. This includes legacy port-based devices and

hostbridges to peripheral buses, and most controllers integrated

intosystem-on-chip platforms. What theyusually have in common

isdirect addressing from a CPU bus. Rarely, a platform_device will

beconnected through a segment of some other kind of bus; but its

registerswill still be directly addressable.

Platform device常常用于那些可以CPU直接寻址的外设,一个集成在SOC中的外设大多可以通过寄存器直接寻址操作,Platform 设备模型可以用于非常多的设备驱动。

通常board文件说明了外设的硬件资源,fireware的启动代码会根据board文件board-specific产生和注册platform device。

Somedrivers are not fully converted to the driver model, because they take

on anon-driver role: the driver registersits platform device, rather than

leavingthat for system infrastructure. Suchdrivers can't be hotplugged

orcoldplugged, since those mechanisms require device creation to be in a

differentsystem component than the driver.

该文档中一段文字强烈的鄙夷了那些把创建platformdevice的工作交给驱动来做的做法,

认为platform device应当由那些系统底层结构去做,那些不支持热插拔或冷插拔的设备在此躺枪,然而还是大度给出了Legacy device的driver接口:

Nonethe less, there are some APIs to support such legacy drivers. Avoid

usingthese calls except with such hotplug-deficient drivers.

structplatform_device *platform_device_alloc(

                       const char *name, int id);

Youcan use platform_device_alloc() to dynamically allocate a device, which

youwill then initialize with resources and platform_device_register().

Abetter solution is usually:

structplatform_device *platform_device_register_simple(

                       const char *name, intid,

                       struct resource *res,unsigned int nres);

Youcan use platform_device_register_simple() as a one-step call to allocate

andregister a device.

include/linux/platform_device.h先查看下structplatform_device和struct platform_driver,它们是对struct device和struct drvier的简单包裹和封装。先用这些老接口函数就可以有了platform 设备模型的框架了。

======

Legace device

static struct platform_driver xyz_driver ={

       .probe = xyz_probe,

       .remove = xyz_remove,

       .driver = {

                   .owner = THIS_MODULE,

                   .name = XYZ_DEV_NAME,

                   .pm = &xyz_pm,

                   },  

};

static int __init xyz_init(void)

{

                   structplatform device  xyz_device =

           platform_device_register_simple(XYZ_DEV_NAME, 0, NULL, 0);

       return platform_driver_register(&xyz_driver);

}

static void __exit xyz_exit(void)

{

       platform_driver_unregister(&xyz_driver);

       platform_device_unregister(xyz_device);

       xyz_device = NULL;

}

 

module_init(xyz_init);

module_exit(xyz_exit);

======

如果系统支持Device tree,设备树device tree, 也称作Open Firmware(OF)或Flattened Device Tree(FDT)。则fireware启动代码会根据board文件产生和添加platformdevice,其实是DTC先编译board文件生成dtb,fireware载入的是该dtb,驱动只需要定义并注册platform driver即可。

先配置内核支持Device tree

配置该选项后CONFIG_OF宏被打开。

1.定义board文件,比如在此添加一个无线wlan驱动。

arch/arm/boot/dts/xyz.dts

/

xyz-wlan {

     compatible= "xyz, Exynos 8890";

 };

2.在驱动中定义of_device_id.

static const struct of_device_id xyz_of_match[] = {

        {.compatible = "xyz, Exynos 8890",},

       {}, 

};

MODULE_DEVICE_TABLE(of, xyz_of_match);

MODULE_DEVICE_TABLE的第一个参数是设备的类型,如果是USB设备,那自然是usb(如果是PCI设备,那将是pciplatform设备用of类型)。

后面一个参数是设备表,这个设备表的最后一个元素是空的,用于标识结束。

 

3.定义和注册platform driver

static struct platform_driver xyz_driver ={

        .probe = xyz_probe,

       .remove = xyz_remove,

       .driver = {

                .owner = THIS_MODULE,

                .name = " Exynos 8890",

               .of_match_table = xyz_of_match,

       },  

};

如果module_init只做platform_driver_register,module_exit只做platform_driver_unregister的话,则函数module_platform_driver完成了module_init和module_exit的动作;

module_platform_driver(xyz_driver);

到此,貌似摊上事了,Device Tree我们这里简单绕过了,显然它是一块无法绕开而又难吭的骨头。系统怎么生成platform device??of_device_id应该就是struct device结构体中的成员,怎么利用它进行match的??

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值