LINUX 设备驱动模型之platform

 

一般的外设驱动是通过module_init();module_exit();加载的,这种情况下是直接加载驱动,没有设备和驱动的匹配过程。

linux总线、设备、驱动模型:驱动只管驱动,设备只管设备,总线则负责匹配设备和驱动。

主机控制器驱动和外设驱动分离

分层设计

在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

虚拟总线:platform总线 ,相应的设备是platform_device,驱动是platform_driver

platform_device是linux系统提供的一种附加手段,例如,我们通常把SOC内部集成的I2C,RTC,LCD等控制器都归纳为platform_device,而他们本身就是字符设备。


/**
 * platform_match - bind platform device to platform driver.
 * @dev: device.
 * @drv: driver.
 *
 * Platform device IDs are assumed to be encoded like this:
 * "<name><instance>", where <name> is a short description of the type of
 * device, like "pci" or "floppy", and <instance> is the enumerated
 * instance of the device, like '0' or '42'.  Driver IDs are simply
 * "<name>".  So, extract the <name> from the platform_device structure,
 * and compare it against the name of the driver. Return whether they match
 * or not.
 */
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);

	/* When driver_override is set, only bind to the matching driver */
	if (pdev->driver_override)
		return !strcmp(pdev->driver_override, drv->name);

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

	/* Then try ACPI style match */
	if (acpi_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);
}

 从以上信息可以知道, bind platform device to platform driver,先有平台设备,然后再去找平台驱动,然后返回匹配结果。

linux 3.x之后,ARM Linux不太喜欢以编码的形式去填写platform_device和注册,而倾向于根据设备树种的内容自动展开platform_device。

platform_driver  通过 module_platform_driver宏所定义的模块加载和卸载函数

#define module_platform_driver(__platform_driver) \
	module_driver(__platform_driver, platform_driver_register, \
			platform_driver_unregister)

#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
        return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
        __unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);

 

1. platform_bus_type--总线先被kenrel注册。

2. 系统初始化过程中调用platform_add_devices或者platform_device_register,将平台设备(platform devices)注册到平台总线中(platform_bus_type)
3. 平台驱动(platform driver)与平台设备(platform device)的关联是在platform_driver_register或者driver_register中实现,一般这个函数在驱动的初始化过程调用。

通过这三步,就将平台总线,设备,驱动关联起来。

1. platform bus先被kenrel注册。
------------------------------------------------------
do_basic_setup() -->-driver_init() -->-platform_bus_init()-->bus_register()

2. 系统初始化过程中调用platform_add_devices或者platform_device_register,将平台设备(platform devices)注册到平台总线中(platform_bus_type)
------------------------------------------------------
系统启动阶段,总线的驱动链表还是空的,所以启动阶段的platform_add_devices()只负责将设备添加到总线的设备链表上。

 

 使用设备树指定硬件资源:

  驱动程序也分为两部分(platform_driver, 设备树*.dts)
  在设备树*.dts中指定硬件资源, dts被编译为dtb文件, 在启动单板时会将dtb文件传给内核,
  内核根据dtb文件分配/设置/注册多个platform_device
  platform_driver的编写方法跟"总线设备驱动模型"一样。

 

 "来自dts的platform_device结构体" 与 "我们写的platform_driver" 的匹配过程:
  "来自dts的platform_device结构体"里面有成员".dev.of_node", 它里面含有各种属性, 比如 compatible, reg, pin
  "我们写的platform_driver"里面有成员".driver.of_match_table", 它表示能支持哪些来自于dts的platform_device
  如果"of_node中的compatible" 跟 "of_match_table中的compatible" 一致, 就表示匹配成功, 则调用 platform_driver中的probe函数;
  在probe函数中, 可以继续从of_node中获得各种属性来确定硬件资源

 

platform_device:

 

platform_driver:

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值