您的位置:首页 > 其它

platform driver and device学习笔记

2014-03-06 23:30 375 查看
-v0.1 2014.3.4 *** 以gpio驱动为中心,整理设备模型和设备树, 只是整理了gpio

驱动的注册过程, gpio的驱动见driver/gpio/gpio-mxc.c

1. 顺序整理device建立,driver和device结合的过程

设备要先写在device tree中,kernel在启动阶段先解析dtb中的信息(dtb由dts编译得来),

解析得到的信息先以device_node组成的结构保存,在启动的do_initcall()函数中再使用该

信息向系统中注册设备,随后驱动程序和设备联系在一起,整个过程完成

从dtb中解析信息:unflatten_device_tree()

向系统中注册设备:

start_kernel()
      -->rest_init();
	  kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
	      -->kernel_init(); // 在1号线程中执行的函数
	          -->kernel_init_freeable();
	              -->do_basic_setup();
		          -->driver_init(); //初始化sys文件系统的顶层文件
			  do_initcalls();
		              -->do_initcall_level(level);
do_initcall_level(level)会调用各级的初始化函数,其中就会调用到:

v2m.c中的v2m_dt_init()函数

DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
		.dt_compat	= v2m_dt_match,
		.smp		= smp_ops(***_smp_ops),
		.smp_init	= smp_init_ops(***_smp_init_ops),
		.map_io		= v2m_dt_map_io,
		.init_early	= v2m_dt_init_early,
		.init_time	= v2m_dt_timer_init,
		.init_machine	= v2m_dt_init,
	MACHINE_END
调用v2m_dt_init()函数其实是因为调用了.init_machine
static void __init v2m_dt_init(void)
	{
		l2x0_of_init(0x00400000, 0xfe0fffff);
	#ifndef CONFIG_ARCH_***
		of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL);
	#else
		of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
	#endif
	}
接着往下走
of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL);
      -->of_platform_bus_create(child, matches, lookup, parent, true);
	      -->of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
	      //上面创建struct platform_device
	          -->of_device_alloc(np, bus_id, parent);
		      -->platform_device_alloc("", -1);
		          -->device_initialize(&pa->pdev.dev); //初始化设备
		          pa->pdev.dev.release = platform_device_release;
			  arch_setup_pdev_archdata(&pa->pdev);
		  ...
		  -->of_device_alloc() end!
		  of_device_add(dev);
	              -->device_add(&ofdev->dev);
		      接第3部分的device_add()之后的内容

2. 从gpio的驱动入手

可以分析下kernel中drivers/gpio/gpio-mxc.c的代码,其中的核心数据结构是platform_driver
struct platform_driver
          |-->int (*probe)(struct platform_device *);
          |-->int (*remove)(struct platform_device *);
	  |-->void (*shutdown)(struct platform_device *);
	  |-->int (*suspend)(struct platform_device *, pm_message_t state);
	  |-->int (*resume)(struct platform_device *);
          |-->struct device_driver driver;-->|-->*name, *bus..
	                                     |-->callbacks: *probe,*remove,*shutdown
					     |              *sudpend,*resume
		             		     |-->struct attribute_group **groups
					     |-->struct driver_private *p
	                                     |-->struct of_device_if *of_match_table
					     |...
	  |
	  |-->const struct platform_device_id *id_table;


platform_driver_register(&***_gpio_driver);
      -->__platform_driver_register(drv, THIS_MODULE) //宏
	  drv->driver.owner = owner;
	  drv->driver.bus = &platform_bus_type;
	  drv->driver.probe = platform_drv_probe;
	  drv->driver.remove = platform_drv_remove;
	  drv->driver.shutdown = platform_drv_shutdown;
      driver_register(&drv->driver);
以上的代码填充了platform_driver中的device_driver中的回调函数,并把device_driver

向系统注册, 可见device_driver中已经有了bus的信息,在driver_register中就可以把

本driver向它对应的bus注册,在driver向bus注册的时候会和device做匹配

3. 怎么调用到probe函数,实现device和driver的绑定

上面gpio-mxc.c代码中的核心是mxc_gpio_probe函数
driver_register()
      -->bus_add_driver(drv);
          -->driver_attach(drv);
__driver_attach(struct device *dev, void *data) //上个函数中的回调函数
      -->driver_probe_device(drv, dev);
	  -->really_probe(dev, drv); // struct device_driver *drv
	      -->drv->probe(dev); // platform_drv_probe
platform_drv_probe(_dev); // struct device *_dev
      -->drv->probe(dev);// struct platform_device *dev
由此可见整个probe的目的就是把platform_device *dev找见传给probe函数,这样可以把驱动和设备绑定

同样的道理,也可以在注册设备的时候实现设备和驱动的绑定:
platform_device_register(struct platform_device *pdev)
     -->platform_device_add(pdev);
         -->device_add(&pdev->dev);
	     -->bus_probe_device(dev);
	         -->device_attach(dev);
		     -->bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
__device_attach()
      -->driver_probe_device(drv, dev);
	  ... 余下和上面相同
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: